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