13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 233348Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm /* helper functions for using libscf with sharemgr */ 303034Sdougm 313034Sdougm #include <libscf.h> 323034Sdougm #include <libxml/parser.h> 333034Sdougm #include <libxml/tree.h> 343034Sdougm #include "libshare.h" 353034Sdougm #include "libshare_impl.h" 363034Sdougm #include "scfutil.h" 373034Sdougm #include <string.h> 383034Sdougm #include <errno.h> 393034Sdougm #include <uuid/uuid.h> 403034Sdougm #include <sys/param.h> 413348Sdougm #include <signal.h> 423034Sdougm 433034Sdougm ssize_t scf_max_name_len; 443034Sdougm extern struct sa_proto_plugin *sap_proto_list; 45*3910Sdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr); 463034Sdougm 473034Sdougm /* 483034Sdougm * The SMF facility uses some properties that must exist. We want to 493034Sdougm * skip over these when processing protocol options. 503034Sdougm */ 513034Sdougm static char *skip_props[] = { 523034Sdougm "modify_authorization", 533034Sdougm "action_authorization", 543034Sdougm "value_authorization", 553034Sdougm NULL 563034Sdougm }; 573034Sdougm 583034Sdougm /* 593034Sdougm * sa_scf_fini(handle) 603034Sdougm * 613034Sdougm * must be called when done. Called with the handle allocated in 623034Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 633034Sdougm * still in use. Called by sa_fini(). 643034Sdougm */ 653034Sdougm 663034Sdougm void 673034Sdougm sa_scf_fini(scfutilhandle_t *handle) 683034Sdougm { 693034Sdougm if (handle != NULL) { 703034Sdougm int unbind = 0; 713034Sdougm if (handle->scope != NULL) { 723034Sdougm unbind = 1; 733034Sdougm scf_scope_destroy(handle->scope); 743034Sdougm } 753034Sdougm if (handle->service != NULL) 763034Sdougm scf_service_destroy(handle->service); 773034Sdougm if (handle->pg != NULL) 783034Sdougm scf_pg_destroy(handle->pg); 793034Sdougm if (handle->handle != NULL) { 803034Sdougm handle->scf_state = SCH_STATE_UNINIT; 813034Sdougm if (unbind) 823034Sdougm (void) scf_handle_unbind(handle->handle); 833034Sdougm scf_handle_destroy(handle->handle); 843034Sdougm } 853034Sdougm free(handle); 863034Sdougm } 873034Sdougm } 883034Sdougm 893034Sdougm /* 903034Sdougm * sa_scf_init() 913034Sdougm * 923034Sdougm * must be called before using any of the SCF functions. Called by 933034Sdougm * sa_init() during the API setup. 943034Sdougm */ 953034Sdougm 963034Sdougm scfutilhandle_t * 97*3910Sdougm sa_scf_init(sa_handle_impl_t ihandle) 983034Sdougm { 993034Sdougm scfutilhandle_t *handle; 1003034Sdougm 1013034Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1023034Sdougm if (scf_max_name_len <= 0) 1033034Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1043034Sdougm 1053034Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 1063034Sdougm if (handle != NULL) { 107*3910Sdougm ihandle->scfhandle = handle; 1083034Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 1093034Sdougm handle->handle = scf_handle_create(SCF_VERSION); 1103034Sdougm if (handle->handle != NULL) { 1113034Sdougm if (scf_handle_bind(handle->handle) == 0) { 1123034Sdougm handle->scope = scf_scope_create(handle->handle); 1133034Sdougm handle->service = scf_service_create(handle->handle); 1143034Sdougm handle->pg = scf_pg_create(handle->handle); 1153034Sdougm handle->instance = scf_instance_create(handle->handle); 1163034Sdougm if (scf_handle_get_scope(handle->handle, 1173034Sdougm SCF_SCOPE_LOCAL, handle->scope) == 0) { 1183034Sdougm if (scf_scope_get_service(handle->scope, 1193034Sdougm SA_GROUP_SVC_NAME, 1203034Sdougm handle->service) != 0) { 1213034Sdougm goto err; 1223034Sdougm } 1233034Sdougm handle->scf_state = SCH_STATE_INIT; 1243034Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 1253034Sdougm char **protolist; 1263034Sdougm int numprotos, i; 1273034Sdougm sa_group_t defgrp; 128*3910Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, 129*3910Sdougm "default", NULL); 1303034Sdougm if (defgrp != NULL) { 1313034Sdougm numprotos = sa_get_protocols(&protolist); 1323034Sdougm for (i = 0; i < numprotos; i++) { 1333034Sdougm (void) sa_create_optionset(defgrp, 1343034Sdougm protolist[i]); 1353034Sdougm } 1363034Sdougm if (protolist != NULL) 1373034Sdougm free(protolist); 1383034Sdougm } 1393034Sdougm } 1403034Sdougm } else { 1413034Sdougm goto err; 1423034Sdougm } 1433034Sdougm } else { 1443034Sdougm goto err; 1453034Sdougm } 1463034Sdougm } else { 1473034Sdougm free(handle); 1483034Sdougm handle = NULL; 1493034Sdougm (void) printf("libshare could not access SMF repository: %s\n", 1503034Sdougm scf_strerror(scf_error())); 1513034Sdougm } 1523034Sdougm } 1533034Sdougm return (handle); 1543034Sdougm 1553034Sdougm /* error handling/unwinding */ 1563034Sdougm err: 1573034Sdougm (void) sa_scf_fini(handle); 1583034Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1593034Sdougm scf_strerror(scf_error())); 1603034Sdougm return (NULL); 1613034Sdougm } 1623034Sdougm 1633034Sdougm /* 1643034Sdougm * get_scf_limit(name) 1653034Sdougm * 1663034Sdougm * Since we use scf_limit a lot and do the same check and return the 1673034Sdougm * same value if it fails, implement as a function for code 1683034Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1693034Sdougm * (1024) so we have a reasonable default buffer size. 1703034Sdougm */ 1713034Sdougm static ssize_t 1723034Sdougm get_scf_limit(uint32_t name) 1733034Sdougm { 1743034Sdougm ssize_t vallen; 1753034Sdougm 1763034Sdougm vallen = scf_limit(name); 1773034Sdougm if (vallen == (ssize_t)-1) 1783034Sdougm vallen = MAXPATHLEN; 1793034Sdougm return (vallen); 1803034Sdougm } 1813034Sdougm 1823034Sdougm /* 1833034Sdougm * skip_property(name) 1843034Sdougm * 1853034Sdougm * internal function to check to see if a property is an SMF magic 1863034Sdougm * property that needs to be skipped. 1873034Sdougm */ 1883034Sdougm static int 1893034Sdougm skip_property(char *name) 1903034Sdougm { 1913034Sdougm int i; 1923034Sdougm 1933034Sdougm for (i = 0; skip_props[i] != NULL; i++) 1943034Sdougm if (strcmp(name, skip_props[i]) == 0) 1953034Sdougm return (1); 1963034Sdougm return (0); 1973034Sdougm } 1983034Sdougm 1993034Sdougm /* 2003034Sdougm * generate_unique_sharename(sharename) 2013034Sdougm * 2023034Sdougm * Shares are represented in SMF as property groups. Due to share 2033034Sdougm * paths containing characters that are not allowed in SMF names and 2043034Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2053034Sdougm */ 2063034Sdougm 2073034Sdougm static void 2083034Sdougm generate_unique_sharename(char *sharename) 2093034Sdougm { 2103034Sdougm uuid_t uuid; 2113034Sdougm 2123034Sdougm uuid_generate(uuid); 2133034Sdougm (void) strcpy(sharename, "S-"); 2143034Sdougm uuid_unparse(uuid, sharename + 2); 2153034Sdougm } 2163034Sdougm 2173034Sdougm /* 2183034Sdougm * valid_protocol(proto) 2193034Sdougm * 2203034Sdougm * check to see if the specified protocol is a valid one for the 2213034Sdougm * general sharemgr facility. We determine this by checking which 2223034Sdougm * plugin protocols were found. 2233034Sdougm */ 2243034Sdougm 2253034Sdougm static int 2263034Sdougm valid_protocol(char *proto) 2273034Sdougm { 2283034Sdougm struct sa_proto_plugin *plugin; 2293034Sdougm for (plugin = sap_proto_list; plugin != NULL; 2303034Sdougm plugin = plugin->plugin_next) 2313034Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2323034Sdougm return (1); 2333034Sdougm return (0); 2343034Sdougm } 2353034Sdougm 2363034Sdougm /* 2373034Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2383034Sdougm * 2393034Sdougm * extract the name property group and create the specified type of 2403034Sdougm * node on the provided group. type will be optionset or security. 2413034Sdougm */ 2423034Sdougm 2433034Sdougm static int 2443034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2453034Sdougm scf_propertygroup_t *pg, 2463034Sdougm char *nodetype, char *proto, char *sectype) 2473034Sdougm { 2483034Sdougm xmlNodePtr node; 2493034Sdougm scf_iter_t *iter; 2503034Sdougm scf_property_t *prop; 2513034Sdougm scf_value_t *value; 2523034Sdougm char *name; 2533034Sdougm char *valuestr; 2543034Sdougm ssize_t vallen; 2553034Sdougm int ret = SA_OK; 2563034Sdougm 2573034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2583034Sdougm 2593034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 2603034Sdougm if (node != NULL) { 2613034Sdougm if (proto != NULL) 2623034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2633034Sdougm if (sectype != NULL) 2643034Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 2653034Sdougm /* 2663034Sdougm * have node to work with so iterate over the properties 2673034Sdougm * in the pg and create option sub nodes. 2683034Sdougm */ 2693034Sdougm iter = scf_iter_create(handle->handle); 2703034Sdougm value = scf_value_create(handle->handle); 2713034Sdougm prop = scf_property_create(handle->handle); 2723034Sdougm name = malloc(scf_max_name_len); 2733034Sdougm valuestr = malloc(vallen); 2743034Sdougm /* 2753034Sdougm * want to iterate through the properties and add them 2763034Sdougm * to the base optionset. 2773034Sdougm */ 2783034Sdougm if (iter != NULL && value != NULL && prop != NULL && 2793034Sdougm valuestr != NULL && name != NULL) { 2803034Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 2813034Sdougm /* now iterate the properties in the group */ 2823034Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2833034Sdougm /* have a property */ 2843034Sdougm if (scf_property_get_name(prop, name, 2853034Sdougm scf_max_name_len) > 0) { 2863034Sdougm /* some properties are part of the framework */ 2873034Sdougm if (skip_property(name)) 2883034Sdougm continue; 2893034Sdougm if (scf_property_get_value(prop, value) == 0) { 2903034Sdougm if (scf_value_get_astring(value, valuestr, 2913034Sdougm vallen) >= 0) { 2923034Sdougm sa_property_t saprop; 2933034Sdougm saprop = sa_create_property(name, 2943034Sdougm valuestr); 2953034Sdougm if (saprop != NULL) { 2963034Sdougm /* 2973034Sdougm * since in SMF, don't 2983034Sdougm * recurse. Use xmlAddChild 2993034Sdougm * directly, instead. 3003034Sdougm */ 3013034Sdougm xmlAddChild(node, 3023034Sdougm (xmlNodePtr) saprop); 3033034Sdougm } 3043034Sdougm } 3053034Sdougm } 3063034Sdougm } 3073034Sdougm } 3083034Sdougm } 3093034Sdougm } else { 3103034Sdougm ret = SA_NO_MEMORY; 3113034Sdougm } 3123034Sdougm /* cleanup to avoid memory leaks */ 3133034Sdougm if (value != NULL) 3143034Sdougm scf_value_destroy(value); 3153034Sdougm if (iter != NULL) 3163034Sdougm scf_iter_destroy(iter); 3173034Sdougm if (prop != NULL) 3183034Sdougm scf_property_destroy(prop); 3193034Sdougm if (name != NULL) 3203034Sdougm free(name); 3213034Sdougm if (valuestr != NULL) 3223034Sdougm free(valuestr); 3233034Sdougm } 3243034Sdougm return (ret); 3253034Sdougm } 3263034Sdougm 3273034Sdougm /* 3283034Sdougm * sa_extract_attrs(root, handle, instance) 3293034Sdougm * 3303034Sdougm * local function to extract the actual attributes/properties from the 3313034Sdougm * property group of the service instance. These are the well known 3323034Sdougm * attributes of "state" and "zfs". If additional attributes are 3333034Sdougm * added, they should be added here. 3343034Sdougm */ 3353034Sdougm 3363034Sdougm static void 3373034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3383034Sdougm scf_instance_t *instance) 3393034Sdougm { 3403034Sdougm scf_property_t *prop; 3413034Sdougm scf_value_t *value; 3423034Sdougm char *valuestr; 3433034Sdougm ssize_t vallen; 3443034Sdougm 3453034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3463034Sdougm prop = scf_property_create(handle->handle); 3473034Sdougm value = scf_value_create(handle->handle); 3483034Sdougm valuestr = malloc(vallen); 3493034Sdougm if (prop != NULL && value != NULL && valuestr != NULL && 3503034Sdougm scf_instance_get_pg(instance, "operation", 3513034Sdougm handle->pg) == 0) { 3523034Sdougm /* 3533034Sdougm * have a property group with desired name so now get 3543034Sdougm * the known attributes. 3553034Sdougm */ 3563034Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 3573034Sdougm /* found the property so get the value */ 3583034Sdougm if (scf_property_get_value(prop, value) == 0) { 3593034Sdougm if (scf_value_get_astring(value, valuestr, vallen) >= 0) { 3603034Sdougm xmlSetProp(root, (xmlChar *)"state", 3613034Sdougm (xmlChar *)valuestr); 3623034Sdougm } 3633034Sdougm } 3643034Sdougm } 3653034Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 3663034Sdougm /* found the property so get the value */ 3673034Sdougm if (scf_property_get_value(prop, value) == 0) { 3683034Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 3693034Sdougm xmlSetProp(root, (xmlChar *)"zfs", 3703034Sdougm (xmlChar *)valuestr); 3713034Sdougm } 3723034Sdougm } 3733034Sdougm } 3743034Sdougm } 3753034Sdougm if (valuestr != NULL) 3763034Sdougm free(valuestr); 3773034Sdougm if (value != NULL) 3783034Sdougm scf_value_destroy(value); 3793034Sdougm if (prop != NULL) 3803034Sdougm scf_property_destroy(prop); 3813034Sdougm } 3823034Sdougm 3833034Sdougm /* 3843034Sdougm * list of known share attributes. 3853034Sdougm */ 3863034Sdougm 3873034Sdougm static char *share_attr[] = { 3883034Sdougm "path", 3893034Sdougm "id", 3903034Sdougm "resource", 3913034Sdougm NULL, 3923034Sdougm }; 3933034Sdougm 3943034Sdougm static int 3953034Sdougm is_share_attr(char *name) 3963034Sdougm { 3973034Sdougm int i; 3983034Sdougm for (i = 0; share_attr[i] != NULL; i++) 3993034Sdougm if (strcmp(name, share_attr[i]) == 0) 4003034Sdougm return (1); 4013034Sdougm return (0); 4023034Sdougm } 4033034Sdougm 4043034Sdougm /* 4053034Sdougm * sa_share_from_pgroup 4063034Sdougm * 4073034Sdougm * extract the share definition from the share property group. We do 4083034Sdougm * some sanity checking to avoid bad data. 4093034Sdougm * 4103034Sdougm * Since this is only constructing the internal data structures, we 4113034Sdougm * don't use the sa_* functions most of the time. 4123034Sdougm */ 4133034Sdougm void 4143034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4153034Sdougm scf_propertygroup_t *pg, char *id) 4163034Sdougm { 4173034Sdougm xmlNodePtr node; 4183034Sdougm char *name; 4193034Sdougm scf_iter_t *iter; 4203034Sdougm scf_property_t *prop; 4213034Sdougm scf_value_t *value; 4223034Sdougm ssize_t vallen; 4233034Sdougm char *valuestr; 4243034Sdougm int ret = SA_OK; 4253348Sdougm int have_path = 0; 4263034Sdougm 4273034Sdougm /* 4283034Sdougm * While preliminary check (starts with 'S') passed before 4293034Sdougm * getting here. Need to make sure it is in ID syntax 4303034Sdougm * (Snnnnnn). Note that shares with properties have similar 4313034Sdougm * pgroups. 4323034Sdougm */ 4333034Sdougm vallen = strlen(id); 4343034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4353034Sdougm uuid_t uuid; 4363034Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) != 0 || 4373034Sdougm uuid_parse(id + 2, uuid) < 0) 4383034Sdougm return; 4393034Sdougm } else { 4403034Sdougm return; 4413034Sdougm } 4423034Sdougm 4433034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 4443034Sdougm 4453034Sdougm iter = scf_iter_create(handle->handle); 4463034Sdougm value = scf_value_create(handle->handle); 4473034Sdougm prop = scf_property_create(handle->handle); 4483034Sdougm name = malloc(scf_max_name_len); 4493034Sdougm valuestr = malloc(vallen); 4503034Sdougm 4513034Sdougm /* 4523034Sdougm * construct the share XML node. It is similar to sa_add_share 4533034Sdougm * but never changes the repository. Also, there won't be any 4543034Sdougm * ZFS or transient shares. Root will be the group it is 4553034Sdougm * associated with. 4563034Sdougm */ 4573034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 4583034Sdougm if (node != NULL) { 4593034Sdougm /* 4603034Sdougm * make sure the UUID part of the property group is 4613034Sdougm * stored in the share "id" property. We use this 4623034Sdougm * later. 4633034Sdougm */ 4643034Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 4653034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 4663034Sdougm } 4673034Sdougm 4683034Sdougm if (iter != NULL && value != NULL && prop != NULL && name != NULL) { 4693034Sdougm /* iterate over the share pg properties */ 4703034Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 4713034Sdougm while (scf_iter_next_property(iter, prop) > 0) { 4723034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 4733034Sdougm if (scf_property_get_name(prop, name, 4743034Sdougm scf_max_name_len) > 0) { 4753034Sdougm if (scf_property_get_value(prop, value) == 0) { 4763034Sdougm if (scf_value_get_astring(value, valuestr, 4773034Sdougm vallen) >= 0) { 4783034Sdougm ret = SA_OK; 4793034Sdougm } 4803034Sdougm } 4813034Sdougm } 4823034Sdougm if (ret == SA_OK) { 4833348Sdougm /* 4843348Sdougm * check that we have the "path" property in 4853348Sdougm * name. The string in name will always be nul 4863348Sdougm * terminated if scf_property_get_name() 4873348Sdougm * succeeded. 4883348Sdougm */ 4893348Sdougm if (strcmp(name, "path") == 0) 4903348Sdougm have_path = 1; 4913034Sdougm if (is_share_attr(name)) { 4923034Sdougm /* 4933034Sdougm * if a share attr, then simple - 4943034Sdougm * usually path and resource name 4953034Sdougm */ 4963034Sdougm xmlSetProp(node, (xmlChar *)name, 4973034Sdougm (xmlChar *)valuestr); 4983034Sdougm } else { 4993034Sdougm if (strcmp(name, "description") == 0) { 5003034Sdougm /* we have a description node */ 5013034Sdougm xmlNodePtr desc; 5023034Sdougm desc = xmlNewChild(node, NULL, 5033034Sdougm (xmlChar *)"description", 5043034Sdougm NULL); 5053034Sdougm if (desc != NULL) 5063034Sdougm xmlNodeSetContent(desc, 5073034Sdougm (xmlChar *)valuestr); 5083034Sdougm } 5093034Sdougm } 5103034Sdougm } 5113034Sdougm } 5123034Sdougm } 5133034Sdougm } 5143348Sdougm /* 5153348Sdougm * a share without a path is broken so we want to not include 5163348Sdougm * these. They shouldn't happen but if you kill a sharemgr in 5173348Sdougm * the process of creating a share, it could happen. They 5183348Sdougm * should be harmless. It is also possible that another 5193348Sdougm * sharemgr is running and in the process of creating a share. 5203348Sdougm */ 5213348Sdougm if (have_path == 0 && node != NULL) { 5223348Sdougm xmlUnlinkNode(node); 5233348Sdougm xmlFreeNode(node); 5243348Sdougm } 5253034Sdougm if (name != NULL) 5263034Sdougm free(name); 5273034Sdougm if (valuestr != NULL) 5283034Sdougm free(valuestr); 5293034Sdougm if (value != NULL) 5303034Sdougm scf_value_destroy(value); 5313034Sdougm if (iter != NULL) 5323034Sdougm scf_iter_destroy(iter); 5333034Sdougm if (prop != NULL) 5343034Sdougm scf_property_destroy(prop); 5353034Sdougm } 5363034Sdougm 5373034Sdougm /* 5383034Sdougm * find_share_by_id(shareid) 5393034Sdougm * 5403034Sdougm * Search all shares in all groups until we find the share represented 5413034Sdougm * by "id". 5423034Sdougm */ 5433034Sdougm 5443034Sdougm static sa_share_t 545*3910Sdougm find_share_by_id(sa_handle_t handle, char *shareid) 5463034Sdougm { 5473034Sdougm sa_group_t group; 5483034Sdougm sa_share_t share = NULL; 5493034Sdougm char *id = NULL; 5503034Sdougm int done = 0; 5513034Sdougm 552*3910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 5533034Sdougm group = sa_get_next_group(group)) { 5543034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 5553034Sdougm share = sa_get_next_share(share)) { 5563034Sdougm id = sa_get_share_attr(share, "id"); 5573034Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 5583034Sdougm sa_free_attr_string(id); 5593034Sdougm id = NULL; 5603034Sdougm done++; 5613034Sdougm break; 5623034Sdougm } 5633034Sdougm if (id != NULL) { 5643034Sdougm sa_free_attr_string(id); 5653034Sdougm id = NULL; 5663034Sdougm } 5673034Sdougm } 5683034Sdougm } 5693034Sdougm return (share); 5703034Sdougm } 5713034Sdougm 5723034Sdougm /* 5733034Sdougm * sa_share_props_from_pgroup(root, handle, pg, id) 5743034Sdougm * 5753034Sdougm * extract share properties from the SMF property group. More sanity 5763034Sdougm * checks are done and the share object is created. We ignore some 5773034Sdougm * errors that could exist in the repository and only worry about 5783034Sdougm * property groups that validate in naming. 5793034Sdougm */ 5803034Sdougm 5813034Sdougm static int 5823034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 583*3910Sdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 5843034Sdougm { 5853034Sdougm xmlNodePtr node; 5863034Sdougm char *name; 5873034Sdougm scf_iter_t *iter; 5883034Sdougm scf_property_t *prop; 5893034Sdougm scf_value_t *value; 5903034Sdougm ssize_t vallen; 5913034Sdougm char *valuestr; 5923034Sdougm int ret = SA_OK; 5933034Sdougm char *sectype = NULL; 5943034Sdougm char *proto; 5953034Sdougm sa_share_t share; 5963034Sdougm 5973034Sdougm /* 5983034Sdougm * While preliminary check (starts with 'S') passed before 5993034Sdougm * getting here. Need to make sure it is in ID syntax 6003034Sdougm * (Snnnnnn). Note that shares with properties have similar 6013034Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 6023034Sdougm * characters, it is likely one of the protocol/security 6033034Sdougm * versions. 6043034Sdougm */ 6053034Sdougm vallen = strlen(id); 6063034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen > SA_SHARE_PG_LEN) { 6073034Sdougm uuid_t uuid; 6083034Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 6093034Sdougm proto = strchr(id, '_'); 6103034Sdougm if (proto == NULL) 6113034Sdougm return (ret); 6123034Sdougm *proto++ = '\0'; 6133034Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 6143034Sdougm return (ret); 6153034Sdougm /* 6163034Sdougm * probably a legal optionset so check a few more 6173034Sdougm * syntax points below. 6183034Sdougm */ 6193034Sdougm if (*proto == '\0') { 6203034Sdougm /* not a valid proto (null) */ 6213034Sdougm return (ret); 6223034Sdougm } 6233034Sdougm sectype = strchr(proto, '_'); 6243034Sdougm if (sectype != NULL) 6253034Sdougm *sectype++ = '\0'; 6263034Sdougm if (!valid_protocol(proto)) 6273034Sdougm return (ret); 6283034Sdougm } 6293034Sdougm } else { 6303034Sdougm /* 6313034Sdougm * it is ok to not have what we thought since someone might 6323034Sdougm * have added a name via SMF. 6333034Sdougm */ 6343034Sdougm return (ret); 6353034Sdougm } 6363034Sdougm 6373034Sdougm /* 6383034Sdougm * to get here, we have a valid protocol and possibly a 6393034Sdougm * security. We now have to find the share that it is really 6403034Sdougm * associated with. The "id" portion of the pgroup name will 6413034Sdougm * match. 6423034Sdougm */ 6433034Sdougm 644*3910Sdougm share = find_share_by_id(sahandle, id); 6453034Sdougm if (share == NULL) 6463034Sdougm return (SA_BAD_PATH); 6473034Sdougm 6483034Sdougm root = (xmlNodePtr)share; 6493034Sdougm 6503034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 6513034Sdougm 6523034Sdougm iter = scf_iter_create(handle->handle); 6533034Sdougm value = scf_value_create(handle->handle); 6543034Sdougm prop = scf_property_create(handle->handle); 6553034Sdougm name = malloc(scf_max_name_len); 6563034Sdougm valuestr = malloc(vallen); 6573034Sdougm 6583034Sdougm if (sectype == NULL) 6593034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 6603034Sdougm else { 6613034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL); 6623034Sdougm if (node != NULL) 6633034Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 6643034Sdougm } 6653034Sdougm if (node != NULL) { 6663034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 6673034Sdougm /* now find the properties */ 6683034Sdougm if (iter != NULL && value != NULL && prop != NULL && name != NULL) { 6693034Sdougm /* iterate over the share pg properties */ 6703034Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 6713034Sdougm while (scf_iter_next_property(iter, prop) > 0) { 6723034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 6733034Sdougm if (scf_property_get_name(prop, name, 6743034Sdougm scf_max_name_len) > 0) { 6753034Sdougm if (scf_property_get_value(prop, value) == 0) { 6763034Sdougm if (scf_value_get_astring(value, valuestr, 6773034Sdougm vallen) >= 0) { 6783034Sdougm ret = SA_OK; 6793034Sdougm } 6803034Sdougm } 6813034Sdougm } else { 6823034Sdougm ret = SA_SYSTEM_ERR; 6833034Sdougm } 6843034Sdougm if (ret == SA_OK) { 6853034Sdougm sa_property_t prop; 6863034Sdougm prop = sa_create_property(name, valuestr); 6873034Sdougm if (prop != NULL) 6883034Sdougm prop = (sa_property_t)xmlAddChild(node, 6893034Sdougm (xmlNodePtr)prop); 6903034Sdougm else 6913034Sdougm ret = SA_NO_MEMORY; 6923034Sdougm } 6933034Sdougm } 6943034Sdougm } else { 6953034Sdougm ret = SA_SYSTEM_ERR; 6963034Sdougm } 6973034Sdougm } 6983034Sdougm } else { 6993034Sdougm ret = SA_NO_MEMORY; 7003034Sdougm } 7013034Sdougm if (iter != NULL) 7023034Sdougm scf_iter_destroy(iter); 7033034Sdougm if (value != NULL) 7043034Sdougm scf_value_destroy(value); 7053034Sdougm if (prop != NULL) 7063034Sdougm scf_property_destroy(prop); 7073034Sdougm if (name != NULL) 7083034Sdougm free(name); 7093034Sdougm if (valuestr != NULL) 7103034Sdougm free(valuestr); 7113034Sdougm return (ret); 7123034Sdougm } 7133034Sdougm 7143034Sdougm /* 7153034Sdougm * sa_extract_group(root, handle, instance) 7163034Sdougm * 7173034Sdougm * get the config info for this instance of a group and create the XML 7183034Sdougm * subtree from it. 7193034Sdougm */ 7203034Sdougm 7213034Sdougm static int 7223034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 723*3910Sdougm scf_instance_t *instance, sa_handle_t sahandle) 7243034Sdougm { 7253034Sdougm char *buff; 7263034Sdougm xmlNodePtr node; 7273034Sdougm scf_iter_t *iter; 7283034Sdougm char *proto; 7293034Sdougm char *sectype; 7303034Sdougm int have_shares = 0; 7313034Sdougm int has_proto = 0; 7323034Sdougm int is_default = 0; 7333034Sdougm int ret = SA_OK; 7343034Sdougm int err; 7353034Sdougm 7363034Sdougm buff = malloc(scf_max_name_len); 7373034Sdougm iter = scf_iter_create(handle->handle); 7383034Sdougm if (buff != NULL) { 7393034Sdougm if (scf_instance_get_name(instance, buff, 7403034Sdougm scf_max_name_len) > 0) { 7413034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 7423034Sdougm if (node != NULL) { 7433034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 7443034Sdougm if (strcmp(buff, "default") == 0) 7453034Sdougm is_default++; 7463034Sdougm sa_extract_attrs(node, handle, instance); 7473034Sdougm /* 7483034Sdougm * Iterate through all the property groups 7493034Sdougm * looking for those with security or 7503034Sdougm * optionset prefixes. The names of the 7513034Sdougm * matching pgroups are parsed to get the 7523034Sdougm * protocol, and for security, the sectype. 7533034Sdougm * Syntax is as follows: 7543034Sdougm * optionset | optionset_<proto> 7553034Sdougm * security_default | security_<proto>_<sectype> 7563034Sdougm * "operation" is handled by 7573034Sdougm * sa_extract_attrs(). 7583034Sdougm */ 7593034Sdougm if (iter != NULL) { 7603034Sdougm if (scf_iter_instance_pgs(iter, instance) == 0) { 7613034Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 7623034Sdougm /* have a pgroup so sort it out */ 7633034Sdougm ret = scf_pg_get_name(handle->pg, buff, 7643034Sdougm scf_max_name_len); 7653034Sdougm if (ret > 0) { 7663034Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 7673034Sdougm sa_share_from_pgroup(node, handle, 7683034Sdougm handle->pg, 7693034Sdougm buff); 7703034Sdougm have_shares++; 7713034Sdougm } else if (strncmp(buff, "optionset", 9) == 7723034Sdougm 0) { 7733034Sdougm char *nodetype = "optionset"; 7743034Sdougm /* have an optionset */ 7753034Sdougm sectype = NULL; 7763034Sdougm proto = strchr(buff, '_'); 7773034Sdougm if (proto != NULL) { 7783034Sdougm *proto++ = '\0'; 7793034Sdougm sectype = strchr(proto, '_'); 7803034Sdougm if (sectype != NULL) { 7813034Sdougm *sectype++ = '\0'; 7823034Sdougm nodetype = "security"; 7833034Sdougm } 7843034Sdougm } 7853034Sdougm ret = sa_extract_pgroup(node, handle, 7863034Sdougm handle->pg, 7873034Sdougm nodetype, 7883034Sdougm proto, sectype); 7893034Sdougm has_proto++; 7903034Sdougm } else if (strncmp(buff, 7913034Sdougm "security", 8) == 0) { 7923034Sdougm /* 7933034Sdougm * have a security (note that 7943034Sdougm * this should change in the 7953034Sdougm * future) 7963034Sdougm */ 7973034Sdougm proto = strchr(buff, '_'); 7983034Sdougm sectype = NULL; 7993034Sdougm if (proto != NULL) { 8003034Sdougm *proto++ = '\0'; 8013034Sdougm sectype = strchr(proto, '_'); 8023034Sdougm if (sectype != NULL) 8033034Sdougm *sectype++ = '\0'; 8043034Sdougm if (strcmp(proto, "default") == 0) 8053034Sdougm proto = NULL; 8063034Sdougm } 8073034Sdougm ret = sa_extract_pgroup(node, handle, 8083034Sdougm handle->pg, 8093034Sdougm "security", proto, 8103034Sdougm sectype); 8113034Sdougm has_proto++; 8123034Sdougm } 8133034Sdougm /* ignore everything else */ 8143034Sdougm } 8153034Sdougm } 8163034Sdougm } else { 8173034Sdougm ret = SA_NO_MEMORY; 8183034Sdougm } 8193034Sdougm /* 8203034Sdougm * Make sure we have a valid default group. 8213034Sdougm * On first boot, default won't have any 8223034Sdougm * protocols defined and won't be enabled (but 8233034Sdougm * should be). 8243034Sdougm */ 8253034Sdougm if (is_default) { 8263034Sdougm char *state = sa_get_group_attr((sa_group_t)node, 8273034Sdougm "state"); 8283034Sdougm char **protos; 8293034Sdougm int numprotos; 8303034Sdougm int i; 8313034Sdougm 8323034Sdougm if (state == NULL) { 8333034Sdougm /* set attribute to enabled */ 8343034Sdougm (void) sa_set_group_attr((sa_group_t)node, 8353034Sdougm "state", 8363034Sdougm "enabled"); 8373034Sdougm /* we can assume no protocols */ 8383034Sdougm numprotos = sa_get_protocols(&protos); 8393034Sdougm for (i = 0; i < numprotos; i++) 8403034Sdougm (void) sa_create_optionset((sa_group_t)node, 8413034Sdougm protos[i]); 8423034Sdougm if (numprotos > 0) 8433034Sdougm free(protos); 8443034Sdougm } else { 8453034Sdougm sa_free_attr_string(state); 8463034Sdougm } 8473034Sdougm } 8483034Sdougm /* do a second pass if shares were found */ 8493034Sdougm if (have_shares && 8503034Sdougm scf_iter_instance_pgs(iter, instance) == 0) { 8513034Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 8523034Sdougm /* 8533034Sdougm * have a pgroup so see if it is a 8543034Sdougm * share optionset 8553034Sdougm */ 8563034Sdougm err = scf_pg_get_name(handle->pg, buff, 8573034Sdougm scf_max_name_len); 8583034Sdougm if (err > 0) { 8593034Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 8603034Sdougm ret = sa_share_props_from_pgroup(node, 8613034Sdougm handle, 8623034Sdougm handle->pg, 863*3910Sdougm buff, sahandle); 8643034Sdougm } 8653034Sdougm } 8663034Sdougm } 8673034Sdougm } 8683034Sdougm } 8693034Sdougm } 8703034Sdougm } 8713034Sdougm } 8723034Sdougm if (iter != NULL) 8733034Sdougm scf_iter_destroy(iter); 8743034Sdougm if (buff != NULL) 8753034Sdougm free(buff); 8763034Sdougm return (ret); 8773034Sdougm } 8783034Sdougm 8793034Sdougm /* 8803034Sdougm * sa_extract_defaults(root, handle, instance) 8813034Sdougm * 8823034Sdougm * local function to find the default properties that live in the 8833034Sdougm * default instance's "operation" proprerty group. 8843034Sdougm */ 8853034Sdougm 8863034Sdougm static void 8873034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 8883034Sdougm scf_instance_t *instance) 8893034Sdougm { 8903034Sdougm xmlNodePtr node; 8913034Sdougm scf_property_t *prop; 8923034Sdougm scf_value_t *value; 8933034Sdougm char *valuestr; 8943034Sdougm ssize_t vallen; 8953034Sdougm 8963034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 8973034Sdougm prop = scf_property_create(handle->handle); 8983034Sdougm value = scf_value_create(handle->handle); 8993034Sdougm valuestr = malloc(vallen); 9003034Sdougm if (prop != NULL && value != NULL && vallen != NULL && 9013034Sdougm scf_instance_get_pg(instance, "operation", 9023034Sdougm handle->pg) == 0) { 9033034Sdougm if (scf_pg_get_property(handle->pg, 9043034Sdougm "legacy-timestamp", prop) == 0) { 9053034Sdougm /* found the property so get the value */ 9063034Sdougm if (scf_property_get_value(prop, value) == 0) { 9073034Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 9083034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 9093034Sdougm NULL); 9103034Sdougm if (node != NULL) { 9113034Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 9123034Sdougm (xmlChar *)valuestr); 9133034Sdougm xmlSetProp(node, (xmlChar *)"path", 9143034Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 9153034Sdougm } 9163034Sdougm } 9173034Sdougm } 9183034Sdougm } 9193034Sdougm } 9203034Sdougm if (valuestr != NULL) 9213034Sdougm free(valuestr); 9223034Sdougm if (value != NULL) 9233034Sdougm scf_value_destroy(value); 9243034Sdougm if (prop != NULL) 9253034Sdougm scf_property_destroy(prop); 9263034Sdougm } 9273034Sdougm 9283034Sdougm 9293034Sdougm /* 930*3910Sdougm * sa_get_config(handle, root, doc, sahandlec) 9313034Sdougm * 9323034Sdougm * walk the SMF repository for /network/shares/group and find all the 9333034Sdougm * instances. These become group names. Then add the XML structure 9343034Sdougm * below the groups based on property groups and properties. 9353034Sdougm */ 9363034Sdougm int 937*3910Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr *root, xmlDocPtr *doc, 938*3910Sdougm sa_handle_t sahandle) 9393034Sdougm { 9403034Sdougm int ret = SA_OK; 9413034Sdougm scf_instance_t *instance; 9423034Sdougm scf_iter_t *iter; 9433034Sdougm char buff[BUFSIZ * 2]; 9443034Sdougm 9453034Sdougm *doc = xmlNewDoc((xmlChar *)"1.0"); 9463034Sdougm *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 9473034Sdougm instance = scf_instance_create(handle->handle); 9483034Sdougm iter = scf_iter_create(handle->handle); 9493034Sdougm if (*doc != NULL && *root != NULL && instance != NULL && iter != NULL) { 9503034Sdougm xmlDocSetRootElement(*doc, *root); 9513034Sdougm if ((ret = scf_iter_service_instances(iter, 9523034Sdougm handle->service)) == 0) { 9533034Sdougm while ((ret = scf_iter_next_instance(iter, 9543034Sdougm instance)) > 0) { 9553034Sdougm if (scf_instance_get_name(instance, buff, 9563034Sdougm sizeof (buff)) > 0) { 9573034Sdougm if (strcmp(buff, "default") == 0) 9583034Sdougm sa_extract_defaults(*root, handle, instance); 959*3910Sdougm ret = sa_extract_group(*root, handle, instance, 960*3910Sdougm sahandle); 9613034Sdougm } 9623034Sdougm } 9633034Sdougm } 9643034Sdougm } else { 9653034Sdougm /* if we can't create the document, cleanup */ 9663034Sdougm if (*doc != NULL) 9673034Sdougm xmlFreeDoc(*doc); 9683034Sdougm if (*root != NULL) 9693034Sdougm xmlFreeNode(*root); 9703034Sdougm *doc = NULL; 9713034Sdougm *root = NULL; 9723034Sdougm } 9733034Sdougm /* always cleanup these */ 9743034Sdougm if (instance != NULL) 9753034Sdougm scf_instance_destroy(instance); 9763034Sdougm if (iter != NULL) 9773034Sdougm scf_iter_destroy(iter); 9783034Sdougm return (ret); 9793034Sdougm } 9803034Sdougm 9813034Sdougm /* 9823034Sdougm * sa_get_instance(handle, instance) 9833034Sdougm * 9843034Sdougm * get the instance of the group service. This is actually the 9853034Sdougm * specific group name. The instance is needed for all property and 9863034Sdougm * control operations. 9873034Sdougm */ 9883034Sdougm 9893034Sdougm int 9903034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 9913034Sdougm { 9923034Sdougm if (scf_service_get_instance(handle->service, instname, 9933034Sdougm handle->instance) != 0) { 9943034Sdougm return (SA_NO_SUCH_GROUP); 9953034Sdougm } 9963034Sdougm return (SA_OK); 9973034Sdougm } 9983034Sdougm 9993034Sdougm /* 10003034Sdougm * sa_create_instance(handle, instname) 10013034Sdougm * 10023034Sdougm * Create a new SMF service instance. There can only be one with a 10033034Sdougm * given name. 10043034Sdougm */ 10053034Sdougm 10063034Sdougm int 10073034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 10083034Sdougm { 10093034Sdougm int ret = SA_OK; 10103034Sdougm char instance[SA_GROUP_INST_LEN]; 10113034Sdougm if (scf_service_add_instance(handle->service, instname, 10123034Sdougm handle->instance) != 0) { 10133034Sdougm /* better error returns need to be added based on real error */ 10143034Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 10153034Sdougm ret = SA_NO_PERMISSION; 10163034Sdougm else 10173034Sdougm ret = SA_DUPLICATE_NAME; 10183034Sdougm } else { 10193034Sdougm /* have the service created, so enable it */ 10203034Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 10213034Sdougm SA_SVC_FMRI_BASE, instname); 10223034Sdougm (void) smf_enable_instance(instance, 0); 10233034Sdougm } 10243034Sdougm return (ret); 10253034Sdougm } 10263034Sdougm 10273034Sdougm /* 10283034Sdougm * sa_delete_instance(handle, instname) 10293034Sdougm * 10303034Sdougm * When a group goes away, we also remove the service instance. 10313034Sdougm */ 10323034Sdougm 10333034Sdougm int 10343034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 10353034Sdougm { 10363034Sdougm int ret; 10373034Sdougm 10383034Sdougm if (strcmp(instname, "default") == 0) { 10393034Sdougm ret = SA_NO_PERMISSION; 10403034Sdougm } else { 10413034Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 10423034Sdougm if (scf_instance_delete(handle->instance) != 0) 10433034Sdougm /* need better analysis */ 10443034Sdougm ret = SA_NO_PERMISSION; 10453034Sdougm } 10463034Sdougm } 10473034Sdougm return (ret); 10483034Sdougm } 10493034Sdougm 10503034Sdougm /* 10513034Sdougm * sa_create_pgroup(handle, pgroup) 10523034Sdougm * 10533034Sdougm * create a new property group 10543034Sdougm */ 10553034Sdougm 10563034Sdougm int 10573034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 10583034Sdougm { 10593034Sdougm int ret = SA_OK; 10603034Sdougm /* 10613034Sdougm * only create a handle if it doesn't exist. It is ok to exist 10623034Sdougm * since the pg handle will be set as a side effect. 10633034Sdougm */ 10643034Sdougm if (handle->pg == NULL) { 10653034Sdougm handle->pg = scf_pg_create(handle->handle); 10663034Sdougm } 10673034Sdougm /* 10683034Sdougm * if the pgroup exists, we are done. If it doesn't, then we 10693034Sdougm * need to actually add one to the service instance. 10703034Sdougm */ 10713034Sdougm if (scf_instance_get_pg(handle->instance, 10723034Sdougm pgroup, handle->pg) != 0) { 10733034Sdougm /* doesn't exist so create one */ 10743034Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 10753034Sdougm SCF_GROUP_APPLICATION, 0, 10763034Sdougm handle->pg) != 0) { 10773034Sdougm switch (scf_error()) { 10783034Sdougm case SCF_ERROR_PERMISSION_DENIED: 10793034Sdougm ret = SA_NO_PERMISSION; 10803034Sdougm break; 10813034Sdougm default: 10823034Sdougm ret = SA_SYSTEM_ERR; 10833034Sdougm break; 10843034Sdougm } 10853034Sdougm } 10863034Sdougm } 10873034Sdougm return (ret); 10883034Sdougm } 10893034Sdougm 10903034Sdougm /* 10913034Sdougm * sa_delete_pgroup(handle, pgroup) 10923034Sdougm * 10933034Sdougm * remove the property group from the current instance of the service, 10943034Sdougm * but only if it actually exists. 10953034Sdougm */ 10963034Sdougm 10973034Sdougm int 10983034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 10993034Sdougm { 11003034Sdougm int ret = SA_OK; 11013034Sdougm /* 11023034Sdougm * only delete if it does exist. 11033034Sdougm */ 11043034Sdougm if (scf_instance_get_pg(handle->instance, 11053034Sdougm pgroup, handle->pg) == 0) { 11063034Sdougm /* does exist so delete it */ 11073034Sdougm if (scf_pg_delete(handle->pg) != 0) { 11083034Sdougm ret = SA_SYSTEM_ERR; 11093034Sdougm } 11103034Sdougm } else { 11113034Sdougm ret = SA_SYSTEM_ERR; 11123034Sdougm } 11133034Sdougm if (ret == SA_SYSTEM_ERR && 11143034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11153034Sdougm ret = SA_NO_PERMISSION; 11163034Sdougm } 11173034Sdougm return (ret); 11183034Sdougm } 11193034Sdougm 11203034Sdougm /* 11213034Sdougm * sa_start_transaction(handle, pgroup) 11223034Sdougm * 11233034Sdougm * Start an SMF transaction so we can deal with properties. it would 11243034Sdougm * be nice to not have to expose this, but we have to in order to 11253034Sdougm * optimize. 11263034Sdougm * 11273034Sdougm * Basic model is to hold the transaction in the handle and allow 11283034Sdougm * property adds/deletes/updates to be added then close the 11293034Sdougm * transaction (or abort). There may eventually be a need to handle 11303034Sdougm * other types of transaction mechanisms but we don't do that now. 11313034Sdougm * 11323034Sdougm * An sa_start_transaction must be followed by either an 11333034Sdougm * sa_end_transaction or sa_abort_transaction before another 11343034Sdougm * sa_start_transaction can be done. 11353034Sdougm */ 11363034Sdougm 11373034Sdougm int 11383034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 11393034Sdougm { 11403034Sdougm int ret = SA_OK; 11413034Sdougm /* 11423034Sdougm * lookup the property group and create it if it doesn't already 11433034Sdougm * exist. 11443034Sdougm */ 11453034Sdougm if (handle->scf_state == SCH_STATE_INIT) { 11463034Sdougm ret = sa_create_pgroup(handle, propgroup); 11473034Sdougm if (ret == SA_OK) { 11483034Sdougm handle->trans = scf_transaction_create(handle->handle); 11493034Sdougm if (handle->trans != NULL) { 11503034Sdougm if (scf_transaction_start(handle->trans, handle->pg) != 0) { 11513034Sdougm ret = SA_SYSTEM_ERR; 11523034Sdougm } 11533034Sdougm if (ret != SA_OK) { 11543034Sdougm scf_transaction_destroy(handle->trans); 11553034Sdougm handle->trans = NULL; 11563034Sdougm } 11573034Sdougm } else { 11583034Sdougm ret = SA_SYSTEM_ERR; 11593034Sdougm } 11603034Sdougm } 11613034Sdougm } 11623034Sdougm if (ret == SA_SYSTEM_ERR && 11633034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11643034Sdougm ret = SA_NO_PERMISSION; 11653034Sdougm } 11663034Sdougm return (ret); 11673034Sdougm } 11683034Sdougm 11693034Sdougm /* 11703034Sdougm * sa_end_transaction(handle) 11713034Sdougm * 11723034Sdougm * Commit the changes that were added to the transaction in the 11733034Sdougm * handle. Do all necessary cleanup. 11743034Sdougm */ 11753034Sdougm 11763034Sdougm int 11773034Sdougm sa_end_transaction(scfutilhandle_t *handle) 11783034Sdougm { 11793034Sdougm int ret = SA_OK; 11803034Sdougm 11813034Sdougm if (handle->trans == NULL) { 11823034Sdougm ret = SA_SYSTEM_ERR; 11833034Sdougm } else { 11843034Sdougm if (scf_transaction_commit(handle->trans) < 0) 11853034Sdougm ret = SA_SYSTEM_ERR; 11863034Sdougm scf_transaction_destroy_children(handle->trans); 11873034Sdougm scf_transaction_destroy(handle->trans); 11883034Sdougm handle->trans = NULL; 11893034Sdougm } 11903034Sdougm return (ret); 11913034Sdougm } 11923034Sdougm 11933034Sdougm /* 11943034Sdougm * sa_abort_transaction(handle) 11953034Sdougm * 11963034Sdougm * Abort the changes that were added to the transaction in the 11973034Sdougm * handle. Do all necessary cleanup. 11983034Sdougm */ 11993034Sdougm 12003034Sdougm void 12013034Sdougm sa_abort_transaction(scfutilhandle_t *handle) 12023034Sdougm { 12033034Sdougm if (handle->trans != NULL) { 12043034Sdougm scf_transaction_reset_all(handle->trans); 12053034Sdougm scf_transaction_destroy_children(handle->trans); 12063034Sdougm scf_transaction_destroy(handle->trans); 12073034Sdougm handle->trans = NULL; 12083034Sdougm } 12093034Sdougm } 12103034Sdougm 12113034Sdougm /* 12123034Sdougm * sa_set_property(handle, prop, value) 12133034Sdougm * 12143034Sdougm * set a property transaction entry into the pending SMF transaction. 12153034Sdougm */ 12163034Sdougm 12173034Sdougm int 12183034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 12193034Sdougm { 12203034Sdougm int ret = SA_OK; 12213034Sdougm scf_value_t *value; 12223034Sdougm scf_transaction_entry_t *entry; 12233034Sdougm /* 12243034Sdougm * properties must be set in transactions and don't take 12253034Sdougm * effect until the transaction has been ended/committed. 12263034Sdougm */ 12273034Sdougm value = scf_value_create(handle->handle); 12283034Sdougm entry = scf_entry_create(handle->handle); 12293034Sdougm if (value != NULL && entry != NULL) { 12303034Sdougm if (scf_transaction_property_change(handle->trans, entry, 12313034Sdougm propname, 12323034Sdougm SCF_TYPE_ASTRING) == 0 || 12333034Sdougm scf_transaction_property_new(handle->trans, entry, 12343034Sdougm propname, 12353034Sdougm SCF_TYPE_ASTRING) == 0) { 12363034Sdougm if (scf_value_set_astring(value, valstr) == 0) { 12373034Sdougm if (scf_entry_add_value(entry, value) != 0) { 12383034Sdougm ret = SA_SYSTEM_ERR; 12393034Sdougm scf_value_destroy(value); 12403034Sdougm } 12413034Sdougm /* the value is in the transaction */ 12423034Sdougm value = NULL; 12433034Sdougm } else { 12443034Sdougm /* value couldn't be constructed */ 12453034Sdougm ret = SA_SYSTEM_ERR; 12463034Sdougm } 12473034Sdougm /* the entry is in the transaction */ 12483034Sdougm entry = NULL; 12493034Sdougm } else { 12503034Sdougm ret = SA_SYSTEM_ERR; 12513034Sdougm } 12523034Sdougm } else { 12533034Sdougm ret = SA_SYSTEM_ERR; 12543034Sdougm } 12553034Sdougm if (ret == SA_SYSTEM_ERR) { 12563034Sdougm switch (scf_error()) { 12573034Sdougm case SCF_ERROR_PERMISSION_DENIED: 12583034Sdougm ret = SA_NO_PERMISSION; 12593034Sdougm break; 12603034Sdougm } 12613034Sdougm } 12623034Sdougm /* 12633034Sdougm * cleanup if there were any errors that didn't leave these 12643034Sdougm * values where they would be cleaned up later. 12653034Sdougm */ 12663034Sdougm if (value != NULL) 12673034Sdougm scf_value_destroy(value); 12683034Sdougm if (entry != NULL) 12693034Sdougm scf_entry_destroy(entry); 12703034Sdougm return (ret); 12713034Sdougm } 12723034Sdougm 12733034Sdougm /* 12743034Sdougm * sa_commit_share(handle, group, share) 12753034Sdougm * 12763034Sdougm * commit this share to the repository. 12773034Sdougm * properties are added if they exist but can be added later. 12783034Sdougm * Need to add to dfstab and sharetab, if appropriate. 12793034Sdougm */ 12803034Sdougm int 12813034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 12823034Sdougm { 12833034Sdougm int ret = SA_OK; 12843034Sdougm char *groupname; 12853034Sdougm char *name; 12863034Sdougm char *resource; 12873034Sdougm char *description; 12883034Sdougm char *sharename; 12893034Sdougm ssize_t proplen; 12903034Sdougm char *propstring; 12913034Sdougm 12923034Sdougm /* 12933034Sdougm * don't commit in the zfs group. We do commit legacy 12943034Sdougm * (default) and all other groups/shares. ZFS is handled 12953034Sdougm * through the ZFS configuration rather than SMF. 12963034Sdougm */ 12973034Sdougm 12983034Sdougm groupname = sa_get_group_attr(group, "name"); 12993034Sdougm if (groupname != NULL) { 13003034Sdougm if (strcmp(groupname, "zfs") == 0) { 13013034Sdougm /* 13023034Sdougm * adding to the ZFS group will result in the sharenfs 13033034Sdougm * property being set but we don't want to do anything 13043034Sdougm * SMF related at this point. 13053034Sdougm */ 13063034Sdougm sa_free_attr_string(groupname); 13073034Sdougm return (ret); 13083034Sdougm } 13093034Sdougm } 13103034Sdougm 13113034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 13123034Sdougm propstring = malloc(proplen); 13133034Sdougm if (propstring == NULL) 13143034Sdougm ret = SA_NO_MEMORY; 13153034Sdougm 13163034Sdougm if (groupname != NULL && ret == SA_OK) { 13173034Sdougm ret = sa_get_instance(handle, groupname); 13183034Sdougm sa_free_attr_string(groupname); 13193034Sdougm groupname = NULL; 13203034Sdougm sharename = sa_get_share_attr(share, "id"); 13213034Sdougm if (sharename == NULL) { 13223034Sdougm /* slipped by */ 13233034Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 13243034Sdougm generate_unique_sharename(shname); 13253034Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 13263034Sdougm (xmlChar *)shname); 13273034Sdougm sharename = strdup(shname); 13283034Sdougm } 13293034Sdougm if (sharename != NULL) { 13303348Sdougm sigset_t old, new; 13313034Sdougm /* 13323348Sdougm * have a share name allocated so create a pgroup for 13333348Sdougm * it. It may already exist, but that is OK. In order 13343348Sdougm * to avoid creating a share pgroup that doesn't have 13353348Sdougm * a path property, block signals around the critical 13363348Sdougm * region of creating the share pgroup and props. 13373034Sdougm */ 13383348Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 13393348Sdougm (void) sigaddset(&new, SIGHUP); 13403348Sdougm (void) sigaddset(&new, SIGINT); 13413348Sdougm (void) sigaddset(&new, SIGQUIT); 13423348Sdougm (void) sigaddset(&new, SIGTSTP); 13433348Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 13443348Sdougm 13453034Sdougm ret = sa_create_pgroup(handle, sharename); 13463034Sdougm if (ret == SA_OK) { 13473034Sdougm /* 13483034Sdougm * now start the transaction for the 13493034Sdougm * properties that define this share. They may 13503034Sdougm * exist so attempt to update before create. 13513034Sdougm */ 13523034Sdougm ret = sa_start_transaction(handle, sharename); 13533034Sdougm } 13543034Sdougm if (ret == SA_OK) { 13553034Sdougm name = sa_get_share_attr(share, "path"); 13563034Sdougm if (name != NULL) { 13573034Sdougm /* there needs to be a path for a share to exist */ 13583034Sdougm ret = sa_set_property(handle, "path", name); 13593034Sdougm sa_free_attr_string(name); 13603034Sdougm } else { 13613034Sdougm ret = SA_NO_MEMORY; 13623034Sdougm } 13633034Sdougm } 13643034Sdougm if (ret == SA_OK) { 13653034Sdougm resource = sa_get_share_attr(share, "resource"); 13663034Sdougm if (resource != NULL) { 13673034Sdougm ret = sa_set_property(handle, "resource", resource); 13683034Sdougm sa_free_attr_string(resource); 13693034Sdougm } 13703034Sdougm } 13713034Sdougm if (ret == SA_OK) { 13723034Sdougm description = sa_get_share_description(share); 13733034Sdougm if (description != NULL) { 13743034Sdougm ret = sa_set_property(handle, "description", 13753034Sdougm description); 13763034Sdougm sa_free_share_description(description); 13773034Sdougm } 13783034Sdougm } 13793034Sdougm /* make sure we cleanup the transaction */ 13803034Sdougm if (ret == SA_OK) { 13813034Sdougm ret = sa_end_transaction(handle); 13823034Sdougm } else { 13833034Sdougm sa_abort_transaction(handle); 13843034Sdougm } 13853348Sdougm 13863348Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 13873348Sdougm 13883034Sdougm free(sharename); 13893034Sdougm } 13903034Sdougm } 13913034Sdougm if (ret == SA_SYSTEM_ERR) { 13923034Sdougm int err = scf_error(); 13933034Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 13943034Sdougm ret = SA_NO_PERMISSION; 13953034Sdougm } 13963034Sdougm if (propstring != NULL) 13973034Sdougm free(propstring); 13983034Sdougm if (groupname != NULL) 13993034Sdougm sa_free_attr_string(groupname); 14003034Sdougm 14013034Sdougm return (ret); 14023034Sdougm } 14033034Sdougm 14043034Sdougm /* 14053034Sdougm * sa_delete_share(handle, group, share) 14063034Sdougm * 14073034Sdougm * remove the specified share from the group (and service instance). 14083034Sdougm */ 14093034Sdougm 14103034Sdougm int 14113034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 14123034Sdougm { 14133034Sdougm int ret = SA_OK; 14143034Sdougm char *groupname = NULL; 14153034Sdougm char *shareid = NULL; 14163034Sdougm sa_optionset_t opt; 14173034Sdougm sa_security_t sec; 14183034Sdougm ssize_t proplen; 14193034Sdougm char *propstring; 14203034Sdougm 14213034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 14223034Sdougm propstring = malloc(proplen); 14233034Sdougm if (propstring == NULL) 14243034Sdougm ret = SA_NO_MEMORY; 14253034Sdougm 14263034Sdougm if (ret == SA_OK) { 14273034Sdougm groupname = sa_get_group_attr(group, "name"); 14283034Sdougm shareid = sa_get_share_attr(share, "id"); 14293034Sdougm if (groupname != NULL && shareid != NULL) { 14303034Sdougm ret = sa_get_instance(handle, groupname); 14313034Sdougm if (ret == SA_OK) { 14323034Sdougm /* if a share has properties, remove them */ 14333034Sdougm ret = sa_delete_pgroup(handle, shareid); 14343034Sdougm for (opt = sa_get_optionset(share, NULL); opt != NULL; 14353034Sdougm opt = sa_get_next_optionset(opt)) { 14363034Sdougm char *proto; 14373034Sdougm proto = sa_get_optionset_attr(opt, "type"); 14383034Sdougm if (proto != NULL) { 14393034Sdougm (void) snprintf(propstring, proplen, "%s_%s", 14403034Sdougm shareid, proto); 14413034Sdougm ret = sa_delete_pgroup(handle, propstring); 14423034Sdougm sa_free_attr_string(proto); 14433034Sdougm } else { 14443034Sdougm ret = SA_NO_MEMORY; 14453034Sdougm } 14463034Sdougm } 14473034Sdougm /* 14483034Sdougm * if a share has security/negotiable 14493034Sdougm * properties, remove them. 14503034Sdougm */ 14513034Sdougm for (sec = sa_get_security(share, NULL, NULL); sec != NULL; 14523034Sdougm sec = sa_get_next_security(sec)) { 14533034Sdougm char *proto; 14543034Sdougm char *sectype; 14553034Sdougm proto = sa_get_security_attr(sec, "type"); 14563034Sdougm sectype = sa_get_security_attr(sec, "sectype"); 14573034Sdougm if (proto != NULL && sectype != NULL) { 14583034Sdougm (void) snprintf(propstring, proplen, "%s_%s_%s", 14593034Sdougm shareid, 14603034Sdougm proto, sectype); 14613034Sdougm ret = sa_delete_pgroup(handle, propstring); 14623034Sdougm } else { 14633034Sdougm ret = SA_NO_MEMORY; 14643034Sdougm } 14653034Sdougm if (proto != NULL) 14663034Sdougm sa_free_attr_string(proto); 14673034Sdougm if (sectype != NULL) 14683034Sdougm sa_free_attr_string(sectype); 14693034Sdougm } 14703034Sdougm } 14713034Sdougm } else { 14723034Sdougm ret = SA_CONFIG_ERR; 14733034Sdougm } 14743034Sdougm } 14753034Sdougm if (groupname != NULL) 14763034Sdougm sa_free_attr_string(groupname); 14773034Sdougm if (shareid != NULL) 14783034Sdougm sa_free_attr_string(shareid); 14793034Sdougm if (propstring != NULL) 14803034Sdougm free(propstring); 14813034Sdougm 14823034Sdougm return (ret); 14833034Sdougm } 1484