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