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