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