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 * 61*4653Sdougm * 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) { 70*4653Sdougm int unbind = 0; 71*4653Sdougm if (handle->scope != NULL) { 72*4653Sdougm unbind = 1; 73*4653Sdougm scf_scope_destroy(handle->scope); 74*4653Sdougm } 75*4653Sdougm if (handle->instance != NULL) 76*4653Sdougm scf_instance_destroy(handle->instance); 77*4653Sdougm if (handle->service != NULL) 78*4653Sdougm scf_service_destroy(handle->service); 79*4653Sdougm if (handle->pg != NULL) 80*4653Sdougm scf_pg_destroy(handle->pg); 81*4653Sdougm if (handle->handle != NULL) { 82*4653Sdougm handle->scf_state = SCH_STATE_UNINIT; 83*4653Sdougm if (unbind) 84*4653Sdougm (void) scf_handle_unbind(handle->handle); 85*4653Sdougm scf_handle_destroy(handle->handle); 86*4653Sdougm } 87*4653Sdougm free(handle); 883034Sdougm } 893034Sdougm } 903034Sdougm 913034Sdougm /* 923034Sdougm * sa_scf_init() 933034Sdougm * 94*4653Sdougm * 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) 105*4653Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1063034Sdougm 1073034Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 108*4653Sdougm if (handle == NULL) 109*4653Sdougm return (handle); 1104345Sdougm 111*4653Sdougm ihandle->scfhandle = handle; 112*4653Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 113*4653Sdougm handle->handle = scf_handle_create(SCF_VERSION); 114*4653Sdougm if (handle->handle == NULL) { 1153034Sdougm free(handle); 1163034Sdougm handle = NULL; 1173034Sdougm (void) printf("libshare could not access SMF repository: %s\n", 118*4653Sdougm scf_strerror(scf_error())); 119*4653Sdougm return (handle); 1203034Sdougm } 121*4653Sdougm if (scf_handle_bind(handle->handle) != 0) 122*4653Sdougm goto err; 123*4653Sdougm 124*4653Sdougm handle->scope = scf_scope_create(handle->handle); 125*4653Sdougm handle->service = scf_service_create(handle->handle); 126*4653Sdougm handle->pg = scf_pg_create(handle->handle); 127*4653Sdougm 128*4653Sdougm /* Make sure we have sufficient SMF running */ 129*4653Sdougm handle->instance = scf_instance_create(handle->handle); 130*4653Sdougm if (handle->scope == NULL || handle->service == NULL || 131*4653Sdougm handle->pg == NULL || handle->instance == NULL) 132*4653Sdougm goto err; 133*4653Sdougm if (scf_handle_get_scope(handle->handle, 134*4653Sdougm SCF_SCOPE_LOCAL, handle->scope) != 0) 135*4653Sdougm goto err; 136*4653Sdougm if (scf_scope_get_service(handle->scope, 137*4653Sdougm SA_GROUP_SVC_NAME, handle->service) != 0) 138*4653Sdougm goto err; 139*4653Sdougm 140*4653Sdougm handle->scf_state = SCH_STATE_INIT; 141*4653Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 142*4653Sdougm char **protolist; 143*4653Sdougm int numprotos, i; 144*4653Sdougm sa_group_t defgrp; 145*4653Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 146*4653Sdougm if (defgrp != NULL) { 147*4653Sdougm numprotos = sa_get_protocols( 148*4653Sdougm &protolist); 149*4653Sdougm for (i = 0; i < numprotos; i++) 150*4653Sdougm (void) sa_create_optionset(defgrp, 151*4653Sdougm protolist[i]); 152*4653Sdougm if (protolist != NULL) 153*4653Sdougm free(protolist); 154*4653Sdougm } 155*4653Sdougm } 156*4653Sdougm 1573034Sdougm return (handle); 1583034Sdougm 159*4653Sdougm /* Error handling/unwinding */ 1603034Sdougm err: 1613034Sdougm (void) sa_scf_fini(handle); 1623034Sdougm (void) printf("libshare SMF initialization problem: %s\n", 163*4653Sdougm scf_strerror(scf_error())); 1643034Sdougm return (NULL); 1653034Sdougm } 1663034Sdougm 1673034Sdougm /* 1683034Sdougm * get_scf_limit(name) 1693034Sdougm * 1703034Sdougm * Since we use scf_limit a lot and do the same check and return the 1713034Sdougm * same value if it fails, implement as a function for code 1723034Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1733034Sdougm * (1024) so we have a reasonable default buffer size. 1743034Sdougm */ 1753034Sdougm static ssize_t 1763034Sdougm get_scf_limit(uint32_t name) 1773034Sdougm { 1783034Sdougm ssize_t vallen; 1793034Sdougm 1803034Sdougm vallen = scf_limit(name); 1813034Sdougm if (vallen == (ssize_t)-1) 182*4653Sdougm vallen = MAXPATHLEN; 1833034Sdougm return (vallen); 1843034Sdougm } 1853034Sdougm 1863034Sdougm /* 1873034Sdougm * skip_property(name) 1883034Sdougm * 189*4653Sdougm * Internal function to check to see if a property is an SMF magic 1903034Sdougm * property that needs to be skipped. 1913034Sdougm */ 1923034Sdougm static int 1933034Sdougm skip_property(char *name) 1943034Sdougm { 1953034Sdougm int i; 1963034Sdougm 1973034Sdougm for (i = 0; skip_props[i] != NULL; i++) 198*4653Sdougm if (strcmp(name, skip_props[i]) == 0) 1993034Sdougm return (1); 2003034Sdougm return (0); 2013034Sdougm } 2023034Sdougm 2033034Sdougm /* 2043034Sdougm * generate_unique_sharename(sharename) 2053034Sdougm * 2063034Sdougm * Shares are represented in SMF as property groups. Due to share 2073034Sdougm * paths containing characters that are not allowed in SMF names and 2083034Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2093034Sdougm */ 2103034Sdougm 2113034Sdougm static void 2123034Sdougm generate_unique_sharename(char *sharename) 2133034Sdougm { 2143034Sdougm uuid_t uuid; 2153034Sdougm 2163034Sdougm uuid_generate(uuid); 2173034Sdougm (void) strcpy(sharename, "S-"); 2183034Sdougm uuid_unparse(uuid, sharename + 2); 2193034Sdougm } 2203034Sdougm 2213034Sdougm /* 2223034Sdougm * valid_protocol(proto) 2233034Sdougm * 224*4653Sdougm * Check to see if the specified protocol is a valid one for the 2253034Sdougm * general sharemgr facility. We determine this by checking which 2263034Sdougm * plugin protocols were found. 2273034Sdougm */ 2283034Sdougm 2293034Sdougm static int 2303034Sdougm valid_protocol(char *proto) 2313034Sdougm { 2323034Sdougm struct sa_proto_plugin *plugin; 2333034Sdougm for (plugin = sap_proto_list; plugin != NULL; 2343034Sdougm plugin = plugin->plugin_next) 235*4653Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 236*4653Sdougm return (1); 2373034Sdougm return (0); 2383034Sdougm } 2393034Sdougm 2403034Sdougm /* 2413034Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2423034Sdougm * 243*4653Sdougm * Extract the name property group and create the specified type of 2443034Sdougm * node on the provided group. type will be optionset or security. 2453034Sdougm */ 2463034Sdougm 2473034Sdougm static int 2483034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2493034Sdougm scf_propertygroup_t *pg, 2503034Sdougm char *nodetype, char *proto, char *sectype) 2513034Sdougm { 2523034Sdougm xmlNodePtr node; 2533034Sdougm scf_iter_t *iter; 2543034Sdougm scf_property_t *prop; 2553034Sdougm scf_value_t *value; 2563034Sdougm char *name; 2573034Sdougm char *valuestr; 2583034Sdougm ssize_t vallen; 2593034Sdougm int ret = SA_OK; 2603034Sdougm 2613034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2623034Sdougm 2633034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 264*4653Sdougm if (node == NULL) 265*4653Sdougm return (ret); 266*4653Sdougm 267*4653Sdougm if (proto != NULL) 2683034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 269*4653Sdougm if (sectype != NULL) 2703034Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 271*4653Sdougm /* 272*4653Sdougm * Have node to work with so iterate over the properties 273*4653Sdougm * in the pg and create option sub nodes. 274*4653Sdougm */ 275*4653Sdougm iter = scf_iter_create(handle->handle); 276*4653Sdougm value = scf_value_create(handle->handle); 277*4653Sdougm prop = scf_property_create(handle->handle); 278*4653Sdougm name = malloc(scf_max_name_len); 279*4653Sdougm valuestr = malloc(vallen); 280*4653Sdougm /* 281*4653Sdougm * Want to iterate through the properties and add them 282*4653Sdougm * to the base optionset. 283*4653Sdougm */ 284*4653Sdougm if (iter == NULL || value == NULL || prop == NULL || 285*4653Sdougm valuestr == NULL || name == NULL) { 286*4653Sdougm ret = SA_NO_MEMORY; 287*4653Sdougm goto out; 288*4653Sdougm } 289*4653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 290*4653Sdougm /* Now iterate the properties in the group */ 291*4653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 292*4653Sdougm /* have a property */ 293*4653Sdougm if (scf_property_get_name(prop, name, 294*4653Sdougm scf_max_name_len) > 0) { 295*4653Sdougm sa_property_t saprop; 296*4653Sdougm /* Some properties are part of the framework */ 2973034Sdougm if (skip_property(name)) 298*4653Sdougm continue; 299*4653Sdougm if (scf_property_get_value(prop, value) != 0) 300*4653Sdougm continue; 301*4653Sdougm if (scf_value_get_astring(value, valuestr, 302*4653Sdougm vallen) < 0) 303*4653Sdougm continue; 304*4653Sdougm saprop = sa_create_property(name, valuestr); 305*4653Sdougm if (saprop != NULL) { 3063034Sdougm /* 307*4653Sdougm * Since in SMF, don't 3083034Sdougm * recurse. Use xmlAddChild 3093034Sdougm * directly, instead. 3103034Sdougm */ 311*4653Sdougm xmlAddChild(node, 312*4653Sdougm (xmlNodePtr) saprop); 3133034Sdougm } 3143034Sdougm } 3153034Sdougm } 3163034Sdougm } 317*4653Sdougm out: 318*4653Sdougm /* cleanup to avoid memory leaks */ 319*4653Sdougm if (value != NULL) 320*4653Sdougm scf_value_destroy(value); 321*4653Sdougm if (iter != NULL) 322*4653Sdougm scf_iter_destroy(iter); 323*4653Sdougm if (prop != NULL) 324*4653Sdougm scf_property_destroy(prop); 325*4653Sdougm if (name != NULL) 326*4653Sdougm free(name); 327*4653Sdougm if (valuestr != NULL) 328*4653Sdougm free(valuestr); 329*4653Sdougm 3303034Sdougm return (ret); 3313034Sdougm } 3323034Sdougm 3333034Sdougm /* 3343034Sdougm * sa_extract_attrs(root, handle, instance) 3353034Sdougm * 336*4653Sdougm * Local function to extract the actual attributes/properties from the 3373034Sdougm * property group of the service instance. These are the well known 3383034Sdougm * attributes of "state" and "zfs". If additional attributes are 3393034Sdougm * added, they should be added here. 3403034Sdougm */ 3413034Sdougm 3423034Sdougm static void 3433034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3443034Sdougm scf_instance_t *instance) 3453034Sdougm { 3463034Sdougm scf_property_t *prop; 3473034Sdougm scf_value_t *value; 3483034Sdougm char *valuestr; 3493034Sdougm ssize_t vallen; 3503034Sdougm 3513034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3523034Sdougm prop = scf_property_create(handle->handle); 3533034Sdougm value = scf_value_create(handle->handle); 3543034Sdougm valuestr = malloc(vallen); 355*4653Sdougm if (prop == NULL || value == NULL || valuestr == NULL || 356*4653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 357*4653Sdougm goto out; 358*4653Sdougm } 359*4653Sdougm /* 360*4653Sdougm * Have a property group with desired name so now get 361*4653Sdougm * the known attributes. 362*4653Sdougm */ 363*4653Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 364*4653Sdougm /* Found the property so get the value */ 3653034Sdougm if (scf_property_get_value(prop, value) == 0) { 366*4653Sdougm if (scf_value_get_astring(value, valuestr, 367*4653Sdougm vallen) >= 0) { 368*4653Sdougm xmlSetProp(root, (xmlChar *)"state", 3693034Sdougm (xmlChar *)valuestr); 370*4653Sdougm } 3713034Sdougm } 372*4653Sdougm } 373*4653Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 374*4653Sdougm /* Found the property so get the value */ 3753034Sdougm if (scf_property_get_value(prop, value) == 0) { 376*4653Sdougm if (scf_value_get_astring(value, valuestr, 377*4653Sdougm vallen) > 0) { 378*4653Sdougm xmlSetProp(root, (xmlChar *)"zfs", 3793034Sdougm (xmlChar *)valuestr); 380*4653Sdougm } 3813034Sdougm } 3823034Sdougm } 383*4653Sdougm out: 3843034Sdougm if (valuestr != NULL) 385*4653Sdougm free(valuestr); 3863034Sdougm if (value != NULL) 387*4653Sdougm scf_value_destroy(value); 3883034Sdougm if (prop != NULL) 389*4653Sdougm scf_property_destroy(prop); 3903034Sdougm } 3913034Sdougm 3923034Sdougm /* 393*4653Sdougm * List of known share attributes. 3943034Sdougm */ 3953034Sdougm 3963034Sdougm static char *share_attr[] = { 3973034Sdougm "path", 3983034Sdougm "id", 3993034Sdougm "resource", 4003034Sdougm NULL, 4013034Sdougm }; 4023034Sdougm 4033034Sdougm static int 4043034Sdougm is_share_attr(char *name) 4053034Sdougm { 4063034Sdougm int i; 4073034Sdougm for (i = 0; share_attr[i] != NULL; i++) 408*4653Sdougm if (strcmp(name, share_attr[i]) == 0) 409*4653Sdougm return (1); 4103034Sdougm return (0); 4113034Sdougm } 4123034Sdougm 4133034Sdougm /* 4143034Sdougm * sa_share_from_pgroup 4153034Sdougm * 416*4653Sdougm * Extract the share definition from the share property group. We do 4173034Sdougm * some sanity checking to avoid bad data. 4183034Sdougm * 4193034Sdougm * Since this is only constructing the internal data structures, we 4203034Sdougm * don't use the sa_* functions most of the time. 4213034Sdougm */ 4223034Sdougm void 4233034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4243034Sdougm scf_propertygroup_t *pg, char *id) 4253034Sdougm { 4263034Sdougm xmlNodePtr node; 4273034Sdougm char *name; 4283034Sdougm scf_iter_t *iter; 4293034Sdougm scf_property_t *prop; 4303034Sdougm scf_value_t *value; 4313034Sdougm ssize_t vallen; 4323034Sdougm char *valuestr; 4333034Sdougm int ret = SA_OK; 4343348Sdougm int have_path = 0; 4353034Sdougm 4363034Sdougm /* 4373034Sdougm * While preliminary check (starts with 'S') passed before 4383034Sdougm * getting here. Need to make sure it is in ID syntax 4393034Sdougm * (Snnnnnn). Note that shares with properties have similar 4403034Sdougm * pgroups. 4413034Sdougm */ 4423034Sdougm vallen = strlen(id); 4433034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 444*4653Sdougm uuid_t uuid; 445*4653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, 446*4653Sdougm SA_SHARE_PG_PREFIXLEN) != 0 || 447*4653Sdougm uuid_parse(id + 2, uuid) < 0) 448*4653Sdougm return; 449*4653Sdougm } else { 4503034Sdougm return; 4513034Sdougm } 4523034Sdougm 4533034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 4543034Sdougm 4553034Sdougm iter = scf_iter_create(handle->handle); 4563034Sdougm value = scf_value_create(handle->handle); 4573034Sdougm prop = scf_property_create(handle->handle); 4583034Sdougm name = malloc(scf_max_name_len); 4593034Sdougm valuestr = malloc(vallen); 4603034Sdougm 4613034Sdougm /* 462*4653Sdougm * Construct the share XML node. It is similar to sa_add_share 4633034Sdougm * but never changes the repository. Also, there won't be any 4643034Sdougm * ZFS or transient shares. Root will be the group it is 4653034Sdougm * associated with. 4663034Sdougm */ 4673034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 4683034Sdougm if (node != NULL) { 4693034Sdougm /* 470*4653Sdougm * Make sure the UUID part of the property group is 4713034Sdougm * stored in the share "id" property. We use this 4723034Sdougm * later. 4733034Sdougm */ 474*4653Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 475*4653Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 4763034Sdougm } 4773034Sdougm 478*4653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 479*4653Sdougm goto out; 480*4653Sdougm 481*4653Sdougm /* Iterate over the share pg properties */ 482*4653Sdougm if (scf_iter_pg_properties(iter, pg) != 0) 483*4653Sdougm goto out; 484*4653Sdougm 485*4653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 486*4653Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 487*4653Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 4883034Sdougm if (scf_property_get_value(prop, value) == 0) { 489*4653Sdougm if (scf_value_get_astring(value, valuestr, 490*4653Sdougm vallen) >= 0) { 491*4653Sdougm ret = SA_OK; 492*4653Sdougm } 4933034Sdougm } 494*4653Sdougm } 495*4653Sdougm if (ret == SA_OK) { 4963348Sdougm /* 497*4653Sdougm * Check that we have the "path" property in 4983348Sdougm * name. The string in name will always be nul 4993348Sdougm * terminated if scf_property_get_name() 5003348Sdougm * succeeded. 5013348Sdougm */ 5023348Sdougm if (strcmp(name, "path") == 0) 503*4653Sdougm have_path = 1; 5043034Sdougm if (is_share_attr(name)) { 5053034Sdougm /* 506*4653Sdougm * If a share attr, then simple - 5073034Sdougm * usually path and resource name 5083034Sdougm */ 509*4653Sdougm xmlSetProp(node, (xmlChar *)name, 510*4653Sdougm (xmlChar *)valuestr); 5113034Sdougm } else { 512*4653Sdougm if (strcmp(name, "description") == 0) { 513*4653Sdougm /* We have a description node */ 514*4653Sdougm xmlNodePtr desc; 515*4653Sdougm desc = xmlNewChild(node, NULL, 516*4653Sdougm (xmlChar *)"description", NULL); 517*4653Sdougm if (desc != NULL) 518*4653Sdougm xmlNodeSetContent(desc, 519*4653Sdougm (xmlChar *)valuestr); 520*4653Sdougm } 5213034Sdougm } 5223034Sdougm } 5233034Sdougm } 524*4653Sdougm out: 5253348Sdougm /* 526*4653Sdougm * A share without a path is broken so we want to not include 5273348Sdougm * these. They shouldn't happen but if you kill a sharemgr in 5283348Sdougm * the process of creating a share, it could happen. They 5293348Sdougm * should be harmless. It is also possible that another 5303348Sdougm * sharemgr is running and in the process of creating a share. 5313348Sdougm */ 5323348Sdougm if (have_path == 0 && node != NULL) { 533*4653Sdougm xmlUnlinkNode(node); 534*4653Sdougm xmlFreeNode(node); 5353348Sdougm } 5363034Sdougm if (name != NULL) 537*4653Sdougm free(name); 5383034Sdougm if (valuestr != NULL) 539*4653Sdougm free(valuestr); 5403034Sdougm if (value != NULL) 541*4653Sdougm scf_value_destroy(value); 5423034Sdougm if (iter != NULL) 543*4653Sdougm scf_iter_destroy(iter); 5443034Sdougm if (prop != NULL) 545*4653Sdougm scf_property_destroy(prop); 5463034Sdougm } 5473034Sdougm 5483034Sdougm /* 5493034Sdougm * find_share_by_id(shareid) 5503034Sdougm * 5513034Sdougm * Search all shares in all groups until we find the share represented 5523034Sdougm * by "id". 5533034Sdougm */ 5543034Sdougm 5553034Sdougm static sa_share_t 5563910Sdougm find_share_by_id(sa_handle_t handle, char *shareid) 5573034Sdougm { 5583034Sdougm sa_group_t group; 5593034Sdougm sa_share_t share = NULL; 5603034Sdougm char *id = NULL; 5613034Sdougm int done = 0; 5623034Sdougm 563*4653Sdougm for (group = sa_get_group(handle, NULL); 564*4653Sdougm group != NULL && !done; 565*4653Sdougm group = sa_get_next_group(group)) { 566*4653Sdougm for (share = sa_get_share(group, NULL); 567*4653Sdougm share != NULL; 568*4653Sdougm share = sa_get_next_share(share)) { 5693034Sdougm id = sa_get_share_attr(share, "id"); 5703034Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 5713034Sdougm sa_free_attr_string(id); 5723034Sdougm id = NULL; 5733034Sdougm done++; 5743034Sdougm break; 5753034Sdougm } 5763034Sdougm if (id != NULL) { 577*4653Sdougm sa_free_attr_string(id); 578*4653Sdougm id = NULL; 5793034Sdougm } 5803034Sdougm } 5813034Sdougm } 5823034Sdougm return (share); 5833034Sdougm } 5843034Sdougm 5853034Sdougm /* 5863034Sdougm * sa_share_props_from_pgroup(root, handle, pg, id) 5873034Sdougm * 588*4653Sdougm * Extract share properties from the SMF property group. More sanity 5893034Sdougm * checks are done and the share object is created. We ignore some 5903034Sdougm * errors that could exist in the repository and only worry about 5913034Sdougm * property groups that validate in naming. 5923034Sdougm */ 5933034Sdougm 5943034Sdougm static int 5953034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 5963910Sdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 5973034Sdougm { 5983034Sdougm xmlNodePtr node; 599*4653Sdougm char *name = NULL; 600*4653Sdougm scf_iter_t *iter = NULL; 601*4653Sdougm scf_property_t *prop = NULL; 602*4653Sdougm scf_value_t *value = NULL; 6033034Sdougm ssize_t vallen; 604*4653Sdougm char *valuestr = NULL; 6053034Sdougm int ret = SA_OK; 6063034Sdougm char *sectype = NULL; 6073034Sdougm char *proto; 6083034Sdougm sa_share_t share; 609*4653Sdougm uuid_t uuid; 6103034Sdougm 6113034Sdougm /* 6123034Sdougm * While preliminary check (starts with 'S') passed before 6133034Sdougm * getting here. Need to make sure it is in ID syntax 6143034Sdougm * (Snnnnnn). Note that shares with properties have similar 6153034Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 6163034Sdougm * characters, it is likely one of the protocol/security 6173034Sdougm * versions. 6183034Sdougm */ 6193034Sdougm vallen = strlen(id); 620*4653Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 621*4653Sdougm /* 622*4653Sdougm * It is ok to not have what we thought since someone might 623*4653Sdougm * have added a name via SMF. 624*4653Sdougm */ 625*4653Sdougm return (ret); 626*4653Sdougm } 627*4653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 6283034Sdougm proto = strchr(id, '_'); 6293034Sdougm if (proto == NULL) 630*4653Sdougm return (ret); 6313034Sdougm *proto++ = '\0'; 6323034Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 633*4653Sdougm return (ret); 6343034Sdougm /* 6353034Sdougm * probably a legal optionset so check a few more 6363034Sdougm * syntax points below. 6373034Sdougm */ 6383034Sdougm if (*proto == '\0') { 639*4653Sdougm /* not a valid proto (null) */ 640*4653Sdougm return (ret); 6413034Sdougm } 6423034Sdougm sectype = strchr(proto, '_'); 6433034Sdougm if (sectype != NULL) 644*4653Sdougm *sectype++ = '\0'; 6453034Sdougm if (!valid_protocol(proto)) 646*4653Sdougm return (ret); 6473034Sdougm } 6483034Sdougm 6493034Sdougm /* 650*4653Sdougm * To get here, we have a valid protocol and possibly a 6513034Sdougm * security. We now have to find the share that it is really 6523034Sdougm * associated with. The "id" portion of the pgroup name will 6533034Sdougm * match. 6543034Sdougm */ 6553034Sdougm 6563910Sdougm share = find_share_by_id(sahandle, id); 6573034Sdougm if (share == NULL) 658*4653Sdougm return (SA_BAD_PATH); 6593034Sdougm 6603034Sdougm root = (xmlNodePtr)share; 6613034Sdougm 6623034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 6633034Sdougm 664*4653Sdougm if (sectype == NULL) 665*4653Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 666*4653Sdougm else { 667*4653Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL); 668*4653Sdougm if (node != NULL) 669*4653Sdougm xmlSetProp(node, (xmlChar *)"sectype", 670*4653Sdougm (xmlChar *)sectype); 671*4653Sdougm } 672*4653Sdougm if (node == NULL) { 673*4653Sdougm ret = SA_NO_MEMORY; 674*4653Sdougm goto out; 675*4653Sdougm } 676*4653Sdougm 677*4653Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 678*4653Sdougm /* now find the properties */ 6793034Sdougm iter = scf_iter_create(handle->handle); 6803034Sdougm value = scf_value_create(handle->handle); 6813034Sdougm prop = scf_property_create(handle->handle); 6823034Sdougm name = malloc(scf_max_name_len); 6833034Sdougm valuestr = malloc(vallen); 6843034Sdougm 685*4653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 686*4653Sdougm goto out; 687*4653Sdougm 688*4653Sdougm /* Iterate over the share pg properties */ 689*4653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 690*4653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 6913034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 6923034Sdougm if (scf_property_get_name(prop, name, 693*4653Sdougm scf_max_name_len) > 0) { 694*4653Sdougm if (scf_property_get_value(prop, value) == 0) { 695*4653Sdougm if (scf_value_get_astring(value, 696*4653Sdougm valuestr, vallen) >= 0) { 697*4653Sdougm ret = SA_OK; 698*4653Sdougm } 6993034Sdougm } 7003034Sdougm } else { 701*4653Sdougm ret = SA_SYSTEM_ERR; 7023034Sdougm } 7033034Sdougm if (ret == SA_OK) { 704*4653Sdougm sa_property_t prop; 705*4653Sdougm prop = sa_create_property(name, valuestr); 706*4653Sdougm if (prop != NULL) 707*4653Sdougm prop = (sa_property_t)xmlAddChild(node, 708*4653Sdougm (xmlNodePtr)prop); 709*4653Sdougm else 710*4653Sdougm ret = SA_NO_MEMORY; 7113034Sdougm } 7123034Sdougm } 7133034Sdougm } else { 714*4653Sdougm ret = SA_SYSTEM_ERR; 7153034Sdougm } 716*4653Sdougm out: 7173034Sdougm if (iter != NULL) 718*4653Sdougm scf_iter_destroy(iter); 7193034Sdougm if (value != NULL) 720*4653Sdougm scf_value_destroy(value); 7213034Sdougm if (prop != NULL) 722*4653Sdougm scf_property_destroy(prop); 7233034Sdougm if (name != NULL) 724*4653Sdougm free(name); 7253034Sdougm if (valuestr != NULL) 726*4653Sdougm free(valuestr); 7273034Sdougm return (ret); 7283034Sdougm } 7293034Sdougm 7303034Sdougm /* 7313034Sdougm * sa_extract_group(root, handle, instance) 7323034Sdougm * 733*4653Sdougm * Get the config info for this instance of a group and create the XML 7343034Sdougm * subtree from it. 7353034Sdougm */ 7363034Sdougm 7373034Sdougm static int 7383034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 7393910Sdougm scf_instance_t *instance, sa_handle_t sahandle) 7403034Sdougm { 7413034Sdougm char *buff; 7423034Sdougm xmlNodePtr node; 7433034Sdougm scf_iter_t *iter; 7443034Sdougm char *proto; 7453034Sdougm char *sectype; 7463034Sdougm int have_shares = 0; 7473034Sdougm int has_proto = 0; 7483034Sdougm int is_default = 0; 7493034Sdougm int ret = SA_OK; 7503034Sdougm int err; 7513034Sdougm 7523034Sdougm buff = malloc(scf_max_name_len); 753*4653Sdougm if (buff == NULL) 754*4653Sdougm return (SA_NO_MEMORY); 755*4653Sdougm 7563034Sdougm iter = scf_iter_create(handle->handle); 757*4653Sdougm if (iter == NULL) { 758*4653Sdougm ret = SA_NO_MEMORY; 759*4653Sdougm goto out; 760*4653Sdougm } 761*4653Sdougm 762*4653Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 7633034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 764*4653Sdougm if (node == NULL) { 765*4653Sdougm ret = SA_NO_MEMORY; 766*4653Sdougm goto out; 767*4653Sdougm } 768*4653Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 769*4653Sdougm if (strcmp(buff, "default") == 0) 7703034Sdougm is_default++; 771*4653Sdougm 772*4653Sdougm sa_extract_attrs(node, handle, instance); 773*4653Sdougm /* 774*4653Sdougm * Iterate through all the property groups 775*4653Sdougm * looking for those with security or 776*4653Sdougm * optionset prefixes. The names of the 777*4653Sdougm * matching pgroups are parsed to get the 778*4653Sdougm * protocol, and for security, the sectype. 779*4653Sdougm * Syntax is as follows: 780*4653Sdougm * optionset | optionset_<proto> 781*4653Sdougm * security_default | security_<proto>_<sectype> 782*4653Sdougm * "operation" is handled by 783*4653Sdougm * sa_extract_attrs(). 784*4653Sdougm */ 785*4653Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) { 786*4653Sdougm ret = SA_NO_MEMORY; 787*4653Sdougm goto out; 788*4653Sdougm } 789*4653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 790*4653Sdougm /* Have a pgroup so sort it out */ 791*4653Sdougm ret = scf_pg_get_name(handle->pg, buff, 792*4653Sdougm scf_max_name_len); 793*4653Sdougm if (ret > 0) { 794*4653Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 7953034Sdougm sa_share_from_pgroup(node, handle, 796*4653Sdougm handle->pg, buff); 7973034Sdougm have_shares++; 798*4653Sdougm } else if (strncmp(buff, "optionset", 9) == 799*4653Sdougm 0) { 8003034Sdougm char *nodetype = "optionset"; 801*4653Sdougm /* Have an optionset */ 8023034Sdougm sectype = NULL; 8033034Sdougm proto = strchr(buff, '_'); 8043034Sdougm if (proto != NULL) { 805*4653Sdougm *proto++ = '\0'; 806*4653Sdougm sectype = strchr(proto, '_'); 807*4653Sdougm if (sectype != NULL) { 808*4653Sdougm *sectype++ = '\0'; 809*4653Sdougm nodetype = "security"; 810*4653Sdougm } 8113034Sdougm } 8123034Sdougm ret = sa_extract_pgroup(node, handle, 813*4653Sdougm handle->pg, nodetype, proto, 814*4653Sdougm sectype); 8153034Sdougm has_proto++; 816*4653Sdougm } else if (strncmp(buff, "security", 8) == 0) { 8173034Sdougm /* 818*4653Sdougm * Have a security (note that 8193034Sdougm * this should change in the 8203034Sdougm * future) 8213034Sdougm */ 8223034Sdougm proto = strchr(buff, '_'); 8233034Sdougm sectype = NULL; 8243034Sdougm if (proto != NULL) { 825*4653Sdougm *proto++ = '\0'; 826*4653Sdougm sectype = strchr(proto, '_'); 827*4653Sdougm if (sectype != NULL) 828*4653Sdougm *sectype++ = '\0'; 829*4653Sdougm if (strcmp(proto, "default") == 830*4653Sdougm 0) 831*4653Sdougm proto = NULL; 8323034Sdougm } 8333034Sdougm ret = sa_extract_pgroup(node, handle, 834*4653Sdougm handle->pg, "security", proto, 835*4653Sdougm sectype); 8363034Sdougm has_proto++; 8373034Sdougm } 838*4653Sdougm /* Ignore everything else */ 8393034Sdougm } 840*4653Sdougm } 841*4653Sdougm /* 842*4653Sdougm * Make sure we have a valid default group. 843*4653Sdougm * On first boot, default won't have any 844*4653Sdougm * protocols defined and won't be enabled (but 845*4653Sdougm * should be). 846*4653Sdougm */ 847*4653Sdougm if (is_default) { 848*4653Sdougm char *state = sa_get_group_attr((sa_group_t)node, 849*4653Sdougm "state"); 850*4653Sdougm char **protos; 851*4653Sdougm int numprotos; 852*4653Sdougm int i; 8533034Sdougm 854*4653Sdougm if (state == NULL) { 8553034Sdougm /* set attribute to enabled */ 8563034Sdougm (void) sa_set_group_attr((sa_group_t)node, 857*4653Sdougm "state", "enabled"); 858*4653Sdougm /* We can assume no protocols */ 8593034Sdougm numprotos = sa_get_protocols(&protos); 8603034Sdougm for (i = 0; i < numprotos; i++) 861*4653Sdougm (void) sa_create_optionset( 862*4653Sdougm (sa_group_t)node, protos[i]); 8633034Sdougm if (numprotos > 0) 864*4653Sdougm free(protos); 865*4653Sdougm } else { 8663034Sdougm sa_free_attr_string(state); 8673034Sdougm } 868*4653Sdougm } 869*4653Sdougm /* Do a second pass if shares were found */ 870*4653Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 871*4653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 8723034Sdougm /* 873*4653Sdougm * Have a pgroup so see if it is a 8743034Sdougm * share optionset 8753034Sdougm */ 8763034Sdougm err = scf_pg_get_name(handle->pg, buff, 877*4653Sdougm scf_max_name_len); 878*4653Sdougm if (err <= 0) 879*4653Sdougm continue; 880*4653Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 8813034Sdougm ret = sa_share_props_from_pgroup(node, 882*4653Sdougm handle, handle->pg, buff, 883*4653Sdougm sahandle); 8843034Sdougm } 8853034Sdougm } 8863034Sdougm } 8873034Sdougm } 888*4653Sdougm out: 8893034Sdougm if (iter != NULL) 890*4653Sdougm scf_iter_destroy(iter); 8913034Sdougm if (buff != NULL) 892*4653Sdougm free(buff); 8933034Sdougm return (ret); 8943034Sdougm } 8953034Sdougm 8963034Sdougm /* 8973034Sdougm * sa_extract_defaults(root, handle, instance) 8983034Sdougm * 899*4653Sdougm * Local function to find the default properties that live in the 9003034Sdougm * default instance's "operation" proprerty group. 9013034Sdougm */ 9023034Sdougm 9033034Sdougm static void 9043034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 9053034Sdougm scf_instance_t *instance) 9063034Sdougm { 9073034Sdougm xmlNodePtr node; 9083034Sdougm scf_property_t *prop; 9093034Sdougm scf_value_t *value; 9103034Sdougm char *valuestr; 9113034Sdougm ssize_t vallen; 9123034Sdougm 9133034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 9143034Sdougm prop = scf_property_create(handle->handle); 9153034Sdougm value = scf_value_create(handle->handle); 9163034Sdougm valuestr = malloc(vallen); 917*4653Sdougm 918*4653Sdougm if (prop == NULL || value == NULL || vallen == 0 || 919*4653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) 920*4653Sdougm goto out; 921*4653Sdougm 922*4653Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 923*4653Sdougm goto out; 924*4653Sdougm 925*4653Sdougm /* Found the property so get the value */ 926*4653Sdougm if (scf_property_get_value(prop, value) == 0) { 927*4653Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 9283034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 929*4653Sdougm NULL); 9303034Sdougm if (node != NULL) { 931*4653Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 932*4653Sdougm (xmlChar *)valuestr); 933*4653Sdougm xmlSetProp(node, (xmlChar *)"path", 934*4653Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 9353034Sdougm } 9363034Sdougm } 9373034Sdougm } 938*4653Sdougm out: 9393034Sdougm if (valuestr != NULL) 940*4653Sdougm free(valuestr); 9413034Sdougm if (value != NULL) 942*4653Sdougm scf_value_destroy(value); 9433034Sdougm if (prop != NULL) 944*4653Sdougm scf_property_destroy(prop); 9453034Sdougm } 9463034Sdougm 9473034Sdougm 9483034Sdougm /* 9493910Sdougm * sa_get_config(handle, root, doc, sahandlec) 9503034Sdougm * 951*4653Sdougm * Walk the SMF repository for /network/shares/group and find all the 9523034Sdougm * instances. These become group names. Then add the XML structure 9533034Sdougm * below the groups based on property groups and properties. 9543034Sdougm */ 9553034Sdougm int 9563973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 9573034Sdougm { 9583034Sdougm int ret = SA_OK; 9593034Sdougm scf_instance_t *instance; 9603034Sdougm scf_iter_t *iter; 9613034Sdougm char buff[BUFSIZ * 2]; 9623034Sdougm 9633034Sdougm instance = scf_instance_create(handle->handle); 9643034Sdougm iter = scf_iter_create(handle->handle); 9653973Sdougm if (instance != NULL && iter != NULL) { 966*4653Sdougm if ((ret = scf_iter_service_instances(iter, 967*4653Sdougm handle->service)) == 0) { 968*4653Sdougm while ((ret = scf_iter_next_instance(iter, 969*4653Sdougm instance)) > 0) { 970*4653Sdougm if (scf_instance_get_name(instance, buff, 971*4653Sdougm sizeof (buff)) > 0) { 972*4653Sdougm if (strcmp(buff, "default") == 0) 973*4653Sdougm sa_extract_defaults(root, 974*4653Sdougm handle, instance); 975*4653Sdougm ret = sa_extract_group(root, handle, 976*4653Sdougm instance, sahandle); 977*4653Sdougm } 978*4653Sdougm } 9793034Sdougm } 9803034Sdougm } 9813973Sdougm 982*4653Sdougm /* Always cleanup these */ 9833034Sdougm if (instance != NULL) 984*4653Sdougm scf_instance_destroy(instance); 9853034Sdougm if (iter != NULL) 986*4653Sdougm scf_iter_destroy(iter); 9873034Sdougm return (ret); 9883034Sdougm } 9893034Sdougm 9903034Sdougm /* 9913034Sdougm * sa_get_instance(handle, instance) 9923034Sdougm * 993*4653Sdougm * Get the instance of the group service. This is actually the 9943034Sdougm * specific group name. The instance is needed for all property and 9953034Sdougm * control operations. 9963034Sdougm */ 9973034Sdougm 9983034Sdougm int 9993034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 10003034Sdougm { 10013034Sdougm if (scf_service_get_instance(handle->service, instname, 1002*4653Sdougm handle->instance) != 0) { 1003*4653Sdougm return (SA_NO_SUCH_GROUP); 10043034Sdougm } 10053034Sdougm return (SA_OK); 10063034Sdougm } 10073034Sdougm 10083034Sdougm /* 10093034Sdougm * sa_create_instance(handle, instname) 10103034Sdougm * 10113034Sdougm * Create a new SMF service instance. There can only be one with a 10123034Sdougm * given name. 10133034Sdougm */ 10143034Sdougm 10153034Sdougm int 10163034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 10173034Sdougm { 10183034Sdougm int ret = SA_OK; 10193034Sdougm char instance[SA_GROUP_INST_LEN]; 10203034Sdougm if (scf_service_add_instance(handle->service, instname, 1021*4653Sdougm handle->instance) != 0) { 10223034Sdougm /* better error returns need to be added based on real error */ 1023*4653Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 1024*4653Sdougm ret = SA_NO_PERMISSION; 1025*4653Sdougm else 1026*4653Sdougm ret = SA_DUPLICATE_NAME; 10273034Sdougm } else { 1028*4653Sdougm /* have the service created, so enable it */ 1029*4653Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 1030*4653Sdougm SA_SVC_FMRI_BASE, instname); 1031*4653Sdougm (void) smf_enable_instance(instance, 0); 10323034Sdougm } 10333034Sdougm return (ret); 10343034Sdougm } 10353034Sdougm 10363034Sdougm /* 10373034Sdougm * sa_delete_instance(handle, instname) 10383034Sdougm * 10393034Sdougm * When a group goes away, we also remove the service instance. 10403034Sdougm */ 10413034Sdougm 10423034Sdougm int 10433034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 10443034Sdougm { 10453034Sdougm int ret; 10463034Sdougm 10473034Sdougm if (strcmp(instname, "default") == 0) { 1048*4653Sdougm ret = SA_NO_PERMISSION; 10493034Sdougm } else { 1050*4653Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 1051*4653Sdougm if (scf_instance_delete(handle->instance) != 0) 1052*4653Sdougm /* need better analysis */ 1053*4653Sdougm ret = SA_NO_PERMISSION; 1054*4653Sdougm } 10553034Sdougm } 10563034Sdougm return (ret); 10573034Sdougm } 10583034Sdougm 10593034Sdougm /* 10603034Sdougm * sa_create_pgroup(handle, pgroup) 10613034Sdougm * 10623034Sdougm * create a new property group 10633034Sdougm */ 10643034Sdougm 10653034Sdougm int 10663034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 10673034Sdougm { 10683034Sdougm int ret = SA_OK; 10693034Sdougm /* 1070*4653Sdougm * Only create a handle if it doesn't exist. It is ok to exist 10713034Sdougm * since the pg handle will be set as a side effect. 10723034Sdougm */ 1073*4653Sdougm if (handle->pg == NULL) 1074*4653Sdougm handle->pg = scf_pg_create(handle->handle); 1075*4653Sdougm 10763034Sdougm /* 1077*4653Sdougm * If the pgroup exists, we are done. If it doesn't, then we 10783034Sdougm * need to actually add one to the service instance. 10793034Sdougm */ 10803034Sdougm if (scf_instance_get_pg(handle->instance, 1081*4653Sdougm pgroup, handle->pg) != 0) { 1082*4653Sdougm /* Doesn't exist so create one */ 1083*4653Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 1084*4653Sdougm SCF_GROUP_APPLICATION, 0, handle->pg) != 0) { 1085*4653Sdougm switch (scf_error()) { 1086*4653Sdougm case SCF_ERROR_PERMISSION_DENIED: 1087*4653Sdougm ret = SA_NO_PERMISSION; 1088*4653Sdougm break; 1089*4653Sdougm default: 1090*4653Sdougm ret = SA_SYSTEM_ERR; 1091*4653Sdougm break; 1092*4653Sdougm } 10933034Sdougm } 10943034Sdougm } 10953034Sdougm return (ret); 10963034Sdougm } 10973034Sdougm 10983034Sdougm /* 10993034Sdougm * sa_delete_pgroup(handle, pgroup) 11003034Sdougm * 1101*4653Sdougm * Remove the property group from the current instance of the service, 11023034Sdougm * but only if it actually exists. 11033034Sdougm */ 11043034Sdougm 11053034Sdougm int 11063034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 11073034Sdougm { 11083034Sdougm int ret = SA_OK; 11093034Sdougm /* 1110*4653Sdougm * Only delete if it does exist. 11113034Sdougm */ 1112*4653Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 1113*4653Sdougm /* does exist so delete it */ 1114*4653Sdougm if (scf_pg_delete(handle->pg) != 0) 1115*4653Sdougm ret = SA_SYSTEM_ERR; 1116*4653Sdougm } else { 11173034Sdougm ret = SA_SYSTEM_ERR; 11183034Sdougm } 11193034Sdougm if (ret == SA_SYSTEM_ERR && 11203034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11213034Sdougm ret = SA_NO_PERMISSION; 11223034Sdougm } 11233034Sdougm return (ret); 11243034Sdougm } 11253034Sdougm 11263034Sdougm /* 11273034Sdougm * sa_start_transaction(handle, pgroup) 11283034Sdougm * 11293034Sdougm * Start an SMF transaction so we can deal with properties. it would 11303034Sdougm * be nice to not have to expose this, but we have to in order to 11313034Sdougm * optimize. 11323034Sdougm * 11333034Sdougm * Basic model is to hold the transaction in the handle and allow 11343034Sdougm * property adds/deletes/updates to be added then close the 11353034Sdougm * transaction (or abort). There may eventually be a need to handle 11363034Sdougm * other types of transaction mechanisms but we don't do that now. 11373034Sdougm * 11383034Sdougm * An sa_start_transaction must be followed by either an 11393034Sdougm * sa_end_transaction or sa_abort_transaction before another 11403034Sdougm * sa_start_transaction can be done. 11413034Sdougm */ 11423034Sdougm 11433034Sdougm int 11443034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 11453034Sdougm { 11463034Sdougm int ret = SA_OK; 11473034Sdougm /* 1148*4653Sdougm * Lookup the property group and create it if it doesn't already 11493034Sdougm * exist. 11503034Sdougm */ 11513034Sdougm if (handle->scf_state == SCH_STATE_INIT) { 1152*4653Sdougm ret = sa_create_pgroup(handle, propgroup); 1153*4653Sdougm if (ret == SA_OK) { 1154*4653Sdougm handle->trans = scf_transaction_create(handle->handle); 1155*4653Sdougm if (handle->trans != NULL) { 1156*4653Sdougm if (scf_transaction_start(handle->trans, 1157*4653Sdougm handle->pg) != 0) { 1158*4653Sdougm ret = SA_SYSTEM_ERR; 1159*4653Sdougm } 1160*4653Sdougm if (ret != SA_OK) { 1161*4653Sdougm scf_transaction_destroy(handle->trans); 1162*4653Sdougm handle->trans = NULL; 1163*4653Sdougm } 1164*4653Sdougm } else { 1165*4653Sdougm ret = SA_SYSTEM_ERR; 1166*4653Sdougm } 11673034Sdougm } 11683034Sdougm } 11693034Sdougm if (ret == SA_SYSTEM_ERR && 11703034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11713034Sdougm ret = SA_NO_PERMISSION; 11723034Sdougm } 11733034Sdougm return (ret); 11743034Sdougm } 11753034Sdougm 11763034Sdougm /* 11773034Sdougm * sa_end_transaction(handle) 11783034Sdougm * 11793034Sdougm * Commit the changes that were added to the transaction in the 11803034Sdougm * handle. Do all necessary cleanup. 11813034Sdougm */ 11823034Sdougm 11833034Sdougm int 11843034Sdougm sa_end_transaction(scfutilhandle_t *handle) 11853034Sdougm { 11863034Sdougm int ret = SA_OK; 11873034Sdougm 11883034Sdougm if (handle->trans == NULL) { 1189*4653Sdougm ret = SA_SYSTEM_ERR; 11903034Sdougm } else { 1191*4653Sdougm if (scf_transaction_commit(handle->trans) < 0) 1192*4653Sdougm ret = SA_SYSTEM_ERR; 1193*4653Sdougm scf_transaction_destroy_children(handle->trans); 1194*4653Sdougm scf_transaction_destroy(handle->trans); 1195*4653Sdougm handle->trans = NULL; 11963034Sdougm } 11973034Sdougm return (ret); 11983034Sdougm } 11993034Sdougm 12003034Sdougm /* 12013034Sdougm * sa_abort_transaction(handle) 12023034Sdougm * 12033034Sdougm * Abort the changes that were added to the transaction in the 12043034Sdougm * handle. Do all necessary cleanup. 12053034Sdougm */ 12063034Sdougm 12073034Sdougm void 12083034Sdougm sa_abort_transaction(scfutilhandle_t *handle) 12093034Sdougm { 12103034Sdougm if (handle->trans != NULL) { 1211*4653Sdougm scf_transaction_reset_all(handle->trans); 1212*4653Sdougm scf_transaction_destroy_children(handle->trans); 1213*4653Sdougm scf_transaction_destroy(handle->trans); 1214*4653Sdougm handle->trans = NULL; 12153034Sdougm } 12163034Sdougm } 12173034Sdougm 12183034Sdougm /* 12193034Sdougm * sa_set_property(handle, prop, value) 12203034Sdougm * 1221*4653Sdougm * Set a property transaction entry into the pending SMF transaction. 12223034Sdougm */ 12233034Sdougm 12243034Sdougm int 12253034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 12263034Sdougm { 12273034Sdougm int ret = SA_OK; 12283034Sdougm scf_value_t *value; 12293034Sdougm scf_transaction_entry_t *entry; 12303034Sdougm /* 1231*4653Sdougm * Properties must be set in transactions and don't take 12323034Sdougm * effect until the transaction has been ended/committed. 12333034Sdougm */ 12343034Sdougm value = scf_value_create(handle->handle); 12353034Sdougm entry = scf_entry_create(handle->handle); 12363034Sdougm if (value != NULL && entry != NULL) { 1237*4653Sdougm if (scf_transaction_property_change(handle->trans, entry, 1238*4653Sdougm propname, SCF_TYPE_ASTRING) == 0 || 1239*4653Sdougm scf_transaction_property_new(handle->trans, entry, 1240*4653Sdougm propname, SCF_TYPE_ASTRING) == 0) { 1241*4653Sdougm if (scf_value_set_astring(value, valstr) == 0) { 1242*4653Sdougm if (scf_entry_add_value(entry, value) != 0) { 1243*4653Sdougm ret = SA_SYSTEM_ERR; 1244*4653Sdougm scf_value_destroy(value); 1245*4653Sdougm } 1246*4653Sdougm /* The value is in the transaction */ 1247*4653Sdougm value = NULL; 1248*4653Sdougm } else { 1249*4653Sdougm /* Value couldn't be constructed */ 1250*4653Sdougm ret = SA_SYSTEM_ERR; 1251*4653Sdougm } 1252*4653Sdougm /* The entry is in the transaction */ 1253*4653Sdougm entry = NULL; 1254*4653Sdougm } else { 12553034Sdougm ret = SA_SYSTEM_ERR; 12563034Sdougm } 1257*4653Sdougm } else { 12583034Sdougm ret = SA_SYSTEM_ERR; 12593034Sdougm } 12603034Sdougm if (ret == SA_SYSTEM_ERR) { 1261*4653Sdougm switch (scf_error()) { 1262*4653Sdougm case SCF_ERROR_PERMISSION_DENIED: 1263*4653Sdougm ret = SA_NO_PERMISSION; 1264*4653Sdougm break; 1265*4653Sdougm } 12663034Sdougm } 12673034Sdougm /* 1268*4653Sdougm * Cleanup if there were any errors that didn't leave these 12693034Sdougm * values where they would be cleaned up later. 12703034Sdougm */ 12713034Sdougm if (value != NULL) 1272*4653Sdougm scf_value_destroy(value); 12733034Sdougm if (entry != NULL) 1274*4653Sdougm scf_entry_destroy(entry); 12753034Sdougm return (ret); 12763034Sdougm } 12773034Sdougm 12783034Sdougm /* 12793034Sdougm * sa_commit_share(handle, group, share) 12803034Sdougm * 1281*4653Sdougm * Commit this share to the repository. 12823034Sdougm * properties are added if they exist but can be added later. 12833034Sdougm * Need to add to dfstab and sharetab, if appropriate. 12843034Sdougm */ 12853034Sdougm int 12863034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 12873034Sdougm { 12883034Sdougm int ret = SA_OK; 12893034Sdougm char *groupname; 12903034Sdougm char *name; 12913034Sdougm char *resource; 12923034Sdougm char *description; 12933034Sdougm char *sharename; 12943034Sdougm ssize_t proplen; 12953034Sdougm char *propstring; 12963034Sdougm 12973034Sdougm /* 1298*4653Sdougm * Don't commit in the zfs group. We do commit legacy 12993034Sdougm * (default) and all other groups/shares. ZFS is handled 13003034Sdougm * through the ZFS configuration rather than SMF. 13013034Sdougm */ 13023034Sdougm 13033034Sdougm groupname = sa_get_group_attr(group, "name"); 13043034Sdougm if (groupname != NULL) { 1305*4653Sdougm if (strcmp(groupname, "zfs") == 0) { 1306*4653Sdougm /* 1307*4653Sdougm * Adding to the ZFS group will result in the sharenfs 1308*4653Sdougm * property being set but we don't want to do anything 1309*4653Sdougm * SMF related at this point. 1310*4653Sdougm */ 1311*4653Sdougm sa_free_attr_string(groupname); 1312*4653Sdougm return (ret); 1313*4653Sdougm } 13143034Sdougm } 13153034Sdougm 13163034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 13173034Sdougm propstring = malloc(proplen); 13183034Sdougm if (propstring == NULL) 1319*4653Sdougm ret = SA_NO_MEMORY; 13203034Sdougm 13213034Sdougm if (groupname != NULL && ret == SA_OK) { 1322*4653Sdougm ret = sa_get_instance(handle, groupname); 1323*4653Sdougm sa_free_attr_string(groupname); 1324*4653Sdougm groupname = NULL; 1325*4653Sdougm sharename = sa_get_share_attr(share, "id"); 1326*4653Sdougm if (sharename == NULL) { 1327*4653Sdougm /* slipped by */ 1328*4653Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 1329*4653Sdougm generate_unique_sharename(shname); 1330*4653Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 13313034Sdougm (xmlChar *)shname); 1332*4653Sdougm sharename = strdup(shname); 13333034Sdougm } 1334*4653Sdougm if (sharename != NULL) { 1335*4653Sdougm sigset_t old, new; 1336*4653Sdougm /* 1337*4653Sdougm * Have a share name allocated so create a pgroup for 1338*4653Sdougm * it. It may already exist, but that is OK. In order 1339*4653Sdougm * to avoid creating a share pgroup that doesn't have 1340*4653Sdougm * a path property, block signals around the critical 1341*4653Sdougm * region of creating the share pgroup and props. 1342*4653Sdougm */ 1343*4653Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 1344*4653Sdougm (void) sigaddset(&new, SIGHUP); 1345*4653Sdougm (void) sigaddset(&new, SIGINT); 1346*4653Sdougm (void) sigaddset(&new, SIGQUIT); 1347*4653Sdougm (void) sigaddset(&new, SIGTSTP); 1348*4653Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 1349*4653Sdougm 1350*4653Sdougm ret = sa_create_pgroup(handle, sharename); 1351*4653Sdougm if (ret == SA_OK) { 1352*4653Sdougm /* 1353*4653Sdougm * Now start the transaction for the 1354*4653Sdougm * properties that define this share. They may 1355*4653Sdougm * exist so attempt to update before create. 1356*4653Sdougm */ 1357*4653Sdougm ret = sa_start_transaction(handle, sharename); 1358*4653Sdougm } 1359*4653Sdougm if (ret == SA_OK) { 1360*4653Sdougm name = sa_get_share_attr(share, "path"); 1361*4653Sdougm if (name != NULL) { 1362*4653Sdougm /* 1363*4653Sdougm * There needs to be a path 1364*4653Sdougm * for a share to exist. 1365*4653Sdougm */ 1366*4653Sdougm ret = sa_set_property(handle, "path", 1367*4653Sdougm name); 1368*4653Sdougm sa_free_attr_string(name); 1369*4653Sdougm } else { 1370*4653Sdougm ret = SA_NO_MEMORY; 1371*4653Sdougm } 1372*4653Sdougm } 1373*4653Sdougm if (ret == SA_OK) { 1374*4653Sdougm resource = sa_get_share_attr(share, 1375*4653Sdougm "resource"); 1376*4653Sdougm if (resource != NULL) { 1377*4653Sdougm ret = sa_set_property(handle, 1378*4653Sdougm "resource", resource); 1379*4653Sdougm sa_free_attr_string(resource); 1380*4653Sdougm } 1381*4653Sdougm } 1382*4653Sdougm if (ret == SA_OK) { 1383*4653Sdougm description = sa_get_share_description(share); 1384*4653Sdougm if (description != NULL) { 1385*4653Sdougm ret = sa_set_property(handle, 1386*4653Sdougm "description", 1387*4653Sdougm description); 1388*4653Sdougm sa_free_share_description(description); 1389*4653Sdougm } 1390*4653Sdougm } 1391*4653Sdougm /* Make sure we cleanup the transaction */ 1392*4653Sdougm if (ret == SA_OK) { 1393*4653Sdougm ret = sa_end_transaction(handle); 1394*4653Sdougm } else { 1395*4653Sdougm sa_abort_transaction(handle); 1396*4653Sdougm } 1397*4653Sdougm 1398*4653Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 1399*4653Sdougm 1400*4653Sdougm free(sharename); 14013034Sdougm } 14023034Sdougm } 14033034Sdougm if (ret == SA_SYSTEM_ERR) { 1404*4653Sdougm int err = scf_error(); 1405*4653Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 1406*4653Sdougm ret = SA_NO_PERMISSION; 14073034Sdougm } 14083034Sdougm if (propstring != NULL) 1409*4653Sdougm free(propstring); 14103034Sdougm if (groupname != NULL) 1411*4653Sdougm sa_free_attr_string(groupname); 14123034Sdougm 14133034Sdougm return (ret); 14143034Sdougm } 14153034Sdougm 14163034Sdougm /* 14173034Sdougm * sa_delete_share(handle, group, share) 14183034Sdougm * 1419*4653Sdougm * Remove the specified share from the group (and service instance). 14203034Sdougm */ 14213034Sdougm 14223034Sdougm int 14233034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 14243034Sdougm { 14253034Sdougm int ret = SA_OK; 14263034Sdougm char *groupname = NULL; 14273034Sdougm char *shareid = NULL; 14283034Sdougm sa_optionset_t opt; 14293034Sdougm sa_security_t sec; 14303034Sdougm ssize_t proplen; 14313034Sdougm char *propstring; 14323034Sdougm 14333034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 14343034Sdougm propstring = malloc(proplen); 14353034Sdougm if (propstring == NULL) 1436*4653Sdougm ret = SA_NO_MEMORY; 14373034Sdougm 14383034Sdougm if (ret == SA_OK) { 1439*4653Sdougm groupname = sa_get_group_attr(group, "name"); 1440*4653Sdougm shareid = sa_get_share_attr(share, "id"); 1441*4653Sdougm if (groupname == NULL || shareid == NULL) { 1442*4653Sdougm ret = SA_CONFIG_ERR; 1443*4653Sdougm goto out; 1444*4653Sdougm } 14453034Sdougm ret = sa_get_instance(handle, groupname); 14463034Sdougm if (ret == SA_OK) { 1447*4653Sdougm /* If a share has properties, remove them */ 1448*4653Sdougm ret = sa_delete_pgroup(handle, shareid); 1449*4653Sdougm for (opt = sa_get_optionset(share, NULL); 1450*4653Sdougm opt != NULL; 1451*4653Sdougm opt = sa_get_next_optionset(opt)) { 1452*4653Sdougm char *proto; 1453*4653Sdougm proto = sa_get_optionset_attr(opt, "type"); 1454*4653Sdougm if (proto != NULL) { 1455*4653Sdougm (void) snprintf(propstring, 1456*4653Sdougm proplen, "%s_%s", shareid, 1457*4653Sdougm proto); 1458*4653Sdougm ret = sa_delete_pgroup(handle, 1459*4653Sdougm propstring); 1460*4653Sdougm sa_free_attr_string(proto); 1461*4653Sdougm } else { 1462*4653Sdougm ret = SA_NO_MEMORY; 1463*4653Sdougm } 14643034Sdougm } 14653034Sdougm /* 1466*4653Sdougm * If a share has security/negotiable 14673034Sdougm * properties, remove them. 14683034Sdougm */ 1469*4653Sdougm for (sec = sa_get_security(share, NULL, NULL); 1470*4653Sdougm sec != NULL; 1471*4653Sdougm sec = sa_get_next_security(sec)) { 1472*4653Sdougm char *proto; 1473*4653Sdougm char *sectype; 1474*4653Sdougm proto = sa_get_security_attr(sec, "type"); 1475*4653Sdougm sectype = sa_get_security_attr(sec, "sectype"); 1476*4653Sdougm if (proto != NULL && sectype != NULL) { 1477*4653Sdougm (void) snprintf(propstring, proplen, 1478*4653Sdougm "%s_%s_%s", shareid, proto, 1479*4653Sdougm sectype); 1480*4653Sdougm ret = sa_delete_pgroup(handle, 1481*4653Sdougm propstring); 1482*4653Sdougm } else { 1483*4653Sdougm ret = SA_NO_MEMORY; 1484*4653Sdougm } 1485*4653Sdougm if (proto != NULL) 1486*4653Sdougm sa_free_attr_string(proto); 1487*4653Sdougm if (sectype != NULL) 1488*4653Sdougm sa_free_attr_string(sectype); 14893034Sdougm } 14903034Sdougm } 14913034Sdougm } 1492*4653Sdougm out: 14933034Sdougm if (groupname != NULL) 1494*4653Sdougm sa_free_attr_string(groupname); 14953034Sdougm if (shareid != NULL) 1496*4653Sdougm sa_free_attr_string(shareid); 14973034Sdougm if (propstring != NULL) 1498*4653Sdougm free(propstring); 14993034Sdougm 15003034Sdougm return (ret); 15013034Sdougm } 1502