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; 453910Sdougm 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 * 973910Sdougm 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) { 1073910Sdougm 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; 1283910Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, 1293910Sdougm "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 5453910Sdougm 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 5523910Sdougm 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, 5833910Sdougm 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 6443910Sdougm 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, 7233910Sdougm 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, 8633910Sdougm 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 /* 9303910Sdougm * 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*3973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 9383034Sdougm { 9393034Sdougm int ret = SA_OK; 9403034Sdougm scf_instance_t *instance; 9413034Sdougm scf_iter_t *iter; 9423034Sdougm char buff[BUFSIZ * 2]; 9433034Sdougm 9443034Sdougm instance = scf_instance_create(handle->handle); 9453034Sdougm iter = scf_iter_create(handle->handle); 946*3973Sdougm if (instance != NULL && iter != NULL) { 9473034Sdougm if ((ret = scf_iter_service_instances(iter, 9483034Sdougm handle->service)) == 0) { 9493034Sdougm while ((ret = scf_iter_next_instance(iter, 9503034Sdougm instance)) > 0) { 9513034Sdougm if (scf_instance_get_name(instance, buff, 9523034Sdougm sizeof (buff)) > 0) { 9533034Sdougm if (strcmp(buff, "default") == 0) 954*3973Sdougm sa_extract_defaults(root, handle, instance); 955*3973Sdougm ret = sa_extract_group(root, handle, instance, 9563910Sdougm sahandle); 9573034Sdougm } 9583034Sdougm } 9593034Sdougm } 9603034Sdougm } 961*3973Sdougm 9623034Sdougm /* always cleanup these */ 9633034Sdougm if (instance != NULL) 9643034Sdougm scf_instance_destroy(instance); 9653034Sdougm if (iter != NULL) 9663034Sdougm scf_iter_destroy(iter); 9673034Sdougm return (ret); 9683034Sdougm } 9693034Sdougm 9703034Sdougm /* 9713034Sdougm * sa_get_instance(handle, instance) 9723034Sdougm * 9733034Sdougm * get the instance of the group service. This is actually the 9743034Sdougm * specific group name. The instance is needed for all property and 9753034Sdougm * control operations. 9763034Sdougm */ 9773034Sdougm 9783034Sdougm int 9793034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 9803034Sdougm { 9813034Sdougm if (scf_service_get_instance(handle->service, instname, 9823034Sdougm handle->instance) != 0) { 9833034Sdougm return (SA_NO_SUCH_GROUP); 9843034Sdougm } 9853034Sdougm return (SA_OK); 9863034Sdougm } 9873034Sdougm 9883034Sdougm /* 9893034Sdougm * sa_create_instance(handle, instname) 9903034Sdougm * 9913034Sdougm * Create a new SMF service instance. There can only be one with a 9923034Sdougm * given name. 9933034Sdougm */ 9943034Sdougm 9953034Sdougm int 9963034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 9973034Sdougm { 9983034Sdougm int ret = SA_OK; 9993034Sdougm char instance[SA_GROUP_INST_LEN]; 10003034Sdougm if (scf_service_add_instance(handle->service, instname, 10013034Sdougm handle->instance) != 0) { 10023034Sdougm /* better error returns need to be added based on real error */ 10033034Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 10043034Sdougm ret = SA_NO_PERMISSION; 10053034Sdougm else 10063034Sdougm ret = SA_DUPLICATE_NAME; 10073034Sdougm } else { 10083034Sdougm /* have the service created, so enable it */ 10093034Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 10103034Sdougm SA_SVC_FMRI_BASE, instname); 10113034Sdougm (void) smf_enable_instance(instance, 0); 10123034Sdougm } 10133034Sdougm return (ret); 10143034Sdougm } 10153034Sdougm 10163034Sdougm /* 10173034Sdougm * sa_delete_instance(handle, instname) 10183034Sdougm * 10193034Sdougm * When a group goes away, we also remove the service instance. 10203034Sdougm */ 10213034Sdougm 10223034Sdougm int 10233034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 10243034Sdougm { 10253034Sdougm int ret; 10263034Sdougm 10273034Sdougm if (strcmp(instname, "default") == 0) { 10283034Sdougm ret = SA_NO_PERMISSION; 10293034Sdougm } else { 10303034Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 10313034Sdougm if (scf_instance_delete(handle->instance) != 0) 10323034Sdougm /* need better analysis */ 10333034Sdougm ret = SA_NO_PERMISSION; 10343034Sdougm } 10353034Sdougm } 10363034Sdougm return (ret); 10373034Sdougm } 10383034Sdougm 10393034Sdougm /* 10403034Sdougm * sa_create_pgroup(handle, pgroup) 10413034Sdougm * 10423034Sdougm * create a new property group 10433034Sdougm */ 10443034Sdougm 10453034Sdougm int 10463034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 10473034Sdougm { 10483034Sdougm int ret = SA_OK; 10493034Sdougm /* 10503034Sdougm * only create a handle if it doesn't exist. It is ok to exist 10513034Sdougm * since the pg handle will be set as a side effect. 10523034Sdougm */ 10533034Sdougm if (handle->pg == NULL) { 10543034Sdougm handle->pg = scf_pg_create(handle->handle); 10553034Sdougm } 10563034Sdougm /* 10573034Sdougm * if the pgroup exists, we are done. If it doesn't, then we 10583034Sdougm * need to actually add one to the service instance. 10593034Sdougm */ 10603034Sdougm if (scf_instance_get_pg(handle->instance, 10613034Sdougm pgroup, handle->pg) != 0) { 10623034Sdougm /* doesn't exist so create one */ 10633034Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 10643034Sdougm SCF_GROUP_APPLICATION, 0, 10653034Sdougm handle->pg) != 0) { 10663034Sdougm switch (scf_error()) { 10673034Sdougm case SCF_ERROR_PERMISSION_DENIED: 10683034Sdougm ret = SA_NO_PERMISSION; 10693034Sdougm break; 10703034Sdougm default: 10713034Sdougm ret = SA_SYSTEM_ERR; 10723034Sdougm break; 10733034Sdougm } 10743034Sdougm } 10753034Sdougm } 10763034Sdougm return (ret); 10773034Sdougm } 10783034Sdougm 10793034Sdougm /* 10803034Sdougm * sa_delete_pgroup(handle, pgroup) 10813034Sdougm * 10823034Sdougm * remove the property group from the current instance of the service, 10833034Sdougm * but only if it actually exists. 10843034Sdougm */ 10853034Sdougm 10863034Sdougm int 10873034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 10883034Sdougm { 10893034Sdougm int ret = SA_OK; 10903034Sdougm /* 10913034Sdougm * only delete if it does exist. 10923034Sdougm */ 10933034Sdougm if (scf_instance_get_pg(handle->instance, 10943034Sdougm pgroup, handle->pg) == 0) { 10953034Sdougm /* does exist so delete it */ 10963034Sdougm if (scf_pg_delete(handle->pg) != 0) { 10973034Sdougm ret = SA_SYSTEM_ERR; 10983034Sdougm } 10993034Sdougm } else { 11003034Sdougm ret = SA_SYSTEM_ERR; 11013034Sdougm } 11023034Sdougm if (ret == SA_SYSTEM_ERR && 11033034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11043034Sdougm ret = SA_NO_PERMISSION; 11053034Sdougm } 11063034Sdougm return (ret); 11073034Sdougm } 11083034Sdougm 11093034Sdougm /* 11103034Sdougm * sa_start_transaction(handle, pgroup) 11113034Sdougm * 11123034Sdougm * Start an SMF transaction so we can deal with properties. it would 11133034Sdougm * be nice to not have to expose this, but we have to in order to 11143034Sdougm * optimize. 11153034Sdougm * 11163034Sdougm * Basic model is to hold the transaction in the handle and allow 11173034Sdougm * property adds/deletes/updates to be added then close the 11183034Sdougm * transaction (or abort). There may eventually be a need to handle 11193034Sdougm * other types of transaction mechanisms but we don't do that now. 11203034Sdougm * 11213034Sdougm * An sa_start_transaction must be followed by either an 11223034Sdougm * sa_end_transaction or sa_abort_transaction before another 11233034Sdougm * sa_start_transaction can be done. 11243034Sdougm */ 11253034Sdougm 11263034Sdougm int 11273034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 11283034Sdougm { 11293034Sdougm int ret = SA_OK; 11303034Sdougm /* 11313034Sdougm * lookup the property group and create it if it doesn't already 11323034Sdougm * exist. 11333034Sdougm */ 11343034Sdougm if (handle->scf_state == SCH_STATE_INIT) { 11353034Sdougm ret = sa_create_pgroup(handle, propgroup); 11363034Sdougm if (ret == SA_OK) { 11373034Sdougm handle->trans = scf_transaction_create(handle->handle); 11383034Sdougm if (handle->trans != NULL) { 11393034Sdougm if (scf_transaction_start(handle->trans, handle->pg) != 0) { 11403034Sdougm ret = SA_SYSTEM_ERR; 11413034Sdougm } 11423034Sdougm if (ret != SA_OK) { 11433034Sdougm scf_transaction_destroy(handle->trans); 11443034Sdougm handle->trans = NULL; 11453034Sdougm } 11463034Sdougm } else { 11473034Sdougm ret = SA_SYSTEM_ERR; 11483034Sdougm } 11493034Sdougm } 11503034Sdougm } 11513034Sdougm if (ret == SA_SYSTEM_ERR && 11523034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11533034Sdougm ret = SA_NO_PERMISSION; 11543034Sdougm } 11553034Sdougm return (ret); 11563034Sdougm } 11573034Sdougm 11583034Sdougm /* 11593034Sdougm * sa_end_transaction(handle) 11603034Sdougm * 11613034Sdougm * Commit the changes that were added to the transaction in the 11623034Sdougm * handle. Do all necessary cleanup. 11633034Sdougm */ 11643034Sdougm 11653034Sdougm int 11663034Sdougm sa_end_transaction(scfutilhandle_t *handle) 11673034Sdougm { 11683034Sdougm int ret = SA_OK; 11693034Sdougm 11703034Sdougm if (handle->trans == NULL) { 11713034Sdougm ret = SA_SYSTEM_ERR; 11723034Sdougm } else { 11733034Sdougm if (scf_transaction_commit(handle->trans) < 0) 11743034Sdougm ret = SA_SYSTEM_ERR; 11753034Sdougm scf_transaction_destroy_children(handle->trans); 11763034Sdougm scf_transaction_destroy(handle->trans); 11773034Sdougm handle->trans = NULL; 11783034Sdougm } 11793034Sdougm return (ret); 11803034Sdougm } 11813034Sdougm 11823034Sdougm /* 11833034Sdougm * sa_abort_transaction(handle) 11843034Sdougm * 11853034Sdougm * Abort the changes that were added to the transaction in the 11863034Sdougm * handle. Do all necessary cleanup. 11873034Sdougm */ 11883034Sdougm 11893034Sdougm void 11903034Sdougm sa_abort_transaction(scfutilhandle_t *handle) 11913034Sdougm { 11923034Sdougm if (handle->trans != NULL) { 11933034Sdougm scf_transaction_reset_all(handle->trans); 11943034Sdougm scf_transaction_destroy_children(handle->trans); 11953034Sdougm scf_transaction_destroy(handle->trans); 11963034Sdougm handle->trans = NULL; 11973034Sdougm } 11983034Sdougm } 11993034Sdougm 12003034Sdougm /* 12013034Sdougm * sa_set_property(handle, prop, value) 12023034Sdougm * 12033034Sdougm * set a property transaction entry into the pending SMF transaction. 12043034Sdougm */ 12053034Sdougm 12063034Sdougm int 12073034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 12083034Sdougm { 12093034Sdougm int ret = SA_OK; 12103034Sdougm scf_value_t *value; 12113034Sdougm scf_transaction_entry_t *entry; 12123034Sdougm /* 12133034Sdougm * properties must be set in transactions and don't take 12143034Sdougm * effect until the transaction has been ended/committed. 12153034Sdougm */ 12163034Sdougm value = scf_value_create(handle->handle); 12173034Sdougm entry = scf_entry_create(handle->handle); 12183034Sdougm if (value != NULL && entry != NULL) { 12193034Sdougm if (scf_transaction_property_change(handle->trans, entry, 12203034Sdougm propname, 12213034Sdougm SCF_TYPE_ASTRING) == 0 || 12223034Sdougm scf_transaction_property_new(handle->trans, entry, 12233034Sdougm propname, 12243034Sdougm SCF_TYPE_ASTRING) == 0) { 12253034Sdougm if (scf_value_set_astring(value, valstr) == 0) { 12263034Sdougm if (scf_entry_add_value(entry, value) != 0) { 12273034Sdougm ret = SA_SYSTEM_ERR; 12283034Sdougm scf_value_destroy(value); 12293034Sdougm } 12303034Sdougm /* the value is in the transaction */ 12313034Sdougm value = NULL; 12323034Sdougm } else { 12333034Sdougm /* value couldn't be constructed */ 12343034Sdougm ret = SA_SYSTEM_ERR; 12353034Sdougm } 12363034Sdougm /* the entry is in the transaction */ 12373034Sdougm entry = NULL; 12383034Sdougm } else { 12393034Sdougm ret = SA_SYSTEM_ERR; 12403034Sdougm } 12413034Sdougm } else { 12423034Sdougm ret = SA_SYSTEM_ERR; 12433034Sdougm } 12443034Sdougm if (ret == SA_SYSTEM_ERR) { 12453034Sdougm switch (scf_error()) { 12463034Sdougm case SCF_ERROR_PERMISSION_DENIED: 12473034Sdougm ret = SA_NO_PERMISSION; 12483034Sdougm break; 12493034Sdougm } 12503034Sdougm } 12513034Sdougm /* 12523034Sdougm * cleanup if there were any errors that didn't leave these 12533034Sdougm * values where they would be cleaned up later. 12543034Sdougm */ 12553034Sdougm if (value != NULL) 12563034Sdougm scf_value_destroy(value); 12573034Sdougm if (entry != NULL) 12583034Sdougm scf_entry_destroy(entry); 12593034Sdougm return (ret); 12603034Sdougm } 12613034Sdougm 12623034Sdougm /* 12633034Sdougm * sa_commit_share(handle, group, share) 12643034Sdougm * 12653034Sdougm * commit this share to the repository. 12663034Sdougm * properties are added if they exist but can be added later. 12673034Sdougm * Need to add to dfstab and sharetab, if appropriate. 12683034Sdougm */ 12693034Sdougm int 12703034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 12713034Sdougm { 12723034Sdougm int ret = SA_OK; 12733034Sdougm char *groupname; 12743034Sdougm char *name; 12753034Sdougm char *resource; 12763034Sdougm char *description; 12773034Sdougm char *sharename; 12783034Sdougm ssize_t proplen; 12793034Sdougm char *propstring; 12803034Sdougm 12813034Sdougm /* 12823034Sdougm * don't commit in the zfs group. We do commit legacy 12833034Sdougm * (default) and all other groups/shares. ZFS is handled 12843034Sdougm * through the ZFS configuration rather than SMF. 12853034Sdougm */ 12863034Sdougm 12873034Sdougm groupname = sa_get_group_attr(group, "name"); 12883034Sdougm if (groupname != NULL) { 12893034Sdougm if (strcmp(groupname, "zfs") == 0) { 12903034Sdougm /* 12913034Sdougm * adding to the ZFS group will result in the sharenfs 12923034Sdougm * property being set but we don't want to do anything 12933034Sdougm * SMF related at this point. 12943034Sdougm */ 12953034Sdougm sa_free_attr_string(groupname); 12963034Sdougm return (ret); 12973034Sdougm } 12983034Sdougm } 12993034Sdougm 13003034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 13013034Sdougm propstring = malloc(proplen); 13023034Sdougm if (propstring == NULL) 13033034Sdougm ret = SA_NO_MEMORY; 13043034Sdougm 13053034Sdougm if (groupname != NULL && ret == SA_OK) { 13063034Sdougm ret = sa_get_instance(handle, groupname); 13073034Sdougm sa_free_attr_string(groupname); 13083034Sdougm groupname = NULL; 13093034Sdougm sharename = sa_get_share_attr(share, "id"); 13103034Sdougm if (sharename == NULL) { 13113034Sdougm /* slipped by */ 13123034Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 13133034Sdougm generate_unique_sharename(shname); 13143034Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 13153034Sdougm (xmlChar *)shname); 13163034Sdougm sharename = strdup(shname); 13173034Sdougm } 13183034Sdougm if (sharename != NULL) { 13193348Sdougm sigset_t old, new; 13203034Sdougm /* 13213348Sdougm * have a share name allocated so create a pgroup for 13223348Sdougm * it. It may already exist, but that is OK. In order 13233348Sdougm * to avoid creating a share pgroup that doesn't have 13243348Sdougm * a path property, block signals around the critical 13253348Sdougm * region of creating the share pgroup and props. 13263034Sdougm */ 13273348Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 13283348Sdougm (void) sigaddset(&new, SIGHUP); 13293348Sdougm (void) sigaddset(&new, SIGINT); 13303348Sdougm (void) sigaddset(&new, SIGQUIT); 13313348Sdougm (void) sigaddset(&new, SIGTSTP); 13323348Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 13333348Sdougm 13343034Sdougm ret = sa_create_pgroup(handle, sharename); 13353034Sdougm if (ret == SA_OK) { 13363034Sdougm /* 13373034Sdougm * now start the transaction for the 13383034Sdougm * properties that define this share. They may 13393034Sdougm * exist so attempt to update before create. 13403034Sdougm */ 13413034Sdougm ret = sa_start_transaction(handle, sharename); 13423034Sdougm } 13433034Sdougm if (ret == SA_OK) { 13443034Sdougm name = sa_get_share_attr(share, "path"); 13453034Sdougm if (name != NULL) { 13463034Sdougm /* there needs to be a path for a share to exist */ 13473034Sdougm ret = sa_set_property(handle, "path", name); 13483034Sdougm sa_free_attr_string(name); 13493034Sdougm } else { 13503034Sdougm ret = SA_NO_MEMORY; 13513034Sdougm } 13523034Sdougm } 13533034Sdougm if (ret == SA_OK) { 13543034Sdougm resource = sa_get_share_attr(share, "resource"); 13553034Sdougm if (resource != NULL) { 13563034Sdougm ret = sa_set_property(handle, "resource", resource); 13573034Sdougm sa_free_attr_string(resource); 13583034Sdougm } 13593034Sdougm } 13603034Sdougm if (ret == SA_OK) { 13613034Sdougm description = sa_get_share_description(share); 13623034Sdougm if (description != NULL) { 13633034Sdougm ret = sa_set_property(handle, "description", 13643034Sdougm description); 13653034Sdougm sa_free_share_description(description); 13663034Sdougm } 13673034Sdougm } 13683034Sdougm /* make sure we cleanup the transaction */ 13693034Sdougm if (ret == SA_OK) { 13703034Sdougm ret = sa_end_transaction(handle); 13713034Sdougm } else { 13723034Sdougm sa_abort_transaction(handle); 13733034Sdougm } 13743348Sdougm 13753348Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 13763348Sdougm 13773034Sdougm free(sharename); 13783034Sdougm } 13793034Sdougm } 13803034Sdougm if (ret == SA_SYSTEM_ERR) { 13813034Sdougm int err = scf_error(); 13823034Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 13833034Sdougm ret = SA_NO_PERMISSION; 13843034Sdougm } 13853034Sdougm if (propstring != NULL) 13863034Sdougm free(propstring); 13873034Sdougm if (groupname != NULL) 13883034Sdougm sa_free_attr_string(groupname); 13893034Sdougm 13903034Sdougm return (ret); 13913034Sdougm } 13923034Sdougm 13933034Sdougm /* 13943034Sdougm * sa_delete_share(handle, group, share) 13953034Sdougm * 13963034Sdougm * remove the specified share from the group (and service instance). 13973034Sdougm */ 13983034Sdougm 13993034Sdougm int 14003034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 14013034Sdougm { 14023034Sdougm int ret = SA_OK; 14033034Sdougm char *groupname = NULL; 14043034Sdougm char *shareid = NULL; 14053034Sdougm sa_optionset_t opt; 14063034Sdougm sa_security_t sec; 14073034Sdougm ssize_t proplen; 14083034Sdougm char *propstring; 14093034Sdougm 14103034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 14113034Sdougm propstring = malloc(proplen); 14123034Sdougm if (propstring == NULL) 14133034Sdougm ret = SA_NO_MEMORY; 14143034Sdougm 14153034Sdougm if (ret == SA_OK) { 14163034Sdougm groupname = sa_get_group_attr(group, "name"); 14173034Sdougm shareid = sa_get_share_attr(share, "id"); 14183034Sdougm if (groupname != NULL && shareid != NULL) { 14193034Sdougm ret = sa_get_instance(handle, groupname); 14203034Sdougm if (ret == SA_OK) { 14213034Sdougm /* if a share has properties, remove them */ 14223034Sdougm ret = sa_delete_pgroup(handle, shareid); 14233034Sdougm for (opt = sa_get_optionset(share, NULL); opt != NULL; 14243034Sdougm opt = sa_get_next_optionset(opt)) { 14253034Sdougm char *proto; 14263034Sdougm proto = sa_get_optionset_attr(opt, "type"); 14273034Sdougm if (proto != NULL) { 14283034Sdougm (void) snprintf(propstring, proplen, "%s_%s", 14293034Sdougm shareid, proto); 14303034Sdougm ret = sa_delete_pgroup(handle, propstring); 14313034Sdougm sa_free_attr_string(proto); 14323034Sdougm } else { 14333034Sdougm ret = SA_NO_MEMORY; 14343034Sdougm } 14353034Sdougm } 14363034Sdougm /* 14373034Sdougm * if a share has security/negotiable 14383034Sdougm * properties, remove them. 14393034Sdougm */ 14403034Sdougm for (sec = sa_get_security(share, NULL, NULL); sec != NULL; 14413034Sdougm sec = sa_get_next_security(sec)) { 14423034Sdougm char *proto; 14433034Sdougm char *sectype; 14443034Sdougm proto = sa_get_security_attr(sec, "type"); 14453034Sdougm sectype = sa_get_security_attr(sec, "sectype"); 14463034Sdougm if (proto != NULL && sectype != NULL) { 14473034Sdougm (void) snprintf(propstring, proplen, "%s_%s_%s", 14483034Sdougm shareid, 14493034Sdougm proto, sectype); 14503034Sdougm ret = sa_delete_pgroup(handle, propstring); 14513034Sdougm } else { 14523034Sdougm ret = SA_NO_MEMORY; 14533034Sdougm } 14543034Sdougm if (proto != NULL) 14553034Sdougm sa_free_attr_string(proto); 14563034Sdougm if (sectype != NULL) 14573034Sdougm sa_free_attr_string(sectype); 14583034Sdougm } 14593034Sdougm } 14603034Sdougm } else { 14613034Sdougm ret = SA_CONFIG_ERR; 14623034Sdougm } 14633034Sdougm } 14643034Sdougm if (groupname != NULL) 14653034Sdougm sa_free_attr_string(groupname); 14663034Sdougm if (shareid != NULL) 14673034Sdougm sa_free_attr_string(shareid); 14683034Sdougm if (propstring != NULL) 14693034Sdougm free(propstring); 14703034Sdougm 14713034Sdougm return (ret); 14723034Sdougm } 1473