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 2006 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 * core library for common functions across all config store types 31 * and file systems to be exported. This includes legacy dfstab/sharetab 32 * parsing. Need to eliminate XML where possible. 33 */ 34 35 #include <stdio.h> 36 #include <string.h> 37 #include <ctype.h> 38 #include <unistd.h> 39 #include <limits.h> 40 #include <errno.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <libxml/parser.h> 44 #include <libxml/tree.h> 45 #include "libshare.h" 46 #include "libshare_impl.h" 47 #include "libfsmgt.h" 48 #include <fcntl.h> 49 #include <sys/stat.h> 50 #include <grp.h> 51 #include <limits.h> 52 #include <sys/param.h> 53 #include <signal.h> 54 #include <libintl.h> 55 56 #include "sharetab.h" 57 58 #define DFSTAB_NOTICE_LINES 5 59 static char *notice[DFSTAB_NOTICE_LINES] = { 60 "# Do not modify this file directly.\n", 61 "# Use the sharemgr(1m) command for all share management\n", 62 "# This file is reconstructed and only maintained for backward\n", 63 "# compatibility. Configuration lines could be lost.\n", 64 "#\n" 65 }; 66 67 #define STRNCAT(x, y, z) (xmlChar *)strncat((char *)x, (char *)y, z) 68 69 /* will be much smaller, but this handles bad syntax in the file */ 70 #define MAXARGSFORSHARE 256 71 72 /* used internally only */ 73 typedef 74 struct sharelist { 75 struct sharelist *next; 76 int persist; 77 char *path; 78 char *resource; 79 char *fstype; 80 char *options; 81 char *description; 82 char *group; 83 char *origline; 84 int lineno; 85 } xfs_sharelist_t; 86 static void parse_dfstab(char *, xmlNodePtr); 87 extern char *get_token(char *); 88 static void dfs_free_list(xfs_sharelist_t *); 89 /* prototypes */ 90 void getlegacyconfig(char *, xmlNodePtr *); 91 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *); 92 extern xmlNodePtr _sa_get_next_error(xmlNodePtr); 93 extern sa_group_t _sa_create_group(char *); 94 static void outdfstab(FILE *, xfs_sharelist_t *); 95 extern int _sa_remove_optionset(sa_optionset_t); 96 extern int set_node_share(void *, char *, char *); 97 extern void set_node_attr(void *, char *, char *); 98 99 /* 100 * alloc_sharelist() 101 * 102 * allocator function to return an zfs_sharelist_t 103 */ 104 105 static xfs_sharelist_t * 106 alloc_sharelist() 107 { 108 xfs_sharelist_t *item; 109 110 item = (xfs_sharelist_t *)malloc(sizeof (xfs_sharelist_t)); 111 if (item != NULL) 112 (void) memset(item, '\0', sizeof (xfs_sharelist_t)); 113 return (item); 114 } 115 116 /* 117 * fix_notice(list) 118 * 119 * Look at the beginning of the current /etc/dfs/dfstab file and add 120 * the do not modify notice if it doesn't exist. 121 */ 122 123 static xfs_sharelist_t * 124 fix_notice(xfs_sharelist_t *list) 125 { 126 xfs_sharelist_t *item, *prev; 127 int i; 128 129 if (list == NULL) { 130 /* zero length dfstab */ 131 list = alloc_sharelist(); 132 if (list == NULL) 133 return (NULL); 134 list->description = strdup("#\n"); 135 } 136 if (list->path == NULL && list->description != NULL && 137 strcmp(list->description, notice[0]) != 0) { 138 for (prev = NULL, i = 0; i < DFSTAB_NOTICE_LINES; i++) { 139 item = alloc_sharelist(); 140 if (item != NULL) { 141 item->description = strdup(notice[i]); 142 if (prev == NULL) { 143 item->next = list; 144 prev = item; 145 list = item; 146 } else { 147 item->next = prev->next; 148 prev->next = item; 149 prev = item; 150 } 151 } 152 } 153 } 154 return (list); 155 } 156 157 /* 158 * getdfstab(dfs) 159 * 160 * Returns an zfs_sharelist_t list of lines from the dfstab file 161 * pointed to by the FILE pointer dfs. Each entry is parsed and the 162 * original line is also preserved. Used in parsing and updating the 163 * dfstab file. 164 */ 165 166 static xfs_sharelist_t * 167 getdfstab(FILE *dfs) 168 { 169 char buff[_POSIX_ARG_MAX]; /* reasonable size given syntax of share */ 170 char *bp; 171 char *token; 172 char *args[MAXARGSFORSHARE]; 173 int argc; 174 int c; 175 static int line = 0; 176 xfs_sharelist_t *item = NULL, *first = NULL, *last; 177 178 if (dfs != NULL) { 179 first = NULL; 180 line = 0; 181 while (fgets(buff, sizeof (buff), dfs) != NULL) { 182 line++; 183 bp = buff; 184 if (buff[0] == '#') { 185 item = alloc_sharelist(); 186 if (item != NULL) { 187 /* if no path, then comment */ 188 item->lineno = line; 189 item->description = strdup(buff); 190 if (first == NULL) { 191 first = item; 192 last = item; 193 } else { 194 last->next = item; 195 last = item; 196 } 197 } else { 198 break; 199 } 200 continue; 201 } else if (buff[0] == '\n') { 202 continue; 203 } 204 optind = 1; 205 item = alloc_sharelist(); 206 if (item == NULL) { 207 break; 208 } else if (first == NULL) { 209 first = item; 210 last = item; 211 } else { 212 last->next = item; 213 last = item; 214 } 215 item->lineno = line; 216 item->origline = strdup(buff); 217 (void) get_token(NULL); /* reset to new pointers */ 218 argc = 0; 219 while ((token = get_token(bp)) != NULL) { 220 if (argc < MAXARGSFORSHARE) { 221 args[argc++] = token; 222 } 223 } 224 while ((c = getopt(argc, args, "F:o:d:pg:")) != -1) { 225 switch (c) { 226 case 'p': 227 item->persist = 1; 228 break; 229 case 'F': 230 item->fstype = strdup(optarg); 231 break; 232 case 'o': 233 item->options = strdup(optarg); 234 break; 235 case 'd': 236 item->description = strdup(optarg); 237 break; 238 case 'g': 239 item->group = strdup(optarg); 240 break; 241 default: 242 break; 243 } 244 } 245 if (optind < argc) { 246 item->path = strdup(args[optind]); 247 optind++; 248 if (optind < argc) { 249 char *resource; 250 char *optgroup; 251 /* resource and/or groupname */ 252 resource = args[optind]; 253 optgroup = strchr(resource, '@'); 254 if (optgroup != NULL) { 255 *optgroup++ = '\0'; 256 } 257 if (optgroup != NULL) 258 item->group = strdup(optgroup); 259 if (resource != NULL && strlen(resource) > 0) 260 item->resource = strdup(resource); 261 } 262 } 263 } 264 if (item != NULL && item->fstype == NULL) 265 item->fstype = strdup("nfs"); /* this is the default */ 266 } 267 first = fix_notice(first); 268 return (first); 269 } 270 271 /* 272 * finddfsentry(list, path) 273 * 274 * Look for path in the zfs_sharelist_t list and return the entry if it 275 * exists. 276 */ 277 278 static xfs_sharelist_t * 279 finddfsentry(xfs_sharelist_t *list, char *path) 280 { 281 xfs_sharelist_t *item; 282 283 for (item = list; item != NULL; item = item->next) { 284 if (item->path != NULL && strcmp(item->path, path) == 0) 285 return (item); 286 } 287 return (NULL); 288 } 289 290 /* 291 * remdfsentry(list, path, proto) 292 * 293 * Remove the specified path (with protocol) from the list. This will 294 * remove it from dfstab when the file is rewritten. 295 */ 296 297 static xfs_sharelist_t * 298 remdfsentry(xfs_sharelist_t *list, char *path, char *proto) 299 { 300 xfs_sharelist_t *item, *prev = NULL; 301 302 303 for (item = prev = list; item != NULL; item = item->next) { 304 /* skip comment entry but don't lose it */ 305 if (item->path == NULL) { 306 prev = item; 307 continue; 308 } 309 /* if proto is NULL, remove all protocols */ 310 if (proto == NULL || (strcmp(item->path, path) == 0 && 311 (item->fstype != NULL && strcmp(item->fstype, proto) == 0))) 312 break; 313 if (item->fstype == NULL && 314 (proto == NULL || strcmp(proto, "nfs") == 0)) 315 break; 316 prev = item; 317 } 318 if (item != NULL) { 319 if (item == prev) { 320 list = item->next; /* this must be the first one */ 321 } else { 322 prev->next = item->next; 323 } 324 item->next = NULL; 325 dfs_free_list(item); 326 } 327 return (list); 328 } 329 330 /* 331 * remdfsline(list, line) 332 * 333 * Remove the line specified from the list. 334 */ 335 336 static xfs_sharelist_t * 337 remdfsline(xfs_sharelist_t *list, char *line) 338 { 339 xfs_sharelist_t *item, *prev = NULL; 340 341 for (item = prev = list; item != NULL; item = item->next) { 342 /* skip comment entry but don't lose it */ 343 if (item->path == NULL) { 344 prev = item; 345 continue; 346 } 347 if (strcmp(item->origline, line) == 0) { 348 break; 349 } 350 prev = item; 351 } 352 if (item != NULL) { 353 if (item == prev) { 354 list = item->next; /* this must be the first one */ 355 } else { 356 prev->next = item->next; 357 } 358 item->next = NULL; 359 dfs_free_list(item); 360 } 361 return (list); 362 } 363 364 /* 365 * adddfsentry(list, share, proto) 366 * 367 * Add an entry to the dfstab list for share (relative to proto). This 368 * is used to update dfstab for legacy purposes. 369 */ 370 371 static xfs_sharelist_t * 372 adddfsentry(xfs_sharelist_t *list, sa_share_t share, char *proto) 373 { 374 xfs_sharelist_t *item, *tmp; 375 sa_group_t parent; 376 char *groupname; 377 378 item = alloc_sharelist(); 379 if (item != NULL) { 380 parent = sa_get_parent_group(share); 381 groupname = sa_get_group_attr(parent, "name"); 382 if (strcmp(groupname, "default") == 0) { 383 sa_free_attr_string(groupname); 384 groupname = NULL; 385 } 386 item->path = sa_get_share_attr(share, "path"); 387 item->resource = sa_get_share_attr(share, "resource"); 388 item->group = groupname; 389 item->fstype = strdup(proto); 390 item->options = sa_proto_legacy_format(proto, share, 1); 391 if (item->options != NULL && strlen(item->options) == 0) { 392 free(item->options); 393 item->options = NULL; 394 } 395 item->description = sa_get_share_description(share); 396 if (item->description != NULL && strlen(item->description) == 0) { 397 sa_free_share_description(item->description); 398 item->description = NULL; 399 } 400 if (list == NULL) { 401 list = item; 402 } else { 403 for (tmp = list; tmp->next != NULL; tmp = tmp->next) 404 /* do nothing */; 405 tmp->next = item; 406 } 407 } 408 return (list); 409 } 410 411 /* 412 * outdfstab(dfstab, list) 413 * 414 * Output the list to dfstab making sure the file is truncated. 415 * Comments and errors are preserved. 416 */ 417 418 static void 419 outdfstab(FILE *dfstab, xfs_sharelist_t *list) 420 { 421 xfs_sharelist_t *item; 422 423 (void) ftruncate(fileno(dfstab), 0); 424 425 for (item = list; item != NULL; item = item->next) { 426 if (item->path != NULL) { 427 if (*item->path == '/') 428 (void) fprintf(dfstab, "share %s%s%s%s%s%s%s %s%s%s%s%s\n", 429 (item->fstype != NULL) ? "-F " : "", 430 (item->fstype != NULL) ? item->fstype : "", 431 (item->options != NULL) ? " -o " : "", 432 (item->options != NULL) ? item->options : "", 433 (item->description != NULL) ? " -d \"" : "", 434 (item->description != NULL) ? 435 item->description : "", 436 (item->description != NULL) ? "\"" : "", 437 item->path, 438 ((item->resource != NULL) || 439 (item->group != NULL)) ? " " : "", 440 (item->resource != NULL) ? item->resource : "", 441 item->group != NULL ? "@" : "", 442 item->group != NULL ? item->group : ""); 443 else 444 (void) fprintf(dfstab, "%s", item->origline); 445 } else { 446 if (item->description != NULL) { 447 (void) fprintf(dfstab, "%s", item->description); 448 } else { 449 (void) fprintf(dfstab, "%s", item->origline); 450 } 451 } 452 } 453 } 454 455 /* 456 * open_dfstab(file) 457 * 458 * Open the specified dfstab file. If the owner/group/perms are wrong, 459 * fix them. 460 */ 461 462 static FILE * 463 open_dfstab(char *file) 464 { 465 struct group *grp; 466 struct group group; 467 char *buff; 468 int grsize; 469 FILE *dfstab; 470 471 dfstab = fopen(file, "r+"); 472 if (dfstab == NULL) { 473 dfstab = fopen(file, "w+"); 474 } 475 if (dfstab != NULL) { 476 grsize = sysconf(_SC_GETGR_R_SIZE_MAX); 477 buff = malloc(grsize); 478 if (buff != NULL) 479 grp = getgrnam_r(SA_DEFAULT_FILE_GRP, &group, buff, grsize); 480 else 481 grp = getgrnam(SA_DEFAULT_FILE_GRP); /* take the risk */ 482 (void) fchmod(fileno(dfstab), 0644); 483 (void) fchown(fileno(dfstab), 0, 484 grp != NULL ? grp->gr_gid : 3); 485 if (buff != NULL) 486 free(buff); 487 rewind(dfstab); 488 } 489 return (dfstab); 490 } 491 492 /* 493 * sa_comment_line(line, err) 494 * 495 * Add a comment to the dfstab file with err as a prefix to the 496 * original line. 497 */ 498 499 static void 500 sa_comment_line(char *line, char *err) 501 { 502 FILE *dfstab; 503 xfs_sharelist_t *list; 504 sigset_t old, new; 505 506 dfstab = open_dfstab(SA_LEGACY_DFSTAB); 507 if (dfstab != NULL) { 508 (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 509 (void) sigprocmask(SIG_BLOCK, NULL, &new); 510 (void) sigaddset(&new, SIGHUP); 511 (void) sigaddset(&new, SIGINT); 512 (void) sigaddset(&new, SIGQUIT); 513 (void) sigaddset(&new, SIGTSTP); 514 (void) sigprocmask(SIG_SETMASK, &new, &old); 515 (void) lockf(fileno(dfstab), F_LOCK, 0); 516 list = getdfstab(dfstab); 517 rewind(dfstab); 518 (void) remdfsline(list, line); 519 outdfstab(dfstab, list); 520 (void) fprintf(dfstab, "# Error: %s: %s", err, line); 521 (void) fsync(fileno(dfstab)); 522 (void) lockf(fileno(dfstab), F_ULOCK, 0); 523 (void) fclose(dfstab); 524 (void) sigprocmask(SIG_SETMASK, &old, NULL); 525 if (list != NULL) 526 dfs_free_list(list); 527 } 528 } 529 530 /* 531 * sa_delete_legacy(share) 532 * 533 * Delete the specified share from the legacy config file. 534 */ 535 536 int 537 sa_delete_legacy(sa_share_t share) 538 { 539 FILE *dfstab; 540 int err; 541 int ret = SA_OK; 542 xfs_sharelist_t *list; 543 char *path; 544 sa_optionset_t optionset; 545 sa_group_t parent; 546 sigset_t old, new; 547 548 dfstab = open_dfstab(SA_LEGACY_DFSTAB); 549 if (dfstab != NULL) { 550 (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 551 (void) sigprocmask(SIG_BLOCK, NULL, &new); 552 (void) sigaddset(&new, SIGHUP); 553 (void) sigaddset(&new, SIGINT); 554 (void) sigaddset(&new, SIGQUIT); 555 (void) sigaddset(&new, SIGTSTP); 556 (void) sigprocmask(SIG_SETMASK, &new, &old); 557 path = sa_get_share_attr(share, "path"); 558 parent = sa_get_parent_group(share); 559 if (parent != NULL) { 560 (void) lockf(fileno(dfstab), F_LOCK, 0); 561 list = getdfstab(dfstab); 562 rewind(dfstab); 563 for (optionset = sa_get_optionset(parent, NULL); 564 optionset != NULL; 565 optionset = sa_get_next_optionset(optionset)) { 566 char *proto = sa_get_optionset_attr(optionset, "type"); 567 if (list != NULL && proto != NULL) 568 list = remdfsentry(list, path, proto); 569 if (proto == NULL) 570 ret = SA_NO_MEMORY; 571 /* 572 * may want to only do the dfstab if this call 573 * returns NOT IMPLEMENTED but it shouldn't 574 * hurt. 575 */ 576 if (ret == SA_OK) { 577 err = sa_proto_delete_legacy(proto, share); 578 if (err != SA_NOT_IMPLEMENTED) 579 ret = err; 580 } 581 if (proto != NULL) 582 sa_free_attr_string(proto); 583 } 584 outdfstab(dfstab, list); 585 if (list != NULL) 586 dfs_free_list(list); 587 (void) fflush(dfstab); 588 (void) lockf(fileno(dfstab), F_ULOCK, 0); 589 } 590 (void) fsync(fileno(dfstab)); 591 (void) sigprocmask(SIG_SETMASK, &old, NULL); 592 (void) fclose(dfstab); 593 sa_free_attr_string(path); 594 } else { 595 if (errno == EACCES || errno == EPERM) { 596 ret = SA_NO_PERMISSION; 597 } else { 598 ret = SA_CONFIG_ERR; 599 } 600 } 601 return (ret); 602 } 603 604 /* 605 * sa_update_legacy(share, proto) 606 * 607 * There is an assumption that dfstab will be the most common form of 608 * legacy configuration file for shares, but not the only one. Because 609 * of that, dfstab handling is done in the main code with calls to 610 * this function and protocol specific calls to deal with formating 611 * options into dfstab/share compatible syntax. Since not everything 612 * will be dfstab, there is a provision for calling a protocol 613 * specific plugin interface that allows the protocol plugin to do its 614 * own legacy files and skip the dfstab update. 615 */ 616 617 int 618 sa_update_legacy(sa_share_t share, char *proto) 619 { 620 FILE *dfstab; 621 int ret = SA_OK; 622 xfs_sharelist_t *list; 623 char *path; 624 sigset_t old, new; 625 char *persist; 626 627 ret = sa_proto_update_legacy(proto, share); 628 if (ret != SA_NOT_IMPLEMENTED) 629 return (ret); 630 /* do the dfstab format */ 631 persist = sa_get_share_attr(share, "type"); 632 /* 633 * only update if the share is not transient -- no share type 634 * set or the type is not "transient". 635 */ 636 if (persist == NULL || strcmp(persist, "transient") != 0) { 637 dfstab = open_dfstab(SA_LEGACY_DFSTAB); 638 if (dfstab != NULL) { 639 (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 640 (void) sigprocmask(SIG_BLOCK, NULL, &new); 641 (void) sigaddset(&new, SIGHUP); 642 (void) sigaddset(&new, SIGINT); 643 (void) sigaddset(&new, SIGQUIT); 644 (void) sigaddset(&new, SIGTSTP); 645 (void) sigprocmask(SIG_SETMASK, &new, &old); 646 path = sa_get_share_attr(share, "path"); 647 (void) lockf(fileno(dfstab), F_LOCK, 0); 648 list = getdfstab(dfstab); 649 rewind(dfstab); 650 if (list != NULL) 651 list = remdfsentry(list, path, proto); 652 list = adddfsentry(list, share, proto); 653 outdfstab(dfstab, list); 654 (void) fflush(dfstab); 655 (void) lockf(fileno(dfstab), F_ULOCK, 0); 656 (void) fsync(fileno(dfstab)); 657 (void) sigprocmask(SIG_SETMASK, &old, NULL); 658 (void) fclose(dfstab); 659 sa_free_attr_string(path); 660 if (list != NULL) 661 dfs_free_list(list); 662 } else { 663 if (errno == EACCES || errno == EPERM) { 664 ret = SA_NO_PERMISSION; 665 } else { 666 ret = SA_CONFIG_ERR; 667 } 668 } 669 } 670 if (persist != NULL) 671 sa_free_attr_string(persist); 672 return (ret); 673 } 674 675 /* 676 * sa_is_security(optname, proto) 677 * 678 * Check to see if optname is a security (named optionset) specific 679 * property for the specified protocol. 680 */ 681 682 int 683 sa_is_security(char *optname, char *proto) 684 { 685 int ret = 0; 686 if (proto != NULL) 687 ret = sa_proto_security_prop(proto, optname); 688 return (ret); 689 } 690 691 /* 692 * add_syntax_comment(root, line, err, todfstab) 693 * 694 * add a comment to the document indicating a syntax error. If 695 * todfstab is set, write it back to the dfstab file as well. 696 */ 697 698 static void 699 add_syntax_comment(xmlNodePtr root, char *line, char *err, int todfstab) 700 { 701 xmlNodePtr node; 702 703 node = xmlNewChild(root, NULL, (xmlChar *)"error", (xmlChar *)line); 704 if (node != NULL) { 705 xmlSetProp(node, (xmlChar *)"type", (xmlChar *)err); 706 } 707 if (todfstab) 708 sa_comment_line(line, err); 709 } 710 711 /* 712 * sa_is_share(object) 713 * 714 * returns true of the object is of type "share". 715 */ 716 717 int 718 sa_is_share(void *object) 719 { 720 if (object != NULL) { 721 if (strcmp((char *)((xmlNodePtr)object)->name, "share") == 0) 722 return (1); 723 } 724 return (0); 725 } 726 727 /* 728 * _sa_remove_property(property) 729 * 730 * remove a property only from the document. 731 */ 732 733 static void 734 _sa_remove_property(sa_property_t property) 735 { 736 xmlUnlinkNode((xmlNodePtr)property); 737 xmlFreeNode((xmlNodePtr)property); 738 } 739 740 /* 741 * sa_parse_legacy_options(group, options, proto) 742 * 743 * In order to support legacy configurations, we allow the protocol 744 * specific plugin to parse legacy syntax options (like those in 745 * /etc/dfs/dfstab). This adds a new optionset to the group (or 746 * share). 747 * 748 * Once the optionset has been created, we then get the derived 749 * optionset of the parent (options from the optionset of the parent 750 * and any parent it might have) and remove those from the created 751 * optionset. This avoids duplication of options. 752 */ 753 754 int 755 sa_parse_legacy_options(sa_group_t group, char *options, char *proto) 756 { 757 int ret = SA_INVALID_PROTOCOL; 758 sa_group_t parent; 759 parent = sa_get_parent_group(group); 760 761 if (proto != NULL) 762 ret = sa_proto_legacy_opts(proto, group, options); 763 /* 764 * if in a group, remove the inherited options and security 765 */ 766 if (ret == SA_OK) { 767 if (parent != NULL) { 768 sa_optionset_t optionset; 769 sa_property_t popt, prop; 770 sa_optionset_t localoptions; 771 /* find parent options to remove from child */ 772 optionset = sa_get_derived_optionset(parent, proto, 1); 773 localoptions = sa_get_optionset(group, proto); 774 if (optionset != NULL) { 775 for (popt = sa_get_property(optionset, NULL); 776 popt != NULL; 777 popt = sa_get_next_property(popt)) { 778 char *tag; 779 char *value1; 780 char *value2; 781 782 tag = sa_get_property_attr(popt, "type"); 783 if (tag != NULL) { 784 prop = sa_get_property(localoptions, tag); 785 if (prop != NULL) { 786 value1 = sa_get_property_attr(popt, "value"); 787 value2 = sa_get_property_attr(prop, "value"); 788 if (value1 != NULL && value2 != NULL && 789 strcmp(value1, value2) == 0) { 790 /* remove the property from the child */ 791 (void) _sa_remove_property(prop); 792 } 793 if (value1 != NULL) 794 sa_free_attr_string(value1); 795 if (value2 != NULL) 796 sa_free_attr_string(value2); 797 } 798 sa_free_attr_string(tag); 799 } 800 } 801 prop = sa_get_property(localoptions, NULL); 802 if (prop == NULL && sa_is_share(group)) { 803 /* 804 * all properties removed so remove the 805 * optionset if it is on a share 806 */ 807 (void) _sa_remove_optionset(localoptions); 808 } 809 sa_free_derived_optionset(optionset); 810 } 811 /* 812 * need to remove security here. If there are no 813 * security options on the local group/share, don't 814 * bother since those are the only ones that would be 815 * affected. 816 */ 817 localoptions = sa_get_all_security_types(group, proto, 0); 818 if (localoptions != NULL) { 819 for (prop = sa_get_property(localoptions, NULL); 820 prop != NULL; prop = sa_get_next_property(prop)) { 821 char *tag; 822 sa_security_t security; 823 tag = sa_get_property_attr(prop, "type"); 824 if (tag != NULL) { 825 security = sa_get_security(group, tag, proto); 826 sa_free_attr_string(tag); 827 for (popt = sa_get_property(security, NULL); 828 popt != NULL; 829 popt = sa_get_next_property(popt)) { 830 char *value1; 831 char *value2; 832 833 /* remove duplicates from this level */ 834 value1 = sa_get_property_attr(popt, "value"); 835 value2 = sa_get_property_attr(prop, "value"); 836 if (value1 != NULL && value2 != NULL && 837 strcmp(value1, value2) == 0) { 838 /* remove the property from the child */ 839 (void) _sa_remove_property(prop); 840 } 841 if (value1 != NULL) 842 sa_free_attr_string(value1); 843 if (value2 != NULL) 844 sa_free_attr_string(value2); 845 } 846 } 847 } 848 (void) sa_destroy_optionset(localoptions); 849 } 850 } 851 } 852 return (ret); 853 } 854 855 /* 856 * dfs_free_list(list) 857 * 858 * Free the data in each list entry of the list as well as freeing the 859 * entries themselves. We need to avoid memory leaks and don't want to 860 * dereference any NULL members. 861 */ 862 863 static void 864 dfs_free_list(xfs_sharelist_t *list) 865 { 866 xfs_sharelist_t *entry; 867 for (entry = list; entry != NULL; entry = list) { 868 if (entry->path != NULL) 869 free(entry->path); 870 if (entry->resource != NULL) 871 free(entry->resource); 872 if (entry->fstype != NULL) 873 free(entry->fstype); 874 if (entry->options != NULL) 875 free(entry->options); 876 if (entry->description != NULL) 877 free(entry->description); 878 if (entry->origline != NULL) 879 free(entry->origline); 880 if (entry->group != NULL) 881 free(entry->group); 882 list = list->next; 883 free(entry); 884 } 885 } 886 887 /* 888 * parse_dfstab(dfstab, root) 889 * 890 * Open and read the existing dfstab, parsing each line and adding it 891 * to the internal configuration. Make sure syntax errors, etc are 892 * preserved as comments. 893 */ 894 895 static void 896 parse_dfstab(char *dfstab, xmlNodePtr root) 897 { 898 sa_share_t share; 899 sa_group_t group; 900 sa_group_t sgroup = NULL; 901 sa_group_t defgroup; 902 xfs_sharelist_t *head, *list; 903 int err; 904 int defined_group; 905 FILE *dfs; 906 char *oldprops; 907 908 /* read the dfstab format file and fill in the doc tree */ 909 910 dfs = fopen(dfstab, "r"); 911 if (dfs == NULL) { 912 return; 913 } 914 915 defgroup = sa_get_group("default"); 916 917 for (head = list = getdfstab(dfs); 918 list != NULL; 919 list = list->next) { 920 share = NULL; 921 group = NULL; 922 defined_group = 0; 923 err = 0; 924 925 if (list->origline == NULL) { 926 /* 927 * Comment line that we will likely skip. 928 * If the line has the syntax: 929 * # error: string: string 930 * It should be preserved until manually deleted. 931 */ 932 if (list->description != NULL && 933 strncmp(list->description, "# Error: ", 9) == 0) { 934 char *line; 935 char *error; 936 char *cmd; 937 line = strdup(list->description); 938 if (line != NULL) { 939 error = line + 9; 940 cmd = strchr(error, ':'); 941 if (cmd != NULL) { 942 int len; 943 *cmd = '\0'; 944 cmd += 2; 945 len = strlen(cmd); 946 cmd[len - 1] = '\0'; 947 add_syntax_comment(root, cmd, error, 0); 948 } 949 free(line); 950 } 951 } 952 continue; 953 } 954 if (list->path != NULL && strlen(list->path) > 0 && 955 *list->path == '/') { 956 share = sa_find_share(list->path); 957 if (share != NULL) 958 sgroup = sa_get_parent_group(share); 959 else 960 sgroup = NULL; 961 } else { 962 (void) printf(gettext("No share specified in dfstab: " 963 "line %d: %s\n"), 964 list->lineno, list->origline); 965 add_syntax_comment(root, list->origline, 966 gettext("No share specified"), 967 1); 968 continue; 969 } 970 if (list->group != NULL && strlen(list->group) > 0) { 971 group = sa_get_group(list->group); 972 defined_group = 1; 973 } else { 974 group = defgroup; 975 } 976 if (defined_group && group == NULL) { 977 (void) printf(gettext("Unknown group used in dfstab: " 978 "line %d: %s\n"), 979 list->lineno, list->origline); 980 add_syntax_comment(root, list->origline, 981 gettext("Unknown group specified"), 1); 982 continue; 983 } 984 if (group != NULL) { 985 if (share == NULL) { 986 if (!defined_group && group == defgroup) { 987 /* this is an OK add for legacy */ 988 share = sa_add_share(defgroup, list->path, 989 SA_SHARE_PERMANENT | SA_SHARE_PARSER, 990 &err); 991 if (share != NULL) { 992 if (list->description != NULL && 993 strlen(list->description) > 0) 994 (void) sa_set_share_description(share, 995 list->description); 996 if (list->options != NULL && 997 strlen(list->options) > 0) { 998 (void) sa_parse_legacy_options(share, 999 list->options, 1000 list->fstype); 1001 } 1002 if (list->resource != NULL) 1003 (void) sa_set_share_attr(share, "resource", 1004 list->resource); 1005 } else { 1006 (void) printf(gettext("Error in dfstab: " 1007 "line %d: %s\n"), 1008 list->lineno, list->origline); 1009 if (err != SA_BAD_PATH) 1010 add_syntax_comment(root, list->origline, 1011 gettext("Syntax"), 1); 1012 else 1013 add_syntax_comment(root, list->origline, 1014 gettext("Path"), 1); 1015 continue; 1016 } 1017 } 1018 } else { 1019 if (group != sgroup) { 1020 (void) printf(gettext("Attempt to change" 1021 "configuration in" 1022 "dfstab: line %d: %s\n"), 1023 list->lineno, list->origline); 1024 add_syntax_comment(root, list->origline, 1025 gettext("Attempt to change configuration"), 1); 1026 continue; 1027 } 1028 /* its the same group but could have changed options */ 1029 oldprops = sa_proto_legacy_format(list->fstype, share, 0); 1030 if (oldprops != NULL) { 1031 if (list->options != NULL && 1032 strcmp(oldprops, list->options) != 0) { 1033 sa_optionset_t opts; 1034 sa_security_t secs; 1035 /* possibly different values */ 1036 opts = sa_get_optionset((sa_group_t)share, 1037 list->fstype); 1038 (void) sa_destroy_optionset(opts); 1039 for (secs = sa_get_security((sa_group_t)share, 1040 NULL, list->fstype); 1041 secs != NULL; 1042 secs = sa_get_security((sa_group_t)share, 1043 NULL, list->fstype)) { 1044 (void) sa_destroy_security(secs); 1045 } 1046 (void) sa_parse_legacy_options(share, 1047 list->options, 1048 list->fstype); 1049 } 1050 } 1051 } 1052 } else { 1053 /* shouldn't happen */ 1054 err = SA_CONFIG_ERR; 1055 } 1056 1057 } 1058 dfs_free_list(head); 1059 } 1060 1061 /* 1062 * legacy_removes(group, file) 1063 * 1064 * Find any shares that are "missing" from the legacy file. These 1065 * should be removed from the configuration since they are likely from 1066 * a legacy app or the admin modified the dfstab file directly. We 1067 * have to support this even if it is not the recommended way to do 1068 * things. 1069 */ 1070 1071 static void 1072 legacy_removes(sa_group_t group, char *file) 1073 { 1074 sa_share_t share; 1075 char *path; 1076 xfs_sharelist_t *list, *item; 1077 FILE *dfstab; 1078 1079 dfstab = fopen(file, "r"); 1080 if (dfstab != NULL) { 1081 list = getdfstab(dfstab); 1082 (void) fclose(dfstab); 1083 for (share = sa_get_share(group, NULL); share != NULL; 1084 share = sa_get_next_share(share)) { 1085 /* now see if the share is in the dfstab file */ 1086 path = sa_get_share_attr(share, "path"); 1087 if (path != NULL) { 1088 item = finddfsentry(list, path); 1089 if (item == NULL) { 1090 /* the share was removed this way */ 1091 (void) sa_remove_share(share); 1092 /* start over since the list was broken */ 1093 share = sa_get_share(group, NULL); 1094 } 1095 sa_free_attr_string(path); 1096 } 1097 } 1098 if (list != NULL) 1099 dfs_free_list(list); 1100 } 1101 } 1102 1103 /* 1104 * getlegacyconfig(path, root) 1105 * 1106 * Parse dfstab and build the legacy configuration. This only gets 1107 * called when a change was detected. 1108 */ 1109 1110 void 1111 getlegacyconfig(char *path, xmlNodePtr *root) 1112 { 1113 sa_group_t defgroup; 1114 1115 if (root != NULL) { 1116 if (*root == NULL) 1117 *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 1118 if (*root != NULL) { 1119 if (strcmp(path, SA_LEGACY_DFSTAB) == 0) { 1120 /* 1121 * walk the default shares and find anything 1122 * missing. we do this first to make sure it 1123 * is cleaned up since there may be legacy 1124 * code add/del via dfstab and we need to 1125 * cleanup SMF. 1126 */ 1127 defgroup = sa_get_group("default"); 1128 if (defgroup != NULL) { 1129 legacy_removes(defgroup, path); 1130 } 1131 /* parse the dfstab and add anything new */ 1132 parse_dfstab(path, *root); 1133 } 1134 } 1135 } 1136 } 1137 1138 /* 1139 * parse_sharetab(void) 1140 * 1141 * Read the /etc/dfs/sharetab file via libfsmgt and see which entries 1142 * don't exist in the repository. These shares are marked transient. 1143 * We also need to see if they are ZFS shares since ZFS bypasses the 1144 * SMF repository. 1145 */ 1146 1147 int 1148 parse_sharetab(void) 1149 { 1150 fs_sharelist_t *list, *tmplist; 1151 int err = 0; 1152 sa_share_t share; 1153 sa_group_t group; 1154 sa_group_t lgroup; 1155 char *groupname; 1156 int legacy = 0; 1157 1158 list = fs_get_share_list(&err); 1159 if (list == NULL) 1160 return (legacy); 1161 1162 lgroup = sa_get_group("default"); 1163 1164 for (tmplist = list; tmplist != NULL; tmplist = tmplist->next) { 1165 group = NULL; 1166 share = sa_find_share(tmplist->path); 1167 if (share == NULL) { 1168 /* 1169 * this share is transient so needs to be 1170 * added. Initially, this will be under 1171 * default(legacy) unless it is a ZFS 1172 * share. If zfs, we need a zfs group. 1173 */ 1174 if (tmplist->resource != NULL && 1175 (groupname = strchr(tmplist->resource, '@')) != NULL) { 1176 /* there is a defined group */ 1177 *groupname++ = '\0'; 1178 group = sa_get_group(groupname); 1179 if (group != NULL) { 1180 share = _sa_add_share(group, tmplist->path, 1181 SA_SHARE_TRANSIENT, &err); 1182 } else { 1183 /* 1184 * While this case shouldn't occur very often, 1185 * it does occur out of a "zfs set 1186 * sharenfs=off" when the dataset is also set 1187 * to canmount=off. A warning will then cause 1188 * the zfs command to abort. Since we add it 1189 * to the default list, everything works 1190 * properly anyway and the library doesn't 1191 * need to give a warning. 1192 */ 1193 share = _sa_add_share(lgroup, tmplist->path, 1194 SA_SHARE_TRANSIENT, &err); 1195 } 1196 } else { 1197 if (sa_zfs_is_shared(tmplist->path)) { 1198 group = sa_get_group("zfs"); 1199 if (group == NULL) { 1200 group = sa_create_group("zfs", &err); 1201 if (group == NULL && err == SA_NO_PERMISSION) { 1202 group = _sa_create_group("zfs"); 1203 } 1204 if (group != NULL) { 1205 (void) sa_create_optionset(group, 1206 tmplist->fstype); 1207 (void) sa_set_group_attr(group, "zfs", "true"); 1208 } 1209 } 1210 if (group != NULL) { 1211 share = _sa_add_share(group, tmplist->path, 1212 SA_SHARE_TRANSIENT, &err); 1213 } 1214 } else { 1215 share = _sa_add_share(lgroup, tmplist->path, 1216 SA_SHARE_TRANSIENT, &err); 1217 } 1218 } 1219 if (share == NULL) 1220 (void) printf(gettext("Problem with transient: %s\n"), 1221 sa_errorstr(err)); 1222 if (share != NULL) 1223 set_node_attr(share, "shared", "true"); 1224 1225 if (err == SA_OK) { 1226 if (tmplist->options != NULL && 1227 strlen(tmplist->options) > 0) { 1228 (void) sa_parse_legacy_options(share, 1229 tmplist->options, 1230 tmplist->fstype); 1231 } 1232 if (tmplist->resource != NULL && 1233 strcmp(tmplist->resource, "-") != 0) 1234 set_node_attr(share, "resource", tmplist->resource); 1235 if (tmplist->description != NULL) { 1236 xmlNodePtr node; 1237 node = xmlNewChild((xmlNodePtr)share, NULL, 1238 (xmlChar *)"description", NULL); 1239 xmlNodeSetContent(node, 1240 (xmlChar *)tmplist->description); 1241 } 1242 legacy = 1; 1243 } 1244 } else { 1245 /* 1246 * if this is a legacy share, mark as shared so we 1247 * only update sharetab appropriately. 1248 */ 1249 set_node_attr(share, "shared", "true"); 1250 } 1251 } 1252 fs_free_share_list(list); 1253 return (legacy); 1254 } 1255 1256 /* 1257 * get the transient shares from the sharetab (or other) file. since 1258 * these are transient, they only appear in the working file and not 1259 * in a repository. 1260 */ 1261 int 1262 gettransients(xmlNodePtr *root) 1263 { 1264 int legacy = 0; 1265 1266 if (root != NULL) { 1267 if (*root == NULL) 1268 *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 1269 if (*root != NULL) { 1270 legacy = parse_sharetab(); 1271 } 1272 } 1273 return (legacy); 1274 } 1275 1276 /* 1277 * sa_has_prop(optionset, prop) 1278 * 1279 * Is the specified property a member of the optionset? 1280 */ 1281 1282 int 1283 sa_has_prop(sa_optionset_t optionset, sa_property_t prop) 1284 { 1285 char *name; 1286 sa_property_t otherprop; 1287 int result = 0; 1288 1289 if (optionset != NULL) { 1290 name = sa_get_property_attr(prop, "type"); 1291 if (name != NULL) { 1292 otherprop = sa_get_property(optionset, name); 1293 if (otherprop != NULL) 1294 result = 1; 1295 sa_free_attr_string(name); 1296 } 1297 } 1298 return (result); 1299 } 1300 1301 /* 1302 * Update legacy files 1303 * 1304 * Provides functions to add/remove/modify individual entries 1305 * in dfstab and sharetab 1306 */ 1307 1308 void 1309 update_legacy_config(void) 1310 { 1311 /* 1312 * no longer used -- this is a placeholder in case we need to 1313 * add it back later. 1314 */ 1315 } 1316 1317 /* 1318 * sa_valid_property(object, proto, property) 1319 * 1320 * check to see if the specified property is valid relative to the 1321 * specified protocol. The protocol plugin is called to do the work. 1322 */ 1323 1324 int 1325 sa_valid_property(void *object, char *proto, sa_property_t property) 1326 { 1327 int ret = SA_OK; 1328 1329 if (proto != NULL && property != NULL) { 1330 ret = sa_proto_valid_prop(proto, property, object); 1331 } 1332 1333 return (ret); 1334 } 1335 1336 /* 1337 * sa_fstype(path) 1338 * 1339 * Given path, return the string representing the path's file system 1340 * type. This is used to discover ZFS shares. 1341 */ 1342 1343 char * 1344 sa_fstype(char *path) 1345 { 1346 int err; 1347 struct stat st; 1348 1349 err = stat(path, &st); 1350 if (err < 0) { 1351 err = SA_NO_SUCH_PATH; 1352 } else { 1353 err = SA_OK; 1354 } 1355 if (err == SA_OK) { 1356 /* have a valid path at this point */ 1357 return (strdup(st.st_fstype)); 1358 } 1359 return (NULL); 1360 } 1361 1362 void 1363 sa_free_fstype(char *type) 1364 { 1365 free(type); 1366 } 1367 1368 /* 1369 * sa_get_derived_optionset(object, proto, hier) 1370 * 1371 * Work backward to the top of the share object tree and start 1372 * copying protocol specific optionsets into a newly created 1373 * optionset that doesn't have a parent (it will be freed 1374 * later). This provides for the property inheritence model. That 1375 * is, properties closer to the share take precedence over group 1376 * level. This also provides for groups of groups in the future. 1377 */ 1378 1379 sa_optionset_t 1380 sa_get_derived_optionset(void *object, char *proto, int hier) 1381 { 1382 sa_optionset_t newoptionset; 1383 sa_optionset_t optionset; 1384 sa_group_t group; 1385 1386 if (hier && 1387 (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 1388 newoptionset = sa_get_derived_optionset((void *)group, proto, hier); 1389 } else { 1390 newoptionset = (sa_optionset_t)xmlNewNode(NULL, 1391 (xmlChar *)"optionset"); 1392 if (newoptionset != NULL) { 1393 sa_set_optionset_attr(newoptionset, "type", proto); 1394 } 1395 } 1396 /* dont' do anything if memory wasn't allocated */ 1397 if (newoptionset == NULL) 1398 return (NULL); 1399 1400 /* found the top so working back down the stack */ 1401 optionset = sa_get_optionset((sa_optionset_t)object, proto); 1402 if (optionset != NULL) { 1403 sa_property_t prop; 1404 /* add optionset to the newoptionset */ 1405 for (prop = sa_get_property(optionset, NULL); 1406 prop != NULL; prop = sa_get_next_property(prop)) { 1407 sa_property_t newprop; 1408 char *name; 1409 char *value; 1410 name = sa_get_property_attr(prop, "type"); 1411 value = sa_get_property_attr(prop, "value"); 1412 if (name != NULL) { 1413 newprop = sa_get_property(newoptionset, name); 1414 /* replace the value with the new value */ 1415 if (newprop != NULL) { 1416 /* 1417 * only set if value is non NULL, old value ok 1418 * if it is NULL. 1419 */ 1420 if (value != NULL) 1421 set_node_attr(newprop, "value", value); 1422 } else { 1423 /* an entirely new property */ 1424 if (value != NULL) { 1425 newprop = sa_create_property(name, value); 1426 if (newprop != NULL) { 1427 newprop = (sa_property_t) 1428 xmlAddChild((xmlNodePtr)newoptionset, 1429 (xmlNodePtr)newprop); 1430 } 1431 } 1432 } 1433 sa_free_attr_string(name); 1434 } 1435 if (value != NULL) 1436 sa_free_attr_string(value); 1437 } 1438 } 1439 return (newoptionset); 1440 } 1441 1442 void 1443 sa_free_derived_optionset(sa_optionset_t optionset) 1444 { 1445 /* while it shouldn't be linked, it doesn't hurt */ 1446 if (optionset != NULL) { 1447 xmlUnlinkNode((xmlNodePtr) optionset); 1448 xmlFreeNode((xmlNodePtr) optionset); 1449 } 1450 } 1451 1452 /* 1453 * sa_get_all_security_types(object, proto, hier) 1454 * 1455 * find all the security types set for this object. This is 1456 * preliminary to getting a derived security set. The return value is an 1457 * optionset containg properties which are the sectype values found by 1458 * walking up the XML document struture. The returned optionset 1459 * is a derived optionset. 1460 * 1461 * If hier is 0, only look at object. If non-zero, walk up the tree. 1462 */ 1463 sa_optionset_t 1464 sa_get_all_security_types(void *object, char *proto, int hier) 1465 { 1466 sa_optionset_t options; 1467 sa_security_t security; 1468 sa_group_t group; 1469 sa_property_t prop; 1470 1471 options = NULL; 1472 1473 if (hier && 1474 (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 1475 options = sa_get_all_security_types((void *)group, proto, hier); 1476 } else { 1477 options = (sa_optionset_t)xmlNewNode(NULL, 1478 (xmlChar *)"optionset"); 1479 } 1480 /* hit the top so collect the security types working back */ 1481 if (options != NULL) { 1482 for (security = sa_get_security((sa_group_t)object, NULL, NULL); 1483 security != NULL; security = sa_get_next_security(security)) { 1484 char *type; 1485 char *sectype; 1486 1487 type = sa_get_security_attr(security, "type"); 1488 if (type != NULL) { 1489 if (strcmp(type, proto) != 0) { 1490 sa_free_attr_string(type); 1491 continue; 1492 } 1493 sectype = sa_get_security_attr(security, "sectype"); 1494 if (sectype != NULL) { 1495 /* 1496 * have a security type, check to see if 1497 * already present in optionset and add if it 1498 * isn't. 1499 */ 1500 if (sa_get_property(options, sectype) == NULL) { 1501 prop = sa_create_property(sectype, "true"); 1502 if (prop != NULL) 1503 prop = (sa_property_t) 1504 xmlAddChild((xmlNodePtr)options, 1505 (xmlNodePtr)prop); 1506 } 1507 sa_free_attr_string(sectype); 1508 } 1509 sa_free_attr_string(type); 1510 } 1511 } 1512 } 1513 return (options); 1514 } 1515 1516 /* 1517 * sa_get_derived_security(object, sectype, proto, hier) 1518 * 1519 * Get the derived security(named optionset) for the object given the 1520 * sectype and proto. If hier is non-zero, walk up the tree to get all 1521 * properties defined for this object, otherwise just those on the 1522 * object. 1523 */ 1524 1525 sa_security_t 1526 sa_get_derived_security(void *object, char *sectype, char *proto, int hier) 1527 { 1528 sa_security_t newsecurity; 1529 sa_security_t security; 1530 sa_group_t group; 1531 1532 if (hier && 1533 (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 1534 newsecurity = sa_get_derived_security((void *)group, 1535 sectype, proto, hier); 1536 } else { 1537 newsecurity = (sa_security_t)xmlNewNode(NULL, 1538 (xmlChar *)"security"); 1539 if (newsecurity != NULL) { 1540 sa_set_security_attr(newsecurity, "type", proto); 1541 sa_set_security_attr(newsecurity, "sectype", sectype); 1542 } 1543 } 1544 /* dont' do anything if memory wasn't allocated */ 1545 if (newsecurity == NULL) 1546 return (NULL); 1547 1548 /* found the top so working back down the stack */ 1549 security = sa_get_security((sa_security_t)object, sectype, proto); 1550 if (security != NULL) { 1551 sa_property_t prop; 1552 /* add security to the newsecurity */ 1553 for (prop = sa_get_property(security, NULL); 1554 prop != NULL; prop = sa_get_next_property(prop)) { 1555 sa_property_t newprop; 1556 char *name; 1557 char *value; 1558 name = sa_get_property_attr(prop, "type"); 1559 value = sa_get_property_attr(prop, "value"); 1560 if (name != NULL) { 1561 newprop = sa_get_property(newsecurity, name); 1562 /* replace the value with the new value */ 1563 if (newprop != NULL) { 1564 /* 1565 * only set if value is non NULL, old value ok 1566 * if it is NULL. 1567 */ 1568 if (value != NULL) 1569 set_node_attr(newprop, name, value); 1570 } else { 1571 /* an entirely new property */ 1572 if (value != NULL) { 1573 newprop = sa_create_property(name, value); 1574 newprop = (sa_property_t) 1575 xmlAddChild((xmlNodePtr)newsecurity, 1576 (xmlNodePtr)newprop); 1577 } 1578 } 1579 sa_free_attr_string(name); 1580 } 1581 if (value != NULL) 1582 sa_free_attr_string(value); 1583 } 1584 } 1585 return (newsecurity); 1586 } 1587 1588 void 1589 sa_free_derived_security(sa_security_t security) 1590 { 1591 /* while it shouldn't be linked, it doesn't hurt */ 1592 if (security != NULL) { 1593 xmlUnlinkNode((xmlNodePtr)security); 1594 xmlFreeNode((xmlNodePtr)security); 1595 } 1596 } 1597 1598 /* 1599 * sharetab utility functions 1600 * 1601 * makes use of the original sharetab.c from fs.d/nfs/lib 1602 */ 1603 1604 /* 1605 * fillshare(share, proto, sh) 1606 * 1607 * Fill the struct share with values obtained from the share object. 1608 */ 1609 static void 1610 fillshare(sa_share_t share, char *proto, struct share *sh) 1611 { 1612 char *groupname = NULL; 1613 char *value; 1614 sa_group_t group; 1615 char *buff; 1616 char *zfs; 1617 1618 group = sa_get_parent_group(share); 1619 if (group != NULL) { 1620 zfs = sa_get_group_attr(group, "zfs"); 1621 groupname = sa_get_group_attr(group, "name"); 1622 1623 if (groupname != NULL && 1624 (strcmp(groupname, "default") == 0 || zfs != NULL)) { 1625 /* 1626 * since the groupname is either "default" or the 1627 * group is a ZFS group, we don't want to keep 1628 * groupname. We do want it if it is any other type of 1629 * group. 1630 */ 1631 sa_free_attr_string(groupname); 1632 groupname = NULL; 1633 } 1634 if (zfs != NULL) 1635 sa_free_attr_string(zfs); 1636 } 1637 1638 value = sa_get_share_attr(share, "path"); 1639 if (value != NULL) { 1640 sh->sh_path = strdup(value); 1641 sa_free_attr_string(value); 1642 } 1643 1644 value = sa_get_share_attr(share, "resource"); 1645 if (value != NULL || groupname != NULL) { 1646 int len = 0; 1647 1648 if (value != NULL) 1649 len += strlen(value); 1650 if (groupname != NULL) 1651 len += strlen(groupname); 1652 len += 3; /* worst case */ 1653 buff = malloc(len); 1654 (void) snprintf(buff, len, "%s%s%s", 1655 (value != NULL && strlen(value) > 0) ? value : "-", 1656 groupname != NULL ? "@" : "", 1657 groupname != NULL ? groupname : ""); 1658 sh->sh_res = buff; 1659 if (value != NULL) 1660 sa_free_attr_string(value); 1661 if (groupname != NULL) { 1662 sa_free_attr_string(groupname); 1663 groupname = NULL; 1664 } 1665 } else { 1666 sh->sh_res = strdup("-"); 1667 } 1668 1669 sh->sh_fstype = strdup(proto); 1670 value = sa_proto_legacy_format(proto, share, 1); 1671 if (value != NULL) { 1672 if (strlen(value) > 0) 1673 sh->sh_opts = strdup(value); 1674 else 1675 sh->sh_opts = strdup("rw"); 1676 free(value); 1677 } else 1678 sh->sh_opts = strdup("rw"); 1679 1680 value = sa_get_share_description(share); 1681 if (value != NULL) { 1682 sh->sh_descr = strdup(value); 1683 sa_free_share_description(value); 1684 } else 1685 sh->sh_descr = strdup(""); 1686 } 1687 1688 /* 1689 * emptyshare(sh) 1690 * 1691 * Free the strings in the non-NULL members of sh. 1692 */ 1693 1694 static void 1695 emptyshare(struct share *sh) 1696 { 1697 if (sh->sh_path != NULL) 1698 free(sh->sh_path); 1699 sh->sh_path = NULL; 1700 if (sh->sh_res != NULL) 1701 free(sh->sh_res); 1702 sh->sh_res = NULL; 1703 if (sh->sh_fstype != NULL) 1704 free(sh->sh_fstype); 1705 sh->sh_fstype = NULL; 1706 if (sh->sh_opts != NULL) 1707 free(sh->sh_opts); 1708 sh->sh_opts = NULL; 1709 if (sh->sh_descr != NULL) 1710 free(sh->sh_descr); 1711 sh->sh_descr = NULL; 1712 } 1713 1714 /* 1715 * sa_update_sharetab(share, proto) 1716 * 1717 * Update the sharetab file with info from the specified share. 1718 * This could be an update or add. 1719 */ 1720 1721 int 1722 sa_update_sharetab(sa_share_t share, char *proto) 1723 { 1724 int ret = SA_OK; 1725 struct share shtab; 1726 char *path; 1727 int logging = 0; 1728 FILE *sharetab; 1729 sigset_t old, new; 1730 1731 path = sa_get_share_attr(share, "path"); 1732 if (path != NULL) { 1733 (void) memset(&shtab, '\0', sizeof (shtab)); 1734 sharetab = fopen(SA_LEGACY_SHARETAB, "r+"); 1735 if (sharetab == NULL) { 1736 sharetab = fopen(SA_LEGACY_SHARETAB, "w+"); 1737 } 1738 if (sharetab != NULL) { 1739 (void) setvbuf(sharetab, NULL, _IOLBF, BUFSIZ * 8); 1740 (void) sigprocmask(SIG_BLOCK, NULL, &new); 1741 (void) sigaddset(&new, SIGHUP); 1742 (void) sigaddset(&new, SIGINT); 1743 (void) sigaddset(&new, SIGQUIT); 1744 (void) sigaddset(&new, SIGTSTP); 1745 (void) sigprocmask(SIG_SETMASK, &new, &old); 1746 (void) lockf(fileno(sharetab), F_LOCK, 0); 1747 (void) remshare(sharetab, path, &logging); 1748 /* fill in share structure and write it out */ 1749 (void) fillshare(share, proto, &shtab); 1750 (void) putshare(sharetab, &shtab); 1751 emptyshare(&shtab); 1752 (void) fflush(sharetab); 1753 (void) lockf(fileno(sharetab), F_ULOCK, 0); 1754 (void) fsync(fileno(sharetab)); 1755 (void) sigprocmask(SIG_SETMASK, &old, NULL); 1756 (void) fclose(sharetab); 1757 } else { 1758 if (errno == EACCES || errno == EPERM) { 1759 ret = SA_NO_PERMISSION; 1760 } else { 1761 ret = SA_CONFIG_ERR; 1762 } 1763 } 1764 sa_free_attr_string(path); 1765 } 1766 return (ret); 1767 } 1768 1769 /* 1770 * sa_delete_sharetab(path, proto) 1771 * 1772 * remove the specified share from sharetab. 1773 */ 1774 1775 int 1776 sa_delete_sharetab(char *path, char *proto) 1777 { 1778 int ret = SA_OK; 1779 int logging = 0; 1780 FILE *sharetab; 1781 sigset_t old, new; 1782 #ifdef lint 1783 proto = proto; 1784 #endif 1785 1786 if (path != NULL) { 1787 sharetab = fopen(SA_LEGACY_SHARETAB, "r+"); 1788 if (sharetab == NULL) { 1789 sharetab = fopen(SA_LEGACY_SHARETAB, "w+"); 1790 } 1791 if (sharetab != NULL) { 1792 /* should block keyboard level signals around the lock */ 1793 (void) sigprocmask(SIG_BLOCK, NULL, &new); 1794 (void) sigaddset(&new, SIGHUP); 1795 (void) sigaddset(&new, SIGINT); 1796 (void) sigaddset(&new, SIGQUIT); 1797 (void) sigaddset(&new, SIGTSTP); 1798 (void) sigprocmask(SIG_SETMASK, &new, &old); 1799 (void) lockf(fileno(sharetab), F_LOCK, 0); 1800 ret = remshare(sharetab, path, &logging); 1801 (void) fflush(sharetab); 1802 (void) lockf(fileno(sharetab), F_ULOCK, 0); 1803 (void) fsync(fileno(sharetab)); 1804 (void) sigprocmask(SIG_SETMASK, &old, NULL); 1805 (void) fclose(sharetab); 1806 } else { 1807 if (errno == EACCES || errno == EPERM) { 1808 ret = SA_NO_PERMISSION; 1809 } else { 1810 ret = SA_CONFIG_ERR; 1811 } 1812 } 1813 } 1814 return (ret); 1815 } 1816