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> 38da6c28aaSamw #include <ctype.h> 396185db85Sdougm #include <errno.h> 406185db85Sdougm #include <uuid/uuid.h> 416185db85Sdougm #include <sys/param.h> 42f345c0beSdougm #include <signal.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); 476185db85Sdougm 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 char **protolist; 1446185db85Sdougm int numprotos, i; 1456185db85Sdougm sa_group_t defgrp; 14625a68471Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 1476185db85Sdougm if (defgrp != NULL) { 14825a68471Sdougm numprotos = sa_get_protocols( 14925a68471Sdougm &protolist); 15025a68471Sdougm for (i = 0; i < numprotos; i++) 1516185db85Sdougm (void) sa_create_optionset(defgrp, 1526185db85Sdougm protolist[i]); 1536185db85Sdougm if (protolist != NULL) 1546185db85Sdougm free(protolist); 1556185db85Sdougm } 1566185db85Sdougm } 15725a68471Sdougm 1586185db85Sdougm return (handle); 1596185db85Sdougm 16025a68471Sdougm /* Error handling/unwinding */ 1616185db85Sdougm err: 1626185db85Sdougm (void) sa_scf_fini(handle); 1636185db85Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1646185db85Sdougm scf_strerror(scf_error())); 1656185db85Sdougm return (NULL); 1666185db85Sdougm } 1676185db85Sdougm 1686185db85Sdougm /* 1696185db85Sdougm * get_scf_limit(name) 1706185db85Sdougm * 1716185db85Sdougm * Since we use scf_limit a lot and do the same check and return the 1726185db85Sdougm * same value if it fails, implement as a function for code 1736185db85Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1746185db85Sdougm * (1024) so we have a reasonable default buffer size. 1756185db85Sdougm */ 1766185db85Sdougm static ssize_t 1776185db85Sdougm get_scf_limit(uint32_t name) 1786185db85Sdougm { 1796185db85Sdougm ssize_t vallen; 1806185db85Sdougm 1816185db85Sdougm vallen = scf_limit(name); 1826185db85Sdougm if (vallen == (ssize_t)-1) 1836185db85Sdougm vallen = MAXPATHLEN; 1846185db85Sdougm return (vallen); 1856185db85Sdougm } 1866185db85Sdougm 1876185db85Sdougm /* 1886185db85Sdougm * skip_property(name) 1896185db85Sdougm * 19025a68471Sdougm * Internal function to check to see if a property is an SMF magic 1916185db85Sdougm * property that needs to be skipped. 1926185db85Sdougm */ 1936185db85Sdougm static int 1946185db85Sdougm skip_property(char *name) 1956185db85Sdougm { 1966185db85Sdougm int i; 1976185db85Sdougm 1986185db85Sdougm for (i = 0; skip_props[i] != NULL; i++) 1996185db85Sdougm if (strcmp(name, skip_props[i]) == 0) 2006185db85Sdougm return (1); 2016185db85Sdougm return (0); 2026185db85Sdougm } 2036185db85Sdougm 2046185db85Sdougm /* 2056185db85Sdougm * generate_unique_sharename(sharename) 2066185db85Sdougm * 2076185db85Sdougm * Shares are represented in SMF as property groups. Due to share 2086185db85Sdougm * paths containing characters that are not allowed in SMF names and 2096185db85Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2106185db85Sdougm */ 2116185db85Sdougm 2126185db85Sdougm static void 2136185db85Sdougm generate_unique_sharename(char *sharename) 2146185db85Sdougm { 2156185db85Sdougm uuid_t uuid; 2166185db85Sdougm 2176185db85Sdougm uuid_generate(uuid); 2186185db85Sdougm (void) strcpy(sharename, "S-"); 2196185db85Sdougm uuid_unparse(uuid, sharename + 2); 2206185db85Sdougm } 2216185db85Sdougm 2226185db85Sdougm /* 2236185db85Sdougm * valid_protocol(proto) 2246185db85Sdougm * 22525a68471Sdougm * Check to see if the specified protocol is a valid one for the 2266185db85Sdougm * general sharemgr facility. We determine this by checking which 2276185db85Sdougm * plugin protocols were found. 2286185db85Sdougm */ 2296185db85Sdougm 2306185db85Sdougm static int 2316185db85Sdougm valid_protocol(char *proto) 2326185db85Sdougm { 2336185db85Sdougm struct sa_proto_plugin *plugin; 2346185db85Sdougm for (plugin = sap_proto_list; plugin != NULL; 2356185db85Sdougm plugin = plugin->plugin_next) 2366185db85Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2376185db85Sdougm return (1); 2386185db85Sdougm return (0); 2396185db85Sdougm } 2406185db85Sdougm 2416185db85Sdougm /* 2426185db85Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2436185db85Sdougm * 24425a68471Sdougm * Extract the name property group and create the specified type of 2456185db85Sdougm * node on the provided group. type will be optionset or security. 2466185db85Sdougm */ 2476185db85Sdougm 2486185db85Sdougm static int 2496185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2506185db85Sdougm scf_propertygroup_t *pg, 2516185db85Sdougm char *nodetype, char *proto, char *sectype) 2526185db85Sdougm { 2536185db85Sdougm xmlNodePtr node; 2546185db85Sdougm scf_iter_t *iter; 2556185db85Sdougm scf_property_t *prop; 2566185db85Sdougm scf_value_t *value; 2576185db85Sdougm char *name; 2586185db85Sdougm char *valuestr; 2596185db85Sdougm ssize_t vallen; 2606185db85Sdougm int ret = SA_OK; 2616185db85Sdougm 2626185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2636185db85Sdougm 2646185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 26525a68471Sdougm if (node == NULL) 26625a68471Sdougm return (ret); 26725a68471Sdougm 2686185db85Sdougm if (proto != NULL) 2696185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2706185db85Sdougm if (sectype != NULL) 2716185db85Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 2726185db85Sdougm /* 27325a68471Sdougm * Have node to work with so iterate over the properties 2746185db85Sdougm * in the pg and create option sub nodes. 2756185db85Sdougm */ 2766185db85Sdougm iter = scf_iter_create(handle->handle); 2776185db85Sdougm value = scf_value_create(handle->handle); 2786185db85Sdougm prop = scf_property_create(handle->handle); 2796185db85Sdougm name = malloc(scf_max_name_len); 2806185db85Sdougm valuestr = malloc(vallen); 2816185db85Sdougm /* 28225a68471Sdougm * Want to iterate through the properties and add them 2836185db85Sdougm * to the base optionset. 2846185db85Sdougm */ 28525a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || 28625a68471Sdougm valuestr == NULL || name == NULL) { 28725a68471Sdougm ret = SA_NO_MEMORY; 28825a68471Sdougm goto out; 28925a68471Sdougm } 2906185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 29125a68471Sdougm /* Now iterate the properties in the group */ 2926185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2936185db85Sdougm /* have a property */ 2946185db85Sdougm if (scf_property_get_name(prop, name, 2956185db85Sdougm scf_max_name_len) > 0) { 29625a68471Sdougm sa_property_t saprop; 29725a68471Sdougm /* Some properties are part of the framework */ 2986185db85Sdougm if (skip_property(name)) 2996185db85Sdougm continue; 30025a68471Sdougm if (scf_property_get_value(prop, value) != 0) 30125a68471Sdougm continue; 3026185db85Sdougm if (scf_value_get_astring(value, valuestr, 30325a68471Sdougm vallen) < 0) 30425a68471Sdougm continue; 30525a68471Sdougm saprop = sa_create_property(name, valuestr); 3066185db85Sdougm if (saprop != NULL) { 3076185db85Sdougm /* 30825a68471Sdougm * Since in SMF, don't 3096185db85Sdougm * recurse. Use xmlAddChild 3106185db85Sdougm * directly, instead. 3116185db85Sdougm */ 3126185db85Sdougm xmlAddChild(node, 3136185db85Sdougm (xmlNodePtr) saprop); 3146185db85Sdougm } 3156185db85Sdougm } 3166185db85Sdougm } 3176185db85Sdougm } 31825a68471Sdougm out: 3196185db85Sdougm /* cleanup to avoid memory leaks */ 3206185db85Sdougm if (value != NULL) 3216185db85Sdougm scf_value_destroy(value); 3226185db85Sdougm if (iter != NULL) 3236185db85Sdougm scf_iter_destroy(iter); 3246185db85Sdougm if (prop != NULL) 3256185db85Sdougm scf_property_destroy(prop); 3266185db85Sdougm if (name != NULL) 3276185db85Sdougm free(name); 3286185db85Sdougm if (valuestr != NULL) 3296185db85Sdougm free(valuestr); 33025a68471Sdougm 3316185db85Sdougm return (ret); 3326185db85Sdougm } 3336185db85Sdougm 3346185db85Sdougm /* 3356185db85Sdougm * sa_extract_attrs(root, handle, instance) 3366185db85Sdougm * 33725a68471Sdougm * Local function to extract the actual attributes/properties from the 3386185db85Sdougm * property group of the service instance. These are the well known 3396185db85Sdougm * attributes of "state" and "zfs". If additional attributes are 3406185db85Sdougm * added, they should be added here. 3416185db85Sdougm */ 3426185db85Sdougm 3436185db85Sdougm static void 3446185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3456185db85Sdougm scf_instance_t *instance) 3466185db85Sdougm { 3476185db85Sdougm scf_property_t *prop; 3486185db85Sdougm scf_value_t *value; 3496185db85Sdougm char *valuestr; 3506185db85Sdougm ssize_t vallen; 3516185db85Sdougm 3526185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3536185db85Sdougm prop = scf_property_create(handle->handle); 3546185db85Sdougm value = scf_value_create(handle->handle); 3556185db85Sdougm valuestr = malloc(vallen); 35625a68471Sdougm if (prop == NULL || value == NULL || valuestr == NULL || 35725a68471Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 35825a68471Sdougm goto out; 35925a68471Sdougm } 3606185db85Sdougm /* 36125a68471Sdougm * 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) { 36525a68471Sdougm /* Found the property so get the value */ 3666185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 36725a68471Sdougm if (scf_value_get_astring(value, valuestr, 36825a68471Sdougm vallen) >= 0) { 3696185db85Sdougm xmlSetProp(root, (xmlChar *)"state", 3706185db85Sdougm (xmlChar *)valuestr); 3716185db85Sdougm } 3726185db85Sdougm } 3736185db85Sdougm } 3746185db85Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 37525a68471Sdougm /* Found the property so get the value */ 3766185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 37725a68471Sdougm if (scf_value_get_astring(value, valuestr, 37825a68471Sdougm vallen) > 0) { 3796185db85Sdougm xmlSetProp(root, (xmlChar *)"zfs", 3806185db85Sdougm (xmlChar *)valuestr); 3816185db85Sdougm } 3826185db85Sdougm } 3836185db85Sdougm } 38425a68471Sdougm out: 3856185db85Sdougm if (valuestr != NULL) 3866185db85Sdougm free(valuestr); 3876185db85Sdougm if (value != NULL) 3886185db85Sdougm scf_value_destroy(value); 3896185db85Sdougm if (prop != NULL) 3906185db85Sdougm scf_property_destroy(prop); 3916185db85Sdougm } 3926185db85Sdougm 3936185db85Sdougm /* 39425a68471Sdougm * List of known share attributes. 3956185db85Sdougm */ 3966185db85Sdougm 3976185db85Sdougm static char *share_attr[] = { 3986185db85Sdougm "path", 3996185db85Sdougm "id", 400da6c28aaSamw "drive-letter", 401da6c28aaSamw "exclude", 4026185db85Sdougm NULL, 4036185db85Sdougm }; 4046185db85Sdougm 4056185db85Sdougm static int 4066185db85Sdougm is_share_attr(char *name) 4076185db85Sdougm { 4086185db85Sdougm int i; 4096185db85Sdougm for (i = 0; share_attr[i] != NULL; i++) 4106185db85Sdougm if (strcmp(name, share_attr[i]) == 0) 4116185db85Sdougm return (1); 4126185db85Sdougm return (0); 4136185db85Sdougm } 4146185db85Sdougm 4156185db85Sdougm /* 416da6c28aaSamw * _sa_make_resource(node, valuestr) 417da6c28aaSamw * 418da6c28aaSamw * Make a resource node on the share node. The valusestr will either 419da6c28aaSamw * be old format (SMF acceptable string) or new format (pretty much an 420da6c28aaSamw * arbitrary string with "nnn:" prefixing in order to persist 421da6c28aaSamw * mapping). The input valuestr will get modified in place. This is 422da6c28aaSamw * only used in SMF repository parsing. A possible third field will be 423da6c28aaSamw * a "description" string. 424da6c28aaSamw */ 425da6c28aaSamw 426da6c28aaSamw static void 427da6c28aaSamw _sa_make_resource(xmlNodePtr node, char *valuestr) 428da6c28aaSamw { 429da6c28aaSamw char *idx; 430da6c28aaSamw char *name; 431da6c28aaSamw char *description = NULL; 432da6c28aaSamw 433da6c28aaSamw idx = valuestr; 434da6c28aaSamw name = strchr(valuestr, ':'); 435da6c28aaSamw if (name == NULL) { 436da6c28aaSamw /* this is old form so give an index of "0" */ 437da6c28aaSamw idx = "0"; 438da6c28aaSamw name = valuestr; 439da6c28aaSamw } else { 440da6c28aaSamw /* NUL the ':' and move past it */ 441da6c28aaSamw *name++ = '\0'; 442da6c28aaSamw /* There could also be a description string */ 443da6c28aaSamw description = strchr(name, ':'); 444da6c28aaSamw if (description != NULL) 445da6c28aaSamw *description++ = '\0'; 446da6c28aaSamw } 447da6c28aaSamw node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL); 448da6c28aaSamw if (node != NULL) { 449da6c28aaSamw xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name); 450da6c28aaSamw xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx); 451da6c28aaSamw /* SMF values are always persistent */ 452da6c28aaSamw xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 453da6c28aaSamw if (description != NULL && strlen(description) > 0) { 454da6c28aaSamw (void) xmlNewChild(node, NULL, (xmlChar *)"description", 455da6c28aaSamw (xmlChar *)description); 456da6c28aaSamw } 457da6c28aaSamw } 458da6c28aaSamw } 459da6c28aaSamw 460da6c28aaSamw 461da6c28aaSamw /* 4626185db85Sdougm * sa_share_from_pgroup 4636185db85Sdougm * 46425a68471Sdougm * Extract the share definition from the share property group. We do 4656185db85Sdougm * some sanity checking to avoid bad data. 4666185db85Sdougm * 4676185db85Sdougm * Since this is only constructing the internal data structures, we 4686185db85Sdougm * don't use the sa_* functions most of the time. 4696185db85Sdougm */ 4706185db85Sdougm void 4716185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4726185db85Sdougm scf_propertygroup_t *pg, char *id) 4736185db85Sdougm { 4746185db85Sdougm xmlNodePtr node; 4756185db85Sdougm char *name; 4766185db85Sdougm scf_iter_t *iter; 4776185db85Sdougm scf_property_t *prop; 4786185db85Sdougm scf_value_t *value; 4796185db85Sdougm ssize_t vallen; 4806185db85Sdougm char *valuestr; 4816185db85Sdougm int ret = SA_OK; 482f345c0beSdougm int have_path = 0; 4836185db85Sdougm 4846185db85Sdougm /* 4856185db85Sdougm * While preliminary check (starts with 'S') passed before 4866185db85Sdougm * getting here. Need to make sure it is in ID syntax 4876185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 4886185db85Sdougm * pgroups. 4896185db85Sdougm */ 4906185db85Sdougm vallen = strlen(id); 4916185db85Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4926185db85Sdougm uuid_t uuid; 49325a68471Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, 49425a68471Sdougm SA_SHARE_PG_PREFIXLEN) != 0 || 4956185db85Sdougm uuid_parse(id + 2, uuid) < 0) 4966185db85Sdougm return; 4976185db85Sdougm } else { 4986185db85Sdougm return; 4996185db85Sdougm } 5006185db85Sdougm 5016185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 5026185db85Sdougm 5036185db85Sdougm iter = scf_iter_create(handle->handle); 5046185db85Sdougm value = scf_value_create(handle->handle); 5056185db85Sdougm prop = scf_property_create(handle->handle); 5066185db85Sdougm name = malloc(scf_max_name_len); 5076185db85Sdougm valuestr = malloc(vallen); 5086185db85Sdougm 5096185db85Sdougm /* 51025a68471Sdougm * Construct the share XML node. It is similar to sa_add_share 5116185db85Sdougm * but never changes the repository. Also, there won't be any 5126185db85Sdougm * ZFS or transient shares. Root will be the group it is 5136185db85Sdougm * associated with. 5146185db85Sdougm */ 5156185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 5166185db85Sdougm if (node != NULL) { 5176185db85Sdougm /* 51825a68471Sdougm * Make sure the UUID part of the property group is 5196185db85Sdougm * stored in the share "id" property. We use this 5206185db85Sdougm * later. 5216185db85Sdougm */ 5226185db85Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 5236185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 5246185db85Sdougm } 5256185db85Sdougm 52625a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 52725a68471Sdougm goto out; 52825a68471Sdougm 52925a68471Sdougm /* Iterate over the share pg properties */ 53025a68471Sdougm if (scf_iter_pg_properties(iter, pg) != 0) 53125a68471Sdougm goto out; 53225a68471Sdougm 5336185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 5346185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 53525a68471Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 5366185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 5376185db85Sdougm if (scf_value_get_astring(value, valuestr, 5386185db85Sdougm vallen) >= 0) { 5396185db85Sdougm ret = SA_OK; 5406185db85Sdougm } 541da6c28aaSamw } else if (strcmp(name, "resource") == 0) { 542da6c28aaSamw ret = SA_OK; 5436185db85Sdougm } 5446185db85Sdougm } 545da6c28aaSamw if (ret != SA_OK) 546da6c28aaSamw continue; 547f345c0beSdougm /* 54825a68471Sdougm * Check that we have the "path" property in 549f345c0beSdougm * name. The string in name will always be nul 550f345c0beSdougm * terminated if scf_property_get_name() 551f345c0beSdougm * succeeded. 552f345c0beSdougm */ 553f345c0beSdougm if (strcmp(name, "path") == 0) 554f345c0beSdougm have_path = 1; 5556185db85Sdougm if (is_share_attr(name)) { 5566185db85Sdougm /* 55725a68471Sdougm * If a share attr, then simple - 558da6c28aaSamw * usually path and id name 5596185db85Sdougm */ 5606185db85Sdougm xmlSetProp(node, (xmlChar *)name, 5616185db85Sdougm (xmlChar *)valuestr); 562da6c28aaSamw } else if (strcmp(name, "resource") == 0) { 563da6c28aaSamw /* 564da6c28aaSamw * Resource names handled differently since 565da6c28aaSamw * there can be multiple on each share. The 566da6c28aaSamw * "resource" id must be preserved since this 567da6c28aaSamw * will be used by some protocols in mapping 568da6c28aaSamw * "property spaces" to names and is always 569da6c28aaSamw * used to create SMF property groups specific 570da6c28aaSamw * to resources. CIFS needs this. The first 571da6c28aaSamw * value is present so add and then loop for 572da6c28aaSamw * any additional. Since this is new and 573da6c28aaSamw * previous values may exist, handle 574da6c28aaSamw * conversions. 575da6c28aaSamw */ 576da6c28aaSamw scf_iter_t *viter; 577da6c28aaSamw viter = scf_iter_create(handle->handle); 578da6c28aaSamw if (viter != NULL && 579da6c28aaSamw scf_iter_property_values(viter, prop) == 0) { 580da6c28aaSamw while (scf_iter_next_value(viter, value) > 0) { 581da6c28aaSamw /* Have a value so process it */ 582da6c28aaSamw if (scf_value_get_ustring(value, 583da6c28aaSamw valuestr, vallen) >= 0) { 584da6c28aaSamw /* have a ustring */ 585da6c28aaSamw _sa_make_resource(node, 586da6c28aaSamw valuestr); 587da6c28aaSamw } else if (scf_value_get_astring(value, 588da6c28aaSamw valuestr, vallen) >= 0) { 589da6c28aaSamw /* have an astring */ 590da6c28aaSamw _sa_make_resource(node, 591da6c28aaSamw valuestr); 592da6c28aaSamw } 593da6c28aaSamw } 594da6c28aaSamw scf_iter_destroy(viter); 595da6c28aaSamw } 5966185db85Sdougm } else { 5976185db85Sdougm if (strcmp(name, "description") == 0) { 59825a68471Sdougm /* We have a description node */ 5996185db85Sdougm xmlNodePtr desc; 6006185db85Sdougm desc = xmlNewChild(node, NULL, 60125a68471Sdougm (xmlChar *)"description", NULL); 6026185db85Sdougm if (desc != NULL) 6036185db85Sdougm xmlNodeSetContent(desc, 6046185db85Sdougm (xmlChar *)valuestr); 6056185db85Sdougm } 6066185db85Sdougm } 6076185db85Sdougm } 60825a68471Sdougm out: 609f345c0beSdougm /* 61025a68471Sdougm * A share without a path is broken so we want to not include 611f345c0beSdougm * these. They shouldn't happen but if you kill a sharemgr in 612f345c0beSdougm * the process of creating a share, it could happen. They 613f345c0beSdougm * should be harmless. It is also possible that another 614f345c0beSdougm * sharemgr is running and in the process of creating a share. 615f345c0beSdougm */ 616f345c0beSdougm if (have_path == 0 && node != NULL) { 617f345c0beSdougm xmlUnlinkNode(node); 618f345c0beSdougm xmlFreeNode(node); 619f345c0beSdougm } 6206185db85Sdougm if (name != NULL) 6216185db85Sdougm free(name); 6226185db85Sdougm if (valuestr != NULL) 6236185db85Sdougm free(valuestr); 6246185db85Sdougm if (value != NULL) 6256185db85Sdougm scf_value_destroy(value); 6266185db85Sdougm if (iter != NULL) 6276185db85Sdougm scf_iter_destroy(iter); 6286185db85Sdougm if (prop != NULL) 6296185db85Sdougm scf_property_destroy(prop); 6306185db85Sdougm } 6316185db85Sdougm 6326185db85Sdougm /* 6336185db85Sdougm * find_share_by_id(shareid) 6346185db85Sdougm * 6356185db85Sdougm * Search all shares in all groups until we find the share represented 6366185db85Sdougm * by "id". 6376185db85Sdougm */ 6386185db85Sdougm 6396185db85Sdougm static sa_share_t 640549ec3ffSdougm find_share_by_id(sa_handle_t handle, char *shareid) 6416185db85Sdougm { 6426185db85Sdougm sa_group_t group; 6436185db85Sdougm sa_share_t share = NULL; 6446185db85Sdougm char *id = NULL; 6456185db85Sdougm int done = 0; 6466185db85Sdougm 64725a68471Sdougm for (group = sa_get_group(handle, NULL); 64825a68471Sdougm group != NULL && !done; 6496185db85Sdougm group = sa_get_next_group(group)) { 65025a68471Sdougm for (share = sa_get_share(group, NULL); 65125a68471Sdougm share != NULL; 6526185db85Sdougm share = sa_get_next_share(share)) { 6536185db85Sdougm id = sa_get_share_attr(share, "id"); 6546185db85Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 6556185db85Sdougm sa_free_attr_string(id); 6566185db85Sdougm id = NULL; 6576185db85Sdougm done++; 6586185db85Sdougm break; 6596185db85Sdougm } 6606185db85Sdougm if (id != NULL) { 6616185db85Sdougm sa_free_attr_string(id); 6626185db85Sdougm id = NULL; 6636185db85Sdougm } 6646185db85Sdougm } 6656185db85Sdougm } 6666185db85Sdougm return (share); 6676185db85Sdougm } 6686185db85Sdougm 6696185db85Sdougm /* 670da6c28aaSamw * find_resource_by_index(share, index) 671da6c28aaSamw * 672da6c28aaSamw * Search the resource records on the share for the id index. 673da6c28aaSamw */ 674da6c28aaSamw static sa_resource_t 675da6c28aaSamw find_resource_by_index(sa_share_t share, char *index) 676da6c28aaSamw { 677da6c28aaSamw sa_resource_t resource; 678da6c28aaSamw sa_resource_t found = NULL; 679da6c28aaSamw char *id; 680da6c28aaSamw 681da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 682da6c28aaSamw resource != NULL && found == NULL; 683da6c28aaSamw resource = sa_get_next_resource(resource)) { 684da6c28aaSamw id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id"); 685da6c28aaSamw if (id != NULL) { 686da6c28aaSamw if (strcmp(id, index) == 0) { 687da6c28aaSamw /* found it so save in "found" */ 688da6c28aaSamw found = resource; 689da6c28aaSamw } 690da6c28aaSamw sa_free_attr_string(id); 691da6c28aaSamw } 692da6c28aaSamw } 693da6c28aaSamw return (found); 694da6c28aaSamw } 695da6c28aaSamw 696da6c28aaSamw /* 697da6c28aaSamw * sa_share_props_from_pgroup(root, handle, pg, id, sahandle) 6986185db85Sdougm * 69925a68471Sdougm * Extract share properties from the SMF property group. More sanity 7006185db85Sdougm * checks are done and the share object is created. We ignore some 7016185db85Sdougm * errors that could exist in the repository and only worry about 7026185db85Sdougm * property groups that validate in naming. 7036185db85Sdougm */ 7046185db85Sdougm 7056185db85Sdougm static int 7066185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 707549ec3ffSdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 7086185db85Sdougm { 7096185db85Sdougm xmlNodePtr node; 71025a68471Sdougm char *name = NULL; 71125a68471Sdougm scf_iter_t *iter = NULL; 71225a68471Sdougm scf_property_t *prop = NULL; 71325a68471Sdougm scf_value_t *value = NULL; 7146185db85Sdougm ssize_t vallen; 71525a68471Sdougm char *valuestr = NULL; 7166185db85Sdougm int ret = SA_OK; 7176185db85Sdougm char *sectype = NULL; 7186185db85Sdougm char *proto; 7196185db85Sdougm sa_share_t share; 72025a68471Sdougm uuid_t uuid; 7216185db85Sdougm 7226185db85Sdougm /* 7236185db85Sdougm * While preliminary check (starts with 'S') passed before 7246185db85Sdougm * getting here. Need to make sure it is in ID syntax 7256185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 7266185db85Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 7276185db85Sdougm * characters, it is likely one of the protocol/security 7286185db85Sdougm * versions. 7296185db85Sdougm */ 7306185db85Sdougm vallen = strlen(id); 73125a68471Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 73225a68471Sdougm /* 73325a68471Sdougm * It is ok to not have what we thought since someone might 73425a68471Sdougm * have added a name via SMF. 73525a68471Sdougm */ 73625a68471Sdougm return (ret); 73725a68471Sdougm } 7386185db85Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 7396185db85Sdougm proto = strchr(id, '_'); 7406185db85Sdougm if (proto == NULL) 7416185db85Sdougm return (ret); 7426185db85Sdougm *proto++ = '\0'; 7436185db85Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 7446185db85Sdougm return (ret); 7456185db85Sdougm /* 7466185db85Sdougm * probably a legal optionset so check a few more 7476185db85Sdougm * syntax points below. 7486185db85Sdougm */ 7496185db85Sdougm if (*proto == '\0') { 7506185db85Sdougm /* not a valid proto (null) */ 7516185db85Sdougm return (ret); 7526185db85Sdougm } 753da6c28aaSamw 7546185db85Sdougm sectype = strchr(proto, '_'); 7556185db85Sdougm if (sectype != NULL) 7566185db85Sdougm *sectype++ = '\0'; 7576185db85Sdougm if (!valid_protocol(proto)) 7586185db85Sdougm return (ret); 7596185db85Sdougm } 7606185db85Sdougm 7616185db85Sdougm /* 76225a68471Sdougm * To get here, we have a valid protocol and possibly a 7636185db85Sdougm * security. We now have to find the share that it is really 7646185db85Sdougm * associated with. The "id" portion of the pgroup name will 7656185db85Sdougm * match. 7666185db85Sdougm */ 7676185db85Sdougm 768549ec3ffSdougm share = find_share_by_id(sahandle, id); 7696185db85Sdougm if (share == NULL) 7706185db85Sdougm return (SA_BAD_PATH); 7716185db85Sdougm 7726185db85Sdougm root = (xmlNodePtr)share; 7736185db85Sdougm 7746185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 7756185db85Sdougm 77625a68471Sdougm if (sectype == NULL) 77725a68471Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 77825a68471Sdougm else { 779da6c28aaSamw if (isdigit((int)*sectype)) { 780da6c28aaSamw sa_resource_t resource; 781da6c28aaSamw /* 782da6c28aaSamw * If sectype[0] is a digit, then it is an index into 783da6c28aaSamw * the resource names. We need to find a resource 784da6c28aaSamw * record and then get the properties into an 785da6c28aaSamw * optionset. The optionset becomes the "node" and the 786da6c28aaSamw * rest is hung off of the share. 787da6c28aaSamw */ 788da6c28aaSamw resource = find_resource_by_index(share, sectype); 789da6c28aaSamw if (resource != NULL) { 790da6c28aaSamw node = xmlNewChild(resource, NULL, 791da6c28aaSamw (xmlChar *)"optionset", NULL); 792da6c28aaSamw } else { 793*55bf511dSas200622 /* This shouldn't happen. */ 794da6c28aaSamw ret = SA_SYSTEM_ERR; 795*55bf511dSas200622 goto out; 796da6c28aaSamw } 797da6c28aaSamw } else { 798da6c28aaSamw /* 799da6c28aaSamw * If not a digit, then it is a security type 800da6c28aaSamw * (alternate option space). Security types start with 801da6c28aaSamw * an alphabetic. 802da6c28aaSamw */ 803da6c28aaSamw node = xmlNewChild(root, NULL, (xmlChar *)"security", 804da6c28aaSamw NULL); 80525a68471Sdougm if (node != NULL) 80625a68471Sdougm xmlSetProp(node, (xmlChar *)"sectype", 80725a68471Sdougm (xmlChar *)sectype); 80825a68471Sdougm } 809da6c28aaSamw } 81025a68471Sdougm if (node == NULL) { 81125a68471Sdougm ret = SA_NO_MEMORY; 81225a68471Sdougm goto out; 81325a68471Sdougm } 81425a68471Sdougm 81525a68471Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 81625a68471Sdougm /* now find the properties */ 8176185db85Sdougm iter = scf_iter_create(handle->handle); 8186185db85Sdougm value = scf_value_create(handle->handle); 8196185db85Sdougm prop = scf_property_create(handle->handle); 8206185db85Sdougm name = malloc(scf_max_name_len); 8216185db85Sdougm valuestr = malloc(vallen); 8226185db85Sdougm 82325a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 82425a68471Sdougm goto out; 82525a68471Sdougm 826da6c28aaSamw /* iterate over the share pg properties */ 8276185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 8286185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 8296185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 8306185db85Sdougm if (scf_property_get_name(prop, name, 8316185db85Sdougm scf_max_name_len) > 0) { 8326185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 83325a68471Sdougm if (scf_value_get_astring(value, 83425a68471Sdougm valuestr, vallen) >= 0) { 8356185db85Sdougm ret = SA_OK; 8366185db85Sdougm } 8376185db85Sdougm } 8386185db85Sdougm } else { 8396185db85Sdougm ret = SA_SYSTEM_ERR; 8406185db85Sdougm } 8416185db85Sdougm if (ret == SA_OK) { 8426185db85Sdougm sa_property_t prop; 8436185db85Sdougm prop = sa_create_property(name, valuestr); 8446185db85Sdougm if (prop != NULL) 8456185db85Sdougm prop = (sa_property_t)xmlAddChild(node, 8466185db85Sdougm (xmlNodePtr)prop); 8476185db85Sdougm else 8486185db85Sdougm ret = SA_NO_MEMORY; 8496185db85Sdougm } 8506185db85Sdougm } 8516185db85Sdougm } else { 8526185db85Sdougm ret = SA_SYSTEM_ERR; 8536185db85Sdougm } 85425a68471Sdougm out: 8556185db85Sdougm if (iter != NULL) 8566185db85Sdougm scf_iter_destroy(iter); 8576185db85Sdougm if (value != NULL) 8586185db85Sdougm scf_value_destroy(value); 8596185db85Sdougm if (prop != NULL) 8606185db85Sdougm scf_property_destroy(prop); 8616185db85Sdougm if (name != NULL) 8626185db85Sdougm free(name); 8636185db85Sdougm if (valuestr != NULL) 8646185db85Sdougm free(valuestr); 8656185db85Sdougm return (ret); 8666185db85Sdougm } 8676185db85Sdougm 8686185db85Sdougm /* 8696185db85Sdougm * sa_extract_group(root, handle, instance) 8706185db85Sdougm * 87125a68471Sdougm * Get the config info for this instance of a group and create the XML 8726185db85Sdougm * subtree from it. 8736185db85Sdougm */ 8746185db85Sdougm 8756185db85Sdougm static int 8766185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 877549ec3ffSdougm scf_instance_t *instance, sa_handle_t sahandle) 8786185db85Sdougm { 8796185db85Sdougm char *buff; 8806185db85Sdougm xmlNodePtr node; 8816185db85Sdougm scf_iter_t *iter; 8826185db85Sdougm char *proto; 8836185db85Sdougm char *sectype; 8846185db85Sdougm int have_shares = 0; 8856185db85Sdougm int has_proto = 0; 8866185db85Sdougm int is_default = 0; 8876185db85Sdougm int ret = SA_OK; 8886185db85Sdougm int err; 8896185db85Sdougm 8906185db85Sdougm buff = malloc(scf_max_name_len); 89125a68471Sdougm if (buff == NULL) 89225a68471Sdougm return (SA_NO_MEMORY); 89325a68471Sdougm 8946185db85Sdougm iter = scf_iter_create(handle->handle); 89525a68471Sdougm if (iter == NULL) { 89625a68471Sdougm ret = SA_NO_MEMORY; 89725a68471Sdougm goto out; 89825a68471Sdougm } 89925a68471Sdougm 90025a68471Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 9016185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 90225a68471Sdougm if (node == NULL) { 90325a68471Sdougm ret = SA_NO_MEMORY; 90425a68471Sdougm goto out; 90525a68471Sdougm } 9066185db85Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 9076185db85Sdougm if (strcmp(buff, "default") == 0) 9086185db85Sdougm is_default++; 90925a68471Sdougm 9106185db85Sdougm sa_extract_attrs(node, handle, instance); 9116185db85Sdougm /* 9126185db85Sdougm * Iterate through all the property groups 9136185db85Sdougm * looking for those with security or 9146185db85Sdougm * optionset prefixes. The names of the 9156185db85Sdougm * matching pgroups are parsed to get the 9166185db85Sdougm * protocol, and for security, the sectype. 9176185db85Sdougm * Syntax is as follows: 9186185db85Sdougm * optionset | optionset_<proto> 9196185db85Sdougm * security_default | security_<proto>_<sectype> 9206185db85Sdougm * "operation" is handled by 9216185db85Sdougm * sa_extract_attrs(). 9226185db85Sdougm */ 92325a68471Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) { 92425a68471Sdougm ret = SA_NO_MEMORY; 92525a68471Sdougm goto out; 92625a68471Sdougm } 9276185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 92825a68471Sdougm /* Have a pgroup so sort it out */ 9296185db85Sdougm ret = scf_pg_get_name(handle->pg, buff, 9306185db85Sdougm scf_max_name_len); 9316185db85Sdougm if (ret > 0) { 9326185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 9336185db85Sdougm sa_share_from_pgroup(node, handle, 93425a68471Sdougm handle->pg, buff); 9356185db85Sdougm have_shares++; 9366185db85Sdougm } else if (strncmp(buff, "optionset", 9) == 9376185db85Sdougm 0) { 9386185db85Sdougm char *nodetype = "optionset"; 93925a68471Sdougm /* Have an optionset */ 9406185db85Sdougm sectype = NULL; 9416185db85Sdougm proto = strchr(buff, '_'); 9426185db85Sdougm if (proto != NULL) { 9436185db85Sdougm *proto++ = '\0'; 9446185db85Sdougm sectype = strchr(proto, '_'); 9456185db85Sdougm if (sectype != NULL) { 9466185db85Sdougm *sectype++ = '\0'; 9476185db85Sdougm nodetype = "security"; 9486185db85Sdougm } 9496185db85Sdougm } 9506185db85Sdougm ret = sa_extract_pgroup(node, handle, 95125a68471Sdougm handle->pg, nodetype, proto, 95225a68471Sdougm sectype); 9536185db85Sdougm has_proto++; 95425a68471Sdougm } else if (strncmp(buff, "security", 8) == 0) { 9556185db85Sdougm /* 95625a68471Sdougm * Have a security (note that 9576185db85Sdougm * this should change in the 9586185db85Sdougm * future) 9596185db85Sdougm */ 9606185db85Sdougm proto = strchr(buff, '_'); 9616185db85Sdougm sectype = NULL; 9626185db85Sdougm if (proto != NULL) { 9636185db85Sdougm *proto++ = '\0'; 9646185db85Sdougm sectype = strchr(proto, '_'); 9656185db85Sdougm if (sectype != NULL) 9666185db85Sdougm *sectype++ = '\0'; 96725a68471Sdougm if (strcmp(proto, "default") == 96825a68471Sdougm 0) 9696185db85Sdougm proto = NULL; 9706185db85Sdougm } 9716185db85Sdougm ret = sa_extract_pgroup(node, handle, 97225a68471Sdougm handle->pg, "security", proto, 9736185db85Sdougm sectype); 9746185db85Sdougm has_proto++; 9756185db85Sdougm } 97625a68471Sdougm /* Ignore everything else */ 9776185db85Sdougm } 9786185db85Sdougm } 9796185db85Sdougm /* 9806185db85Sdougm * Make sure we have a valid default group. 9816185db85Sdougm * On first boot, default won't have any 9826185db85Sdougm * protocols defined and won't be enabled (but 9836185db85Sdougm * should be). 9846185db85Sdougm */ 9856185db85Sdougm if (is_default) { 9866185db85Sdougm char *state = sa_get_group_attr((sa_group_t)node, 9876185db85Sdougm "state"); 9886185db85Sdougm char **protos; 9896185db85Sdougm int numprotos; 9906185db85Sdougm int i; 9916185db85Sdougm 9926185db85Sdougm if (state == NULL) { 9936185db85Sdougm /* set attribute to enabled */ 9946185db85Sdougm (void) sa_set_group_attr((sa_group_t)node, 99525a68471Sdougm "state", "enabled"); 99625a68471Sdougm /* We can assume no protocols */ 9976185db85Sdougm numprotos = sa_get_protocols(&protos); 9986185db85Sdougm for (i = 0; i < numprotos; i++) 99925a68471Sdougm (void) sa_create_optionset( 100025a68471Sdougm (sa_group_t)node, protos[i]); 10016185db85Sdougm if (numprotos > 0) 10026185db85Sdougm free(protos); 10036185db85Sdougm } else { 10046185db85Sdougm sa_free_attr_string(state); 10056185db85Sdougm } 10066185db85Sdougm } 100725a68471Sdougm /* Do a second pass if shares were found */ 100825a68471Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 10096185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 10106185db85Sdougm /* 101125a68471Sdougm * Have a pgroup so see if it is a 10126185db85Sdougm * share optionset 10136185db85Sdougm */ 10146185db85Sdougm err = scf_pg_get_name(handle->pg, buff, 10156185db85Sdougm scf_max_name_len); 101625a68471Sdougm if (err <= 0) 101725a68471Sdougm continue; 10186185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 10196185db85Sdougm ret = sa_share_props_from_pgroup(node, 102025a68471Sdougm handle, handle->pg, buff, 102125a68471Sdougm sahandle); 10226185db85Sdougm } 10236185db85Sdougm } 10246185db85Sdougm } 10256185db85Sdougm } 102625a68471Sdougm out: 10276185db85Sdougm if (iter != NULL) 10286185db85Sdougm scf_iter_destroy(iter); 10296185db85Sdougm if (buff != NULL) 10306185db85Sdougm free(buff); 10316185db85Sdougm return (ret); 10326185db85Sdougm } 10336185db85Sdougm 10346185db85Sdougm /* 10356185db85Sdougm * sa_extract_defaults(root, handle, instance) 10366185db85Sdougm * 103725a68471Sdougm * Local function to find the default properties that live in the 1038da6c28aaSamw * default instance's "operation" property group. 10396185db85Sdougm */ 10406185db85Sdougm 10416185db85Sdougm static void 10426185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 10436185db85Sdougm scf_instance_t *instance) 10446185db85Sdougm { 10456185db85Sdougm xmlNodePtr node; 10466185db85Sdougm scf_property_t *prop; 10476185db85Sdougm scf_value_t *value; 10486185db85Sdougm char *valuestr; 10496185db85Sdougm ssize_t vallen; 10506185db85Sdougm 10516185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 10526185db85Sdougm prop = scf_property_create(handle->handle); 10536185db85Sdougm value = scf_value_create(handle->handle); 10546185db85Sdougm valuestr = malloc(vallen); 105525a68471Sdougm 105625a68471Sdougm if (prop == NULL || value == NULL || vallen == 0 || 105725a68471Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) 105825a68471Sdougm goto out; 105925a68471Sdougm 106025a68471Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 106125a68471Sdougm goto out; 106225a68471Sdougm 106325a68471Sdougm /* Found the property so get the value */ 10646185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 10656185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 10666185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 10676185db85Sdougm NULL); 10686185db85Sdougm if (node != NULL) { 10696185db85Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 10706185db85Sdougm (xmlChar *)valuestr); 10716185db85Sdougm xmlSetProp(node, (xmlChar *)"path", 10726185db85Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 10736185db85Sdougm } 10746185db85Sdougm } 10756185db85Sdougm } 107625a68471Sdougm out: 10776185db85Sdougm if (valuestr != NULL) 10786185db85Sdougm free(valuestr); 10796185db85Sdougm if (value != NULL) 10806185db85Sdougm scf_value_destroy(value); 10816185db85Sdougm if (prop != NULL) 10826185db85Sdougm scf_property_destroy(prop); 10836185db85Sdougm } 10846185db85Sdougm 10856185db85Sdougm 10866185db85Sdougm /* 1087da6c28aaSamw * sa_get_config(handle, root, doc, sahandle) 10886185db85Sdougm * 108925a68471Sdougm * Walk the SMF repository for /network/shares/group and find all the 10906185db85Sdougm * instances. These become group names. Then add the XML structure 10916185db85Sdougm * below the groups based on property groups and properties. 10926185db85Sdougm */ 10936185db85Sdougm int 10941d1813a7Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 10956185db85Sdougm { 10966185db85Sdougm int ret = SA_OK; 10976185db85Sdougm scf_instance_t *instance; 10986185db85Sdougm scf_iter_t *iter; 10996185db85Sdougm char buff[BUFSIZ * 2]; 11006185db85Sdougm 11016185db85Sdougm instance = scf_instance_create(handle->handle); 11026185db85Sdougm iter = scf_iter_create(handle->handle); 11031d1813a7Sdougm if (instance != NULL && iter != NULL) { 11046185db85Sdougm if ((ret = scf_iter_service_instances(iter, 11056185db85Sdougm handle->service)) == 0) { 11066185db85Sdougm while ((ret = scf_iter_next_instance(iter, 11076185db85Sdougm instance)) > 0) { 11086185db85Sdougm if (scf_instance_get_name(instance, buff, 11096185db85Sdougm sizeof (buff)) > 0) { 11106185db85Sdougm if (strcmp(buff, "default") == 0) 111125a68471Sdougm sa_extract_defaults(root, 111225a68471Sdougm handle, instance); 111325a68471Sdougm ret = sa_extract_group(root, handle, 111425a68471Sdougm instance, sahandle); 11156185db85Sdougm } 11166185db85Sdougm } 11176185db85Sdougm } 11186185db85Sdougm } 11191d1813a7Sdougm 112025a68471Sdougm /* Always cleanup these */ 11216185db85Sdougm if (instance != NULL) 11226185db85Sdougm scf_instance_destroy(instance); 11236185db85Sdougm if (iter != NULL) 11246185db85Sdougm scf_iter_destroy(iter); 11256185db85Sdougm return (ret); 11266185db85Sdougm } 11276185db85Sdougm 11286185db85Sdougm /* 11296185db85Sdougm * sa_get_instance(handle, instance) 11306185db85Sdougm * 113125a68471Sdougm * Get the instance of the group service. This is actually the 11326185db85Sdougm * specific group name. The instance is needed for all property and 11336185db85Sdougm * control operations. 11346185db85Sdougm */ 11356185db85Sdougm 11366185db85Sdougm int 11376185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 11386185db85Sdougm { 11396185db85Sdougm if (scf_service_get_instance(handle->service, instname, 11406185db85Sdougm handle->instance) != 0) { 11416185db85Sdougm return (SA_NO_SUCH_GROUP); 11426185db85Sdougm } 11436185db85Sdougm return (SA_OK); 11446185db85Sdougm } 11456185db85Sdougm 11466185db85Sdougm /* 11476185db85Sdougm * sa_create_instance(handle, instname) 11486185db85Sdougm * 11496185db85Sdougm * Create a new SMF service instance. There can only be one with a 11506185db85Sdougm * given name. 11516185db85Sdougm */ 11526185db85Sdougm 11536185db85Sdougm int 11546185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 11556185db85Sdougm { 11566185db85Sdougm int ret = SA_OK; 11576185db85Sdougm char instance[SA_GROUP_INST_LEN]; 11586185db85Sdougm if (scf_service_add_instance(handle->service, instname, 11596185db85Sdougm handle->instance) != 0) { 11606185db85Sdougm /* better error returns need to be added based on real error */ 11616185db85Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 11626185db85Sdougm ret = SA_NO_PERMISSION; 11636185db85Sdougm else 11646185db85Sdougm ret = SA_DUPLICATE_NAME; 11656185db85Sdougm } else { 11666185db85Sdougm /* have the service created, so enable it */ 11676185db85Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 11686185db85Sdougm SA_SVC_FMRI_BASE, instname); 11696185db85Sdougm (void) smf_enable_instance(instance, 0); 11706185db85Sdougm } 11716185db85Sdougm return (ret); 11726185db85Sdougm } 11736185db85Sdougm 11746185db85Sdougm /* 11756185db85Sdougm * sa_delete_instance(handle, instname) 11766185db85Sdougm * 11776185db85Sdougm * When a group goes away, we also remove the service instance. 11786185db85Sdougm */ 11796185db85Sdougm 11806185db85Sdougm int 11816185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 11826185db85Sdougm { 11836185db85Sdougm int ret; 11846185db85Sdougm 11856185db85Sdougm if (strcmp(instname, "default") == 0) { 11866185db85Sdougm ret = SA_NO_PERMISSION; 11876185db85Sdougm } else { 11886185db85Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 11896185db85Sdougm if (scf_instance_delete(handle->instance) != 0) 11906185db85Sdougm /* need better analysis */ 11916185db85Sdougm ret = SA_NO_PERMISSION; 11926185db85Sdougm } 11936185db85Sdougm } 11946185db85Sdougm return (ret); 11956185db85Sdougm } 11966185db85Sdougm 11976185db85Sdougm /* 11986185db85Sdougm * sa_create_pgroup(handle, pgroup) 11996185db85Sdougm * 12006185db85Sdougm * create a new property group 12016185db85Sdougm */ 12026185db85Sdougm 12036185db85Sdougm int 12046185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 12056185db85Sdougm { 12066185db85Sdougm int ret = SA_OK; 12076185db85Sdougm /* 120825a68471Sdougm * Only create a handle if it doesn't exist. It is ok to exist 12096185db85Sdougm * since the pg handle will be set as a side effect. 12106185db85Sdougm */ 121125a68471Sdougm if (handle->pg == NULL) 12126185db85Sdougm handle->pg = scf_pg_create(handle->handle); 121325a68471Sdougm 12146185db85Sdougm /* 121525a68471Sdougm * If the pgroup exists, we are done. If it doesn't, then we 12166185db85Sdougm * need to actually add one to the service instance. 12176185db85Sdougm */ 12186185db85Sdougm if (scf_instance_get_pg(handle->instance, 12196185db85Sdougm pgroup, handle->pg) != 0) { 122025a68471Sdougm /* Doesn't exist so create one */ 12216185db85Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 122225a68471Sdougm SCF_GROUP_APPLICATION, 0, handle->pg) != 0) { 12236185db85Sdougm switch (scf_error()) { 12246185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 12256185db85Sdougm ret = SA_NO_PERMISSION; 12266185db85Sdougm break; 12276185db85Sdougm default: 12286185db85Sdougm ret = SA_SYSTEM_ERR; 12296185db85Sdougm break; 12306185db85Sdougm } 12316185db85Sdougm } 12326185db85Sdougm } 12336185db85Sdougm return (ret); 12346185db85Sdougm } 12356185db85Sdougm 12366185db85Sdougm /* 12376185db85Sdougm * sa_delete_pgroup(handle, pgroup) 12386185db85Sdougm * 123925a68471Sdougm * Remove the property group from the current instance of the service, 12406185db85Sdougm * but only if it actually exists. 12416185db85Sdougm */ 12426185db85Sdougm 12436185db85Sdougm int 12446185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 12456185db85Sdougm { 12466185db85Sdougm int ret = SA_OK; 12476185db85Sdougm /* 124825a68471Sdougm * Only delete if it does exist. 12496185db85Sdougm */ 125025a68471Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 12516185db85Sdougm /* does exist so delete it */ 125225a68471Sdougm if (scf_pg_delete(handle->pg) != 0) 12536185db85Sdougm ret = SA_SYSTEM_ERR; 12546185db85Sdougm } else { 12556185db85Sdougm ret = SA_SYSTEM_ERR; 12566185db85Sdougm } 12576185db85Sdougm if (ret == SA_SYSTEM_ERR && 12586185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 12596185db85Sdougm ret = SA_NO_PERMISSION; 12606185db85Sdougm } 12616185db85Sdougm return (ret); 12626185db85Sdougm } 12636185db85Sdougm 12646185db85Sdougm /* 12656185db85Sdougm * sa_start_transaction(handle, pgroup) 12666185db85Sdougm * 12676185db85Sdougm * Start an SMF transaction so we can deal with properties. it would 12686185db85Sdougm * be nice to not have to expose this, but we have to in order to 12696185db85Sdougm * optimize. 12706185db85Sdougm * 12716185db85Sdougm * Basic model is to hold the transaction in the handle and allow 12726185db85Sdougm * property adds/deletes/updates to be added then close the 12736185db85Sdougm * transaction (or abort). There may eventually be a need to handle 12746185db85Sdougm * other types of transaction mechanisms but we don't do that now. 12756185db85Sdougm * 12766185db85Sdougm * An sa_start_transaction must be followed by either an 12776185db85Sdougm * sa_end_transaction or sa_abort_transaction before another 12786185db85Sdougm * sa_start_transaction can be done. 12796185db85Sdougm */ 12806185db85Sdougm 12816185db85Sdougm int 12826185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 12836185db85Sdougm { 12846185db85Sdougm int ret = SA_OK; 12856185db85Sdougm /* 128625a68471Sdougm * Lookup the property group and create it if it doesn't already 12876185db85Sdougm * exist. 12886185db85Sdougm */ 12896185db85Sdougm if (handle->scf_state == SCH_STATE_INIT) { 12906185db85Sdougm ret = sa_create_pgroup(handle, propgroup); 12916185db85Sdougm if (ret == SA_OK) { 12926185db85Sdougm handle->trans = scf_transaction_create(handle->handle); 12936185db85Sdougm if (handle->trans != NULL) { 129425a68471Sdougm if (scf_transaction_start(handle->trans, 129525a68471Sdougm handle->pg) != 0) { 12966185db85Sdougm ret = SA_SYSTEM_ERR; 12976185db85Sdougm } 12986185db85Sdougm if (ret != SA_OK) { 12996185db85Sdougm scf_transaction_destroy(handle->trans); 13006185db85Sdougm handle->trans = NULL; 13016185db85Sdougm } 13026185db85Sdougm } else { 13036185db85Sdougm ret = SA_SYSTEM_ERR; 13046185db85Sdougm } 13056185db85Sdougm } 13066185db85Sdougm } 13076185db85Sdougm if (ret == SA_SYSTEM_ERR && 13086185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 13096185db85Sdougm ret = SA_NO_PERMISSION; 13106185db85Sdougm } 13116185db85Sdougm return (ret); 13126185db85Sdougm } 13136185db85Sdougm 13146185db85Sdougm /* 13156185db85Sdougm * sa_end_transaction(handle) 13166185db85Sdougm * 13176185db85Sdougm * Commit the changes that were added to the transaction in the 13186185db85Sdougm * handle. Do all necessary cleanup. 13196185db85Sdougm */ 13206185db85Sdougm 13216185db85Sdougm int 13226185db85Sdougm sa_end_transaction(scfutilhandle_t *handle) 13236185db85Sdougm { 13246185db85Sdougm int ret = SA_OK; 13256185db85Sdougm 13266185db85Sdougm if (handle->trans == NULL) { 13276185db85Sdougm ret = SA_SYSTEM_ERR; 13286185db85Sdougm } else { 13296185db85Sdougm if (scf_transaction_commit(handle->trans) < 0) 13306185db85Sdougm ret = SA_SYSTEM_ERR; 13316185db85Sdougm scf_transaction_destroy_children(handle->trans); 13326185db85Sdougm scf_transaction_destroy(handle->trans); 13336185db85Sdougm handle->trans = NULL; 13346185db85Sdougm } 13356185db85Sdougm return (ret); 13366185db85Sdougm } 13376185db85Sdougm 13386185db85Sdougm /* 13396185db85Sdougm * sa_abort_transaction(handle) 13406185db85Sdougm * 13416185db85Sdougm * Abort the changes that were added to the transaction in the 13426185db85Sdougm * handle. Do all necessary cleanup. 13436185db85Sdougm */ 13446185db85Sdougm 13456185db85Sdougm void 13466185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle) 13476185db85Sdougm { 13486185db85Sdougm if (handle->trans != NULL) { 13496185db85Sdougm scf_transaction_reset_all(handle->trans); 13506185db85Sdougm scf_transaction_destroy_children(handle->trans); 13516185db85Sdougm scf_transaction_destroy(handle->trans); 13526185db85Sdougm handle->trans = NULL; 13536185db85Sdougm } 13546185db85Sdougm } 13556185db85Sdougm 13566185db85Sdougm /* 13576185db85Sdougm * sa_set_property(handle, prop, value) 13586185db85Sdougm * 135925a68471Sdougm * Set a property transaction entry into the pending SMF transaction. 13606185db85Sdougm */ 13616185db85Sdougm 13626185db85Sdougm int 13636185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 13646185db85Sdougm { 13656185db85Sdougm int ret = SA_OK; 13666185db85Sdougm scf_value_t *value; 13676185db85Sdougm scf_transaction_entry_t *entry; 13686185db85Sdougm /* 136925a68471Sdougm * Properties must be set in transactions and don't take 13706185db85Sdougm * effect until the transaction has been ended/committed. 13716185db85Sdougm */ 13726185db85Sdougm value = scf_value_create(handle->handle); 13736185db85Sdougm entry = scf_entry_create(handle->handle); 13746185db85Sdougm if (value != NULL && entry != NULL) { 13756185db85Sdougm if (scf_transaction_property_change(handle->trans, entry, 137625a68471Sdougm propname, SCF_TYPE_ASTRING) == 0 || 13776185db85Sdougm scf_transaction_property_new(handle->trans, entry, 137825a68471Sdougm propname, SCF_TYPE_ASTRING) == 0) { 13796185db85Sdougm if (scf_value_set_astring(value, valstr) == 0) { 13806185db85Sdougm if (scf_entry_add_value(entry, value) != 0) { 13816185db85Sdougm ret = SA_SYSTEM_ERR; 13826185db85Sdougm scf_value_destroy(value); 13836185db85Sdougm } 138425a68471Sdougm /* The value is in the transaction */ 13856185db85Sdougm value = NULL; 13866185db85Sdougm } else { 138725a68471Sdougm /* Value couldn't be constructed */ 13886185db85Sdougm ret = SA_SYSTEM_ERR; 13896185db85Sdougm } 139025a68471Sdougm /* The entry is in the transaction */ 13916185db85Sdougm entry = NULL; 13926185db85Sdougm } else { 13936185db85Sdougm ret = SA_SYSTEM_ERR; 13946185db85Sdougm } 13956185db85Sdougm } else { 13966185db85Sdougm ret = SA_SYSTEM_ERR; 13976185db85Sdougm } 13986185db85Sdougm if (ret == SA_SYSTEM_ERR) { 13996185db85Sdougm switch (scf_error()) { 14006185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 14016185db85Sdougm ret = SA_NO_PERMISSION; 14026185db85Sdougm break; 14036185db85Sdougm } 14046185db85Sdougm } 14056185db85Sdougm /* 140625a68471Sdougm * Cleanup if there were any errors that didn't leave these 14076185db85Sdougm * values where they would be cleaned up later. 14086185db85Sdougm */ 14096185db85Sdougm if (value != NULL) 14106185db85Sdougm scf_value_destroy(value); 14116185db85Sdougm if (entry != NULL) 14126185db85Sdougm scf_entry_destroy(entry); 14136185db85Sdougm return (ret); 14146185db85Sdougm } 14156185db85Sdougm 14166185db85Sdougm /* 1417da6c28aaSamw * check_resource(share) 1418da6c28aaSamw * 1419da6c28aaSamw * Check to see if share has any persistent resources. We don't want 1420da6c28aaSamw * to save if they are all transient. 1421da6c28aaSamw */ 1422da6c28aaSamw static int 1423da6c28aaSamw check_resource(sa_share_t share) 1424da6c28aaSamw { 1425da6c28aaSamw sa_resource_t resource; 1426da6c28aaSamw int ret = B_FALSE; 1427da6c28aaSamw 1428da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1429da6c28aaSamw resource != NULL && ret == B_FALSE; 1430da6c28aaSamw resource = sa_get_next_resource(resource)) { 1431da6c28aaSamw char *type; 1432da6c28aaSamw type = sa_get_resource_attr(resource, "type"); 1433da6c28aaSamw if (type != NULL) { 1434da6c28aaSamw if (strcmp(type, "transient") != 0) { 1435da6c28aaSamw ret = B_TRUE; 1436da6c28aaSamw } 1437da6c28aaSamw sa_free_attr_string(type); 1438da6c28aaSamw } 1439da6c28aaSamw } 1440da6c28aaSamw return (ret); 1441da6c28aaSamw } 1442da6c28aaSamw 1443da6c28aaSamw /* 1444da6c28aaSamw * sa_set_resource_property(handle, prop, value) 1445da6c28aaSamw * 1446da6c28aaSamw * set a property transaction entry into the pending SMF 1447da6c28aaSamw * transaction. We don't want to include any transient resources 1448da6c28aaSamw */ 1449da6c28aaSamw 1450da6c28aaSamw static int 1451da6c28aaSamw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) 1452da6c28aaSamw { 1453da6c28aaSamw int ret = SA_OK; 1454da6c28aaSamw scf_value_t *value; 1455da6c28aaSamw scf_transaction_entry_t *entry; 1456da6c28aaSamw sa_resource_t resource; 1457da6c28aaSamw char *valstr; 1458da6c28aaSamw char *idstr; 1459da6c28aaSamw char *description; 1460da6c28aaSamw char *propstr = NULL; 1461da6c28aaSamw size_t strsize; 1462da6c28aaSamw 1463da6c28aaSamw /* don't bother if no persistent resources */ 1464da6c28aaSamw if (check_resource(share) == B_FALSE) 1465da6c28aaSamw return (ret); 1466da6c28aaSamw 1467da6c28aaSamw /* 1468da6c28aaSamw * properties must be set in transactions and don't take 1469da6c28aaSamw * effect until the transaction has been ended/committed. 1470da6c28aaSamw */ 1471da6c28aaSamw entry = scf_entry_create(handle->handle); 1472da6c28aaSamw if (entry == NULL) 1473da6c28aaSamw return (SA_SYSTEM_ERR); 1474da6c28aaSamw 1475da6c28aaSamw if (scf_transaction_property_change(handle->trans, entry, 1476da6c28aaSamw "resource", SCF_TYPE_ASTRING) != 0 && 1477da6c28aaSamw scf_transaction_property_new(handle->trans, entry, 1478da6c28aaSamw "resource", SCF_TYPE_ASTRING) != 0) { 1479da6c28aaSamw scf_entry_destroy(entry); 1480da6c28aaSamw return (SA_SYSTEM_ERR); 1481da6c28aaSamw 1482da6c28aaSamw } 1483da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1484da6c28aaSamw resource != NULL; 1485da6c28aaSamw resource = sa_get_next_resource(resource)) { 1486da6c28aaSamw value = scf_value_create(handle->handle); 1487da6c28aaSamw if (value == NULL) { 1488da6c28aaSamw ret = SA_NO_MEMORY; 1489da6c28aaSamw break; 1490da6c28aaSamw } 1491da6c28aaSamw /* Get size of complete string */ 1492da6c28aaSamw valstr = sa_get_resource_attr(resource, "name"); 1493da6c28aaSamw idstr = sa_get_resource_attr(resource, "id"); 1494da6c28aaSamw description = sa_get_resource_description(resource); 1495da6c28aaSamw strsize = (valstr != NULL) ? strlen(valstr) : 0; 1496da6c28aaSamw strsize += (idstr != NULL) ? strlen(idstr) : 0; 1497da6c28aaSamw strsize += (description != NULL) ? strlen(description) : 0; 1498da6c28aaSamw if (strsize > 0) { 1499da6c28aaSamw strsize += 3; /* add nul and ':' */ 1500da6c28aaSamw propstr = (char *)malloc(strsize); 1501da6c28aaSamw if (propstr == NULL) { 1502da6c28aaSamw scf_value_destroy(value); 1503da6c28aaSamw ret = SA_NO_MEMORY; 1504da6c28aaSamw goto err; 1505da6c28aaSamw } 1506da6c28aaSamw if (idstr == NULL) 1507da6c28aaSamw (void) snprintf(propstr, strsize, "%s", 1508da6c28aaSamw valstr ? valstr : ""); 1509da6c28aaSamw else 1510da6c28aaSamw (void) snprintf(propstr, strsize, "%s:%s:%s", 1511da6c28aaSamw idstr ? idstr : "", valstr ? valstr : "", 1512da6c28aaSamw description ? description : ""); 1513da6c28aaSamw if (scf_value_set_astring(value, propstr) != 0) { 1514da6c28aaSamw ret = SA_SYSTEM_ERR; 1515da6c28aaSamw free(propstr); 1516da6c28aaSamw scf_value_destroy(value); 1517da6c28aaSamw break; 1518da6c28aaSamw } 1519da6c28aaSamw if (scf_entry_add_value(entry, value) != 0) { 1520da6c28aaSamw ret = SA_SYSTEM_ERR; 1521da6c28aaSamw free(propstr); 1522da6c28aaSamw scf_value_destroy(value); 1523da6c28aaSamw break; 1524da6c28aaSamw } 1525da6c28aaSamw /* the value is in the transaction */ 1526da6c28aaSamw value = NULL; 1527da6c28aaSamw free(propstr); 1528da6c28aaSamw } 1529da6c28aaSamw err: 1530da6c28aaSamw if (valstr != NULL) 1531da6c28aaSamw sa_free_attr_string(valstr); 1532da6c28aaSamw if (idstr != NULL) 1533da6c28aaSamw sa_free_attr_string(idstr); 1534da6c28aaSamw if (description != NULL) 1535da6c28aaSamw sa_free_share_description(description); 1536da6c28aaSamw } 1537da6c28aaSamw /* the entry is in the transaction */ 1538da6c28aaSamw entry = NULL; 1539da6c28aaSamw 1540da6c28aaSamw if (ret == SA_SYSTEM_ERR) { 1541da6c28aaSamw switch (scf_error()) { 1542da6c28aaSamw case SCF_ERROR_PERMISSION_DENIED: 1543da6c28aaSamw ret = SA_NO_PERMISSION; 1544da6c28aaSamw break; 1545da6c28aaSamw } 1546da6c28aaSamw } 1547da6c28aaSamw /* 1548da6c28aaSamw * cleanup if there were any errors that didn't leave 1549da6c28aaSamw * these values where they would be cleaned up later. 1550da6c28aaSamw */ 1551da6c28aaSamw if (entry != NULL) 1552da6c28aaSamw scf_entry_destroy(entry); 1553da6c28aaSamw 1554da6c28aaSamw return (ret); 1555da6c28aaSamw } 1556da6c28aaSamw 1557da6c28aaSamw /* 15586185db85Sdougm * sa_commit_share(handle, group, share) 15596185db85Sdougm * 156025a68471Sdougm * Commit this share to the repository. 15616185db85Sdougm * properties are added if they exist but can be added later. 15626185db85Sdougm * Need to add to dfstab and sharetab, if appropriate. 15636185db85Sdougm */ 15646185db85Sdougm int 15656185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 15666185db85Sdougm { 15676185db85Sdougm int ret = SA_OK; 15686185db85Sdougm char *groupname; 15696185db85Sdougm char *name; 15706185db85Sdougm char *description; 15716185db85Sdougm char *sharename; 15726185db85Sdougm ssize_t proplen; 15736185db85Sdougm char *propstring; 15746185db85Sdougm 15756185db85Sdougm /* 157625a68471Sdougm * Don't commit in the zfs group. We do commit legacy 15776185db85Sdougm * (default) and all other groups/shares. ZFS is handled 15786185db85Sdougm * through the ZFS configuration rather than SMF. 15796185db85Sdougm */ 15806185db85Sdougm 15816185db85Sdougm groupname = sa_get_group_attr(group, "name"); 15826185db85Sdougm if (groupname != NULL) { 15836185db85Sdougm if (strcmp(groupname, "zfs") == 0) { 15846185db85Sdougm /* 158525a68471Sdougm * Adding to the ZFS group will result in the sharenfs 15866185db85Sdougm * property being set but we don't want to do anything 15876185db85Sdougm * SMF related at this point. 15886185db85Sdougm */ 15896185db85Sdougm sa_free_attr_string(groupname); 15906185db85Sdougm return (ret); 15916185db85Sdougm } 15926185db85Sdougm } 15936185db85Sdougm 15946185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 15956185db85Sdougm propstring = malloc(proplen); 15966185db85Sdougm if (propstring == NULL) 15976185db85Sdougm ret = SA_NO_MEMORY; 15986185db85Sdougm 15996185db85Sdougm if (groupname != NULL && ret == SA_OK) { 16006185db85Sdougm ret = sa_get_instance(handle, groupname); 16016185db85Sdougm sa_free_attr_string(groupname); 16026185db85Sdougm groupname = NULL; 16036185db85Sdougm sharename = sa_get_share_attr(share, "id"); 16046185db85Sdougm if (sharename == NULL) { 16056185db85Sdougm /* slipped by */ 16066185db85Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 16076185db85Sdougm generate_unique_sharename(shname); 16086185db85Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 16096185db85Sdougm (xmlChar *)shname); 16106185db85Sdougm sharename = strdup(shname); 16116185db85Sdougm } 16126185db85Sdougm if (sharename != NULL) { 1613f345c0beSdougm sigset_t old, new; 16146185db85Sdougm /* 161525a68471Sdougm * Have a share name allocated so create a pgroup for 1616f345c0beSdougm * it. It may already exist, but that is OK. In order 1617f345c0beSdougm * to avoid creating a share pgroup that doesn't have 1618f345c0beSdougm * a path property, block signals around the critical 1619f345c0beSdougm * region of creating the share pgroup and props. 16206185db85Sdougm */ 1621f345c0beSdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 1622f345c0beSdougm (void) sigaddset(&new, SIGHUP); 1623f345c0beSdougm (void) sigaddset(&new, SIGINT); 1624f345c0beSdougm (void) sigaddset(&new, SIGQUIT); 1625f345c0beSdougm (void) sigaddset(&new, SIGTSTP); 1626f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 1627f345c0beSdougm 16286185db85Sdougm ret = sa_create_pgroup(handle, sharename); 16296185db85Sdougm if (ret == SA_OK) { 16306185db85Sdougm /* 163125a68471Sdougm * Now start the transaction for the 16326185db85Sdougm * properties that define this share. They may 16336185db85Sdougm * exist so attempt to update before create. 16346185db85Sdougm */ 16356185db85Sdougm ret = sa_start_transaction(handle, sharename); 16366185db85Sdougm } 16376185db85Sdougm if (ret == SA_OK) { 16386185db85Sdougm name = sa_get_share_attr(share, "path"); 16396185db85Sdougm if (name != NULL) { 164025a68471Sdougm /* 164125a68471Sdougm * There needs to be a path 164225a68471Sdougm * for a share to exist. 164325a68471Sdougm */ 164425a68471Sdougm ret = sa_set_property(handle, "path", 164525a68471Sdougm name); 16466185db85Sdougm sa_free_attr_string(name); 16476185db85Sdougm } else { 16486185db85Sdougm ret = SA_NO_MEMORY; 16496185db85Sdougm } 16506185db85Sdougm } 16516185db85Sdougm if (ret == SA_OK) { 1652da6c28aaSamw name = sa_get_share_attr(share, "drive-letter"); 1653da6c28aaSamw if (name != NULL) { 1654da6c28aaSamw /* A drive letter may exist for SMB */ 165525a68471Sdougm ret = sa_set_property(handle, 1656da6c28aaSamw "drive-letter", name); 1657da6c28aaSamw sa_free_attr_string(name); 16586185db85Sdougm } 16596185db85Sdougm } 16606185db85Sdougm if (ret == SA_OK) { 1661da6c28aaSamw name = sa_get_share_attr(share, "exclude"); 1662da6c28aaSamw if (name != NULL) { 1663da6c28aaSamw /* 1664da6c28aaSamw * In special cases need to 1665da6c28aaSamw * exclude proto enable. 1666da6c28aaSamw */ 1667da6c28aaSamw ret = sa_set_property(handle, 1668da6c28aaSamw "exclude", name); 1669da6c28aaSamw sa_free_attr_string(name); 1670da6c28aaSamw } 1671da6c28aaSamw } 1672da6c28aaSamw if (ret == SA_OK) { 1673da6c28aaSamw /* 1674da6c28aaSamw * If there are resource names, bundle them up 1675da6c28aaSamw * and save appropriately. 1676da6c28aaSamw */ 1677da6c28aaSamw ret = sa_set_resource_property(handle, share); 1678da6c28aaSamw } 1679da6c28aaSamw 1680da6c28aaSamw if (ret == SA_OK) { 16816185db85Sdougm description = sa_get_share_description(share); 16826185db85Sdougm if (description != NULL) { 168325a68471Sdougm ret = sa_set_property(handle, 168425a68471Sdougm "description", 16856185db85Sdougm description); 16866185db85Sdougm sa_free_share_description(description); 16876185db85Sdougm } 16886185db85Sdougm } 168925a68471Sdougm /* Make sure we cleanup the transaction */ 16906185db85Sdougm if (ret == SA_OK) { 16916185db85Sdougm ret = sa_end_transaction(handle); 16926185db85Sdougm } else { 16936185db85Sdougm sa_abort_transaction(handle); 16946185db85Sdougm } 1695f345c0beSdougm 1696f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 1697f345c0beSdougm 16986185db85Sdougm free(sharename); 16996185db85Sdougm } 17006185db85Sdougm } 17016185db85Sdougm if (ret == SA_SYSTEM_ERR) { 17026185db85Sdougm int err = scf_error(); 17036185db85Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 17046185db85Sdougm ret = SA_NO_PERMISSION; 17056185db85Sdougm } 17066185db85Sdougm if (propstring != NULL) 17076185db85Sdougm free(propstring); 17086185db85Sdougm if (groupname != NULL) 17096185db85Sdougm sa_free_attr_string(groupname); 17106185db85Sdougm 17116185db85Sdougm return (ret); 17126185db85Sdougm } 17136185db85Sdougm 17146185db85Sdougm /* 1715da6c28aaSamw * remove_resources(handle, share, shareid) 1716da6c28aaSamw * 1717da6c28aaSamw * If the share has resources, remove all of them and their 1718da6c28aaSamw * optionsets. 1719da6c28aaSamw */ 1720da6c28aaSamw static int 1721da6c28aaSamw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid) 1722da6c28aaSamw { 1723da6c28aaSamw sa_resource_t resource; 1724da6c28aaSamw sa_optionset_t opt; 1725da6c28aaSamw char *proto; 1726da6c28aaSamw char *id; 1727da6c28aaSamw ssize_t proplen; 1728da6c28aaSamw char *propstring; 1729da6c28aaSamw int ret = SA_OK; 1730da6c28aaSamw 1731da6c28aaSamw proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1732da6c28aaSamw propstring = malloc(proplen); 1733da6c28aaSamw if (propstring == NULL) 1734da6c28aaSamw return (SA_NO_MEMORY); 1735da6c28aaSamw 1736da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1737da6c28aaSamw resource != NULL; resource = sa_get_next_resource(resource)) { 1738da6c28aaSamw id = sa_get_resource_attr(resource, "id"); 1739da6c28aaSamw if (id == NULL) 1740da6c28aaSamw continue; 1741da6c28aaSamw for (opt = sa_get_optionset(resource, NULL); 1742da6c28aaSamw opt != NULL; opt = sa_get_next_optionset(resource)) { 1743da6c28aaSamw proto = sa_get_optionset_attr(opt, "type"); 1744da6c28aaSamw if (proto != NULL) { 1745da6c28aaSamw (void) snprintf(propstring, proplen, 1746da6c28aaSamw "%s_%s_%s", shareid, proto, id); 1747da6c28aaSamw ret = sa_delete_pgroup(handle, propstring); 1748da6c28aaSamw sa_free_attr_string(proto); 1749da6c28aaSamw } 1750da6c28aaSamw } 1751da6c28aaSamw sa_free_attr_string(id); 1752da6c28aaSamw } 1753da6c28aaSamw free(propstring); 1754da6c28aaSamw return (ret); 1755da6c28aaSamw } 1756da6c28aaSamw 1757da6c28aaSamw /* 17586185db85Sdougm * sa_delete_share(handle, group, share) 17596185db85Sdougm * 176025a68471Sdougm * Remove the specified share from the group (and service instance). 17616185db85Sdougm */ 17626185db85Sdougm 17636185db85Sdougm int 17646185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 17656185db85Sdougm { 17666185db85Sdougm int ret = SA_OK; 17676185db85Sdougm char *groupname = NULL; 17686185db85Sdougm char *shareid = NULL; 17696185db85Sdougm sa_optionset_t opt; 17706185db85Sdougm sa_security_t sec; 17716185db85Sdougm ssize_t proplen; 17726185db85Sdougm char *propstring; 17736185db85Sdougm 17746185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 17756185db85Sdougm propstring = malloc(proplen); 17766185db85Sdougm if (propstring == NULL) 17776185db85Sdougm ret = SA_NO_MEMORY; 17786185db85Sdougm 17796185db85Sdougm if (ret == SA_OK) { 17806185db85Sdougm groupname = sa_get_group_attr(group, "name"); 17816185db85Sdougm shareid = sa_get_share_attr(share, "id"); 178225a68471Sdougm if (groupname == NULL || shareid == NULL) { 178325a68471Sdougm ret = SA_CONFIG_ERR; 178425a68471Sdougm goto out; 178525a68471Sdougm } 17866185db85Sdougm ret = sa_get_instance(handle, groupname); 17876185db85Sdougm if (ret == SA_OK) { 1788da6c28aaSamw /* If a share has resources, remove them */ 1789da6c28aaSamw ret = remove_resources(handle, share, shareid); 179025a68471Sdougm /* If a share has properties, remove them */ 17916185db85Sdougm ret = sa_delete_pgroup(handle, shareid); 179225a68471Sdougm for (opt = sa_get_optionset(share, NULL); 179325a68471Sdougm opt != NULL; 17946185db85Sdougm opt = sa_get_next_optionset(opt)) { 17956185db85Sdougm char *proto; 17966185db85Sdougm proto = sa_get_optionset_attr(opt, "type"); 17976185db85Sdougm if (proto != NULL) { 179825a68471Sdougm (void) snprintf(propstring, 179925a68471Sdougm proplen, "%s_%s", shareid, 180025a68471Sdougm proto); 180125a68471Sdougm ret = sa_delete_pgroup(handle, 180225a68471Sdougm propstring); 18036185db85Sdougm sa_free_attr_string(proto); 18046185db85Sdougm } else { 18056185db85Sdougm ret = SA_NO_MEMORY; 18066185db85Sdougm } 18076185db85Sdougm } 18086185db85Sdougm /* 180925a68471Sdougm * If a share has security/negotiable 18106185db85Sdougm * properties, remove them. 18116185db85Sdougm */ 181225a68471Sdougm for (sec = sa_get_security(share, NULL, NULL); 181325a68471Sdougm sec != NULL; 18146185db85Sdougm sec = sa_get_next_security(sec)) { 18156185db85Sdougm char *proto; 18166185db85Sdougm char *sectype; 18176185db85Sdougm proto = sa_get_security_attr(sec, "type"); 18186185db85Sdougm sectype = sa_get_security_attr(sec, "sectype"); 18196185db85Sdougm if (proto != NULL && sectype != NULL) { 182025a68471Sdougm (void) snprintf(propstring, proplen, 182125a68471Sdougm "%s_%s_%s", shareid, proto, 182225a68471Sdougm sectype); 182325a68471Sdougm ret = sa_delete_pgroup(handle, 182425a68471Sdougm propstring); 18256185db85Sdougm } else { 18266185db85Sdougm ret = SA_NO_MEMORY; 18276185db85Sdougm } 18286185db85Sdougm if (proto != NULL) 18296185db85Sdougm sa_free_attr_string(proto); 18306185db85Sdougm if (sectype != NULL) 18316185db85Sdougm sa_free_attr_string(sectype); 18326185db85Sdougm } 18336185db85Sdougm } 18346185db85Sdougm } 183525a68471Sdougm out: 18366185db85Sdougm if (groupname != NULL) 18376185db85Sdougm sa_free_attr_string(groupname); 18386185db85Sdougm if (shareid != NULL) 18396185db85Sdougm sa_free_attr_string(shareid); 18406185db85Sdougm if (propstring != NULL) 18416185db85Sdougm free(propstring); 18426185db85Sdougm 18436185db85Sdougm return (ret); 18446185db85Sdougm } 1845