1*3034Sdougm /*
2*3034Sdougm  * CDDL HEADER START
3*3034Sdougm  *
4*3034Sdougm  * The contents of this file are subject to the terms of the
5*3034Sdougm  * Common Development and Distribution License (the "License").
6*3034Sdougm  * You may not use this file except in compliance with the License.
7*3034Sdougm  *
8*3034Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3034Sdougm  * or http://www.opensolaris.org/os/licensing.
10*3034Sdougm  * See the License for the specific language governing permissions
11*3034Sdougm  * and limitations under the License.
12*3034Sdougm  *
13*3034Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
14*3034Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3034Sdougm  * If applicable, add the following below this CDDL HEADER, with the
16*3034Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
17*3034Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3034Sdougm  *
19*3034Sdougm  * CDDL HEADER END
20*3034Sdougm  */
21*3034Sdougm 
22*3034Sdougm /*
23*3034Sdougm  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*3034Sdougm  * Use is subject to license terms.
25*3034Sdougm  */
26*3034Sdougm 
27*3034Sdougm #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*3034Sdougm 
29*3034Sdougm /* helper functions for using libscf with sharemgr */
30*3034Sdougm 
31*3034Sdougm #include <libscf.h>
32*3034Sdougm #include <libxml/parser.h>
33*3034Sdougm #include <libxml/tree.h>
34*3034Sdougm #include "libshare.h"
35*3034Sdougm #include "libshare_impl.h"
36*3034Sdougm #include "scfutil.h"
37*3034Sdougm #include <string.h>
38*3034Sdougm #include <errno.h>
39*3034Sdougm #include <uuid/uuid.h>
40*3034Sdougm #include <sys/param.h>
41*3034Sdougm 
42*3034Sdougm ssize_t scf_max_name_len;
43*3034Sdougm extern struct sa_proto_plugin *sap_proto_list;
44*3034Sdougm 
45*3034Sdougm /*
46*3034Sdougm  * The SMF facility uses some properties that must exist. We want to
47*3034Sdougm  * skip over these when processing protocol options.
48*3034Sdougm  */
49*3034Sdougm static char *skip_props[] = {
50*3034Sdougm 	"modify_authorization",
51*3034Sdougm 	"action_authorization",
52*3034Sdougm 	"value_authorization",
53*3034Sdougm 	NULL
54*3034Sdougm };
55*3034Sdougm 
56*3034Sdougm /*
57*3034Sdougm  * sa_scf_fini(handle)
58*3034Sdougm  *
59*3034Sdougm  * must be called when done. Called with the handle allocated in
60*3034Sdougm  * sa_scf_init(), it cleans up the state and frees any SCF resources
61*3034Sdougm  * still in use. Called by sa_fini().
62*3034Sdougm  */
63*3034Sdougm 
64*3034Sdougm void
65*3034Sdougm sa_scf_fini(scfutilhandle_t *handle)
66*3034Sdougm {
67*3034Sdougm 	if (handle != NULL) {
68*3034Sdougm 	    int unbind = 0;
69*3034Sdougm 	    if (handle->scope != NULL) {
70*3034Sdougm 		unbind = 1;
71*3034Sdougm 		scf_scope_destroy(handle->scope);
72*3034Sdougm 	    }
73*3034Sdougm 	    if (handle->service != NULL)
74*3034Sdougm 		    scf_service_destroy(handle->service);
75*3034Sdougm 	    if (handle->pg != NULL)
76*3034Sdougm 		scf_pg_destroy(handle->pg);
77*3034Sdougm 	    if (handle->handle != NULL) {
78*3034Sdougm 		handle->scf_state = SCH_STATE_UNINIT;
79*3034Sdougm 		if (unbind)
80*3034Sdougm 		    (void) scf_handle_unbind(handle->handle);
81*3034Sdougm 		scf_handle_destroy(handle->handle);
82*3034Sdougm 	    }
83*3034Sdougm 	    free(handle);
84*3034Sdougm 	}
85*3034Sdougm }
86*3034Sdougm 
87*3034Sdougm /*
88*3034Sdougm  * sa_scf_init()
89*3034Sdougm  *
90*3034Sdougm  * must be called before using any of the SCF functions. Called by
91*3034Sdougm  * sa_init() during the API setup.
92*3034Sdougm  */
93*3034Sdougm 
94*3034Sdougm scfutilhandle_t *
95*3034Sdougm sa_scf_init()
96*3034Sdougm {
97*3034Sdougm 	scfutilhandle_t *handle;
98*3034Sdougm 
99*3034Sdougm 	scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
100*3034Sdougm 	if (scf_max_name_len <= 0)
101*3034Sdougm 	    scf_max_name_len = SA_MAX_NAME_LEN + 1;
102*3034Sdougm 
103*3034Sdougm 	handle = calloc(1, sizeof (scfutilhandle_t));
104*3034Sdougm 	if (handle != NULL) {
105*3034Sdougm 	    handle->scf_state = SCH_STATE_INITIALIZING;
106*3034Sdougm 	    handle->handle = scf_handle_create(SCF_VERSION);
107*3034Sdougm 	    if (handle->handle != NULL) {
108*3034Sdougm 		if (scf_handle_bind(handle->handle) == 0) {
109*3034Sdougm 		    handle->scope = scf_scope_create(handle->handle);
110*3034Sdougm 		    handle->service = scf_service_create(handle->handle);
111*3034Sdougm 		    handle->pg = scf_pg_create(handle->handle);
112*3034Sdougm 		    handle->instance = scf_instance_create(handle->handle);
113*3034Sdougm 		    if (scf_handle_get_scope(handle->handle,
114*3034Sdougm 					SCF_SCOPE_LOCAL, handle->scope) == 0) {
115*3034Sdougm 			if (scf_scope_get_service(handle->scope,
116*3034Sdougm 						    SA_GROUP_SVC_NAME,
117*3034Sdougm 						    handle->service) != 0) {
118*3034Sdougm 			    goto err;
119*3034Sdougm 			}
120*3034Sdougm 			handle->scf_state = SCH_STATE_INIT;
121*3034Sdougm 			if (sa_get_instance(handle, "default") != SA_OK) {
122*3034Sdougm 			    char **protolist;
123*3034Sdougm 			    int numprotos, i;
124*3034Sdougm 			    sa_group_t defgrp;
125*3034Sdougm 			    defgrp = sa_create_group("default", NULL);
126*3034Sdougm 			    if (defgrp != NULL) {
127*3034Sdougm 				numprotos = sa_get_protocols(&protolist);
128*3034Sdougm 				for (i = 0; i < numprotos; i++) {
129*3034Sdougm 				    (void) sa_create_optionset(defgrp,
130*3034Sdougm 								protolist[i]);
131*3034Sdougm 				}
132*3034Sdougm 				if (protolist != NULL)
133*3034Sdougm 				    free(protolist);
134*3034Sdougm 			    }
135*3034Sdougm 			}
136*3034Sdougm 		    } else {
137*3034Sdougm 			goto err;
138*3034Sdougm 		    }
139*3034Sdougm 		} else {
140*3034Sdougm 		    goto err;
141*3034Sdougm 		}
142*3034Sdougm 	    } else {
143*3034Sdougm 		free(handle);
144*3034Sdougm 		handle = NULL;
145*3034Sdougm 		(void) printf("libshare could not access SMF repository: %s\n",
146*3034Sdougm 				scf_strerror(scf_error()));
147*3034Sdougm 	    }
148*3034Sdougm 	}
149*3034Sdougm 	return (handle);
150*3034Sdougm 
151*3034Sdougm 	/* error handling/unwinding */
152*3034Sdougm err:
153*3034Sdougm 	(void) sa_scf_fini(handle);
154*3034Sdougm 	(void) printf("libshare SMF initialization problem: %s\n",
155*3034Sdougm 			scf_strerror(scf_error()));
156*3034Sdougm 	return (NULL);
157*3034Sdougm }
158*3034Sdougm 
159*3034Sdougm /*
160*3034Sdougm  * get_scf_limit(name)
161*3034Sdougm  *
162*3034Sdougm  * Since we use  scf_limit a lot and do the same  check and return the
163*3034Sdougm  * same  value  if  it  fails,   implement  as  a  function  for  code
164*3034Sdougm  * simplification.  Basically, if  name isn't found, return MAXPATHLEN
165*3034Sdougm  * (1024) so we have a reasonable default buffer size.
166*3034Sdougm  */
167*3034Sdougm static ssize_t
168*3034Sdougm get_scf_limit(uint32_t name)
169*3034Sdougm {
170*3034Sdougm 	ssize_t vallen;
171*3034Sdougm 
172*3034Sdougm 	vallen = scf_limit(name);
173*3034Sdougm 	if (vallen == (ssize_t)-1)
174*3034Sdougm 	    vallen = MAXPATHLEN;
175*3034Sdougm 	return (vallen);
176*3034Sdougm }
177*3034Sdougm 
178*3034Sdougm /*
179*3034Sdougm  * skip_property(name)
180*3034Sdougm  *
181*3034Sdougm  * internal function to check to see if a property is an SMF magic
182*3034Sdougm  * property that needs to be skipped.
183*3034Sdougm  */
184*3034Sdougm static int
185*3034Sdougm skip_property(char *name)
186*3034Sdougm {
187*3034Sdougm 	int i;
188*3034Sdougm 
189*3034Sdougm 	for (i = 0; skip_props[i] != NULL; i++)
190*3034Sdougm 	    if (strcmp(name, skip_props[i]) == 0)
191*3034Sdougm 		return (1);
192*3034Sdougm 	return (0);
193*3034Sdougm }
194*3034Sdougm 
195*3034Sdougm /*
196*3034Sdougm  * generate_unique_sharename(sharename)
197*3034Sdougm  *
198*3034Sdougm  * Shares are represented in SMF as property groups. Due to share
199*3034Sdougm  * paths containing characters that are not allowed in SMF names and
200*3034Sdougm  * the need to be unique, we use UUIDs to construct a unique name.
201*3034Sdougm  */
202*3034Sdougm 
203*3034Sdougm static void
204*3034Sdougm generate_unique_sharename(char *sharename)
205*3034Sdougm {
206*3034Sdougm 	uuid_t uuid;
207*3034Sdougm 
208*3034Sdougm 	uuid_generate(uuid);
209*3034Sdougm 	(void) strcpy(sharename, "S-");
210*3034Sdougm 	uuid_unparse(uuid, sharename + 2);
211*3034Sdougm }
212*3034Sdougm 
213*3034Sdougm /*
214*3034Sdougm  * valid_protocol(proto)
215*3034Sdougm  *
216*3034Sdougm  * check to see if the specified protocol is a valid one for the
217*3034Sdougm  * general sharemgr facility. We determine this by checking which
218*3034Sdougm  * plugin protocols were found.
219*3034Sdougm  */
220*3034Sdougm 
221*3034Sdougm static int
222*3034Sdougm valid_protocol(char *proto)
223*3034Sdougm {
224*3034Sdougm 	struct sa_proto_plugin *plugin;
225*3034Sdougm 	for (plugin = sap_proto_list; plugin != NULL;
226*3034Sdougm 	    plugin = plugin->plugin_next)
227*3034Sdougm 	    if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
228*3034Sdougm 		return (1);
229*3034Sdougm 	return (0);
230*3034Sdougm }
231*3034Sdougm 
232*3034Sdougm /*
233*3034Sdougm  * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
234*3034Sdougm  *
235*3034Sdougm  * extract the name property group and create the specified type of
236*3034Sdougm  * node on the provided group.  type will be optionset or security.
237*3034Sdougm  */
238*3034Sdougm 
239*3034Sdougm static int
240*3034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
241*3034Sdougm 			scf_propertygroup_t *pg,
242*3034Sdougm 			char *nodetype, char *proto, char *sectype)
243*3034Sdougm {
244*3034Sdougm 	xmlNodePtr node;
245*3034Sdougm 	scf_iter_t *iter;
246*3034Sdougm 	scf_property_t *prop;
247*3034Sdougm 	scf_value_t *value;
248*3034Sdougm 	char *name;
249*3034Sdougm 	char *valuestr;
250*3034Sdougm 	ssize_t vallen;
251*3034Sdougm 	int ret = SA_OK;
252*3034Sdougm 
253*3034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
254*3034Sdougm 
255*3034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
256*3034Sdougm 	if (node != NULL) {
257*3034Sdougm 	    if (proto != NULL)
258*3034Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
259*3034Sdougm 	    if (sectype != NULL)
260*3034Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
261*3034Sdougm 		/*
262*3034Sdougm 		 * have node to work with so iterate over the properties
263*3034Sdougm 		 * in the pg and create option sub nodes.
264*3034Sdougm 		 */
265*3034Sdougm 		iter = scf_iter_create(handle->handle);
266*3034Sdougm 		value = scf_value_create(handle->handle);
267*3034Sdougm 		prop = scf_property_create(handle->handle);
268*3034Sdougm 		name = malloc(scf_max_name_len);
269*3034Sdougm 		valuestr = malloc(vallen);
270*3034Sdougm 		/*
271*3034Sdougm 		 * want to iterate through the properties and add them
272*3034Sdougm 		 * to the base optionset.
273*3034Sdougm 		 */
274*3034Sdougm 		if (iter != NULL && value != NULL && prop != NULL &&
275*3034Sdougm 		    valuestr != NULL && name != NULL) {
276*3034Sdougm 		    if (scf_iter_pg_properties(iter, pg) == 0) {
277*3034Sdougm 			/* now iterate the properties in the group */
278*3034Sdougm 			while (scf_iter_next_property(iter, prop) > 0) {
279*3034Sdougm 			    /* have a property */
280*3034Sdougm 			    if (scf_property_get_name(prop, name,
281*3034Sdougm 							scf_max_name_len) > 0) {
282*3034Sdougm 				/* some properties are part of the framework */
283*3034Sdougm 				if (skip_property(name))
284*3034Sdougm 				    continue;
285*3034Sdougm 				if (scf_property_get_value(prop, value) == 0) {
286*3034Sdougm 				    if (scf_value_get_astring(value, valuestr,
287*3034Sdougm 								vallen) >= 0) {
288*3034Sdougm 					sa_property_t saprop;
289*3034Sdougm 					saprop = sa_create_property(name,
290*3034Sdougm 								    valuestr);
291*3034Sdougm 					if (saprop != NULL) {
292*3034Sdougm 					/*
293*3034Sdougm 					 * since in SMF, don't
294*3034Sdougm 					 * recurse. Use xmlAddChild
295*3034Sdougm 					 * directly, instead.
296*3034Sdougm 					 */
297*3034Sdougm 					    xmlAddChild(node,
298*3034Sdougm 							(xmlNodePtr) saprop);
299*3034Sdougm 					}
300*3034Sdougm 				    }
301*3034Sdougm 				}
302*3034Sdougm 			    }
303*3034Sdougm 			}
304*3034Sdougm 		    }
305*3034Sdougm 		} else {
306*3034Sdougm 		    ret = SA_NO_MEMORY;
307*3034Sdougm 		}
308*3034Sdougm 		/* cleanup to avoid memory leaks */
309*3034Sdougm 		if (value != NULL)
310*3034Sdougm 		    scf_value_destroy(value);
311*3034Sdougm 		if (iter != NULL)
312*3034Sdougm 		    scf_iter_destroy(iter);
313*3034Sdougm 		if (prop != NULL)
314*3034Sdougm 		    scf_property_destroy(prop);
315*3034Sdougm 		if (name != NULL)
316*3034Sdougm 		    free(name);
317*3034Sdougm 		if (valuestr != NULL)
318*3034Sdougm 		    free(valuestr);
319*3034Sdougm 	}
320*3034Sdougm 	return (ret);
321*3034Sdougm }
322*3034Sdougm 
323*3034Sdougm /*
324*3034Sdougm  * sa_extract_attrs(root, handle, instance)
325*3034Sdougm  *
326*3034Sdougm  * local function to extract the actual attributes/properties from the
327*3034Sdougm  * property group of the service instance. These are the well known
328*3034Sdougm  * attributes of "state" and "zfs". If additional attributes are
329*3034Sdougm  * added, they should be added here.
330*3034Sdougm  */
331*3034Sdougm 
332*3034Sdougm static void
333*3034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
334*3034Sdougm 		    scf_instance_t *instance)
335*3034Sdougm {
336*3034Sdougm 	scf_property_t *prop;
337*3034Sdougm 	scf_value_t *value;
338*3034Sdougm 	char *valuestr;
339*3034Sdougm 	ssize_t vallen;
340*3034Sdougm 
341*3034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
342*3034Sdougm 	prop = scf_property_create(handle->handle);
343*3034Sdougm 	value = scf_value_create(handle->handle);
344*3034Sdougm 	valuestr = malloc(vallen);
345*3034Sdougm 	if (prop != NULL && value != NULL && valuestr != NULL &&
346*3034Sdougm 	    scf_instance_get_pg(instance, "operation",
347*3034Sdougm 				handle->pg) == 0) {
348*3034Sdougm 		/*
349*3034Sdougm 		 * have a property group with desired name so now get
350*3034Sdougm 		 * the known attributes.
351*3034Sdougm 		 */
352*3034Sdougm 	    if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
353*3034Sdougm 		/* found the property so get the value */
354*3034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
355*3034Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) >= 0) {
356*3034Sdougm 			xmlSetProp(root, (xmlChar *)"state",
357*3034Sdougm 				    (xmlChar *)valuestr);
358*3034Sdougm 		    }
359*3034Sdougm 		}
360*3034Sdougm 	    }
361*3034Sdougm 	    if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
362*3034Sdougm 		/* found the property so get the value */
363*3034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
364*3034Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) > 0) {
365*3034Sdougm 			xmlSetProp(root, (xmlChar *)"zfs",
366*3034Sdougm 				    (xmlChar *)valuestr);
367*3034Sdougm 		    }
368*3034Sdougm 		}
369*3034Sdougm 	    }
370*3034Sdougm 	}
371*3034Sdougm 	if (valuestr != NULL)
372*3034Sdougm 	    free(valuestr);
373*3034Sdougm 	if (value != NULL)
374*3034Sdougm 	    scf_value_destroy(value);
375*3034Sdougm 	if (prop != NULL)
376*3034Sdougm 	    scf_property_destroy(prop);
377*3034Sdougm }
378*3034Sdougm 
379*3034Sdougm /*
380*3034Sdougm  * list of known share attributes.
381*3034Sdougm  */
382*3034Sdougm 
383*3034Sdougm static char *share_attr[] = {
384*3034Sdougm 	"path",
385*3034Sdougm 	"id",
386*3034Sdougm 	"resource",
387*3034Sdougm 	NULL,
388*3034Sdougm };
389*3034Sdougm 
390*3034Sdougm static int
391*3034Sdougm is_share_attr(char *name)
392*3034Sdougm {
393*3034Sdougm 	int i;
394*3034Sdougm 	for (i = 0; share_attr[i] != NULL; i++)
395*3034Sdougm 	    if (strcmp(name, share_attr[i]) == 0)
396*3034Sdougm 		return (1);
397*3034Sdougm 	return (0);
398*3034Sdougm }
399*3034Sdougm 
400*3034Sdougm /*
401*3034Sdougm  * sa_share_from_pgroup
402*3034Sdougm  *
403*3034Sdougm  * extract the share definition from the share property group. We do
404*3034Sdougm  * some sanity checking to avoid bad data.
405*3034Sdougm  *
406*3034Sdougm  * Since this is only constructing the internal data structures, we
407*3034Sdougm  * don't use the sa_* functions most of the time.
408*3034Sdougm  */
409*3034Sdougm void
410*3034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
411*3034Sdougm 			scf_propertygroup_t *pg, char *id)
412*3034Sdougm {
413*3034Sdougm 	xmlNodePtr node;
414*3034Sdougm 	char *name;
415*3034Sdougm 	scf_iter_t *iter;
416*3034Sdougm 	scf_property_t *prop;
417*3034Sdougm 	scf_value_t *value;
418*3034Sdougm 	ssize_t vallen;
419*3034Sdougm 	char *valuestr;
420*3034Sdougm 	int ret = SA_OK;
421*3034Sdougm 
422*3034Sdougm 	/*
423*3034Sdougm 	 * While preliminary check (starts with 'S') passed before
424*3034Sdougm 	 * getting here. Need to make sure it is in ID syntax
425*3034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
426*3034Sdougm 	 * pgroups.
427*3034Sdougm 	 */
428*3034Sdougm 	vallen = strlen(id);
429*3034Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
430*3034Sdougm 	    uuid_t uuid;
431*3034Sdougm 	    if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) != 0 ||
432*3034Sdougm 		uuid_parse(id + 2, uuid) < 0)
433*3034Sdougm 		return;
434*3034Sdougm 	} else {
435*3034Sdougm 	    return;
436*3034Sdougm 	}
437*3034Sdougm 
438*3034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
439*3034Sdougm 
440*3034Sdougm 	iter = scf_iter_create(handle->handle);
441*3034Sdougm 	value = scf_value_create(handle->handle);
442*3034Sdougm 	prop = scf_property_create(handle->handle);
443*3034Sdougm 	name = malloc(scf_max_name_len);
444*3034Sdougm 	valuestr = malloc(vallen);
445*3034Sdougm 
446*3034Sdougm 	/*
447*3034Sdougm 	 * construct the share XML node. It is similar to sa_add_share
448*3034Sdougm 	 * but never changes the repository. Also, there won't be any
449*3034Sdougm 	 * ZFS or transient shares.  Root will be the group it is
450*3034Sdougm 	 * associated with.
451*3034Sdougm 	 */
452*3034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
453*3034Sdougm 	if (node != NULL) {
454*3034Sdougm 		/*
455*3034Sdougm 		 * make sure the UUID part of the property group is
456*3034Sdougm 		 * stored in the share "id" property. We use this
457*3034Sdougm 		 * later.
458*3034Sdougm 		 */
459*3034Sdougm 	    xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
460*3034Sdougm 	    xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
461*3034Sdougm 	}
462*3034Sdougm 
463*3034Sdougm 	if (iter != NULL && value != NULL && prop != NULL && name != NULL) {
464*3034Sdougm 		/* iterate over the share pg properties */
465*3034Sdougm 	    if (scf_iter_pg_properties(iter, pg) == 0) {
466*3034Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
467*3034Sdougm 		    ret = SA_SYSTEM_ERR; /* assume the worst */
468*3034Sdougm 		    if (scf_property_get_name(prop, name,
469*3034Sdougm 						scf_max_name_len) > 0) {
470*3034Sdougm 			if (scf_property_get_value(prop, value) == 0) {
471*3034Sdougm 			    if (scf_value_get_astring(value, valuestr,
472*3034Sdougm 							vallen) >= 0) {
473*3034Sdougm 				ret = SA_OK;
474*3034Sdougm 			    }
475*3034Sdougm 			}
476*3034Sdougm 		    }
477*3034Sdougm 		    if (ret == SA_OK) {
478*3034Sdougm 			if (is_share_attr(name)) {
479*3034Sdougm 				/*
480*3034Sdougm 				 * if a share attr, then simple -
481*3034Sdougm 				 * usually path and resource name
482*3034Sdougm 				 */
483*3034Sdougm 			    xmlSetProp(node, (xmlChar *)name,
484*3034Sdougm 					(xmlChar *)valuestr);
485*3034Sdougm 			} else {
486*3034Sdougm 			    if (strcmp(name, "description") == 0) {
487*3034Sdougm 				/* we have a description node */
488*3034Sdougm 				xmlNodePtr desc;
489*3034Sdougm 				desc = xmlNewChild(node, NULL,
490*3034Sdougm 						    (xmlChar *)"description",
491*3034Sdougm 						    NULL);
492*3034Sdougm 				if (desc != NULL)
493*3034Sdougm 				    xmlNodeSetContent(desc,
494*3034Sdougm 							(xmlChar *)valuestr);
495*3034Sdougm 			    }
496*3034Sdougm 			}
497*3034Sdougm 		    }
498*3034Sdougm 		}
499*3034Sdougm 	    }
500*3034Sdougm 	}
501*3034Sdougm 	if (name != NULL)
502*3034Sdougm 	    free(name);
503*3034Sdougm 	if (valuestr != NULL)
504*3034Sdougm 	    free(valuestr);
505*3034Sdougm 	if (value != NULL)
506*3034Sdougm 	    scf_value_destroy(value);
507*3034Sdougm 	if (iter != NULL)
508*3034Sdougm 	    scf_iter_destroy(iter);
509*3034Sdougm 	if (prop != NULL)
510*3034Sdougm 	    scf_property_destroy(prop);
511*3034Sdougm }
512*3034Sdougm 
513*3034Sdougm /*
514*3034Sdougm  * find_share_by_id(shareid)
515*3034Sdougm  *
516*3034Sdougm  * Search all shares in all groups until we find the share represented
517*3034Sdougm  * by "id".
518*3034Sdougm  */
519*3034Sdougm 
520*3034Sdougm static sa_share_t
521*3034Sdougm find_share_by_id(char *shareid)
522*3034Sdougm {
523*3034Sdougm 	sa_group_t group;
524*3034Sdougm 	sa_share_t share = NULL;
525*3034Sdougm 	char *id = NULL;
526*3034Sdougm 	int done = 0;
527*3034Sdougm 
528*3034Sdougm 	for (group = sa_get_group(NULL); group != NULL && !done;
529*3034Sdougm 		group = sa_get_next_group(group)) {
530*3034Sdougm 		for (share = sa_get_share(group, NULL); share != NULL;
531*3034Sdougm 			share = sa_get_next_share(share)) {
532*3034Sdougm 			id = sa_get_share_attr(share, "id");
533*3034Sdougm 			if (id != NULL && strcmp(id, shareid) == 0) {
534*3034Sdougm 				sa_free_attr_string(id);
535*3034Sdougm 				id = NULL;
536*3034Sdougm 				done++;
537*3034Sdougm 				break;
538*3034Sdougm 			}
539*3034Sdougm 			if (id != NULL) {
540*3034Sdougm 			    sa_free_attr_string(id);
541*3034Sdougm 			    id = NULL;
542*3034Sdougm 			}
543*3034Sdougm 		}
544*3034Sdougm 	}
545*3034Sdougm 	return (share);
546*3034Sdougm }
547*3034Sdougm 
548*3034Sdougm /*
549*3034Sdougm  * sa_share_props_from_pgroup(root, handle, pg, id)
550*3034Sdougm  *
551*3034Sdougm  * extract share properties from the SMF property group. More sanity
552*3034Sdougm  * checks are done and the share object is created. We ignore some
553*3034Sdougm  * errors that could exist in the repository and only worry about
554*3034Sdougm  * property groups that validate in naming.
555*3034Sdougm  */
556*3034Sdougm 
557*3034Sdougm static int
558*3034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
559*3034Sdougm 			scf_propertygroup_t *pg, char *id)
560*3034Sdougm {
561*3034Sdougm 	xmlNodePtr node;
562*3034Sdougm 	char *name;
563*3034Sdougm 	scf_iter_t *iter;
564*3034Sdougm 	scf_property_t *prop;
565*3034Sdougm 	scf_value_t *value;
566*3034Sdougm 	ssize_t vallen;
567*3034Sdougm 	char *valuestr;
568*3034Sdougm 	int ret = SA_OK;
569*3034Sdougm 	char *sectype = NULL;
570*3034Sdougm 	char *proto;
571*3034Sdougm 	sa_share_t share;
572*3034Sdougm 
573*3034Sdougm 	/*
574*3034Sdougm 	 * While preliminary check (starts with 'S') passed before
575*3034Sdougm 	 * getting here. Need to make sure it is in ID syntax
576*3034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
577*3034Sdougm 	 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
578*3034Sdougm 	 * characters, it is likely one of the protocol/security
579*3034Sdougm 	 * versions.
580*3034Sdougm 	 */
581*3034Sdougm 	vallen = strlen(id);
582*3034Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen > SA_SHARE_PG_LEN) {
583*3034Sdougm 	    uuid_t uuid;
584*3034Sdougm 	    if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
585*3034Sdougm 		proto = strchr(id, '_');
586*3034Sdougm 		if (proto == NULL)
587*3034Sdougm 		    return (ret);
588*3034Sdougm 		*proto++ = '\0';
589*3034Sdougm 		if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
590*3034Sdougm 		    return (ret);
591*3034Sdougm 		/*
592*3034Sdougm 		 * probably a legal optionset so check a few more
593*3034Sdougm 		 * syntax points below.
594*3034Sdougm 		 */
595*3034Sdougm 		if (*proto == '\0') {
596*3034Sdougm 		    /* not a valid proto (null) */
597*3034Sdougm 		    return (ret);
598*3034Sdougm 		}
599*3034Sdougm 		sectype = strchr(proto, '_');
600*3034Sdougm 		if (sectype != NULL)
601*3034Sdougm 		    *sectype++ = '\0';
602*3034Sdougm 		if (!valid_protocol(proto))
603*3034Sdougm 		    return (ret);
604*3034Sdougm 	    }
605*3034Sdougm 	} else {
606*3034Sdougm 	/*
607*3034Sdougm 	 * it is ok to not have what we thought since someone might
608*3034Sdougm 	 * have added a name via SMF.
609*3034Sdougm 	 */
610*3034Sdougm 	    return (ret);
611*3034Sdougm 	}
612*3034Sdougm 
613*3034Sdougm 	/*
614*3034Sdougm 	 * to get here, we have a valid protocol and possibly a
615*3034Sdougm 	 * security. We now have to find the share that it is really
616*3034Sdougm 	 * associated with. The "id" portion of the pgroup name will
617*3034Sdougm 	 * match.
618*3034Sdougm 	 */
619*3034Sdougm 
620*3034Sdougm 	share = find_share_by_id(id);
621*3034Sdougm 	if (share == NULL)
622*3034Sdougm 	    return (SA_BAD_PATH);
623*3034Sdougm 
624*3034Sdougm 	root = (xmlNodePtr)share;
625*3034Sdougm 
626*3034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
627*3034Sdougm 
628*3034Sdougm 	iter = scf_iter_create(handle->handle);
629*3034Sdougm 	value = scf_value_create(handle->handle);
630*3034Sdougm 	prop = scf_property_create(handle->handle);
631*3034Sdougm 	name = malloc(scf_max_name_len);
632*3034Sdougm 	valuestr = malloc(vallen);
633*3034Sdougm 
634*3034Sdougm 	if (sectype == NULL)
635*3034Sdougm 	    node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
636*3034Sdougm 	else {
637*3034Sdougm 	    node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL);
638*3034Sdougm 	    if (node != NULL)
639*3034Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
640*3034Sdougm 	}
641*3034Sdougm 	if (node != NULL) {
642*3034Sdougm 	    xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
643*3034Sdougm 	    /* now find the properties */
644*3034Sdougm 	    if (iter != NULL && value != NULL && prop != NULL && name != NULL) {
645*3034Sdougm 		/* iterate over the share pg properties */
646*3034Sdougm 		if (scf_iter_pg_properties(iter, pg) == 0) {
647*3034Sdougm 		    while (scf_iter_next_property(iter, prop) > 0) {
648*3034Sdougm 			ret = SA_SYSTEM_ERR; /* assume the worst */
649*3034Sdougm 			if (scf_property_get_name(prop, name,
650*3034Sdougm 						    scf_max_name_len) > 0) {
651*3034Sdougm 			    if (scf_property_get_value(prop, value) == 0) {
652*3034Sdougm 				if (scf_value_get_astring(value, valuestr,
653*3034Sdougm 							    vallen) >= 0) {
654*3034Sdougm 				    ret = SA_OK;
655*3034Sdougm 				}
656*3034Sdougm 			    }
657*3034Sdougm 			} else {
658*3034Sdougm 			    ret = SA_SYSTEM_ERR;
659*3034Sdougm 			}
660*3034Sdougm 			if (ret == SA_OK) {
661*3034Sdougm 			    sa_property_t prop;
662*3034Sdougm 			    prop = sa_create_property(name, valuestr);
663*3034Sdougm 			    if (prop != NULL)
664*3034Sdougm 				prop = (sa_property_t)xmlAddChild(node,
665*3034Sdougm 							(xmlNodePtr)prop);
666*3034Sdougm 			    else
667*3034Sdougm 				ret = SA_NO_MEMORY;
668*3034Sdougm 			}
669*3034Sdougm 		    }
670*3034Sdougm 		} else {
671*3034Sdougm 		    ret = SA_SYSTEM_ERR;
672*3034Sdougm 		}
673*3034Sdougm 	    }
674*3034Sdougm 	} else {
675*3034Sdougm 	    ret = SA_NO_MEMORY;
676*3034Sdougm 	}
677*3034Sdougm 	if (iter != NULL)
678*3034Sdougm 	    scf_iter_destroy(iter);
679*3034Sdougm 	if (value != NULL)
680*3034Sdougm 	    scf_value_destroy(value);
681*3034Sdougm 	if (prop != NULL)
682*3034Sdougm 	    scf_property_destroy(prop);
683*3034Sdougm 	if (name != NULL)
684*3034Sdougm 	    free(name);
685*3034Sdougm 	if (valuestr != NULL)
686*3034Sdougm 	    free(valuestr);
687*3034Sdougm 	return (ret);
688*3034Sdougm }
689*3034Sdougm 
690*3034Sdougm /*
691*3034Sdougm  * sa_extract_group(root, handle, instance)
692*3034Sdougm  *
693*3034Sdougm  * get the config info for this instance of a group and create the XML
694*3034Sdougm  * subtree from it.
695*3034Sdougm  */
696*3034Sdougm 
697*3034Sdougm static int
698*3034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
699*3034Sdougm 			scf_instance_t *instance)
700*3034Sdougm {
701*3034Sdougm 	char *buff;
702*3034Sdougm 	xmlNodePtr node;
703*3034Sdougm 	scf_iter_t *iter;
704*3034Sdougm 	char *proto;
705*3034Sdougm 	char *sectype;
706*3034Sdougm 	int have_shares = 0;
707*3034Sdougm 	int has_proto = 0;
708*3034Sdougm 	int is_default = 0;
709*3034Sdougm 	int ret = SA_OK;
710*3034Sdougm 	int err;
711*3034Sdougm 
712*3034Sdougm 	buff = malloc(scf_max_name_len);
713*3034Sdougm 	iter = scf_iter_create(handle->handle);
714*3034Sdougm 	if (buff != NULL) {
715*3034Sdougm 	    if (scf_instance_get_name(instance, buff,
716*3034Sdougm 						scf_max_name_len) > 0) {
717*3034Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
718*3034Sdougm 		if (node != NULL) {
719*3034Sdougm 		    xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
720*3034Sdougm 		    if (strcmp(buff, "default") == 0)
721*3034Sdougm 			is_default++;
722*3034Sdougm 		    sa_extract_attrs(node, handle, instance);
723*3034Sdougm 			/*
724*3034Sdougm 			 * Iterate through all the property groups
725*3034Sdougm 			 * looking for those with security or
726*3034Sdougm 			 * optionset prefixes. The names of the
727*3034Sdougm 			 * matching pgroups are parsed to get the
728*3034Sdougm 			 * protocol, and for security, the sectype.
729*3034Sdougm 			 * Syntax is as follows:
730*3034Sdougm 			 *    optionset | optionset_<proto>
731*3034Sdougm 			 *    security_default | security_<proto>_<sectype>
732*3034Sdougm 			 * "operation" is handled by
733*3034Sdougm 			 * sa_extract_attrs().
734*3034Sdougm 			 */
735*3034Sdougm 		    if (iter != NULL) {
736*3034Sdougm 			if (scf_iter_instance_pgs(iter, instance) == 0) {
737*3034Sdougm 			    while (scf_iter_next_pg(iter, handle->pg) > 0) {
738*3034Sdougm 				/* have a pgroup so sort it out */
739*3034Sdougm 				ret = scf_pg_get_name(handle->pg, buff,
740*3034Sdougm 							scf_max_name_len);
741*3034Sdougm 				if (ret  > 0) {
742*3034Sdougm 				    if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
743*3034Sdougm 					sa_share_from_pgroup(node, handle,
744*3034Sdougm 								handle->pg,
745*3034Sdougm 								buff);
746*3034Sdougm 					have_shares++;
747*3034Sdougm 				    } else if (strncmp(buff, "optionset", 9) ==
748*3034Sdougm 						0) {
749*3034Sdougm 					char *nodetype = "optionset";
750*3034Sdougm 					/* have an optionset */
751*3034Sdougm 					sectype = NULL;
752*3034Sdougm 					proto = strchr(buff, '_');
753*3034Sdougm 					if (proto != NULL) {
754*3034Sdougm 					    *proto++ = '\0';
755*3034Sdougm 					    sectype = strchr(proto, '_');
756*3034Sdougm 					    if (sectype != NULL) {
757*3034Sdougm 						*sectype++ = '\0';
758*3034Sdougm 						nodetype = "security";
759*3034Sdougm 					    }
760*3034Sdougm 					}
761*3034Sdougm 					ret = sa_extract_pgroup(node, handle,
762*3034Sdougm 							    handle->pg,
763*3034Sdougm 							    nodetype,
764*3034Sdougm 							    proto, sectype);
765*3034Sdougm 					has_proto++;
766*3034Sdougm 				    } else if (strncmp(buff,
767*3034Sdougm 							"security", 8) == 0) {
768*3034Sdougm 					/*
769*3034Sdougm 					 * have a security (note that
770*3034Sdougm 					 * this should change in the
771*3034Sdougm 					 * future)
772*3034Sdougm 					 */
773*3034Sdougm 					proto = strchr(buff, '_');
774*3034Sdougm 					sectype = NULL;
775*3034Sdougm 					if (proto != NULL) {
776*3034Sdougm 					    *proto++ = '\0';
777*3034Sdougm 					    sectype = strchr(proto, '_');
778*3034Sdougm 					    if (sectype != NULL)
779*3034Sdougm 						*sectype++ = '\0';
780*3034Sdougm 					    if (strcmp(proto, "default") == 0)
781*3034Sdougm 						proto = NULL;
782*3034Sdougm 					}
783*3034Sdougm 					ret = sa_extract_pgroup(node, handle,
784*3034Sdougm 							    handle->pg,
785*3034Sdougm 							    "security", proto,
786*3034Sdougm 							    sectype);
787*3034Sdougm 					has_proto++;
788*3034Sdougm 				    }
789*3034Sdougm 				    /* ignore everything else */
790*3034Sdougm 				}
791*3034Sdougm 			    }
792*3034Sdougm 			} else {
793*3034Sdougm 			    ret = SA_NO_MEMORY;
794*3034Sdougm 			}
795*3034Sdougm 			/*
796*3034Sdougm 			 * Make sure we have a valid default group.
797*3034Sdougm 			 * On first boot, default won't have any
798*3034Sdougm 			 * protocols defined and won't be enabled (but
799*3034Sdougm 			 * should be).
800*3034Sdougm 			 */
801*3034Sdougm 			if (is_default) {
802*3034Sdougm 			    char *state = sa_get_group_attr((sa_group_t)node,
803*3034Sdougm 							    "state");
804*3034Sdougm 			    char **protos;
805*3034Sdougm 			    int numprotos;
806*3034Sdougm 			    int i;
807*3034Sdougm 
808*3034Sdougm 			    if (state == NULL) {
809*3034Sdougm 				/* set attribute to enabled */
810*3034Sdougm 				(void) sa_set_group_attr((sa_group_t)node,
811*3034Sdougm 							    "state",
812*3034Sdougm 							    "enabled");
813*3034Sdougm 				/* we can assume no protocols */
814*3034Sdougm 				numprotos = sa_get_protocols(&protos);
815*3034Sdougm 				for (i = 0; i < numprotos; i++)
816*3034Sdougm 				    (void) sa_create_optionset((sa_group_t)node,
817*3034Sdougm 								protos[i]);
818*3034Sdougm 				if (numprotos > 0)
819*3034Sdougm 				    free(protos);
820*3034Sdougm 			    } else {
821*3034Sdougm 				sa_free_attr_string(state);
822*3034Sdougm 			    }
823*3034Sdougm 			}
824*3034Sdougm 			/* do a second pass if shares were found */
825*3034Sdougm 			if (have_shares &&
826*3034Sdougm 				scf_iter_instance_pgs(iter, instance) == 0) {
827*3034Sdougm 			    while (scf_iter_next_pg(iter, handle->pg) > 0) {
828*3034Sdougm 				/*
829*3034Sdougm 				 * have a pgroup so see if it is a
830*3034Sdougm 				 * share optionset
831*3034Sdougm 				 */
832*3034Sdougm 				err = scf_pg_get_name(handle->pg, buff,
833*3034Sdougm 							scf_max_name_len);
834*3034Sdougm 				if (err  > 0) {
835*3034Sdougm 				    if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
836*3034Sdougm 					ret = sa_share_props_from_pgroup(node,
837*3034Sdougm 								handle,
838*3034Sdougm 								handle->pg,
839*3034Sdougm 								buff);
840*3034Sdougm 				    }
841*3034Sdougm 				}
842*3034Sdougm 			    }
843*3034Sdougm 			}
844*3034Sdougm 		    }
845*3034Sdougm 		}
846*3034Sdougm 	    }
847*3034Sdougm 	}
848*3034Sdougm 	if (iter != NULL)
849*3034Sdougm 	    scf_iter_destroy(iter);
850*3034Sdougm 	if (buff != NULL)
851*3034Sdougm 	    free(buff);
852*3034Sdougm 	return (ret);
853*3034Sdougm }
854*3034Sdougm 
855*3034Sdougm /*
856*3034Sdougm  * sa_extract_defaults(root, handle, instance)
857*3034Sdougm  *
858*3034Sdougm  * local function to find the default properties that live in the
859*3034Sdougm  * default instance's "operation" proprerty group.
860*3034Sdougm  */
861*3034Sdougm 
862*3034Sdougm static void
863*3034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
864*3034Sdougm 		    scf_instance_t *instance)
865*3034Sdougm {
866*3034Sdougm 	xmlNodePtr node;
867*3034Sdougm 	scf_property_t *prop;
868*3034Sdougm 	scf_value_t *value;
869*3034Sdougm 	char *valuestr;
870*3034Sdougm 	ssize_t vallen;
871*3034Sdougm 
872*3034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
873*3034Sdougm 	prop = scf_property_create(handle->handle);
874*3034Sdougm 	value = scf_value_create(handle->handle);
875*3034Sdougm 	valuestr = malloc(vallen);
876*3034Sdougm 	if (prop != NULL && value != NULL && vallen != NULL &&
877*3034Sdougm 	    scf_instance_get_pg(instance, "operation",
878*3034Sdougm 				handle->pg) == 0) {
879*3034Sdougm 	    if (scf_pg_get_property(handle->pg,
880*3034Sdougm 				    "legacy-timestamp", prop) == 0) {
881*3034Sdougm 		/* found the property so get the value */
882*3034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
883*3034Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) > 0) {
884*3034Sdougm 			node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
885*3034Sdougm 					    NULL);
886*3034Sdougm 			if (node != NULL) {
887*3034Sdougm 			    xmlSetProp(node, (xmlChar *)"timestamp",
888*3034Sdougm 					(xmlChar *)valuestr);
889*3034Sdougm 			    xmlSetProp(node, (xmlChar *)"path",
890*3034Sdougm 					(xmlChar *)SA_LEGACY_DFSTAB);
891*3034Sdougm 			}
892*3034Sdougm 		    }
893*3034Sdougm 		}
894*3034Sdougm 	    }
895*3034Sdougm 	}
896*3034Sdougm 	if (valuestr != NULL)
897*3034Sdougm 	    free(valuestr);
898*3034Sdougm 	if (value != NULL)
899*3034Sdougm 	    scf_value_destroy(value);
900*3034Sdougm 	if (prop != NULL)
901*3034Sdougm 	    scf_property_destroy(prop);
902*3034Sdougm }
903*3034Sdougm 
904*3034Sdougm 
905*3034Sdougm /*
906*3034Sdougm  * sa_get_config(handle, root, doc)
907*3034Sdougm  *
908*3034Sdougm  * walk the SMF repository for /network/shares/group and find all the
909*3034Sdougm  * instances. These become group names.  Then add the XML structure
910*3034Sdougm  * below the groups based on property groups and properties.
911*3034Sdougm  */
912*3034Sdougm int
913*3034Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr *root, xmlDocPtr *doc)
914*3034Sdougm {
915*3034Sdougm 	int ret = SA_OK;
916*3034Sdougm 	scf_instance_t *instance;
917*3034Sdougm 	scf_iter_t *iter;
918*3034Sdougm 	char buff[BUFSIZ * 2];
919*3034Sdougm 
920*3034Sdougm 	*doc = xmlNewDoc((xmlChar *)"1.0");
921*3034Sdougm 	*root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
922*3034Sdougm 	instance = scf_instance_create(handle->handle);
923*3034Sdougm 	iter = scf_iter_create(handle->handle);
924*3034Sdougm 	if (*doc != NULL && *root != NULL && instance != NULL && iter != NULL) {
925*3034Sdougm 	    xmlDocSetRootElement(*doc, *root);
926*3034Sdougm 	    if ((ret = scf_iter_service_instances(iter,
927*3034Sdougm 						    handle->service)) == 0) {
928*3034Sdougm 		while ((ret = scf_iter_next_instance(iter,
929*3034Sdougm 							instance)) > 0) {
930*3034Sdougm 		    if (scf_instance_get_name(instance, buff,
931*3034Sdougm 						sizeof (buff)) > 0) {
932*3034Sdougm 			if (strcmp(buff, "default") == 0)
933*3034Sdougm 			    sa_extract_defaults(*root, handle, instance);
934*3034Sdougm 			ret = sa_extract_group(*root, handle, instance);
935*3034Sdougm 		    }
936*3034Sdougm 		}
937*3034Sdougm 	    }
938*3034Sdougm 	} else {
939*3034Sdougm 	    /* if we can't create the document, cleanup */
940*3034Sdougm 	    if (*doc != NULL)
941*3034Sdougm 		xmlFreeDoc(*doc);
942*3034Sdougm 	    if (*root != NULL)
943*3034Sdougm 		xmlFreeNode(*root);
944*3034Sdougm 	    *doc = NULL;
945*3034Sdougm 	    *root = NULL;
946*3034Sdougm 	}
947*3034Sdougm 	/* always cleanup these */
948*3034Sdougm 	if (instance != NULL)
949*3034Sdougm 	    scf_instance_destroy(instance);
950*3034Sdougm 	if (iter != NULL)
951*3034Sdougm 	    scf_iter_destroy(iter);
952*3034Sdougm 	return (ret);
953*3034Sdougm }
954*3034Sdougm 
955*3034Sdougm /*
956*3034Sdougm  * sa_get_instance(handle, instance)
957*3034Sdougm  *
958*3034Sdougm  * get the instance of the group service. This is actually the
959*3034Sdougm  * specific group name. The instance is needed for all property and
960*3034Sdougm  * control operations.
961*3034Sdougm  */
962*3034Sdougm 
963*3034Sdougm int
964*3034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
965*3034Sdougm {
966*3034Sdougm 	if (scf_service_get_instance(handle->service, instname,
967*3034Sdougm 					handle->instance) != 0) {
968*3034Sdougm 	    return (SA_NO_SUCH_GROUP);
969*3034Sdougm 	}
970*3034Sdougm 	return (SA_OK);
971*3034Sdougm }
972*3034Sdougm 
973*3034Sdougm /*
974*3034Sdougm  * sa_create_instance(handle, instname)
975*3034Sdougm  *
976*3034Sdougm  * Create a new SMF service instance. There can only be one with a
977*3034Sdougm  * given name.
978*3034Sdougm  */
979*3034Sdougm 
980*3034Sdougm int
981*3034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
982*3034Sdougm {
983*3034Sdougm 	int ret = SA_OK;
984*3034Sdougm 	char instance[SA_GROUP_INST_LEN];
985*3034Sdougm 	if (scf_service_add_instance(handle->service, instname,
986*3034Sdougm 					handle->instance) != 0) {
987*3034Sdougm 	/* better error returns need to be added based on real error */
988*3034Sdougm 	    if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
989*3034Sdougm 		ret = SA_NO_PERMISSION;
990*3034Sdougm 	    else
991*3034Sdougm 		ret = SA_DUPLICATE_NAME;
992*3034Sdougm 	} else {
993*3034Sdougm 	    /* have the service created, so enable it */
994*3034Sdougm 	    (void) snprintf(instance, sizeof (instance), "%s:%s",
995*3034Sdougm 				SA_SVC_FMRI_BASE, instname);
996*3034Sdougm 	    (void) smf_enable_instance(instance, 0);
997*3034Sdougm 	}
998*3034Sdougm 	return (ret);
999*3034Sdougm }
1000*3034Sdougm 
1001*3034Sdougm /*
1002*3034Sdougm  * sa_delete_instance(handle, instname)
1003*3034Sdougm  *
1004*3034Sdougm  * When a group goes away, we also remove the service instance.
1005*3034Sdougm  */
1006*3034Sdougm 
1007*3034Sdougm int
1008*3034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
1009*3034Sdougm {
1010*3034Sdougm 	int ret;
1011*3034Sdougm 
1012*3034Sdougm 	if (strcmp(instname, "default") == 0) {
1013*3034Sdougm 	    ret = SA_NO_PERMISSION;
1014*3034Sdougm 	} else {
1015*3034Sdougm 	    if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
1016*3034Sdougm 		if (scf_instance_delete(handle->instance) != 0)
1017*3034Sdougm 			/* need better analysis */
1018*3034Sdougm 		    ret = SA_NO_PERMISSION;
1019*3034Sdougm 	    }
1020*3034Sdougm 	}
1021*3034Sdougm 	return (ret);
1022*3034Sdougm }
1023*3034Sdougm 
1024*3034Sdougm /*
1025*3034Sdougm  * sa_create_pgroup(handle, pgroup)
1026*3034Sdougm  *
1027*3034Sdougm  * create a new property group
1028*3034Sdougm  */
1029*3034Sdougm 
1030*3034Sdougm int
1031*3034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
1032*3034Sdougm {
1033*3034Sdougm 	int ret = SA_OK;
1034*3034Sdougm 	/*
1035*3034Sdougm 	 * only create a handle if it doesn't exist. It is ok to exist
1036*3034Sdougm 	 * since the pg handle will be set as a side effect.
1037*3034Sdougm 	 */
1038*3034Sdougm 	if (handle->pg == NULL) {
1039*3034Sdougm 	    handle->pg = scf_pg_create(handle->handle);
1040*3034Sdougm 	}
1041*3034Sdougm 	/*
1042*3034Sdougm 	 * if the pgroup exists, we are done. If it doesn't, then we
1043*3034Sdougm 	 * need to actually add one to the service instance.
1044*3034Sdougm 	 */
1045*3034Sdougm 	if (scf_instance_get_pg(handle->instance,
1046*3034Sdougm 				pgroup, handle->pg) != 0) {
1047*3034Sdougm 	    /* doesn't exist so create one */
1048*3034Sdougm 	    if (scf_instance_add_pg(handle->instance, pgroup,
1049*3034Sdougm 				    SCF_GROUP_APPLICATION, 0,
1050*3034Sdougm 				    handle->pg) != 0) {
1051*3034Sdougm 		switch (scf_error()) {
1052*3034Sdougm 		case SCF_ERROR_PERMISSION_DENIED:
1053*3034Sdougm 		    ret = SA_NO_PERMISSION;
1054*3034Sdougm 		    break;
1055*3034Sdougm 		default:
1056*3034Sdougm 		    ret = SA_SYSTEM_ERR;
1057*3034Sdougm 		    break;
1058*3034Sdougm 		}
1059*3034Sdougm 	    }
1060*3034Sdougm 	}
1061*3034Sdougm 	return (ret);
1062*3034Sdougm }
1063*3034Sdougm 
1064*3034Sdougm /*
1065*3034Sdougm  * sa_delete_pgroup(handle, pgroup)
1066*3034Sdougm  *
1067*3034Sdougm  * remove the property group from the current instance of the service,
1068*3034Sdougm  * but only if it actually exists.
1069*3034Sdougm  */
1070*3034Sdougm 
1071*3034Sdougm int
1072*3034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
1073*3034Sdougm {
1074*3034Sdougm 	int ret = SA_OK;
1075*3034Sdougm 	/*
1076*3034Sdougm 	 * only delete if it does exist.
1077*3034Sdougm 	 */
1078*3034Sdougm 	if (scf_instance_get_pg(handle->instance,
1079*3034Sdougm 				pgroup, handle->pg) == 0) {
1080*3034Sdougm 	    /* does exist so delete it */
1081*3034Sdougm 	    if (scf_pg_delete(handle->pg) != 0) {
1082*3034Sdougm 		ret = SA_SYSTEM_ERR;
1083*3034Sdougm 	    }
1084*3034Sdougm 	} else {
1085*3034Sdougm 	    ret = SA_SYSTEM_ERR;
1086*3034Sdougm 	}
1087*3034Sdougm 	if (ret == SA_SYSTEM_ERR &&
1088*3034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
1089*3034Sdougm 		ret = SA_NO_PERMISSION;
1090*3034Sdougm 	}
1091*3034Sdougm 	return (ret);
1092*3034Sdougm }
1093*3034Sdougm 
1094*3034Sdougm /*
1095*3034Sdougm  * sa_start_transaction(handle, pgroup)
1096*3034Sdougm  *
1097*3034Sdougm  * Start an SMF transaction so we can deal with properties. it would
1098*3034Sdougm  * be nice to not have to expose this, but we have to in order to
1099*3034Sdougm  * optimize.
1100*3034Sdougm  *
1101*3034Sdougm  * Basic model is to hold the transaction in the handle and allow
1102*3034Sdougm  * property adds/deletes/updates to be added then close the
1103*3034Sdougm  * transaction (or abort).  There may eventually be a need to handle
1104*3034Sdougm  * other types of transaction mechanisms but we don't do that now.
1105*3034Sdougm  *
1106*3034Sdougm  * An sa_start_transaction must be followed by either an
1107*3034Sdougm  * sa_end_transaction or sa_abort_transaction before another
1108*3034Sdougm  * sa_start_transaction can be done.
1109*3034Sdougm  */
1110*3034Sdougm 
1111*3034Sdougm int
1112*3034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
1113*3034Sdougm {
1114*3034Sdougm 	int ret = SA_OK;
1115*3034Sdougm 	/*
1116*3034Sdougm 	 * lookup the property group and create it if it doesn't already
1117*3034Sdougm 	 * exist.
1118*3034Sdougm 	 */
1119*3034Sdougm 	if (handle->scf_state == SCH_STATE_INIT) {
1120*3034Sdougm 	    ret = sa_create_pgroup(handle, propgroup);
1121*3034Sdougm 	    if (ret == SA_OK) {
1122*3034Sdougm 		handle->trans = scf_transaction_create(handle->handle);
1123*3034Sdougm 		if (handle->trans != NULL) {
1124*3034Sdougm 		    if (scf_transaction_start(handle->trans, handle->pg) != 0) {
1125*3034Sdougm 			ret = SA_SYSTEM_ERR;
1126*3034Sdougm 		    }
1127*3034Sdougm 		    if (ret != SA_OK) {
1128*3034Sdougm 			scf_transaction_destroy(handle->trans);
1129*3034Sdougm 			handle->trans = NULL;
1130*3034Sdougm 		    }
1131*3034Sdougm 		} else {
1132*3034Sdougm 		    ret = SA_SYSTEM_ERR;
1133*3034Sdougm 		}
1134*3034Sdougm 	    }
1135*3034Sdougm 	}
1136*3034Sdougm 	if (ret == SA_SYSTEM_ERR &&
1137*3034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
1138*3034Sdougm 		ret = SA_NO_PERMISSION;
1139*3034Sdougm 	}
1140*3034Sdougm 	return (ret);
1141*3034Sdougm }
1142*3034Sdougm 
1143*3034Sdougm /*
1144*3034Sdougm  * sa_end_transaction(handle)
1145*3034Sdougm  *
1146*3034Sdougm  * Commit the changes that were added to the transaction in the
1147*3034Sdougm  * handle. Do all necessary cleanup.
1148*3034Sdougm  */
1149*3034Sdougm 
1150*3034Sdougm int
1151*3034Sdougm sa_end_transaction(scfutilhandle_t *handle)
1152*3034Sdougm {
1153*3034Sdougm 	int ret = SA_OK;
1154*3034Sdougm 
1155*3034Sdougm 	if (handle->trans == NULL) {
1156*3034Sdougm 	    ret = SA_SYSTEM_ERR;
1157*3034Sdougm 	} else {
1158*3034Sdougm 	    if (scf_transaction_commit(handle->trans) < 0)
1159*3034Sdougm 		ret = SA_SYSTEM_ERR;
1160*3034Sdougm 	    scf_transaction_destroy_children(handle->trans);
1161*3034Sdougm 	    scf_transaction_destroy(handle->trans);
1162*3034Sdougm 	    handle->trans = NULL;
1163*3034Sdougm 	}
1164*3034Sdougm 	return (ret);
1165*3034Sdougm }
1166*3034Sdougm 
1167*3034Sdougm /*
1168*3034Sdougm  * sa_abort_transaction(handle)
1169*3034Sdougm  *
1170*3034Sdougm  * Abort the changes that were added to the transaction in the
1171*3034Sdougm  * handle. Do all necessary cleanup.
1172*3034Sdougm  */
1173*3034Sdougm 
1174*3034Sdougm void
1175*3034Sdougm sa_abort_transaction(scfutilhandle_t *handle)
1176*3034Sdougm {
1177*3034Sdougm 	if (handle->trans != NULL) {
1178*3034Sdougm 	    scf_transaction_reset_all(handle->trans);
1179*3034Sdougm 	    scf_transaction_destroy_children(handle->trans);
1180*3034Sdougm 	    scf_transaction_destroy(handle->trans);
1181*3034Sdougm 	    handle->trans = NULL;
1182*3034Sdougm 	}
1183*3034Sdougm }
1184*3034Sdougm 
1185*3034Sdougm /*
1186*3034Sdougm  * sa_set_property(handle, prop, value)
1187*3034Sdougm  *
1188*3034Sdougm  * set a property transaction entry into the pending SMF transaction.
1189*3034Sdougm  */
1190*3034Sdougm 
1191*3034Sdougm int
1192*3034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
1193*3034Sdougm {
1194*3034Sdougm 	int ret = SA_OK;
1195*3034Sdougm 	scf_value_t *value;
1196*3034Sdougm 	scf_transaction_entry_t *entry;
1197*3034Sdougm 	/*
1198*3034Sdougm 	 * properties must be set in transactions and don't take
1199*3034Sdougm 	 * effect until the transaction has been ended/committed.
1200*3034Sdougm 	 */
1201*3034Sdougm 	value = scf_value_create(handle->handle);
1202*3034Sdougm 	entry = scf_entry_create(handle->handle);
1203*3034Sdougm 	if (value != NULL && entry != NULL) {
1204*3034Sdougm 	    if (scf_transaction_property_change(handle->trans, entry,
1205*3034Sdougm 						propname,
1206*3034Sdougm 						SCF_TYPE_ASTRING) == 0 ||
1207*3034Sdougm 		scf_transaction_property_new(handle->trans, entry,
1208*3034Sdougm 						propname,
1209*3034Sdougm 						SCF_TYPE_ASTRING) == 0) {
1210*3034Sdougm 		if (scf_value_set_astring(value, valstr) == 0) {
1211*3034Sdougm 		    if (scf_entry_add_value(entry, value) != 0) {
1212*3034Sdougm 			ret = SA_SYSTEM_ERR;
1213*3034Sdougm 			scf_value_destroy(value);
1214*3034Sdougm 		    }
1215*3034Sdougm 		    /* the value is in the transaction */
1216*3034Sdougm 		    value = NULL;
1217*3034Sdougm 		} else {
1218*3034Sdougm 		    /* value couldn't be constructed */
1219*3034Sdougm 		    ret = SA_SYSTEM_ERR;
1220*3034Sdougm 		}
1221*3034Sdougm 		/* the entry is in the transaction */
1222*3034Sdougm 		entry = NULL;
1223*3034Sdougm 	    } else {
1224*3034Sdougm 		ret = SA_SYSTEM_ERR;
1225*3034Sdougm 	    }
1226*3034Sdougm 	} else {
1227*3034Sdougm 	    ret = SA_SYSTEM_ERR;
1228*3034Sdougm 	}
1229*3034Sdougm 	if (ret == SA_SYSTEM_ERR) {
1230*3034Sdougm 	    switch (scf_error()) {
1231*3034Sdougm 	    case SCF_ERROR_PERMISSION_DENIED:
1232*3034Sdougm 		ret = SA_NO_PERMISSION;
1233*3034Sdougm 		break;
1234*3034Sdougm 	    }
1235*3034Sdougm 	}
1236*3034Sdougm 	/*
1237*3034Sdougm 	 * cleanup if there were any errors that didn't leave these
1238*3034Sdougm 	 * values where they would be cleaned up later.
1239*3034Sdougm 	 */
1240*3034Sdougm 	if (value != NULL)
1241*3034Sdougm 	    scf_value_destroy(value);
1242*3034Sdougm 	if (entry != NULL)
1243*3034Sdougm 	    scf_entry_destroy(entry);
1244*3034Sdougm 	return (ret);
1245*3034Sdougm }
1246*3034Sdougm 
1247*3034Sdougm /*
1248*3034Sdougm  * sa_commit_share(handle, group, share)
1249*3034Sdougm  *
1250*3034Sdougm  *	commit this share to the repository.
1251*3034Sdougm  *	properties are added if they exist but can be added later.
1252*3034Sdougm  *	Need to add to dfstab and sharetab, if appropriate.
1253*3034Sdougm  */
1254*3034Sdougm int
1255*3034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
1256*3034Sdougm {
1257*3034Sdougm 	int ret = SA_OK;
1258*3034Sdougm 	char *groupname;
1259*3034Sdougm 	char *name;
1260*3034Sdougm 	char *resource;
1261*3034Sdougm 	char *description;
1262*3034Sdougm 	char *sharename;
1263*3034Sdougm 	ssize_t proplen;
1264*3034Sdougm 	char *propstring;
1265*3034Sdougm 
1266*3034Sdougm 	/*
1267*3034Sdougm 	 * don't commit in the zfs group. We do commit legacy
1268*3034Sdougm 	 * (default) and all other groups/shares. ZFS is handled
1269*3034Sdougm 	 * through the ZFS configuration rather than SMF.
1270*3034Sdougm 	 */
1271*3034Sdougm 
1272*3034Sdougm 	groupname = sa_get_group_attr(group, "name");
1273*3034Sdougm 	if (groupname != NULL) {
1274*3034Sdougm 	    if (strcmp(groupname, "zfs") == 0) {
1275*3034Sdougm 		/*
1276*3034Sdougm 		 * adding to the ZFS group will result in the sharenfs
1277*3034Sdougm 		 * property being set but we don't want to do anything
1278*3034Sdougm 		 * SMF related at this point.
1279*3034Sdougm 		 */
1280*3034Sdougm 		sa_free_attr_string(groupname);
1281*3034Sdougm 		return (ret);
1282*3034Sdougm 	    }
1283*3034Sdougm 	}
1284*3034Sdougm 
1285*3034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1286*3034Sdougm 	propstring = malloc(proplen);
1287*3034Sdougm 	if (propstring == NULL)
1288*3034Sdougm 	    ret = SA_NO_MEMORY;
1289*3034Sdougm 
1290*3034Sdougm 	if (groupname != NULL && ret == SA_OK) {
1291*3034Sdougm 	    ret = sa_get_instance(handle, groupname);
1292*3034Sdougm 	    sa_free_attr_string(groupname);
1293*3034Sdougm 	    groupname = NULL;
1294*3034Sdougm 	    sharename = sa_get_share_attr(share, "id");
1295*3034Sdougm 	    if (sharename == NULL) {
1296*3034Sdougm 		/* slipped by */
1297*3034Sdougm 		char shname[SA_SHARE_UUID_BUFLEN];
1298*3034Sdougm 		generate_unique_sharename(shname);
1299*3034Sdougm 		xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
1300*3034Sdougm 			    (xmlChar *)shname);
1301*3034Sdougm 		sharename = strdup(shname);
1302*3034Sdougm 	    }
1303*3034Sdougm 	    if (sharename != NULL) {
1304*3034Sdougm 		/*
1305*3034Sdougm 		 * have a share name allocated so create a pgroup
1306*3034Sdougm 		 * for it. It may already exist, but that is OK.
1307*3034Sdougm 		 */
1308*3034Sdougm 		ret = sa_create_pgroup(handle, sharename);
1309*3034Sdougm 		if (ret == SA_OK) {
1310*3034Sdougm 			/*
1311*3034Sdougm 			 * now start the transaction for the
1312*3034Sdougm 			 * properties that define this share. They may
1313*3034Sdougm 			 * exist so attempt to update before create.
1314*3034Sdougm 			 */
1315*3034Sdougm 		    ret = sa_start_transaction(handle, sharename);
1316*3034Sdougm 		}
1317*3034Sdougm 		if (ret == SA_OK) {
1318*3034Sdougm 		    name = sa_get_share_attr(share, "path");
1319*3034Sdougm 		    if (name != NULL) {
1320*3034Sdougm 			/* there needs to be a path for a share to exist */
1321*3034Sdougm 			ret = sa_set_property(handle, "path", name);
1322*3034Sdougm 			sa_free_attr_string(name);
1323*3034Sdougm 		    } else {
1324*3034Sdougm 			ret = SA_NO_MEMORY;
1325*3034Sdougm 		    }
1326*3034Sdougm 		}
1327*3034Sdougm 		if (ret == SA_OK) {
1328*3034Sdougm 		    resource = sa_get_share_attr(share, "resource");
1329*3034Sdougm 		    if (resource != NULL) {
1330*3034Sdougm 			ret = sa_set_property(handle, "resource", resource);
1331*3034Sdougm 			sa_free_attr_string(resource);
1332*3034Sdougm 		    }
1333*3034Sdougm 		}
1334*3034Sdougm 		if (ret == SA_OK) {
1335*3034Sdougm 		    description = sa_get_share_description(share);
1336*3034Sdougm 		    if (description != NULL) {
1337*3034Sdougm 			ret = sa_set_property(handle, "description",
1338*3034Sdougm 						description);
1339*3034Sdougm 			sa_free_share_description(description);
1340*3034Sdougm 		    }
1341*3034Sdougm 		}
1342*3034Sdougm 		/* make sure we cleanup the transaction */
1343*3034Sdougm 		if (ret == SA_OK) {
1344*3034Sdougm 		    ret = sa_end_transaction(handle);
1345*3034Sdougm 		} else {
1346*3034Sdougm 		    sa_abort_transaction(handle);
1347*3034Sdougm 		}
1348*3034Sdougm 		free(sharename);
1349*3034Sdougm 	    }
1350*3034Sdougm 	}
1351*3034Sdougm 	if (ret == SA_SYSTEM_ERR) {
1352*3034Sdougm 	    int err = scf_error();
1353*3034Sdougm 	    if (err == SCF_ERROR_PERMISSION_DENIED)
1354*3034Sdougm 		ret = SA_NO_PERMISSION;
1355*3034Sdougm 	}
1356*3034Sdougm 	if (propstring != NULL)
1357*3034Sdougm 	    free(propstring);
1358*3034Sdougm 	if (groupname != NULL)
1359*3034Sdougm 	    sa_free_attr_string(groupname);
1360*3034Sdougm 
1361*3034Sdougm 	return (ret);
1362*3034Sdougm }
1363*3034Sdougm 
1364*3034Sdougm /*
1365*3034Sdougm  * sa_delete_share(handle, group, share)
1366*3034Sdougm  *
1367*3034Sdougm  * remove the specified share from the group (and service instance).
1368*3034Sdougm  */
1369*3034Sdougm 
1370*3034Sdougm int
1371*3034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
1372*3034Sdougm {
1373*3034Sdougm 	int ret = SA_OK;
1374*3034Sdougm 	char *groupname = NULL;
1375*3034Sdougm 	char *shareid = NULL;
1376*3034Sdougm 	sa_optionset_t opt;
1377*3034Sdougm 	sa_security_t sec;
1378*3034Sdougm 	ssize_t proplen;
1379*3034Sdougm 	char *propstring;
1380*3034Sdougm 
1381*3034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1382*3034Sdougm 	propstring = malloc(proplen);
1383*3034Sdougm 	if (propstring == NULL)
1384*3034Sdougm 	    ret = SA_NO_MEMORY;
1385*3034Sdougm 
1386*3034Sdougm 	if (ret == SA_OK) {
1387*3034Sdougm 	    groupname = sa_get_group_attr(group, "name");
1388*3034Sdougm 	    shareid = sa_get_share_attr(share, "id");
1389*3034Sdougm 	    if (groupname != NULL && shareid != NULL) {
1390*3034Sdougm 		ret = sa_get_instance(handle, groupname);
1391*3034Sdougm 		if (ret == SA_OK) {
1392*3034Sdougm 		    /* if a share has properties, remove them */
1393*3034Sdougm 		    ret = sa_delete_pgroup(handle, shareid);
1394*3034Sdougm 		    for (opt = sa_get_optionset(share, NULL); opt != NULL;
1395*3034Sdougm 			opt = sa_get_next_optionset(opt)) {
1396*3034Sdougm 			char *proto;
1397*3034Sdougm 			proto = sa_get_optionset_attr(opt, "type");
1398*3034Sdougm 			if (proto != NULL) {
1399*3034Sdougm 			    (void) snprintf(propstring, proplen, "%s_%s",
1400*3034Sdougm 						shareid, proto);
1401*3034Sdougm 			    ret = sa_delete_pgroup(handle, propstring);
1402*3034Sdougm 			    sa_free_attr_string(proto);
1403*3034Sdougm 			} else {
1404*3034Sdougm 			    ret = SA_NO_MEMORY;
1405*3034Sdougm 			}
1406*3034Sdougm 		    }
1407*3034Sdougm 			/*
1408*3034Sdougm 			 * if a share has security/negotiable
1409*3034Sdougm 			 * properties, remove them.
1410*3034Sdougm 			 */
1411*3034Sdougm 		    for (sec = sa_get_security(share, NULL, NULL); sec != NULL;
1412*3034Sdougm 			sec = sa_get_next_security(sec)) {
1413*3034Sdougm 			char *proto;
1414*3034Sdougm 			char *sectype;
1415*3034Sdougm 			proto = sa_get_security_attr(sec, "type");
1416*3034Sdougm 			sectype = sa_get_security_attr(sec, "sectype");
1417*3034Sdougm 			if (proto != NULL && sectype != NULL) {
1418*3034Sdougm 			    (void) snprintf(propstring, proplen, "%s_%s_%s",
1419*3034Sdougm 					shareid,
1420*3034Sdougm 					proto, sectype);
1421*3034Sdougm 			    ret = sa_delete_pgroup(handle, propstring);
1422*3034Sdougm 			} else {
1423*3034Sdougm 			    ret = SA_NO_MEMORY;
1424*3034Sdougm 			}
1425*3034Sdougm 			if (proto != NULL)
1426*3034Sdougm 			    sa_free_attr_string(proto);
1427*3034Sdougm 			if (sectype != NULL)
1428*3034Sdougm 			    sa_free_attr_string(sectype);
1429*3034Sdougm 		    }
1430*3034Sdougm 		}
1431*3034Sdougm 	    } else {
1432*3034Sdougm 		ret = SA_CONFIG_ERR;
1433*3034Sdougm 	    }
1434*3034Sdougm 	}
1435*3034Sdougm 	if (groupname != NULL)
1436*3034Sdougm 	    sa_free_attr_string(groupname);
1437*3034Sdougm 	if (shareid != NULL)
1438*3034Sdougm 	    sa_free_attr_string(shareid);
1439*3034Sdougm 	if (propstring != NULL)
1440*3034Sdougm 	    free(propstring);
1441*3034Sdougm 
1442*3034Sdougm 	return (ret);
1443*3034Sdougm }
1444