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