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 /* 30 * Share control API 31 */ 32 #include <stdio.h> 33 #include <string.h> 34 #include <ctype.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <unistd.h> 39 #include <libxml/parser.h> 40 #include <libxml/tree.h> 41 #include "libshare.h" 42 #include "libshare_impl.h" 43 #include <libscf.h> 44 #include "scfutil.h" 45 #include <ctype.h> 46 #include <libintl.h> 47 48 #if _NOT_SMF 49 #define CONFIG_FILE "/var/tmp/share.cfg" 50 #define CONFIG_FILE_TMP "/var/tmp/share.cfg.tmp" 51 #endif 52 #define TSTAMP(tm) (uint64_t)(((uint64_t)tm.tv_sec << 32) | \ 53 (tm.tv_nsec & 0xffffffff)) 54 55 #define DFS_LOCK_FILE "/etc/dfs/fstypes" 56 57 /* 58 * internal data structures 59 */ 60 61 static xmlNodePtr sa_config_tree; /* the current config */ 62 static xmlDocPtr sa_config_doc = NULL; /* current config document */ 63 extern struct sa_proto_plugin *sap_proto_list; 64 65 /* current SMF/SVC repository handle */ 66 static scfutilhandle_t *scf_handle = NULL; 67 extern void getlegacyconfig(char *, xmlNodePtr *); 68 extern int gettransients(xmlNodePtr *); 69 extern int sa_valid_property(void *, char *, sa_property_t); 70 extern char *sa_fstype(char *); 71 extern int sa_is_share(void *); 72 extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 73 extern int sa_group_is_zfs(sa_group_t); 74 extern int sa_path_is_zfs(char *); 75 extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 76 extern void update_legacy_config(void); 77 extern int issubdir(char *, char *); 78 extern void sa_zfs_init(void); 79 extern void sa_zfs_fini(void); 80 extern void sablocksigs(sigset_t *); 81 extern void saunblocksigs(sigset_t *); 82 83 static int sa_initialized = 0; 84 85 /* helper functions */ 86 87 char * 88 sa_errorstr(int err) 89 { 90 static char errstr[32]; 91 char *ret = NULL; 92 93 switch (err) { 94 case SA_OK: 95 ret = dgettext(TEXT_DOMAIN, "ok"); 96 break; 97 case SA_NO_SUCH_PATH: 98 ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 99 break; 100 case SA_NO_MEMORY: 101 ret = dgettext(TEXT_DOMAIN, "no memory"); 102 break; 103 case SA_DUPLICATE_NAME: 104 ret = dgettext(TEXT_DOMAIN, "name in use"); 105 break; 106 case SA_BAD_PATH: 107 ret = dgettext(TEXT_DOMAIN, "bad path"); 108 break; 109 case SA_NO_SUCH_GROUP: 110 ret = dgettext(TEXT_DOMAIN, "no such group"); 111 break; 112 case SA_CONFIG_ERR: 113 ret = dgettext(TEXT_DOMAIN, "configuration error"); 114 break; 115 case SA_SYSTEM_ERR: 116 ret = dgettext(TEXT_DOMAIN, "system error"); 117 break; 118 case SA_SYNTAX_ERR: 119 ret = dgettext(TEXT_DOMAIN, "syntax error"); 120 break; 121 case SA_NO_PERMISSION: 122 ret = dgettext(TEXT_DOMAIN, "no permission"); 123 break; 124 case SA_BUSY: 125 ret = dgettext(TEXT_DOMAIN, "busy"); 126 break; 127 case SA_NO_SUCH_PROP: 128 ret = dgettext(TEXT_DOMAIN, "no such property"); 129 break; 130 case SA_INVALID_NAME: 131 ret = dgettext(TEXT_DOMAIN, "invalid name"); 132 break; 133 case SA_INVALID_PROTOCOL: 134 ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 135 break; 136 case SA_NOT_ALLOWED: 137 ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 138 break; 139 case SA_BAD_VALUE: 140 ret = dgettext(TEXT_DOMAIN, "bad property value"); 141 break; 142 case SA_INVALID_SECURITY: 143 ret = dgettext(TEXT_DOMAIN, "invalid security type"); 144 break; 145 case SA_NO_SUCH_SECURITY: 146 ret = dgettext(TEXT_DOMAIN, "security type not found"); 147 break; 148 case SA_VALUE_CONFLICT: 149 ret = dgettext(TEXT_DOMAIN, "property value conflict"); 150 break; 151 case SA_NOT_IMPLEMENTED: 152 ret = dgettext(TEXT_DOMAIN, "not implemented"); 153 break; 154 case SA_INVALID_PATH: 155 ret = dgettext(TEXT_DOMAIN, "invalid path"); 156 break; 157 case SA_NOT_SUPPORTED: 158 ret = dgettext(TEXT_DOMAIN, "operation not supported"); 159 break; 160 case SA_PROP_SHARE_ONLY: 161 ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 162 break; 163 case SA_NOT_SHARED: 164 ret = dgettext(TEXT_DOMAIN, "not shared"); 165 break; 166 default: 167 (void) snprintf(errstr, sizeof (errstr), 168 dgettext(TEXT_DOMAIN, "unknown %d"), err); 169 ret = errstr; 170 } 171 return (ret); 172 } 173 174 /* 175 * set_legacy_timestamp(root, path, timevalue) 176 * 177 * add the current timestamp value to the configuration for use in 178 * determining when to update the legacy files. For SMF, this 179 * property is kept in default/operation/legacy_timestamp 180 */ 181 182 static void 183 set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 184 { 185 xmlNodePtr node; 186 xmlChar *lpath = NULL; 187 188 for (node = root->xmlChildrenNode; node != NULL; 189 node = node->next) { 190 if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 191 /* a possible legacy node for this path */ 192 lpath = xmlGetProp(node, (xmlChar *)"path"); 193 if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) { 194 xmlFree(lpath); 195 break; 196 } 197 if (lpath != NULL) 198 xmlFree(lpath); 199 } 200 } 201 if (node == NULL) { 202 /* need to create the first legacy timestamp node */ 203 node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 204 } 205 if (node != NULL) { 206 char tstring[32]; 207 int ret; 208 209 (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 210 xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 211 xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 212 /* now commit to SMF */ 213 ret = sa_get_instance(scf_handle, "default"); 214 if (ret == SA_OK) { 215 ret = sa_start_transaction(scf_handle, "operation"); 216 if (ret == SA_OK) { 217 ret = sa_set_property(scf_handle, "legacy-timestamp", 218 tstring); 219 if (ret == SA_OK) { 220 (void) sa_end_transaction(scf_handle); 221 } else { 222 sa_abort_transaction(scf_handle); 223 } 224 } 225 } 226 } 227 } 228 229 /* 230 * is_shared(share) 231 * 232 * determine if the specified share is currently shared or not. 233 */ 234 static int 235 is_shared(sa_share_t share) 236 { 237 char *shared; 238 int result = 0; /* assume not */ 239 240 shared = sa_get_share_attr(share, "shared"); 241 if (shared != NULL) { 242 if (strcmp(shared, "true") == 0) 243 result = 1; 244 sa_free_attr_string(shared); 245 } 246 return (result); 247 } 248 249 /* 250 * checksubdirgroup(group, newpath, strictness) 251 * 252 * check all the specified newpath against all the paths in the 253 * group. This is a helper function for checksubdir to make it easier 254 * to also check ZFS subgroups. 255 * The strictness values mean: 256 * SA_CHECK_NORMAL == only check newpath against shares that are active 257 * SA_CHECK_STRICT == check newpath against both active shares and those 258 * stored in the repository 259 */ 260 static int 261 checksubdirgroup(sa_group_t group, char *newpath, int strictness) 262 { 263 sa_share_t share; 264 char *path; 265 int issub = SA_OK; 266 267 for (share = sa_get_share(group, NULL); share != NULL; 268 share = sa_get_next_share(share)) { 269 /* 270 * The original behavior of share never checked 271 * against the permanent configuration 272 * (/etc/dfs/dfstab). PIT has a number of cases where 273 * it depends on this older behavior even though it 274 * could be considered incorrect. We may tighten this 275 * up in the future. 276 */ 277 if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 278 continue; 279 280 path = sa_get_share_attr(share, "path"); 281 /* 282 * If path is NULL, then a share is in the process of 283 * construction or someone has modified the property 284 * group inappropriately. It should be 285 * ignored. issubdir() comes from the original share 286 * implementation and does the difficult part of 287 * checking subdirectories. 288 */ 289 if (path == NULL) 290 continue; 291 if (newpath != NULL && 292 (strcmp(path, newpath) == 0 || issubdir(newpath, path) || 293 issubdir(path, newpath))) { 294 sa_free_attr_string(path); 295 path = NULL; 296 issub = SA_INVALID_PATH; 297 break; 298 } 299 sa_free_attr_string(path); 300 path = NULL; 301 } 302 return (issub); 303 } 304 305 /* 306 * checksubdir(newpath, strictness) 307 * 308 * checksubdir determines if the specified path (newpath) is a 309 * subdirectory of another share. It calls checksubdirgroup() to do 310 * the complicated work. The strictness parameter determines how 311 * strict a check to make against the path. The strictness values 312 * mean: SA_CHECK_NORMAL == only check newpath against shares that are 313 * active SA_CHECK_STRICT == check newpath against both active shares 314 * and those * stored in the repository 315 */ 316 static int 317 checksubdir(char *newpath, int strictness) 318 { 319 sa_group_t group; 320 int issub; 321 char *path = NULL; 322 323 for (issub = 0, group = sa_get_group(NULL); 324 group != NULL && !issub; 325 group = sa_get_next_group(group)) { 326 if (sa_group_is_zfs(group)) { 327 sa_group_t subgroup; 328 for (subgroup = sa_get_sub_group(group); 329 subgroup != NULL && !issub; 330 subgroup = sa_get_next_group(subgroup)) 331 issub = checksubdirgroup(subgroup, newpath, strictness); 332 } else { 333 issub = checksubdirgroup(group, newpath, strictness); 334 } 335 } 336 if (path != NULL) 337 sa_free_attr_string(path); 338 return (issub); 339 } 340 341 /* 342 * validpath(path, strictness) 343 * determine if the provided path is valid for a share. It shouldn't 344 * be a sub-dir of an already shared path or the parent directory of a 345 * share path. 346 */ 347 static int 348 validpath(char *path, int strictness) 349 { 350 int error = SA_OK; 351 struct stat st; 352 sa_share_t share; 353 char *fstype; 354 355 if (*path != '/') { 356 return (SA_BAD_PATH); 357 } 358 if (stat(path, &st) < 0) { 359 error = SA_NO_SUCH_PATH; 360 } else { 361 share = sa_find_share(path); 362 if (share != NULL) { 363 error = SA_DUPLICATE_NAME; 364 } 365 if (error == SA_OK) { 366 /* 367 * check for special case with file system that might 368 * have restrictions. For now, ZFS is the only case 369 * since it has its own idea of how to configure 370 * shares. We do this before subdir checking since 371 * things like ZFS will do that for us. This should 372 * also be done via plugin interface. 373 */ 374 fstype = sa_fstype(path); 375 if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 376 if (sa_zfs_is_shared(path)) 377 error = SA_INVALID_NAME; 378 } 379 if (fstype != NULL) 380 sa_free_fstype(fstype); 381 } 382 if (error == SA_OK) { 383 error = checksubdir(path, strictness); 384 } 385 } 386 return (error); 387 } 388 389 /* 390 * check to see if group/share is persistent. 391 */ 392 static int 393 is_persistent(sa_group_t group) 394 { 395 char *type; 396 int persist = 1; 397 398 type = sa_get_group_attr(group, "type"); 399 if (type != NULL && strcmp(type, "transient") == 0) 400 persist = 0; 401 if (type != NULL) 402 sa_free_attr_string(type); 403 return (persist); 404 } 405 406 /* 407 * sa_valid_group_name(name) 408 * 409 * check that the "name" contains only valid characters and otherwise 410 * fits the required naming conventions. Valid names must start with 411 * an alphabetic and the remainder may consist of only alphanumeric 412 * plus the '-' and '_' characters. This name limitation comes from 413 * inherent limitations in SMF. 414 */ 415 416 int 417 sa_valid_group_name(char *name) 418 { 419 int ret = 1; 420 ssize_t len; 421 422 if (name != NULL && isalpha(*name)) { 423 char c; 424 len = strlen(name); 425 if (len < (scf_max_name_len - sizeof ("group:"))) { 426 for (c = *name++; c != '\0' && ret != 0; c = *name++) { 427 if (!isalnum(c) && c != '-' && c != '_') 428 ret = 0; 429 } 430 } else { 431 ret = 0; 432 } 433 } else { 434 ret = 0; 435 } 436 return (ret); 437 } 438 439 440 /* 441 * is_zfs_group(group) 442 * Determine if the specified group is a ZFS sharenfs group 443 */ 444 static int 445 is_zfs_group(sa_group_t group) 446 { 447 int ret = 0; 448 xmlNodePtr parent; 449 xmlChar *zfs; 450 451 if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) { 452 parent = (xmlNodePtr)sa_get_parent_group(group); 453 } else { 454 parent = (xmlNodePtr)group; 455 } 456 zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 457 if (zfs != NULL) { 458 xmlFree(zfs); 459 ret = 1; 460 } 461 return (ret); 462 } 463 464 /* 465 * sa_optionset_name(optionset, oname, len, id) 466 * return the SMF name for the optionset. If id is not NULL, it 467 * will have the GUID value for a share and should be used 468 * instead of the keyword "optionset" which is used for 469 * groups. If the optionset doesn't have a protocol type 470 * associated with it, "default" is used. This shouldn't happen 471 * at this point but may be desirable in the future if there are 472 * protocol independent properties added. The name is returned in 473 * oname. 474 */ 475 476 static int 477 sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 478 { 479 char *proto; 480 481 if (id == NULL) 482 id = "optionset"; 483 484 proto = sa_get_optionset_attr(optionset, "type"); 485 len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default"); 486 487 if (proto != NULL) 488 sa_free_attr_string(proto); 489 return (len); 490 } 491 492 /* 493 * sa_security_name(optionset, oname, len, id) 494 * 495 * return the SMF name for the security. If id is not NULL, it will 496 * have the GUID value for a share and should be used instead of the 497 * keyword "optionset" which is used for groups. If the optionset 498 * doesn't have a protocol type associated with it, "default" is 499 * used. This shouldn't happen at this point but may be desirable in 500 * the future if there are protocol independent properties added. The 501 * name is returned in oname. The security type is also encoded into 502 * the name. In the future, this wil *be handled a bit differently. 503 */ 504 505 static int 506 sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 507 { 508 char *proto; 509 char *sectype; 510 511 if (id == NULL) 512 id = "optionset"; 513 514 proto = sa_get_security_attr(security, "type"); 515 sectype = sa_get_security_attr(security, "sectype"); 516 len = snprintf(oname, len, "%s_%s_%s", id, 517 proto ? proto : "default", 518 sectype ? sectype : "default"); 519 if (proto != NULL) 520 sa_free_attr_string(proto); 521 if (sectype != NULL) 522 sa_free_attr_string(sectype); 523 return (len); 524 } 525 526 /* 527 * sa_init(init_service) 528 * Initialize the API 529 * find all the shared objects 530 * init the tables with all objects 531 * read in the current configuration 532 */ 533 534 void 535 sa_init(int init_service) 536 { 537 struct stat st; 538 int legacy = 0; 539 uint64_t tval = 0; 540 int lockfd; 541 sigset_t old; 542 int updatelegacy = B_FALSE; 543 scf_simple_prop_t *prop; 544 545 if (!sa_initialized) { 546 /* get protocol specific structures */ 547 (void) proto_plugin_init(); 548 if (init_service & SA_INIT_SHARE_API) { 549 /* 550 * initialize access into libzfs. We use this when 551 * collecting info about ZFS datasets and shares. 552 */ 553 sa_zfs_init(); 554 /* 555 * since we want to use SMF, initialize an svc handle 556 * and find out what is there. 557 */ 558 scf_handle = sa_scf_init(); 559 if (scf_handle != NULL) { 560 /* 561 * Need to lock the extraction of the 562 * configuration if the dfstab file has 563 * changed. Lock everything now and release if 564 * not needed. Use a file that isn't being 565 * manipulated by other parts of the system in 566 * order to not interfere with locking. Using 567 * dfstab doesn't work. 568 */ 569 sablocksigs(&old); 570 lockfd = open(DFS_LOCK_FILE, O_RDWR); 571 if (lockfd >= 0) { 572 extern int errno; 573 errno = 0; 574 (void) lockf(lockfd, F_LOCK, 0); 575 /* 576 * Check whether we are going to need to merge 577 * any dfstab changes. This is done by 578 * comparing the value of legacy-timestamp 579 * with the current st_ctim of the file. If 580 * they are different, an update is needed and 581 * the file must remain locked until the merge 582 * is done in order to prevent multiple 583 * startups from changing the SMF repository 584 * at the same time. The first to get the 585 * lock will make any changes before the 586 * others can read the repository. 587 */ 588 prop = scf_simple_prop_get(scf_handle->handle, 589 (const char *) 590 SA_SVC_FMRI_BASE ":default", 591 "operation", 592 "legacy-timestamp"); 593 if (prop != NULL) { 594 char *i64; 595 i64 = scf_simple_prop_next_astring(prop); 596 if (i64 != NULL) { 597 tval = strtoull(i64, NULL, 0); 598 } 599 if (stat(SA_LEGACY_DFSTAB, &st) >= 0 && 600 tval != TSTAMP(st.st_ctim)) { 601 updatelegacy = B_TRUE; 602 } 603 } else { 604 /* We haven't set the timestamp before so do it. */ 605 updatelegacy = B_TRUE; 606 } 607 } 608 if (updatelegacy == B_FALSE) { 609 /* Don't need the lock anymore */ 610 (void) lockf(lockfd, F_ULOCK, 0); 611 (void) close(lockfd); 612 } 613 (void) sa_get_config(scf_handle, &sa_config_tree, 614 &sa_config_doc); 615 saunblocksigs(&old); 616 if (tval == 0) { 617 /* first time so make sure default is setup */ 618 sa_group_t defgrp; 619 sa_optionset_t opt; 620 defgrp = sa_get_group("default"); 621 if (defgrp != NULL) { 622 opt = sa_get_optionset(defgrp, NULL); 623 if (opt == NULL) 624 /* NFS is the default for default */ 625 opt = sa_create_optionset(defgrp, "nfs"); 626 } 627 } 628 if (updatelegacy == B_TRUE) { 629 sablocksigs(&old); 630 getlegacyconfig(SA_LEGACY_DFSTAB, &sa_config_tree); 631 if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 632 set_legacy_timestamp(sa_config_tree, 633 SA_LEGACY_DFSTAB, 634 TSTAMP(st.st_ctim)); 635 saunblocksigs(&old); 636 /* Safe to unlock now to allow others to run */ 637 (void) lockf(lockfd, F_ULOCK, 0); 638 (void) close(lockfd); 639 } 640 legacy |= sa_get_zfs_shares("zfs"); 641 legacy |= gettransients(&sa_config_tree); 642 } 643 } 644 } 645 } 646 647 /* 648 * sa_fini() 649 * Uninitialize the API structures including the configuration 650 * data structures and ZFS related data. 651 */ 652 653 void 654 sa_fini() 655 { 656 if (sa_initialized) { 657 /* free the config trees */ 658 sa_initialized = 0; 659 if (sa_config_doc != NULL) 660 xmlFreeDoc(sa_config_doc); 661 sa_config_tree = NULL; 662 sa_config_doc = NULL; 663 sa_scf_fini(scf_handle); 664 sa_zfs_fini(); 665 (void) proto_plugin_init(); 666 } 667 } 668 669 /* 670 * sa_get_protocols(char **protocol) 671 * Get array of protocols that are supported 672 * Returns pointer to an allocated and NULL terminated 673 * array of strings. Caller must free. 674 * This really should be determined dynamically. 675 * If there aren't any defined, return -1. 676 * Use free() to return memory. 677 */ 678 679 int 680 sa_get_protocols(char ***protocols) 681 { 682 int numproto = -1; 683 684 if (protocols != NULL) { 685 struct sa_proto_plugin *plug; 686 for (numproto = 0, plug = sap_proto_list; plug != NULL; 687 plug = plug->plugin_next) { 688 numproto++; 689 } 690 691 *protocols = calloc(numproto + 1, sizeof (char *)); 692 if (*protocols != NULL) { 693 int ret = 0; 694 for (plug = sap_proto_list; plug != NULL; 695 plug = plug->plugin_next) { 696 /* faking for now */ 697 (*protocols)[ret++] = plug->plugin_ops->sa_protocol; 698 } 699 } else { 700 numproto = -1; 701 } 702 } 703 return (numproto); 704 } 705 706 /* 707 * find_group_by_name(node, group) 708 * 709 * search the XML document subtree specified by node to find the group 710 * specified by group. Searching subtree allows subgroups to be 711 * searched for. 712 */ 713 714 static xmlNodePtr 715 find_group_by_name(xmlNodePtr node, xmlChar *group) 716 { 717 xmlChar *name = NULL; 718 719 for (node = node->xmlChildrenNode; node != NULL; 720 node = node->next) { 721 if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 722 /* if no groupname, return the first found */ 723 if (group == NULL) 724 break; 725 name = xmlGetProp(node, (xmlChar *)"name"); 726 if (name != NULL && 727 xmlStrcmp(name, group) == 0) { 728 break; 729 } 730 if (name != NULL) { 731 xmlFree(name); 732 name = NULL; 733 } 734 } 735 } 736 if (name != NULL) 737 xmlFree(name); 738 return (node); 739 } 740 741 /* 742 * sa_get_group(groupname) 743 * Return the "group" specified. If groupname is NULL, 744 * return the first group of the list of groups. 745 */ 746 sa_group_t 747 sa_get_group(char *groupname) 748 { 749 xmlNodePtr node = NULL; 750 char *subgroup = NULL; 751 char *group = NULL; 752 753 if (sa_config_tree != NULL) { 754 if (groupname != NULL) { 755 group = strdup(groupname); 756 subgroup = strchr(group, '/'); 757 if (subgroup != NULL) 758 *subgroup++ = '\0'; 759 } 760 node = find_group_by_name(sa_config_tree, (xmlChar *)group); 761 /* if a subgroup, find it before returning */ 762 if (subgroup != NULL && node != NULL) { 763 node = find_group_by_name(node, (xmlChar *)subgroup); 764 } 765 } 766 if (node != NULL && (char *)group != NULL) 767 (void) sa_get_instance(scf_handle, (char *)group); 768 if (group != NULL) 769 free(group); 770 return ((sa_group_t)(node)); 771 } 772 773 /* 774 * sa_get_next_group(group) 775 * Return the "next" group after the specified group from 776 * the internal group list. NULL if there are no more. 777 */ 778 sa_group_t 779 sa_get_next_group(sa_group_t group) 780 { 781 xmlNodePtr ngroup = NULL; 782 if (group != NULL) { 783 for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 784 ngroup = ngroup->next) { 785 if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 786 break; 787 } 788 } 789 return ((sa_group_t)ngroup); 790 } 791 792 /* 793 * sa_get_share(group, sharepath) 794 * Return the share object for the share specified. The share 795 * must be in the specified group. Return NULL if not found. 796 */ 797 sa_share_t 798 sa_get_share(sa_group_t group, char *sharepath) 799 { 800 xmlNodePtr node = NULL; 801 xmlChar *path; 802 803 /* 804 * For future scalability, this should end up building a cache 805 * since it will get called regularly by the mountd and info 806 * services. 807 */ 808 if (group != NULL) { 809 for (node = ((xmlNodePtr)group)->children; node != NULL; 810 node = node->next) { 811 if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 812 if (sharepath == NULL) { 813 break; 814 } else { 815 /* is it the correct share? */ 816 path = xmlGetProp(node, (xmlChar *)"path"); 817 if (path != NULL && 818 xmlStrcmp(path, (xmlChar *)sharepath) == 0) { 819 xmlFree(path); 820 break; 821 } 822 xmlFree(path); 823 } 824 } 825 } 826 } 827 return ((sa_share_t)node); 828 } 829 830 /* 831 * sa_get_next_share(share) 832 * Return the next share following the specified share 833 * from the internal list of shares. Returns NULL if there 834 * are no more shares. The list is relative to the same 835 * group. 836 */ 837 sa_share_t 838 sa_get_next_share(sa_share_t share) 839 { 840 xmlNodePtr node = NULL; 841 842 if (share != NULL) { 843 for (node = ((xmlNodePtr)share)->next; node != NULL; 844 node = node->next) { 845 if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 846 break; 847 } 848 } 849 } 850 return ((sa_share_t)node); 851 } 852 853 /* 854 * _sa_get_child_node(node, type) 855 * 856 * find the child node of the specified node that has "type". This is 857 * used to implement several internal functions. 858 */ 859 860 static xmlNodePtr 861 _sa_get_child_node(xmlNodePtr node, xmlChar *type) 862 { 863 xmlNodePtr child; 864 for (child = node->xmlChildrenNode; child != NULL; 865 child = child->next) 866 if (xmlStrcmp(child->name, type) == 0) 867 return (child); 868 return ((xmlNodePtr)NULL); 869 } 870 871 /* 872 * find_share(group, path) 873 * 874 * Search all the shares in the specified group for one that has the 875 * specified path. 876 */ 877 878 static sa_share_t 879 find_share(sa_group_t group, char *sharepath) 880 { 881 sa_share_t share; 882 char *path; 883 884 for (share = sa_get_share(group, NULL); share != NULL; 885 share = sa_get_next_share(share)) { 886 path = sa_get_share_attr(share, "path"); 887 if (path != NULL && strcmp(path, sharepath) == 0) { 888 sa_free_attr_string(path); 889 break; 890 } 891 if (path != NULL) 892 sa_free_attr_string(path); 893 } 894 return (share); 895 } 896 897 /* 898 * sa_get_sub_group(group) 899 * 900 * Get the first sub-group of group. The sa_get_next_group() function 901 * can be used to get the rest. This is currently only used for ZFS 902 * sub-groups but could be used to implement a more general mechanism. 903 */ 904 905 sa_group_t 906 sa_get_sub_group(sa_group_t group) 907 { 908 return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 909 (xmlChar *)"group")); 910 } 911 912 /* 913 * sa_find_share(sharepath) 914 * Finds a share regardless of group. In the future, this 915 * function should utilize a cache and hash table of some kind. 916 * The current assumption is that a path will only be shared 917 * once. In the future, this may change as implementation of 918 * resource names comes into being. 919 */ 920 sa_share_t 921 sa_find_share(char *sharepath) 922 { 923 sa_group_t group; 924 sa_group_t zgroup; 925 sa_share_t share = NULL; 926 int done = 0; 927 928 for (group = sa_get_group(NULL); group != NULL && !done; 929 group = sa_get_next_group(group)) { 930 if (is_zfs_group(group)) { 931 for (zgroup = (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 932 (xmlChar *)"group"); 933 zgroup != NULL; zgroup = sa_get_next_group(zgroup)) { 934 share = find_share(zgroup, sharepath); 935 if (share != NULL) 936 break; 937 } 938 } else { 939 share = find_share(group, sharepath); 940 } 941 if (share != NULL) 942 break; 943 } 944 return (share); 945 } 946 947 /* 948 * sa_check_path(group, path, strictness) 949 * 950 * check that path is a valid path relative to the group. Currently, 951 * we are ignoring the group and checking only the NFS rules. Later, 952 * we may want to use the group to then check against the protocols 953 * enabled on the group. The strictness values mean: 954 * SA_CHECK_NORMAL == only check newpath against shares that are active 955 * SA_CHECK_STRICT == check newpath against both active shares and those 956 * stored in the repository 957 */ 958 959 int 960 sa_check_path(sa_group_t group, char *path, int strictness) 961 { 962 #ifdef lint 963 group = group; 964 #endif 965 return (validpath(path, strictness)); 966 } 967 968 /* 969 * _sa_add_share(group, sharepath, persist, *error) 970 * 971 * common code for all types of add_share. sa_add_share() is the 972 * public API, we also need to be able to do this when parsing legacy 973 * files and construction of the internal configuration while 974 * extracting config info from SMF. 975 */ 976 977 sa_share_t 978 _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 979 { 980 xmlNodePtr node = NULL; 981 int err; 982 983 err = SA_OK; /* assume success */ 984 985 node = xmlNewChild((xmlNodePtr)group, NULL, 986 (xmlChar *)"share", NULL); 987 if (node != NULL) { 988 xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 989 xmlSetProp(node, (xmlChar *)"type", persist ? 990 (xmlChar *)"persist" : (xmlChar *)"transient"); 991 if (persist != SA_SHARE_TRANSIENT) { 992 /* 993 * persistent shares come in two flavors: SMF and 994 * ZFS. Sort this one out based on target group and 995 * path type. Currently, only NFS is supported in the 996 * ZFS group and it is always on. 997 */ 998 if (sa_group_is_zfs(group) && sa_path_is_zfs(sharepath)) { 999 err = sa_zfs_set_sharenfs(group, sharepath, 1); 1000 } else { 1001 err = sa_commit_share(scf_handle, group, 1002 (sa_share_t)node); 1003 } 1004 } 1005 if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) { 1006 /* called by the dfstab parser so could be a show */ 1007 err = SA_OK; 1008 } 1009 if (err != SA_OK) { 1010 /* 1011 * we couldn't commit to the repository so undo 1012 * our internal state to reflect reality. 1013 */ 1014 xmlUnlinkNode(node); 1015 xmlFreeNode(node); 1016 node = NULL; 1017 } 1018 } else { 1019 err = SA_NO_MEMORY; 1020 } 1021 if (error != NULL) 1022 *error = err; 1023 return (node); 1024 } 1025 1026 /* 1027 * sa_add_share(group, sharepath, persist, *error) 1028 * 1029 * Add a new share object to the specified group. The share will 1030 * have the specified sharepath and will only be constructed if 1031 * it is a valid path to be shared. NULL is returned on error 1032 * and a detailed error value will be returned via the error 1033 * pointer. 1034 */ 1035 sa_share_t 1036 sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 1037 { 1038 xmlNodePtr node = NULL; 1039 sa_share_t dup; 1040 int strictness = SA_CHECK_NORMAL; 1041 1042 /* 1043 * If the share is to be permanent, use strict checking so a 1044 * bad config doesn't get created. Transient shares only need 1045 * to check against the currently active 1046 * shares. SA_SHARE_PARSER is a modifier used internally to 1047 * indicate that we are being called by the dfstab parser and 1048 * that we need strict checking in all cases. Normally persist 1049 * is in integer value but SA_SHARE_PARSER may be or'd into 1050 * it as an override. 1051 */ 1052 if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 1053 strictness = SA_CHECK_STRICT; 1054 1055 if ((dup = sa_find_share(sharepath)) == NULL && 1056 (*error = sa_check_path(group, sharepath, strictness)) == 1057 SA_OK) { 1058 node = _sa_add_share(group, sharepath, persist, error); 1059 } 1060 if (dup != NULL) 1061 *error = SA_DUPLICATE_NAME; 1062 1063 return ((sa_share_t)node); 1064 } 1065 1066 /* 1067 * sa_enable_share(share, protocol) 1068 * Enable the specified share to the specified protocol. 1069 * If protocol is NULL, then all protocols. 1070 */ 1071 int 1072 sa_enable_share(sa_share_t share, char *protocol) 1073 { 1074 char *sharepath; 1075 struct stat st; 1076 int err = 0; 1077 1078 sharepath = sa_get_share_attr(share, "path"); 1079 if (stat(sharepath, &st) < 0) { 1080 err = SA_NO_SUCH_PATH; 1081 } else { 1082 /* tell the server about the share */ 1083 if (protocol != NULL) { 1084 /* lookup protocol specific handler */ 1085 err = sa_proto_share(protocol, share); 1086 if (err == SA_OK) 1087 (void) sa_set_share_attr(share, "shared", "true"); 1088 } else { 1089 /* tell all protocols */ 1090 err = sa_proto_share("nfs", share); /* only NFS for now */ 1091 (void) sa_set_share_attr(share, "shared", "true"); 1092 } 1093 } 1094 if (sharepath != NULL) 1095 sa_free_attr_string(sharepath); 1096 return (err); 1097 } 1098 1099 /* 1100 * sa_disable_share(share, protocol) 1101 * Disable the specified share to the specified protocol. 1102 * If protocol is NULL, then all protocols. 1103 */ 1104 int 1105 sa_disable_share(sa_share_t share, char *protocol) 1106 { 1107 char *path; 1108 char *shared; 1109 int ret = SA_OK; 1110 1111 path = sa_get_share_attr(share, "path"); 1112 shared = sa_get_share_attr(share, "shared"); 1113 1114 if (protocol != NULL) { 1115 ret = sa_proto_unshare(protocol, path); 1116 } else { 1117 /* need to do all protocols */ 1118 ret = sa_proto_unshare("nfs", path); 1119 } 1120 if (ret == SA_OK) 1121 (void) sa_set_share_attr(share, "shared", NULL); 1122 if (path != NULL) 1123 sa_free_attr_string(path); 1124 if (shared != NULL) 1125 sa_free_attr_string(shared); 1126 return (ret); 1127 } 1128 1129 /* 1130 * sa_remove_share(share) 1131 * 1132 * remove the specified share from its containing group. 1133 * Remove from the SMF or ZFS configuration space. 1134 */ 1135 1136 int 1137 sa_remove_share(sa_share_t share) 1138 { 1139 sa_group_t group; 1140 int ret = SA_OK; 1141 char *type; 1142 int transient = 0; 1143 char *groupname; 1144 char *zfs; 1145 1146 type = sa_get_share_attr(share, "type"); 1147 group = sa_get_parent_group(share); 1148 zfs = sa_get_group_attr(group, "zfs"); 1149 groupname = sa_get_group_attr(group, "name"); 1150 if (type != NULL && strcmp(type, "persist") != 0) 1151 transient = 1; 1152 if (type != NULL) 1153 sa_free_attr_string(type); 1154 1155 /* remove the node from its group then free the memory */ 1156 1157 /* 1158 * need to test if "busy" 1159 */ 1160 /* only do SMF action if permanent */ 1161 if (!transient || zfs != NULL) { 1162 /* remove from legacy dfstab as well as possible SMF */ 1163 ret = sa_delete_legacy(share); 1164 if (ret == SA_OK) { 1165 if (!sa_group_is_zfs(group)) { 1166 ret = sa_delete_share(scf_handle, group, share); 1167 } else { 1168 char *sharepath = sa_get_share_attr(share, "path"); 1169 if (sharepath != NULL) { 1170 ret = sa_zfs_set_sharenfs(group, sharepath, 0); 1171 sa_free_attr_string(sharepath); 1172 } 1173 } 1174 } 1175 } 1176 if (groupname != NULL) 1177 sa_free_attr_string(groupname); 1178 if (zfs != NULL) 1179 sa_free_attr_string(zfs); 1180 1181 xmlUnlinkNode((xmlNodePtr)share); 1182 xmlFreeNode((xmlNodePtr)share); 1183 return (ret); 1184 } 1185 1186 /* 1187 * sa_move_share(group, share) 1188 * 1189 * move the specified share to the specified group. Update SMF 1190 * appropriately. 1191 */ 1192 1193 int 1194 sa_move_share(sa_group_t group, sa_share_t share) 1195 { 1196 sa_group_t oldgroup; 1197 int ret = SA_OK; 1198 1199 /* remove the node from its group then free the memory */ 1200 1201 oldgroup = sa_get_parent_group(share); 1202 if (oldgroup != group) { 1203 xmlUnlinkNode((xmlNodePtr)share); 1204 /* now that the share isn't in its old group, add to the new one */ 1205 xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 1206 /* need to deal with SMF */ 1207 if (ret == SA_OK) { 1208 /* 1209 * need to remove from old group first and then add to 1210 * new group. Ideally, we would do the other order but 1211 * need to avoid having the share in two groups at the 1212 * same time. 1213 */ 1214 ret = sa_delete_share(scf_handle, oldgroup, share); 1215 } 1216 ret = sa_commit_share(scf_handle, group, share); 1217 } 1218 return (ret); 1219 } 1220 1221 /* 1222 * sa_get_parent_group(share) 1223 * 1224 * Return the containg group for the share. If a group was actually 1225 * passed in, we don't want a parent so return NULL. 1226 */ 1227 1228 sa_group_t 1229 sa_get_parent_group(sa_share_t share) 1230 { 1231 xmlNodePtr node = NULL; 1232 if (share != NULL) { 1233 node = ((xmlNodePtr)share)->parent; 1234 /* 1235 * make sure parent is a group and not sharecfg since 1236 * we may be cheating and passing in a group. 1237 * Eventually, groups of groups might come into being. 1238 */ 1239 if (node == NULL || 1240 xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 1241 node = NULL; 1242 } 1243 return ((sa_group_t)node); 1244 } 1245 1246 /* 1247 * _sa_create_group(groupname) 1248 * 1249 * Create a group in the document. The caller will need to deal with 1250 * configuration store and activation. 1251 */ 1252 1253 sa_group_t 1254 _sa_create_group(char *groupname) 1255 { 1256 xmlNodePtr node = NULL; 1257 1258 if (sa_valid_group_name(groupname)) { 1259 node = xmlNewChild(sa_config_tree, NULL, 1260 (xmlChar *)"group", NULL); 1261 if (node != NULL) { 1262 xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 1263 xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 1264 } 1265 } 1266 return ((sa_group_t)node); 1267 } 1268 1269 /* 1270 * _sa_create_zfs_group(group, groupname) 1271 * 1272 * Create a ZFS subgroup under the specified group. This may 1273 * eventually form the basis of general sub-groups, but is currently 1274 * restricted to ZFS. 1275 */ 1276 sa_group_t 1277 _sa_create_zfs_group(sa_group_t group, char *groupname) 1278 { 1279 xmlNodePtr node = NULL; 1280 1281 node = xmlNewChild((xmlNodePtr)group, NULL, 1282 (xmlChar *)"group", NULL); 1283 if (node != NULL) { 1284 xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 1285 xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 1286 } 1287 1288 return ((sa_group_t)node); 1289 } 1290 1291 /* 1292 * sa_create_group(groupname, *error) 1293 * 1294 * Create a new group with groupname. Need to validate that it is a 1295 * legal name for SMF and the construct the SMF service instance of 1296 * svc:/network/shares/group to implement the group. All necessary 1297 * operational properties must be added to the group at this point 1298 * (via the SMF transaction model). 1299 */ 1300 sa_group_t 1301 sa_create_group(char *groupname, int *error) 1302 { 1303 xmlNodePtr node = NULL; 1304 sa_group_t group; 1305 int ret; 1306 char rbacstr[256]; 1307 1308 ret = SA_OK; 1309 1310 if (scf_handle == NULL) { 1311 ret = SA_SYSTEM_ERR; 1312 goto err; 1313 } 1314 1315 group = sa_get_group(groupname); 1316 if (group != NULL) { 1317 ret = SA_DUPLICATE_NAME; 1318 } else { 1319 if (sa_valid_group_name(groupname)) { 1320 node = xmlNewChild(sa_config_tree, NULL, 1321 (xmlChar *)"group", NULL); 1322 if (node != NULL) { 1323 xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 1324 /* default to the group being enabled */ 1325 xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 1326 ret = sa_create_instance(scf_handle, groupname); 1327 if (ret == SA_OK) { 1328 ret = sa_start_transaction(scf_handle, "operation"); 1329 } 1330 if (ret == SA_OK) { 1331 ret = sa_set_property(scf_handle, "state", "enabled"); 1332 if (ret == SA_OK) { 1333 ret = sa_end_transaction(scf_handle); 1334 } else { 1335 sa_abort_transaction(scf_handle); 1336 } 1337 } 1338 if (ret == SA_OK) { 1339 /* initialize the RBAC strings */ 1340 ret = sa_start_transaction(scf_handle, "general"); 1341 if (ret == SA_OK) { 1342 (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 1343 SA_RBAC_MANAGE, groupname); 1344 ret = sa_set_property(scf_handle, 1345 "action_authorization", 1346 rbacstr); 1347 } 1348 if (ret == SA_OK) { 1349 (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 1350 SA_RBAC_VALUE, groupname); 1351 ret = sa_set_property(scf_handle, 1352 "value_authorization", 1353 rbacstr); 1354 } 1355 if (ret == SA_OK) { 1356 ret = sa_end_transaction(scf_handle); 1357 } else { 1358 sa_abort_transaction(scf_handle); 1359 } 1360 } 1361 if (ret != SA_OK) { 1362 /* 1363 * Couldn't commit the group so we need to 1364 * undo internally. 1365 */ 1366 xmlUnlinkNode(node); 1367 xmlFreeNode(node); 1368 node = NULL; 1369 } 1370 } else { 1371 ret = SA_NO_MEMORY; 1372 } 1373 } else { 1374 ret = SA_INVALID_NAME; 1375 } 1376 } 1377 err: 1378 if (error != NULL) 1379 *error = ret; 1380 return ((sa_group_t)node); 1381 } 1382 1383 /* 1384 * sa_remove_group(group) 1385 * 1386 * Remove the specified group. This deletes from the SMF repository. 1387 * All property groups and properties are removed. 1388 */ 1389 1390 int 1391 sa_remove_group(sa_group_t group) 1392 { 1393 char *name; 1394 int ret = SA_OK; 1395 1396 name = sa_get_group_attr(group, "name"); 1397 if (name != NULL) { 1398 ret = sa_delete_instance(scf_handle, name); 1399 sa_free_attr_string(name); 1400 } 1401 xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 1402 xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 1403 return (ret); 1404 } 1405 1406 /* 1407 * sa_update_config() 1408 * 1409 * Used to update legacy files that need to be updated in bulk 1410 * Currently, this is a placeholder and will go away in a future 1411 * release. 1412 */ 1413 1414 int 1415 sa_update_config() 1416 { 1417 /* 1418 * do legacy files first so we can tell when they change. 1419 * This will go away when we start updating individual records 1420 * rather than the whole file. 1421 */ 1422 update_legacy_config(); 1423 return (SA_OK); 1424 } 1425 1426 /* 1427 * get_node_attr(node, tag) 1428 * 1429 * Get the speficied tag(attribute) if it exists on the node. This is 1430 * used internally by a number of attribute oriented functions. 1431 */ 1432 1433 static char * 1434 get_node_attr(void *nodehdl, char *tag) 1435 { 1436 xmlNodePtr node = (xmlNodePtr)nodehdl; 1437 xmlChar *name = NULL; 1438 1439 if (node != NULL) { 1440 name = xmlGetProp(node, (xmlChar *)tag); 1441 } 1442 return ((char *)name); 1443 } 1444 1445 /* 1446 * get_node_attr(node, tag) 1447 * 1448 * Set the speficied tag(attribute) to the specified value This is 1449 * used internally by a number of attribute oriented functions. It 1450 * doesn't update the repository, only the internal document state. 1451 */ 1452 1453 void 1454 set_node_attr(void *nodehdl, char *tag, char *value) 1455 { 1456 xmlNodePtr node = (xmlNodePtr)nodehdl; 1457 if (node != NULL && tag != NULL) { 1458 if (value != NULL) { 1459 xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 1460 } else { 1461 xmlUnsetProp(node, (xmlChar *)tag); 1462 } 1463 } 1464 } 1465 1466 /* 1467 * sa_get_group_attr(group, tag) 1468 * 1469 * Get the specied attribute, if defined, for the group. 1470 */ 1471 1472 char * 1473 sa_get_group_attr(sa_group_t group, char *tag) 1474 { 1475 return (get_node_attr((void *)group, tag)); 1476 } 1477 1478 /* 1479 * sa_set_group_attr(group, tag, value) 1480 * 1481 * set the specified tag/attribute on the group using value as its 1482 * value. 1483 * 1484 * This will result in setting the property in the SMF repository as 1485 * well as in the internal document. 1486 */ 1487 1488 int 1489 sa_set_group_attr(sa_group_t group, char *tag, char *value) 1490 { 1491 int ret; 1492 char *groupname; 1493 1494 groupname = sa_get_group_attr(group, "name"); 1495 ret = sa_get_instance(scf_handle, groupname); 1496 if (ret == SA_OK) { 1497 set_node_attr((void *)group, tag, value); 1498 ret = sa_start_transaction(scf_handle, "operation"); 1499 if (ret == SA_OK) { 1500 ret = sa_set_property(scf_handle, tag, value); 1501 if (ret == SA_OK) 1502 (void) sa_end_transaction(scf_handle); 1503 else { 1504 sa_abort_transaction(scf_handle); 1505 } 1506 } 1507 } 1508 if (groupname != NULL) 1509 sa_free_attr_string(groupname); 1510 return (ret); 1511 } 1512 1513 /* 1514 * sa_get_share_attr(share, tag) 1515 * 1516 * Return the value of the tag/attribute set on the specified 1517 * share. Returns NULL if the tag doesn't exist. 1518 */ 1519 1520 char * 1521 sa_get_share_attr(sa_share_t share, char *tag) 1522 { 1523 return (get_node_attr((void *)share, tag)); 1524 } 1525 1526 /* 1527 * sa_get_resource(group, resource) 1528 * 1529 * Search all the shares in the speified group for a share with a 1530 * resource name matching the one specified. 1531 * 1532 * In the future, it may be advantageous to allow group to be NULL and 1533 * search all groups but that isn't needed at present. 1534 */ 1535 1536 sa_share_t 1537 sa_get_resource(sa_group_t group, char *resource) 1538 { 1539 sa_share_t share = NULL; 1540 char *name = NULL; 1541 1542 if (resource != NULL) { 1543 for (share = sa_get_share(group, NULL); share != NULL; 1544 share = sa_get_next_share(share)) { 1545 name = sa_get_share_attr(share, "resource"); 1546 if (name != NULL) { 1547 if (strcmp(name, resource) == 0) 1548 break; 1549 sa_free_attr_string(name); 1550 name = NULL; 1551 } 1552 } 1553 if (name != NULL) 1554 sa_free_attr_string(name); 1555 } 1556 return ((sa_share_t)share); 1557 } 1558 1559 /* 1560 * _sa_set_share_description(share, description) 1561 * 1562 * Add a description tag with text contents to the specified share. 1563 * A separate XML tag is used rather than a property. 1564 */ 1565 1566 xmlNodePtr 1567 _sa_set_share_description(sa_share_t share, char *content) 1568 { 1569 xmlNodePtr node; 1570 node = xmlNewChild((xmlNodePtr)share, 1571 NULL, (xmlChar *)"description", NULL); 1572 xmlNodeSetContent(node, (xmlChar *)content); 1573 return (node); 1574 } 1575 1576 /* 1577 * sa_set_share_attr(share, tag, value) 1578 * 1579 * Set the share attribute specified by tag to the specified value. In 1580 * the case of "resource", enforce a no duplicates in a group rule. If 1581 * the share is not transient, commit the changes to the repository 1582 * else just update the share internally. 1583 */ 1584 1585 int 1586 sa_set_share_attr(sa_share_t share, char *tag, char *value) 1587 { 1588 sa_group_t group; 1589 sa_share_t resource; 1590 int ret = SA_OK; 1591 1592 group = sa_get_parent_group(share); 1593 1594 /* 1595 * There are some attributes that may have specific 1596 * restrictions on them. Initially, only "resource" has 1597 * special meaning that needs to be checked. Only one instance 1598 * of a resource name may exist within a group. 1599 */ 1600 1601 if (strcmp(tag, "resource") == 0) { 1602 resource = sa_get_resource(group, value); 1603 if (resource != share && resource != NULL) 1604 ret = SA_DUPLICATE_NAME; 1605 } 1606 if (ret == SA_OK) { 1607 set_node_attr((void *)share, tag, value); 1608 if (group != NULL) { 1609 char *type; 1610 /* we can probably optimize this some */ 1611 type = sa_get_share_attr(share, "type"); 1612 if (type == NULL || strcmp(type, "transient") != 0) 1613 ret = sa_commit_share(scf_handle, group, share); 1614 if (type != NULL) 1615 sa_free_attr_string(type); 1616 } 1617 } 1618 return (ret); 1619 } 1620 1621 /* 1622 * sa_get_property_attr(prop, tag) 1623 * 1624 * Get the value of the specified property attribute. Standard 1625 * attributes are "type" and "value". 1626 */ 1627 1628 char * 1629 sa_get_property_attr(sa_property_t prop, char *tag) 1630 { 1631 return (get_node_attr((void *)prop, tag)); 1632 } 1633 1634 /* 1635 * sa_get_optionset_attr(prop, tag) 1636 * 1637 * Get the value of the specified property attribute. Standard 1638 * attribute is "type". 1639 */ 1640 1641 char * 1642 sa_get_optionset_attr(sa_property_t optionset, char *tag) 1643 { 1644 return (get_node_attr((void *)optionset, tag)); 1645 1646 } 1647 1648 /* 1649 * sa_set_optionset_attr(optionset, tag, value) 1650 * 1651 * Set the specified attribute(tag) to the specified value on the 1652 * optionset. 1653 */ 1654 1655 void 1656 sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 1657 { 1658 set_node_attr((void *)optionset, tag, value); 1659 } 1660 1661 /* 1662 * sa_free_attr_string(string) 1663 * 1664 * Free the string that was returned in one of the sa_get_*_attr() 1665 * functions. 1666 */ 1667 1668 void 1669 sa_free_attr_string(char *string) 1670 { 1671 xmlFree((xmlChar *)string); 1672 } 1673 1674 /* 1675 * sa_get_optionset(group, proto) 1676 * 1677 * Return the optionset, if it exists, that is associated with the 1678 * specified protocol. 1679 */ 1680 1681 sa_optionset_t 1682 sa_get_optionset(void *group, char *proto) 1683 { 1684 xmlNodePtr node; 1685 xmlChar *value = NULL; 1686 1687 for (node = ((xmlNodePtr)group)->children; node != NULL; 1688 node = node->next) { 1689 if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 1690 value = xmlGetProp(node, (xmlChar *)"type"); 1691 if (proto != NULL) { 1692 if (value != NULL && 1693 xmlStrcmp(value, (xmlChar *)proto) == 0) { 1694 break; 1695 } 1696 if (value != NULL) { 1697 xmlFree(value); 1698 value = NULL; 1699 } 1700 } else { 1701 break; 1702 } 1703 } 1704 } 1705 if (value != NULL) 1706 xmlFree(value); 1707 return ((sa_optionset_t)node); 1708 } 1709 1710 /* 1711 * sa_get_next_optionset(optionset) 1712 * 1713 * Return the next optionset in the group. NULL if this was the last. 1714 */ 1715 1716 sa_optionset_t 1717 sa_get_next_optionset(sa_optionset_t optionset) 1718 { 1719 xmlNodePtr node; 1720 1721 for (node = ((xmlNodePtr)optionset)->next; node != NULL; 1722 node = node->next) { 1723 if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 1724 break; 1725 } 1726 } 1727 return ((sa_optionset_t)node); 1728 } 1729 1730 /* 1731 * sa_get_security(group, sectype, proto) 1732 * 1733 * Return the security optionset. The internal name is a hold over 1734 * from the implementation and will be changed before the API is 1735 * finalized. This is really a named optionset that can be negotiated 1736 * as a group of properties (like NFS security options). 1737 */ 1738 1739 sa_security_t 1740 sa_get_security(sa_group_t group, char *sectype, char *proto) 1741 { 1742 xmlNodePtr node; 1743 xmlChar *value = NULL; 1744 1745 for (node = ((xmlNodePtr)group)->children; node != NULL; 1746 node = node->next) { 1747 if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 1748 if (proto != NULL) { 1749 value = xmlGetProp(node, (xmlChar *)"type"); 1750 if (value == NULL || 1751 (value != NULL && 1752 xmlStrcmp(value, (xmlChar *)proto) != 0)) { 1753 /* it doesn't match so continue */ 1754 xmlFree(value); 1755 value = NULL; 1756 continue; 1757 } 1758 } 1759 if (value != NULL) { 1760 xmlFree(value); 1761 value = NULL; 1762 } 1763 /* potential match */ 1764 if (sectype != NULL) { 1765 value = xmlGetProp(node, (xmlChar *)"sectype"); 1766 if (value != NULL && 1767 xmlStrcmp(value, (xmlChar *)sectype) == 0) { 1768 break; 1769 } 1770 } else { 1771 break; 1772 } 1773 } 1774 if (value != NULL) { 1775 xmlFree(value); 1776 value = NULL; 1777 } 1778 } 1779 if (value != NULL) 1780 xmlFree(value); 1781 return ((sa_security_t)node); 1782 } 1783 1784 /* 1785 * sa_get_next_security(security) 1786 * 1787 * Get the next security optionset if one exists. 1788 */ 1789 1790 sa_security_t 1791 sa_get_next_security(sa_security_t security) 1792 { 1793 xmlNodePtr node; 1794 1795 for (node = ((xmlNodePtr)security)->next; node != NULL; 1796 node = node->next) { 1797 if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 1798 break; 1799 } 1800 } 1801 return ((sa_security_t)node); 1802 } 1803 1804 /* 1805 * sa_get_property(optionset, prop) 1806 * 1807 * Get the property object with the name specified in prop from the 1808 * optionset. 1809 */ 1810 1811 sa_property_t 1812 sa_get_property(sa_optionset_t optionset, char *prop) 1813 { 1814 xmlNodePtr node = (xmlNodePtr)optionset; 1815 xmlChar *value = NULL; 1816 1817 if (optionset == NULL) 1818 return (NULL); 1819 1820 for (node = node->children; node != NULL; 1821 node = node->next) { 1822 if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 1823 if (prop == NULL) 1824 break; 1825 value = xmlGetProp(node, (xmlChar *)"type"); 1826 if (value != NULL && xmlStrcmp(value, (xmlChar *)prop) == 0) { 1827 break; 1828 } 1829 if (value != NULL) { 1830 xmlFree(value); 1831 value = NULL; 1832 } 1833 } 1834 } 1835 if (value != NULL) 1836 xmlFree(value); 1837 if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 1838 /* avoid a non option node -- it is possible to be a text node */ 1839 node = NULL; 1840 } 1841 return ((sa_property_t)node); 1842 } 1843 1844 /* 1845 * sa_get_next_property(property) 1846 * 1847 * Get the next property following the specified property. NULL if 1848 * this was the last. 1849 */ 1850 1851 sa_property_t 1852 sa_get_next_property(sa_property_t property) 1853 { 1854 xmlNodePtr node; 1855 1856 for (node = ((xmlNodePtr)property)->next; node != NULL; 1857 node = node->next) { 1858 if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 1859 break; 1860 } 1861 } 1862 return ((sa_property_t)node); 1863 } 1864 1865 /* 1866 * sa_set_share_description(share, content) 1867 * 1868 * Set the description of share to content. 1869 */ 1870 1871 int 1872 sa_set_share_description(sa_share_t share, char *content) 1873 { 1874 xmlNodePtr node; 1875 sa_group_t group; 1876 int ret = SA_OK; 1877 1878 for (node = ((xmlNodePtr)share)->children; node != NULL; 1879 node = node->next) { 1880 if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 1881 break; 1882 } 1883 } 1884 group = sa_get_parent_group(share); 1885 /* no existing description but want to add */ 1886 if (node == NULL && content != NULL) { 1887 /* add a description */ 1888 node = _sa_set_share_description(share, content); 1889 } else if (node != NULL && content != NULL) { 1890 /* update a description */ 1891 xmlNodeSetContent(node, (xmlChar *)content); 1892 } else if (node != NULL && content == NULL) { 1893 /* remove an existing description */ 1894 xmlUnlinkNode(node); 1895 xmlFreeNode(node); 1896 } 1897 if (group != NULL && is_persistent((sa_group_t)share)) 1898 ret = sa_commit_share(scf_handle, group, share); 1899 return (ret); 1900 } 1901 1902 /* 1903 * fixproblemchars(string) 1904 * 1905 * don't want any newline or tab characters in the text since these 1906 * could break display of data and legacy file formats. 1907 */ 1908 static void 1909 fixproblemchars(char *str) 1910 { 1911 int c; 1912 for (c = *str; c != '\0'; c = *++str) { 1913 if (c == '\t' || c == '\n') 1914 *str = ' '; 1915 else if (c == '"') 1916 *str = '\''; 1917 } 1918 } 1919 1920 /* 1921 * sa_get_share_description(share) 1922 * 1923 * Return the description text for the specified share if it 1924 * exists. NULL if no description exists. 1925 */ 1926 1927 char * 1928 sa_get_share_description(sa_share_t share) 1929 { 1930 xmlChar *description = NULL; 1931 xmlNodePtr node; 1932 1933 for (node = ((xmlNodePtr)share)->children; node != NULL; 1934 node = node->next) { 1935 if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 1936 break; 1937 } 1938 } 1939 if (node != NULL) { 1940 description = xmlNodeGetContent((xmlNodePtr)share); 1941 fixproblemchars((char *)description); 1942 } 1943 return ((char *)description); 1944 } 1945 1946 /* 1947 * sa_free(share_description(description) 1948 * 1949 * Free the description string. 1950 */ 1951 1952 void 1953 sa_free_share_description(char *description) 1954 { 1955 xmlFree((xmlChar *)description); 1956 } 1957 1958 /* 1959 * sa_create_optionset(group, proto) 1960 * 1961 * Create an optionset for the specified protocol in the specied 1962 * group. This is manifested as a property group within SMF. 1963 */ 1964 1965 sa_optionset_t 1966 sa_create_optionset(sa_group_t group, char *proto) 1967 { 1968 sa_optionset_t optionset; 1969 sa_group_t parent = group; 1970 1971 optionset = sa_get_optionset(group, proto); 1972 if (optionset != NULL) { 1973 /* can't have a duplicate protocol */ 1974 optionset = NULL; 1975 } else { 1976 optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 1977 NULL, 1978 (xmlChar *)"optionset", 1979 NULL); 1980 /* 1981 * only put to repository if on a group and we were 1982 * able to create an optionset. 1983 */ 1984 if (optionset != NULL) { 1985 char oname[256]; 1986 char *groupname; 1987 char *id = NULL; 1988 1989 if (sa_is_share(group)) 1990 parent = sa_get_parent_group((sa_share_t)group); 1991 1992 sa_set_optionset_attr(optionset, "type", proto); 1993 1994 if (sa_is_share(group)) { 1995 id = sa_get_share_attr((sa_share_t)group, "id"); 1996 } 1997 (void) sa_optionset_name(optionset, oname, 1998 sizeof (oname), id); 1999 groupname = sa_get_group_attr(parent, "name"); 2000 if (groupname != NULL && is_persistent(group)) { 2001 (void) sa_get_instance(scf_handle, groupname); 2002 sa_free_attr_string(groupname); 2003 (void) sa_create_pgroup(scf_handle, oname); 2004 } 2005 if (id != NULL) 2006 sa_free_attr_string(id); 2007 } 2008 } 2009 return (optionset); 2010 } 2011 2012 /* 2013 * sa_get_property_parent(property) 2014 * 2015 * Given a property, return the object it is a property of. This will 2016 * be an optionset of some type. 2017 */ 2018 2019 static sa_optionset_t 2020 sa_get_property_parent(sa_property_t property) 2021 { 2022 xmlNodePtr node = NULL; 2023 2024 if (property != NULL) { 2025 node = ((xmlNodePtr)property)->parent; 2026 } 2027 return ((sa_optionset_t)node); 2028 } 2029 2030 /* 2031 * sa_get_optionset_parent(optionset) 2032 * 2033 * Return the parent of the specified optionset. This could be a group 2034 * or a share. 2035 */ 2036 2037 static sa_group_t 2038 sa_get_optionset_parent(sa_optionset_t optionset) 2039 { 2040 xmlNodePtr node = NULL; 2041 2042 if (optionset != NULL) { 2043 node = ((xmlNodePtr)optionset)->parent; 2044 } 2045 return ((sa_group_t)node); 2046 } 2047 2048 /* 2049 * zfs_needs_update(share) 2050 * 2051 * In order to avoid making multiple updates to a ZFS share when 2052 * setting properties, the share attribute "changed" will be set to 2053 * true when a property is added or modifed. When done adding 2054 * properties, we can then detect that an update is needed. We then 2055 * clear the state here to detect additional changes. 2056 */ 2057 2058 static int 2059 zfs_needs_update(sa_share_t share) 2060 { 2061 char *attr; 2062 int result = 0; 2063 2064 attr = sa_get_share_attr(share, "changed"); 2065 if (attr != NULL) { 2066 sa_free_attr_string(attr); 2067 result = 1; 2068 } 2069 set_node_attr((void *)share, "changed", NULL); 2070 return (result); 2071 } 2072 2073 /* 2074 * zfs_set_update(share) 2075 * 2076 * Set the changed attribute of the share to true. 2077 */ 2078 2079 static void 2080 zfs_set_update(sa_share_t share) 2081 { 2082 set_node_attr((void *)share, "changed", "true"); 2083 } 2084 2085 /* 2086 * sa_commit_properties(optionset, clear) 2087 * 2088 * Check if SMF or ZFS config and either update or abort the pending 2089 * changes. 2090 */ 2091 2092 int 2093 sa_commit_properties(sa_optionset_t optionset, int clear) 2094 { 2095 sa_group_t group; 2096 sa_group_t parent; 2097 int zfs = 0; 2098 int needsupdate = 0; 2099 int ret = SA_OK; 2100 2101 group = sa_get_optionset_parent(optionset); 2102 if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 2103 /* only update ZFS if on a share */ 2104 parent = sa_get_parent_group(group); 2105 zfs++; 2106 if (parent != NULL && is_zfs_group(parent)) { 2107 needsupdate = zfs_needs_update(group); 2108 } else { 2109 zfs = 0; 2110 } 2111 } 2112 if (zfs) { 2113 if (!clear && needsupdate) 2114 ret = sa_zfs_update((sa_share_t)group); 2115 } else { 2116 if (clear) 2117 (void) sa_abort_transaction(scf_handle); 2118 else 2119 ret = sa_end_transaction(scf_handle); 2120 } 2121 return (ret); 2122 } 2123 2124 /* 2125 * sa_destroy_optionset(optionset) 2126 * 2127 * Remove the optionset from its group. Update the repostory to 2128 * reflect this change. 2129 */ 2130 2131 int 2132 sa_destroy_optionset(sa_optionset_t optionset) 2133 { 2134 char name[256]; 2135 int len; 2136 int ret; 2137 char *id = NULL; 2138 sa_group_t group; 2139 int ispersist = 1; 2140 2141 /* now delete the prop group */ 2142 group = sa_get_optionset_parent(optionset); 2143 if (group != NULL && sa_is_share(group)) { 2144 ispersist = is_persistent(group); 2145 id = sa_get_share_attr((sa_share_t)group, "id"); 2146 } 2147 if (ispersist) { 2148 len = sa_optionset_name(optionset, name, sizeof (name), id); 2149 if (len > 0) { 2150 ret = sa_delete_pgroup(scf_handle, name); 2151 } 2152 } 2153 xmlUnlinkNode((xmlNodePtr)optionset); 2154 xmlFreeNode((xmlNodePtr)optionset); 2155 if (id != NULL) 2156 sa_free_attr_string(id); 2157 return (ret); 2158 } 2159 2160 /* private to the implementation */ 2161 int 2162 _sa_remove_optionset(sa_optionset_t optionset) 2163 { 2164 int ret = SA_OK; 2165 2166 xmlUnlinkNode((xmlNodePtr)optionset); 2167 xmlFreeNode((xmlNodePtr)optionset); 2168 return (ret); 2169 } 2170 2171 /* 2172 * sa_create_security(group, sectype, proto) 2173 * 2174 * Create a security optionset (one that has a type name and a 2175 * proto). Security is left over from a pure NFS implementation. The 2176 * naming will change in the future when the API is released. 2177 */ 2178 sa_security_t 2179 sa_create_security(sa_group_t group, char *sectype, char *proto) 2180 { 2181 sa_security_t security; 2182 char *id = NULL; 2183 sa_group_t parent; 2184 char *groupname = NULL; 2185 2186 if (group != NULL && sa_is_share(group)) { 2187 id = sa_get_share_attr((sa_share_t)group, "id"); 2188 parent = sa_get_parent_group(group); 2189 if (parent != NULL) 2190 groupname = sa_get_group_attr(parent, "name"); 2191 } else if (group != NULL) { 2192 groupname = sa_get_group_attr(group, "name"); 2193 } 2194 2195 security = sa_get_security(group, sectype, proto); 2196 if (security != NULL) { 2197 /* can't have a duplicate security option */ 2198 security = NULL; 2199 } else { 2200 security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 2201 NULL, 2202 (xmlChar *)"security", 2203 NULL); 2204 if (security != NULL) { 2205 char oname[256]; 2206 sa_set_security_attr(security, "type", proto); 2207 2208 sa_set_security_attr(security, "sectype", sectype); 2209 (void) sa_security_name(security, oname, 2210 sizeof (oname), id); 2211 if (groupname != NULL && is_persistent(group)) { 2212 (void) sa_get_instance(scf_handle, groupname); 2213 (void) sa_create_pgroup(scf_handle, oname); 2214 } 2215 } 2216 } 2217 if (groupname != NULL) 2218 sa_free_attr_string(groupname); 2219 return (security); 2220 } 2221 2222 /* 2223 * sa_destroy_security(security) 2224 * 2225 * Remove the specified optionset from the document and the 2226 * configuration. 2227 */ 2228 2229 int 2230 sa_destroy_security(sa_security_t security) 2231 { 2232 char name[256]; 2233 int len; 2234 int ret = SA_OK; 2235 char *id = NULL; 2236 sa_group_t group; 2237 int iszfs = 0; 2238 int ispersist = 1; 2239 2240 group = sa_get_optionset_parent(security); 2241 2242 if (group != NULL) 2243 iszfs = sa_group_is_zfs(group); 2244 2245 if (group != NULL && !iszfs) { 2246 if (sa_is_share(group)) 2247 ispersist = is_persistent(group); 2248 id = sa_get_share_attr((sa_share_t)group, "id"); 2249 } 2250 if (ispersist) { 2251 len = sa_security_name(security, name, sizeof (name), id); 2252 if (!iszfs && len > 0) { 2253 ret = sa_delete_pgroup(scf_handle, name); 2254 } 2255 } 2256 xmlUnlinkNode((xmlNodePtr)security); 2257 xmlFreeNode((xmlNodePtr)security); 2258 if (iszfs) { 2259 ret = sa_zfs_update(group); 2260 } 2261 if (id != NULL) 2262 sa_free_attr_string(id); 2263 return (ret); 2264 } 2265 2266 /* 2267 * sa_get_security_attr(optionset, tag) 2268 * 2269 * Return the specified attribute value from the optionset. 2270 */ 2271 2272 char * 2273 sa_get_security_attr(sa_property_t optionset, char *tag) 2274 { 2275 return (get_node_attr((void *)optionset, tag)); 2276 2277 } 2278 2279 /* 2280 * sa_set_security_attr(optionset, tag, value) 2281 * 2282 * Set the optioset attribute specied by tag to the specified value. 2283 */ 2284 2285 void 2286 sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 2287 { 2288 set_node_attr((void *)optionset, tag, value); 2289 } 2290 2291 /* 2292 * is_nodetype(node, type) 2293 * 2294 * Check to see if node is of the type specified. 2295 */ 2296 2297 static int 2298 is_nodetype(void *node, char *type) 2299 { 2300 return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 2301 } 2302 2303 /* 2304 * sa_set_prop_by_prop(optionset, group, prop, type) 2305 * 2306 * Add/remove/update the specified property prop into the optionset or 2307 * share. If a share, sort out which property group based on GUID. In 2308 * all cases, the appropriate transaction is set (or ZFS share is 2309 * marked as needing an update) 2310 */ 2311 2312 #define SA_PROP_OP_REMOVE 1 2313 #define SA_PROP_OP_ADD 2 2314 #define SA_PROP_OP_UPDATE 3 2315 static int 2316 sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 2317 sa_property_t prop, int type) 2318 { 2319 char *name; 2320 char *valstr; 2321 int ret = SA_OK; 2322 scf_transaction_entry_t *entry; 2323 scf_value_t *value; 2324 int opttype; /* 1 == optionset, 0 == security */ 2325 char *id = NULL; 2326 int iszfs = 0; 2327 int isshare = 0; 2328 sa_group_t parent = NULL; 2329 2330 if (!is_persistent(group)) { 2331 /* 2332 * if the group/share is not persistent we don't need 2333 * to do anything here 2334 */ 2335 return (SA_OK); 2336 } 2337 name = sa_get_property_attr(prop, "type"); 2338 valstr = sa_get_property_attr(prop, "value"); 2339 entry = scf_entry_create(scf_handle->handle); 2340 opttype = is_nodetype((void *)optionset, "optionset"); 2341 2342 if (valstr != NULL && entry != NULL) { 2343 if (sa_is_share(group)) { 2344 isshare = 1; 2345 parent = sa_get_parent_group(group); 2346 if (parent != NULL) { 2347 iszfs = is_zfs_group(parent); 2348 } 2349 } else { 2350 iszfs = is_zfs_group(group); 2351 } 2352 if (!iszfs) { 2353 if (scf_handle->trans == NULL) { 2354 char oname[256]; 2355 char *groupname = NULL; 2356 if (isshare) { 2357 if (parent != NULL) { 2358 groupname = sa_get_group_attr(parent, "name"); 2359 } 2360 id = sa_get_share_attr((sa_share_t)group, "id"); 2361 } else { 2362 groupname = sa_get_group_attr(group, "name"); 2363 } 2364 if (groupname != NULL) { 2365 ret = sa_get_instance(scf_handle, groupname); 2366 sa_free_attr_string(groupname); 2367 } 2368 if (opttype) 2369 (void) sa_optionset_name(optionset, oname, 2370 sizeof (oname), id); 2371 else 2372 (void) sa_security_name(optionset, oname, 2373 sizeof (oname), id); 2374 ret = sa_start_transaction(scf_handle, oname); 2375 } 2376 if (ret == SA_OK) { 2377 switch (type) { 2378 case SA_PROP_OP_REMOVE: 2379 ret = scf_transaction_property_delete(scf_handle->trans, 2380 entry, 2381 name); 2382 break; 2383 case SA_PROP_OP_ADD: 2384 case SA_PROP_OP_UPDATE: 2385 value = scf_value_create(scf_handle->handle); 2386 if (value != NULL) { 2387 if (type == SA_PROP_OP_ADD) 2388 ret = scf_transaction_property_new( 2389 scf_handle->trans, 2390 entry, 2391 name, 2392 SCF_TYPE_ASTRING); 2393 else 2394 ret = scf_transaction_property_change( 2395 scf_handle->trans, 2396 entry, 2397 name, 2398 SCF_TYPE_ASTRING); 2399 if (ret == 0) { 2400 ret = scf_value_set_astring(value, valstr); 2401 if (ret == 0) 2402 ret = scf_entry_add_value(entry, value); 2403 if (ret != 0) { 2404 scf_value_destroy(value); 2405 ret = SA_SYSTEM_ERR; 2406 } 2407 } else { 2408 scf_entry_destroy(entry); 2409 ret = SA_SYSTEM_ERR; 2410 } 2411 break; 2412 } 2413 } 2414 } 2415 } else { 2416 /* 2417 * ZFS update. The calling function would have updated 2418 * the internal XML structure. Just need to flag it as 2419 * changed for ZFS. 2420 */ 2421 zfs_set_update((sa_share_t)group); 2422 } 2423 } 2424 2425 if (name != NULL) 2426 sa_free_attr_string(name); 2427 if (valstr != NULL) 2428 sa_free_attr_string(valstr); 2429 else if (entry != NULL) 2430 scf_entry_destroy(entry); 2431 2432 if (ret == -1) 2433 ret = SA_SYSTEM_ERR; 2434 2435 return (ret); 2436 } 2437 2438 /* 2439 * sa_create_property(name, value) 2440 * 2441 * Create a new property with the specified name and value. 2442 */ 2443 2444 sa_property_t 2445 sa_create_property(char *name, char *value) 2446 { 2447 xmlNodePtr node; 2448 2449 node = xmlNewNode(NULL, (xmlChar *)"option"); 2450 if (node != NULL) { 2451 xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 2452 xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 2453 } 2454 return ((sa_property_t)node); 2455 } 2456 2457 /* 2458 * sa_add_property(object, property) 2459 * 2460 * Add the specified property to the object. Issue the appropriate 2461 * transaction or mark a ZFS object as needing an update. 2462 */ 2463 2464 int 2465 sa_add_property(void *object, sa_property_t property) 2466 { 2467 int ret = SA_OK; 2468 sa_group_t parent; 2469 sa_group_t group; 2470 char *proto; 2471 2472 proto = sa_get_optionset_attr(object, "type"); 2473 if (property != NULL) { 2474 if ((ret = sa_valid_property(object, proto, property)) == SA_OK) { 2475 property = (sa_property_t)xmlAddChild((xmlNodePtr)object, 2476 (xmlNodePtr)property); 2477 } else { 2478 if (proto != NULL) 2479 sa_free_attr_string(proto); 2480 return (ret); 2481 } 2482 } 2483 2484 if (proto != NULL) 2485 sa_free_attr_string(proto); 2486 2487 parent = sa_get_parent_group(object); 2488 if (!is_persistent(parent)) { 2489 return (ret); 2490 } 2491 2492 if (sa_is_share(parent)) 2493 group = sa_get_parent_group(parent); 2494 else 2495 group = parent; 2496 2497 if (property == NULL) 2498 ret = SA_NO_MEMORY; 2499 else { 2500 char oname[256]; 2501 2502 if (!is_zfs_group(group)) { 2503 char *id = NULL; 2504 if (sa_is_share((sa_group_t)parent)) { 2505 id = sa_get_share_attr((sa_share_t)parent, "id"); 2506 } 2507 if (scf_handle->trans == NULL) { 2508 if (is_nodetype(object, "optionset")) 2509 (void) sa_optionset_name((sa_optionset_t)object, 2510 oname, sizeof (oname), id); 2511 else 2512 (void) sa_security_name((sa_optionset_t)object, 2513 oname, sizeof (oname), id); 2514 ret = sa_start_transaction(scf_handle, oname); 2515 } 2516 if (ret == SA_OK) { 2517 char *name; 2518 char *value; 2519 name = sa_get_property_attr(property, "type"); 2520 value = sa_get_property_attr(property, "value"); 2521 if (name != NULL && value != NULL) { 2522 if (scf_handle->scf_state == SCH_STATE_INIT) 2523 ret = sa_set_property(scf_handle, name, value); 2524 } else 2525 ret = SA_CONFIG_ERR; 2526 if (name != NULL) 2527 sa_free_attr_string(name); 2528 if (value != NULL) 2529 sa_free_attr_string(value); 2530 } 2531 if (id != NULL) 2532 sa_free_attr_string(id); 2533 } else { 2534 /* 2535 * ZFS is a special case. We do want to allow editing 2536 * property/security lists since we can have a better 2537 * syntax and we also want to keep things consistent 2538 * when possible. 2539 * 2540 * Right now, we defer until the sa_commit_properties 2541 * so we can get them all at once. We do need to mark 2542 * the share as "changed" 2543 */ 2544 zfs_set_update((sa_share_t)parent); 2545 } 2546 } 2547 return (ret); 2548 } 2549 2550 /* 2551 * sa_remove_property(property) 2552 * 2553 * Remove the specied property from its containing object. Update the 2554 * repository as appropriate. 2555 */ 2556 2557 int 2558 sa_remove_property(sa_property_t property) 2559 { 2560 int ret = SA_OK; 2561 2562 if (property != NULL) { 2563 sa_optionset_t optionset; 2564 sa_group_t group; 2565 optionset = sa_get_property_parent(property); 2566 if (optionset != NULL) { 2567 group = sa_get_optionset_parent(optionset); 2568 if (group != NULL) { 2569 ret = sa_set_prop_by_prop(optionset, group, property, 2570 SA_PROP_OP_REMOVE); 2571 } 2572 } 2573 xmlUnlinkNode((xmlNodePtr)property); 2574 xmlFreeNode((xmlNodePtr)property); 2575 } else { 2576 ret = SA_NO_SUCH_PROP; 2577 } 2578 return (ret); 2579 } 2580 2581 /* 2582 * sa_update_property(property, value) 2583 * 2584 * Update the specified property to the new value. If value is NULL, 2585 * we currently treat this as a remove. 2586 */ 2587 2588 int 2589 sa_update_property(sa_property_t property, char *value) 2590 { 2591 int ret = SA_OK; 2592 if (value == NULL) { 2593 return (sa_remove_property(property)); 2594 } else { 2595 sa_optionset_t optionset; 2596 sa_group_t group; 2597 set_node_attr((void *)property, "value", value); 2598 optionset = sa_get_property_parent(property); 2599 if (optionset != NULL) { 2600 group = sa_get_optionset_parent(optionset); 2601 if (group != NULL) { 2602 ret = sa_set_prop_by_prop(optionset, group, property, 2603 SA_PROP_OP_UPDATE); 2604 } 2605 } else { 2606 ret = SA_NO_SUCH_PROP; 2607 } 2608 } 2609 return (ret); 2610 } 2611 2612 /* 2613 * _sa_get_next_error(node) 2614 * 2615 * Get the next (first if node==NULL) error node in the 2616 * document. "error" nodes are added if there were syntax errors 2617 * during parsing of the /etc/dfs/dfstab file. They are preserved in 2618 * comments and recreated in the doc on the next parse. 2619 */ 2620 2621 xmlNodePtr 2622 _sa_get_next_error(xmlNodePtr node) 2623 { 2624 if (node == NULL) { 2625 for (node = sa_config_tree->xmlChildrenNode; 2626 node != NULL; node = node->next) 2627 if (xmlStrcmp(node->name, (xmlChar *)"error") == 0) 2628 return (node); 2629 } else { 2630 for (node = node->next; node != NULL; node = node->next) 2631 if (xmlStrcmp(node->name, (xmlChar *)"error") == 0) 2632 return (node); 2633 } 2634 return (node); 2635 } 2636 2637 /* 2638 * sa_get_protocol_property(propset, prop) 2639 * 2640 * Get the specified protocol specific property. These are global to 2641 * the protocol and not specific to a group or share. 2642 */ 2643 2644 sa_property_t 2645 sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 2646 { 2647 xmlNodePtr node = (xmlNodePtr)propset; 2648 xmlChar *value = NULL; 2649 2650 for (node = node->children; node != NULL; 2651 node = node->next) { 2652 if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 2653 if (prop == NULL) 2654 break; 2655 value = xmlGetProp(node, (xmlChar *)"type"); 2656 if (value != NULL && 2657 xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 2658 break; 2659 } 2660 if (value != NULL) { 2661 xmlFree(value); 2662 value = NULL; 2663 } 2664 } 2665 } 2666 if (value != NULL) 2667 xmlFree(value); 2668 if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 2669 /* avoid a non option node -- it is possible to be a text node */ 2670 node = NULL; 2671 } 2672 return ((sa_property_t)node); 2673 } 2674 2675 /* 2676 * sa_get_next_protocol_property(prop) 2677 * 2678 * Get the next protocol specific property in the list. 2679 */ 2680 2681 sa_property_t 2682 sa_get_next_protocol_property(sa_property_t prop) 2683 { 2684 xmlNodePtr node; 2685 2686 for (node = ((xmlNodePtr)prop)->next; node != NULL; 2687 node = node->next) { 2688 if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 2689 break; 2690 } 2691 } 2692 return ((sa_property_t)node); 2693 } 2694 2695 /* 2696 * sa_set_protocol_property(prop, value) 2697 * 2698 * Set the specified property to have the new value. The protocol 2699 * specific plugin will then be called to update the property. 2700 */ 2701 2702 int 2703 sa_set_protocol_property(sa_property_t prop, char *value) 2704 { 2705 sa_protocol_properties_t propset; 2706 char *proto; 2707 int ret = SA_INVALID_PROTOCOL; 2708 2709 propset = ((xmlNodePtr)prop)->parent; 2710 if (propset != NULL) { 2711 proto = sa_get_optionset_attr(propset, "type"); 2712 if (proto != NULL) { 2713 set_node_attr((xmlNodePtr)prop, "value", value); 2714 ret = sa_proto_set_property(proto, prop); 2715 sa_free_attr_string(proto); 2716 } 2717 } 2718 return (ret); 2719 } 2720 2721 /* 2722 * sa_add_protocol_property(propset, prop) 2723 * 2724 * Add a new property to the protocol sepcific property set. 2725 */ 2726 2727 int 2728 sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 2729 { 2730 xmlNodePtr node; 2731 2732 /* should check for legitimacy */ 2733 node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 2734 if (node != NULL) 2735 return (SA_OK); 2736 return (SA_NO_MEMORY); 2737 } 2738 2739 /* 2740 * sa_create_protocol_properties(proto) 2741 * 2742 * Create a protocol specifity property set. 2743 */ 2744 2745 sa_protocol_properties_t 2746 sa_create_protocol_properties(char *proto) 2747 { 2748 xmlNodePtr node; 2749 node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 2750 if (node != NULL) { 2751 xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2752 } 2753 return (node); 2754 } 2755