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