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