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 /* 23*12679SPavel.Filipensky@Sun.COM * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 243910Sdougm */ 253910Sdougm 263910Sdougm /* 273910Sdougm * NFS specific functions 283910Sdougm */ 293910Sdougm #include <stdio.h> 303910Sdougm #include <string.h> 313910Sdougm #include <ctype.h> 323910Sdougm #include <stdlib.h> 333910Sdougm #include <unistd.h> 343910Sdougm #include <zone.h> 353910Sdougm #include <errno.h> 363910Sdougm #include <locale.h> 373910Sdougm #include <signal.h> 383910Sdougm #include "libshare.h" 393910Sdougm #include "libshare_impl.h" 403910Sdougm #include <nfs/export.h> 413910Sdougm #include <pwd.h> 423910Sdougm #include <limits.h> 433910Sdougm #include <libscf.h> 443910Sdougm #include "nfslog_config.h" 453910Sdougm #include "nfslogtab.h" 463910Sdougm #include "libshare_nfs.h" 473910Sdougm #include <rpcsvc/daemon_utils.h> 483910Sdougm #include <nfs/nfs.h> 494543Smarks #include <nfs/nfssys.h> 503910Sdougm 513910Sdougm /* should really be in some global place */ 523910Sdougm #define DEF_WIN 30000 533910Sdougm #define OPT_CHUNK 1024 543910Sdougm 553910Sdougm int debug = 0; 563910Sdougm 574543Smarks #define NFS_SERVER_SVC "svc:/network/nfs/server:default" 583910Sdougm 593910Sdougm /* internal functions */ 603910Sdougm static int nfs_init(); 613910Sdougm static void nfs_fini(); 623910Sdougm static int nfs_enable_share(sa_share_t); 634543Smarks static int nfs_disable_share(sa_share_t, char *); 646214Sdougm static int nfs_validate_property(sa_handle_t, sa_property_t, sa_optionset_t); 653910Sdougm static int nfs_validate_security_mode(char *); 663910Sdougm static int nfs_is_security_opt(char *); 673910Sdougm static int nfs_parse_legacy_options(sa_group_t, char *); 683910Sdougm static char *nfs_format_options(sa_group_t, int); 693910Sdougm static int nfs_set_proto_prop(sa_property_t); 703910Sdougm static sa_protocol_properties_t nfs_get_proto_set(); 713910Sdougm static char *nfs_get_status(); 723910Sdougm static char *nfs_space_alias(char *); 735331Samw static uint64_t nfs_features(); 743910Sdougm 753910Sdougm /* 763910Sdougm * ops vector that provides the protocol specific info and operations 773910Sdougm * for share management. 783910Sdougm */ 793910Sdougm 803910Sdougm struct sa_plugin_ops sa_plugin_ops = { 813910Sdougm SA_PLUGIN_VERSION, 823910Sdougm "nfs", 833910Sdougm nfs_init, 843910Sdougm nfs_fini, 853910Sdougm nfs_enable_share, 863910Sdougm nfs_disable_share, 873910Sdougm nfs_validate_property, 883910Sdougm nfs_validate_security_mode, 893910Sdougm nfs_is_security_opt, 903910Sdougm nfs_parse_legacy_options, 913910Sdougm nfs_format_options, 923910Sdougm nfs_set_proto_prop, 933910Sdougm nfs_get_proto_set, 943910Sdougm nfs_get_status, 953910Sdougm nfs_space_alias, 965331Samw NULL, /* update_legacy */ 975331Samw NULL, /* delete_legacy */ 985331Samw NULL, /* change_notify */ 995331Samw NULL, /* enable_resource */ 1005331Samw NULL, /* disable_resource */ 1015331Samw nfs_features, 1025331Samw NULL, /* transient shares */ 1035331Samw NULL, /* notify resource */ 1046007Sthurlow NULL, /* rename_resource */ 1056007Sthurlow NULL, /* run_command */ 1066007Sthurlow NULL, /* command_help */ 1076007Sthurlow NULL /* delete_proto_section */ 1083910Sdougm }; 1093910Sdougm 1103910Sdougm /* 1113910Sdougm * list of support services needed 1123910Sdougm * defines should come from head/rpcsvc/daemon_utils.h 1133910Sdougm */ 1143910Sdougm 1153910Sdougm static char *service_list_default[] = 11611291SRobert.Thurlow@Sun.COM { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, REPARSED, NULL }; 1173910Sdougm static char *service_list_logging[] = 11811291SRobert.Thurlow@Sun.COM { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, REPARSED, 11911291SRobert.Thurlow@Sun.COM NULL }; 1203910Sdougm 1213910Sdougm /* 1223910Sdougm * option definitions. Make sure to keep the #define for the option 1233910Sdougm * index just before the entry it is the index for. Changing the order 1243910Sdougm * can cause breakage. E.g OPT_RW is index 1 and must precede the 1253910Sdougm * line that includes the SHOPT_RW and OPT_RW entries. 1263910Sdougm */ 1273910Sdougm 1283910Sdougm struct option_defs optdefs[] = { 1293910Sdougm #define OPT_RO 0 1303910Sdougm {SHOPT_RO, OPT_RO, OPT_TYPE_ACCLIST}, 1313910Sdougm #define OPT_RW 1 1323910Sdougm {SHOPT_RW, OPT_RW, OPT_TYPE_ACCLIST}, 1333910Sdougm #define OPT_ROOT 2 1343910Sdougm {SHOPT_ROOT, OPT_ROOT, OPT_TYPE_ACCLIST}, 1353910Sdougm #define OPT_SECURE 3 1363910Sdougm {SHOPT_SECURE, OPT_SECURE, OPT_TYPE_DEPRECATED}, 1373910Sdougm #define OPT_ANON 4 1383910Sdougm {SHOPT_ANON, OPT_ANON, OPT_TYPE_USER}, 1393910Sdougm #define OPT_WINDOW 5 1403910Sdougm {SHOPT_WINDOW, OPT_WINDOW, OPT_TYPE_NUMBER}, 1413910Sdougm #define OPT_NOSUID 6 1423910Sdougm {SHOPT_NOSUID, OPT_NOSUID, OPT_TYPE_BOOLEAN}, 1433910Sdougm #define OPT_ACLOK 7 1443910Sdougm {SHOPT_ACLOK, OPT_ACLOK, OPT_TYPE_BOOLEAN}, 1453910Sdougm #define OPT_NOSUB 8 1463910Sdougm {SHOPT_NOSUB, OPT_NOSUB, OPT_TYPE_BOOLEAN}, 1473910Sdougm #define OPT_SEC 9 1483910Sdougm {SHOPT_SEC, OPT_SEC, OPT_TYPE_SECURITY}, 1493910Sdougm #define OPT_PUBLIC 10 1503910Sdougm {SHOPT_PUBLIC, OPT_PUBLIC, OPT_TYPE_BOOLEAN, OPT_SHARE_ONLY}, 1513910Sdougm #define OPT_INDEX 11 1523910Sdougm {SHOPT_INDEX, OPT_INDEX, OPT_TYPE_FILE}, 1533910Sdougm #define OPT_LOG 12 1543910Sdougm {SHOPT_LOG, OPT_LOG, OPT_TYPE_LOGTAG}, 1553910Sdougm #define OPT_CKSUM 13 1563910Sdougm {SHOPT_CKSUM, OPT_CKSUM, OPT_TYPE_STRINGSET}, 1577961SNatalie.Li@Sun.COM #define OPT_NONE 14 1587961SNatalie.Li@Sun.COM {SHOPT_NONE, OPT_NONE, OPT_TYPE_ACCLIST}, 1597961SNatalie.Li@Sun.COM #define OPT_ROOT_MAPPING 15 1607961SNatalie.Li@Sun.COM {SHOPT_ROOT_MAPPING, OPT_ROOT_MAPPING, OPT_TYPE_USER}, 1617961SNatalie.Li@Sun.COM #define OPT_CHARSET_MAP 16 1627961SNatalie.Li@Sun.COM {"", OPT_CHARSET_MAP, OPT_TYPE_ACCLIST}, 16311323SVallish.Vaidyeshwara@Sun.COM #define OPT_NOACLFAB 17 16411323SVallish.Vaidyeshwara@Sun.COM {SHOPT_NOACLFAB, OPT_NOACLFAB, OPT_TYPE_BOOLEAN}, 1653910Sdougm #ifdef VOLATILE_FH_TEST /* XXX added for testing volatile fh's only */ 16611323SVallish.Vaidyeshwara@Sun.COM #define OPT_VOLFH 18 1673910Sdougm {SHOPT_VOLFH, OPT_VOLFH}, 1683910Sdougm #endif /* VOLATILE_FH_TEST */ 1693910Sdougm NULL 1703910Sdougm }; 1713910Sdougm 1723910Sdougm /* 1737961SNatalie.Li@Sun.COM * Codesets that may need to be converted to UTF-8 for file paths. 1747961SNatalie.Li@Sun.COM * Add new names here to add new property support. If we ever get a 1757961SNatalie.Li@Sun.COM * way to query the kernel for character sets, this should become 1767961SNatalie.Li@Sun.COM * dynamically loaded. Make sure changes here are reflected in 1777961SNatalie.Li@Sun.COM * cmd/fs.d/nfs/mountd/nfscmd.c 1787961SNatalie.Li@Sun.COM */ 1797961SNatalie.Li@Sun.COM 1807961SNatalie.Li@Sun.COM static char *legal_conv[] = { 1817961SNatalie.Li@Sun.COM "euc-cn", 1827961SNatalie.Li@Sun.COM "euc-jp", 1837961SNatalie.Li@Sun.COM "euc-jpms", 1847961SNatalie.Li@Sun.COM "euc-kr", 1857961SNatalie.Li@Sun.COM "euc-tw", 1867961SNatalie.Li@Sun.COM "iso8859-1", 1877961SNatalie.Li@Sun.COM "iso8859-2", 1887961SNatalie.Li@Sun.COM "iso8859-5", 1897961SNatalie.Li@Sun.COM "iso8859-6", 1907961SNatalie.Li@Sun.COM "iso8859-7", 1917961SNatalie.Li@Sun.COM "iso8859-8", 1927961SNatalie.Li@Sun.COM "iso8859-9", 1937961SNatalie.Li@Sun.COM "iso8859-13", 1947961SNatalie.Li@Sun.COM "iso8859-15", 1957961SNatalie.Li@Sun.COM "koi8-r", 1967961SNatalie.Li@Sun.COM NULL 1977961SNatalie.Li@Sun.COM }; 1987961SNatalie.Li@Sun.COM 1997961SNatalie.Li@Sun.COM /* 2003910Sdougm * list of properties that are related to security flavors. 2013910Sdougm */ 2023910Sdougm static char *seclist[] = { 2033910Sdougm SHOPT_RO, 2043910Sdougm SHOPT_RW, 2053910Sdougm SHOPT_ROOT, 2063910Sdougm SHOPT_WINDOW, 2077961SNatalie.Li@Sun.COM SHOPT_NONE, 2087961SNatalie.Li@Sun.COM SHOPT_ROOT_MAPPING, 2093910Sdougm NULL 2103910Sdougm }; 2113910Sdougm 2123910Sdougm /* structure for list of securities */ 2133910Sdougm struct securities { 2143910Sdougm sa_security_t security; 2153910Sdougm struct securities *next; 2163910Sdougm }; 2173910Sdougm 2183910Sdougm /* 2197961SNatalie.Li@Sun.COM * findcharset(charset) 2207961SNatalie.Li@Sun.COM * 2217961SNatalie.Li@Sun.COM * Returns B_TRUE if the charset is a legal conversion otherwise 2227961SNatalie.Li@Sun.COM * B_FALSE. This will need to be rewritten to be more efficient when 2237961SNatalie.Li@Sun.COM * we have a dynamic list of legal conversions. 2247961SNatalie.Li@Sun.COM */ 2257961SNatalie.Li@Sun.COM 2267961SNatalie.Li@Sun.COM static boolean_t 2277961SNatalie.Li@Sun.COM findcharset(char *charset) 2287961SNatalie.Li@Sun.COM { 2297961SNatalie.Li@Sun.COM int i; 2307961SNatalie.Li@Sun.COM 2317961SNatalie.Li@Sun.COM for (i = 0; legal_conv[i] != NULL; i++) 2327961SNatalie.Li@Sun.COM if (strcmp(charset, legal_conv[i]) == 0) 2337961SNatalie.Li@Sun.COM return (B_TRUE); 2347961SNatalie.Li@Sun.COM return (B_FALSE); 2357961SNatalie.Li@Sun.COM } 2367961SNatalie.Li@Sun.COM 2377961SNatalie.Li@Sun.COM /* 2383910Sdougm * findopt(name) 2393910Sdougm * 2403910Sdougm * Lookup option "name" in the option table and return the table 2413910Sdougm * index. 2423910Sdougm */ 2433910Sdougm 2443910Sdougm static int 2453910Sdougm findopt(char *name) 2463910Sdougm { 2473910Sdougm int i; 2483910Sdougm if (name != NULL) { 2494345Sdougm for (i = 0; optdefs[i].tag != NULL; i++) { 2504345Sdougm if (strcmp(optdefs[i].tag, name) == 0) 2514345Sdougm return (i); 2524345Sdougm } 2537961SNatalie.Li@Sun.COM if (findcharset(name)) 2547961SNatalie.Li@Sun.COM return (OPT_CHARSET_MAP); 2553910Sdougm } 2563910Sdougm return (-1); 2573910Sdougm } 2583910Sdougm 2593910Sdougm /* 2603910Sdougm * gettype(name) 2613910Sdougm * 2623910Sdougm * Return the type of option "name". 2633910Sdougm */ 2643910Sdougm 2653910Sdougm static int 2663910Sdougm gettype(char *name) 2673910Sdougm { 2683910Sdougm int optdef; 2693910Sdougm 2703910Sdougm optdef = findopt(name); 2713910Sdougm if (optdef != -1) 2724345Sdougm return (optdefs[optdef].type); 2733910Sdougm return (OPT_TYPE_ANY); 2743910Sdougm } 2753910Sdougm 2763910Sdougm /* 2773910Sdougm * nfs_validate_security_mode(mode) 2783910Sdougm * 2793910Sdougm * is the specified mode string a valid one for use with NFS? 2803910Sdougm */ 2813910Sdougm 2823910Sdougm static int 2833910Sdougm nfs_validate_security_mode(char *mode) 2843910Sdougm { 2853910Sdougm seconfig_t secinfo; 2863910Sdougm int err; 2873910Sdougm 2883910Sdougm (void) memset(&secinfo, '\0', sizeof (secinfo)); 2893910Sdougm err = nfs_getseconfig_byname(mode, &secinfo); 2903910Sdougm if (err == SC_NOERROR) 2914345Sdougm return (1); 2923910Sdougm return (0); 2933910Sdougm } 2943910Sdougm 2953910Sdougm /* 2963910Sdougm * nfs_is_security_opt(tok) 2973910Sdougm * 2983910Sdougm * check to see if tok represents an option that is only valid in some 2993910Sdougm * security flavor. 3003910Sdougm */ 3013910Sdougm 3023910Sdougm static int 3033910Sdougm nfs_is_security_opt(char *tok) 3043910Sdougm { 3053910Sdougm int i; 3063910Sdougm 3073910Sdougm for (i = 0; seclist[i] != NULL; i++) { 3084345Sdougm if (strcmp(tok, seclist[i]) == 0) 3094345Sdougm return (1); 3103910Sdougm } 3113910Sdougm return (0); 3123910Sdougm } 3133910Sdougm 3143910Sdougm /* 3153910Sdougm * find_security(seclist, sec) 3163910Sdougm * 3173910Sdougm * Walk the current list of security flavors and return true if it is 3183910Sdougm * present, else return false. 3193910Sdougm */ 3203910Sdougm 3213910Sdougm static int 3223910Sdougm find_security(struct securities *seclist, sa_security_t sec) 3233910Sdougm { 3243910Sdougm while (seclist != NULL) { 3254345Sdougm if (seclist->security == sec) 3264345Sdougm return (1); 3274345Sdougm seclist = seclist->next; 3283910Sdougm } 3293910Sdougm return (0); 3303910Sdougm } 3313910Sdougm 3323910Sdougm /* 3333910Sdougm * make_security_list(group, securitymodes, proto) 3343910Sdougm * go through the list of securitymodes and add them to the 3353910Sdougm * group's list of security optionsets. We also keep a list of 3363910Sdougm * those optionsets so we don't have to find them later. All of 3373910Sdougm * these will get copies of the same properties. 3383910Sdougm */ 3393910Sdougm 3403910Sdougm static struct securities * 3413910Sdougm make_security_list(sa_group_t group, char *securitymodes, char *proto) 3423910Sdougm { 3433910Sdougm char *tok, *next = NULL; 3443910Sdougm struct securities *curp, *headp = NULL, *prev; 3453910Sdougm sa_security_t check; 3463910Sdougm int freetok = 0; 3473910Sdougm 3483910Sdougm for (tok = securitymodes; tok != NULL; tok = next) { 3494345Sdougm next = strchr(tok, ':'); 3504345Sdougm if (next != NULL) 3514345Sdougm *next++ = '\0'; 3524345Sdougm if (strcmp(tok, "default") == 0) { 3534345Sdougm /* resolve default into the real type */ 3544345Sdougm tok = nfs_space_alias(tok); 3554345Sdougm freetok = 1; 3564345Sdougm } 3574345Sdougm check = sa_get_security(group, tok, proto); 3583910Sdougm 3594345Sdougm /* add to the security list if it isn't there already */ 3604345Sdougm if (check == NULL || !find_security(headp, check)) { 3614345Sdougm curp = (struct securities *)calloc(1, 3624345Sdougm sizeof (struct securities)); 3634345Sdougm if (curp != NULL) { 3644345Sdougm if (check == NULL) { 3654345Sdougm curp->security = sa_create_security( 3664345Sdougm group, tok, proto); 3674345Sdougm } else { 3684345Sdougm curp->security = check; 3694345Sdougm } 3704345Sdougm /* 3714345Sdougm * note that the first time through the loop, 3724345Sdougm * headp will be NULL and prev will be 3734345Sdougm * undefined. Since headp is NULL, we set 3744345Sdougm * both it and prev to the curp (first 3754345Sdougm * structure to be allocated). 3764345Sdougm * 3774345Sdougm * later passes through the loop will have 3784345Sdougm * headp not being NULL and prev will be used 3794345Sdougm * to allocate at the end of the list. 3804345Sdougm */ 3814345Sdougm if (headp == NULL) { 3824345Sdougm headp = curp; 3834345Sdougm prev = curp; 3844345Sdougm } else { 3854345Sdougm prev->next = curp; 3864345Sdougm prev = curp; 3874345Sdougm } 3884345Sdougm } 3893910Sdougm } 3903910Sdougm 3914345Sdougm if (freetok) { 3924345Sdougm freetok = 0; 3934345Sdougm sa_free_attr_string(tok); 3944345Sdougm } 3953910Sdougm } 3963910Sdougm return (headp); 3973910Sdougm } 3983910Sdougm 3993910Sdougm static void 4003910Sdougm free_security_list(struct securities *sec) 4013910Sdougm { 4023910Sdougm struct securities *next; 4033910Sdougm if (sec != NULL) { 4044345Sdougm for (next = sec->next; sec != NULL; sec = next) { 4054345Sdougm next = sec->next; 4064345Sdougm free(sec); 4074345Sdougm } 4083910Sdougm } 4093910Sdougm } 4103910Sdougm 4113910Sdougm /* 4123910Sdougm * nfs_alistcat(str1, str2, sep) 4133910Sdougm * 4143910Sdougm * concatenate str1 and str2 into a new string using sep as a separate 4153910Sdougm * character. If memory allocation fails, return NULL; 4163910Sdougm */ 4173910Sdougm 4183910Sdougm static char * 4193910Sdougm nfs_alistcat(char *str1, char *str2, char sep) 4203910Sdougm { 4213910Sdougm char *newstr; 4223910Sdougm size_t len; 4233910Sdougm 4243910Sdougm len = strlen(str1) + strlen(str2) + 2; 4253910Sdougm newstr = (char *)malloc(len); 4263910Sdougm if (newstr != NULL) 4274345Sdougm (void) snprintf(newstr, len, "%s%c%s", str1, sep, str2); 4283910Sdougm return (newstr); 4293910Sdougm } 4303910Sdougm 4313910Sdougm /* 4323910Sdougm * add_security_prop(sec, name, value, persist) 4333910Sdougm * 4343910Sdougm * Add the property to the securities structure. This accumulates 4353910Sdougm * properties for as part of parsing legacy options. 4363910Sdougm */ 4373910Sdougm 4383910Sdougm static int 4393910Sdougm add_security_prop(struct securities *sec, char *name, char *value, 4403910Sdougm int persist, int iszfs) 4413910Sdougm { 4423910Sdougm sa_property_t prop; 4433910Sdougm int ret = SA_OK; 4443910Sdougm 4453910Sdougm for (; sec != NULL; sec = sec->next) { 4464345Sdougm if (value == NULL) { 4474345Sdougm if (strcmp(name, SHOPT_RW) == 0 || 4484345Sdougm strcmp(name, SHOPT_RO) == 0) 4494345Sdougm value = "*"; 4504345Sdougm else 4514345Sdougm value = "true"; 4524345Sdougm } 4533910Sdougm 4543910Sdougm /* 4553910Sdougm * Get the existing property, if it exists, so we can 4563910Sdougm * determine what to do with it. The ro/rw/root 4573910Sdougm * properties can be merged if multiple instances of 4583910Sdougm * these properies are given. For example, if "rw" 4593910Sdougm * exists with a value "host1" and a later token of 4603910Sdougm * rw="host2" is seen, the values are merged into a 4613910Sdougm * single rw="host1:host2". 4623910Sdougm */ 4634345Sdougm prop = sa_get_property(sec->security, name); 4643910Sdougm 4654345Sdougm if (prop != NULL) { 4664345Sdougm char *oldvalue; 4674345Sdougm char *newvalue; 4683910Sdougm 4693910Sdougm /* 4704345Sdougm * The security options of ro/rw/root might appear 4714345Sdougm * multiple times. If they do, the values need to be 4724345Sdougm * merged into an access list. If it was previously 4734345Sdougm * empty, the new value alone is added. 4743910Sdougm */ 4754345Sdougm oldvalue = sa_get_property_attr(prop, "value"); 4764345Sdougm if (oldvalue != NULL) { 4774345Sdougm /* 4784345Sdougm * The general case is to concatenate the new 4794345Sdougm * value onto the old value for multiple 4804345Sdougm * rw(ro/root) properties. A special case 4814345Sdougm * exists when either the old or new is the 4824345Sdougm * "all" case. In the special case, if both 4834345Sdougm * are "all", then it is "all", else if one is 4844345Sdougm * an access-list, that replaces the "all". 4854345Sdougm */ 4864345Sdougm if (strcmp(oldvalue, "*") == 0) { 4874345Sdougm /* Replace old value with new value. */ 4884345Sdougm newvalue = strdup(value); 4895454Sdougm } else if (strcmp(value, "*") == 0 || 4905454Sdougm strcmp(oldvalue, value) == 0) { 4914345Sdougm /* 4924345Sdougm * Keep old value and ignore 4934345Sdougm * the new value. 4944345Sdougm */ 4954345Sdougm newvalue = NULL; 4964345Sdougm } else { 4974345Sdougm /* 4984345Sdougm * Make a new list of old plus new 4994345Sdougm * access-list. 5004345Sdougm */ 5014345Sdougm newvalue = nfs_alistcat(oldvalue, 5024345Sdougm value, ':'); 5034345Sdougm } 5043910Sdougm 5054345Sdougm if (newvalue != NULL) { 5064345Sdougm (void) sa_remove_property(prop); 5074345Sdougm prop = sa_create_property(name, 5084345Sdougm newvalue); 5094345Sdougm ret = sa_add_property(sec->security, 5104345Sdougm prop); 5114345Sdougm free(newvalue); 5124345Sdougm } 5134345Sdougm if (oldvalue != NULL) 5144345Sdougm sa_free_attr_string(oldvalue); 5154345Sdougm } 5164345Sdougm } else { 5174345Sdougm prop = sa_create_property(name, value); 5183910Sdougm ret = sa_add_property(sec->security, prop); 5193910Sdougm } 5204345Sdougm if (ret == SA_OK && !iszfs) { 5214345Sdougm ret = sa_commit_properties(sec->security, !persist); 5224345Sdougm } 5233910Sdougm } 5243910Sdougm return (ret); 5253910Sdougm } 5263910Sdougm 5273910Sdougm /* 5283910Sdougm * check to see if group/share is persistent. 5293910Sdougm */ 5303910Sdougm static int 5313910Sdougm is_persistent(sa_group_t group) 5323910Sdougm { 5333910Sdougm char *type; 5343910Sdougm int persist = 1; 5353910Sdougm 5363910Sdougm type = sa_get_group_attr(group, "type"); 5373910Sdougm if (type != NULL && strcmp(type, "persist") != 0) 5384345Sdougm persist = 0; 5393910Sdougm if (type != NULL) 5404345Sdougm sa_free_attr_string(type); 5413910Sdougm return (persist); 5423910Sdougm } 5433910Sdougm 5443910Sdougm /* 5453910Sdougm * invalid_security(options) 5463910Sdougm * 5473910Sdougm * search option string for any invalid sec= type. 5483910Sdougm * return true (1) if any are not valid else false (0) 5493910Sdougm */ 5503910Sdougm static int 5513910Sdougm invalid_security(char *options) 5523910Sdougm { 5533910Sdougm char *copy, *base, *token, *value; 5543910Sdougm int ret = 0; 5553910Sdougm 5563910Sdougm copy = strdup(options); 5573910Sdougm token = base = copy; 5583910Sdougm while (token != NULL && ret == 0) { 5594345Sdougm token = strtok(base, ","); 5604345Sdougm base = NULL; 5614345Sdougm if (token != NULL) { 5624345Sdougm value = strchr(token, '='); 5634345Sdougm if (value != NULL) 5644345Sdougm *value++ = '\0'; 5654345Sdougm if (strcmp(token, "sec") == 0) { 5664345Sdougm /* HAVE security flavors so check them */ 5674345Sdougm char *tok, *next; 5684345Sdougm for (next = NULL, tok = value; tok != NULL; 5694345Sdougm tok = next) { 5704345Sdougm next = strchr(tok, ':'); 5714345Sdougm if (next != NULL) 5724345Sdougm *next++ = '\0'; 5734345Sdougm ret = !nfs_validate_security_mode(tok); 5744345Sdougm if (ret) 5754345Sdougm break; 5764345Sdougm } 5774345Sdougm } 5783910Sdougm } 5793910Sdougm } 5803910Sdougm if (copy != NULL) 5814345Sdougm free(copy); 5823910Sdougm return (ret); 5833910Sdougm } 5843910Sdougm 5853910Sdougm /* 5863910Sdougm * nfs_parse_legacy_options(group, options) 5873910Sdougm * 5883910Sdougm * Parse the old style options into internal format and store on the 5893910Sdougm * specified group. Group could be a share for full legacy support. 5903910Sdougm */ 5913910Sdougm 5923910Sdougm static int 5933910Sdougm nfs_parse_legacy_options(sa_group_t group, char *options) 5943910Sdougm { 5954704Sdougm char *dup; 5963910Sdougm char *base; 5973910Sdougm char *token; 5983910Sdougm sa_optionset_t optionset; 5993910Sdougm struct securities *security_list = NULL; 6003910Sdougm sa_property_t prop; 6013910Sdougm int ret = SA_OK; 6023910Sdougm int iszfs = 0; 6033910Sdougm sa_group_t parent; 6043910Sdougm int persist = 0; 6053910Sdougm char *lasts; 6063910Sdougm 6073910Sdougm /* do we have an existing optionset? */ 6083910Sdougm optionset = sa_get_optionset(group, "nfs"); 6093910Sdougm if (optionset == NULL) { 6104345Sdougm /* didn't find existing optionset so create one */ 6114345Sdougm optionset = sa_create_optionset(group, "nfs"); 6123910Sdougm } else { 6133910Sdougm /* 6145331Samw * Have an existing optionset . Ideally, we would need 6155331Samw * to compare options in order to detect errors. For 6165331Samw * now, we assume that the first optionset is the 6175331Samw * correct one and the others will be the same. An 6185331Samw * empty optionset is the same as no optionset so we 6195331Samw * don't want to exit in that case. Getting an empty 6205331Samw * optionset can occur with ZFS property checking. 6213910Sdougm */ 6225331Samw if (sa_get_property(optionset, NULL) != NULL) 6235331Samw return (ret); 6243910Sdougm } 6253910Sdougm 6263910Sdougm if (strcmp(options, SHOPT_RW) == 0) { 6273910Sdougm /* 6283910Sdougm * there is a special case of only the option "rw" 6293910Sdougm * being the default option. We don't have to do 6303910Sdougm * anything. 6313910Sdougm */ 6324345Sdougm return (ret); 6333910Sdougm } 6343910Sdougm 6353910Sdougm /* 6363910Sdougm * check if security types are present and validate them. If 6373910Sdougm * any are not legal, fail. 6383910Sdougm */ 6393910Sdougm 6403910Sdougm if (invalid_security(options)) { 6414345Sdougm return (SA_INVALID_SECURITY); 6423910Sdougm } 6433910Sdougm 6443910Sdougm /* 6453910Sdougm * in order to not attempt to change ZFS properties unless 6463910Sdougm * absolutely necessary, we never do it in the legacy parsing. 6473910Sdougm */ 6483910Sdougm if (sa_is_share(group)) { 6494345Sdougm char *zfs; 6504345Sdougm parent = sa_get_parent_group(group); 6514345Sdougm if (parent != NULL) { 6524345Sdougm zfs = sa_get_group_attr(parent, "zfs"); 6534345Sdougm if (zfs != NULL) { 6544345Sdougm sa_free_attr_string(zfs); 6554345Sdougm iszfs++; 6564345Sdougm } 6573910Sdougm } 6583910Sdougm } else { 6594345Sdougm iszfs = sa_group_is_zfs(group); 6603910Sdougm } 6613910Sdougm 6624704Sdougm /* We need a copy of options for the next part. */ 6634704Sdougm dup = strdup(options); 6644704Sdougm if (dup == NULL) 6654704Sdougm return (SA_NO_MEMORY); 6664704Sdougm 6673910Sdougm /* 6683910Sdougm * we need to step through each option in the string and then 6693910Sdougm * add either the option or the security option as needed. If 6703910Sdougm * this is not a persistent share, don't commit to the 6713910Sdougm * repository. If there is an error, we also want to abort the 6723910Sdougm * processing and report it. 6733910Sdougm */ 6743910Sdougm persist = is_persistent(group); 6753910Sdougm base = dup; 6763910Sdougm token = dup; 6773910Sdougm lasts = NULL; 6783910Sdougm while (token != NULL && ret == SA_OK) { 6794345Sdougm ret = SA_OK; 6804345Sdougm token = strtok_r(base, ",", &lasts); 6814345Sdougm base = NULL; 6824345Sdougm if (token != NULL) { 6834345Sdougm char *value; 6843910Sdougm /* 6854345Sdougm * if the option has a value, it will have an '=' to 6864345Sdougm * separate the name from the value. The following 6874345Sdougm * code will result in value != NULL and token 6884345Sdougm * pointing to just the name if there is a value. 6893910Sdougm */ 6904345Sdougm value = strchr(token, '='); 6914345Sdougm if (value != NULL) { 6924345Sdougm *value++ = '\0'; 6934345Sdougm } 6944345Sdougm if (strcmp(token, "sec") == 0 || 6954345Sdougm strcmp(token, "secure") == 0) { 6963910Sdougm /* 6974345Sdougm * Once in security parsing, we only 6984345Sdougm * do security. We do need to move 6994345Sdougm * between the security node and the 7004345Sdougm * toplevel. The security tag goes on 7014345Sdougm * the root while the following ones 7024345Sdougm * go on the security. 7033910Sdougm */ 7044345Sdougm if (security_list != NULL) { 7054345Sdougm /* 7064345Sdougm * have an old list so close it and 7074345Sdougm * start the new 7084345Sdougm */ 7094345Sdougm free_security_list(security_list); 7104345Sdougm } 7114345Sdougm if (strcmp(token, "secure") == 0) { 7124345Sdougm value = "dh"; 7134345Sdougm } else { 7144345Sdougm if (value == NULL) { 7154345Sdougm ret = SA_SYNTAX_ERR; 7164345Sdougm break; 7174345Sdougm } 7184345Sdougm } 7194345Sdougm security_list = make_security_list(group, 7204345Sdougm value, "nfs"); 7213910Sdougm } else { 7224345Sdougm /* 7234345Sdougm * Note that the "old" syntax allowed a 7244345Sdougm * default security model This must be 7254345Sdougm * accounted for and internally converted to 7264345Sdougm * "standard" security structure. 7274345Sdougm */ 7284345Sdougm if (nfs_is_security_opt(token)) { 7294345Sdougm if (security_list == NULL) { 7304345Sdougm /* 7314345Sdougm * need to have a 7324345Sdougm * security 7334345Sdougm * option. This will 7344345Sdougm * be "closed" when a 7354345Sdougm * defined "sec=" 7364345Sdougm * option is 7374345Sdougm * seen. This is 7384345Sdougm * technically an 7394345Sdougm * error but will be 7404345Sdougm * allowed with 7414345Sdougm * warning. 7424345Sdougm */ 7434345Sdougm security_list = 7444345Sdougm make_security_list(group, 7454345Sdougm "default", 7464345Sdougm "nfs"); 7474345Sdougm } 7484345Sdougm if (security_list != NULL) { 7494345Sdougm ret = add_security_prop( 7504345Sdougm security_list, token, 7514345Sdougm value, persist, iszfs); 7524345Sdougm } else { 7534345Sdougm ret = SA_NO_MEMORY; 7544345Sdougm } 7554345Sdougm } else { 7564345Sdougm /* regular options */ 7574345Sdougm if (value == NULL) { 7584345Sdougm if (strcmp(token, SHOPT_RW) == 7594345Sdougm 0 || strcmp(token, 7604345Sdougm SHOPT_RO) == 0) { 7614345Sdougm value = "*"; 7624345Sdougm } else { 7634345Sdougm value = "global"; 7644345Sdougm if (strcmp(token, 7654345Sdougm SHOPT_LOG) != 0) { 7664345Sdougm value = "true"; 7674345Sdougm } 7684345Sdougm } 7694345Sdougm } 7704372Sdougm /* 7714372Sdougm * In all cases, create the 7724372Sdougm * property specified. If the 7734372Sdougm * value was NULL, the default 7744372Sdougm * value will have been 7754372Sdougm * substituted. 7764372Sdougm */ 7774372Sdougm prop = sa_create_property(token, value); 7784372Sdougm ret = sa_add_property(optionset, prop); 7794372Sdougm if (ret != SA_OK) 7804372Sdougm break; 7814372Sdougm 7824345Sdougm if (!iszfs) { 7834345Sdougm ret = sa_commit_properties( 7844345Sdougm optionset, !persist); 7854345Sdougm } 7864345Sdougm } 7873910Sdougm } 7883910Sdougm } 7893910Sdougm } 7903910Sdougm if (security_list != NULL) 7914345Sdougm free_security_list(security_list); 7924704Sdougm 7934704Sdougm free(dup); 7943910Sdougm return (ret); 7953910Sdougm } 7963910Sdougm 7973910Sdougm /* 7983910Sdougm * is_a_number(number) 7993910Sdougm * 8003910Sdougm * is the string a number in one of the forms we want to use? 8013910Sdougm */ 8023910Sdougm 8033910Sdougm static int 8043910Sdougm is_a_number(char *number) 8053910Sdougm { 8063910Sdougm int ret = 1; 8073910Sdougm int hex = 0; 8083910Sdougm 8093910Sdougm if (strncmp(number, "0x", 2) == 0) { 8104345Sdougm number += 2; 8114345Sdougm hex = 1; 8124345Sdougm } else if (*number == '-') { 8134345Sdougm number++; /* skip the minus */ 8144345Sdougm } 8153910Sdougm while (ret == 1 && *number != '\0') { 8164345Sdougm if (hex) { 8174345Sdougm ret = isxdigit(*number++); 8184345Sdougm } else { 8194345Sdougm ret = isdigit(*number++); 8204345Sdougm } 8213910Sdougm } 8223910Sdougm return (ret); 8233910Sdougm } 8243910Sdougm 8253910Sdougm /* 8263910Sdougm * Look for the specified tag in the configuration file. If it is found, 8273910Sdougm * enable logging and set the logging configuration information for exp. 8283910Sdougm */ 8293910Sdougm static void 8303910Sdougm configlog(struct exportdata *exp, char *tag) 8313910Sdougm { 8323910Sdougm nfsl_config_t *configlist = NULL, *configp; 8333910Sdougm int error = 0; 8343910Sdougm char globaltag[] = DEFAULTTAG; 8353910Sdougm 8363910Sdougm /* 8373910Sdougm * Sends config errors to stderr 8383910Sdougm */ 8393910Sdougm nfsl_errs_to_syslog = B_FALSE; 8403910Sdougm 8413910Sdougm /* 8423910Sdougm * get the list of configuration settings 8433910Sdougm */ 8443910Sdougm error = nfsl_getconfig_list(&configlist); 8453910Sdougm if (error) { 8463910Sdougm (void) fprintf(stderr, 8474345Sdougm dgettext(TEXT_DOMAIN, "Cannot get log configuration: %s\n"), 8484345Sdougm strerror(error)); 8493910Sdougm } 8503910Sdougm 8513910Sdougm if (tag == NULL) 8523910Sdougm tag = globaltag; 8533910Sdougm if ((configp = nfsl_findconfig(configlist, tag, &error)) == NULL) { 8543910Sdougm nfsl_freeconfig_list(&configlist); 8553910Sdougm (void) fprintf(stderr, 8564345Sdougm dgettext(TEXT_DOMAIN, "No tags matching \"%s\"\n"), tag); 8573910Sdougm /* bad configuration */ 8583910Sdougm error = ENOENT; 8593910Sdougm goto err; 8603910Sdougm } 8613910Sdougm 8623910Sdougm if ((exp->ex_tag = strdup(tag)) == NULL) { 8633910Sdougm error = ENOMEM; 8643910Sdougm goto out; 8653910Sdougm } 8663910Sdougm if ((exp->ex_log_buffer = strdup(configp->nc_bufferpath)) == NULL) { 8673910Sdougm error = ENOMEM; 8683910Sdougm goto out; 8693910Sdougm } 8703910Sdougm exp->ex_flags |= EX_LOG; 8713910Sdougm if (configp->nc_rpclogpath != NULL) 8723910Sdougm exp->ex_flags |= EX_LOG_ALLOPS; 8733910Sdougm out: 8743910Sdougm if (configlist != NULL) 8754345Sdougm nfsl_freeconfig_list(&configlist); 8763910Sdougm 8773910Sdougm err: 8783910Sdougm if (error != 0) { 8793910Sdougm if (exp->ex_flags != NULL) 8803910Sdougm free(exp->ex_tag); 8813910Sdougm if (exp->ex_log_buffer != NULL) 8823910Sdougm free(exp->ex_log_buffer); 8833910Sdougm (void) fprintf(stderr, 8844345Sdougm dgettext(TEXT_DOMAIN, "Cannot set log configuration: %s\n"), 8854345Sdougm strerror(error)); 8863910Sdougm } 8873910Sdougm } 8883910Sdougm 8893910Sdougm /* 8903910Sdougm * fill_export_from_optionset(export, optionset) 8913910Sdougm * 8923910Sdougm * In order to share, we need to set all the possible general options 8933910Sdougm * into the export structure. Share info will be filled in by the 8943910Sdougm * caller. Various property values get turned into structure specific 8953910Sdougm * values. 8963910Sdougm */ 8973910Sdougm 8983910Sdougm static int 8993910Sdougm fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset) 9003910Sdougm { 9013910Sdougm sa_property_t option; 9023910Sdougm int ret = SA_OK; 9033910Sdougm 9043910Sdougm for (option = sa_get_property(optionset, NULL); 9054345Sdougm option != NULL; option = sa_get_next_property(option)) { 9064345Sdougm char *name; 9074345Sdougm char *value; 9084345Sdougm uint32_t val; 9093910Sdougm 9104345Sdougm /* 9114345Sdougm * since options may be set/reset multiple times, always do an 9124345Sdougm * explicit set or clear of the option. This allows defaults 9135331Samw * to be set and then the protocol specific to override. 9144345Sdougm */ 9153910Sdougm 9164345Sdougm name = sa_get_property_attr(option, "type"); 9174345Sdougm value = sa_get_property_attr(option, "value"); 9184345Sdougm switch (findopt(name)) { 9194345Sdougm case OPT_ANON: 9204345Sdougm if (value != NULL && is_a_number(value)) { 9214345Sdougm val = strtoul(value, NULL, 0); 9224345Sdougm } else { 9234345Sdougm struct passwd *pw; 9244345Sdougm pw = getpwnam(value != NULL ? value : "nobody"); 9254345Sdougm if (pw != NULL) { 9264345Sdougm val = pw->pw_uid; 9274345Sdougm } else { 9284345Sdougm val = UID_NOBODY; 9294345Sdougm } 9304345Sdougm endpwent(); 9314345Sdougm } 9324345Sdougm export->ex_anon = val; 9334345Sdougm break; 9344345Sdougm case OPT_NOSUID: 9354345Sdougm if (value != NULL && (strcasecmp(value, "true") == 0 || 9364345Sdougm strcmp(value, "1") == 0)) 9374345Sdougm export->ex_flags |= EX_NOSUID; 9384345Sdougm else 9394345Sdougm export->ex_flags &= ~EX_NOSUID; 9404345Sdougm break; 9414345Sdougm case OPT_ACLOK: 9424345Sdougm if (value != NULL && (strcasecmp(value, "true") == 0 || 9434345Sdougm strcmp(value, "1") == 0)) 9444345Sdougm export->ex_flags |= EX_ACLOK; 9454345Sdougm else 9464345Sdougm export->ex_flags &= ~EX_ACLOK; 9474345Sdougm break; 9484345Sdougm case OPT_NOSUB: 9494345Sdougm if (value != NULL && (strcasecmp(value, "true") == 0 || 9504345Sdougm strcmp(value, "1") == 0)) 9514345Sdougm export->ex_flags |= EX_NOSUB; 9524345Sdougm else 9534345Sdougm export->ex_flags &= ~EX_NOSUB; 9544345Sdougm break; 9554345Sdougm case OPT_PUBLIC: 9564345Sdougm if (value != NULL && (strcasecmp(value, "true") == 0 || 9574345Sdougm strcmp(value, "1") == 0)) 9584345Sdougm export->ex_flags |= EX_PUBLIC; 9594345Sdougm else 9604345Sdougm export->ex_flags &= ~EX_PUBLIC; 9614345Sdougm break; 9624345Sdougm case OPT_INDEX: 9634345Sdougm if (value != NULL && (strcmp(value, "..") == 0 || 9644345Sdougm strchr(value, '/') != NULL)) { 9654345Sdougm /* this is an error */ 9664345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 9674345Sdougm "NFS: index=\"%s\" not valid;" 9684345Sdougm "must be a filename.\n"), 9694345Sdougm value); 9704345Sdougm break; 9714345Sdougm } 9724345Sdougm if (value != NULL && *value != '\0' && 9734345Sdougm strcmp(value, ".") != 0) { 9744345Sdougm /* valid index file string */ 9754345Sdougm if (export->ex_index != NULL) { 9764345Sdougm /* left over from "default" */ 9774345Sdougm free(export->ex_index); 9784345Sdougm } 9794345Sdougm /* remember to free */ 9804345Sdougm export->ex_index = strdup(value); 9814345Sdougm if (export->ex_index == NULL) { 9824345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 9834345Sdougm "NFS: out of memory setting " 9844345Sdougm "index property\n")); 9854345Sdougm break; 9864345Sdougm } 9874345Sdougm export->ex_flags |= EX_INDEX; 9884345Sdougm } 9894345Sdougm break; 9904345Sdougm case OPT_LOG: 9914345Sdougm if (value == NULL) 9924345Sdougm value = strdup("global"); 9934345Sdougm if (value != NULL) 9944345Sdougm configlog(export, 9954345Sdougm strlen(value) ? value : "global"); 9964345Sdougm break; 9977961SNatalie.Li@Sun.COM case OPT_CHARSET_MAP: 9987961SNatalie.Li@Sun.COM /* 9997961SNatalie.Li@Sun.COM * Set EX_CHARMAP when there is at least one 10007961SNatalie.Li@Sun.COM * charmap conversion property. This will get 10017961SNatalie.Li@Sun.COM * checked by the nfs server when it needs to. 10027961SNatalie.Li@Sun.COM */ 10037961SNatalie.Li@Sun.COM export->ex_flags |= EX_CHARMAP; 10047961SNatalie.Li@Sun.COM break; 100511323SVallish.Vaidyeshwara@Sun.COM case OPT_NOACLFAB: 100611323SVallish.Vaidyeshwara@Sun.COM if (value != NULL && (strcasecmp(value, "true") == 0 || 100711323SVallish.Vaidyeshwara@Sun.COM strcmp(value, "1") == 0)) 100811323SVallish.Vaidyeshwara@Sun.COM export->ex_flags |= EX_NOACLFAB; 100911323SVallish.Vaidyeshwara@Sun.COM else 101011323SVallish.Vaidyeshwara@Sun.COM export->ex_flags &= ~EX_NOACLFAB; 101111323SVallish.Vaidyeshwara@Sun.COM break; 10124345Sdougm default: 10134345Sdougm /* have a syntactic error */ 10144345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 10154345Sdougm "NFS: unrecognized option %s=%s\n"), 101611337SWilliam.Krier@Sun.COM name != NULL ? name : "", 101711337SWilliam.Krier@Sun.COM value != NULL ? value : ""); 10184345Sdougm break; 10193910Sdougm } 10204345Sdougm if (name != NULL) 10214345Sdougm sa_free_attr_string(name); 10223910Sdougm if (value != NULL) 10234345Sdougm sa_free_attr_string(value); 10243910Sdougm } 10253910Sdougm return (ret); 10263910Sdougm } 10273910Sdougm 10283910Sdougm /* 10293910Sdougm * cleanup_export(export) 10303910Sdougm * 10313910Sdougm * Cleanup the allocated areas so we don't leak memory 10323910Sdougm */ 10333910Sdougm 10343910Sdougm static void 10353910Sdougm cleanup_export(struct exportdata *export) 10363910Sdougm { 10373910Sdougm int i; 10383910Sdougm 10393910Sdougm if (export->ex_index != NULL) 10404345Sdougm free(export->ex_index); 10413910Sdougm if (export->ex_secinfo != NULL) { 10424345Sdougm for (i = 0; i < export->ex_seccnt; i++) 10434345Sdougm if (export->ex_secinfo[i].s_rootnames != NULL) 10444345Sdougm free(export->ex_secinfo[i].s_rootnames); 10454345Sdougm free(export->ex_secinfo); 10463910Sdougm } 10473910Sdougm } 10483910Sdougm 10493910Sdougm /* 10503910Sdougm * Given a seconfig entry and a colon-separated 10513910Sdougm * list of names, allocate an array big enough 10523910Sdougm * to hold the root list, then convert each name to 10533910Sdougm * a principal name according to the security 10543910Sdougm * info and assign it to an array element. 10553910Sdougm * Return the array and its size. 10563910Sdougm */ 10573910Sdougm static caddr_t * 10583910Sdougm get_rootnames(seconfig_t *sec, char *list, int *count) 10593910Sdougm { 10603910Sdougm caddr_t *a; 10613910Sdougm int c, i; 10623910Sdougm char *host, *p; 10633910Sdougm 10643910Sdougm /* 10653910Sdougm * Count the number of strings in the list. 10663910Sdougm * This is the number of colon separators + 1. 10673910Sdougm */ 10683910Sdougm c = 1; 10693910Sdougm for (p = list; *p; p++) 10703910Sdougm if (*p == ':') 10713910Sdougm c++; 10723910Sdougm *count = c; 10733910Sdougm 10743910Sdougm a = (caddr_t *)malloc(c * sizeof (char *)); 10753910Sdougm if (a == NULL) { 10763910Sdougm (void) printf(dgettext(TEXT_DOMAIN, 10774345Sdougm "get_rootnames: no memory\n")); 10783910Sdougm } else { 10794345Sdougm for (i = 0; i < c; i++) { 10804345Sdougm host = strtok(list, ":"); 10814345Sdougm if (!nfs_get_root_principal(sec, host, &a[i])) { 10824345Sdougm free(a); 10834345Sdougm a = NULL; 10844345Sdougm break; 10854345Sdougm } 10864345Sdougm list = NULL; 10873910Sdougm } 10883910Sdougm } 10893910Sdougm 10903910Sdougm return (a); 10913910Sdougm } 10923910Sdougm 10933910Sdougm /* 10943910Sdougm * fill_security_from_secopts(sp, secopts) 10953910Sdougm * 10963910Sdougm * Fill the secinfo structure from the secopts optionset. 10973910Sdougm */ 10983910Sdougm 10993910Sdougm static int 11003910Sdougm fill_security_from_secopts(struct secinfo *sp, sa_security_t secopts) 11013910Sdougm { 11023910Sdougm sa_property_t prop; 11033910Sdougm char *type; 11043910Sdougm int longform; 11053910Sdougm int err = SC_NOERROR; 11067961SNatalie.Li@Sun.COM uint32_t val; 11073910Sdougm 11083910Sdougm type = sa_get_security_attr(secopts, "sectype"); 11093910Sdougm if (type != NULL) { 11104345Sdougm /* named security type needs secinfo to be filled in */ 11114345Sdougm err = nfs_getseconfig_byname(type, &sp->s_secinfo); 11124345Sdougm sa_free_attr_string(type); 11134345Sdougm if (err != SC_NOERROR) 11144345Sdougm return (err); 11153910Sdougm } else { 11164345Sdougm /* default case */ 11174345Sdougm err = nfs_getseconfig_default(&sp->s_secinfo); 11184345Sdougm if (err != SC_NOERROR) 11194345Sdougm return (err); 11203910Sdougm } 11213910Sdougm 11223910Sdougm err = SA_OK; 11233910Sdougm for (prop = sa_get_property(secopts, NULL); 11244345Sdougm prop != NULL && err == SA_OK; 11254345Sdougm prop = sa_get_next_property(prop)) { 11264345Sdougm char *name; 11274345Sdougm char *value; 11283910Sdougm 11294345Sdougm name = sa_get_property_attr(prop, "type"); 11304345Sdougm value = sa_get_property_attr(prop, "value"); 11313910Sdougm 11324345Sdougm longform = value != NULL && strcmp(value, "*") != 0; 11333910Sdougm 11344345Sdougm switch (findopt(name)) { 11354345Sdougm case OPT_RO: 11364345Sdougm sp->s_flags |= longform ? M_ROL : M_RO; 11374345Sdougm break; 11384345Sdougm case OPT_RW: 11394345Sdougm sp->s_flags |= longform ? M_RWL : M_RW; 11404345Sdougm break; 11414345Sdougm case OPT_ROOT: 11424345Sdougm sp->s_flags |= M_ROOT; 11434345Sdougm /* 11444345Sdougm * if we are using AUTH_UNIX, handle like other things 11454345Sdougm * such as RO/RW 11464345Sdougm */ 11474345Sdougm if (sp->s_secinfo.sc_rpcnum == AUTH_UNIX) 11484345Sdougm continue; 11494345Sdougm /* not AUTH_UNIX */ 11504345Sdougm if (value != NULL) { 11514345Sdougm sp->s_rootnames = get_rootnames(&sp->s_secinfo, 11524345Sdougm value, &sp->s_rootcnt); 11534345Sdougm if (sp->s_rootnames == NULL) { 11544345Sdougm err = SA_BAD_VALUE; 11554345Sdougm (void) fprintf(stderr, 11564345Sdougm dgettext(TEXT_DOMAIN, 11574345Sdougm "Bad root list\n")); 11584345Sdougm } 11594345Sdougm } 11604345Sdougm break; 11617961SNatalie.Li@Sun.COM case OPT_NONE: 11627961SNatalie.Li@Sun.COM sp->s_flags |= M_NONE; 11637961SNatalie.Li@Sun.COM break; 11644345Sdougm case OPT_WINDOW: 11654345Sdougm if (value != NULL) { 11664345Sdougm sp->s_window = atoi(value); 11674345Sdougm /* just in case */ 11684345Sdougm if (sp->s_window < 0) 11694345Sdougm sp->s_window = DEF_WIN; 11704345Sdougm } 11714345Sdougm break; 11727961SNatalie.Li@Sun.COM case OPT_ROOT_MAPPING: 11737961SNatalie.Li@Sun.COM if (value != NULL && is_a_number(value)) { 11747961SNatalie.Li@Sun.COM val = strtoul(value, NULL, 0); 11757961SNatalie.Li@Sun.COM } else { 11767961SNatalie.Li@Sun.COM struct passwd *pw; 11777961SNatalie.Li@Sun.COM pw = getpwnam(value != NULL ? value : "nobody"); 11787961SNatalie.Li@Sun.COM if (pw != NULL) { 11797961SNatalie.Li@Sun.COM val = pw->pw_uid; 11807961SNatalie.Li@Sun.COM } else { 11817961SNatalie.Li@Sun.COM val = UID_NOBODY; 11827961SNatalie.Li@Sun.COM } 11837961SNatalie.Li@Sun.COM endpwent(); 11847961SNatalie.Li@Sun.COM } 11857961SNatalie.Li@Sun.COM sp->s_rootid = val; 11867961SNatalie.Li@Sun.COM break; 11874345Sdougm default: 11884345Sdougm break; 11893910Sdougm } 11904345Sdougm if (name != NULL) 11914345Sdougm sa_free_attr_string(name); 11924345Sdougm if (value != NULL) 11934345Sdougm sa_free_attr_string(value); 11943910Sdougm } 11953910Sdougm /* if rw/ro options not set, use default of RW */ 11963910Sdougm if ((sp->s_flags & NFS_RWMODES) == 0) 11974345Sdougm sp->s_flags |= M_RW; 11983910Sdougm return (err); 11993910Sdougm } 12003910Sdougm 12013910Sdougm /* 12023910Sdougm * This is for testing only 12033910Sdougm * It displays the export structure that 12043910Sdougm * goes into the kernel. 12053910Sdougm */ 12063910Sdougm static void 12073910Sdougm printarg(char *path, struct exportdata *ep) 12083910Sdougm { 12093910Sdougm int i, j; 12103910Sdougm struct secinfo *sp; 12113910Sdougm 12123910Sdougm if (debug == 0) 12134345Sdougm return; 12143910Sdougm 12153910Sdougm (void) printf("%s:\n", path); 12163910Sdougm (void) printf("\tex_version = %d\n", ep->ex_version); 12173910Sdougm (void) printf("\tex_path = %s\n", ep->ex_path); 12183910Sdougm (void) printf("\tex_pathlen = %ld\n", (ulong_t)ep->ex_pathlen); 12193910Sdougm (void) printf("\tex_flags: (0x%02x) ", ep->ex_flags); 12203910Sdougm if (ep->ex_flags & EX_NOSUID) 12213910Sdougm (void) printf("NOSUID "); 12223910Sdougm if (ep->ex_flags & EX_ACLOK) 12233910Sdougm (void) printf("ACLOK "); 12243910Sdougm if (ep->ex_flags & EX_PUBLIC) 12253910Sdougm (void) printf("PUBLIC "); 12263910Sdougm if (ep->ex_flags & EX_NOSUB) 12273910Sdougm (void) printf("NOSUB "); 12283910Sdougm if (ep->ex_flags & EX_LOG) 12293910Sdougm (void) printf("LOG "); 12307961SNatalie.Li@Sun.COM if (ep->ex_flags & EX_CHARMAP) 12317961SNatalie.Li@Sun.COM (void) printf("CHARMAP "); 12323910Sdougm if (ep->ex_flags & EX_LOG_ALLOPS) 12333910Sdougm (void) printf("LOG_ALLOPS "); 12343910Sdougm if (ep->ex_flags == 0) 12353910Sdougm (void) printf("(none)"); 12363910Sdougm (void) printf("\n"); 12373910Sdougm if (ep->ex_flags & EX_LOG) { 12383910Sdougm (void) printf("\tex_log_buffer = %s\n", 12394345Sdougm (ep->ex_log_buffer ? ep->ex_log_buffer : "(NULL)")); 12403910Sdougm (void) printf("\tex_tag = %s\n", 12414345Sdougm (ep->ex_tag ? ep->ex_tag : "(NULL)")); 12423910Sdougm } 12433910Sdougm (void) printf("\tex_anon = %d\n", ep->ex_anon); 12443910Sdougm (void) printf("\tex_seccnt = %d\n", ep->ex_seccnt); 12453910Sdougm (void) printf("\n"); 12463910Sdougm for (i = 0; i < ep->ex_seccnt; i++) { 12473910Sdougm sp = &ep->ex_secinfo[i]; 12483910Sdougm (void) printf("\t\ts_secinfo = %s\n", sp->s_secinfo.sc_name); 12493910Sdougm (void) printf("\t\ts_flags: (0x%02x) ", sp->s_flags); 12503910Sdougm if (sp->s_flags & M_ROOT) (void) printf("M_ROOT "); 12513910Sdougm if (sp->s_flags & M_RO) (void) printf("M_RO "); 12523910Sdougm if (sp->s_flags & M_ROL) (void) printf("M_ROL "); 12533910Sdougm if (sp->s_flags & M_RW) (void) printf("M_RW "); 12543910Sdougm if (sp->s_flags & M_RWL) (void) printf("M_RWL "); 12557961SNatalie.Li@Sun.COM if (sp->s_flags & M_NONE) (void) printf("M_NONE "); 12563910Sdougm if (sp->s_flags == 0) (void) printf("(none)"); 12573910Sdougm (void) printf("\n"); 12583910Sdougm (void) printf("\t\ts_window = %d\n", sp->s_window); 12597961SNatalie.Li@Sun.COM (void) printf("\t\ts_rootid = %d\n", sp->s_rootid); 12603910Sdougm (void) printf("\t\ts_rootcnt = %d ", sp->s_rootcnt); 12613910Sdougm (void) fflush(stdout); 12623910Sdougm for (j = 0; j < sp->s_rootcnt; j++) 12633910Sdougm (void) printf("%s ", sp->s_rootnames[j] ? 12644345Sdougm sp->s_rootnames[j] : "<null>"); 12653910Sdougm (void) printf("\n\n"); 12663910Sdougm } 12673910Sdougm } 12683910Sdougm 12693910Sdougm /* 12703910Sdougm * count_security(opts) 12713910Sdougm * 12723910Sdougm * Count the number of security types (flavors). The optionset has 12733910Sdougm * been populated with the security flavors as a holding mechanism. 12743910Sdougm * We later use this number to allocate data structures. 12753910Sdougm */ 12763910Sdougm 12773910Sdougm static int 12783910Sdougm count_security(sa_optionset_t opts) 12793910Sdougm { 12803910Sdougm int count = 0; 12813910Sdougm sa_property_t prop; 12823910Sdougm if (opts != NULL) { 12834345Sdougm for (prop = sa_get_property(opts, NULL); prop != NULL; 12844345Sdougm prop = sa_get_next_property(prop)) { 12854345Sdougm count++; 12864345Sdougm } 12873910Sdougm } 12883910Sdougm return (count); 12893910Sdougm } 12903910Sdougm 12913910Sdougm /* 12923910Sdougm * nfs_sprint_option(rbuff, rbuffsize, incr, prop, sep) 12933910Sdougm * 12943910Sdougm * provides a mechanism to format NFS properties into legacy output 12953910Sdougm * format. If the buffer would overflow, it is reallocated and grown 12963910Sdougm * as appropriate. Special cases of converting internal form of values 12973910Sdougm * to those used by "share" are done. this function does one property 12983910Sdougm * at a time. 12993910Sdougm */ 13003910Sdougm 13015179Sdougm static int 13023910Sdougm nfs_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr, 13033910Sdougm sa_property_t prop, int sep) 13043910Sdougm { 13053910Sdougm char *name; 13063910Sdougm char *value; 13073910Sdougm int curlen; 13083910Sdougm char *buff = *rbuff; 13093910Sdougm size_t buffsize = *rbuffsize; 13105179Sdougm int printed = B_FALSE; 13113910Sdougm 13123910Sdougm name = sa_get_property_attr(prop, "type"); 13133910Sdougm value = sa_get_property_attr(prop, "value"); 13143910Sdougm if (buff != NULL) 13154345Sdougm curlen = strlen(buff); 13163910Sdougm else 13174345Sdougm curlen = 0; 13183910Sdougm if (name != NULL) { 13194345Sdougm int len; 13204345Sdougm len = strlen(name) + sep; 13213910Sdougm 13223910Sdougm /* 13233910Sdougm * A future RFE would be to replace this with more 13243910Sdougm * generic code and to possibly handle more types. 13253910Sdougm */ 13264345Sdougm switch (gettype(name)) { 13274345Sdougm case OPT_TYPE_BOOLEAN: 13285179Sdougm /* 13295179Sdougm * For NFS, boolean value of FALSE means it 13305179Sdougm * doesn't show up in the option list at all. 13315179Sdougm */ 13324345Sdougm if (value != NULL && strcasecmp(value, "false") == 0) 13335179Sdougm goto skip; 13345179Sdougm if (value != NULL) { 13354345Sdougm sa_free_attr_string(value); 13365179Sdougm value = NULL; 13375179Sdougm } 13384345Sdougm break; 13394345Sdougm case OPT_TYPE_ACCLIST: 13404345Sdougm if (value != NULL && strcmp(value, "*") == 0) { 13414345Sdougm sa_free_attr_string(value); 13424345Sdougm value = NULL; 13434345Sdougm } else { 13444345Sdougm if (value != NULL) 13454345Sdougm len += 1 + strlen(value); 13464345Sdougm } 13474345Sdougm break; 13484345Sdougm case OPT_TYPE_LOGTAG: 13494345Sdougm if (value != NULL && strlen(value) == 0) { 13504345Sdougm sa_free_attr_string(value); 13514345Sdougm value = NULL; 13524345Sdougm } else { 13534345Sdougm if (value != NULL) 13544345Sdougm len += 1 + strlen(value); 13554345Sdougm } 13564345Sdougm break; 13574345Sdougm default: 13584345Sdougm if (value != NULL) 13594345Sdougm len += 1 + strlen(value); 13604345Sdougm break; 13613910Sdougm } 13624345Sdougm while (buffsize <= (curlen + len)) { 13634345Sdougm /* need more room */ 13644345Sdougm buffsize += incr; 13654345Sdougm buff = realloc(buff, buffsize); 13664345Sdougm if (buff == NULL) { 13674345Sdougm /* realloc failed so free everything */ 13684345Sdougm if (*rbuff != NULL) 13694345Sdougm free(*rbuff); 13704345Sdougm } 13714345Sdougm *rbuff = buff; 13724345Sdougm *rbuffsize = buffsize; 13735179Sdougm if (buff == NULL) 13745179Sdougm goto skip; 13755179Sdougm 13763910Sdougm } 13775179Sdougm 13784345Sdougm if (buff == NULL) 13795179Sdougm goto skip; 13805179Sdougm 13814345Sdougm if (value == NULL) { 13824345Sdougm (void) snprintf(buff + curlen, buffsize - curlen, 13834345Sdougm "%s%s", sep ? "," : "", 13844345Sdougm name, value != NULL ? value : ""); 13854345Sdougm } else { 13864345Sdougm (void) snprintf(buff + curlen, buffsize - curlen, 13874345Sdougm "%s%s=%s", sep ? "," : "", 13884345Sdougm name, value != NULL ? value : ""); 13893910Sdougm } 13905179Sdougm printed = B_TRUE; 13913910Sdougm } 13925179Sdougm skip: 13933910Sdougm if (name != NULL) 13944345Sdougm sa_free_attr_string(name); 13953910Sdougm if (value != NULL) 13964345Sdougm sa_free_attr_string(value); 13975179Sdougm return (printed); 13983910Sdougm } 13993910Sdougm 14003910Sdougm /* 14013910Sdougm * nfs_format_options(group, hier) 14023910Sdougm * 14033910Sdougm * format all the options on the group into an old-style option 14043910Sdougm * string. If hier is non-zero, walk up the tree to get inherited 14053910Sdougm * options. 14063910Sdougm */ 14073910Sdougm 14083910Sdougm static char * 14093910Sdougm nfs_format_options(sa_group_t group, int hier) 14103910Sdougm { 14113910Sdougm sa_optionset_t options = NULL; 14124345Sdougm sa_optionset_t secoptions = NULL; 14133910Sdougm sa_property_t prop, secprop; 14144345Sdougm sa_security_t security = NULL; 14153910Sdougm char *buff; 14163910Sdougm size_t buffsize; 14174345Sdougm char *sectype = NULL; 14184345Sdougm int sep = 0; 14194345Sdougm 14204345Sdougm 14214345Sdougm buff = malloc(OPT_CHUNK); 14224345Sdougm if (buff == NULL) { 14234345Sdougm return (NULL); 14244345Sdougm } 14254345Sdougm 14264345Sdougm buff[0] = '\0'; 14274345Sdougm buffsize = OPT_CHUNK; 14284345Sdougm 14294345Sdougm /* 14304345Sdougm * We may have a an optionset relative to this item. format 14314345Sdougm * these if we find them and then add any security definitions. 14324345Sdougm */ 14333910Sdougm 14343910Sdougm options = sa_get_derived_optionset(group, "nfs", hier); 14353910Sdougm 14363910Sdougm /* 14374345Sdougm * do the default set first but skip any option that is also 14384345Sdougm * in the protocol specific optionset. 14393910Sdougm */ 14404345Sdougm if (options != NULL) { 14414345Sdougm for (prop = sa_get_property(options, NULL); 14424345Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 14433910Sdougm /* 14444345Sdougm * use this one since we skipped any 14454345Sdougm * of these that were also in 14464345Sdougm * optdefault 14473910Sdougm */ 14485179Sdougm if (nfs_sprint_option(&buff, &buffsize, OPT_CHUNK, 14495179Sdougm prop, sep)) 14505179Sdougm sep = 1; 14514345Sdougm if (buff == NULL) { 14524345Sdougm /* 14534345Sdougm * buff could become NULL if there 14544345Sdougm * isn't enough memory for 14554345Sdougm * nfs_sprint_option to realloc() 14564345Sdougm * as necessary. We can't really 14574345Sdougm * do anything about it at this 14584345Sdougm * point so we return NULL. The 14594345Sdougm * caller should handle the 14604345Sdougm * failure. 14614345Sdougm */ 14624345Sdougm if (options != NULL) 14634345Sdougm sa_free_derived_optionset( 14644345Sdougm options); 14654345Sdougm return (buff); 14664345Sdougm } 14673910Sdougm } 14684345Sdougm } 14694345Sdougm secoptions = (sa_optionset_t)sa_get_all_security_types(group, 14704345Sdougm "nfs", hier); 14714345Sdougm if (secoptions != NULL) { 14723910Sdougm for (secprop = sa_get_property(secoptions, NULL); 14734345Sdougm secprop != NULL; 14744345Sdougm secprop = sa_get_next_property(secprop)) { 14754345Sdougm sectype = sa_get_property_attr(secprop, "type"); 14764345Sdougm security = 14774345Sdougm (sa_security_t)sa_get_derived_security( 14784345Sdougm group, sectype, "nfs", hier); 14794345Sdougm if (security != NULL) { 14804345Sdougm if (sectype != NULL) { 14814345Sdougm prop = sa_create_property( 14824345Sdougm "sec", sectype); 14835179Sdougm if (prop == NULL) 14845179Sdougm goto err; 14855179Sdougm if (nfs_sprint_option(&buff, 14865179Sdougm &buffsize, OPT_CHUNK, prop, sep)) 14875179Sdougm sep = 1; 14884345Sdougm (void) sa_remove_property(prop); 14895179Sdougm if (buff == NULL) 14905179Sdougm goto err; 14914345Sdougm } 14924345Sdougm for (prop = sa_get_property(security, 14934345Sdougm NULL); prop != NULL; 14944345Sdougm prop = sa_get_next_property(prop)) { 14955179Sdougm if (nfs_sprint_option(&buff, 14965179Sdougm &buffsize, OPT_CHUNK, prop, sep)) 14975179Sdougm sep = 1; 14984345Sdougm if (buff == NULL) 14994345Sdougm goto err; 15004345Sdougm } 15014345Sdougm sa_free_derived_optionset(security); 15023910Sdougm } 15034345Sdougm if (sectype != NULL) 15044345Sdougm sa_free_attr_string(sectype); 15053910Sdougm } 15063910Sdougm sa_free_derived_optionset(secoptions); 15073910Sdougm } 15084345Sdougm 15093910Sdougm if (options != NULL) 15104345Sdougm sa_free_derived_optionset(options); 15114345Sdougm return (buff); 15124345Sdougm 15134345Sdougm err: 15144345Sdougm /* 15154345Sdougm * If we couldn't allocate memory for option printing, we need 15164345Sdougm * to break out of the nested loops, cleanup and return NULL. 15174345Sdougm */ 15184345Sdougm if (secoptions != NULL) 15194345Sdougm sa_free_derived_optionset(secoptions); 15204345Sdougm if (security != NULL) 15214345Sdougm sa_free_derived_optionset(security); 15224345Sdougm if (sectype != NULL) 15234345Sdougm sa_free_attr_string(sectype); 15244345Sdougm if (options != NULL) 15254345Sdougm sa_free_derived_optionset(options); 15268334SJose.Borrego@Sun.COM return (NULL); 15273910Sdougm } 15284345Sdougm 15293910Sdougm /* 15303910Sdougm * Append an entry to the nfslogtab file 15313910Sdougm */ 15323910Sdougm static int 15333910Sdougm nfslogtab_add(dir, buffer, tag) 15343910Sdougm char *dir, *buffer, *tag; 15353910Sdougm { 15363910Sdougm FILE *f; 15373910Sdougm struct logtab_ent lep; 15383910Sdougm int error = 0; 15393910Sdougm 15403910Sdougm /* 15413910Sdougm * Open the file for update and create it if necessary. 15423910Sdougm * This may leave the I/O offset at the end of the file, 15433910Sdougm * so rewind back to the beginning of the file. 15443910Sdougm */ 15453910Sdougm f = fopen(NFSLOGTAB, "a+"); 15463910Sdougm if (f == NULL) { 15473910Sdougm error = errno; 15483910Sdougm goto out; 15493910Sdougm } 15503910Sdougm rewind(f); 15513910Sdougm 15523910Sdougm if (lockf(fileno(f), F_LOCK, 0L) < 0) { 15533910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 15544345Sdougm "share complete, however failed to lock %s " 15554345Sdougm "for update: %s\n"), NFSLOGTAB, strerror(errno)); 15563910Sdougm error = -1; 15573910Sdougm goto out; 15583910Sdougm } 15593910Sdougm 15603910Sdougm if (logtab_deactivate_after_boot(f) == -1) { 15613910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 15624345Sdougm "share complete, however could not deactivate " 15634345Sdougm "entries in %s\n"), NFSLOGTAB); 15643910Sdougm error = -1; 15653910Sdougm goto out; 15663910Sdougm } 15673910Sdougm 15683910Sdougm /* 15693910Sdougm * Remove entries matching buffer and sharepoint since we're 15703910Sdougm * going to replace it with perhaps an entry with a new tag. 15713910Sdougm */ 15723910Sdougm if (logtab_rement(f, buffer, dir, NULL, -1)) { 15733910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 15744345Sdougm "share complete, however could not remove matching " 15754345Sdougm "entries in %s\n"), NFSLOGTAB); 15763910Sdougm error = -1; 15773910Sdougm goto out; 15783910Sdougm } 15793910Sdougm 15803910Sdougm /* 15813910Sdougm * Deactivate all active entries matching this sharepoint 15823910Sdougm */ 15833910Sdougm if (logtab_deactivate(f, NULL, dir, NULL)) { 15843910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 15854345Sdougm "share complete, however could not deactivate matching " 15864345Sdougm "entries in %s\n"), NFSLOGTAB); 15873910Sdougm error = -1; 15883910Sdougm goto out; 15893910Sdougm } 15903910Sdougm 15913910Sdougm lep.le_buffer = buffer; 15923910Sdougm lep.le_path = dir; 15933910Sdougm lep.le_tag = tag; 15943910Sdougm lep.le_state = LES_ACTIVE; 15953910Sdougm 15963910Sdougm /* 15973910Sdougm * Add new sharepoint / buffer location to nfslogtab 15983910Sdougm */ 15993910Sdougm if (logtab_putent(f, &lep) < 0) { 16003910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 16014345Sdougm "share complete, however could not add %s to %s\n"), 16024345Sdougm dir, NFSLOGTAB); 16033910Sdougm error = -1; 16043910Sdougm } 16053910Sdougm 16063910Sdougm out: 16073910Sdougm if (f != NULL) 16083910Sdougm (void) fclose(f); 16093910Sdougm return (error); 16103910Sdougm } 16113910Sdougm 16123910Sdougm /* 16133910Sdougm * Deactivate an entry from the nfslogtab file 16143910Sdougm */ 16153910Sdougm static int 16163910Sdougm nfslogtab_deactivate(path) 16173910Sdougm char *path; 16183910Sdougm { 16193910Sdougm FILE *f; 16203910Sdougm int error = 0; 16213910Sdougm 16223910Sdougm f = fopen(NFSLOGTAB, "r+"); 16233910Sdougm if (f == NULL) { 16243910Sdougm error = errno; 16253910Sdougm goto out; 16263910Sdougm } 16273910Sdougm if (lockf(fileno(f), F_LOCK, 0L) < 0) { 16283910Sdougm error = errno; 16293910Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 16304345Sdougm "share complete, however could not lock %s for " 16314345Sdougm "update: %s\n"), NFSLOGTAB, strerror(error)); 16323910Sdougm goto out; 16333910Sdougm } 16343910Sdougm if (logtab_deactivate(f, NULL, path, NULL) == -1) { 16353910Sdougm error = -1; 16363910Sdougm (void) fprintf(stderr, 16374345Sdougm dgettext(TEXT_DOMAIN, 16384345Sdougm "share complete, however could not " 16394345Sdougm "deactivate %s in %s\n"), path, NFSLOGTAB); 16403910Sdougm goto out; 16413910Sdougm } 16423910Sdougm 16433910Sdougm out: if (f != NULL) 16443910Sdougm (void) fclose(f); 16453910Sdougm 16463910Sdougm return (error); 16473910Sdougm } 16483910Sdougm 16493910Sdougm /* 16504524Sdougm * check_public(group, skipshare) 16514524Sdougm * 16524524Sdougm * Check the group for any shares that have the public property 16534524Sdougm * enabled. We skip "skipshare" since that is the one we are 16544524Sdougm * working with. This is a separate function to make handling 16554524Sdougm * subgroups simpler. Returns true if there is a share with public. 16564524Sdougm */ 16574524Sdougm static int 16584524Sdougm check_public(sa_group_t group, sa_share_t skipshare) 16594524Sdougm { 16604524Sdougm int exists = B_FALSE; 16614524Sdougm sa_share_t share; 16624524Sdougm sa_optionset_t opt; 16634524Sdougm sa_property_t prop; 16644524Sdougm char *shared; 16654524Sdougm 16664524Sdougm for (share = sa_get_share(group, NULL); share != NULL; 16674524Sdougm share = sa_get_next_share(share)) { 16684524Sdougm if (share == skipshare) 16694524Sdougm continue; 16704524Sdougm 16714524Sdougm opt = sa_get_optionset(share, "nfs"); 16724524Sdougm if (opt == NULL) 16734524Sdougm continue; 16744524Sdougm prop = sa_get_property(opt, "public"); 16754524Sdougm if (prop == NULL) 16764524Sdougm continue; 16774524Sdougm shared = sa_get_share_attr(share, "shared"); 16784524Sdougm if (shared != NULL) { 16794524Sdougm exists = strcmp(shared, "true") == 0; 16804524Sdougm sa_free_attr_string(shared); 16814524Sdougm if (exists == B_TRUE) 16824524Sdougm break; 16834524Sdougm } 16844524Sdougm } 16854524Sdougm 16864524Sdougm return (exists); 16874524Sdougm } 16884524Sdougm 16894524Sdougm /* 16906214Sdougm * public_exists(handle, share) 16913910Sdougm * 16923910Sdougm * check to see if public option is set on any other share than the 16934524Sdougm * one specified. Need to check zfs sub-groups as well as the top 16944524Sdougm * level groups. 16953910Sdougm */ 16963910Sdougm static int 16976214Sdougm public_exists(sa_handle_t handle, sa_share_t skipshare) 16983910Sdougm { 16996214Sdougm sa_group_t group = NULL; 17003910Sdougm 17016271Sdougm /* 17026271Sdougm * If we don't have a handle, we can only do syntax check. We 17036271Sdougm * can't check against other shares so we assume OK and will 17046271Sdougm * catch the problem only when we actually try to apply it. 17056271Sdougm */ 17063910Sdougm if (handle == NULL) 17076271Sdougm return (SA_OK); 17083910Sdougm 17096214Sdougm if (skipshare != NULL) { 17106214Sdougm group = sa_get_parent_group(skipshare); 17116214Sdougm if (group == NULL) 17126214Sdougm return (SA_NO_SUCH_GROUP); 17136214Sdougm } 17146214Sdougm 17153910Sdougm for (group = sa_get_group(handle, NULL); group != NULL; 17163910Sdougm group = sa_get_next_group(group)) { 17174524Sdougm /* Walk any ZFS subgroups as well as all standard groups */ 17184524Sdougm if (sa_group_is_zfs(group)) { 17194524Sdougm sa_group_t subgroup; 17204524Sdougm for (subgroup = sa_get_sub_group(group); 17214524Sdougm subgroup != NULL; 17224524Sdougm subgroup = sa_get_next_group(subgroup)) { 17234524Sdougm if (check_public(subgroup, skipshare)) 17244524Sdougm return (B_TRUE); 17253910Sdougm } 17264524Sdougm } else { 17274524Sdougm if (check_public(group, skipshare)) 17284524Sdougm return (B_TRUE); 17293910Sdougm } 17303910Sdougm } 17314524Sdougm return (B_FALSE); 17323910Sdougm } 17333910Sdougm 17343910Sdougm /* 17353910Sdougm * sa_enable_share at the protocol level, enable_share must tell the 17363910Sdougm * implementation that it is to enable the share. This entails 17373910Sdougm * converting the path and options into the appropriate ioctl 17383910Sdougm * calls. It is assumed that all error checking of paths, etc. were 17393910Sdougm * done earlier. 17403910Sdougm */ 17413910Sdougm static int 17423910Sdougm nfs_enable_share(sa_share_t share) 17433910Sdougm { 17443910Sdougm struct exportdata export; 17453910Sdougm sa_optionset_t secoptlist; 17463910Sdougm struct secinfo *sp; 17473910Sdougm int num_secinfo; 17483910Sdougm sa_optionset_t opt; 17493910Sdougm sa_security_t sec; 17503910Sdougm sa_property_t prop; 17513910Sdougm char *path; 17523910Sdougm int err = SA_OK; 17534524Sdougm int i; 17544543Smarks int iszfs; 17556214Sdougm sa_handle_t handle; 17563910Sdougm 17573910Sdougm /* Don't drop core if the NFS module isn't loaded. */ 17583910Sdougm (void) signal(SIGSYS, SIG_IGN); 17593910Sdougm 17603910Sdougm /* get the path since it is important in several places */ 17613910Sdougm path = sa_get_share_attr(share, "path"); 17623910Sdougm if (path == NULL) 17634345Sdougm return (SA_NO_SUCH_PATH); 17643910Sdougm 17654543Smarks iszfs = sa_path_is_zfs(path); 17663910Sdougm /* 17673910Sdougm * find the optionsets and security sets. There may not be 17683910Sdougm * any or there could be one or two for each of optionset and 17693910Sdougm * security may have multiple, one per security type per 17703910Sdougm * protocol type. 17713910Sdougm */ 17723910Sdougm opt = sa_get_derived_optionset(share, "nfs", 1); 17733910Sdougm secoptlist = (sa_optionset_t)sa_get_all_security_types(share, "nfs", 1); 17743910Sdougm if (secoptlist != NULL) 17754345Sdougm num_secinfo = MAX(1, count_security(secoptlist)); 17763910Sdougm else 17774345Sdougm num_secinfo = 1; 17783910Sdougm 17793910Sdougm /* 17803910Sdougm * walk through the options and fill in the structure 17813910Sdougm * appropriately. 17823910Sdougm */ 17833910Sdougm 17843910Sdougm (void) memset(&export, '\0', sizeof (export)); 17853910Sdougm 17863910Sdougm /* 17873910Sdougm * do non-security options first since there is only one after 17883910Sdougm * the derived group is constructed. 17893910Sdougm */ 17903910Sdougm export.ex_version = EX_CURRENT_VERSION; 17913910Sdougm export.ex_anon = UID_NOBODY; /* this is our default value */ 17923910Sdougm export.ex_index = NULL; 17933910Sdougm export.ex_path = path; 17943910Sdougm export.ex_pathlen = strlen(path) + 1; 17953910Sdougm 17963910Sdougm if (opt != NULL) 17974345Sdougm err = fill_export_from_optionset(&export, opt); 17983910Sdougm 17993910Sdougm /* 18003910Sdougm * check to see if "public" is set. If it is, then make sure 18013910Sdougm * no other share has it set. If it is already used, fail. 18023910Sdougm */ 18033910Sdougm 18046214Sdougm handle = sa_find_group_handle((sa_group_t)share); 18056214Sdougm if (export.ex_flags & EX_PUBLIC && public_exists(handle, share)) { 18064345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 18074345Sdougm "NFS: Cannot share more than one file " 18084345Sdougm "system with 'public' property\n")); 18094345Sdougm err = SA_NOT_ALLOWED; 18104345Sdougm goto out; 18113910Sdougm } 18123910Sdougm 18134524Sdougm sp = calloc(num_secinfo, sizeof (struct secinfo)); 18143910Sdougm if (sp == NULL) { 18154345Sdougm err = SA_NO_MEMORY; 18164524Sdougm (void) printf(dgettext(TEXT_DOMAIN, 18174524Sdougm "NFS: NFS: no memory for security\n")); 18184524Sdougm goto out; 18194524Sdougm } 18204524Sdougm export.ex_secinfo = sp; 18214524Sdougm /* get default secinfo */ 18224524Sdougm export.ex_seccnt = num_secinfo; 18234524Sdougm /* 18244524Sdougm * since we must have one security option defined, we 18254524Sdougm * init to the default and then override as we find 18264524Sdougm * defined security options. This handles the case 18274524Sdougm * where we have no defined options but we need to set 18284524Sdougm * up one. 18294524Sdougm */ 18304524Sdougm sp[0].s_window = DEF_WIN; 18314524Sdougm sp[0].s_rootnames = NULL; 18324524Sdougm /* setup a default in case no properties defined */ 18334524Sdougm if (nfs_getseconfig_default(&sp[0].s_secinfo)) { 18344524Sdougm (void) printf(dgettext(TEXT_DOMAIN, 18354524Sdougm "NFS: nfs_getseconfig_default: failed to " 18364524Sdougm "get default security mode\n")); 18374524Sdougm err = SA_CONFIG_ERR; 18384524Sdougm } 18394524Sdougm if (secoptlist != NULL) { 18404524Sdougm for (i = 0, prop = sa_get_property(secoptlist, NULL); 18414524Sdougm prop != NULL && i < num_secinfo; 18424524Sdougm prop = sa_get_next_property(prop), i++) { 18434524Sdougm char *sectype; 184411337SWilliam.Krier@Sun.COM sectype = sa_get_property_attr(prop, "type"); 18454524Sdougm /* 18464524Sdougm * if sectype is NULL, we probably 18474524Sdougm * have a memory problem and can't get 18484524Sdougm * the correct values. Rather than 18494524Sdougm * exporting with incorrect security, 18504524Sdougm * don't share it. 18514524Sdougm */ 18524524Sdougm if (sectype == NULL) { 18534524Sdougm err = SA_NO_MEMORY; 18544524Sdougm (void) printf(dgettext(TEXT_DOMAIN, 18554524Sdougm "NFS: Cannot share %s: " 18564524Sdougm "no memory\n"), path); 18574524Sdougm goto out; 18584524Sdougm } 18594524Sdougm sec = (sa_security_t)sa_get_derived_security( 18604524Sdougm share, sectype, "nfs", 1); 18614524Sdougm sp[i].s_window = DEF_WIN; 18624524Sdougm sp[i].s_rootcnt = 0; 18634524Sdougm sp[i].s_rootnames = NULL; 18644345Sdougm (void) fill_security_from_secopts(&sp[i], sec); 18654524Sdougm if (sec != NULL) 18664524Sdougm sa_free_derived_security(sec); 18674524Sdougm if (sectype != NULL) 18684524Sdougm sa_free_attr_string(sectype); 18693910Sdougm } 18704524Sdougm } 18714524Sdougm /* 18724524Sdougm * when we get here, we can do the exportfs system call and 18734524Sdougm * initiate thinsg. We probably want to enable the nfs.server 18744524Sdougm * service first if it isn't running within SMF. 18754524Sdougm */ 18764524Sdougm /* check nfs.server status and start if needed */ 18774524Sdougm /* now add the share to the internal tables */ 18784524Sdougm printarg(path, &export); 18794524Sdougm /* 18804524Sdougm * call the exportfs system call which is implemented 18814524Sdougm * via the nfssys() call as the EXPORTFS subfunction. 18824524Sdougm */ 18834543Smarks if (iszfs) { 18844543Smarks struct exportfs_args ea; 18854543Smarks share_t sh; 18864543Smarks char *str; 18874543Smarks priv_set_t *priv_effective; 18884543Smarks int privileged; 18894543Smarks 18904543Smarks /* 18914543Smarks * If we aren't a privileged user 18924543Smarks * and NFS server service isn't running 18934543Smarks * then print out an error message 18944543Smarks * and return EPERM 18954543Smarks */ 18964543Smarks 18974543Smarks priv_effective = priv_allocset(); 18984543Smarks (void) getppriv(PRIV_EFFECTIVE, priv_effective); 18994543Smarks 19004543Smarks privileged = (priv_isfullset(priv_effective) == B_TRUE); 19014543Smarks priv_freeset(priv_effective); 19024543Smarks 19034543Smarks if (!privileged && 19044543Smarks (str = smf_get_state(NFS_SERVER_SVC)) != NULL) { 19054543Smarks err = 0; 19064543Smarks if (strcmp(str, SCF_STATE_STRING_ONLINE) != 0) { 19074543Smarks (void) printf(dgettext(TEXT_DOMAIN, 19084543Smarks "NFS: Cannot share remote " 19094543Smarks "filesystem: %s\n"), path); 19104543Smarks (void) printf(dgettext(TEXT_DOMAIN, 19114543Smarks "NFS: Service needs to be enabled " 19124543Smarks "by a privileged user\n")); 19134543Smarks err = SA_SYSTEM_ERR; 19144543Smarks errno = EPERM; 19154543Smarks } 19164543Smarks free(str); 19174543Smarks } 19184543Smarks 19194543Smarks if (err == 0) { 19204543Smarks ea.dname = path; 19214543Smarks ea.uex = &export; 19224543Smarks 192311411SSurya.Prakki@Sun.COM (void) sa_sharetab_fill_zfs(share, &sh, "nfs"); 19248845Samw@Sun.COM err = sa_share_zfs(share, NULL, path, &sh, 19255331Samw &ea, ZFS_SHARE_NFS); 192610761SWilliam.Krier@Sun.COM if (err != SA_OK) { 192710761SWilliam.Krier@Sun.COM errno = err; 192810761SWilliam.Krier@Sun.COM err = -1; 192910761SWilliam.Krier@Sun.COM } 19304543Smarks sa_emptyshare(&sh); 19314543Smarks } 19324543Smarks } else { 19334543Smarks err = exportfs(path, &export); 19344543Smarks } 19354543Smarks 19364543Smarks if (err < 0) { 19374524Sdougm err = SA_SYSTEM_ERR; 19384524Sdougm switch (errno) { 19394524Sdougm case EREMOTE: 19404524Sdougm (void) printf(dgettext(TEXT_DOMAIN, 19414543Smarks "NFS: Cannot share filesystems " 19424543Smarks "in non-global zones: %s\n"), path); 19434543Smarks err = SA_NOT_SUPPORTED; 19444524Sdougm break; 19454524Sdougm case EPERM: 19464524Sdougm if (getzoneid() != GLOBAL_ZONEID) { 19474345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 19484543Smarks "NFS: Cannot share file systems " 19494524Sdougm "in non-global zones: %s\n"), path); 19504524Sdougm err = SA_NOT_SUPPORTED; 19514345Sdougm break; 19524345Sdougm } 19534524Sdougm err = SA_NO_PERMISSION; 1954*12679SPavel.Filipensky@Sun.COM break; 1955*12679SPavel.Filipensky@Sun.COM case EEXIST: 1956*12679SPavel.Filipensky@Sun.COM err = SA_SHARE_EXISTS; 1957*12679SPavel.Filipensky@Sun.COM break; 19584524Sdougm default: 19594524Sdougm break; 19603910Sdougm } 19614524Sdougm } else { 19624524Sdougm /* update sharetab with an add/modify */ 19634543Smarks if (!iszfs) { 19644543Smarks (void) sa_update_sharetab(share, "nfs"); 19654543Smarks } 19663910Sdougm } 19673910Sdougm 19683910Sdougm if (err == SA_OK) { 19693910Sdougm /* 19703910Sdougm * enable services as needed. This should probably be 19713910Sdougm * done elsewhere in order to minimize the calls to 19723910Sdougm * check services. 19733910Sdougm */ 19743910Sdougm /* 19753910Sdougm * check to see if logging and other services need to 19763910Sdougm * be triggered, but only if there wasn't an 19773910Sdougm * error. This is probably where sharetab should be 19783910Sdougm * updated with the NFS specific entry. 19793910Sdougm */ 19804345Sdougm if (export.ex_flags & EX_LOG) { 19814345Sdougm /* enable logging */ 19824345Sdougm if (nfslogtab_add(path, export.ex_log_buffer, 19834345Sdougm export.ex_tag) != 0) { 19844345Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 19854345Sdougm "Could not enable logging for %s\n"), 19864345Sdougm path); 19874345Sdougm } 19884345Sdougm _check_services(service_list_logging); 19894345Sdougm } else { 19904345Sdougm /* 19914345Sdougm * don't have logging so remove it from file. It might 19924345Sdougm * not be thre, but that doesn't matter. 19934345Sdougm */ 19944345Sdougm (void) nfslogtab_deactivate(path); 19954345Sdougm _check_services(service_list_default); 19963910Sdougm } 19973910Sdougm } 19983910Sdougm 19993910Sdougm out: 20003910Sdougm if (path != NULL) 20014345Sdougm free(path); 20023910Sdougm 20033910Sdougm cleanup_export(&export); 20043910Sdougm if (opt != NULL) 20054345Sdougm sa_free_derived_optionset(opt); 20063910Sdougm if (secoptlist != NULL) 20074345Sdougm (void) sa_destroy_optionset(secoptlist); 20083910Sdougm return (err); 20093910Sdougm } 20103910Sdougm 20113910Sdougm /* 20125800Sdougm * nfs_disable_share(share, path) 20133910Sdougm * 20145800Sdougm * Unshare the specified share. Note that "path" is the same path as 20155800Sdougm * what is in the "share" object. It is passed in to avoid an 20165800Sdougm * additional lookup. A missing "path" value makes this a no-op 20175800Sdougm * function. 20183910Sdougm */ 20193910Sdougm static int 20204543Smarks nfs_disable_share(sa_share_t share, char *path) 20213910Sdougm { 20223910Sdougm int err; 20233910Sdougm int ret = SA_OK; 20244543Smarks int iszfs; 20255800Sdougm sa_group_t parent; 20265951Sdougm sa_handle_t handle; 20274543Smarks 20285800Sdougm if (path == NULL) 20295800Sdougm return (ret); 20304543Smarks 20315800Sdougm /* 20325800Sdougm * If the share is in a ZFS group we need to handle it 20335800Sdougm * differently. Just being on a ZFS file system isn't 20345800Sdougm * enough since we may be in a legacy share case. 20355800Sdougm */ 20365800Sdougm parent = sa_get_parent_group(share); 20375800Sdougm iszfs = sa_group_is_zfs(parent); 20385800Sdougm if (iszfs) { 20395800Sdougm struct exportfs_args ea; 20405800Sdougm share_t sh = { 0 }; 20415800Sdougm ea.dname = path; 20425800Sdougm ea.uex = NULL; 20435800Sdougm sh.sh_path = path; 20445800Sdougm sh.sh_fstype = "nfs"; 20454543Smarks 20468845Samw@Sun.COM err = sa_share_zfs(share, NULL, path, &sh, 20475800Sdougm &ea, ZFS_UNSHARE_NFS); 204810761SWilliam.Krier@Sun.COM if (err != SA_OK) { 204910761SWilliam.Krier@Sun.COM errno = err; 205010761SWilliam.Krier@Sun.COM err = -1; 205110761SWilliam.Krier@Sun.COM } 20525800Sdougm } else { 20535800Sdougm err = exportfs(path, NULL); 20545800Sdougm } 20555800Sdougm if (err < 0) { 20565800Sdougm /* 20575800Sdougm * TBD: only an error in some 20585800Sdougm * cases - need better analysis 20595800Sdougm */ 20605800Sdougm switch (errno) { 20615800Sdougm case EPERM: 20625800Sdougm case EACCES: 20635800Sdougm ret = SA_NO_PERMISSION; 20645800Sdougm if (getzoneid() != GLOBAL_ZONEID) { 20655800Sdougm ret = SA_NOT_SUPPORTED; 20665800Sdougm } 20675800Sdougm break; 20685800Sdougm case EINVAL: 20695800Sdougm case ENOENT: 20705800Sdougm ret = SA_NO_SUCH_PATH; 20714543Smarks break; 207210761SWilliam.Krier@Sun.COM default: 207310761SWilliam.Krier@Sun.COM ret = SA_SYSTEM_ERR; 20744543Smarks break; 20753910Sdougm } 20765800Sdougm } 20775800Sdougm if (ret == SA_OK || ret == SA_NO_SUCH_PATH) { 20785951Sdougm handle = sa_find_group_handle((sa_group_t)share); 20795800Sdougm if (!iszfs) 20805951Sdougm (void) sa_delete_sharetab(handle, path, "nfs"); 20815800Sdougm /* just in case it was logged */ 20825800Sdougm (void) nfslogtab_deactivate(path); 20833910Sdougm } 20843910Sdougm return (ret); 20853910Sdougm } 20863910Sdougm 20873910Sdougm /* 20887961SNatalie.Li@Sun.COM * check_rorwnone(v1, v2, v3) 20897961SNatalie.Li@Sun.COM * 20907961SNatalie.Li@Sun.COM * check ro vs rw vs none values. Over time this may get beefed up. 20917961SNatalie.Li@Sun.COM * for now it just does simple checks. v1 is never NULL but v2 or v3 20927961SNatalie.Li@Sun.COM * could be. 20933910Sdougm */ 20943910Sdougm 20953910Sdougm static int 20967961SNatalie.Li@Sun.COM check_rorwnone(char *v1, char *v2, char *v3) 20973910Sdougm { 20983910Sdougm int ret = SA_OK; 20997961SNatalie.Li@Sun.COM if (v2 != NULL && strcmp(v1, v2) == 0) 21004345Sdougm ret = SA_VALUE_CONFLICT; 21017961SNatalie.Li@Sun.COM else if (v3 != NULL && strcmp(v1, v3) == 0) 21027961SNatalie.Li@Sun.COM ret = SA_VALUE_CONFLICT; 21037961SNatalie.Li@Sun.COM 21043910Sdougm return (ret); 21053910Sdougm } 21063910Sdougm 21073910Sdougm /* 21086214Sdougm * nfs_validate_property(handle, property, parent) 21093910Sdougm * 21103910Sdougm * Check that the property has a legitimate value for its type. 21113910Sdougm */ 21123910Sdougm 21133910Sdougm static int 21146214Sdougm nfs_validate_property(sa_handle_t handle, sa_property_t property, 21156214Sdougm sa_optionset_t parent) 21163910Sdougm { 21173910Sdougm int ret = SA_OK; 21183910Sdougm char *propname; 21197961SNatalie.Li@Sun.COM char *other1; 21207961SNatalie.Li@Sun.COM char *other2; 21213910Sdougm int optindex; 21223910Sdougm nfsl_config_t *configlist; 21233910Sdougm sa_group_t parent_group; 21243910Sdougm char *value; 21253910Sdougm 21263910Sdougm propname = sa_get_property_attr(property, "type"); 21273910Sdougm 21283910Sdougm if ((optindex = findopt(propname)) < 0) 21294345Sdougm ret = SA_NO_SUCH_PROP; 21303910Sdougm 21313910Sdougm /* need to validate value range here as well */ 21323910Sdougm 21333910Sdougm if (ret == SA_OK) { 21344345Sdougm parent_group = sa_get_parent_group((sa_share_t)parent); 21356214Sdougm if (optdefs[optindex].share && parent_group != NULL && 21366214Sdougm !sa_is_share(parent_group)) 21374345Sdougm ret = SA_PROP_SHARE_ONLY; 21383910Sdougm } 21393910Sdougm if (ret == SA_OK) { 21406214Sdougm if (optdefs[optindex].index == OPT_PUBLIC) { 21416214Sdougm /* 21426214Sdougm * Public is special in that only one instance can 21436214Sdougm * be in the repository at the same time. 21446214Sdougm */ 21456214Sdougm if (public_exists(handle, parent_group)) { 21467961SNatalie.Li@Sun.COM sa_free_attr_string(propname); 21476214Sdougm return (SA_VALUE_CONFLICT); 21486214Sdougm } 21496214Sdougm } 21504345Sdougm value = sa_get_property_attr(property, "value"); 21514345Sdougm if (value != NULL) { 21524345Sdougm /* first basic type checking */ 21534345Sdougm switch (optdefs[optindex].type) { 21544345Sdougm case OPT_TYPE_NUMBER: 21554345Sdougm /* check that the value is all digits */ 21564345Sdougm if (!is_a_number(value)) 21574345Sdougm ret = SA_BAD_VALUE; 21584345Sdougm break; 21594345Sdougm case OPT_TYPE_BOOLEAN: 21604345Sdougm if (strlen(value) == 0 || 21614345Sdougm strcasecmp(value, "true") == 0 || 21624345Sdougm strcmp(value, "1") == 0 || 21634345Sdougm strcasecmp(value, "false") == 0 || 21644345Sdougm strcmp(value, "0") == 0) { 21654345Sdougm ret = SA_OK; 21664345Sdougm } else { 21674345Sdougm ret = SA_BAD_VALUE; 21684345Sdougm } 21694345Sdougm break; 21704345Sdougm case OPT_TYPE_USER: 21714345Sdougm if (!is_a_number(value)) { 21724345Sdougm struct passwd *pw; 21734345Sdougm /* 21744345Sdougm * in this case it would have to be a 21754345Sdougm * user name 21764345Sdougm */ 21774345Sdougm pw = getpwnam(value); 21784345Sdougm if (pw == NULL) 21794345Sdougm ret = SA_BAD_VALUE; 21804345Sdougm endpwent(); 21814345Sdougm } else { 21824345Sdougm uint64_t intval; 21834345Sdougm intval = strtoull(value, NULL, 0); 21844345Sdougm if (intval > UID_MAX && intval != ~0) 21854345Sdougm ret = SA_BAD_VALUE; 21864345Sdougm } 21874345Sdougm break; 21884345Sdougm case OPT_TYPE_FILE: 21894345Sdougm if (strcmp(value, "..") == 0 || 21904345Sdougm strchr(value, '/') != NULL) { 21914345Sdougm ret = SA_BAD_VALUE; 21924345Sdougm } 21934345Sdougm break; 21947961SNatalie.Li@Sun.COM case OPT_TYPE_ACCLIST: { 21957961SNatalie.Li@Sun.COM sa_property_t oprop1; 21967961SNatalie.Li@Sun.COM sa_property_t oprop2; 21977961SNatalie.Li@Sun.COM char *ovalue1 = NULL; 21987961SNatalie.Li@Sun.COM char *ovalue2 = NULL; 21997961SNatalie.Li@Sun.COM 22007961SNatalie.Li@Sun.COM if (parent == NULL) 22017961SNatalie.Li@Sun.COM break; 22024345Sdougm /* 22034345Sdougm * access list handling. Should eventually 22044345Sdougm * validate that all the values make sense. 22054345Sdougm * Also, ro and rw may have cross value 22064345Sdougm * conflicts. 22074345Sdougm */ 22087961SNatalie.Li@Sun.COM if (strcmp(propname, SHOPT_RO) == 0) { 22097961SNatalie.Li@Sun.COM other1 = SHOPT_RW; 22107961SNatalie.Li@Sun.COM other2 = SHOPT_NONE; 22117961SNatalie.Li@Sun.COM } else if (strcmp(propname, SHOPT_RW) == 0) { 22127961SNatalie.Li@Sun.COM other1 = SHOPT_RO; 22137961SNatalie.Li@Sun.COM other2 = SHOPT_NONE; 22147961SNatalie.Li@Sun.COM } else if (strcmp(propname, SHOPT_NONE) == 0) { 22157961SNatalie.Li@Sun.COM other1 = SHOPT_RO; 22167961SNatalie.Li@Sun.COM other2 = SHOPT_RW; 22177961SNatalie.Li@Sun.COM } else { 22187961SNatalie.Li@Sun.COM other1 = NULL; 22197961SNatalie.Li@Sun.COM other2 = NULL; 22207961SNatalie.Li@Sun.COM } 22217961SNatalie.Li@Sun.COM if (other1 == NULL && other2 == NULL) 22227961SNatalie.Li@Sun.COM break; 22237961SNatalie.Li@Sun.COM 22247961SNatalie.Li@Sun.COM /* compare rw(ro) with ro(rw) */ 22254345Sdougm 22267961SNatalie.Li@Sun.COM oprop1 = sa_get_property(parent, other1); 22277961SNatalie.Li@Sun.COM oprop2 = sa_get_property(parent, other2); 22287961SNatalie.Li@Sun.COM if (oprop1 == NULL && oprop2 == NULL) 22297961SNatalie.Li@Sun.COM break; 22307961SNatalie.Li@Sun.COM /* 22317961SNatalie.Li@Sun.COM * Only potential confusion if other1 22327961SNatalie.Li@Sun.COM * or other2 exists. Check the values 22337961SNatalie.Li@Sun.COM * and run the check if there is a 22347961SNatalie.Li@Sun.COM * value other than the one we are 22357961SNatalie.Li@Sun.COM * explicitly looking at. 22367961SNatalie.Li@Sun.COM */ 22377961SNatalie.Li@Sun.COM ovalue1 = sa_get_property_attr(oprop1, "value"); 22387961SNatalie.Li@Sun.COM ovalue2 = sa_get_property_attr(oprop2, "value"); 22397961SNatalie.Li@Sun.COM if (ovalue1 != NULL || ovalue2 != NULL) 22407961SNatalie.Li@Sun.COM ret = check_rorwnone(value, ovalue1, 22417961SNatalie.Li@Sun.COM ovalue2); 22427961SNatalie.Li@Sun.COM 22437961SNatalie.Li@Sun.COM if (ovalue1 != NULL) 22447961SNatalie.Li@Sun.COM sa_free_attr_string(ovalue1); 22457961SNatalie.Li@Sun.COM if (ovalue2 != NULL) 22467961SNatalie.Li@Sun.COM sa_free_attr_string(ovalue2); 22474345Sdougm break; 22487961SNatalie.Li@Sun.COM } 22494345Sdougm case OPT_TYPE_LOGTAG: 22504345Sdougm if (nfsl_getconfig_list(&configlist) == 0) { 22514345Sdougm int error; 22524345Sdougm if (value == NULL || 22534345Sdougm strlen(value) == 0) { 22544345Sdougm if (value != NULL) 22554345Sdougm sa_free_attr_string( 22564345Sdougm value); 22574345Sdougm value = strdup("global"); 22584345Sdougm } 22594345Sdougm if (value != NULL && 22604345Sdougm nfsl_findconfig(configlist, value, 22614345Sdougm &error) == NULL) { 22624345Sdougm ret = SA_BAD_VALUE; 22634345Sdougm } 22645179Sdougm /* Must always free when done */ 22655179Sdougm nfsl_freeconfig_list(&configlist); 22664345Sdougm } else { 22674345Sdougm ret = SA_CONFIG_ERR; 22684345Sdougm } 22694345Sdougm break; 22704345Sdougm case OPT_TYPE_STRING: 22714345Sdougm /* whatever is here should be ok */ 22724345Sdougm break; 22734345Sdougm case OPT_TYPE_SECURITY: 22744345Sdougm /* 22754345Sdougm * The "sec" property isn't used in the 22764345Sdougm * non-legacy parts of sharemgr. We need to 22774345Sdougm * reject it here. For legacy, it is pulled 22784345Sdougm * out well before we get here. 22794345Sdougm */ 22804345Sdougm ret = SA_NO_SUCH_PROP; 22814345Sdougm break; 22824345Sdougm default: 22834345Sdougm break; 22843910Sdougm } 22855179Sdougm 22865179Sdougm if (value != NULL) 22875179Sdougm sa_free_attr_string(value); 22885179Sdougm 22894345Sdougm if (ret == SA_OK && optdefs[optindex].check != NULL) { 22904345Sdougm /* do the property specific check */ 22916214Sdougm ret = optdefs[optindex].check(handle, property); 22923910Sdougm } 22933910Sdougm } 22943910Sdougm } 22953910Sdougm 22963910Sdougm if (propname != NULL) 22974345Sdougm sa_free_attr_string(propname); 22983910Sdougm return (ret); 22993910Sdougm } 23003910Sdougm 23013910Sdougm /* 23023910Sdougm * Protocol management functions 23033910Sdougm * 23043910Sdougm * Properties defined in the default files are defined in 23053910Sdougm * proto_option_defs for parsing and validation. If "other" and 23063910Sdougm * "compare" are set, then the value for this property should be 23073910Sdougm * compared against the property specified in "other" using the 23083910Sdougm * "compare" check (either <= or >=) in order to ensure that the 23093910Sdougm * values are in the correct range. E.g. setting server_versmin 23103910Sdougm * higher than server_versmax should not be allowed. 23113910Sdougm */ 23123910Sdougm 23133910Sdougm struct proto_option_defs { 23143910Sdougm char *tag; 23153910Sdougm char *name; /* display name -- remove protocol identifier */ 23163910Sdougm int index; 23173910Sdougm int type; 23183910Sdougm union { 23193910Sdougm int intval; 23203910Sdougm char *string; 23213910Sdougm } defvalue; 23223910Sdougm uint32_t svcs; 23233910Sdougm int32_t minval; 23243910Sdougm int32_t maxval; 23253910Sdougm char *file; 23263910Sdougm char *other; 23273910Sdougm int compare; 23283910Sdougm #define OPT_CMP_GE 0 23293910Sdougm #define OPT_CMP_LE 1 23303910Sdougm int (*check)(char *); 23313910Sdougm } proto_options[] = { 23323910Sdougm #define PROTO_OPT_NFSD_SERVERS 0 23333910Sdougm {"nfsd_servers", 23343910Sdougm "servers", PROTO_OPT_NFSD_SERVERS, OPT_TYPE_NUMBER, 16, SVC_NFSD, 23353910Sdougm 1, INT32_MAX, NFSADMIN}, 23363910Sdougm #define PROTO_OPT_LOCKD_LISTEN_BACKLOG 1 23373910Sdougm {"lockd_listen_backlog", 23383910Sdougm "lockd_listen_backlog", PROTO_OPT_LOCKD_LISTEN_BACKLOG, 23393910Sdougm OPT_TYPE_NUMBER, 32, SVC_LOCKD, 32, INT32_MAX, NFSADMIN}, 23403910Sdougm #define PROTO_OPT_LOCKD_SERVERS 2 23413910Sdougm {"lockd_servers", 23423910Sdougm "lockd_servers", PROTO_OPT_LOCKD_SERVERS, OPT_TYPE_NUMBER, 20, 23433910Sdougm SVC_LOCKD, 1, INT32_MAX, NFSADMIN}, 23443910Sdougm #define PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT 3 23453910Sdougm {"lockd_retransmit_timeout", 23463910Sdougm "lockd_retransmit_timeout", PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT, 23473910Sdougm OPT_TYPE_NUMBER, 5, SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 23483910Sdougm #define PROTO_OPT_GRACE_PERIOD 4 23493910Sdougm {"grace_period", 23503910Sdougm "grace_period", PROTO_OPT_GRACE_PERIOD, OPT_TYPE_NUMBER, 90, 23513910Sdougm SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 23523910Sdougm #define PROTO_OPT_NFS_SERVER_VERSMIN 5 23533910Sdougm {"nfs_server_versmin", 23543910Sdougm "server_versmin", PROTO_OPT_NFS_SERVER_VERSMIN, OPT_TYPE_NUMBER, 23553910Sdougm (int)NFS_VERSMIN_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN, 23563910Sdougm NFS_VERSMAX, NFSADMIN, "server_versmax", OPT_CMP_LE}, 23573910Sdougm #define PROTO_OPT_NFS_SERVER_VERSMAX 6 23583910Sdougm {"nfs_server_versmax", 23593910Sdougm "server_versmax", PROTO_OPT_NFS_SERVER_VERSMAX, OPT_TYPE_NUMBER, 23603910Sdougm (int)NFS_VERSMAX_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN, 23613910Sdougm NFS_VERSMAX, NFSADMIN, "server_versmin", OPT_CMP_GE}, 23623910Sdougm #define PROTO_OPT_NFS_CLIENT_VERSMIN 7 23633910Sdougm {"nfs_client_versmin", 23643910Sdougm "client_versmin", PROTO_OPT_NFS_CLIENT_VERSMIN, OPT_TYPE_NUMBER, 23653910Sdougm (int)NFS_VERSMIN_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX, 23663910Sdougm NFSADMIN, "client_versmax", OPT_CMP_LE}, 23673910Sdougm #define PROTO_OPT_NFS_CLIENT_VERSMAX 8 23683910Sdougm {"nfs_client_versmax", 23693910Sdougm "client_versmax", PROTO_OPT_NFS_CLIENT_VERSMAX, OPT_TYPE_NUMBER, 23703910Sdougm (int)NFS_VERSMAX_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX, 23713910Sdougm NFSADMIN, "client_versmin", OPT_CMP_GE}, 23723910Sdougm #define PROTO_OPT_NFS_SERVER_DELEGATION 9 23733910Sdougm {"nfs_server_delegation", 23743910Sdougm "server_delegation", PROTO_OPT_NFS_SERVER_DELEGATION, 23753910Sdougm OPT_TYPE_ONOFF, NFS_SERVER_DELEGATION_DEFAULT, SVC_NFSD, 0, 0, 23763910Sdougm NFSADMIN}, 23773910Sdougm #define PROTO_OPT_NFSMAPID_DOMAIN 10 23783910Sdougm {"nfsmapid_domain", 23793910Sdougm "nfsmapid_domain", PROTO_OPT_NFSMAPID_DOMAIN, OPT_TYPE_DOMAIN, 23803910Sdougm NULL, SVC_NFSMAPID, 0, 0, NFSADMIN}, 23813910Sdougm #define PROTO_OPT_NFSD_MAX_CONNECTIONS 11 23823910Sdougm {"nfsd_max_connections", 23833910Sdougm "max_connections", PROTO_OPT_NFSD_MAX_CONNECTIONS, 23843910Sdougm OPT_TYPE_NUMBER, -1, SVC_NFSD, -1, INT32_MAX, NFSADMIN}, 23853910Sdougm #define PROTO_OPT_NFSD_PROTOCOL 12 23863910Sdougm {"nfsd_protocol", 23873910Sdougm "protocol", PROTO_OPT_NFSD_PROTOCOL, OPT_TYPE_PROTOCOL, 0, 23883910Sdougm SVC_NFSD, 0, 0, NFSADMIN}, 23893910Sdougm #define PROTO_OPT_NFSD_LISTEN_BACKLOG 13 23903910Sdougm {"nfsd_listen_backlog", 23913910Sdougm "listen_backlog", PROTO_OPT_NFSD_LISTEN_BACKLOG, 23923910Sdougm OPT_TYPE_NUMBER, 0, 23933910Sdougm SVC_LOCKD, 0, INT32_MAX, NFSADMIN}, 23943910Sdougm {NULL} 23953910Sdougm }; 23963910Sdougm 23973910Sdougm /* 23983910Sdougm * the protoset holds the defined options so we don't have to read 23993910Sdougm * them multiple times 24003910Sdougm */ 24015179Sdougm static sa_protocol_properties_t protoset; 24023910Sdougm 24033910Sdougm static int 24043910Sdougm findprotoopt(char *name, int whichname) 24053910Sdougm { 24063910Sdougm int i; 24073910Sdougm for (i = 0; proto_options[i].tag != NULL; i++) { 24084345Sdougm if (whichname == 1) { 24094345Sdougm if (strcasecmp(proto_options[i].name, name) == 0) 24103910Sdougm return (i); 24114345Sdougm } else { 24124345Sdougm if (strcasecmp(proto_options[i].tag, name) == 0) 24134345Sdougm return (i); 24144345Sdougm } 24153910Sdougm } 24163910Sdougm return (-1); 24173910Sdougm } 24183910Sdougm 24193910Sdougm /* 24203910Sdougm * fixcaselower(str) 24213910Sdougm * 24223910Sdougm * convert a string to lower case (inplace). 24233910Sdougm */ 24243910Sdougm 24253910Sdougm static void 24263910Sdougm fixcaselower(char *str) 24273910Sdougm { 24283910Sdougm while (*str) { 24294345Sdougm *str = tolower(*str); 24304345Sdougm str++; 24313910Sdougm } 24323910Sdougm } 24333910Sdougm 24343910Sdougm /* 24353910Sdougm * fixcaseupper(str) 24363910Sdougm * 24373910Sdougm * convert a string to upper case (inplace). 24383910Sdougm */ 24393910Sdougm 24403910Sdougm static void 24413910Sdougm fixcaseupper(char *str) 24423910Sdougm { 24433910Sdougm while (*str) { 24444345Sdougm *str = toupper(*str); 24454345Sdougm str++; 24463910Sdougm } 24473910Sdougm } 24483910Sdougm 24493910Sdougm /* 24504241Sdougm * skipwhitespace(str) 24514241Sdougm * 24524241Sdougm * Skip leading white space. It is assumed that it is called with a 24534241Sdougm * valid pointer. 24544241Sdougm */ 24554241Sdougm 24564241Sdougm static char * 24574241Sdougm skipwhitespace(char *str) 24584241Sdougm { 24594241Sdougm while (*str && isspace(*str)) 24604241Sdougm str++; 24614241Sdougm 24624241Sdougm return (str); 24634241Sdougm } 24644241Sdougm 24654241Sdougm /* 24664345Sdougm * extractprop() 24674345Sdougm * 24684345Sdougm * Extract the property and value out of the line and create the 24694345Sdougm * property in the optionset. 24704345Sdougm */ 24716019Sdougm static int 24724345Sdougm extractprop(char *name, char *value) 24734345Sdougm { 24744345Sdougm sa_property_t prop; 24754345Sdougm int index; 24766019Sdougm int ret = SA_OK; 24774345Sdougm /* 24784345Sdougm * Remove any leading 24794345Sdougm * white space. 24804345Sdougm */ 24814345Sdougm name = skipwhitespace(name); 24824345Sdougm 24834345Sdougm index = findprotoopt(name, 0); 24844345Sdougm if (index >= 0) { 24854345Sdougm fixcaselower(name); 24864345Sdougm prop = sa_create_property(proto_options[index].name, value); 24874345Sdougm if (prop != NULL) 24886019Sdougm ret = sa_add_protocol_property(protoset, prop); 24896019Sdougm else 24906019Sdougm ret = SA_NO_MEMORY; 24914345Sdougm } 24926019Sdougm return (ret); 24934345Sdougm } 24944345Sdougm 24954345Sdougm /* 24963910Sdougm * initprotofromdefault() 24973910Sdougm * 24986162Sdougm * Read the default file(s) and add the defined values to the 24993910Sdougm * protoset. Note that default values are known from the built in 25006162Sdougm * table in case the file doesn't have a definition. Not having the 25016162Sdougm * /etc/default/nfs file is OK since we have builtin default 25026162Sdougm * values. The default file will get constructed as needed if values 25036162Sdougm * are changed from the defaults. 25043910Sdougm */ 25053910Sdougm 25063910Sdougm static int 25073910Sdougm initprotofromdefault() 25083910Sdougm { 25093910Sdougm FILE *nfs; 25103910Sdougm char buff[BUFSIZ]; 25113910Sdougm char *name; 25123910Sdougm char *value; 25136019Sdougm int ret = SA_OK; 25143910Sdougm 25153910Sdougm protoset = sa_create_protocol_properties("nfs"); 25163910Sdougm 25173910Sdougm if (protoset != NULL) { 25184345Sdougm nfs = fopen(NFSADMIN, "r"); 25194345Sdougm if (nfs != NULL) { 25206019Sdougm while (ret == SA_OK && 25216019Sdougm fgets(buff, sizeof (buff), nfs) != NULL) { 25224345Sdougm switch (buff[0]) { 25234345Sdougm case '\n': 25244345Sdougm case '#': 25254345Sdougm /* skip */ 25264345Sdougm break; 25274345Sdougm default: 25284345Sdougm name = buff; 25294345Sdougm buff[strlen(buff) - 1] = '\0'; 25304345Sdougm value = strchr(name, '='); 25314345Sdougm if (value != NULL) { 25324345Sdougm *value++ = '\0'; 25336019Sdougm ret = extractprop(name, value); 25344345Sdougm } 25354345Sdougm } 25363910Sdougm } 25376019Sdougm (void) fclose(nfs); 25386019Sdougm } else { 25396162Sdougm switch (errno) { 25406162Sdougm case EPERM: 25416162Sdougm case EACCES: 25426162Sdougm ret = SA_NO_PERMISSION; 25436162Sdougm break; 25446162Sdougm case ENOENT: 25456162Sdougm break; 25466162Sdougm default: 25476162Sdougm ret = SA_SYSTEM_ERR; 25486162Sdougm break; 25496162Sdougm } 25503910Sdougm } 25516019Sdougm } else { 25526019Sdougm ret = SA_NO_MEMORY; 25533910Sdougm } 25546019Sdougm return (ret); 25553910Sdougm } 25563910Sdougm 25573910Sdougm /* 25584345Sdougm * add_defaults() 25593910Sdougm * 25603910Sdougm * Add the default values for any property not defined in the parsing 25613910Sdougm * of the default files. Values are set according to their defined 25623910Sdougm * types. 25633910Sdougm */ 25643910Sdougm 25653910Sdougm static void 25663910Sdougm add_defaults() 25673910Sdougm { 25683910Sdougm int i; 25693910Sdougm char number[MAXDIGITS]; 25703910Sdougm 25713910Sdougm for (i = 0; proto_options[i].tag != NULL; i++) { 25724345Sdougm sa_property_t prop; 25734345Sdougm prop = sa_get_protocol_property(protoset, 25744345Sdougm proto_options[i].name); 25754345Sdougm if (prop == NULL) { 25764345Sdougm /* add the default value */ 25774345Sdougm switch (proto_options[i].type) { 25784345Sdougm case OPT_TYPE_NUMBER: 25794345Sdougm (void) snprintf(number, sizeof (number), "%d", 25804345Sdougm proto_options[i].defvalue.intval); 25814345Sdougm prop = sa_create_property(proto_options[i].name, 25824345Sdougm number); 25834345Sdougm break; 25843910Sdougm 25854345Sdougm case OPT_TYPE_BOOLEAN: 25864345Sdougm prop = sa_create_property(proto_options[i].name, 25874345Sdougm proto_options[i].defvalue.intval ? 25884345Sdougm "true" : "false"); 25894345Sdougm break; 25903910Sdougm 25914345Sdougm case OPT_TYPE_ONOFF: 25924345Sdougm prop = sa_create_property(proto_options[i].name, 25934345Sdougm proto_options[i].defvalue.intval ? 25944345Sdougm "on" : "off"); 25954345Sdougm break; 25963910Sdougm 25974345Sdougm default: 25984345Sdougm /* treat as strings of zero length */ 25994345Sdougm prop = sa_create_property(proto_options[i].name, 26004345Sdougm ""); 26014345Sdougm break; 26024345Sdougm } 26034345Sdougm if (prop != NULL) 26044345Sdougm (void) sa_add_protocol_property(protoset, prop); 26053910Sdougm } 26063910Sdougm } 26073910Sdougm } 26083910Sdougm 26093910Sdougm static void 26103910Sdougm free_protoprops() 26113910Sdougm { 26125179Sdougm if (protoset != NULL) { 26135179Sdougm xmlFreeNode(protoset); 26145179Sdougm protoset = NULL; 26155179Sdougm } 26163910Sdougm } 26173910Sdougm 26183910Sdougm /* 26193910Sdougm * nfs_init() 26203910Sdougm * 26213910Sdougm * Initialize the NFS plugin. 26223910Sdougm */ 26233910Sdougm 26243910Sdougm static int 26253910Sdougm nfs_init() 26263910Sdougm { 26273910Sdougm int ret = SA_OK; 26283910Sdougm 26296162Sdougm if (sa_plugin_ops.sa_init != nfs_init) { 26304345Sdougm (void) printf(dgettext(TEXT_DOMAIN, 26314345Sdougm "NFS plugin not properly initialized\n")); 26326162Sdougm return (SA_CONFIG_ERR); 26336162Sdougm } 26343910Sdougm 26353910Sdougm ret = initprotofromdefault(); 26366162Sdougm if (ret != SA_OK) { 26376162Sdougm (void) printf(dgettext(TEXT_DOMAIN, 26386162Sdougm "NFS plugin problem with default file: %s\n"), 26396162Sdougm sa_errorstr(ret)); 26406162Sdougm ret = SA_OK; 26416162Sdougm } 26426162Sdougm add_defaults(); 26433910Sdougm 26443910Sdougm return (ret); 26453910Sdougm } 26463910Sdougm 26473910Sdougm /* 26483910Sdougm * nfs_fini() 26493910Sdougm * 26503910Sdougm * uninitialize the NFS plugin. Want to avoid memory leaks. 26513910Sdougm */ 26523910Sdougm 26533910Sdougm static void 26543910Sdougm nfs_fini() 26553910Sdougm { 26563910Sdougm free_protoprops(); 26573910Sdougm } 26583910Sdougm 26593910Sdougm /* 26603910Sdougm * nfs_get_proto_set() 26613910Sdougm * 26623910Sdougm * Return an optionset with all the protocol specific properties in 26633910Sdougm * it. 26643910Sdougm */ 26653910Sdougm 26663910Sdougm static sa_protocol_properties_t 26673910Sdougm nfs_get_proto_set() 26683910Sdougm { 26693910Sdougm return (protoset); 26703910Sdougm } 26713910Sdougm 26723910Sdougm struct deffile { 26733910Sdougm struct deffile *next; 26743910Sdougm char *line; 26753910Sdougm }; 26763910Sdougm 26773910Sdougm /* 26783910Sdougm * read_default_file(fname) 26793910Sdougm * 26803910Sdougm * Read the specified default file. We return a list of entries. This 26813910Sdougm * get used for adding or removing values. 26823910Sdougm */ 26833910Sdougm 26843910Sdougm static struct deffile * 26853910Sdougm read_default_file(char *fname) 26863910Sdougm { 26873910Sdougm FILE *file; 26883910Sdougm struct deffile *defs = NULL; 26893910Sdougm struct deffile *newdef; 26903910Sdougm struct deffile *prevdef = NULL; 26913910Sdougm char buff[BUFSIZ * 2]; 26923910Sdougm 26933910Sdougm file = fopen(fname, "r"); 26943910Sdougm if (file != NULL) { 26954345Sdougm while (fgets(buff, sizeof (buff), file) != NULL) { 26964345Sdougm newdef = (struct deffile *)calloc(1, 26974345Sdougm sizeof (struct deffile)); 26984345Sdougm if (newdef != NULL) { 26994345Sdougm /* Make sure we skip any leading whitespace. */ 27004345Sdougm newdef->line = strdup(skipwhitespace(buff)); 27014345Sdougm if (defs == NULL) { 27024345Sdougm prevdef = defs = newdef; 27034345Sdougm } else { 27044345Sdougm prevdef->next = newdef; 27054345Sdougm prevdef = newdef; 27064345Sdougm } 27074345Sdougm } 27083910Sdougm } 27096162Sdougm (void) fclose(file); 27106162Sdougm } else { 27116162Sdougm int ret = SA_OK; 27126162Sdougm switch (errno) { 27136162Sdougm case EPERM: 27146162Sdougm case EACCES: 27156162Sdougm ret = SA_NO_PERMISSION; 27166162Sdougm break; 27176162Sdougm case ENOENT: 27186162Sdougm break; 27196162Sdougm default: 27206162Sdougm ret = SA_SYSTEM_ERR; 27216162Sdougm break; 27226162Sdougm } 27236162Sdougm if (ret == SA_OK) { 27246162Sdougm /* Want at least one comment line */ 27256162Sdougm defs = (struct deffile *) 27266162Sdougm calloc(1, sizeof (struct deffile)); 27276162Sdougm defs->line = strdup("# NFS default file\n"); 27286162Sdougm } 27293910Sdougm } 27303910Sdougm return (defs); 27313910Sdougm } 27323910Sdougm 27333910Sdougm static void 27343910Sdougm free_default_file(struct deffile *defs) 27353910Sdougm { 27363910Sdougm struct deffile *curdefs = NULL; 27373910Sdougm 27383910Sdougm while (defs != NULL) { 27394345Sdougm curdefs = defs; 27404345Sdougm defs = defs->next; 27414345Sdougm if (curdefs->line != NULL) 27424345Sdougm free(curdefs->line); 27434345Sdougm free(curdefs); 27443910Sdougm } 27453910Sdougm } 27463910Sdougm 27473910Sdougm /* 27483910Sdougm * write_default_file(fname, defs) 27493910Sdougm * 27503910Sdougm * Write the default file back. 27513910Sdougm */ 27523910Sdougm 27533910Sdougm static int 27543910Sdougm write_default_file(char *fname, struct deffile *defs) 27553910Sdougm { 27563910Sdougm FILE *file; 27573910Sdougm int ret = SA_OK; 27583910Sdougm sigset_t old, new; 27593910Sdougm 27603910Sdougm file = fopen(fname, "w+"); 27613910Sdougm if (file != NULL) { 27624345Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 27634345Sdougm (void) sigaddset(&new, SIGHUP); 27644345Sdougm (void) sigaddset(&new, SIGINT); 27654345Sdougm (void) sigaddset(&new, SIGQUIT); 27664345Sdougm (void) sigaddset(&new, SIGTSTP); 27674345Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 27684345Sdougm while (defs != NULL) { 27694345Sdougm (void) fputs(defs->line, file); 27704345Sdougm defs = defs->next; 27714345Sdougm } 27724345Sdougm (void) fsync(fileno(file)); 27734345Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 27744345Sdougm (void) fclose(file); 27753910Sdougm } else { 27764345Sdougm switch (errno) { 27774345Sdougm case EPERM: 27784345Sdougm case EACCES: 27794345Sdougm ret = SA_NO_PERMISSION; 27804345Sdougm break; 27814345Sdougm default: 27824345Sdougm ret = SA_SYSTEM_ERR; 27834345Sdougm } 27843910Sdougm } 27853910Sdougm return (ret); 27863910Sdougm } 27873910Sdougm 27883910Sdougm 27893910Sdougm /* 27903910Sdougm * set_default_file_value(tag, value) 27913910Sdougm * 27923910Sdougm * Set the default file value for tag to value. Then rewrite the file. 27933910Sdougm * tag and value are always set. The caller must ensure this. 27943910Sdougm */ 27953910Sdougm 27963910Sdougm #define MAX_STRING_LENGTH 256 27973910Sdougm static int 27983910Sdougm set_default_file_value(char *tag, char *value) 27993910Sdougm { 28003910Sdougm int ret = SA_OK; 28013910Sdougm struct deffile *root; 28023910Sdougm struct deffile *defs; 28033910Sdougm struct deffile *prev; 28043910Sdougm char string[MAX_STRING_LENGTH]; 28053910Sdougm int len; 28066162Sdougm boolean_t update = B_FALSE; 28073910Sdougm 28083910Sdougm (void) snprintf(string, MAX_STRING_LENGTH, "%s=", tag); 28093910Sdougm len = strlen(string); 28103910Sdougm 28113910Sdougm root = defs = read_default_file(NFSADMIN); 28123910Sdougm if (root == NULL) { 28136162Sdougm switch (errno) { 28146162Sdougm case EPERM: 28156162Sdougm case EACCES: 28164345Sdougm ret = SA_NO_PERMISSION; 28176162Sdougm break; 28186162Sdougm default: 28196162Sdougm ret = SA_NO_MEMORY; 28206162Sdougm break; 28216162Sdougm } 28226162Sdougm return (ret); 28236162Sdougm } 28246162Sdougm 28256162Sdougm while (defs != NULL) { 28266162Sdougm if (defs->line != NULL && 28276162Sdougm strncasecmp(defs->line, string, len) == 0) { 28286162Sdougm /* replace with the new value */ 28296162Sdougm free(defs->line); 28306162Sdougm fixcaseupper(tag); 28316162Sdougm (void) snprintf(string, sizeof (string), 28326162Sdougm "%s=%s\n", tag, value); 28336162Sdougm string[MAX_STRING_LENGTH - 1] = '\0'; 28346162Sdougm defs->line = strdup(string); 28356162Sdougm update = B_TRUE; 28366162Sdougm break; 28376162Sdougm } 28386162Sdougm defs = defs->next; 28396162Sdougm } 28406162Sdougm if (!update) { 28416162Sdougm defs = root; 28426162Sdougm /* didn't find, so see if it is a comment */ 28436162Sdougm (void) snprintf(string, MAX_STRING_LENGTH, "#%s=", tag); 28446162Sdougm len = strlen(string); 28453910Sdougm while (defs != NULL) { 28466162Sdougm if (strncasecmp(defs->line, string, len) == 0) { 28474345Sdougm /* replace with the new value */ 28484345Sdougm free(defs->line); 28494345Sdougm fixcaseupper(tag); 28504345Sdougm (void) snprintf(string, sizeof (string), 28513910Sdougm "%s=%s\n", tag, value); 28524345Sdougm string[MAX_STRING_LENGTH - 1] = '\0'; 28534345Sdougm defs->line = strdup(string); 28546162Sdougm update = B_TRUE; 28554345Sdougm break; 28564345Sdougm } 28574345Sdougm defs = defs->next; 28583910Sdougm } 28596162Sdougm } 28606162Sdougm if (!update) { 28616162Sdougm fixcaseupper(tag); 28626162Sdougm (void) snprintf(string, sizeof (string), "%s=%s\n", 28636162Sdougm tag, value); 28646162Sdougm prev = root; 28656162Sdougm while (prev->next != NULL) 28666162Sdougm prev = prev->next; 28676162Sdougm defs = malloc(sizeof (struct deffile)); 28686162Sdougm prev->next = defs; 28696162Sdougm if (defs != NULL) { 28706162Sdougm defs->next = NULL; 28716162Sdougm defs->line = strdup(string); 28726162Sdougm update = B_TRUE; 28733910Sdougm } 28743910Sdougm } 28756162Sdougm if (update) { 28766162Sdougm ret = write_default_file(NFSADMIN, root); 28776162Sdougm } 28786162Sdougm free_default_file(root); 28793910Sdougm return (ret); 28803910Sdougm } 28813910Sdougm 28823910Sdougm /* 28833910Sdougm * service_in_state(service, chkstate) 28843910Sdougm * 28853910Sdougm * Want to know if the specified service is in the desired state 28863910Sdougm * (chkstate) or not. Return true (1) if it is and false (0) if it 28873910Sdougm * isn't. 28883910Sdougm */ 28893910Sdougm static int 28903910Sdougm service_in_state(char *service, const char *chkstate) 28913910Sdougm { 28923910Sdougm char *state; 28933910Sdougm int ret = B_FALSE; 28943910Sdougm 28953910Sdougm state = smf_get_state(service); 28963910Sdougm if (state != NULL) { 28974345Sdougm /* got the state so get the equality for the return value */ 28984345Sdougm ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE; 28994345Sdougm free(state); 29003910Sdougm } 29013910Sdougm return (ret); 29023910Sdougm } 29033910Sdougm 29043910Sdougm /* 29053910Sdougm * restart_service(svcs) 29063910Sdougm * 29073910Sdougm * Walk through the bit mask of services that need to be restarted in 29083910Sdougm * order to use the new property values. Some properties affect 29093910Sdougm * multiple daemons. Should only restart a service if it is currently 29103910Sdougm * enabled (online). 29113910Sdougm */ 29123910Sdougm 29133910Sdougm static void 29143910Sdougm restart_service(uint32_t svcs) 29153910Sdougm { 29163910Sdougm uint32_t mask; 29173910Sdougm int ret; 29183910Sdougm char *service; 29193910Sdougm 29203910Sdougm for (mask = 1; svcs != 0; mask <<= 1) { 29214345Sdougm switch (svcs & mask) { 29224345Sdougm case SVC_LOCKD: 29234345Sdougm service = LOCKD; 29244345Sdougm break; 29254345Sdougm case SVC_STATD: 29264345Sdougm service = STATD; 29274345Sdougm break; 29284345Sdougm case SVC_NFSD: 29294345Sdougm service = NFSD; 29304345Sdougm break; 29314345Sdougm case SVC_MOUNTD: 29324345Sdougm service = MOUNTD; 29334345Sdougm break; 29344345Sdougm case SVC_NFS4CBD: 29354345Sdougm service = NFS4CBD; 29364345Sdougm break; 29374345Sdougm case SVC_NFSMAPID: 29384345Sdougm service = NFSMAPID; 29394345Sdougm break; 29404345Sdougm case SVC_RQUOTAD: 29414345Sdougm service = RQUOTAD; 29424345Sdougm break; 29434345Sdougm case SVC_NFSLOGD: 29444345Sdougm service = NFSLOGD; 29454345Sdougm break; 294611291SRobert.Thurlow@Sun.COM case SVC_REPARSED: 294711291SRobert.Thurlow@Sun.COM service = REPARSED; 294811291SRobert.Thurlow@Sun.COM break; 29494345Sdougm default: 29504345Sdougm continue; 29514345Sdougm } 29523910Sdougm 29533910Sdougm /* 29543910Sdougm * Only attempt to restart the service if it is 29553910Sdougm * currently running. In the future, it may be 29563910Sdougm * desirable to use smf_refresh_instance if the NFS 29573910Sdougm * services ever implement the refresh method. 29583910Sdougm */ 29594345Sdougm if (service_in_state(service, SCF_STATE_STRING_ONLINE)) { 29604345Sdougm ret = smf_restart_instance(service); 29613910Sdougm /* 29624345Sdougm * There are only a few SMF errors at this point, but 29634345Sdougm * it is also possible that a bad value may have put 29644345Sdougm * the service into maintenance if there wasn't an 29654345Sdougm * SMF level error. 29663910Sdougm */ 29674345Sdougm if (ret != 0) { 29684345Sdougm (void) fprintf(stderr, 29694345Sdougm dgettext(TEXT_DOMAIN, 29704345Sdougm "%s failed to restart: %s\n"), 29714345Sdougm scf_strerror(scf_error())); 29724345Sdougm } else { 29734345Sdougm /* 29744345Sdougm * Check whether it has gone to "maintenance" 29754345Sdougm * mode or not. Maintenance implies something 29764345Sdougm * went wrong. 29774345Sdougm */ 29784345Sdougm if (service_in_state(service, 29794345Sdougm SCF_STATE_STRING_MAINT)) { 29804345Sdougm (void) fprintf(stderr, 29814345Sdougm dgettext(TEXT_DOMAIN, 29824345Sdougm "%s failed to restart\n"), 29834345Sdougm service); 29844345Sdougm } 29854345Sdougm } 29863910Sdougm } 29874345Sdougm svcs &= ~mask; 29883910Sdougm } 29893910Sdougm } 29903910Sdougm 29913910Sdougm /* 29923910Sdougm * nfs_minmax_check(name, value) 29933910Sdougm * 29943910Sdougm * Verify that the value for the property specified by index is valid 29953910Sdougm * relative to the opposite value in the case of a min/max variable. 29963910Sdougm * Currently, server_minvers/server_maxvers and 29973910Sdougm * client_minvers/client_maxvers are the only ones to check. 29983910Sdougm */ 29993910Sdougm 30003910Sdougm static int 30013910Sdougm nfs_minmax_check(int index, int value) 30023910Sdougm { 30033910Sdougm int val; 30043910Sdougm char *pval; 30053910Sdougm sa_property_t prop; 30063910Sdougm sa_optionset_t opts; 30073910Sdougm int ret = B_TRUE; 30083910Sdougm 30093910Sdougm if (proto_options[index].other != NULL) { 30104345Sdougm /* have a property to compare against */ 30114345Sdougm opts = nfs_get_proto_set(); 30124345Sdougm prop = sa_get_property(opts, proto_options[index].other); 30133910Sdougm /* 30143910Sdougm * If we don't find the property, assume default 30153910Sdougm * values which will work since the max will be at the 30163910Sdougm * max and the min at the min. 30173910Sdougm */ 30184345Sdougm if (prop != NULL) { 30194345Sdougm pval = sa_get_property_attr(prop, "value"); 30204345Sdougm if (pval != NULL) { 30214345Sdougm val = strtoul(pval, NULL, 0); 30224345Sdougm if (proto_options[index].compare == 30234345Sdougm OPT_CMP_LE) { 30244345Sdougm ret = value <= val ? B_TRUE : B_FALSE; 30254345Sdougm } else if (proto_options[index].compare == 30264345Sdougm OPT_CMP_GE) { 30274345Sdougm ret = value >= val ? B_TRUE : B_FALSE; 30284345Sdougm } 302911337SWilliam.Krier@Sun.COM sa_free_attr_string(pval); 30304345Sdougm } 30313910Sdougm } 30323910Sdougm } 30333910Sdougm return (ret); 30343910Sdougm } 30353910Sdougm 30363910Sdougm /* 30373910Sdougm * nfs_validate_proto_prop(index, name, value) 30383910Sdougm * 30395331Samw * Verify that the property specified by name can take the new 30403910Sdougm * value. This is a sanity check to prevent bad values getting into 30413910Sdougm * the default files. All values need to be checked against what is 30423910Sdougm * allowed by their defined type. If a type isn't explicitly defined 30433910Sdougm * here, it is treated as a string. 30443910Sdougm * 30453910Sdougm * Note that OPT_TYPE_NUMBER will additionally check that the value is 30463910Sdougm * within the range specified and potentially against another property 30473910Sdougm * value as well as specified in the proto_options members other and 30483910Sdougm * compare. 30493910Sdougm */ 30503910Sdougm 30513910Sdougm static int 30523910Sdougm nfs_validate_proto_prop(int index, char *name, char *value) 30533910Sdougm { 30543910Sdougm int ret = SA_OK; 30553910Sdougm char *cp; 30563910Sdougm #ifdef lint 30573910Sdougm name = name; 30583910Sdougm #endif 30593910Sdougm 30603910Sdougm switch (proto_options[index].type) { 30613910Sdougm case OPT_TYPE_NUMBER: 30624345Sdougm if (!is_a_number(value)) 30634345Sdougm ret = SA_BAD_VALUE; 30644345Sdougm else { 30654345Sdougm int val; 30664345Sdougm val = strtoul(value, NULL, 0); 30674345Sdougm if (val < proto_options[index].minval || 30684345Sdougm val > proto_options[index].maxval) 30694345Sdougm ret = SA_BAD_VALUE; 30704345Sdougm /* 30714345Sdougm * For server_versmin/server_versmax and 30724345Sdougm * client_versmin/client_versmax, the value of the 30734345Sdougm * min(max) should be checked to be correct relative 30744345Sdougm * to the current max(min). 30754345Sdougm */ 30764345Sdougm if (!nfs_minmax_check(index, val)) { 30774345Sdougm ret = SA_BAD_VALUE; 30784345Sdougm } 30793910Sdougm } 30804345Sdougm break; 30813910Sdougm 30823910Sdougm case OPT_TYPE_DOMAIN: 30833910Sdougm /* 30843910Sdougm * needs to be a qualified domain so will have at 30853910Sdougm * least one period and other characters on either 30863910Sdougm * side of it. A zero length string is also allowed 30873910Sdougm * and is the way to turn off the override. 30883910Sdougm */ 30894345Sdougm if (strlen(value) == 0) 30904345Sdougm break; 30914345Sdougm cp = strchr(value, '.'); 30924345Sdougm if (cp == NULL || cp == value || strchr(value, '@') != NULL) 30934345Sdougm ret = SA_BAD_VALUE; 30943910Sdougm break; 30953910Sdougm 30963910Sdougm case OPT_TYPE_BOOLEAN: 30974345Sdougm if (strlen(value) == 0 || 30984345Sdougm strcasecmp(value, "true") == 0 || 30994345Sdougm strcmp(value, "1") == 0 || 31004345Sdougm strcasecmp(value, "false") == 0 || 31014345Sdougm strcmp(value, "0") == 0) { 31024345Sdougm ret = SA_OK; 31034345Sdougm } else { 31044345Sdougm ret = SA_BAD_VALUE; 31054345Sdougm } 31064345Sdougm break; 31073910Sdougm 31083910Sdougm case OPT_TYPE_ONOFF: 31094345Sdougm if (strcasecmp(value, "on") != 0 && 31104345Sdougm strcasecmp(value, "off") != 0) { 31114345Sdougm ret = SA_BAD_VALUE; 31124345Sdougm } 31134345Sdougm break; 31143910Sdougm 31153910Sdougm case OPT_TYPE_PROTOCOL: 31166162Sdougm if (strlen(value) != 0 && 31176162Sdougm strcasecmp(value, "all") != 0 && 31184345Sdougm strcasecmp(value, "tcp") != 0 && 31194345Sdougm strcasecmp(value, "udp") != 0) 31204345Sdougm ret = SA_BAD_VALUE; 31214345Sdougm break; 31223910Sdougm 31233910Sdougm default: 31244345Sdougm /* treat as a string */ 31254345Sdougm break; 31263910Sdougm } 31273910Sdougm return (ret); 31283910Sdougm } 31293910Sdougm 31303910Sdougm /* 31313910Sdougm * nfs_set_proto_prop(prop) 31323910Sdougm * 31333910Sdougm * check that prop is valid. 31343910Sdougm */ 31353910Sdougm 31363910Sdougm static int 31373910Sdougm nfs_set_proto_prop(sa_property_t prop) 31383910Sdougm { 31393910Sdougm int ret = SA_OK; 31403910Sdougm char *name; 31413910Sdougm char *value; 31423910Sdougm 31433910Sdougm name = sa_get_property_attr(prop, "type"); 31443910Sdougm value = sa_get_property_attr(prop, "value"); 31453910Sdougm if (name != NULL && value != NULL) { 31464345Sdougm int index = findprotoopt(name, 1); 31474345Sdougm if (index >= 0) { 31484345Sdougm /* should test for valid value */ 31494345Sdougm ret = nfs_validate_proto_prop(index, name, value); 31504345Sdougm if (ret == SA_OK) 31514345Sdougm ret = set_default_file_value( 31524345Sdougm proto_options[index].tag, value); 31534345Sdougm if (ret == SA_OK) 31544345Sdougm restart_service(proto_options[index].svcs); 31554345Sdougm } 31563910Sdougm } 31573910Sdougm if (name != NULL) 31584345Sdougm sa_free_attr_string(name); 31593910Sdougm if (value != NULL) 31604345Sdougm sa_free_attr_string(value); 31613910Sdougm return (ret); 31623910Sdougm } 31633910Sdougm 31643910Sdougm /* 31653910Sdougm * nfs_get_status() 31663910Sdougm * 31673910Sdougm * What is the current status of the nfsd? We use the SMF state here. 31683910Sdougm * Caller must free the returned value. 31693910Sdougm */ 31703910Sdougm 31713910Sdougm static char * 31723910Sdougm nfs_get_status() 31733910Sdougm { 31743910Sdougm char *state; 31753910Sdougm state = smf_get_state(NFSD); 31763910Sdougm return (state != NULL ? state : strdup("-")); 31773910Sdougm } 31783910Sdougm 31793910Sdougm /* 31803910Sdougm * nfs_space_alias(alias) 31813910Sdougm * 31823910Sdougm * Lookup the space (security) name. If it is default, convert to the 31833910Sdougm * real name. 31843910Sdougm */ 31853910Sdougm 31863910Sdougm static char * 31873910Sdougm nfs_space_alias(char *space) 31883910Sdougm { 31893910Sdougm char *name = space; 31903910Sdougm seconfig_t secconf; 31913910Sdougm 31923910Sdougm /* 31933910Sdougm * Only the space named "default" is special. If it is used, 31943910Sdougm * the default needs to be looked up and the real name used. 31953910Sdougm * This is normally "sys" but could be changed. We always 31963910Sdougm * change defautl to the real name. 31973910Sdougm */ 31983910Sdougm if (strcmp(space, "default") == 0 && 31993910Sdougm nfs_getseconfig_default(&secconf) == 0) { 32004345Sdougm if (nfs_getseconfig_bynumber(secconf.sc_nfsnum, &secconf) == 0) 32014345Sdougm name = secconf.sc_name; 32023910Sdougm } 32033910Sdougm return (strdup(name)); 32043910Sdougm } 32055331Samw 32065331Samw /* 32075331Samw * nfs_features() 32085331Samw * 32095331Samw * Return a mask of the features required. 32105331Samw */ 32115331Samw 32125331Samw static uint64_t 32135331Samw nfs_features() 32145331Samw { 32156088Sdougm return ((uint64_t)SA_FEATURE_DFSTAB | SA_FEATURE_SERVER); 32165331Samw } 3217