16185db85Sdougm /* 26185db85Sdougm * CDDL HEADER START 36185db85Sdougm * 46185db85Sdougm * The contents of this file are subject to the terms of the 56185db85Sdougm * Common Development and Distribution License (the "License"). 66185db85Sdougm * You may not use this file except in compliance with the License. 76185db85Sdougm * 86185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96185db85Sdougm * or http://www.opensolaris.org/os/licensing. 106185db85Sdougm * See the License for the specific language governing permissions 116185db85Sdougm * and limitations under the License. 126185db85Sdougm * 136185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each 146185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the 166185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 176185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 186185db85Sdougm * 196185db85Sdougm * CDDL HEADER END 206185db85Sdougm */ 216185db85Sdougm 226185db85Sdougm /* 23f345c0beSdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 246185db85Sdougm * Use is subject to license terms. 256185db85Sdougm */ 266185db85Sdougm 276185db85Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 286185db85Sdougm 296185db85Sdougm /* helper functions for using libscf with sharemgr */ 306185db85Sdougm 316185db85Sdougm #include <libscf.h> 326185db85Sdougm #include <libxml/parser.h> 336185db85Sdougm #include <libxml/tree.h> 346185db85Sdougm #include "libshare.h" 356185db85Sdougm #include "libshare_impl.h" 366185db85Sdougm #include "scfutil.h" 376185db85Sdougm #include <string.h> 386185db85Sdougm #include <errno.h> 396185db85Sdougm #include <uuid/uuid.h> 406185db85Sdougm #include <sys/param.h> 41f345c0beSdougm #include <signal.h> 426185db85Sdougm 436185db85Sdougm ssize_t scf_max_name_len; 446185db85Sdougm extern struct sa_proto_plugin *sap_proto_list; 45549ec3ffSdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr); 466185db85Sdougm 476185db85Sdougm /* 486185db85Sdougm * The SMF facility uses some properties that must exist. We want to 496185db85Sdougm * skip over these when processing protocol options. 506185db85Sdougm */ 516185db85Sdougm static char *skip_props[] = { 526185db85Sdougm "modify_authorization", 536185db85Sdougm "action_authorization", 546185db85Sdougm "value_authorization", 556185db85Sdougm NULL 566185db85Sdougm }; 576185db85Sdougm 586185db85Sdougm /* 596185db85Sdougm * sa_scf_fini(handle) 606185db85Sdougm * 616185db85Sdougm * must be called when done. Called with the handle allocated in 626185db85Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 636185db85Sdougm * still in use. Called by sa_fini(). 646185db85Sdougm */ 656185db85Sdougm 666185db85Sdougm void 676185db85Sdougm sa_scf_fini(scfutilhandle_t *handle) 686185db85Sdougm { 696185db85Sdougm if (handle != NULL) { 706185db85Sdougm int unbind = 0; 716185db85Sdougm if (handle->scope != NULL) { 726185db85Sdougm unbind = 1; 736185db85Sdougm scf_scope_destroy(handle->scope); 746185db85Sdougm } 75*a3351425Sdougm if (handle->instance != NULL) 76*a3351425Sdougm scf_instance_destroy(handle->instance); 776185db85Sdougm if (handle->service != NULL) 786185db85Sdougm scf_service_destroy(handle->service); 796185db85Sdougm if (handle->pg != NULL) 806185db85Sdougm scf_pg_destroy(handle->pg); 816185db85Sdougm if (handle->handle != NULL) { 826185db85Sdougm handle->scf_state = SCH_STATE_UNINIT; 836185db85Sdougm if (unbind) 846185db85Sdougm (void) scf_handle_unbind(handle->handle); 856185db85Sdougm scf_handle_destroy(handle->handle); 866185db85Sdougm } 876185db85Sdougm free(handle); 886185db85Sdougm } 896185db85Sdougm } 906185db85Sdougm 916185db85Sdougm /* 926185db85Sdougm * sa_scf_init() 936185db85Sdougm * 946185db85Sdougm * must be called before using any of the SCF functions. Called by 956185db85Sdougm * sa_init() during the API setup. 966185db85Sdougm */ 976185db85Sdougm 986185db85Sdougm scfutilhandle_t * 99549ec3ffSdougm sa_scf_init(sa_handle_impl_t ihandle) 1006185db85Sdougm { 1016185db85Sdougm scfutilhandle_t *handle; 1026185db85Sdougm 1036185db85Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1046185db85Sdougm if (scf_max_name_len <= 0) 1056185db85Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1066185db85Sdougm 1076185db85Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 1086185db85Sdougm if (handle != NULL) { 109549ec3ffSdougm ihandle->scfhandle = handle; 1106185db85Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 1116185db85Sdougm handle->handle = scf_handle_create(SCF_VERSION); 1126185db85Sdougm if (handle->handle != NULL) { 1136185db85Sdougm if (scf_handle_bind(handle->handle) == 0) { 1146185db85Sdougm handle->scope = scf_scope_create(handle->handle); 1156185db85Sdougm handle->service = scf_service_create(handle->handle); 1166185db85Sdougm handle->pg = scf_pg_create(handle->handle); 117*a3351425Sdougm 118*a3351425Sdougm /* make sure we have sufficient SMF running */ 1196185db85Sdougm handle->instance = scf_instance_create(handle->handle); 120*a3351425Sdougm if (handle->scope == NULL || handle->service == NULL || 121*a3351425Sdougm handle->pg == NULL || handle->instance == NULL) 122*a3351425Sdougm goto err; 123*a3351425Sdougm 1246185db85Sdougm if (scf_handle_get_scope(handle->handle, 1256185db85Sdougm SCF_SCOPE_LOCAL, handle->scope) == 0) { 1266185db85Sdougm if (scf_scope_get_service(handle->scope, 1276185db85Sdougm SA_GROUP_SVC_NAME, 1286185db85Sdougm handle->service) != 0) { 1296185db85Sdougm goto err; 1306185db85Sdougm } 1316185db85Sdougm handle->scf_state = SCH_STATE_INIT; 1326185db85Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 1336185db85Sdougm char **protolist; 1346185db85Sdougm int numprotos, i; 1356185db85Sdougm sa_group_t defgrp; 136549ec3ffSdougm defgrp = sa_create_group((sa_handle_t)ihandle, 137549ec3ffSdougm "default", NULL); 1386185db85Sdougm if (defgrp != NULL) { 1396185db85Sdougm numprotos = sa_get_protocols(&protolist); 1406185db85Sdougm for (i = 0; i < numprotos; i++) { 1416185db85Sdougm (void) sa_create_optionset(defgrp, 1426185db85Sdougm protolist[i]); 1436185db85Sdougm } 1446185db85Sdougm if (protolist != NULL) 1456185db85Sdougm free(protolist); 1466185db85Sdougm } 1476185db85Sdougm } 1486185db85Sdougm } else { 1496185db85Sdougm goto err; 1506185db85Sdougm } 1516185db85Sdougm } else { 1526185db85Sdougm goto err; 1536185db85Sdougm } 1546185db85Sdougm } else { 1556185db85Sdougm free(handle); 1566185db85Sdougm handle = NULL; 1576185db85Sdougm (void) printf("libshare could not access SMF repository: %s\n", 1586185db85Sdougm scf_strerror(scf_error())); 1596185db85Sdougm } 1606185db85Sdougm } 1616185db85Sdougm return (handle); 1626185db85Sdougm 1636185db85Sdougm /* error handling/unwinding */ 1646185db85Sdougm err: 1656185db85Sdougm (void) sa_scf_fini(handle); 1666185db85Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1676185db85Sdougm scf_strerror(scf_error())); 1686185db85Sdougm return (NULL); 1696185db85Sdougm } 1706185db85Sdougm 1716185db85Sdougm /* 1726185db85Sdougm * get_scf_limit(name) 1736185db85Sdougm * 1746185db85Sdougm * Since we use scf_limit a lot and do the same check and return the 1756185db85Sdougm * same value if it fails, implement as a function for code 1766185db85Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1776185db85Sdougm * (1024) so we have a reasonable default buffer size. 1786185db85Sdougm */ 1796185db85Sdougm static ssize_t 1806185db85Sdougm get_scf_limit(uint32_t name) 1816185db85Sdougm { 1826185db85Sdougm ssize_t vallen; 1836185db85Sdougm 1846185db85Sdougm vallen = scf_limit(name); 1856185db85Sdougm if (vallen == (ssize_t)-1) 1866185db85Sdougm vallen = MAXPATHLEN; 1876185db85Sdougm return (vallen); 1886185db85Sdougm } 1896185db85Sdougm 1906185db85Sdougm /* 1916185db85Sdougm * skip_property(name) 1926185db85Sdougm * 1936185db85Sdougm * internal function to check to see if a property is an SMF magic 1946185db85Sdougm * property that needs to be skipped. 1956185db85Sdougm */ 1966185db85Sdougm static int 1976185db85Sdougm skip_property(char *name) 1986185db85Sdougm { 1996185db85Sdougm int i; 2006185db85Sdougm 2016185db85Sdougm for (i = 0; skip_props[i] != NULL; i++) 2026185db85Sdougm if (strcmp(name, skip_props[i]) == 0) 2036185db85Sdougm return (1); 2046185db85Sdougm return (0); 2056185db85Sdougm } 2066185db85Sdougm 2076185db85Sdougm /* 2086185db85Sdougm * generate_unique_sharename(sharename) 2096185db85Sdougm * 2106185db85Sdougm * Shares are represented in SMF as property groups. Due to share 2116185db85Sdougm * paths containing characters that are not allowed in SMF names and 2126185db85Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2136185db85Sdougm */ 2146185db85Sdougm 2156185db85Sdougm static void 2166185db85Sdougm generate_unique_sharename(char *sharename) 2176185db85Sdougm { 2186185db85Sdougm uuid_t uuid; 2196185db85Sdougm 2206185db85Sdougm uuid_generate(uuid); 2216185db85Sdougm (void) strcpy(sharename, "S-"); 2226185db85Sdougm uuid_unparse(uuid, sharename + 2); 2236185db85Sdougm } 2246185db85Sdougm 2256185db85Sdougm /* 2266185db85Sdougm * valid_protocol(proto) 2276185db85Sdougm * 2286185db85Sdougm * check to see if the specified protocol is a valid one for the 2296185db85Sdougm * general sharemgr facility. We determine this by checking which 2306185db85Sdougm * plugin protocols were found. 2316185db85Sdougm */ 2326185db85Sdougm 2336185db85Sdougm static int 2346185db85Sdougm valid_protocol(char *proto) 2356185db85Sdougm { 2366185db85Sdougm struct sa_proto_plugin *plugin; 2376185db85Sdougm for (plugin = sap_proto_list; plugin != NULL; 2386185db85Sdougm plugin = plugin->plugin_next) 2396185db85Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2406185db85Sdougm return (1); 2416185db85Sdougm return (0); 2426185db85Sdougm } 2436185db85Sdougm 2446185db85Sdougm /* 2456185db85Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2466185db85Sdougm * 2476185db85Sdougm * extract the name property group and create the specified type of 2486185db85Sdougm * node on the provided group. type will be optionset or security. 2496185db85Sdougm */ 2506185db85Sdougm 2516185db85Sdougm static int 2526185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2536185db85Sdougm scf_propertygroup_t *pg, 2546185db85Sdougm char *nodetype, char *proto, char *sectype) 2556185db85Sdougm { 2566185db85Sdougm xmlNodePtr node; 2576185db85Sdougm scf_iter_t *iter; 2586185db85Sdougm scf_property_t *prop; 2596185db85Sdougm scf_value_t *value; 2606185db85Sdougm char *name; 2616185db85Sdougm char *valuestr; 2626185db85Sdougm ssize_t vallen; 2636185db85Sdougm int ret = SA_OK; 2646185db85Sdougm 2656185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2666185db85Sdougm 2676185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 2686185db85Sdougm if (node != NULL) { 2696185db85Sdougm if (proto != NULL) 2706185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2716185db85Sdougm if (sectype != NULL) 2726185db85Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 2736185db85Sdougm /* 2746185db85Sdougm * have node to work with so iterate over the properties 2756185db85Sdougm * in the pg and create option sub nodes. 2766185db85Sdougm */ 2776185db85Sdougm iter = scf_iter_create(handle->handle); 2786185db85Sdougm value = scf_value_create(handle->handle); 2796185db85Sdougm prop = scf_property_create(handle->handle); 2806185db85Sdougm name = malloc(scf_max_name_len); 2816185db85Sdougm valuestr = malloc(vallen); 2826185db85Sdougm /* 2836185db85Sdougm * want to iterate through the properties and add them 2846185db85Sdougm * to the base optionset. 2856185db85Sdougm */ 2866185db85Sdougm if (iter != NULL && value != NULL && prop != NULL && 2876185db85Sdougm valuestr != NULL && name != NULL) { 2886185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 2896185db85Sdougm /* now iterate the properties in the group */ 2906185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2916185db85Sdougm /* have a property */ 2926185db85Sdougm if (scf_property_get_name(prop, name, 2936185db85Sdougm scf_max_name_len) > 0) { 2946185db85Sdougm /* some properties are part of the framework */ 2956185db85Sdougm if (skip_property(name)) 2966185db85Sdougm continue; 2976185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 2986185db85Sdougm if (scf_value_get_astring(value, valuestr, 2996185db85Sdougm vallen) >= 0) { 3006185db85Sdougm sa_property_t saprop; 3016185db85Sdougm saprop = sa_create_property(name, 3026185db85Sdougm valuestr); 3036185db85Sdougm if (saprop != NULL) { 3046185db85Sdougm /* 3056185db85Sdougm * since in SMF, don't 3066185db85Sdougm * recurse. Use xmlAddChild 3076185db85Sdougm * directly, instead. 3086185db85Sdougm */ 3096185db85Sdougm xmlAddChild(node, 3106185db85Sdougm (xmlNodePtr) saprop); 3116185db85Sdougm } 3126185db85Sdougm } 3136185db85Sdougm } 3146185db85Sdougm } 3156185db85Sdougm } 3166185db85Sdougm } 3176185db85Sdougm } else { 3186185db85Sdougm ret = SA_NO_MEMORY; 3196185db85Sdougm } 3206185db85Sdougm /* cleanup to avoid memory leaks */ 3216185db85Sdougm if (value != NULL) 3226185db85Sdougm scf_value_destroy(value); 3236185db85Sdougm if (iter != NULL) 3246185db85Sdougm scf_iter_destroy(iter); 3256185db85Sdougm if (prop != NULL) 3266185db85Sdougm scf_property_destroy(prop); 3276185db85Sdougm if (name != NULL) 3286185db85Sdougm free(name); 3296185db85Sdougm if (valuestr != NULL) 3306185db85Sdougm free(valuestr); 3316185db85Sdougm } 3326185db85Sdougm return (ret); 3336185db85Sdougm } 3346185db85Sdougm 3356185db85Sdougm /* 3366185db85Sdougm * sa_extract_attrs(root, handle, instance) 3376185db85Sdougm * 3386185db85Sdougm * local function to extract the actual attributes/properties from the 3396185db85Sdougm * property group of the service instance. These are the well known 3406185db85Sdougm * attributes of "state" and "zfs". If additional attributes are 3416185db85Sdougm * added, they should be added here. 3426185db85Sdougm */ 3436185db85Sdougm 3446185db85Sdougm static void 3456185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3466185db85Sdougm scf_instance_t *instance) 3476185db85Sdougm { 3486185db85Sdougm scf_property_t *prop; 3496185db85Sdougm scf_value_t *value; 3506185db85Sdougm char *valuestr; 3516185db85Sdougm ssize_t vallen; 3526185db85Sdougm 3536185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3546185db85Sdougm prop = scf_property_create(handle->handle); 3556185db85Sdougm value = scf_value_create(handle->handle); 3566185db85Sdougm valuestr = malloc(vallen); 3576185db85Sdougm if (prop != NULL && value != NULL && valuestr != NULL && 3586185db85Sdougm scf_instance_get_pg(instance, "operation", 3596185db85Sdougm handle->pg) == 0) { 3606185db85Sdougm /* 3616185db85Sdougm * have a property group with desired name so now get 3626185db85Sdougm * the known attributes. 3636185db85Sdougm */ 3646185db85Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 3656185db85Sdougm /* found the property so get the value */ 3666185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 3676185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) >= 0) { 3686185db85Sdougm xmlSetProp(root, (xmlChar *)"state", 3696185db85Sdougm (xmlChar *)valuestr); 3706185db85Sdougm } 3716185db85Sdougm } 3726185db85Sdougm } 3736185db85Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 3746185db85Sdougm /* found the property so get the value */ 3756185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 3766185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 3776185db85Sdougm xmlSetProp(root, (xmlChar *)"zfs", 3786185db85Sdougm (xmlChar *)valuestr); 3796185db85Sdougm } 3806185db85Sdougm } 3816185db85Sdougm } 3826185db85Sdougm } 3836185db85Sdougm if (valuestr != NULL) 3846185db85Sdougm free(valuestr); 3856185db85Sdougm if (value != NULL) 3866185db85Sdougm scf_value_destroy(value); 3876185db85Sdougm if (prop != NULL) 3886185db85Sdougm scf_property_destroy(prop); 3896185db85Sdougm } 3906185db85Sdougm 3916185db85Sdougm /* 3926185db85Sdougm * list of known share attributes. 3936185db85Sdougm */ 3946185db85Sdougm 3956185db85Sdougm static char *share_attr[] = { 3966185db85Sdougm "path", 3976185db85Sdougm "id", 3986185db85Sdougm "resource", 3996185db85Sdougm NULL, 4006185db85Sdougm }; 4016185db85Sdougm 4026185db85Sdougm static int 4036185db85Sdougm is_share_attr(char *name) 4046185db85Sdougm { 4056185db85Sdougm int i; 4066185db85Sdougm for (i = 0; share_attr[i] != NULL; i++) 4076185db85Sdougm if (strcmp(name, share_attr[i]) == 0) 4086185db85Sdougm return (1); 4096185db85Sdougm return (0); 4106185db85Sdougm } 4116185db85Sdougm 4126185db85Sdougm /* 4136185db85Sdougm * sa_share_from_pgroup 4146185db85Sdougm * 4156185db85Sdougm * extract the share definition from the share property group. We do 4166185db85Sdougm * some sanity checking to avoid bad data. 4176185db85Sdougm * 4186185db85Sdougm * Since this is only constructing the internal data structures, we 4196185db85Sdougm * don't use the sa_* functions most of the time. 4206185db85Sdougm */ 4216185db85Sdougm void 4226185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4236185db85Sdougm scf_propertygroup_t *pg, char *id) 4246185db85Sdougm { 4256185db85Sdougm xmlNodePtr node; 4266185db85Sdougm char *name; 4276185db85Sdougm scf_iter_t *iter; 4286185db85Sdougm scf_property_t *prop; 4296185db85Sdougm scf_value_t *value; 4306185db85Sdougm ssize_t vallen; 4316185db85Sdougm char *valuestr; 4326185db85Sdougm int ret = SA_OK; 433f345c0beSdougm int have_path = 0; 4346185db85Sdougm 4356185db85Sdougm /* 4366185db85Sdougm * While preliminary check (starts with 'S') passed before 4376185db85Sdougm * getting here. Need to make sure it is in ID syntax 4386185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 4396185db85Sdougm * pgroups. 4406185db85Sdougm */ 4416185db85Sdougm vallen = strlen(id); 4426185db85Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4436185db85Sdougm uuid_t uuid; 4446185db85Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) != 0 || 4456185db85Sdougm uuid_parse(id + 2, uuid) < 0) 4466185db85Sdougm return; 4476185db85Sdougm } else { 4486185db85Sdougm return; 4496185db85Sdougm } 4506185db85Sdougm 4516185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 4526185db85Sdougm 4536185db85Sdougm iter = scf_iter_create(handle->handle); 4546185db85Sdougm value = scf_value_create(handle->handle); 4556185db85Sdougm prop = scf_property_create(handle->handle); 4566185db85Sdougm name = malloc(scf_max_name_len); 4576185db85Sdougm valuestr = malloc(vallen); 4586185db85Sdougm 4596185db85Sdougm /* 4606185db85Sdougm * construct the share XML node. It is similar to sa_add_share 4616185db85Sdougm * but never changes the repository. Also, there won't be any 4626185db85Sdougm * ZFS or transient shares. Root will be the group it is 4636185db85Sdougm * associated with. 4646185db85Sdougm */ 4656185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 4666185db85Sdougm if (node != NULL) { 4676185db85Sdougm /* 4686185db85Sdougm * make sure the UUID part of the property group is 4696185db85Sdougm * stored in the share "id" property. We use this 4706185db85Sdougm * later. 4716185db85Sdougm */ 4726185db85Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 4736185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 4746185db85Sdougm } 4756185db85Sdougm 4766185db85Sdougm if (iter != NULL && value != NULL && prop != NULL && name != NULL) { 4776185db85Sdougm /* iterate over the share pg properties */ 4786185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 4796185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 4806185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 4816185db85Sdougm if (scf_property_get_name(prop, name, 4826185db85Sdougm scf_max_name_len) > 0) { 4836185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 4846185db85Sdougm if (scf_value_get_astring(value, valuestr, 4856185db85Sdougm vallen) >= 0) { 4866185db85Sdougm ret = SA_OK; 4876185db85Sdougm } 4886185db85Sdougm } 4896185db85Sdougm } 4906185db85Sdougm if (ret == SA_OK) { 491f345c0beSdougm /* 492f345c0beSdougm * check that we have the "path" property in 493f345c0beSdougm * name. The string in name will always be nul 494f345c0beSdougm * terminated if scf_property_get_name() 495f345c0beSdougm * succeeded. 496f345c0beSdougm */ 497f345c0beSdougm if (strcmp(name, "path") == 0) 498f345c0beSdougm have_path = 1; 4996185db85Sdougm if (is_share_attr(name)) { 5006185db85Sdougm /* 5016185db85Sdougm * if a share attr, then simple - 5026185db85Sdougm * usually path and resource name 5036185db85Sdougm */ 5046185db85Sdougm xmlSetProp(node, (xmlChar *)name, 5056185db85Sdougm (xmlChar *)valuestr); 5066185db85Sdougm } else { 5076185db85Sdougm if (strcmp(name, "description") == 0) { 5086185db85Sdougm /* we have a description node */ 5096185db85Sdougm xmlNodePtr desc; 5106185db85Sdougm desc = xmlNewChild(node, NULL, 5116185db85Sdougm (xmlChar *)"description", 5126185db85Sdougm NULL); 5136185db85Sdougm if (desc != NULL) 5146185db85Sdougm xmlNodeSetContent(desc, 5156185db85Sdougm (xmlChar *)valuestr); 5166185db85Sdougm } 5176185db85Sdougm } 5186185db85Sdougm } 5196185db85Sdougm } 5206185db85Sdougm } 5216185db85Sdougm } 522f345c0beSdougm /* 523f345c0beSdougm * a share without a path is broken so we want to not include 524f345c0beSdougm * these. They shouldn't happen but if you kill a sharemgr in 525f345c0beSdougm * the process of creating a share, it could happen. They 526f345c0beSdougm * should be harmless. It is also possible that another 527f345c0beSdougm * sharemgr is running and in the process of creating a share. 528f345c0beSdougm */ 529f345c0beSdougm if (have_path == 0 && node != NULL) { 530f345c0beSdougm xmlUnlinkNode(node); 531f345c0beSdougm xmlFreeNode(node); 532f345c0beSdougm } 5336185db85Sdougm if (name != NULL) 5346185db85Sdougm free(name); 5356185db85Sdougm if (valuestr != NULL) 5366185db85Sdougm free(valuestr); 5376185db85Sdougm if (value != NULL) 5386185db85Sdougm scf_value_destroy(value); 5396185db85Sdougm if (iter != NULL) 5406185db85Sdougm scf_iter_destroy(iter); 5416185db85Sdougm if (prop != NULL) 5426185db85Sdougm scf_property_destroy(prop); 5436185db85Sdougm } 5446185db85Sdougm 5456185db85Sdougm /* 5466185db85Sdougm * find_share_by_id(shareid) 5476185db85Sdougm * 5486185db85Sdougm * Search all shares in all groups until we find the share represented 5496185db85Sdougm * by "id". 5506185db85Sdougm */ 5516185db85Sdougm 5526185db85Sdougm static sa_share_t 553549ec3ffSdougm find_share_by_id(sa_handle_t handle, char *shareid) 5546185db85Sdougm { 5556185db85Sdougm sa_group_t group; 5566185db85Sdougm sa_share_t share = NULL; 5576185db85Sdougm char *id = NULL; 5586185db85Sdougm int done = 0; 5596185db85Sdougm 560549ec3ffSdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 5616185db85Sdougm group = sa_get_next_group(group)) { 5626185db85Sdougm for (share = sa_get_share(group, NULL); share != NULL; 5636185db85Sdougm share = sa_get_next_share(share)) { 5646185db85Sdougm id = sa_get_share_attr(share, "id"); 5656185db85Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 5666185db85Sdougm sa_free_attr_string(id); 5676185db85Sdougm id = NULL; 5686185db85Sdougm done++; 5696185db85Sdougm break; 5706185db85Sdougm } 5716185db85Sdougm if (id != NULL) { 5726185db85Sdougm sa_free_attr_string(id); 5736185db85Sdougm id = NULL; 5746185db85Sdougm } 5756185db85Sdougm } 5766185db85Sdougm } 5776185db85Sdougm return (share); 5786185db85Sdougm } 5796185db85Sdougm 5806185db85Sdougm /* 5816185db85Sdougm * sa_share_props_from_pgroup(root, handle, pg, id) 5826185db85Sdougm * 5836185db85Sdougm * extract share properties from the SMF property group. More sanity 5846185db85Sdougm * checks are done and the share object is created. We ignore some 5856185db85Sdougm * errors that could exist in the repository and only worry about 5866185db85Sdougm * property groups that validate in naming. 5876185db85Sdougm */ 5886185db85Sdougm 5896185db85Sdougm static int 5906185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 591549ec3ffSdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 5926185db85Sdougm { 5936185db85Sdougm xmlNodePtr node; 5946185db85Sdougm char *name; 5956185db85Sdougm scf_iter_t *iter; 5966185db85Sdougm scf_property_t *prop; 5976185db85Sdougm scf_value_t *value; 5986185db85Sdougm ssize_t vallen; 5996185db85Sdougm char *valuestr; 6006185db85Sdougm int ret = SA_OK; 6016185db85Sdougm char *sectype = NULL; 6026185db85Sdougm char *proto; 6036185db85Sdougm sa_share_t share; 6046185db85Sdougm 6056185db85Sdougm /* 6066185db85Sdougm * While preliminary check (starts with 'S') passed before 6076185db85Sdougm * getting here. Need to make sure it is in ID syntax 6086185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 6096185db85Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 6106185db85Sdougm * characters, it is likely one of the protocol/security 6116185db85Sdougm * versions. 6126185db85Sdougm */ 6136185db85Sdougm vallen = strlen(id); 6146185db85Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen > SA_SHARE_PG_LEN) { 6156185db85Sdougm uuid_t uuid; 6166185db85Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 6176185db85Sdougm proto = strchr(id, '_'); 6186185db85Sdougm if (proto == NULL) 6196185db85Sdougm return (ret); 6206185db85Sdougm *proto++ = '\0'; 6216185db85Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 6226185db85Sdougm return (ret); 6236185db85Sdougm /* 6246185db85Sdougm * probably a legal optionset so check a few more 6256185db85Sdougm * syntax points below. 6266185db85Sdougm */ 6276185db85Sdougm if (*proto == '\0') { 6286185db85Sdougm /* not a valid proto (null) */ 6296185db85Sdougm return (ret); 6306185db85Sdougm } 6316185db85Sdougm sectype = strchr(proto, '_'); 6326185db85Sdougm if (sectype != NULL) 6336185db85Sdougm *sectype++ = '\0'; 6346185db85Sdougm if (!valid_protocol(proto)) 6356185db85Sdougm return (ret); 6366185db85Sdougm } 6376185db85Sdougm } else { 6386185db85Sdougm /* 6396185db85Sdougm * it is ok to not have what we thought since someone might 6406185db85Sdougm * have added a name via SMF. 6416185db85Sdougm */ 6426185db85Sdougm return (ret); 6436185db85Sdougm } 6446185db85Sdougm 6456185db85Sdougm /* 6466185db85Sdougm * to get here, we have a valid protocol and possibly a 6476185db85Sdougm * security. We now have to find the share that it is really 6486185db85Sdougm * associated with. The "id" portion of the pgroup name will 6496185db85Sdougm * match. 6506185db85Sdougm */ 6516185db85Sdougm 652549ec3ffSdougm share = find_share_by_id(sahandle, id); 6536185db85Sdougm if (share == NULL) 6546185db85Sdougm return (SA_BAD_PATH); 6556185db85Sdougm 6566185db85Sdougm root = (xmlNodePtr)share; 6576185db85Sdougm 6586185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 6596185db85Sdougm 6606185db85Sdougm iter = scf_iter_create(handle->handle); 6616185db85Sdougm value = scf_value_create(handle->handle); 6626185db85Sdougm prop = scf_property_create(handle->handle); 6636185db85Sdougm name = malloc(scf_max_name_len); 6646185db85Sdougm valuestr = malloc(vallen); 6656185db85Sdougm 6666185db85Sdougm if (sectype == NULL) 6676185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 6686185db85Sdougm else { 6696185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL); 6706185db85Sdougm if (node != NULL) 6716185db85Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 6726185db85Sdougm } 6736185db85Sdougm if (node != NULL) { 6746185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 6756185db85Sdougm /* now find the properties */ 6766185db85Sdougm if (iter != NULL && value != NULL && prop != NULL && name != NULL) { 6776185db85Sdougm /* iterate over the share pg properties */ 6786185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 6796185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 6806185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 6816185db85Sdougm if (scf_property_get_name(prop, name, 6826185db85Sdougm scf_max_name_len) > 0) { 6836185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 6846185db85Sdougm if (scf_value_get_astring(value, valuestr, 6856185db85Sdougm vallen) >= 0) { 6866185db85Sdougm ret = SA_OK; 6876185db85Sdougm } 6886185db85Sdougm } 6896185db85Sdougm } else { 6906185db85Sdougm ret = SA_SYSTEM_ERR; 6916185db85Sdougm } 6926185db85Sdougm if (ret == SA_OK) { 6936185db85Sdougm sa_property_t prop; 6946185db85Sdougm prop = sa_create_property(name, valuestr); 6956185db85Sdougm if (prop != NULL) 6966185db85Sdougm prop = (sa_property_t)xmlAddChild(node, 6976185db85Sdougm (xmlNodePtr)prop); 6986185db85Sdougm else 6996185db85Sdougm ret = SA_NO_MEMORY; 7006185db85Sdougm } 7016185db85Sdougm } 7026185db85Sdougm } else { 7036185db85Sdougm ret = SA_SYSTEM_ERR; 7046185db85Sdougm } 7056185db85Sdougm } 7066185db85Sdougm } else { 7076185db85Sdougm ret = SA_NO_MEMORY; 7086185db85Sdougm } 7096185db85Sdougm if (iter != NULL) 7106185db85Sdougm scf_iter_destroy(iter); 7116185db85Sdougm if (value != NULL) 7126185db85Sdougm scf_value_destroy(value); 7136185db85Sdougm if (prop != NULL) 7146185db85Sdougm scf_property_destroy(prop); 7156185db85Sdougm if (name != NULL) 7166185db85Sdougm free(name); 7176185db85Sdougm if (valuestr != NULL) 7186185db85Sdougm free(valuestr); 7196185db85Sdougm return (ret); 7206185db85Sdougm } 7216185db85Sdougm 7226185db85Sdougm /* 7236185db85Sdougm * sa_extract_group(root, handle, instance) 7246185db85Sdougm * 7256185db85Sdougm * get the config info for this instance of a group and create the XML 7266185db85Sdougm * subtree from it. 7276185db85Sdougm */ 7286185db85Sdougm 7296185db85Sdougm static int 7306185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 731549ec3ffSdougm scf_instance_t *instance, sa_handle_t sahandle) 7326185db85Sdougm { 7336185db85Sdougm char *buff; 7346185db85Sdougm xmlNodePtr node; 7356185db85Sdougm scf_iter_t *iter; 7366185db85Sdougm char *proto; 7376185db85Sdougm char *sectype; 7386185db85Sdougm int have_shares = 0; 7396185db85Sdougm int has_proto = 0; 7406185db85Sdougm int is_default = 0; 7416185db85Sdougm int ret = SA_OK; 7426185db85Sdougm int err; 7436185db85Sdougm 7446185db85Sdougm buff = malloc(scf_max_name_len); 7456185db85Sdougm iter = scf_iter_create(handle->handle); 7466185db85Sdougm if (buff != NULL) { 7476185db85Sdougm if (scf_instance_get_name(instance, buff, 7486185db85Sdougm scf_max_name_len) > 0) { 7496185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 7506185db85Sdougm if (node != NULL) { 7516185db85Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 7526185db85Sdougm if (strcmp(buff, "default") == 0) 7536185db85Sdougm is_default++; 7546185db85Sdougm sa_extract_attrs(node, handle, instance); 7556185db85Sdougm /* 7566185db85Sdougm * Iterate through all the property groups 7576185db85Sdougm * looking for those with security or 7586185db85Sdougm * optionset prefixes. The names of the 7596185db85Sdougm * matching pgroups are parsed to get the 7606185db85Sdougm * protocol, and for security, the sectype. 7616185db85Sdougm * Syntax is as follows: 7626185db85Sdougm * optionset | optionset_<proto> 7636185db85Sdougm * security_default | security_<proto>_<sectype> 7646185db85Sdougm * "operation" is handled by 7656185db85Sdougm * sa_extract_attrs(). 7666185db85Sdougm */ 7676185db85Sdougm if (iter != NULL) { 7686185db85Sdougm if (scf_iter_instance_pgs(iter, instance) == 0) { 7696185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 7706185db85Sdougm /* have a pgroup so sort it out */ 7716185db85Sdougm ret = scf_pg_get_name(handle->pg, buff, 7726185db85Sdougm scf_max_name_len); 7736185db85Sdougm if (ret > 0) { 7746185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 7756185db85Sdougm sa_share_from_pgroup(node, handle, 7766185db85Sdougm handle->pg, 7776185db85Sdougm buff); 7786185db85Sdougm have_shares++; 7796185db85Sdougm } else if (strncmp(buff, "optionset", 9) == 7806185db85Sdougm 0) { 7816185db85Sdougm char *nodetype = "optionset"; 7826185db85Sdougm /* have an optionset */ 7836185db85Sdougm sectype = NULL; 7846185db85Sdougm proto = strchr(buff, '_'); 7856185db85Sdougm if (proto != NULL) { 7866185db85Sdougm *proto++ = '\0'; 7876185db85Sdougm sectype = strchr(proto, '_'); 7886185db85Sdougm if (sectype != NULL) { 7896185db85Sdougm *sectype++ = '\0'; 7906185db85Sdougm nodetype = "security"; 7916185db85Sdougm } 7926185db85Sdougm } 7936185db85Sdougm ret = sa_extract_pgroup(node, handle, 7946185db85Sdougm handle->pg, 7956185db85Sdougm nodetype, 7966185db85Sdougm proto, sectype); 7976185db85Sdougm has_proto++; 7986185db85Sdougm } else if (strncmp(buff, 7996185db85Sdougm "security", 8) == 0) { 8006185db85Sdougm /* 8016185db85Sdougm * have a security (note that 8026185db85Sdougm * this should change in the 8036185db85Sdougm * future) 8046185db85Sdougm */ 8056185db85Sdougm proto = strchr(buff, '_'); 8066185db85Sdougm sectype = NULL; 8076185db85Sdougm if (proto != NULL) { 8086185db85Sdougm *proto++ = '\0'; 8096185db85Sdougm sectype = strchr(proto, '_'); 8106185db85Sdougm if (sectype != NULL) 8116185db85Sdougm *sectype++ = '\0'; 8126185db85Sdougm if (strcmp(proto, "default") == 0) 8136185db85Sdougm proto = NULL; 8146185db85Sdougm } 8156185db85Sdougm ret = sa_extract_pgroup(node, handle, 8166185db85Sdougm handle->pg, 8176185db85Sdougm "security", proto, 8186185db85Sdougm sectype); 8196185db85Sdougm has_proto++; 8206185db85Sdougm } 8216185db85Sdougm /* ignore everything else */ 8226185db85Sdougm } 8236185db85Sdougm } 8246185db85Sdougm } else { 8256185db85Sdougm ret = SA_NO_MEMORY; 8266185db85Sdougm } 8276185db85Sdougm /* 8286185db85Sdougm * Make sure we have a valid default group. 8296185db85Sdougm * On first boot, default won't have any 8306185db85Sdougm * protocols defined and won't be enabled (but 8316185db85Sdougm * should be). 8326185db85Sdougm */ 8336185db85Sdougm if (is_default) { 8346185db85Sdougm char *state = sa_get_group_attr((sa_group_t)node, 8356185db85Sdougm "state"); 8366185db85Sdougm char **protos; 8376185db85Sdougm int numprotos; 8386185db85Sdougm int i; 8396185db85Sdougm 8406185db85Sdougm if (state == NULL) { 8416185db85Sdougm /* set attribute to enabled */ 8426185db85Sdougm (void) sa_set_group_attr((sa_group_t)node, 8436185db85Sdougm "state", 8446185db85Sdougm "enabled"); 8456185db85Sdougm /* we can assume no protocols */ 8466185db85Sdougm numprotos = sa_get_protocols(&protos); 8476185db85Sdougm for (i = 0; i < numprotos; i++) 8486185db85Sdougm (void) sa_create_optionset((sa_group_t)node, 8496185db85Sdougm protos[i]); 8506185db85Sdougm if (numprotos > 0) 8516185db85Sdougm free(protos); 8526185db85Sdougm } else { 8536185db85Sdougm sa_free_attr_string(state); 8546185db85Sdougm } 8556185db85Sdougm } 8566185db85Sdougm /* do a second pass if shares were found */ 8576185db85Sdougm if (have_shares && 8586185db85Sdougm scf_iter_instance_pgs(iter, instance) == 0) { 8596185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 8606185db85Sdougm /* 8616185db85Sdougm * have a pgroup so see if it is a 8626185db85Sdougm * share optionset 8636185db85Sdougm */ 8646185db85Sdougm err = scf_pg_get_name(handle->pg, buff, 8656185db85Sdougm scf_max_name_len); 8666185db85Sdougm if (err > 0) { 8676185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 8686185db85Sdougm ret = sa_share_props_from_pgroup(node, 8696185db85Sdougm handle, 8706185db85Sdougm handle->pg, 871549ec3ffSdougm buff, sahandle); 8726185db85Sdougm } 8736185db85Sdougm } 8746185db85Sdougm } 8756185db85Sdougm } 8766185db85Sdougm } 8776185db85Sdougm } 8786185db85Sdougm } 8796185db85Sdougm } 8806185db85Sdougm if (iter != NULL) 8816185db85Sdougm scf_iter_destroy(iter); 8826185db85Sdougm if (buff != NULL) 8836185db85Sdougm free(buff); 8846185db85Sdougm return (ret); 8856185db85Sdougm } 8866185db85Sdougm 8876185db85Sdougm /* 8886185db85Sdougm * sa_extract_defaults(root, handle, instance) 8896185db85Sdougm * 8906185db85Sdougm * local function to find the default properties that live in the 8916185db85Sdougm * default instance's "operation" proprerty group. 8926185db85Sdougm */ 8936185db85Sdougm 8946185db85Sdougm static void 8956185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 8966185db85Sdougm scf_instance_t *instance) 8976185db85Sdougm { 8986185db85Sdougm xmlNodePtr node; 8996185db85Sdougm scf_property_t *prop; 9006185db85Sdougm scf_value_t *value; 9016185db85Sdougm char *valuestr; 9026185db85Sdougm ssize_t vallen; 9036185db85Sdougm 9046185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 9056185db85Sdougm prop = scf_property_create(handle->handle); 9066185db85Sdougm value = scf_value_create(handle->handle); 9076185db85Sdougm valuestr = malloc(vallen); 9086185db85Sdougm if (prop != NULL && value != NULL && vallen != NULL && 9096185db85Sdougm scf_instance_get_pg(instance, "operation", 9106185db85Sdougm handle->pg) == 0) { 9116185db85Sdougm if (scf_pg_get_property(handle->pg, 9126185db85Sdougm "legacy-timestamp", prop) == 0) { 9136185db85Sdougm /* found the property so get the value */ 9146185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 9156185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 9166185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 9176185db85Sdougm NULL); 9186185db85Sdougm if (node != NULL) { 9196185db85Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 9206185db85Sdougm (xmlChar *)valuestr); 9216185db85Sdougm xmlSetProp(node, (xmlChar *)"path", 9226185db85Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 9236185db85Sdougm } 9246185db85Sdougm } 9256185db85Sdougm } 9266185db85Sdougm } 9276185db85Sdougm } 9286185db85Sdougm if (valuestr != NULL) 9296185db85Sdougm free(valuestr); 9306185db85Sdougm if (value != NULL) 9316185db85Sdougm scf_value_destroy(value); 9326185db85Sdougm if (prop != NULL) 9336185db85Sdougm scf_property_destroy(prop); 9346185db85Sdougm } 9356185db85Sdougm 9366185db85Sdougm 9376185db85Sdougm /* 938549ec3ffSdougm * sa_get_config(handle, root, doc, sahandlec) 9396185db85Sdougm * 9406185db85Sdougm * walk the SMF repository for /network/shares/group and find all the 9416185db85Sdougm * instances. These become group names. Then add the XML structure 9426185db85Sdougm * below the groups based on property groups and properties. 9436185db85Sdougm */ 9446185db85Sdougm int 9451d1813a7Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 9466185db85Sdougm { 9476185db85Sdougm int ret = SA_OK; 9486185db85Sdougm scf_instance_t *instance; 9496185db85Sdougm scf_iter_t *iter; 9506185db85Sdougm char buff[BUFSIZ * 2]; 9516185db85Sdougm 9526185db85Sdougm instance = scf_instance_create(handle->handle); 9536185db85Sdougm iter = scf_iter_create(handle->handle); 9541d1813a7Sdougm if (instance != NULL && iter != NULL) { 9556185db85Sdougm if ((ret = scf_iter_service_instances(iter, 9566185db85Sdougm handle->service)) == 0) { 9576185db85Sdougm while ((ret = scf_iter_next_instance(iter, 9586185db85Sdougm instance)) > 0) { 9596185db85Sdougm if (scf_instance_get_name(instance, buff, 9606185db85Sdougm sizeof (buff)) > 0) { 9616185db85Sdougm if (strcmp(buff, "default") == 0) 9621d1813a7Sdougm sa_extract_defaults(root, handle, instance); 9631d1813a7Sdougm ret = sa_extract_group(root, handle, instance, 964549ec3ffSdougm sahandle); 9656185db85Sdougm } 9666185db85Sdougm } 9676185db85Sdougm } 9686185db85Sdougm } 9691d1813a7Sdougm 9706185db85Sdougm /* always cleanup these */ 9716185db85Sdougm if (instance != NULL) 9726185db85Sdougm scf_instance_destroy(instance); 9736185db85Sdougm if (iter != NULL) 9746185db85Sdougm scf_iter_destroy(iter); 9756185db85Sdougm return (ret); 9766185db85Sdougm } 9776185db85Sdougm 9786185db85Sdougm /* 9796185db85Sdougm * sa_get_instance(handle, instance) 9806185db85Sdougm * 9816185db85Sdougm * get the instance of the group service. This is actually the 9826185db85Sdougm * specific group name. The instance is needed for all property and 9836185db85Sdougm * control operations. 9846185db85Sdougm */ 9856185db85Sdougm 9866185db85Sdougm int 9876185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 9886185db85Sdougm { 9896185db85Sdougm if (scf_service_get_instance(handle->service, instname, 9906185db85Sdougm handle->instance) != 0) { 9916185db85Sdougm return (SA_NO_SUCH_GROUP); 9926185db85Sdougm } 9936185db85Sdougm return (SA_OK); 9946185db85Sdougm } 9956185db85Sdougm 9966185db85Sdougm /* 9976185db85Sdougm * sa_create_instance(handle, instname) 9986185db85Sdougm * 9996185db85Sdougm * Create a new SMF service instance. There can only be one with a 10006185db85Sdougm * given name. 10016185db85Sdougm */ 10026185db85Sdougm 10036185db85Sdougm int 10046185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 10056185db85Sdougm { 10066185db85Sdougm int ret = SA_OK; 10076185db85Sdougm char instance[SA_GROUP_INST_LEN]; 10086185db85Sdougm if (scf_service_add_instance(handle->service, instname, 10096185db85Sdougm handle->instance) != 0) { 10106185db85Sdougm /* better error returns need to be added based on real error */ 10116185db85Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 10126185db85Sdougm ret = SA_NO_PERMISSION; 10136185db85Sdougm else 10146185db85Sdougm ret = SA_DUPLICATE_NAME; 10156185db85Sdougm } else { 10166185db85Sdougm /* have the service created, so enable it */ 10176185db85Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 10186185db85Sdougm SA_SVC_FMRI_BASE, instname); 10196185db85Sdougm (void) smf_enable_instance(instance, 0); 10206185db85Sdougm } 10216185db85Sdougm return (ret); 10226185db85Sdougm } 10236185db85Sdougm 10246185db85Sdougm /* 10256185db85Sdougm * sa_delete_instance(handle, instname) 10266185db85Sdougm * 10276185db85Sdougm * When a group goes away, we also remove the service instance. 10286185db85Sdougm */ 10296185db85Sdougm 10306185db85Sdougm int 10316185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 10326185db85Sdougm { 10336185db85Sdougm int ret; 10346185db85Sdougm 10356185db85Sdougm if (strcmp(instname, "default") == 0) { 10366185db85Sdougm ret = SA_NO_PERMISSION; 10376185db85Sdougm } else { 10386185db85Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 10396185db85Sdougm if (scf_instance_delete(handle->instance) != 0) 10406185db85Sdougm /* need better analysis */ 10416185db85Sdougm ret = SA_NO_PERMISSION; 10426185db85Sdougm } 10436185db85Sdougm } 10446185db85Sdougm return (ret); 10456185db85Sdougm } 10466185db85Sdougm 10476185db85Sdougm /* 10486185db85Sdougm * sa_create_pgroup(handle, pgroup) 10496185db85Sdougm * 10506185db85Sdougm * create a new property group 10516185db85Sdougm */ 10526185db85Sdougm 10536185db85Sdougm int 10546185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 10556185db85Sdougm { 10566185db85Sdougm int ret = SA_OK; 10576185db85Sdougm /* 10586185db85Sdougm * only create a handle if it doesn't exist. It is ok to exist 10596185db85Sdougm * since the pg handle will be set as a side effect. 10606185db85Sdougm */ 10616185db85Sdougm if (handle->pg == NULL) { 10626185db85Sdougm handle->pg = scf_pg_create(handle->handle); 10636185db85Sdougm } 10646185db85Sdougm /* 10656185db85Sdougm * if the pgroup exists, we are done. If it doesn't, then we 10666185db85Sdougm * need to actually add one to the service instance. 10676185db85Sdougm */ 10686185db85Sdougm if (scf_instance_get_pg(handle->instance, 10696185db85Sdougm pgroup, handle->pg) != 0) { 10706185db85Sdougm /* doesn't exist so create one */ 10716185db85Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 10726185db85Sdougm SCF_GROUP_APPLICATION, 0, 10736185db85Sdougm handle->pg) != 0) { 10746185db85Sdougm switch (scf_error()) { 10756185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 10766185db85Sdougm ret = SA_NO_PERMISSION; 10776185db85Sdougm break; 10786185db85Sdougm default: 10796185db85Sdougm ret = SA_SYSTEM_ERR; 10806185db85Sdougm break; 10816185db85Sdougm } 10826185db85Sdougm } 10836185db85Sdougm } 10846185db85Sdougm return (ret); 10856185db85Sdougm } 10866185db85Sdougm 10876185db85Sdougm /* 10886185db85Sdougm * sa_delete_pgroup(handle, pgroup) 10896185db85Sdougm * 10906185db85Sdougm * remove the property group from the current instance of the service, 10916185db85Sdougm * but only if it actually exists. 10926185db85Sdougm */ 10936185db85Sdougm 10946185db85Sdougm int 10956185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 10966185db85Sdougm { 10976185db85Sdougm int ret = SA_OK; 10986185db85Sdougm /* 10996185db85Sdougm * only delete if it does exist. 11006185db85Sdougm */ 11016185db85Sdougm if (scf_instance_get_pg(handle->instance, 11026185db85Sdougm pgroup, handle->pg) == 0) { 11036185db85Sdougm /* does exist so delete it */ 11046185db85Sdougm if (scf_pg_delete(handle->pg) != 0) { 11056185db85Sdougm ret = SA_SYSTEM_ERR; 11066185db85Sdougm } 11076185db85Sdougm } else { 11086185db85Sdougm ret = SA_SYSTEM_ERR; 11096185db85Sdougm } 11106185db85Sdougm if (ret == SA_SYSTEM_ERR && 11116185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11126185db85Sdougm ret = SA_NO_PERMISSION; 11136185db85Sdougm } 11146185db85Sdougm return (ret); 11156185db85Sdougm } 11166185db85Sdougm 11176185db85Sdougm /* 11186185db85Sdougm * sa_start_transaction(handle, pgroup) 11196185db85Sdougm * 11206185db85Sdougm * Start an SMF transaction so we can deal with properties. it would 11216185db85Sdougm * be nice to not have to expose this, but we have to in order to 11226185db85Sdougm * optimize. 11236185db85Sdougm * 11246185db85Sdougm * Basic model is to hold the transaction in the handle and allow 11256185db85Sdougm * property adds/deletes/updates to be added then close the 11266185db85Sdougm * transaction (or abort). There may eventually be a need to handle 11276185db85Sdougm * other types of transaction mechanisms but we don't do that now. 11286185db85Sdougm * 11296185db85Sdougm * An sa_start_transaction must be followed by either an 11306185db85Sdougm * sa_end_transaction or sa_abort_transaction before another 11316185db85Sdougm * sa_start_transaction can be done. 11326185db85Sdougm */ 11336185db85Sdougm 11346185db85Sdougm int 11356185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 11366185db85Sdougm { 11376185db85Sdougm int ret = SA_OK; 11386185db85Sdougm /* 11396185db85Sdougm * lookup the property group and create it if it doesn't already 11406185db85Sdougm * exist. 11416185db85Sdougm */ 11426185db85Sdougm if (handle->scf_state == SCH_STATE_INIT) { 11436185db85Sdougm ret = sa_create_pgroup(handle, propgroup); 11446185db85Sdougm if (ret == SA_OK) { 11456185db85Sdougm handle->trans = scf_transaction_create(handle->handle); 11466185db85Sdougm if (handle->trans != NULL) { 11476185db85Sdougm if (scf_transaction_start(handle->trans, handle->pg) != 0) { 11486185db85Sdougm ret = SA_SYSTEM_ERR; 11496185db85Sdougm } 11506185db85Sdougm if (ret != SA_OK) { 11516185db85Sdougm scf_transaction_destroy(handle->trans); 11526185db85Sdougm handle->trans = NULL; 11536185db85Sdougm } 11546185db85Sdougm } else { 11556185db85Sdougm ret = SA_SYSTEM_ERR; 11566185db85Sdougm } 11576185db85Sdougm } 11586185db85Sdougm } 11596185db85Sdougm if (ret == SA_SYSTEM_ERR && 11606185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11616185db85Sdougm ret = SA_NO_PERMISSION; 11626185db85Sdougm } 11636185db85Sdougm return (ret); 11646185db85Sdougm } 11656185db85Sdougm 11666185db85Sdougm /* 11676185db85Sdougm * sa_end_transaction(handle) 11686185db85Sdougm * 11696185db85Sdougm * Commit the changes that were added to the transaction in the 11706185db85Sdougm * handle. Do all necessary cleanup. 11716185db85Sdougm */ 11726185db85Sdougm 11736185db85Sdougm int 11746185db85Sdougm sa_end_transaction(scfutilhandle_t *handle) 11756185db85Sdougm { 11766185db85Sdougm int ret = SA_OK; 11776185db85Sdougm 11786185db85Sdougm if (handle->trans == NULL) { 11796185db85Sdougm ret = SA_SYSTEM_ERR; 11806185db85Sdougm } else { 11816185db85Sdougm if (scf_transaction_commit(handle->trans) < 0) 11826185db85Sdougm ret = SA_SYSTEM_ERR; 11836185db85Sdougm scf_transaction_destroy_children(handle->trans); 11846185db85Sdougm scf_transaction_destroy(handle->trans); 11856185db85Sdougm handle->trans = NULL; 11866185db85Sdougm } 11876185db85Sdougm return (ret); 11886185db85Sdougm } 11896185db85Sdougm 11906185db85Sdougm /* 11916185db85Sdougm * sa_abort_transaction(handle) 11926185db85Sdougm * 11936185db85Sdougm * Abort the changes that were added to the transaction in the 11946185db85Sdougm * handle. Do all necessary cleanup. 11956185db85Sdougm */ 11966185db85Sdougm 11976185db85Sdougm void 11986185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle) 11996185db85Sdougm { 12006185db85Sdougm if (handle->trans != NULL) { 12016185db85Sdougm scf_transaction_reset_all(handle->trans); 12026185db85Sdougm scf_transaction_destroy_children(handle->trans); 12036185db85Sdougm scf_transaction_destroy(handle->trans); 12046185db85Sdougm handle->trans = NULL; 12056185db85Sdougm } 12066185db85Sdougm } 12076185db85Sdougm 12086185db85Sdougm /* 12096185db85Sdougm * sa_set_property(handle, prop, value) 12106185db85Sdougm * 12116185db85Sdougm * set a property transaction entry into the pending SMF transaction. 12126185db85Sdougm */ 12136185db85Sdougm 12146185db85Sdougm int 12156185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 12166185db85Sdougm { 12176185db85Sdougm int ret = SA_OK; 12186185db85Sdougm scf_value_t *value; 12196185db85Sdougm scf_transaction_entry_t *entry; 12206185db85Sdougm /* 12216185db85Sdougm * properties must be set in transactions and don't take 12226185db85Sdougm * effect until the transaction has been ended/committed. 12236185db85Sdougm */ 12246185db85Sdougm value = scf_value_create(handle->handle); 12256185db85Sdougm entry = scf_entry_create(handle->handle); 12266185db85Sdougm if (value != NULL && entry != NULL) { 12276185db85Sdougm if (scf_transaction_property_change(handle->trans, entry, 12286185db85Sdougm propname, 12296185db85Sdougm SCF_TYPE_ASTRING) == 0 || 12306185db85Sdougm scf_transaction_property_new(handle->trans, entry, 12316185db85Sdougm propname, 12326185db85Sdougm SCF_TYPE_ASTRING) == 0) { 12336185db85Sdougm if (scf_value_set_astring(value, valstr) == 0) { 12346185db85Sdougm if (scf_entry_add_value(entry, value) != 0) { 12356185db85Sdougm ret = SA_SYSTEM_ERR; 12366185db85Sdougm scf_value_destroy(value); 12376185db85Sdougm } 12386185db85Sdougm /* the value is in the transaction */ 12396185db85Sdougm value = NULL; 12406185db85Sdougm } else { 12416185db85Sdougm /* value couldn't be constructed */ 12426185db85Sdougm ret = SA_SYSTEM_ERR; 12436185db85Sdougm } 12446185db85Sdougm /* the entry is in the transaction */ 12456185db85Sdougm entry = NULL; 12466185db85Sdougm } else { 12476185db85Sdougm ret = SA_SYSTEM_ERR; 12486185db85Sdougm } 12496185db85Sdougm } else { 12506185db85Sdougm ret = SA_SYSTEM_ERR; 12516185db85Sdougm } 12526185db85Sdougm if (ret == SA_SYSTEM_ERR) { 12536185db85Sdougm switch (scf_error()) { 12546185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 12556185db85Sdougm ret = SA_NO_PERMISSION; 12566185db85Sdougm break; 12576185db85Sdougm } 12586185db85Sdougm } 12596185db85Sdougm /* 12606185db85Sdougm * cleanup if there were any errors that didn't leave these 12616185db85Sdougm * values where they would be cleaned up later. 12626185db85Sdougm */ 12636185db85Sdougm if (value != NULL) 12646185db85Sdougm scf_value_destroy(value); 12656185db85Sdougm if (entry != NULL) 12666185db85Sdougm scf_entry_destroy(entry); 12676185db85Sdougm return (ret); 12686185db85Sdougm } 12696185db85Sdougm 12706185db85Sdougm /* 12716185db85Sdougm * sa_commit_share(handle, group, share) 12726185db85Sdougm * 12736185db85Sdougm * commit this share to the repository. 12746185db85Sdougm * properties are added if they exist but can be added later. 12756185db85Sdougm * Need to add to dfstab and sharetab, if appropriate. 12766185db85Sdougm */ 12776185db85Sdougm int 12786185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 12796185db85Sdougm { 12806185db85Sdougm int ret = SA_OK; 12816185db85Sdougm char *groupname; 12826185db85Sdougm char *name; 12836185db85Sdougm char *resource; 12846185db85Sdougm char *description; 12856185db85Sdougm char *sharename; 12866185db85Sdougm ssize_t proplen; 12876185db85Sdougm char *propstring; 12886185db85Sdougm 12896185db85Sdougm /* 12906185db85Sdougm * don't commit in the zfs group. We do commit legacy 12916185db85Sdougm * (default) and all other groups/shares. ZFS is handled 12926185db85Sdougm * through the ZFS configuration rather than SMF. 12936185db85Sdougm */ 12946185db85Sdougm 12956185db85Sdougm groupname = sa_get_group_attr(group, "name"); 12966185db85Sdougm if (groupname != NULL) { 12976185db85Sdougm if (strcmp(groupname, "zfs") == 0) { 12986185db85Sdougm /* 12996185db85Sdougm * adding to the ZFS group will result in the sharenfs 13006185db85Sdougm * property being set but we don't want to do anything 13016185db85Sdougm * SMF related at this point. 13026185db85Sdougm */ 13036185db85Sdougm sa_free_attr_string(groupname); 13046185db85Sdougm return (ret); 13056185db85Sdougm } 13066185db85Sdougm } 13076185db85Sdougm 13086185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 13096185db85Sdougm propstring = malloc(proplen); 13106185db85Sdougm if (propstring == NULL) 13116185db85Sdougm ret = SA_NO_MEMORY; 13126185db85Sdougm 13136185db85Sdougm if (groupname != NULL && ret == SA_OK) { 13146185db85Sdougm ret = sa_get_instance(handle, groupname); 13156185db85Sdougm sa_free_attr_string(groupname); 13166185db85Sdougm groupname = NULL; 13176185db85Sdougm sharename = sa_get_share_attr(share, "id"); 13186185db85Sdougm if (sharename == NULL) { 13196185db85Sdougm /* slipped by */ 13206185db85Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 13216185db85Sdougm generate_unique_sharename(shname); 13226185db85Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 13236185db85Sdougm (xmlChar *)shname); 13246185db85Sdougm sharename = strdup(shname); 13256185db85Sdougm } 13266185db85Sdougm if (sharename != NULL) { 1327f345c0beSdougm sigset_t old, new; 13286185db85Sdougm /* 1329f345c0beSdougm * have a share name allocated so create a pgroup for 1330f345c0beSdougm * it. It may already exist, but that is OK. In order 1331f345c0beSdougm * to avoid creating a share pgroup that doesn't have 1332f345c0beSdougm * a path property, block signals around the critical 1333f345c0beSdougm * region of creating the share pgroup and props. 13346185db85Sdougm */ 1335f345c0beSdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 1336f345c0beSdougm (void) sigaddset(&new, SIGHUP); 1337f345c0beSdougm (void) sigaddset(&new, SIGINT); 1338f345c0beSdougm (void) sigaddset(&new, SIGQUIT); 1339f345c0beSdougm (void) sigaddset(&new, SIGTSTP); 1340f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 1341f345c0beSdougm 13426185db85Sdougm ret = sa_create_pgroup(handle, sharename); 13436185db85Sdougm if (ret == SA_OK) { 13446185db85Sdougm /* 13456185db85Sdougm * now start the transaction for the 13466185db85Sdougm * properties that define this share. They may 13476185db85Sdougm * exist so attempt to update before create. 13486185db85Sdougm */ 13496185db85Sdougm ret = sa_start_transaction(handle, sharename); 13506185db85Sdougm } 13516185db85Sdougm if (ret == SA_OK) { 13526185db85Sdougm name = sa_get_share_attr(share, "path"); 13536185db85Sdougm if (name != NULL) { 13546185db85Sdougm /* there needs to be a path for a share to exist */ 13556185db85Sdougm ret = sa_set_property(handle, "path", name); 13566185db85Sdougm sa_free_attr_string(name); 13576185db85Sdougm } else { 13586185db85Sdougm ret = SA_NO_MEMORY; 13596185db85Sdougm } 13606185db85Sdougm } 13616185db85Sdougm if (ret == SA_OK) { 13626185db85Sdougm resource = sa_get_share_attr(share, "resource"); 13636185db85Sdougm if (resource != NULL) { 13646185db85Sdougm ret = sa_set_property(handle, "resource", resource); 13656185db85Sdougm sa_free_attr_string(resource); 13666185db85Sdougm } 13676185db85Sdougm } 13686185db85Sdougm if (ret == SA_OK) { 13696185db85Sdougm description = sa_get_share_description(share); 13706185db85Sdougm if (description != NULL) { 13716185db85Sdougm ret = sa_set_property(handle, "description", 13726185db85Sdougm description); 13736185db85Sdougm sa_free_share_description(description); 13746185db85Sdougm } 13756185db85Sdougm } 13766185db85Sdougm /* make sure we cleanup the transaction */ 13776185db85Sdougm if (ret == SA_OK) { 13786185db85Sdougm ret = sa_end_transaction(handle); 13796185db85Sdougm } else { 13806185db85Sdougm sa_abort_transaction(handle); 13816185db85Sdougm } 1382f345c0beSdougm 1383f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 1384f345c0beSdougm 13856185db85Sdougm free(sharename); 13866185db85Sdougm } 13876185db85Sdougm } 13886185db85Sdougm if (ret == SA_SYSTEM_ERR) { 13896185db85Sdougm int err = scf_error(); 13906185db85Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 13916185db85Sdougm ret = SA_NO_PERMISSION; 13926185db85Sdougm } 13936185db85Sdougm if (propstring != NULL) 13946185db85Sdougm free(propstring); 13956185db85Sdougm if (groupname != NULL) 13966185db85Sdougm sa_free_attr_string(groupname); 13976185db85Sdougm 13986185db85Sdougm return (ret); 13996185db85Sdougm } 14006185db85Sdougm 14016185db85Sdougm /* 14026185db85Sdougm * sa_delete_share(handle, group, share) 14036185db85Sdougm * 14046185db85Sdougm * remove the specified share from the group (and service instance). 14056185db85Sdougm */ 14066185db85Sdougm 14076185db85Sdougm int 14086185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 14096185db85Sdougm { 14106185db85Sdougm int ret = SA_OK; 14116185db85Sdougm char *groupname = NULL; 14126185db85Sdougm char *shareid = NULL; 14136185db85Sdougm sa_optionset_t opt; 14146185db85Sdougm sa_security_t sec; 14156185db85Sdougm ssize_t proplen; 14166185db85Sdougm char *propstring; 14176185db85Sdougm 14186185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 14196185db85Sdougm propstring = malloc(proplen); 14206185db85Sdougm if (propstring == NULL) 14216185db85Sdougm ret = SA_NO_MEMORY; 14226185db85Sdougm 14236185db85Sdougm if (ret == SA_OK) { 14246185db85Sdougm groupname = sa_get_group_attr(group, "name"); 14256185db85Sdougm shareid = sa_get_share_attr(share, "id"); 14266185db85Sdougm if (groupname != NULL && shareid != NULL) { 14276185db85Sdougm ret = sa_get_instance(handle, groupname); 14286185db85Sdougm if (ret == SA_OK) { 14296185db85Sdougm /* if a share has properties, remove them */ 14306185db85Sdougm ret = sa_delete_pgroup(handle, shareid); 14316185db85Sdougm for (opt = sa_get_optionset(share, NULL); opt != NULL; 14326185db85Sdougm opt = sa_get_next_optionset(opt)) { 14336185db85Sdougm char *proto; 14346185db85Sdougm proto = sa_get_optionset_attr(opt, "type"); 14356185db85Sdougm if (proto != NULL) { 14366185db85Sdougm (void) snprintf(propstring, proplen, "%s_%s", 14376185db85Sdougm shareid, proto); 14386185db85Sdougm ret = sa_delete_pgroup(handle, propstring); 14396185db85Sdougm sa_free_attr_string(proto); 14406185db85Sdougm } else { 14416185db85Sdougm ret = SA_NO_MEMORY; 14426185db85Sdougm } 14436185db85Sdougm } 14446185db85Sdougm /* 14456185db85Sdougm * if a share has security/negotiable 14466185db85Sdougm * properties, remove them. 14476185db85Sdougm */ 14486185db85Sdougm for (sec = sa_get_security(share, NULL, NULL); sec != NULL; 14496185db85Sdougm sec = sa_get_next_security(sec)) { 14506185db85Sdougm char *proto; 14516185db85Sdougm char *sectype; 14526185db85Sdougm proto = sa_get_security_attr(sec, "type"); 14536185db85Sdougm sectype = sa_get_security_attr(sec, "sectype"); 14546185db85Sdougm if (proto != NULL && sectype != NULL) { 14556185db85Sdougm (void) snprintf(propstring, proplen, "%s_%s_%s", 14566185db85Sdougm shareid, 14576185db85Sdougm proto, sectype); 14586185db85Sdougm ret = sa_delete_pgroup(handle, propstring); 14596185db85Sdougm } else { 14606185db85Sdougm ret = SA_NO_MEMORY; 14616185db85Sdougm } 14626185db85Sdougm if (proto != NULL) 14636185db85Sdougm sa_free_attr_string(proto); 14646185db85Sdougm if (sectype != NULL) 14656185db85Sdougm sa_free_attr_string(sectype); 14666185db85Sdougm } 14676185db85Sdougm } 14686185db85Sdougm } else { 14696185db85Sdougm ret = SA_CONFIG_ERR; 14706185db85Sdougm } 14716185db85Sdougm } 14726185db85Sdougm if (groupname != NULL) 14736185db85Sdougm sa_free_attr_string(groupname); 14746185db85Sdougm if (shareid != NULL) 14756185db85Sdougm sa_free_attr_string(shareid); 14766185db85Sdougm if (propstring != NULL) 14776185db85Sdougm free(propstring); 14786185db85Sdougm 14796185db85Sdougm return (ret); 14806185db85Sdougm } 1481