summaryrefslogtreecommitdiff
path: root/usr/src/lib/libshare
diff options
context:
space:
mode:
authoramw <none@none>2007-10-25 16:34:29 -0700
committeramw <none@none>2007-10-25 16:34:29 -0700
commitda6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch)
tree65be91fb78a6a66183197595333f2e8aafb4640a /usr/src/lib/libshare
parente845e33dd0d1aea22db7edaa8c7d43955d24609b (diff)
downloadillumos-joyent-da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0.tar.gz
PSARC/2007/218 caller_context_t in all VOPs
PSARC/2007/227 VFS Feature Registration and ACL on Create PSARC/2007/244 ZFS Case-insensitive support PSARC/2007/315 Extensible Attribute Interfaces PSARC/2007/394 ls(1) new command line options '-/' and '-%': CIFS system attributes support PSARC/2007/403 Modified Access Checks for CIFS PSARC/2007/410 Add system attribute support to chmod(1) PSARC/2007/432 CIFS system attributes support for cp(1), pack(1), unpack(1), compress(1) and uncompress(1) PSARC/2007/444 Rescind SETTABLE Attribute PSARC/2007/459 CIFS system attributes support for cpio(1), pax(1), tar(1) PSARC/2007/546 Update utilities to match CIFS system attributes changes. PSARC/2007/560 ZFS sharesmb property 4890717 want append-only files 6417428 Case-insensitive file system name lookup to support CIFS 6417435 DOS attributes and additional timestamps to support for CIFS 6417442 File system quarantined and modified attributes to support an integrated Anti-Virus service 6417453 FS boolean property for rejecting/allowing invalid UTF-8 sequences in file names 6473733 RFE: Need support for open-deny modes 6473755 RFE: Need ability to reconcile oplock and delegation conflicts 6494624 sharemgr needs to support CIFS shares better 6546705 All vnode operations need to pass caller_context_t 6546706 Need VOP_SETATTR/VOP_GETATTR to support new, optional attributes 6546893 Solaris system attribute support 6550962 ZFS ACL inheritance needs to be enhanced to support Automatic Inheritance 6553589 RFE: VFS Feature Registration facility 6553770 RFE: ZFS support for ACL-on-CREATE (PSARC 2007/227) 6565581 ls(1) should support file system attributes proposed in PSARC/2007/315 6566784 NTFS streams are not copied along with the files. 6576205 cp(1), pack(1) and compress(1) should support file system attributes proposed in PSARC/2007/315 6578875 RFE: kernel interfaces for nbmand need improvement 6578883 RFE: VOP_SHRLOCK needs additional access types 6578885 chmod(1) should support file system attributes proposed in PSARC/2007/315 6578886 RFE: disallow nbmand state to change on remount 6583349 ACL parser needs to support audit/alarm ACE types 6590347 tar(1) should support filesystem attributes proposed in PSARC/2007/315 6597357 *tar* xv@ doesn't show the hidden directory even though it is restored 6597360 *tar* should re-init xattr info if openat() fails during extraction of and extended attribute 6597368 *tar* cannot restore hard linked extended attributes 6597374 *tar* doesn't display "x " when hard linked attributes are restored 6597375 *tar* extended attribute header off by one 6614861 *cpio* incorrectly archives extended system attributes with -@ 6614896 *pax* incorrectly archives extended system attributes with -@ 6615225 *tar* incorrectly archives extended system attributes with -@ 6617183 CIFS Service - PSARC 2006/715
Diffstat (limited to 'usr/src/lib/libshare')
-rw-r--r--usr/src/lib/libshare/Makefile2
-rw-r--r--usr/src/lib/libshare/common/libshare.c1194
-rw-r--r--usr/src/lib/libshare/common/libshare.h48
-rw-r--r--usr/src/lib/libshare/common/libshare_impl.h13
-rw-r--r--usr/src/lib/libshare/common/libshare_zfs.c388
-rw-r--r--usr/src/lib/libshare/common/libsharecore.c236
-rw-r--r--usr/src/lib/libshare/common/mapfile-vers19
-rw-r--r--usr/src/lib/libshare/common/plugin.c175
-rw-r--r--usr/src/lib/libshare/common/scfutil.c418
-rw-r--r--usr/src/lib/libshare/nfs/libshare_nfs.c47
-rw-r--r--usr/src/lib/libshare/smb/Makefile51
-rw-r--r--usr/src/lib/libshare/smb/Makefile.com88
-rw-r--r--usr/src/lib/libshare/smb/amd64/Makefile31
-rw-r--r--usr/src/lib/libshare/smb/i386/Makefile30
-rw-r--r--usr/src/lib/libshare/smb/libshare_smb.c1641
-rw-r--r--usr/src/lib/libshare/smb/libshare_smb.h75
-rw-r--r--usr/src/lib/libshare/smb/mapfile-vers34
-rw-r--r--usr/src/lib/libshare/smb/smb_share_doorclnt.c951
-rw-r--r--usr/src/lib/libshare/smb/sparc/Makefile30
-rw-r--r--usr/src/lib/libshare/smb/sparcv9/Makefile31
20 files changed, 5142 insertions, 360 deletions
diff --git a/usr/src/lib/libshare/Makefile b/usr/src/lib/libshare/Makefile
index fb19160065..0c333e4459 100644
--- a/usr/src/lib/libshare/Makefile
+++ b/usr/src/lib/libshare/Makefile
@@ -35,7 +35,7 @@ $(BUILD64)MACHS += $(MACH64)
# Add plugin module directories here. They need to build after the libshare
# objects are built.
-PLUGINS = nfs
+PLUGINS = smb nfs
$(PLUGINS): $(MACHS)
SUBDIRS = $(MACHS) $(PLUGINS)
diff --git a/usr/src/lib/libshare/common/libshare.c b/usr/src/lib/libshare/common/libshare.c
index 25213e97a4..49104b2abe 100644
--- a/usr/src/lib/libshare/common/libshare.c
+++ b/usr/src/lib/libshare/common/libshare.c
@@ -58,6 +58,16 @@
#define SA_STRSIZE 256 /* max string size for names */
/*
+ * internal object type values returned by sa_get_object_type()
+ */
+#define SA_TYPE_UNKNOWN 0
+#define SA_TYPE_GROUP 1
+#define SA_TYPE_SHARE 2
+#define SA_TYPE_RESOURCE 3
+#define SA_TYPE_OPTIONSET 4
+#define SA_TYPE_ALTSPACE 5
+
+/*
* internal data structures
*/
@@ -69,16 +79,20 @@ extern int gettransients(sa_handle_impl_t, xmlNodePtr *);
extern int sa_valid_property(void *, char *, sa_property_t);
extern char *sa_fstype(char *);
extern int sa_is_share(void *);
+extern int sa_is_resource(void *);
extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */
extern int sa_group_is_zfs(sa_group_t);
extern int sa_path_is_zfs(char *);
extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
+extern int sa_zfs_set_sharesmb(sa_group_t, char *, int);
extern void update_legacy_config(sa_handle_t);
extern int issubdir(char *, char *);
extern int sa_zfs_init(sa_handle_impl_t);
extern void sa_zfs_fini(sa_handle_impl_t);
extern void sablocksigs(sigset_t *);
extern void saunblocksigs(sigset_t *);
+static sa_group_t sa_get_optionset_parent(sa_optionset_t);
+static char *get_node_attr(void *, char *);
/*
* Data structures for finding/managing the document root to access
@@ -188,6 +202,21 @@ sa_errorstr(int err)
case SA_NOT_SHARED:
ret = dgettext(TEXT_DOMAIN, "not shared");
break;
+ case SA_NO_SUCH_RESOURCE:
+ ret = dgettext(TEXT_DOMAIN, "no such resource");
+ break;
+ case SA_RESOURCE_REQUIRED:
+ ret = dgettext(TEXT_DOMAIN, "resource name required");
+ break;
+ case SA_MULTIPLE_ERROR:
+ ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
+ break;
+ case SA_PATH_IS_SUBDIR:
+ ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
+ break;
+ case SA_PATH_IS_PARENTDIR:
+ ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
+ break;
default:
(void) snprintf(errstr, sizeof (errstr),
dgettext(TEXT_DOMAIN, "unknown %d"), err);
@@ -376,6 +405,36 @@ is_shared(sa_share_t share)
}
/*
+ * excluded_protocol(share, proto)
+ *
+ * Returns B_TRUE if the specified protocol appears in the "exclude"
+ * property. This is used to prevent sharing special case shares
+ * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is
+ * returned if the protocol isn't in the list.
+ */
+static boolean_t
+excluded_protocol(sa_share_t share, char *proto)
+{
+ char *protolist;
+ char *str;
+ char *token;
+
+ protolist = sa_get_share_attr(share, "exclude");
+ if (protolist != NULL) {
+ str = protolist;
+ while ((token = strtok(str, ",")) != NULL) {
+ if (strcmp(token, proto) == 0) {
+ sa_free_attr_string(protolist);
+ return (B_TRUE);
+ }
+ str = NULL;
+ }
+ sa_free_attr_string(protolist);
+ }
+ return (B_FALSE);
+}
+
+/*
* checksubdirgroup(group, newpath, strictness)
*
* check all the specified newpath against all the paths in the
@@ -392,6 +451,11 @@ checksubdirgroup(sa_group_t group, char *newpath, int strictness)
sa_share_t share;
char *path;
int issub = SA_OK;
+ int subdir;
+ int parent;
+
+ if (newpath == NULL)
+ return (SA_INVALID_PATH);
for (share = sa_get_share(group, NULL); share != NULL;
share = sa_get_next_share(share)) {
@@ -417,13 +481,18 @@ checksubdirgroup(sa_group_t group, char *newpath, int strictness)
*/
if (path == NULL)
continue;
- if (newpath != NULL &&
- (strcmp(path, newpath) == 0 || issubdir(newpath, path) ||
- issubdir(path, newpath))) {
- sa_free_attr_string(path);
- path = NULL;
+
+ if (strcmp(path, newpath) == 0) {
issub = SA_INVALID_PATH;
- break;
+ } else {
+ subdir = issubdir(newpath, path);
+ parent = issubdir(path, newpath);
+ if (subdir || parent) {
+ sa_free_attr_string(path);
+ path = NULL;
+ return (subdir ?
+ SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR);
+ }
}
sa_free_attr_string(path);
path = NULL;
@@ -446,15 +515,16 @@ static int
checksubdir(sa_handle_t handle, char *newpath, int strictness)
{
sa_group_t group;
- int issub;
+ int issub = SA_OK;
char *path = NULL;
- for (issub = 0, group = sa_get_group(handle, NULL);
- group != NULL && !issub; group = sa_get_next_group(group)) {
+ for (group = sa_get_group(handle, NULL);
+ group != NULL && issub == SA_OK;
+ group = sa_get_next_group(group)) {
if (sa_group_is_zfs(group)) {
sa_group_t subgroup;
for (subgroup = sa_get_sub_group(group);
- subgroup != NULL && !issub;
+ subgroup != NULL && issub == SA_OK;
subgroup = sa_get_next_group(subgroup))
issub = checksubdirgroup(subgroup, newpath,
strictness);
@@ -517,14 +587,17 @@ validpath(sa_handle_t handle, char *path, int strictness)
/*
* check to see if group/share is persistent.
+ *
+ * "group" can be either an sa_group_t or an sa_share_t. (void *)
+ * works since both thse types are also void *.
*/
-static int
-is_persistent(sa_group_t group)
+int
+sa_is_persistent(void *group)
{
char *type;
int persist = 1;
- type = sa_get_group_attr(group, "type");
+ type = sa_get_group_attr((sa_group_t)group, "type");
if (type != NULL && strcmp(type, "transient") == 0)
persist = 0;
if (type != NULL)
@@ -590,6 +663,35 @@ is_zfs_group(sa_group_t group)
}
/*
+ * sa_get_object_type(object)
+ *
+ * This function returns a numeric value representing the object
+ * type. This allows using simpler checks when doing type specific
+ * operations.
+ */
+
+static int
+sa_get_object_type(void *object)
+{
+ xmlNodePtr node = (xmlNodePtr)object;
+ int type;
+
+ if (xmlStrcmp(node->name, (xmlChar *)"group") == 0)
+ type = SA_TYPE_GROUP;
+ else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0)
+ type = SA_TYPE_SHARE;
+ else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
+ type = SA_TYPE_RESOURCE;
+ else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0)
+ type = SA_TYPE_OPTIONSET;
+ else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0)
+ type = SA_TYPE_ALTSPACE;
+ else
+ assert(0);
+ return (type);
+}
+
+/*
* sa_optionset_name(optionset, oname, len, id)
* return the SMF name for the optionset. If id is not NULL, it
* will have the GUID value for a share and should be used
@@ -605,15 +707,34 @@ static int
sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id)
{
char *proto;
+ void *parent;
+ int ptype;
if (id == NULL)
id = "optionset";
- proto = sa_get_optionset_attr(optionset, "type");
- len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default");
+ parent = sa_get_optionset_parent(optionset);
+ if (parent != NULL) {
+ ptype = sa_get_object_type(parent);
+ proto = sa_get_optionset_attr(optionset, "type");
+ if (ptype != SA_TYPE_RESOURCE) {
+ len = snprintf(oname, len, "%s_%s", id,
+ proto ? proto : "default");
+ } else {
+ char *index;
+ index = get_node_attr((void *)parent, "id");
+ if (index != NULL)
+ len = snprintf(oname, len, "%s_%s_%s", id,
+ proto ? proto : "default", index);
+ else
+ len = 0;
+ }
- if (proto != NULL)
- sa_free_attr_string(proto);
+ if (proto != NULL)
+ sa_free_attr_string(proto);
+ } else {
+ len = 0;
+ }
return (len);
}
@@ -660,6 +781,7 @@ verifydefgroupopts(sa_handle_t handle)
{
sa_group_t defgrp;
sa_optionset_t opt;
+
defgrp = sa_get_group(handle, "default");
if (defgrp != NULL) {
opt = sa_get_optionset(defgrp, NULL);
@@ -1187,7 +1309,7 @@ sa_find_share(sa_handle_t handle, char *sharepath)
/*
* sa_check_path(group, path, strictness)
*
- * check that path is a valid path relative to the group. Currently,
+ * Check that path is a valid path relative to the group. Currently,
* we are ignoring the group and checking only the NFS rules. Later,
* we may want to use the group to then check against the protocols
* enabled on the group. The strictness values mean:
@@ -1206,16 +1328,84 @@ sa_check_path(sa_group_t group, char *path, int strictness)
}
/*
- * _sa_add_share(group, sharepath, persist, *error)
+ * mark_excluded_protos(group, share, flags)
+ *
+ * Walk through all the protocols enabled for the group and check to
+ * see if the share has any of them should be in the exclude list
+ * based on the featureset of the protocol. If there are any, add the
+ * "exclude" property to the share.
+ */
+static void
+mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags)
+{
+ sa_optionset_t optionset;
+ char exclude_list[SA_STRSIZE];
+ char *sep = "";
+
+ exclude_list[0] = '\0';
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *value;
+ uint64_t features;
+ value = sa_get_optionset_attr(optionset, "type");
+ if (value == NULL)
+ continue;
+ features = sa_proto_get_featureset(value);
+ sa_free_attr_string(value);
+ if (!(features & flags)) {
+ (void) strlcat(exclude_list, sep,
+ sizeof (exclude_list));
+ (void) strlcat(exclude_list, value,
+ sizeof (exclude_list));
+ sep = ",";
+ }
+ }
+ if (exclude_list[0] != '\0')
+ xmlSetProp(share, (xmlChar *)"exclude",
+ (xmlChar *)exclude_list);
+}
+
+/*
+ * get_all_features(group)
*
- * common code for all types of add_share. sa_add_share() is the
+ * Walk through all the protocols on the group and collect all
+ * possible enabled features. This is the OR of all the featuresets.
+ */
+static uint64_t
+get_all_features(sa_group_t group)
+{
+ sa_optionset_t optionset;
+ uint64_t features = 0;
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *value;
+ value = sa_get_optionset_attr(optionset, "type");
+ if (value == NULL)
+ continue;
+ features |= sa_proto_get_featureset(value);
+ sa_free_attr_string(value);
+ }
+ return (features);
+}
+
+
+/*
+ * _sa_add_share(group, sharepath, persist, *error, flags)
+ *
+ * Common code for all types of add_share. sa_add_share() is the
* public API, we also need to be able to do this when parsing legacy
* files and construction of the internal configuration while
- * extracting config info from SMF.
+ * extracting config info from SMF. "flags" indicates if some
+ * protocols need relaxed rules while other don't. These values are
+ * the featureset values defined in libshare.h.
*/
sa_share_t
-_sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
+_sa_add_share(sa_group_t group, char *sharepath, int persist, int *error,
+ uint64_t flags)
{
xmlNodePtr node = NULL;
int err;
@@ -1223,52 +1413,60 @@ _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
err = SA_OK; /* assume success */
node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL);
- if (node != NULL) {
- xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
- xmlSetProp(node, (xmlChar *)"type",
- persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
- if (persist != SA_SHARE_TRANSIENT) {
- /*
- * persistent shares come in two flavors: SMF and
- * ZFS. Sort this one out based on target group and
- * path type. Currently, only NFS is supported in the
- * ZFS group and it is always on.
- */
- if (sa_group_is_zfs(group) &&
- sa_path_is_zfs(sharepath)) {
+ if (node == NULL) {
+ if (error != NULL)
+ *error = SA_NO_MEMORY;
+ return (node);
+ }
+
+ xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
+ xmlSetProp(node, (xmlChar *)"type",
+ persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
+ if (flags != 0)
+ mark_excluded_protos(group, node, flags);
+ if (persist != SA_SHARE_TRANSIENT) {
+ /*
+ * persistent shares come in two flavors: SMF and
+ * ZFS. Sort this one out based on target group and
+ * path type. Both NFS and SMB are supported. First,
+ * check to see if the protocol is enabled on the
+ * subgroup and then setup the share appropriately.
+ */
+ if (sa_group_is_zfs(group) &&
+ sa_path_is_zfs(sharepath)) {
+ if (sa_get_optionset(group, "nfs") != NULL)
err = sa_zfs_set_sharenfs(group, sharepath, 1);
+ else if (sa_get_optionset(group, "smb") != NULL)
+ err = sa_zfs_set_sharesmb(group, sharepath, 1);
+ } else {
+ sa_handle_impl_t impl_handle;
+ impl_handle =
+ (sa_handle_impl_t)sa_find_group_handle(group);
+ if (impl_handle != NULL) {
+ err = sa_commit_share(impl_handle->scfhandle,
+ group, (sa_share_t)node);
} else {
- sa_handle_impl_t impl_handle;
- impl_handle =
- (sa_handle_impl_t)sa_find_group_handle(
- group);
- if (impl_handle != NULL) {
- err = sa_commit_share(
- impl_handle->scfhandle, group,
- (sa_share_t)node);
- } else {
- err = SA_SYSTEM_ERR;
- }
+ err = SA_SYSTEM_ERR;
}
}
- if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) {
- /* called by the dfstab parser so could be a show */
- err = SA_OK;
- }
- if (err != SA_OK) {
- /*
- * we couldn't commit to the repository so undo
- * our internal state to reflect reality.
- */
- xmlUnlinkNode(node);
- xmlFreeNode(node);
- node = NULL;
- }
- } else {
- err = SA_NO_MEMORY;
}
+ if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER)
+ /* called by the dfstab parser so could be a show */
+ err = SA_OK;
+
+ if (err != SA_OK) {
+ /*
+ * we couldn't commit to the repository so undo
+ * our internal state to reflect reality.
+ */
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+ node = NULL;
+ }
+
if (error != NULL)
*error = err;
+
return (node);
}
@@ -1285,9 +1483,10 @@ sa_share_t
sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
{
xmlNodePtr node = NULL;
- sa_share_t dup;
int strictness = SA_CHECK_NORMAL;
sa_handle_t handle;
+ uint64_t special = 0;
+ uint64_t features;
/*
* If the share is to be permanent, use strict checking so a
@@ -1304,12 +1503,33 @@ sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
handle = sa_find_group_handle(group);
- if ((dup = sa_find_share(handle, sharepath)) == NULL &&
- (*error = sa_check_path(group, sharepath, strictness)) == SA_OK) {
- node = _sa_add_share(group, sharepath, persist, error);
- }
- if (dup != NULL)
+ /*
+ * need to determine if the share is valid. The rules are:
+ * - The path must not already exist
+ * - The path must not be a subdir or parent dir of an
+ * existing path unless at least one protocol allows it.
+ * The sub/parent check is done in sa_check_path().
+ */
+
+ if (sa_find_share(handle, sharepath) == NULL) {
+ *error = sa_check_path(group, sharepath, strictness);
+ features = get_all_features(group);
+ switch (*error) {
+ case SA_PATH_IS_SUBDIR:
+ if (features & SA_FEATURE_ALLOWSUBDIRS)
+ special |= SA_FEATURE_ALLOWSUBDIRS;
+ break;
+ case SA_PATH_IS_PARENTDIR:
+ if (features & SA_FEATURE_ALLOWPARDIRS)
+ special |= SA_FEATURE_ALLOWPARDIRS;
+ break;
+ }
+ if (*error == SA_OK || special != SA_FEATURE_NONE)
+ node = _sa_add_share(group, sharepath, persist,
+ error, special);
+ } else {
*error = SA_DUPLICATE_NAME;
+ }
return ((sa_share_t)node);
}
@@ -1324,28 +1544,52 @@ sa_enable_share(sa_share_t share, char *protocol)
{
char *sharepath;
struct stat st;
- int err = 0;
+ int err = SA_OK;
+ int ret;
sharepath = sa_get_share_attr(share, "path");
+ if (sharepath == NULL)
+ return (SA_NO_MEMORY);
if (stat(sharepath, &st) < 0) {
err = SA_NO_SUCH_PATH;
} else {
/* tell the server about the share */
if (protocol != NULL) {
+ if (excluded_protocol(share, protocol))
+ goto done;
+
/* lookup protocol specific handler */
err = sa_proto_share(protocol, share);
if (err == SA_OK)
- (void) sa_set_share_attr(share, "shared",
- "true");
+ (void) sa_set_share_attr(share,
+ "shared", "true");
} else {
- /*
- * Tell all protocols. Only NFS for now but
- * SMB is coming.
- */
- err = sa_proto_share("nfs", share);
+ /* Tell all protocols about the share */
+ sa_group_t group;
+ sa_optionset_t optionset;
+
+ group = sa_get_parent_group(share);
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *proto;
+ proto = sa_get_optionset_attr(optionset,
+ "type");
+ if (proto != NULL) {
+ if (!excluded_protocol(share, proto)) {
+ ret = sa_proto_share(proto,
+ share);
+ if (ret != SA_OK)
+ err = ret;
+ }
+ sa_free_attr_string(proto);
+ }
+ }
(void) sa_set_share_attr(share, "shared", "true");
}
}
+done:
if (sharepath != NULL)
sa_free_attr_string(sharepath);
return (err);
@@ -1353,31 +1597,47 @@ sa_enable_share(sa_share_t share, char *protocol)
/*
* sa_disable_share(share, protocol)
- * Disable the specified share to the specified protocol.
- * If protocol is NULL, then all protocols.
+ * Disable the specified share to the specified protocol. If
+ * protocol is NULL, then all protocols that are enabled for the
+ * share should be disabled.
*/
int
sa_disable_share(sa_share_t share, char *protocol)
{
char *path;
- char *shared;
+ int err = SA_OK;
int ret = SA_OK;
path = sa_get_share_attr(share, "path");
- shared = sa_get_share_attr(share, "shared");
if (protocol != NULL) {
ret = sa_proto_unshare(share, protocol, path);
} else {
/* need to do all protocols */
- ret = sa_proto_unshare(share, "nfs", path);
+ sa_group_t group;
+ sa_optionset_t optionset;
+
+ group = sa_get_parent_group(share);
+
+ /* Tell all protocols about the share */
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *proto;
+
+ proto = sa_get_optionset_attr(optionset, "type");
+ if (proto != NULL) {
+ err = sa_proto_unshare(share, proto, path);
+ if (err != SA_OK)
+ ret = err;
+ sa_free_attr_string(proto);
+ }
+ }
}
if (ret == SA_OK)
(void) sa_set_share_attr(share, "shared", NULL);
if (path != NULL)
sa_free_attr_string(path);
- if (shared != NULL)
- sa_free_attr_string(shared);
return (ret);
}
@@ -1415,7 +1675,7 @@ sa_remove_share(sa_share_t share)
/* only do SMF action if permanent */
if (!transient || zfs != NULL) {
/* remove from legacy dfstab as well as possible SMF */
- ret = sa_delete_legacy(share);
+ ret = sa_delete_legacy(share, NULL);
if (ret == SA_OK) {
if (!sa_group_is_zfs(group)) {
sa_handle_impl_t impl_handle;
@@ -1497,7 +1757,7 @@ sa_move_share(sa_group_t group, sa_share_t share)
/*
* sa_get_parent_group(share)
*
- * Return the containg group for the share. If a group was actually
+ * Return the containing group for the share. If a group was actually
* passed in, we don't want a parent so return NULL.
*/
@@ -1728,7 +1988,7 @@ sa_update_config(sa_handle_t handle)
/*
* get_node_attr(node, tag)
*
- * Get the speficied tag(attribute) if it exists on the node. This is
+ * Get the specified tag(attribute) if it exists on the node. This is
* used internally by a number of attribute oriented functions.
*/
@@ -1746,7 +2006,7 @@ get_node_attr(void *nodehdl, char *tag)
/*
* get_node_attr(node, tag)
*
- * Set the speficied tag(attribute) to the specified value This is
+ * Set the specified tag(attribute) to the specified value This is
* used internally by a number of attribute oriented functions. It
* doesn't update the repository, only the internal document state.
*/
@@ -1792,6 +2052,14 @@ sa_set_group_attr(sa_group_t group, char *tag, char *value)
char *groupname;
sa_handle_impl_t impl_handle;
+ /*
+ * ZFS group/subgroup doesn't need the handle so shortcut.
+ */
+ if (sa_group_is_zfs(group)) {
+ set_node_attr((void *)group, tag, value);
+ return (SA_OK);
+ }
+
impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
if (impl_handle != NULL) {
groupname = sa_get_group_attr(group, "name");
@@ -1833,47 +2101,15 @@ sa_get_share_attr(sa_share_t share, char *tag)
}
/*
- * sa_get_resource(group, resource)
- *
- * Search all the shares in the speified group for a share with a
- * resource name matching the one specified.
- *
- * In the future, it may be advantageous to allow group to be NULL and
- * search all groups but that isn't needed at present.
- */
-
-sa_share_t
-sa_get_resource(sa_group_t group, char *resource)
-{
- sa_share_t share = NULL;
- char *name = NULL;
-
- if (resource != NULL) {
- for (share = sa_get_share(group, NULL); share != NULL;
- share = sa_get_next_share(share)) {
- name = sa_get_share_attr(share, "resource");
- if (name != NULL) {
- if (strcmp(name, resource) == 0)
- break;
- sa_free_attr_string(name);
- name = NULL;
- }
- }
- if (name != NULL)
- sa_free_attr_string(name);
- }
- return ((sa_share_t)share);
-}
-
-/*
* _sa_set_share_description(share, description)
*
- * Add a description tag with text contents to the specified share.
- * A separate XML tag is used rather than a property.
+ * Add a description tag with text contents to the specified share. A
+ * separate XML tag is used rather than a property. This can also be
+ * used with resources.
*/
xmlNodePtr
-_sa_set_share_description(sa_share_t share, char *content)
+_sa_set_share_description(void *share, char *content)
{
xmlNodePtr node;
node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description",
@@ -2205,7 +2441,6 @@ sa_set_share_description(sa_share_t share, char *content)
break;
}
}
- group = sa_get_parent_group(share);
/* no existing description but want to add */
if (node == NULL && content != NULL) {
/* add a description */
@@ -2218,7 +2453,8 @@ sa_set_share_description(sa_share_t share, char *content)
xmlUnlinkNode(node);
xmlFreeNode(node);
}
- if (group != NULL && is_persistent((sa_group_t)share)) {
+ group = sa_get_parent_group(share);
+ if (group != NULL && sa_is_persistent(share)) {
sa_handle_impl_t impl_handle;
impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
if (impl_handle != NULL) {
@@ -2269,7 +2505,7 @@ sa_get_share_description(sa_share_t share)
}
}
if (node != NULL) {
- description = xmlNodeGetContent((xmlNodePtr)share);
+ description = xmlNodeGetContent(node);
fixproblemchars((char *)description);
}
return ((char *)description);
@@ -2299,12 +2535,44 @@ sa_create_optionset(sa_group_t group, char *proto)
{
sa_optionset_t optionset;
sa_group_t parent = group;
+ sa_share_t share = NULL;
+ int err = SA_OK;
+ char *id = NULL;
optionset = sa_get_optionset(group, proto);
if (optionset != NULL) {
/* can't have a duplicate protocol */
optionset = NULL;
} else {
+ /*
+ * Account for resource names being slightly
+ * different.
+ */
+ if (sa_is_share(group)) {
+ /*
+ * Transient shares do not have an "id" so not an
+ * error to not find one.
+ */
+ id = sa_get_share_attr((sa_share_t)group, "id");
+ } else if (sa_is_resource(group)) {
+ share = sa_get_resource_parent(
+ (sa_resource_t)group);
+ id = sa_get_resource_attr(share, "id");
+
+ /* id can be NULL if the group is transient (ZFS) */
+ if (id == NULL && sa_is_persistent(group))
+ err = SA_NO_MEMORY;
+ }
+ if (err == SA_NO_MEMORY) {
+ /*
+ * Couldn't get the id for the share or
+ * resource. While this could be a
+ * configuration issue, it is most likely an
+ * out of memory. In any case, fail the create.
+ */
+ return (NULL);
+ }
+
optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group,
NULL, (xmlChar *)"optionset", NULL);
/*
@@ -2314,38 +2582,44 @@ sa_create_optionset(sa_group_t group, char *proto)
if (optionset != NULL) {
char oname[SA_STRSIZE];
char *groupname;
- char *id = NULL;
- if (sa_is_share(group))
+ /*
+ * Need to get parent group in all cases, but also get
+ * the share if this is a resource.
+ */
+ if (sa_is_share(group)) {
parent = sa_get_parent_group((sa_share_t)group);
+ } else if (sa_is_resource(group)) {
+ share = sa_get_resource_parent(
+ (sa_resource_t)group);
+ parent = sa_get_parent_group(share);
+ }
sa_set_optionset_attr(optionset, "type", proto);
- if (sa_is_share(group)) {
- id = sa_get_share_attr((sa_share_t)group, "id");
- }
(void) sa_optionset_name(optionset, oname,
sizeof (oname), id);
groupname = sa_get_group_attr(parent, "name");
- if (groupname != NULL && is_persistent(group)) {
+ if (groupname != NULL && sa_is_persistent(group)) {
sa_handle_impl_t impl_handle;
- impl_handle = (sa_handle_impl_t)
- sa_find_group_handle(group);
+ impl_handle =
+ (sa_handle_impl_t)sa_find_group_handle(
+ group);
assert(impl_handle != NULL);
if (impl_handle != NULL) {
(void) sa_get_instance(
- impl_handle->scfhandle,
- groupname);
+ impl_handle->scfhandle, groupname);
(void) sa_create_pgroup(
impl_handle->scfhandle, oname);
}
}
if (groupname != NULL)
sa_free_attr_string(groupname);
- if (id != NULL)
- sa_free_attr_string(id);
}
}
+
+ if (id != NULL)
+ sa_free_attr_string(id);
return (optionset);
}
@@ -2388,7 +2662,7 @@ sa_get_optionset_parent(sa_optionset_t optionset)
*
* In order to avoid making multiple updates to a ZFS share when
* setting properties, the share attribute "changed" will be set to
- * true when a property is added or modifed. When done adding
+ * true when a property is added or modified. When done adding
* properties, we can then detect that an update is needed. We then
* clear the state here to detect additional changes.
*/
@@ -2470,7 +2744,7 @@ sa_commit_properties(sa_optionset_t optionset, int clear)
/*
* sa_destroy_optionset(optionset)
*
- * Remove the optionset from its group. Update the repostory to
+ * Remove the optionset from its group. Update the repository to
* reflect this change.
*/
@@ -2486,9 +2760,16 @@ sa_destroy_optionset(sa_optionset_t optionset)
/* now delete the prop group */
group = sa_get_optionset_parent(optionset);
- if (group != NULL && sa_is_share(group)) {
- ispersist = is_persistent(group);
- id = sa_get_share_attr((sa_share_t)group, "id");
+ if (group != NULL) {
+ if (sa_is_resource(group)) {
+ sa_resource_t resource = group;
+ sa_share_t share = sa_get_resource_parent(resource);
+ group = sa_get_parent_group(share);
+ id = sa_get_share_attr(share, "id");
+ } else if (sa_is_share(group)) {
+ id = sa_get_share_attr((sa_share_t)group, "id");
+ }
+ ispersist = sa_is_persistent(group);
}
if (ispersist) {
sa_handle_impl_t impl_handle;
@@ -2559,7 +2840,7 @@ sa_create_security(sa_group_t group, char *sectype, char *proto)
sa_set_security_attr(security, "sectype", sectype);
(void) sa_security_name(security, oname,
sizeof (oname), id);
- if (groupname != NULL && is_persistent(group)) {
+ if (groupname != NULL && sa_is_persistent(group)) {
sa_handle_impl_t impl_handle;
impl_handle =
(sa_handle_impl_t)sa_find_group_handle(
@@ -2603,7 +2884,7 @@ sa_destroy_security(sa_security_t security)
if (group != NULL && !iszfs) {
if (sa_is_share(group))
- ispersist = is_persistent(group);
+ ispersist = sa_is_persistent(group);
id = sa_get_share_attr((sa_share_t)group, "id");
}
if (ispersist) {
@@ -2666,7 +2947,6 @@ is_nodetype(void *node, char *type)
return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0);
}
-
/*
* add_or_update()
*
@@ -2721,12 +3001,12 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
int opttype; /* 1 == optionset, 0 == security */
char *id = NULL;
int iszfs = 0;
- int isshare = 0;
sa_group_t parent = NULL;
+ sa_share_t share = NULL;
sa_handle_impl_t impl_handle;
scfutilhandle_t *scf_handle;
- if (!is_persistent(group)) {
+ if (!sa_is_persistent(group)) {
/*
* if the group/share is not persistent we don't need
* to do anything here
@@ -2742,12 +3022,20 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
entry = scf_entry_create(scf_handle->handle);
opttype = is_nodetype((void *)optionset, "optionset");
+ /*
+ * Check for share vs. resource since they need slightly
+ * different treatment given the hierarchy.
+ */
if (valstr != NULL && entry != NULL) {
if (sa_is_share(group)) {
- isshare = 1;
parent = sa_get_parent_group(group);
+ share = (sa_share_t)group;
if (parent != NULL)
iszfs = is_zfs_group(parent);
+ } else if (sa_is_resource(group)) {
+ share = sa_get_parent_group(group);
+ if (share != NULL)
+ parent = sa_get_parent_group(share);
} else {
iszfs = is_zfs_group(group);
}
@@ -2755,15 +3043,13 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
if (scf_handle->trans == NULL) {
char oname[SA_STRSIZE];
char *groupname = NULL;
- if (isshare) {
- if (parent != NULL) {
+ if (share != NULL) {
+ if (parent != NULL)
groupname =
sa_get_group_attr(parent,
"name");
- }
- id =
- sa_get_share_attr((sa_share_t)group,
- "id");
+ id = sa_get_share_attr(
+ (sa_share_t)share, "id");
} else {
groupname = sa_get_group_attr(group,
"name");
@@ -2870,14 +3156,22 @@ sa_add_property(void *object, sa_property_t property)
sa_free_attr_string(proto);
parent = sa_get_parent_group(object);
- if (!is_persistent(parent)) {
+ if (!sa_is_persistent(parent))
return (ret);
- }
- if (sa_is_share(parent))
+ if (sa_is_resource(parent)) {
+ /*
+ * Resources are children of share. Need to go up two
+ * levels to find the group but the parent needs to be
+ * the share at this point in order to get the "id".
+ */
+ parent = sa_get_parent_group(parent);
group = sa_get_parent_group(parent);
- else
+ } else if (sa_is_share(parent)) {
+ group = sa_get_parent_group(parent);
+ } else {
group = parent;
+ }
if (property == NULL) {
ret = SA_NO_MEMORY;
@@ -3110,7 +3404,7 @@ sa_set_protocol_property(sa_property_t prop, char *value)
/*
* sa_add_protocol_property(propset, prop)
*
- * Add a new property to the protocol sepcific property set.
+ * Add a new property to the protocol specific property set.
*/
int
@@ -3128,7 +3422,7 @@ sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop)
/*
* sa_create_protocol_properties(proto)
*
- * Create a protocol specifity property set.
+ * Create a protocol specific property set.
*/
sa_protocol_properties_t
@@ -3141,3 +3435,583 @@ sa_create_protocol_properties(char *proto)
xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
return (node);
}
+
+/*
+ * sa_get_share_resource(share, resource)
+ *
+ * Get the named resource from the share, if it exists. If resource is
+ * NULL, get the first resource.
+ */
+
+sa_resource_t
+sa_get_share_resource(sa_share_t share, char *resource)
+{
+ xmlNodePtr node = NULL;
+ xmlChar *name;
+
+ if (share != NULL) {
+ for (node = ((xmlNodePtr)share)->children; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) {
+ if (resource == NULL) {
+ /*
+ * We are looking for the first
+ * resource node and not a names
+ * resource.
+ */
+ break;
+ } else {
+ /* is it the correct share? */
+ name = xmlGetProp(node,
+ (xmlChar *)"name");
+ if (name != NULL &&
+ xmlStrcasecmp(name,
+ (xmlChar *)resource) == 0) {
+ xmlFree(name);
+ break;
+ }
+ xmlFree(name);
+ }
+ }
+ }
+ }
+ return ((sa_resource_t)node);
+}
+
+/*
+ * sa_get_next_resource(resource)
+ * Return the next share following the specified share
+ * from the internal list of shares. Returns NULL if there
+ * are no more shares. The list is relative to the same
+ * group.
+ */
+sa_share_t
+sa_get_next_resource(sa_resource_t resource)
+{
+ xmlNodePtr node = NULL;
+
+ if (resource != NULL) {
+ for (node = ((xmlNodePtr)resource)->next; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
+ break;
+ }
+ }
+ return ((sa_share_t)node);
+}
+
+/*
+ * _sa_get_next_resource_index(share)
+ *
+ * get the next resource index number (one greater then current largest)
+ */
+
+static int
+_sa_get_next_resource_index(sa_share_t share)
+{
+ sa_resource_t resource;
+ int index = 0;
+ char *id;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ id = get_node_attr((void *)resource, "id");
+ if (id != NULL) {
+ int val;
+ val = atoi(id);
+ if (val > index)
+ index = val;
+ sa_free_attr_string(id);
+ }
+ }
+ return (index + 1);
+}
+
+
+/*
+ * sa_add_resource(share, resource, persist, &err)
+ *
+ * Adds a new resource name associated with share. The resource name
+ * must be unique in the system and will be case insensitive (eventually).
+ */
+
+sa_resource_t
+sa_add_resource(sa_share_t share, char *resource, int persist, int *error)
+{
+ xmlNodePtr node;
+ int err = SA_OK;
+ sa_resource_t res;
+ sa_group_t group;
+ sa_handle_t handle;
+ char istring[8]; /* just big enough for an integer value */
+ int index;
+
+ group = sa_get_parent_group(share);
+ handle = sa_find_group_handle(group);
+ res = sa_find_resource(handle, resource);
+ if (res != NULL) {
+ err = SA_DUPLICATE_NAME;
+ res = NULL;
+ } else {
+ node = xmlNewChild((xmlNodePtr)share, NULL,
+ (xmlChar *)"resource", NULL);
+ if (node != NULL) {
+ xmlSetProp(node, (xmlChar *)"name",
+ (xmlChar *)resource);
+ xmlSetProp(node, (xmlChar *)"type", persist ?
+ (xmlChar *)"persist" : (xmlChar *)"transient");
+ if (persist != SA_SHARE_TRANSIENT) {
+ index = _sa_get_next_resource_index(share);
+ (void) snprintf(istring, sizeof (istring), "%d",
+ index);
+ xmlSetProp(node, (xmlChar *)"id",
+ (xmlChar *)istring);
+ if (!sa_group_is_zfs(group) &&
+ sa_is_persistent((sa_group_t)share)) {
+ /* ZFS doesn't use resource names */
+ sa_handle_impl_t ihandle;
+ ihandle = (sa_handle_impl_t)
+ sa_find_group_handle(
+ group);
+ if (ihandle != NULL)
+ err = sa_commit_share(
+ ihandle->scfhandle, group,
+ share);
+ else
+ err = SA_SYSTEM_ERR;
+ }
+ }
+ }
+ }
+ if (error != NULL)
+ *error = err;
+ return ((sa_resource_t)node);
+}
+
+/*
+ * sa_remove_resource(resource)
+ *
+ * Remove the resource name from the share (and the system)
+ */
+
+int
+sa_remove_resource(sa_resource_t resource)
+{
+ sa_share_t share;
+ sa_group_t group;
+ char *type;
+ int ret = SA_OK;
+ int transient = 0;
+
+ share = sa_get_resource_parent(resource);
+ type = sa_get_share_attr(share, "type");
+ group = sa_get_parent_group(share);
+
+
+ if (type != NULL) {
+ if (strcmp(type, "persist") != 0)
+ transient = 1;
+ sa_free_attr_string(type);
+ }
+
+ /* Remove from the share */
+ xmlUnlinkNode((xmlNode *)resource);
+ xmlFreeNode((xmlNode *)resource);
+
+ /* only do SMF action if permanent and not ZFS */
+ if (!transient && !sa_group_is_zfs(group)) {
+ sa_handle_impl_t ihandle;
+ ihandle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (ihandle != NULL)
+ ret = sa_commit_share(ihandle->scfhandle, group, share);
+ else
+ ret = SA_SYSTEM_ERR;
+ }
+ return (ret);
+}
+
+/*
+ * proto_resource_rename(handle, group, resource, newname)
+ *
+ * Helper function for sa_rename_resource that notifies the protocol
+ * of a resource name change prior to a config repository update.
+ */
+static int
+proto_rename_resource(sa_handle_t handle, sa_group_t group,
+ sa_resource_t resource, char *newname)
+{
+ sa_optionset_t optionset;
+ int ret = SA_OK;
+ int err;
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *type;
+ type = sa_get_optionset_attr(optionset, "type");
+ if (type != NULL) {
+ err = sa_proto_rename_resource(handle, type, resource,
+ newname);
+ if (err != SA_OK)
+ ret = err;
+ sa_free_attr_string(type);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_rename_resource(resource, newname)
+ *
+ * Rename the resource to the new name, if it is unique.
+ */
+
+int
+sa_rename_resource(sa_resource_t resource, char *newname)
+{
+ sa_share_t share;
+ sa_group_t group = NULL;
+ sa_resource_t target;
+ int ret = SA_CONFIG_ERR;
+ sa_handle_t handle = NULL;
+
+ share = sa_get_resource_parent(resource);
+ if (share == NULL)
+ return (ret);
+
+ group = sa_get_parent_group(share);
+ if (group == NULL)
+ return (ret);
+
+ handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (handle == NULL)
+ return (ret);
+
+ target = sa_find_resource(handle, newname);
+ if (target != NULL) {
+ ret = SA_DUPLICATE_NAME;
+ } else {
+ /*
+ * Everything appears to be valid at this
+ * point. Change the name of the active share and then
+ * update the share in the appropriate repository.
+ */
+ ret = proto_rename_resource(handle, group, resource, newname);
+ set_node_attr(resource, "name", newname);
+ if (!sa_group_is_zfs(group) &&
+ sa_is_persistent((sa_group_t)share)) {
+ sa_handle_impl_t ihandle = (sa_handle_impl_t)handle;
+ ret = sa_commit_share(ihandle->scfhandle, group,
+ share);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_get_resource_attr(resource, tag)
+ *
+ * Get the named attribute of the resource. "name" and "id" are
+ * currently defined. NULL if tag not defined.
+ */
+
+char *
+sa_get_resource_attr(sa_resource_t resource, char *tag)
+{
+ return (get_node_attr((void *)resource, tag));
+}
+
+/*
+ * sa_set_resource_attr(resource, tag, value)
+ *
+ * Get the named attribute of the resource. "name" and "id" are
+ * currently defined. NULL if tag not defined. Currently we don't do
+ * much, but additional checking may be needed in the future.
+ */
+
+int
+sa_set_resource_attr(sa_resource_t resource, char *tag, char *value)
+{
+ set_node_attr((void *)resource, tag, value);
+ return (SA_OK);
+}
+
+/*
+ * sa_get_resource_parent(resource_t)
+ *
+ * Returns the share associated with the resource.
+ */
+
+sa_share_t
+sa_get_resource_parent(sa_resource_t resource)
+{
+ sa_share_t share = NULL;
+
+ if (resource != NULL)
+ share = (sa_share_t)((xmlNodePtr)resource)->parent;
+ return (share);
+}
+
+/*
+ * find_resource(group, name)
+ *
+ * Find the resource within the group.
+ */
+
+static sa_resource_t
+find_resource(sa_group_t group, char *resname)
+{
+ sa_share_t share;
+ sa_resource_t resource = NULL;
+ char *name;
+
+ /* Iterate over all the shares and resources in the group. */
+ for (share = sa_get_share(group, NULL);
+ share != NULL && resource == NULL;
+ share = sa_get_next_share(share)) {
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ name = sa_get_resource_attr(resource, "name");
+ if (name != NULL && xmlStrcasecmp((xmlChar*)name,
+ (xmlChar*)resname) == 0) {
+ sa_free_attr_string(name);
+ break;
+ }
+ if (name != NULL) {
+ sa_free_attr_string(name);
+ }
+ }
+ }
+ return (resource);
+}
+
+/*
+ * sa_find_resource(name)
+ *
+ * Find the named resource in the system.
+ */
+
+sa_resource_t
+sa_find_resource(sa_handle_t handle, char *name)
+{
+ sa_group_t group;
+ sa_group_t zgroup;
+ sa_resource_t resource = NULL;
+
+ /*
+ * Iterate over all groups and zfs subgroups and check for
+ * resource name in them.
+ */
+ for (group = sa_get_group(handle, NULL); group != NULL;
+ group = sa_get_next_group(group)) {
+
+ if (is_zfs_group(group)) {
+ for (zgroup =
+ (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
+ (xmlChar *)"group");
+ zgroup != NULL && resource == NULL;
+ zgroup = sa_get_next_group(zgroup)) {
+ resource = find_resource(zgroup, name);
+ }
+ } else {
+ resource = find_resource(group, name);
+ }
+ if (resource != NULL)
+ break;
+ }
+ return (resource);
+}
+
+/*
+ * sa_get_resource(group, resource)
+ *
+ * Search all the shares in the specified group for a share with a
+ * resource name matching the one specified.
+ *
+ * In the future, it may be advantageous to allow group to be NULL and
+ * search all groups but that isn't needed at present.
+ */
+
+sa_resource_t
+sa_get_resource(sa_group_t group, char *resource)
+{
+ sa_share_t share = NULL;
+ sa_resource_t res = NULL;
+
+ if (resource != NULL) {
+ for (share = sa_get_share(group, NULL);
+ share != NULL && res == NULL;
+ share = sa_get_next_share(share)) {
+ res = sa_get_share_resource(share, resource);
+ }
+ }
+ return (res);
+}
+
+/*
+ * sa_enable_resource, protocol)
+ * Disable the specified share to the specified protocol.
+ * If protocol is NULL, then all protocols.
+ */
+int
+sa_enable_resource(sa_resource_t resource, char *protocol)
+{
+ int ret = SA_OK;
+ char **protocols;
+ int numproto;
+
+ if (protocol != NULL) {
+ ret = sa_proto_share_resource(protocol, resource);
+ } else {
+ /* need to do all protocols */
+ if ((numproto = sa_get_protocols(&protocols)) >= 0) {
+ int i, err;
+ for (i = 0; i < numproto; i++) {
+ err = sa_proto_share_resource(
+ protocols[i], resource);
+ if (err != SA_OK)
+ ret = err;
+ }
+ free(protocols);
+ }
+ }
+ if (ret == SA_OK)
+ (void) sa_set_resource_attr(resource, "shared", NULL);
+
+ return (ret);
+}
+
+/*
+ * sa_disable_resource(resource, protocol)
+ *
+ * Disable the specified share for the specified protocol. If
+ * protocol is NULL, then all protocols. If the underlying
+ * protocol doesn't implement disable at the resource level, we
+ * disable at the share level.
+ */
+int
+sa_disable_resource(sa_resource_t resource, char *protocol)
+{
+ int ret = SA_OK;
+ char **protocols;
+ int numproto;
+
+ if (protocol != NULL) {
+ ret = sa_proto_unshare_resource(protocol, resource);
+ if (ret == SA_NOT_IMPLEMENTED) {
+ sa_share_t parent;
+ /*
+ * The protocol doesn't implement unshare
+ * resource. That implies that resource names are
+ * simple aliases for this protocol so we need to
+ * unshare the share.
+ */
+ parent = sa_get_resource_parent(resource);
+ if (parent != NULL)
+ ret = sa_disable_share(parent, protocol);
+ else
+ ret = SA_CONFIG_ERR;
+ }
+ } else {
+ /* need to do all protocols */
+ if ((numproto = sa_get_protocols(&protocols)) >= 0) {
+ int i, err;
+ for (i = 0; i < numproto; i++) {
+ err = sa_proto_unshare_resource(protocols[i],
+ resource);
+ if (err == SA_NOT_SUPPORTED) {
+ sa_share_t parent;
+ parent = sa_get_resource_parent(
+ resource);
+ if (parent != NULL)
+ err = sa_disable_share(parent,
+ protocols[i]);
+ else
+ err = SA_CONFIG_ERR;
+ }
+ if (err != SA_OK)
+ ret = err;
+ }
+ free(protocols);
+ }
+ }
+ if (ret == SA_OK)
+ (void) sa_set_resource_attr(resource, "shared", NULL);
+
+ return (ret);
+}
+
+/*
+ * sa_set_resource_description(resource, content)
+ *
+ * Set the description of share to content.
+ */
+
+int
+sa_set_resource_description(sa_resource_t resource, char *content)
+{
+ xmlNodePtr node;
+ sa_group_t group;
+ sa_share_t share;
+ int ret = SA_OK;
+
+ for (node = ((xmlNodePtr)resource)->children;
+ node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
+ break;
+ }
+ }
+
+ /* no existing description but want to add */
+ if (node == NULL && content != NULL) {
+ /* add a description */
+ node = _sa_set_share_description(resource, content);
+ } else if (node != NULL && content != NULL) {
+ /* update a description */
+ xmlNodeSetContent(node, (xmlChar *)content);
+ } else if (node != NULL && content == NULL) {
+ /* remove an existing description */
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+ }
+ share = sa_get_resource_parent(resource);
+ group = sa_get_parent_group(share);
+ if (group != NULL && sa_is_persistent(share)) {
+ sa_handle_impl_t impl_handle;
+ impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (impl_handle != NULL)
+ ret = sa_commit_share(impl_handle->scfhandle,
+ group, share);
+ else
+ ret = SA_SYSTEM_ERR;
+ }
+ return (ret);
+}
+
+/*
+ * sa_get_resource_description(share)
+ *
+ * Return the description text for the specified share if it
+ * exists. NULL if no description exists.
+ */
+
+char *
+sa_get_resource_description(sa_resource_t resource)
+{
+ xmlChar *description = NULL;
+ xmlNodePtr node;
+
+ for (node = ((xmlNodePtr)resource)->children; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"description") == 0)
+ break;
+ }
+ if (node != NULL) {
+ description = xmlNodeGetContent(node);
+ fixproblemchars((char *)description);
+ }
+ return ((char *)description);
+}
diff --git a/usr/src/lib/libshare/common/libshare.h b/usr/src/lib/libshare/common/libshare.h
index c78b0822c6..bdac6a6d64 100644
--- a/usr/src/lib/libshare/common/libshare.h
+++ b/usr/src/lib/libshare/common/libshare.h
@@ -37,6 +37,8 @@
extern "C" {
#endif
+#include <sys/types.h>
+
/*
* Basic datatypes for most functions
*/
@@ -46,6 +48,7 @@ typedef void *sa_property_t;
typedef void *sa_optionset_t;
typedef void *sa_security_t;
typedef void *sa_protocol_properties_t;
+typedef void *sa_resource_t;
typedef void *sa_handle_t; /* opaque handle to access core functions */
@@ -77,6 +80,11 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
#define SA_NOT_SUPPORTED 21 /* operation not supported for proto */
#define SA_PROP_SHARE_ONLY 22 /* property valid on share only */
#define SA_NOT_SHARED 23 /* path is not shared */
+#define SA_NO_SUCH_RESOURCE 24 /* resource not found */
+#define SA_RESOURCE_REQUIRED 25 /* resource name is required */
+#define SA_MULTIPLE_ERROR 26 /* multiple protocols reported error */
+#define SA_PATH_IS_SUBDIR 27 /* check_path found path is subdir */
+#define SA_PATH_IS_PARENTDIR 28 /* check_path found path is parent */
/* API Initialization */
#define SA_INIT_SHARE_API 0x0001 /* init share specific interface */
@@ -90,8 +98,9 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
*/
#define SA_MAX_NAME_LEN 100 /* must fit service instance name */
+#define SA_MAX_RESOURCE_NAME 255 /* Maximum length of resource name */
-/* Used in calls to sa_add_share() */
+/* Used in calls to sa_add_share() and sa_add_resource() */
#define SA_SHARE_TRANSIENT 0 /* shared but not across reboot */
#define SA_SHARE_LEGACY 1 /* share is in dfstab only */
#define SA_SHARE_PERMANENT 2 /* share goes to repository */
@@ -105,6 +114,16 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
#define SA_RBAC_VALUE "solaris.smf.value.shares"
/*
+ * Feature set bit definitions
+ */
+
+#define SA_FEATURE_NONE 0x0000 /* no feature flags set */
+#define SA_FEATURE_RESOURCE 0x0001 /* resource names are required */
+#define SA_FEATURE_DFSTAB 0x0002 /* need to manage in dfstab */
+#define SA_FEATURE_ALLOWSUBDIRS 0x0004 /* allow subdirs to be shared */
+#define SA_FEATURE_ALLOWPARDIRS 0x0008 /* allow parent dirs to be shared */
+
+/*
* legacy files
*/
@@ -143,7 +162,6 @@ extern int sa_check_path(sa_group_t, char *, int);
extern int sa_move_share(sa_group_t, sa_share_t);
extern int sa_remove_share(sa_share_t);
extern sa_share_t sa_get_share(sa_group_t, char *);
-extern sa_share_t sa_get_resource(sa_group_t, char *);
extern sa_share_t sa_find_share(sa_handle_t, char *);
extern sa_share_t sa_get_next_share(sa_share_t);
extern char *sa_get_share_attr(sa_share_t, char *);
@@ -152,9 +170,26 @@ extern sa_group_t sa_get_parent_group(sa_share_t);
extern int sa_set_share_attr(sa_share_t, char *, char *);
extern int sa_set_share_description(sa_share_t, char *);
extern int sa_enable_share(sa_group_t, char *);
-extern int sa_disable_share(sa_group_t, char *);
+extern int sa_disable_share(sa_share_t, char *);
extern int sa_is_share(void *);
+/* resource name related */
+extern sa_resource_t sa_find_resource(sa_handle_t, char *);
+extern sa_resource_t sa_get_resource(sa_group_t, char *);
+extern sa_resource_t sa_get_next_resource(sa_resource_t);
+extern sa_share_t sa_get_resource_parent(sa_resource_t);
+extern sa_resource_t sa_get_share_resource(sa_share_t, char *);
+extern sa_resource_t sa_add_resource(sa_share_t, char *, int, int *);
+extern int sa_remove_resource(sa_resource_t);
+extern char *sa_get_resource_attr(sa_resource_t, char *);
+extern int sa_set_resource_attr(sa_resource_t, char *, char *);
+extern int sa_set_resource_description(sa_resource_t, char *);
+extern char *sa_get_resource_description(sa_resource_t);
+extern int sa_enable_resource(sa_resource_t, char *);
+extern int sa_disable_resource(sa_resource_t, char *);
+extern int sa_rename_resource(sa_resource_t, char *);
+extern void sa_fix_resource_name(char *);
+
/* data structure free calls */
extern void sa_free_attr_string(char *);
extern void sa_free_share_description(char *);
@@ -179,6 +214,7 @@ extern int sa_update_property(sa_property_t, char *);
extern int sa_remove_property(sa_property_t);
extern int sa_commit_properties(sa_optionset_t, int);
extern int sa_valid_property(void *, char *, sa_property_t);
+extern int sa_is_persistent(void *);
/* security control */
extern sa_security_t sa_get_security(sa_group_t, char *, char *);
@@ -196,6 +232,7 @@ extern int sa_parse_legacy_options(sa_group_t, char *, char *);
extern char *sa_proto_legacy_format(char *, sa_group_t, int);
extern int sa_is_security(char *, char *);
extern sa_protocol_properties_t sa_proto_get_properties(char *);
+extern uint64_t sa_proto_get_featureset(char *);
extern sa_property_t sa_get_protocol_property(sa_protocol_properties_t, char *);
extern sa_property_t sa_get_next_protocol_property(sa_property_t);
extern int sa_set_protocol_property(sa_property_t, char *);
@@ -206,9 +243,12 @@ extern int sa_add_protocol_property(sa_protocol_properties_t, sa_property_t);
extern int sa_proto_valid_prop(char *, sa_property_t, sa_optionset_t);
extern int sa_proto_valid_space(char *, char *);
extern char *sa_proto_space_alias(char *, char *);
+extern int sa_proto_get_transients(sa_handle_t, char *);
+extern int sa_proto_notify_resource(sa_resource_t, char *);
+extern int sa_proto_change_notify(sa_share_t, char *);
/* handle legacy (dfstab/sharetab) files */
-extern int sa_delete_legacy(sa_share_t);
+extern int sa_delete_legacy(sa_share_t, char *);
extern int sa_update_legacy(sa_share_t, char *);
extern int sa_update_sharetab(sa_share_t, char *);
extern int sa_delete_sharetab(char *, char *);
diff --git a/usr/src/lib/libshare/common/libshare_impl.h b/usr/src/lib/libshare/common/libshare_impl.h
index a454e3ef75..ab661e432f 100644
--- a/usr/src/lib/libshare/common/libshare_impl.h
+++ b/usr/src/lib/libshare/common/libshare_impl.h
@@ -72,6 +72,13 @@ struct sa_plugin_ops {
char *(*sa_space_alias)(char *);
int (*sa_update_legacy)(sa_share_t);
int (*sa_delete_legacy)(sa_share_t);
+ int (*sa_change_notify)(sa_share_t);
+ int (*sa_enable_resource)(sa_resource_t);
+ int (*sa_disable_resource)(sa_resource_t);
+ uint64_t (*sa_features)(void);
+ int (*sa_get_transient_shares)(sa_handle_t); /* add transients */
+ int (*sa_notify_resource)(sa_resource_t);
+ int (*sa_rename_resource)(sa_handle_t, sa_resource_t, char *);
int (*sa_run_command)(int, int, char **); /* proto specific */
int (*sa_command_help)();
};
@@ -97,6 +104,8 @@ extern int sa_proto_unshare(sa_share_t, char *, char *);
extern int sa_proto_valid_prop(char *, sa_property_t, sa_optionset_t);
extern int sa_proto_security_prop(char *, char *);
extern int sa_proto_legacy_opts(char *, sa_group_t, char *);
+extern int sa_proto_share_resource(char *, sa_resource_t);
+extern int sa_proto_unshare_resource(char *, sa_resource_t);
/* internal utility functions */
extern sa_optionset_t sa_get_derived_optionset(sa_group_t, char *, int);
@@ -121,7 +130,7 @@ extern void sa_emptyshare(struct share *sh);
/* ZFS functions */
extern int sa_get_zfs_shares(sa_handle_t, char *);
extern int sa_zfs_update(sa_share_t);
-extern int sa_share_zfs(sa_share_t, char *, share_t *, void *, boolean_t);
+extern int sa_share_zfs(sa_share_t, char *, share_t *, void *, zfs_share_op_t);
extern int sa_sharetab_fill_zfs(sa_share_t share, struct share *sh,
char *proto);
@@ -131,6 +140,8 @@ extern void proto_plugin_fini();
extern int sa_proto_set_property(char *, sa_property_t);
extern int sa_proto_delete_legacy(char *, sa_share_t);
extern int sa_proto_update_legacy(char *, sa_share_t);
+extern int sa_proto_rename_resource(sa_handle_t, char *,
+ sa_resource_t, char *);
#define PL_TYPE_PROPERTY 0
#define PL_TYPE_SECURITY 1
diff --git a/usr/src/lib/libshare/common/libshare_zfs.c b/usr/src/lib/libshare/common/libshare_zfs.c
index 1cfbcbe72a..e0ee84ef8a 100644
--- a/usr/src/lib/libshare/common/libshare_zfs.c
+++ b/usr/src/lib/libshare/common/libshare_zfs.c
@@ -36,7 +36,7 @@
#include <sys/mnttab.h>
#include <sys/mntent.h>
-extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *);
+extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
extern char *sa_fstype(char *);
extern void set_node_attr(void *, char *, char *);
@@ -109,7 +109,7 @@ sa_zfs_fini(sa_handle_impl_t impl_handle)
/*
* get_one_filesystem(zfs_handle_t, data)
*
- * an interator function called while iterating through the ZFS
+ * an iterator function called while iterating through the ZFS
* root. It accumulates into an array of file system handles that can
* be used to derive info about those file systems.
*
@@ -390,7 +390,7 @@ sa_zfs_is_shared(sa_handle_t sahandle, char *path)
}
/*
- * find_or_create_group(groupname, proto, *err)
+ * find_or_create_group(handle, groupname, proto, *err)
*
* While walking the ZFS tree, we need to add shares to a defined
* group. If the group doesn't exist, create it first, making sure it
@@ -424,19 +424,8 @@ find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
if (group != NULL) {
if (proto != NULL) {
optionset = sa_get_optionset(group, proto);
- if (optionset == NULL) {
+ if (optionset == NULL)
optionset = sa_create_optionset(group, proto);
- } else {
- char **protolist;
- int numprotos, i;
- numprotos = sa_get_protocols(&protolist);
- for (i = 0; i < numprotos; i++) {
- optionset = sa_create_optionset(group,
- protolist[i]);
- }
- if (protolist != NULL)
- free(protolist);
- }
}
}
if (err != NULL)
@@ -457,8 +446,8 @@ find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
*/
static sa_group_t
-find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname,
- char *optstring, int *err)
+find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto,
+ char *optstring, int *err)
{
sa_group_t group = NULL;
sa_group_t zfs;
@@ -494,30 +483,58 @@ find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname,
options = strdup(optstring);
if (options != NULL) {
*err = sa_parse_legacy_options(group,
- options, "nfs");
+ options, proto);
+
+ /* If no optionset, add one */
+ if (sa_get_optionset(group, proto) ==
+ NULL)
+ (void) sa_create_optionset(
+ group, proto);
free(options);
} else {
*err = SA_NO_MEMORY;
}
}
+ } else if (proto != NULL && strcmp(proto, "smb") == 0) {
+ *err = SA_PROP_SHARE_ONLY;
}
}
return (group);
}
/*
+ * zfs_construct_resource(share, name, base, dataset)
+ *
+ * Add a resource to the share using name as a template. If name ==
+ * NULL, then construct a name based on the dataset value.
+ * name.
+ */
+static void
+zfs_construct_resource(sa_share_t share, char *dataset)
+{
+ char buff[SA_MAX_RESOURCE_NAME + 1];
+ int ret = SA_OK;
+
+ (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset);
+ sa_fix_resource_name(buff);
+ (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret);
+}
+
+/*
* zfs_inherited(handle, source, sourcestr)
*
- * handle case of inherited sharenfs. Pulled out of sa_get_zfs_shares
+ * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares
* for readability.
*/
static int
zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
- char *shareopts, char *mountpoint)
+ char *shareopts, char *mountpoint, char *proto, char *dataset)
{
int doshopt = 0;
int err = SA_OK;
sa_group_t group;
+ sa_resource_t resource;
+ uint64_t features;
/*
* Need to find the "real" parent sub-group. It may not be
@@ -525,11 +542,18 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
* variable. The real parent not mounted can occur if
* "canmount=off and sharenfs=on".
*/
- group = find_or_create_zfs_subgroup(handle, sourcestr, shareopts,
- &doshopt);
+ group = find_or_create_zfs_subgroup(handle, sourcestr, proto,
+ shareopts, &doshopt);
if (group != NULL) {
- share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
- &err);
+ /*
+ * We may need the first share for resource
+ * prototype. We only care about it if it has a
+ * resource that sets a prefix value.
+ */
+ if (share == NULL)
+ share = _sa_add_share(group, mountpoint,
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
/*
* some options may only be on shares. If the opt
* string contains one of those, we put it just on the
@@ -539,10 +563,27 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
char *options;
options = strdup(shareopts);
if (options != NULL) {
+ set_node_attr(share, "dataset", dataset);
err = sa_parse_legacy_options(share, options,
- "nfs");
+ proto);
+ set_node_attr(share, "dataset", NULL);
free(options);
}
+ if (sa_get_optionset(group, proto) == NULL)
+ (void) sa_create_optionset(group, proto);
+ }
+ features = sa_proto_get_featureset(proto);
+ if (share != NULL && features & SA_FEATURE_RESOURCE) {
+ /*
+ * We have a share and the protocol requires
+ * that at least one resource exist (probably
+ * SMB). We need to make sure that there is at
+ * least one.
+ */
+ resource = sa_get_share_resource(share, NULL);
+ if (resource == NULL) {
+ zfs_construct_resource(share, dataset);
+ }
}
} else {
err = SA_NO_MEMORY;
@@ -557,45 +598,60 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
* of sa_get_zfs_shares for readability.
*/
static int
-zfs_notinherited(sa_group_t group, char *mountpoint, char *shareopts)
+zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint,
+ char *shareopts, char *proto, char *dataset)
{
int err = SA_OK;
- sa_share_t share;
- char *options;
+ sa_resource_t resource;
+ uint64_t features;
set_node_attr(group, "zfs", "true");
- share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, &err);
+ if (share == NULL)
+ share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
+ &err, (uint64_t)SA_FEATURE_NONE);
if (err == SA_OK) {
if (strcmp(shareopts, "on") == 0)
- shareopts = "rw";
-
- options = strdup(shareopts);
- if (options != NULL) {
- err = sa_parse_legacy_options(group, options,
- "nfs");
- free(options);
- }
- if (err == SA_PROP_SHARE_ONLY) {
- /*
- * Same as above, some properties may
- * only be on shares, but due to the
- * ZFS sub-groups being artificial, we
- * sometimes get this and have to deal
- * with it. We do it by attempting to
- * put it on the share.
- */
+ shareopts = "";
+ if (shareopts != NULL) {
+ char *options;
options = strdup(shareopts);
if (options != NULL) {
- err = sa_parse_legacy_options(share,
- options, "nfs");
+ err = sa_parse_legacy_options(group, options,
+ proto);
free(options);
}
+ if (err == SA_PROP_SHARE_ONLY) {
+ /*
+ * Same as above, some properties may
+ * only be on shares, but due to the
+ * ZFS sub-groups being artificial, we
+ * sometimes get this and have to deal
+ * with it. We do it by attempting to
+ * put it on the share.
+ */
+ options = strdup(shareopts);
+ if (options != NULL) {
+ err = sa_parse_legacy_options(share,
+ options, proto);
+ free(options);
+ }
+ }
+ /* unmark the share's changed state */
+ set_node_attr(share, "changed", NULL);
+ }
+ features = sa_proto_get_featureset(proto);
+ if (share != NULL && features & SA_FEATURE_RESOURCE) {
+ /*
+ * We have a share and the protocol requires
+ * that at least one resource exist (probably
+ * SMB). We need to make sure that there is at
+ * least one.
+ */
+ resource = sa_get_share_resource(share, NULL);
+ if (resource == NULL) {
+ zfs_construct_resource(share, dataset);
+ }
}
- /* Mark as the defining node of the subgroup */
- set_node_attr(share, "subgroup", "true");
-
- /* unmark the share's changed state */
- set_node_attr(share, "changed", NULL);
}
return (err);
}
@@ -619,6 +675,46 @@ zfs_grp_error(int err)
}
/*
+ * zfs_process_share(handle, share, mountpoint, proto, source,
+ * shareopts, sourcestr)
+ *
+ * Creates the subgroup, if necessary and adds shares and adds shares
+ * and properties.
+ */
+static int
+zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
+ char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
+ char *sourcestr, char *dataset)
+{
+ int err = SA_OK;
+
+ if (source & ZPROP_SRC_INHERITED) {
+ err = zfs_inherited(handle, share, sourcestr, shareopts,
+ mountpoint, proto, dataset);
+ } else {
+ group = find_or_create_zfs_subgroup(handle, dataset, proto,
+ shareopts, &err);
+ if (group == NULL) {
+ static int err = 0;
+ /*
+ * there is a problem, but we can't do
+ * anything about it at this point so we issue
+ * a warning an move on.
+ */
+ zfs_grp_error(err);
+ err = 1;
+ }
+ set_node_attr(group, "zfs", "true");
+ /*
+ * Add share with local opts via zfs_notinherited.
+ */
+ err = zfs_notinherited(group, share, mountpoint, shareopts,
+ proto, dataset);
+ }
+ return (err);
+}
+
+/*
* sa_get_zfs_shares(handle, groupname)
*
* Walk the mnttab for all zfs mounts and determine which are
@@ -652,7 +748,7 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
if (zfs_libhandle == NULL)
return (SA_SYSTEM_ERR);
- zfsgroup = find_or_create_group(handle, groupname, "nfs", &err);
+ zfsgroup = find_or_create_group(handle, groupname, NULL, &err);
if (zfsgroup == NULL)
return (legacy);
@@ -666,6 +762,7 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
group = zfsgroup;
for (i = 0; i < count; i++) {
char *dataset;
+ int foundnfs = 0;
source = ZPROP_SRC_ALL;
/* If no mountpoint, skip. */
@@ -694,8 +791,9 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
ZFS_MAXPROPLEN, B_FALSE) == 0 &&
strcmp(shareopts, "off") != 0) {
/* it is shared so add to list */
- share = sa_find_share(handle, mountpoint);
err = SA_OK;
+ foundnfs = 1;
+ share = sa_find_share(handle, mountpoint);
if (share != NULL) {
/*
* A zfs file system had been shared
@@ -711,36 +809,36 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
share = NULL;
}
if (err == SA_OK) {
- if (source & ZPROP_SRC_INHERITED) {
- err = zfs_inherited(handle,
- share, sourcestr,
- shareopts, mountpoint);
- } else {
- group = _sa_create_zfs_group(
- zfsgroup, dataset);
- if (group == NULL) {
- static int err = 0;
- /*
- * there is a problem,
- * but we can't do
- * anything about it
- * at this point so we
- * issue a warning an
- * move on.
- */
- zfs_grp_error(err);
- err = 1;
- continue;
- }
- set_node_attr(group, "zfs",
- "true");
- /*
- * Add share with local opts via
- * zfs_notinherited.
- */
- err = zfs_notinherited(group,
- mountpoint, shareopts);
- }
+ err = zfs_process_share(handle, group,
+ share, mountpoint, "nfs", source,
+ shareopts, sourcestr, dataset);
+ }
+ }
+ if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, shareopts,
+ sizeof (shareopts), &source, sourcestr,
+ ZFS_MAXPROPLEN, B_FALSE) == 0 &&
+ strcmp(shareopts, "off") != 0) {
+ /* it is shared so add to list */
+ err = SA_OK;
+ share = sa_find_share(handle, mountpoint);
+ if (share != NULL && !foundnfs) {
+ /*
+ * A zfs file system had been shared
+ * through traditional methods
+ * (share/dfstab or added to a non-zfs
+ * group. Now it has been added to a
+ * ZFS group via the zfs
+ * command. Remove from previous
+ * config and setup with current
+ * options.
+ */
+ err = sa_remove_share(share);
+ share = NULL;
+ }
+ if (err == SA_OK) {
+ err = zfs_process_share(handle, group,
+ share, mountpoint, "smb", source,
+ shareopts, sourcestr, dataset);
}
}
}
@@ -811,6 +909,122 @@ sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
}
/*
+ * add_resources(share, opt)
+ *
+ * Add resource properties to those in "opt". Resources are prefixed
+ * with name=resourcename.
+ */
+static char *
+add_resources(sa_share_t share, char *opt)
+{
+ char *newopt = NULL;
+ char *propstr;
+ sa_resource_t resource;
+
+ newopt = strdup(opt);
+ if (newopt == NULL)
+ return (newopt);
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ char *name;
+ size_t size;
+
+ name = sa_get_resource_attr(resource, "name");
+ if (name == NULL) {
+ free(newopt);
+ return (NULL);
+ }
+ size = strlen(name) + strlen(opt) + sizeof ("name=") + 1;
+ newopt = calloc(1, size);
+ if (newopt != NULL)
+ (void) snprintf(newopt, size, "%s,name=%s", opt, name);
+ free(opt);
+ opt = newopt;
+ propstr = sa_proto_legacy_format("smb", resource, 0);
+ if (propstr == NULL) {
+ free(opt);
+ return (NULL);
+ }
+ size = strlen(propstr) + strlen(opt) + 2;
+ newopt = calloc(1, size);
+ if (newopt != NULL)
+ (void) snprintf(newopt, size, "%s,%s", opt, propstr);
+ free(opt);
+ opt = newopt;
+ }
+ return (opt);
+}
+
+/*
+ * sa_zfs_set_sharesmb(group, path, on)
+ *
+ * Update the "sharesmb" property on the path. If on is true, then set
+ * to the properties on the group or "on" if no properties are
+ * defined. Set to "off" if on is false.
+ */
+
+int
+sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
+{
+ int ret = SA_NOT_IMPLEMENTED;
+ char *command;
+ sa_share_t share;
+
+ /* In case SMB not enabled */
+ if (sa_get_optionset(group, "smb") == NULL)
+ return (SA_NOT_SUPPORTED);
+
+ command = malloc(ZFS_MAXPROPLEN * 2);
+ if (command != NULL) {
+ char *opts = NULL;
+ char *dataset = NULL;
+ FILE *pfile;
+ sa_handle_impl_t impl_handle;
+
+ if (on) {
+ char *newopt;
+
+ share = sa_get_share(group, NULL);
+ opts = sa_proto_legacy_format("smb", share, 1);
+ if (opts != NULL && strlen(opts) == 0) {
+ free(opts);
+ opts = strdup("on");
+ }
+ newopt = add_resources(opts, share);
+ free(opts);
+ opts = newopt;
+ }
+
+ impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ assert(impl_handle != NULL);
+ if (impl_handle != NULL)
+ dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
+ else
+ ret = SA_SYSTEM_ERR;
+
+ if (dataset != NULL) {
+ (void) snprintf(command, ZFS_MAXPROPLEN * 2,
+ "echo %s set sharesmb=\"%s\" %s", COMMAND,
+ opts != NULL ? opts : "off", dataset);
+ pfile = popen(command, "r");
+ if (pfile != NULL) {
+ ret = pclose(pfile);
+ if (ret != 0)
+ ret = SA_SYSTEM_ERR;
+ }
+ }
+ if (opts != NULL)
+ free(opts);
+ if (dataset != NULL)
+ free(dataset);
+ free(command);
+ }
+ return (ret);
+}
+
+/*
* sa_zfs_update(group)
*
* call back to ZFS to update the share if necessary.
@@ -986,7 +1200,7 @@ sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
int
sa_share_zfs(sa_share_t share, char *path, share_t *sh,
- void *exportdata, boolean_t on)
+ void *exportdata, zfs_share_op_t operation)
{
libzfs_handle_t *libhandle;
sa_group_t group;
@@ -1057,7 +1271,7 @@ sa_share_zfs(sa_share_t share, char *path, share_t *sh,
sh->sh_size += j;
SMAX(i, j);
err = zfs_deleg_share_nfs(libhandle, dataset, path,
- exportdata, sh, i, on);
+ exportdata, sh, i, operation);
libzfs_fini(libhandle);
}
free(dataset);
diff --git a/usr/src/lib/libshare/common/libsharecore.c b/usr/src/lib/libshare/common/libsharecore.c
index 503a424cc6..2e39594fc3 100644
--- a/usr/src/lib/libshare/common/libsharecore.c
+++ b/usr/src/lib/libshare/common/libsharecore.c
@@ -51,6 +51,7 @@
#include <sys/param.h>
#include <signal.h>
#include <libintl.h>
+#include <dirent.h>
#include <sharefs/share.h>
#include "sharetab.h"
@@ -88,7 +89,7 @@ extern char *get_token(char *);
static void dfs_free_list(xfs_sharelist_t *);
/* prototypes */
void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
-extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *);
+extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
extern sa_group_t _sa_create_group(sa_handle_impl_t, char *);
static void outdfstab(FILE *, xfs_sharelist_t *);
extern int _sa_remove_optionset(sa_optionset_t);
@@ -563,13 +564,13 @@ sa_comment_line(char *line, char *err)
}
/*
- * sa_delete_legacy(share)
+ * sa_delete_legacy(share, protocol)
*
* Delete the specified share from the legacy config file.
*/
int
-sa_delete_legacy(sa_share_t share)
+sa_delete_legacy(sa_share_t share, char *protocol)
{
FILE *dfstab;
int err;
@@ -580,39 +581,54 @@ sa_delete_legacy(sa_share_t share)
sa_group_t parent;
sigset_t old;
+ /*
+ * Protect against shares that don't have paths. This is not
+ * really an error at this point.
+ */
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (ret);
+
dfstab = open_dfstab(SA_LEGACY_DFSTAB);
if (dfstab != NULL) {
(void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8);
sablocksigs(&old);
- path = sa_get_share_attr(share, "path");
parent = sa_get_parent_group(share);
if (parent != NULL) {
(void) lockf(fileno(dfstab), F_LOCK, 0);
list = getdfstab(dfstab);
rewind(dfstab);
- for (optionset = sa_get_optionset(parent, NULL);
- optionset != NULL;
- optionset = sa_get_next_optionset(optionset)) {
- char *proto = sa_get_optionset_attr(optionset,
- "type");
- if (list != NULL && proto != NULL)
+ if (protocol != NULL) {
+ if (list != NULL)
list = remdfsentry(list, path,
- proto);
- if (proto == NULL)
- ret = SA_NO_MEMORY;
- /*
- * May want to only do the dfstab if
- * this call returns NOT IMPLEMENTED
- * but it shouldn't hurt.
- */
- if (ret == SA_OK) {
- err = sa_proto_delete_legacy(proto,
- share);
- if (err != SA_NOT_IMPLEMENTED)
- ret = err;
+ protocol);
+ } else {
+ for (optionset = sa_get_optionset(parent, NULL);
+ optionset != NULL;
+ optionset =
+ sa_get_next_optionset(optionset)) {
+ char *proto = sa_get_optionset_attr(
+ optionset, "type");
+
+ if (list != NULL && proto != NULL)
+ list = remdfsentry(list, path,
+ proto);
+ if (proto == NULL)
+ ret = SA_NO_MEMORY;
+ /*
+ * may want to only do the dfstab if
+ * this call returns NOT IMPLEMENTED
+ * but it shouldn't hurt.
+ */
+ if (ret == SA_OK) {
+ err = sa_proto_delete_legacy(
+ proto, share);
+ if (err != SA_NOT_IMPLEMENTED)
+ ret = err;
+ }
+ if (proto != NULL)
+ sa_free_attr_string(proto);
}
- if (proto != NULL)
- sa_free_attr_string(proto);
}
outdfstab(dfstab, list);
if (list != NULL)
@@ -623,13 +639,16 @@ sa_delete_legacy(sa_share_t share)
(void) fsync(fileno(dfstab));
saunblocksigs(&old);
(void) fclose(dfstab);
- sa_free_attr_string(path);
} else {
if (errno == EACCES || errno == EPERM)
ret = SA_NO_PERMISSION;
else
ret = SA_CONFIG_ERR;
}
+
+ if (path != NULL)
+ sa_free_attr_string(path);
+
return (ret);
}
@@ -639,7 +658,7 @@ sa_delete_legacy(sa_share_t share)
* There is an assumption that dfstab will be the most common form of
* legacy configuration file for shares, but not the only one. Because
* of that, dfstab handling is done in the main code with calls to
- * this function and protocol specific calls to deal with formating
+ * this function and protocol specific calls to deal with formatting
* options into dfstab/share compatible syntax. Since not everything
* will be dfstab, there is a provision for calling a protocol
* specific plugin interface that allows the protocol plugin to do its
@@ -655,10 +674,16 @@ sa_update_legacy(sa_share_t share, char *proto)
char *path;
sigset_t old;
char *persist;
+ uint64_t features;
ret = sa_proto_update_legacy(proto, share);
if (ret != SA_NOT_IMPLEMENTED)
return (ret);
+
+ features = sa_proto_get_featureset(proto);
+ if (!(features & SA_FEATURE_DFSTAB))
+ return (ret);
+
/* do the dfstab format */
persist = sa_get_share_attr(share, "type");
/*
@@ -748,6 +773,21 @@ sa_is_share(void *object)
}
return (0);
}
+/*
+ * sa_is_resource(object)
+ *
+ * returns true of the object is of type "share".
+ */
+
+int
+sa_is_resource(void *object)
+{
+ if (object != NULL) {
+ if (strcmp((char *)((xmlNodePtr)object)->name, "resource") == 0)
+ return (1);
+ }
+ return (0);
+}
/*
* _sa_remove_property(property)
@@ -1392,6 +1432,7 @@ parse_sharetab(sa_handle_t handle)
sa_group_t lgroup;
char *groupname;
int legacy = 0;
+ char shareopts[MAXNAMLEN];
list = get_share_list(&err);
if (list == NULL)
@@ -1410,7 +1451,9 @@ parse_sharetab(sa_handle_t handle)
* share with no arguments.
*/
set_node_attr(share, "shared", "true");
- set_node_attr(share, "shareopts", tmplist->options);
+ (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s",
+ tmplist->fstype);
+ set_node_attr(share, shareopts, tmplist->options);
continue;
}
@@ -1426,9 +1469,9 @@ parse_sharetab(sa_handle_t handle)
*groupname++ = '\0';
group = sa_get_group(handle, groupname);
if (group != NULL) {
- share = _sa_add_share(group,
- tmplist->path,
- SA_SHARE_TRANSIENT, &err);
+ share = _sa_add_share(group, tmplist->path,
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
} else {
/*
* While this case shouldn't
@@ -1447,7 +1490,7 @@ parse_sharetab(sa_handle_t handle)
*/
share = _sa_add_share(lgroup,
tmplist->path, SA_SHARE_TRANSIENT,
- &err);
+ &err, (uint64_t)SA_FEATURE_NONE);
}
} else {
if (sa_zfs_is_shared(handle, tmplist->path)) {
@@ -1472,11 +1515,12 @@ parse_sharetab(sa_handle_t handle)
if (group != NULL) {
share = _sa_add_share(group,
tmplist->path, SA_SHARE_TRANSIENT,
- &err);
+ &err, (uint64_t)SA_FEATURE_NONE);
}
} else {
share = _sa_add_share(lgroup, tmplist->path,
- SA_SHARE_TRANSIENT, &err);
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
}
}
if (share == NULL)
@@ -1517,12 +1561,22 @@ int
gettransients(sa_handle_impl_t ihandle, xmlNodePtr *root)
{
int legacy = 0;
+ int numproto;
+ char **protocols = NULL;
+ int i;
if (root != NULL) {
if (*root == NULL)
*root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
- if (*root != NULL)
+ if (*root != NULL) {
legacy = parse_sharetab(ihandle);
+ numproto = sa_get_protocols(&protocols);
+ for (i = 0; i < numproto; i++)
+ legacy |= sa_proto_get_transients(
+ (sa_handle_t)ihandle, protocols[i]);
+ if (protocols != NULL)
+ free(protocols);
+ }
}
return (legacy);
}
@@ -1630,7 +1684,7 @@ sa_free_fstype(char *type)
* Work backward to the top of the share object tree and start
* copying protocol specific optionsets into a newly created
* optionset that doesn't have a parent (it will be freed
- * later). This provides for the property inheritence model. That
+ * later). This provides for the property inheritance model. That
* is, properties closer to the share take precedence over group
* level. This also provides for groups of groups in the future.
*/
@@ -1719,7 +1773,7 @@ sa_free_derived_optionset(sa_optionset_t optionset)
* Find all the security types set for this object. This is
* preliminary to getting a derived security set. The return value is an
* optionset containg properties which are the sectype values found by
- * walking up the XML document struture. The returned optionset
+ * walking up the XML document structure. The returned optionset
* is a derived optionset.
*
* If hier is 0, only look at object. If non-zero, walk up the tree.
@@ -1885,6 +1939,19 @@ sa_fillshare(sa_share_t share, char *proto, struct share *sh)
sa_group_t group;
char *buff;
char *zfs;
+ sa_resource_t resource;
+ char *rsrcname = NULL;
+ char *defprop;
+
+ /*
+ * We only want to deal with the path level shares for the
+ * sharetab file. If a resource, get the parent.
+ */
+ if (sa_is_resource(share)) {
+ resource = (sa_resource_t)share;
+ share = sa_get_resource_parent(resource);
+ rsrcname = sa_get_resource_attr(resource, "name");
+ }
group = sa_get_parent_group(share);
if (group != NULL) {
@@ -1912,41 +1979,48 @@ sa_fillshare(sa_share_t share, char *proto, struct share *sh)
sa_free_attr_string(value);
}
- value = sa_get_share_attr(share, "resource");
- if (value != NULL || groupname != NULL) {
+ if (rsrcname != NULL || groupname != NULL) {
int len = 0;
- if (value != NULL)
- len += strlen(value);
+ if (rsrcname != NULL)
+ len += strlen(rsrcname);
if (groupname != NULL)
len += strlen(groupname);
len += 3; /* worst case */
buff = malloc(len);
(void) snprintf(buff, len, "%s%s%s",
- (value != NULL && strlen(value) > 0) ? value : "-",
+ (rsrcname != NULL &&
+ strlen(rsrcname) > 0) ? rsrcname : "-",
groupname != NULL ? "@" : "",
groupname != NULL ? groupname : "");
sh->sh_res = buff;
- if (value != NULL)
- sa_free_attr_string(value);
- if (groupname != NULL) {
+ if (rsrcname != NULL)
+ sa_free_attr_string(rsrcname);
+ if (groupname != NULL)
sa_free_attr_string(groupname);
- groupname = NULL;
- }
} else {
sh->sh_res = strdup("-");
}
+ /*
+ * Get correct default prop string. NFS uses "rw", others use
+ * "".
+ */
+ if (strcmp(proto, "nfs") != 0)
+ defprop = "\"\"";
+ else
+ defprop = "rw";
+
sh->sh_fstype = strdup(proto);
value = sa_proto_legacy_format(proto, share, 1);
if (value != NULL) {
if (strlen(value) > 0)
sh->sh_opts = strdup(value);
else
- sh->sh_opts = strdup("rw");
+ sh->sh_opts = strdup(defprop);
free(value);
} else {
- sh->sh_opts = strdup("rw");
+ sh->sh_opts = strdup(defprop);
}
value = sa_get_share_description(share);
@@ -2041,3 +2115,67 @@ sa_delete_sharetab(char *path, char *proto)
return (ret);
}
+/*
+ * sa_fix_resource_name(path)
+ *
+ * change all illegal characters to something else. For now, all get
+ * converted to '_' and the leading '/' is stripped off. This is used
+ * to construct an resource name (SMB share name) that is valid.
+ * Caller must pass a valid path.
+ */
+void
+sa_fix_resource_name(char *path)
+{
+ char *cp;
+ size_t len;
+
+ assert(path != NULL);
+
+ /* make sure we are appropriate length */
+ cp = path;
+ if (*cp == '/')
+ cp++; /* skip leading slash */
+ while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) {
+ cp = strchr(cp, '/');
+ if (cp != NULL)
+ cp++;
+ }
+ /* two cases - cp == NULL and cp is substring of path */
+ if (cp == NULL) {
+ /* just take last SA_MAX_RESOURCE_NAME chars */
+ len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME;
+ (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME);
+ path[SA_MAX_RESOURCE_NAME] = '\0';
+ } else {
+ len = strlen(cp) + 1;
+ (void) memmove(path, cp, len);
+ }
+
+ /*
+ * Don't want any of the characters that are not allowed
+ * in an SMB share name. Replace them with '_'.
+ */
+ while (*path) {
+ switch (*path) {
+ case '/':
+ case '"':
+ case '\\':
+ case '[':
+ case ']':
+ case ':':
+ case '|':
+ case '<':
+ case '>':
+ case '+':
+ case ';':
+ case ',':
+ case '?':
+ case '*':
+ case '=':
+ case '\t':
+ *path = '_';
+ break;
+ }
+ path++;
+ }
+}
diff --git a/usr/src/lib/libshare/common/mapfile-vers b/usr/src/lib/libshare/common/mapfile-vers
index 317623b3b4..f7dfde5730 100644
--- a/usr/src/lib/libshare/common/mapfile-vers
+++ b/usr/src/lib/libshare/common/mapfile-vers
@@ -106,9 +106,28 @@ SUNWprivate {
sa_delete_legacy;
sa_free_derived_security;
sa_enable_share;
+ sa_enable_resource;
sa_create_group;
sa_valid_protocol;
sa_find_group_handle;
+ sa_add_resource;
+ sa_remove_resource;
+ sa_rename_resource;
+ sa_get_resource;
+ sa_get_next_resource;
+ sa_get_resource_attr;
+ sa_set_resource_attr;
+ sa_get_share_resource;
+ sa_get_resource_parent;
+ sa_find_resource;
+ sa_proto_change_notify;
+ sa_proto_notify_resource;
+ sa_disable_resource;
+ sa_proto_get_featureset;
+ sa_is_persistent;
+ sa_set_resource_description;
+ sa_get_resource_description;
+ sa_fix_resource_name;
local:
*;
};
diff --git a/usr/src/lib/libshare/common/plugin.c b/usr/src/lib/libshare/common/plugin.c
index 4079e24ff7..08856a8951 100644
--- a/usr/src/lib/libshare/common/plugin.c
+++ b/usr/src/lib/libshare/common/plugin.c
@@ -64,7 +64,7 @@ void proto_plugin_fini();
* /usr/lib/fs/nfs/libshare_nfs.so. The protocol specific directory
* would have a modules with name libshare_<proto>.so. If one is
* found, initialize it and add to the internal list of
- * protocols. These are used for protocol specifici operations.
+ * protocols. These are used for protocol specific operations.
*/
int
@@ -242,9 +242,9 @@ sa_proto_share(char *proto, sa_share_t share)
}
/*
- * sa_proto_unshare(proto, path)
+ * sa_proto_unshare(proto, share)
*
- * Deactivate (unshare) the path for this protocol.
+ * Deactivate (unshare) the share for this protocol.
*/
int
@@ -259,6 +259,52 @@ sa_proto_unshare(sa_share_t share, char *proto, char *path)
}
/*
+ * sa_proto_share_resource(char *proto, sa_resource_t resource)
+ *
+ * For protocols that actually enable at the resource level, do the
+ * protocol specific resource enable. If it doesn't, return an error.
+ * Note that the resource functions are optional so can return
+ * SA_NOT_SUPPORTED.
+ */
+
+int
+sa_proto_share_resource(char *proto, sa_resource_t resource)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_INVALID_PROTOCOL;
+
+ if (ops != NULL) {
+ if (ops->sa_enable_resource != NULL)
+ ret = ops->sa_enable_resource(resource);
+ else
+ ret = SA_NOT_SUPPORTED;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_unshare_resource(char *proto, sa_resource_t resource)
+ *
+ * For protocols that actually disable at the resource level, do the
+ * protocol specific resource disable. If it doesn't, return an error.
+ */
+
+int
+sa_proto_unshare_resource(char *proto, sa_resource_t resource)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_INVALID_PROTOCOL;
+
+ if (ops != NULL) {
+ if (ops->sa_disable_resource != NULL)
+ ret = ops->sa_disable_resource(resource);
+ else
+ ret = SA_NOT_SUPPORTED;
+ }
+ return (ret);
+}
+
+/*
* sa_proto_valid_prop(proto, prop, opt)
*
* Check to see if the specified prop is valid for this protocol.
@@ -395,7 +441,7 @@ sa_proto_get_properties(char *proto)
/*
* sa_proto_set_property(proto, prop)
*
- * Update the protocol specifiec property.
+ * Update the protocol specific property.
*/
int
@@ -467,16 +513,127 @@ int
sa_proto_delete_legacy(char *proto, sa_share_t share)
{
struct sa_plugin_ops *ops = find_protocol(proto);
- int ret = SA_OK;
+ int ret = SA_NOT_IMPLEMENTED;
if (ops != NULL) {
if (ops->sa_delete_legacy != NULL)
ret = ops->sa_delete_legacy(share);
- } else {
- if (proto != NULL)
- ret = SA_NOT_IMPLEMENTED;
- else
+ } else if (proto == NULL) {
+ ret = SA_INVALID_PROTOCOL;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_change_notify(share, char *protocol)
+ *
+ * Notify the protocol that a change has been made to the share
+ */
+
+int
+sa_proto_change_notify(sa_share_t share, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_NOT_IMPLEMENTED;
+
+ if (ops != NULL) {
+ if (ops->sa_change_notify != NULL)
+ ret = ops->sa_change_notify(share);
+ } else if (proto == NULL) {
ret = SA_INVALID_PROTOCOL;
}
return (ret);
}
+
+/*
+ * sa_proto_notify_resource(resource, char *protocol)
+ *
+ * Notify the protocol that a change has been made to the share
+ */
+
+int
+sa_proto_notify_resource(sa_resource_t resource, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_NOT_IMPLEMENTED;
+
+ if (ops != NULL) {
+ if (ops->sa_notify_resource != NULL)
+ ret = ops->sa_notify_resource(resource);
+ } else if (proto == NULL) {
+ ret = SA_INVALID_PROTOCOL;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_get_featureset(protocol)
+ *
+ * Get bitmask of defined features of the protocol. These are
+ * primarily things like SA_FEATURE_RESOURCE (shares are by resource
+ * name rather than path) and other operational features that affect
+ * behavior.
+ */
+
+uint64_t
+sa_proto_get_featureset(char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ uint64_t ret = 0;
+
+ if (ops != NULL) {
+ if (ops->sa_features != NULL)
+ ret = ops->sa_features();
+ }
+ /* if not implemented, zero is valid */
+ return (ret);
+}
+
+/*
+ * sa_proto_get_transients(sa_handle_t)
+ *
+ * Called to get any protocol specific transient shares. NFS doesn't
+ * use this since the info is in sharetab which is processed as a
+ * common transient store.
+ *
+ * The protocol plugin should verify that the share isn't in the
+ * repository and then add it as a transient.
+ *
+ * Not having an entry is not a problem. It returns 0 in that case.
+ */
+
+int
+sa_proto_get_transients(sa_handle_t handle, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = 0;
+
+ if (ops != NULL) {
+ if (ops->sa_get_transient_shares != NULL)
+ ret = ops->sa_get_transient_shares(handle);
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_rename_resource(sa_handle_t, proto, sa_resource_t, newname)
+ *
+ * Protocols may need to know when a resource has changed names in
+ * order to notify clients. This must be done "before" the name in the
+ * resource has been changed. Not being implemented is not a problem.
+ */
+
+int
+sa_proto_rename_resource(sa_handle_t handle, char *proto,
+ sa_resource_t resource, char *newname)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_OK;
+
+ if (ops != NULL) {
+ if (ops->sa_rename_resource != NULL)
+ ret = ops->sa_rename_resource(handle, resource,
+ newname);
+ }
+ return (ret);
+}
diff --git a/usr/src/lib/libshare/common/scfutil.c b/usr/src/lib/libshare/common/scfutil.c
index 05421d605b..344d3729bb 100644
--- a/usr/src/lib/libshare/common/scfutil.c
+++ b/usr/src/lib/libshare/common/scfutil.c
@@ -35,6 +35,7 @@
#include "libshare_impl.h"
#include "scfutil.h"
#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include <uuid/uuid.h>
#include <sys/param.h>
@@ -396,7 +397,8 @@ out:
static char *share_attr[] = {
"path",
"id",
- "resource",
+ "drive-letter",
+ "exclude",
NULL,
};
@@ -411,6 +413,52 @@ is_share_attr(char *name)
}
/*
+ * _sa_make_resource(node, valuestr)
+ *
+ * Make a resource node on the share node. The valusestr will either
+ * be old format (SMF acceptable string) or new format (pretty much an
+ * arbitrary string with "nnn:" prefixing in order to persist
+ * mapping). The input valuestr will get modified in place. This is
+ * only used in SMF repository parsing. A possible third field will be
+ * a "description" string.
+ */
+
+static void
+_sa_make_resource(xmlNodePtr node, char *valuestr)
+{
+ char *idx;
+ char *name;
+ char *description = NULL;
+
+ idx = valuestr;
+ name = strchr(valuestr, ':');
+ if (name == NULL) {
+ /* this is old form so give an index of "0" */
+ idx = "0";
+ name = valuestr;
+ } else {
+ /* NUL the ':' and move past it */
+ *name++ = '\0';
+ /* There could also be a description string */
+ description = strchr(name, ':');
+ if (description != NULL)
+ *description++ = '\0';
+ }
+ node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
+ if (node != NULL) {
+ xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
+ xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
+ /* SMF values are always persistent */
+ xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
+ if (description != NULL && strlen(description) > 0) {
+ (void) xmlNewChild(node, NULL, (xmlChar *)"description",
+ (xmlChar *)description);
+ }
+ }
+}
+
+
+/*
* sa_share_from_pgroup
*
* Extract the share definition from the share property group. We do
@@ -490,34 +538,70 @@ sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
vallen) >= 0) {
ret = SA_OK;
}
+ } else if (strcmp(name, "resource") == 0) {
+ ret = SA_OK;
}
}
- if (ret == SA_OK) {
+ if (ret != SA_OK)
+ continue;
+ /*
+ * Check that we have the "path" property in
+ * name. The string in name will always be nul
+ * terminated if scf_property_get_name()
+ * succeeded.
+ */
+ if (strcmp(name, "path") == 0)
+ have_path = 1;
+ if (is_share_attr(name)) {
/*
- * Check that we have the "path" property in
- * name. The string in name will always be nul
- * terminated if scf_property_get_name()
- * succeeded.
+ * If a share attr, then simple -
+ * usually path and id name
*/
- if (strcmp(name, "path") == 0)
- have_path = 1;
- if (is_share_attr(name)) {
- /*
- * If a share attr, then simple -
- * usually path and resource name
- */
- xmlSetProp(node, (xmlChar *)name,
- (xmlChar *)valuestr);
- } else {
- if (strcmp(name, "description") == 0) {
- /* We have a description node */
- xmlNodePtr desc;
- desc = xmlNewChild(node, NULL,
- (xmlChar *)"description", NULL);
- if (desc != NULL)
- xmlNodeSetContent(desc,
- (xmlChar *)valuestr);
+ xmlSetProp(node, (xmlChar *)name,
+ (xmlChar *)valuestr);
+ } else if (strcmp(name, "resource") == 0) {
+ /*
+ * Resource names handled differently since
+ * there can be multiple on each share. The
+ * "resource" id must be preserved since this
+ * will be used by some protocols in mapping
+ * "property spaces" to names and is always
+ * used to create SMF property groups specific
+ * to resources. CIFS needs this. The first
+ * value is present so add and then loop for
+ * any additional. Since this is new and
+ * previous values may exist, handle
+ * conversions.
+ */
+ scf_iter_t *viter;
+ viter = scf_iter_create(handle->handle);
+ if (viter != NULL &&
+ scf_iter_property_values(viter, prop) == 0) {
+ while (scf_iter_next_value(viter, value) > 0) {
+ /* Have a value so process it */
+ if (scf_value_get_ustring(value,
+ valuestr, vallen) >= 0) {
+ /* have a ustring */
+ _sa_make_resource(node,
+ valuestr);
+ } else if (scf_value_get_astring(value,
+ valuestr, vallen) >= 0) {
+ /* have an astring */
+ _sa_make_resource(node,
+ valuestr);
+ }
}
+ scf_iter_destroy(viter);
+ }
+ } else {
+ if (strcmp(name, "description") == 0) {
+ /* We have a description node */
+ xmlNodePtr desc;
+ desc = xmlNewChild(node, NULL,
+ (xmlChar *)"description", NULL);
+ if (desc != NULL)
+ xmlNodeSetContent(desc,
+ (xmlChar *)valuestr);
}
}
}
@@ -583,7 +667,34 @@ find_share_by_id(sa_handle_t handle, char *shareid)
}
/*
- * sa_share_props_from_pgroup(root, handle, pg, id)
+ * find_resource_by_index(share, index)
+ *
+ * Search the resource records on the share for the id index.
+ */
+static sa_resource_t
+find_resource_by_index(sa_share_t share, char *index)
+{
+ sa_resource_t resource;
+ sa_resource_t found = NULL;
+ char *id;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL && found == NULL;
+ resource = sa_get_next_resource(resource)) {
+ id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
+ if (id != NULL) {
+ if (strcmp(id, index) == 0) {
+ /* found it so save in "found" */
+ found = resource;
+ }
+ sa_free_attr_string(id);
+ }
+ }
+ return (found);
+}
+
+/*
+ * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
*
* Extract share properties from the SMF property group. More sanity
* checks are done and the share object is created. We ignore some
@@ -639,6 +750,7 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
/* not a valid proto (null) */
return (ret);
}
+
sectype = strchr(proto, '_');
if (sectype != NULL)
*sectype++ = '\0';
@@ -664,10 +776,35 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
if (sectype == NULL)
node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
else {
- node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL);
- if (node != NULL)
- xmlSetProp(node, (xmlChar *)"sectype",
- (xmlChar *)sectype);
+ if (isdigit((int)*sectype)) {
+ sa_resource_t resource;
+ /*
+ * If sectype[0] is a digit, then it is an index into
+ * the resource names. We need to find a resource
+ * record and then get the properties into an
+ * optionset. The optionset becomes the "node" and the
+ * rest is hung off of the share.
+ */
+ resource = find_resource_by_index(share, sectype);
+ if (resource != NULL) {
+ node = xmlNewChild(resource, NULL,
+ (xmlChar *)"optionset", NULL);
+ } else {
+ /* this shouldn't happen */
+ ret = SA_SYSTEM_ERR;
+ }
+ } else {
+ /*
+ * If not a digit, then it is a security type
+ * (alternate option space). Security types start with
+ * an alphabetic.
+ */
+ node = xmlNewChild(root, NULL, (xmlChar *)"security",
+ NULL);
+ if (node != NULL)
+ xmlSetProp(node, (xmlChar *)"sectype",
+ (xmlChar *)sectype);
+ }
}
if (node == NULL) {
ret = SA_NO_MEMORY;
@@ -685,7 +822,7 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
if (iter == NULL || value == NULL || prop == NULL || name == NULL)
goto out;
- /* Iterate over the share pg properties */
+ /* iterate over the share pg properties */
if (scf_iter_pg_properties(iter, pg) == 0) {
while (scf_iter_next_property(iter, prop) > 0) {
ret = SA_SYSTEM_ERR; /* assume the worst */
@@ -897,7 +1034,7 @@ out:
* sa_extract_defaults(root, handle, instance)
*
* Local function to find the default properties that live in the
- * default instance's "operation" proprerty group.
+ * default instance's "operation" property group.
*/
static void
@@ -946,7 +1083,7 @@ out:
/*
- * sa_get_config(handle, root, doc, sahandlec)
+ * sa_get_config(handle, root, doc, sahandle)
*
* Walk the SMF repository for /network/shares/group and find all the
* instances. These become group names. Then add the XML structure
@@ -1276,6 +1413,147 @@ sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
}
/*
+ * check_resource(share)
+ *
+ * Check to see if share has any persistent resources. We don't want
+ * to save if they are all transient.
+ */
+static int
+check_resource(sa_share_t share)
+{
+ sa_resource_t resource;
+ int ret = B_FALSE;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL && ret == B_FALSE;
+ resource = sa_get_next_resource(resource)) {
+ char *type;
+ type = sa_get_resource_attr(resource, "type");
+ if (type != NULL) {
+ if (strcmp(type, "transient") != 0) {
+ ret = B_TRUE;
+ }
+ sa_free_attr_string(type);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_set_resource_property(handle, prop, value)
+ *
+ * set a property transaction entry into the pending SMF
+ * transaction. We don't want to include any transient resources
+ */
+
+static int
+sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
+{
+ int ret = SA_OK;
+ scf_value_t *value;
+ scf_transaction_entry_t *entry;
+ sa_resource_t resource;
+ char *valstr;
+ char *idstr;
+ char *description;
+ char *propstr = NULL;
+ size_t strsize;
+
+ /* don't bother if no persistent resources */
+ if (check_resource(share) == B_FALSE)
+ return (ret);
+
+ /*
+ * properties must be set in transactions and don't take
+ * effect until the transaction has been ended/committed.
+ */
+ entry = scf_entry_create(handle->handle);
+ if (entry == NULL)
+ return (SA_SYSTEM_ERR);
+
+ if (scf_transaction_property_change(handle->trans, entry,
+ "resource", SCF_TYPE_ASTRING) != 0 &&
+ scf_transaction_property_new(handle->trans, entry,
+ "resource", SCF_TYPE_ASTRING) != 0) {
+ scf_entry_destroy(entry);
+ return (SA_SYSTEM_ERR);
+
+ }
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ value = scf_value_create(handle->handle);
+ if (value == NULL) {
+ ret = SA_NO_MEMORY;
+ break;
+ }
+ /* Get size of complete string */
+ valstr = sa_get_resource_attr(resource, "name");
+ idstr = sa_get_resource_attr(resource, "id");
+ description = sa_get_resource_description(resource);
+ strsize = (valstr != NULL) ? strlen(valstr) : 0;
+ strsize += (idstr != NULL) ? strlen(idstr) : 0;
+ strsize += (description != NULL) ? strlen(description) : 0;
+ if (strsize > 0) {
+ strsize += 3; /* add nul and ':' */
+ propstr = (char *)malloc(strsize);
+ if (propstr == NULL) {
+ scf_value_destroy(value);
+ ret = SA_NO_MEMORY;
+ goto err;
+ }
+ if (idstr == NULL)
+ (void) snprintf(propstr, strsize, "%s",
+ valstr ? valstr : "");
+ else
+ (void) snprintf(propstr, strsize, "%s:%s:%s",
+ idstr ? idstr : "", valstr ? valstr : "",
+ description ? description : "");
+ if (scf_value_set_astring(value, propstr) != 0) {
+ ret = SA_SYSTEM_ERR;
+ free(propstr);
+ scf_value_destroy(value);
+ break;
+ }
+ if (scf_entry_add_value(entry, value) != 0) {
+ ret = SA_SYSTEM_ERR;
+ free(propstr);
+ scf_value_destroy(value);
+ break;
+ }
+ /* the value is in the transaction */
+ value = NULL;
+ free(propstr);
+ }
+err:
+ if (valstr != NULL)
+ sa_free_attr_string(valstr);
+ if (idstr != NULL)
+ sa_free_attr_string(idstr);
+ if (description != NULL)
+ sa_free_share_description(description);
+ }
+ /* the entry is in the transaction */
+ entry = NULL;
+
+ if (ret == SA_SYSTEM_ERR) {
+ switch (scf_error()) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SA_NO_PERMISSION;
+ break;
+ }
+ }
+ /*
+ * cleanup if there were any errors that didn't leave
+ * these values where they would be cleaned up later.
+ */
+ if (entry != NULL)
+ scf_entry_destroy(entry);
+
+ return (ret);
+}
+
+/*
* sa_commit_share(handle, group, share)
*
* Commit this share to the repository.
@@ -1288,7 +1566,6 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
int ret = SA_OK;
char *groupname;
char *name;
- char *resource;
char *description;
char *sharename;
ssize_t proplen;
@@ -1371,15 +1648,35 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
}
if (ret == SA_OK) {
- resource = sa_get_share_attr(share,
- "resource");
- if (resource != NULL) {
+ name = sa_get_share_attr(share, "drive-letter");
+ if (name != NULL) {
+ /* A drive letter may exist for SMB */
+ ret = sa_set_property(handle,
+ "drive-letter", name);
+ sa_free_attr_string(name);
+ }
+ }
+ if (ret == SA_OK) {
+ name = sa_get_share_attr(share, "exclude");
+ if (name != NULL) {
+ /*
+ * In special cases need to
+ * exclude proto enable.
+ */
ret = sa_set_property(handle,
- "resource", resource);
- sa_free_attr_string(resource);
+ "exclude", name);
+ sa_free_attr_string(name);
}
}
if (ret == SA_OK) {
+ /*
+ * If there are resource names, bundle them up
+ * and save appropriately.
+ */
+ ret = sa_set_resource_property(handle, share);
+ }
+
+ if (ret == SA_OK) {
description = sa_get_share_description(share);
if (description != NULL) {
ret = sa_set_property(handle,
@@ -1414,6 +1711,49 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
/*
+ * remove_resources(handle, share, shareid)
+ *
+ * If the share has resources, remove all of them and their
+ * optionsets.
+ */
+static int
+remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
+{
+ sa_resource_t resource;
+ sa_optionset_t opt;
+ char *proto;
+ char *id;
+ ssize_t proplen;
+ char *propstring;
+ int ret = SA_OK;
+
+ proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
+ propstring = malloc(proplen);
+ if (propstring == NULL)
+ return (SA_NO_MEMORY);
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL; resource = sa_get_next_resource(resource)) {
+ id = sa_get_resource_attr(resource, "id");
+ if (id == NULL)
+ continue;
+ for (opt = sa_get_optionset(resource, NULL);
+ opt != NULL; opt = sa_get_next_optionset(resource)) {
+ proto = sa_get_optionset_attr(opt, "type");
+ if (proto != NULL) {
+ (void) snprintf(propstring, proplen,
+ "%s_%s_%s", shareid, proto, id);
+ ret = sa_delete_pgroup(handle, propstring);
+ sa_free_attr_string(proto);
+ }
+ }
+ sa_free_attr_string(id);
+ }
+ free(propstring);
+ return (ret);
+}
+
+/*
* sa_delete_share(handle, group, share)
*
* Remove the specified share from the group (and service instance).
@@ -1444,6 +1784,8 @@ sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
ret = sa_get_instance(handle, groupname);
if (ret == SA_OK) {
+ /* If a share has resources, remove them */
+ ret = remove_resources(handle, share, shareid);
/* If a share has properties, remove them */
ret = sa_delete_pgroup(handle, shareid);
for (opt = sa_get_optionset(share, NULL);
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c
index a7426ab841..0a3175de70 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c
@@ -73,6 +73,7 @@ static int nfs_set_proto_prop(sa_property_t);
static sa_protocol_properties_t nfs_get_proto_set();
static char *nfs_get_status();
static char *nfs_space_alias(char *);
+static uint64_t nfs_features();
/*
* ops vector that provides the protocol specific info and operations
@@ -95,7 +96,14 @@ struct sa_plugin_ops sa_plugin_ops = {
nfs_get_proto_set,
nfs_get_status,
nfs_space_alias,
- NULL,
+ NULL, /* update_legacy */
+ NULL, /* delete_legacy */
+ NULL, /* change_notify */
+ NULL, /* enable_resource */
+ NULL, /* disable_resource */
+ nfs_features,
+ NULL, /* transient shares */
+ NULL, /* notify resource */
NULL
};
@@ -543,13 +551,16 @@ nfs_parse_legacy_options(sa_group_t group, char *options)
optionset = sa_create_optionset(group, "nfs");
} else {
/*
- * have an existing optionset so we need to compare
- * options in order to detect errors. For now, we
- * assume that the first optionset is the correct one
- * and the others will be the same. This needs to be
- * fixed before the final code is ready.
+ * Have an existing optionset . Ideally, we would need
+ * to compare options in order to detect errors. For
+ * now, we assume that the first optionset is the
+ * correct one and the others will be the same. An
+ * empty optionset is the same as no optionset so we
+ * don't want to exit in that case. Getting an empty
+ * optionset can occur with ZFS property checking.
*/
- return (ret);
+ if (sa_get_property(optionset, NULL) != NULL)
+ return (ret);
}
if (strcmp(options, SHOPT_RW) == 0) {
@@ -839,7 +850,7 @@ fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset)
/*
* since options may be set/reset multiple times, always do an
* explicit set or clear of the option. This allows defaults
- * to be set and then the protocol specifici to override.
+ * to be set and then the protocol specific to override.
*/
name = sa_get_property_attr(option, "type");
@@ -1804,7 +1815,8 @@ nfs_enable_share(sa_share_t share)
ea.uex = &export;
sa_sharetab_fill_zfs(share, &sh, "nfs");
- err = sa_share_zfs(share, path, &sh, &ea, B_TRUE);
+ err = sa_share_zfs(share, path, &sh,
+ &ea, ZFS_SHARE_NFS);
sa_emptyshare(&sh);
}
} else {
@@ -1909,7 +1921,8 @@ nfs_disable_share(sa_share_t share, char *path)
sh.sh_path = path;
sh.sh_fstype = "nfs";
- err = sa_share_zfs(share, path, &sh, &ea, B_FALSE);
+ err = sa_share_zfs(share, path, &sh,
+ &ea, ZFS_UNSHARE_NFS);
} else
err = exportfs(path, NULL);
if (err < 0) {
@@ -2802,7 +2815,7 @@ nfs_minmax_check(int index, int value)
/*
* nfs_validate_proto_prop(index, name, value)
*
- * Verify that the property specifed by name can take the new
+ * Verify that the property specified by name can take the new
* value. This is a sanity check to prevent bad values getting into
* the default files. All values need to be checked against what is
* allowed by their defined type. If a type isn't explicitly defined
@@ -2967,3 +2980,15 @@ nfs_space_alias(char *space)
}
return (strdup(name));
}
+
+/*
+ * nfs_features()
+ *
+ * Return a mask of the features required.
+ */
+
+static uint64_t
+nfs_features()
+{
+ return ((uint64_t)SA_FEATURE_DFSTAB);
+}
diff --git a/usr/src/lib/libshare/smb/Makefile b/usr/src/lib/libshare/smb/Makefile
new file mode 100644
index 0000000000..d5f3df5233
--- /dev/null
+++ b/usr/src/lib/libshare/smb/Makefile
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+MSGFILES = libshare_smb.c
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
+include ../../../Makefile.msg.targ
diff --git a/usr/src/lib/libshare/smb/Makefile.com b/usr/src/lib/libshare/smb/Makefile.com
new file mode 100644
index 0000000000..997f47daef
--- /dev/null
+++ b/usr/src/lib/libshare/smb/Makefile.com
@@ -0,0 +1,88 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = libshare_smb.a
+VERS = .1
+SMBMLSVC_DIR = $(SRC)/lib/smbsrv/libmlsvc/common
+SMBBASE_DIR = $(SRC)/lib/smbsrv/libsmb/common
+SMBCOMMON_DIR = $(SRC)/common/smbsrv
+
+LIBOBJS = libshare_smb.o smb_share_doorclnt.o
+SMBCOMMON_OBJ = smb_share_door_decode.o smb_common_door_decode.o
+SMBBASE_OBJ = smb_cfg.o smb_scfutil.o smb_door_client.o
+SMBMLSVC_OBJ = smb_share_util.o
+OBJECTS = $(LIBOBJS) $(SMBCOMMON_OBJ) $(SMBBASE_OBJ) $(SMBMLSVC_OBJ)
+
+include ../../../Makefile.lib
+
+ROOTLIBDIR = $(ROOT)/usr/lib/fs/smb
+ROOTLIBDIR64 = $(ROOT)/usr/lib/fs/smb/$(MACH64)
+
+LIBSRCS = $(LIBOBJS:%.o=$(SRCDIR)/%.c)
+lintcheck := SRCS = $(LIBSRCS)
+
+LIBS = $(DYNLIB)
+LDLIBS += -lshare -lnsl -lscf -lumem -lc
+all install := LDLIBS += -lxml2
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I/usr/include/libxml2 \
+ -I$(SRCDIR)/../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: all
+
+lint: lintcheck
+
+pics/smb_door_client.o: $(SMBBASE_DIR)/smb_door_client.c
+ $(COMPILE.c) -o $@ $(SMBBASE_DIR)/smb_door_client.c
+ $(POST_PROCESS_O)
+
+pics/smb_share_door_decode.o: $(SMBCOMMON_DIR)/smb_share_door_decode.c
+ $(COMPILE.c) -o $@ $(SMBCOMMON_DIR)/smb_share_door_decode.c
+ $(POST_PROCESS_O)
+
+pics/smb_common_door_decode.o: $(SMBCOMMON_DIR)/smb_common_door_decode.c
+ $(COMPILE.c) -o $@ $(SMBCOMMON_DIR)/smb_common_door_decode.c
+ $(POST_PROCESS_O)
+
+pics/smb_cfg.o: $(SMBBASE_DIR)/smb_cfg.c
+ $(COMPILE.c) -o $@ $(SMBBASE_DIR)/smb_cfg.c
+ $(POST_PROCESS_O)
+
+pics/smb_scfutil.o: $(SMBBASE_DIR)/smb_scfutil.c
+ $(COMPILE.c) -o $@ $(SMBBASE_DIR)/smb_scfutil.c
+ $(POST_PROCESS_O)
+
+pics/smb_share_util.o: $(SMBMLSVC_DIR)/smb_share_util.c
+ $(COMPILE.c) -o $@ $(SMBMLSVC_DIR)/smb_share_util.c
+ $(POST_PROCESS_O)
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/libshare/smb/amd64/Makefile b/usr/src/lib/libshare/smb/amd64/Makefile
new file mode 100644
index 0000000000..90b1730d23
--- /dev/null
+++ b/usr/src/lib/libshare/smb/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libshare/smb/i386/Makefile b/usr/src/lib/libshare/smb/i386/Makefile
new file mode 100644
index 0000000000..543238473c
--- /dev/null
+++ b/usr/src/lib/libshare/smb/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libshare/smb/libshare_smb.c b/usr/src/lib/libshare/smb/libshare_smb.c
new file mode 100644
index 0000000000..7d705e0369
--- /dev/null
+++ b/usr/src/lib/libshare/smb/libshare_smb.c
@@ -0,0 +1,1641 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB specific functions
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <zone.h>
+#include <errno.h>
+#include <locale.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include "libshare.h"
+#include "libshare_impl.h"
+#include <pwd.h>
+#include <limits.h>
+#include <libscf.h>
+#include <strings.h>
+#include "libshare_smb.h"
+#include <rpcsvc/daemon_utils.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/libsmb.h>
+
+/* internal functions */
+static int smb_share_init(void);
+static void smb_share_fini(void);
+static int smb_enable_share(sa_share_t);
+static int smb_share_changed(sa_share_t);
+static int smb_resource_changed(sa_resource_t);
+static int smb_rename_resource(sa_handle_t, sa_resource_t, char *);
+static int smb_disable_share(sa_share_t share, char *);
+static int smb_validate_property(sa_property_t, sa_optionset_t);
+static int smb_set_proto_prop(sa_property_t);
+static sa_protocol_properties_t smb_get_proto_set(void);
+static char *smb_get_status(void);
+static int smb_parse_optstring(sa_group_t, char *);
+static char *smb_format_options(sa_group_t, int);
+
+static int smb_enable_service(void);
+
+static int range_check_validator(int, char *);
+static int range_check_validator_zero_ok(int, char *);
+static int string_length_check_validator(int, char *);
+static int true_false_validator(int, char *);
+static int ip_address_validator_empty_ok(int, char *);
+static int ip_address_csv_list_validator_empty_ok(int, char *);
+static int ipc_mode_validator(int, char *);
+static int path_validator(int, char *);
+
+static int smb_enable_resource(sa_resource_t);
+static int smb_disable_resource(sa_resource_t);
+static uint64_t smb_share_features(void);
+static int smb_list_transient(sa_handle_t);
+
+/* size of basic format allocation */
+#define OPT_CHUNK 1024
+
+/*
+ * Indexes of entries in smb_proto_options table.
+ * Changes to smb_proto_options table may require
+ * an update to these values.
+ */
+#define PROTO_OPT_WINS1 6
+#define PROTO_OPT_WINS_EXCLUDE 8
+
+
+/*
+ * ops vector that provides the protocol specific info and operations
+ * for share management.
+ */
+
+struct sa_plugin_ops sa_plugin_ops = {
+ SA_PLUGIN_VERSION,
+ SMB_PROTOCOL_NAME,
+ smb_share_init,
+ smb_share_fini,
+ smb_enable_share,
+ smb_disable_share,
+ smb_validate_property,
+ NULL,
+ NULL,
+ smb_parse_optstring,
+ smb_format_options,
+ smb_set_proto_prop,
+ smb_get_proto_set,
+ smb_get_status,
+ NULL,
+ NULL,
+ NULL,
+ smb_share_changed,
+ smb_enable_resource,
+ smb_disable_resource,
+ smb_share_features,
+ smb_list_transient,
+ smb_resource_changed,
+ smb_rename_resource,
+ NULL,
+ NULL
+};
+
+/*
+ * option definitions. Make sure to keep the #define for the option
+ * index just before the entry it is the index for. Changing the order
+ * can cause breakage.
+ */
+
+struct option_defs optdefs[] = {
+ {SHOPT_AD_CONTAINER, OPT_TYPE_STRING},
+ {SHOPT_NAME, OPT_TYPE_NAME},
+ {NULL, NULL},
+};
+
+/*
+ * findopt(name)
+ *
+ * Lookup option "name" in the option table and return the table
+ * index.
+ */
+
+static int
+findopt(char *name)
+{
+ int i;
+ if (name != NULL) {
+ for (i = 0; optdefs[i].tag != NULL; i++) {
+ if (strcmp(optdefs[i].tag, name) == 0)
+ return (i);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * is_a_number(number)
+ *
+ * is the string a number in one of the forms we want to use?
+ */
+
+static int
+is_a_number(char *number)
+{
+ int ret = 1;
+ int hex = 0;
+
+ if (strncmp(number, "0x", 2) == 0) {
+ number += 2;
+ hex = 1;
+ } else if (*number == '-') {
+ number++; /* skip the minus */
+ }
+
+ while (ret == 1 && *number != '\0') {
+ if (hex) {
+ ret = isxdigit(*number++);
+ } else {
+ ret = isdigit(*number++);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * validresource(name)
+ *
+ * Check that name only has valid characters in it. The current valid
+ * set are the printable characters but not including:
+ * " / \ [ ] : | < > + ; , ? * = \t
+ * Note that space is included and there is a maximum length.
+ */
+static int
+validresource(const char *name)
+{
+ const char *cp;
+ size_t len;
+
+ if (name == NULL)
+ return (B_FALSE);
+
+ len = strlen(name);
+ if (len == 0 || len > SA_MAX_RESOURCE_NAME)
+ return (B_FALSE);
+
+ if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
+ return (B_FALSE);
+ }
+
+ for (cp = name; *cp != '\0'; cp++)
+ if (iscntrl(*cp))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * smb_isonline()
+ *
+ * Determine if the SMF service instance is in the online state or
+ * not. A number of operations depend on this state.
+ */
+static boolean_t
+smb_isonline(void)
+{
+ char *str;
+ boolean_t ret = B_FALSE;
+
+ if ((str = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI)) != NULL) {
+ ret = (strcmp(str, SCF_STATE_STRING_ONLINE) == 0);
+ free(str);
+ }
+ return (ret);
+}
+
+/*
+ * smb_enable_share tells the implementation that it is to enable the share.
+ * This entails converting the path and options into the appropriate ioctl
+ * calls. It is assumed that all error checking of paths, etc. were
+ * done earlier.
+ */
+static int
+smb_enable_share(sa_share_t share)
+{
+ char *path;
+ char *rname;
+ lmshare_info_t si;
+ sa_resource_t resource;
+ boolean_t iszfs;
+ boolean_t privileged;
+ int err = SA_OK;
+ priv_set_t *priv_effective;
+ boolean_t online;
+
+ priv_effective = priv_allocset();
+ (void) getppriv(PRIV_EFFECTIVE, priv_effective);
+ privileged = (priv_isfullset(priv_effective) == B_TRUE);
+ priv_freeset(priv_effective);
+
+ /* get the path since it is important in several places */
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (SA_NO_SUCH_PATH);
+
+ online = smb_isonline();
+
+ iszfs = sa_path_is_zfs(path);
+
+ if (iszfs) {
+
+ if (privileged == B_FALSE && !online) {
+
+ if (!online) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "SMB: Cannot share remove "
+ "file system: %s\n"), path);
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "SMB: Service needs to be enabled "
+ "by a privileged user\n"));
+ err = SA_NO_PERMISSION;
+ errno = EPERM;
+ }
+ if (err) {
+ sa_free_attr_string(path);
+ return (err);
+ }
+
+ }
+ }
+
+ if (privileged == B_TRUE && !online) {
+ err = smb_enable_service();
+ if (err != SA_OK) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "SMB: Unable to enable service\n"));
+ /*
+ * For now, it is OK to not be able to enable
+ * the service.
+ */
+ if (err == SA_BUSY)
+ err = SA_OK;
+ } else {
+ online = B_TRUE;
+ }
+ }
+
+ /*
+ * Don't bother trying to start shares if the service isn't
+ * running.
+ */
+ if (!online)
+ goto done;
+
+ /* Each share can have multiple resources */
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ sa_optionset_t opts;
+ bzero(&si, sizeof (lmshare_info_t));
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL) {
+ sa_free_attr_string(path);
+ return (SA_NO_SUCH_RESOURCE);
+ }
+
+ opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
+ smb_build_lmshare_info(rname, path, opts, &si);
+ sa_free_attr_string(rname);
+
+ sa_free_derived_optionset(opts);
+ if (!iszfs) {
+ err = lmshrd_add(&si);
+ } else {
+ share_t sh;
+
+ sa_sharetab_fill_zfs(share, &sh, "smb");
+ err = sa_share_zfs(share, (char *)path, &sh,
+ &si, ZFS_SHARE_SMB);
+
+ sa_emptyshare(&sh);
+ }
+ }
+ if (!iszfs)
+ (void) sa_update_sharetab(share, "smb");
+done:
+ sa_free_attr_string(path);
+
+ return (err == NERR_DuplicateShare ? 0 : err);
+}
+
+/*
+ * This is the share for CIFS all shares have resource names.
+ * Enable tells the smb server to update its hash. If it fails
+ * because smb server is down, we just ignore as smb server loads
+ * the resources from sharemanager at startup.
+ */
+
+static int
+smb_enable_resource(sa_resource_t resource)
+{
+ char *path;
+ char *rname;
+ sa_optionset_t opts;
+ sa_share_t share;
+ lmshare_info_t si;
+ int ret;
+
+ share = sa_get_resource_parent(resource);
+ if (share == NULL)
+ return (SA_NO_SUCH_PATH);
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (SA_SYSTEM_ERR);
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL) {
+ sa_free_attr_string(path);
+ return (SA_NO_SUCH_RESOURCE);
+ }
+
+ ret = smb_enable_service();
+
+ if (!smb_isonline()) {
+ ret = SA_OK;
+ goto done;
+ }
+
+ opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
+ smb_build_lmshare_info(rname, path, opts, &si);
+ sa_free_attr_string(path);
+ sa_free_attr_string(rname);
+ sa_free_derived_optionset(opts);
+ if (lmshrd_add(&si) != NERR_Success)
+ return (SA_NOT_SHARED);
+ (void) sa_update_sharetab(share, "smb");
+
+done:
+ return (ret);
+}
+
+/*
+ * Remove it from smb server hash.
+ */
+static int
+smb_disable_resource(sa_resource_t resource)
+{
+ char *rname;
+ DWORD res;
+ sa_share_t share;
+
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL)
+ return (SA_NO_SUCH_RESOURCE);
+
+ if (smb_isonline()) {
+ res = lmshrd_delete(rname);
+ if (res != NERR_Success) {
+ sa_free_attr_string(rname);
+ return (SA_CONFIG_ERR);
+ }
+ sa_free_attr_string(rname);
+ rname = NULL;
+ }
+ share = sa_get_resource_parent(resource);
+ if (share != NULL) {
+ rname = sa_get_share_attr(share, "path");
+ if (rname != NULL) {
+ (void) sa_delete_sharetab(rname, "smb");
+ sa_free_attr_string(rname);
+ rname = NULL;
+ }
+ }
+ if (rname != NULL)
+ sa_free_attr_string(rname);
+ /*
+ * Always return OK as smb/server may be down and
+ * Shares will be picked up when loaded.
+ */
+ return (SA_OK);
+}
+
+/*
+ * smb_share_changed(sa_share_t share)
+ *
+ * The specified share has changed.
+ */
+static int
+smb_share_changed(sa_share_t share)
+{
+ char *path;
+ sa_resource_t resource;
+
+ /* get the path since it is important in several places */
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (SA_NO_SUCH_PATH);
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource))
+ (void) smb_resource_changed(resource);
+
+ sa_free_attr_string(path);
+
+ return (SA_OK);
+}
+
+/*
+ * smb_resource_changed(sa_resource_t resource)
+ *
+ * The specified resource has changed.
+ */
+static int
+smb_resource_changed(sa_resource_t resource)
+{
+ DWORD res;
+ lmshare_info_t si;
+ lmshare_info_t new_si;
+ char *rname, *path;
+ sa_optionset_t opts;
+ sa_share_t share;
+
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL)
+ return (SA_NO_SUCH_RESOURCE);
+
+ share = sa_get_resource_parent(resource);
+ if (share == NULL) {
+ sa_free_attr_string(rname);
+ return (SA_CONFIG_ERR);
+ }
+
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL) {
+ sa_free_attr_string(rname);
+ return (SA_NO_SUCH_PATH);
+ }
+
+ if (!smb_isonline()) {
+ sa_free_attr_string(rname);
+ return (SA_OK);
+ }
+
+ /* Update the share cache in smb/server */
+ res = lmshrd_getinfo(rname, &si);
+ if (res != NERR_Success) {
+ sa_free_attr_string(path);
+ sa_free_attr_string(rname);
+ return (SA_CONFIG_ERR);
+ }
+
+ opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
+ smb_build_lmshare_info(rname, path, opts, &new_si);
+ sa_free_derived_optionset(opts);
+ sa_free_attr_string(path);
+ sa_free_attr_string(rname);
+
+ /*
+ * Update all fields from sa_share_t
+ * Get derived values.
+ */
+ if (lmshrd_setinfo(&new_si) != LMSHR_DOOR_SRV_SUCCESS)
+ return (SA_CONFIG_ERR);
+ return (smb_enable_service());
+}
+
+/*
+ * smb_disable_share(sa_share_t share)
+ *
+ * Unshare the specified share.
+ */
+static int
+smb_disable_share(sa_share_t share, char *path)
+{
+ char *rname;
+ sa_resource_t resource;
+ boolean_t iszfs;
+ int err = SA_OK;
+
+ iszfs = sa_path_is_zfs(path);
+ if (!smb_isonline())
+ goto done;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL) {
+ continue;
+ }
+ if (!iszfs) {
+ err = lmshrd_delete(rname);
+ switch (err) {
+ case NERR_NetNameNotFound:
+ case NERR_Success:
+ err = SA_OK;
+ break;
+ default:
+ err = SA_CONFIG_ERR;
+ break;
+ }
+ } else {
+ share_t sh;
+
+ sa_sharetab_fill_zfs(share, &sh, "smb");
+ err = sa_share_zfs(share, (char *)path, &sh,
+ rname, ZFS_UNSHARE_SMB);
+ sa_emptyshare(&sh);
+ }
+ sa_free_attr_string(rname);
+ }
+done:
+ if (!iszfs)
+ (void) sa_delete_sharetab(path, "smb");
+ return (err);
+}
+
+/*
+ * smb_validate_property(property, parent)
+ *
+ * Check that the property has a legitimate value for its type.
+ */
+
+static int
+smb_validate_property(sa_property_t property, sa_optionset_t parent)
+{
+ int ret = SA_OK;
+ char *propname;
+ int optindex;
+ sa_group_t parent_group;
+ char *value;
+
+ propname = sa_get_property_attr(property, "type");
+
+ if ((optindex = findopt(propname)) < 0)
+ ret = SA_NO_SUCH_PROP;
+
+ /* need to validate value range here as well */
+ if (ret == SA_OK) {
+ parent_group = sa_get_parent_group((sa_share_t)parent);
+ if (optdefs[optindex].share && !sa_is_share(parent_group))
+ ret = SA_PROP_SHARE_ONLY;
+ }
+ if (ret != SA_OK) {
+ if (propname != NULL)
+ sa_free_attr_string(propname);
+ return (ret);
+ }
+
+ value = sa_get_property_attr(property, "value");
+ if (value != NULL) {
+ /* first basic type checking */
+ switch (optdefs[optindex].type) {
+ case OPT_TYPE_NUMBER:
+ /* check that the value is all digits */
+ if (!is_a_number(value))
+ ret = SA_BAD_VALUE;
+ break;
+ case OPT_TYPE_BOOLEAN:
+ if (strlen(value) == 0 ||
+ strcasecmp(value, "true") == 0 ||
+ strcmp(value, "1") == 0 ||
+ strcasecmp(value, "false") == 0 ||
+ strcmp(value, "0") == 0) {
+ ret = SA_OK;
+ } else {
+ ret = SA_BAD_VALUE;
+ }
+ break;
+ case OPT_TYPE_NAME:
+ /*
+ * Make sure no invalid characters
+ */
+ if (validresource(value) == B_FALSE)
+ ret = SA_BAD_VALUE;
+ break;
+ case OPT_TYPE_STRING:
+ /* whatever is here should be ok */
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (value != NULL)
+ sa_free_attr_string(value);
+ if (ret == SA_OK && optdefs[optindex].check != NULL)
+ /* do the property specific check */
+ ret = optdefs[optindex].check(property);
+
+ if (propname != NULL)
+ sa_free_attr_string(propname);
+ return (ret);
+}
+
+/*
+ * Protocol management functions
+ *
+ * properties defined in the default files are defined in
+ * proto_option_defs for parsing and validation.
+ */
+
+struct smb_proto_option_defs {
+ char *name; /* display name -- remove protocol identifier */
+ int smb_index;
+ int32_t minval;
+ int32_t maxval; /* In case of length of string this should be max */
+ int (*validator)(int, char *);
+ int32_t refresh;
+} smb_proto_options[] = {
+ { SMB_CD_SYS_CMNT,
+ SMB_CI_SYS_CMNT, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_MAX_WORKERS,
+ SMB_CI_MAX_WORKERS, 64, 1024, range_check_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_NBSCOPE,
+ SMB_CI_NBSCOPE, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_RDR_IPCMODE,
+ SMB_CI_RDR_IPCMODE, 0, 0, ipc_mode_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_LM_LEVEL,
+ SMB_CI_LM_LEVEL, 2, 5, range_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_KEEPALIVE,
+ SMB_CI_KEEPALIVE, 20, 5400, range_check_validator_zero_ok,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_WINS_SRV1,
+ SMB_CI_WINS_SRV1, 0, MAX_VALUE_BUFLEN,
+ ip_address_validator_empty_ok, SMB_REFRESH_REFRESH},
+ { SMB_CD_WINS_SRV2,
+ SMB_CI_WINS_SRV2, 0, MAX_VALUE_BUFLEN,
+ ip_address_validator_empty_ok, SMB_REFRESH_REFRESH},
+ { SMB_CD_WINS_EXCL,
+ SMB_CI_WINS_EXCL, 0, MAX_VALUE_BUFLEN,
+ ip_address_csv_list_validator_empty_ok, SMB_REFRESH_REFRESH},
+ { SMB_CD_SIGNING_ENABLE,
+ SMB_CI_SIGNING_ENABLE, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_SIGNING_REQD,
+ SMB_CI_SIGNING_REQD, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_RESTRICT_ANON,
+ SMB_CI_RESTRICT_ANON, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_DOMAIN_SRV,
+ SMB_CI_DOMAIN_SRV, 0, MAX_VALUE_BUFLEN,
+ ip_address_validator_empty_ok, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_ENABLE,
+ SMB_CI_ADS_ENABLE, 0, 0, true_false_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_USER,
+ SMB_CI_ADS_USER, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_USER_CONTAINER,
+ SMB_CI_ADS_USER_CONTAINER, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_DOMAIN,
+ SMB_CI_ADS_DOMAIN, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_PASSWD,
+ SMB_CI_ADS_PASSWD, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_IPLOOKUP,
+ SMB_CI_ADS_IPLOOKUP, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_SITE,
+ SMB_CI_ADS_SITE, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_DYNDNS_ENABLE,
+ SMB_CI_DYNDNS_ENABLE, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_DYNDNS_RETRY_SEC,
+ SMB_CI_DYNDNS_RETRY_SEC, 0, 20, range_check_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_DYNDNS_RETRY_COUNT,
+ SMB_CI_DYNDNS_RETRY_COUNT, 3, 5, range_check_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_AUTOHOME_MAP,
+ SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN,
+ path_validator},
+ {NULL, -1, 0, 0, NULL}
+};
+
+/*
+ * Check the range of value as int range.
+ */
+static int
+range_check_validator(int index, char *value)
+{
+ int ret = SA_OK;
+
+ if (!is_a_number(value)) {
+ ret = SA_BAD_VALUE;
+ } else {
+ int val;
+ val = strtoul(value, NULL, 0);
+ if (val < smb_proto_options[index].minval ||
+ val > smb_proto_options[index].maxval)
+ ret = SA_BAD_VALUE;
+ }
+ return (ret);
+}
+
+/*
+ * Check the range of value as int range.
+ */
+static int
+range_check_validator_zero_ok(int index, char *value)
+{
+ int ret = SA_OK;
+
+ if (!is_a_number(value)) {
+ ret = SA_BAD_VALUE;
+ } else {
+ int val;
+ val = strtoul(value, NULL, 0);
+ if (val == 0)
+ ret = SA_OK;
+ else {
+ if (val < smb_proto_options[index].minval ||
+ val > smb_proto_options[index].maxval)
+ ret = SA_BAD_VALUE;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * Check the length of the string
+ */
+static int
+string_length_check_validator(int index, char *value)
+{
+ int ret = SA_OK;
+
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ if (strlen(value) > smb_proto_options[index].maxval)
+ ret = SA_BAD_VALUE;
+ return (ret);
+}
+
+/*
+ * Check yes/no
+ */
+/*ARGSUSED*/
+static int
+true_false_validator(int index, char *value)
+{
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ if ((strcasecmp(value, "true") == 0) ||
+ (strcasecmp(value, "false") == 0))
+ return (SA_OK);
+ return (SA_BAD_VALUE);
+}
+
+/*
+ * Check IP address.
+ */
+/*ARGSUSED*/
+static int
+ip_address_validator_empty_ok(int index, char *value)
+{
+ char sbytes[16];
+ int len;
+
+ if (value == NULL)
+ return (SA_OK);
+ len = strlen(value);
+ if (len == 0)
+ return (SA_OK);
+ if (inet_pton(AF_INET, value, (void *)sbytes) != 1)
+ return (SA_BAD_VALUE);
+
+ return (SA_OK);
+}
+
+/*
+ * Check IP address list
+ */
+/*ARGSUSED*/
+static int
+ip_address_csv_list_validator_empty_ok(int index, char *value)
+{
+ char sbytes[16];
+ char *ip, *tmp, *ctx;
+
+ if (value == NULL || *value == '\0')
+ return (SA_OK);
+
+ if (strlen(value) > MAX_VALUE_BUFLEN)
+ return (SA_BAD_VALUE);
+
+ if ((tmp = strdup(value)) == NULL)
+ return (SA_NO_MEMORY);
+
+ ip = strtok_r(tmp, ",", &ctx);
+ while (ip) {
+ if (strlen(ip) == 0) {
+ free(tmp);
+ return (SA_BAD_VALUE);
+ }
+ if (*ip != 0) {
+ if (inet_pton(AF_INET, ip,
+ (void *)sbytes) != 1) {
+ free(tmp);
+ return (SA_BAD_VALUE);
+ }
+ }
+ ip = strtok_r(0, ",", &ctx);
+ }
+
+ free(tmp);
+ return (SA_OK);
+}
+
+/*
+ * Check IPC mode
+ */
+/*ARGSUSED*/
+static int
+ipc_mode_validator(int index, char *value)
+{
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ if (strcasecmp(value, "anon") == 0)
+ return (SA_OK);
+ if (strcasecmp(value, "auth") == 0)
+ return (SA_OK);
+ return (SA_BAD_VALUE);
+}
+
+/*
+ * Check path
+ */
+/*ARGSUSED*/
+static int
+path_validator(int index, char *value)
+{
+ struct stat buffer;
+ int fd, status;
+
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+
+ fd = open(value, O_RDONLY);
+ if (fd < 0)
+ return (SA_BAD_VALUE);
+
+ status = fstat(fd, &buffer);
+ (void) close(fd);
+
+ if (status < 0)
+ return (SA_BAD_VALUE);
+
+ if (buffer.st_mode & S_IFDIR)
+ return (SA_OK);
+ return (SA_BAD_VALUE);
+}
+
+/*
+ * the protoset holds the defined options so we don't have to read
+ * them multiple times
+ */
+static sa_protocol_properties_t protoset;
+
+static int
+findprotoopt(char *name)
+{
+ int i;
+ for (i = 0; smb_proto_options[i].name != NULL; i++) {
+ if (strcasecmp(smb_proto_options[i].name, name) == 0)
+ return (i);
+ }
+ return (-1);
+}
+
+/*
+ * smb_load_proto_properties()
+ *
+ * read the smb config values from SMF.
+ */
+
+static int
+smb_load_proto_properties()
+{
+ sa_property_t prop;
+ int index;
+ char *value;
+
+ protoset = sa_create_protocol_properties(SMB_PROTOCOL_NAME);
+ if (protoset == NULL)
+ return (SA_NO_MEMORY);
+
+ if (smb_config_load() != 0)
+ return (SA_CONFIG_ERR);
+ for (index = 0; smb_proto_options[index].name != NULL; index++) {
+ value = smb_config_getenv(smb_proto_options[index].smb_index);
+ prop = sa_create_property(
+ smb_proto_options[index].name, value);
+ (void) sa_add_protocol_property(protoset, prop);
+ }
+ return (SA_OK);
+}
+
+/*
+ * smb_share_init()
+ *
+ * Initialize the smb plugin.
+ */
+
+static int
+smb_share_init(void)
+{
+ int ret = SA_OK;
+
+ if (sa_plugin_ops.sa_init != smb_share_init)
+ return (SA_SYSTEM_ERR);
+
+ if (smb_load_proto_properties() != SA_OK)
+ return (SA_SYSTEM_ERR);
+
+ return (ret);
+}
+
+/*
+ * smb_share_fini()
+ *
+ */
+static void
+smb_share_fini(void)
+{
+ xmlFreeNode(protoset);
+ protoset = NULL;
+}
+
+/*
+ * smb_get_proto_set()
+ *
+ * Return an optionset with all the protocol specific properties in
+ * it.
+ */
+static sa_protocol_properties_t
+smb_get_proto_set(void)
+{
+ return (protoset);
+}
+
+/*
+ * How long to wait for service to come online
+ */
+#define WAIT_FOR_SERVICE 15
+
+/*
+ * smb_enable_service()
+ *
+ */
+static int
+smb_enable_service(void)
+{
+ int i;
+ int ret = SA_OK;
+
+ if (!smb_isonline()) {
+ if (smf_enable_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0) != 0) {
+ (void) fprintf(stderr,
+ dgettext(TEXT_DOMAIN,
+ "%s failed to restart: %s\n"),
+ scf_strerror(scf_error()));
+ return (SA_CONFIG_ERR);
+ }
+
+ /* Wait for service to come online */
+ for (i = 0; i < WAIT_FOR_SERVICE; i++) {
+ if (smb_isonline()) {
+ ret = SA_OK;
+ break;
+ } else {
+ ret = SA_BUSY;
+ (void) sleep(1);
+ }
+ }
+ }
+ return (ret);
+}
+
+/*
+ * smb_validate_proto_prop(index, name, value)
+ *
+ * Verify that the property specified by name can take the new
+ * value. This is a sanity check to prevent bad values getting into
+ * the default files.
+ */
+static int
+smb_validate_proto_prop(int index, char *name, char *value)
+{
+ if ((name == NULL) || (index < 0))
+ return (SA_BAD_VALUE);
+
+ if (smb_proto_options[index].validator == NULL)
+ return (SA_OK);
+
+ if (smb_proto_options[index].validator(index, value) == SA_OK)
+ return (SA_OK);
+ return (SA_BAD_VALUE);
+}
+
+/*
+ * smb_set_proto_prop(prop)
+ *
+ * check that prop is valid.
+ */
+/*ARGSUSED*/
+static int
+smb_set_proto_prop(sa_property_t prop)
+{
+ int ret = SA_OK;
+ char *name;
+ char *value;
+ int index = -1;
+
+ name = sa_get_property_attr(prop, "type");
+ value = sa_get_property_attr(prop, "value");
+ if (name != NULL && value != NULL) {
+ index = findprotoopt(name);
+ if (index >= 0) {
+ /* should test for valid value */
+ ret = smb_validate_proto_prop(index, name, value);
+ if (ret == SA_OK) {
+ /* Save to SMF */
+ smb_config_setenv(
+ smb_proto_options[index].smb_index, value);
+ /*
+ * Specialized refresh mechanisms can
+ * be flagged in the proto_options and
+ * processed here.
+ */
+ if (smb_proto_options[index].refresh &
+ SMB_REFRESH_REFRESH)
+ (void) smf_refresh_instance(
+ SMBD_DEFAULT_INSTANCE_FMRI);
+ else if (smb_proto_options[index].refresh &
+ SMB_REFRESH_RESTART)
+ (void) smf_restart_instance(
+ SMBD_DEFAULT_INSTANCE_FMRI);
+ }
+ }
+ }
+ if (name != NULL)
+ sa_free_attr_string(name);
+ if (value != NULL)
+ sa_free_attr_string(value);
+
+ return (ret);
+}
+
+/*
+ * smb_get_status()
+ *
+ * What is the current status of the smbd? We use the SMF state here.
+ * Caller must free the returned value.
+ */
+
+static char *
+smb_get_status(void)
+{
+ char *state = NULL;
+ state = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI);
+ return (state != NULL ? state : "-");
+}
+
+/*
+ * This protocol plugin require resource names
+ */
+static uint64_t
+smb_share_features(void)
+{
+ return (SA_FEATURE_RESOURCE | SA_FEATURE_ALLOWSUBDIRS |
+ SA_FEATURE_ALLOWPARDIRS);
+}
+
+/*
+ * This should be used to convert lmshare_info to sa_resource_t
+ * Should only be needed to build temp shares/resources to be
+ * supplied to sharemanager to display temp shares.
+ */
+static int
+smb_build_tmp_sa_resource(sa_handle_t handle, lmshare_info_t *si)
+{
+ int err;
+ sa_share_t share;
+ sa_group_t group;
+ sa_resource_t resource;
+
+ if (si == NULL)
+ return (SA_INVALID_NAME);
+
+ /*
+ * First determine if the "share path" is already shared
+ * somewhere. If it is, we have to use it as the authority on
+ * where the transient share lives so will use it's parent
+ * group. If it doesn't exist, it needs to land in "smb".
+ */
+
+ share = sa_find_share(handle, si->directory);
+ if (share != NULL) {
+ group = sa_get_parent_group(share);
+ } else {
+ group = smb_get_smb_share_group(handle);
+ if (group == NULL)
+ return (SA_NO_SUCH_GROUP);
+ share = sa_get_share(group, si->directory);
+ if (share == NULL) {
+ share = sa_add_share(group, si->directory,
+ SA_SHARE_TRANSIENT, &err);
+ if (share == NULL)
+ return (SA_NO_SUCH_PATH);
+ }
+ }
+
+ /*
+ * Now handle the resource. Make sure that the resource is
+ * transient and added to the share.
+ */
+ resource = sa_get_share_resource(share, si->share_name);
+ if (resource == NULL) {
+ resource = sa_add_resource(share,
+ si->share_name, SA_SHARE_TRANSIENT, &err);
+ if (resource == NULL)
+ return (SA_NO_SUCH_RESOURCE);
+ }
+
+ /* set resource attributes now */
+ (void) sa_set_resource_attr(resource, "description", si->comment);
+ (void) sa_set_resource_attr(resource, SHOPT_AD_CONTAINER,
+ si->container);
+
+ return (SA_OK);
+}
+
+/*
+ * Return smb transient shares. Note that we really want to look at
+ * all current shares from SMB in order to determine this. Transient
+ * shares should be those that don't appear in either the SMF or ZFS
+ * configurations. Those that are in the repositories will be
+ * filtered out by smb_build_tmp_sa_resource.
+ */
+static int
+smb_list_transient(sa_handle_t handle)
+{
+ int i, offset, num;
+ lmshare_list_t list;
+ int res;
+
+ num = lmshrd_num_shares();
+ if (num <= 0)
+ return (SA_OK);
+ offset = 0;
+ while (lmshrd_list(offset, &list) != NERR_InternalError) {
+ if (list.no == 0)
+ break;
+ for (i = 0; i < list.no; i++) {
+ res = smb_build_tmp_sa_resource(handle,
+ &(list.smbshr[i]));
+ if (res != SA_OK)
+ return (res);
+ }
+ offset += list.no;
+ }
+
+ return (SA_OK);
+}
+
+/*
+ * fix_resource_name(share, name, prefix)
+ *
+ * Construct a name where the ZFS dataset has the prefix replaced with "name".
+ */
+static char *
+fix_resource_name(sa_share_t share, char *name, char *prefix)
+{
+ char *dataset = NULL;
+ char *newname = NULL;
+ size_t psize;
+ size_t nsize;
+
+ dataset = sa_get_share_attr(share, "dataset");
+
+ if (dataset != NULL && strcmp(dataset, prefix) != 0) {
+ psize = strlen(prefix);
+ if (strncmp(dataset, prefix, psize) == 0) {
+ /* need string plus ',' and NULL */
+ nsize = (strlen(dataset) - psize) + strlen(name) + 2;
+ newname = calloc(nsize, 1);
+ if (newname != NULL) {
+ (void) snprintf(newname, nsize, "%s%s", name,
+ dataset + psize);
+ sa_fix_resource_name(newname);
+ }
+ sa_free_attr_string(dataset);
+ return (newname);
+ }
+ }
+ if (dataset != NULL)
+ sa_free_attr_string(dataset);
+ return (strdup(name));
+}
+
+/*
+ * smb_parse_optstring(group, options)
+ *
+ * parse a compact option string into individual options. This allows
+ * ZFS sharesmb and sharemgr "share" command to work. group can be a
+ * group, a share or a resource.
+ */
+static int
+smb_parse_optstring(sa_group_t group, char *options)
+{
+ char *dup;
+ char *base;
+ char *lasts;
+ char *token;
+ sa_optionset_t optionset;
+ sa_group_t parent = NULL;
+ sa_resource_t resource = NULL;
+ int iszfs = 0;
+ int persist = 0;
+ int need_optionset = 0;
+ int ret = SA_OK;
+ sa_property_t prop;
+
+ /*
+ * In order to not attempt to change ZFS properties unless
+ * absolutely necessary, we never do it in the legacy parsing
+ * so we need to keep track of this.
+ */
+ if (sa_is_share(group)) {
+ char *zfs;
+
+ parent = sa_get_parent_group(group);
+ if (parent != NULL) {
+ zfs = sa_get_group_attr(parent, "zfs");
+ if (zfs != NULL) {
+ sa_free_attr_string(zfs);
+ iszfs = 1;
+ }
+ }
+ } else {
+ iszfs = sa_group_is_zfs(group);
+ /*
+ * If a ZFS group, then we need to see if a resource
+ * name is being set. If so, bail with
+ * SA_PROP_SHARE_ONLY, so we come back in with a share
+ * instead of a group.
+ */
+ if (strncmp(options, "name=", sizeof ("name=") - 1) == 0 ||
+ strstr(options, ",name=") != NULL) {
+ return (SA_PROP_SHARE_ONLY);
+ }
+ }
+
+ /* do we have an existing optionset? */
+ optionset = sa_get_optionset(group, "smb");
+ if (optionset == NULL) {
+ /* didn't find existing optionset so create one */
+ optionset = sa_create_optionset(group, "smb");
+ if (optionset == NULL)
+ return (SA_NO_MEMORY);
+ } else {
+ /*
+ * If an optionset already exists, we've come through
+ * twice so ignore the second time.
+ */
+ return (ret);
+ }
+
+ /* We need a copy of options for the next part. */
+ dup = strdup(options);
+ if (dup == NULL)
+ return (SA_NO_MEMORY);
+
+ /*
+ * SMB properties are straightforward and are strings,
+ * integers or booleans. Properties are separated by
+ * commas. It will be necessary to parse quotes due to some
+ * strings not having a restricted characters set.
+ *
+ * Note that names will create a resource. For now, if there
+ * is a set of properties "before" the first name="", those
+ * properties will be placed on the group.
+ */
+ persist = sa_is_persistent(group);
+ base = dup;
+ token = dup;
+ lasts = NULL;
+ while (token != NULL && ret == SA_OK) {
+ ret = SA_OK;
+ token = strtok_r(base, ",", &lasts);
+ base = NULL;
+ if (token != NULL) {
+ char *value;
+ /*
+ * All SMB properties have values so there
+ * MUST be an '=' character. If it doesn't,
+ * it is a syntax error.
+ */
+ value = strchr(token, '=');
+ if (value != NULL) {
+ *value++ = '\0';
+ } else {
+ ret = SA_SYNTAX_ERR;
+ break;
+ }
+ /*
+ * We may need to handle a "name" property
+ * that is a ZFS imposed resource name. Each
+ * name would trigger getting a new "resource"
+ * to put properties on. For now, assume no
+ * "name" property for special handling.
+ */
+
+ if (strcmp(token, "name") == 0) {
+ char *prefix;
+ char *name = NULL;
+ /*
+ * We have a name, so now work on the
+ * resource level. We have a "share"
+ * in "group" due to the caller having
+ * added it. If we are called with a
+ * group, the check for group/share
+ * at the beginning of this function
+ * will bail out the parse if there is a
+ * "name" but no share.
+ */
+ if (!iszfs) {
+ ret = SA_SYNTAX_ERR;
+ break;
+ }
+ /*
+ * Make sure the parent group has the
+ * "prefix" property since we will
+ * need to use this for constructing
+ * inherited name= values.
+ */
+ prefix = sa_get_group_attr(parent, "prefix");
+ if (prefix == NULL) {
+ prefix = sa_get_group_attr(parent,
+ "name");
+ if (prefix != NULL) {
+ (void) sa_set_group_attr(parent,
+ "prefix", prefix);
+ }
+ }
+ name = fix_resource_name((sa_share_t)group,
+ value, prefix);
+ if (name != NULL) {
+ resource = sa_add_resource(
+ (sa_share_t)group, name,
+ SA_SHARE_TRANSIENT, &ret);
+ sa_free_attr_string(name);
+ } else {
+ ret = SA_NO_MEMORY;
+ }
+ if (prefix != NULL)
+ sa_free_attr_string(prefix);
+
+ /* A resource level optionset is needed */
+
+ need_optionset = 1;
+ if (resource == NULL) {
+ ret = SA_NO_MEMORY;
+ break;
+ }
+ continue;
+ }
+
+ if (need_optionset) {
+ optionset = sa_create_optionset(resource,
+ "smb");
+ need_optionset = 0;
+ }
+
+ prop = sa_create_property(token, value);
+ if (prop == NULL)
+ ret = SA_NO_MEMORY;
+ else
+ ret = sa_add_property(optionset, prop);
+ if (ret != SA_OK)
+ break;
+ if (!iszfs)
+ ret = sa_commit_properties(optionset, !persist);
+ }
+ }
+ free(dup);
+ return (ret);
+}
+
+/*
+ * smb_sprint_option(rbuff, rbuffsize, incr, prop, sep)
+ *
+ * provides a mechanism to format SMB properties into legacy output
+ * format. If the buffer would overflow, it is reallocated and grown
+ * as appropriate. Special cases of converting internal form of values
+ * to those used by "share" are done. this function does one property
+ * at a time.
+ */
+
+static void
+smb_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr,
+ sa_property_t prop, int sep)
+{
+ char *name;
+ char *value;
+ int curlen;
+ char *buff = *rbuff;
+ size_t buffsize = *rbuffsize;
+
+ name = sa_get_property_attr(prop, "type");
+ value = sa_get_property_attr(prop, "value");
+ if (buff != NULL)
+ curlen = strlen(buff);
+ else
+ curlen = 0;
+ if (name != NULL) {
+ int len;
+ len = strlen(name) + sep;
+
+ /*
+ * A future RFE would be to replace this with more
+ * generic code and to possibly handle more types.
+ *
+ * For now, everything else is treated as a string. If
+ * we get any properties that aren't exactly
+ * name/value pairs, we may need to
+ * interpret/transform.
+ */
+ if (value != NULL)
+ len += 1 + strlen(value);
+
+ while (buffsize <= (curlen + len)) {
+ /* need more room */
+ buffsize += incr;
+ buff = realloc(buff, buffsize);
+ *rbuff = buff;
+ *rbuffsize = buffsize;
+ if (buff == NULL) {
+ /* realloc failed so free everything */
+ if (*rbuff != NULL)
+ free(*rbuff);
+ goto err;
+ }
+ }
+ if (buff == NULL)
+ goto err;
+ (void) snprintf(buff + curlen, buffsize - curlen,
+ "%s%s=%s", sep ? "," : "",
+ name, value != NULL ? value : "\"\"");
+
+ }
+err:
+ if (name != NULL)
+ sa_free_attr_string(name);
+ if (value != NULL)
+ sa_free_attr_string(value);
+}
+
+/*
+ * smb_format_resource_options(resource, hier)
+ *
+ * format all the options on the group into a flattened option
+ * string. If hier is non-zero, walk up the tree to get inherited
+ * options.
+ */
+
+static char *
+smb_format_options(sa_group_t group, int hier)
+{
+ sa_optionset_t options = NULL;
+ sa_property_t prop;
+ int sep = 0;
+ char *buff;
+ size_t buffsize;
+
+
+ buff = malloc(OPT_CHUNK);
+ if (buff == NULL)
+ return (NULL);
+
+ buff[0] = '\0';
+ buffsize = OPT_CHUNK;
+
+ /*
+ * We may have a an optionset relative to this item. format
+ * these if we find them and then add any security definitions.
+ */
+
+ options = sa_get_derived_optionset(group, "smb", hier);
+
+ /*
+ * do the default set first but skip any option that is also
+ * in the protocol specific optionset.
+ */
+ if (options != NULL) {
+ for (prop = sa_get_property(options, NULL);
+ prop != NULL; prop = sa_get_next_property(prop)) {
+ /*
+ * use this one since we skipped any
+ * of these that were also in
+ * optdefault
+ */
+ smb_sprint_option(&buff, &buffsize, OPT_CHUNK,
+ prop, sep);
+ if (buff == NULL) {
+ /*
+ * buff could become NULL if there
+ * isn't enough memory for
+ * smb_sprint_option to realloc()
+ * as necessary. We can't really
+ * do anything about it at this
+ * point so we return NULL. The
+ * caller should handle the
+ * failure.
+ */
+ if (options != NULL)
+ sa_free_derived_optionset(
+ options);
+ return (buff);
+ }
+ sep = 1;
+ }
+ }
+
+ if (options != NULL)
+ sa_free_derived_optionset(options);
+ return (buff);
+}
+
+/*
+ * smb_rename_resource(resource, newname)
+ *
+ * Change the current exported name of the resource to newname.
+ */
+/*ARGSUSED*/
+int
+smb_rename_resource(sa_handle_t handle, sa_resource_t resource, char *newname)
+{
+ int ret = SA_OK;
+ int err;
+ char *oldname;
+
+ oldname = sa_get_resource_attr(resource, "name");
+ if (oldname == NULL)
+ return (SA_NO_SUCH_RESOURCE);
+
+ err = lmshrd_rename(oldname, newname);
+
+ /* improve error values somewhat */
+ switch (err) {
+ case NERR_Success:
+ break;
+ case NERR_InternalError:
+ ret = SA_SYSTEM_ERR;
+ break;
+ case NERR_DuplicateShare:
+ ret = SA_DUPLICATE_NAME;
+ break;
+ default:
+ ret = SA_CONFIG_ERR;
+ break;
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libshare/smb/libshare_smb.h b/usr/src/lib/libshare/smb/libshare_smb.h
new file mode 100644
index 0000000000..2d86c9ed32
--- /dev/null
+++ b/usr/src/lib/libshare/smb/libshare_smb.h
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * basic API declarations for share management
+ */
+
+#ifndef _LIBSHARE_SMB_H
+#define _LIBSHARE_SMB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <smbsrv/lmshare.h>
+
+/*
+ * defined options types. These should be in a file rather than
+ * compiled in. Until there is a plugin mechanism to add new types,
+ * this is sufficient.
+ */
+#define OPT_TYPE_ANY 0
+#define OPT_TYPE_STRING 1
+#define OPT_TYPE_BOOLEAN 2
+#define OPT_TYPE_NUMBER 3
+#define OPT_TYPE_PATH 4
+#define OPT_TYPE_PROTOCOL 5
+#define OPT_TYPE_NAME 6
+
+struct option_defs {
+ char *tag;
+ int type;
+ int share; /* share only option */
+ int (*check)(char *);
+};
+
+/*
+ * Sharectl property refresh types. Bit mask to indicate which type(s)
+ * of refresh might be needed on the service(s).
+ */
+
+#define SMB_REFRESH_RESTART 0x0001 /* restart smb/server */
+#define SMB_REFRESH_REFRESH 0x0002 /* refresh smb/server */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSHARE_SMB_H */
diff --git a/usr/src/lib/libshare/smb/mapfile-vers b/usr/src/lib/libshare/smb/mapfile-vers
new file mode 100644
index 0000000000..18c216bf6b
--- /dev/null
+++ b/usr/src/lib/libshare/smb/mapfile-vers
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ sa_plugin_ops;
+ local:
+ *;
+};
+
diff --git a/usr/src/lib/libshare/smb/smb_share_doorclnt.c b/usr/src/lib/libshare/smb/smb_share_doorclnt.c
new file mode 100644
index 0000000000..0ebf61b7a9
--- /dev/null
+++ b/usr/src/lib/libshare/smb/smb_share_doorclnt.c
@@ -0,0 +1,951 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * User-space door client for LanMan share management.
+ */
+
+#include <syslog.h>
+#include <door.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+
+#include <smbsrv/lmshare.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/cifs.h>
+
+int lmshrd_fildes = -1;
+
+char *lmshrd_desc[] = {
+ "",
+ "LmshrdOpenIter",
+ "LmshrdCloseIter",
+ "LmshrdIterate",
+ "LmshrdNumShares",
+ "LmshrdDelete",
+ "LmshrdRename",
+ "LmshrdGetinfo",
+ "LmshrdAdd",
+ "LmshrdSetinfo",
+ "LmshrdExists",
+ "LmshrdIsSpecial",
+ "LmshrdIsRestricted",
+ "LmshrdIsAdmin",
+ "LmshrdIsValid",
+ "LmshrdIsDir",
+ "LmshrdList",
+ "LmshrdListTrans",
+ "LmshrdNumTrans",
+ "N/A",
+ 0
+};
+
+/*
+ * Returns 0 on success. Otherwise, -1.
+ */
+static int
+lmshrd_door_open(int opcode)
+{
+ int rc = 0;
+
+ if (lmshrd_fildes == -1 &&
+ (lmshrd_fildes = open(LMSHR_DOOR_NAME, O_RDONLY)) < 0) {
+ syslog(LOG_DEBUG, "%s: open %s failed %s", lmshrd_desc[opcode],
+ LMSHR_DOOR_NAME, strerror(errno));
+ rc = -1;
+ }
+ return (rc);
+}
+
+/*
+ * Return 0 upon success. Otherwise, -1.
+ */
+static int
+lmshrd_door_check_srv_status(int opcode, smb_dr_ctx_t *dec_ctx)
+{
+ int status = smb_dr_get_int32(dec_ctx);
+ int err;
+ int rc = -1;
+
+ switch (status) {
+ case LMSHR_DOOR_SRV_SUCCESS:
+ rc = 0;
+ break;
+
+ case LMSHR_DOOR_SRV_ERROR:
+ err = smb_dr_get_uint32(dec_ctx);
+ syslog(LOG_ERR, "%s: Encountered door server error %s",
+ lmshrd_desc[opcode], strerror(err));
+ break;
+
+ default:
+ syslog(LOG_ERR, "%s: Unknown door server status",
+ lmshrd_desc[opcode]);
+ }
+
+ if (rc != 0) {
+ if ((err = smb_dr_decode_finish(dec_ctx)) != 0)
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(err));
+ }
+
+ return (rc);
+}
+
+uint64_t
+lmshrd_open_iterator(int mode)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ uint64_t lmshr_iter = 0;
+ int opcode = LMSHR_DOOR_OPEN_ITERATOR;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (lmshr_iter);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (lmshr_iter);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_int32(enc_ctx, mode);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (lmshr_iter);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (lmshr_iter);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (lmshr_iter);
+ }
+
+ lmshr_iter = smb_dr_get_lmshr_iterator(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (lmshr_iter);
+ }
+
+ (void) free(buf);
+ return (lmshr_iter);
+}
+
+
+DWORD
+lmshrd_close_iterator(uint64_t iterator)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ int opcode = LMSHR_DOOR_CLOSE_ITERATOR;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshr_iterator(enc_ctx, iterator);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (NERR_Success);
+}
+
+DWORD
+lmshrd_iterate(uint64_t iterator, lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ int opcode = LMSHR_DOOR_ITERATE;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ bzero(si, sizeof (lmshare_info_t));
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshr_iterator(enc_ctx, iterator);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (NERR_Success);
+}
+
+DWORD
+lmshrd_list(int offset, lmshare_list_t *list)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_LIST;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_int32(enc_ctx, offset);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ smb_dr_get_lmshr_list(dec_ctx, list);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+
+ return (rc);
+}
+
+int
+lmshrd_num_shares(void)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ DWORD num_shares;
+ int opcode = LMSHR_DOOR_NUM_SHARES;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (-1);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (-1);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_NUM_SHARES);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (-1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (-1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (-1);
+ }
+
+ num_shares = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (-1);
+ }
+
+ (void) free(buf);
+ return (num_shares);
+}
+
+DWORD
+lmshrd_delete(char *share_name)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_DELETE;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_DELETE);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+
+}
+
+DWORD
+lmshrd_rename(char *from, char *to)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_RENAME;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_RENAME);
+ smb_dr_put_string(enc_ctx, from);
+ smb_dr_put_string(enc_ctx, to);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+DWORD
+lmshrd_getinfo(char *share_name, lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_GETINFO;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_GETINFO);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+DWORD
+lmshrd_add(lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_ADD;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshare(enc_ctx, si);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+DWORD
+lmshrd_setinfo(lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_SETINFO;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshare(enc_ctx, si);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+static int
+lmshrd_check(char *share_name, int opcode)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status, rc;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_int32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+int
+lmshrd_exists(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_EXISTS));
+}
+
+int
+lmshrd_is_special(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_SPECIAL));
+}
+
+int
+lmshrd_is_restricted(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_RESTRICTED));
+}
+
+int
+lmshrd_is_admin(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_ADMIN));
+}
+
+int
+lmshrd_is_valid(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_VALID));
+}
+
+int
+lmshrd_is_dir(char *path)
+{
+ return (lmshrd_check(path, LMSHR_DOOR_IS_DIR));
+}
+
+static char *
+lmshare_decode_type(unsigned int stype)
+{
+ switch (stype) {
+ case STYPE_DISKTREE:
+ return ("Disk");
+ case STYPE_PRINTQ:
+ return ("Print Queue");
+ case STYPE_DEVICE:
+ return ("Device");
+ case STYPE_IPC:
+ return ("IPC");
+ case STYPE_DFS:
+ return ("DFS");
+ case STYPE_SPECIAL:
+ return ("Special");
+ default:
+ return ("Unknown");
+ };
+}
+
+
+static void
+lmshare_loginfo(FILE *fp, lmshare_info_t *si)
+{
+ if (!si) {
+ return;
+ }
+
+ (void) fprintf(fp, "\n%s Information:\n", si->share_name);
+ (void) fprintf(fp, "\tFolder: %s\n", si->directory);
+ (void) fprintf(fp, "\tType: %s\n", lmshare_decode_type(si->stype));
+ (void) fprintf(fp, "\tComment: %s\n", si->comment);
+
+ (void) fprintf(fp, "\tStatus: %s\n",
+ ((si->mode & LMSHRM_TRANS) ? "Transient" : "Permanent"));
+
+ (void) fprintf(fp, "\tContainer: %s\n", si->container);
+}
+
+int
+lmshrd_dump_hash(char *logfname)
+{
+ lmshare_info_t si;
+ uint64_t it;
+ FILE *fp;
+
+ if ((logfname == 0) || (*logfname == 0))
+ fp = stdout;
+ else {
+ fp = fopen(logfname, "w");
+ if (fp == 0) {
+ syslog(LOG_WARNING, "LmshareDump [%s]:"
+ " cannot create logfile", logfname);
+ syslog(LOG_WARNING, "LmshareDump:"
+ " output will be written on screen");
+ }
+ }
+
+ it = lmshrd_open_iterator(LMSHRM_PERM);
+ if (it == NULL) {
+ syslog(LOG_ERR, "LmshareDump: resource shortage");
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (1);
+ }
+
+ if (lmshrd_iterate(it, &si) != NERR_Success) {
+ syslog(LOG_ERR, "LmshareDump: Iterator iterate failed");
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (1);
+ }
+ while (*si.share_name != 0) {
+ lmshare_loginfo(fp, &si);
+ if (lmshrd_iterate(it, &si) != NERR_Success) {
+ syslog(LOG_ERR, "LmshareDump: Iterator iterate failed");
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (1);
+ }
+ }
+
+ if (lmshrd_close_iterator(it) != NERR_Success) {
+ syslog(LOG_ERR, "LmshareDump: Iterator close failed");
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (1);
+ }
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libshare/smb/sparc/Makefile b/usr/src/lib/libshare/smb/sparc/Makefile
new file mode 100644
index 0000000000..543238473c
--- /dev/null
+++ b/usr/src/lib/libshare/smb/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libshare/smb/sparcv9/Makefile b/usr/src/lib/libshare/smb/sparcv9/Makefile
new file mode 100644
index 0000000000..90b1730d23
--- /dev/null
+++ b/usr/src/lib/libshare/smb/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)