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