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 /* 23*fe1c642dSBill Krier * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 246185db85Sdougm * Use is subject to license terms. 256185db85Sdougm */ 266185db85Sdougm 276185db85Sdougm /* helper functions for using libscf with sharemgr */ 286185db85Sdougm 296185db85Sdougm #include <libscf.h> 306185db85Sdougm #include <libxml/parser.h> 316185db85Sdougm #include <libxml/tree.h> 326185db85Sdougm #include "libshare.h" 336185db85Sdougm #include "libshare_impl.h" 346185db85Sdougm #include "scfutil.h" 356185db85Sdougm #include <string.h> 36da6c28aaSamw #include <ctype.h> 376185db85Sdougm #include <errno.h> 386185db85Sdougm #include <uuid/uuid.h> 396185db85Sdougm #include <sys/param.h> 40f345c0beSdougm #include <signal.h> 415b6e0c46Sdougm #include <sys/time.h> 421f29d134Sdougm #include <libintl.h> 436185db85Sdougm 446185db85Sdougm ssize_t scf_max_name_len; 456185db85Sdougm extern struct sa_proto_plugin *sap_proto_list; 46549ec3ffSdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr); 475b6e0c46Sdougm static void set_transaction_tstamp(sa_handle_impl_t); 486185db85Sdougm /* 496185db85Sdougm * The SMF facility uses some properties that must exist. We want to 506185db85Sdougm * skip over these when processing protocol options. 516185db85Sdougm */ 526185db85Sdougm static char *skip_props[] = { 536185db85Sdougm "modify_authorization", 546185db85Sdougm "action_authorization", 556185db85Sdougm "value_authorization", 566185db85Sdougm NULL 576185db85Sdougm }; 586185db85Sdougm 596185db85Sdougm /* 606185db85Sdougm * sa_scf_fini(handle) 616185db85Sdougm * 6225a68471Sdougm * Must be called when done. Called with the handle allocated in 636185db85Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 646185db85Sdougm * still in use. Called by sa_fini(). 656185db85Sdougm */ 666185db85Sdougm 676185db85Sdougm void 686185db85Sdougm sa_scf_fini(scfutilhandle_t *handle) 696185db85Sdougm { 706185db85Sdougm if (handle != NULL) { 716185db85Sdougm int unbind = 0; 726185db85Sdougm if (handle->scope != NULL) { 736185db85Sdougm unbind = 1; 746185db85Sdougm scf_scope_destroy(handle->scope); 756185db85Sdougm } 76a3351425Sdougm if (handle->instance != NULL) 77a3351425Sdougm scf_instance_destroy(handle->instance); 786185db85Sdougm if (handle->service != NULL) 796185db85Sdougm scf_service_destroy(handle->service); 806185db85Sdougm if (handle->pg != NULL) 816185db85Sdougm scf_pg_destroy(handle->pg); 826185db85Sdougm if (handle->handle != NULL) { 836185db85Sdougm handle->scf_state = SCH_STATE_UNINIT; 846185db85Sdougm if (unbind) 856185db85Sdougm (void) scf_handle_unbind(handle->handle); 866185db85Sdougm scf_handle_destroy(handle->handle); 876185db85Sdougm } 886185db85Sdougm free(handle); 896185db85Sdougm } 906185db85Sdougm } 916185db85Sdougm 926185db85Sdougm /* 936185db85Sdougm * sa_scf_init() 946185db85Sdougm * 9525a68471Sdougm * Must be called before using any of the SCF functions. Called by 966185db85Sdougm * sa_init() during the API setup. 976185db85Sdougm */ 986185db85Sdougm 996185db85Sdougm scfutilhandle_t * 100549ec3ffSdougm sa_scf_init(sa_handle_impl_t ihandle) 1016185db85Sdougm { 1026185db85Sdougm scfutilhandle_t *handle; 1036185db85Sdougm 1046185db85Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1056185db85Sdougm if (scf_max_name_len <= 0) 1066185db85Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1076185db85Sdougm 1086185db85Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 10925a68471Sdougm if (handle == NULL) 11025a68471Sdougm return (handle); 11125a68471Sdougm 112549ec3ffSdougm ihandle->scfhandle = handle; 1136185db85Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 1146185db85Sdougm handle->handle = scf_handle_create(SCF_VERSION); 11525a68471Sdougm if (handle->handle == NULL) { 11625a68471Sdougm free(handle); 11725a68471Sdougm handle = NULL; 11825a68471Sdougm (void) printf("libshare could not access SMF repository: %s\n", 11925a68471Sdougm scf_strerror(scf_error())); 12025a68471Sdougm return (handle); 12125a68471Sdougm } 12225a68471Sdougm if (scf_handle_bind(handle->handle) != 0) 12325a68471Sdougm goto err; 12425a68471Sdougm 1256185db85Sdougm handle->scope = scf_scope_create(handle->handle); 1266185db85Sdougm handle->service = scf_service_create(handle->handle); 1276185db85Sdougm handle->pg = scf_pg_create(handle->handle); 128a3351425Sdougm 12925a68471Sdougm /* Make sure we have sufficient SMF running */ 1306185db85Sdougm handle->instance = scf_instance_create(handle->handle); 131a3351425Sdougm if (handle->scope == NULL || handle->service == NULL || 132a3351425Sdougm handle->pg == NULL || handle->instance == NULL) 133a3351425Sdougm goto err; 1346185db85Sdougm if (scf_handle_get_scope(handle->handle, 13525a68471Sdougm SCF_SCOPE_LOCAL, handle->scope) != 0) 1366185db85Sdougm goto err; 13725a68471Sdougm if (scf_scope_get_service(handle->scope, 13825a68471Sdougm SA_GROUP_SVC_NAME, handle->service) != 0) 13925a68471Sdougm goto err; 14025a68471Sdougm 1416185db85Sdougm handle->scf_state = SCH_STATE_INIT; 1426185db85Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 1436185db85Sdougm sa_group_t defgrp; 14425a68471Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 1451f29d134Sdougm /* Only NFS enabled for "default" group. */ 1461f29d134Sdougm if (defgrp != NULL) 1471f29d134Sdougm (void) sa_create_optionset(defgrp, "nfs"); 1486185db85Sdougm } 14925a68471Sdougm 1506185db85Sdougm return (handle); 1516185db85Sdougm 15225a68471Sdougm /* Error handling/unwinding */ 1536185db85Sdougm err: 1546185db85Sdougm (void) sa_scf_fini(handle); 1556185db85Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1566185db85Sdougm scf_strerror(scf_error())); 1576185db85Sdougm return (NULL); 1586185db85Sdougm } 1596185db85Sdougm 1606185db85Sdougm /* 1616185db85Sdougm * get_scf_limit(name) 1626185db85Sdougm * 1636185db85Sdougm * Since we use scf_limit a lot and do the same check and return the 1646185db85Sdougm * same value if it fails, implement as a function for code 1656185db85Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1666185db85Sdougm * (1024) so we have a reasonable default buffer size. 1676185db85Sdougm */ 1686185db85Sdougm static ssize_t 1696185db85Sdougm get_scf_limit(uint32_t name) 1706185db85Sdougm { 1716185db85Sdougm ssize_t vallen; 1726185db85Sdougm 1736185db85Sdougm vallen = scf_limit(name); 1746185db85Sdougm if (vallen == (ssize_t)-1) 1756185db85Sdougm vallen = MAXPATHLEN; 1766185db85Sdougm return (vallen); 1776185db85Sdougm } 1786185db85Sdougm 1796185db85Sdougm /* 1806185db85Sdougm * skip_property(name) 1816185db85Sdougm * 18225a68471Sdougm * Internal function to check to see if a property is an SMF magic 1836185db85Sdougm * property that needs to be skipped. 1846185db85Sdougm */ 1856185db85Sdougm static int 1866185db85Sdougm skip_property(char *name) 1876185db85Sdougm { 1886185db85Sdougm int i; 1896185db85Sdougm 1906185db85Sdougm for (i = 0; skip_props[i] != NULL; i++) 1916185db85Sdougm if (strcmp(name, skip_props[i]) == 0) 1926185db85Sdougm return (1); 1936185db85Sdougm return (0); 1946185db85Sdougm } 1956185db85Sdougm 1966185db85Sdougm /* 1976185db85Sdougm * generate_unique_sharename(sharename) 1986185db85Sdougm * 1996185db85Sdougm * Shares are represented in SMF as property groups. Due to share 2006185db85Sdougm * paths containing characters that are not allowed in SMF names and 2016185db85Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2026185db85Sdougm */ 2036185db85Sdougm 2046185db85Sdougm static void 2056185db85Sdougm generate_unique_sharename(char *sharename) 2066185db85Sdougm { 2076185db85Sdougm uuid_t uuid; 2086185db85Sdougm 2096185db85Sdougm uuid_generate(uuid); 2106185db85Sdougm (void) strcpy(sharename, "S-"); 2116185db85Sdougm uuid_unparse(uuid, sharename + 2); 2126185db85Sdougm } 2136185db85Sdougm 2146185db85Sdougm /* 2156185db85Sdougm * valid_protocol(proto) 2166185db85Sdougm * 21725a68471Sdougm * Check to see if the specified protocol is a valid one for the 2186185db85Sdougm * general sharemgr facility. We determine this by checking which 2196185db85Sdougm * plugin protocols were found. 2206185db85Sdougm */ 2216185db85Sdougm 2226185db85Sdougm static int 2236185db85Sdougm valid_protocol(char *proto) 2246185db85Sdougm { 2256185db85Sdougm struct sa_proto_plugin *plugin; 2266185db85Sdougm for (plugin = sap_proto_list; plugin != NULL; 2276185db85Sdougm plugin = plugin->plugin_next) 2286185db85Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2296185db85Sdougm return (1); 2306185db85Sdougm return (0); 2316185db85Sdougm } 2326185db85Sdougm 2336185db85Sdougm /* 2346185db85Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2356185db85Sdougm * 23625a68471Sdougm * Extract the name property group and create the specified type of 2376185db85Sdougm * node on the provided group. type will be optionset or security. 2386185db85Sdougm */ 2396185db85Sdougm 2406185db85Sdougm static int 2416185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2426185db85Sdougm scf_propertygroup_t *pg, 2436185db85Sdougm char *nodetype, char *proto, char *sectype) 2446185db85Sdougm { 2456185db85Sdougm xmlNodePtr node; 2466185db85Sdougm scf_iter_t *iter; 2476185db85Sdougm scf_property_t *prop; 2486185db85Sdougm scf_value_t *value; 2496185db85Sdougm char *name; 2506185db85Sdougm char *valuestr; 2516185db85Sdougm ssize_t vallen; 2526185db85Sdougm int ret = SA_OK; 2536185db85Sdougm 2546185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2556185db85Sdougm 2566185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 25725a68471Sdougm if (node == NULL) 25825a68471Sdougm return (ret); 25925a68471Sdougm 2606185db85Sdougm if (proto != NULL) 2617a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2626185db85Sdougm if (sectype != NULL) 2637a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"sectype", 2647a9d7716Sthurlow (xmlChar *)sectype); 2656185db85Sdougm /* 26625a68471Sdougm * Have node to work with so iterate over the properties 2676185db85Sdougm * in the pg and create option sub nodes. 2686185db85Sdougm */ 2696185db85Sdougm iter = scf_iter_create(handle->handle); 2706185db85Sdougm value = scf_value_create(handle->handle); 2716185db85Sdougm prop = scf_property_create(handle->handle); 2726185db85Sdougm name = malloc(scf_max_name_len); 2736185db85Sdougm valuestr = malloc(vallen); 2746185db85Sdougm /* 27525a68471Sdougm * Want to iterate through the properties and add them 2766185db85Sdougm * to the base optionset. 2776185db85Sdougm */ 27825a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || 27925a68471Sdougm valuestr == NULL || name == NULL) { 28025a68471Sdougm ret = SA_NO_MEMORY; 28125a68471Sdougm goto out; 28225a68471Sdougm } 2836185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 28425a68471Sdougm /* Now iterate the properties in the group */ 2856185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2866185db85Sdougm /* have a property */ 2876185db85Sdougm if (scf_property_get_name(prop, name, 2886185db85Sdougm scf_max_name_len) > 0) { 28925a68471Sdougm sa_property_t saprop; 29025a68471Sdougm /* Some properties are part of the framework */ 2916185db85Sdougm if (skip_property(name)) 2926185db85Sdougm continue; 29325a68471Sdougm if (scf_property_get_value(prop, value) != 0) 29425a68471Sdougm continue; 2956185db85Sdougm if (scf_value_get_astring(value, valuestr, 29625a68471Sdougm vallen) < 0) 29725a68471Sdougm continue; 29825a68471Sdougm saprop = sa_create_property(name, valuestr); 2996185db85Sdougm if (saprop != NULL) { 3006185db85Sdougm /* 30125a68471Sdougm * Since in SMF, don't 3026185db85Sdougm * recurse. Use xmlAddChild 3036185db85Sdougm * directly, instead. 3046185db85Sdougm */ 3057a9d7716Sthurlow (void) xmlAddChild(node, 3066185db85Sdougm (xmlNodePtr) saprop); 3076185db85Sdougm } 3086185db85Sdougm } 3096185db85Sdougm } 3106185db85Sdougm } 31125a68471Sdougm out: 3126185db85Sdougm /* cleanup to avoid memory leaks */ 3136185db85Sdougm if (value != NULL) 3146185db85Sdougm scf_value_destroy(value); 3156185db85Sdougm if (iter != NULL) 3166185db85Sdougm scf_iter_destroy(iter); 3176185db85Sdougm if (prop != NULL) 3186185db85Sdougm scf_property_destroy(prop); 3196185db85Sdougm if (name != NULL) 3206185db85Sdougm free(name); 3216185db85Sdougm if (valuestr != NULL) 3226185db85Sdougm free(valuestr); 32325a68471Sdougm 3246185db85Sdougm return (ret); 3256185db85Sdougm } 3266185db85Sdougm 3276185db85Sdougm /* 3286185db85Sdougm * sa_extract_attrs(root, handle, instance) 3296185db85Sdougm * 33025a68471Sdougm * Local function to extract the actual attributes/properties from the 3316185db85Sdougm * property group of the service instance. These are the well known 3326185db85Sdougm * attributes of "state" and "zfs". If additional attributes are 3336185db85Sdougm * added, they should be added here. 3346185db85Sdougm */ 3356185db85Sdougm 3366185db85Sdougm static void 3376185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3386185db85Sdougm scf_instance_t *instance) 3396185db85Sdougm { 3406185db85Sdougm scf_property_t *prop; 3416185db85Sdougm scf_value_t *value; 3426185db85Sdougm char *valuestr; 3436185db85Sdougm ssize_t vallen; 3446185db85Sdougm 3456185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3466185db85Sdougm prop = scf_property_create(handle->handle); 3476185db85Sdougm value = scf_value_create(handle->handle); 3486185db85Sdougm valuestr = malloc(vallen); 34925a68471Sdougm if (prop == NULL || value == NULL || valuestr == NULL || 35025a68471Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 35125a68471Sdougm goto out; 35225a68471Sdougm } 3536185db85Sdougm /* 35425a68471Sdougm * Have a property group with desired name so now get 3556185db85Sdougm * the known attributes. 3566185db85Sdougm */ 3576185db85Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 35825a68471Sdougm /* Found the property so get the value */ 3596185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 36025a68471Sdougm if (scf_value_get_astring(value, valuestr, 36125a68471Sdougm vallen) >= 0) { 3627a9d7716Sthurlow (void) xmlSetProp(root, (xmlChar *)"state", 3636185db85Sdougm (xmlChar *)valuestr); 3646185db85Sdougm } 3656185db85Sdougm } 3666185db85Sdougm } 3676185db85Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 36825a68471Sdougm /* Found the property so get the value */ 3696185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 37025a68471Sdougm if (scf_value_get_astring(value, valuestr, 37125a68471Sdougm vallen) > 0) { 3727a9d7716Sthurlow (void) xmlSetProp(root, (xmlChar *)"zfs", 3736185db85Sdougm (xmlChar *)valuestr); 3746185db85Sdougm } 3756185db85Sdougm } 3766185db85Sdougm } 37725a68471Sdougm out: 3786185db85Sdougm if (valuestr != NULL) 3796185db85Sdougm free(valuestr); 3806185db85Sdougm if (value != NULL) 3816185db85Sdougm scf_value_destroy(value); 3826185db85Sdougm if (prop != NULL) 3836185db85Sdougm scf_property_destroy(prop); 3846185db85Sdougm } 3856185db85Sdougm 3866185db85Sdougm /* 38725a68471Sdougm * List of known share attributes. 3886185db85Sdougm */ 3896185db85Sdougm 3906185db85Sdougm static char *share_attr[] = { 3916185db85Sdougm "path", 3926185db85Sdougm "id", 393da6c28aaSamw "drive-letter", 394da6c28aaSamw "exclude", 3956185db85Sdougm NULL, 3966185db85Sdougm }; 3976185db85Sdougm 3986185db85Sdougm static int 3996185db85Sdougm is_share_attr(char *name) 4006185db85Sdougm { 4016185db85Sdougm int i; 4026185db85Sdougm for (i = 0; share_attr[i] != NULL; i++) 4036185db85Sdougm if (strcmp(name, share_attr[i]) == 0) 4046185db85Sdougm return (1); 4056185db85Sdougm return (0); 4066185db85Sdougm } 4076185db85Sdougm 4086185db85Sdougm /* 409da6c28aaSamw * _sa_make_resource(node, valuestr) 410da6c28aaSamw * 411da6c28aaSamw * Make a resource node on the share node. The valusestr will either 412da6c28aaSamw * be old format (SMF acceptable string) or new format (pretty much an 413da6c28aaSamw * arbitrary string with "nnn:" prefixing in order to persist 414da6c28aaSamw * mapping). The input valuestr will get modified in place. This is 415da6c28aaSamw * only used in SMF repository parsing. A possible third field will be 416da6c28aaSamw * a "description" string. 417da6c28aaSamw */ 418da6c28aaSamw 419da6c28aaSamw static void 420da6c28aaSamw _sa_make_resource(xmlNodePtr node, char *valuestr) 421da6c28aaSamw { 422da6c28aaSamw char *idx; 423da6c28aaSamw char *name; 424da6c28aaSamw char *description = NULL; 425da6c28aaSamw 426da6c28aaSamw idx = valuestr; 427da6c28aaSamw name = strchr(valuestr, ':'); 428da6c28aaSamw if (name == NULL) { 429da6c28aaSamw /* this is old form so give an index of "0" */ 430da6c28aaSamw idx = "0"; 431da6c28aaSamw name = valuestr; 432da6c28aaSamw } else { 433da6c28aaSamw /* NUL the ':' and move past it */ 434da6c28aaSamw *name++ = '\0'; 435da6c28aaSamw /* There could also be a description string */ 436da6c28aaSamw description = strchr(name, ':'); 437da6c28aaSamw if (description != NULL) 438da6c28aaSamw *description++ = '\0'; 439da6c28aaSamw } 440da6c28aaSamw node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL); 441da6c28aaSamw if (node != NULL) { 4427a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name); 4437a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx); 444da6c28aaSamw /* SMF values are always persistent */ 4457a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 4467a9d7716Sthurlow (xmlChar *)"persist"); 447da6c28aaSamw if (description != NULL && strlen(description) > 0) { 448da6c28aaSamw (void) xmlNewChild(node, NULL, (xmlChar *)"description", 449da6c28aaSamw (xmlChar *)description); 450da6c28aaSamw } 451da6c28aaSamw } 452da6c28aaSamw } 453da6c28aaSamw 454da6c28aaSamw 455da6c28aaSamw /* 4566185db85Sdougm * sa_share_from_pgroup 4576185db85Sdougm * 45825a68471Sdougm * Extract the share definition from the share property group. We do 4596185db85Sdougm * some sanity checking to avoid bad data. 4606185db85Sdougm * 4616185db85Sdougm * Since this is only constructing the internal data structures, we 4626185db85Sdougm * don't use the sa_* functions most of the time. 4636185db85Sdougm */ 4646185db85Sdougm void 4656185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4666185db85Sdougm scf_propertygroup_t *pg, char *id) 4676185db85Sdougm { 4686185db85Sdougm xmlNodePtr node; 4696185db85Sdougm char *name; 4706185db85Sdougm scf_iter_t *iter; 4716185db85Sdougm scf_property_t *prop; 4726185db85Sdougm scf_value_t *value; 4736185db85Sdougm ssize_t vallen; 4746185db85Sdougm char *valuestr; 4756185db85Sdougm int ret = SA_OK; 476f345c0beSdougm int have_path = 0; 4776185db85Sdougm 4786185db85Sdougm /* 4796185db85Sdougm * While preliminary check (starts with 'S') passed before 4806185db85Sdougm * getting here. Need to make sure it is in ID syntax 4816185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 4826185db85Sdougm * pgroups. 4836185db85Sdougm */ 4846185db85Sdougm vallen = strlen(id); 4856185db85Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4866185db85Sdougm uuid_t uuid; 48725a68471Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, 48825a68471Sdougm SA_SHARE_PG_PREFIXLEN) != 0 || 4896185db85Sdougm uuid_parse(id + 2, uuid) < 0) 4906185db85Sdougm return; 4916185db85Sdougm } else { 4926185db85Sdougm return; 4936185db85Sdougm } 4946185db85Sdougm 4956185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 4966185db85Sdougm 4976185db85Sdougm iter = scf_iter_create(handle->handle); 4986185db85Sdougm value = scf_value_create(handle->handle); 4996185db85Sdougm prop = scf_property_create(handle->handle); 5006185db85Sdougm name = malloc(scf_max_name_len); 5016185db85Sdougm valuestr = malloc(vallen); 5026185db85Sdougm 5036185db85Sdougm /* 50425a68471Sdougm * Construct the share XML node. It is similar to sa_add_share 5056185db85Sdougm * but never changes the repository. Also, there won't be any 5066185db85Sdougm * ZFS or transient shares. Root will be the group it is 5076185db85Sdougm * associated with. 5086185db85Sdougm */ 5096185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 5106185db85Sdougm if (node != NULL) { 5116185db85Sdougm /* 51225a68471Sdougm * Make sure the UUID part of the property group is 5136185db85Sdougm * stored in the share "id" property. We use this 5146185db85Sdougm * later. 5156185db85Sdougm */ 5167a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 5177a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 5187a9d7716Sthurlow (xmlChar *)"persist"); 5196185db85Sdougm } 5206185db85Sdougm 52125a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 52225a68471Sdougm goto out; 52325a68471Sdougm 52425a68471Sdougm /* Iterate over the share pg properties */ 52525a68471Sdougm if (scf_iter_pg_properties(iter, pg) != 0) 52625a68471Sdougm goto out; 52725a68471Sdougm 5286185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 5296185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 53025a68471Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 5316185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 5326185db85Sdougm if (scf_value_get_astring(value, valuestr, 5336185db85Sdougm vallen) >= 0) { 5346185db85Sdougm ret = SA_OK; 5356185db85Sdougm } 536da6c28aaSamw } else if (strcmp(name, "resource") == 0) { 537da6c28aaSamw ret = SA_OK; 5386185db85Sdougm } 5396185db85Sdougm } 540da6c28aaSamw if (ret != SA_OK) 541da6c28aaSamw continue; 542f345c0beSdougm /* 54325a68471Sdougm * Check that we have the "path" property in 544f345c0beSdougm * name. The string in name will always be nul 545f345c0beSdougm * terminated if scf_property_get_name() 546f345c0beSdougm * succeeded. 547f345c0beSdougm */ 548f345c0beSdougm if (strcmp(name, "path") == 0) 549f345c0beSdougm have_path = 1; 5506185db85Sdougm if (is_share_attr(name)) { 5516185db85Sdougm /* 55225a68471Sdougm * If a share attr, then simple - 553da6c28aaSamw * usually path and id name 5546185db85Sdougm */ 5557a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)name, 5566185db85Sdougm (xmlChar *)valuestr); 557da6c28aaSamw } else if (strcmp(name, "resource") == 0) { 558da6c28aaSamw /* 559da6c28aaSamw * Resource names handled differently since 560da6c28aaSamw * there can be multiple on each share. The 561da6c28aaSamw * "resource" id must be preserved since this 562da6c28aaSamw * will be used by some protocols in mapping 563da6c28aaSamw * "property spaces" to names and is always 564da6c28aaSamw * used to create SMF property groups specific 565da6c28aaSamw * to resources. CIFS needs this. The first 566da6c28aaSamw * value is present so add and then loop for 567da6c28aaSamw * any additional. Since this is new and 568da6c28aaSamw * previous values may exist, handle 569da6c28aaSamw * conversions. 570da6c28aaSamw */ 571da6c28aaSamw scf_iter_t *viter; 572da6c28aaSamw viter = scf_iter_create(handle->handle); 573da6c28aaSamw if (viter != NULL && 574da6c28aaSamw scf_iter_property_values(viter, prop) == 0) { 575da6c28aaSamw while (scf_iter_next_value(viter, value) > 0) { 576da6c28aaSamw /* Have a value so process it */ 577da6c28aaSamw if (scf_value_get_ustring(value, 578da6c28aaSamw valuestr, vallen) >= 0) { 579da6c28aaSamw /* have a ustring */ 580da6c28aaSamw _sa_make_resource(node, 581da6c28aaSamw valuestr); 582da6c28aaSamw } else if (scf_value_get_astring(value, 583da6c28aaSamw valuestr, vallen) >= 0) { 584da6c28aaSamw /* have an astring */ 585da6c28aaSamw _sa_make_resource(node, 586da6c28aaSamw valuestr); 587da6c28aaSamw } 588da6c28aaSamw } 589da6c28aaSamw scf_iter_destroy(viter); 590da6c28aaSamw } 5916185db85Sdougm } else { 5926185db85Sdougm if (strcmp(name, "description") == 0) { 59325a68471Sdougm /* We have a description node */ 5946185db85Sdougm xmlNodePtr desc; 5956185db85Sdougm desc = xmlNewChild(node, NULL, 59625a68471Sdougm (xmlChar *)"description", NULL); 5976185db85Sdougm if (desc != NULL) 5986185db85Sdougm xmlNodeSetContent(desc, 5996185db85Sdougm (xmlChar *)valuestr); 6006185db85Sdougm } 6016185db85Sdougm } 6026185db85Sdougm } 60325a68471Sdougm out: 604f345c0beSdougm /* 60525a68471Sdougm * A share without a path is broken so we want to not include 606f345c0beSdougm * these. They shouldn't happen but if you kill a sharemgr in 607f345c0beSdougm * the process of creating a share, it could happen. They 608f345c0beSdougm * should be harmless. It is also possible that another 609f345c0beSdougm * sharemgr is running and in the process of creating a share. 610f345c0beSdougm */ 611f345c0beSdougm if (have_path == 0 && node != NULL) { 612f345c0beSdougm xmlUnlinkNode(node); 613f345c0beSdougm xmlFreeNode(node); 614f345c0beSdougm } 6156185db85Sdougm if (name != NULL) 6166185db85Sdougm free(name); 6176185db85Sdougm if (valuestr != NULL) 6186185db85Sdougm free(valuestr); 6196185db85Sdougm if (value != NULL) 6206185db85Sdougm scf_value_destroy(value); 6216185db85Sdougm if (iter != NULL) 6226185db85Sdougm scf_iter_destroy(iter); 6236185db85Sdougm if (prop != NULL) 6246185db85Sdougm scf_property_destroy(prop); 6256185db85Sdougm } 6266185db85Sdougm 6276185db85Sdougm /* 6286185db85Sdougm * find_share_by_id(shareid) 6296185db85Sdougm * 6306185db85Sdougm * Search all shares in all groups until we find the share represented 6316185db85Sdougm * by "id". 6326185db85Sdougm */ 6336185db85Sdougm 6346185db85Sdougm static sa_share_t 635549ec3ffSdougm find_share_by_id(sa_handle_t handle, char *shareid) 6366185db85Sdougm { 6376185db85Sdougm sa_group_t group; 6386185db85Sdougm sa_share_t share = NULL; 6396185db85Sdougm char *id = NULL; 6406185db85Sdougm int done = 0; 6416185db85Sdougm 64225a68471Sdougm for (group = sa_get_group(handle, NULL); 64325a68471Sdougm group != NULL && !done; 6446185db85Sdougm group = sa_get_next_group(group)) { 64525a68471Sdougm for (share = sa_get_share(group, NULL); 64625a68471Sdougm share != NULL; 6476185db85Sdougm share = sa_get_next_share(share)) { 6486185db85Sdougm id = sa_get_share_attr(share, "id"); 6496185db85Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 6506185db85Sdougm sa_free_attr_string(id); 6516185db85Sdougm id = NULL; 6526185db85Sdougm done++; 6536185db85Sdougm break; 6546185db85Sdougm } 6556185db85Sdougm if (id != NULL) { 6566185db85Sdougm sa_free_attr_string(id); 6576185db85Sdougm id = NULL; 6586185db85Sdougm } 6596185db85Sdougm } 6606185db85Sdougm } 6616185db85Sdougm return (share); 6626185db85Sdougm } 6636185db85Sdougm 6646185db85Sdougm /* 665da6c28aaSamw * find_resource_by_index(share, index) 666da6c28aaSamw * 667da6c28aaSamw * Search the resource records on the share for the id index. 668da6c28aaSamw */ 669da6c28aaSamw static sa_resource_t 670da6c28aaSamw find_resource_by_index(sa_share_t share, char *index) 671da6c28aaSamw { 672da6c28aaSamw sa_resource_t resource; 673da6c28aaSamw sa_resource_t found = NULL; 674da6c28aaSamw char *id; 675da6c28aaSamw 676da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 677da6c28aaSamw resource != NULL && found == NULL; 678da6c28aaSamw resource = sa_get_next_resource(resource)) { 679da6c28aaSamw id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id"); 680da6c28aaSamw if (id != NULL) { 681da6c28aaSamw if (strcmp(id, index) == 0) { 682da6c28aaSamw /* found it so save in "found" */ 683da6c28aaSamw found = resource; 684da6c28aaSamw } 685da6c28aaSamw sa_free_attr_string(id); 686da6c28aaSamw } 687da6c28aaSamw } 688da6c28aaSamw return (found); 689da6c28aaSamw } 690da6c28aaSamw 691da6c28aaSamw /* 692da6c28aaSamw * sa_share_props_from_pgroup(root, handle, pg, id, sahandle) 6936185db85Sdougm * 69425a68471Sdougm * Extract share properties from the SMF property group. More sanity 6956185db85Sdougm * checks are done and the share object is created. We ignore some 6966185db85Sdougm * errors that could exist in the repository and only worry about 6976185db85Sdougm * property groups that validate in naming. 6986185db85Sdougm */ 6996185db85Sdougm 7006185db85Sdougm static int 7016185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 702549ec3ffSdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 7036185db85Sdougm { 7046185db85Sdougm xmlNodePtr node; 70525a68471Sdougm char *name = NULL; 70625a68471Sdougm scf_iter_t *iter = NULL; 70725a68471Sdougm scf_property_t *prop = NULL; 70825a68471Sdougm scf_value_t *value = NULL; 7096185db85Sdougm ssize_t vallen; 71025a68471Sdougm char *valuestr = NULL; 7116185db85Sdougm int ret = SA_OK; 7126185db85Sdougm char *sectype = NULL; 7136185db85Sdougm char *proto; 7146185db85Sdougm sa_share_t share; 71525a68471Sdougm uuid_t uuid; 7166185db85Sdougm 7176185db85Sdougm /* 7186185db85Sdougm * While preliminary check (starts with 'S') passed before 7196185db85Sdougm * getting here. Need to make sure it is in ID syntax 7206185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 7216185db85Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 7226185db85Sdougm * characters, it is likely one of the protocol/security 7236185db85Sdougm * versions. 7246185db85Sdougm */ 7256185db85Sdougm vallen = strlen(id); 72625a68471Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 72725a68471Sdougm /* 72825a68471Sdougm * It is ok to not have what we thought since someone might 72925a68471Sdougm * have added a name via SMF. 73025a68471Sdougm */ 73125a68471Sdougm return (ret); 73225a68471Sdougm } 7336185db85Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 7346185db85Sdougm proto = strchr(id, '_'); 7356185db85Sdougm if (proto == NULL) 7366185db85Sdougm return (ret); 7376185db85Sdougm *proto++ = '\0'; 7386185db85Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 7396185db85Sdougm return (ret); 7406185db85Sdougm /* 7416185db85Sdougm * probably a legal optionset so check a few more 7426185db85Sdougm * syntax points below. 7436185db85Sdougm */ 7446185db85Sdougm if (*proto == '\0') { 7456185db85Sdougm /* not a valid proto (null) */ 7466185db85Sdougm return (ret); 7476185db85Sdougm } 748da6c28aaSamw 7496185db85Sdougm sectype = strchr(proto, '_'); 7506185db85Sdougm if (sectype != NULL) 7516185db85Sdougm *sectype++ = '\0'; 7526185db85Sdougm if (!valid_protocol(proto)) 7536185db85Sdougm return (ret); 7546185db85Sdougm } 7556185db85Sdougm 7566185db85Sdougm /* 75725a68471Sdougm * To get here, we have a valid protocol and possibly a 7586185db85Sdougm * security. We now have to find the share that it is really 7596185db85Sdougm * associated with. The "id" portion of the pgroup name will 7606185db85Sdougm * match. 7616185db85Sdougm */ 7626185db85Sdougm 763549ec3ffSdougm share = find_share_by_id(sahandle, id); 7646185db85Sdougm if (share == NULL) 7656185db85Sdougm return (SA_BAD_PATH); 7666185db85Sdougm 7676185db85Sdougm root = (xmlNodePtr)share; 7686185db85Sdougm 7696185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 7706185db85Sdougm 77125a68471Sdougm if (sectype == NULL) 77225a68471Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 77325a68471Sdougm else { 774da6c28aaSamw if (isdigit((int)*sectype)) { 775da6c28aaSamw sa_resource_t resource; 776da6c28aaSamw /* 777da6c28aaSamw * If sectype[0] is a digit, then it is an index into 778da6c28aaSamw * the resource names. We need to find a resource 779da6c28aaSamw * record and then get the properties into an 780da6c28aaSamw * optionset. The optionset becomes the "node" and the 781da6c28aaSamw * rest is hung off of the share. 782da6c28aaSamw */ 783da6c28aaSamw resource = find_resource_by_index(share, sectype); 784da6c28aaSamw if (resource != NULL) { 785da6c28aaSamw node = xmlNewChild(resource, NULL, 786da6c28aaSamw (xmlChar *)"optionset", NULL); 787da6c28aaSamw } else { 78855bf511dSas200622 /* This shouldn't happen. */ 789da6c28aaSamw ret = SA_SYSTEM_ERR; 79055bf511dSas200622 goto out; 791da6c28aaSamw } 792da6c28aaSamw } else { 793da6c28aaSamw /* 794da6c28aaSamw * If not a digit, then it is a security type 795da6c28aaSamw * (alternate option space). Security types start with 796da6c28aaSamw * an alphabetic. 797da6c28aaSamw */ 798da6c28aaSamw node = xmlNewChild(root, NULL, (xmlChar *)"security", 799da6c28aaSamw NULL); 80025a68471Sdougm if (node != NULL) 8017a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"sectype", 80225a68471Sdougm (xmlChar *)sectype); 80325a68471Sdougm } 804da6c28aaSamw } 80525a68471Sdougm if (node == NULL) { 80625a68471Sdougm ret = SA_NO_MEMORY; 80725a68471Sdougm goto out; 80825a68471Sdougm } 80925a68471Sdougm 8107a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 81125a68471Sdougm /* now find the properties */ 8126185db85Sdougm iter = scf_iter_create(handle->handle); 8136185db85Sdougm value = scf_value_create(handle->handle); 8146185db85Sdougm prop = scf_property_create(handle->handle); 8156185db85Sdougm name = malloc(scf_max_name_len); 8166185db85Sdougm valuestr = malloc(vallen); 8176185db85Sdougm 81825a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 81925a68471Sdougm goto out; 82025a68471Sdougm 821da6c28aaSamw /* iterate over the share pg properties */ 8226185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 8236185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 8246185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 8256185db85Sdougm if (scf_property_get_name(prop, name, 8266185db85Sdougm scf_max_name_len) > 0) { 8276185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 82825a68471Sdougm if (scf_value_get_astring(value, 82925a68471Sdougm valuestr, vallen) >= 0) { 8306185db85Sdougm ret = SA_OK; 8316185db85Sdougm } 8326185db85Sdougm } 8336185db85Sdougm } else { 8346185db85Sdougm ret = SA_SYSTEM_ERR; 8356185db85Sdougm } 8366185db85Sdougm if (ret == SA_OK) { 8376185db85Sdougm sa_property_t prop; 8386185db85Sdougm prop = sa_create_property(name, valuestr); 8396185db85Sdougm if (prop != NULL) 8406185db85Sdougm prop = (sa_property_t)xmlAddChild(node, 8416185db85Sdougm (xmlNodePtr)prop); 8426185db85Sdougm else 8436185db85Sdougm ret = SA_NO_MEMORY; 8446185db85Sdougm } 8456185db85Sdougm } 8466185db85Sdougm } else { 8476185db85Sdougm ret = SA_SYSTEM_ERR; 8486185db85Sdougm } 84925a68471Sdougm out: 8506185db85Sdougm if (iter != NULL) 8516185db85Sdougm scf_iter_destroy(iter); 8526185db85Sdougm if (value != NULL) 8536185db85Sdougm scf_value_destroy(value); 8546185db85Sdougm if (prop != NULL) 8556185db85Sdougm scf_property_destroy(prop); 8566185db85Sdougm if (name != NULL) 8576185db85Sdougm free(name); 8586185db85Sdougm if (valuestr != NULL) 8596185db85Sdougm free(valuestr); 8606185db85Sdougm return (ret); 8616185db85Sdougm } 8626185db85Sdougm 8636185db85Sdougm /* 8646185db85Sdougm * sa_extract_group(root, handle, instance) 8656185db85Sdougm * 86625a68471Sdougm * Get the config info for this instance of a group and create the XML 8676185db85Sdougm * subtree from it. 8686185db85Sdougm */ 8696185db85Sdougm 8706185db85Sdougm static int 8716185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 872549ec3ffSdougm scf_instance_t *instance, sa_handle_t sahandle) 8736185db85Sdougm { 8746185db85Sdougm char *buff; 8756185db85Sdougm xmlNodePtr node; 8766185db85Sdougm scf_iter_t *iter; 8776185db85Sdougm char *proto; 8786185db85Sdougm char *sectype; 8791f29d134Sdougm boolean_t have_shares = B_FALSE; 8801f29d134Sdougm boolean_t is_default = B_FALSE; 8811f29d134Sdougm boolean_t is_nfs = B_FALSE; 8826185db85Sdougm int ret = SA_OK; 8836185db85Sdougm int err; 8846185db85Sdougm 8856185db85Sdougm buff = malloc(scf_max_name_len); 88625a68471Sdougm if (buff == NULL) 88725a68471Sdougm return (SA_NO_MEMORY); 88825a68471Sdougm 8896185db85Sdougm iter = scf_iter_create(handle->handle); 89025a68471Sdougm if (iter == NULL) { 89125a68471Sdougm ret = SA_NO_MEMORY; 89225a68471Sdougm goto out; 89325a68471Sdougm } 89425a68471Sdougm 89525a68471Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 8966185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 89725a68471Sdougm if (node == NULL) { 89825a68471Sdougm ret = SA_NO_MEMORY; 89925a68471Sdougm goto out; 90025a68471Sdougm } 9017a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 9026185db85Sdougm if (strcmp(buff, "default") == 0) 9031f29d134Sdougm is_default = B_TRUE; 90425a68471Sdougm 9056185db85Sdougm sa_extract_attrs(node, handle, instance); 9066185db85Sdougm /* 9076185db85Sdougm * Iterate through all the property groups 9086185db85Sdougm * looking for those with security or 9096185db85Sdougm * optionset prefixes. The names of the 9106185db85Sdougm * matching pgroups are parsed to get the 9116185db85Sdougm * protocol, and for security, the sectype. 9126185db85Sdougm * Syntax is as follows: 9136185db85Sdougm * optionset | optionset_<proto> 9146185db85Sdougm * security_default | security_<proto>_<sectype> 9156185db85Sdougm * "operation" is handled by 9166185db85Sdougm * sa_extract_attrs(). 9176185db85Sdougm */ 91825a68471Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) { 91925a68471Sdougm ret = SA_NO_MEMORY; 92025a68471Sdougm goto out; 92125a68471Sdougm } 9226185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 92325a68471Sdougm /* Have a pgroup so sort it out */ 9246185db85Sdougm ret = scf_pg_get_name(handle->pg, buff, 9256185db85Sdougm scf_max_name_len); 9261f29d134Sdougm if (ret <= 0) 9271f29d134Sdougm continue; 9281f29d134Sdougm is_nfs = B_FALSE; 9291f29d134Sdougm 9306185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 9316185db85Sdougm sa_share_from_pgroup(node, handle, 93225a68471Sdougm handle->pg, buff); 9331f29d134Sdougm have_shares = B_TRUE; 9341f29d134Sdougm } else if (strncmp(buff, "optionset", 9) == 0) { 9356185db85Sdougm char *nodetype = "optionset"; 93625a68471Sdougm /* Have an optionset */ 9376185db85Sdougm sectype = NULL; 9386185db85Sdougm proto = strchr(buff, '_'); 9396185db85Sdougm if (proto != NULL) { 9406185db85Sdougm *proto++ = '\0'; 9416185db85Sdougm sectype = strchr(proto, '_'); 9426185db85Sdougm if (sectype != NULL) { 9436185db85Sdougm *sectype++ = '\0'; 9446185db85Sdougm nodetype = "security"; 9456185db85Sdougm } 9461f29d134Sdougm is_nfs = strcmp(proto, "nfs") == 0; 9471f29d134Sdougm } else if (strlen(buff) > 9) { 9481f29d134Sdougm /* 9491f29d134Sdougm * This can only occur if 9501f29d134Sdougm * someone has made changes 9511f29d134Sdougm * via an SMF command. Since 9521f29d134Sdougm * this would be an unknown 9531f29d134Sdougm * syntax, we just ignore it. 9541f29d134Sdougm */ 9551f29d134Sdougm continue; 9566185db85Sdougm } 9571f29d134Sdougm /* 9581f29d134Sdougm * If the group is not "default" or is 9591f29d134Sdougm * "default" and is_nfs, then extract the 9601f29d134Sdougm * pgroup. If it is_default and !is_nfs, 9611f29d134Sdougm * then we have an error and should remove 9621f29d134Sdougm * the extraneous protocols. We don't care 9631f29d134Sdougm * about errors on scf_pg_delete since we 9641f29d134Sdougm * might not have permission during an 9651f29d134Sdougm * extract only. 9661f29d134Sdougm */ 9671f29d134Sdougm if (!is_default || is_nfs) { 9686185db85Sdougm ret = sa_extract_pgroup(node, handle, 96925a68471Sdougm handle->pg, nodetype, proto, 97025a68471Sdougm sectype); 9711f29d134Sdougm } else { 9721f29d134Sdougm err = scf_pg_delete(handle->pg); 9731f29d134Sdougm if (err == 0) 9741f29d134Sdougm (void) fprintf(stderr, 9751f29d134Sdougm dgettext(TEXT_DOMAIN, 9761f29d134Sdougm "Removed protocol \"%s\" " 9771f29d134Sdougm "from group \"default\"\n"), 9781f29d134Sdougm proto); 9791f29d134Sdougm } 98025a68471Sdougm } else if (strncmp(buff, "security", 8) == 0) { 9816185db85Sdougm /* 98225a68471Sdougm * Have a security (note that 9836185db85Sdougm * this should change in the 9846185db85Sdougm * future) 9856185db85Sdougm */ 9866185db85Sdougm proto = strchr(buff, '_'); 9876185db85Sdougm sectype = NULL; 9886185db85Sdougm if (proto != NULL) { 9896185db85Sdougm *proto++ = '\0'; 9906185db85Sdougm sectype = strchr(proto, '_'); 9916185db85Sdougm if (sectype != NULL) 9926185db85Sdougm *sectype++ = '\0'; 9931f29d134Sdougm if (strcmp(proto, "default") == 0) 9946185db85Sdougm proto = NULL; 9956185db85Sdougm } 9966185db85Sdougm ret = sa_extract_pgroup(node, handle, 9971f29d134Sdougm handle->pg, "security", proto, sectype); 9986185db85Sdougm } 99925a68471Sdougm /* Ignore everything else */ 10006185db85Sdougm } 10016185db85Sdougm /* 10026185db85Sdougm * Make sure we have a valid default group. 10036185db85Sdougm * On first boot, default won't have any 10046185db85Sdougm * protocols defined and won't be enabled (but 10051f29d134Sdougm * should be). "default" only has NFS enabled on it. 10066185db85Sdougm */ 10076185db85Sdougm if (is_default) { 10086185db85Sdougm char *state = sa_get_group_attr((sa_group_t)node, 10096185db85Sdougm "state"); 10106185db85Sdougm 10116185db85Sdougm if (state == NULL) { 10126185db85Sdougm /* set attribute to enabled */ 10136185db85Sdougm (void) sa_set_group_attr((sa_group_t)node, 101425a68471Sdougm "state", "enabled"); 10151f29d134Sdougm (void) sa_create_optionset((sa_group_t)node, 10161f29d134Sdougm "nfs"); 10176185db85Sdougm } else { 10186185db85Sdougm sa_free_attr_string(state); 10196185db85Sdougm } 10206185db85Sdougm } 102125a68471Sdougm /* Do a second pass if shares were found */ 102225a68471Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 10236185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 10246185db85Sdougm /* 102525a68471Sdougm * Have a pgroup so see if it is a 10266185db85Sdougm * share optionset 10276185db85Sdougm */ 10286185db85Sdougm err = scf_pg_get_name(handle->pg, buff, 10296185db85Sdougm scf_max_name_len); 103025a68471Sdougm if (err <= 0) 103125a68471Sdougm continue; 10326185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 10336185db85Sdougm ret = sa_share_props_from_pgroup(node, 103425a68471Sdougm handle, handle->pg, buff, 103525a68471Sdougm sahandle); 10366185db85Sdougm } 10376185db85Sdougm } 10386185db85Sdougm } 10396185db85Sdougm } 104025a68471Sdougm out: 10416185db85Sdougm if (iter != NULL) 10426185db85Sdougm scf_iter_destroy(iter); 10436185db85Sdougm if (buff != NULL) 10446185db85Sdougm free(buff); 10456185db85Sdougm return (ret); 10466185db85Sdougm } 10476185db85Sdougm 10486185db85Sdougm /* 10496185db85Sdougm * sa_extract_defaults(root, handle, instance) 10506185db85Sdougm * 105125a68471Sdougm * Local function to find the default properties that live in the 1052da6c28aaSamw * default instance's "operation" property group. 10536185db85Sdougm */ 10546185db85Sdougm 10556185db85Sdougm static void 10566185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 10576185db85Sdougm scf_instance_t *instance) 10586185db85Sdougm { 10596185db85Sdougm xmlNodePtr node; 10606185db85Sdougm scf_property_t *prop; 10616185db85Sdougm scf_value_t *value; 10626185db85Sdougm char *valuestr; 10636185db85Sdougm ssize_t vallen; 10646185db85Sdougm 10656185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 10666185db85Sdougm prop = scf_property_create(handle->handle); 10676185db85Sdougm value = scf_value_create(handle->handle); 10686185db85Sdougm valuestr = malloc(vallen); 106925a68471Sdougm 107025a68471Sdougm if (prop == NULL || value == NULL || vallen == 0 || 107125a68471Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) 107225a68471Sdougm goto out; 107325a68471Sdougm 107425a68471Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 107525a68471Sdougm goto out; 107625a68471Sdougm 107725a68471Sdougm /* Found the property so get the value */ 10786185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 10796185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 10806185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 10816185db85Sdougm NULL); 10826185db85Sdougm if (node != NULL) { 10837a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 10846185db85Sdougm (xmlChar *)valuestr); 10857a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", 10866185db85Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 10876185db85Sdougm } 10886185db85Sdougm } 10896185db85Sdougm } 109025a68471Sdougm out: 10916185db85Sdougm if (valuestr != NULL) 10926185db85Sdougm free(valuestr); 10936185db85Sdougm if (value != NULL) 10946185db85Sdougm scf_value_destroy(value); 10956185db85Sdougm if (prop != NULL) 10966185db85Sdougm scf_property_destroy(prop); 10976185db85Sdougm } 10986185db85Sdougm 10996185db85Sdougm 11006185db85Sdougm /* 1101da6c28aaSamw * sa_get_config(handle, root, doc, sahandle) 11026185db85Sdougm * 110325a68471Sdougm * Walk the SMF repository for /network/shares/group and find all the 11046185db85Sdougm * instances. These become group names. Then add the XML structure 11056185db85Sdougm * below the groups based on property groups and properties. 11066185db85Sdougm */ 11076185db85Sdougm int 11081d1813a7Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 11096185db85Sdougm { 11106185db85Sdougm int ret = SA_OK; 11116185db85Sdougm scf_instance_t *instance; 11126185db85Sdougm scf_iter_t *iter; 11136185db85Sdougm char buff[BUFSIZ * 2]; 11146185db85Sdougm 11156185db85Sdougm instance = scf_instance_create(handle->handle); 11166185db85Sdougm iter = scf_iter_create(handle->handle); 11171d1813a7Sdougm if (instance != NULL && iter != NULL) { 11186185db85Sdougm if ((ret = scf_iter_service_instances(iter, 11196185db85Sdougm handle->service)) == 0) { 11206185db85Sdougm while ((ret = scf_iter_next_instance(iter, 11216185db85Sdougm instance)) > 0) { 11226185db85Sdougm if (scf_instance_get_name(instance, buff, 11236185db85Sdougm sizeof (buff)) > 0) { 11246185db85Sdougm if (strcmp(buff, "default") == 0) 112525a68471Sdougm sa_extract_defaults(root, 112625a68471Sdougm handle, instance); 112725a68471Sdougm ret = sa_extract_group(root, handle, 112825a68471Sdougm instance, sahandle); 11296185db85Sdougm } 11306185db85Sdougm } 11316185db85Sdougm } 11326185db85Sdougm } 11331d1813a7Sdougm 113425a68471Sdougm /* Always cleanup these */ 11356185db85Sdougm if (instance != NULL) 11366185db85Sdougm scf_instance_destroy(instance); 11376185db85Sdougm if (iter != NULL) 11386185db85Sdougm scf_iter_destroy(iter); 11396185db85Sdougm return (ret); 11406185db85Sdougm } 11416185db85Sdougm 11426185db85Sdougm /* 11436185db85Sdougm * sa_get_instance(handle, instance) 11446185db85Sdougm * 114525a68471Sdougm * Get the instance of the group service. This is actually the 11466185db85Sdougm * specific group name. The instance is needed for all property and 11476185db85Sdougm * control operations. 11486185db85Sdougm */ 11496185db85Sdougm 11506185db85Sdougm int 11516185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 11526185db85Sdougm { 11536185db85Sdougm if (scf_service_get_instance(handle->service, instname, 11546185db85Sdougm handle->instance) != 0) { 11556185db85Sdougm return (SA_NO_SUCH_GROUP); 11566185db85Sdougm } 11576185db85Sdougm return (SA_OK); 11586185db85Sdougm } 11596185db85Sdougm 11606185db85Sdougm /* 11616185db85Sdougm * sa_create_instance(handle, instname) 11626185db85Sdougm * 11636185db85Sdougm * Create a new SMF service instance. There can only be one with a 11646185db85Sdougm * given name. 11656185db85Sdougm */ 11666185db85Sdougm 11676185db85Sdougm int 11686185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 11696185db85Sdougm { 11706185db85Sdougm int ret = SA_OK; 11716185db85Sdougm char instance[SA_GROUP_INST_LEN]; 11726185db85Sdougm if (scf_service_add_instance(handle->service, instname, 11736185db85Sdougm handle->instance) != 0) { 11746185db85Sdougm /* better error returns need to be added based on real error */ 11756185db85Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 11766185db85Sdougm ret = SA_NO_PERMISSION; 11776185db85Sdougm else 11786185db85Sdougm ret = SA_DUPLICATE_NAME; 11796185db85Sdougm } else { 11806185db85Sdougm /* have the service created, so enable it */ 11816185db85Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 11826185db85Sdougm SA_SVC_FMRI_BASE, instname); 11836185db85Sdougm (void) smf_enable_instance(instance, 0); 11846185db85Sdougm } 11856185db85Sdougm return (ret); 11866185db85Sdougm } 11876185db85Sdougm 11886185db85Sdougm /* 11896185db85Sdougm * sa_delete_instance(handle, instname) 11906185db85Sdougm * 11916185db85Sdougm * When a group goes away, we also remove the service instance. 11926185db85Sdougm */ 11936185db85Sdougm 11946185db85Sdougm int 11956185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 11966185db85Sdougm { 11976185db85Sdougm int ret; 11986185db85Sdougm 11996185db85Sdougm if (strcmp(instname, "default") == 0) { 12006185db85Sdougm ret = SA_NO_PERMISSION; 12016185db85Sdougm } else { 12026185db85Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 12036185db85Sdougm if (scf_instance_delete(handle->instance) != 0) 12046185db85Sdougm /* need better analysis */ 12056185db85Sdougm ret = SA_NO_PERMISSION; 12066185db85Sdougm } 12076185db85Sdougm } 12086185db85Sdougm return (ret); 12096185db85Sdougm } 12106185db85Sdougm 12116185db85Sdougm /* 12126185db85Sdougm * sa_create_pgroup(handle, pgroup) 12136185db85Sdougm * 12146185db85Sdougm * create a new property group 12156185db85Sdougm */ 12166185db85Sdougm 12176185db85Sdougm int 12186185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 12196185db85Sdougm { 12206185db85Sdougm int ret = SA_OK; 12215b6e0c46Sdougm int persist = 0; 12225b6e0c46Sdougm 12236185db85Sdougm /* 122425a68471Sdougm * Only create a handle if it doesn't exist. It is ok to exist 12256185db85Sdougm * since the pg handle will be set as a side effect. 12266185db85Sdougm */ 122725a68471Sdougm if (handle->pg == NULL) 12286185db85Sdougm handle->pg = scf_pg_create(handle->handle); 122925a68471Sdougm 12306185db85Sdougm /* 12315b6e0c46Sdougm * Special case for a non-persistent property group. This is 12325b6e0c46Sdougm * internal use only. 12335b6e0c46Sdougm */ 12345b6e0c46Sdougm if (*pgroup == '*') { 12355b6e0c46Sdougm persist = SCF_PG_FLAG_NONPERSISTENT; 12365b6e0c46Sdougm pgroup++; 12375b6e0c46Sdougm } 12385b6e0c46Sdougm 12395b6e0c46Sdougm /* 124025a68471Sdougm * If the pgroup exists, we are done. If it doesn't, then we 12416185db85Sdougm * need to actually add one to the service instance. 12426185db85Sdougm */ 12436185db85Sdougm if (scf_instance_get_pg(handle->instance, 12446185db85Sdougm pgroup, handle->pg) != 0) { 12455b6e0c46Sdougm 124625a68471Sdougm /* Doesn't exist so create one */ 12476185db85Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 12485b6e0c46Sdougm SCF_GROUP_APPLICATION, persist, handle->pg) != 0) { 12496185db85Sdougm switch (scf_error()) { 12506185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 12516185db85Sdougm ret = SA_NO_PERMISSION; 12526185db85Sdougm break; 12536185db85Sdougm default: 12546185db85Sdougm ret = SA_SYSTEM_ERR; 12556185db85Sdougm break; 12566185db85Sdougm } 12576185db85Sdougm } 12586185db85Sdougm } 12596185db85Sdougm return (ret); 12606185db85Sdougm } 12616185db85Sdougm 12626185db85Sdougm /* 12636185db85Sdougm * sa_delete_pgroup(handle, pgroup) 12646185db85Sdougm * 126525a68471Sdougm * Remove the property group from the current instance of the service, 12666185db85Sdougm * but only if it actually exists. 12676185db85Sdougm */ 12686185db85Sdougm 12696185db85Sdougm int 12706185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 12716185db85Sdougm { 12726185db85Sdougm int ret = SA_OK; 12736185db85Sdougm /* 127425a68471Sdougm * Only delete if it does exist. 12756185db85Sdougm */ 127625a68471Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 12776185db85Sdougm /* does exist so delete it */ 127825a68471Sdougm if (scf_pg_delete(handle->pg) != 0) 12796185db85Sdougm ret = SA_SYSTEM_ERR; 12806185db85Sdougm } else { 12816185db85Sdougm ret = SA_SYSTEM_ERR; 12826185db85Sdougm } 12836185db85Sdougm if (ret == SA_SYSTEM_ERR && 12846185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 12856185db85Sdougm ret = SA_NO_PERMISSION; 12866185db85Sdougm } 12876185db85Sdougm return (ret); 12886185db85Sdougm } 12896185db85Sdougm 12906185db85Sdougm /* 12916185db85Sdougm * sa_start_transaction(handle, pgroup) 12926185db85Sdougm * 12936185db85Sdougm * Start an SMF transaction so we can deal with properties. it would 12946185db85Sdougm * be nice to not have to expose this, but we have to in order to 12956185db85Sdougm * optimize. 12966185db85Sdougm * 12976185db85Sdougm * Basic model is to hold the transaction in the handle and allow 12986185db85Sdougm * property adds/deletes/updates to be added then close the 12996185db85Sdougm * transaction (or abort). There may eventually be a need to handle 13006185db85Sdougm * other types of transaction mechanisms but we don't do that now. 13016185db85Sdougm * 13026185db85Sdougm * An sa_start_transaction must be followed by either an 13036185db85Sdougm * sa_end_transaction or sa_abort_transaction before another 13046185db85Sdougm * sa_start_transaction can be done. 13056185db85Sdougm */ 13066185db85Sdougm 13076185db85Sdougm int 13086185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 13096185db85Sdougm { 13106185db85Sdougm int ret = SA_OK; 13116185db85Sdougm /* 131225a68471Sdougm * Lookup the property group and create it if it doesn't already 13136185db85Sdougm * exist. 13146185db85Sdougm */ 13155b6e0c46Sdougm if (handle == NULL) 13165b6e0c46Sdougm return (SA_CONFIG_ERR); 13175b6e0c46Sdougm 13186185db85Sdougm if (handle->scf_state == SCH_STATE_INIT) { 13196185db85Sdougm ret = sa_create_pgroup(handle, propgroup); 13206185db85Sdougm if (ret == SA_OK) { 13216185db85Sdougm handle->trans = scf_transaction_create(handle->handle); 13226185db85Sdougm if (handle->trans != NULL) { 132325a68471Sdougm if (scf_transaction_start(handle->trans, 132425a68471Sdougm handle->pg) != 0) { 13256185db85Sdougm ret = SA_SYSTEM_ERR; 13266185db85Sdougm } 13276185db85Sdougm if (ret != SA_OK) { 13286185db85Sdougm scf_transaction_destroy(handle->trans); 13296185db85Sdougm handle->trans = NULL; 13306185db85Sdougm } 13316185db85Sdougm } else { 13326185db85Sdougm ret = SA_SYSTEM_ERR; 13336185db85Sdougm } 13346185db85Sdougm } 13356185db85Sdougm } 13366185db85Sdougm if (ret == SA_SYSTEM_ERR && 13376185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 13386185db85Sdougm ret = SA_NO_PERMISSION; 13396185db85Sdougm } 13406185db85Sdougm return (ret); 13416185db85Sdougm } 13426185db85Sdougm 13435b6e0c46Sdougm 13446185db85Sdougm /* 13455b6e0c46Sdougm * sa_end_transaction(scfhandle, sahandle) 13466185db85Sdougm * 13476185db85Sdougm * Commit the changes that were added to the transaction in the 13486185db85Sdougm * handle. Do all necessary cleanup. 13496185db85Sdougm */ 13506185db85Sdougm 13516185db85Sdougm int 13525b6e0c46Sdougm sa_end_transaction(scfutilhandle_t *handle, sa_handle_impl_t sahandle) 13536185db85Sdougm { 13546185db85Sdougm int ret = SA_OK; 13556185db85Sdougm 13565b6e0c46Sdougm if (handle == NULL || handle->trans == NULL || sahandle == NULL) { 13576185db85Sdougm ret = SA_SYSTEM_ERR; 13586185db85Sdougm } else { 13596185db85Sdougm if (scf_transaction_commit(handle->trans) < 0) 13606185db85Sdougm ret = SA_SYSTEM_ERR; 13616185db85Sdougm scf_transaction_destroy_children(handle->trans); 13626185db85Sdougm scf_transaction_destroy(handle->trans); 13635b6e0c46Sdougm if (ret == SA_OK) 13645b6e0c46Sdougm set_transaction_tstamp(sahandle); 13656185db85Sdougm handle->trans = NULL; 13666185db85Sdougm } 13676185db85Sdougm return (ret); 13686185db85Sdougm } 13696185db85Sdougm 13706185db85Sdougm /* 13716185db85Sdougm * sa_abort_transaction(handle) 13726185db85Sdougm * 13736185db85Sdougm * Abort the changes that were added to the transaction in the 13746185db85Sdougm * handle. Do all necessary cleanup. 13756185db85Sdougm */ 13766185db85Sdougm 13776185db85Sdougm void 13786185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle) 13796185db85Sdougm { 13806185db85Sdougm if (handle->trans != NULL) { 13816185db85Sdougm scf_transaction_reset_all(handle->trans); 13826185db85Sdougm scf_transaction_destroy_children(handle->trans); 13836185db85Sdougm scf_transaction_destroy(handle->trans); 13846185db85Sdougm handle->trans = NULL; 13856185db85Sdougm } 13866185db85Sdougm } 13876185db85Sdougm 13886185db85Sdougm /* 13895b6e0c46Sdougm * set_transaction_tstamp(sahandle) 13905b6e0c46Sdougm * 13915b6e0c46Sdougm * After a successful transaction commit, update the timestamp of the 13925b6e0c46Sdougm * last transaction. This lets us detect changes from other processes. 13935b6e0c46Sdougm */ 13945b6e0c46Sdougm static void 13955b6e0c46Sdougm set_transaction_tstamp(sa_handle_impl_t sahandle) 13965b6e0c46Sdougm { 13975b6e0c46Sdougm char tstring[32]; 13985b6e0c46Sdougm struct timeval tv; 13995b6e0c46Sdougm scfutilhandle_t *scfhandle; 14005b6e0c46Sdougm 14015b6e0c46Sdougm if (sahandle == NULL || sahandle->scfhandle == NULL) 14025b6e0c46Sdougm return; 14035b6e0c46Sdougm 14045b6e0c46Sdougm scfhandle = sahandle->scfhandle; 14055b6e0c46Sdougm 14065b6e0c46Sdougm if (sa_get_instance(scfhandle, "default") != SA_OK) 14075b6e0c46Sdougm return; 14085b6e0c46Sdougm 14095b6e0c46Sdougm if (gettimeofday(&tv, NULL) != 0) 14105b6e0c46Sdougm return; 14115b6e0c46Sdougm 14125b6e0c46Sdougm if (sa_start_transaction(scfhandle, "*state") != SA_OK) 14135b6e0c46Sdougm return; 14145b6e0c46Sdougm 14155b6e0c46Sdougm sahandle->tstrans = TSTAMP((*(timestruc_t *)&tv)); 14165b6e0c46Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", sahandle->tstrans); 14175b6e0c46Sdougm if (sa_set_property(sahandle->scfhandle, "lastupdate", tstring) == 14185b6e0c46Sdougm SA_OK) { 14195b6e0c46Sdougm /* 14205b6e0c46Sdougm * While best if it succeeds, a failure doesn't cause 14215b6e0c46Sdougm * problems and we will ignore it anyway. 14225b6e0c46Sdougm */ 14235b6e0c46Sdougm (void) scf_transaction_commit(scfhandle->trans); 14245b6e0c46Sdougm scf_transaction_destroy_children(scfhandle->trans); 14255b6e0c46Sdougm scf_transaction_destroy(scfhandle->trans); 14265b6e0c46Sdougm } else { 14275b6e0c46Sdougm sa_abort_transaction(scfhandle); 14285b6e0c46Sdougm } 14295b6e0c46Sdougm } 14305b6e0c46Sdougm 14315b6e0c46Sdougm /* 14326185db85Sdougm * sa_set_property(handle, prop, value) 14336185db85Sdougm * 143425a68471Sdougm * Set a property transaction entry into the pending SMF transaction. 14356185db85Sdougm */ 14366185db85Sdougm 14376185db85Sdougm int 14386185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 14396185db85Sdougm { 14406185db85Sdougm int ret = SA_OK; 14416185db85Sdougm scf_value_t *value; 14426185db85Sdougm scf_transaction_entry_t *entry; 14436185db85Sdougm /* 144425a68471Sdougm * Properties must be set in transactions and don't take 14456185db85Sdougm * effect until the transaction has been ended/committed. 14466185db85Sdougm */ 14476185db85Sdougm value = scf_value_create(handle->handle); 14486185db85Sdougm entry = scf_entry_create(handle->handle); 14496185db85Sdougm if (value != NULL && entry != NULL) { 14506185db85Sdougm if (scf_transaction_property_change(handle->trans, entry, 145125a68471Sdougm propname, SCF_TYPE_ASTRING) == 0 || 14526185db85Sdougm scf_transaction_property_new(handle->trans, entry, 145325a68471Sdougm propname, SCF_TYPE_ASTRING) == 0) { 14546185db85Sdougm if (scf_value_set_astring(value, valstr) == 0) { 14556185db85Sdougm if (scf_entry_add_value(entry, value) != 0) { 14566185db85Sdougm ret = SA_SYSTEM_ERR; 14576185db85Sdougm scf_value_destroy(value); 14586185db85Sdougm } 145925a68471Sdougm /* The value is in the transaction */ 14606185db85Sdougm value = NULL; 14616185db85Sdougm } else { 146225a68471Sdougm /* Value couldn't be constructed */ 14636185db85Sdougm ret = SA_SYSTEM_ERR; 14646185db85Sdougm } 146525a68471Sdougm /* The entry is in the transaction */ 14666185db85Sdougm entry = NULL; 14676185db85Sdougm } else { 14686185db85Sdougm ret = SA_SYSTEM_ERR; 14696185db85Sdougm } 14706185db85Sdougm } else { 14716185db85Sdougm ret = SA_SYSTEM_ERR; 14726185db85Sdougm } 14736185db85Sdougm if (ret == SA_SYSTEM_ERR) { 14746185db85Sdougm switch (scf_error()) { 14756185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 14766185db85Sdougm ret = SA_NO_PERMISSION; 14776185db85Sdougm break; 14786185db85Sdougm } 14796185db85Sdougm } 14806185db85Sdougm /* 148125a68471Sdougm * Cleanup if there were any errors that didn't leave these 14826185db85Sdougm * values where they would be cleaned up later. 14836185db85Sdougm */ 14846185db85Sdougm if (value != NULL) 14856185db85Sdougm scf_value_destroy(value); 14866185db85Sdougm if (entry != NULL) 14876185db85Sdougm scf_entry_destroy(entry); 14886185db85Sdougm return (ret); 14896185db85Sdougm } 14906185db85Sdougm 14916185db85Sdougm /* 1492da6c28aaSamw * check_resource(share) 1493da6c28aaSamw * 1494da6c28aaSamw * Check to see if share has any persistent resources. We don't want 1495da6c28aaSamw * to save if they are all transient. 1496da6c28aaSamw */ 1497da6c28aaSamw static int 1498da6c28aaSamw check_resource(sa_share_t share) 1499da6c28aaSamw { 1500da6c28aaSamw sa_resource_t resource; 1501da6c28aaSamw int ret = B_FALSE; 1502da6c28aaSamw 1503da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1504da6c28aaSamw resource != NULL && ret == B_FALSE; 1505da6c28aaSamw resource = sa_get_next_resource(resource)) { 1506da6c28aaSamw char *type; 1507da6c28aaSamw type = sa_get_resource_attr(resource, "type"); 1508da6c28aaSamw if (type != NULL) { 1509da6c28aaSamw if (strcmp(type, "transient") != 0) { 1510da6c28aaSamw ret = B_TRUE; 1511da6c28aaSamw } 1512da6c28aaSamw sa_free_attr_string(type); 1513da6c28aaSamw } 1514da6c28aaSamw } 1515da6c28aaSamw return (ret); 1516da6c28aaSamw } 1517da6c28aaSamw 1518da6c28aaSamw /* 1519da6c28aaSamw * sa_set_resource_property(handle, prop, value) 1520da6c28aaSamw * 1521da6c28aaSamw * set a property transaction entry into the pending SMF 1522da6c28aaSamw * transaction. We don't want to include any transient resources 1523da6c28aaSamw */ 1524da6c28aaSamw 1525da6c28aaSamw static int 1526da6c28aaSamw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) 1527da6c28aaSamw { 1528da6c28aaSamw int ret = SA_OK; 1529da6c28aaSamw scf_value_t *value; 1530da6c28aaSamw scf_transaction_entry_t *entry; 1531da6c28aaSamw sa_resource_t resource; 1532da6c28aaSamw char *valstr; 1533da6c28aaSamw char *idstr; 1534da6c28aaSamw char *description; 1535da6c28aaSamw char *propstr = NULL; 1536da6c28aaSamw size_t strsize; 1537da6c28aaSamw 1538da6c28aaSamw /* don't bother if no persistent resources */ 1539da6c28aaSamw if (check_resource(share) == B_FALSE) 1540da6c28aaSamw return (ret); 1541da6c28aaSamw 1542da6c28aaSamw /* 1543da6c28aaSamw * properties must be set in transactions and don't take 1544da6c28aaSamw * effect until the transaction has been ended/committed. 1545da6c28aaSamw */ 1546da6c28aaSamw entry = scf_entry_create(handle->handle); 1547da6c28aaSamw if (entry == NULL) 1548da6c28aaSamw return (SA_SYSTEM_ERR); 1549da6c28aaSamw 1550da6c28aaSamw if (scf_transaction_property_change(handle->trans, entry, 1551da6c28aaSamw "resource", SCF_TYPE_ASTRING) != 0 && 1552da6c28aaSamw scf_transaction_property_new(handle->trans, entry, 1553da6c28aaSamw "resource", SCF_TYPE_ASTRING) != 0) { 1554da6c28aaSamw scf_entry_destroy(entry); 1555da6c28aaSamw return (SA_SYSTEM_ERR); 1556da6c28aaSamw 1557da6c28aaSamw } 1558da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1559da6c28aaSamw resource != NULL; 1560da6c28aaSamw resource = sa_get_next_resource(resource)) { 1561da6c28aaSamw value = scf_value_create(handle->handle); 1562da6c28aaSamw if (value == NULL) { 1563da6c28aaSamw ret = SA_NO_MEMORY; 1564da6c28aaSamw break; 1565da6c28aaSamw } 1566da6c28aaSamw /* Get size of complete string */ 1567da6c28aaSamw valstr = sa_get_resource_attr(resource, "name"); 1568da6c28aaSamw idstr = sa_get_resource_attr(resource, "id"); 1569da6c28aaSamw description = sa_get_resource_description(resource); 1570da6c28aaSamw strsize = (valstr != NULL) ? strlen(valstr) : 0; 1571da6c28aaSamw strsize += (idstr != NULL) ? strlen(idstr) : 0; 1572da6c28aaSamw strsize += (description != NULL) ? strlen(description) : 0; 1573da6c28aaSamw if (strsize > 0) { 1574da6c28aaSamw strsize += 3; /* add nul and ':' */ 1575da6c28aaSamw propstr = (char *)malloc(strsize); 1576da6c28aaSamw if (propstr == NULL) { 1577da6c28aaSamw scf_value_destroy(value); 1578da6c28aaSamw ret = SA_NO_MEMORY; 1579da6c28aaSamw goto err; 1580da6c28aaSamw } 1581da6c28aaSamw if (idstr == NULL) 1582da6c28aaSamw (void) snprintf(propstr, strsize, "%s", 1583da6c28aaSamw valstr ? valstr : ""); 1584da6c28aaSamw else 1585da6c28aaSamw (void) snprintf(propstr, strsize, "%s:%s:%s", 1586*fe1c642dSBill Krier idstr, valstr ? valstr : "", 1587da6c28aaSamw description ? description : ""); 1588da6c28aaSamw if (scf_value_set_astring(value, propstr) != 0) { 1589da6c28aaSamw ret = SA_SYSTEM_ERR; 1590da6c28aaSamw free(propstr); 1591da6c28aaSamw scf_value_destroy(value); 1592da6c28aaSamw break; 1593da6c28aaSamw } 1594da6c28aaSamw if (scf_entry_add_value(entry, value) != 0) { 1595da6c28aaSamw ret = SA_SYSTEM_ERR; 1596da6c28aaSamw free(propstr); 1597da6c28aaSamw scf_value_destroy(value); 1598da6c28aaSamw break; 1599da6c28aaSamw } 1600da6c28aaSamw /* the value is in the transaction */ 1601da6c28aaSamw value = NULL; 1602da6c28aaSamw free(propstr); 1603da6c28aaSamw } 1604da6c28aaSamw err: 1605*fe1c642dSBill Krier if (valstr != NULL) { 1606*fe1c642dSBill Krier sa_free_attr_string(valstr); 1607*fe1c642dSBill Krier valstr = NULL; 1608*fe1c642dSBill Krier } 1609*fe1c642dSBill Krier if (idstr != NULL) { 1610*fe1c642dSBill Krier sa_free_attr_string(idstr); 1611*fe1c642dSBill Krier idstr = NULL; 1612*fe1c642dSBill Krier } 1613*fe1c642dSBill Krier if (description != NULL) { 1614*fe1c642dSBill Krier sa_free_share_description(description); 1615*fe1c642dSBill Krier description = NULL; 1616*fe1c642dSBill Krier } 1617*fe1c642dSBill Krier } 1618*fe1c642dSBill Krier /* the entry is in the transaction */ 1619*fe1c642dSBill Krier entry = NULL; 1620*fe1c642dSBill Krier 1621da6c28aaSamw if (valstr != NULL) 1622da6c28aaSamw sa_free_attr_string(valstr); 1623da6c28aaSamw if (idstr != NULL) 1624da6c28aaSamw sa_free_attr_string(idstr); 1625da6c28aaSamw if (description != NULL) 1626da6c28aaSamw sa_free_share_description(description); 1627da6c28aaSamw 1628da6c28aaSamw if (ret == SA_SYSTEM_ERR) { 1629da6c28aaSamw switch (scf_error()) { 1630da6c28aaSamw case SCF_ERROR_PERMISSION_DENIED: 1631da6c28aaSamw ret = SA_NO_PERMISSION; 1632da6c28aaSamw break; 1633da6c28aaSamw } 1634da6c28aaSamw } 1635da6c28aaSamw /* 1636da6c28aaSamw * cleanup if there were any errors that didn't leave 1637da6c28aaSamw * these values where they would be cleaned up later. 1638da6c28aaSamw */ 1639da6c28aaSamw if (entry != NULL) 1640da6c28aaSamw scf_entry_destroy(entry); 1641da6c28aaSamw 1642da6c28aaSamw return (ret); 1643da6c28aaSamw } 1644da6c28aaSamw 1645da6c28aaSamw /* 16466185db85Sdougm * sa_commit_share(handle, group, share) 16476185db85Sdougm * 164825a68471Sdougm * Commit this share to the repository. 16496185db85Sdougm * properties are added if they exist but can be added later. 16506185db85Sdougm * Need to add to dfstab and sharetab, if appropriate. 16516185db85Sdougm */ 16526185db85Sdougm int 16536185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 16546185db85Sdougm { 16556185db85Sdougm int ret = SA_OK; 16566185db85Sdougm char *groupname; 16576185db85Sdougm char *name; 16586185db85Sdougm char *description; 16596185db85Sdougm char *sharename; 16606185db85Sdougm ssize_t proplen; 16616185db85Sdougm char *propstring; 16626185db85Sdougm 16636185db85Sdougm /* 166425a68471Sdougm * Don't commit in the zfs group. We do commit legacy 16656185db85Sdougm * (default) and all other groups/shares. ZFS is handled 16666185db85Sdougm * through the ZFS configuration rather than SMF. 16676185db85Sdougm */ 16686185db85Sdougm 16696185db85Sdougm groupname = sa_get_group_attr(group, "name"); 16706185db85Sdougm if (groupname != NULL) { 16716185db85Sdougm if (strcmp(groupname, "zfs") == 0) { 16726185db85Sdougm /* 167325a68471Sdougm * Adding to the ZFS group will result in the sharenfs 16746185db85Sdougm * property being set but we don't want to do anything 16756185db85Sdougm * SMF related at this point. 16766185db85Sdougm */ 16776185db85Sdougm sa_free_attr_string(groupname); 16786185db85Sdougm return (ret); 16796185db85Sdougm } 16806185db85Sdougm } 16816185db85Sdougm 16826185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 16836185db85Sdougm propstring = malloc(proplen); 16846185db85Sdougm if (propstring == NULL) 16856185db85Sdougm ret = SA_NO_MEMORY; 16866185db85Sdougm 16876185db85Sdougm if (groupname != NULL && ret == SA_OK) { 16886185db85Sdougm ret = sa_get_instance(handle, groupname); 16896185db85Sdougm sa_free_attr_string(groupname); 16906185db85Sdougm groupname = NULL; 16916185db85Sdougm sharename = sa_get_share_attr(share, "id"); 16926185db85Sdougm if (sharename == NULL) { 16936185db85Sdougm /* slipped by */ 16946185db85Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 16956185db85Sdougm generate_unique_sharename(shname); 16967a9d7716Sthurlow (void) xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 16976185db85Sdougm (xmlChar *)shname); 16986185db85Sdougm sharename = strdup(shname); 16996185db85Sdougm } 17006185db85Sdougm if (sharename != NULL) { 1701f345c0beSdougm sigset_t old, new; 17026185db85Sdougm /* 170325a68471Sdougm * Have a share name allocated so create a pgroup for 1704f345c0beSdougm * it. It may already exist, but that is OK. In order 1705f345c0beSdougm * to avoid creating a share pgroup that doesn't have 1706f345c0beSdougm * a path property, block signals around the critical 1707f345c0beSdougm * region of creating the share pgroup and props. 17086185db85Sdougm */ 1709f345c0beSdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 1710f345c0beSdougm (void) sigaddset(&new, SIGHUP); 1711f345c0beSdougm (void) sigaddset(&new, SIGINT); 1712f345c0beSdougm (void) sigaddset(&new, SIGQUIT); 1713f345c0beSdougm (void) sigaddset(&new, SIGTSTP); 1714f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 1715f345c0beSdougm 17166185db85Sdougm ret = sa_create_pgroup(handle, sharename); 17176185db85Sdougm if (ret == SA_OK) { 17186185db85Sdougm /* 171925a68471Sdougm * Now start the transaction for the 17206185db85Sdougm * properties that define this share. They may 17216185db85Sdougm * exist so attempt to update before create. 17226185db85Sdougm */ 17236185db85Sdougm ret = sa_start_transaction(handle, sharename); 17246185db85Sdougm } 17256185db85Sdougm if (ret == SA_OK) { 17266185db85Sdougm name = sa_get_share_attr(share, "path"); 17276185db85Sdougm if (name != NULL) { 172825a68471Sdougm /* 172925a68471Sdougm * There needs to be a path 173025a68471Sdougm * for a share to exist. 173125a68471Sdougm */ 173225a68471Sdougm ret = sa_set_property(handle, "path", 173325a68471Sdougm name); 17346185db85Sdougm sa_free_attr_string(name); 17356185db85Sdougm } else { 17366185db85Sdougm ret = SA_NO_MEMORY; 17376185db85Sdougm } 17386185db85Sdougm } 17396185db85Sdougm if (ret == SA_OK) { 1740da6c28aaSamw name = sa_get_share_attr(share, "drive-letter"); 1741da6c28aaSamw if (name != NULL) { 1742da6c28aaSamw /* A drive letter may exist for SMB */ 174325a68471Sdougm ret = sa_set_property(handle, 1744da6c28aaSamw "drive-letter", name); 1745da6c28aaSamw sa_free_attr_string(name); 17466185db85Sdougm } 17476185db85Sdougm } 17486185db85Sdougm if (ret == SA_OK) { 1749da6c28aaSamw name = sa_get_share_attr(share, "exclude"); 1750da6c28aaSamw if (name != NULL) { 1751da6c28aaSamw /* 1752da6c28aaSamw * In special cases need to 1753da6c28aaSamw * exclude proto enable. 1754da6c28aaSamw */ 1755da6c28aaSamw ret = sa_set_property(handle, 1756da6c28aaSamw "exclude", name); 1757da6c28aaSamw sa_free_attr_string(name); 1758da6c28aaSamw } 1759da6c28aaSamw } 1760da6c28aaSamw if (ret == SA_OK) { 1761da6c28aaSamw /* 1762da6c28aaSamw * If there are resource names, bundle them up 1763da6c28aaSamw * and save appropriately. 1764da6c28aaSamw */ 1765da6c28aaSamw ret = sa_set_resource_property(handle, share); 1766da6c28aaSamw } 1767da6c28aaSamw 1768da6c28aaSamw if (ret == SA_OK) { 17696185db85Sdougm description = sa_get_share_description(share); 17706185db85Sdougm if (description != NULL) { 177125a68471Sdougm ret = sa_set_property(handle, 177225a68471Sdougm "description", 17736185db85Sdougm description); 17746185db85Sdougm sa_free_share_description(description); 17756185db85Sdougm } 17766185db85Sdougm } 177725a68471Sdougm /* Make sure we cleanup the transaction */ 17786185db85Sdougm if (ret == SA_OK) { 17795b6e0c46Sdougm sa_handle_impl_t sahandle; 17805b6e0c46Sdougm sahandle = (sa_handle_impl_t) 17815b6e0c46Sdougm sa_find_group_handle(group); 17825b6e0c46Sdougm if (sahandle != NULL) 17835b6e0c46Sdougm ret = sa_end_transaction(handle, 17845b6e0c46Sdougm sahandle); 17855b6e0c46Sdougm else 17865b6e0c46Sdougm ret = SA_SYSTEM_ERR; 17876185db85Sdougm } else { 17886185db85Sdougm sa_abort_transaction(handle); 17896185db85Sdougm } 1790f345c0beSdougm 1791f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 1792f345c0beSdougm 17936185db85Sdougm free(sharename); 17946185db85Sdougm } 17956185db85Sdougm } 17966185db85Sdougm if (ret == SA_SYSTEM_ERR) { 17976185db85Sdougm int err = scf_error(); 17986185db85Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 17996185db85Sdougm ret = SA_NO_PERMISSION; 18006185db85Sdougm } 18016185db85Sdougm if (propstring != NULL) 18026185db85Sdougm free(propstring); 18036185db85Sdougm if (groupname != NULL) 18046185db85Sdougm sa_free_attr_string(groupname); 18056185db85Sdougm 18066185db85Sdougm return (ret); 18076185db85Sdougm } 18086185db85Sdougm 18096185db85Sdougm /* 1810da6c28aaSamw * remove_resources(handle, share, shareid) 1811da6c28aaSamw * 1812da6c28aaSamw * If the share has resources, remove all of them and their 1813da6c28aaSamw * optionsets. 1814da6c28aaSamw */ 1815da6c28aaSamw static int 1816da6c28aaSamw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid) 1817da6c28aaSamw { 1818da6c28aaSamw sa_resource_t resource; 1819da6c28aaSamw sa_optionset_t opt; 1820da6c28aaSamw char *proto; 1821da6c28aaSamw char *id; 1822da6c28aaSamw ssize_t proplen; 1823da6c28aaSamw char *propstring; 1824da6c28aaSamw int ret = SA_OK; 1825da6c28aaSamw 1826da6c28aaSamw proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1827da6c28aaSamw propstring = malloc(proplen); 1828da6c28aaSamw if (propstring == NULL) 1829da6c28aaSamw return (SA_NO_MEMORY); 1830da6c28aaSamw 1831da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1832da6c28aaSamw resource != NULL; resource = sa_get_next_resource(resource)) { 1833da6c28aaSamw id = sa_get_resource_attr(resource, "id"); 1834da6c28aaSamw if (id == NULL) 1835da6c28aaSamw continue; 1836da6c28aaSamw for (opt = sa_get_optionset(resource, NULL); 1837da6c28aaSamw opt != NULL; opt = sa_get_next_optionset(resource)) { 1838da6c28aaSamw proto = sa_get_optionset_attr(opt, "type"); 1839da6c28aaSamw if (proto != NULL) { 1840da6c28aaSamw (void) snprintf(propstring, proplen, 1841da6c28aaSamw "%s_%s_%s", shareid, proto, id); 1842da6c28aaSamw ret = sa_delete_pgroup(handle, propstring); 1843da6c28aaSamw sa_free_attr_string(proto); 1844da6c28aaSamw } 1845da6c28aaSamw } 1846da6c28aaSamw sa_free_attr_string(id); 1847da6c28aaSamw } 1848da6c28aaSamw free(propstring); 1849da6c28aaSamw return (ret); 1850da6c28aaSamw } 1851da6c28aaSamw 1852da6c28aaSamw /* 18536185db85Sdougm * sa_delete_share(handle, group, share) 18546185db85Sdougm * 185525a68471Sdougm * Remove the specified share from the group (and service instance). 18566185db85Sdougm */ 18576185db85Sdougm 18586185db85Sdougm int 18596185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 18606185db85Sdougm { 18616185db85Sdougm int ret = SA_OK; 18626185db85Sdougm char *groupname = NULL; 18636185db85Sdougm char *shareid = NULL; 18646185db85Sdougm sa_optionset_t opt; 18656185db85Sdougm sa_security_t sec; 18666185db85Sdougm ssize_t proplen; 18676185db85Sdougm char *propstring; 18686185db85Sdougm 18696185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 18706185db85Sdougm propstring = malloc(proplen); 18716185db85Sdougm if (propstring == NULL) 18726185db85Sdougm ret = SA_NO_MEMORY; 18736185db85Sdougm 18746185db85Sdougm if (ret == SA_OK) { 18756185db85Sdougm groupname = sa_get_group_attr(group, "name"); 18766185db85Sdougm shareid = sa_get_share_attr(share, "id"); 187725a68471Sdougm if (groupname == NULL || shareid == NULL) { 187825a68471Sdougm ret = SA_CONFIG_ERR; 187925a68471Sdougm goto out; 188025a68471Sdougm } 18816185db85Sdougm ret = sa_get_instance(handle, groupname); 18826185db85Sdougm if (ret == SA_OK) { 1883da6c28aaSamw /* If a share has resources, remove them */ 1884da6c28aaSamw ret = remove_resources(handle, share, shareid); 188525a68471Sdougm /* If a share has properties, remove them */ 18866185db85Sdougm ret = sa_delete_pgroup(handle, shareid); 188725a68471Sdougm for (opt = sa_get_optionset(share, NULL); 188825a68471Sdougm opt != NULL; 18896185db85Sdougm opt = sa_get_next_optionset(opt)) { 18906185db85Sdougm char *proto; 18916185db85Sdougm proto = sa_get_optionset_attr(opt, "type"); 18926185db85Sdougm if (proto != NULL) { 189325a68471Sdougm (void) snprintf(propstring, 189425a68471Sdougm proplen, "%s_%s", shareid, 189525a68471Sdougm proto); 189625a68471Sdougm ret = sa_delete_pgroup(handle, 189725a68471Sdougm propstring); 18986185db85Sdougm sa_free_attr_string(proto); 18996185db85Sdougm } else { 19006185db85Sdougm ret = SA_NO_MEMORY; 19016185db85Sdougm } 19026185db85Sdougm } 19036185db85Sdougm /* 190425a68471Sdougm * If a share has security/negotiable 19056185db85Sdougm * properties, remove them. 19066185db85Sdougm */ 190725a68471Sdougm for (sec = sa_get_security(share, NULL, NULL); 190825a68471Sdougm sec != NULL; 19096185db85Sdougm sec = sa_get_next_security(sec)) { 19106185db85Sdougm char *proto; 19116185db85Sdougm char *sectype; 19126185db85Sdougm proto = sa_get_security_attr(sec, "type"); 19136185db85Sdougm sectype = sa_get_security_attr(sec, "sectype"); 19146185db85Sdougm if (proto != NULL && sectype != NULL) { 191525a68471Sdougm (void) snprintf(propstring, proplen, 191625a68471Sdougm "%s_%s_%s", shareid, proto, 191725a68471Sdougm sectype); 191825a68471Sdougm ret = sa_delete_pgroup(handle, 191925a68471Sdougm propstring); 19206185db85Sdougm } else { 19216185db85Sdougm ret = SA_NO_MEMORY; 19226185db85Sdougm } 19236185db85Sdougm if (proto != NULL) 19246185db85Sdougm sa_free_attr_string(proto); 19256185db85Sdougm if (sectype != NULL) 19266185db85Sdougm sa_free_attr_string(sectype); 19276185db85Sdougm } 19286185db85Sdougm } 19296185db85Sdougm } 193025a68471Sdougm out: 19316185db85Sdougm if (groupname != NULL) 19326185db85Sdougm sa_free_attr_string(groupname); 19336185db85Sdougm if (shareid != NULL) 19346185db85Sdougm sa_free_attr_string(shareid); 19356185db85Sdougm if (propstring != NULL) 19366185db85Sdougm free(propstring); 19376185db85Sdougm 19386185db85Sdougm return (ret); 19396185db85Sdougm } 1940