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, sa_handle_t sahandle) 938 { 939 int ret = SA_OK; 940 scf_instance_t *instance; 941 scf_iter_t *iter; 942 char buff[BUFSIZ * 2]; 943 944 instance = scf_instance_create(handle->handle); 945 iter = scf_iter_create(handle->handle); 946 if (instance != NULL && iter != NULL) { 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 sahandle); 957 } 958 } 959 } 960 } 961 962 /* always cleanup these */ 963 if (instance != NULL) 964 scf_instance_destroy(instance); 965 if (iter != NULL) 966 scf_iter_destroy(iter); 967 return (ret); 968 } 969 970 /* 971 * sa_get_instance(handle, instance) 972 * 973 * get the instance of the group service. This is actually the 974 * specific group name. The instance is needed for all property and 975 * control operations. 976 */ 977 978 int 979 sa_get_instance(scfutilhandle_t *handle, char *instname) 980 { 981 if (scf_service_get_instance(handle->service, instname, 982 handle->instance) != 0) { 983 return (SA_NO_SUCH_GROUP); 984 } 985 return (SA_OK); 986 } 987 988 /* 989 * sa_create_instance(handle, instname) 990 * 991 * Create a new SMF service instance. There can only be one with a 992 * given name. 993 */ 994 995 int 996 sa_create_instance(scfutilhandle_t *handle, char *instname) 997 { 998 int ret = SA_OK; 999 char instance[SA_GROUP_INST_LEN]; 1000 if (scf_service_add_instance(handle->service, instname, 1001 handle->instance) != 0) { 1002 /* better error returns need to be added based on real error */ 1003 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 1004 ret = SA_NO_PERMISSION; 1005 else 1006 ret = SA_DUPLICATE_NAME; 1007 } else { 1008 /* have the service created, so enable it */ 1009 (void) snprintf(instance, sizeof (instance), "%s:%s", 1010 SA_SVC_FMRI_BASE, instname); 1011 (void) smf_enable_instance(instance, 0); 1012 } 1013 return (ret); 1014 } 1015 1016 /* 1017 * sa_delete_instance(handle, instname) 1018 * 1019 * When a group goes away, we also remove the service instance. 1020 */ 1021 1022 int 1023 sa_delete_instance(scfutilhandle_t *handle, char *instname) 1024 { 1025 int ret; 1026 1027 if (strcmp(instname, "default") == 0) { 1028 ret = SA_NO_PERMISSION; 1029 } else { 1030 if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 1031 if (scf_instance_delete(handle->instance) != 0) 1032 /* need better analysis */ 1033 ret = SA_NO_PERMISSION; 1034 } 1035 } 1036 return (ret); 1037 } 1038 1039 /* 1040 * sa_create_pgroup(handle, pgroup) 1041 * 1042 * create a new property group 1043 */ 1044 1045 int 1046 sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 1047 { 1048 int ret = SA_OK; 1049 /* 1050 * only create a handle if it doesn't exist. It is ok to exist 1051 * since the pg handle will be set as a side effect. 1052 */ 1053 if (handle->pg == NULL) { 1054 handle->pg = scf_pg_create(handle->handle); 1055 } 1056 /* 1057 * if the pgroup exists, we are done. If it doesn't, then we 1058 * need to actually add one to the service instance. 1059 */ 1060 if (scf_instance_get_pg(handle->instance, 1061 pgroup, handle->pg) != 0) { 1062 /* doesn't exist so create one */ 1063 if (scf_instance_add_pg(handle->instance, pgroup, 1064 SCF_GROUP_APPLICATION, 0, 1065 handle->pg) != 0) { 1066 switch (scf_error()) { 1067 case SCF_ERROR_PERMISSION_DENIED: 1068 ret = SA_NO_PERMISSION; 1069 break; 1070 default: 1071 ret = SA_SYSTEM_ERR; 1072 break; 1073 } 1074 } 1075 } 1076 return (ret); 1077 } 1078 1079 /* 1080 * sa_delete_pgroup(handle, pgroup) 1081 * 1082 * remove the property group from the current instance of the service, 1083 * but only if it actually exists. 1084 */ 1085 1086 int 1087 sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 1088 { 1089 int ret = SA_OK; 1090 /* 1091 * only delete if it does exist. 1092 */ 1093 if (scf_instance_get_pg(handle->instance, 1094 pgroup, handle->pg) == 0) { 1095 /* does exist so delete it */ 1096 if (scf_pg_delete(handle->pg) != 0) { 1097 ret = SA_SYSTEM_ERR; 1098 } 1099 } else { 1100 ret = SA_SYSTEM_ERR; 1101 } 1102 if (ret == SA_SYSTEM_ERR && 1103 scf_error() == SCF_ERROR_PERMISSION_DENIED) { 1104 ret = SA_NO_PERMISSION; 1105 } 1106 return (ret); 1107 } 1108 1109 /* 1110 * sa_start_transaction(handle, pgroup) 1111 * 1112 * Start an SMF transaction so we can deal with properties. it would 1113 * be nice to not have to expose this, but we have to in order to 1114 * optimize. 1115 * 1116 * Basic model is to hold the transaction in the handle and allow 1117 * property adds/deletes/updates to be added then close the 1118 * transaction (or abort). There may eventually be a need to handle 1119 * other types of transaction mechanisms but we don't do that now. 1120 * 1121 * An sa_start_transaction must be followed by either an 1122 * sa_end_transaction or sa_abort_transaction before another 1123 * sa_start_transaction can be done. 1124 */ 1125 1126 int 1127 sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 1128 { 1129 int ret = SA_OK; 1130 /* 1131 * lookup the property group and create it if it doesn't already 1132 * exist. 1133 */ 1134 if (handle->scf_state == SCH_STATE_INIT) { 1135 ret = sa_create_pgroup(handle, propgroup); 1136 if (ret == SA_OK) { 1137 handle->trans = scf_transaction_create(handle->handle); 1138 if (handle->trans != NULL) { 1139 if (scf_transaction_start(handle->trans, handle->pg) != 0) { 1140 ret = SA_SYSTEM_ERR; 1141 } 1142 if (ret != SA_OK) { 1143 scf_transaction_destroy(handle->trans); 1144 handle->trans = NULL; 1145 } 1146 } else { 1147 ret = SA_SYSTEM_ERR; 1148 } 1149 } 1150 } 1151 if (ret == SA_SYSTEM_ERR && 1152 scf_error() == SCF_ERROR_PERMISSION_DENIED) { 1153 ret = SA_NO_PERMISSION; 1154 } 1155 return (ret); 1156 } 1157 1158 /* 1159 * sa_end_transaction(handle) 1160 * 1161 * Commit the changes that were added to the transaction in the 1162 * handle. Do all necessary cleanup. 1163 */ 1164 1165 int 1166 sa_end_transaction(scfutilhandle_t *handle) 1167 { 1168 int ret = SA_OK; 1169 1170 if (handle->trans == NULL) { 1171 ret = SA_SYSTEM_ERR; 1172 } else { 1173 if (scf_transaction_commit(handle->trans) < 0) 1174 ret = SA_SYSTEM_ERR; 1175 scf_transaction_destroy_children(handle->trans); 1176 scf_transaction_destroy(handle->trans); 1177 handle->trans = NULL; 1178 } 1179 return (ret); 1180 } 1181 1182 /* 1183 * sa_abort_transaction(handle) 1184 * 1185 * Abort the changes that were added to the transaction in the 1186 * handle. Do all necessary cleanup. 1187 */ 1188 1189 void 1190 sa_abort_transaction(scfutilhandle_t *handle) 1191 { 1192 if (handle->trans != NULL) { 1193 scf_transaction_reset_all(handle->trans); 1194 scf_transaction_destroy_children(handle->trans); 1195 scf_transaction_destroy(handle->trans); 1196 handle->trans = NULL; 1197 } 1198 } 1199 1200 /* 1201 * sa_set_property(handle, prop, value) 1202 * 1203 * set a property transaction entry into the pending SMF transaction. 1204 */ 1205 1206 int 1207 sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 1208 { 1209 int ret = SA_OK; 1210 scf_value_t *value; 1211 scf_transaction_entry_t *entry; 1212 /* 1213 * properties must be set in transactions and don't take 1214 * effect until the transaction has been ended/committed. 1215 */ 1216 value = scf_value_create(handle->handle); 1217 entry = scf_entry_create(handle->handle); 1218 if (value != NULL && entry != NULL) { 1219 if (scf_transaction_property_change(handle->trans, entry, 1220 propname, 1221 SCF_TYPE_ASTRING) == 0 || 1222 scf_transaction_property_new(handle->trans, entry, 1223 propname, 1224 SCF_TYPE_ASTRING) == 0) { 1225 if (scf_value_set_astring(value, valstr) == 0) { 1226 if (scf_entry_add_value(entry, value) != 0) { 1227 ret = SA_SYSTEM_ERR; 1228 scf_value_destroy(value); 1229 } 1230 /* the value is in the transaction */ 1231 value = NULL; 1232 } else { 1233 /* value couldn't be constructed */ 1234 ret = SA_SYSTEM_ERR; 1235 } 1236 /* the entry is in the transaction */ 1237 entry = NULL; 1238 } else { 1239 ret = SA_SYSTEM_ERR; 1240 } 1241 } else { 1242 ret = SA_SYSTEM_ERR; 1243 } 1244 if (ret == SA_SYSTEM_ERR) { 1245 switch (scf_error()) { 1246 case SCF_ERROR_PERMISSION_DENIED: 1247 ret = SA_NO_PERMISSION; 1248 break; 1249 } 1250 } 1251 /* 1252 * cleanup if there were any errors that didn't leave these 1253 * values where they would be cleaned up later. 1254 */ 1255 if (value != NULL) 1256 scf_value_destroy(value); 1257 if (entry != NULL) 1258 scf_entry_destroy(entry); 1259 return (ret); 1260 } 1261 1262 /* 1263 * sa_commit_share(handle, group, share) 1264 * 1265 * commit this share to the repository. 1266 * properties are added if they exist but can be added later. 1267 * Need to add to dfstab and sharetab, if appropriate. 1268 */ 1269 int 1270 sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 1271 { 1272 int ret = SA_OK; 1273 char *groupname; 1274 char *name; 1275 char *resource; 1276 char *description; 1277 char *sharename; 1278 ssize_t proplen; 1279 char *propstring; 1280 1281 /* 1282 * don't commit in the zfs group. We do commit legacy 1283 * (default) and all other groups/shares. ZFS is handled 1284 * through the ZFS configuration rather than SMF. 1285 */ 1286 1287 groupname = sa_get_group_attr(group, "name"); 1288 if (groupname != NULL) { 1289 if (strcmp(groupname, "zfs") == 0) { 1290 /* 1291 * adding to the ZFS group will result in the sharenfs 1292 * property being set but we don't want to do anything 1293 * SMF related at this point. 1294 */ 1295 sa_free_attr_string(groupname); 1296 return (ret); 1297 } 1298 } 1299 1300 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1301 propstring = malloc(proplen); 1302 if (propstring == NULL) 1303 ret = SA_NO_MEMORY; 1304 1305 if (groupname != NULL && ret == SA_OK) { 1306 ret = sa_get_instance(handle, groupname); 1307 sa_free_attr_string(groupname); 1308 groupname = NULL; 1309 sharename = sa_get_share_attr(share, "id"); 1310 if (sharename == NULL) { 1311 /* slipped by */ 1312 char shname[SA_SHARE_UUID_BUFLEN]; 1313 generate_unique_sharename(shname); 1314 xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 1315 (xmlChar *)shname); 1316 sharename = strdup(shname); 1317 } 1318 if (sharename != NULL) { 1319 sigset_t old, new; 1320 /* 1321 * have a share name allocated so create a pgroup for 1322 * it. It may already exist, but that is OK. In order 1323 * to avoid creating a share pgroup that doesn't have 1324 * a path property, block signals around the critical 1325 * region of creating the share pgroup and props. 1326 */ 1327 (void) sigprocmask(SIG_BLOCK, NULL, &new); 1328 (void) sigaddset(&new, SIGHUP); 1329 (void) sigaddset(&new, SIGINT); 1330 (void) sigaddset(&new, SIGQUIT); 1331 (void) sigaddset(&new, SIGTSTP); 1332 (void) sigprocmask(SIG_SETMASK, &new, &old); 1333 1334 ret = sa_create_pgroup(handle, sharename); 1335 if (ret == SA_OK) { 1336 /* 1337 * now start the transaction for the 1338 * properties that define this share. They may 1339 * exist so attempt to update before create. 1340 */ 1341 ret = sa_start_transaction(handle, sharename); 1342 } 1343 if (ret == SA_OK) { 1344 name = sa_get_share_attr(share, "path"); 1345 if (name != NULL) { 1346 /* there needs to be a path for a share to exist */ 1347 ret = sa_set_property(handle, "path", name); 1348 sa_free_attr_string(name); 1349 } else { 1350 ret = SA_NO_MEMORY; 1351 } 1352 } 1353 if (ret == SA_OK) { 1354 resource = sa_get_share_attr(share, "resource"); 1355 if (resource != NULL) { 1356 ret = sa_set_property(handle, "resource", resource); 1357 sa_free_attr_string(resource); 1358 } 1359 } 1360 if (ret == SA_OK) { 1361 description = sa_get_share_description(share); 1362 if (description != NULL) { 1363 ret = sa_set_property(handle, "description", 1364 description); 1365 sa_free_share_description(description); 1366 } 1367 } 1368 /* make sure we cleanup the transaction */ 1369 if (ret == SA_OK) { 1370 ret = sa_end_transaction(handle); 1371 } else { 1372 sa_abort_transaction(handle); 1373 } 1374 1375 (void) sigprocmask(SIG_SETMASK, &old, NULL); 1376 1377 free(sharename); 1378 } 1379 } 1380 if (ret == SA_SYSTEM_ERR) { 1381 int err = scf_error(); 1382 if (err == SCF_ERROR_PERMISSION_DENIED) 1383 ret = SA_NO_PERMISSION; 1384 } 1385 if (propstring != NULL) 1386 free(propstring); 1387 if (groupname != NULL) 1388 sa_free_attr_string(groupname); 1389 1390 return (ret); 1391 } 1392 1393 /* 1394 * sa_delete_share(handle, group, share) 1395 * 1396 * remove the specified share from the group (and service instance). 1397 */ 1398 1399 int 1400 sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 1401 { 1402 int ret = SA_OK; 1403 char *groupname = NULL; 1404 char *shareid = NULL; 1405 sa_optionset_t opt; 1406 sa_security_t sec; 1407 ssize_t proplen; 1408 char *propstring; 1409 1410 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1411 propstring = malloc(proplen); 1412 if (propstring == NULL) 1413 ret = SA_NO_MEMORY; 1414 1415 if (ret == SA_OK) { 1416 groupname = sa_get_group_attr(group, "name"); 1417 shareid = sa_get_share_attr(share, "id"); 1418 if (groupname != NULL && shareid != NULL) { 1419 ret = sa_get_instance(handle, groupname); 1420 if (ret == SA_OK) { 1421 /* if a share has properties, remove them */ 1422 ret = sa_delete_pgroup(handle, shareid); 1423 for (opt = sa_get_optionset(share, NULL); opt != NULL; 1424 opt = sa_get_next_optionset(opt)) { 1425 char *proto; 1426 proto = sa_get_optionset_attr(opt, "type"); 1427 if (proto != NULL) { 1428 (void) snprintf(propstring, proplen, "%s_%s", 1429 shareid, proto); 1430 ret = sa_delete_pgroup(handle, propstring); 1431 sa_free_attr_string(proto); 1432 } else { 1433 ret = SA_NO_MEMORY; 1434 } 1435 } 1436 /* 1437 * if a share has security/negotiable 1438 * properties, remove them. 1439 */ 1440 for (sec = sa_get_security(share, NULL, NULL); sec != NULL; 1441 sec = sa_get_next_security(sec)) { 1442 char *proto; 1443 char *sectype; 1444 proto = sa_get_security_attr(sec, "type"); 1445 sectype = sa_get_security_attr(sec, "sectype"); 1446 if (proto != NULL && sectype != NULL) { 1447 (void) snprintf(propstring, proplen, "%s_%s_%s", 1448 shareid, 1449 proto, sectype); 1450 ret = sa_delete_pgroup(handle, propstring); 1451 } else { 1452 ret = SA_NO_MEMORY; 1453 } 1454 if (proto != NULL) 1455 sa_free_attr_string(proto); 1456 if (sectype != NULL) 1457 sa_free_attr_string(sectype); 1458 } 1459 } 1460 } else { 1461 ret = SA_CONFIG_ERR; 1462 } 1463 } 1464 if (groupname != NULL) 1465 sa_free_attr_string(groupname); 1466 if (shareid != NULL) 1467 sa_free_attr_string(shareid); 1468 if (propstring != NULL) 1469 free(propstring); 1470 1471 return (ret); 1472 } 1473