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