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