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