1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* helper functions for using libscf with sharemgr */ 30 31 #include <libscf.h> 32 #include <libxml/parser.h> 33 #include <libxml/tree.h> 34 #include "libshare.h" 35 #include "libshare_impl.h" 36 #include "scfutil.h" 37 #include <string.h> 38 #include <ctype.h> 39 #include <errno.h> 40 #include <uuid/uuid.h> 41 #include <sys/param.h> 42 #include <signal.h> 43 44 ssize_t scf_max_name_len; 45 extern struct sa_proto_plugin *sap_proto_list; 46 extern sa_handle_impl_t get_handle_for_root(xmlNodePtr); 47 48 /* 49 * The SMF facility uses some properties that must exist. We want to 50 * skip over these when processing protocol options. 51 */ 52 static char *skip_props[] = { 53 "modify_authorization", 54 "action_authorization", 55 "value_authorization", 56 NULL 57 }; 58 59 /* 60 * sa_scf_fini(handle) 61 * 62 * Must be called when done. Called with the handle allocated in 63 * sa_scf_init(), it cleans up the state and frees any SCF resources 64 * still in use. Called by sa_fini(). 65 */ 66 67 void 68 sa_scf_fini(scfutilhandle_t *handle) 69 { 70 if (handle != NULL) { 71 int unbind = 0; 72 if (handle->scope != NULL) { 73 unbind = 1; 74 scf_scope_destroy(handle->scope); 75 } 76 if (handle->instance != NULL) 77 scf_instance_destroy(handle->instance); 78 if (handle->service != NULL) 79 scf_service_destroy(handle->service); 80 if (handle->pg != NULL) 81 scf_pg_destroy(handle->pg); 82 if (handle->handle != NULL) { 83 handle->scf_state = SCH_STATE_UNINIT; 84 if (unbind) 85 (void) scf_handle_unbind(handle->handle); 86 scf_handle_destroy(handle->handle); 87 } 88 free(handle); 89 } 90 } 91 92 /* 93 * sa_scf_init() 94 * 95 * Must be called before using any of the SCF functions. Called by 96 * sa_init() during the API setup. 97 */ 98 99 scfutilhandle_t * 100 sa_scf_init(sa_handle_impl_t ihandle) 101 { 102 scfutilhandle_t *handle; 103 104 scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 105 if (scf_max_name_len <= 0) 106 scf_max_name_len = SA_MAX_NAME_LEN + 1; 107 108 handle = calloc(1, sizeof (scfutilhandle_t)); 109 if (handle == NULL) 110 return (handle); 111 112 ihandle->scfhandle = handle; 113 handle->scf_state = SCH_STATE_INITIALIZING; 114 handle->handle = scf_handle_create(SCF_VERSION); 115 if (handle->handle == NULL) { 116 free(handle); 117 handle = NULL; 118 (void) printf("libshare could not access SMF repository: %s\n", 119 scf_strerror(scf_error())); 120 return (handle); 121 } 122 if (scf_handle_bind(handle->handle) != 0) 123 goto err; 124 125 handle->scope = scf_scope_create(handle->handle); 126 handle->service = scf_service_create(handle->handle); 127 handle->pg = scf_pg_create(handle->handle); 128 129 /* Make sure we have sufficient SMF running */ 130 handle->instance = scf_instance_create(handle->handle); 131 if (handle->scope == NULL || handle->service == NULL || 132 handle->pg == NULL || handle->instance == NULL) 133 goto err; 134 if (scf_handle_get_scope(handle->handle, 135 SCF_SCOPE_LOCAL, handle->scope) != 0) 136 goto err; 137 if (scf_scope_get_service(handle->scope, 138 SA_GROUP_SVC_NAME, handle->service) != 0) 139 goto err; 140 141 handle->scf_state = SCH_STATE_INIT; 142 if (sa_get_instance(handle, "default") != SA_OK) { 143 char **protolist; 144 int numprotos, i; 145 sa_group_t defgrp; 146 defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 147 if (defgrp != NULL) { 148 numprotos = sa_get_protocols( 149 &protolist); 150 for (i = 0; i < numprotos; i++) 151 (void) sa_create_optionset(defgrp, 152 protolist[i]); 153 if (protolist != NULL) 154 free(protolist); 155 } 156 } 157 158 return (handle); 159 160 /* Error handling/unwinding */ 161 err: 162 (void) sa_scf_fini(handle); 163 (void) printf("libshare SMF initialization problem: %s\n", 164 scf_strerror(scf_error())); 165 return (NULL); 166 } 167 168 /* 169 * get_scf_limit(name) 170 * 171 * Since we use scf_limit a lot and do the same check and return the 172 * same value if it fails, implement as a function for code 173 * simplification. Basically, if name isn't found, return MAXPATHLEN 174 * (1024) so we have a reasonable default buffer size. 175 */ 176 static ssize_t 177 get_scf_limit(uint32_t name) 178 { 179 ssize_t vallen; 180 181 vallen = scf_limit(name); 182 if (vallen == (ssize_t)-1) 183 vallen = MAXPATHLEN; 184 return (vallen); 185 } 186 187 /* 188 * skip_property(name) 189 * 190 * Internal function to check to see if a property is an SMF magic 191 * property that needs to be skipped. 192 */ 193 static int 194 skip_property(char *name) 195 { 196 int i; 197 198 for (i = 0; skip_props[i] != NULL; i++) 199 if (strcmp(name, skip_props[i]) == 0) 200 return (1); 201 return (0); 202 } 203 204 /* 205 * generate_unique_sharename(sharename) 206 * 207 * Shares are represented in SMF as property groups. Due to share 208 * paths containing characters that are not allowed in SMF names and 209 * the need to be unique, we use UUIDs to construct a unique name. 210 */ 211 212 static void 213 generate_unique_sharename(char *sharename) 214 { 215 uuid_t uuid; 216 217 uuid_generate(uuid); 218 (void) strcpy(sharename, "S-"); 219 uuid_unparse(uuid, sharename + 2); 220 } 221 222 /* 223 * valid_protocol(proto) 224 * 225 * Check to see if the specified protocol is a valid one for the 226 * general sharemgr facility. We determine this by checking which 227 * plugin protocols were found. 228 */ 229 230 static int 231 valid_protocol(char *proto) 232 { 233 struct sa_proto_plugin *plugin; 234 for (plugin = sap_proto_list; plugin != NULL; 235 plugin = plugin->plugin_next) 236 if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 237 return (1); 238 return (0); 239 } 240 241 /* 242 * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 243 * 244 * Extract the name property group and create the specified type of 245 * node on the provided group. type will be optionset or security. 246 */ 247 248 static int 249 sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 250 scf_propertygroup_t *pg, 251 char *nodetype, char *proto, char *sectype) 252 { 253 xmlNodePtr node; 254 scf_iter_t *iter; 255 scf_property_t *prop; 256 scf_value_t *value; 257 char *name; 258 char *valuestr; 259 ssize_t vallen; 260 int ret = SA_OK; 261 262 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 263 264 node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 265 if (node == NULL) 266 return (ret); 267 268 if (proto != NULL) 269 xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 270 if (sectype != NULL) 271 xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 272 /* 273 * Have node to work with so iterate over the properties 274 * in the pg and create option sub nodes. 275 */ 276 iter = scf_iter_create(handle->handle); 277 value = scf_value_create(handle->handle); 278 prop = scf_property_create(handle->handle); 279 name = malloc(scf_max_name_len); 280 valuestr = malloc(vallen); 281 /* 282 * Want to iterate through the properties and add them 283 * to the base optionset. 284 */ 285 if (iter == NULL || value == NULL || prop == NULL || 286 valuestr == NULL || name == NULL) { 287 ret = SA_NO_MEMORY; 288 goto out; 289 } 290 if (scf_iter_pg_properties(iter, pg) == 0) { 291 /* Now iterate the properties in the group */ 292 while (scf_iter_next_property(iter, prop) > 0) { 293 /* have a property */ 294 if (scf_property_get_name(prop, name, 295 scf_max_name_len) > 0) { 296 sa_property_t saprop; 297 /* Some properties are part of the framework */ 298 if (skip_property(name)) 299 continue; 300 if (scf_property_get_value(prop, value) != 0) 301 continue; 302 if (scf_value_get_astring(value, valuestr, 303 vallen) < 0) 304 continue; 305 saprop = sa_create_property(name, valuestr); 306 if (saprop != NULL) { 307 /* 308 * Since in SMF, don't 309 * recurse. Use xmlAddChild 310 * directly, instead. 311 */ 312 xmlAddChild(node, 313 (xmlNodePtr) saprop); 314 } 315 } 316 } 317 } 318 out: 319 /* cleanup to avoid memory leaks */ 320 if (value != NULL) 321 scf_value_destroy(value); 322 if (iter != NULL) 323 scf_iter_destroy(iter); 324 if (prop != NULL) 325 scf_property_destroy(prop); 326 if (name != NULL) 327 free(name); 328 if (valuestr != NULL) 329 free(valuestr); 330 331 return (ret); 332 } 333 334 /* 335 * sa_extract_attrs(root, handle, instance) 336 * 337 * Local function to extract the actual attributes/properties from the 338 * property group of the service instance. These are the well known 339 * attributes of "state" and "zfs". If additional attributes are 340 * added, they should be added here. 341 */ 342 343 static void 344 sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 345 scf_instance_t *instance) 346 { 347 scf_property_t *prop; 348 scf_value_t *value; 349 char *valuestr; 350 ssize_t vallen; 351 352 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 353 prop = scf_property_create(handle->handle); 354 value = scf_value_create(handle->handle); 355 valuestr = malloc(vallen); 356 if (prop == NULL || value == NULL || valuestr == NULL || 357 scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 358 goto out; 359 } 360 /* 361 * Have a property group with desired name so now get 362 * the known attributes. 363 */ 364 if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 365 /* Found the property so get the value */ 366 if (scf_property_get_value(prop, value) == 0) { 367 if (scf_value_get_astring(value, valuestr, 368 vallen) >= 0) { 369 xmlSetProp(root, (xmlChar *)"state", 370 (xmlChar *)valuestr); 371 } 372 } 373 } 374 if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 375 /* Found the property so get the value */ 376 if (scf_property_get_value(prop, value) == 0) { 377 if (scf_value_get_astring(value, valuestr, 378 vallen) > 0) { 379 xmlSetProp(root, (xmlChar *)"zfs", 380 (xmlChar *)valuestr); 381 } 382 } 383 } 384 out: 385 if (valuestr != NULL) 386 free(valuestr); 387 if (value != NULL) 388 scf_value_destroy(value); 389 if (prop != NULL) 390 scf_property_destroy(prop); 391 } 392 393 /* 394 * List of known share attributes. 395 */ 396 397 static char *share_attr[] = { 398 "path", 399 "id", 400 "drive-letter", 401 "exclude", 402 NULL, 403 }; 404 405 static int 406 is_share_attr(char *name) 407 { 408 int i; 409 for (i = 0; share_attr[i] != NULL; i++) 410 if (strcmp(name, share_attr[i]) == 0) 411 return (1); 412 return (0); 413 } 414 415 /* 416 * _sa_make_resource(node, valuestr) 417 * 418 * Make a resource node on the share node. The valusestr will either 419 * be old format (SMF acceptable string) or new format (pretty much an 420 * arbitrary string with "nnn:" prefixing in order to persist 421 * mapping). The input valuestr will get modified in place. This is 422 * only used in SMF repository parsing. A possible third field will be 423 * a "description" string. 424 */ 425 426 static void 427 _sa_make_resource(xmlNodePtr node, char *valuestr) 428 { 429 char *idx; 430 char *name; 431 char *description = NULL; 432 433 idx = valuestr; 434 name = strchr(valuestr, ':'); 435 if (name == NULL) { 436 /* this is old form so give an index of "0" */ 437 idx = "0"; 438 name = valuestr; 439 } else { 440 /* NUL the ':' and move past it */ 441 *name++ = '\0'; 442 /* There could also be a description string */ 443 description = strchr(name, ':'); 444 if (description != NULL) 445 *description++ = '\0'; 446 } 447 node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL); 448 if (node != NULL) { 449 xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name); 450 xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx); 451 /* SMF values are always persistent */ 452 xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 453 if (description != NULL && strlen(description) > 0) { 454 (void) xmlNewChild(node, NULL, (xmlChar *)"description", 455 (xmlChar *)description); 456 } 457 } 458 } 459 460 461 /* 462 * sa_share_from_pgroup 463 * 464 * Extract the share definition from the share property group. We do 465 * some sanity checking to avoid bad data. 466 * 467 * Since this is only constructing the internal data structures, we 468 * don't use the sa_* functions most of the time. 469 */ 470 void 471 sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 472 scf_propertygroup_t *pg, char *id) 473 { 474 xmlNodePtr node; 475 char *name; 476 scf_iter_t *iter; 477 scf_property_t *prop; 478 scf_value_t *value; 479 ssize_t vallen; 480 char *valuestr; 481 int ret = SA_OK; 482 int have_path = 0; 483 484 /* 485 * While preliminary check (starts with 'S') passed before 486 * getting here. Need to make sure it is in ID syntax 487 * (Snnnnnn). Note that shares with properties have similar 488 * pgroups. 489 */ 490 vallen = strlen(id); 491 if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 492 uuid_t uuid; 493 if (strncmp(id, SA_SHARE_PG_PREFIX, 494 SA_SHARE_PG_PREFIXLEN) != 0 || 495 uuid_parse(id + 2, uuid) < 0) 496 return; 497 } else { 498 return; 499 } 500 501 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 502 503 iter = scf_iter_create(handle->handle); 504 value = scf_value_create(handle->handle); 505 prop = scf_property_create(handle->handle); 506 name = malloc(scf_max_name_len); 507 valuestr = malloc(vallen); 508 509 /* 510 * Construct the share XML node. It is similar to sa_add_share 511 * but never changes the repository. Also, there won't be any 512 * ZFS or transient shares. Root will be the group it is 513 * associated with. 514 */ 515 node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 516 if (node != NULL) { 517 /* 518 * Make sure the UUID part of the property group is 519 * stored in the share "id" property. We use this 520 * later. 521 */ 522 xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 523 xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 524 } 525 526 if (iter == NULL || value == NULL || prop == NULL || name == NULL) 527 goto out; 528 529 /* Iterate over the share pg properties */ 530 if (scf_iter_pg_properties(iter, pg) != 0) 531 goto out; 532 533 while (scf_iter_next_property(iter, prop) > 0) { 534 ret = SA_SYSTEM_ERR; /* assume the worst */ 535 if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 536 if (scf_property_get_value(prop, value) == 0) { 537 if (scf_value_get_astring(value, valuestr, 538 vallen) >= 0) { 539 ret = SA_OK; 540 } 541 } else if (strcmp(name, "resource") == 0) { 542 ret = SA_OK; 543 } 544 } 545 if (ret != SA_OK) 546 continue; 547 /* 548 * Check that we have the "path" property in 549 * name. The string in name will always be nul 550 * terminated if scf_property_get_name() 551 * succeeded. 552 */ 553 if (strcmp(name, "path") == 0) 554 have_path = 1; 555 if (is_share_attr(name)) { 556 /* 557 * If a share attr, then simple - 558 * usually path and id name 559 */ 560 xmlSetProp(node, (xmlChar *)name, 561 (xmlChar *)valuestr); 562 } else if (strcmp(name, "resource") == 0) { 563 /* 564 * Resource names handled differently since 565 * there can be multiple on each share. The 566 * "resource" id must be preserved since this 567 * will be used by some protocols in mapping 568 * "property spaces" to names and is always 569 * used to create SMF property groups specific 570 * to resources. CIFS needs this. The first 571 * value is present so add and then loop for 572 * any additional. Since this is new and 573 * previous values may exist, handle 574 * conversions. 575 */ 576 scf_iter_t *viter; 577 viter = scf_iter_create(handle->handle); 578 if (viter != NULL && 579 scf_iter_property_values(viter, prop) == 0) { 580 while (scf_iter_next_value(viter, value) > 0) { 581 /* Have a value so process it */ 582 if (scf_value_get_ustring(value, 583 valuestr, vallen) >= 0) { 584 /* have a ustring */ 585 _sa_make_resource(node, 586 valuestr); 587 } else if (scf_value_get_astring(value, 588 valuestr, vallen) >= 0) { 589 /* have an astring */ 590 _sa_make_resource(node, 591 valuestr); 592 } 593 } 594 scf_iter_destroy(viter); 595 } 596 } else { 597 if (strcmp(name, "description") == 0) { 598 /* We have a description node */ 599 xmlNodePtr desc; 600 desc = xmlNewChild(node, NULL, 601 (xmlChar *)"description", NULL); 602 if (desc != NULL) 603 xmlNodeSetContent(desc, 604 (xmlChar *)valuestr); 605 } 606 } 607 } 608 out: 609 /* 610 * A share without a path is broken so we want to not include 611 * these. They shouldn't happen but if you kill a sharemgr in 612 * the process of creating a share, it could happen. They 613 * should be harmless. It is also possible that another 614 * sharemgr is running and in the process of creating a share. 615 */ 616 if (have_path == 0 && node != NULL) { 617 xmlUnlinkNode(node); 618 xmlFreeNode(node); 619 } 620 if (name != NULL) 621 free(name); 622 if (valuestr != NULL) 623 free(valuestr); 624 if (value != NULL) 625 scf_value_destroy(value); 626 if (iter != NULL) 627 scf_iter_destroy(iter); 628 if (prop != NULL) 629 scf_property_destroy(prop); 630 } 631 632 /* 633 * find_share_by_id(shareid) 634 * 635 * Search all shares in all groups until we find the share represented 636 * by "id". 637 */ 638 639 static sa_share_t 640 find_share_by_id(sa_handle_t handle, char *shareid) 641 { 642 sa_group_t group; 643 sa_share_t share = NULL; 644 char *id = NULL; 645 int done = 0; 646 647 for (group = sa_get_group(handle, NULL); 648 group != NULL && !done; 649 group = sa_get_next_group(group)) { 650 for (share = sa_get_share(group, NULL); 651 share != NULL; 652 share = sa_get_next_share(share)) { 653 id = sa_get_share_attr(share, "id"); 654 if (id != NULL && strcmp(id, shareid) == 0) { 655 sa_free_attr_string(id); 656 id = NULL; 657 done++; 658 break; 659 } 660 if (id != NULL) { 661 sa_free_attr_string(id); 662 id = NULL; 663 } 664 } 665 } 666 return (share); 667 } 668 669 /* 670 * find_resource_by_index(share, index) 671 * 672 * Search the resource records on the share for the id index. 673 */ 674 static sa_resource_t 675 find_resource_by_index(sa_share_t share, char *index) 676 { 677 sa_resource_t resource; 678 sa_resource_t found = NULL; 679 char *id; 680 681 for (resource = sa_get_share_resource(share, NULL); 682 resource != NULL && found == NULL; 683 resource = sa_get_next_resource(resource)) { 684 id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id"); 685 if (id != NULL) { 686 if (strcmp(id, index) == 0) { 687 /* found it so save in "found" */ 688 found = resource; 689 } 690 sa_free_attr_string(id); 691 } 692 } 693 return (found); 694 } 695 696 /* 697 * sa_share_props_from_pgroup(root, handle, pg, id, sahandle) 698 * 699 * Extract share properties from the SMF property group. More sanity 700 * checks are done and the share object is created. We ignore some 701 * errors that could exist in the repository and only worry about 702 * property groups that validate in naming. 703 */ 704 705 static int 706 sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 707 scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 708 { 709 xmlNodePtr node; 710 char *name = NULL; 711 scf_iter_t *iter = NULL; 712 scf_property_t *prop = NULL; 713 scf_value_t *value = NULL; 714 ssize_t vallen; 715 char *valuestr = NULL; 716 int ret = SA_OK; 717 char *sectype = NULL; 718 char *proto; 719 sa_share_t share; 720 uuid_t uuid; 721 722 /* 723 * While preliminary check (starts with 'S') passed before 724 * getting here. Need to make sure it is in ID syntax 725 * (Snnnnnn). Note that shares with properties have similar 726 * pgroups. If the pg name is more than SA_SHARE_PG_LEN 727 * characters, it is likely one of the protocol/security 728 * versions. 729 */ 730 vallen = strlen(id); 731 if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 732 /* 733 * It is ok to not have what we thought since someone might 734 * have added a name via SMF. 735 */ 736 return (ret); 737 } 738 if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 739 proto = strchr(id, '_'); 740 if (proto == NULL) 741 return (ret); 742 *proto++ = '\0'; 743 if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 744 return (ret); 745 /* 746 * probably a legal optionset so check a few more 747 * syntax points below. 748 */ 749 if (*proto == '\0') { 750 /* not a valid proto (null) */ 751 return (ret); 752 } 753 754 sectype = strchr(proto, '_'); 755 if (sectype != NULL) 756 *sectype++ = '\0'; 757 if (!valid_protocol(proto)) 758 return (ret); 759 } 760 761 /* 762 * To get here, we have a valid protocol and possibly a 763 * security. We now have to find the share that it is really 764 * associated with. The "id" portion of the pgroup name will 765 * match. 766 */ 767 768 share = find_share_by_id(sahandle, id); 769 if (share == NULL) 770 return (SA_BAD_PATH); 771 772 root = (xmlNodePtr)share; 773 774 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 775 776 if (sectype == NULL) 777 node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 778 else { 779 if (isdigit((int)*sectype)) { 780 sa_resource_t resource; 781 /* 782 * If sectype[0] is a digit, then it is an index into 783 * the resource names. We need to find a resource 784 * record and then get the properties into an 785 * optionset. The optionset becomes the "node" and the 786 * rest is hung off of the share. 787 */ 788 resource = find_resource_by_index(share, sectype); 789 if (resource != NULL) { 790 node = xmlNewChild(resource, NULL, 791 (xmlChar *)"optionset", NULL); 792 } else { 793 /* This shouldn't happen. */ 794 ret = SA_SYSTEM_ERR; 795 goto out; 796 } 797 } else { 798 /* 799 * If not a digit, then it is a security type 800 * (alternate option space). Security types start with 801 * an alphabetic. 802 */ 803 node = xmlNewChild(root, NULL, (xmlChar *)"security", 804 NULL); 805 if (node != NULL) 806 xmlSetProp(node, (xmlChar *)"sectype", 807 (xmlChar *)sectype); 808 } 809 } 810 if (node == NULL) { 811 ret = SA_NO_MEMORY; 812 goto out; 813 } 814 815 xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 816 /* now find the properties */ 817 iter = scf_iter_create(handle->handle); 818 value = scf_value_create(handle->handle); 819 prop = scf_property_create(handle->handle); 820 name = malloc(scf_max_name_len); 821 valuestr = malloc(vallen); 822 823 if (iter == NULL || value == NULL || prop == NULL || name == NULL) 824 goto out; 825 826 /* iterate over the share pg properties */ 827 if (scf_iter_pg_properties(iter, pg) == 0) { 828 while (scf_iter_next_property(iter, prop) > 0) { 829 ret = SA_SYSTEM_ERR; /* assume the worst */ 830 if (scf_property_get_name(prop, name, 831 scf_max_name_len) > 0) { 832 if (scf_property_get_value(prop, value) == 0) { 833 if (scf_value_get_astring(value, 834 valuestr, vallen) >= 0) { 835 ret = SA_OK; 836 } 837 } 838 } else { 839 ret = SA_SYSTEM_ERR; 840 } 841 if (ret == SA_OK) { 842 sa_property_t prop; 843 prop = sa_create_property(name, valuestr); 844 if (prop != NULL) 845 prop = (sa_property_t)xmlAddChild(node, 846 (xmlNodePtr)prop); 847 else 848 ret = SA_NO_MEMORY; 849 } 850 } 851 } else { 852 ret = SA_SYSTEM_ERR; 853 } 854 out: 855 if (iter != NULL) 856 scf_iter_destroy(iter); 857 if (value != NULL) 858 scf_value_destroy(value); 859 if (prop != NULL) 860 scf_property_destroy(prop); 861 if (name != NULL) 862 free(name); 863 if (valuestr != NULL) 864 free(valuestr); 865 return (ret); 866 } 867 868 /* 869 * sa_extract_group(root, handle, instance) 870 * 871 * Get the config info for this instance of a group and create the XML 872 * subtree from it. 873 */ 874 875 static int 876 sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 877 scf_instance_t *instance, sa_handle_t sahandle) 878 { 879 char *buff; 880 xmlNodePtr node; 881 scf_iter_t *iter; 882 char *proto; 883 char *sectype; 884 int have_shares = 0; 885 int has_proto = 0; 886 int is_default = 0; 887 int ret = SA_OK; 888 int err; 889 890 buff = malloc(scf_max_name_len); 891 if (buff == NULL) 892 return (SA_NO_MEMORY); 893 894 iter = scf_iter_create(handle->handle); 895 if (iter == NULL) { 896 ret = SA_NO_MEMORY; 897 goto out; 898 } 899 900 if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 901 node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 902 if (node == NULL) { 903 ret = SA_NO_MEMORY; 904 goto out; 905 } 906 xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 907 if (strcmp(buff, "default") == 0) 908 is_default++; 909 910 sa_extract_attrs(node, handle, instance); 911 /* 912 * Iterate through all the property groups 913 * looking for those with security or 914 * optionset prefixes. The names of the 915 * matching pgroups are parsed to get the 916 * protocol, and for security, the sectype. 917 * Syntax is as follows: 918 * optionset | optionset_<proto> 919 * security_default | security_<proto>_<sectype> 920 * "operation" is handled by 921 * sa_extract_attrs(). 922 */ 923 if (scf_iter_instance_pgs(iter, instance) != 0) { 924 ret = SA_NO_MEMORY; 925 goto out; 926 } 927 while (scf_iter_next_pg(iter, handle->pg) > 0) { 928 /* Have a pgroup so sort it out */ 929 ret = scf_pg_get_name(handle->pg, buff, 930 scf_max_name_len); 931 if (ret > 0) { 932 if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 933 sa_share_from_pgroup(node, handle, 934 handle->pg, buff); 935 have_shares++; 936 } else if (strncmp(buff, "optionset", 9) == 937 0) { 938 char *nodetype = "optionset"; 939 /* Have an optionset */ 940 sectype = NULL; 941 proto = strchr(buff, '_'); 942 if (proto != NULL) { 943 *proto++ = '\0'; 944 sectype = strchr(proto, '_'); 945 if (sectype != NULL) { 946 *sectype++ = '\0'; 947 nodetype = "security"; 948 } 949 } 950 ret = sa_extract_pgroup(node, handle, 951 handle->pg, nodetype, proto, 952 sectype); 953 has_proto++; 954 } else if (strncmp(buff, "security", 8) == 0) { 955 /* 956 * Have a security (note that 957 * this should change in the 958 * future) 959 */ 960 proto = strchr(buff, '_'); 961 sectype = NULL; 962 if (proto != NULL) { 963 *proto++ = '\0'; 964 sectype = strchr(proto, '_'); 965 if (sectype != NULL) 966 *sectype++ = '\0'; 967 if (strcmp(proto, "default") == 968 0) 969 proto = NULL; 970 } 971 ret = sa_extract_pgroup(node, handle, 972 handle->pg, "security", proto, 973 sectype); 974 has_proto++; 975 } 976 /* Ignore everything else */ 977 } 978 } 979 /* 980 * Make sure we have a valid default group. 981 * On first boot, default won't have any 982 * protocols defined and won't be enabled (but 983 * should be). 984 */ 985 if (is_default) { 986 char *state = sa_get_group_attr((sa_group_t)node, 987 "state"); 988 char **protos; 989 int numprotos; 990 int i; 991 992 if (state == NULL) { 993 /* set attribute to enabled */ 994 (void) sa_set_group_attr((sa_group_t)node, 995 "state", "enabled"); 996 /* We can assume no protocols */ 997 numprotos = sa_get_protocols(&protos); 998 for (i = 0; i < numprotos; i++) 999 (void) sa_create_optionset( 1000 (sa_group_t)node, protos[i]); 1001 if (numprotos > 0) 1002 free(protos); 1003 } else { 1004 sa_free_attr_string(state); 1005 } 1006 } 1007 /* Do a second pass if shares were found */ 1008 if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 1009 while (scf_iter_next_pg(iter, handle->pg) > 0) { 1010 /* 1011 * Have a pgroup so see if it is a 1012 * share optionset 1013 */ 1014 err = scf_pg_get_name(handle->pg, buff, 1015 scf_max_name_len); 1016 if (err <= 0) 1017 continue; 1018 if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 1019 ret = sa_share_props_from_pgroup(node, 1020 handle, handle->pg, buff, 1021 sahandle); 1022 } 1023 } 1024 } 1025 } 1026 out: 1027 if (iter != NULL) 1028 scf_iter_destroy(iter); 1029 if (buff != NULL) 1030 free(buff); 1031 return (ret); 1032 } 1033 1034 /* 1035 * sa_extract_defaults(root, handle, instance) 1036 * 1037 * Local function to find the default properties that live in the 1038 * default instance's "operation" property group. 1039 */ 1040 1041 static void 1042 sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 1043 scf_instance_t *instance) 1044 { 1045 xmlNodePtr node; 1046 scf_property_t *prop; 1047 scf_value_t *value; 1048 char *valuestr; 1049 ssize_t vallen; 1050 1051 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1052 prop = scf_property_create(handle->handle); 1053 value = scf_value_create(handle->handle); 1054 valuestr = malloc(vallen); 1055 1056 if (prop == NULL || value == NULL || vallen == 0 || 1057 scf_instance_get_pg(instance, "operation", handle->pg) != 0) 1058 goto out; 1059 1060 if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 1061 goto out; 1062 1063 /* Found the property so get the value */ 1064 if (scf_property_get_value(prop, value) == 0) { 1065 if (scf_value_get_astring(value, valuestr, vallen) > 0) { 1066 node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 1067 NULL); 1068 if (node != NULL) { 1069 xmlSetProp(node, (xmlChar *)"timestamp", 1070 (xmlChar *)valuestr); 1071 xmlSetProp(node, (xmlChar *)"path", 1072 (xmlChar *)SA_LEGACY_DFSTAB); 1073 } 1074 } 1075 } 1076 out: 1077 if (valuestr != NULL) 1078 free(valuestr); 1079 if (value != NULL) 1080 scf_value_destroy(value); 1081 if (prop != NULL) 1082 scf_property_destroy(prop); 1083 } 1084 1085 1086 /* 1087 * sa_get_config(handle, root, doc, sahandle) 1088 * 1089 * Walk the SMF repository for /network/shares/group and find all the 1090 * instances. These become group names. Then add the XML structure 1091 * below the groups based on property groups and properties. 1092 */ 1093 int 1094 sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 1095 { 1096 int ret = SA_OK; 1097 scf_instance_t *instance; 1098 scf_iter_t *iter; 1099 char buff[BUFSIZ * 2]; 1100 1101 instance = scf_instance_create(handle->handle); 1102 iter = scf_iter_create(handle->handle); 1103 if (instance != NULL && iter != NULL) { 1104 if ((ret = scf_iter_service_instances(iter, 1105 handle->service)) == 0) { 1106 while ((ret = scf_iter_next_instance(iter, 1107 instance)) > 0) { 1108 if (scf_instance_get_name(instance, buff, 1109 sizeof (buff)) > 0) { 1110 if (strcmp(buff, "default") == 0) 1111 sa_extract_defaults(root, 1112 handle, instance); 1113 ret = sa_extract_group(root, handle, 1114 instance, sahandle); 1115 } 1116 } 1117 } 1118 } 1119 1120 /* Always cleanup these */ 1121 if (instance != NULL) 1122 scf_instance_destroy(instance); 1123 if (iter != NULL) 1124 scf_iter_destroy(iter); 1125 return (ret); 1126 } 1127 1128 /* 1129 * sa_get_instance(handle, instance) 1130 * 1131 * Get the instance of the group service. This is actually the 1132 * specific group name. The instance is needed for all property and 1133 * control operations. 1134 */ 1135 1136 int 1137 sa_get_instance(scfutilhandle_t *handle, char *instname) 1138 { 1139 if (scf_service_get_instance(handle->service, instname, 1140 handle->instance) != 0) { 1141 return (SA_NO_SUCH_GROUP); 1142 } 1143 return (SA_OK); 1144 } 1145 1146 /* 1147 * sa_create_instance(handle, instname) 1148 * 1149 * Create a new SMF service instance. There can only be one with a 1150 * given name. 1151 */ 1152 1153 int 1154 sa_create_instance(scfutilhandle_t *handle, char *instname) 1155 { 1156 int ret = SA_OK; 1157 char instance[SA_GROUP_INST_LEN]; 1158 if (scf_service_add_instance(handle->service, instname, 1159 handle->instance) != 0) { 1160 /* better error returns need to be added based on real error */ 1161 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 1162 ret = SA_NO_PERMISSION; 1163 else 1164 ret = SA_DUPLICATE_NAME; 1165 } else { 1166 /* have the service created, so enable it */ 1167 (void) snprintf(instance, sizeof (instance), "%s:%s", 1168 SA_SVC_FMRI_BASE, instname); 1169 (void) smf_enable_instance(instance, 0); 1170 } 1171 return (ret); 1172 } 1173 1174 /* 1175 * sa_delete_instance(handle, instname) 1176 * 1177 * When a group goes away, we also remove the service instance. 1178 */ 1179 1180 int 1181 sa_delete_instance(scfutilhandle_t *handle, char *instname) 1182 { 1183 int ret; 1184 1185 if (strcmp(instname, "default") == 0) { 1186 ret = SA_NO_PERMISSION; 1187 } else { 1188 if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 1189 if (scf_instance_delete(handle->instance) != 0) 1190 /* need better analysis */ 1191 ret = SA_NO_PERMISSION; 1192 } 1193 } 1194 return (ret); 1195 } 1196 1197 /* 1198 * sa_create_pgroup(handle, pgroup) 1199 * 1200 * create a new property group 1201 */ 1202 1203 int 1204 sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 1205 { 1206 int ret = SA_OK; 1207 /* 1208 * Only create a handle if it doesn't exist. It is ok to exist 1209 * since the pg handle will be set as a side effect. 1210 */ 1211 if (handle->pg == NULL) 1212 handle->pg = scf_pg_create(handle->handle); 1213 1214 /* 1215 * If the pgroup exists, we are done. If it doesn't, then we 1216 * need to actually add one to the service instance. 1217 */ 1218 if (scf_instance_get_pg(handle->instance, 1219 pgroup, handle->pg) != 0) { 1220 /* Doesn't exist so create one */ 1221 if (scf_instance_add_pg(handle->instance, pgroup, 1222 SCF_GROUP_APPLICATION, 0, handle->pg) != 0) { 1223 switch (scf_error()) { 1224 case SCF_ERROR_PERMISSION_DENIED: 1225 ret = SA_NO_PERMISSION; 1226 break; 1227 default: 1228 ret = SA_SYSTEM_ERR; 1229 break; 1230 } 1231 } 1232 } 1233 return (ret); 1234 } 1235 1236 /* 1237 * sa_delete_pgroup(handle, pgroup) 1238 * 1239 * Remove the property group from the current instance of the service, 1240 * but only if it actually exists. 1241 */ 1242 1243 int 1244 sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 1245 { 1246 int ret = SA_OK; 1247 /* 1248 * Only delete if it does exist. 1249 */ 1250 if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 1251 /* does exist so delete it */ 1252 if (scf_pg_delete(handle->pg) != 0) 1253 ret = SA_SYSTEM_ERR; 1254 } else { 1255 ret = SA_SYSTEM_ERR; 1256 } 1257 if (ret == SA_SYSTEM_ERR && 1258 scf_error() == SCF_ERROR_PERMISSION_DENIED) { 1259 ret = SA_NO_PERMISSION; 1260 } 1261 return (ret); 1262 } 1263 1264 /* 1265 * sa_start_transaction(handle, pgroup) 1266 * 1267 * Start an SMF transaction so we can deal with properties. it would 1268 * be nice to not have to expose this, but we have to in order to 1269 * optimize. 1270 * 1271 * Basic model is to hold the transaction in the handle and allow 1272 * property adds/deletes/updates to be added then close the 1273 * transaction (or abort). There may eventually be a need to handle 1274 * other types of transaction mechanisms but we don't do that now. 1275 * 1276 * An sa_start_transaction must be followed by either an 1277 * sa_end_transaction or sa_abort_transaction before another 1278 * sa_start_transaction can be done. 1279 */ 1280 1281 int 1282 sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 1283 { 1284 int ret = SA_OK; 1285 /* 1286 * Lookup the property group and create it if it doesn't already 1287 * exist. 1288 */ 1289 if (handle->scf_state == SCH_STATE_INIT) { 1290 ret = sa_create_pgroup(handle, propgroup); 1291 if (ret == SA_OK) { 1292 handle->trans = scf_transaction_create(handle->handle); 1293 if (handle->trans != NULL) { 1294 if (scf_transaction_start(handle->trans, 1295 handle->pg) != 0) { 1296 ret = SA_SYSTEM_ERR; 1297 } 1298 if (ret != SA_OK) { 1299 scf_transaction_destroy(handle->trans); 1300 handle->trans = NULL; 1301 } 1302 } else { 1303 ret = SA_SYSTEM_ERR; 1304 } 1305 } 1306 } 1307 if (ret == SA_SYSTEM_ERR && 1308 scf_error() == SCF_ERROR_PERMISSION_DENIED) { 1309 ret = SA_NO_PERMISSION; 1310 } 1311 return (ret); 1312 } 1313 1314 /* 1315 * sa_end_transaction(handle) 1316 * 1317 * Commit the changes that were added to the transaction in the 1318 * handle. Do all necessary cleanup. 1319 */ 1320 1321 int 1322 sa_end_transaction(scfutilhandle_t *handle) 1323 { 1324 int ret = SA_OK; 1325 1326 if (handle->trans == NULL) { 1327 ret = SA_SYSTEM_ERR; 1328 } else { 1329 if (scf_transaction_commit(handle->trans) < 0) 1330 ret = SA_SYSTEM_ERR; 1331 scf_transaction_destroy_children(handle->trans); 1332 scf_transaction_destroy(handle->trans); 1333 handle->trans = NULL; 1334 } 1335 return (ret); 1336 } 1337 1338 /* 1339 * sa_abort_transaction(handle) 1340 * 1341 * Abort the changes that were added to the transaction in the 1342 * handle. Do all necessary cleanup. 1343 */ 1344 1345 void 1346 sa_abort_transaction(scfutilhandle_t *handle) 1347 { 1348 if (handle->trans != NULL) { 1349 scf_transaction_reset_all(handle->trans); 1350 scf_transaction_destroy_children(handle->trans); 1351 scf_transaction_destroy(handle->trans); 1352 handle->trans = NULL; 1353 } 1354 } 1355 1356 /* 1357 * sa_set_property(handle, prop, value) 1358 * 1359 * Set a property transaction entry into the pending SMF transaction. 1360 */ 1361 1362 int 1363 sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 1364 { 1365 int ret = SA_OK; 1366 scf_value_t *value; 1367 scf_transaction_entry_t *entry; 1368 /* 1369 * Properties must be set in transactions and don't take 1370 * effect until the transaction has been ended/committed. 1371 */ 1372 value = scf_value_create(handle->handle); 1373 entry = scf_entry_create(handle->handle); 1374 if (value != NULL && entry != NULL) { 1375 if (scf_transaction_property_change(handle->trans, entry, 1376 propname, SCF_TYPE_ASTRING) == 0 || 1377 scf_transaction_property_new(handle->trans, entry, 1378 propname, SCF_TYPE_ASTRING) == 0) { 1379 if (scf_value_set_astring(value, valstr) == 0) { 1380 if (scf_entry_add_value(entry, value) != 0) { 1381 ret = SA_SYSTEM_ERR; 1382 scf_value_destroy(value); 1383 } 1384 /* The value is in the transaction */ 1385 value = NULL; 1386 } else { 1387 /* Value couldn't be constructed */ 1388 ret = SA_SYSTEM_ERR; 1389 } 1390 /* The entry is in the transaction */ 1391 entry = NULL; 1392 } else { 1393 ret = SA_SYSTEM_ERR; 1394 } 1395 } else { 1396 ret = SA_SYSTEM_ERR; 1397 } 1398 if (ret == SA_SYSTEM_ERR) { 1399 switch (scf_error()) { 1400 case SCF_ERROR_PERMISSION_DENIED: 1401 ret = SA_NO_PERMISSION; 1402 break; 1403 } 1404 } 1405 /* 1406 * Cleanup if there were any errors that didn't leave these 1407 * values where they would be cleaned up later. 1408 */ 1409 if (value != NULL) 1410 scf_value_destroy(value); 1411 if (entry != NULL) 1412 scf_entry_destroy(entry); 1413 return (ret); 1414 } 1415 1416 /* 1417 * check_resource(share) 1418 * 1419 * Check to see if share has any persistent resources. We don't want 1420 * to save if they are all transient. 1421 */ 1422 static int 1423 check_resource(sa_share_t share) 1424 { 1425 sa_resource_t resource; 1426 int ret = B_FALSE; 1427 1428 for (resource = sa_get_share_resource(share, NULL); 1429 resource != NULL && ret == B_FALSE; 1430 resource = sa_get_next_resource(resource)) { 1431 char *type; 1432 type = sa_get_resource_attr(resource, "type"); 1433 if (type != NULL) { 1434 if (strcmp(type, "transient") != 0) { 1435 ret = B_TRUE; 1436 } 1437 sa_free_attr_string(type); 1438 } 1439 } 1440 return (ret); 1441 } 1442 1443 /* 1444 * sa_set_resource_property(handle, prop, value) 1445 * 1446 * set a property transaction entry into the pending SMF 1447 * transaction. We don't want to include any transient resources 1448 */ 1449 1450 static int 1451 sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) 1452 { 1453 int ret = SA_OK; 1454 scf_value_t *value; 1455 scf_transaction_entry_t *entry; 1456 sa_resource_t resource; 1457 char *valstr; 1458 char *idstr; 1459 char *description; 1460 char *propstr = NULL; 1461 size_t strsize; 1462 1463 /* don't bother if no persistent resources */ 1464 if (check_resource(share) == B_FALSE) 1465 return (ret); 1466 1467 /* 1468 * properties must be set in transactions and don't take 1469 * effect until the transaction has been ended/committed. 1470 */ 1471 entry = scf_entry_create(handle->handle); 1472 if (entry == NULL) 1473 return (SA_SYSTEM_ERR); 1474 1475 if (scf_transaction_property_change(handle->trans, entry, 1476 "resource", SCF_TYPE_ASTRING) != 0 && 1477 scf_transaction_property_new(handle->trans, entry, 1478 "resource", SCF_TYPE_ASTRING) != 0) { 1479 scf_entry_destroy(entry); 1480 return (SA_SYSTEM_ERR); 1481 1482 } 1483 for (resource = sa_get_share_resource(share, NULL); 1484 resource != NULL; 1485 resource = sa_get_next_resource(resource)) { 1486 value = scf_value_create(handle->handle); 1487 if (value == NULL) { 1488 ret = SA_NO_MEMORY; 1489 break; 1490 } 1491 /* Get size of complete string */ 1492 valstr = sa_get_resource_attr(resource, "name"); 1493 idstr = sa_get_resource_attr(resource, "id"); 1494 description = sa_get_resource_description(resource); 1495 strsize = (valstr != NULL) ? strlen(valstr) : 0; 1496 strsize += (idstr != NULL) ? strlen(idstr) : 0; 1497 strsize += (description != NULL) ? strlen(description) : 0; 1498 if (strsize > 0) { 1499 strsize += 3; /* add nul and ':' */ 1500 propstr = (char *)malloc(strsize); 1501 if (propstr == NULL) { 1502 scf_value_destroy(value); 1503 ret = SA_NO_MEMORY; 1504 goto err; 1505 } 1506 if (idstr == NULL) 1507 (void) snprintf(propstr, strsize, "%s", 1508 valstr ? valstr : ""); 1509 else 1510 (void) snprintf(propstr, strsize, "%s:%s:%s", 1511 idstr ? idstr : "", valstr ? valstr : "", 1512 description ? description : ""); 1513 if (scf_value_set_astring(value, propstr) != 0) { 1514 ret = SA_SYSTEM_ERR; 1515 free(propstr); 1516 scf_value_destroy(value); 1517 break; 1518 } 1519 if (scf_entry_add_value(entry, value) != 0) { 1520 ret = SA_SYSTEM_ERR; 1521 free(propstr); 1522 scf_value_destroy(value); 1523 break; 1524 } 1525 /* the value is in the transaction */ 1526 value = NULL; 1527 free(propstr); 1528 } 1529 err: 1530 if (valstr != NULL) 1531 sa_free_attr_string(valstr); 1532 if (idstr != NULL) 1533 sa_free_attr_string(idstr); 1534 if (description != NULL) 1535 sa_free_share_description(description); 1536 } 1537 /* the entry is in the transaction */ 1538 entry = NULL; 1539 1540 if (ret == SA_SYSTEM_ERR) { 1541 switch (scf_error()) { 1542 case SCF_ERROR_PERMISSION_DENIED: 1543 ret = SA_NO_PERMISSION; 1544 break; 1545 } 1546 } 1547 /* 1548 * cleanup if there were any errors that didn't leave 1549 * these values where they would be cleaned up later. 1550 */ 1551 if (entry != NULL) 1552 scf_entry_destroy(entry); 1553 1554 return (ret); 1555 } 1556 1557 /* 1558 * sa_commit_share(handle, group, share) 1559 * 1560 * Commit this share to the repository. 1561 * properties are added if they exist but can be added later. 1562 * Need to add to dfstab and sharetab, if appropriate. 1563 */ 1564 int 1565 sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 1566 { 1567 int ret = SA_OK; 1568 char *groupname; 1569 char *name; 1570 char *description; 1571 char *sharename; 1572 ssize_t proplen; 1573 char *propstring; 1574 1575 /* 1576 * Don't commit in the zfs group. We do commit legacy 1577 * (default) and all other groups/shares. ZFS is handled 1578 * through the ZFS configuration rather than SMF. 1579 */ 1580 1581 groupname = sa_get_group_attr(group, "name"); 1582 if (groupname != NULL) { 1583 if (strcmp(groupname, "zfs") == 0) { 1584 /* 1585 * Adding to the ZFS group will result in the sharenfs 1586 * property being set but we don't want to do anything 1587 * SMF related at this point. 1588 */ 1589 sa_free_attr_string(groupname); 1590 return (ret); 1591 } 1592 } 1593 1594 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1595 propstring = malloc(proplen); 1596 if (propstring == NULL) 1597 ret = SA_NO_MEMORY; 1598 1599 if (groupname != NULL && ret == SA_OK) { 1600 ret = sa_get_instance(handle, groupname); 1601 sa_free_attr_string(groupname); 1602 groupname = NULL; 1603 sharename = sa_get_share_attr(share, "id"); 1604 if (sharename == NULL) { 1605 /* slipped by */ 1606 char shname[SA_SHARE_UUID_BUFLEN]; 1607 generate_unique_sharename(shname); 1608 xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 1609 (xmlChar *)shname); 1610 sharename = strdup(shname); 1611 } 1612 if (sharename != NULL) { 1613 sigset_t old, new; 1614 /* 1615 * Have a share name allocated so create a pgroup for 1616 * it. It may already exist, but that is OK. In order 1617 * to avoid creating a share pgroup that doesn't have 1618 * a path property, block signals around the critical 1619 * region of creating the share pgroup and props. 1620 */ 1621 (void) sigprocmask(SIG_BLOCK, NULL, &new); 1622 (void) sigaddset(&new, SIGHUP); 1623 (void) sigaddset(&new, SIGINT); 1624 (void) sigaddset(&new, SIGQUIT); 1625 (void) sigaddset(&new, SIGTSTP); 1626 (void) sigprocmask(SIG_SETMASK, &new, &old); 1627 1628 ret = sa_create_pgroup(handle, sharename); 1629 if (ret == SA_OK) { 1630 /* 1631 * Now start the transaction for the 1632 * properties that define this share. They may 1633 * exist so attempt to update before create. 1634 */ 1635 ret = sa_start_transaction(handle, sharename); 1636 } 1637 if (ret == SA_OK) { 1638 name = sa_get_share_attr(share, "path"); 1639 if (name != NULL) { 1640 /* 1641 * There needs to be a path 1642 * for a share to exist. 1643 */ 1644 ret = sa_set_property(handle, "path", 1645 name); 1646 sa_free_attr_string(name); 1647 } else { 1648 ret = SA_NO_MEMORY; 1649 } 1650 } 1651 if (ret == SA_OK) { 1652 name = sa_get_share_attr(share, "drive-letter"); 1653 if (name != NULL) { 1654 /* A drive letter may exist for SMB */ 1655 ret = sa_set_property(handle, 1656 "drive-letter", name); 1657 sa_free_attr_string(name); 1658 } 1659 } 1660 if (ret == SA_OK) { 1661 name = sa_get_share_attr(share, "exclude"); 1662 if (name != NULL) { 1663 /* 1664 * In special cases need to 1665 * exclude proto enable. 1666 */ 1667 ret = sa_set_property(handle, 1668 "exclude", name); 1669 sa_free_attr_string(name); 1670 } 1671 } 1672 if (ret == SA_OK) { 1673 /* 1674 * If there are resource names, bundle them up 1675 * and save appropriately. 1676 */ 1677 ret = sa_set_resource_property(handle, share); 1678 } 1679 1680 if (ret == SA_OK) { 1681 description = sa_get_share_description(share); 1682 if (description != NULL) { 1683 ret = sa_set_property(handle, 1684 "description", 1685 description); 1686 sa_free_share_description(description); 1687 } 1688 } 1689 /* Make sure we cleanup the transaction */ 1690 if (ret == SA_OK) { 1691 ret = sa_end_transaction(handle); 1692 } else { 1693 sa_abort_transaction(handle); 1694 } 1695 1696 (void) sigprocmask(SIG_SETMASK, &old, NULL); 1697 1698 free(sharename); 1699 } 1700 } 1701 if (ret == SA_SYSTEM_ERR) { 1702 int err = scf_error(); 1703 if (err == SCF_ERROR_PERMISSION_DENIED) 1704 ret = SA_NO_PERMISSION; 1705 } 1706 if (propstring != NULL) 1707 free(propstring); 1708 if (groupname != NULL) 1709 sa_free_attr_string(groupname); 1710 1711 return (ret); 1712 } 1713 1714 /* 1715 * remove_resources(handle, share, shareid) 1716 * 1717 * If the share has resources, remove all of them and their 1718 * optionsets. 1719 */ 1720 static int 1721 remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid) 1722 { 1723 sa_resource_t resource; 1724 sa_optionset_t opt; 1725 char *proto; 1726 char *id; 1727 ssize_t proplen; 1728 char *propstring; 1729 int ret = SA_OK; 1730 1731 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1732 propstring = malloc(proplen); 1733 if (propstring == NULL) 1734 return (SA_NO_MEMORY); 1735 1736 for (resource = sa_get_share_resource(share, NULL); 1737 resource != NULL; resource = sa_get_next_resource(resource)) { 1738 id = sa_get_resource_attr(resource, "id"); 1739 if (id == NULL) 1740 continue; 1741 for (opt = sa_get_optionset(resource, NULL); 1742 opt != NULL; opt = sa_get_next_optionset(resource)) { 1743 proto = sa_get_optionset_attr(opt, "type"); 1744 if (proto != NULL) { 1745 (void) snprintf(propstring, proplen, 1746 "%s_%s_%s", shareid, proto, id); 1747 ret = sa_delete_pgroup(handle, propstring); 1748 sa_free_attr_string(proto); 1749 } 1750 } 1751 sa_free_attr_string(id); 1752 } 1753 free(propstring); 1754 return (ret); 1755 } 1756 1757 /* 1758 * sa_delete_share(handle, group, share) 1759 * 1760 * Remove the specified share from the group (and service instance). 1761 */ 1762 1763 int 1764 sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 1765 { 1766 int ret = SA_OK; 1767 char *groupname = NULL; 1768 char *shareid = NULL; 1769 sa_optionset_t opt; 1770 sa_security_t sec; 1771 ssize_t proplen; 1772 char *propstring; 1773 1774 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1775 propstring = malloc(proplen); 1776 if (propstring == NULL) 1777 ret = SA_NO_MEMORY; 1778 1779 if (ret == SA_OK) { 1780 groupname = sa_get_group_attr(group, "name"); 1781 shareid = sa_get_share_attr(share, "id"); 1782 if (groupname == NULL || shareid == NULL) { 1783 ret = SA_CONFIG_ERR; 1784 goto out; 1785 } 1786 ret = sa_get_instance(handle, groupname); 1787 if (ret == SA_OK) { 1788 /* If a share has resources, remove them */ 1789 ret = remove_resources(handle, share, shareid); 1790 /* If a share has properties, remove them */ 1791 ret = sa_delete_pgroup(handle, shareid); 1792 for (opt = sa_get_optionset(share, NULL); 1793 opt != NULL; 1794 opt = sa_get_next_optionset(opt)) { 1795 char *proto; 1796 proto = sa_get_optionset_attr(opt, "type"); 1797 if (proto != NULL) { 1798 (void) snprintf(propstring, 1799 proplen, "%s_%s", shareid, 1800 proto); 1801 ret = sa_delete_pgroup(handle, 1802 propstring); 1803 sa_free_attr_string(proto); 1804 } else { 1805 ret = SA_NO_MEMORY; 1806 } 1807 } 1808 /* 1809 * If a share has security/negotiable 1810 * properties, remove them. 1811 */ 1812 for (sec = sa_get_security(share, NULL, NULL); 1813 sec != NULL; 1814 sec = sa_get_next_security(sec)) { 1815 char *proto; 1816 char *sectype; 1817 proto = sa_get_security_attr(sec, "type"); 1818 sectype = sa_get_security_attr(sec, "sectype"); 1819 if (proto != NULL && sectype != NULL) { 1820 (void) snprintf(propstring, proplen, 1821 "%s_%s_%s", shareid, proto, 1822 sectype); 1823 ret = sa_delete_pgroup(handle, 1824 propstring); 1825 } else { 1826 ret = SA_NO_MEMORY; 1827 } 1828 if (proto != NULL) 1829 sa_free_attr_string(proto); 1830 if (sectype != NULL) 1831 sa_free_attr_string(sectype); 1832 } 1833 } 1834 } 1835 out: 1836 if (groupname != NULL) 1837 sa_free_attr_string(groupname); 1838 if (shareid != NULL) 1839 sa_free_attr_string(shareid); 1840 if (propstring != NULL) 1841 free(propstring); 1842 1843 return (ret); 1844 } 1845