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