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