1*3034Sdougm /* 2*3034Sdougm * CDDL HEADER START 3*3034Sdougm * 4*3034Sdougm * The contents of this file are subject to the terms of the 5*3034Sdougm * Common Development and Distribution License (the "License"). 6*3034Sdougm * You may not use this file except in compliance with the License. 7*3034Sdougm * 8*3034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3034Sdougm * or http://www.opensolaris.org/os/licensing. 10*3034Sdougm * See the License for the specific language governing permissions 11*3034Sdougm * and limitations under the License. 12*3034Sdougm * 13*3034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 14*3034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3034Sdougm * If applicable, add the following below this CDDL HEADER, with the 16*3034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 17*3034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 18*3034Sdougm * 19*3034Sdougm * CDDL HEADER END 20*3034Sdougm */ 21*3034Sdougm 22*3034Sdougm /* 23*3034Sdougm * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*3034Sdougm * Use is subject to license terms. 25*3034Sdougm */ 26*3034Sdougm 27*3034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 28*3034Sdougm 29*3034Sdougm /* helper functions for using libscf with sharemgr */ 30*3034Sdougm 31*3034Sdougm #include <libscf.h> 32*3034Sdougm #include <libxml/parser.h> 33*3034Sdougm #include <libxml/tree.h> 34*3034Sdougm #include "libshare.h" 35*3034Sdougm #include "libshare_impl.h" 36*3034Sdougm #include "scfutil.h" 37*3034Sdougm #include <string.h> 38*3034Sdougm #include <errno.h> 39*3034Sdougm #include <uuid/uuid.h> 40*3034Sdougm #include <sys/param.h> 41*3034Sdougm 42*3034Sdougm ssize_t scf_max_name_len; 43*3034Sdougm extern struct sa_proto_plugin *sap_proto_list; 44*3034Sdougm 45*3034Sdougm /* 46*3034Sdougm * The SMF facility uses some properties that must exist. We want to 47*3034Sdougm * skip over these when processing protocol options. 48*3034Sdougm */ 49*3034Sdougm static char *skip_props[] = { 50*3034Sdougm "modify_authorization", 51*3034Sdougm "action_authorization", 52*3034Sdougm "value_authorization", 53*3034Sdougm NULL 54*3034Sdougm }; 55*3034Sdougm 56*3034Sdougm /* 57*3034Sdougm * sa_scf_fini(handle) 58*3034Sdougm * 59*3034Sdougm * must be called when done. Called with the handle allocated in 60*3034Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 61*3034Sdougm * still in use. Called by sa_fini(). 62*3034Sdougm */ 63*3034Sdougm 64*3034Sdougm void 65*3034Sdougm sa_scf_fini(scfutilhandle_t *handle) 66*3034Sdougm { 67*3034Sdougm if (handle != NULL) { 68*3034Sdougm int unbind = 0; 69*3034Sdougm if (handle->scope != NULL) { 70*3034Sdougm unbind = 1; 71*3034Sdougm scf_scope_destroy(handle->scope); 72*3034Sdougm } 73*3034Sdougm if (handle->service != NULL) 74*3034Sdougm scf_service_destroy(handle->service); 75*3034Sdougm if (handle->pg != NULL) 76*3034Sdougm scf_pg_destroy(handle->pg); 77*3034Sdougm if (handle->handle != NULL) { 78*3034Sdougm handle->scf_state = SCH_STATE_UNINIT; 79*3034Sdougm if (unbind) 80*3034Sdougm (void) scf_handle_unbind(handle->handle); 81*3034Sdougm scf_handle_destroy(handle->handle); 82*3034Sdougm } 83*3034Sdougm free(handle); 84*3034Sdougm } 85*3034Sdougm } 86*3034Sdougm 87*3034Sdougm /* 88*3034Sdougm * sa_scf_init() 89*3034Sdougm * 90*3034Sdougm * must be called before using any of the SCF functions. Called by 91*3034Sdougm * sa_init() during the API setup. 92*3034Sdougm */ 93*3034Sdougm 94*3034Sdougm scfutilhandle_t * 95*3034Sdougm sa_scf_init() 96*3034Sdougm { 97*3034Sdougm scfutilhandle_t *handle; 98*3034Sdougm 99*3034Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 100*3034Sdougm if (scf_max_name_len <= 0) 101*3034Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 102*3034Sdougm 103*3034Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 104*3034Sdougm if (handle != NULL) { 105*3034Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 106*3034Sdougm handle->handle = scf_handle_create(SCF_VERSION); 107*3034Sdougm if (handle->handle != NULL) { 108*3034Sdougm if (scf_handle_bind(handle->handle) == 0) { 109*3034Sdougm handle->scope = scf_scope_create(handle->handle); 110*3034Sdougm handle->service = scf_service_create(handle->handle); 111*3034Sdougm handle->pg = scf_pg_create(handle->handle); 112*3034Sdougm handle->instance = scf_instance_create(handle->handle); 113*3034Sdougm if (scf_handle_get_scope(handle->handle, 114*3034Sdougm SCF_SCOPE_LOCAL, handle->scope) == 0) { 115*3034Sdougm if (scf_scope_get_service(handle->scope, 116*3034Sdougm SA_GROUP_SVC_NAME, 117*3034Sdougm handle->service) != 0) { 118*3034Sdougm goto err; 119*3034Sdougm } 120*3034Sdougm handle->scf_state = SCH_STATE_INIT; 121*3034Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 122*3034Sdougm char **protolist; 123*3034Sdougm int numprotos, i; 124*3034Sdougm sa_group_t defgrp; 125*3034Sdougm defgrp = sa_create_group("default", NULL); 126*3034Sdougm if (defgrp != NULL) { 127*3034Sdougm numprotos = sa_get_protocols(&protolist); 128*3034Sdougm for (i = 0; i < numprotos; i++) { 129*3034Sdougm (void) sa_create_optionset(defgrp, 130*3034Sdougm protolist[i]); 131*3034Sdougm } 132*3034Sdougm if (protolist != NULL) 133*3034Sdougm free(protolist); 134*3034Sdougm } 135*3034Sdougm } 136*3034Sdougm } else { 137*3034Sdougm goto err; 138*3034Sdougm } 139*3034Sdougm } else { 140*3034Sdougm goto err; 141*3034Sdougm } 142*3034Sdougm } else { 143*3034Sdougm free(handle); 144*3034Sdougm handle = NULL; 145*3034Sdougm (void) printf("libshare could not access SMF repository: %s\n", 146*3034Sdougm scf_strerror(scf_error())); 147*3034Sdougm } 148*3034Sdougm } 149*3034Sdougm return (handle); 150*3034Sdougm 151*3034Sdougm /* error handling/unwinding */ 152*3034Sdougm err: 153*3034Sdougm (void) sa_scf_fini(handle); 154*3034Sdougm (void) printf("libshare SMF initialization problem: %s\n", 155*3034Sdougm scf_strerror(scf_error())); 156*3034Sdougm return (NULL); 157*3034Sdougm } 158*3034Sdougm 159*3034Sdougm /* 160*3034Sdougm * get_scf_limit(name) 161*3034Sdougm * 162*3034Sdougm * Since we use scf_limit a lot and do the same check and return the 163*3034Sdougm * same value if it fails, implement as a function for code 164*3034Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 165*3034Sdougm * (1024) so we have a reasonable default buffer size. 166*3034Sdougm */ 167*3034Sdougm static ssize_t 168*3034Sdougm get_scf_limit(uint32_t name) 169*3034Sdougm { 170*3034Sdougm ssize_t vallen; 171*3034Sdougm 172*3034Sdougm vallen = scf_limit(name); 173*3034Sdougm if (vallen == (ssize_t)-1) 174*3034Sdougm vallen = MAXPATHLEN; 175*3034Sdougm return (vallen); 176*3034Sdougm } 177*3034Sdougm 178*3034Sdougm /* 179*3034Sdougm * skip_property(name) 180*3034Sdougm * 181*3034Sdougm * internal function to check to see if a property is an SMF magic 182*3034Sdougm * property that needs to be skipped. 183*3034Sdougm */ 184*3034Sdougm static int 185*3034Sdougm skip_property(char *name) 186*3034Sdougm { 187*3034Sdougm int i; 188*3034Sdougm 189*3034Sdougm for (i = 0; skip_props[i] != NULL; i++) 190*3034Sdougm if (strcmp(name, skip_props[i]) == 0) 191*3034Sdougm return (1); 192*3034Sdougm return (0); 193*3034Sdougm } 194*3034Sdougm 195*3034Sdougm /* 196*3034Sdougm * generate_unique_sharename(sharename) 197*3034Sdougm * 198*3034Sdougm * Shares are represented in SMF as property groups. Due to share 199*3034Sdougm * paths containing characters that are not allowed in SMF names and 200*3034Sdougm * the need to be unique, we use UUIDs to construct a unique name. 201*3034Sdougm */ 202*3034Sdougm 203*3034Sdougm static void 204*3034Sdougm generate_unique_sharename(char *sharename) 205*3034Sdougm { 206*3034Sdougm uuid_t uuid; 207*3034Sdougm 208*3034Sdougm uuid_generate(uuid); 209*3034Sdougm (void) strcpy(sharename, "S-"); 210*3034Sdougm uuid_unparse(uuid, sharename + 2); 211*3034Sdougm } 212*3034Sdougm 213*3034Sdougm /* 214*3034Sdougm * valid_protocol(proto) 215*3034Sdougm * 216*3034Sdougm * check to see if the specified protocol is a valid one for the 217*3034Sdougm * general sharemgr facility. We determine this by checking which 218*3034Sdougm * plugin protocols were found. 219*3034Sdougm */ 220*3034Sdougm 221*3034Sdougm static int 222*3034Sdougm valid_protocol(char *proto) 223*3034Sdougm { 224*3034Sdougm struct sa_proto_plugin *plugin; 225*3034Sdougm for (plugin = sap_proto_list; plugin != NULL; 226*3034Sdougm plugin = plugin->plugin_next) 227*3034Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 228*3034Sdougm return (1); 229*3034Sdougm return (0); 230*3034Sdougm } 231*3034Sdougm 232*3034Sdougm /* 233*3034Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 234*3034Sdougm * 235*3034Sdougm * extract the name property group and create the specified type of 236*3034Sdougm * node on the provided group. type will be optionset or security. 237*3034Sdougm */ 238*3034Sdougm 239*3034Sdougm static int 240*3034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 241*3034Sdougm scf_propertygroup_t *pg, 242*3034Sdougm char *nodetype, char *proto, char *sectype) 243*3034Sdougm { 244*3034Sdougm xmlNodePtr node; 245*3034Sdougm scf_iter_t *iter; 246*3034Sdougm scf_property_t *prop; 247*3034Sdougm scf_value_t *value; 248*3034Sdougm char *name; 249*3034Sdougm char *valuestr; 250*3034Sdougm ssize_t vallen; 251*3034Sdougm int ret = SA_OK; 252*3034Sdougm 253*3034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 254*3034Sdougm 255*3034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 256*3034Sdougm if (node != NULL) { 257*3034Sdougm if (proto != NULL) 258*3034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 259*3034Sdougm if (sectype != NULL) 260*3034Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 261*3034Sdougm /* 262*3034Sdougm * have node to work with so iterate over the properties 263*3034Sdougm * in the pg and create option sub nodes. 264*3034Sdougm */ 265*3034Sdougm iter = scf_iter_create(handle->handle); 266*3034Sdougm value = scf_value_create(handle->handle); 267*3034Sdougm prop = scf_property_create(handle->handle); 268*3034Sdougm name = malloc(scf_max_name_len); 269*3034Sdougm valuestr = malloc(vallen); 270*3034Sdougm /* 271*3034Sdougm * want to iterate through the properties and add them 272*3034Sdougm * to the base optionset. 273*3034Sdougm */ 274*3034Sdougm if (iter != NULL && value != NULL && prop != NULL && 275*3034Sdougm valuestr != NULL && name != NULL) { 276*3034Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 277*3034Sdougm /* now iterate the properties in the group */ 278*3034Sdougm while (scf_iter_next_property(iter, prop) > 0) { 279*3034Sdougm /* have a property */ 280*3034Sdougm if (scf_property_get_name(prop, name, 281*3034Sdougm scf_max_name_len) > 0) { 282*3034Sdougm /* some properties are part of the framework */ 283*3034Sdougm if (skip_property(name)) 284*3034Sdougm continue; 285*3034Sdougm if (scf_property_get_value(prop, value) == 0) { 286*3034Sdougm if (scf_value_get_astring(value, valuestr, 287*3034Sdougm vallen) >= 0) { 288*3034Sdougm sa_property_t saprop; 289*3034Sdougm saprop = sa_create_property(name, 290*3034Sdougm valuestr); 291*3034Sdougm if (saprop != NULL) { 292*3034Sdougm /* 293*3034Sdougm * since in SMF, don't 294*3034Sdougm * recurse. Use xmlAddChild 295*3034Sdougm * directly, instead. 296*3034Sdougm */ 297*3034Sdougm xmlAddChild(node, 298*3034Sdougm (xmlNodePtr) saprop); 299*3034Sdougm } 300*3034Sdougm } 301*3034Sdougm } 302*3034Sdougm } 303*3034Sdougm } 304*3034Sdougm } 305*3034Sdougm } else { 306*3034Sdougm ret = SA_NO_MEMORY; 307*3034Sdougm } 308*3034Sdougm /* cleanup to avoid memory leaks */ 309*3034Sdougm if (value != NULL) 310*3034Sdougm scf_value_destroy(value); 311*3034Sdougm if (iter != NULL) 312*3034Sdougm scf_iter_destroy(iter); 313*3034Sdougm if (prop != NULL) 314*3034Sdougm scf_property_destroy(prop); 315*3034Sdougm if (name != NULL) 316*3034Sdougm free(name); 317*3034Sdougm if (valuestr != NULL) 318*3034Sdougm free(valuestr); 319*3034Sdougm } 320*3034Sdougm return (ret); 321*3034Sdougm } 322*3034Sdougm 323*3034Sdougm /* 324*3034Sdougm * sa_extract_attrs(root, handle, instance) 325*3034Sdougm * 326*3034Sdougm * local function to extract the actual attributes/properties from the 327*3034Sdougm * property group of the service instance. These are the well known 328*3034Sdougm * attributes of "state" and "zfs". If additional attributes are 329*3034Sdougm * added, they should be added here. 330*3034Sdougm */ 331*3034Sdougm 332*3034Sdougm static void 333*3034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 334*3034Sdougm scf_instance_t *instance) 335*3034Sdougm { 336*3034Sdougm scf_property_t *prop; 337*3034Sdougm scf_value_t *value; 338*3034Sdougm char *valuestr; 339*3034Sdougm ssize_t vallen; 340*3034Sdougm 341*3034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 342*3034Sdougm prop = scf_property_create(handle->handle); 343*3034Sdougm value = scf_value_create(handle->handle); 344*3034Sdougm valuestr = malloc(vallen); 345*3034Sdougm if (prop != NULL && value != NULL && valuestr != NULL && 346*3034Sdougm scf_instance_get_pg(instance, "operation", 347*3034Sdougm handle->pg) == 0) { 348*3034Sdougm /* 349*3034Sdougm * have a property group with desired name so now get 350*3034Sdougm * the known attributes. 351*3034Sdougm */ 352*3034Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 353*3034Sdougm /* found the property so get the value */ 354*3034Sdougm if (scf_property_get_value(prop, value) == 0) { 355*3034Sdougm if (scf_value_get_astring(value, valuestr, vallen) >= 0) { 356*3034Sdougm xmlSetProp(root, (xmlChar *)"state", 357*3034Sdougm (xmlChar *)valuestr); 358*3034Sdougm } 359*3034Sdougm } 360*3034Sdougm } 361*3034Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 362*3034Sdougm /* found the property so get the value */ 363*3034Sdougm if (scf_property_get_value(prop, value) == 0) { 364*3034Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 365*3034Sdougm xmlSetProp(root, (xmlChar *)"zfs", 366*3034Sdougm (xmlChar *)valuestr); 367*3034Sdougm } 368*3034Sdougm } 369*3034Sdougm } 370*3034Sdougm } 371*3034Sdougm if (valuestr != NULL) 372*3034Sdougm free(valuestr); 373*3034Sdougm if (value != NULL) 374*3034Sdougm scf_value_destroy(value); 375*3034Sdougm if (prop != NULL) 376*3034Sdougm scf_property_destroy(prop); 377*3034Sdougm } 378*3034Sdougm 379*3034Sdougm /* 380*3034Sdougm * list of known share attributes. 381*3034Sdougm */ 382*3034Sdougm 383*3034Sdougm static char *share_attr[] = { 384*3034Sdougm "path", 385*3034Sdougm "id", 386*3034Sdougm "resource", 387*3034Sdougm NULL, 388*3034Sdougm }; 389*3034Sdougm 390*3034Sdougm static int 391*3034Sdougm is_share_attr(char *name) 392*3034Sdougm { 393*3034Sdougm int i; 394*3034Sdougm for (i = 0; share_attr[i] != NULL; i++) 395*3034Sdougm if (strcmp(name, share_attr[i]) == 0) 396*3034Sdougm return (1); 397*3034Sdougm return (0); 398*3034Sdougm } 399*3034Sdougm 400*3034Sdougm /* 401*3034Sdougm * sa_share_from_pgroup 402*3034Sdougm * 403*3034Sdougm * extract the share definition from the share property group. We do 404*3034Sdougm * some sanity checking to avoid bad data. 405*3034Sdougm * 406*3034Sdougm * Since this is only constructing the internal data structures, we 407*3034Sdougm * don't use the sa_* functions most of the time. 408*3034Sdougm */ 409*3034Sdougm void 410*3034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 411*3034Sdougm scf_propertygroup_t *pg, char *id) 412*3034Sdougm { 413*3034Sdougm xmlNodePtr node; 414*3034Sdougm char *name; 415*3034Sdougm scf_iter_t *iter; 416*3034Sdougm scf_property_t *prop; 417*3034Sdougm scf_value_t *value; 418*3034Sdougm ssize_t vallen; 419*3034Sdougm char *valuestr; 420*3034Sdougm int ret = SA_OK; 421*3034Sdougm 422*3034Sdougm /* 423*3034Sdougm * While preliminary check (starts with 'S') passed before 424*3034Sdougm * getting here. Need to make sure it is in ID syntax 425*3034Sdougm * (Snnnnnn). Note that shares with properties have similar 426*3034Sdougm * pgroups. 427*3034Sdougm */ 428*3034Sdougm vallen = strlen(id); 429*3034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 430*3034Sdougm uuid_t uuid; 431*3034Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) != 0 || 432*3034Sdougm uuid_parse(id + 2, uuid) < 0) 433*3034Sdougm return; 434*3034Sdougm } else { 435*3034Sdougm return; 436*3034Sdougm } 437*3034Sdougm 438*3034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 439*3034Sdougm 440*3034Sdougm iter = scf_iter_create(handle->handle); 441*3034Sdougm value = scf_value_create(handle->handle); 442*3034Sdougm prop = scf_property_create(handle->handle); 443*3034Sdougm name = malloc(scf_max_name_len); 444*3034Sdougm valuestr = malloc(vallen); 445*3034Sdougm 446*3034Sdougm /* 447*3034Sdougm * construct the share XML node. It is similar to sa_add_share 448*3034Sdougm * but never changes the repository. Also, there won't be any 449*3034Sdougm * ZFS or transient shares. Root will be the group it is 450*3034Sdougm * associated with. 451*3034Sdougm */ 452*3034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 453*3034Sdougm if (node != NULL) { 454*3034Sdougm /* 455*3034Sdougm * make sure the UUID part of the property group is 456*3034Sdougm * stored in the share "id" property. We use this 457*3034Sdougm * later. 458*3034Sdougm */ 459*3034Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 460*3034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 461*3034Sdougm } 462*3034Sdougm 463*3034Sdougm if (iter != NULL && value != NULL && prop != NULL && name != NULL) { 464*3034Sdougm /* iterate over the share pg properties */ 465*3034Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 466*3034Sdougm while (scf_iter_next_property(iter, prop) > 0) { 467*3034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 468*3034Sdougm if (scf_property_get_name(prop, name, 469*3034Sdougm scf_max_name_len) > 0) { 470*3034Sdougm if (scf_property_get_value(prop, value) == 0) { 471*3034Sdougm if (scf_value_get_astring(value, valuestr, 472*3034Sdougm vallen) >= 0) { 473*3034Sdougm ret = SA_OK; 474*3034Sdougm } 475*3034Sdougm } 476*3034Sdougm } 477*3034Sdougm if (ret == SA_OK) { 478*3034Sdougm if (is_share_attr(name)) { 479*3034Sdougm /* 480*3034Sdougm * if a share attr, then simple - 481*3034Sdougm * usually path and resource name 482*3034Sdougm */ 483*3034Sdougm xmlSetProp(node, (xmlChar *)name, 484*3034Sdougm (xmlChar *)valuestr); 485*3034Sdougm } else { 486*3034Sdougm if (strcmp(name, "description") == 0) { 487*3034Sdougm /* we have a description node */ 488*3034Sdougm xmlNodePtr desc; 489*3034Sdougm desc = xmlNewChild(node, NULL, 490*3034Sdougm (xmlChar *)"description", 491*3034Sdougm NULL); 492*3034Sdougm if (desc != NULL) 493*3034Sdougm xmlNodeSetContent(desc, 494*3034Sdougm (xmlChar *)valuestr); 495*3034Sdougm } 496*3034Sdougm } 497*3034Sdougm } 498*3034Sdougm } 499*3034Sdougm } 500*3034Sdougm } 501*3034Sdougm if (name != NULL) 502*3034Sdougm free(name); 503*3034Sdougm if (valuestr != NULL) 504*3034Sdougm free(valuestr); 505*3034Sdougm if (value != NULL) 506*3034Sdougm scf_value_destroy(value); 507*3034Sdougm if (iter != NULL) 508*3034Sdougm scf_iter_destroy(iter); 509*3034Sdougm if (prop != NULL) 510*3034Sdougm scf_property_destroy(prop); 511*3034Sdougm } 512*3034Sdougm 513*3034Sdougm /* 514*3034Sdougm * find_share_by_id(shareid) 515*3034Sdougm * 516*3034Sdougm * Search all shares in all groups until we find the share represented 517*3034Sdougm * by "id". 518*3034Sdougm */ 519*3034Sdougm 520*3034Sdougm static sa_share_t 521*3034Sdougm find_share_by_id(char *shareid) 522*3034Sdougm { 523*3034Sdougm sa_group_t group; 524*3034Sdougm sa_share_t share = NULL; 525*3034Sdougm char *id = NULL; 526*3034Sdougm int done = 0; 527*3034Sdougm 528*3034Sdougm for (group = sa_get_group(NULL); group != NULL && !done; 529*3034Sdougm group = sa_get_next_group(group)) { 530*3034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 531*3034Sdougm share = sa_get_next_share(share)) { 532*3034Sdougm id = sa_get_share_attr(share, "id"); 533*3034Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 534*3034Sdougm sa_free_attr_string(id); 535*3034Sdougm id = NULL; 536*3034Sdougm done++; 537*3034Sdougm break; 538*3034Sdougm } 539*3034Sdougm if (id != NULL) { 540*3034Sdougm sa_free_attr_string(id); 541*3034Sdougm id = NULL; 542*3034Sdougm } 543*3034Sdougm } 544*3034Sdougm } 545*3034Sdougm return (share); 546*3034Sdougm } 547*3034Sdougm 548*3034Sdougm /* 549*3034Sdougm * sa_share_props_from_pgroup(root, handle, pg, id) 550*3034Sdougm * 551*3034Sdougm * extract share properties from the SMF property group. More sanity 552*3034Sdougm * checks are done and the share object is created. We ignore some 553*3034Sdougm * errors that could exist in the repository and only worry about 554*3034Sdougm * property groups that validate in naming. 555*3034Sdougm */ 556*3034Sdougm 557*3034Sdougm static int 558*3034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 559*3034Sdougm scf_propertygroup_t *pg, char *id) 560*3034Sdougm { 561*3034Sdougm xmlNodePtr node; 562*3034Sdougm char *name; 563*3034Sdougm scf_iter_t *iter; 564*3034Sdougm scf_property_t *prop; 565*3034Sdougm scf_value_t *value; 566*3034Sdougm ssize_t vallen; 567*3034Sdougm char *valuestr; 568*3034Sdougm int ret = SA_OK; 569*3034Sdougm char *sectype = NULL; 570*3034Sdougm char *proto; 571*3034Sdougm sa_share_t share; 572*3034Sdougm 573*3034Sdougm /* 574*3034Sdougm * While preliminary check (starts with 'S') passed before 575*3034Sdougm * getting here. Need to make sure it is in ID syntax 576*3034Sdougm * (Snnnnnn). Note that shares with properties have similar 577*3034Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 578*3034Sdougm * characters, it is likely one of the protocol/security 579*3034Sdougm * versions. 580*3034Sdougm */ 581*3034Sdougm vallen = strlen(id); 582*3034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen > SA_SHARE_PG_LEN) { 583*3034Sdougm uuid_t uuid; 584*3034Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 585*3034Sdougm proto = strchr(id, '_'); 586*3034Sdougm if (proto == NULL) 587*3034Sdougm return (ret); 588*3034Sdougm *proto++ = '\0'; 589*3034Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 590*3034Sdougm return (ret); 591*3034Sdougm /* 592*3034Sdougm * probably a legal optionset so check a few more 593*3034Sdougm * syntax points below. 594*3034Sdougm */ 595*3034Sdougm if (*proto == '\0') { 596*3034Sdougm /* not a valid proto (null) */ 597*3034Sdougm return (ret); 598*3034Sdougm } 599*3034Sdougm sectype = strchr(proto, '_'); 600*3034Sdougm if (sectype != NULL) 601*3034Sdougm *sectype++ = '\0'; 602*3034Sdougm if (!valid_protocol(proto)) 603*3034Sdougm return (ret); 604*3034Sdougm } 605*3034Sdougm } else { 606*3034Sdougm /* 607*3034Sdougm * it is ok to not have what we thought since someone might 608*3034Sdougm * have added a name via SMF. 609*3034Sdougm */ 610*3034Sdougm return (ret); 611*3034Sdougm } 612*3034Sdougm 613*3034Sdougm /* 614*3034Sdougm * to get here, we have a valid protocol and possibly a 615*3034Sdougm * security. We now have to find the share that it is really 616*3034Sdougm * associated with. The "id" portion of the pgroup name will 617*3034Sdougm * match. 618*3034Sdougm */ 619*3034Sdougm 620*3034Sdougm share = find_share_by_id(id); 621*3034Sdougm if (share == NULL) 622*3034Sdougm return (SA_BAD_PATH); 623*3034Sdougm 624*3034Sdougm root = (xmlNodePtr)share; 625*3034Sdougm 626*3034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 627*3034Sdougm 628*3034Sdougm iter = scf_iter_create(handle->handle); 629*3034Sdougm value = scf_value_create(handle->handle); 630*3034Sdougm prop = scf_property_create(handle->handle); 631*3034Sdougm name = malloc(scf_max_name_len); 632*3034Sdougm valuestr = malloc(vallen); 633*3034Sdougm 634*3034Sdougm if (sectype == NULL) 635*3034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 636*3034Sdougm else { 637*3034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL); 638*3034Sdougm if (node != NULL) 639*3034Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 640*3034Sdougm } 641*3034Sdougm if (node != NULL) { 642*3034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 643*3034Sdougm /* now find the properties */ 644*3034Sdougm if (iter != NULL && value != NULL && prop != NULL && name != NULL) { 645*3034Sdougm /* iterate over the share pg properties */ 646*3034Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 647*3034Sdougm while (scf_iter_next_property(iter, prop) > 0) { 648*3034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 649*3034Sdougm if (scf_property_get_name(prop, name, 650*3034Sdougm scf_max_name_len) > 0) { 651*3034Sdougm if (scf_property_get_value(prop, value) == 0) { 652*3034Sdougm if (scf_value_get_astring(value, valuestr, 653*3034Sdougm vallen) >= 0) { 654*3034Sdougm ret = SA_OK; 655*3034Sdougm } 656*3034Sdougm } 657*3034Sdougm } else { 658*3034Sdougm ret = SA_SYSTEM_ERR; 659*3034Sdougm } 660*3034Sdougm if (ret == SA_OK) { 661*3034Sdougm sa_property_t prop; 662*3034Sdougm prop = sa_create_property(name, valuestr); 663*3034Sdougm if (prop != NULL) 664*3034Sdougm prop = (sa_property_t)xmlAddChild(node, 665*3034Sdougm (xmlNodePtr)prop); 666*3034Sdougm else 667*3034Sdougm ret = SA_NO_MEMORY; 668*3034Sdougm } 669*3034Sdougm } 670*3034Sdougm } else { 671*3034Sdougm ret = SA_SYSTEM_ERR; 672*3034Sdougm } 673*3034Sdougm } 674*3034Sdougm } else { 675*3034Sdougm ret = SA_NO_MEMORY; 676*3034Sdougm } 677*3034Sdougm if (iter != NULL) 678*3034Sdougm scf_iter_destroy(iter); 679*3034Sdougm if (value != NULL) 680*3034Sdougm scf_value_destroy(value); 681*3034Sdougm if (prop != NULL) 682*3034Sdougm scf_property_destroy(prop); 683*3034Sdougm if (name != NULL) 684*3034Sdougm free(name); 685*3034Sdougm if (valuestr != NULL) 686*3034Sdougm free(valuestr); 687*3034Sdougm return (ret); 688*3034Sdougm } 689*3034Sdougm 690*3034Sdougm /* 691*3034Sdougm * sa_extract_group(root, handle, instance) 692*3034Sdougm * 693*3034Sdougm * get the config info for this instance of a group and create the XML 694*3034Sdougm * subtree from it. 695*3034Sdougm */ 696*3034Sdougm 697*3034Sdougm static int 698*3034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 699*3034Sdougm scf_instance_t *instance) 700*3034Sdougm { 701*3034Sdougm char *buff; 702*3034Sdougm xmlNodePtr node; 703*3034Sdougm scf_iter_t *iter; 704*3034Sdougm char *proto; 705*3034Sdougm char *sectype; 706*3034Sdougm int have_shares = 0; 707*3034Sdougm int has_proto = 0; 708*3034Sdougm int is_default = 0; 709*3034Sdougm int ret = SA_OK; 710*3034Sdougm int err; 711*3034Sdougm 712*3034Sdougm buff = malloc(scf_max_name_len); 713*3034Sdougm iter = scf_iter_create(handle->handle); 714*3034Sdougm if (buff != NULL) { 715*3034Sdougm if (scf_instance_get_name(instance, buff, 716*3034Sdougm scf_max_name_len) > 0) { 717*3034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 718*3034Sdougm if (node != NULL) { 719*3034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 720*3034Sdougm if (strcmp(buff, "default") == 0) 721*3034Sdougm is_default++; 722*3034Sdougm sa_extract_attrs(node, handle, instance); 723*3034Sdougm /* 724*3034Sdougm * Iterate through all the property groups 725*3034Sdougm * looking for those with security or 726*3034Sdougm * optionset prefixes. The names of the 727*3034Sdougm * matching pgroups are parsed to get the 728*3034Sdougm * protocol, and for security, the sectype. 729*3034Sdougm * Syntax is as follows: 730*3034Sdougm * optionset | optionset_<proto> 731*3034Sdougm * security_default | security_<proto>_<sectype> 732*3034Sdougm * "operation" is handled by 733*3034Sdougm * sa_extract_attrs(). 734*3034Sdougm */ 735*3034Sdougm if (iter != NULL) { 736*3034Sdougm if (scf_iter_instance_pgs(iter, instance) == 0) { 737*3034Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 738*3034Sdougm /* have a pgroup so sort it out */ 739*3034Sdougm ret = scf_pg_get_name(handle->pg, buff, 740*3034Sdougm scf_max_name_len); 741*3034Sdougm if (ret > 0) { 742*3034Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 743*3034Sdougm sa_share_from_pgroup(node, handle, 744*3034Sdougm handle->pg, 745*3034Sdougm buff); 746*3034Sdougm have_shares++; 747*3034Sdougm } else if (strncmp(buff, "optionset", 9) == 748*3034Sdougm 0) { 749*3034Sdougm char *nodetype = "optionset"; 750*3034Sdougm /* have an optionset */ 751*3034Sdougm sectype = NULL; 752*3034Sdougm proto = strchr(buff, '_'); 753*3034Sdougm if (proto != NULL) { 754*3034Sdougm *proto++ = '\0'; 755*3034Sdougm sectype = strchr(proto, '_'); 756*3034Sdougm if (sectype != NULL) { 757*3034Sdougm *sectype++ = '\0'; 758*3034Sdougm nodetype = "security"; 759*3034Sdougm } 760*3034Sdougm } 761*3034Sdougm ret = sa_extract_pgroup(node, handle, 762*3034Sdougm handle->pg, 763*3034Sdougm nodetype, 764*3034Sdougm proto, sectype); 765*3034Sdougm has_proto++; 766*3034Sdougm } else if (strncmp(buff, 767*3034Sdougm "security", 8) == 0) { 768*3034Sdougm /* 769*3034Sdougm * have a security (note that 770*3034Sdougm * this should change in the 771*3034Sdougm * future) 772*3034Sdougm */ 773*3034Sdougm proto = strchr(buff, '_'); 774*3034Sdougm sectype = NULL; 775*3034Sdougm if (proto != NULL) { 776*3034Sdougm *proto++ = '\0'; 777*3034Sdougm sectype = strchr(proto, '_'); 778*3034Sdougm if (sectype != NULL) 779*3034Sdougm *sectype++ = '\0'; 780*3034Sdougm if (strcmp(proto, "default") == 0) 781*3034Sdougm proto = NULL; 782*3034Sdougm } 783*3034Sdougm ret = sa_extract_pgroup(node, handle, 784*3034Sdougm handle->pg, 785*3034Sdougm "security", proto, 786*3034Sdougm sectype); 787*3034Sdougm has_proto++; 788*3034Sdougm } 789*3034Sdougm /* ignore everything else */ 790*3034Sdougm } 791*3034Sdougm } 792*3034Sdougm } else { 793*3034Sdougm ret = SA_NO_MEMORY; 794*3034Sdougm } 795*3034Sdougm /* 796*3034Sdougm * Make sure we have a valid default group. 797*3034Sdougm * On first boot, default won't have any 798*3034Sdougm * protocols defined and won't be enabled (but 799*3034Sdougm * should be). 800*3034Sdougm */ 801*3034Sdougm if (is_default) { 802*3034Sdougm char *state = sa_get_group_attr((sa_group_t)node, 803*3034Sdougm "state"); 804*3034Sdougm char **protos; 805*3034Sdougm int numprotos; 806*3034Sdougm int i; 807*3034Sdougm 808*3034Sdougm if (state == NULL) { 809*3034Sdougm /* set attribute to enabled */ 810*3034Sdougm (void) sa_set_group_attr((sa_group_t)node, 811*3034Sdougm "state", 812*3034Sdougm "enabled"); 813*3034Sdougm /* we can assume no protocols */ 814*3034Sdougm numprotos = sa_get_protocols(&protos); 815*3034Sdougm for (i = 0; i < numprotos; i++) 816*3034Sdougm (void) sa_create_optionset((sa_group_t)node, 817*3034Sdougm protos[i]); 818*3034Sdougm if (numprotos > 0) 819*3034Sdougm free(protos); 820*3034Sdougm } else { 821*3034Sdougm sa_free_attr_string(state); 822*3034Sdougm } 823*3034Sdougm } 824*3034Sdougm /* do a second pass if shares were found */ 825*3034Sdougm if (have_shares && 826*3034Sdougm scf_iter_instance_pgs(iter, instance) == 0) { 827*3034Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 828*3034Sdougm /* 829*3034Sdougm * have a pgroup so see if it is a 830*3034Sdougm * share optionset 831*3034Sdougm */ 832*3034Sdougm err = scf_pg_get_name(handle->pg, buff, 833*3034Sdougm scf_max_name_len); 834*3034Sdougm if (err > 0) { 835*3034Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 836*3034Sdougm ret = sa_share_props_from_pgroup(node, 837*3034Sdougm handle, 838*3034Sdougm handle->pg, 839*3034Sdougm buff); 840*3034Sdougm } 841*3034Sdougm } 842*3034Sdougm } 843*3034Sdougm } 844*3034Sdougm } 845*3034Sdougm } 846*3034Sdougm } 847*3034Sdougm } 848*3034Sdougm if (iter != NULL) 849*3034Sdougm scf_iter_destroy(iter); 850*3034Sdougm if (buff != NULL) 851*3034Sdougm free(buff); 852*3034Sdougm return (ret); 853*3034Sdougm } 854*3034Sdougm 855*3034Sdougm /* 856*3034Sdougm * sa_extract_defaults(root, handle, instance) 857*3034Sdougm * 858*3034Sdougm * local function to find the default properties that live in the 859*3034Sdougm * default instance's "operation" proprerty group. 860*3034Sdougm */ 861*3034Sdougm 862*3034Sdougm static void 863*3034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 864*3034Sdougm scf_instance_t *instance) 865*3034Sdougm { 866*3034Sdougm xmlNodePtr node; 867*3034Sdougm scf_property_t *prop; 868*3034Sdougm scf_value_t *value; 869*3034Sdougm char *valuestr; 870*3034Sdougm ssize_t vallen; 871*3034Sdougm 872*3034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 873*3034Sdougm prop = scf_property_create(handle->handle); 874*3034Sdougm value = scf_value_create(handle->handle); 875*3034Sdougm valuestr = malloc(vallen); 876*3034Sdougm if (prop != NULL && value != NULL && vallen != NULL && 877*3034Sdougm scf_instance_get_pg(instance, "operation", 878*3034Sdougm handle->pg) == 0) { 879*3034Sdougm if (scf_pg_get_property(handle->pg, 880*3034Sdougm "legacy-timestamp", prop) == 0) { 881*3034Sdougm /* found the property so get the value */ 882*3034Sdougm if (scf_property_get_value(prop, value) == 0) { 883*3034Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 884*3034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 885*3034Sdougm NULL); 886*3034Sdougm if (node != NULL) { 887*3034Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 888*3034Sdougm (xmlChar *)valuestr); 889*3034Sdougm xmlSetProp(node, (xmlChar *)"path", 890*3034Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 891*3034Sdougm } 892*3034Sdougm } 893*3034Sdougm } 894*3034Sdougm } 895*3034Sdougm } 896*3034Sdougm if (valuestr != NULL) 897*3034Sdougm free(valuestr); 898*3034Sdougm if (value != NULL) 899*3034Sdougm scf_value_destroy(value); 900*3034Sdougm if (prop != NULL) 901*3034Sdougm scf_property_destroy(prop); 902*3034Sdougm } 903*3034Sdougm 904*3034Sdougm 905*3034Sdougm /* 906*3034Sdougm * sa_get_config(handle, root, doc) 907*3034Sdougm * 908*3034Sdougm * walk the SMF repository for /network/shares/group and find all the 909*3034Sdougm * instances. These become group names. Then add the XML structure 910*3034Sdougm * below the groups based on property groups and properties. 911*3034Sdougm */ 912*3034Sdougm int 913*3034Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr *root, xmlDocPtr *doc) 914*3034Sdougm { 915*3034Sdougm int ret = SA_OK; 916*3034Sdougm scf_instance_t *instance; 917*3034Sdougm scf_iter_t *iter; 918*3034Sdougm char buff[BUFSIZ * 2]; 919*3034Sdougm 920*3034Sdougm *doc = xmlNewDoc((xmlChar *)"1.0"); 921*3034Sdougm *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 922*3034Sdougm instance = scf_instance_create(handle->handle); 923*3034Sdougm iter = scf_iter_create(handle->handle); 924*3034Sdougm if (*doc != NULL && *root != NULL && instance != NULL && iter != NULL) { 925*3034Sdougm xmlDocSetRootElement(*doc, *root); 926*3034Sdougm if ((ret = scf_iter_service_instances(iter, 927*3034Sdougm handle->service)) == 0) { 928*3034Sdougm while ((ret = scf_iter_next_instance(iter, 929*3034Sdougm instance)) > 0) { 930*3034Sdougm if (scf_instance_get_name(instance, buff, 931*3034Sdougm sizeof (buff)) > 0) { 932*3034Sdougm if (strcmp(buff, "default") == 0) 933*3034Sdougm sa_extract_defaults(*root, handle, instance); 934*3034Sdougm ret = sa_extract_group(*root, handle, instance); 935*3034Sdougm } 936*3034Sdougm } 937*3034Sdougm } 938*3034Sdougm } else { 939*3034Sdougm /* if we can't create the document, cleanup */ 940*3034Sdougm if (*doc != NULL) 941*3034Sdougm xmlFreeDoc(*doc); 942*3034Sdougm if (*root != NULL) 943*3034Sdougm xmlFreeNode(*root); 944*3034Sdougm *doc = NULL; 945*3034Sdougm *root = NULL; 946*3034Sdougm } 947*3034Sdougm /* always cleanup these */ 948*3034Sdougm if (instance != NULL) 949*3034Sdougm scf_instance_destroy(instance); 950*3034Sdougm if (iter != NULL) 951*3034Sdougm scf_iter_destroy(iter); 952*3034Sdougm return (ret); 953*3034Sdougm } 954*3034Sdougm 955*3034Sdougm /* 956*3034Sdougm * sa_get_instance(handle, instance) 957*3034Sdougm * 958*3034Sdougm * get the instance of the group service. This is actually the 959*3034Sdougm * specific group name. The instance is needed for all property and 960*3034Sdougm * control operations. 961*3034Sdougm */ 962*3034Sdougm 963*3034Sdougm int 964*3034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 965*3034Sdougm { 966*3034Sdougm if (scf_service_get_instance(handle->service, instname, 967*3034Sdougm handle->instance) != 0) { 968*3034Sdougm return (SA_NO_SUCH_GROUP); 969*3034Sdougm } 970*3034Sdougm return (SA_OK); 971*3034Sdougm } 972*3034Sdougm 973*3034Sdougm /* 974*3034Sdougm * sa_create_instance(handle, instname) 975*3034Sdougm * 976*3034Sdougm * Create a new SMF service instance. There can only be one with a 977*3034Sdougm * given name. 978*3034Sdougm */ 979*3034Sdougm 980*3034Sdougm int 981*3034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 982*3034Sdougm { 983*3034Sdougm int ret = SA_OK; 984*3034Sdougm char instance[SA_GROUP_INST_LEN]; 985*3034Sdougm if (scf_service_add_instance(handle->service, instname, 986*3034Sdougm handle->instance) != 0) { 987*3034Sdougm /* better error returns need to be added based on real error */ 988*3034Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 989*3034Sdougm ret = SA_NO_PERMISSION; 990*3034Sdougm else 991*3034Sdougm ret = SA_DUPLICATE_NAME; 992*3034Sdougm } else { 993*3034Sdougm /* have the service created, so enable it */ 994*3034Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 995*3034Sdougm SA_SVC_FMRI_BASE, instname); 996*3034Sdougm (void) smf_enable_instance(instance, 0); 997*3034Sdougm } 998*3034Sdougm return (ret); 999*3034Sdougm } 1000*3034Sdougm 1001*3034Sdougm /* 1002*3034Sdougm * sa_delete_instance(handle, instname) 1003*3034Sdougm * 1004*3034Sdougm * When a group goes away, we also remove the service instance. 1005*3034Sdougm */ 1006*3034Sdougm 1007*3034Sdougm int 1008*3034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 1009*3034Sdougm { 1010*3034Sdougm int ret; 1011*3034Sdougm 1012*3034Sdougm if (strcmp(instname, "default") == 0) { 1013*3034Sdougm ret = SA_NO_PERMISSION; 1014*3034Sdougm } else { 1015*3034Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 1016*3034Sdougm if (scf_instance_delete(handle->instance) != 0) 1017*3034Sdougm /* need better analysis */ 1018*3034Sdougm ret = SA_NO_PERMISSION; 1019*3034Sdougm } 1020*3034Sdougm } 1021*3034Sdougm return (ret); 1022*3034Sdougm } 1023*3034Sdougm 1024*3034Sdougm /* 1025*3034Sdougm * sa_create_pgroup(handle, pgroup) 1026*3034Sdougm * 1027*3034Sdougm * create a new property group 1028*3034Sdougm */ 1029*3034Sdougm 1030*3034Sdougm int 1031*3034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 1032*3034Sdougm { 1033*3034Sdougm int ret = SA_OK; 1034*3034Sdougm /* 1035*3034Sdougm * only create a handle if it doesn't exist. It is ok to exist 1036*3034Sdougm * since the pg handle will be set as a side effect. 1037*3034Sdougm */ 1038*3034Sdougm if (handle->pg == NULL) { 1039*3034Sdougm handle->pg = scf_pg_create(handle->handle); 1040*3034Sdougm } 1041*3034Sdougm /* 1042*3034Sdougm * if the pgroup exists, we are done. If it doesn't, then we 1043*3034Sdougm * need to actually add one to the service instance. 1044*3034Sdougm */ 1045*3034Sdougm if (scf_instance_get_pg(handle->instance, 1046*3034Sdougm pgroup, handle->pg) != 0) { 1047*3034Sdougm /* doesn't exist so create one */ 1048*3034Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 1049*3034Sdougm SCF_GROUP_APPLICATION, 0, 1050*3034Sdougm handle->pg) != 0) { 1051*3034Sdougm switch (scf_error()) { 1052*3034Sdougm case SCF_ERROR_PERMISSION_DENIED: 1053*3034Sdougm ret = SA_NO_PERMISSION; 1054*3034Sdougm break; 1055*3034Sdougm default: 1056*3034Sdougm ret = SA_SYSTEM_ERR; 1057*3034Sdougm break; 1058*3034Sdougm } 1059*3034Sdougm } 1060*3034Sdougm } 1061*3034Sdougm return (ret); 1062*3034Sdougm } 1063*3034Sdougm 1064*3034Sdougm /* 1065*3034Sdougm * sa_delete_pgroup(handle, pgroup) 1066*3034Sdougm * 1067*3034Sdougm * remove the property group from the current instance of the service, 1068*3034Sdougm * but only if it actually exists. 1069*3034Sdougm */ 1070*3034Sdougm 1071*3034Sdougm int 1072*3034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 1073*3034Sdougm { 1074*3034Sdougm int ret = SA_OK; 1075*3034Sdougm /* 1076*3034Sdougm * only delete if it does exist. 1077*3034Sdougm */ 1078*3034Sdougm if (scf_instance_get_pg(handle->instance, 1079*3034Sdougm pgroup, handle->pg) == 0) { 1080*3034Sdougm /* does exist so delete it */ 1081*3034Sdougm if (scf_pg_delete(handle->pg) != 0) { 1082*3034Sdougm ret = SA_SYSTEM_ERR; 1083*3034Sdougm } 1084*3034Sdougm } else { 1085*3034Sdougm ret = SA_SYSTEM_ERR; 1086*3034Sdougm } 1087*3034Sdougm if (ret == SA_SYSTEM_ERR && 1088*3034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 1089*3034Sdougm ret = SA_NO_PERMISSION; 1090*3034Sdougm } 1091*3034Sdougm return (ret); 1092*3034Sdougm } 1093*3034Sdougm 1094*3034Sdougm /* 1095*3034Sdougm * sa_start_transaction(handle, pgroup) 1096*3034Sdougm * 1097*3034Sdougm * Start an SMF transaction so we can deal with properties. it would 1098*3034Sdougm * be nice to not have to expose this, but we have to in order to 1099*3034Sdougm * optimize. 1100*3034Sdougm * 1101*3034Sdougm * Basic model is to hold the transaction in the handle and allow 1102*3034Sdougm * property adds/deletes/updates to be added then close the 1103*3034Sdougm * transaction (or abort). There may eventually be a need to handle 1104*3034Sdougm * other types of transaction mechanisms but we don't do that now. 1105*3034Sdougm * 1106*3034Sdougm * An sa_start_transaction must be followed by either an 1107*3034Sdougm * sa_end_transaction or sa_abort_transaction before another 1108*3034Sdougm * sa_start_transaction can be done. 1109*3034Sdougm */ 1110*3034Sdougm 1111*3034Sdougm int 1112*3034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 1113*3034Sdougm { 1114*3034Sdougm int ret = SA_OK; 1115*3034Sdougm /* 1116*3034Sdougm * lookup the property group and create it if it doesn't already 1117*3034Sdougm * exist. 1118*3034Sdougm */ 1119*3034Sdougm if (handle->scf_state == SCH_STATE_INIT) { 1120*3034Sdougm ret = sa_create_pgroup(handle, propgroup); 1121*3034Sdougm if (ret == SA_OK) { 1122*3034Sdougm handle->trans = scf_transaction_create(handle->handle); 1123*3034Sdougm if (handle->trans != NULL) { 1124*3034Sdougm if (scf_transaction_start(handle->trans, handle->pg) != 0) { 1125*3034Sdougm ret = SA_SYSTEM_ERR; 1126*3034Sdougm } 1127*3034Sdougm if (ret != SA_OK) { 1128*3034Sdougm scf_transaction_destroy(handle->trans); 1129*3034Sdougm handle->trans = NULL; 1130*3034Sdougm } 1131*3034Sdougm } else { 1132*3034Sdougm ret = SA_SYSTEM_ERR; 1133*3034Sdougm } 1134*3034Sdougm } 1135*3034Sdougm } 1136*3034Sdougm if (ret == SA_SYSTEM_ERR && 1137*3034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 1138*3034Sdougm ret = SA_NO_PERMISSION; 1139*3034Sdougm } 1140*3034Sdougm return (ret); 1141*3034Sdougm } 1142*3034Sdougm 1143*3034Sdougm /* 1144*3034Sdougm * sa_end_transaction(handle) 1145*3034Sdougm * 1146*3034Sdougm * Commit the changes that were added to the transaction in the 1147*3034Sdougm * handle. Do all necessary cleanup. 1148*3034Sdougm */ 1149*3034Sdougm 1150*3034Sdougm int 1151*3034Sdougm sa_end_transaction(scfutilhandle_t *handle) 1152*3034Sdougm { 1153*3034Sdougm int ret = SA_OK; 1154*3034Sdougm 1155*3034Sdougm if (handle->trans == NULL) { 1156*3034Sdougm ret = SA_SYSTEM_ERR; 1157*3034Sdougm } else { 1158*3034Sdougm if (scf_transaction_commit(handle->trans) < 0) 1159*3034Sdougm ret = SA_SYSTEM_ERR; 1160*3034Sdougm scf_transaction_destroy_children(handle->trans); 1161*3034Sdougm scf_transaction_destroy(handle->trans); 1162*3034Sdougm handle->trans = NULL; 1163*3034Sdougm } 1164*3034Sdougm return (ret); 1165*3034Sdougm } 1166*3034Sdougm 1167*3034Sdougm /* 1168*3034Sdougm * sa_abort_transaction(handle) 1169*3034Sdougm * 1170*3034Sdougm * Abort the changes that were added to the transaction in the 1171*3034Sdougm * handle. Do all necessary cleanup. 1172*3034Sdougm */ 1173*3034Sdougm 1174*3034Sdougm void 1175*3034Sdougm sa_abort_transaction(scfutilhandle_t *handle) 1176*3034Sdougm { 1177*3034Sdougm if (handle->trans != NULL) { 1178*3034Sdougm scf_transaction_reset_all(handle->trans); 1179*3034Sdougm scf_transaction_destroy_children(handle->trans); 1180*3034Sdougm scf_transaction_destroy(handle->trans); 1181*3034Sdougm handle->trans = NULL; 1182*3034Sdougm } 1183*3034Sdougm } 1184*3034Sdougm 1185*3034Sdougm /* 1186*3034Sdougm * sa_set_property(handle, prop, value) 1187*3034Sdougm * 1188*3034Sdougm * set a property transaction entry into the pending SMF transaction. 1189*3034Sdougm */ 1190*3034Sdougm 1191*3034Sdougm int 1192*3034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 1193*3034Sdougm { 1194*3034Sdougm int ret = SA_OK; 1195*3034Sdougm scf_value_t *value; 1196*3034Sdougm scf_transaction_entry_t *entry; 1197*3034Sdougm /* 1198*3034Sdougm * properties must be set in transactions and don't take 1199*3034Sdougm * effect until the transaction has been ended/committed. 1200*3034Sdougm */ 1201*3034Sdougm value = scf_value_create(handle->handle); 1202*3034Sdougm entry = scf_entry_create(handle->handle); 1203*3034Sdougm if (value != NULL && entry != NULL) { 1204*3034Sdougm if (scf_transaction_property_change(handle->trans, entry, 1205*3034Sdougm propname, 1206*3034Sdougm SCF_TYPE_ASTRING) == 0 || 1207*3034Sdougm scf_transaction_property_new(handle->trans, entry, 1208*3034Sdougm propname, 1209*3034Sdougm SCF_TYPE_ASTRING) == 0) { 1210*3034Sdougm if (scf_value_set_astring(value, valstr) == 0) { 1211*3034Sdougm if (scf_entry_add_value(entry, value) != 0) { 1212*3034Sdougm ret = SA_SYSTEM_ERR; 1213*3034Sdougm scf_value_destroy(value); 1214*3034Sdougm } 1215*3034Sdougm /* the value is in the transaction */ 1216*3034Sdougm value = NULL; 1217*3034Sdougm } else { 1218*3034Sdougm /* value couldn't be constructed */ 1219*3034Sdougm ret = SA_SYSTEM_ERR; 1220*3034Sdougm } 1221*3034Sdougm /* the entry is in the transaction */ 1222*3034Sdougm entry = NULL; 1223*3034Sdougm } else { 1224*3034Sdougm ret = SA_SYSTEM_ERR; 1225*3034Sdougm } 1226*3034Sdougm } else { 1227*3034Sdougm ret = SA_SYSTEM_ERR; 1228*3034Sdougm } 1229*3034Sdougm if (ret == SA_SYSTEM_ERR) { 1230*3034Sdougm switch (scf_error()) { 1231*3034Sdougm case SCF_ERROR_PERMISSION_DENIED: 1232*3034Sdougm ret = SA_NO_PERMISSION; 1233*3034Sdougm break; 1234*3034Sdougm } 1235*3034Sdougm } 1236*3034Sdougm /* 1237*3034Sdougm * cleanup if there were any errors that didn't leave these 1238*3034Sdougm * values where they would be cleaned up later. 1239*3034Sdougm */ 1240*3034Sdougm if (value != NULL) 1241*3034Sdougm scf_value_destroy(value); 1242*3034Sdougm if (entry != NULL) 1243*3034Sdougm scf_entry_destroy(entry); 1244*3034Sdougm return (ret); 1245*3034Sdougm } 1246*3034Sdougm 1247*3034Sdougm /* 1248*3034Sdougm * sa_commit_share(handle, group, share) 1249*3034Sdougm * 1250*3034Sdougm * commit this share to the repository. 1251*3034Sdougm * properties are added if they exist but can be added later. 1252*3034Sdougm * Need to add to dfstab and sharetab, if appropriate. 1253*3034Sdougm */ 1254*3034Sdougm int 1255*3034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 1256*3034Sdougm { 1257*3034Sdougm int ret = SA_OK; 1258*3034Sdougm char *groupname; 1259*3034Sdougm char *name; 1260*3034Sdougm char *resource; 1261*3034Sdougm char *description; 1262*3034Sdougm char *sharename; 1263*3034Sdougm ssize_t proplen; 1264*3034Sdougm char *propstring; 1265*3034Sdougm 1266*3034Sdougm /* 1267*3034Sdougm * don't commit in the zfs group. We do commit legacy 1268*3034Sdougm * (default) and all other groups/shares. ZFS is handled 1269*3034Sdougm * through the ZFS configuration rather than SMF. 1270*3034Sdougm */ 1271*3034Sdougm 1272*3034Sdougm groupname = sa_get_group_attr(group, "name"); 1273*3034Sdougm if (groupname != NULL) { 1274*3034Sdougm if (strcmp(groupname, "zfs") == 0) { 1275*3034Sdougm /* 1276*3034Sdougm * adding to the ZFS group will result in the sharenfs 1277*3034Sdougm * property being set but we don't want to do anything 1278*3034Sdougm * SMF related at this point. 1279*3034Sdougm */ 1280*3034Sdougm sa_free_attr_string(groupname); 1281*3034Sdougm return (ret); 1282*3034Sdougm } 1283*3034Sdougm } 1284*3034Sdougm 1285*3034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1286*3034Sdougm propstring = malloc(proplen); 1287*3034Sdougm if (propstring == NULL) 1288*3034Sdougm ret = SA_NO_MEMORY; 1289*3034Sdougm 1290*3034Sdougm if (groupname != NULL && ret == SA_OK) { 1291*3034Sdougm ret = sa_get_instance(handle, groupname); 1292*3034Sdougm sa_free_attr_string(groupname); 1293*3034Sdougm groupname = NULL; 1294*3034Sdougm sharename = sa_get_share_attr(share, "id"); 1295*3034Sdougm if (sharename == NULL) { 1296*3034Sdougm /* slipped by */ 1297*3034Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 1298*3034Sdougm generate_unique_sharename(shname); 1299*3034Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 1300*3034Sdougm (xmlChar *)shname); 1301*3034Sdougm sharename = strdup(shname); 1302*3034Sdougm } 1303*3034Sdougm if (sharename != NULL) { 1304*3034Sdougm /* 1305*3034Sdougm * have a share name allocated so create a pgroup 1306*3034Sdougm * for it. It may already exist, but that is OK. 1307*3034Sdougm */ 1308*3034Sdougm ret = sa_create_pgroup(handle, sharename); 1309*3034Sdougm if (ret == SA_OK) { 1310*3034Sdougm /* 1311*3034Sdougm * now start the transaction for the 1312*3034Sdougm * properties that define this share. They may 1313*3034Sdougm * exist so attempt to update before create. 1314*3034Sdougm */ 1315*3034Sdougm ret = sa_start_transaction(handle, sharename); 1316*3034Sdougm } 1317*3034Sdougm if (ret == SA_OK) { 1318*3034Sdougm name = sa_get_share_attr(share, "path"); 1319*3034Sdougm if (name != NULL) { 1320*3034Sdougm /* there needs to be a path for a share to exist */ 1321*3034Sdougm ret = sa_set_property(handle, "path", name); 1322*3034Sdougm sa_free_attr_string(name); 1323*3034Sdougm } else { 1324*3034Sdougm ret = SA_NO_MEMORY; 1325*3034Sdougm } 1326*3034Sdougm } 1327*3034Sdougm if (ret == SA_OK) { 1328*3034Sdougm resource = sa_get_share_attr(share, "resource"); 1329*3034Sdougm if (resource != NULL) { 1330*3034Sdougm ret = sa_set_property(handle, "resource", resource); 1331*3034Sdougm sa_free_attr_string(resource); 1332*3034Sdougm } 1333*3034Sdougm } 1334*3034Sdougm if (ret == SA_OK) { 1335*3034Sdougm description = sa_get_share_description(share); 1336*3034Sdougm if (description != NULL) { 1337*3034Sdougm ret = sa_set_property(handle, "description", 1338*3034Sdougm description); 1339*3034Sdougm sa_free_share_description(description); 1340*3034Sdougm } 1341*3034Sdougm } 1342*3034Sdougm /* make sure we cleanup the transaction */ 1343*3034Sdougm if (ret == SA_OK) { 1344*3034Sdougm ret = sa_end_transaction(handle); 1345*3034Sdougm } else { 1346*3034Sdougm sa_abort_transaction(handle); 1347*3034Sdougm } 1348*3034Sdougm free(sharename); 1349*3034Sdougm } 1350*3034Sdougm } 1351*3034Sdougm if (ret == SA_SYSTEM_ERR) { 1352*3034Sdougm int err = scf_error(); 1353*3034Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 1354*3034Sdougm ret = SA_NO_PERMISSION; 1355*3034Sdougm } 1356*3034Sdougm if (propstring != NULL) 1357*3034Sdougm free(propstring); 1358*3034Sdougm if (groupname != NULL) 1359*3034Sdougm sa_free_attr_string(groupname); 1360*3034Sdougm 1361*3034Sdougm return (ret); 1362*3034Sdougm } 1363*3034Sdougm 1364*3034Sdougm /* 1365*3034Sdougm * sa_delete_share(handle, group, share) 1366*3034Sdougm * 1367*3034Sdougm * remove the specified share from the group (and service instance). 1368*3034Sdougm */ 1369*3034Sdougm 1370*3034Sdougm int 1371*3034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 1372*3034Sdougm { 1373*3034Sdougm int ret = SA_OK; 1374*3034Sdougm char *groupname = NULL; 1375*3034Sdougm char *shareid = NULL; 1376*3034Sdougm sa_optionset_t opt; 1377*3034Sdougm sa_security_t sec; 1378*3034Sdougm ssize_t proplen; 1379*3034Sdougm char *propstring; 1380*3034Sdougm 1381*3034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1382*3034Sdougm propstring = malloc(proplen); 1383*3034Sdougm if (propstring == NULL) 1384*3034Sdougm ret = SA_NO_MEMORY; 1385*3034Sdougm 1386*3034Sdougm if (ret == SA_OK) { 1387*3034Sdougm groupname = sa_get_group_attr(group, "name"); 1388*3034Sdougm shareid = sa_get_share_attr(share, "id"); 1389*3034Sdougm if (groupname != NULL && shareid != NULL) { 1390*3034Sdougm ret = sa_get_instance(handle, groupname); 1391*3034Sdougm if (ret == SA_OK) { 1392*3034Sdougm /* if a share has properties, remove them */ 1393*3034Sdougm ret = sa_delete_pgroup(handle, shareid); 1394*3034Sdougm for (opt = sa_get_optionset(share, NULL); opt != NULL; 1395*3034Sdougm opt = sa_get_next_optionset(opt)) { 1396*3034Sdougm char *proto; 1397*3034Sdougm proto = sa_get_optionset_attr(opt, "type"); 1398*3034Sdougm if (proto != NULL) { 1399*3034Sdougm (void) snprintf(propstring, proplen, "%s_%s", 1400*3034Sdougm shareid, proto); 1401*3034Sdougm ret = sa_delete_pgroup(handle, propstring); 1402*3034Sdougm sa_free_attr_string(proto); 1403*3034Sdougm } else { 1404*3034Sdougm ret = SA_NO_MEMORY; 1405*3034Sdougm } 1406*3034Sdougm } 1407*3034Sdougm /* 1408*3034Sdougm * if a share has security/negotiable 1409*3034Sdougm * properties, remove them. 1410*3034Sdougm */ 1411*3034Sdougm for (sec = sa_get_security(share, NULL, NULL); sec != NULL; 1412*3034Sdougm sec = sa_get_next_security(sec)) { 1413*3034Sdougm char *proto; 1414*3034Sdougm char *sectype; 1415*3034Sdougm proto = sa_get_security_attr(sec, "type"); 1416*3034Sdougm sectype = sa_get_security_attr(sec, "sectype"); 1417*3034Sdougm if (proto != NULL && sectype != NULL) { 1418*3034Sdougm (void) snprintf(propstring, proplen, "%s_%s_%s", 1419*3034Sdougm shareid, 1420*3034Sdougm proto, sectype); 1421*3034Sdougm ret = sa_delete_pgroup(handle, propstring); 1422*3034Sdougm } else { 1423*3034Sdougm ret = SA_NO_MEMORY; 1424*3034Sdougm } 1425*3034Sdougm if (proto != NULL) 1426*3034Sdougm sa_free_attr_string(proto); 1427*3034Sdougm if (sectype != NULL) 1428*3034Sdougm sa_free_attr_string(sectype); 1429*3034Sdougm } 1430*3034Sdougm } 1431*3034Sdougm } else { 1432*3034Sdougm ret = SA_CONFIG_ERR; 1433*3034Sdougm } 1434*3034Sdougm } 1435*3034Sdougm if (groupname != NULL) 1436*3034Sdougm sa_free_attr_string(groupname); 1437*3034Sdougm if (shareid != NULL) 1438*3034Sdougm sa_free_attr_string(shareid); 1439*3034Sdougm if (propstring != NULL) 1440*3034Sdougm free(propstring); 1441*3034Sdougm 1442*3034Sdougm return (ret); 1443*3034Sdougm } 1444