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 /*
235951Sdougm  * Copyright 2008 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>
385331Samw #include <ctype.h>
393034Sdougm #include <errno.h>
403034Sdougm #include <uuid/uuid.h>
413034Sdougm #include <sys/param.h>
423348Sdougm #include <signal.h>
435951Sdougm #include <sys/time.h>
445997Sdougm #include <libintl.h>
453034Sdougm 
463034Sdougm ssize_t scf_max_name_len;
473034Sdougm extern struct sa_proto_plugin *sap_proto_list;
483910Sdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
495951Sdougm static void set_transaction_tstamp(sa_handle_impl_t);
503034Sdougm /*
513034Sdougm  * The SMF facility uses some properties that must exist. We want to
523034Sdougm  * skip over these when processing protocol options.
533034Sdougm  */
543034Sdougm static char *skip_props[] = {
553034Sdougm 	"modify_authorization",
563034Sdougm 	"action_authorization",
573034Sdougm 	"value_authorization",
583034Sdougm 	NULL
593034Sdougm };
603034Sdougm 
613034Sdougm /*
623034Sdougm  * sa_scf_fini(handle)
633034Sdougm  *
644653Sdougm  * Must be called when done. Called with the handle allocated in
653034Sdougm  * sa_scf_init(), it cleans up the state and frees any SCF resources
663034Sdougm  * still in use. Called by sa_fini().
673034Sdougm  */
683034Sdougm 
693034Sdougm void
703034Sdougm sa_scf_fini(scfutilhandle_t *handle)
713034Sdougm {
723034Sdougm 	if (handle != NULL) {
734653Sdougm 		int unbind = 0;
744653Sdougm 		if (handle->scope != NULL) {
754653Sdougm 			unbind = 1;
764653Sdougm 			scf_scope_destroy(handle->scope);
774653Sdougm 		}
784653Sdougm 		if (handle->instance != NULL)
794653Sdougm 			scf_instance_destroy(handle->instance);
804653Sdougm 		if (handle->service != NULL)
814653Sdougm 			scf_service_destroy(handle->service);
824653Sdougm 		if (handle->pg != NULL)
834653Sdougm 			scf_pg_destroy(handle->pg);
844653Sdougm 		if (handle->handle != NULL) {
854653Sdougm 			handle->scf_state = SCH_STATE_UNINIT;
864653Sdougm 			if (unbind)
874653Sdougm 				(void) scf_handle_unbind(handle->handle);
884653Sdougm 			scf_handle_destroy(handle->handle);
894653Sdougm 		}
904653Sdougm 		free(handle);
913034Sdougm 	}
923034Sdougm }
933034Sdougm 
943034Sdougm /*
953034Sdougm  * sa_scf_init()
963034Sdougm  *
974653Sdougm  * Must be called before using any of the SCF functions. Called by
983034Sdougm  * sa_init() during the API setup.
993034Sdougm  */
1003034Sdougm 
1013034Sdougm scfutilhandle_t *
1023910Sdougm sa_scf_init(sa_handle_impl_t ihandle)
1033034Sdougm {
1043034Sdougm 	scfutilhandle_t *handle;
1053034Sdougm 
1063034Sdougm 	scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1073034Sdougm 	if (scf_max_name_len <= 0)
1084653Sdougm 		scf_max_name_len = SA_MAX_NAME_LEN + 1;
1093034Sdougm 
1103034Sdougm 	handle = calloc(1, sizeof (scfutilhandle_t));
1114653Sdougm 	if (handle == NULL)
1124653Sdougm 		return (handle);
1134345Sdougm 
1144653Sdougm 	ihandle->scfhandle = handle;
1154653Sdougm 	handle->scf_state = SCH_STATE_INITIALIZING;
1164653Sdougm 	handle->handle = scf_handle_create(SCF_VERSION);
1174653Sdougm 	if (handle->handle == NULL) {
1183034Sdougm 		free(handle);
1193034Sdougm 		handle = NULL;
1203034Sdougm 		(void) printf("libshare could not access SMF repository: %s\n",
1214653Sdougm 		    scf_strerror(scf_error()));
1224653Sdougm 		return (handle);
1233034Sdougm 	}
1244653Sdougm 	if (scf_handle_bind(handle->handle) != 0)
1254653Sdougm 		goto err;
1264653Sdougm 
1274653Sdougm 	handle->scope = scf_scope_create(handle->handle);
1284653Sdougm 	handle->service = scf_service_create(handle->handle);
1294653Sdougm 	handle->pg = scf_pg_create(handle->handle);
1304653Sdougm 
1314653Sdougm 	/* Make sure we have sufficient SMF running */
1324653Sdougm 	handle->instance = scf_instance_create(handle->handle);
1334653Sdougm 	if (handle->scope == NULL || handle->service == NULL ||
1344653Sdougm 	    handle->pg == NULL || handle->instance == NULL)
1354653Sdougm 		goto err;
1364653Sdougm 	if (scf_handle_get_scope(handle->handle,
1374653Sdougm 	    SCF_SCOPE_LOCAL, handle->scope) != 0)
1384653Sdougm 		goto err;
1394653Sdougm 	if (scf_scope_get_service(handle->scope,
1404653Sdougm 	    SA_GROUP_SVC_NAME, handle->service) != 0)
1414653Sdougm 		goto err;
1424653Sdougm 
1434653Sdougm 	handle->scf_state = SCH_STATE_INIT;
1444653Sdougm 	if (sa_get_instance(handle, "default") != SA_OK) {
1454653Sdougm 		sa_group_t defgrp;
1464653Sdougm 		defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL);
1475997Sdougm 		/* Only NFS enabled for "default" group. */
1485997Sdougm 		if (defgrp != NULL)
1495997Sdougm 			(void) sa_create_optionset(defgrp, "nfs");
1504653Sdougm 	}
1514653Sdougm 
1523034Sdougm 	return (handle);
1533034Sdougm 
1544653Sdougm 	/* Error handling/unwinding */
1553034Sdougm err:
1563034Sdougm 	(void) sa_scf_fini(handle);
1573034Sdougm 	(void) printf("libshare SMF initialization problem: %s\n",
1584653Sdougm 	    scf_strerror(scf_error()));
1593034Sdougm 	return (NULL);
1603034Sdougm }
1613034Sdougm 
1623034Sdougm /*
1633034Sdougm  * get_scf_limit(name)
1643034Sdougm  *
1653034Sdougm  * Since we use  scf_limit a lot and do the same  check and return the
1663034Sdougm  * same  value  if  it  fails,   implement  as  a  function  for  code
1673034Sdougm  * simplification.  Basically, if  name isn't found, return MAXPATHLEN
1683034Sdougm  * (1024) so we have a reasonable default buffer size.
1693034Sdougm  */
1703034Sdougm static ssize_t
1713034Sdougm get_scf_limit(uint32_t name)
1723034Sdougm {
1733034Sdougm 	ssize_t vallen;
1743034Sdougm 
1753034Sdougm 	vallen = scf_limit(name);
1763034Sdougm 	if (vallen == (ssize_t)-1)
1774653Sdougm 		vallen = MAXPATHLEN;
1783034Sdougm 	return (vallen);
1793034Sdougm }
1803034Sdougm 
1813034Sdougm /*
1823034Sdougm  * skip_property(name)
1833034Sdougm  *
1844653Sdougm  * Internal function to check to see if a property is an SMF magic
1853034Sdougm  * property that needs to be skipped.
1863034Sdougm  */
1873034Sdougm static int
1883034Sdougm skip_property(char *name)
1893034Sdougm {
1903034Sdougm 	int i;
1913034Sdougm 
1923034Sdougm 	for (i = 0; skip_props[i] != NULL; i++)
1934653Sdougm 		if (strcmp(name, skip_props[i]) == 0)
1943034Sdougm 		return (1);
1953034Sdougm 	return (0);
1963034Sdougm }
1973034Sdougm 
1983034Sdougm /*
1993034Sdougm  * generate_unique_sharename(sharename)
2003034Sdougm  *
2013034Sdougm  * Shares are represented in SMF as property groups. Due to share
2023034Sdougm  * paths containing characters that are not allowed in SMF names and
2033034Sdougm  * the need to be unique, we use UUIDs to construct a unique name.
2043034Sdougm  */
2053034Sdougm 
2063034Sdougm static void
2073034Sdougm generate_unique_sharename(char *sharename)
2083034Sdougm {
2093034Sdougm 	uuid_t uuid;
2103034Sdougm 
2113034Sdougm 	uuid_generate(uuid);
2123034Sdougm 	(void) strcpy(sharename, "S-");
2133034Sdougm 	uuid_unparse(uuid, sharename + 2);
2143034Sdougm }
2153034Sdougm 
2163034Sdougm /*
2173034Sdougm  * valid_protocol(proto)
2183034Sdougm  *
2194653Sdougm  * Check to see if the specified protocol is a valid one for the
2203034Sdougm  * general sharemgr facility. We determine this by checking which
2213034Sdougm  * plugin protocols were found.
2223034Sdougm  */
2233034Sdougm 
2243034Sdougm static int
2253034Sdougm valid_protocol(char *proto)
2263034Sdougm {
2273034Sdougm 	struct sa_proto_plugin *plugin;
2283034Sdougm 	for (plugin = sap_proto_list; plugin != NULL;
2293034Sdougm 	    plugin = plugin->plugin_next)
2304653Sdougm 		if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
2314653Sdougm 			return (1);
2323034Sdougm 	return (0);
2333034Sdougm }
2343034Sdougm 
2353034Sdougm /*
2363034Sdougm  * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
2373034Sdougm  *
2384653Sdougm  * Extract the name property group and create the specified type of
2393034Sdougm  * node on the provided group.  type will be optionset or security.
2403034Sdougm  */
2413034Sdougm 
2423034Sdougm static int
2433034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
2443034Sdougm 			scf_propertygroup_t *pg,
2453034Sdougm 			char *nodetype, char *proto, char *sectype)
2463034Sdougm {
2473034Sdougm 	xmlNodePtr node;
2483034Sdougm 	scf_iter_t *iter;
2493034Sdougm 	scf_property_t *prop;
2503034Sdougm 	scf_value_t *value;
2513034Sdougm 	char *name;
2523034Sdougm 	char *valuestr;
2533034Sdougm 	ssize_t vallen;
2543034Sdougm 	int ret = SA_OK;
2553034Sdougm 
2563034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2573034Sdougm 
2583034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
2594653Sdougm 	if (node == NULL)
2604653Sdougm 		return (ret);
2614653Sdougm 
2624653Sdougm 	if (proto != NULL)
263*6012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
2644653Sdougm 	if (sectype != NULL)
265*6012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"sectype",
266*6012Sthurlow 		    (xmlChar *)sectype);
2674653Sdougm 	/*
2684653Sdougm 	 * Have node to work with so iterate over the properties
2694653Sdougm 	 * in the pg and create option sub nodes.
2704653Sdougm 	 */
2714653Sdougm 	iter = scf_iter_create(handle->handle);
2724653Sdougm 	value = scf_value_create(handle->handle);
2734653Sdougm 	prop = scf_property_create(handle->handle);
2744653Sdougm 	name = malloc(scf_max_name_len);
2754653Sdougm 	valuestr = malloc(vallen);
2764653Sdougm 	/*
2774653Sdougm 	 * Want to iterate through the properties and add them
2784653Sdougm 	 * to the base optionset.
2794653Sdougm 	 */
2804653Sdougm 	if (iter == NULL || value == NULL || prop == NULL ||
2814653Sdougm 	    valuestr == NULL || name == NULL) {
2824653Sdougm 		ret = SA_NO_MEMORY;
2834653Sdougm 		goto out;
2844653Sdougm 	}
2854653Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
2864653Sdougm 		/* Now iterate the properties in the group */
2874653Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
2884653Sdougm 			/* have a property */
2894653Sdougm 			if (scf_property_get_name(prop, name,
2904653Sdougm 			    scf_max_name_len) > 0) {
2914653Sdougm 				sa_property_t saprop;
2924653Sdougm 				/* Some properties are part of the framework */
2933034Sdougm 				if (skip_property(name))
2944653Sdougm 					continue;
2954653Sdougm 				if (scf_property_get_value(prop, value) != 0)
2964653Sdougm 					continue;
2974653Sdougm 				if (scf_value_get_astring(value, valuestr,
2984653Sdougm 				    vallen) < 0)
2994653Sdougm 					continue;
3004653Sdougm 				saprop = sa_create_property(name, valuestr);
3014653Sdougm 				if (saprop != NULL) {
3023034Sdougm 					/*
3034653Sdougm 					 * Since in SMF, don't
3043034Sdougm 					 * recurse. Use xmlAddChild
3053034Sdougm 					 * directly, instead.
3063034Sdougm 					 */
307*6012Sthurlow 					(void) xmlAddChild(node,
3084653Sdougm 					    (xmlNodePtr) saprop);
3093034Sdougm 				}
3103034Sdougm 			}
3113034Sdougm 		}
3123034Sdougm 	}
3134653Sdougm out:
3144653Sdougm 	/* cleanup to avoid memory leaks */
3154653Sdougm 	if (value != NULL)
3164653Sdougm 		scf_value_destroy(value);
3174653Sdougm 	if (iter != NULL)
3184653Sdougm 		scf_iter_destroy(iter);
3194653Sdougm 	if (prop != NULL)
3204653Sdougm 		scf_property_destroy(prop);
3214653Sdougm 	if (name != NULL)
3224653Sdougm 		free(name);
3234653Sdougm 	if (valuestr != NULL)
3244653Sdougm 		free(valuestr);
3254653Sdougm 
3263034Sdougm 	return (ret);
3273034Sdougm }
3283034Sdougm 
3293034Sdougm /*
3303034Sdougm  * sa_extract_attrs(root, handle, instance)
3313034Sdougm  *
3324653Sdougm  * Local function to extract the actual attributes/properties from the
3333034Sdougm  * property group of the service instance. These are the well known
3343034Sdougm  * attributes of "state" and "zfs". If additional attributes are
3353034Sdougm  * added, they should be added here.
3363034Sdougm  */
3373034Sdougm 
3383034Sdougm static void
3393034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
3403034Sdougm 		    scf_instance_t *instance)
3413034Sdougm {
3423034Sdougm 	scf_property_t *prop;
3433034Sdougm 	scf_value_t *value;
3443034Sdougm 	char *valuestr;
3453034Sdougm 	ssize_t vallen;
3463034Sdougm 
3473034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3483034Sdougm 	prop = scf_property_create(handle->handle);
3493034Sdougm 	value = scf_value_create(handle->handle);
3503034Sdougm 	valuestr = malloc(vallen);
3514653Sdougm 	if (prop == NULL || value == NULL || valuestr == NULL ||
3524653Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0) {
3534653Sdougm 		goto out;
3544653Sdougm 	}
3554653Sdougm 	/*
3564653Sdougm 	 * Have a property group with desired name so now get
3574653Sdougm 	 * the known attributes.
3584653Sdougm 	 */
3594653Sdougm 	if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
3604653Sdougm 		/* Found the property so get the value */
3613034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
3624653Sdougm 			if (scf_value_get_astring(value, valuestr,
3634653Sdougm 			    vallen) >= 0) {
364*6012Sthurlow 				(void) xmlSetProp(root, (xmlChar *)"state",
3653034Sdougm 				    (xmlChar *)valuestr);
3664653Sdougm 			}
3673034Sdougm 		}
3684653Sdougm 	}
3694653Sdougm 	if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
3704653Sdougm 		/* Found the property so get the value */
3713034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
3724653Sdougm 			if (scf_value_get_astring(value, valuestr,
3734653Sdougm 			    vallen) > 0) {
374*6012Sthurlow 				(void) xmlSetProp(root, (xmlChar *)"zfs",
3753034Sdougm 				    (xmlChar *)valuestr);
3764653Sdougm 			}
3773034Sdougm 		}
3783034Sdougm 	}
3794653Sdougm out:
3803034Sdougm 	if (valuestr != NULL)
3814653Sdougm 		free(valuestr);
3823034Sdougm 	if (value != NULL)
3834653Sdougm 		scf_value_destroy(value);
3843034Sdougm 	if (prop != NULL)
3854653Sdougm 		scf_property_destroy(prop);
3863034Sdougm }
3873034Sdougm 
3883034Sdougm /*
3894653Sdougm  * List of known share attributes.
3903034Sdougm  */
3913034Sdougm 
3923034Sdougm static char *share_attr[] = {
3933034Sdougm 	"path",
3943034Sdougm 	"id",
3955331Samw 	"drive-letter",
3965331Samw 	"exclude",
3973034Sdougm 	NULL,
3983034Sdougm };
3993034Sdougm 
4003034Sdougm static int
4013034Sdougm is_share_attr(char *name)
4023034Sdougm {
4033034Sdougm 	int i;
4043034Sdougm 	for (i = 0; share_attr[i] != NULL; i++)
4054653Sdougm 		if (strcmp(name, share_attr[i]) == 0)
4064653Sdougm 			return (1);
4073034Sdougm 	return (0);
4083034Sdougm }
4093034Sdougm 
4103034Sdougm /*
4115331Samw  * _sa_make_resource(node, valuestr)
4125331Samw  *
4135331Samw  * Make a resource node on the share node. The valusestr will either
4145331Samw  * be old format (SMF acceptable string) or new format (pretty much an
4155331Samw  * arbitrary string with "nnn:" prefixing in order to persist
4165331Samw  * mapping). The input valuestr will get modified in place. This is
4175331Samw  * only used in SMF repository parsing. A possible third field will be
4185331Samw  * a "description" string.
4195331Samw  */
4205331Samw 
4215331Samw static void
4225331Samw _sa_make_resource(xmlNodePtr node, char *valuestr)
4235331Samw {
4245331Samw 	char *idx;
4255331Samw 	char *name;
4265331Samw 	char *description = NULL;
4275331Samw 
4285331Samw 	idx = valuestr;
4295331Samw 	name = strchr(valuestr, ':');
4305331Samw 	if (name == NULL) {
4315331Samw 		/* this is old form so give an index of "0" */
4325331Samw 		idx = "0";
4335331Samw 		name = valuestr;
4345331Samw 	} else {
4355331Samw 		/* NUL the ':' and move past it */
4365331Samw 		*name++ = '\0';
4375331Samw 		/* There could also be a description string */
4385331Samw 		description = strchr(name, ':');
4395331Samw 		if (description != NULL)
4405331Samw 			*description++ = '\0';
4415331Samw 	}
4425331Samw 	node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
4435331Samw 	if (node != NULL) {
444*6012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
445*6012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
4465331Samw 		/* SMF values are always persistent */
447*6012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"type",
448*6012Sthurlow 		    (xmlChar *)"persist");
4495331Samw 		if (description != NULL && strlen(description) > 0) {
4505331Samw 			(void) xmlNewChild(node, NULL, (xmlChar *)"description",
4515331Samw 			    (xmlChar *)description);
4525331Samw 		}
4535331Samw 	}
4545331Samw }
4555331Samw 
4565331Samw 
4575331Samw /*
4583034Sdougm  * sa_share_from_pgroup
4593034Sdougm  *
4604653Sdougm  * Extract the share definition from the share property group. We do
4613034Sdougm  * some sanity checking to avoid bad data.
4623034Sdougm  *
4633034Sdougm  * Since this is only constructing the internal data structures, we
4643034Sdougm  * don't use the sa_* functions most of the time.
4653034Sdougm  */
4663034Sdougm void
4673034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
4683034Sdougm 			scf_propertygroup_t *pg, char *id)
4693034Sdougm {
4703034Sdougm 	xmlNodePtr node;
4713034Sdougm 	char *name;
4723034Sdougm 	scf_iter_t *iter;
4733034Sdougm 	scf_property_t *prop;
4743034Sdougm 	scf_value_t *value;
4753034Sdougm 	ssize_t vallen;
4763034Sdougm 	char *valuestr;
4773034Sdougm 	int ret = SA_OK;
4783348Sdougm 	int have_path = 0;
4793034Sdougm 
4803034Sdougm 	/*
4813034Sdougm 	 * While preliminary check (starts with 'S') passed before
4823034Sdougm 	 * getting here. Need to make sure it is in ID syntax
4833034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
4843034Sdougm 	 * pgroups.
4853034Sdougm 	 */
4863034Sdougm 	vallen = strlen(id);
4873034Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
4884653Sdougm 		uuid_t uuid;
4894653Sdougm 		if (strncmp(id, SA_SHARE_PG_PREFIX,
4904653Sdougm 		    SA_SHARE_PG_PREFIXLEN) != 0 ||
4914653Sdougm 		    uuid_parse(id + 2, uuid) < 0)
4924653Sdougm 			return;
4934653Sdougm 	} else {
4943034Sdougm 		return;
4953034Sdougm 	}
4963034Sdougm 
4973034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
4983034Sdougm 
4993034Sdougm 	iter = scf_iter_create(handle->handle);
5003034Sdougm 	value = scf_value_create(handle->handle);
5013034Sdougm 	prop = scf_property_create(handle->handle);
5023034Sdougm 	name = malloc(scf_max_name_len);
5033034Sdougm 	valuestr = malloc(vallen);
5043034Sdougm 
5053034Sdougm 	/*
5064653Sdougm 	 * Construct the share XML node. It is similar to sa_add_share
5073034Sdougm 	 * but never changes the repository. Also, there won't be any
5083034Sdougm 	 * ZFS or transient shares.  Root will be the group it is
5093034Sdougm 	 * associated with.
5103034Sdougm 	 */
5113034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
5123034Sdougm 	if (node != NULL) {
5133034Sdougm 		/*
5144653Sdougm 		 * Make sure the UUID part of the property group is
5153034Sdougm 		 * stored in the share "id" property. We use this
5163034Sdougm 		 * later.
5173034Sdougm 		 */
518*6012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
519*6012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"type",
520*6012Sthurlow 		    (xmlChar *)"persist");
5213034Sdougm 	}
5223034Sdougm 
5234653Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
5244653Sdougm 		goto out;
5254653Sdougm 
5264653Sdougm 	/* Iterate over the share pg properties */
5274653Sdougm 	if (scf_iter_pg_properties(iter, pg) != 0)
5284653Sdougm 		goto out;
5294653Sdougm 
5304653Sdougm 	while (scf_iter_next_property(iter, prop) > 0) {
5314653Sdougm 		ret = SA_SYSTEM_ERR; /* assume the worst */
5324653Sdougm 		if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
5333034Sdougm 			if (scf_property_get_value(prop, value) == 0) {
5344653Sdougm 				if (scf_value_get_astring(value, valuestr,
5354653Sdougm 				    vallen) >= 0) {
5364653Sdougm 					ret = SA_OK;
5374653Sdougm 				}
5385331Samw 			} else if (strcmp(name, "resource") == 0) {
5395331Samw 				ret = SA_OK;
5403034Sdougm 			}
5414653Sdougm 		}
5425331Samw 		if (ret != SA_OK)
5435331Samw 			continue;
5445331Samw 		/*
5455331Samw 		 * Check that we have the "path" property in
5465331Samw 		 * name. The string in name will always be nul
5475331Samw 		 * terminated if scf_property_get_name()
5485331Samw 		 * succeeded.
5495331Samw 		 */
5505331Samw 		if (strcmp(name, "path") == 0)
5515331Samw 			have_path = 1;
5525331Samw 		if (is_share_attr(name)) {
5533348Sdougm 			/*
5545331Samw 			 * If a share attr, then simple -
5555331Samw 			 * usually path and id name
5563348Sdougm 			 */
557*6012Sthurlow 			(void) xmlSetProp(node, (xmlChar *)name,
5585331Samw 			    (xmlChar *)valuestr);
5595331Samw 		} else if (strcmp(name, "resource") == 0) {
5605331Samw 			/*
5615331Samw 			 * Resource names handled differently since
5625331Samw 			 * there can be multiple on each share. The
5635331Samw 			 * "resource" id must be preserved since this
5645331Samw 			 * will be used by some protocols in mapping
5655331Samw 			 * "property spaces" to names and is always
5665331Samw 			 * used to create SMF property groups specific
5675331Samw 			 * to resources.  CIFS needs this.  The first
5685331Samw 			 * value is present so add and then loop for
5695331Samw 			 * any additional. Since this is new and
5705331Samw 			 * previous values may exist, handle
5715331Samw 			 * conversions.
5725331Samw 			 */
5735331Samw 			scf_iter_t *viter;
5745331Samw 			viter = scf_iter_create(handle->handle);
5755331Samw 			if (viter != NULL &&
5765331Samw 			    scf_iter_property_values(viter, prop) == 0) {
5775331Samw 				while (scf_iter_next_value(viter, value) > 0) {
5785331Samw 					/* Have a value so process it */
5795331Samw 					if (scf_value_get_ustring(value,
5805331Samw 					    valuestr, vallen) >= 0) {
5815331Samw 						/* have a ustring */
5825331Samw 						_sa_make_resource(node,
5835331Samw 						    valuestr);
5845331Samw 					} else if (scf_value_get_astring(value,
5855331Samw 					    valuestr, vallen) >= 0) {
5865331Samw 						/* have an astring */
5875331Samw 						_sa_make_resource(node,
5885331Samw 						    valuestr);
5895331Samw 					}
5904653Sdougm 				}
5915331Samw 				scf_iter_destroy(viter);
5925331Samw 			}
5935331Samw 		} else {
5945331Samw 			if (strcmp(name, "description") == 0) {
5955331Samw 				/* We have a description node */
5965331Samw 				xmlNodePtr desc;
5975331Samw 				desc = xmlNewChild(node, NULL,
5985331Samw 				    (xmlChar *)"description", NULL);
5995331Samw 				if (desc != NULL)
6005331Samw 					xmlNodeSetContent(desc,
6015331Samw 					    (xmlChar *)valuestr);
6023034Sdougm 			}
6033034Sdougm 		}
6043034Sdougm 	}
6054653Sdougm out:
6063348Sdougm 	/*
6074653Sdougm 	 * A share without a path is broken so we want to not include
6083348Sdougm 	 * these.  They shouldn't happen but if you kill a sharemgr in
6093348Sdougm 	 * the process of creating a share, it could happen.  They
6103348Sdougm 	 * should be harmless.  It is also possible that another
6113348Sdougm 	 * sharemgr is running and in the process of creating a share.
6123348Sdougm 	 */
6133348Sdougm 	if (have_path == 0 && node != NULL) {
6144653Sdougm 		xmlUnlinkNode(node);
6154653Sdougm 		xmlFreeNode(node);
6163348Sdougm 	}
6173034Sdougm 	if (name != NULL)
6184653Sdougm 		free(name);
6193034Sdougm 	if (valuestr != NULL)
6204653Sdougm 		free(valuestr);
6213034Sdougm 	if (value != NULL)
6224653Sdougm 		scf_value_destroy(value);
6233034Sdougm 	if (iter != NULL)
6244653Sdougm 		scf_iter_destroy(iter);
6253034Sdougm 	if (prop != NULL)
6264653Sdougm 		scf_property_destroy(prop);
6273034Sdougm }
6283034Sdougm 
6293034Sdougm /*
6303034Sdougm  * find_share_by_id(shareid)
6313034Sdougm  *
6323034Sdougm  * Search all shares in all groups until we find the share represented
6333034Sdougm  * by "id".
6343034Sdougm  */
6353034Sdougm 
6363034Sdougm static sa_share_t
6373910Sdougm find_share_by_id(sa_handle_t handle, char *shareid)
6383034Sdougm {
6393034Sdougm 	sa_group_t group;
6403034Sdougm 	sa_share_t share = NULL;
6413034Sdougm 	char *id = NULL;
6423034Sdougm 	int done = 0;
6433034Sdougm 
6444653Sdougm 	for (group = sa_get_group(handle, NULL);
6454653Sdougm 	    group != NULL && !done;
6464653Sdougm 	    group = sa_get_next_group(group)) {
6474653Sdougm 		for (share = sa_get_share(group, NULL);
6484653Sdougm 		    share != NULL;
6494653Sdougm 		    share = sa_get_next_share(share)) {
6503034Sdougm 			id = sa_get_share_attr(share, "id");
6513034Sdougm 			if (id != NULL && strcmp(id, shareid) == 0) {
6523034Sdougm 				sa_free_attr_string(id);
6533034Sdougm 				id = NULL;
6543034Sdougm 				done++;
6553034Sdougm 				break;
6563034Sdougm 			}
6573034Sdougm 			if (id != NULL) {
6584653Sdougm 				sa_free_attr_string(id);
6594653Sdougm 				id = NULL;
6603034Sdougm 			}
6613034Sdougm 		}
6623034Sdougm 	}
6633034Sdougm 	return (share);
6643034Sdougm }
6653034Sdougm 
6663034Sdougm /*
6675331Samw  * find_resource_by_index(share, index)
6685331Samw  *
6695331Samw  * Search the resource records on the share for the id index.
6705331Samw  */
6715331Samw static sa_resource_t
6725331Samw find_resource_by_index(sa_share_t share, char *index)
6735331Samw {
6745331Samw 	sa_resource_t resource;
6755331Samw 	sa_resource_t found = NULL;
6765331Samw 	char *id;
6775331Samw 
6785331Samw 	for (resource = sa_get_share_resource(share, NULL);
6795331Samw 	    resource != NULL && found == NULL;
6805331Samw 	    resource = sa_get_next_resource(resource)) {
6815331Samw 		id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
6825331Samw 		if (id != NULL) {
6835331Samw 			if (strcmp(id, index) == 0) {
6845331Samw 				/* found it so save in "found" */
6855331Samw 				found = resource;
6865331Samw 			}
6875331Samw 			sa_free_attr_string(id);
6885331Samw 		}
6895331Samw 	}
6905331Samw 	return (found);
6915331Samw }
6925331Samw 
6935331Samw /*
6945331Samw  * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
6953034Sdougm  *
6964653Sdougm  * Extract share properties from the SMF property group. More sanity
6973034Sdougm  * checks are done and the share object is created. We ignore some
6983034Sdougm  * errors that could exist in the repository and only worry about
6993034Sdougm  * property groups that validate in naming.
7003034Sdougm  */
7013034Sdougm 
7023034Sdougm static int
7033034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
7043910Sdougm 			scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
7053034Sdougm {
7063034Sdougm 	xmlNodePtr node;
7074653Sdougm 	char *name = NULL;
7084653Sdougm 	scf_iter_t *iter = NULL;
7094653Sdougm 	scf_property_t *prop = NULL;
7104653Sdougm 	scf_value_t *value = NULL;
7113034Sdougm 	ssize_t vallen;
7124653Sdougm 	char *valuestr = NULL;
7133034Sdougm 	int ret = SA_OK;
7143034Sdougm 	char *sectype = NULL;
7153034Sdougm 	char *proto;
7163034Sdougm 	sa_share_t share;
7174653Sdougm 	uuid_t uuid;
7183034Sdougm 
7193034Sdougm 	/*
7203034Sdougm 	 * While preliminary check (starts with 'S') passed before
7213034Sdougm 	 * getting here. Need to make sure it is in ID syntax
7223034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
7233034Sdougm 	 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
7243034Sdougm 	 * characters, it is likely one of the protocol/security
7253034Sdougm 	 * versions.
7263034Sdougm 	 */
7273034Sdougm 	vallen = strlen(id);
7284653Sdougm 	if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) {
7294653Sdougm 		/*
7304653Sdougm 		 * It is ok to not have what we thought since someone might
7314653Sdougm 		 * have added a name via SMF.
7324653Sdougm 		 */
7334653Sdougm 		return (ret);
7344653Sdougm 	}
7354653Sdougm 	if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
7363034Sdougm 		proto = strchr(id, '_');
7373034Sdougm 		if (proto == NULL)
7384653Sdougm 			return (ret);
7393034Sdougm 		*proto++ = '\0';
7403034Sdougm 		if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
7414653Sdougm 			return (ret);
7423034Sdougm 		/*
7433034Sdougm 		 * probably a legal optionset so check a few more
7443034Sdougm 		 * syntax points below.
7453034Sdougm 		 */
7463034Sdougm 		if (*proto == '\0') {
7474653Sdougm 			/* not a valid proto (null) */
7484653Sdougm 			return (ret);
7493034Sdougm 		}
7505331Samw 
7513034Sdougm 		sectype = strchr(proto, '_');
7523034Sdougm 		if (sectype != NULL)
7534653Sdougm 			*sectype++ = '\0';
7543034Sdougm 		if (!valid_protocol(proto))
7554653Sdougm 			return (ret);
7563034Sdougm 	}
7573034Sdougm 
7583034Sdougm 	/*
7594653Sdougm 	 * To get here, we have a valid protocol and possibly a
7603034Sdougm 	 * security. We now have to find the share that it is really
7613034Sdougm 	 * associated with. The "id" portion of the pgroup name will
7623034Sdougm 	 * match.
7633034Sdougm 	 */
7643034Sdougm 
7653910Sdougm 	share = find_share_by_id(sahandle, id);
7663034Sdougm 	if (share == NULL)
7674653Sdougm 		return (SA_BAD_PATH);
7683034Sdougm 
7693034Sdougm 	root = (xmlNodePtr)share;
7703034Sdougm 
7713034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
7723034Sdougm 
7734653Sdougm 	if (sectype == NULL)
7744653Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
7754653Sdougm 	else {
7765331Samw 		if (isdigit((int)*sectype)) {
7775331Samw 			sa_resource_t resource;
7785331Samw 			/*
7795331Samw 			 * If sectype[0] is a digit, then it is an index into
7805331Samw 			 * the resource names. We need to find a resource
7815331Samw 			 * record and then get the properties into an
7825331Samw 			 * optionset. The optionset becomes the "node" and the
7835331Samw 			 * rest is hung off of the share.
7845331Samw 			 */
7855331Samw 			resource = find_resource_by_index(share, sectype);
7865331Samw 			if (resource != NULL) {
7875331Samw 				node = xmlNewChild(resource, NULL,
7885331Samw 				    (xmlChar *)"optionset", NULL);
7895331Samw 			} else {
7905521Sas200622 				/* This shouldn't happen. */
7915331Samw 				ret = SA_SYSTEM_ERR;
7925521Sas200622 				goto out;
7935331Samw 			}
7945331Samw 		} else {
7955331Samw 			/*
7965331Samw 			 * If not a digit, then it is a security type
7975331Samw 			 * (alternate option space). Security types start with
7985331Samw 			 * an alphabetic.
7995331Samw 			 */
8005331Samw 			node = xmlNewChild(root, NULL, (xmlChar *)"security",
8015331Samw 			    NULL);
8025331Samw 			if (node != NULL)
803*6012Sthurlow 				(void) xmlSetProp(node, (xmlChar *)"sectype",
8045331Samw 				    (xmlChar *)sectype);
8055331Samw 		}
8064653Sdougm 	}
8074653Sdougm 	if (node == NULL) {
8084653Sdougm 		ret = SA_NO_MEMORY;
8094653Sdougm 		goto out;
8104653Sdougm 	}
8114653Sdougm 
812*6012Sthurlow 	(void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
8134653Sdougm 	/* now find the properties */
8143034Sdougm 	iter = scf_iter_create(handle->handle);
8153034Sdougm 	value = scf_value_create(handle->handle);
8163034Sdougm 	prop = scf_property_create(handle->handle);
8173034Sdougm 	name = malloc(scf_max_name_len);
8183034Sdougm 	valuestr = malloc(vallen);
8193034Sdougm 
8204653Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
8214653Sdougm 		goto out;
8224653Sdougm 
8235331Samw 	/* iterate over the share pg properties */
8244653Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
8254653Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
8263034Sdougm 			ret = SA_SYSTEM_ERR; /* assume the worst */
8273034Sdougm 			if (scf_property_get_name(prop, name,
8284653Sdougm 			    scf_max_name_len) > 0) {
8294653Sdougm 				if (scf_property_get_value(prop, value) == 0) {
8304653Sdougm 					if (scf_value_get_astring(value,
8314653Sdougm 					    valuestr, vallen) >= 0) {
8324653Sdougm 						ret = SA_OK;
8334653Sdougm 					}
8343034Sdougm 				}
8353034Sdougm 			} else {
8364653Sdougm 				ret = SA_SYSTEM_ERR;
8373034Sdougm 			}
8383034Sdougm 			if (ret == SA_OK) {
8394653Sdougm 				sa_property_t prop;
8404653Sdougm 				prop = sa_create_property(name, valuestr);
8414653Sdougm 				if (prop != NULL)
8424653Sdougm 					prop = (sa_property_t)xmlAddChild(node,
8434653Sdougm 					    (xmlNodePtr)prop);
8444653Sdougm 				else
8454653Sdougm 					ret = SA_NO_MEMORY;
8463034Sdougm 			}
8473034Sdougm 		}
8483034Sdougm 	} else {
8494653Sdougm 		ret = SA_SYSTEM_ERR;
8503034Sdougm 	}
8514653Sdougm out:
8523034Sdougm 	if (iter != NULL)
8534653Sdougm 		scf_iter_destroy(iter);
8543034Sdougm 	if (value != NULL)
8554653Sdougm 		scf_value_destroy(value);
8563034Sdougm 	if (prop != NULL)
8574653Sdougm 		scf_property_destroy(prop);
8583034Sdougm 	if (name != NULL)
8594653Sdougm 		free(name);
8603034Sdougm 	if (valuestr != NULL)
8614653Sdougm 		free(valuestr);
8623034Sdougm 	return (ret);
8633034Sdougm }
8643034Sdougm 
8653034Sdougm /*
8663034Sdougm  * sa_extract_group(root, handle, instance)
8673034Sdougm  *
8684653Sdougm  * Get the config info for this instance of a group and create the XML
8693034Sdougm  * subtree from it.
8703034Sdougm  */
8713034Sdougm 
8723034Sdougm static int
8733034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
8745951Sdougm     scf_instance_t *instance, sa_handle_t sahandle)
8753034Sdougm {
8763034Sdougm 	char *buff;
8773034Sdougm 	xmlNodePtr node;
8783034Sdougm 	scf_iter_t *iter;
8793034Sdougm 	char *proto;
8803034Sdougm 	char *sectype;
8815997Sdougm 	boolean_t have_shares = B_FALSE;
8825997Sdougm 	boolean_t is_default = B_FALSE;
8835997Sdougm 	boolean_t is_nfs = B_FALSE;
8843034Sdougm 	int ret = SA_OK;
8853034Sdougm 	int err;
8863034Sdougm 
8873034Sdougm 	buff = malloc(scf_max_name_len);
8884653Sdougm 	if (buff == NULL)
8894653Sdougm 		return (SA_NO_MEMORY);
8904653Sdougm 
8913034Sdougm 	iter = scf_iter_create(handle->handle);
8924653Sdougm 	if (iter == NULL) {
8934653Sdougm 		ret = SA_NO_MEMORY;
8944653Sdougm 		goto out;
8954653Sdougm 	}
8964653Sdougm 
8974653Sdougm 	if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
8983034Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
8994653Sdougm 		if (node == NULL) {
9004653Sdougm 			ret = SA_NO_MEMORY;
9014653Sdougm 			goto out;
9024653Sdougm 		}
903*6012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
9044653Sdougm 		if (strcmp(buff, "default") == 0)
9055997Sdougm 			is_default = B_TRUE;
9064653Sdougm 
9074653Sdougm 		sa_extract_attrs(node, handle, instance);
9084653Sdougm 		/*
9094653Sdougm 		 * Iterate through all the property groups
9104653Sdougm 		 * looking for those with security or
9114653Sdougm 		 * optionset prefixes. The names of the
9124653Sdougm 		 * matching pgroups are parsed to get the
9134653Sdougm 		 * protocol, and for security, the sectype.
9144653Sdougm 		 * Syntax is as follows:
9154653Sdougm 		 *    optionset | optionset_<proto>
9164653Sdougm 		 *    security_default | security_<proto>_<sectype>
9174653Sdougm 		 * "operation" is handled by
9184653Sdougm 		 * sa_extract_attrs().
9194653Sdougm 		 */
9204653Sdougm 		if (scf_iter_instance_pgs(iter, instance) != 0) {
9214653Sdougm 			ret = SA_NO_MEMORY;
9224653Sdougm 			goto out;
9234653Sdougm 		}
9244653Sdougm 		while (scf_iter_next_pg(iter, handle->pg) > 0) {
9254653Sdougm 			/* Have a pgroup so sort it out */
9264653Sdougm 			ret = scf_pg_get_name(handle->pg, buff,
9274653Sdougm 			    scf_max_name_len);
9285997Sdougm 			if (ret <= 0)
9295997Sdougm 				continue;
9305997Sdougm 			is_nfs = B_FALSE;
9315997Sdougm 
9325997Sdougm 			if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
9335997Sdougm 				sa_share_from_pgroup(node, handle,
9345997Sdougm 				    handle->pg, buff);
9355997Sdougm 				have_shares = B_TRUE;
9365997Sdougm 			} else if (strncmp(buff, "optionset", 9) == 0) {
9375997Sdougm 				char *nodetype = "optionset";
9385997Sdougm 				/* Have an optionset */
9395997Sdougm 				sectype = NULL;
9405997Sdougm 				proto = strchr(buff, '_');
9415997Sdougm 				if (proto != NULL) {
9425997Sdougm 					*proto++ = '\0';
9435997Sdougm 					sectype = strchr(proto, '_');
9445997Sdougm 					if (sectype != NULL) {
9455997Sdougm 						*sectype++ = '\0';
9465997Sdougm 						nodetype = "security";
9473034Sdougm 					}
9485997Sdougm 					is_nfs = strcmp(proto, "nfs") == 0;
9495997Sdougm 				} else if (strlen(buff) > 9) {
9505997Sdougm 					/*
9515997Sdougm 					 * This can only occur if
9525997Sdougm 					 * someone has made changes
9535997Sdougm 					 * via an SMF command. Since
9545997Sdougm 					 * this would be an unknown
9555997Sdougm 					 * syntax, we just ignore it.
9565997Sdougm 					 */
9575997Sdougm 					continue;
9585997Sdougm 				}
9595997Sdougm 				/*
9605997Sdougm 				 * If the group is not "default" or is
9615997Sdougm 				 * "default" and is_nfs, then extract the
9625997Sdougm 				 * pgroup.  If it is_default and !is_nfs,
9635997Sdougm 				 * then we have an error and should remove
9645997Sdougm 				 * the extraneous protocols.  We don't care
9655997Sdougm 				 * about errors on scf_pg_delete since we
9665997Sdougm 				 * might not have permission during an
9675997Sdougm 				 * extract only.
9685997Sdougm 				 */
9695997Sdougm 				if (!is_default || is_nfs) {
9703034Sdougm 					ret = sa_extract_pgroup(node, handle,
9714653Sdougm 					    handle->pg, nodetype, proto,
9724653Sdougm 					    sectype);
9735997Sdougm 				} else {
9745997Sdougm 					err = scf_pg_delete(handle->pg);
9755997Sdougm 					if (err == 0)
9765997Sdougm 						(void) fprintf(stderr,
9775997Sdougm 						    dgettext(TEXT_DOMAIN,
9785997Sdougm 						    "Removed protocol \"%s\" "
9795997Sdougm 						    "from group \"default\"\n"),
9805997Sdougm 						    proto);
9813034Sdougm 				}
9825997Sdougm 			} else if (strncmp(buff, "security", 8) == 0) {
9835997Sdougm 				/*
9845997Sdougm 				 * Have a security (note that
9855997Sdougm 				 * this should change in the
9865997Sdougm 				 * future)
9875997Sdougm 				 */
9885997Sdougm 				proto = strchr(buff, '_');
9895997Sdougm 				sectype = NULL;
9905997Sdougm 				if (proto != NULL) {
9915997Sdougm 					*proto++ = '\0';
9925997Sdougm 					sectype = strchr(proto, '_');
9935997Sdougm 					if (sectype != NULL)
9945997Sdougm 						*sectype++ = '\0';
9955997Sdougm 					if (strcmp(proto, "default") == 0)
9965997Sdougm 						proto = NULL;
9975997Sdougm 				}
9985997Sdougm 				ret = sa_extract_pgroup(node, handle,
9995997Sdougm 				    handle->pg, "security", proto, sectype);
10003034Sdougm 			}
10015997Sdougm 			/* Ignore everything else */
10024653Sdougm 		}
10034653Sdougm 		/*
10044653Sdougm 		 * Make sure we have a valid default group.
10054653Sdougm 		 * On first boot, default won't have any
10064653Sdougm 		 * protocols defined and won't be enabled (but
10075997Sdougm 		 * should be).  "default" only has NFS enabled on it.
10084653Sdougm 		 */
10094653Sdougm 		if (is_default) {
10104653Sdougm 			char *state = sa_get_group_attr((sa_group_t)node,
10114653Sdougm 			    "state");
10123034Sdougm 
10134653Sdougm 			if (state == NULL) {
10143034Sdougm 				/* set attribute to enabled */
10153034Sdougm 				(void) sa_set_group_attr((sa_group_t)node,
10164653Sdougm 				    "state", "enabled");
10175997Sdougm 				(void) sa_create_optionset((sa_group_t)node,
10185997Sdougm 				    "nfs");
10194653Sdougm 			} else {
10203034Sdougm 				sa_free_attr_string(state);
10213034Sdougm 			}
10224653Sdougm 		}
10234653Sdougm 		/* Do a second pass if shares were found */
10244653Sdougm 		if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) {
10254653Sdougm 			while (scf_iter_next_pg(iter, handle->pg) > 0) {
10263034Sdougm 				/*
10274653Sdougm 				 * Have a pgroup so see if it is a
10283034Sdougm 				 * share optionset
10293034Sdougm 				 */
10303034Sdougm 				err = scf_pg_get_name(handle->pg, buff,
10314653Sdougm 				    scf_max_name_len);
10324653Sdougm 				if (err  <= 0)
10334653Sdougm 					continue;
10344653Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
10353034Sdougm 					ret = sa_share_props_from_pgroup(node,
10364653Sdougm 					    handle, handle->pg, buff,
10374653Sdougm 					    sahandle);
10383034Sdougm 				}
10393034Sdougm 			}
10403034Sdougm 		}
10413034Sdougm 	}
10424653Sdougm out:
10433034Sdougm 	if (iter != NULL)
10444653Sdougm 		scf_iter_destroy(iter);
10453034Sdougm 	if (buff != NULL)
10464653Sdougm 		free(buff);
10473034Sdougm 	return (ret);
10483034Sdougm }
10493034Sdougm 
10503034Sdougm /*
10513034Sdougm  * sa_extract_defaults(root, handle, instance)
10523034Sdougm  *
10534653Sdougm  * Local function to find the default properties that live in the
10545331Samw  * default instance's "operation" property group.
10553034Sdougm  */
10563034Sdougm 
10573034Sdougm static void
10583034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
10593034Sdougm 		    scf_instance_t *instance)
10603034Sdougm {
10613034Sdougm 	xmlNodePtr node;
10623034Sdougm 	scf_property_t *prop;
10633034Sdougm 	scf_value_t *value;
10643034Sdougm 	char *valuestr;
10653034Sdougm 	ssize_t vallen;
10663034Sdougm 
10673034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
10683034Sdougm 	prop = scf_property_create(handle->handle);
10693034Sdougm 	value = scf_value_create(handle->handle);
10703034Sdougm 	valuestr = malloc(vallen);
10714653Sdougm 
10724653Sdougm 	if (prop == NULL || value == NULL || vallen == 0 ||
10734653Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0)
10744653Sdougm 		goto out;
10754653Sdougm 
10764653Sdougm 	if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0)
10774653Sdougm 		goto out;
10784653Sdougm 
10794653Sdougm 	/* Found the property so get the value */
10804653Sdougm 	if (scf_property_get_value(prop, value) == 0) {
10814653Sdougm 		if (scf_value_get_astring(value, valuestr, vallen) > 0) {
10823034Sdougm 			node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
10834653Sdougm 			    NULL);
10843034Sdougm 			if (node != NULL) {
1085*6012Sthurlow 				(void) xmlSetProp(node, (xmlChar *)"timestamp",
10864653Sdougm 				    (xmlChar *)valuestr);
1087*6012Sthurlow 				(void) xmlSetProp(node, (xmlChar *)"path",
10884653Sdougm 				    (xmlChar *)SA_LEGACY_DFSTAB);
10893034Sdougm 			}
10903034Sdougm 		}
10913034Sdougm 	}
10924653Sdougm out:
10933034Sdougm 	if (valuestr != NULL)
10944653Sdougm 		free(valuestr);
10953034Sdougm 	if (value != NULL)
10964653Sdougm 		scf_value_destroy(value);
10973034Sdougm 	if (prop != NULL)
10984653Sdougm 		scf_property_destroy(prop);
10993034Sdougm }
11003034Sdougm 
11013034Sdougm 
11023034Sdougm /*
11035331Samw  * sa_get_config(handle, root, doc, sahandle)
11043034Sdougm  *
11054653Sdougm  * Walk the SMF repository for /network/shares/group and find all the
11063034Sdougm  * instances. These become group names.  Then add the XML structure
11073034Sdougm  * below the groups based on property groups and properties.
11083034Sdougm  */
11093034Sdougm int
11103973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
11113034Sdougm {
11123034Sdougm 	int ret = SA_OK;
11133034Sdougm 	scf_instance_t *instance;
11143034Sdougm 	scf_iter_t *iter;
11153034Sdougm 	char buff[BUFSIZ * 2];
11163034Sdougm 
11173034Sdougm 	instance = scf_instance_create(handle->handle);
11183034Sdougm 	iter = scf_iter_create(handle->handle);
11193973Sdougm 	if (instance != NULL && iter != NULL) {
11204653Sdougm 		if ((ret = scf_iter_service_instances(iter,
11214653Sdougm 		    handle->service)) == 0) {
11224653Sdougm 			while ((ret = scf_iter_next_instance(iter,
11234653Sdougm 			    instance)) > 0) {
11244653Sdougm 				if (scf_instance_get_name(instance, buff,
11254653Sdougm 				    sizeof (buff)) > 0) {
11264653Sdougm 					if (strcmp(buff, "default") == 0)
11274653Sdougm 						sa_extract_defaults(root,
11284653Sdougm 						    handle, instance);
11294653Sdougm 					ret = sa_extract_group(root, handle,
11304653Sdougm 					    instance, sahandle);
11314653Sdougm 				}
11324653Sdougm 			}
11333034Sdougm 		}
11343034Sdougm 	}
11353973Sdougm 
11364653Sdougm 	/* Always cleanup these */
11373034Sdougm 	if (instance != NULL)
11384653Sdougm 		scf_instance_destroy(instance);
11393034Sdougm 	if (iter != NULL)
11404653Sdougm 		scf_iter_destroy(iter);
11413034Sdougm 	return (ret);
11423034Sdougm }
11433034Sdougm 
11443034Sdougm /*
11453034Sdougm  * sa_get_instance(handle, instance)
11463034Sdougm  *
11474653Sdougm  * Get the instance of the group service. This is actually the
11483034Sdougm  * specific group name. The instance is needed for all property and
11493034Sdougm  * control operations.
11503034Sdougm  */
11513034Sdougm 
11523034Sdougm int
11533034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
11543034Sdougm {
11553034Sdougm 	if (scf_service_get_instance(handle->service, instname,
11564653Sdougm 	    handle->instance) != 0) {
11574653Sdougm 		return (SA_NO_SUCH_GROUP);
11583034Sdougm 	}
11593034Sdougm 	return (SA_OK);
11603034Sdougm }
11613034Sdougm 
11623034Sdougm /*
11633034Sdougm  * sa_create_instance(handle, instname)
11643034Sdougm  *
11653034Sdougm  * Create a new SMF service instance. There can only be one with a
11663034Sdougm  * given name.
11673034Sdougm  */
11683034Sdougm 
11693034Sdougm int
11703034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
11713034Sdougm {
11723034Sdougm 	int ret = SA_OK;
11733034Sdougm 	char instance[SA_GROUP_INST_LEN];
11743034Sdougm 	if (scf_service_add_instance(handle->service, instname,
11754653Sdougm 	    handle->instance) != 0) {
11763034Sdougm 	/* better error returns need to be added based on real error */
11774653Sdougm 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
11784653Sdougm 			ret = SA_NO_PERMISSION;
11794653Sdougm 		else
11804653Sdougm 			ret = SA_DUPLICATE_NAME;
11813034Sdougm 	} else {
11824653Sdougm 		/* have the service created, so enable it */
11834653Sdougm 		(void) snprintf(instance, sizeof (instance), "%s:%s",
11844653Sdougm 		    SA_SVC_FMRI_BASE, instname);
11854653Sdougm 		(void) smf_enable_instance(instance, 0);
11863034Sdougm 	}
11873034Sdougm 	return (ret);
11883034Sdougm }
11893034Sdougm 
11903034Sdougm /*
11913034Sdougm  * sa_delete_instance(handle, instname)
11923034Sdougm  *
11933034Sdougm  * When a group goes away, we also remove the service instance.
11943034Sdougm  */
11953034Sdougm 
11963034Sdougm int
11973034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
11983034Sdougm {
11993034Sdougm 	int ret;
12003034Sdougm 
12013034Sdougm 	if (strcmp(instname, "default") == 0) {
12024653Sdougm 		ret = SA_NO_PERMISSION;
12033034Sdougm 	} else {
12044653Sdougm 		if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
12054653Sdougm 			if (scf_instance_delete(handle->instance) != 0)
12064653Sdougm 				/* need better analysis */
12074653Sdougm 				ret = SA_NO_PERMISSION;
12084653Sdougm 		}
12093034Sdougm 	}
12103034Sdougm 	return (ret);
12113034Sdougm }
12123034Sdougm 
12133034Sdougm /*
12143034Sdougm  * sa_create_pgroup(handle, pgroup)
12153034Sdougm  *
12163034Sdougm  * create a new property group
12173034Sdougm  */
12183034Sdougm 
12193034Sdougm int
12203034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
12213034Sdougm {
12223034Sdougm 	int ret = SA_OK;
12235951Sdougm 	int persist = 0;
12245951Sdougm 
12253034Sdougm 	/*
12264653Sdougm 	 * Only create a handle if it doesn't exist. It is ok to exist
12273034Sdougm 	 * since the pg handle will be set as a side effect.
12283034Sdougm 	 */
12294653Sdougm 	if (handle->pg == NULL)
12304653Sdougm 		handle->pg = scf_pg_create(handle->handle);
12314653Sdougm 
12323034Sdougm 	/*
12335951Sdougm 	 * Special case for a non-persistent property group. This is
12345951Sdougm 	 * internal use only.
12355951Sdougm 	 */
12365951Sdougm 	if (*pgroup == '*') {
12375951Sdougm 		persist = SCF_PG_FLAG_NONPERSISTENT;
12385951Sdougm 		pgroup++;
12395951Sdougm 	}
12405951Sdougm 
12415951Sdougm 	/*
12424653Sdougm 	 * If the pgroup exists, we are done. If it doesn't, then we
12433034Sdougm 	 * need to actually add one to the service instance.
12443034Sdougm 	 */
12453034Sdougm 	if (scf_instance_get_pg(handle->instance,
12464653Sdougm 	    pgroup, handle->pg) != 0) {
12475951Sdougm 
12484653Sdougm 		/* Doesn't exist so create one */
12494653Sdougm 		if (scf_instance_add_pg(handle->instance, pgroup,
12505951Sdougm 		    SCF_GROUP_APPLICATION, persist, handle->pg) != 0) {
12514653Sdougm 			switch (scf_error()) {
12524653Sdougm 			case SCF_ERROR_PERMISSION_DENIED:
12534653Sdougm 				ret = SA_NO_PERMISSION;
12544653Sdougm 				break;
12554653Sdougm 			default:
12564653Sdougm 				ret = SA_SYSTEM_ERR;
12574653Sdougm 				break;
12584653Sdougm 			}
12593034Sdougm 		}
12603034Sdougm 	}
12613034Sdougm 	return (ret);
12623034Sdougm }
12633034Sdougm 
12643034Sdougm /*
12653034Sdougm  * sa_delete_pgroup(handle, pgroup)
12663034Sdougm  *
12674653Sdougm  * Remove the property group from the current instance of the service,
12683034Sdougm  * but only if it actually exists.
12693034Sdougm  */
12703034Sdougm 
12713034Sdougm int
12723034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
12733034Sdougm {
12743034Sdougm 	int ret = SA_OK;
12753034Sdougm 	/*
12764653Sdougm 	 * Only delete if it does exist.
12773034Sdougm 	 */
12784653Sdougm 	if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) {
12794653Sdougm 		/* does exist so delete it */
12804653Sdougm 		if (scf_pg_delete(handle->pg) != 0)
12814653Sdougm 			ret = SA_SYSTEM_ERR;
12824653Sdougm 	} else {
12833034Sdougm 		ret = SA_SYSTEM_ERR;
12843034Sdougm 	}
12853034Sdougm 	if (ret == SA_SYSTEM_ERR &&
12863034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
12873034Sdougm 		ret = SA_NO_PERMISSION;
12883034Sdougm 	}
12893034Sdougm 	return (ret);
12903034Sdougm }
12913034Sdougm 
12923034Sdougm /*
12933034Sdougm  * sa_start_transaction(handle, pgroup)
12943034Sdougm  *
12953034Sdougm  * Start an SMF transaction so we can deal with properties. it would
12963034Sdougm  * be nice to not have to expose this, but we have to in order to
12973034Sdougm  * optimize.
12983034Sdougm  *
12993034Sdougm  * Basic model is to hold the transaction in the handle and allow
13003034Sdougm  * property adds/deletes/updates to be added then close the
13013034Sdougm  * transaction (or abort).  There may eventually be a need to handle
13023034Sdougm  * other types of transaction mechanisms but we don't do that now.
13033034Sdougm  *
13043034Sdougm  * An sa_start_transaction must be followed by either an
13053034Sdougm  * sa_end_transaction or sa_abort_transaction before another
13063034Sdougm  * sa_start_transaction can be done.
13073034Sdougm  */
13083034Sdougm 
13093034Sdougm int
13103034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
13113034Sdougm {
13123034Sdougm 	int ret = SA_OK;
13133034Sdougm 	/*
13144653Sdougm 	 * Lookup the property group and create it if it doesn't already
13153034Sdougm 	 * exist.
13163034Sdougm 	 */
13175951Sdougm 	if (handle == NULL)
13185951Sdougm 		return (SA_CONFIG_ERR);
13195951Sdougm 
13203034Sdougm 	if (handle->scf_state == SCH_STATE_INIT) {
13214653Sdougm 		ret = sa_create_pgroup(handle, propgroup);
13224653Sdougm 		if (ret == SA_OK) {
13234653Sdougm 			handle->trans = scf_transaction_create(handle->handle);
13244653Sdougm 			if (handle->trans != NULL) {
13254653Sdougm 				if (scf_transaction_start(handle->trans,
13264653Sdougm 				    handle->pg) != 0) {
13274653Sdougm 					ret = SA_SYSTEM_ERR;
13284653Sdougm 				}
13294653Sdougm 				if (ret != SA_OK) {
13304653Sdougm 					scf_transaction_destroy(handle->trans);
13314653Sdougm 					handle->trans = NULL;
13324653Sdougm 				}
13334653Sdougm 			} else {
13344653Sdougm 				ret = SA_SYSTEM_ERR;
13354653Sdougm 			}
13363034Sdougm 		}
13373034Sdougm 	}
13383034Sdougm 	if (ret == SA_SYSTEM_ERR &&
13393034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
13403034Sdougm 		ret = SA_NO_PERMISSION;
13413034Sdougm 	}
13423034Sdougm 	return (ret);
13433034Sdougm }
13443034Sdougm 
13455951Sdougm 
13463034Sdougm /*
13475951Sdougm  * sa_end_transaction(scfhandle, sahandle)
13483034Sdougm  *
13493034Sdougm  * Commit the changes that were added to the transaction in the
13503034Sdougm  * handle. Do all necessary cleanup.
13513034Sdougm  */
13523034Sdougm 
13533034Sdougm int
13545951Sdougm sa_end_transaction(scfutilhandle_t *handle, sa_handle_impl_t sahandle)
13553034Sdougm {
13563034Sdougm 	int ret = SA_OK;
13573034Sdougm 
13585951Sdougm 	if (handle == NULL || handle->trans == NULL || sahandle == NULL) {
13594653Sdougm 		ret = SA_SYSTEM_ERR;
13603034Sdougm 	} else {
13614653Sdougm 		if (scf_transaction_commit(handle->trans) < 0)
13624653Sdougm 			ret = SA_SYSTEM_ERR;
13634653Sdougm 		scf_transaction_destroy_children(handle->trans);
13644653Sdougm 		scf_transaction_destroy(handle->trans);
13655951Sdougm 		if (ret == SA_OK)
13665951Sdougm 			set_transaction_tstamp(sahandle);
13674653Sdougm 		handle->trans = NULL;
13683034Sdougm 	}
13693034Sdougm 	return (ret);
13703034Sdougm }
13713034Sdougm 
13723034Sdougm /*
13733034Sdougm  * sa_abort_transaction(handle)
13743034Sdougm  *
13753034Sdougm  * Abort the changes that were added to the transaction in the
13763034Sdougm  * handle. Do all necessary cleanup.
13773034Sdougm  */
13783034Sdougm 
13793034Sdougm void
13803034Sdougm sa_abort_transaction(scfutilhandle_t *handle)
13813034Sdougm {
13823034Sdougm 	if (handle->trans != NULL) {
13834653Sdougm 		scf_transaction_reset_all(handle->trans);
13844653Sdougm 		scf_transaction_destroy_children(handle->trans);
13854653Sdougm 		scf_transaction_destroy(handle->trans);
13864653Sdougm 		handle->trans = NULL;
13873034Sdougm 	}
13883034Sdougm }
13893034Sdougm 
13903034Sdougm /*
13915951Sdougm  * set_transaction_tstamp(sahandle)
13925951Sdougm  *
13935951Sdougm  * After a successful transaction commit, update the timestamp of the
13945951Sdougm  * last transaction. This lets us detect changes from other processes.
13955951Sdougm  */
13965951Sdougm static void
13975951Sdougm set_transaction_tstamp(sa_handle_impl_t sahandle)
13985951Sdougm {
13995951Sdougm 	char tstring[32];
14005951Sdougm 	struct timeval tv;
14015951Sdougm 	scfutilhandle_t *scfhandle;
14025951Sdougm 
14035951Sdougm 	if (sahandle == NULL || sahandle->scfhandle == NULL)
14045951Sdougm 		return;
14055951Sdougm 
14065951Sdougm 	scfhandle = sahandle->scfhandle;
14075951Sdougm 
14085951Sdougm 	if (sa_get_instance(scfhandle, "default") != SA_OK)
14095951Sdougm 		return;
14105951Sdougm 
14115951Sdougm 	if (gettimeofday(&tv, NULL) != 0)
14125951Sdougm 		return;
14135951Sdougm 
14145951Sdougm 	if (sa_start_transaction(scfhandle, "*state") != SA_OK)
14155951Sdougm 		return;
14165951Sdougm 
14175951Sdougm 	sahandle->tstrans = TSTAMP((*(timestruc_t *)&tv));
14185951Sdougm 	(void) snprintf(tstring, sizeof (tstring), "%lld", sahandle->tstrans);
14195951Sdougm 	if (sa_set_property(sahandle->scfhandle, "lastupdate", tstring) ==
14205951Sdougm 	    SA_OK) {
14215951Sdougm 		/*
14225951Sdougm 		 * While best if it succeeds, a failure doesn't cause
14235951Sdougm 		 * problems and we will ignore it anyway.
14245951Sdougm 		 */
14255951Sdougm 		(void) scf_transaction_commit(scfhandle->trans);
14265951Sdougm 		scf_transaction_destroy_children(scfhandle->trans);
14275951Sdougm 		scf_transaction_destroy(scfhandle->trans);
14285951Sdougm 	} else {
14295951Sdougm 		sa_abort_transaction(scfhandle);
14305951Sdougm 	}
14315951Sdougm }
14325951Sdougm 
14335951Sdougm /*
14343034Sdougm  * sa_set_property(handle, prop, value)
14353034Sdougm  *
14364653Sdougm  * Set a property transaction entry into the pending SMF transaction.
14373034Sdougm  */
14383034Sdougm 
14393034Sdougm int
14403034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
14413034Sdougm {
14423034Sdougm 	int ret = SA_OK;
14433034Sdougm 	scf_value_t *value;
14443034Sdougm 	scf_transaction_entry_t *entry;
14453034Sdougm 	/*
14464653Sdougm 	 * Properties must be set in transactions and don't take
14473034Sdougm 	 * effect until the transaction has been ended/committed.
14483034Sdougm 	 */
14493034Sdougm 	value = scf_value_create(handle->handle);
14503034Sdougm 	entry = scf_entry_create(handle->handle);
14513034Sdougm 	if (value != NULL && entry != NULL) {
14524653Sdougm 		if (scf_transaction_property_change(handle->trans, entry,
14534653Sdougm 		    propname, SCF_TYPE_ASTRING) == 0 ||
14544653Sdougm 		    scf_transaction_property_new(handle->trans, entry,
14554653Sdougm 		    propname, SCF_TYPE_ASTRING) == 0) {
14564653Sdougm 			if (scf_value_set_astring(value, valstr) == 0) {
14574653Sdougm 				if (scf_entry_add_value(entry, value) != 0) {
14584653Sdougm 					ret = SA_SYSTEM_ERR;
14594653Sdougm 					scf_value_destroy(value);
14604653Sdougm 				}
14614653Sdougm 				/* The value is in the transaction */
14624653Sdougm 				value = NULL;
14634653Sdougm 			} else {
14644653Sdougm 				/* Value couldn't be constructed */
14654653Sdougm 				ret = SA_SYSTEM_ERR;
14664653Sdougm 			}
14674653Sdougm 			/* The entry is in the transaction */
14684653Sdougm 			entry = NULL;
14694653Sdougm 		} else {
14703034Sdougm 			ret = SA_SYSTEM_ERR;
14713034Sdougm 		}
14724653Sdougm 	} else {
14733034Sdougm 		ret = SA_SYSTEM_ERR;
14743034Sdougm 	}
14753034Sdougm 	if (ret == SA_SYSTEM_ERR) {
14764653Sdougm 		switch (scf_error()) {
14774653Sdougm 		case SCF_ERROR_PERMISSION_DENIED:
14784653Sdougm 			ret = SA_NO_PERMISSION;
14794653Sdougm 			break;
14804653Sdougm 		}
14813034Sdougm 	}
14823034Sdougm 	/*
14834653Sdougm 	 * Cleanup if there were any errors that didn't leave these
14843034Sdougm 	 * values where they would be cleaned up later.
14853034Sdougm 	 */
14863034Sdougm 	if (value != NULL)
14874653Sdougm 		scf_value_destroy(value);
14883034Sdougm 	if (entry != NULL)
14894653Sdougm 		scf_entry_destroy(entry);
14903034Sdougm 	return (ret);
14913034Sdougm }
14923034Sdougm 
14933034Sdougm /*
14945331Samw  * check_resource(share)
14955331Samw  *
14965331Samw  * Check to see if share has any persistent resources. We don't want
14975331Samw  * to save if they are all transient.
14985331Samw  */
14995331Samw static int
15005331Samw check_resource(sa_share_t share)
15015331Samw {
15025331Samw 	sa_resource_t resource;
15035331Samw 	int ret = B_FALSE;
15045331Samw 
15055331Samw 	for (resource = sa_get_share_resource(share, NULL);
15065331Samw 	    resource != NULL && ret == B_FALSE;
15075331Samw 	    resource = sa_get_next_resource(resource)) {
15085331Samw 		char *type;
15095331Samw 		type = sa_get_resource_attr(resource, "type");
15105331Samw 		if (type != NULL) {
15115331Samw 			if (strcmp(type, "transient") != 0) {
15125331Samw 				ret = B_TRUE;
15135331Samw 			}
15145331Samw 			sa_free_attr_string(type);
15155331Samw 		}
15165331Samw 	}
15175331Samw 	return (ret);
15185331Samw }
15195331Samw 
15205331Samw /*
15215331Samw  * sa_set_resource_property(handle, prop, value)
15225331Samw  *
15235331Samw  * set a property transaction entry into the pending SMF
15245331Samw  * transaction. We don't want to include any transient resources
15255331Samw  */
15265331Samw 
15275331Samw static int
15285331Samw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
15295331Samw {
15305331Samw 	int ret = SA_OK;
15315331Samw 	scf_value_t *value;
15325331Samw 	scf_transaction_entry_t *entry;
15335331Samw 	sa_resource_t resource;
15345331Samw 	char *valstr;
15355331Samw 	char *idstr;
15365331Samw 	char *description;
15375331Samw 	char *propstr = NULL;
15385331Samw 	size_t strsize;
15395331Samw 
15405331Samw 	/* don't bother if no persistent resources */
15415331Samw 	if (check_resource(share) == B_FALSE)
15425331Samw 		return (ret);
15435331Samw 
15445331Samw 	/*
15455331Samw 	 * properties must be set in transactions and don't take
15465331Samw 	 * effect until the transaction has been ended/committed.
15475331Samw 	 */
15485331Samw 	entry = scf_entry_create(handle->handle);
15495331Samw 	if (entry == NULL)
15505331Samw 		return (SA_SYSTEM_ERR);
15515331Samw 
15525331Samw 	if (scf_transaction_property_change(handle->trans, entry,
15535331Samw 	    "resource",	SCF_TYPE_ASTRING) != 0 &&
15545331Samw 	    scf_transaction_property_new(handle->trans, entry,
15555331Samw 	    "resource", SCF_TYPE_ASTRING) != 0) {
15565331Samw 		scf_entry_destroy(entry);
15575331Samw 		return (SA_SYSTEM_ERR);
15585331Samw 
15595331Samw 	}
15605331Samw 	for (resource = sa_get_share_resource(share, NULL);
15615331Samw 	    resource != NULL;
15625331Samw 	    resource = sa_get_next_resource(resource)) {
15635331Samw 		value = scf_value_create(handle->handle);
15645331Samw 		if (value == NULL) {
15655331Samw 			ret = SA_NO_MEMORY;
15665331Samw 			break;
15675331Samw 		}
15685331Samw 			/* Get size of complete string */
15695331Samw 		valstr = sa_get_resource_attr(resource, "name");
15705331Samw 		idstr = sa_get_resource_attr(resource, "id");
15715331Samw 		description = sa_get_resource_description(resource);
15725331Samw 		strsize = (valstr != NULL) ? strlen(valstr) : 0;
15735331Samw 		strsize += (idstr != NULL) ? strlen(idstr) : 0;
15745331Samw 		strsize += (description != NULL) ? strlen(description) : 0;
15755331Samw 		if (strsize > 0) {
15765331Samw 			strsize += 3; /* add nul and ':' */
15775331Samw 			propstr = (char *)malloc(strsize);
15785331Samw 			if (propstr == NULL) {
15795331Samw 				scf_value_destroy(value);
15805331Samw 				ret = SA_NO_MEMORY;
15815331Samw 				goto err;
15825331Samw 			}
15835331Samw 			if (idstr == NULL)
15845331Samw 				(void) snprintf(propstr, strsize, "%s",
15855331Samw 				    valstr ? valstr : "");
15865331Samw 			else
15875331Samw 				(void) snprintf(propstr, strsize, "%s:%s:%s",
15885331Samw 				    idstr ? idstr : "", valstr ? valstr : "",
15895331Samw 				    description ? description : "");
15905331Samw 			if (scf_value_set_astring(value, propstr) != 0) {
15915331Samw 				ret = SA_SYSTEM_ERR;
15925331Samw 				free(propstr);
15935331Samw 				scf_value_destroy(value);
15945331Samw 				break;
15955331Samw 			}
15965331Samw 			if (scf_entry_add_value(entry, value) != 0) {
15975331Samw 				ret = SA_SYSTEM_ERR;
15985331Samw 				free(propstr);
15995331Samw 				scf_value_destroy(value);
16005331Samw 				break;
16015331Samw 			}
16025331Samw 			/* the value is in the transaction */
16035331Samw 			value = NULL;
16045331Samw 			free(propstr);
16055331Samw 		}
16065331Samw err:
16075331Samw 		if (valstr != NULL)
16085331Samw 			sa_free_attr_string(valstr);
16095331Samw 		if (idstr != NULL)
16105331Samw 			sa_free_attr_string(idstr);
16115331Samw 		if (description != NULL)
16125331Samw 			sa_free_share_description(description);
16135331Samw 	}
16145331Samw 	/* the entry is in the transaction */
16155331Samw 	entry = NULL;
16165331Samw 
16175331Samw 	if (ret == SA_SYSTEM_ERR) {
16185331Samw 		switch (scf_error()) {
16195331Samw 		case SCF_ERROR_PERMISSION_DENIED:
16205331Samw 			ret = SA_NO_PERMISSION;
16215331Samw 			break;
16225331Samw 		}
16235331Samw 	}
16245331Samw 	/*
16255331Samw 	 * cleanup if there were any errors that didn't leave
16265331Samw 	 * these values where they would be cleaned up later.
16275331Samw 	 */
16285331Samw 	if (entry != NULL)
16295331Samw 		scf_entry_destroy(entry);
16305331Samw 
16315331Samw 	return (ret);
16325331Samw }
16335331Samw 
16345331Samw /*
16353034Sdougm  * sa_commit_share(handle, group, share)
16363034Sdougm  *
16374653Sdougm  *	Commit this share to the repository.
16383034Sdougm  *	properties are added if they exist but can be added later.
16393034Sdougm  *	Need to add to dfstab and sharetab, if appropriate.
16403034Sdougm  */
16413034Sdougm int
16423034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
16433034Sdougm {
16443034Sdougm 	int ret = SA_OK;
16453034Sdougm 	char *groupname;
16463034Sdougm 	char *name;
16473034Sdougm 	char *description;
16483034Sdougm 	char *sharename;
16493034Sdougm 	ssize_t proplen;
16503034Sdougm 	char *propstring;
16513034Sdougm 
16523034Sdougm 	/*
16534653Sdougm 	 * Don't commit in the zfs group. We do commit legacy
16543034Sdougm 	 * (default) and all other groups/shares. ZFS is handled
16553034Sdougm 	 * through the ZFS configuration rather than SMF.
16563034Sdougm 	 */
16573034Sdougm 
16583034Sdougm 	groupname = sa_get_group_attr(group, "name");
16593034Sdougm 	if (groupname != NULL) {
16604653Sdougm 		if (strcmp(groupname, "zfs") == 0) {
16614653Sdougm 			/*
16624653Sdougm 			 * Adding to the ZFS group will result in the sharenfs
16634653Sdougm 			 * property being set but we don't want to do anything
16644653Sdougm 			 * SMF related at this point.
16654653Sdougm 			 */
16664653Sdougm 			sa_free_attr_string(groupname);
16674653Sdougm 			return (ret);
16684653Sdougm 		}
16693034Sdougm 	}
16703034Sdougm 
16713034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
16723034Sdougm 	propstring = malloc(proplen);
16733034Sdougm 	if (propstring == NULL)
16744653Sdougm 		ret = SA_NO_MEMORY;
16753034Sdougm 
16763034Sdougm 	if (groupname != NULL && ret == SA_OK) {
16774653Sdougm 		ret = sa_get_instance(handle, groupname);
16784653Sdougm 		sa_free_attr_string(groupname);
16794653Sdougm 		groupname = NULL;
16804653Sdougm 		sharename = sa_get_share_attr(share, "id");
16814653Sdougm 		if (sharename == NULL) {
16824653Sdougm 			/* slipped by */
16834653Sdougm 			char shname[SA_SHARE_UUID_BUFLEN];
16844653Sdougm 			generate_unique_sharename(shname);
1685*6012Sthurlow 			(void) xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
16863034Sdougm 			    (xmlChar *)shname);
16874653Sdougm 			sharename = strdup(shname);
16883034Sdougm 		}
16894653Sdougm 		if (sharename != NULL) {
16904653Sdougm 			sigset_t old, new;
16914653Sdougm 			/*
16924653Sdougm 			 * Have a share name allocated so create a pgroup for
16934653Sdougm 			 * it. It may already exist, but that is OK.  In order
16944653Sdougm 			 * to avoid creating a share pgroup that doesn't have
16954653Sdougm 			 * a path property, block signals around the critical
16964653Sdougm 			 * region of creating the share pgroup and props.
16974653Sdougm 			 */
16984653Sdougm 			(void) sigprocmask(SIG_BLOCK, NULL, &new);
16994653Sdougm 			(void) sigaddset(&new, SIGHUP);
17004653Sdougm 			(void) sigaddset(&new, SIGINT);
17014653Sdougm 			(void) sigaddset(&new, SIGQUIT);
17024653Sdougm 			(void) sigaddset(&new, SIGTSTP);
17034653Sdougm 			(void) sigprocmask(SIG_SETMASK, &new, &old);
17044653Sdougm 
17054653Sdougm 			ret = sa_create_pgroup(handle, sharename);
17064653Sdougm 			if (ret == SA_OK) {
17074653Sdougm 				/*
17084653Sdougm 				 * Now start the transaction for the
17094653Sdougm 				 * properties that define this share. They may
17104653Sdougm 				 * exist so attempt to update before create.
17114653Sdougm 				 */
17124653Sdougm 				ret = sa_start_transaction(handle, sharename);
17134653Sdougm 			}
17144653Sdougm 			if (ret == SA_OK) {
17154653Sdougm 				name = sa_get_share_attr(share, "path");
17164653Sdougm 				if (name != NULL) {
17174653Sdougm 					/*
17184653Sdougm 					 * There needs to be a path
17194653Sdougm 					 * for a share to exist.
17204653Sdougm 					 */
17214653Sdougm 					ret = sa_set_property(handle, "path",
17224653Sdougm 					    name);
17234653Sdougm 					sa_free_attr_string(name);
17244653Sdougm 				} else {
17254653Sdougm 					ret = SA_NO_MEMORY;
17264653Sdougm 				}
17274653Sdougm 			}
17284653Sdougm 			if (ret == SA_OK) {
17295331Samw 				name = sa_get_share_attr(share, "drive-letter");
17305331Samw 				if (name != NULL) {
17315331Samw 					/* A drive letter may exist for SMB */
17324653Sdougm 					ret = sa_set_property(handle,
17335331Samw 					    "drive-letter", name);
17345331Samw 					sa_free_attr_string(name);
17354653Sdougm 				}
17364653Sdougm 			}
17374653Sdougm 			if (ret == SA_OK) {
17385331Samw 				name = sa_get_share_attr(share, "exclude");
17395331Samw 				if (name != NULL) {
17405331Samw 					/*
17415331Samw 					 * In special cases need to
17425331Samw 					 * exclude proto enable.
17435331Samw 					 */
17445331Samw 					ret = sa_set_property(handle,
17455331Samw 					    "exclude", name);
17465331Samw 					sa_free_attr_string(name);
17475331Samw 				}
17485331Samw 			}
17495331Samw 			if (ret == SA_OK) {
17505331Samw 				/*
17515331Samw 				 * If there are resource names, bundle them up
17525331Samw 				 * and save appropriately.
17535331Samw 				 */
17545331Samw 				ret = sa_set_resource_property(handle, share);
17555331Samw 			}
17565331Samw 
17575331Samw 			if (ret == SA_OK) {
17584653Sdougm 				description = sa_get_share_description(share);
17594653Sdougm 				if (description != NULL) {
17604653Sdougm 					ret = sa_set_property(handle,
17614653Sdougm 					    "description",
17624653Sdougm 					    description);
17634653Sdougm 					sa_free_share_description(description);
17644653Sdougm 				}
17654653Sdougm 			}
17664653Sdougm 			/* Make sure we cleanup the transaction */
17674653Sdougm 			if (ret == SA_OK) {
17685951Sdougm 				sa_handle_impl_t sahandle;
17695951Sdougm 				sahandle = (sa_handle_impl_t)
17705951Sdougm 				    sa_find_group_handle(group);
17715951Sdougm 				if (sahandle != NULL)
17725951Sdougm 					ret = sa_end_transaction(handle,
17735951Sdougm 					    sahandle);
17745951Sdougm 				else
17755951Sdougm 					ret = SA_SYSTEM_ERR;
17764653Sdougm 			} else {
17774653Sdougm 				sa_abort_transaction(handle);
17784653Sdougm 			}
17794653Sdougm 
17804653Sdougm 			(void) sigprocmask(SIG_SETMASK, &old, NULL);
17814653Sdougm 
17824653Sdougm 			free(sharename);
17833034Sdougm 		}
17843034Sdougm 	}
17853034Sdougm 	if (ret == SA_SYSTEM_ERR) {
17864653Sdougm 		int err = scf_error();
17874653Sdougm 		if (err == SCF_ERROR_PERMISSION_DENIED)
17884653Sdougm 			ret = SA_NO_PERMISSION;
17893034Sdougm 	}
17903034Sdougm 	if (propstring != NULL)
17914653Sdougm 		free(propstring);
17923034Sdougm 	if (groupname != NULL)
17934653Sdougm 		sa_free_attr_string(groupname);
17943034Sdougm 
17953034Sdougm 	return (ret);
17963034Sdougm }
17973034Sdougm 
17983034Sdougm /*
17995331Samw  * remove_resources(handle, share, shareid)
18005331Samw  *
18015331Samw  * If the share has resources, remove all of them and their
18025331Samw  * optionsets.
18035331Samw  */
18045331Samw static int
18055331Samw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
18065331Samw {
18075331Samw 	sa_resource_t resource;
18085331Samw 	sa_optionset_t opt;
18095331Samw 	char *proto;
18105331Samw 	char *id;
18115331Samw 	ssize_t proplen;
18125331Samw 	char *propstring;
18135331Samw 	int ret = SA_OK;
18145331Samw 
18155331Samw 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
18165331Samw 	propstring = malloc(proplen);
18175331Samw 	if (propstring == NULL)
18185331Samw 		return (SA_NO_MEMORY);
18195331Samw 
18205331Samw 	for (resource = sa_get_share_resource(share, NULL);
18215331Samw 	    resource != NULL; resource = sa_get_next_resource(resource)) {
18225331Samw 		id = sa_get_resource_attr(resource, "id");
18235331Samw 		if (id == NULL)
18245331Samw 			continue;
18255331Samw 		for (opt = sa_get_optionset(resource, NULL);
18265331Samw 		    opt != NULL; opt = sa_get_next_optionset(resource)) {
18275331Samw 			proto = sa_get_optionset_attr(opt, "type");
18285331Samw 			if (proto != NULL) {
18295331Samw 				(void) snprintf(propstring, proplen,
18305331Samw 				    "%s_%s_%s", shareid, proto, id);
18315331Samw 				ret = sa_delete_pgroup(handle, propstring);
18325331Samw 				sa_free_attr_string(proto);
18335331Samw 			}
18345331Samw 		}
18355331Samw 		sa_free_attr_string(id);
18365331Samw 	}
18375331Samw 	free(propstring);
18385331Samw 	return (ret);
18395331Samw }
18405331Samw 
18415331Samw /*
18423034Sdougm  * sa_delete_share(handle, group, share)
18433034Sdougm  *
18444653Sdougm  * Remove the specified share from the group (and service instance).
18453034Sdougm  */
18463034Sdougm 
18473034Sdougm int
18483034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
18493034Sdougm {
18503034Sdougm 	int ret = SA_OK;
18513034Sdougm 	char *groupname = NULL;
18523034Sdougm 	char *shareid = NULL;
18533034Sdougm 	sa_optionset_t opt;
18543034Sdougm 	sa_security_t sec;
18553034Sdougm 	ssize_t proplen;
18563034Sdougm 	char *propstring;
18573034Sdougm 
18583034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
18593034Sdougm 	propstring = malloc(proplen);
18603034Sdougm 	if (propstring == NULL)
18614653Sdougm 		ret = SA_NO_MEMORY;
18623034Sdougm 
18633034Sdougm 	if (ret == SA_OK) {
18644653Sdougm 		groupname = sa_get_group_attr(group, "name");
18654653Sdougm 		shareid = sa_get_share_attr(share, "id");
18664653Sdougm 		if (groupname == NULL || shareid == NULL) {
18674653Sdougm 			ret = SA_CONFIG_ERR;
18684653Sdougm 			goto out;
18694653Sdougm 		}
18703034Sdougm 		ret = sa_get_instance(handle, groupname);
18713034Sdougm 		if (ret == SA_OK) {
18725331Samw 			/* If a share has resources, remove them */
18735331Samw 			ret = remove_resources(handle, share, shareid);
18744653Sdougm 			/* If a share has properties, remove them */
18754653Sdougm 			ret = sa_delete_pgroup(handle, shareid);
18764653Sdougm 			for (opt = sa_get_optionset(share, NULL);
18774653Sdougm 			    opt != NULL;
18784653Sdougm 			    opt = sa_get_next_optionset(opt)) {
18794653Sdougm 				char *proto;
18804653Sdougm 				proto = sa_get_optionset_attr(opt, "type");
18814653Sdougm 				if (proto != NULL) {
18824653Sdougm 					(void) snprintf(propstring,
18834653Sdougm 					    proplen, "%s_%s", shareid,
18844653Sdougm 					    proto);
18854653Sdougm 					ret = sa_delete_pgroup(handle,
18864653Sdougm 					    propstring);
18874653Sdougm 					sa_free_attr_string(proto);
18884653Sdougm 				} else {
18894653Sdougm 					ret = SA_NO_MEMORY;
18904653Sdougm 				}
18913034Sdougm 			}
18923034Sdougm 			/*
18934653Sdougm 			 * If a share has security/negotiable
18943034Sdougm 			 * properties, remove them.
18953034Sdougm 			 */
18964653Sdougm 			for (sec = sa_get_security(share, NULL, NULL);
18974653Sdougm 			    sec != NULL;
18984653Sdougm 			    sec = sa_get_next_security(sec)) {
18994653Sdougm 				char *proto;
19004653Sdougm 				char *sectype;
19014653Sdougm 				proto = sa_get_security_attr(sec, "type");
19024653Sdougm 				sectype = sa_get_security_attr(sec, "sectype");
19034653Sdougm 				if (proto != NULL && sectype != NULL) {
19044653Sdougm 					(void) snprintf(propstring, proplen,
19054653Sdougm 					    "%s_%s_%s", shareid,  proto,
19064653Sdougm 					    sectype);
19074653Sdougm 					ret = sa_delete_pgroup(handle,
19084653Sdougm 					    propstring);
19094653Sdougm 				} else {
19104653Sdougm 					ret = SA_NO_MEMORY;
19114653Sdougm 				}
19124653Sdougm 				if (proto != NULL)
19134653Sdougm 					sa_free_attr_string(proto);
19144653Sdougm 				if (sectype != NULL)
19154653Sdougm 					sa_free_attr_string(sectype);
19163034Sdougm 			}
19173034Sdougm 		}
19183034Sdougm 	}
19194653Sdougm out:
19203034Sdougm 	if (groupname != NULL)
19214653Sdougm 		sa_free_attr_string(groupname);
19223034Sdougm 	if (shareid != NULL)
19234653Sdougm 		sa_free_attr_string(shareid);
19243034Sdougm 	if (propstring != NULL)
19254653Sdougm 		free(propstring);
19263034Sdougm 
19273034Sdougm 	return (ret);
19283034Sdougm }
1929