13034Sdougm /*
23034Sdougm  * CDDL HEADER START
33034Sdougm  *
43034Sdougm  * The contents of this file are subject to the terms of the
53034Sdougm  * Common Development and Distribution License (the "License").
63034Sdougm  * You may not use this file except in compliance with the License.
73034Sdougm  *
83034Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93034Sdougm  * or http://www.opensolaris.org/os/licensing.
103034Sdougm  * See the License for the specific language governing permissions
113034Sdougm  * and limitations under the License.
123034Sdougm  *
133034Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
143034Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153034Sdougm  * If applicable, add the following below this CDDL HEADER, with the
163034Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
173034Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
183034Sdougm  *
193034Sdougm  * CDDL HEADER END
203034Sdougm  */
213034Sdougm 
223034Sdougm /*
233348Sdougm  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
243034Sdougm  * Use is subject to license terms.
253034Sdougm  */
263034Sdougm 
273034Sdougm #pragma ident	"%Z%%M%	%I%	%E% SMI"
283034Sdougm 
293034Sdougm /* helper functions for using libscf with sharemgr */
303034Sdougm 
313034Sdougm #include <libscf.h>
323034Sdougm #include <libxml/parser.h>
333034Sdougm #include <libxml/tree.h>
343034Sdougm #include "libshare.h"
353034Sdougm #include "libshare_impl.h"
363034Sdougm #include "scfutil.h"
373034Sdougm #include <string.h>
383034Sdougm #include <errno.h>
393034Sdougm #include <uuid/uuid.h>
403034Sdougm #include <sys/param.h>
413348Sdougm #include <signal.h>
423034Sdougm 
433034Sdougm ssize_t scf_max_name_len;
443034Sdougm extern struct sa_proto_plugin *sap_proto_list;
453910Sdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
463034Sdougm 
473034Sdougm /*
483034Sdougm  * The SMF facility uses some properties that must exist. We want to
493034Sdougm  * skip over these when processing protocol options.
503034Sdougm  */
513034Sdougm static char *skip_props[] = {
523034Sdougm 	"modify_authorization",
533034Sdougm 	"action_authorization",
543034Sdougm 	"value_authorization",
553034Sdougm 	NULL
563034Sdougm };
573034Sdougm 
583034Sdougm /*
593034Sdougm  * sa_scf_fini(handle)
603034Sdougm  *
613034Sdougm  * must be called when done. Called with the handle allocated in
623034Sdougm  * sa_scf_init(), it cleans up the state and frees any SCF resources
633034Sdougm  * still in use. Called by sa_fini().
643034Sdougm  */
653034Sdougm 
663034Sdougm void
673034Sdougm sa_scf_fini(scfutilhandle_t *handle)
683034Sdougm {
693034Sdougm 	if (handle != NULL) {
703034Sdougm 	    int unbind = 0;
713034Sdougm 	    if (handle->scope != NULL) {
723034Sdougm 		unbind = 1;
733034Sdougm 		scf_scope_destroy(handle->scope);
743034Sdougm 	    }
753034Sdougm 	    if (handle->service != NULL)
763034Sdougm 		    scf_service_destroy(handle->service);
773034Sdougm 	    if (handle->pg != NULL)
783034Sdougm 		scf_pg_destroy(handle->pg);
793034Sdougm 	    if (handle->handle != NULL) {
803034Sdougm 		handle->scf_state = SCH_STATE_UNINIT;
813034Sdougm 		if (unbind)
823034Sdougm 		    (void) scf_handle_unbind(handle->handle);
833034Sdougm 		scf_handle_destroy(handle->handle);
843034Sdougm 	    }
853034Sdougm 	    free(handle);
863034Sdougm 	}
873034Sdougm }
883034Sdougm 
893034Sdougm /*
903034Sdougm  * sa_scf_init()
913034Sdougm  *
923034Sdougm  * must be called before using any of the SCF functions. Called by
933034Sdougm  * sa_init() during the API setup.
943034Sdougm  */
953034Sdougm 
963034Sdougm scfutilhandle_t *
973910Sdougm sa_scf_init(sa_handle_impl_t ihandle)
983034Sdougm {
993034Sdougm 	scfutilhandle_t *handle;
1003034Sdougm 
1013034Sdougm 	scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1023034Sdougm 	if (scf_max_name_len <= 0)
1033034Sdougm 	    scf_max_name_len = SA_MAX_NAME_LEN + 1;
1043034Sdougm 
1053034Sdougm 	handle = calloc(1, sizeof (scfutilhandle_t));
1063034Sdougm 	if (handle != NULL) {
1073910Sdougm 	    ihandle->scfhandle = handle;
1083034Sdougm 	    handle->scf_state = SCH_STATE_INITIALIZING;
1093034Sdougm 	    handle->handle = scf_handle_create(SCF_VERSION);
1103034Sdougm 	    if (handle->handle != NULL) {
1113034Sdougm 		if (scf_handle_bind(handle->handle) == 0) {
1123034Sdougm 		    handle->scope = scf_scope_create(handle->handle);
1133034Sdougm 		    handle->service = scf_service_create(handle->handle);
1143034Sdougm 		    handle->pg = scf_pg_create(handle->handle);
1153034Sdougm 		    handle->instance = scf_instance_create(handle->handle);
1163034Sdougm 		    if (scf_handle_get_scope(handle->handle,
1173034Sdougm 					SCF_SCOPE_LOCAL, handle->scope) == 0) {
1183034Sdougm 			if (scf_scope_get_service(handle->scope,
1193034Sdougm 						    SA_GROUP_SVC_NAME,
1203034Sdougm 						    handle->service) != 0) {
1213034Sdougm 			    goto err;
1223034Sdougm 			}
1233034Sdougm 			handle->scf_state = SCH_STATE_INIT;
1243034Sdougm 			if (sa_get_instance(handle, "default") != SA_OK) {
1253034Sdougm 			    char **protolist;
1263034Sdougm 			    int numprotos, i;
1273034Sdougm 			    sa_group_t defgrp;
1283910Sdougm 			    defgrp = sa_create_group((sa_handle_t)ihandle,
1293910Sdougm 							"default", NULL);
1303034Sdougm 			    if (defgrp != NULL) {
1313034Sdougm 				numprotos = sa_get_protocols(&protolist);
1323034Sdougm 				for (i = 0; i < numprotos; i++) {
1333034Sdougm 				    (void) sa_create_optionset(defgrp,
1343034Sdougm 								protolist[i]);
1353034Sdougm 				}
1363034Sdougm 				if (protolist != NULL)
1373034Sdougm 				    free(protolist);
1383034Sdougm 			    }
1393034Sdougm 			}
1403034Sdougm 		    } else {
1413034Sdougm 			goto err;
1423034Sdougm 		    }
1433034Sdougm 		} else {
1443034Sdougm 		    goto err;
1453034Sdougm 		}
1463034Sdougm 	    } else {
1473034Sdougm 		free(handle);
1483034Sdougm 		handle = NULL;
1493034Sdougm 		(void) printf("libshare could not access SMF repository: %s\n",
1503034Sdougm 				scf_strerror(scf_error()));
1513034Sdougm 	    }
1523034Sdougm 	}
1533034Sdougm 	return (handle);
1543034Sdougm 
1553034Sdougm 	/* error handling/unwinding */
1563034Sdougm err:
1573034Sdougm 	(void) sa_scf_fini(handle);
1583034Sdougm 	(void) printf("libshare SMF initialization problem: %s\n",
1593034Sdougm 			scf_strerror(scf_error()));
1603034Sdougm 	return (NULL);
1613034Sdougm }
1623034Sdougm 
1633034Sdougm /*
1643034Sdougm  * get_scf_limit(name)
1653034Sdougm  *
1663034Sdougm  * Since we use  scf_limit a lot and do the same  check and return the
1673034Sdougm  * same  value  if  it  fails,   implement  as  a  function  for  code
1683034Sdougm  * simplification.  Basically, if  name isn't found, return MAXPATHLEN
1693034Sdougm  * (1024) so we have a reasonable default buffer size.
1703034Sdougm  */
1713034Sdougm static ssize_t
1723034Sdougm get_scf_limit(uint32_t name)
1733034Sdougm {
1743034Sdougm 	ssize_t vallen;
1753034Sdougm 
1763034Sdougm 	vallen = scf_limit(name);
1773034Sdougm 	if (vallen == (ssize_t)-1)
1783034Sdougm 	    vallen = MAXPATHLEN;
1793034Sdougm 	return (vallen);
1803034Sdougm }
1813034Sdougm 
1823034Sdougm /*
1833034Sdougm  * skip_property(name)
1843034Sdougm  *
1853034Sdougm  * internal function to check to see if a property is an SMF magic
1863034Sdougm  * property that needs to be skipped.
1873034Sdougm  */
1883034Sdougm static int
1893034Sdougm skip_property(char *name)
1903034Sdougm {
1913034Sdougm 	int i;
1923034Sdougm 
1933034Sdougm 	for (i = 0; skip_props[i] != NULL; i++)
1943034Sdougm 	    if (strcmp(name, skip_props[i]) == 0)
1953034Sdougm 		return (1);
1963034Sdougm 	return (0);
1973034Sdougm }
1983034Sdougm 
1993034Sdougm /*
2003034Sdougm  * generate_unique_sharename(sharename)
2013034Sdougm  *
2023034Sdougm  * Shares are represented in SMF as property groups. Due to share
2033034Sdougm  * paths containing characters that are not allowed in SMF names and
2043034Sdougm  * the need to be unique, we use UUIDs to construct a unique name.
2053034Sdougm  */
2063034Sdougm 
2073034Sdougm static void
2083034Sdougm generate_unique_sharename(char *sharename)
2093034Sdougm {
2103034Sdougm 	uuid_t uuid;
2113034Sdougm 
2123034Sdougm 	uuid_generate(uuid);
2133034Sdougm 	(void) strcpy(sharename, "S-");
2143034Sdougm 	uuid_unparse(uuid, sharename + 2);
2153034Sdougm }
2163034Sdougm 
2173034Sdougm /*
2183034Sdougm  * valid_protocol(proto)
2193034Sdougm  *
2203034Sdougm  * check to see if the specified protocol is a valid one for the
2213034Sdougm  * general sharemgr facility. We determine this by checking which
2223034Sdougm  * plugin protocols were found.
2233034Sdougm  */
2243034Sdougm 
2253034Sdougm static int
2263034Sdougm valid_protocol(char *proto)
2273034Sdougm {
2283034Sdougm 	struct sa_proto_plugin *plugin;
2293034Sdougm 	for (plugin = sap_proto_list; plugin != NULL;
2303034Sdougm 	    plugin = plugin->plugin_next)
2313034Sdougm 	    if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
2323034Sdougm 		return (1);
2333034Sdougm 	return (0);
2343034Sdougm }
2353034Sdougm 
2363034Sdougm /*
2373034Sdougm  * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
2383034Sdougm  *
2393034Sdougm  * extract the name property group and create the specified type of
2403034Sdougm  * node on the provided group.  type will be optionset or security.
2413034Sdougm  */
2423034Sdougm 
2433034Sdougm static int
2443034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
2453034Sdougm 			scf_propertygroup_t *pg,
2463034Sdougm 			char *nodetype, char *proto, char *sectype)
2473034Sdougm {
2483034Sdougm 	xmlNodePtr node;
2493034Sdougm 	scf_iter_t *iter;
2503034Sdougm 	scf_property_t *prop;
2513034Sdougm 	scf_value_t *value;
2523034Sdougm 	char *name;
2533034Sdougm 	char *valuestr;
2543034Sdougm 	ssize_t vallen;
2553034Sdougm 	int ret = SA_OK;
2563034Sdougm 
2573034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2583034Sdougm 
2593034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
2603034Sdougm 	if (node != NULL) {
2613034Sdougm 	    if (proto != NULL)
2623034Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
2633034Sdougm 	    if (sectype != NULL)
2643034Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
2653034Sdougm 		/*
2663034Sdougm 		 * have node to work with so iterate over the properties
2673034Sdougm 		 * in the pg and create option sub nodes.
2683034Sdougm 		 */
2693034Sdougm 		iter = scf_iter_create(handle->handle);
2703034Sdougm 		value = scf_value_create(handle->handle);
2713034Sdougm 		prop = scf_property_create(handle->handle);
2723034Sdougm 		name = malloc(scf_max_name_len);
2733034Sdougm 		valuestr = malloc(vallen);
2743034Sdougm 		/*
2753034Sdougm 		 * want to iterate through the properties and add them
2763034Sdougm 		 * to the base optionset.
2773034Sdougm 		 */
2783034Sdougm 		if (iter != NULL && value != NULL && prop != NULL &&
2793034Sdougm 		    valuestr != NULL && name != NULL) {
2803034Sdougm 		    if (scf_iter_pg_properties(iter, pg) == 0) {
2813034Sdougm 			/* now iterate the properties in the group */
2823034Sdougm 			while (scf_iter_next_property(iter, prop) > 0) {
2833034Sdougm 			    /* have a property */
2843034Sdougm 			    if (scf_property_get_name(prop, name,
2853034Sdougm 							scf_max_name_len) > 0) {
2863034Sdougm 				/* some properties are part of the framework */
2873034Sdougm 				if (skip_property(name))
2883034Sdougm 				    continue;
2893034Sdougm 				if (scf_property_get_value(prop, value) == 0) {
2903034Sdougm 				    if (scf_value_get_astring(value, valuestr,
2913034Sdougm 								vallen) >= 0) {
2923034Sdougm 					sa_property_t saprop;
2933034Sdougm 					saprop = sa_create_property(name,
2943034Sdougm 								    valuestr);
2953034Sdougm 					if (saprop != NULL) {
2963034Sdougm 					/*
2973034Sdougm 					 * since in SMF, don't
2983034Sdougm 					 * recurse. Use xmlAddChild
2993034Sdougm 					 * directly, instead.
3003034Sdougm 					 */
3013034Sdougm 					    xmlAddChild(node,
3023034Sdougm 							(xmlNodePtr) saprop);
3033034Sdougm 					}
3043034Sdougm 				    }
3053034Sdougm 				}
3063034Sdougm 			    }
3073034Sdougm 			}
3083034Sdougm 		    }
3093034Sdougm 		} else {
3103034Sdougm 		    ret = SA_NO_MEMORY;
3113034Sdougm 		}
3123034Sdougm 		/* cleanup to avoid memory leaks */
3133034Sdougm 		if (value != NULL)
3143034Sdougm 		    scf_value_destroy(value);
3153034Sdougm 		if (iter != NULL)
3163034Sdougm 		    scf_iter_destroy(iter);
3173034Sdougm 		if (prop != NULL)
3183034Sdougm 		    scf_property_destroy(prop);
3193034Sdougm 		if (name != NULL)
3203034Sdougm 		    free(name);
3213034Sdougm 		if (valuestr != NULL)
3223034Sdougm 		    free(valuestr);
3233034Sdougm 	}
3243034Sdougm 	return (ret);
3253034Sdougm }
3263034Sdougm 
3273034Sdougm /*
3283034Sdougm  * sa_extract_attrs(root, handle, instance)
3293034Sdougm  *
3303034Sdougm  * local function to extract the actual attributes/properties from the
3313034Sdougm  * property group of the service instance. These are the well known
3323034Sdougm  * attributes of "state" and "zfs". If additional attributes are
3333034Sdougm  * added, they should be added here.
3343034Sdougm  */
3353034Sdougm 
3363034Sdougm static void
3373034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
3383034Sdougm 		    scf_instance_t *instance)
3393034Sdougm {
3403034Sdougm 	scf_property_t *prop;
3413034Sdougm 	scf_value_t *value;
3423034Sdougm 	char *valuestr;
3433034Sdougm 	ssize_t vallen;
3443034Sdougm 
3453034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3463034Sdougm 	prop = scf_property_create(handle->handle);
3473034Sdougm 	value = scf_value_create(handle->handle);
3483034Sdougm 	valuestr = malloc(vallen);
3493034Sdougm 	if (prop != NULL && value != NULL && valuestr != NULL &&
3503034Sdougm 	    scf_instance_get_pg(instance, "operation",
3513034Sdougm 				handle->pg) == 0) {
3523034Sdougm 		/*
3533034Sdougm 		 * have a property group with desired name so now get
3543034Sdougm 		 * the known attributes.
3553034Sdougm 		 */
3563034Sdougm 	    if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
3573034Sdougm 		/* found the property so get the value */
3583034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
3593034Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) >= 0) {
3603034Sdougm 			xmlSetProp(root, (xmlChar *)"state",
3613034Sdougm 				    (xmlChar *)valuestr);
3623034Sdougm 		    }
3633034Sdougm 		}
3643034Sdougm 	    }
3653034Sdougm 	    if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
3663034Sdougm 		/* found the property so get the value */
3673034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
3683034Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) > 0) {
3693034Sdougm 			xmlSetProp(root, (xmlChar *)"zfs",
3703034Sdougm 				    (xmlChar *)valuestr);
3713034Sdougm 		    }
3723034Sdougm 		}
3733034Sdougm 	    }
3743034Sdougm 	}
3753034Sdougm 	if (valuestr != NULL)
3763034Sdougm 	    free(valuestr);
3773034Sdougm 	if (value != NULL)
3783034Sdougm 	    scf_value_destroy(value);
3793034Sdougm 	if (prop != NULL)
3803034Sdougm 	    scf_property_destroy(prop);
3813034Sdougm }
3823034Sdougm 
3833034Sdougm /*
3843034Sdougm  * list of known share attributes.
3853034Sdougm  */
3863034Sdougm 
3873034Sdougm static char *share_attr[] = {
3883034Sdougm 	"path",
3893034Sdougm 	"id",
3903034Sdougm 	"resource",
3913034Sdougm 	NULL,
3923034Sdougm };
3933034Sdougm 
3943034Sdougm static int
3953034Sdougm is_share_attr(char *name)
3963034Sdougm {
3973034Sdougm 	int i;
3983034Sdougm 	for (i = 0; share_attr[i] != NULL; i++)
3993034Sdougm 	    if (strcmp(name, share_attr[i]) == 0)
4003034Sdougm 		return (1);
4013034Sdougm 	return (0);
4023034Sdougm }
4033034Sdougm 
4043034Sdougm /*
4053034Sdougm  * sa_share_from_pgroup
4063034Sdougm  *
4073034Sdougm  * extract the share definition from the share property group. We do
4083034Sdougm  * some sanity checking to avoid bad data.
4093034Sdougm  *
4103034Sdougm  * Since this is only constructing the internal data structures, we
4113034Sdougm  * don't use the sa_* functions most of the time.
4123034Sdougm  */
4133034Sdougm void
4143034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
4153034Sdougm 			scf_propertygroup_t *pg, char *id)
4163034Sdougm {
4173034Sdougm 	xmlNodePtr node;
4183034Sdougm 	char *name;
4193034Sdougm 	scf_iter_t *iter;
4203034Sdougm 	scf_property_t *prop;
4213034Sdougm 	scf_value_t *value;
4223034Sdougm 	ssize_t vallen;
4233034Sdougm 	char *valuestr;
4243034Sdougm 	int ret = SA_OK;
4253348Sdougm 	int have_path = 0;
4263034Sdougm 
4273034Sdougm 	/*
4283034Sdougm 	 * While preliminary check (starts with 'S') passed before
4293034Sdougm 	 * getting here. Need to make sure it is in ID syntax
4303034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
4313034Sdougm 	 * pgroups.
4323034Sdougm 	 */
4333034Sdougm 	vallen = strlen(id);
4343034Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
4353034Sdougm 	    uuid_t uuid;
4363034Sdougm 	    if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) != 0 ||
4373034Sdougm 		uuid_parse(id + 2, uuid) < 0)
4383034Sdougm 		return;
4393034Sdougm 	} else {
4403034Sdougm 	    return;
4413034Sdougm 	}
4423034Sdougm 
4433034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
4443034Sdougm 
4453034Sdougm 	iter = scf_iter_create(handle->handle);
4463034Sdougm 	value = scf_value_create(handle->handle);
4473034Sdougm 	prop = scf_property_create(handle->handle);
4483034Sdougm 	name = malloc(scf_max_name_len);
4493034Sdougm 	valuestr = malloc(vallen);
4503034Sdougm 
4513034Sdougm 	/*
4523034Sdougm 	 * construct the share XML node. It is similar to sa_add_share
4533034Sdougm 	 * but never changes the repository. Also, there won't be any
4543034Sdougm 	 * ZFS or transient shares.  Root will be the group it is
4553034Sdougm 	 * associated with.
4563034Sdougm 	 */
4573034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
4583034Sdougm 	if (node != NULL) {
4593034Sdougm 		/*
4603034Sdougm 		 * make sure the UUID part of the property group is
4613034Sdougm 		 * stored in the share "id" property. We use this
4623034Sdougm 		 * later.
4633034Sdougm 		 */
4643034Sdougm 	    xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
4653034Sdougm 	    xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
4663034Sdougm 	}
4673034Sdougm 
4683034Sdougm 	if (iter != NULL && value != NULL && prop != NULL && name != NULL) {
4693034Sdougm 		/* iterate over the share pg properties */
4703034Sdougm 	    if (scf_iter_pg_properties(iter, pg) == 0) {
4713034Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
4723034Sdougm 		    ret = SA_SYSTEM_ERR; /* assume the worst */
4733034Sdougm 		    if (scf_property_get_name(prop, name,
4743034Sdougm 						scf_max_name_len) > 0) {
4753034Sdougm 			if (scf_property_get_value(prop, value) == 0) {
4763034Sdougm 			    if (scf_value_get_astring(value, valuestr,
4773034Sdougm 							vallen) >= 0) {
4783034Sdougm 				ret = SA_OK;
4793034Sdougm 			    }
4803034Sdougm 			}
4813034Sdougm 		    }
4823034Sdougm 		    if (ret == SA_OK) {
4833348Sdougm 			/*
4843348Sdougm 			 * check that we have the "path" property in
4853348Sdougm 			 * name. The string in name will always be nul
4863348Sdougm 			 * terminated if scf_property_get_name()
4873348Sdougm 			 * succeeded.
4883348Sdougm 			 */
4893348Sdougm 			if (strcmp(name, "path") == 0)
4903348Sdougm 			    have_path = 1;
4913034Sdougm 			if (is_share_attr(name)) {
4923034Sdougm 				/*
4933034Sdougm 				 * if a share attr, then simple -
4943034Sdougm 				 * usually path and resource name
4953034Sdougm 				 */
4963034Sdougm 			    xmlSetProp(node, (xmlChar *)name,
4973034Sdougm 					(xmlChar *)valuestr);
4983034Sdougm 			} else {
4993034Sdougm 			    if (strcmp(name, "description") == 0) {
5003034Sdougm 				/* we have a description node */
5013034Sdougm 				xmlNodePtr desc;
5023034Sdougm 				desc = xmlNewChild(node, NULL,
5033034Sdougm 						    (xmlChar *)"description",
5043034Sdougm 						    NULL);
5053034Sdougm 				if (desc != NULL)
5063034Sdougm 				    xmlNodeSetContent(desc,
5073034Sdougm 							(xmlChar *)valuestr);
5083034Sdougm 			    }
5093034Sdougm 			}
5103034Sdougm 		    }
5113034Sdougm 		}
5123034Sdougm 	    }
5133034Sdougm 	}
5143348Sdougm 	/*
5153348Sdougm 	 * a share without a path is broken so we want to not include
5163348Sdougm 	 * these.  They shouldn't happen but if you kill a sharemgr in
5173348Sdougm 	 * the process of creating a share, it could happen.  They
5183348Sdougm 	 * should be harmless.  It is also possible that another
5193348Sdougm 	 * sharemgr is running and in the process of creating a share.
5203348Sdougm 	 */
5213348Sdougm 	if (have_path == 0 && node != NULL) {
5223348Sdougm 	    xmlUnlinkNode(node);
5233348Sdougm 	    xmlFreeNode(node);
5243348Sdougm 	}
5253034Sdougm 	if (name != NULL)
5263034Sdougm 	    free(name);
5273034Sdougm 	if (valuestr != NULL)
5283034Sdougm 	    free(valuestr);
5293034Sdougm 	if (value != NULL)
5303034Sdougm 	    scf_value_destroy(value);
5313034Sdougm 	if (iter != NULL)
5323034Sdougm 	    scf_iter_destroy(iter);
5333034Sdougm 	if (prop != NULL)
5343034Sdougm 	    scf_property_destroy(prop);
5353034Sdougm }
5363034Sdougm 
5373034Sdougm /*
5383034Sdougm  * find_share_by_id(shareid)
5393034Sdougm  *
5403034Sdougm  * Search all shares in all groups until we find the share represented
5413034Sdougm  * by "id".
5423034Sdougm  */
5433034Sdougm 
5443034Sdougm static sa_share_t
5453910Sdougm find_share_by_id(sa_handle_t handle, char *shareid)
5463034Sdougm {
5473034Sdougm 	sa_group_t group;
5483034Sdougm 	sa_share_t share = NULL;
5493034Sdougm 	char *id = NULL;
5503034Sdougm 	int done = 0;
5513034Sdougm 
5523910Sdougm 	for (group = sa_get_group(handle, NULL); group != NULL && !done;
5533034Sdougm 		group = sa_get_next_group(group)) {
5543034Sdougm 		for (share = sa_get_share(group, NULL); share != NULL;
5553034Sdougm 			share = sa_get_next_share(share)) {
5563034Sdougm 			id = sa_get_share_attr(share, "id");
5573034Sdougm 			if (id != NULL && strcmp(id, shareid) == 0) {
5583034Sdougm 				sa_free_attr_string(id);
5593034Sdougm 				id = NULL;
5603034Sdougm 				done++;
5613034Sdougm 				break;
5623034Sdougm 			}
5633034Sdougm 			if (id != NULL) {
5643034Sdougm 			    sa_free_attr_string(id);
5653034Sdougm 			    id = NULL;
5663034Sdougm 			}
5673034Sdougm 		}
5683034Sdougm 	}
5693034Sdougm 	return (share);
5703034Sdougm }
5713034Sdougm 
5723034Sdougm /*
5733034Sdougm  * sa_share_props_from_pgroup(root, handle, pg, id)
5743034Sdougm  *
5753034Sdougm  * extract share properties from the SMF property group. More sanity
5763034Sdougm  * checks are done and the share object is created. We ignore some
5773034Sdougm  * errors that could exist in the repository and only worry about
5783034Sdougm  * property groups that validate in naming.
5793034Sdougm  */
5803034Sdougm 
5813034Sdougm static int
5823034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
5833910Sdougm 			scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
5843034Sdougm {
5853034Sdougm 	xmlNodePtr node;
5863034Sdougm 	char *name;
5873034Sdougm 	scf_iter_t *iter;
5883034Sdougm 	scf_property_t *prop;
5893034Sdougm 	scf_value_t *value;
5903034Sdougm 	ssize_t vallen;
5913034Sdougm 	char *valuestr;
5923034Sdougm 	int ret = SA_OK;
5933034Sdougm 	char *sectype = NULL;
5943034Sdougm 	char *proto;
5953034Sdougm 	sa_share_t share;
5963034Sdougm 
5973034Sdougm 	/*
5983034Sdougm 	 * While preliminary check (starts with 'S') passed before
5993034Sdougm 	 * getting here. Need to make sure it is in ID syntax
6003034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
6013034Sdougm 	 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
6023034Sdougm 	 * characters, it is likely one of the protocol/security
6033034Sdougm 	 * versions.
6043034Sdougm 	 */
6053034Sdougm 	vallen = strlen(id);
6063034Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen > SA_SHARE_PG_LEN) {
6073034Sdougm 	    uuid_t uuid;
6083034Sdougm 	    if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
6093034Sdougm 		proto = strchr(id, '_');
6103034Sdougm 		if (proto == NULL)
6113034Sdougm 		    return (ret);
6123034Sdougm 		*proto++ = '\0';
6133034Sdougm 		if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
6143034Sdougm 		    return (ret);
6153034Sdougm 		/*
6163034Sdougm 		 * probably a legal optionset so check a few more
6173034Sdougm 		 * syntax points below.
6183034Sdougm 		 */
6193034Sdougm 		if (*proto == '\0') {
6203034Sdougm 		    /* not a valid proto (null) */
6213034Sdougm 		    return (ret);
6223034Sdougm 		}
6233034Sdougm 		sectype = strchr(proto, '_');
6243034Sdougm 		if (sectype != NULL)
6253034Sdougm 		    *sectype++ = '\0';
6263034Sdougm 		if (!valid_protocol(proto))
6273034Sdougm 		    return (ret);
6283034Sdougm 	    }
6293034Sdougm 	} else {
6303034Sdougm 	/*
6313034Sdougm 	 * it is ok to not have what we thought since someone might
6323034Sdougm 	 * have added a name via SMF.
6333034Sdougm 	 */
6343034Sdougm 	    return (ret);
6353034Sdougm 	}
6363034Sdougm 
6373034Sdougm 	/*
6383034Sdougm 	 * to get here, we have a valid protocol and possibly a
6393034Sdougm 	 * security. We now have to find the share that it is really
6403034Sdougm 	 * associated with. The "id" portion of the pgroup name will
6413034Sdougm 	 * match.
6423034Sdougm 	 */
6433034Sdougm 
6443910Sdougm 	share = find_share_by_id(sahandle, id);
6453034Sdougm 	if (share == NULL)
6463034Sdougm 	    return (SA_BAD_PATH);
6473034Sdougm 
6483034Sdougm 	root = (xmlNodePtr)share;
6493034Sdougm 
6503034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
6513034Sdougm 
6523034Sdougm 	iter = scf_iter_create(handle->handle);
6533034Sdougm 	value = scf_value_create(handle->handle);
6543034Sdougm 	prop = scf_property_create(handle->handle);
6553034Sdougm 	name = malloc(scf_max_name_len);
6563034Sdougm 	valuestr = malloc(vallen);
6573034Sdougm 
6583034Sdougm 	if (sectype == NULL)
6593034Sdougm 	    node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
6603034Sdougm 	else {
6613034Sdougm 	    node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL);
6623034Sdougm 	    if (node != NULL)
6633034Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
6643034Sdougm 	}
6653034Sdougm 	if (node != NULL) {
6663034Sdougm 	    xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
6673034Sdougm 	    /* now find the properties */
6683034Sdougm 	    if (iter != NULL && value != NULL && prop != NULL && name != NULL) {
6693034Sdougm 		/* iterate over the share pg properties */
6703034Sdougm 		if (scf_iter_pg_properties(iter, pg) == 0) {
6713034Sdougm 		    while (scf_iter_next_property(iter, prop) > 0) {
6723034Sdougm 			ret = SA_SYSTEM_ERR; /* assume the worst */
6733034Sdougm 			if (scf_property_get_name(prop, name,
6743034Sdougm 						    scf_max_name_len) > 0) {
6753034Sdougm 			    if (scf_property_get_value(prop, value) == 0) {
6763034Sdougm 				if (scf_value_get_astring(value, valuestr,
6773034Sdougm 							    vallen) >= 0) {
6783034Sdougm 				    ret = SA_OK;
6793034Sdougm 				}
6803034Sdougm 			    }
6813034Sdougm 			} else {
6823034Sdougm 			    ret = SA_SYSTEM_ERR;
6833034Sdougm 			}
6843034Sdougm 			if (ret == SA_OK) {
6853034Sdougm 			    sa_property_t prop;
6863034Sdougm 			    prop = sa_create_property(name, valuestr);
6873034Sdougm 			    if (prop != NULL)
6883034Sdougm 				prop = (sa_property_t)xmlAddChild(node,
6893034Sdougm 							(xmlNodePtr)prop);
6903034Sdougm 			    else
6913034Sdougm 				ret = SA_NO_MEMORY;
6923034Sdougm 			}
6933034Sdougm 		    }
6943034Sdougm 		} else {
6953034Sdougm 		    ret = SA_SYSTEM_ERR;
6963034Sdougm 		}
6973034Sdougm 	    }
6983034Sdougm 	} else {
6993034Sdougm 	    ret = SA_NO_MEMORY;
7003034Sdougm 	}
7013034Sdougm 	if (iter != NULL)
7023034Sdougm 	    scf_iter_destroy(iter);
7033034Sdougm 	if (value != NULL)
7043034Sdougm 	    scf_value_destroy(value);
7053034Sdougm 	if (prop != NULL)
7063034Sdougm 	    scf_property_destroy(prop);
7073034Sdougm 	if (name != NULL)
7083034Sdougm 	    free(name);
7093034Sdougm 	if (valuestr != NULL)
7103034Sdougm 	    free(valuestr);
7113034Sdougm 	return (ret);
7123034Sdougm }
7133034Sdougm 
7143034Sdougm /*
7153034Sdougm  * sa_extract_group(root, handle, instance)
7163034Sdougm  *
7173034Sdougm  * get the config info for this instance of a group and create the XML
7183034Sdougm  * subtree from it.
7193034Sdougm  */
7203034Sdougm 
7213034Sdougm static int
7223034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
7233910Sdougm 			scf_instance_t *instance, sa_handle_t sahandle)
7243034Sdougm {
7253034Sdougm 	char *buff;
7263034Sdougm 	xmlNodePtr node;
7273034Sdougm 	scf_iter_t *iter;
7283034Sdougm 	char *proto;
7293034Sdougm 	char *sectype;
7303034Sdougm 	int have_shares = 0;
7313034Sdougm 	int has_proto = 0;
7323034Sdougm 	int is_default = 0;
7333034Sdougm 	int ret = SA_OK;
7343034Sdougm 	int err;
7353034Sdougm 
7363034Sdougm 	buff = malloc(scf_max_name_len);
7373034Sdougm 	iter = scf_iter_create(handle->handle);
7383034Sdougm 	if (buff != NULL) {
7393034Sdougm 	    if (scf_instance_get_name(instance, buff,
7403034Sdougm 						scf_max_name_len) > 0) {
7413034Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
7423034Sdougm 		if (node != NULL) {
7433034Sdougm 		    xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
7443034Sdougm 		    if (strcmp(buff, "default") == 0)
7453034Sdougm 			is_default++;
7463034Sdougm 		    sa_extract_attrs(node, handle, instance);
7473034Sdougm 			/*
7483034Sdougm 			 * Iterate through all the property groups
7493034Sdougm 			 * looking for those with security or
7503034Sdougm 			 * optionset prefixes. The names of the
7513034Sdougm 			 * matching pgroups are parsed to get the
7523034Sdougm 			 * protocol, and for security, the sectype.
7533034Sdougm 			 * Syntax is as follows:
7543034Sdougm 			 *    optionset | optionset_<proto>
7553034Sdougm 			 *    security_default | security_<proto>_<sectype>
7563034Sdougm 			 * "operation" is handled by
7573034Sdougm 			 * sa_extract_attrs().
7583034Sdougm 			 */
7593034Sdougm 		    if (iter != NULL) {
7603034Sdougm 			if (scf_iter_instance_pgs(iter, instance) == 0) {
7613034Sdougm 			    while (scf_iter_next_pg(iter, handle->pg) > 0) {
7623034Sdougm 				/* have a pgroup so sort it out */
7633034Sdougm 				ret = scf_pg_get_name(handle->pg, buff,
7643034Sdougm 							scf_max_name_len);
7653034Sdougm 				if (ret  > 0) {
7663034Sdougm 				    if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
7673034Sdougm 					sa_share_from_pgroup(node, handle,
7683034Sdougm 								handle->pg,
7693034Sdougm 								buff);
7703034Sdougm 					have_shares++;
7713034Sdougm 				    } else if (strncmp(buff, "optionset", 9) ==
7723034Sdougm 						0) {
7733034Sdougm 					char *nodetype = "optionset";
7743034Sdougm 					/* have an optionset */
7753034Sdougm 					sectype = NULL;
7763034Sdougm 					proto = strchr(buff, '_');
7773034Sdougm 					if (proto != NULL) {
7783034Sdougm 					    *proto++ = '\0';
7793034Sdougm 					    sectype = strchr(proto, '_');
7803034Sdougm 					    if (sectype != NULL) {
7813034Sdougm 						*sectype++ = '\0';
7823034Sdougm 						nodetype = "security";
7833034Sdougm 					    }
7843034Sdougm 					}
7853034Sdougm 					ret = sa_extract_pgroup(node, handle,
7863034Sdougm 							    handle->pg,
7873034Sdougm 							    nodetype,
7883034Sdougm 							    proto, sectype);
7893034Sdougm 					has_proto++;
7903034Sdougm 				    } else if (strncmp(buff,
7913034Sdougm 							"security", 8) == 0) {
7923034Sdougm 					/*
7933034Sdougm 					 * have a security (note that
7943034Sdougm 					 * this should change in the
7953034Sdougm 					 * future)
7963034Sdougm 					 */
7973034Sdougm 					proto = strchr(buff, '_');
7983034Sdougm 					sectype = NULL;
7993034Sdougm 					if (proto != NULL) {
8003034Sdougm 					    *proto++ = '\0';
8013034Sdougm 					    sectype = strchr(proto, '_');
8023034Sdougm 					    if (sectype != NULL)
8033034Sdougm 						*sectype++ = '\0';
8043034Sdougm 					    if (strcmp(proto, "default") == 0)
8053034Sdougm 						proto = NULL;
8063034Sdougm 					}
8073034Sdougm 					ret = sa_extract_pgroup(node, handle,
8083034Sdougm 							    handle->pg,
8093034Sdougm 							    "security", proto,
8103034Sdougm 							    sectype);
8113034Sdougm 					has_proto++;
8123034Sdougm 				    }
8133034Sdougm 				    /* ignore everything else */
8143034Sdougm 				}
8153034Sdougm 			    }
8163034Sdougm 			} else {
8173034Sdougm 			    ret = SA_NO_MEMORY;
8183034Sdougm 			}
8193034Sdougm 			/*
8203034Sdougm 			 * Make sure we have a valid default group.
8213034Sdougm 			 * On first boot, default won't have any
8223034Sdougm 			 * protocols defined and won't be enabled (but
8233034Sdougm 			 * should be).
8243034Sdougm 			 */
8253034Sdougm 			if (is_default) {
8263034Sdougm 			    char *state = sa_get_group_attr((sa_group_t)node,
8273034Sdougm 							    "state");
8283034Sdougm 			    char **protos;
8293034Sdougm 			    int numprotos;
8303034Sdougm 			    int i;
8313034Sdougm 
8323034Sdougm 			    if (state == NULL) {
8333034Sdougm 				/* set attribute to enabled */
8343034Sdougm 				(void) sa_set_group_attr((sa_group_t)node,
8353034Sdougm 							    "state",
8363034Sdougm 							    "enabled");
8373034Sdougm 				/* we can assume no protocols */
8383034Sdougm 				numprotos = sa_get_protocols(&protos);
8393034Sdougm 				for (i = 0; i < numprotos; i++)
8403034Sdougm 				    (void) sa_create_optionset((sa_group_t)node,
8413034Sdougm 								protos[i]);
8423034Sdougm 				if (numprotos > 0)
8433034Sdougm 				    free(protos);
8443034Sdougm 			    } else {
8453034Sdougm 				sa_free_attr_string(state);
8463034Sdougm 			    }
8473034Sdougm 			}
8483034Sdougm 			/* do a second pass if shares were found */
8493034Sdougm 			if (have_shares &&
8503034Sdougm 				scf_iter_instance_pgs(iter, instance) == 0) {
8513034Sdougm 			    while (scf_iter_next_pg(iter, handle->pg) > 0) {
8523034Sdougm 				/*
8533034Sdougm 				 * have a pgroup so see if it is a
8543034Sdougm 				 * share optionset
8553034Sdougm 				 */
8563034Sdougm 				err = scf_pg_get_name(handle->pg, buff,
8573034Sdougm 							scf_max_name_len);
8583034Sdougm 				if (err  > 0) {
8593034Sdougm 				    if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
8603034Sdougm 					ret = sa_share_props_from_pgroup(node,
8613034Sdougm 								handle,
8623034Sdougm 								handle->pg,
8633910Sdougm 								buff, sahandle);
8643034Sdougm 				    }
8653034Sdougm 				}
8663034Sdougm 			    }
8673034Sdougm 			}
8683034Sdougm 		    }
8693034Sdougm 		}
8703034Sdougm 	    }
8713034Sdougm 	}
8723034Sdougm 	if (iter != NULL)
8733034Sdougm 	    scf_iter_destroy(iter);
8743034Sdougm 	if (buff != NULL)
8753034Sdougm 	    free(buff);
8763034Sdougm 	return (ret);
8773034Sdougm }
8783034Sdougm 
8793034Sdougm /*
8803034Sdougm  * sa_extract_defaults(root, handle, instance)
8813034Sdougm  *
8823034Sdougm  * local function to find the default properties that live in the
8833034Sdougm  * default instance's "operation" proprerty group.
8843034Sdougm  */
8853034Sdougm 
8863034Sdougm static void
8873034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
8883034Sdougm 		    scf_instance_t *instance)
8893034Sdougm {
8903034Sdougm 	xmlNodePtr node;
8913034Sdougm 	scf_property_t *prop;
8923034Sdougm 	scf_value_t *value;
8933034Sdougm 	char *valuestr;
8943034Sdougm 	ssize_t vallen;
8953034Sdougm 
8963034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
8973034Sdougm 	prop = scf_property_create(handle->handle);
8983034Sdougm 	value = scf_value_create(handle->handle);
8993034Sdougm 	valuestr = malloc(vallen);
9003034Sdougm 	if (prop != NULL && value != NULL && vallen != NULL &&
9013034Sdougm 	    scf_instance_get_pg(instance, "operation",
9023034Sdougm 				handle->pg) == 0) {
9033034Sdougm 	    if (scf_pg_get_property(handle->pg,
9043034Sdougm 				    "legacy-timestamp", prop) == 0) {
9053034Sdougm 		/* found the property so get the value */
9063034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
9073034Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) > 0) {
9083034Sdougm 			node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
9093034Sdougm 					    NULL);
9103034Sdougm 			if (node != NULL) {
9113034Sdougm 			    xmlSetProp(node, (xmlChar *)"timestamp",
9123034Sdougm 					(xmlChar *)valuestr);
9133034Sdougm 			    xmlSetProp(node, (xmlChar *)"path",
9143034Sdougm 					(xmlChar *)SA_LEGACY_DFSTAB);
9153034Sdougm 			}
9163034Sdougm 		    }
9173034Sdougm 		}
9183034Sdougm 	    }
9193034Sdougm 	}
9203034Sdougm 	if (valuestr != NULL)
9213034Sdougm 	    free(valuestr);
9223034Sdougm 	if (value != NULL)
9233034Sdougm 	    scf_value_destroy(value);
9243034Sdougm 	if (prop != NULL)
9253034Sdougm 	    scf_property_destroy(prop);
9263034Sdougm }
9273034Sdougm 
9283034Sdougm 
9293034Sdougm /*
9303910Sdougm  * sa_get_config(handle, root, doc, sahandlec)
9313034Sdougm  *
9323034Sdougm  * walk the SMF repository for /network/shares/group and find all the
9333034Sdougm  * instances. These become group names.  Then add the XML structure
9343034Sdougm  * below the groups based on property groups and properties.
9353034Sdougm  */
9363034Sdougm int
937*3973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
9383034Sdougm {
9393034Sdougm 	int ret = SA_OK;
9403034Sdougm 	scf_instance_t *instance;
9413034Sdougm 	scf_iter_t *iter;
9423034Sdougm 	char buff[BUFSIZ * 2];
9433034Sdougm 
9443034Sdougm 	instance = scf_instance_create(handle->handle);
9453034Sdougm 	iter = scf_iter_create(handle->handle);
946*3973Sdougm 	if (instance != NULL && iter != NULL) {
9473034Sdougm 	    if ((ret = scf_iter_service_instances(iter,
9483034Sdougm 						    handle->service)) == 0) {
9493034Sdougm 		while ((ret = scf_iter_next_instance(iter,
9503034Sdougm 							instance)) > 0) {
9513034Sdougm 		    if (scf_instance_get_name(instance, buff,
9523034Sdougm 						sizeof (buff)) > 0) {
9533034Sdougm 			if (strcmp(buff, "default") == 0)
954*3973Sdougm 			    sa_extract_defaults(root, handle, instance);
955*3973Sdougm 			ret = sa_extract_group(root, handle, instance,
9563910Sdougm 						sahandle);
9573034Sdougm 		    }
9583034Sdougm 		}
9593034Sdougm 	    }
9603034Sdougm 	}
961*3973Sdougm 
9623034Sdougm 	/* always cleanup these */
9633034Sdougm 	if (instance != NULL)
9643034Sdougm 	    scf_instance_destroy(instance);
9653034Sdougm 	if (iter != NULL)
9663034Sdougm 	    scf_iter_destroy(iter);
9673034Sdougm 	return (ret);
9683034Sdougm }
9693034Sdougm 
9703034Sdougm /*
9713034Sdougm  * sa_get_instance(handle, instance)
9723034Sdougm  *
9733034Sdougm  * get the instance of the group service. This is actually the
9743034Sdougm  * specific group name. The instance is needed for all property and
9753034Sdougm  * control operations.
9763034Sdougm  */
9773034Sdougm 
9783034Sdougm int
9793034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
9803034Sdougm {
9813034Sdougm 	if (scf_service_get_instance(handle->service, instname,
9823034Sdougm 					handle->instance) != 0) {
9833034Sdougm 	    return (SA_NO_SUCH_GROUP);
9843034Sdougm 	}
9853034Sdougm 	return (SA_OK);
9863034Sdougm }
9873034Sdougm 
9883034Sdougm /*
9893034Sdougm  * sa_create_instance(handle, instname)
9903034Sdougm  *
9913034Sdougm  * Create a new SMF service instance. There can only be one with a
9923034Sdougm  * given name.
9933034Sdougm  */
9943034Sdougm 
9953034Sdougm int
9963034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
9973034Sdougm {
9983034Sdougm 	int ret = SA_OK;
9993034Sdougm 	char instance[SA_GROUP_INST_LEN];
10003034Sdougm 	if (scf_service_add_instance(handle->service, instname,
10013034Sdougm 					handle->instance) != 0) {
10023034Sdougm 	/* better error returns need to be added based on real error */
10033034Sdougm 	    if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
10043034Sdougm 		ret = SA_NO_PERMISSION;
10053034Sdougm 	    else
10063034Sdougm 		ret = SA_DUPLICATE_NAME;
10073034Sdougm 	} else {
10083034Sdougm 	    /* have the service created, so enable it */
10093034Sdougm 	    (void) snprintf(instance, sizeof (instance), "%s:%s",
10103034Sdougm 				SA_SVC_FMRI_BASE, instname);
10113034Sdougm 	    (void) smf_enable_instance(instance, 0);
10123034Sdougm 	}
10133034Sdougm 	return (ret);
10143034Sdougm }
10153034Sdougm 
10163034Sdougm /*
10173034Sdougm  * sa_delete_instance(handle, instname)
10183034Sdougm  *
10193034Sdougm  * When a group goes away, we also remove the service instance.
10203034Sdougm  */
10213034Sdougm 
10223034Sdougm int
10233034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
10243034Sdougm {
10253034Sdougm 	int ret;
10263034Sdougm 
10273034Sdougm 	if (strcmp(instname, "default") == 0) {
10283034Sdougm 	    ret = SA_NO_PERMISSION;
10293034Sdougm 	} else {
10303034Sdougm 	    if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
10313034Sdougm 		if (scf_instance_delete(handle->instance) != 0)
10323034Sdougm 			/* need better analysis */
10333034Sdougm 		    ret = SA_NO_PERMISSION;
10343034Sdougm 	    }
10353034Sdougm 	}
10363034Sdougm 	return (ret);
10373034Sdougm }
10383034Sdougm 
10393034Sdougm /*
10403034Sdougm  * sa_create_pgroup(handle, pgroup)
10413034Sdougm  *
10423034Sdougm  * create a new property group
10433034Sdougm  */
10443034Sdougm 
10453034Sdougm int
10463034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
10473034Sdougm {
10483034Sdougm 	int ret = SA_OK;
10493034Sdougm 	/*
10503034Sdougm 	 * only create a handle if it doesn't exist. It is ok to exist
10513034Sdougm 	 * since the pg handle will be set as a side effect.
10523034Sdougm 	 */
10533034Sdougm 	if (handle->pg == NULL) {
10543034Sdougm 	    handle->pg = scf_pg_create(handle->handle);
10553034Sdougm 	}
10563034Sdougm 	/*
10573034Sdougm 	 * if the pgroup exists, we are done. If it doesn't, then we
10583034Sdougm 	 * need to actually add one to the service instance.
10593034Sdougm 	 */
10603034Sdougm 	if (scf_instance_get_pg(handle->instance,
10613034Sdougm 				pgroup, handle->pg) != 0) {
10623034Sdougm 	    /* doesn't exist so create one */
10633034Sdougm 	    if (scf_instance_add_pg(handle->instance, pgroup,
10643034Sdougm 				    SCF_GROUP_APPLICATION, 0,
10653034Sdougm 				    handle->pg) != 0) {
10663034Sdougm 		switch (scf_error()) {
10673034Sdougm 		case SCF_ERROR_PERMISSION_DENIED:
10683034Sdougm 		    ret = SA_NO_PERMISSION;
10693034Sdougm 		    break;
10703034Sdougm 		default:
10713034Sdougm 		    ret = SA_SYSTEM_ERR;
10723034Sdougm 		    break;
10733034Sdougm 		}
10743034Sdougm 	    }
10753034Sdougm 	}
10763034Sdougm 	return (ret);
10773034Sdougm }
10783034Sdougm 
10793034Sdougm /*
10803034Sdougm  * sa_delete_pgroup(handle, pgroup)
10813034Sdougm  *
10823034Sdougm  * remove the property group from the current instance of the service,
10833034Sdougm  * but only if it actually exists.
10843034Sdougm  */
10853034Sdougm 
10863034Sdougm int
10873034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
10883034Sdougm {
10893034Sdougm 	int ret = SA_OK;
10903034Sdougm 	/*
10913034Sdougm 	 * only delete if it does exist.
10923034Sdougm 	 */
10933034Sdougm 	if (scf_instance_get_pg(handle->instance,
10943034Sdougm 				pgroup, handle->pg) == 0) {
10953034Sdougm 	    /* does exist so delete it */
10963034Sdougm 	    if (scf_pg_delete(handle->pg) != 0) {
10973034Sdougm 		ret = SA_SYSTEM_ERR;
10983034Sdougm 	    }
10993034Sdougm 	} else {
11003034Sdougm 	    ret = SA_SYSTEM_ERR;
11013034Sdougm 	}
11023034Sdougm 	if (ret == SA_SYSTEM_ERR &&
11033034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
11043034Sdougm 		ret = SA_NO_PERMISSION;
11053034Sdougm 	}
11063034Sdougm 	return (ret);
11073034Sdougm }
11083034Sdougm 
11093034Sdougm /*
11103034Sdougm  * sa_start_transaction(handle, pgroup)
11113034Sdougm  *
11123034Sdougm  * Start an SMF transaction so we can deal with properties. it would
11133034Sdougm  * be nice to not have to expose this, but we have to in order to
11143034Sdougm  * optimize.
11153034Sdougm  *
11163034Sdougm  * Basic model is to hold the transaction in the handle and allow
11173034Sdougm  * property adds/deletes/updates to be added then close the
11183034Sdougm  * transaction (or abort).  There may eventually be a need to handle
11193034Sdougm  * other types of transaction mechanisms but we don't do that now.
11203034Sdougm  *
11213034Sdougm  * An sa_start_transaction must be followed by either an
11223034Sdougm  * sa_end_transaction or sa_abort_transaction before another
11233034Sdougm  * sa_start_transaction can be done.
11243034Sdougm  */
11253034Sdougm 
11263034Sdougm int
11273034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
11283034Sdougm {
11293034Sdougm 	int ret = SA_OK;
11303034Sdougm 	/*
11313034Sdougm 	 * lookup the property group and create it if it doesn't already
11323034Sdougm 	 * exist.
11333034Sdougm 	 */
11343034Sdougm 	if (handle->scf_state == SCH_STATE_INIT) {
11353034Sdougm 	    ret = sa_create_pgroup(handle, propgroup);
11363034Sdougm 	    if (ret == SA_OK) {
11373034Sdougm 		handle->trans = scf_transaction_create(handle->handle);
11383034Sdougm 		if (handle->trans != NULL) {
11393034Sdougm 		    if (scf_transaction_start(handle->trans, handle->pg) != 0) {
11403034Sdougm 			ret = SA_SYSTEM_ERR;
11413034Sdougm 		    }
11423034Sdougm 		    if (ret != SA_OK) {
11433034Sdougm 			scf_transaction_destroy(handle->trans);
11443034Sdougm 			handle->trans = NULL;
11453034Sdougm 		    }
11463034Sdougm 		} else {
11473034Sdougm 		    ret = SA_SYSTEM_ERR;
11483034Sdougm 		}
11493034Sdougm 	    }
11503034Sdougm 	}
11513034Sdougm 	if (ret == SA_SYSTEM_ERR &&
11523034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
11533034Sdougm 		ret = SA_NO_PERMISSION;
11543034Sdougm 	}
11553034Sdougm 	return (ret);
11563034Sdougm }
11573034Sdougm 
11583034Sdougm /*
11593034Sdougm  * sa_end_transaction(handle)
11603034Sdougm  *
11613034Sdougm  * Commit the changes that were added to the transaction in the
11623034Sdougm  * handle. Do all necessary cleanup.
11633034Sdougm  */
11643034Sdougm 
11653034Sdougm int
11663034Sdougm sa_end_transaction(scfutilhandle_t *handle)
11673034Sdougm {
11683034Sdougm 	int ret = SA_OK;
11693034Sdougm 
11703034Sdougm 	if (handle->trans == NULL) {
11713034Sdougm 	    ret = SA_SYSTEM_ERR;
11723034Sdougm 	} else {
11733034Sdougm 	    if (scf_transaction_commit(handle->trans) < 0)
11743034Sdougm 		ret = SA_SYSTEM_ERR;
11753034Sdougm 	    scf_transaction_destroy_children(handle->trans);
11763034Sdougm 	    scf_transaction_destroy(handle->trans);
11773034Sdougm 	    handle->trans = NULL;
11783034Sdougm 	}
11793034Sdougm 	return (ret);
11803034Sdougm }
11813034Sdougm 
11823034Sdougm /*
11833034Sdougm  * sa_abort_transaction(handle)
11843034Sdougm  *
11853034Sdougm  * Abort the changes that were added to the transaction in the
11863034Sdougm  * handle. Do all necessary cleanup.
11873034Sdougm  */
11883034Sdougm 
11893034Sdougm void
11903034Sdougm sa_abort_transaction(scfutilhandle_t *handle)
11913034Sdougm {
11923034Sdougm 	if (handle->trans != NULL) {
11933034Sdougm 	    scf_transaction_reset_all(handle->trans);
11943034Sdougm 	    scf_transaction_destroy_children(handle->trans);
11953034Sdougm 	    scf_transaction_destroy(handle->trans);
11963034Sdougm 	    handle->trans = NULL;
11973034Sdougm 	}
11983034Sdougm }
11993034Sdougm 
12003034Sdougm /*
12013034Sdougm  * sa_set_property(handle, prop, value)
12023034Sdougm  *
12033034Sdougm  * set a property transaction entry into the pending SMF transaction.
12043034Sdougm  */
12053034Sdougm 
12063034Sdougm int
12073034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
12083034Sdougm {
12093034Sdougm 	int ret = SA_OK;
12103034Sdougm 	scf_value_t *value;
12113034Sdougm 	scf_transaction_entry_t *entry;
12123034Sdougm 	/*
12133034Sdougm 	 * properties must be set in transactions and don't take
12143034Sdougm 	 * effect until the transaction has been ended/committed.
12153034Sdougm 	 */
12163034Sdougm 	value = scf_value_create(handle->handle);
12173034Sdougm 	entry = scf_entry_create(handle->handle);
12183034Sdougm 	if (value != NULL && entry != NULL) {
12193034Sdougm 	    if (scf_transaction_property_change(handle->trans, entry,
12203034Sdougm 						propname,
12213034Sdougm 						SCF_TYPE_ASTRING) == 0 ||
12223034Sdougm 		scf_transaction_property_new(handle->trans, entry,
12233034Sdougm 						propname,
12243034Sdougm 						SCF_TYPE_ASTRING) == 0) {
12253034Sdougm 		if (scf_value_set_astring(value, valstr) == 0) {
12263034Sdougm 		    if (scf_entry_add_value(entry, value) != 0) {
12273034Sdougm 			ret = SA_SYSTEM_ERR;
12283034Sdougm 			scf_value_destroy(value);
12293034Sdougm 		    }
12303034Sdougm 		    /* the value is in the transaction */
12313034Sdougm 		    value = NULL;
12323034Sdougm 		} else {
12333034Sdougm 		    /* value couldn't be constructed */
12343034Sdougm 		    ret = SA_SYSTEM_ERR;
12353034Sdougm 		}
12363034Sdougm 		/* the entry is in the transaction */
12373034Sdougm 		entry = NULL;
12383034Sdougm 	    } else {
12393034Sdougm 		ret = SA_SYSTEM_ERR;
12403034Sdougm 	    }
12413034Sdougm 	} else {
12423034Sdougm 	    ret = SA_SYSTEM_ERR;
12433034Sdougm 	}
12443034Sdougm 	if (ret == SA_SYSTEM_ERR) {
12453034Sdougm 	    switch (scf_error()) {
12463034Sdougm 	    case SCF_ERROR_PERMISSION_DENIED:
12473034Sdougm 		ret = SA_NO_PERMISSION;
12483034Sdougm 		break;
12493034Sdougm 	    }
12503034Sdougm 	}
12513034Sdougm 	/*
12523034Sdougm 	 * cleanup if there were any errors that didn't leave these
12533034Sdougm 	 * values where they would be cleaned up later.
12543034Sdougm 	 */
12553034Sdougm 	if (value != NULL)
12563034Sdougm 	    scf_value_destroy(value);
12573034Sdougm 	if (entry != NULL)
12583034Sdougm 	    scf_entry_destroy(entry);
12593034Sdougm 	return (ret);
12603034Sdougm }
12613034Sdougm 
12623034Sdougm /*
12633034Sdougm  * sa_commit_share(handle, group, share)
12643034Sdougm  *
12653034Sdougm  *	commit this share to the repository.
12663034Sdougm  *	properties are added if they exist but can be added later.
12673034Sdougm  *	Need to add to dfstab and sharetab, if appropriate.
12683034Sdougm  */
12693034Sdougm int
12703034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
12713034Sdougm {
12723034Sdougm 	int ret = SA_OK;
12733034Sdougm 	char *groupname;
12743034Sdougm 	char *name;
12753034Sdougm 	char *resource;
12763034Sdougm 	char *description;
12773034Sdougm 	char *sharename;
12783034Sdougm 	ssize_t proplen;
12793034Sdougm 	char *propstring;
12803034Sdougm 
12813034Sdougm 	/*
12823034Sdougm 	 * don't commit in the zfs group. We do commit legacy
12833034Sdougm 	 * (default) and all other groups/shares. ZFS is handled
12843034Sdougm 	 * through the ZFS configuration rather than SMF.
12853034Sdougm 	 */
12863034Sdougm 
12873034Sdougm 	groupname = sa_get_group_attr(group, "name");
12883034Sdougm 	if (groupname != NULL) {
12893034Sdougm 	    if (strcmp(groupname, "zfs") == 0) {
12903034Sdougm 		/*
12913034Sdougm 		 * adding to the ZFS group will result in the sharenfs
12923034Sdougm 		 * property being set but we don't want to do anything
12933034Sdougm 		 * SMF related at this point.
12943034Sdougm 		 */
12953034Sdougm 		sa_free_attr_string(groupname);
12963034Sdougm 		return (ret);
12973034Sdougm 	    }
12983034Sdougm 	}
12993034Sdougm 
13003034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
13013034Sdougm 	propstring = malloc(proplen);
13023034Sdougm 	if (propstring == NULL)
13033034Sdougm 	    ret = SA_NO_MEMORY;
13043034Sdougm 
13053034Sdougm 	if (groupname != NULL && ret == SA_OK) {
13063034Sdougm 	    ret = sa_get_instance(handle, groupname);
13073034Sdougm 	    sa_free_attr_string(groupname);
13083034Sdougm 	    groupname = NULL;
13093034Sdougm 	    sharename = sa_get_share_attr(share, "id");
13103034Sdougm 	    if (sharename == NULL) {
13113034Sdougm 		/* slipped by */
13123034Sdougm 		char shname[SA_SHARE_UUID_BUFLEN];
13133034Sdougm 		generate_unique_sharename(shname);
13143034Sdougm 		xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
13153034Sdougm 			    (xmlChar *)shname);
13163034Sdougm 		sharename = strdup(shname);
13173034Sdougm 	    }
13183034Sdougm 	    if (sharename != NULL) {
13193348Sdougm 		sigset_t old, new;
13203034Sdougm 		/*
13213348Sdougm 		 * have a share name allocated so create a pgroup for
13223348Sdougm 		 * it. It may already exist, but that is OK.  In order
13233348Sdougm 		 * to avoid creating a share pgroup that doesn't have
13243348Sdougm 		 * a path property, block signals around the critical
13253348Sdougm 		 * region of creating the share pgroup and props.
13263034Sdougm 		 */
13273348Sdougm 		(void) sigprocmask(SIG_BLOCK, NULL, &new);
13283348Sdougm 		(void) sigaddset(&new, SIGHUP);
13293348Sdougm 		(void) sigaddset(&new, SIGINT);
13303348Sdougm 		(void) sigaddset(&new, SIGQUIT);
13313348Sdougm 		(void) sigaddset(&new, SIGTSTP);
13323348Sdougm 		(void) sigprocmask(SIG_SETMASK, &new, &old);
13333348Sdougm 
13343034Sdougm 		ret = sa_create_pgroup(handle, sharename);
13353034Sdougm 		if (ret == SA_OK) {
13363034Sdougm 			/*
13373034Sdougm 			 * now start the transaction for the
13383034Sdougm 			 * properties that define this share. They may
13393034Sdougm 			 * exist so attempt to update before create.
13403034Sdougm 			 */
13413034Sdougm 		    ret = sa_start_transaction(handle, sharename);
13423034Sdougm 		}
13433034Sdougm 		if (ret == SA_OK) {
13443034Sdougm 		    name = sa_get_share_attr(share, "path");
13453034Sdougm 		    if (name != NULL) {
13463034Sdougm 			/* there needs to be a path for a share to exist */
13473034Sdougm 			ret = sa_set_property(handle, "path", name);
13483034Sdougm 			sa_free_attr_string(name);
13493034Sdougm 		    } else {
13503034Sdougm 			ret = SA_NO_MEMORY;
13513034Sdougm 		    }
13523034Sdougm 		}
13533034Sdougm 		if (ret == SA_OK) {
13543034Sdougm 		    resource = sa_get_share_attr(share, "resource");
13553034Sdougm 		    if (resource != NULL) {
13563034Sdougm 			ret = sa_set_property(handle, "resource", resource);
13573034Sdougm 			sa_free_attr_string(resource);
13583034Sdougm 		    }
13593034Sdougm 		}
13603034Sdougm 		if (ret == SA_OK) {
13613034Sdougm 		    description = sa_get_share_description(share);
13623034Sdougm 		    if (description != NULL) {
13633034Sdougm 			ret = sa_set_property(handle, "description",
13643034Sdougm 						description);
13653034Sdougm 			sa_free_share_description(description);
13663034Sdougm 		    }
13673034Sdougm 		}
13683034Sdougm 		/* make sure we cleanup the transaction */
13693034Sdougm 		if (ret == SA_OK) {
13703034Sdougm 		    ret = sa_end_transaction(handle);
13713034Sdougm 		} else {
13723034Sdougm 		    sa_abort_transaction(handle);
13733034Sdougm 		}
13743348Sdougm 
13753348Sdougm 		(void) sigprocmask(SIG_SETMASK, &old, NULL);
13763348Sdougm 
13773034Sdougm 		free(sharename);
13783034Sdougm 	    }
13793034Sdougm 	}
13803034Sdougm 	if (ret == SA_SYSTEM_ERR) {
13813034Sdougm 	    int err = scf_error();
13823034Sdougm 	    if (err == SCF_ERROR_PERMISSION_DENIED)
13833034Sdougm 		ret = SA_NO_PERMISSION;
13843034Sdougm 	}
13853034Sdougm 	if (propstring != NULL)
13863034Sdougm 	    free(propstring);
13873034Sdougm 	if (groupname != NULL)
13883034Sdougm 	    sa_free_attr_string(groupname);
13893034Sdougm 
13903034Sdougm 	return (ret);
13913034Sdougm }
13923034Sdougm 
13933034Sdougm /*
13943034Sdougm  * sa_delete_share(handle, group, share)
13953034Sdougm  *
13963034Sdougm  * remove the specified share from the group (and service instance).
13973034Sdougm  */
13983034Sdougm 
13993034Sdougm int
14003034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
14013034Sdougm {
14023034Sdougm 	int ret = SA_OK;
14033034Sdougm 	char *groupname = NULL;
14043034Sdougm 	char *shareid = NULL;
14053034Sdougm 	sa_optionset_t opt;
14063034Sdougm 	sa_security_t sec;
14073034Sdougm 	ssize_t proplen;
14083034Sdougm 	char *propstring;
14093034Sdougm 
14103034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
14113034Sdougm 	propstring = malloc(proplen);
14123034Sdougm 	if (propstring == NULL)
14133034Sdougm 	    ret = SA_NO_MEMORY;
14143034Sdougm 
14153034Sdougm 	if (ret == SA_OK) {
14163034Sdougm 	    groupname = sa_get_group_attr(group, "name");
14173034Sdougm 	    shareid = sa_get_share_attr(share, "id");
14183034Sdougm 	    if (groupname != NULL && shareid != NULL) {
14193034Sdougm 		ret = sa_get_instance(handle, groupname);
14203034Sdougm 		if (ret == SA_OK) {
14213034Sdougm 		    /* if a share has properties, remove them */
14223034Sdougm 		    ret = sa_delete_pgroup(handle, shareid);
14233034Sdougm 		    for (opt = sa_get_optionset(share, NULL); opt != NULL;
14243034Sdougm 			opt = sa_get_next_optionset(opt)) {
14253034Sdougm 			char *proto;
14263034Sdougm 			proto = sa_get_optionset_attr(opt, "type");
14273034Sdougm 			if (proto != NULL) {
14283034Sdougm 			    (void) snprintf(propstring, proplen, "%s_%s",
14293034Sdougm 						shareid, proto);
14303034Sdougm 			    ret = sa_delete_pgroup(handle, propstring);
14313034Sdougm 			    sa_free_attr_string(proto);
14323034Sdougm 			} else {
14333034Sdougm 			    ret = SA_NO_MEMORY;
14343034Sdougm 			}
14353034Sdougm 		    }
14363034Sdougm 			/*
14373034Sdougm 			 * if a share has security/negotiable
14383034Sdougm 			 * properties, remove them.
14393034Sdougm 			 */
14403034Sdougm 		    for (sec = sa_get_security(share, NULL, NULL); sec != NULL;
14413034Sdougm 			sec = sa_get_next_security(sec)) {
14423034Sdougm 			char *proto;
14433034Sdougm 			char *sectype;
14443034Sdougm 			proto = sa_get_security_attr(sec, "type");
14453034Sdougm 			sectype = sa_get_security_attr(sec, "sectype");
14463034Sdougm 			if (proto != NULL && sectype != NULL) {
14473034Sdougm 			    (void) snprintf(propstring, proplen, "%s_%s_%s",
14483034Sdougm 					shareid,
14493034Sdougm 					proto, sectype);
14503034Sdougm 			    ret = sa_delete_pgroup(handle, propstring);
14513034Sdougm 			} else {
14523034Sdougm 			    ret = SA_NO_MEMORY;
14533034Sdougm 			}
14543034Sdougm 			if (proto != NULL)
14553034Sdougm 			    sa_free_attr_string(proto);
14563034Sdougm 			if (sectype != NULL)
14573034Sdougm 			    sa_free_attr_string(sectype);
14583034Sdougm 		    }
14593034Sdougm 		}
14603034Sdougm 	    } else {
14613034Sdougm 		ret = SA_CONFIG_ERR;
14623034Sdougm 	    }
14633034Sdougm 	}
14643034Sdougm 	if (groupname != NULL)
14653034Sdougm 	    sa_free_attr_string(groupname);
14663034Sdougm 	if (shareid != NULL)
14673034Sdougm 	    sa_free_attr_string(shareid);
14683034Sdougm 	if (propstring != NULL)
14693034Sdougm 	    free(propstring);
14703034Sdougm 
14713034Sdougm 	return (ret);
14723034Sdougm }
1473