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