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