13910Sdougm /* 23910Sdougm * CDDL HEADER START 33910Sdougm * 43910Sdougm * The contents of this file are subject to the terms of the 53910Sdougm * Common Development and Distribution License (the "License"). 63910Sdougm * You may not use this file except in compliance with the License. 73910Sdougm * 83910Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93910Sdougm * or http://www.opensolaris.org/os/licensing. 103910Sdougm * See the License for the specific language governing permissions 113910Sdougm * and limitations under the License. 123910Sdougm * 133910Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143910Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153910Sdougm * If applicable, add the following below this CDDL HEADER, with the 163910Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173910Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183910Sdougm * 193910Sdougm * CDDL HEADER END 203910Sdougm */ 213910Sdougm 223910Sdougm /* 235800Sdougm * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243910Sdougm * Use is subject to license terms. 253910Sdougm */ 263910Sdougm 273910Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283910Sdougm 293910Sdougm /* 303910Sdougm * NFS specific functions 313910Sdougm */ 323910Sdougm #include <stdio.h> 333910Sdougm #include <string.h> 343910Sdougm #include <ctype.h> 353910Sdougm #include <stdlib.h> 363910Sdougm #include <unistd.h> 373910Sdougm #include <zone.h> 383910Sdougm #include <errno.h> 393910Sdougm #include <locale.h> 403910Sdougm #include <signal.h> 413910Sdougm #include "libshare.h" 423910Sdougm #include "libshare_impl.h" 433910Sdougm #include <nfs/export.h> 443910Sdougm #include <pwd.h> 453910Sdougm #include <limits.h> 463910Sdougm #include <libscf.h> 473910Sdougm #include "nfslog_config.h" 483910Sdougm #include "nfslogtab.h" 493910Sdougm #include "libshare_nfs.h" 503910Sdougm #include <rpcsvc/daemon_utils.h> 513910Sdougm #include <nfs/nfs.h> 524543Smarks #include <nfs/nfssys.h> 533910Sdougm 543910Sdougm /* should really be in some global place */ 553910Sdougm #define DEF_WIN 30000 563910Sdougm #define OPT_CHUNK 1024 573910Sdougm 583910Sdougm int debug = 0; 593910Sdougm 604543Smarks #define NFS_SERVER_SVC "svc:/network/nfs/server:default" 613910Sdougm 623910Sdougm /* internal functions */ 633910Sdougm static int nfs_init(); 643910Sdougm static void nfs_fini(); 653910Sdougm static int nfs_enable_share(sa_share_t); 664543Smarks static int nfs_disable_share(sa_share_t, char *); 673910Sdougm static int nfs_validate_property(sa_property_t, sa_optionset_t); 683910Sdougm static int nfs_validate_security_mode(char *); 693910Sdougm static int nfs_is_security_opt(char *); 703910Sdougm static int nfs_parse_legacy_options(sa_group_t, char *); 713910Sdougm static char *nfs_format_options(sa_group_t, int); 723910Sdougm static int nfs_set_proto_prop(sa_property_t); 733910Sdougm static sa_protocol_properties_t nfs_get_proto_set(); 743910Sdougm static char *nfs_get_status(); 753910Sdougm static char *nfs_space_alias(char *); 765331Samw static uint64_t nfs_features(); 773910Sdougm 783910Sdougm /* 793910Sdougm * ops vector that provides the protocol specific info and operations 803910Sdougm * for share management. 813910Sdougm */ 823910Sdougm 833910Sdougm struct sa_plugin_ops sa_plugin_ops = { 843910Sdougm SA_PLUGIN_VERSION, 853910Sdougm "nfs", 863910Sdougm nfs_init, 873910Sdougm nfs_fini, 883910Sdougm nfs_enable_share, 893910Sdougm nfs_disable_share, 903910Sdougm nfs_validate_property, 913910Sdougm nfs_validate_security_mode, 923910Sdougm nfs_is_security_opt, 933910Sdougm nfs_parse_legacy_options, 943910Sdougm nfs_format_options, 953910Sdougm nfs_set_proto_prop, 963910Sdougm nfs_get_proto_set, 973910Sdougm nfs_get_status, 983910Sdougm nfs_space_alias, 995331Samw NULL, /* update_legacy */ 1005331Samw NULL, /* delete_legacy */ 1015331Samw NULL, /* change_notify */ 1025331Samw NULL, /* enable_resource */ 1035331Samw NULL, /* disable_resource */ 1045331Samw nfs_features, 1055331Samw NULL, /* transient shares */ 1065331Samw NULL, /* notify resource */ 1076007Sthurlow NULL, /* rename_resource */ 1086007Sthurlow NULL, /* run_command */ 1096007Sthurlow NULL, /* command_help */ 1106007Sthurlow NULL /* delete_proto_section */ 1113910Sdougm }; 1123910Sdougm 1133910Sdougm /* 1143910Sdougm * list of support services needed 1153910Sdougm * defines should come from head/rpcsvc/daemon_utils.h 1163910Sdougm */ 1173910Sdougm 1183910Sdougm static char *service_list_default[] = 1193910Sdougm { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NULL }; 1203910Sdougm static char *service_list_logging[] = 1213910Sdougm { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, NULL }; 1223910Sdougm 1233910Sdougm /* 1243910Sdougm * option definitions. Make sure to keep the #define for the option 1253910Sdougm * index just before the entry it is the index for. Changing the order 1263910Sdougm * can cause breakage. E.g OPT_RW is index 1 and must precede the 1273910Sdougm * line that includes the SHOPT_RW and OPT_RW entries. 1283910Sdougm */ 1293910Sdougm 1303910Sdougm struct option_defs optdefs[] = { 1313910Sdougm #define OPT_RO 0 1323910Sdougm {SHOPT_RO, OPT_RO, OPT_TYPE_ACCLIST}, 1333910Sdougm #define OPT_RW 1 1343910Sdougm {SHOPT_RW, OPT_RW, OPT_TYPE_ACCLIST}, 1353910Sdougm #define OPT_ROOT 2 1363910Sdougm {SHOPT_ROOT, OPT_ROOT, OPT_TYPE_ACCLIST}, 1373910Sdougm #define OPT_SECURE 3 1383910Sdougm {SHOPT_SECURE, OPT_SECURE, OPT_TYPE_DEPRECATED}, 1393910Sdougm #define OPT_ANON 4 1403910Sdougm {SHOPT_ANON, OPT_ANON, OPT_TYPE_USER}, 1413910Sdougm #define OPT_WINDOW 5 1423910Sdougm {SHOPT_WINDOW, OPT_WINDOW, OPT_TYPE_NUMBER}, 1433910Sdougm #define OPT_NOSUID 6 1443910Sdougm {SHOPT_NOSUID, OPT_NOSUID, OPT_TYPE_BOOLEAN}, 1453910Sdougm #define OPT_ACLOK 7 1463910Sdougm {SHOPT_ACLOK, OPT_ACLOK, OPT_TYPE_BOOLEAN}, 1473910Sdougm #define OPT_NOSUB 8 1483910Sdougm {SHOPT_NOSUB, OPT_NOSUB, OPT_TYPE_BOOLEAN}, 1493910Sdougm #define OPT_SEC 9 1503910Sdougm {SHOPT_SEC, OPT_SEC, OPT_TYPE_SECURITY}, 1513910Sdougm #define OPT_PUBLIC 10 1523910Sdougm {SHOPT_PUBLIC, OPT_PUBLIC, OPT_TYPE_BOOLEAN, OPT_SHARE_ONLY}, 1533910Sdougm #define OPT_INDEX 11 1543910Sdougm {SHOPT_INDEX, OPT_INDEX, OPT_TYPE_FILE}, 1553910Sdougm #define OPT_LOG 12 1563910Sdougm {SHOPT_LOG, OPT_LOG, OPT_TYPE_LOGTAG}, 1573910Sdougm #define OPT_CKSUM 13 1583910Sdougm {SHOPT_CKSUM, OPT_CKSUM, OPT_TYPE_STRINGSET}, 1593910Sdougm #ifdef VOLATILE_FH_TEST /* XXX added for testing volatile fh's only */ 1603910Sdougm #define OPT_VOLFH 14 1613910Sdougm {SHOPT_VOLFH, OPT_VOLFH}, 1623910Sdougm #endif /* VOLATILE_FH_TEST */ 1633910Sdougm NULL 1643910Sdougm }; 1653910Sdougm 1663910Sdougm /* 1673910Sdougm * list of properties that are related to security flavors. 1683910Sdougm */ 1693910Sdougm static char *seclist[] = { 1703910Sdougm SHOPT_RO, 1713910Sdougm SHOPT_RW, 1723910Sdougm SHOPT_ROOT, 1733910Sdougm SHOPT_WINDOW, 1743910Sdougm NULL 1753910Sdougm }; 1763910Sdougm 1773910Sdougm /* structure for list of securities */ 1783910Sdougm struct securities { 1793910Sdougm sa_security_t security; 1803910Sdougm struct securities *next; 1813910Sdougm }; 1823910Sdougm 1833910Sdougm /* 1843910Sdougm * findopt(name) 1853910Sdougm * 1863910Sdougm * Lookup option "name" in the option table and return the table 1873910Sdougm * index. 1883910Sdougm */ 1893910Sdougm 1903910Sdougm static int 1913910Sdougm findopt(char *name) 1923910Sdougm { 1933910Sdougm int i; 1943910Sdougm if (name != NULL) { 1954345Sdougm for (i = 0; optdefs[i].tag != NULL; i++) { 1964345Sdougm if (strcmp(optdefs[i].tag, name) == 0) 1974345Sdougm return (i); 1984345Sdougm } 1993910Sdougm } 2003910Sdougm return (-1); 2013910Sdougm } 2023910Sdougm 2033910Sdougm /* 2043910Sdougm * gettype(name) 2053910Sdougm * 2063910Sdougm * Return the type of option "name". 2073910Sdougm */ 2083910Sdougm 2093910Sdougm static int 2103910Sdougm gettype(char *name) 2113910Sdougm { 2123910Sdougm int optdef; 2133910Sdougm 2143910Sdougm optdef = findopt(name); 2153910Sdougm if (optdef != -1) 2164345Sdougm return (optdefs[optdef].type); 2173910Sdougm return (OPT_TYPE_ANY); 2183910Sdougm } 2193910Sdougm 2203910Sdougm /* 2213910Sdougm * nfs_validate_security_mode(mode) 2223910Sdougm * 2233910Sdougm * is the specified mode string a valid one for use with NFS? 2243910Sdougm */ 2253910Sdougm 2263910Sdougm static int 2273910Sdougm nfs_validate_security_mode(char *mode) 2283910Sdougm { 2293910Sdougm seconfig_t secinfo; 2303910Sdougm int err; 2313910Sdougm 2323910Sdougm (void) memset(&secinfo, '\0', sizeof (secinfo)); 2333910Sdougm err = nfs_getseconfig_byname(mode, &secinfo); 2343910Sdougm if (err == SC_NOERROR) 2354345Sdougm return (1); 2363910Sdougm return (0); 2373910Sdougm } 2383910Sdougm 2393910Sdougm /* 2403910Sdougm * nfs_is_security_opt(tok) 2413910Sdougm * 2423910Sdougm * check to see if tok represents an option that is only valid in some 2433910Sdougm * security flavor. 2443910Sdougm */ 2453910Sdougm 2463910Sdougm static int 2473910Sdougm nfs_is_security_opt(char *tok) 2483910Sdougm { 2493910Sdougm int i; 2503910Sdougm 2513910Sdougm for (i = 0; seclist[i] != NULL; i++) { 2524345Sdougm if (strcmp(tok, seclist[i]) == 0) 2534345Sdougm return (1); 2543910Sdougm } 2553910Sdougm return (0); 2563910Sdougm } 2573910Sdougm 2583910Sdougm /* 2593910Sdougm * find_security(seclist, sec) 2603910Sdougm * 2613910Sdougm * Walk the current list of security flavors and return true if it is 2623910Sdougm * present, else return false. 2633910Sdougm */ 2643910Sdougm 2653910Sdougm static int 2663910Sdougm find_security(struct securities *seclist, sa_security_t sec) 2673910Sdougm { 2683910Sdougm while (seclist != NULL) { 2694345Sdougm if (seclist->security == sec) 2704345Sdougm return (1); 2714345Sdougm seclist = seclist->next; 2723910Sdougm } 2733910Sdougm return (0); 2743910Sdougm } 2753910Sdougm 2763910Sdougm /* 2773910Sdougm * make_security_list(group, securitymodes, proto) 2783910Sdougm * go through the list of securitymodes and add them to the 2793910Sdougm * group's list of security optionsets. We also keep a list of 2803910Sdougm * those optionsets so we don't have to find them later. All of 2813910Sdougm * these will get copies of the same properties. 2823910Sdougm */ 2833910Sdougm 2843910Sdougm static struct securities * 2853910Sdougm make_security_list(sa_group_t group, char *securitymodes, char *proto) 2863910Sdougm { 2873910Sdougm char *tok, *next = NULL; 2883910Sdougm struct securities *curp, *headp = NULL, *prev; 2893910Sdougm sa_security_t check; 2903910Sdougm int freetok = 0; 2913910Sdougm 2923910Sdougm for (tok = securitymodes; tok != NULL; tok = next) { 2934345Sdougm next = strchr(tok, ':'); 2944345Sdougm if (next != NULL) 2954345Sdougm *next++ = '\0'; 2964345Sdougm if (strcmp(tok, "default") == 0) { 2974345Sdougm /* resolve default into the real type */ 2984345Sdougm tok = nfs_space_alias(tok); 2994345Sdougm freetok = 1; 3004345Sdougm } 3014345Sdougm check = sa_get_security(group, tok, proto); 3023910Sdougm 3034345Sdougm /* add to the security list if it isn't there already */ 3044345Sdougm if (check == NULL || !find_security(headp, check)) { 3054345Sdougm curp = (struct securities *)calloc(1, 3064345Sdougm sizeof (struct securities)); 3074345Sdougm if (curp != NULL) { 3084345Sdougm if (check == NULL) { 3094345Sdougm curp->security = sa_create_security( 3104345Sdougm group, tok, proto); 3114345Sdougm } else { 3124345Sdougm curp->security = check; 3134345Sdougm } 3144345Sdougm /* 3154345Sdougm * note that the first time through the loop, 3164345Sdougm * headp will be NULL and prev will be 3174345Sdougm * undefined. Since headp is NULL, we set 3184345Sdougm * both it and prev to the curp (first 3194345Sdougm * structure to be allocated). 3204345Sdougm * 3214345Sdougm * later passes through the loop will have 3224345Sdougm * headp not being NULL and prev will be used 3234345Sdougm * to allocate at the end of the list. 3244345Sdougm */ 3254345Sdougm if (headp == NULL) { 3264345Sdougm headp = curp; 3274345Sdougm prev = curp; 3284345Sdougm } else { 3294345Sdougm prev->next = curp; 3304345Sdougm prev = curp; 3314345Sdougm } 3324345Sdougm } 3333910Sdougm } 3343910Sdougm 3354345Sdougm if (freetok) { 3364345Sdougm freetok = 0; 3374345Sdougm sa_free_attr_string(tok); 3384345Sdougm } 3393910Sdougm } 3403910Sdougm return (headp); 3413910Sdougm } 3423910Sdougm 3433910Sdougm static void 3443910Sdougm free_security_list(struct securities *sec) 3453910Sdougm { 3463910Sdougm struct securities *next; 3473910Sdougm if (sec != NULL) { 3484345Sdougm for (next = sec->next; sec != NULL; sec = next) { 3494345Sdougm next = sec->next; 3504345Sdougm free(sec); 3514345Sdougm } 3523910Sdougm } 3533910Sdougm } 3543910Sdougm 3553910Sdougm /* 3563910Sdougm * nfs_alistcat(str1, str2, sep) 3573910Sdougm * 3583910Sdougm * concatenate str1 and str2 into a new string using sep as a separate 3593910Sdougm * character. If memory allocation fails, return NULL; 3603910Sdougm */ 3613910Sdougm 3623910Sdougm static char * 3633910Sdougm nfs_alistcat(char *str1, char *str2, char sep) 3643910Sdougm { 3653910Sdougm char *newstr; 3663910Sdougm size_t len; 3673910Sdougm 3683910Sdougm len = strlen(str1) + strlen(str2) + 2; 3693910Sdougm newstr = (char *)malloc(len); 3703910Sdougm if (newstr != NULL) 3714345Sdougm (void) snprintf(newstr, len, "%s%c%s", str1, sep, str2); 3723910Sdougm return (newstr); 3733910Sdougm } 3743910Sdougm 3753910Sdougm /* 3763910Sdougm * add_security_prop(sec, name, value, persist) 3773910Sdougm * 3783910Sdougm * Add the property to the securities structure. This accumulates 3793910Sdougm * properties for as part of parsing legacy options. 3803910Sdougm */ 3813910Sdougm 3823910Sdougm static int 3833910Sdougm add_security_prop(struct securities *sec, char *name, char *value, 3843910Sdougm int persist, int iszfs) 3853910Sdougm { 3863910Sdougm sa_property_t prop; 3873910Sdougm int ret = SA_OK; 3883910Sdougm 3893910Sdougm for (; sec != NULL; sec = sec->next) { 3904345Sdougm if (value == NULL) { 3914345Sdougm if (strcmp(name, SHOPT_RW) == 0 || 3924345Sdougm strcmp(name, SHOPT_RO) == 0) 3934345Sdougm value = "*"; 3944345Sdougm else 3954345Sdougm value = "true"; 3964345Sdougm } 3973910Sdougm 3983910Sdougm /* 3993910Sdougm * Get the existing property, if it exists, so we can 4003910Sdougm * determine what to do with it. The ro/rw/root 4013910Sdougm * properties can be merged if multiple instances of 4023910Sdougm * these properies are given. For example, if "rw" 4033910Sdougm * exists with a value "host1" and a later token of 4043910Sdougm * rw="host2" is seen, the values are merged into a 4053910Sdougm * single rw="host1:host2". 4063910Sdougm */ 4074345Sdougm prop = sa_get_property(sec->security, name); 4083910Sdougm 4094345Sdougm if (prop != NULL) { 4104345Sdougm char *oldvalue; 4114345Sdougm char *newvalue; 4123910Sdougm 4133910Sdougm /* 4144345Sdougm * The security options of ro/rw/root might appear 4154345Sdougm * multiple times. If they do, the values need to be 4164345Sdougm * merged into an access list. If it was previously 4174345Sdougm * empty, the new value alone is added. 4183910Sdougm */ 4194345Sdougm oldvalue = sa_get_property_attr(prop, "value"); 4204345Sdougm if (oldvalue != NULL) { 4214345Sdougm /* 4224345Sdougm * The general case is to concatenate the new 4234345Sdougm * value onto the old value for multiple 4244345Sdougm * rw(ro/root) properties. A special case 4254345Sdougm * exists when either the old or new is the 4264345Sdougm * "all" case. In the special case, if both 4274345Sdougm * are "all", then it is "all", else if one is 4284345Sdougm * an access-list, that replaces the "all". 4294345Sdougm */ 4304345Sdougm if (strcmp(oldvalue, "*") == 0) { 4314345Sdougm /* Replace old value with new value. */ 4324345Sdougm newvalue = strdup(value); 4335454Sdougm } else if (strcmp(value, "*") == 0 || 4345454Sdougm strcmp(oldvalue, value) == 0) { 4354345Sdougm /* 4364345Sdougm * Keep old value and ignore 4374345Sdougm * the new value. 4384345Sdougm */ 4394345Sdougm newvalue = NULL; 4404345Sdougm } else { 4414345Sdougm /* 4424345Sdougm * Make a new list of old plus new 4434345Sdougm * access-list. 4444345Sdougm */ 4454345Sdougm newvalue = nfs_alistcat(oldvalue, 4464345Sdougm value, ':'); 4474345Sdougm } 4483910Sdougm 4494345Sdougm if (newvalue != NULL) { 4504345Sdougm (void) sa_remove_property(prop); 4514345Sdougm prop = sa_create_property(name, 4524345Sdougm newvalue); 4534345Sdougm ret = sa_add_property(sec->security, 4544345Sdougm prop); 4554345Sdougm free(newvalue); 4564345Sdougm } 4574345Sdougm if (oldvalue != NULL) 4584345Sdougm sa_free_attr_string(oldvalue); 4594345Sdougm } 4604345Sdougm } else { 4614345Sdougm prop = sa_create_property(name, value); 4623910Sdougm ret = sa_add_property(sec->security, prop); 4633910Sdougm } 4644345Sdougm if (ret == SA_OK && !iszfs) { 4654345Sdougm ret = sa_commit_properties(sec->security, !persist); 4664345Sdougm } 4673910Sdougm } 4683910Sdougm return (ret); 4693910Sdougm } 4703910Sdougm 4713910Sdougm /* 4723910Sdougm * check to see if group/share is persistent. 4733910Sdougm */ 4743910Sdougm static int 4753910Sdougm is_persistent(sa_group_t group) 4763910Sdougm { 4773910Sdougm char *type; 4783910Sdougm int persist = 1; 4793910Sdougm 4803910Sdougm type = sa_get_group_attr(group, "type"); 4813910Sdougm if (type != NULL && strcmp(type, "persist") != 0) 4824345Sdougm persist = 0; 4833910Sdougm if (type != NULL) 4844345Sdougm sa_free_attr_string(type); 4853910Sdougm return (persist); 4863910Sdougm } 4873910Sdougm 4883910Sdougm /* 4893910Sdougm * invalid_security(options) 4903910Sdougm * 4913910Sdougm * search option string for any invalid sec= type. 4923910Sdougm * return true (1) if any are not valid else false (0) 4933910Sdougm */ 4943910Sdougm static int 4953910Sdougm invalid_security(char *options) 4963910Sdougm { 4973910Sdougm char *copy, *base, *token, *value; 4983910Sdougm int ret = 0; 4993910Sdougm 5003910Sdougm copy = strdup(options); 5013910Sdougm token = base = copy; 5023910Sdougm while (token != NULL && ret == 0) { 5034345Sdougm token = strtok(base, ","); 5044345Sdougm base = NULL; 5054345Sdougm if (token != NULL) { 5064345Sdougm value = strchr(token, '='); 5074345Sdougm if (value != NULL) 5084345Sdougm *value++ = '\0'; 5094345Sdougm if (strcmp(token, "sec") == 0) { 5104345Sdougm /* HAVE security flavors so check them */ 5114345Sdougm char *tok, *next; 5124345Sdougm for (next = NULL, tok = value; tok != NULL; 5134345Sdougm tok = next) { 5144345Sdougm next = strchr(tok, ':'); 5154345Sdougm if (next != NULL) 5164345Sdougm *next++ = '\0'; 5174345Sdougm ret = !nfs_validate_security_mode(tok); 5184345Sdougm if (ret) 5194345Sdougm break; 5204345Sdougm } 5214345Sdougm } 5223910Sdougm } 5233910Sdougm } 5243910Sdougm if (copy != NULL) 5254345Sdougm free(copy); 5263910Sdougm return (ret); 5273910Sdougm } 5283910Sdougm 5293910Sdougm /* 5303910Sdougm * nfs_parse_legacy_options(group, options) 5313910Sdougm * 5323910Sdougm * Parse the old style options into internal format and store on the 5333910Sdougm * specified group. Group could be a share for full legacy support. 5343910Sdougm */ 5353910Sdougm 5363910Sdougm static int 5373910Sdougm nfs_parse_legacy_options(sa_group_t group, char *options) 5383910Sdougm { 5394704Sdougm char *dup; 5403910Sdougm char *base; 5413910Sdougm char *token; 5423910Sdougm sa_optionset_t optionset; 5433910Sdougm struct securities *security_list = NULL; 5443910Sdougm sa_property_t prop; 5453910Sdougm int ret = SA_OK; 5463910Sdougm int iszfs = 0; 5473910Sdougm sa_group_t parent; 5483910Sdougm int persist = 0; 5493910Sdougm char *lasts; 5503910Sdougm 5513910Sdougm /* do we have an existing optionset? */ 5523910Sdougm optionset = sa_get_optionset(group, "nfs"); 5533910Sdougm if (optionset == NULL) { 5544345Sdougm /* didn't find existing optionset so create one */ 5554345Sdougm optionset = sa_create_optionset(group, "nfs"); 5563910Sdougm } else { 5573910Sdougm /* 5585331Samw * Have an existing optionset . Ideally, we would need 5595331Samw * to compare options in order to detect errors. For 5605331Samw * now, we assume that the first optionset is the 5615331Samw * correct one and the others will be the same. An 5625331Samw * empty optionset is the same as no optionset so we 5635331Samw * don't want to exit in that case. Getting an empty 5645331Samw * optionset can occur with ZFS property checking. 5653910Sdougm */ 5665331Samw if (sa_get_property(optionset, NULL) != NULL) 5675331Samw return (ret); 5683910Sdougm } 5693910Sdougm 5703910Sdougm if (strcmp(options, SHOPT_RW) == 0) { 5713910Sdougm /* 5723910Sdougm * there is a special case of only the option "rw" 5733910Sdougm * being the default option. We don't have to do 5743910Sdougm * anything. 5753910Sdougm */ 5764345Sdougm return (ret); 5773910Sdougm } 5783910Sdougm 5793910Sdougm /* 5803910Sdougm * check if security types are present and validate them. If 5813910Sdougm * any are not legal, fail. 5823910Sdougm */ 5833910Sdougm 5843910Sdougm if (invalid_security(options)) { 5854345Sdougm return (SA_INVALID_SECURITY); 5863910Sdougm } 5873910Sdougm 5883910Sdougm /* 5893910Sdougm * in order to not attempt to change ZFS properties unless 5903910Sdougm * absolutely necessary, we never do it in the legacy parsing. 5913910Sdougm */ 5923910Sdougm if (sa_is_share(group)) { 5934345Sdougm char *zfs; 5944345Sdougm parent = sa_get_parent_group(group); 5954345Sdougm if (parent != NULL) { 5964345Sdougm zfs = sa_get_group_attr(parent, "zfs"); 5974345Sdougm if (zfs != NULL) { 5984345Sdougm sa_free_attr_string(zfs); 5994345Sdougm iszfs++; 6004345Sdougm } 6013910Sdougm } 6023910Sdougm } else { 6034345Sdougm iszfs = sa_group_is_zfs(group); 6043910Sdougm } 6053910Sdougm 6064704Sdougm /* We need a copy of options for the next part. */ 6074704Sdougm dup = strdup(options); 6084704Sdougm if (dup == NULL) 6094704Sdougm return (SA_NO_MEMORY); 6104704Sdougm 6113910Sdougm /* 6123910Sdougm * we need to step through each option in the string and then 6133910Sdougm * add either the option or the security option as needed. If 6143910Sdougm * this is not a persistent share, don't commit to the 6153910Sdougm * repository. If there is an error, we also want to abort the 6163910Sdougm * processing and report it. 6173910Sdougm */ 6183910Sdougm persist = is_persistent(group); 6193910Sdougm base = dup; 6203910Sdougm token = dup; 6213910Sdougm lasts = NULL; 6223910Sdougm while (token != NULL && ret == SA_OK) { 6234345Sdougm ret = SA_OK; 6244345Sdougm token = strtok_r(base, ",", &lasts); 6254345Sdougm base = NULL; 6264345Sdougm if (token != NULL) { 6274345Sdougm char *value; 6283910Sdougm /* 6294345Sdougm * if the option has a value, it will have an '=' to 6304345Sdougm * separate the name from the value. The following 6314345Sdougm * code will result in value != NULL and token 6324345Sdougm * pointing to just the name if there is a value. 6333910Sdougm */ 6344345Sdougm value = strchr(token, '='); 6354345Sdougm if (value != NULL) { 6364345Sdougm *value++ = '\0'; 6374345Sdougm } 6384345Sdougm if (strcmp(token, "sec") == 0 || 6394345Sdougm strcmp(token, "secure") == 0) { 6403910Sdougm /* 6414345Sdougm * Once in security parsing, we only 6424345Sdougm * do security. We do need to move 6434345Sdougm * between the security node and the 6444345Sdougm * toplevel. The security tag goes on 6454345Sdougm * the root while the following ones 6464345Sdougm * go on the security. 6473910Sdougm */ 6484345Sdougm if (security_list != NULL) { 6494345Sdougm /* 6504345Sdougm * have an old list so close it and 6514345Sdougm * start the new 6524345Sdougm */ 6534345Sdougm free_security_list(security_list); 6544345Sdougm } 6554345Sdougm if (strcmp(token, "secure") == 0) { 6564345Sdougm value = "dh"; 6574345Sdougm } else { 6584345Sdougm if (value == NULL) { 6594345Sdougm ret = SA_SYNTAX_ERR; 6604345Sdougm break; 6614345Sdougm } 6624345Sdougm } 6634345Sdougm security_list = make_security_list(group, 6644345Sdougm value, "nfs"); 6653910Sdougm } else { 6664345Sdougm /* 6674345Sdougm * Note that the "old" syntax allowed a 6684345Sdougm * default security model This must be 6694345Sdougm * accounted for and internally converted to 6704345Sdougm * "standard" security structure. 6714345Sdougm */ 6724345Sdougm if (nfs_is_security_opt(token)) { 6734345Sdougm if (security_list == NULL) { 6744345Sdougm /* 6754345Sdougm * need to have a 6764345Sdougm * security 6774345Sdougm * option. This will 6784345Sdougm * be "closed" when a 6794345Sdougm * defined "sec=" 6804345Sdougm * option is 6814345Sdougm * seen. This is 6824345Sdougm * technically an 6834345Sdougm * error but will be 6844345Sdougm * allowed with 6854345Sdougm * warning. 6864345Sdougm */ 6874345Sdougm security_list = 6884345Sdougm make_security_list(group, 6894345Sdougm "default", 6904345Sdougm "nfs"); 6914345Sdougm } 6924345Sdougm if (security_list != NULL) { 6934345Sdougm ret = add_security_prop( 6944345Sdougm security_list, token, 6954345Sdougm value, persist, iszfs); 6964345Sdougm } else { 6974345Sdougm ret = SA_NO_MEMORY; 6984345Sdougm } 6994345Sdougm } else { 7004345Sdougm /* regular options */ 7014345Sdougm if (value == NULL) { 7024345Sdougm if (strcmp(token, SHOPT_RW) == 7034345Sdougm 0 || strcmp(token, 7044345Sdougm SHOPT_RO) == 0) { 7054345Sdougm value = "*"; 7064345Sdougm } else { 7074345Sdougm value = "global"; 7084345Sdougm if (strcmp(token, 7094345Sdougm SHOPT_LOG) != 0) { 7104345Sdougm value = "true"; 7114345Sdougm } 7124345Sdougm } 7134345Sdougm } 7144372Sdougm /* 7154372Sdougm * In all cases, create the 7164372Sdougm * property specified. If the 7174372Sdougm * value was NULL, the default 7184372Sdougm * value will have been 7194372Sdougm * substituted. 7204372Sdougm */ 7214372Sdougm prop = sa_create_property(token, value); 7224372Sdougm ret = sa_add_property(optionset, prop); 7234372Sdougm if (ret != SA_OK) 7244372Sdougm break; 7254372Sdougm 7264345Sdougm if (!iszfs) { 7274345Sdougm ret = sa_commit_properties( 7284345Sdougm optionset, !persist); 7294345Sdougm } 7304345Sdougm } 7313910Sdougm } 7323910Sdougm } 7333910Sdougm } 7343910Sdougm if (security_list != NULL) 7354345Sdougm free_security_list(security_list); 7364704Sdougm 7374704Sdougm free(dup); 7383910Sdougm return (ret); 7393910Sdougm } 7403910Sdougm 7413910Sdougm /* 7423910Sdougm * is_a_number(number) 7433910Sdougm * 7443910Sdougm * is the string a number in one of the forms we want to use? 7453910Sdougm */ 7463910Sdougm 7473910Sdougm static int 7483910Sdougm is_a_number(char *number) 7493910Sdougm { 7503910Sdougm int ret = 1; 7513910Sdougm int hex = 0; 7523910Sdougm 7533910Sdougm if (strncmp(number, "0x", 2) == 0) { 7544345Sdougm number += 2; 7554345Sdougm hex = 1; 7564345Sdougm } else if (*number == '-') { 7574345Sdougm number++; /* skip the minus */ 7584345Sdougm } 7593910Sdougm while (ret == 1 && *number != '\0') { 7604345Sdougm if (hex) { 7614345Sdougm ret = isxdigit(*number++); 7624345Sdougm } else { 7634345Sdougm ret = isdigit(*number++); 7644345Sdougm } 7653910Sdougm } 7663910Sdougm return (ret); 7673910Sdougm } 7683910Sdougm 7693910Sdougm /* 7703910Sdougm * Look for the specified tag in the configuration file. If it is found, 7713910Sdougm * enable logging and set the logging configuration information for exp. 7723910Sdougm */ 7733910Sdougm static void 7743910Sdougm configlog(struct exportdata *exp, char *tag) 7753910Sdougm { 7763910Sdougm nfsl_config_t *configlist = NULL, *configp; 7773910Sdougm int error = 0; 7783910Sdougm char globaltag[] = DEFAULTTAG; 7793910Sdougm 7803910Sdougm /* 7813910Sdougm * Sends config errors to stderr 7823910Sdougm */ 7833910Sdougm nfsl_errs_to_syslog = B_FALSE; 7843910Sdougm 7853910Sdougm /* 7863910Sdougm * get the list of configuration settings 7873910Sdougm */ 7883910Sdougm error = nfsl_getconfig_list(&configlist); 7893910Sdougm if (error) { 7903910Sdougm (void) fprintf(stderr, 7914345Sdougm dgettext(TEXT_DOMAIN, "Cannot get log configuration: %s\n"), 7924345Sdougm strerror(error)); 7933910Sdougm } 7943910Sdougm 7953910Sdougm if (tag == NULL) 7963910Sdougm tag = globaltag; 7973910Sdougm if ((configp = nfsl_findconfig(configlist, tag, &error)) == NULL) { 7983910Sdougm nfsl_freeconfig_list(&configlist); 7993910Sdougm (void) fprintf(stderr, 8004345Sdougm dgettext(TEXT_DOMAIN, "No tags matching \"%s\"\n"), tag); 8013910Sdougm /* bad configuration */ 8023910Sdougm error = ENOENT; 8033910Sdougm goto err; 8043910Sdougm } 8053910Sdougm 8063910Sdougm if ((exp->ex_tag = strdup(tag)) == NULL) { 8073910Sdougm error = ENOMEM; 8083910Sdougm goto out; 8093910Sdougm } 8103910Sdougm if ((exp->ex_log_buffer = strdup(configp->nc_bufferpath)) == NULL) { 8113910Sdougm error = ENOMEM; 8123910Sdougm goto out; 8133910Sdougm } 8143910Sdougm exp->ex_flags |= EX_LOG; 8153910Sdougm if (configp->nc_rpclogpath != NULL) 8163910Sdougm exp->ex_flags |= EX_LOG_ALLOPS; 8173910Sdougm out: 8183910Sdougm if (configlist != NULL) 8194345Sdougm nfsl_freeconfig_list(&configlist); 8203910Sdougm 8213910Sdougm err: 8223910Sdougm if (error != 0) { 8233910Sdougm if (exp->ex_flags != NULL) 8243910Sdougm free(exp->ex_tag); 8253910Sdougm if (exp->ex_log_buffer != NULL) 8263910Sdougm free(exp->ex_log_buffer); 8273910Sdougm (void) fprintf(stderr, 8284345Sdougm dgettext(TEXT_DOMAIN, "Cannot set log configuration: %s\n"), 8294345Sdougm strerror(error)); 8303910Sdougm } 8313910Sdougm } 8323910Sdougm 8333910Sdougm /* 8343910Sdougm * fill_export_from_optionset(export, optionset) 8353910Sdougm * 8363910Sdougm * In order to share, we need to set all the possible general options 8373910Sdougm * into the export structure. Share info will be filled in by the 8383910Sdougm * caller. Various property values get turned into structure specific 8393910Sdougm * values. 8403910Sdougm */ 8413910Sdougm 8423910Sdougm static int 8433910Sdougm fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset) 8443910Sdougm { 8453910Sdougm sa_property_t option; 8463910Sdougm int ret = SA_OK; 8473910Sdougm 8483910Sdougm for (option = sa_get_property(optionset, NULL); 8494345Sdougm option != NULL; option = sa_get_next_property(option)) { 8504345Sdougm char *name; 8514345Sdougm char *value; 8524345Sdougm uint32_t val; 8533910Sdougm 8544345Sdougm /* 8554345Sdougm * since options may be set/reset multiple times, always do an 8564345Sdougm * explicit set or clear of the option. This allows defaults 8575331Samw * to be set and then the protocol specific to override. 8584345Sdougm */ 8593910Sdougm 8604345Sdougm name = sa_get_property_attr(option, "type"); 8614345Sdougm value = sa_get_property_attr(option, "value"); 8624345Sdougm switch (findopt(name)) { 8634345Sdougm case OPT_ANON: 8644345Sdougm if (value != NULL && is_a_number(value)) { 8654345Sdougm val = strtoul(value, NULL, 0); 8664345Sdougm } else { 8674345Sdougm struct passwd *pw; 8684345Sdougm pw = getpwnam(value != NULL ? value : "nobody"); 8694345Sdougm if (pw != NULL) { 8704345Sdougm val = pw->pw_uid; 8714345Sdougm } else { 8724345Sdougm val = UID_NOBODY; 8734345Sdougm } 8744345Sdougm endpwent(); 8754345Sdougm } 8764345Sdougm export->ex_anon = val; 8774345Sdougm break; 8784345Sdougm case OPT_NOSUID: 8794345Sdougm if (value != NULL && (strcasecmp(value, "true") == 0 || 8804345Sdougm strcmp(value, "1") == 0)) 8814345Sdougm export->ex_flags |= EX_NOSUID; 8824345Sdougm else 8834345Sdougm export->ex_flags &= ~EX_NOSUID; 8844345Sdougm break; 8854345Sdougm case OPT_ACLOK: 8864345Sdougm if (value != NULL && (strcasecmp(value, "true") == 0 || 8874345Sdougm strcmp(value, "1") == 0)) 8884345Sdougm export->ex_flags |= EX_ACLOK; 8894345Sdougm else 8904345Sdougm export->ex_flags &= ~EX_ACLOK; 8914345Sdougm break; 8924345Sdougm case OPT_NOSUB: 8934345Sdougm if (value != NULL && (strcasecmp(value, "true") == 0 || 8944345Sdougm strcmp(value, "1") == 0)) 8954345Sdougm export->ex_flags |= EX_NOSUB; 8964345Sdougm else 8974345Sdougm export->ex_flags &= ~EX_NOSUB; 8984345Sdougm break; 8994345Sdougm case OPT_PUBLIC: 9004345Sdougm if (value != NULL && (strcasecmp(value, "true") == 0 || 9014345Sdougm strcmp(value, "1") == 0)) 9024345Sdougm export->ex_flags |= EX_PUBLIC; 9034345Sdougm else 9044345Sdougm export->ex_flags &= ~EX_PUBLIC; 9054345Sdougm break; 9064345Sdougm case OPT_INDEX: 9074345Sdougm if (value != NULL && (strcmp(value, "..") == 0 || 9084345Sdougm strchr(value, '/') != NULL)) { 9094345Sdougm /* this is an error */ 9104345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 9114345Sdougm "NFS: index=\"%s\" not valid;" 9124345Sdougm "must be a filename.\n"), 9134345Sdougm value); 9144345Sdougm break; 9154345Sdougm } 9164345Sdougm if (value != NULL && *value != '\0' && 9174345Sdougm strcmp(value, ".") != 0) { 9184345Sdougm /* valid index file string */ 9194345Sdougm if (export->ex_index != NULL) { 9204345Sdougm /* left over from "default" */ 9214345Sdougm free(export->ex_index); 9224345Sdougm } 9234345Sdougm /* remember to free */ 9244345Sdougm export->ex_index = strdup(value); 9254345Sdougm if (export->ex_index == NULL) { 9264345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 9274345Sdougm "NFS: out of memory setting " 9284345Sdougm "index property\n")); 9294345Sdougm break; 9304345Sdougm } 9314345Sdougm export->ex_flags |= EX_INDEX; 9324345Sdougm } 9334345Sdougm break; 9344345Sdougm case OPT_LOG: 9354345Sdougm if (value == NULL) 9364345Sdougm value = strdup("global"); 9374345Sdougm if (value != NULL) 9384345Sdougm configlog(export, 9394345Sdougm strlen(value) ? value : "global"); 9404345Sdougm break; 9414345Sdougm default: 9424345Sdougm /* have a syntactic error */ 9434345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 9444345Sdougm "NFS: unrecognized option %s=%s\n"), 9454345Sdougm name, value != NULL ? value : ""); 9464345Sdougm break; 9473910Sdougm } 9484345Sdougm if (name != NULL) 9494345Sdougm sa_free_attr_string(name); 9503910Sdougm if (value != NULL) 9514345Sdougm sa_free_attr_string(value); 9523910Sdougm } 9533910Sdougm return (ret); 9543910Sdougm } 9553910Sdougm 9563910Sdougm /* 9573910Sdougm * cleanup_export(export) 9583910Sdougm * 9593910Sdougm * Cleanup the allocated areas so we don't leak memory 9603910Sdougm */ 9613910Sdougm 9623910Sdougm static void 9633910Sdougm cleanup_export(struct exportdata *export) 9643910Sdougm { 9653910Sdougm int i; 9663910Sdougm 9673910Sdougm if (export->ex_index != NULL) 9684345Sdougm free(export->ex_index); 9693910Sdougm if (export->ex_secinfo != NULL) { 9704345Sdougm for (i = 0; i < export->ex_seccnt; i++) 9714345Sdougm if (export->ex_secinfo[i].s_rootnames != NULL) 9724345Sdougm free(export->ex_secinfo[i].s_rootnames); 9734345Sdougm free(export->ex_secinfo); 9743910Sdougm } 9753910Sdougm } 9763910Sdougm 9773910Sdougm /* 9783910Sdougm * Given a seconfig entry and a colon-separated 9793910Sdougm * list of names, allocate an array big enough 9803910Sdougm * to hold the root list, then convert each name to 9813910Sdougm * a principal name according to the security 9823910Sdougm * info and assign it to an array element. 9833910Sdougm * Return the array and its size. 9843910Sdougm */ 9853910Sdougm static caddr_t * 9863910Sdougm get_rootnames(seconfig_t *sec, char *list, int *count) 9873910Sdougm { 9883910Sdougm caddr_t *a; 9893910Sdougm int c, i; 9903910Sdougm char *host, *p; 9913910Sdougm 9923910Sdougm /* 9933910Sdougm * Count the number of strings in the list. 9943910Sdougm * This is the number of colon separators + 1. 9953910Sdougm */ 9963910Sdougm c = 1; 9973910Sdougm for (p = list; *p; p++) 9983910Sdougm if (*p == ':') 9993910Sdougm c++; 10003910Sdougm *count = c; 10013910Sdougm 10023910Sdougm a = (caddr_t *)malloc(c * sizeof (char *)); 10033910Sdougm if (a == NULL) { 10043910Sdougm (void) printf(dgettext(TEXT_DOMAIN, 10054345Sdougm "get_rootnames: no memory\n")); 10063910Sdougm } else { 10074345Sdougm for (i = 0; i < c; i++) { 10084345Sdougm host = strtok(list, ":"); 10094345Sdougm if (!nfs_get_root_principal(sec, host, &a[i])) { 10104345Sdougm free(a); 10114345Sdougm a = NULL; 10124345Sdougm break; 10134345Sdougm } 10144345Sdougm list = NULL; 10153910Sdougm } 10163910Sdougm } 10173910Sdougm 10183910Sdougm return (a); 10193910Sdougm } 10203910Sdougm 10213910Sdougm /* 10223910Sdougm * fill_security_from_secopts(sp, secopts) 10233910Sdougm * 10243910Sdougm * Fill the secinfo structure from the secopts optionset. 10253910Sdougm */ 10263910Sdougm 10273910Sdougm static int 10283910Sdougm fill_security_from_secopts(struct secinfo *sp, sa_security_t secopts) 10293910Sdougm { 10303910Sdougm sa_property_t prop; 10313910Sdougm char *type; 10323910Sdougm int longform; 10333910Sdougm int err = SC_NOERROR; 10343910Sdougm 10353910Sdougm type = sa_get_security_attr(secopts, "sectype"); 10363910Sdougm if (type != NULL) { 10374345Sdougm /* named security type needs secinfo to be filled in */ 10384345Sdougm err = nfs_getseconfig_byname(type, &sp->s_secinfo); 10394345Sdougm sa_free_attr_string(type); 10404345Sdougm if (err != SC_NOERROR) 10414345Sdougm return (err); 10423910Sdougm } else { 10434345Sdougm /* default case */ 10444345Sdougm err = nfs_getseconfig_default(&sp->s_secinfo); 10454345Sdougm if (err != SC_NOERROR) 10464345Sdougm return (err); 10473910Sdougm } 10483910Sdougm 10493910Sdougm err = SA_OK; 10503910Sdougm for (prop = sa_get_property(secopts, NULL); 10514345Sdougm prop != NULL && err == SA_OK; 10524345Sdougm prop = sa_get_next_property(prop)) { 10534345Sdougm char *name; 10544345Sdougm char *value; 10553910Sdougm 10564345Sdougm name = sa_get_property_attr(prop, "type"); 10574345Sdougm value = sa_get_property_attr(prop, "value"); 10583910Sdougm 10594345Sdougm longform = value != NULL && strcmp(value, "*") != 0; 10603910Sdougm 10614345Sdougm switch (findopt(name)) { 10624345Sdougm case OPT_RO: 10634345Sdougm sp->s_flags |= longform ? M_ROL : M_RO; 10644345Sdougm break; 10654345Sdougm case OPT_RW: 10664345Sdougm sp->s_flags |= longform ? M_RWL : M_RW; 10674345Sdougm break; 10684345Sdougm case OPT_ROOT: 10694345Sdougm sp->s_flags |= M_ROOT; 10704345Sdougm /* 10714345Sdougm * if we are using AUTH_UNIX, handle like other things 10724345Sdougm * such as RO/RW 10734345Sdougm */ 10744345Sdougm if (sp->s_secinfo.sc_rpcnum == AUTH_UNIX) 10754345Sdougm continue; 10764345Sdougm /* not AUTH_UNIX */ 10774345Sdougm if (value != NULL) { 10784345Sdougm sp->s_rootnames = get_rootnames(&sp->s_secinfo, 10794345Sdougm value, &sp->s_rootcnt); 10804345Sdougm if (sp->s_rootnames == NULL) { 10814345Sdougm err = SA_BAD_VALUE; 10824345Sdougm (void) fprintf(stderr, 10834345Sdougm dgettext(TEXT_DOMAIN, 10844345Sdougm "Bad root list\n")); 10854345Sdougm } 10864345Sdougm } 10874345Sdougm break; 10884345Sdougm case OPT_WINDOW: 10894345Sdougm if (value != NULL) { 10904345Sdougm sp->s_window = atoi(value); 10914345Sdougm /* just in case */ 10924345Sdougm if (sp->s_window < 0) 10934345Sdougm sp->s_window = DEF_WIN; 10944345Sdougm } 10954345Sdougm break; 10964345Sdougm default: 10974345Sdougm break; 10983910Sdougm } 10994345Sdougm if (name != NULL) 11004345Sdougm sa_free_attr_string(name); 11014345Sdougm if (value != NULL) 11024345Sdougm sa_free_attr_string(value); 11033910Sdougm } 11043910Sdougm /* if rw/ro options not set, use default of RW */ 11053910Sdougm if ((sp->s_flags & NFS_RWMODES) == 0) 11064345Sdougm sp->s_flags |= M_RW; 11073910Sdougm return (err); 11083910Sdougm } 11093910Sdougm 11103910Sdougm /* 11113910Sdougm * This is for testing only 11123910Sdougm * It displays the export structure that 11133910Sdougm * goes into the kernel. 11143910Sdougm */ 11153910Sdougm static void 11163910Sdougm printarg(char *path, struct exportdata *ep) 11173910Sdougm { 11183910Sdougm int i, j; 11193910Sdougm struct secinfo *sp; 11203910Sdougm 11213910Sdougm if (debug == 0) 11224345Sdougm return; 11233910Sdougm 11243910Sdougm (void) printf("%s:\n", path); 11253910Sdougm (void) printf("\tex_version = %d\n", ep->ex_version); 11263910Sdougm (void) printf("\tex_path = %s\n", ep->ex_path); 11273910Sdougm (void) printf("\tex_pathlen = %ld\n", (ulong_t)ep->ex_pathlen); 11283910Sdougm (void) printf("\tex_flags: (0x%02x) ", ep->ex_flags); 11293910Sdougm if (ep->ex_flags & EX_NOSUID) 11303910Sdougm (void) printf("NOSUID "); 11313910Sdougm if (ep->ex_flags & EX_ACLOK) 11323910Sdougm (void) printf("ACLOK "); 11333910Sdougm if (ep->ex_flags & EX_PUBLIC) 11343910Sdougm (void) printf("PUBLIC "); 11353910Sdougm if (ep->ex_flags & EX_NOSUB) 11363910Sdougm (void) printf("NOSUB "); 11373910Sdougm if (ep->ex_flags & EX_LOG) 11383910Sdougm (void) printf("LOG "); 11393910Sdougm if (ep->ex_flags & EX_LOG_ALLOPS) 11403910Sdougm (void) printf("LOG_ALLOPS "); 11413910Sdougm if (ep->ex_flags == 0) 11423910Sdougm (void) printf("(none)"); 11433910Sdougm (void) printf("\n"); 11443910Sdougm if (ep->ex_flags & EX_LOG) { 11453910Sdougm (void) printf("\tex_log_buffer = %s\n", 11464345Sdougm (ep->ex_log_buffer ? ep->ex_log_buffer : "(NULL)")); 11473910Sdougm (void) printf("\tex_tag = %s\n", 11484345Sdougm (ep->ex_tag ? ep->ex_tag : "(NULL)")); 11493910Sdougm } 11503910Sdougm (void) printf("\tex_anon = %d\n", ep->ex_anon); 11513910Sdougm (void) printf("\tex_seccnt = %d\n", ep->ex_seccnt); 11523910Sdougm (void) printf("\n"); 11533910Sdougm for (i = 0; i < ep->ex_seccnt; i++) { 11543910Sdougm sp = &ep->ex_secinfo[i]; 11553910Sdougm (void) printf("\t\ts_secinfo = %s\n", sp->s_secinfo.sc_name); 11563910Sdougm (void) printf("\t\ts_flags: (0x%02x) ", sp->s_flags); 11573910Sdougm if (sp->s_flags & M_ROOT) (void) printf("M_ROOT "); 11583910Sdougm if (sp->s_flags & M_RO) (void) printf("M_RO "); 11593910Sdougm if (sp->s_flags & M_ROL) (void) printf("M_ROL "); 11603910Sdougm if (sp->s_flags & M_RW) (void) printf("M_RW "); 11613910Sdougm if (sp->s_flags & M_RWL) (void) printf("M_RWL "); 11623910Sdougm if (sp->s_flags == 0) (void) printf("(none)"); 11633910Sdougm (void) printf("\n"); 11643910Sdougm (void) printf("\t\ts_window = %d\n", sp->s_window); 11653910Sdougm (void) printf("\t\ts_rootcnt = %d ", sp->s_rootcnt); 11663910Sdougm (void) fflush(stdout); 11673910Sdougm for (j = 0; j < sp->s_rootcnt; j++) 11683910Sdougm (void) printf("%s ", sp->s_rootnames[j] ? 11694345Sdougm sp->s_rootnames[j] : "<null>"); 11703910Sdougm (void) printf("\n\n"); 11713910Sdougm } 11723910Sdougm } 11733910Sdougm 11743910Sdougm /* 11753910Sdougm * count_security(opts) 11763910Sdougm * 11773910Sdougm * Count the number of security types (flavors). The optionset has 11783910Sdougm * been populated with the security flavors as a holding mechanism. 11793910Sdougm * We later use this number to allocate data structures. 11803910Sdougm */ 11813910Sdougm 11823910Sdougm static int 11833910Sdougm count_security(sa_optionset_t opts) 11843910Sdougm { 11853910Sdougm int count = 0; 11863910Sdougm sa_property_t prop; 11873910Sdougm if (opts != NULL) { 11884345Sdougm for (prop = sa_get_property(opts, NULL); prop != NULL; 11894345Sdougm prop = sa_get_next_property(prop)) { 11904345Sdougm count++; 11914345Sdougm } 11923910Sdougm } 11933910Sdougm return (count); 11943910Sdougm } 11953910Sdougm 11963910Sdougm /* 11973910Sdougm * nfs_sprint_option(rbuff, rbuffsize, incr, prop, sep) 11983910Sdougm * 11993910Sdougm * provides a mechanism to format NFS properties into legacy output 12003910Sdougm * format. If the buffer would overflow, it is reallocated and grown 12013910Sdougm * as appropriate. Special cases of converting internal form of values 12023910Sdougm * to those used by "share" are done. this function does one property 12033910Sdougm * at a time. 12043910Sdougm */ 12053910Sdougm 12065179Sdougm static int 12073910Sdougm nfs_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr, 12083910Sdougm sa_property_t prop, int sep) 12093910Sdougm { 12103910Sdougm char *name; 12113910Sdougm char *value; 12123910Sdougm int curlen; 12133910Sdougm char *buff = *rbuff; 12143910Sdougm size_t buffsize = *rbuffsize; 12155179Sdougm int printed = B_FALSE; 12163910Sdougm 12173910Sdougm name = sa_get_property_attr(prop, "type"); 12183910Sdougm value = sa_get_property_attr(prop, "value"); 12193910Sdougm if (buff != NULL) 12204345Sdougm curlen = strlen(buff); 12213910Sdougm else 12224345Sdougm curlen = 0; 12233910Sdougm if (name != NULL) { 12244345Sdougm int len; 12254345Sdougm len = strlen(name) + sep; 12263910Sdougm 12273910Sdougm /* 12283910Sdougm * A future RFE would be to replace this with more 12293910Sdougm * generic code and to possibly handle more types. 12303910Sdougm */ 12314345Sdougm switch (gettype(name)) { 12324345Sdougm case OPT_TYPE_BOOLEAN: 12335179Sdougm /* 12345179Sdougm * For NFS, boolean value of FALSE means it 12355179Sdougm * doesn't show up in the option list at all. 12365179Sdougm */ 12374345Sdougm if (value != NULL && strcasecmp(value, "false") == 0) 12385179Sdougm goto skip; 12395179Sdougm if (value != NULL) { 12404345Sdougm sa_free_attr_string(value); 12415179Sdougm value = NULL; 12425179Sdougm } 12434345Sdougm break; 12444345Sdougm case OPT_TYPE_ACCLIST: 12454345Sdougm if (value != NULL && strcmp(value, "*") == 0) { 12464345Sdougm sa_free_attr_string(value); 12474345Sdougm value = NULL; 12484345Sdougm } else { 12494345Sdougm if (value != NULL) 12504345Sdougm len += 1 + strlen(value); 12514345Sdougm } 12524345Sdougm break; 12534345Sdougm case OPT_TYPE_LOGTAG: 12544345Sdougm if (value != NULL && strlen(value) == 0) { 12554345Sdougm sa_free_attr_string(value); 12564345Sdougm value = NULL; 12574345Sdougm } else { 12584345Sdougm if (value != NULL) 12594345Sdougm len += 1 + strlen(value); 12604345Sdougm } 12614345Sdougm break; 12624345Sdougm default: 12634345Sdougm if (value != NULL) 12644345Sdougm len += 1 + strlen(value); 12654345Sdougm break; 12663910Sdougm } 12674345Sdougm while (buffsize <= (curlen + len)) { 12684345Sdougm /* need more room */ 12694345Sdougm buffsize += incr; 12704345Sdougm buff = realloc(buff, buffsize); 12714345Sdougm if (buff == NULL) { 12724345Sdougm /* realloc failed so free everything */ 12734345Sdougm if (*rbuff != NULL) 12744345Sdougm free(*rbuff); 12754345Sdougm } 12764345Sdougm *rbuff = buff; 12774345Sdougm *rbuffsize = buffsize; 12785179Sdougm if (buff == NULL) 12795179Sdougm goto skip; 12805179Sdougm 12813910Sdougm } 12825179Sdougm 12834345Sdougm if (buff == NULL) 12845179Sdougm goto skip; 12855179Sdougm 12864345Sdougm if (value == NULL) { 12874345Sdougm (void) snprintf(buff + curlen, buffsize - curlen, 12884345Sdougm "%s%s", sep ? "," : "", 12894345Sdougm name, value != NULL ? value : ""); 12904345Sdougm } else { 12914345Sdougm (void) snprintf(buff + curlen, buffsize - curlen, 12924345Sdougm "%s%s=%s", sep ? "," : "", 12934345Sdougm name, value != NULL ? value : ""); 12943910Sdougm } 12955179Sdougm printed = B_TRUE; 12963910Sdougm } 12975179Sdougm skip: 12983910Sdougm if (name != NULL) 12994345Sdougm sa_free_attr_string(name); 13003910Sdougm if (value != NULL) 13014345Sdougm sa_free_attr_string(value); 13025179Sdougm return (printed); 13033910Sdougm } 13043910Sdougm 13053910Sdougm /* 13063910Sdougm * nfs_format_options(group, hier) 13073910Sdougm * 13083910Sdougm * format all the options on the group into an old-style option 13093910Sdougm * string. If hier is non-zero, walk up the tree to get inherited 13103910Sdougm * options. 13113910Sdougm */ 13123910Sdougm 13133910Sdougm static char * 13143910Sdougm nfs_format_options(sa_group_t group, int hier) 13153910Sdougm { 13163910Sdougm sa_optionset_t options = NULL; 13174345Sdougm sa_optionset_t secoptions = NULL; 13183910Sdougm sa_property_t prop, secprop; 13194345Sdougm sa_security_t security = NULL; 13203910Sdougm char *buff; 13213910Sdougm size_t buffsize; 13224345Sdougm char *sectype = NULL; 13234345Sdougm int sep = 0; 13244345Sdougm 13254345Sdougm 13264345Sdougm buff = malloc(OPT_CHUNK); 13274345Sdougm if (buff == NULL) { 13284345Sdougm return (NULL); 13294345Sdougm } 13304345Sdougm 13314345Sdougm buff[0] = '\0'; 13324345Sdougm buffsize = OPT_CHUNK; 13334345Sdougm 13344345Sdougm /* 13354345Sdougm * We may have a an optionset relative to this item. format 13364345Sdougm * these if we find them and then add any security definitions. 13374345Sdougm */ 13383910Sdougm 13393910Sdougm options = sa_get_derived_optionset(group, "nfs", hier); 13403910Sdougm 13413910Sdougm /* 13424345Sdougm * do the default set first but skip any option that is also 13434345Sdougm * in the protocol specific optionset. 13443910Sdougm */ 13454345Sdougm if (options != NULL) { 13464345Sdougm for (prop = sa_get_property(options, NULL); 13474345Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 13483910Sdougm /* 13494345Sdougm * use this one since we skipped any 13504345Sdougm * of these that were also in 13514345Sdougm * optdefault 13523910Sdougm */ 13535179Sdougm if (nfs_sprint_option(&buff, &buffsize, OPT_CHUNK, 13545179Sdougm prop, sep)) 13555179Sdougm sep = 1; 13564345Sdougm if (buff == NULL) { 13574345Sdougm /* 13584345Sdougm * buff could become NULL if there 13594345Sdougm * isn't enough memory for 13604345Sdougm * nfs_sprint_option to realloc() 13614345Sdougm * as necessary. We can't really 13624345Sdougm * do anything about it at this 13634345Sdougm * point so we return NULL. The 13644345Sdougm * caller should handle the 13654345Sdougm * failure. 13664345Sdougm */ 13674345Sdougm if (options != NULL) 13684345Sdougm sa_free_derived_optionset( 13694345Sdougm options); 13704345Sdougm return (buff); 13714345Sdougm } 13723910Sdougm } 13734345Sdougm } 13744345Sdougm secoptions = (sa_optionset_t)sa_get_all_security_types(group, 13754345Sdougm "nfs", hier); 13764345Sdougm if (secoptions != NULL) { 13773910Sdougm for (secprop = sa_get_property(secoptions, NULL); 13784345Sdougm secprop != NULL; 13794345Sdougm secprop = sa_get_next_property(secprop)) { 13804345Sdougm sectype = sa_get_property_attr(secprop, "type"); 13814345Sdougm security = 13824345Sdougm (sa_security_t)sa_get_derived_security( 13834345Sdougm group, sectype, "nfs", hier); 13844345Sdougm if (security != NULL) { 13854345Sdougm if (sectype != NULL) { 13864345Sdougm prop = sa_create_property( 13874345Sdougm "sec", sectype); 13885179Sdougm if (prop == NULL) 13895179Sdougm goto err; 13905179Sdougm if (nfs_sprint_option(&buff, 13915179Sdougm &buffsize, OPT_CHUNK, prop, sep)) 13925179Sdougm sep = 1; 13934345Sdougm (void) sa_remove_property(prop); 13945179Sdougm if (buff == NULL) 13955179Sdougm goto err; 13964345Sdougm } 13974345Sdougm for (prop = sa_get_property(security, 13984345Sdougm NULL); prop != NULL; 13994345Sdougm prop = sa_get_next_property(prop)) { 14005179Sdougm if (nfs_sprint_option(&buff, 14015179Sdougm &buffsize, OPT_CHUNK, prop, sep)) 14025179Sdougm sep = 1; 14034345Sdougm if (buff == NULL) 14044345Sdougm goto err; 14054345Sdougm } 14064345Sdougm sa_free_derived_optionset(security); 14073910Sdougm } 14084345Sdougm if (sectype != NULL) 14094345Sdougm sa_free_attr_string(sectype); 14103910Sdougm } 14113910Sdougm sa_free_derived_optionset(secoptions); 14123910Sdougm } 14134345Sdougm 14143910Sdougm if (options != NULL) 14154345Sdougm sa_free_derived_optionset(options); 14164345Sdougm return (buff); 14174345Sdougm 14184345Sdougm err: 14194345Sdougm /* 14204345Sdougm * If we couldn't allocate memory for option printing, we need 14214345Sdougm * to break out of the nested loops, cleanup and return NULL. 14224345Sdougm */ 14234345Sdougm if (secoptions != NULL) 14244345Sdougm sa_free_derived_optionset(secoptions); 14254345Sdougm if (security != NULL) 14264345Sdougm sa_free_derived_optionset(security); 14274345Sdougm if (sectype != NULL) 14284345Sdougm sa_free_attr_string(sectype); 14294345Sdougm if (options != NULL) 14304345Sdougm sa_free_derived_optionset(options); 14313910Sdougm return (buff); 14323910Sdougm } 14334345Sdougm 14343910Sdougm /* 14353910Sdougm * Append an entry to the nfslogtab file 14363910Sdougm */ 14373910Sdougm static int 14383910Sdougm nfslogtab_add(dir, buffer, tag) 14393910Sdougm char *dir, *buffer, *tag; 14403910Sdougm { 14413910Sdougm FILE *f; 14423910Sdougm struct logtab_ent lep; 14433910Sdougm int error = 0; 14443910Sdougm 14453910Sdougm /* 14463910Sdougm * Open the file for update and create it if necessary. 14473910Sdougm * This may leave the I/O offset at the end of the file, 14483910Sdougm * so rewind back to the beginning of the file. 14493910Sdougm */ 14503910Sdougm f = fopen(NFSLOGTAB, "a+"); 14513910Sdougm if (f == NULL) { 14523910Sdougm error = errno; 14533910Sdougm goto out; 14543910Sdougm } 14553910Sdougm rewind(f); 14563910Sdougm 14573910Sdougm if (lockf(fileno(f), F_LOCK, 0L) < 0) { 14583910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 14594345Sdougm "share complete, however failed to lock %s " 14604345Sdougm "for update: %s\n"), NFSLOGTAB, strerror(errno)); 14613910Sdougm error = -1; 14623910Sdougm goto out; 14633910Sdougm } 14643910Sdougm 14653910Sdougm if (logtab_deactivate_after_boot(f) == -1) { 14663910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 14674345Sdougm "share complete, however could not deactivate " 14684345Sdougm "entries in %s\n"), NFSLOGTAB); 14693910Sdougm error = -1; 14703910Sdougm goto out; 14713910Sdougm } 14723910Sdougm 14733910Sdougm /* 14743910Sdougm * Remove entries matching buffer and sharepoint since we're 14753910Sdougm * going to replace it with perhaps an entry with a new tag. 14763910Sdougm */ 14773910Sdougm if (logtab_rement(f, buffer, dir, NULL, -1)) { 14783910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 14794345Sdougm "share complete, however could not remove matching " 14804345Sdougm "entries in %s\n"), NFSLOGTAB); 14813910Sdougm error = -1; 14823910Sdougm goto out; 14833910Sdougm } 14843910Sdougm 14853910Sdougm /* 14863910Sdougm * Deactivate all active entries matching this sharepoint 14873910Sdougm */ 14883910Sdougm if (logtab_deactivate(f, NULL, dir, NULL)) { 14893910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 14904345Sdougm "share complete, however could not deactivate matching " 14914345Sdougm "entries in %s\n"), NFSLOGTAB); 14923910Sdougm error = -1; 14933910Sdougm goto out; 14943910Sdougm } 14953910Sdougm 14963910Sdougm lep.le_buffer = buffer; 14973910Sdougm lep.le_path = dir; 14983910Sdougm lep.le_tag = tag; 14993910Sdougm lep.le_state = LES_ACTIVE; 15003910Sdougm 15013910Sdougm /* 15023910Sdougm * Add new sharepoint / buffer location to nfslogtab 15033910Sdougm */ 15043910Sdougm if (logtab_putent(f, &lep) < 0) { 15053910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 15064345Sdougm "share complete, however could not add %s to %s\n"), 15074345Sdougm dir, NFSLOGTAB); 15083910Sdougm error = -1; 15093910Sdougm } 15103910Sdougm 15113910Sdougm out: 15123910Sdougm if (f != NULL) 15133910Sdougm (void) fclose(f); 15143910Sdougm return (error); 15153910Sdougm } 15163910Sdougm 15173910Sdougm /* 15183910Sdougm * Deactivate an entry from the nfslogtab file 15193910Sdougm */ 15203910Sdougm static int 15213910Sdougm nfslogtab_deactivate(path) 15223910Sdougm char *path; 15233910Sdougm { 15243910Sdougm FILE *f; 15253910Sdougm int error = 0; 15263910Sdougm 15273910Sdougm f = fopen(NFSLOGTAB, "r+"); 15283910Sdougm if (f == NULL) { 15293910Sdougm error = errno; 15303910Sdougm goto out; 15313910Sdougm } 15323910Sdougm if (lockf(fileno(f), F_LOCK, 0L) < 0) { 15333910Sdougm error = errno; 15343910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 15354345Sdougm "share complete, however could not lock %s for " 15364345Sdougm "update: %s\n"), NFSLOGTAB, strerror(error)); 15373910Sdougm goto out; 15383910Sdougm } 15393910Sdougm if (logtab_deactivate(f, NULL, path, NULL) == -1) { 15403910Sdougm error = -1; 15413910Sdougm (void) fprintf(stderr, 15424345Sdougm dgettext(TEXT_DOMAIN, 15434345Sdougm "share complete, however could not " 15444345Sdougm "deactivate %s in %s\n"), path, NFSLOGTAB); 15453910Sdougm goto out; 15463910Sdougm } 15473910Sdougm 15483910Sdougm out: if (f != NULL) 15493910Sdougm (void) fclose(f); 15503910Sdougm 15513910Sdougm return (error); 15523910Sdougm } 15533910Sdougm 15543910Sdougm /* 15554524Sdougm * check_public(group, skipshare) 15564524Sdougm * 15574524Sdougm * Check the group for any shares that have the public property 15584524Sdougm * enabled. We skip "skipshare" since that is the one we are 15594524Sdougm * working with. This is a separate function to make handling 15604524Sdougm * subgroups simpler. Returns true if there is a share with public. 15614524Sdougm */ 15624524Sdougm static int 15634524Sdougm check_public(sa_group_t group, sa_share_t skipshare) 15644524Sdougm { 15654524Sdougm int exists = B_FALSE; 15664524Sdougm sa_share_t share; 15674524Sdougm sa_optionset_t opt; 15684524Sdougm sa_property_t prop; 15694524Sdougm char *shared; 15704524Sdougm 15714524Sdougm for (share = sa_get_share(group, NULL); share != NULL; 15724524Sdougm share = sa_get_next_share(share)) { 15734524Sdougm if (share == skipshare) 15744524Sdougm continue; 15754524Sdougm 15764524Sdougm opt = sa_get_optionset(share, "nfs"); 15774524Sdougm if (opt == NULL) 15784524Sdougm continue; 15794524Sdougm prop = sa_get_property(opt, "public"); 15804524Sdougm if (prop == NULL) 15814524Sdougm continue; 15824524Sdougm shared = sa_get_share_attr(share, "shared"); 15834524Sdougm if (shared != NULL) { 15844524Sdougm exists = strcmp(shared, "true") == 0; 15854524Sdougm sa_free_attr_string(shared); 15864524Sdougm if (exists == B_TRUE) 15874524Sdougm break; 15884524Sdougm } 15894524Sdougm } 15904524Sdougm 15914524Sdougm return (exists); 15924524Sdougm } 15934524Sdougm 15944524Sdougm /* 15953910Sdougm * public_exists(share) 15963910Sdougm * 15973910Sdougm * check to see if public option is set on any other share than the 15984524Sdougm * one specified. Need to check zfs sub-groups as well as the top 15994524Sdougm * level groups. 16003910Sdougm */ 16013910Sdougm static int 16023910Sdougm public_exists(sa_share_t skipshare) 16033910Sdougm { 16043910Sdougm sa_group_t group; 16053910Sdougm sa_handle_t handle; 16063910Sdougm 16073910Sdougm group = sa_get_parent_group(skipshare); 16083910Sdougm if (group == NULL) 16094345Sdougm return (SA_NO_SUCH_GROUP); 16103910Sdougm 16113910Sdougm handle = sa_find_group_handle(group); 16123910Sdougm if (handle == NULL) 16134345Sdougm return (SA_SYSTEM_ERR); 16143910Sdougm 16153910Sdougm for (group = sa_get_group(handle, NULL); group != NULL; 16163910Sdougm group = sa_get_next_group(group)) { 16174524Sdougm /* Walk any ZFS subgroups as well as all standard groups */ 16184524Sdougm if (sa_group_is_zfs(group)) { 16194524Sdougm sa_group_t subgroup; 16204524Sdougm for (subgroup = sa_get_sub_group(group); 16214524Sdougm subgroup != NULL; 16224524Sdougm subgroup = sa_get_next_group(subgroup)) { 16234524Sdougm if (check_public(subgroup, skipshare)) 16244524Sdougm return (B_TRUE); 16253910Sdougm } 16264524Sdougm } else { 16274524Sdougm if (check_public(group, skipshare)) 16284524Sdougm return (B_TRUE); 16293910Sdougm } 16303910Sdougm } 16314524Sdougm return (B_FALSE); 16323910Sdougm } 16333910Sdougm 16343910Sdougm /* 16353910Sdougm * sa_enable_share at the protocol level, enable_share must tell the 16363910Sdougm * implementation that it is to enable the share. This entails 16373910Sdougm * converting the path and options into the appropriate ioctl 16383910Sdougm * calls. It is assumed that all error checking of paths, etc. were 16393910Sdougm * done earlier. 16403910Sdougm */ 16413910Sdougm static int 16423910Sdougm nfs_enable_share(sa_share_t share) 16433910Sdougm { 16443910Sdougm struct exportdata export; 16453910Sdougm sa_optionset_t secoptlist; 16463910Sdougm struct secinfo *sp; 16473910Sdougm int num_secinfo; 16483910Sdougm sa_optionset_t opt; 16493910Sdougm sa_security_t sec; 16503910Sdougm sa_property_t prop; 16513910Sdougm char *path; 16523910Sdougm int err = SA_OK; 16534524Sdougm int i; 16544543Smarks int iszfs; 16553910Sdougm 16563910Sdougm /* Don't drop core if the NFS module isn't loaded. */ 16573910Sdougm (void) signal(SIGSYS, SIG_IGN); 16583910Sdougm 16593910Sdougm /* get the path since it is important in several places */ 16603910Sdougm path = sa_get_share_attr(share, "path"); 16613910Sdougm if (path == NULL) 16624345Sdougm return (SA_NO_SUCH_PATH); 16633910Sdougm 16644543Smarks iszfs = sa_path_is_zfs(path); 16653910Sdougm /* 16663910Sdougm * find the optionsets and security sets. There may not be 16673910Sdougm * any or there could be one or two for each of optionset and 16683910Sdougm * security may have multiple, one per security type per 16693910Sdougm * protocol type. 16703910Sdougm */ 16713910Sdougm opt = sa_get_derived_optionset(share, "nfs", 1); 16723910Sdougm secoptlist = (sa_optionset_t)sa_get_all_security_types(share, "nfs", 1); 16733910Sdougm if (secoptlist != NULL) 16744345Sdougm num_secinfo = MAX(1, count_security(secoptlist)); 16753910Sdougm else 16764345Sdougm num_secinfo = 1; 16773910Sdougm 16783910Sdougm /* 16793910Sdougm * walk through the options and fill in the structure 16803910Sdougm * appropriately. 16813910Sdougm */ 16823910Sdougm 16833910Sdougm (void) memset(&export, '\0', sizeof (export)); 16843910Sdougm 16853910Sdougm /* 16863910Sdougm * do non-security options first since there is only one after 16873910Sdougm * the derived group is constructed. 16883910Sdougm */ 16893910Sdougm export.ex_version = EX_CURRENT_VERSION; 16903910Sdougm export.ex_anon = UID_NOBODY; /* this is our default value */ 16913910Sdougm export.ex_index = NULL; 16923910Sdougm export.ex_path = path; 16933910Sdougm export.ex_pathlen = strlen(path) + 1; 16943910Sdougm 16953910Sdougm if (opt != NULL) 16964345Sdougm err = fill_export_from_optionset(&export, opt); 16973910Sdougm 16983910Sdougm /* 16993910Sdougm * check to see if "public" is set. If it is, then make sure 17003910Sdougm * no other share has it set. If it is already used, fail. 17013910Sdougm */ 17023910Sdougm 17033910Sdougm if (export.ex_flags & EX_PUBLIC && public_exists(share)) { 17044345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 17054345Sdougm "NFS: Cannot share more than one file " 17064345Sdougm "system with 'public' property\n")); 17074345Sdougm err = SA_NOT_ALLOWED; 17084345Sdougm goto out; 17093910Sdougm } 17103910Sdougm 17114524Sdougm sp = calloc(num_secinfo, sizeof (struct secinfo)); 17123910Sdougm if (sp == NULL) { 17134345Sdougm err = SA_NO_MEMORY; 17144524Sdougm (void) printf(dgettext(TEXT_DOMAIN, 17154524Sdougm "NFS: NFS: no memory for security\n")); 17164524Sdougm goto out; 17174524Sdougm } 17184524Sdougm export.ex_secinfo = sp; 17194524Sdougm /* get default secinfo */ 17204524Sdougm export.ex_seccnt = num_secinfo; 17214524Sdougm /* 17224524Sdougm * since we must have one security option defined, we 17234524Sdougm * init to the default and then override as we find 17244524Sdougm * defined security options. This handles the case 17254524Sdougm * where we have no defined options but we need to set 17264524Sdougm * up one. 17274524Sdougm */ 17284524Sdougm sp[0].s_window = DEF_WIN; 17294524Sdougm sp[0].s_rootnames = NULL; 17304524Sdougm /* setup a default in case no properties defined */ 17314524Sdougm if (nfs_getseconfig_default(&sp[0].s_secinfo)) { 17324524Sdougm (void) printf(dgettext(TEXT_DOMAIN, 17334524Sdougm "NFS: nfs_getseconfig_default: failed to " 17344524Sdougm "get default security mode\n")); 17354524Sdougm err = SA_CONFIG_ERR; 17364524Sdougm } 17374524Sdougm if (secoptlist != NULL) { 17384524Sdougm for (i = 0, prop = sa_get_property(secoptlist, NULL); 17394524Sdougm prop != NULL && i < num_secinfo; 17404524Sdougm prop = sa_get_next_property(prop), i++) { 17414524Sdougm char *sectype; 17424345Sdougm sectype = sa_get_property_attr(prop, "type"); 17434524Sdougm /* 17444524Sdougm * if sectype is NULL, we probably 17454524Sdougm * have a memory problem and can't get 17464524Sdougm * the correct values. Rather than 17474524Sdougm * exporting with incorrect security, 17484524Sdougm * don't share it. 17494524Sdougm */ 17504524Sdougm if (sectype == NULL) { 17514524Sdougm err = SA_NO_MEMORY; 17524524Sdougm (void) printf(dgettext(TEXT_DOMAIN, 17534524Sdougm "NFS: Cannot share %s: " 17544524Sdougm "no memory\n"), path); 17554524Sdougm goto out; 17564524Sdougm } 17574524Sdougm sec = (sa_security_t)sa_get_derived_security( 17584524Sdougm share, sectype, "nfs", 1); 17594524Sdougm sp[i].s_window = DEF_WIN; 17604524Sdougm sp[i].s_rootcnt = 0; 17614524Sdougm sp[i].s_rootnames = NULL; 17624345Sdougm (void) fill_security_from_secopts(&sp[i], sec); 17634524Sdougm if (sec != NULL) 17644524Sdougm sa_free_derived_security(sec); 17654524Sdougm if (sectype != NULL) 17664524Sdougm sa_free_attr_string(sectype); 17673910Sdougm } 17684524Sdougm } 17694524Sdougm /* 17704524Sdougm * when we get here, we can do the exportfs system call and 17714524Sdougm * initiate thinsg. We probably want to enable the nfs.server 17724524Sdougm * service first if it isn't running within SMF. 17734524Sdougm */ 17744524Sdougm /* check nfs.server status and start if needed */ 17754524Sdougm /* now add the share to the internal tables */ 17764524Sdougm printarg(path, &export); 17774524Sdougm /* 17784524Sdougm * call the exportfs system call which is implemented 17794524Sdougm * via the nfssys() call as the EXPORTFS subfunction. 17804524Sdougm */ 17814543Smarks if (iszfs) { 17824543Smarks struct exportfs_args ea; 17834543Smarks share_t sh; 17844543Smarks char *str; 17854543Smarks priv_set_t *priv_effective; 17864543Smarks int privileged; 17874543Smarks 17884543Smarks /* 17894543Smarks * If we aren't a privileged user 17904543Smarks * and NFS server service isn't running 17914543Smarks * then print out an error message 17924543Smarks * and return EPERM 17934543Smarks */ 17944543Smarks 17954543Smarks priv_effective = priv_allocset(); 17964543Smarks (void) getppriv(PRIV_EFFECTIVE, priv_effective); 17974543Smarks 17984543Smarks privileged = (priv_isfullset(priv_effective) == B_TRUE); 17994543Smarks priv_freeset(priv_effective); 18004543Smarks 18014543Smarks if (!privileged && 18024543Smarks (str = smf_get_state(NFS_SERVER_SVC)) != NULL) { 18034543Smarks err = 0; 18044543Smarks if (strcmp(str, SCF_STATE_STRING_ONLINE) != 0) { 18054543Smarks (void) printf(dgettext(TEXT_DOMAIN, 18064543Smarks "NFS: Cannot share remote " 18074543Smarks "filesystem: %s\n"), path); 18084543Smarks (void) printf(dgettext(TEXT_DOMAIN, 18094543Smarks "NFS: Service needs to be enabled " 18104543Smarks "by a privileged user\n")); 18114543Smarks err = SA_SYSTEM_ERR; 18124543Smarks errno = EPERM; 18134543Smarks } 18144543Smarks free(str); 18154543Smarks } 18164543Smarks 18174543Smarks if (err == 0) { 18184543Smarks ea.dname = path; 18194543Smarks ea.uex = &export; 18204543Smarks 18214543Smarks sa_sharetab_fill_zfs(share, &sh, "nfs"); 18225331Samw err = sa_share_zfs(share, path, &sh, 18235331Samw &ea, ZFS_SHARE_NFS); 18244543Smarks sa_emptyshare(&sh); 18254543Smarks } 18264543Smarks } else { 18274543Smarks err = exportfs(path, &export); 18284543Smarks } 18294543Smarks 18304543Smarks if (err < 0) { 18314524Sdougm err = SA_SYSTEM_ERR; 18324524Sdougm switch (errno) { 18334524Sdougm case EREMOTE: 18344524Sdougm (void) printf(dgettext(TEXT_DOMAIN, 18354543Smarks "NFS: Cannot share filesystems " 18364543Smarks "in non-global zones: %s\n"), path); 18374543Smarks err = SA_NOT_SUPPORTED; 18384524Sdougm break; 18394524Sdougm case EPERM: 18404524Sdougm if (getzoneid() != GLOBAL_ZONEID) { 18414345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 18424543Smarks "NFS: Cannot share file systems " 18434524Sdougm "in non-global zones: %s\n"), path); 18444524Sdougm err = SA_NOT_SUPPORTED; 18454345Sdougm break; 18464345Sdougm } 18474524Sdougm err = SA_NO_PERMISSION; 18484524Sdougm /* FALLTHROUGH */ 18494524Sdougm default: 18504524Sdougm break; 18513910Sdougm } 18524524Sdougm } else { 18534524Sdougm /* update sharetab with an add/modify */ 18544543Smarks if (!iszfs) { 18554543Smarks (void) sa_update_sharetab(share, "nfs"); 18564543Smarks } 18573910Sdougm } 18583910Sdougm 18593910Sdougm if (err == SA_OK) { 18603910Sdougm /* 18613910Sdougm * enable services as needed. This should probably be 18623910Sdougm * done elsewhere in order to minimize the calls to 18633910Sdougm * check services. 18643910Sdougm */ 18653910Sdougm /* 18663910Sdougm * check to see if logging and other services need to 18673910Sdougm * be triggered, but only if there wasn't an 18683910Sdougm * error. This is probably where sharetab should be 18693910Sdougm * updated with the NFS specific entry. 18703910Sdougm */ 18714345Sdougm if (export.ex_flags & EX_LOG) { 18724345Sdougm /* enable logging */ 18734345Sdougm if (nfslogtab_add(path, export.ex_log_buffer, 18744345Sdougm export.ex_tag) != 0) { 18754345Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 18764345Sdougm "Could not enable logging for %s\n"), 18774345Sdougm path); 18784345Sdougm } 18794345Sdougm _check_services(service_list_logging); 18804345Sdougm } else { 18814345Sdougm /* 18824345Sdougm * don't have logging so remove it from file. It might 18834345Sdougm * not be thre, but that doesn't matter. 18844345Sdougm */ 18854345Sdougm (void) nfslogtab_deactivate(path); 18864345Sdougm _check_services(service_list_default); 18873910Sdougm } 18883910Sdougm } 18893910Sdougm 18903910Sdougm out: 18913910Sdougm if (path != NULL) 18924345Sdougm free(path); 18933910Sdougm 18943910Sdougm cleanup_export(&export); 18953910Sdougm if (opt != NULL) 18964345Sdougm sa_free_derived_optionset(opt); 18973910Sdougm if (secoptlist != NULL) 18984345Sdougm (void) sa_destroy_optionset(secoptlist); 18993910Sdougm return (err); 19003910Sdougm } 19013910Sdougm 19023910Sdougm /* 19035800Sdougm * nfs_disable_share(share, path) 19043910Sdougm * 19055800Sdougm * Unshare the specified share. Note that "path" is the same path as 19065800Sdougm * what is in the "share" object. It is passed in to avoid an 19075800Sdougm * additional lookup. A missing "path" value makes this a no-op 19085800Sdougm * function. 19093910Sdougm */ 19103910Sdougm static int 19114543Smarks nfs_disable_share(sa_share_t share, char *path) 19123910Sdougm { 19133910Sdougm int err; 19143910Sdougm int ret = SA_OK; 19154543Smarks int iszfs; 19165800Sdougm sa_group_t parent; 19175951Sdougm sa_handle_t handle; 19184543Smarks 19195800Sdougm if (path == NULL) 19205800Sdougm return (ret); 19214543Smarks 19225800Sdougm /* 19235800Sdougm * If the share is in a ZFS group we need to handle it 19245800Sdougm * differently. Just being on a ZFS file system isn't 19255800Sdougm * enough since we may be in a legacy share case. 19265800Sdougm */ 19275800Sdougm parent = sa_get_parent_group(share); 19285800Sdougm iszfs = sa_group_is_zfs(parent); 19295800Sdougm if (iszfs) { 19305800Sdougm struct exportfs_args ea; 19315800Sdougm share_t sh = { 0 }; 19325800Sdougm ea.dname = path; 19335800Sdougm ea.uex = NULL; 19345800Sdougm sh.sh_path = path; 19355800Sdougm sh.sh_fstype = "nfs"; 19364543Smarks 19375800Sdougm err = sa_share_zfs(share, path, &sh, 19385800Sdougm &ea, ZFS_UNSHARE_NFS); 19395800Sdougm } else { 19405800Sdougm err = exportfs(path, NULL); 19415800Sdougm } 19425800Sdougm if (err < 0) { 19435800Sdougm /* 19445800Sdougm * TBD: only an error in some 19455800Sdougm * cases - need better analysis 19465800Sdougm */ 19475800Sdougm switch (errno) { 19485800Sdougm case EPERM: 19495800Sdougm case EACCES: 19505800Sdougm ret = SA_NO_PERMISSION; 19515800Sdougm if (getzoneid() != GLOBAL_ZONEID) { 19525800Sdougm ret = SA_NOT_SUPPORTED; 19535800Sdougm } 19545800Sdougm break; 19555800Sdougm case EINVAL: 19565800Sdougm case ENOENT: 19575800Sdougm ret = SA_NO_SUCH_PATH; 19584543Smarks break; 19594345Sdougm default: 19604345Sdougm ret = SA_SYSTEM_ERR; 19614543Smarks break; 19623910Sdougm } 19635800Sdougm } 19645800Sdougm if (ret == SA_OK || ret == SA_NO_SUCH_PATH) { 19655951Sdougm handle = sa_find_group_handle((sa_group_t)share); 19665800Sdougm if (!iszfs) 19675951Sdougm (void) sa_delete_sharetab(handle, path, "nfs"); 19685800Sdougm /* just in case it was logged */ 19695800Sdougm (void) nfslogtab_deactivate(path); 19703910Sdougm } 19713910Sdougm return (ret); 19723910Sdougm } 19733910Sdougm 19743910Sdougm /* 19753910Sdougm * check ro vs rw values. Over time this may get beefed up. 19763910Sdougm * for now it just does simple checks. 19773910Sdougm */ 19783910Sdougm 19793910Sdougm static int 19803910Sdougm check_rorw(char *v1, char *v2) 19813910Sdougm { 19823910Sdougm int ret = SA_OK; 19833910Sdougm if (strcmp(v1, v2) == 0) 19844345Sdougm ret = SA_VALUE_CONFLICT; 19853910Sdougm return (ret); 19863910Sdougm } 19873910Sdougm 19883910Sdougm /* 19893910Sdougm * nfs_validate_property(property, parent) 19903910Sdougm * 19913910Sdougm * Check that the property has a legitimate value for its type. 19923910Sdougm */ 19933910Sdougm 19943910Sdougm static int 19953910Sdougm nfs_validate_property(sa_property_t property, sa_optionset_t parent) 19963910Sdougm { 19973910Sdougm int ret = SA_OK; 19983910Sdougm char *propname; 19993910Sdougm char *other; 20003910Sdougm int optindex; 20013910Sdougm nfsl_config_t *configlist; 20023910Sdougm sa_group_t parent_group; 20033910Sdougm char *value; 20043910Sdougm 20053910Sdougm propname = sa_get_property_attr(property, "type"); 20063910Sdougm 20073910Sdougm if ((optindex = findopt(propname)) < 0) 20084345Sdougm ret = SA_NO_SUCH_PROP; 20093910Sdougm 20103910Sdougm /* need to validate value range here as well */ 20113910Sdougm 20123910Sdougm if (ret == SA_OK) { 20134345Sdougm parent_group = sa_get_parent_group((sa_share_t)parent); 20144345Sdougm if (optdefs[optindex].share && !sa_is_share(parent_group)) 20154345Sdougm ret = SA_PROP_SHARE_ONLY; 20163910Sdougm } 20173910Sdougm if (ret == SA_OK) { 20184345Sdougm value = sa_get_property_attr(property, "value"); 20194345Sdougm if (value != NULL) { 20204345Sdougm /* first basic type checking */ 20214345Sdougm switch (optdefs[optindex].type) { 20224345Sdougm case OPT_TYPE_NUMBER: 20234345Sdougm /* check that the value is all digits */ 20244345Sdougm if (!is_a_number(value)) 20254345Sdougm ret = SA_BAD_VALUE; 20264345Sdougm break; 20274345Sdougm case OPT_TYPE_BOOLEAN: 20284345Sdougm if (strlen(value) == 0 || 20294345Sdougm strcasecmp(value, "true") == 0 || 20304345Sdougm strcmp(value, "1") == 0 || 20314345Sdougm strcasecmp(value, "false") == 0 || 20324345Sdougm strcmp(value, "0") == 0) { 20334345Sdougm ret = SA_OK; 20344345Sdougm } else { 20354345Sdougm ret = SA_BAD_VALUE; 20364345Sdougm } 20374345Sdougm break; 20384345Sdougm case OPT_TYPE_USER: 20394345Sdougm if (!is_a_number(value)) { 20404345Sdougm struct passwd *pw; 20414345Sdougm /* 20424345Sdougm * in this case it would have to be a 20434345Sdougm * user name 20444345Sdougm */ 20454345Sdougm pw = getpwnam(value); 20464345Sdougm if (pw == NULL) 20474345Sdougm ret = SA_BAD_VALUE; 20484345Sdougm endpwent(); 20494345Sdougm } else { 20504345Sdougm uint64_t intval; 20514345Sdougm intval = strtoull(value, NULL, 0); 20524345Sdougm if (intval > UID_MAX && intval != ~0) 20534345Sdougm ret = SA_BAD_VALUE; 20544345Sdougm } 20554345Sdougm break; 20564345Sdougm case OPT_TYPE_FILE: 20574345Sdougm if (strcmp(value, "..") == 0 || 20584345Sdougm strchr(value, '/') != NULL) { 20594345Sdougm ret = SA_BAD_VALUE; 20604345Sdougm } 20614345Sdougm break; 20624345Sdougm case OPT_TYPE_ACCLIST: 20634345Sdougm /* 20644345Sdougm * access list handling. Should eventually 20654345Sdougm * validate that all the values make sense. 20664345Sdougm * Also, ro and rw may have cross value 20674345Sdougm * conflicts. 20684345Sdougm */ 20694345Sdougm if (strcmp(propname, SHOPT_RO) == 0) 20704345Sdougm other = SHOPT_RW; 20714345Sdougm else if (strcmp(propname, SHOPT_RW) == 0) 20724345Sdougm other = SHOPT_RO; 20734345Sdougm else 20744345Sdougm other = NULL; 20754345Sdougm 20764345Sdougm if (other != NULL && parent != NULL) { 20774345Sdougm /* compare rw(ro) with ro(rw) */ 20784345Sdougm sa_property_t oprop; 20794345Sdougm oprop = sa_get_property(parent, other); 20804345Sdougm if (oprop != NULL) { 20814345Sdougm /* 20824345Sdougm * only potential 20834345Sdougm * confusion if other 20844345Sdougm * exists 20854345Sdougm */ 20864345Sdougm char *ovalue; 20874345Sdougm ovalue = sa_get_property_attr( 20884345Sdougm oprop, "value"); 20894345Sdougm if (ovalue != NULL) { 20904345Sdougm ret = check_rorw(value, 20914345Sdougm ovalue); 20924345Sdougm sa_free_attr_string( 20934345Sdougm ovalue); 20944345Sdougm } 20954345Sdougm } 20964345Sdougm } 20974345Sdougm break; 20984345Sdougm case OPT_TYPE_LOGTAG: 20994345Sdougm if (nfsl_getconfig_list(&configlist) == 0) { 21004345Sdougm int error; 21014345Sdougm if (value == NULL || 21024345Sdougm strlen(value) == 0) { 21034345Sdougm if (value != NULL) 21044345Sdougm sa_free_attr_string( 21054345Sdougm value); 21064345Sdougm value = strdup("global"); 21074345Sdougm } 21084345Sdougm if (value != NULL && 21094345Sdougm nfsl_findconfig(configlist, value, 21104345Sdougm &error) == NULL) { 21114345Sdougm ret = SA_BAD_VALUE; 21124345Sdougm } 21135179Sdougm /* Must always free when done */ 21145179Sdougm nfsl_freeconfig_list(&configlist); 21154345Sdougm } else { 21164345Sdougm ret = SA_CONFIG_ERR; 21174345Sdougm } 21184345Sdougm break; 21194345Sdougm case OPT_TYPE_STRING: 21204345Sdougm /* whatever is here should be ok */ 21214345Sdougm break; 21224345Sdougm case OPT_TYPE_SECURITY: 21234345Sdougm /* 21244345Sdougm * The "sec" property isn't used in the 21254345Sdougm * non-legacy parts of sharemgr. We need to 21264345Sdougm * reject it here. For legacy, it is pulled 21274345Sdougm * out well before we get here. 21284345Sdougm */ 21294345Sdougm ret = SA_NO_SUCH_PROP; 21304345Sdougm break; 21314345Sdougm default: 21324345Sdougm break; 21333910Sdougm } 21345179Sdougm 21355179Sdougm if (value != NULL) 21365179Sdougm sa_free_attr_string(value); 21375179Sdougm 21384345Sdougm if (ret == SA_OK && optdefs[optindex].check != NULL) { 21394345Sdougm /* do the property specific check */ 21404345Sdougm ret = optdefs[optindex].check(property); 21413910Sdougm } 21423910Sdougm } 21433910Sdougm } 21443910Sdougm 21453910Sdougm if (propname != NULL) 21464345Sdougm sa_free_attr_string(propname); 21473910Sdougm return (ret); 21483910Sdougm } 21493910Sdougm 21503910Sdougm /* 21513910Sdougm * Protocol management functions 21523910Sdougm * 21533910Sdougm * Properties defined in the default files are defined in 21543910Sdougm * proto_option_defs for parsing and validation. If "other" and 21553910Sdougm * "compare" are set, then the value for this property should be 21563910Sdougm * compared against the property specified in "other" using the 21573910Sdougm * "compare" check (either <= or >=) in order to ensure that the 21583910Sdougm * values are in the correct range. E.g. setting server_versmin 21593910Sdougm * higher than server_versmax should not be allowed. 21603910Sdougm */ 21613910Sdougm 21623910Sdougm struct proto_option_defs { 21633910Sdougm char *tag; 21643910Sdougm char *name; /* display name -- remove protocol identifier */ 21653910Sdougm int index; 21663910Sdougm int type; 21673910Sdougm union { 21683910Sdougm int intval; 21693910Sdougm char *string; 21703910Sdougm } defvalue; 21713910Sdougm uint32_t svcs; 21723910Sdougm int32_t minval; 21733910Sdougm int32_t maxval; 21743910Sdougm char *file; 21753910Sdougm char *other; 21763910Sdougm int compare; 21773910Sdougm #define OPT_CMP_GE 0 21783910Sdougm #define OPT_CMP_LE 1 21793910Sdougm int (*check)(char *); 21803910Sdougm } proto_options[] = { 21813910Sdougm #define PROTO_OPT_NFSD_SERVERS 0 21823910Sdougm {"nfsd_servers", 21833910Sdougm "servers", PROTO_OPT_NFSD_SERVERS, OPT_TYPE_NUMBER, 16, SVC_NFSD, 21843910Sdougm 1, INT32_MAX, NFSADMIN}, 21853910Sdougm #define PROTO_OPT_LOCKD_LISTEN_BACKLOG 1 21863910Sdougm {"lockd_listen_backlog", 21873910Sdougm "lockd_listen_backlog", PROTO_OPT_LOCKD_LISTEN_BACKLOG, 21883910Sdougm OPT_TYPE_NUMBER, 32, SVC_LOCKD, 32, INT32_MAX, NFSADMIN}, 21893910Sdougm #define PROTO_OPT_LOCKD_SERVERS 2 21903910Sdougm {"lockd_servers", 21913910Sdougm "lockd_servers", PROTO_OPT_LOCKD_SERVERS, OPT_TYPE_NUMBER, 20, 21923910Sdougm SVC_LOCKD, 1, INT32_MAX, NFSADMIN}, 21933910Sdougm #define PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT 3 21943910Sdougm {"lockd_retransmit_timeout", 21953910Sdougm "lockd_retransmit_timeout", PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT, 21963910Sdougm OPT_TYPE_NUMBER, 5, SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 21973910Sdougm #define PROTO_OPT_GRACE_PERIOD 4 21983910Sdougm {"grace_period", 21993910Sdougm "grace_period", PROTO_OPT_GRACE_PERIOD, OPT_TYPE_NUMBER, 90, 22003910Sdougm SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 22013910Sdougm #define PROTO_OPT_NFS_SERVER_VERSMIN 5 22023910Sdougm {"nfs_server_versmin", 22033910Sdougm "server_versmin", PROTO_OPT_NFS_SERVER_VERSMIN, OPT_TYPE_NUMBER, 22043910Sdougm (int)NFS_VERSMIN_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN, 22053910Sdougm NFS_VERSMAX, NFSADMIN, "server_versmax", OPT_CMP_LE}, 22063910Sdougm #define PROTO_OPT_NFS_SERVER_VERSMAX 6 22073910Sdougm {"nfs_server_versmax", 22083910Sdougm "server_versmax", PROTO_OPT_NFS_SERVER_VERSMAX, OPT_TYPE_NUMBER, 22093910Sdougm (int)NFS_VERSMAX_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN, 22103910Sdougm NFS_VERSMAX, NFSADMIN, "server_versmin", OPT_CMP_GE}, 22113910Sdougm #define PROTO_OPT_NFS_CLIENT_VERSMIN 7 22123910Sdougm {"nfs_client_versmin", 22133910Sdougm "client_versmin", PROTO_OPT_NFS_CLIENT_VERSMIN, OPT_TYPE_NUMBER, 22143910Sdougm (int)NFS_VERSMIN_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX, 22153910Sdougm NFSADMIN, "client_versmax", OPT_CMP_LE}, 22163910Sdougm #define PROTO_OPT_NFS_CLIENT_VERSMAX 8 22173910Sdougm {"nfs_client_versmax", 22183910Sdougm "client_versmax", PROTO_OPT_NFS_CLIENT_VERSMAX, OPT_TYPE_NUMBER, 22193910Sdougm (int)NFS_VERSMAX_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX, 22203910Sdougm NFSADMIN, "client_versmin", OPT_CMP_GE}, 22213910Sdougm #define PROTO_OPT_NFS_SERVER_DELEGATION 9 22223910Sdougm {"nfs_server_delegation", 22233910Sdougm "server_delegation", PROTO_OPT_NFS_SERVER_DELEGATION, 22243910Sdougm OPT_TYPE_ONOFF, NFS_SERVER_DELEGATION_DEFAULT, SVC_NFSD, 0, 0, 22253910Sdougm NFSADMIN}, 22263910Sdougm #define PROTO_OPT_NFSMAPID_DOMAIN 10 22273910Sdougm {"nfsmapid_domain", 22283910Sdougm "nfsmapid_domain", PROTO_OPT_NFSMAPID_DOMAIN, OPT_TYPE_DOMAIN, 22293910Sdougm NULL, SVC_NFSMAPID, 0, 0, NFSADMIN}, 22303910Sdougm #define PROTO_OPT_NFSD_MAX_CONNECTIONS 11 22313910Sdougm {"nfsd_max_connections", 22323910Sdougm "max_connections", PROTO_OPT_NFSD_MAX_CONNECTIONS, 22333910Sdougm OPT_TYPE_NUMBER, -1, SVC_NFSD, -1, INT32_MAX, NFSADMIN}, 22343910Sdougm #define PROTO_OPT_NFSD_PROTOCOL 12 22353910Sdougm {"nfsd_protocol", 22363910Sdougm "protocol", PROTO_OPT_NFSD_PROTOCOL, OPT_TYPE_PROTOCOL, 0, 22373910Sdougm SVC_NFSD, 0, 0, NFSADMIN}, 22383910Sdougm #define PROTO_OPT_NFSD_LISTEN_BACKLOG 13 22393910Sdougm {"nfsd_listen_backlog", 22403910Sdougm "listen_backlog", PROTO_OPT_NFSD_LISTEN_BACKLOG, 22413910Sdougm OPT_TYPE_NUMBER, 0, 22423910Sdougm SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 22433910Sdougm {NULL} 22443910Sdougm }; 22453910Sdougm 22463910Sdougm /* 22473910Sdougm * the protoset holds the defined options so we don't have to read 22483910Sdougm * them multiple times 22493910Sdougm */ 22505179Sdougm static sa_protocol_properties_t protoset; 22513910Sdougm 22523910Sdougm static int 22533910Sdougm findprotoopt(char *name, int whichname) 22543910Sdougm { 22553910Sdougm int i; 22563910Sdougm for (i = 0; proto_options[i].tag != NULL; i++) { 22574345Sdougm if (whichname == 1) { 22584345Sdougm if (strcasecmp(proto_options[i].name, name) == 0) 22593910Sdougm return (i); 22604345Sdougm } else { 22614345Sdougm if (strcasecmp(proto_options[i].tag, name) == 0) 22624345Sdougm return (i); 22634345Sdougm } 22643910Sdougm } 22653910Sdougm return (-1); 22663910Sdougm } 22673910Sdougm 22683910Sdougm /* 22693910Sdougm * fixcaselower(str) 22703910Sdougm * 22713910Sdougm * convert a string to lower case (inplace). 22723910Sdougm */ 22733910Sdougm 22743910Sdougm static void 22753910Sdougm fixcaselower(char *str) 22763910Sdougm { 22773910Sdougm while (*str) { 22784345Sdougm *str = tolower(*str); 22794345Sdougm str++; 22803910Sdougm } 22813910Sdougm } 22823910Sdougm 22833910Sdougm /* 22843910Sdougm * fixcaseupper(str) 22853910Sdougm * 22863910Sdougm * convert a string to upper case (inplace). 22873910Sdougm */ 22883910Sdougm 22893910Sdougm static void 22903910Sdougm fixcaseupper(char *str) 22913910Sdougm { 22923910Sdougm while (*str) { 22934345Sdougm *str = toupper(*str); 22944345Sdougm str++; 22953910Sdougm } 22963910Sdougm } 22973910Sdougm 22983910Sdougm /* 22994241Sdougm * skipwhitespace(str) 23004241Sdougm * 23014241Sdougm * Skip leading white space. It is assumed that it is called with a 23024241Sdougm * valid pointer. 23034241Sdougm */ 23044241Sdougm 23054241Sdougm static char * 23064241Sdougm skipwhitespace(char *str) 23074241Sdougm { 23084241Sdougm while (*str && isspace(*str)) 23094241Sdougm str++; 23104241Sdougm 23114241Sdougm return (str); 23124241Sdougm } 23134241Sdougm 23144241Sdougm /* 23154345Sdougm * extractprop() 23164345Sdougm * 23174345Sdougm * Extract the property and value out of the line and create the 23184345Sdougm * property in the optionset. 23194345Sdougm */ 23206019Sdougm static int 23214345Sdougm extractprop(char *name, char *value) 23224345Sdougm { 23234345Sdougm sa_property_t prop; 23244345Sdougm int index; 23256019Sdougm int ret = SA_OK; 23264345Sdougm /* 23274345Sdougm * Remove any leading 23284345Sdougm * white space. 23294345Sdougm */ 23304345Sdougm name = skipwhitespace(name); 23314345Sdougm 23324345Sdougm index = findprotoopt(name, 0); 23334345Sdougm if (index >= 0) { 23344345Sdougm fixcaselower(name); 23354345Sdougm prop = sa_create_property(proto_options[index].name, value); 23364345Sdougm if (prop != NULL) 23376019Sdougm ret = sa_add_protocol_property(protoset, prop); 23386019Sdougm else 23396019Sdougm ret = SA_NO_MEMORY; 23404345Sdougm } 23416019Sdougm return (ret); 23424345Sdougm } 23434345Sdougm 23444345Sdougm /* 23453910Sdougm * initprotofromdefault() 23463910Sdougm * 23473910Sdougm * read the default file(s) and add the defined values to the 23483910Sdougm * protoset. Note that default values are known from the built in 23493910Sdougm * table in case the file doesn't have a definition. 23503910Sdougm */ 23513910Sdougm 23523910Sdougm static int 23533910Sdougm initprotofromdefault() 23543910Sdougm { 23553910Sdougm FILE *nfs; 23563910Sdougm char buff[BUFSIZ]; 23573910Sdougm char *name; 23583910Sdougm char *value; 23596019Sdougm int ret = SA_OK; 23603910Sdougm 23613910Sdougm protoset = sa_create_protocol_properties("nfs"); 23623910Sdougm 23633910Sdougm if (protoset != NULL) { 23644345Sdougm nfs = fopen(NFSADMIN, "r"); 23654345Sdougm if (nfs != NULL) { 23666019Sdougm while (ret == SA_OK && 23676019Sdougm fgets(buff, sizeof (buff), nfs) != NULL) { 23684345Sdougm switch (buff[0]) { 23694345Sdougm case '\n': 23704345Sdougm case '#': 23714345Sdougm /* skip */ 23724345Sdougm break; 23734345Sdougm default: 23744345Sdougm name = buff; 23754345Sdougm buff[strlen(buff) - 1] = '\0'; 23764345Sdougm value = strchr(name, '='); 23774345Sdougm if (value != NULL) { 23784345Sdougm *value++ = '\0'; 23796019Sdougm ret = extractprop(name, value); 23804345Sdougm } 23814345Sdougm } 23823910Sdougm } 23836019Sdougm (void) fclose(nfs); 23846019Sdougm } else { 23856019Sdougm (void) printf(gettext("Problem with file: %s\n"), 23866019Sdougm NFSADMIN); 23876019Sdougm ret = SA_SYSTEM_ERR; 23883910Sdougm } 23896019Sdougm } else { 23906019Sdougm ret = SA_NO_MEMORY; 23913910Sdougm } 23926019Sdougm return (ret); 23933910Sdougm } 23943910Sdougm 23953910Sdougm /* 23964345Sdougm * add_defaults() 23973910Sdougm * 23983910Sdougm * Add the default values for any property not defined in the parsing 23993910Sdougm * of the default files. Values are set according to their defined 24003910Sdougm * types. 24013910Sdougm */ 24023910Sdougm 24033910Sdougm static void 24043910Sdougm add_defaults() 24053910Sdougm { 24063910Sdougm int i; 24073910Sdougm char number[MAXDIGITS]; 24083910Sdougm 24093910Sdougm for (i = 0; proto_options[i].tag != NULL; i++) { 24104345Sdougm sa_property_t prop; 24114345Sdougm prop = sa_get_protocol_property(protoset, 24124345Sdougm proto_options[i].name); 24134345Sdougm if (prop == NULL) { 24144345Sdougm /* add the default value */ 24154345Sdougm switch (proto_options[i].type) { 24164345Sdougm case OPT_TYPE_NUMBER: 24174345Sdougm (void) snprintf(number, sizeof (number), "%d", 24184345Sdougm proto_options[i].defvalue.intval); 24194345Sdougm prop = sa_create_property(proto_options[i].name, 24204345Sdougm number); 24214345Sdougm break; 24223910Sdougm 24234345Sdougm case OPT_TYPE_BOOLEAN: 24244345Sdougm prop = sa_create_property(proto_options[i].name, 24254345Sdougm proto_options[i].defvalue.intval ? 24264345Sdougm "true" : "false"); 24274345Sdougm break; 24283910Sdougm 24294345Sdougm case OPT_TYPE_ONOFF: 24304345Sdougm prop = sa_create_property(proto_options[i].name, 24314345Sdougm proto_options[i].defvalue.intval ? 24324345Sdougm "on" : "off"); 24334345Sdougm break; 24343910Sdougm 24354345Sdougm default: 24364345Sdougm /* treat as strings of zero length */ 24374345Sdougm prop = sa_create_property(proto_options[i].name, 24384345Sdougm ""); 24394345Sdougm break; 24404345Sdougm } 24414345Sdougm if (prop != NULL) 24424345Sdougm (void) sa_add_protocol_property(protoset, prop); 24433910Sdougm } 24443910Sdougm } 24453910Sdougm } 24463910Sdougm 24473910Sdougm static void 24483910Sdougm free_protoprops() 24493910Sdougm { 24505179Sdougm if (protoset != NULL) { 24515179Sdougm xmlFreeNode(protoset); 24525179Sdougm protoset = NULL; 24535179Sdougm } 24543910Sdougm } 24553910Sdougm 24563910Sdougm /* 24573910Sdougm * nfs_init() 24583910Sdougm * 24593910Sdougm * Initialize the NFS plugin. 24603910Sdougm */ 24613910Sdougm 24623910Sdougm static int 24633910Sdougm nfs_init() 24643910Sdougm { 24653910Sdougm int ret = SA_OK; 24663910Sdougm 24673910Sdougm if (sa_plugin_ops.sa_init != nfs_init) 24684345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 24694345Sdougm "NFS plugin not properly initialized\n")); 24703910Sdougm 24713910Sdougm ret = initprotofromdefault(); 24724345Sdougm if (ret == SA_OK) 24734345Sdougm add_defaults(); 24743910Sdougm 24753910Sdougm return (ret); 24763910Sdougm } 24773910Sdougm 24783910Sdougm /* 24793910Sdougm * nfs_fini() 24803910Sdougm * 24813910Sdougm * uninitialize the NFS plugin. Want to avoid memory leaks. 24823910Sdougm */ 24833910Sdougm 24843910Sdougm static void 24853910Sdougm nfs_fini() 24863910Sdougm { 24873910Sdougm free_protoprops(); 24883910Sdougm } 24893910Sdougm 24903910Sdougm /* 24913910Sdougm * nfs_get_proto_set() 24923910Sdougm * 24933910Sdougm * Return an optionset with all the protocol specific properties in 24943910Sdougm * it. 24953910Sdougm */ 24963910Sdougm 24973910Sdougm static sa_protocol_properties_t 24983910Sdougm nfs_get_proto_set() 24993910Sdougm { 25003910Sdougm return (protoset); 25013910Sdougm } 25023910Sdougm 25033910Sdougm struct deffile { 25043910Sdougm struct deffile *next; 25053910Sdougm char *line; 25063910Sdougm }; 25073910Sdougm 25083910Sdougm /* 25093910Sdougm * read_default_file(fname) 25103910Sdougm * 25113910Sdougm * Read the specified default file. We return a list of entries. This 25123910Sdougm * get used for adding or removing values. 25133910Sdougm */ 25143910Sdougm 25153910Sdougm static struct deffile * 25163910Sdougm read_default_file(char *fname) 25173910Sdougm { 25183910Sdougm FILE *file; 25193910Sdougm struct deffile *defs = NULL; 25203910Sdougm struct deffile *newdef; 25213910Sdougm struct deffile *prevdef = NULL; 25223910Sdougm char buff[BUFSIZ * 2]; 25233910Sdougm 25243910Sdougm file = fopen(fname, "r"); 25253910Sdougm if (file != NULL) { 25264345Sdougm while (fgets(buff, sizeof (buff), file) != NULL) { 25274345Sdougm newdef = (struct deffile *)calloc(1, 25284345Sdougm sizeof (struct deffile)); 25294345Sdougm if (newdef != NULL) { 25304345Sdougm /* Make sure we skip any leading whitespace. */ 25314345Sdougm newdef->line = strdup(skipwhitespace(buff)); 25324345Sdougm if (defs == NULL) { 25334345Sdougm prevdef = defs = newdef; 25344345Sdougm } else { 25354345Sdougm prevdef->next = newdef; 25364345Sdougm prevdef = newdef; 25374345Sdougm } 25384345Sdougm } 25393910Sdougm } 25403910Sdougm } 25413910Sdougm (void) fclose(file); 25423910Sdougm return (defs); 25433910Sdougm } 25443910Sdougm 25453910Sdougm static void 25463910Sdougm free_default_file(struct deffile *defs) 25473910Sdougm { 25483910Sdougm struct deffile *curdefs = NULL; 25493910Sdougm 25503910Sdougm while (defs != NULL) { 25514345Sdougm curdefs = defs; 25524345Sdougm defs = defs->next; 25534345Sdougm if (curdefs->line != NULL) 25544345Sdougm free(curdefs->line); 25554345Sdougm free(curdefs); 25563910Sdougm } 25573910Sdougm } 25583910Sdougm 25593910Sdougm /* 25603910Sdougm * write_default_file(fname, defs) 25613910Sdougm * 25623910Sdougm * Write the default file back. 25633910Sdougm */ 25643910Sdougm 25653910Sdougm static int 25663910Sdougm write_default_file(char *fname, struct deffile *defs) 25673910Sdougm { 25683910Sdougm FILE *file; 25693910Sdougm int ret = SA_OK; 25703910Sdougm sigset_t old, new; 25713910Sdougm 25723910Sdougm file = fopen(fname, "w+"); 25733910Sdougm if (file != NULL) { 25744345Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 25754345Sdougm (void) sigaddset(&new, SIGHUP); 25764345Sdougm (void) sigaddset(&new, SIGINT); 25774345Sdougm (void) sigaddset(&new, SIGQUIT); 25784345Sdougm (void) sigaddset(&new, SIGTSTP); 25794345Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 25804345Sdougm while (defs != NULL) { 25814345Sdougm (void) fputs(defs->line, file); 25824345Sdougm defs = defs->next; 25834345Sdougm } 25844345Sdougm (void) fsync(fileno(file)); 25854345Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 25864345Sdougm (void) fclose(file); 25873910Sdougm } else { 25884345Sdougm switch (errno) { 25894345Sdougm case EPERM: 25904345Sdougm case EACCES: 25914345Sdougm ret = SA_NO_PERMISSION; 25924345Sdougm break; 25934345Sdougm default: 25944345Sdougm ret = SA_SYSTEM_ERR; 25954345Sdougm } 25963910Sdougm } 25973910Sdougm return (ret); 25983910Sdougm } 25993910Sdougm 26003910Sdougm 26013910Sdougm /* 26023910Sdougm * set_default_file_value(tag, value) 26033910Sdougm * 26043910Sdougm * Set the default file value for tag to value. Then rewrite the file. 26053910Sdougm * tag and value are always set. The caller must ensure this. 26063910Sdougm */ 26073910Sdougm 26083910Sdougm #define MAX_STRING_LENGTH 256 26093910Sdougm static int 26103910Sdougm set_default_file_value(char *tag, char *value) 26113910Sdougm { 26123910Sdougm int ret = SA_OK; 26133910Sdougm struct deffile *root; 26143910Sdougm struct deffile *defs; 26153910Sdougm struct deffile *prev; 26163910Sdougm char string[MAX_STRING_LENGTH]; 26173910Sdougm int len; 26183910Sdougm int update = 0; 26193910Sdougm 26203910Sdougm (void) snprintf(string, MAX_STRING_LENGTH, "%s=", tag); 26213910Sdougm len = strlen(string); 26223910Sdougm 26233910Sdougm root = defs = read_default_file(NFSADMIN); 26243910Sdougm if (root == NULL) { 26254345Sdougm if (errno == EPERM || errno == EACCES) 26264345Sdougm ret = SA_NO_PERMISSION; 26274345Sdougm else 26284345Sdougm ret = SA_SYSTEM_ERR; 26293910Sdougm } else { 26303910Sdougm while (defs != NULL) { 26314345Sdougm if (defs->line != NULL && 26324345Sdougm strncasecmp(defs->line, string, len) == 0) { 26334345Sdougm /* replace with the new value */ 26344345Sdougm free(defs->line); 26354345Sdougm fixcaseupper(tag); 26364345Sdougm (void) snprintf(string, sizeof (string), 26373910Sdougm "%s=%s\n", tag, value); 26384345Sdougm string[MAX_STRING_LENGTH - 1] = '\0'; 26394345Sdougm defs->line = strdup(string); 26404345Sdougm update = 1; 26414345Sdougm break; 26424345Sdougm } 26434345Sdougm defs = defs->next; 26443910Sdougm } 26454345Sdougm if (!update) { 26464345Sdougm defs = root; 26474345Sdougm /* didn't find, so see if it is a comment */ 26484345Sdougm (void) snprintf(string, MAX_STRING_LENGTH, "#%s=", tag); 26494345Sdougm len = strlen(string); 26504345Sdougm while (defs != NULL) { 26514345Sdougm if (strncasecmp(defs->line, string, len) == 0) { 26524345Sdougm /* replace with the new value */ 26534345Sdougm free(defs->line); 26544345Sdougm fixcaseupper(tag); 26554345Sdougm (void) snprintf(string, sizeof (string), 26564345Sdougm "%s=%s\n", tag, value); 26574345Sdougm string[MAX_STRING_LENGTH - 1] = '\0'; 26584345Sdougm defs->line = strdup(string); 26594345Sdougm update = 1; 26604345Sdougm break; 26614345Sdougm } 26624345Sdougm defs = defs->next; 26634345Sdougm } 26643910Sdougm } 26654345Sdougm if (!update) { 26664345Sdougm fixcaseupper(tag); 26674345Sdougm (void) snprintf(string, sizeof (string), "%s=%s\n", 26684345Sdougm tag, value); 26694345Sdougm prev = root; 26704345Sdougm while (prev->next != NULL) 26714345Sdougm prev = prev->next; 26724345Sdougm defs = malloc(sizeof (struct deffile)); 26734345Sdougm prev->next = defs; 26744345Sdougm if (defs != NULL) { 26754345Sdougm defs->next = NULL; 26764345Sdougm defs->line = strdup(string); 26774345Sdougm } 26784345Sdougm } 26794345Sdougm if (update) { 26804345Sdougm ret = write_default_file(NFSADMIN, root); 26814345Sdougm } 26824345Sdougm free_default_file(root); 26833910Sdougm } 26843910Sdougm return (ret); 26853910Sdougm } 26863910Sdougm 26873910Sdougm /* 26883910Sdougm * service_in_state(service, chkstate) 26893910Sdougm * 26903910Sdougm * Want to know if the specified service is in the desired state 26913910Sdougm * (chkstate) or not. Return true (1) if it is and false (0) if it 26923910Sdougm * isn't. 26933910Sdougm */ 26943910Sdougm static int 26953910Sdougm service_in_state(char *service, const char *chkstate) 26963910Sdougm { 26973910Sdougm char *state; 26983910Sdougm int ret = B_FALSE; 26993910Sdougm 27003910Sdougm state = smf_get_state(service); 27013910Sdougm if (state != NULL) { 27024345Sdougm /* got the state so get the equality for the return value */ 27034345Sdougm ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE; 27044345Sdougm free(state); 27053910Sdougm } 27063910Sdougm return (ret); 27073910Sdougm } 27083910Sdougm 27093910Sdougm /* 27103910Sdougm * restart_service(svcs) 27113910Sdougm * 27123910Sdougm * Walk through the bit mask of services that need to be restarted in 27133910Sdougm * order to use the new property values. Some properties affect 27143910Sdougm * multiple daemons. Should only restart a service if it is currently 27153910Sdougm * enabled (online). 27163910Sdougm */ 27173910Sdougm 27183910Sdougm static void 27193910Sdougm restart_service(uint32_t svcs) 27203910Sdougm { 27213910Sdougm uint32_t mask; 27223910Sdougm int ret; 27233910Sdougm char *service; 27243910Sdougm 27253910Sdougm for (mask = 1; svcs != 0; mask <<= 1) { 27264345Sdougm switch (svcs & mask) { 27274345Sdougm case SVC_LOCKD: 27284345Sdougm service = LOCKD; 27294345Sdougm break; 27304345Sdougm case SVC_STATD: 27314345Sdougm service = STATD; 27324345Sdougm break; 27334345Sdougm case SVC_NFSD: 27344345Sdougm service = NFSD; 27354345Sdougm break; 27364345Sdougm case SVC_MOUNTD: 27374345Sdougm service = MOUNTD; 27384345Sdougm break; 27394345Sdougm case SVC_NFS4CBD: 27404345Sdougm service = NFS4CBD; 27414345Sdougm break; 27424345Sdougm case SVC_NFSMAPID: 27434345Sdougm service = NFSMAPID; 27444345Sdougm break; 27454345Sdougm case SVC_RQUOTAD: 27464345Sdougm service = RQUOTAD; 27474345Sdougm break; 27484345Sdougm case SVC_NFSLOGD: 27494345Sdougm service = NFSLOGD; 27504345Sdougm break; 27514345Sdougm default: 27524345Sdougm continue; 27534345Sdougm } 27543910Sdougm 27553910Sdougm /* 27563910Sdougm * Only attempt to restart the service if it is 27573910Sdougm * currently running. In the future, it may be 27583910Sdougm * desirable to use smf_refresh_instance if the NFS 27593910Sdougm * services ever implement the refresh method. 27603910Sdougm */ 27614345Sdougm if (service_in_state(service, SCF_STATE_STRING_ONLINE)) { 27624345Sdougm ret = smf_restart_instance(service); 27633910Sdougm /* 27644345Sdougm * There are only a few SMF errors at this point, but 27654345Sdougm * it is also possible that a bad value may have put 27664345Sdougm * the service into maintenance if there wasn't an 27674345Sdougm * SMF level error. 27683910Sdougm */ 27694345Sdougm if (ret != 0) { 27704345Sdougm (void) fprintf(stderr, 27714345Sdougm dgettext(TEXT_DOMAIN, 27724345Sdougm "%s failed to restart: %s\n"), 27734345Sdougm scf_strerror(scf_error())); 27744345Sdougm } else { 27754345Sdougm /* 27764345Sdougm * Check whether it has gone to "maintenance" 27774345Sdougm * mode or not. Maintenance implies something 27784345Sdougm * went wrong. 27794345Sdougm */ 27804345Sdougm if (service_in_state(service, 27814345Sdougm SCF_STATE_STRING_MAINT)) { 27824345Sdougm (void) fprintf(stderr, 27834345Sdougm dgettext(TEXT_DOMAIN, 27844345Sdougm "%s failed to restart\n"), 27854345Sdougm service); 27864345Sdougm } 27874345Sdougm } 27883910Sdougm } 27894345Sdougm svcs &= ~mask; 27903910Sdougm } 27913910Sdougm } 27923910Sdougm 27933910Sdougm /* 27943910Sdougm * nfs_minmax_check(name, value) 27953910Sdougm * 27963910Sdougm * Verify that the value for the property specified by index is valid 27973910Sdougm * relative to the opposite value in the case of a min/max variable. 27983910Sdougm * Currently, server_minvers/server_maxvers and 27993910Sdougm * client_minvers/client_maxvers are the only ones to check. 28003910Sdougm */ 28013910Sdougm 28023910Sdougm static int 28033910Sdougm nfs_minmax_check(int index, int value) 28043910Sdougm { 28053910Sdougm int val; 28063910Sdougm char *pval; 28073910Sdougm sa_property_t prop; 28083910Sdougm sa_optionset_t opts; 28093910Sdougm int ret = B_TRUE; 28103910Sdougm 28113910Sdougm if (proto_options[index].other != NULL) { 28124345Sdougm /* have a property to compare against */ 28134345Sdougm opts = nfs_get_proto_set(); 28144345Sdougm prop = sa_get_property(opts, proto_options[index].other); 28153910Sdougm /* 28163910Sdougm * If we don't find the property, assume default 28173910Sdougm * values which will work since the max will be at the 28183910Sdougm * max and the min at the min. 28193910Sdougm */ 28204345Sdougm if (prop != NULL) { 28214345Sdougm pval = sa_get_property_attr(prop, "value"); 28224345Sdougm if (pval != NULL) { 28234345Sdougm val = strtoul(pval, NULL, 0); 28244345Sdougm if (proto_options[index].compare == 28254345Sdougm OPT_CMP_LE) { 28264345Sdougm ret = value <= val ? B_TRUE : B_FALSE; 28274345Sdougm } else if (proto_options[index].compare == 28284345Sdougm OPT_CMP_GE) { 28294345Sdougm ret = value >= val ? B_TRUE : B_FALSE; 28304345Sdougm } 28314345Sdougm } 28323910Sdougm } 28333910Sdougm } 28343910Sdougm return (ret); 28353910Sdougm } 28363910Sdougm 28373910Sdougm /* 28383910Sdougm * nfs_validate_proto_prop(index, name, value) 28393910Sdougm * 28405331Samw * Verify that the property specified by name can take the new 28413910Sdougm * value. This is a sanity check to prevent bad values getting into 28423910Sdougm * the default files. All values need to be checked against what is 28433910Sdougm * allowed by their defined type. If a type isn't explicitly defined 28443910Sdougm * here, it is treated as a string. 28453910Sdougm * 28463910Sdougm * Note that OPT_TYPE_NUMBER will additionally check that the value is 28473910Sdougm * within the range specified and potentially against another property 28483910Sdougm * value as well as specified in the proto_options members other and 28493910Sdougm * compare. 28503910Sdougm */ 28513910Sdougm 28523910Sdougm static int 28533910Sdougm nfs_validate_proto_prop(int index, char *name, char *value) 28543910Sdougm { 28553910Sdougm int ret = SA_OK; 28563910Sdougm char *cp; 28573910Sdougm #ifdef lint 28583910Sdougm name = name; 28593910Sdougm #endif 28603910Sdougm 28613910Sdougm switch (proto_options[index].type) { 28623910Sdougm case OPT_TYPE_NUMBER: 28634345Sdougm if (!is_a_number(value)) 28644345Sdougm ret = SA_BAD_VALUE; 28654345Sdougm else { 28664345Sdougm int val; 28674345Sdougm val = strtoul(value, NULL, 0); 28684345Sdougm if (val < proto_options[index].minval || 28694345Sdougm val > proto_options[index].maxval) 28704345Sdougm ret = SA_BAD_VALUE; 28714345Sdougm /* 28724345Sdougm * For server_versmin/server_versmax and 28734345Sdougm * client_versmin/client_versmax, the value of the 28744345Sdougm * min(max) should be checked to be correct relative 28754345Sdougm * to the current max(min). 28764345Sdougm */ 28774345Sdougm if (!nfs_minmax_check(index, val)) { 28784345Sdougm ret = SA_BAD_VALUE; 28794345Sdougm } 28803910Sdougm } 28814345Sdougm break; 28823910Sdougm 28833910Sdougm case OPT_TYPE_DOMAIN: 28843910Sdougm /* 28853910Sdougm * needs to be a qualified domain so will have at 28863910Sdougm * least one period and other characters on either 28873910Sdougm * side of it. A zero length string is also allowed 28883910Sdougm * and is the way to turn off the override. 28893910Sdougm */ 28904345Sdougm if (strlen(value) == 0) 28914345Sdougm break; 28924345Sdougm cp = strchr(value, '.'); 28934345Sdougm if (cp == NULL || cp == value || strchr(value, '@') != NULL) 28944345Sdougm ret = SA_BAD_VALUE; 28953910Sdougm break; 28963910Sdougm 28973910Sdougm case OPT_TYPE_BOOLEAN: 28984345Sdougm if (strlen(value) == 0 || 28994345Sdougm strcasecmp(value, "true") == 0 || 29004345Sdougm strcmp(value, "1") == 0 || 29014345Sdougm strcasecmp(value, "false") == 0 || 29024345Sdougm strcmp(value, "0") == 0) { 29034345Sdougm ret = SA_OK; 29044345Sdougm } else { 29054345Sdougm ret = SA_BAD_VALUE; 29064345Sdougm } 29074345Sdougm break; 29083910Sdougm 29093910Sdougm case OPT_TYPE_ONOFF: 29104345Sdougm if (strcasecmp(value, "on") != 0 && 29114345Sdougm strcasecmp(value, "off") != 0) { 29124345Sdougm ret = SA_BAD_VALUE; 29134345Sdougm } 29144345Sdougm break; 29153910Sdougm 29163910Sdougm case OPT_TYPE_PROTOCOL: 29174345Sdougm if (strcasecmp(value, "all") != 0 && 29184345Sdougm strcasecmp(value, "tcp") != 0 && 29194345Sdougm strcasecmp(value, "udp") != 0) 29204345Sdougm ret = SA_BAD_VALUE; 29214345Sdougm break; 29223910Sdougm 29233910Sdougm default: 29244345Sdougm /* treat as a string */ 29254345Sdougm break; 29263910Sdougm } 29273910Sdougm return (ret); 29283910Sdougm } 29293910Sdougm 29303910Sdougm /* 29313910Sdougm * nfs_set_proto_prop(prop) 29323910Sdougm * 29333910Sdougm * check that prop is valid. 29343910Sdougm */ 29353910Sdougm 29363910Sdougm static int 29373910Sdougm nfs_set_proto_prop(sa_property_t prop) 29383910Sdougm { 29393910Sdougm int ret = SA_OK; 29403910Sdougm char *name; 29413910Sdougm char *value; 29423910Sdougm 29433910Sdougm name = sa_get_property_attr(prop, "type"); 29443910Sdougm value = sa_get_property_attr(prop, "value"); 29453910Sdougm if (name != NULL && value != NULL) { 29464345Sdougm int index = findprotoopt(name, 1); 29474345Sdougm if (index >= 0) { 29484345Sdougm /* should test for valid value */ 29494345Sdougm ret = nfs_validate_proto_prop(index, name, value); 29504345Sdougm if (ret == SA_OK) 29514345Sdougm ret = set_default_file_value( 29524345Sdougm proto_options[index].tag, value); 29534345Sdougm if (ret == SA_OK) 29544345Sdougm restart_service(proto_options[index].svcs); 29554345Sdougm } 29563910Sdougm } 29573910Sdougm if (name != NULL) 29584345Sdougm sa_free_attr_string(name); 29593910Sdougm if (value != NULL) 29604345Sdougm sa_free_attr_string(value); 29613910Sdougm return (ret); 29623910Sdougm } 29633910Sdougm 29643910Sdougm /* 29653910Sdougm * nfs_get_status() 29663910Sdougm * 29673910Sdougm * What is the current status of the nfsd? We use the SMF state here. 29683910Sdougm * Caller must free the returned value. 29693910Sdougm */ 29703910Sdougm 29713910Sdougm static char * 29723910Sdougm nfs_get_status() 29733910Sdougm { 29743910Sdougm char *state; 29753910Sdougm state = smf_get_state(NFSD); 29763910Sdougm return (state != NULL ? state : strdup("-")); 29773910Sdougm } 29783910Sdougm 29793910Sdougm /* 29803910Sdougm * nfs_space_alias(alias) 29813910Sdougm * 29823910Sdougm * Lookup the space (security) name. If it is default, convert to the 29833910Sdougm * real name. 29843910Sdougm */ 29853910Sdougm 29863910Sdougm static char * 29873910Sdougm nfs_space_alias(char *space) 29883910Sdougm { 29893910Sdougm char *name = space; 29903910Sdougm seconfig_t secconf; 29913910Sdougm 29923910Sdougm /* 29933910Sdougm * Only the space named "default" is special. If it is used, 29943910Sdougm * the default needs to be looked up and the real name used. 29953910Sdougm * This is normally "sys" but could be changed. We always 29963910Sdougm * change defautl to the real name. 29973910Sdougm */ 29983910Sdougm if (strcmp(space, "default") == 0 && 29993910Sdougm nfs_getseconfig_default(&secconf) == 0) { 30004345Sdougm if (nfs_getseconfig_bynumber(secconf.sc_nfsnum, &secconf) == 0) 30014345Sdougm name = secconf.sc_name; 30023910Sdougm } 30033910Sdougm return (strdup(name)); 30043910Sdougm } 30055331Samw 30065331Samw /* 30075331Samw * nfs_features() 30085331Samw * 30095331Samw * Return a mask of the features required. 30105331Samw */ 30115331Samw 30125331Samw static uint64_t 30135331Samw nfs_features() 30145331Samw { 3015*6088Sdougm return ((uint64_t)SA_FEATURE_DFSTAB | SA_FEATURE_SERVER); 30165331Samw } 3017