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