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