1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * NFS specific functions 31 */ 32 #include <stdio.h> 33 #include <string.h> 34 #include <ctype.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <zone.h> 38 #include <errno.h> 39 #include <locale.h> 40 #include <signal.h> 41 #include "libshare.h" 42 #include "libshare_impl.h" 43 #include <nfs/export.h> 44 #include <pwd.h> 45 #include <limits.h> 46 #include <libscf.h> 47 #include "nfslog_config.h" 48 #include "nfslogtab.h" 49 #include "libshare_nfs.h" 50 #include <rpcsvc/daemon_utils.h> 51 #include <nfs/nfs.h> 52 #include <nfs/nfssys.h> 53 54 /* should really be in some global place */ 55 #define DEF_WIN 30000 56 #define OPT_CHUNK 1024 57 58 int debug = 0; 59 60 #define NFS_SERVER_SVC "svc:/network/nfs/server:default" 61 62 /* internal functions */ 63 static int nfs_init(); 64 static void nfs_fini(); 65 static int nfs_enable_share(sa_share_t); 66 static int nfs_disable_share(sa_share_t, char *); 67 static int nfs_validate_property(sa_property_t, sa_optionset_t); 68 static int nfs_validate_security_mode(char *); 69 static int nfs_is_security_opt(char *); 70 static int nfs_parse_legacy_options(sa_group_t, char *); 71 static char *nfs_format_options(sa_group_t, int); 72 static int nfs_set_proto_prop(sa_property_t); 73 static sa_protocol_properties_t nfs_get_proto_set(); 74 static char *nfs_get_status(); 75 static char *nfs_space_alias(char *); 76 77 /* 78 * ops vector that provides the protocol specific info and operations 79 * for share management. 80 */ 81 82 struct sa_plugin_ops sa_plugin_ops = { 83 SA_PLUGIN_VERSION, 84 "nfs", 85 nfs_init, 86 nfs_fini, 87 nfs_enable_share, 88 nfs_disable_share, 89 nfs_validate_property, 90 nfs_validate_security_mode, 91 nfs_is_security_opt, 92 nfs_parse_legacy_options, 93 nfs_format_options, 94 nfs_set_proto_prop, 95 nfs_get_proto_set, 96 nfs_get_status, 97 nfs_space_alias, 98 NULL, 99 NULL 100 }; 101 102 /* 103 * list of support services needed 104 * defines should come from head/rpcsvc/daemon_utils.h 105 */ 106 107 static char *service_list_default[] = 108 { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NULL }; 109 static char *service_list_logging[] = 110 { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, NULL }; 111 112 /* 113 * option definitions. Make sure to keep the #define for the option 114 * index just before the entry it is the index for. Changing the order 115 * can cause breakage. E.g OPT_RW is index 1 and must precede the 116 * line that includes the SHOPT_RW and OPT_RW entries. 117 */ 118 119 struct option_defs optdefs[] = { 120 #define OPT_RO 0 121 {SHOPT_RO, OPT_RO, OPT_TYPE_ACCLIST}, 122 #define OPT_RW 1 123 {SHOPT_RW, OPT_RW, OPT_TYPE_ACCLIST}, 124 #define OPT_ROOT 2 125 {SHOPT_ROOT, OPT_ROOT, OPT_TYPE_ACCLIST}, 126 #define OPT_SECURE 3 127 {SHOPT_SECURE, OPT_SECURE, OPT_TYPE_DEPRECATED}, 128 #define OPT_ANON 4 129 {SHOPT_ANON, OPT_ANON, OPT_TYPE_USER}, 130 #define OPT_WINDOW 5 131 {SHOPT_WINDOW, OPT_WINDOW, OPT_TYPE_NUMBER}, 132 #define OPT_NOSUID 6 133 {SHOPT_NOSUID, OPT_NOSUID, OPT_TYPE_BOOLEAN}, 134 #define OPT_ACLOK 7 135 {SHOPT_ACLOK, OPT_ACLOK, OPT_TYPE_BOOLEAN}, 136 #define OPT_NOSUB 8 137 {SHOPT_NOSUB, OPT_NOSUB, OPT_TYPE_BOOLEAN}, 138 #define OPT_SEC 9 139 {SHOPT_SEC, OPT_SEC, OPT_TYPE_SECURITY}, 140 #define OPT_PUBLIC 10 141 {SHOPT_PUBLIC, OPT_PUBLIC, OPT_TYPE_BOOLEAN, OPT_SHARE_ONLY}, 142 #define OPT_INDEX 11 143 {SHOPT_INDEX, OPT_INDEX, OPT_TYPE_FILE}, 144 #define OPT_LOG 12 145 {SHOPT_LOG, OPT_LOG, OPT_TYPE_LOGTAG}, 146 #define OPT_CKSUM 13 147 {SHOPT_CKSUM, OPT_CKSUM, OPT_TYPE_STRINGSET}, 148 #ifdef VOLATILE_FH_TEST /* XXX added for testing volatile fh's only */ 149 #define OPT_VOLFH 14 150 {SHOPT_VOLFH, OPT_VOLFH}, 151 #endif /* VOLATILE_FH_TEST */ 152 NULL 153 }; 154 155 /* 156 * list of properties that are related to security flavors. 157 */ 158 static char *seclist[] = { 159 SHOPT_RO, 160 SHOPT_RW, 161 SHOPT_ROOT, 162 SHOPT_WINDOW, 163 NULL 164 }; 165 166 /* structure for list of securities */ 167 struct securities { 168 sa_security_t security; 169 struct securities *next; 170 }; 171 172 /* 173 * findopt(name) 174 * 175 * Lookup option "name" in the option table and return the table 176 * index. 177 */ 178 179 static int 180 findopt(char *name) 181 { 182 int i; 183 if (name != NULL) { 184 for (i = 0; optdefs[i].tag != NULL; i++) { 185 if (strcmp(optdefs[i].tag, name) == 0) 186 return (i); 187 } 188 } 189 return (-1); 190 } 191 192 /* 193 * gettype(name) 194 * 195 * Return the type of option "name". 196 */ 197 198 static int 199 gettype(char *name) 200 { 201 int optdef; 202 203 optdef = findopt(name); 204 if (optdef != -1) 205 return (optdefs[optdef].type); 206 return (OPT_TYPE_ANY); 207 } 208 209 /* 210 * nfs_validate_security_mode(mode) 211 * 212 * is the specified mode string a valid one for use with NFS? 213 */ 214 215 static int 216 nfs_validate_security_mode(char *mode) 217 { 218 seconfig_t secinfo; 219 int err; 220 221 (void) memset(&secinfo, '\0', sizeof (secinfo)); 222 err = nfs_getseconfig_byname(mode, &secinfo); 223 if (err == SC_NOERROR) 224 return (1); 225 return (0); 226 } 227 228 /* 229 * nfs_is_security_opt(tok) 230 * 231 * check to see if tok represents an option that is only valid in some 232 * security flavor. 233 */ 234 235 static int 236 nfs_is_security_opt(char *tok) 237 { 238 int i; 239 240 for (i = 0; seclist[i] != NULL; i++) { 241 if (strcmp(tok, seclist[i]) == 0) 242 return (1); 243 } 244 return (0); 245 } 246 247 /* 248 * find_security(seclist, sec) 249 * 250 * Walk the current list of security flavors and return true if it is 251 * present, else return false. 252 */ 253 254 static int 255 find_security(struct securities *seclist, sa_security_t sec) 256 { 257 while (seclist != NULL) { 258 if (seclist->security == sec) 259 return (1); 260 seclist = seclist->next; 261 } 262 return (0); 263 } 264 265 /* 266 * make_security_list(group, securitymodes, proto) 267 * go through the list of securitymodes and add them to the 268 * group's list of security optionsets. We also keep a list of 269 * those optionsets so we don't have to find them later. All of 270 * these will get copies of the same properties. 271 */ 272 273 static struct securities * 274 make_security_list(sa_group_t group, char *securitymodes, char *proto) 275 { 276 char *tok, *next = NULL; 277 struct securities *curp, *headp = NULL, *prev; 278 sa_security_t check; 279 int freetok = 0; 280 281 for (tok = securitymodes; tok != NULL; tok = next) { 282 next = strchr(tok, ':'); 283 if (next != NULL) 284 *next++ = '\0'; 285 if (strcmp(tok, "default") == 0) { 286 /* resolve default into the real type */ 287 tok = nfs_space_alias(tok); 288 freetok = 1; 289 } 290 check = sa_get_security(group, tok, proto); 291 292 /* add to the security list if it isn't there already */ 293 if (check == NULL || !find_security(headp, check)) { 294 curp = (struct securities *)calloc(1, 295 sizeof (struct securities)); 296 if (curp != NULL) { 297 if (check == NULL) { 298 curp->security = sa_create_security( 299 group, tok, proto); 300 } else { 301 curp->security = check; 302 } 303 /* 304 * note that the first time through the loop, 305 * headp will be NULL and prev will be 306 * undefined. Since headp is NULL, we set 307 * both it and prev to the curp (first 308 * structure to be allocated). 309 * 310 * later passes through the loop will have 311 * headp not being NULL and prev will be used 312 * to allocate at the end of the list. 313 */ 314 if (headp == NULL) { 315 headp = curp; 316 prev = curp; 317 } else { 318 prev->next = curp; 319 prev = curp; 320 } 321 } 322 } 323 324 if (freetok) { 325 freetok = 0; 326 sa_free_attr_string(tok); 327 } 328 } 329 return (headp); 330 } 331 332 static void 333 free_security_list(struct securities *sec) 334 { 335 struct securities *next; 336 if (sec != NULL) { 337 for (next = sec->next; sec != NULL; sec = next) { 338 next = sec->next; 339 free(sec); 340 } 341 } 342 } 343 344 /* 345 * nfs_alistcat(str1, str2, sep) 346 * 347 * concatenate str1 and str2 into a new string using sep as a separate 348 * character. If memory allocation fails, return NULL; 349 */ 350 351 static char * 352 nfs_alistcat(char *str1, char *str2, char sep) 353 { 354 char *newstr; 355 size_t len; 356 357 len = strlen(str1) + strlen(str2) + 2; 358 newstr = (char *)malloc(len); 359 if (newstr != NULL) 360 (void) snprintf(newstr, len, "%s%c%s", str1, sep, str2); 361 return (newstr); 362 } 363 364 /* 365 * add_security_prop(sec, name, value, persist) 366 * 367 * Add the property to the securities structure. This accumulates 368 * properties for as part of parsing legacy options. 369 */ 370 371 static int 372 add_security_prop(struct securities *sec, char *name, char *value, 373 int persist, int iszfs) 374 { 375 sa_property_t prop; 376 int ret = SA_OK; 377 378 for (; sec != NULL; sec = sec->next) { 379 if (value == NULL) { 380 if (strcmp(name, SHOPT_RW) == 0 || 381 strcmp(name, SHOPT_RO) == 0) 382 value = "*"; 383 else 384 value = "true"; 385 } 386 387 /* 388 * Get the existing property, if it exists, so we can 389 * determine what to do with it. The ro/rw/root 390 * properties can be merged if multiple instances of 391 * these properies are given. For example, if "rw" 392 * exists with a value "host1" and a later token of 393 * rw="host2" is seen, the values are merged into a 394 * single rw="host1:host2". 395 */ 396 prop = sa_get_property(sec->security, name); 397 398 if (prop != NULL) { 399 char *oldvalue; 400 char *newvalue; 401 402 /* 403 * The security options of ro/rw/root might appear 404 * multiple times. If they do, the values need to be 405 * merged into an access list. If it was previously 406 * empty, the new value alone is added. 407 */ 408 oldvalue = sa_get_property_attr(prop, "value"); 409 if (oldvalue != NULL) { 410 /* 411 * The general case is to concatenate the new 412 * value onto the old value for multiple 413 * rw(ro/root) properties. A special case 414 * exists when either the old or new is the 415 * "all" case. In the special case, if both 416 * are "all", then it is "all", else if one is 417 * an access-list, that replaces the "all". 418 */ 419 if (strcmp(oldvalue, "*") == 0) { 420 /* Replace old value with new value. */ 421 newvalue = strdup(value); 422 } else if (strcmp(value, "*") == 0) { 423 /* 424 * Keep old value and ignore 425 * the new value. 426 */ 427 newvalue = NULL; 428 } else { 429 /* 430 * Make a new list of old plus new 431 * access-list. 432 */ 433 newvalue = nfs_alistcat(oldvalue, 434 value, ':'); 435 } 436 437 if (newvalue != NULL) { 438 (void) sa_remove_property(prop); 439 prop = sa_create_property(name, 440 newvalue); 441 ret = sa_add_property(sec->security, 442 prop); 443 free(newvalue); 444 } 445 if (oldvalue != NULL) 446 sa_free_attr_string(oldvalue); 447 } 448 } else { 449 prop = sa_create_property(name, value); 450 ret = sa_add_property(sec->security, prop); 451 } 452 if (ret == SA_OK && !iszfs) { 453 ret = sa_commit_properties(sec->security, !persist); 454 } 455 } 456 return (ret); 457 } 458 459 /* 460 * check to see if group/share is persistent. 461 */ 462 static int 463 is_persistent(sa_group_t group) 464 { 465 char *type; 466 int persist = 1; 467 468 type = sa_get_group_attr(group, "type"); 469 if (type != NULL && strcmp(type, "persist") != 0) 470 persist = 0; 471 if (type != NULL) 472 sa_free_attr_string(type); 473 return (persist); 474 } 475 476 /* 477 * invalid_security(options) 478 * 479 * search option string for any invalid sec= type. 480 * return true (1) if any are not valid else false (0) 481 */ 482 static int 483 invalid_security(char *options) 484 { 485 char *copy, *base, *token, *value; 486 int ret = 0; 487 488 copy = strdup(options); 489 token = base = copy; 490 while (token != NULL && ret == 0) { 491 token = strtok(base, ","); 492 base = NULL; 493 if (token != NULL) { 494 value = strchr(token, '='); 495 if (value != NULL) 496 *value++ = '\0'; 497 if (strcmp(token, "sec") == 0) { 498 /* HAVE security flavors so check them */ 499 char *tok, *next; 500 for (next = NULL, tok = value; tok != NULL; 501 tok = next) { 502 next = strchr(tok, ':'); 503 if (next != NULL) 504 *next++ = '\0'; 505 ret = !nfs_validate_security_mode(tok); 506 if (ret) 507 break; 508 } 509 } 510 } 511 } 512 if (copy != NULL) 513 free(copy); 514 return (ret); 515 } 516 517 /* 518 * nfs_parse_legacy_options(group, options) 519 * 520 * Parse the old style options into internal format and store on the 521 * specified group. Group could be a share for full legacy support. 522 */ 523 524 static int 525 nfs_parse_legacy_options(sa_group_t group, char *options) 526 { 527 char *dup = strdup(options); 528 char *base; 529 char *token; 530 sa_optionset_t optionset; 531 struct securities *security_list = NULL; 532 sa_property_t prop; 533 int ret = SA_OK; 534 int iszfs = 0; 535 sa_group_t parent; 536 int persist = 0; 537 char *lasts; 538 539 /* do we have an existing optionset? */ 540 optionset = sa_get_optionset(group, "nfs"); 541 if (optionset == NULL) { 542 /* didn't find existing optionset so create one */ 543 optionset = sa_create_optionset(group, "nfs"); 544 } else { 545 /* 546 * have an existing optionset so we need to compare 547 * options in order to detect errors. For now, we 548 * assume that the first optionset is the correct one 549 * and the others will be the same. This needs to be 550 * fixed before the final code is ready. 551 */ 552 return (ret); 553 } 554 555 if (strcmp(options, SHOPT_RW) == 0) { 556 /* 557 * there is a special case of only the option "rw" 558 * being the default option. We don't have to do 559 * anything. 560 */ 561 return (ret); 562 } 563 564 /* 565 * check if security types are present and validate them. If 566 * any are not legal, fail. 567 */ 568 569 if (invalid_security(options)) { 570 return (SA_INVALID_SECURITY); 571 } 572 573 /* 574 * in order to not attempt to change ZFS properties unless 575 * absolutely necessary, we never do it in the legacy parsing. 576 */ 577 if (sa_is_share(group)) { 578 char *zfs; 579 parent = sa_get_parent_group(group); 580 if (parent != NULL) { 581 zfs = sa_get_group_attr(parent, "zfs"); 582 if (zfs != NULL) { 583 sa_free_attr_string(zfs); 584 iszfs++; 585 } 586 } 587 } else { 588 iszfs = sa_group_is_zfs(group); 589 } 590 591 /* 592 * we need to step through each option in the string and then 593 * add either the option or the security option as needed. If 594 * this is not a persistent share, don't commit to the 595 * repository. If there is an error, we also want to abort the 596 * processing and report it. 597 */ 598 persist = is_persistent(group); 599 base = dup; 600 token = dup; 601 lasts = NULL; 602 while (token != NULL && ret == SA_OK) { 603 ret = SA_OK; 604 token = strtok_r(base, ",", &lasts); 605 base = NULL; 606 if (token != NULL) { 607 char *value; 608 /* 609 * if the option has a value, it will have an '=' to 610 * separate the name from the value. The following 611 * code will result in value != NULL and token 612 * pointing to just the name if there is a value. 613 */ 614 value = strchr(token, '='); 615 if (value != NULL) { 616 *value++ = '\0'; 617 } 618 if (strcmp(token, "sec") == 0 || 619 strcmp(token, "secure") == 0) { 620 /* 621 * Once in security parsing, we only 622 * do security. We do need to move 623 * between the security node and the 624 * toplevel. The security tag goes on 625 * the root while the following ones 626 * go on the security. 627 */ 628 if (security_list != NULL) { 629 /* 630 * have an old list so close it and 631 * start the new 632 */ 633 free_security_list(security_list); 634 } 635 if (strcmp(token, "secure") == 0) { 636 value = "dh"; 637 } else { 638 if (value == NULL) { 639 ret = SA_SYNTAX_ERR; 640 break; 641 } 642 } 643 security_list = make_security_list(group, 644 value, "nfs"); 645 } else { 646 /* 647 * Note that the "old" syntax allowed a 648 * default security model This must be 649 * accounted for and internally converted to 650 * "standard" security structure. 651 */ 652 if (nfs_is_security_opt(token)) { 653 if (security_list == NULL) { 654 /* 655 * need to have a 656 * security 657 * option. This will 658 * be "closed" when a 659 * defined "sec=" 660 * option is 661 * seen. This is 662 * technically an 663 * error but will be 664 * allowed with 665 * warning. 666 */ 667 security_list = 668 make_security_list(group, 669 "default", 670 "nfs"); 671 } 672 if (security_list != NULL) { 673 ret = add_security_prop( 674 security_list, token, 675 value, persist, iszfs); 676 } else { 677 ret = SA_NO_MEMORY; 678 } 679 } else { 680 /* regular options */ 681 if (value == NULL) { 682 if (strcmp(token, SHOPT_RW) == 683 0 || strcmp(token, 684 SHOPT_RO) == 0) { 685 value = "*"; 686 } else { 687 value = "global"; 688 if (strcmp(token, 689 SHOPT_LOG) != 0) { 690 value = "true"; 691 } 692 } 693 } 694 /* 695 * In all cases, create the 696 * property specified. If the 697 * value was NULL, the default 698 * value will have been 699 * substituted. 700 */ 701 prop = sa_create_property(token, value); 702 ret = sa_add_property(optionset, prop); 703 if (ret != SA_OK) 704 break; 705 706 if (!iszfs) { 707 ret = sa_commit_properties( 708 optionset, !persist); 709 } 710 } 711 } 712 } 713 } 714 if (security_list != NULL) 715 free_security_list(security_list); 716 if (dup != NULL) 717 free(dup); 718 return (ret); 719 } 720 721 /* 722 * is_a_number(number) 723 * 724 * is the string a number in one of the forms we want to use? 725 */ 726 727 static int 728 is_a_number(char *number) 729 { 730 int ret = 1; 731 int hex = 0; 732 733 if (strncmp(number, "0x", 2) == 0) { 734 number += 2; 735 hex = 1; 736 } else if (*number == '-') { 737 number++; /* skip the minus */ 738 } 739 while (ret == 1 && *number != '\0') { 740 if (hex) { 741 ret = isxdigit(*number++); 742 } else { 743 ret = isdigit(*number++); 744 } 745 } 746 return (ret); 747 } 748 749 /* 750 * Look for the specified tag in the configuration file. If it is found, 751 * enable logging and set the logging configuration information for exp. 752 */ 753 static void 754 configlog(struct exportdata *exp, char *tag) 755 { 756 nfsl_config_t *configlist = NULL, *configp; 757 int error = 0; 758 char globaltag[] = DEFAULTTAG; 759 760 /* 761 * Sends config errors to stderr 762 */ 763 nfsl_errs_to_syslog = B_FALSE; 764 765 /* 766 * get the list of configuration settings 767 */ 768 error = nfsl_getconfig_list(&configlist); 769 if (error) { 770 (void) fprintf(stderr, 771 dgettext(TEXT_DOMAIN, "Cannot get log configuration: %s\n"), 772 strerror(error)); 773 } 774 775 if (tag == NULL) 776 tag = globaltag; 777 if ((configp = nfsl_findconfig(configlist, tag, &error)) == NULL) { 778 nfsl_freeconfig_list(&configlist); 779 (void) fprintf(stderr, 780 dgettext(TEXT_DOMAIN, "No tags matching \"%s\"\n"), tag); 781 /* bad configuration */ 782 error = ENOENT; 783 goto err; 784 } 785 786 if ((exp->ex_tag = strdup(tag)) == NULL) { 787 error = ENOMEM; 788 goto out; 789 } 790 if ((exp->ex_log_buffer = strdup(configp->nc_bufferpath)) == NULL) { 791 error = ENOMEM; 792 goto out; 793 } 794 exp->ex_flags |= EX_LOG; 795 if (configp->nc_rpclogpath != NULL) 796 exp->ex_flags |= EX_LOG_ALLOPS; 797 out: 798 if (configlist != NULL) 799 nfsl_freeconfig_list(&configlist); 800 801 err: 802 if (error != 0) { 803 if (exp->ex_flags != NULL) 804 free(exp->ex_tag); 805 if (exp->ex_log_buffer != NULL) 806 free(exp->ex_log_buffer); 807 (void) fprintf(stderr, 808 dgettext(TEXT_DOMAIN, "Cannot set log configuration: %s\n"), 809 strerror(error)); 810 } 811 } 812 813 /* 814 * fill_export_from_optionset(export, optionset) 815 * 816 * In order to share, we need to set all the possible general options 817 * into the export structure. Share info will be filled in by the 818 * caller. Various property values get turned into structure specific 819 * values. 820 */ 821 822 static int 823 fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset) 824 { 825 sa_property_t option; 826 int ret = SA_OK; 827 828 for (option = sa_get_property(optionset, NULL); 829 option != NULL; option = sa_get_next_property(option)) { 830 char *name; 831 char *value; 832 uint32_t val; 833 834 /* 835 * since options may be set/reset multiple times, always do an 836 * explicit set or clear of the option. This allows defaults 837 * to be set and then the protocol specifici to override. 838 */ 839 840 name = sa_get_property_attr(option, "type"); 841 value = sa_get_property_attr(option, "value"); 842 switch (findopt(name)) { 843 case OPT_ANON: 844 if (value != NULL && is_a_number(value)) { 845 val = strtoul(value, NULL, 0); 846 } else { 847 struct passwd *pw; 848 pw = getpwnam(value != NULL ? value : "nobody"); 849 if (pw != NULL) { 850 val = pw->pw_uid; 851 } else { 852 val = UID_NOBODY; 853 } 854 endpwent(); 855 } 856 export->ex_anon = val; 857 break; 858 case OPT_NOSUID: 859 if (value != NULL && (strcasecmp(value, "true") == 0 || 860 strcmp(value, "1") == 0)) 861 export->ex_flags |= EX_NOSUID; 862 else 863 export->ex_flags &= ~EX_NOSUID; 864 break; 865 case OPT_ACLOK: 866 if (value != NULL && (strcasecmp(value, "true") == 0 || 867 strcmp(value, "1") == 0)) 868 export->ex_flags |= EX_ACLOK; 869 else 870 export->ex_flags &= ~EX_ACLOK; 871 break; 872 case OPT_NOSUB: 873 if (value != NULL && (strcasecmp(value, "true") == 0 || 874 strcmp(value, "1") == 0)) 875 export->ex_flags |= EX_NOSUB; 876 else 877 export->ex_flags &= ~EX_NOSUB; 878 break; 879 case OPT_PUBLIC: 880 if (value != NULL && (strcasecmp(value, "true") == 0 || 881 strcmp(value, "1") == 0)) 882 export->ex_flags |= EX_PUBLIC; 883 else 884 export->ex_flags &= ~EX_PUBLIC; 885 break; 886 case OPT_INDEX: 887 if (value != NULL && (strcmp(value, "..") == 0 || 888 strchr(value, '/') != NULL)) { 889 /* this is an error */ 890 (void) printf(dgettext(TEXT_DOMAIN, 891 "NFS: index=\"%s\" not valid;" 892 "must be a filename.\n"), 893 value); 894 break; 895 } 896 if (value != NULL && *value != '\0' && 897 strcmp(value, ".") != 0) { 898 /* valid index file string */ 899 if (export->ex_index != NULL) { 900 /* left over from "default" */ 901 free(export->ex_index); 902 } 903 /* remember to free */ 904 export->ex_index = strdup(value); 905 if (export->ex_index == NULL) { 906 (void) printf(dgettext(TEXT_DOMAIN, 907 "NFS: out of memory setting " 908 "index property\n")); 909 break; 910 } 911 export->ex_flags |= EX_INDEX; 912 } 913 break; 914 case OPT_LOG: 915 if (value == NULL) 916 value = strdup("global"); 917 if (value != NULL) 918 configlog(export, 919 strlen(value) ? value : "global"); 920 break; 921 default: 922 /* have a syntactic error */ 923 (void) printf(dgettext(TEXT_DOMAIN, 924 "NFS: unrecognized option %s=%s\n"), 925 name, value != NULL ? value : ""); 926 break; 927 } 928 if (name != NULL) 929 sa_free_attr_string(name); 930 if (value != NULL) 931 sa_free_attr_string(value); 932 } 933 return (ret); 934 } 935 936 /* 937 * cleanup_export(export) 938 * 939 * Cleanup the allocated areas so we don't leak memory 940 */ 941 942 static void 943 cleanup_export(struct exportdata *export) 944 { 945 int i; 946 947 if (export->ex_index != NULL) 948 free(export->ex_index); 949 if (export->ex_secinfo != NULL) { 950 for (i = 0; i < export->ex_seccnt; i++) 951 if (export->ex_secinfo[i].s_rootnames != NULL) 952 free(export->ex_secinfo[i].s_rootnames); 953 free(export->ex_secinfo); 954 } 955 } 956 957 /* 958 * Given a seconfig entry and a colon-separated 959 * list of names, allocate an array big enough 960 * to hold the root list, then convert each name to 961 * a principal name according to the security 962 * info and assign it to an array element. 963 * Return the array and its size. 964 */ 965 static caddr_t * 966 get_rootnames(seconfig_t *sec, char *list, int *count) 967 { 968 caddr_t *a; 969 int c, i; 970 char *host, *p; 971 972 /* 973 * Count the number of strings in the list. 974 * This is the number of colon separators + 1. 975 */ 976 c = 1; 977 for (p = list; *p; p++) 978 if (*p == ':') 979 c++; 980 *count = c; 981 982 a = (caddr_t *)malloc(c * sizeof (char *)); 983 if (a == NULL) { 984 (void) printf(dgettext(TEXT_DOMAIN, 985 "get_rootnames: no memory\n")); 986 } else { 987 for (i = 0; i < c; i++) { 988 host = strtok(list, ":"); 989 if (!nfs_get_root_principal(sec, host, &a[i])) { 990 free(a); 991 a = NULL; 992 break; 993 } 994 list = NULL; 995 } 996 } 997 998 return (a); 999 } 1000 1001 /* 1002 * fill_security_from_secopts(sp, secopts) 1003 * 1004 * Fill the secinfo structure from the secopts optionset. 1005 */ 1006 1007 static int 1008 fill_security_from_secopts(struct secinfo *sp, sa_security_t secopts) 1009 { 1010 sa_property_t prop; 1011 char *type; 1012 int longform; 1013 int err = SC_NOERROR; 1014 1015 type = sa_get_security_attr(secopts, "sectype"); 1016 if (type != NULL) { 1017 /* named security type needs secinfo to be filled in */ 1018 err = nfs_getseconfig_byname(type, &sp->s_secinfo); 1019 sa_free_attr_string(type); 1020 if (err != SC_NOERROR) 1021 return (err); 1022 } else { 1023 /* default case */ 1024 err = nfs_getseconfig_default(&sp->s_secinfo); 1025 if (err != SC_NOERROR) 1026 return (err); 1027 } 1028 1029 err = SA_OK; 1030 for (prop = sa_get_property(secopts, NULL); 1031 prop != NULL && err == SA_OK; 1032 prop = sa_get_next_property(prop)) { 1033 char *name; 1034 char *value; 1035 1036 name = sa_get_property_attr(prop, "type"); 1037 value = sa_get_property_attr(prop, "value"); 1038 1039 longform = value != NULL && strcmp(value, "*") != 0; 1040 1041 switch (findopt(name)) { 1042 case OPT_RO: 1043 sp->s_flags |= longform ? M_ROL : M_RO; 1044 break; 1045 case OPT_RW: 1046 sp->s_flags |= longform ? M_RWL : M_RW; 1047 break; 1048 case OPT_ROOT: 1049 sp->s_flags |= M_ROOT; 1050 /* 1051 * if we are using AUTH_UNIX, handle like other things 1052 * such as RO/RW 1053 */ 1054 if (sp->s_secinfo.sc_rpcnum == AUTH_UNIX) 1055 continue; 1056 /* not AUTH_UNIX */ 1057 if (value != NULL) { 1058 sp->s_rootnames = get_rootnames(&sp->s_secinfo, 1059 value, &sp->s_rootcnt); 1060 if (sp->s_rootnames == NULL) { 1061 err = SA_BAD_VALUE; 1062 (void) fprintf(stderr, 1063 dgettext(TEXT_DOMAIN, 1064 "Bad root list\n")); 1065 } 1066 } 1067 break; 1068 case OPT_WINDOW: 1069 if (value != NULL) { 1070 sp->s_window = atoi(value); 1071 /* just in case */ 1072 if (sp->s_window < 0) 1073 sp->s_window = DEF_WIN; 1074 } 1075 break; 1076 default: 1077 break; 1078 } 1079 if (name != NULL) 1080 sa_free_attr_string(name); 1081 if (value != NULL) 1082 sa_free_attr_string(value); 1083 } 1084 /* if rw/ro options not set, use default of RW */ 1085 if ((sp->s_flags & NFS_RWMODES) == 0) 1086 sp->s_flags |= M_RW; 1087 return (err); 1088 } 1089 1090 /* 1091 * This is for testing only 1092 * It displays the export structure that 1093 * goes into the kernel. 1094 */ 1095 static void 1096 printarg(char *path, struct exportdata *ep) 1097 { 1098 int i, j; 1099 struct secinfo *sp; 1100 1101 if (debug == 0) 1102 return; 1103 1104 (void) printf("%s:\n", path); 1105 (void) printf("\tex_version = %d\n", ep->ex_version); 1106 (void) printf("\tex_path = %s\n", ep->ex_path); 1107 (void) printf("\tex_pathlen = %ld\n", (ulong_t)ep->ex_pathlen); 1108 (void) printf("\tex_flags: (0x%02x) ", ep->ex_flags); 1109 if (ep->ex_flags & EX_NOSUID) 1110 (void) printf("NOSUID "); 1111 if (ep->ex_flags & EX_ACLOK) 1112 (void) printf("ACLOK "); 1113 if (ep->ex_flags & EX_PUBLIC) 1114 (void) printf("PUBLIC "); 1115 if (ep->ex_flags & EX_NOSUB) 1116 (void) printf("NOSUB "); 1117 if (ep->ex_flags & EX_LOG) 1118 (void) printf("LOG "); 1119 if (ep->ex_flags & EX_LOG_ALLOPS) 1120 (void) printf("LOG_ALLOPS "); 1121 if (ep->ex_flags == 0) 1122 (void) printf("(none)"); 1123 (void) printf("\n"); 1124 if (ep->ex_flags & EX_LOG) { 1125 (void) printf("\tex_log_buffer = %s\n", 1126 (ep->ex_log_buffer ? ep->ex_log_buffer : "(NULL)")); 1127 (void) printf("\tex_tag = %s\n", 1128 (ep->ex_tag ? ep->ex_tag : "(NULL)")); 1129 } 1130 (void) printf("\tex_anon = %d\n", ep->ex_anon); 1131 (void) printf("\tex_seccnt = %d\n", ep->ex_seccnt); 1132 (void) printf("\n"); 1133 for (i = 0; i < ep->ex_seccnt; i++) { 1134 sp = &ep->ex_secinfo[i]; 1135 (void) printf("\t\ts_secinfo = %s\n", sp->s_secinfo.sc_name); 1136 (void) printf("\t\ts_flags: (0x%02x) ", sp->s_flags); 1137 if (sp->s_flags & M_ROOT) (void) printf("M_ROOT "); 1138 if (sp->s_flags & M_RO) (void) printf("M_RO "); 1139 if (sp->s_flags & M_ROL) (void) printf("M_ROL "); 1140 if (sp->s_flags & M_RW) (void) printf("M_RW "); 1141 if (sp->s_flags & M_RWL) (void) printf("M_RWL "); 1142 if (sp->s_flags == 0) (void) printf("(none)"); 1143 (void) printf("\n"); 1144 (void) printf("\t\ts_window = %d\n", sp->s_window); 1145 (void) printf("\t\ts_rootcnt = %d ", sp->s_rootcnt); 1146 (void) fflush(stdout); 1147 for (j = 0; j < sp->s_rootcnt; j++) 1148 (void) printf("%s ", sp->s_rootnames[j] ? 1149 sp->s_rootnames[j] : "<null>"); 1150 (void) printf("\n\n"); 1151 } 1152 } 1153 1154 /* 1155 * count_security(opts) 1156 * 1157 * Count the number of security types (flavors). The optionset has 1158 * been populated with the security flavors as a holding mechanism. 1159 * We later use this number to allocate data structures. 1160 */ 1161 1162 static int 1163 count_security(sa_optionset_t opts) 1164 { 1165 int count = 0; 1166 sa_property_t prop; 1167 if (opts != NULL) { 1168 for (prop = sa_get_property(opts, NULL); prop != NULL; 1169 prop = sa_get_next_property(prop)) { 1170 count++; 1171 } 1172 } 1173 return (count); 1174 } 1175 1176 /* 1177 * nfs_sprint_option(rbuff, rbuffsize, incr, prop, sep) 1178 * 1179 * provides a mechanism to format NFS properties into legacy output 1180 * format. If the buffer would overflow, it is reallocated and grown 1181 * as appropriate. Special cases of converting internal form of values 1182 * to those used by "share" are done. this function does one property 1183 * at a time. 1184 */ 1185 1186 static void 1187 nfs_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr, 1188 sa_property_t prop, int sep) 1189 { 1190 char *name; 1191 char *value; 1192 int curlen; 1193 char *buff = *rbuff; 1194 size_t buffsize = *rbuffsize; 1195 1196 name = sa_get_property_attr(prop, "type"); 1197 value = sa_get_property_attr(prop, "value"); 1198 if (buff != NULL) 1199 curlen = strlen(buff); 1200 else 1201 curlen = 0; 1202 if (name != NULL) { 1203 int len; 1204 len = strlen(name) + sep; 1205 1206 /* 1207 * A future RFE would be to replace this with more 1208 * generic code and to possibly handle more types. 1209 */ 1210 switch (gettype(name)) { 1211 case OPT_TYPE_BOOLEAN: 1212 if (value != NULL && strcasecmp(value, "false") == 0) 1213 *name = '\0'; 1214 if (value != NULL) 1215 sa_free_attr_string(value); 1216 value = NULL; 1217 break; 1218 case OPT_TYPE_ACCLIST: 1219 if (value != NULL && strcmp(value, "*") == 0) { 1220 sa_free_attr_string(value); 1221 value = NULL; 1222 } else { 1223 if (value != NULL) 1224 len += 1 + strlen(value); 1225 } 1226 break; 1227 case OPT_TYPE_LOGTAG: 1228 if (value != NULL && strlen(value) == 0) { 1229 sa_free_attr_string(value); 1230 value = NULL; 1231 } else { 1232 if (value != NULL) 1233 len += 1 + strlen(value); 1234 } 1235 break; 1236 default: 1237 if (value != NULL) 1238 len += 1 + strlen(value); 1239 break; 1240 } 1241 while (buffsize <= (curlen + len)) { 1242 /* need more room */ 1243 buffsize += incr; 1244 buff = realloc(buff, buffsize); 1245 if (buff == NULL) { 1246 /* realloc failed so free everything */ 1247 if (*rbuff != NULL) 1248 free(*rbuff); 1249 } 1250 *rbuff = buff; 1251 *rbuffsize = buffsize; 1252 if (buff == NULL) { 1253 return; 1254 } 1255 } 1256 if (buff == NULL) 1257 return; 1258 if (value == NULL) { 1259 (void) snprintf(buff + curlen, buffsize - curlen, 1260 "%s%s", sep ? "," : "", 1261 name, value != NULL ? value : ""); 1262 } else { 1263 (void) snprintf(buff + curlen, buffsize - curlen, 1264 "%s%s=%s", sep ? "," : "", 1265 name, value != NULL ? value : ""); 1266 } 1267 } 1268 if (name != NULL) 1269 sa_free_attr_string(name); 1270 if (value != NULL) 1271 sa_free_attr_string(value); 1272 } 1273 1274 /* 1275 * nfs_format_options(group, hier) 1276 * 1277 * format all the options on the group into an old-style option 1278 * string. If hier is non-zero, walk up the tree to get inherited 1279 * options. 1280 */ 1281 1282 static char * 1283 nfs_format_options(sa_group_t group, int hier) 1284 { 1285 sa_optionset_t options = NULL; 1286 sa_optionset_t secoptions = NULL; 1287 sa_property_t prop, secprop; 1288 sa_security_t security = NULL; 1289 char *buff; 1290 size_t buffsize; 1291 char *sectype = NULL; 1292 int sep = 0; 1293 1294 1295 buff = malloc(OPT_CHUNK); 1296 if (buff == NULL) { 1297 return (NULL); 1298 } 1299 1300 buff[0] = '\0'; 1301 buffsize = OPT_CHUNK; 1302 1303 /* 1304 * We may have a an optionset relative to this item. format 1305 * these if we find them and then add any security definitions. 1306 */ 1307 1308 options = sa_get_derived_optionset(group, "nfs", hier); 1309 1310 /* 1311 * do the default set first but skip any option that is also 1312 * in the protocol specific optionset. 1313 */ 1314 if (options != NULL) { 1315 for (prop = sa_get_property(options, NULL); 1316 prop != NULL; prop = sa_get_next_property(prop)) { 1317 /* 1318 * use this one since we skipped any 1319 * of these that were also in 1320 * optdefault 1321 */ 1322 nfs_sprint_option(&buff, &buffsize, OPT_CHUNK, 1323 prop, sep); 1324 if (buff == NULL) { 1325 /* 1326 * buff could become NULL if there 1327 * isn't enough memory for 1328 * nfs_sprint_option to realloc() 1329 * as necessary. We can't really 1330 * do anything about it at this 1331 * point so we return NULL. The 1332 * caller should handle the 1333 * failure. 1334 */ 1335 if (options != NULL) 1336 sa_free_derived_optionset( 1337 options); 1338 return (buff); 1339 } 1340 sep = 1; 1341 } 1342 } 1343 secoptions = (sa_optionset_t)sa_get_all_security_types(group, 1344 "nfs", hier); 1345 if (secoptions != NULL) { 1346 for (secprop = sa_get_property(secoptions, NULL); 1347 secprop != NULL; 1348 secprop = sa_get_next_property(secprop)) { 1349 sectype = sa_get_property_attr(secprop, "type"); 1350 security = 1351 (sa_security_t)sa_get_derived_security( 1352 group, sectype, "nfs", hier); 1353 if (security != NULL) { 1354 if (sectype != NULL) { 1355 prop = sa_create_property( 1356 "sec", sectype); 1357 nfs_sprint_option(&buff, 1358 &buffsize, OPT_CHUNK, 1359 prop, sep); 1360 (void) sa_remove_property(prop); 1361 sep = 1; 1362 } 1363 for (prop = sa_get_property(security, 1364 NULL); prop != NULL; 1365 prop = sa_get_next_property(prop)) { 1366 nfs_sprint_option(&buff, 1367 &buffsize, OPT_CHUNK, prop, 1368 sep); 1369 if (buff == NULL) 1370 goto err; 1371 sep = 1; 1372 } 1373 sa_free_derived_optionset(security); 1374 } 1375 if (sectype != NULL) 1376 sa_free_attr_string(sectype); 1377 } 1378 sa_free_derived_optionset(secoptions); 1379 } 1380 1381 if (options != NULL) 1382 sa_free_derived_optionset(options); 1383 return (buff); 1384 1385 err: 1386 /* 1387 * If we couldn't allocate memory for option printing, we need 1388 * to break out of the nested loops, cleanup and return NULL. 1389 */ 1390 if (secoptions != NULL) 1391 sa_free_derived_optionset(secoptions); 1392 if (security != NULL) 1393 sa_free_derived_optionset(security); 1394 if (sectype != NULL) 1395 sa_free_attr_string(sectype); 1396 if (options != NULL) 1397 sa_free_derived_optionset(options); 1398 return (buff); 1399 } 1400 1401 /* 1402 * Append an entry to the nfslogtab file 1403 */ 1404 static int 1405 nfslogtab_add(dir, buffer, tag) 1406 char *dir, *buffer, *tag; 1407 { 1408 FILE *f; 1409 struct logtab_ent lep; 1410 int error = 0; 1411 1412 /* 1413 * Open the file for update and create it if necessary. 1414 * This may leave the I/O offset at the end of the file, 1415 * so rewind back to the beginning of the file. 1416 */ 1417 f = fopen(NFSLOGTAB, "a+"); 1418 if (f == NULL) { 1419 error = errno; 1420 goto out; 1421 } 1422 rewind(f); 1423 1424 if (lockf(fileno(f), F_LOCK, 0L) < 0) { 1425 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 1426 "share complete, however failed to lock %s " 1427 "for update: %s\n"), NFSLOGTAB, strerror(errno)); 1428 error = -1; 1429 goto out; 1430 } 1431 1432 if (logtab_deactivate_after_boot(f) == -1) { 1433 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 1434 "share complete, however could not deactivate " 1435 "entries in %s\n"), NFSLOGTAB); 1436 error = -1; 1437 goto out; 1438 } 1439 1440 /* 1441 * Remove entries matching buffer and sharepoint since we're 1442 * going to replace it with perhaps an entry with a new tag. 1443 */ 1444 if (logtab_rement(f, buffer, dir, NULL, -1)) { 1445 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 1446 "share complete, however could not remove matching " 1447 "entries in %s\n"), NFSLOGTAB); 1448 error = -1; 1449 goto out; 1450 } 1451 1452 /* 1453 * Deactivate all active entries matching this sharepoint 1454 */ 1455 if (logtab_deactivate(f, NULL, dir, NULL)) { 1456 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 1457 "share complete, however could not deactivate matching " 1458 "entries in %s\n"), NFSLOGTAB); 1459 error = -1; 1460 goto out; 1461 } 1462 1463 lep.le_buffer = buffer; 1464 lep.le_path = dir; 1465 lep.le_tag = tag; 1466 lep.le_state = LES_ACTIVE; 1467 1468 /* 1469 * Add new sharepoint / buffer location to nfslogtab 1470 */ 1471 if (logtab_putent(f, &lep) < 0) { 1472 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 1473 "share complete, however could not add %s to %s\n"), 1474 dir, NFSLOGTAB); 1475 error = -1; 1476 } 1477 1478 out: 1479 if (f != NULL) 1480 (void) fclose(f); 1481 return (error); 1482 } 1483 1484 /* 1485 * Deactivate an entry from the nfslogtab file 1486 */ 1487 static int 1488 nfslogtab_deactivate(path) 1489 char *path; 1490 { 1491 FILE *f; 1492 int error = 0; 1493 1494 f = fopen(NFSLOGTAB, "r+"); 1495 if (f == NULL) { 1496 error = errno; 1497 goto out; 1498 } 1499 if (lockf(fileno(f), F_LOCK, 0L) < 0) { 1500 error = errno; 1501 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 1502 "share complete, however could not lock %s for " 1503 "update: %s\n"), NFSLOGTAB, strerror(error)); 1504 goto out; 1505 } 1506 if (logtab_deactivate(f, NULL, path, NULL) == -1) { 1507 error = -1; 1508 (void) fprintf(stderr, 1509 dgettext(TEXT_DOMAIN, 1510 "share complete, however could not " 1511 "deactivate %s in %s\n"), path, NFSLOGTAB); 1512 goto out; 1513 } 1514 1515 out: if (f != NULL) 1516 (void) fclose(f); 1517 1518 return (error); 1519 } 1520 1521 /* 1522 * check_public(group, skipshare) 1523 * 1524 * Check the group for any shares that have the public property 1525 * enabled. We skip "skipshare" since that is the one we are 1526 * working with. This is a separate function to make handling 1527 * subgroups simpler. Returns true if there is a share with public. 1528 */ 1529 static int 1530 check_public(sa_group_t group, sa_share_t skipshare) 1531 { 1532 int exists = B_FALSE; 1533 sa_share_t share; 1534 sa_optionset_t opt; 1535 sa_property_t prop; 1536 char *shared; 1537 1538 for (share = sa_get_share(group, NULL); share != NULL; 1539 share = sa_get_next_share(share)) { 1540 if (share == skipshare) 1541 continue; 1542 1543 opt = sa_get_optionset(share, "nfs"); 1544 if (opt == NULL) 1545 continue; 1546 prop = sa_get_property(opt, "public"); 1547 if (prop == NULL) 1548 continue; 1549 shared = sa_get_share_attr(share, "shared"); 1550 if (shared != NULL) { 1551 exists = strcmp(shared, "true") == 0; 1552 sa_free_attr_string(shared); 1553 if (exists == B_TRUE) 1554 break; 1555 } 1556 } 1557 1558 return (exists); 1559 } 1560 1561 /* 1562 * public_exists(share) 1563 * 1564 * check to see if public option is set on any other share than the 1565 * one specified. Need to check zfs sub-groups as well as the top 1566 * level groups. 1567 */ 1568 static int 1569 public_exists(sa_share_t skipshare) 1570 { 1571 sa_group_t group; 1572 sa_handle_t handle; 1573 1574 group = sa_get_parent_group(skipshare); 1575 if (group == NULL) 1576 return (SA_NO_SUCH_GROUP); 1577 1578 handle = sa_find_group_handle(group); 1579 if (handle == NULL) 1580 return (SA_SYSTEM_ERR); 1581 1582 for (group = sa_get_group(handle, NULL); group != NULL; 1583 group = sa_get_next_group(group)) { 1584 /* Walk any ZFS subgroups as well as all standard groups */ 1585 if (sa_group_is_zfs(group)) { 1586 sa_group_t subgroup; 1587 for (subgroup = sa_get_sub_group(group); 1588 subgroup != NULL; 1589 subgroup = sa_get_next_group(subgroup)) { 1590 if (check_public(subgroup, skipshare)) 1591 return (B_TRUE); 1592 } 1593 } else { 1594 if (check_public(group, skipshare)) 1595 return (B_TRUE); 1596 } 1597 } 1598 return (B_FALSE); 1599 } 1600 1601 /* 1602 * sa_enable_share at the protocol level, enable_share must tell the 1603 * implementation that it is to enable the share. This entails 1604 * converting the path and options into the appropriate ioctl 1605 * calls. It is assumed that all error checking of paths, etc. were 1606 * done earlier. 1607 */ 1608 static int 1609 nfs_enable_share(sa_share_t share) 1610 { 1611 struct exportdata export; 1612 sa_optionset_t secoptlist; 1613 struct secinfo *sp; 1614 int num_secinfo; 1615 sa_optionset_t opt; 1616 sa_security_t sec; 1617 sa_property_t prop; 1618 char *path; 1619 int err = SA_OK; 1620 int i; 1621 int iszfs; 1622 1623 /* Don't drop core if the NFS module isn't loaded. */ 1624 (void) signal(SIGSYS, SIG_IGN); 1625 1626 /* get the path since it is important in several places */ 1627 path = sa_get_share_attr(share, "path"); 1628 if (path == NULL) 1629 return (SA_NO_SUCH_PATH); 1630 1631 iszfs = sa_path_is_zfs(path); 1632 /* 1633 * find the optionsets and security sets. There may not be 1634 * any or there could be one or two for each of optionset and 1635 * security may have multiple, one per security type per 1636 * protocol type. 1637 */ 1638 opt = sa_get_derived_optionset(share, "nfs", 1); 1639 secoptlist = (sa_optionset_t)sa_get_all_security_types(share, "nfs", 1); 1640 if (secoptlist != NULL) 1641 num_secinfo = MAX(1, count_security(secoptlist)); 1642 else 1643 num_secinfo = 1; 1644 1645 /* 1646 * walk through the options and fill in the structure 1647 * appropriately. 1648 */ 1649 1650 (void) memset(&export, '\0', sizeof (export)); 1651 1652 /* 1653 * do non-security options first since there is only one after 1654 * the derived group is constructed. 1655 */ 1656 export.ex_version = EX_CURRENT_VERSION; 1657 export.ex_anon = UID_NOBODY; /* this is our default value */ 1658 export.ex_index = NULL; 1659 export.ex_path = path; 1660 export.ex_pathlen = strlen(path) + 1; 1661 1662 if (opt != NULL) 1663 err = fill_export_from_optionset(&export, opt); 1664 1665 /* 1666 * check to see if "public" is set. If it is, then make sure 1667 * no other share has it set. If it is already used, fail. 1668 */ 1669 1670 if (export.ex_flags & EX_PUBLIC && public_exists(share)) { 1671 (void) printf(dgettext(TEXT_DOMAIN, 1672 "NFS: Cannot share more than one file " 1673 "system with 'public' property\n")); 1674 err = SA_NOT_ALLOWED; 1675 goto out; 1676 } 1677 1678 sp = calloc(num_secinfo, sizeof (struct secinfo)); 1679 if (sp == NULL) { 1680 err = SA_NO_MEMORY; 1681 (void) printf(dgettext(TEXT_DOMAIN, 1682 "NFS: NFS: no memory for security\n")); 1683 goto out; 1684 } 1685 export.ex_secinfo = sp; 1686 /* get default secinfo */ 1687 export.ex_seccnt = num_secinfo; 1688 /* 1689 * since we must have one security option defined, we 1690 * init to the default and then override as we find 1691 * defined security options. This handles the case 1692 * where we have no defined options but we need to set 1693 * up one. 1694 */ 1695 sp[0].s_window = DEF_WIN; 1696 sp[0].s_rootnames = NULL; 1697 /* setup a default in case no properties defined */ 1698 if (nfs_getseconfig_default(&sp[0].s_secinfo)) { 1699 (void) printf(dgettext(TEXT_DOMAIN, 1700 "NFS: nfs_getseconfig_default: failed to " 1701 "get default security mode\n")); 1702 err = SA_CONFIG_ERR; 1703 } 1704 if (secoptlist != NULL) { 1705 for (i = 0, prop = sa_get_property(secoptlist, NULL); 1706 prop != NULL && i < num_secinfo; 1707 prop = sa_get_next_property(prop), i++) { 1708 char *sectype; 1709 sectype = sa_get_property_attr(prop, "type"); 1710 /* 1711 * if sectype is NULL, we probably 1712 * have a memory problem and can't get 1713 * the correct values. Rather than 1714 * exporting with incorrect security, 1715 * don't share it. 1716 */ 1717 if (sectype == NULL) { 1718 err = SA_NO_MEMORY; 1719 (void) printf(dgettext(TEXT_DOMAIN, 1720 "NFS: Cannot share %s: " 1721 "no memory\n"), path); 1722 goto out; 1723 } 1724 sec = (sa_security_t)sa_get_derived_security( 1725 share, sectype, "nfs", 1); 1726 sp[i].s_window = DEF_WIN; 1727 sp[i].s_rootcnt = 0; 1728 sp[i].s_rootnames = NULL; 1729 (void) fill_security_from_secopts(&sp[i], sec); 1730 if (sec != NULL) 1731 sa_free_derived_security(sec); 1732 if (sectype != NULL) 1733 sa_free_attr_string(sectype); 1734 } 1735 } 1736 /* 1737 * when we get here, we can do the exportfs system call and 1738 * initiate thinsg. We probably want to enable the nfs.server 1739 * service first if it isn't running within SMF. 1740 */ 1741 /* check nfs.server status and start if needed */ 1742 /* now add the share to the internal tables */ 1743 printarg(path, &export); 1744 /* 1745 * call the exportfs system call which is implemented 1746 * via the nfssys() call as the EXPORTFS subfunction. 1747 */ 1748 if (iszfs) { 1749 struct exportfs_args ea; 1750 share_t sh; 1751 char *str; 1752 priv_set_t *priv_effective; 1753 int privileged; 1754 1755 /* 1756 * If we aren't a privileged user 1757 * and NFS server service isn't running 1758 * then print out an error message 1759 * and return EPERM 1760 */ 1761 1762 priv_effective = priv_allocset(); 1763 (void) getppriv(PRIV_EFFECTIVE, priv_effective); 1764 1765 privileged = (priv_isfullset(priv_effective) == B_TRUE); 1766 priv_freeset(priv_effective); 1767 1768 if (!privileged && 1769 (str = smf_get_state(NFS_SERVER_SVC)) != NULL) { 1770 err = 0; 1771 if (strcmp(str, SCF_STATE_STRING_ONLINE) != 0) { 1772 (void) printf(dgettext(TEXT_DOMAIN, 1773 "NFS: Cannot share remote " 1774 "filesystem: %s\n"), path); 1775 (void) printf(dgettext(TEXT_DOMAIN, 1776 "NFS: Service needs to be enabled " 1777 "by a privileged user\n")); 1778 err = SA_SYSTEM_ERR; 1779 errno = EPERM; 1780 } 1781 free(str); 1782 } 1783 1784 if (err == 0) { 1785 ea.dname = path; 1786 ea.uex = &export; 1787 1788 sa_sharetab_fill_zfs(share, &sh, "nfs"); 1789 err = sa_share_zfs(share, path, &sh, &ea, B_TRUE); 1790 sa_emptyshare(&sh); 1791 } 1792 } else { 1793 err = exportfs(path, &export); 1794 } 1795 1796 if (err < 0) { 1797 err = SA_SYSTEM_ERR; 1798 switch (errno) { 1799 case EREMOTE: 1800 (void) printf(dgettext(TEXT_DOMAIN, 1801 "NFS: Cannot share filesystems " 1802 "in non-global zones: %s\n"), path); 1803 err = SA_NOT_SUPPORTED; 1804 break; 1805 case EPERM: 1806 if (getzoneid() != GLOBAL_ZONEID) { 1807 (void) printf(dgettext(TEXT_DOMAIN, 1808 "NFS: Cannot share file systems " 1809 "in non-global zones: %s\n"), path); 1810 err = SA_NOT_SUPPORTED; 1811 break; 1812 } 1813 err = SA_NO_PERMISSION; 1814 /* FALLTHROUGH */ 1815 default: 1816 break; 1817 } 1818 } else { 1819 /* update sharetab with an add/modify */ 1820 if (!iszfs) { 1821 (void) sa_update_sharetab(share, "nfs"); 1822 } 1823 } 1824 1825 if (err == SA_OK) { 1826 /* 1827 * enable services as needed. This should probably be 1828 * done elsewhere in order to minimize the calls to 1829 * check services. 1830 */ 1831 /* 1832 * check to see if logging and other services need to 1833 * be triggered, but only if there wasn't an 1834 * error. This is probably where sharetab should be 1835 * updated with the NFS specific entry. 1836 */ 1837 if (export.ex_flags & EX_LOG) { 1838 /* enable logging */ 1839 if (nfslogtab_add(path, export.ex_log_buffer, 1840 export.ex_tag) != 0) { 1841 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 1842 "Could not enable logging for %s\n"), 1843 path); 1844 } 1845 _check_services(service_list_logging); 1846 } else { 1847 /* 1848 * don't have logging so remove it from file. It might 1849 * not be thre, but that doesn't matter. 1850 */ 1851 (void) nfslogtab_deactivate(path); 1852 _check_services(service_list_default); 1853 } 1854 } 1855 1856 out: 1857 if (path != NULL) 1858 free(path); 1859 1860 cleanup_export(&export); 1861 if (opt != NULL) 1862 sa_free_derived_optionset(opt); 1863 if (secoptlist != NULL) 1864 (void) sa_destroy_optionset(secoptlist); 1865 return (err); 1866 } 1867 1868 /* 1869 * nfs_disable_share(share) 1870 * 1871 * Unshare the specified share. How much error checking should be 1872 * done? We only do basic errors for now. 1873 */ 1874 static int 1875 nfs_disable_share(sa_share_t share, char *path) 1876 { 1877 int err; 1878 int ret = SA_OK; 1879 int iszfs; 1880 1881 1882 if (path != NULL) { 1883 iszfs = sa_path_is_zfs(path); 1884 1885 if (iszfs) { 1886 struct exportfs_args ea; 1887 share_t sh = { 0 }; 1888 1889 ea.dname = path; 1890 ea.uex = NULL; 1891 sh.sh_path = path; 1892 sh.sh_fstype = "nfs"; 1893 1894 err = sa_share_zfs(share, path, &sh, &ea, B_FALSE); 1895 } else 1896 err = exportfs(path, NULL); 1897 if (err < 0) { 1898 /* 1899 * TBD: only an error in some 1900 * cases - need better analysis 1901 */ 1902 1903 switch (errno) { 1904 case EPERM: 1905 case EACCES: 1906 ret = SA_NO_PERMISSION; 1907 if (getzoneid() != GLOBAL_ZONEID) { 1908 ret = SA_NOT_SUPPORTED; 1909 } 1910 break; 1911 case EINVAL: 1912 case ENOENT: 1913 ret = SA_NO_SUCH_PATH; 1914 break; 1915 default: 1916 ret = SA_SYSTEM_ERR; 1917 break; 1918 } 1919 } 1920 if (ret == SA_OK || ret == SA_NO_SUCH_PATH) { 1921 if (!iszfs) 1922 (void) sa_delete_sharetab(path, "nfs"); 1923 /* just in case it was logged */ 1924 (void) nfslogtab_deactivate(path); 1925 } 1926 } 1927 return (ret); 1928 } 1929 1930 /* 1931 * check ro vs rw values. Over time this may get beefed up. 1932 * for now it just does simple checks. 1933 */ 1934 1935 static int 1936 check_rorw(char *v1, char *v2) 1937 { 1938 int ret = SA_OK; 1939 if (strcmp(v1, v2) == 0) 1940 ret = SA_VALUE_CONFLICT; 1941 return (ret); 1942 } 1943 1944 /* 1945 * nfs_validate_property(property, parent) 1946 * 1947 * Check that the property has a legitimate value for its type. 1948 */ 1949 1950 static int 1951 nfs_validate_property(sa_property_t property, sa_optionset_t parent) 1952 { 1953 int ret = SA_OK; 1954 char *propname; 1955 char *other; 1956 int optindex; 1957 nfsl_config_t *configlist; 1958 sa_group_t parent_group; 1959 char *value; 1960 1961 propname = sa_get_property_attr(property, "type"); 1962 1963 if ((optindex = findopt(propname)) < 0) 1964 ret = SA_NO_SUCH_PROP; 1965 1966 /* need to validate value range here as well */ 1967 1968 if (ret == SA_OK) { 1969 parent_group = sa_get_parent_group((sa_share_t)parent); 1970 if (optdefs[optindex].share && !sa_is_share(parent_group)) 1971 ret = SA_PROP_SHARE_ONLY; 1972 } 1973 if (ret == SA_OK) { 1974 value = sa_get_property_attr(property, "value"); 1975 if (value != NULL) { 1976 /* first basic type checking */ 1977 switch (optdefs[optindex].type) { 1978 case OPT_TYPE_NUMBER: 1979 /* check that the value is all digits */ 1980 if (!is_a_number(value)) 1981 ret = SA_BAD_VALUE; 1982 break; 1983 case OPT_TYPE_BOOLEAN: 1984 if (strlen(value) == 0 || 1985 strcasecmp(value, "true") == 0 || 1986 strcmp(value, "1") == 0 || 1987 strcasecmp(value, "false") == 0 || 1988 strcmp(value, "0") == 0) { 1989 ret = SA_OK; 1990 } else { 1991 ret = SA_BAD_VALUE; 1992 } 1993 break; 1994 case OPT_TYPE_USER: 1995 if (!is_a_number(value)) { 1996 struct passwd *pw; 1997 /* 1998 * in this case it would have to be a 1999 * user name 2000 */ 2001 pw = getpwnam(value); 2002 if (pw == NULL) 2003 ret = SA_BAD_VALUE; 2004 endpwent(); 2005 } else { 2006 uint64_t intval; 2007 intval = strtoull(value, NULL, 0); 2008 if (intval > UID_MAX && intval != ~0) 2009 ret = SA_BAD_VALUE; 2010 } 2011 break; 2012 case OPT_TYPE_FILE: 2013 if (strcmp(value, "..") == 0 || 2014 strchr(value, '/') != NULL) { 2015 ret = SA_BAD_VALUE; 2016 } 2017 break; 2018 case OPT_TYPE_ACCLIST: 2019 /* 2020 * access list handling. Should eventually 2021 * validate that all the values make sense. 2022 * Also, ro and rw may have cross value 2023 * conflicts. 2024 */ 2025 if (strcmp(propname, SHOPT_RO) == 0) 2026 other = SHOPT_RW; 2027 else if (strcmp(propname, SHOPT_RW) == 0) 2028 other = SHOPT_RO; 2029 else 2030 other = NULL; 2031 2032 if (other != NULL && parent != NULL) { 2033 /* compare rw(ro) with ro(rw) */ 2034 sa_property_t oprop; 2035 oprop = sa_get_property(parent, other); 2036 if (oprop != NULL) { 2037 /* 2038 * only potential 2039 * confusion if other 2040 * exists 2041 */ 2042 char *ovalue; 2043 ovalue = sa_get_property_attr( 2044 oprop, "value"); 2045 if (ovalue != NULL) { 2046 ret = check_rorw(value, 2047 ovalue); 2048 sa_free_attr_string( 2049 ovalue); 2050 } 2051 } 2052 } 2053 break; 2054 case OPT_TYPE_LOGTAG: 2055 if (nfsl_getconfig_list(&configlist) == 0) { 2056 int error; 2057 if (value == NULL || 2058 strlen(value) == 0) { 2059 if (value != NULL) 2060 sa_free_attr_string( 2061 value); 2062 value = strdup("global"); 2063 } 2064 if (value != NULL && 2065 nfsl_findconfig(configlist, value, 2066 &error) == NULL) { 2067 ret = SA_BAD_VALUE; 2068 } else { 2069 nfsl_freeconfig_list( 2070 &configlist); 2071 } 2072 } else { 2073 ret = SA_CONFIG_ERR; 2074 } 2075 break; 2076 case OPT_TYPE_STRING: 2077 /* whatever is here should be ok */ 2078 break; 2079 case OPT_TYPE_SECURITY: 2080 /* 2081 * The "sec" property isn't used in the 2082 * non-legacy parts of sharemgr. We need to 2083 * reject it here. For legacy, it is pulled 2084 * out well before we get here. 2085 */ 2086 ret = SA_NO_SUCH_PROP; 2087 break; 2088 default: 2089 break; 2090 } 2091 sa_free_attr_string(value); 2092 if (ret == SA_OK && optdefs[optindex].check != NULL) { 2093 /* do the property specific check */ 2094 ret = optdefs[optindex].check(property); 2095 } 2096 } 2097 } 2098 2099 if (propname != NULL) 2100 sa_free_attr_string(propname); 2101 return (ret); 2102 } 2103 2104 /* 2105 * Protocol management functions 2106 * 2107 * Properties defined in the default files are defined in 2108 * proto_option_defs for parsing and validation. If "other" and 2109 * "compare" are set, then the value for this property should be 2110 * compared against the property specified in "other" using the 2111 * "compare" check (either <= or >=) in order to ensure that the 2112 * values are in the correct range. E.g. setting server_versmin 2113 * higher than server_versmax should not be allowed. 2114 */ 2115 2116 struct proto_option_defs { 2117 char *tag; 2118 char *name; /* display name -- remove protocol identifier */ 2119 int index; 2120 int type; 2121 union { 2122 int intval; 2123 char *string; 2124 } defvalue; 2125 uint32_t svcs; 2126 int32_t minval; 2127 int32_t maxval; 2128 char *file; 2129 char *other; 2130 int compare; 2131 #define OPT_CMP_GE 0 2132 #define OPT_CMP_LE 1 2133 int (*check)(char *); 2134 } proto_options[] = { 2135 #define PROTO_OPT_NFSD_SERVERS 0 2136 {"nfsd_servers", 2137 "servers", PROTO_OPT_NFSD_SERVERS, OPT_TYPE_NUMBER, 16, SVC_NFSD, 2138 1, INT32_MAX, NFSADMIN}, 2139 #define PROTO_OPT_LOCKD_LISTEN_BACKLOG 1 2140 {"lockd_listen_backlog", 2141 "lockd_listen_backlog", PROTO_OPT_LOCKD_LISTEN_BACKLOG, 2142 OPT_TYPE_NUMBER, 32, SVC_LOCKD, 32, INT32_MAX, NFSADMIN}, 2143 #define PROTO_OPT_LOCKD_SERVERS 2 2144 {"lockd_servers", 2145 "lockd_servers", PROTO_OPT_LOCKD_SERVERS, OPT_TYPE_NUMBER, 20, 2146 SVC_LOCKD, 1, INT32_MAX, NFSADMIN}, 2147 #define PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT 3 2148 {"lockd_retransmit_timeout", 2149 "lockd_retransmit_timeout", PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT, 2150 OPT_TYPE_NUMBER, 5, SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 2151 #define PROTO_OPT_GRACE_PERIOD 4 2152 {"grace_period", 2153 "grace_period", PROTO_OPT_GRACE_PERIOD, OPT_TYPE_NUMBER, 90, 2154 SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 2155 #define PROTO_OPT_NFS_SERVER_VERSMIN 5 2156 {"nfs_server_versmin", 2157 "server_versmin", PROTO_OPT_NFS_SERVER_VERSMIN, OPT_TYPE_NUMBER, 2158 (int)NFS_VERSMIN_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN, 2159 NFS_VERSMAX, NFSADMIN, "server_versmax", OPT_CMP_LE}, 2160 #define PROTO_OPT_NFS_SERVER_VERSMAX 6 2161 {"nfs_server_versmax", 2162 "server_versmax", PROTO_OPT_NFS_SERVER_VERSMAX, OPT_TYPE_NUMBER, 2163 (int)NFS_VERSMAX_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN, 2164 NFS_VERSMAX, NFSADMIN, "server_versmin", OPT_CMP_GE}, 2165 #define PROTO_OPT_NFS_CLIENT_VERSMIN 7 2166 {"nfs_client_versmin", 2167 "client_versmin", PROTO_OPT_NFS_CLIENT_VERSMIN, OPT_TYPE_NUMBER, 2168 (int)NFS_VERSMIN_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX, 2169 NFSADMIN, "client_versmax", OPT_CMP_LE}, 2170 #define PROTO_OPT_NFS_CLIENT_VERSMAX 8 2171 {"nfs_client_versmax", 2172 "client_versmax", PROTO_OPT_NFS_CLIENT_VERSMAX, OPT_TYPE_NUMBER, 2173 (int)NFS_VERSMAX_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX, 2174 NFSADMIN, "client_versmin", OPT_CMP_GE}, 2175 #define PROTO_OPT_NFS_SERVER_DELEGATION 9 2176 {"nfs_server_delegation", 2177 "server_delegation", PROTO_OPT_NFS_SERVER_DELEGATION, 2178 OPT_TYPE_ONOFF, NFS_SERVER_DELEGATION_DEFAULT, SVC_NFSD, 0, 0, 2179 NFSADMIN}, 2180 #define PROTO_OPT_NFSMAPID_DOMAIN 10 2181 {"nfsmapid_domain", 2182 "nfsmapid_domain", PROTO_OPT_NFSMAPID_DOMAIN, OPT_TYPE_DOMAIN, 2183 NULL, SVC_NFSMAPID, 0, 0, NFSADMIN}, 2184 #define PROTO_OPT_NFSD_MAX_CONNECTIONS 11 2185 {"nfsd_max_connections", 2186 "max_connections", PROTO_OPT_NFSD_MAX_CONNECTIONS, 2187 OPT_TYPE_NUMBER, -1, SVC_NFSD, -1, INT32_MAX, NFSADMIN}, 2188 #define PROTO_OPT_NFSD_PROTOCOL 12 2189 {"nfsd_protocol", 2190 "protocol", PROTO_OPT_NFSD_PROTOCOL, OPT_TYPE_PROTOCOL, 0, 2191 SVC_NFSD, 0, 0, NFSADMIN}, 2192 #define PROTO_OPT_NFSD_LISTEN_BACKLOG 13 2193 {"nfsd_listen_backlog", 2194 "listen_backlog", PROTO_OPT_NFSD_LISTEN_BACKLOG, 2195 OPT_TYPE_NUMBER, 0, 2196 SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 2197 {NULL} 2198 }; 2199 2200 /* 2201 * the protoset holds the defined options so we don't have to read 2202 * them multiple times 2203 */ 2204 sa_protocol_properties_t protoset; 2205 2206 static int 2207 findprotoopt(char *name, int whichname) 2208 { 2209 int i; 2210 for (i = 0; proto_options[i].tag != NULL; i++) { 2211 if (whichname == 1) { 2212 if (strcasecmp(proto_options[i].name, name) == 0) 2213 return (i); 2214 } else { 2215 if (strcasecmp(proto_options[i].tag, name) == 0) 2216 return (i); 2217 } 2218 } 2219 return (-1); 2220 } 2221 2222 /* 2223 * fixcaselower(str) 2224 * 2225 * convert a string to lower case (inplace). 2226 */ 2227 2228 static void 2229 fixcaselower(char *str) 2230 { 2231 while (*str) { 2232 *str = tolower(*str); 2233 str++; 2234 } 2235 } 2236 2237 /* 2238 * fixcaseupper(str) 2239 * 2240 * convert a string to upper case (inplace). 2241 */ 2242 2243 static void 2244 fixcaseupper(char *str) 2245 { 2246 while (*str) { 2247 *str = toupper(*str); 2248 str++; 2249 } 2250 } 2251 2252 /* 2253 * skipwhitespace(str) 2254 * 2255 * Skip leading white space. It is assumed that it is called with a 2256 * valid pointer. 2257 */ 2258 2259 static char * 2260 skipwhitespace(char *str) 2261 { 2262 while (*str && isspace(*str)) 2263 str++; 2264 2265 return (str); 2266 } 2267 2268 /* 2269 * extractprop() 2270 * 2271 * Extract the property and value out of the line and create the 2272 * property in the optionset. 2273 */ 2274 static void 2275 extractprop(char *name, char *value) 2276 { 2277 sa_property_t prop; 2278 int index; 2279 /* 2280 * Remove any leading 2281 * white space. 2282 */ 2283 name = skipwhitespace(name); 2284 2285 index = findprotoopt(name, 0); 2286 if (index >= 0) { 2287 fixcaselower(name); 2288 prop = sa_create_property(proto_options[index].name, value); 2289 if (prop != NULL) 2290 (void) sa_add_protocol_property(protoset, prop); 2291 } 2292 } 2293 2294 /* 2295 * initprotofromdefault() 2296 * 2297 * read the default file(s) and add the defined values to the 2298 * protoset. Note that default values are known from the built in 2299 * table in case the file doesn't have a definition. 2300 */ 2301 2302 static int 2303 initprotofromdefault() 2304 { 2305 FILE *nfs; 2306 char buff[BUFSIZ]; 2307 char *name; 2308 char *value; 2309 2310 protoset = sa_create_protocol_properties("nfs"); 2311 2312 if (protoset != NULL) { 2313 nfs = fopen(NFSADMIN, "r"); 2314 if (nfs != NULL) { 2315 while (fgets(buff, sizeof (buff), nfs) != NULL) { 2316 switch (buff[0]) { 2317 case '\n': 2318 case '#': 2319 /* skip */ 2320 break; 2321 default: 2322 name = buff; 2323 buff[strlen(buff) - 1] = '\0'; 2324 value = strchr(name, '='); 2325 if (value != NULL) { 2326 *value++ = '\0'; 2327 extractprop(name, value); 2328 } 2329 } 2330 } 2331 if (nfs != NULL) 2332 (void) fclose(nfs); 2333 } 2334 } 2335 if (protoset == NULL) 2336 return (SA_NO_MEMORY); 2337 return (SA_OK); 2338 } 2339 2340 /* 2341 * add_defaults() 2342 * 2343 * Add the default values for any property not defined in the parsing 2344 * of the default files. Values are set according to their defined 2345 * types. 2346 */ 2347 2348 static void 2349 add_defaults() 2350 { 2351 int i; 2352 char number[MAXDIGITS]; 2353 2354 for (i = 0; proto_options[i].tag != NULL; i++) { 2355 sa_property_t prop; 2356 prop = sa_get_protocol_property(protoset, 2357 proto_options[i].name); 2358 if (prop == NULL) { 2359 /* add the default value */ 2360 switch (proto_options[i].type) { 2361 case OPT_TYPE_NUMBER: 2362 (void) snprintf(number, sizeof (number), "%d", 2363 proto_options[i].defvalue.intval); 2364 prop = sa_create_property(proto_options[i].name, 2365 number); 2366 break; 2367 2368 case OPT_TYPE_BOOLEAN: 2369 prop = sa_create_property(proto_options[i].name, 2370 proto_options[i].defvalue.intval ? 2371 "true" : "false"); 2372 break; 2373 2374 case OPT_TYPE_ONOFF: 2375 prop = sa_create_property(proto_options[i].name, 2376 proto_options[i].defvalue.intval ? 2377 "on" : "off"); 2378 break; 2379 2380 default: 2381 /* treat as strings of zero length */ 2382 prop = sa_create_property(proto_options[i].name, 2383 ""); 2384 break; 2385 } 2386 if (prop != NULL) 2387 (void) sa_add_protocol_property(protoset, prop); 2388 } 2389 } 2390 } 2391 2392 static void 2393 free_protoprops() 2394 { 2395 xmlFreeNode(protoset); 2396 } 2397 2398 /* 2399 * nfs_init() 2400 * 2401 * Initialize the NFS plugin. 2402 */ 2403 2404 static int 2405 nfs_init() 2406 { 2407 int ret = SA_OK; 2408 2409 if (sa_plugin_ops.sa_init != nfs_init) 2410 (void) printf(dgettext(TEXT_DOMAIN, 2411 "NFS plugin not properly initialized\n")); 2412 2413 ret = initprotofromdefault(); 2414 if (ret == SA_OK) 2415 add_defaults(); 2416 2417 return (ret); 2418 } 2419 2420 /* 2421 * nfs_fini() 2422 * 2423 * uninitialize the NFS plugin. Want to avoid memory leaks. 2424 */ 2425 2426 static void 2427 nfs_fini() 2428 { 2429 free_protoprops(); 2430 } 2431 2432 /* 2433 * nfs_get_proto_set() 2434 * 2435 * Return an optionset with all the protocol specific properties in 2436 * it. 2437 */ 2438 2439 static sa_protocol_properties_t 2440 nfs_get_proto_set() 2441 { 2442 return (protoset); 2443 } 2444 2445 struct deffile { 2446 struct deffile *next; 2447 char *line; 2448 }; 2449 2450 /* 2451 * read_default_file(fname) 2452 * 2453 * Read the specified default file. We return a list of entries. This 2454 * get used for adding or removing values. 2455 */ 2456 2457 static struct deffile * 2458 read_default_file(char *fname) 2459 { 2460 FILE *file; 2461 struct deffile *defs = NULL; 2462 struct deffile *newdef; 2463 struct deffile *prevdef = NULL; 2464 char buff[BUFSIZ * 2]; 2465 2466 file = fopen(fname, "r"); 2467 if (file != NULL) { 2468 while (fgets(buff, sizeof (buff), file) != NULL) { 2469 newdef = (struct deffile *)calloc(1, 2470 sizeof (struct deffile)); 2471 if (newdef != NULL) { 2472 /* Make sure we skip any leading whitespace. */ 2473 newdef->line = strdup(skipwhitespace(buff)); 2474 if (defs == NULL) { 2475 prevdef = defs = newdef; 2476 } else { 2477 prevdef->next = newdef; 2478 prevdef = newdef; 2479 } 2480 } 2481 } 2482 } 2483 (void) fclose(file); 2484 return (defs); 2485 } 2486 2487 static void 2488 free_default_file(struct deffile *defs) 2489 { 2490 struct deffile *curdefs = NULL; 2491 2492 while (defs != NULL) { 2493 curdefs = defs; 2494 defs = defs->next; 2495 if (curdefs->line != NULL) 2496 free(curdefs->line); 2497 free(curdefs); 2498 } 2499 } 2500 2501 /* 2502 * write_default_file(fname, defs) 2503 * 2504 * Write the default file back. 2505 */ 2506 2507 static int 2508 write_default_file(char *fname, struct deffile *defs) 2509 { 2510 FILE *file; 2511 int ret = SA_OK; 2512 sigset_t old, new; 2513 2514 file = fopen(fname, "w+"); 2515 if (file != NULL) { 2516 (void) sigprocmask(SIG_BLOCK, NULL, &new); 2517 (void) sigaddset(&new, SIGHUP); 2518 (void) sigaddset(&new, SIGINT); 2519 (void) sigaddset(&new, SIGQUIT); 2520 (void) sigaddset(&new, SIGTSTP); 2521 (void) sigprocmask(SIG_SETMASK, &new, &old); 2522 while (defs != NULL) { 2523 (void) fputs(defs->line, file); 2524 defs = defs->next; 2525 } 2526 (void) fsync(fileno(file)); 2527 (void) sigprocmask(SIG_SETMASK, &old, NULL); 2528 (void) fclose(file); 2529 } else { 2530 switch (errno) { 2531 case EPERM: 2532 case EACCES: 2533 ret = SA_NO_PERMISSION; 2534 break; 2535 default: 2536 ret = SA_SYSTEM_ERR; 2537 } 2538 } 2539 return (ret); 2540 } 2541 2542 2543 /* 2544 * set_default_file_value(tag, value) 2545 * 2546 * Set the default file value for tag to value. Then rewrite the file. 2547 * tag and value are always set. The caller must ensure this. 2548 */ 2549 2550 #define MAX_STRING_LENGTH 256 2551 static int 2552 set_default_file_value(char *tag, char *value) 2553 { 2554 int ret = SA_OK; 2555 struct deffile *root; 2556 struct deffile *defs; 2557 struct deffile *prev; 2558 char string[MAX_STRING_LENGTH]; 2559 int len; 2560 int update = 0; 2561 2562 (void) snprintf(string, MAX_STRING_LENGTH, "%s=", tag); 2563 len = strlen(string); 2564 2565 root = defs = read_default_file(NFSADMIN); 2566 if (root == NULL) { 2567 if (errno == EPERM || errno == EACCES) 2568 ret = SA_NO_PERMISSION; 2569 else 2570 ret = SA_SYSTEM_ERR; 2571 } else { 2572 while (defs != NULL) { 2573 if (defs->line != NULL && 2574 strncasecmp(defs->line, string, len) == 0) { 2575 /* replace with the new value */ 2576 free(defs->line); 2577 fixcaseupper(tag); 2578 (void) snprintf(string, sizeof (string), 2579 "%s=%s\n", tag, value); 2580 string[MAX_STRING_LENGTH - 1] = '\0'; 2581 defs->line = strdup(string); 2582 update = 1; 2583 break; 2584 } 2585 defs = defs->next; 2586 } 2587 if (!update) { 2588 defs = root; 2589 /* didn't find, so see if it is a comment */ 2590 (void) snprintf(string, MAX_STRING_LENGTH, "#%s=", tag); 2591 len = strlen(string); 2592 while (defs != NULL) { 2593 if (strncasecmp(defs->line, string, len) == 0) { 2594 /* replace with the new value */ 2595 free(defs->line); 2596 fixcaseupper(tag); 2597 (void) snprintf(string, sizeof (string), 2598 "%s=%s\n", tag, value); 2599 string[MAX_STRING_LENGTH - 1] = '\0'; 2600 defs->line = strdup(string); 2601 update = 1; 2602 break; 2603 } 2604 defs = defs->next; 2605 } 2606 } 2607 if (!update) { 2608 fixcaseupper(tag); 2609 (void) snprintf(string, sizeof (string), "%s=%s\n", 2610 tag, value); 2611 prev = root; 2612 while (prev->next != NULL) 2613 prev = prev->next; 2614 defs = malloc(sizeof (struct deffile)); 2615 prev->next = defs; 2616 if (defs != NULL) { 2617 defs->next = NULL; 2618 defs->line = strdup(string); 2619 } 2620 } 2621 if (update) { 2622 ret = write_default_file(NFSADMIN, root); 2623 } 2624 free_default_file(root); 2625 } 2626 return (ret); 2627 } 2628 2629 /* 2630 * service_in_state(service, chkstate) 2631 * 2632 * Want to know if the specified service is in the desired state 2633 * (chkstate) or not. Return true (1) if it is and false (0) if it 2634 * isn't. 2635 */ 2636 static int 2637 service_in_state(char *service, const char *chkstate) 2638 { 2639 char *state; 2640 int ret = B_FALSE; 2641 2642 state = smf_get_state(service); 2643 if (state != NULL) { 2644 /* got the state so get the equality for the return value */ 2645 ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE; 2646 free(state); 2647 } 2648 return (ret); 2649 } 2650 2651 /* 2652 * restart_service(svcs) 2653 * 2654 * Walk through the bit mask of services that need to be restarted in 2655 * order to use the new property values. Some properties affect 2656 * multiple daemons. Should only restart a service if it is currently 2657 * enabled (online). 2658 */ 2659 2660 static void 2661 restart_service(uint32_t svcs) 2662 { 2663 uint32_t mask; 2664 int ret; 2665 char *service; 2666 2667 for (mask = 1; svcs != 0; mask <<= 1) { 2668 switch (svcs & mask) { 2669 case SVC_LOCKD: 2670 service = LOCKD; 2671 break; 2672 case SVC_STATD: 2673 service = STATD; 2674 break; 2675 case SVC_NFSD: 2676 service = NFSD; 2677 break; 2678 case SVC_MOUNTD: 2679 service = MOUNTD; 2680 break; 2681 case SVC_NFS4CBD: 2682 service = NFS4CBD; 2683 break; 2684 case SVC_NFSMAPID: 2685 service = NFSMAPID; 2686 break; 2687 case SVC_RQUOTAD: 2688 service = RQUOTAD; 2689 break; 2690 case SVC_NFSLOGD: 2691 service = NFSLOGD; 2692 break; 2693 default: 2694 continue; 2695 } 2696 2697 /* 2698 * Only attempt to restart the service if it is 2699 * currently running. In the future, it may be 2700 * desirable to use smf_refresh_instance if the NFS 2701 * services ever implement the refresh method. 2702 */ 2703 if (service_in_state(service, SCF_STATE_STRING_ONLINE)) { 2704 ret = smf_restart_instance(service); 2705 /* 2706 * There are only a few SMF errors at this point, but 2707 * it is also possible that a bad value may have put 2708 * the service into maintenance if there wasn't an 2709 * SMF level error. 2710 */ 2711 if (ret != 0) { 2712 (void) fprintf(stderr, 2713 dgettext(TEXT_DOMAIN, 2714 "%s failed to restart: %s\n"), 2715 scf_strerror(scf_error())); 2716 } else { 2717 /* 2718 * Check whether it has gone to "maintenance" 2719 * mode or not. Maintenance implies something 2720 * went wrong. 2721 */ 2722 if (service_in_state(service, 2723 SCF_STATE_STRING_MAINT)) { 2724 (void) fprintf(stderr, 2725 dgettext(TEXT_DOMAIN, 2726 "%s failed to restart\n"), 2727 service); 2728 } 2729 } 2730 } 2731 svcs &= ~mask; 2732 } 2733 } 2734 2735 /* 2736 * nfs_minmax_check(name, value) 2737 * 2738 * Verify that the value for the property specified by index is valid 2739 * relative to the opposite value in the case of a min/max variable. 2740 * Currently, server_minvers/server_maxvers and 2741 * client_minvers/client_maxvers are the only ones to check. 2742 */ 2743 2744 static int 2745 nfs_minmax_check(int index, int value) 2746 { 2747 int val; 2748 char *pval; 2749 sa_property_t prop; 2750 sa_optionset_t opts; 2751 int ret = B_TRUE; 2752 2753 if (proto_options[index].other != NULL) { 2754 /* have a property to compare against */ 2755 opts = nfs_get_proto_set(); 2756 prop = sa_get_property(opts, proto_options[index].other); 2757 /* 2758 * If we don't find the property, assume default 2759 * values which will work since the max will be at the 2760 * max and the min at the min. 2761 */ 2762 if (prop != NULL) { 2763 pval = sa_get_property_attr(prop, "value"); 2764 if (pval != NULL) { 2765 val = strtoul(pval, NULL, 0); 2766 if (proto_options[index].compare == 2767 OPT_CMP_LE) { 2768 ret = value <= val ? B_TRUE : B_FALSE; 2769 } else if (proto_options[index].compare == 2770 OPT_CMP_GE) { 2771 ret = value >= val ? B_TRUE : B_FALSE; 2772 } 2773 } 2774 } 2775 } 2776 return (ret); 2777 } 2778 2779 /* 2780 * nfs_validate_proto_prop(index, name, value) 2781 * 2782 * Verify that the property specifed by name can take the new 2783 * value. This is a sanity check to prevent bad values getting into 2784 * the default files. All values need to be checked against what is 2785 * allowed by their defined type. If a type isn't explicitly defined 2786 * here, it is treated as a string. 2787 * 2788 * Note that OPT_TYPE_NUMBER will additionally check that the value is 2789 * within the range specified and potentially against another property 2790 * value as well as specified in the proto_options members other and 2791 * compare. 2792 */ 2793 2794 static int 2795 nfs_validate_proto_prop(int index, char *name, char *value) 2796 { 2797 int ret = SA_OK; 2798 char *cp; 2799 #ifdef lint 2800 name = name; 2801 #endif 2802 2803 switch (proto_options[index].type) { 2804 case OPT_TYPE_NUMBER: 2805 if (!is_a_number(value)) 2806 ret = SA_BAD_VALUE; 2807 else { 2808 int val; 2809 val = strtoul(value, NULL, 0); 2810 if (val < proto_options[index].minval || 2811 val > proto_options[index].maxval) 2812 ret = SA_BAD_VALUE; 2813 /* 2814 * For server_versmin/server_versmax and 2815 * client_versmin/client_versmax, the value of the 2816 * min(max) should be checked to be correct relative 2817 * to the current max(min). 2818 */ 2819 if (!nfs_minmax_check(index, val)) { 2820 ret = SA_BAD_VALUE; 2821 } 2822 } 2823 break; 2824 2825 case OPT_TYPE_DOMAIN: 2826 /* 2827 * needs to be a qualified domain so will have at 2828 * least one period and other characters on either 2829 * side of it. A zero length string is also allowed 2830 * and is the way to turn off the override. 2831 */ 2832 if (strlen(value) == 0) 2833 break; 2834 cp = strchr(value, '.'); 2835 if (cp == NULL || cp == value || strchr(value, '@') != NULL) 2836 ret = SA_BAD_VALUE; 2837 break; 2838 2839 case OPT_TYPE_BOOLEAN: 2840 if (strlen(value) == 0 || 2841 strcasecmp(value, "true") == 0 || 2842 strcmp(value, "1") == 0 || 2843 strcasecmp(value, "false") == 0 || 2844 strcmp(value, "0") == 0) { 2845 ret = SA_OK; 2846 } else { 2847 ret = SA_BAD_VALUE; 2848 } 2849 break; 2850 2851 case OPT_TYPE_ONOFF: 2852 if (strcasecmp(value, "on") != 0 && 2853 strcasecmp(value, "off") != 0) { 2854 ret = SA_BAD_VALUE; 2855 } 2856 break; 2857 2858 case OPT_TYPE_PROTOCOL: 2859 if (strcasecmp(value, "all") != 0 && 2860 strcasecmp(value, "tcp") != 0 && 2861 strcasecmp(value, "udp") != 0) 2862 ret = SA_BAD_VALUE; 2863 break; 2864 2865 default: 2866 /* treat as a string */ 2867 break; 2868 } 2869 return (ret); 2870 } 2871 2872 /* 2873 * nfs_set_proto_prop(prop) 2874 * 2875 * check that prop is valid. 2876 */ 2877 2878 static int 2879 nfs_set_proto_prop(sa_property_t prop) 2880 { 2881 int ret = SA_OK; 2882 char *name; 2883 char *value; 2884 2885 name = sa_get_property_attr(prop, "type"); 2886 value = sa_get_property_attr(prop, "value"); 2887 if (name != NULL && value != NULL) { 2888 int index = findprotoopt(name, 1); 2889 if (index >= 0) { 2890 /* should test for valid value */ 2891 ret = nfs_validate_proto_prop(index, name, value); 2892 if (ret == SA_OK) 2893 ret = set_default_file_value( 2894 proto_options[index].tag, value); 2895 if (ret == SA_OK) 2896 restart_service(proto_options[index].svcs); 2897 } 2898 } 2899 if (name != NULL) 2900 sa_free_attr_string(name); 2901 if (value != NULL) 2902 sa_free_attr_string(value); 2903 return (ret); 2904 } 2905 2906 /* 2907 * nfs_get_status() 2908 * 2909 * What is the current status of the nfsd? We use the SMF state here. 2910 * Caller must free the returned value. 2911 */ 2912 2913 static char * 2914 nfs_get_status() 2915 { 2916 char *state; 2917 state = smf_get_state(NFSD); 2918 return (state != NULL ? state : strdup("-")); 2919 } 2920 2921 /* 2922 * nfs_space_alias(alias) 2923 * 2924 * Lookup the space (security) name. If it is default, convert to the 2925 * real name. 2926 */ 2927 2928 static char * 2929 nfs_space_alias(char *space) 2930 { 2931 char *name = space; 2932 seconfig_t secconf; 2933 2934 /* 2935 * Only the space named "default" is special. If it is used, 2936 * the default needs to be looked up and the real name used. 2937 * This is normally "sys" but could be changed. We always 2938 * change defautl to the real name. 2939 */ 2940 if (strcmp(space, "default") == 0 && 2941 nfs_getseconfig_default(&secconf) == 0) { 2942 if (nfs_getseconfig_bynumber(secconf.sc_nfsnum, &secconf) == 0) 2943 name = secconf.sc_name; 2944 } 2945 return (strdup(name)); 2946 } 2947