summaryrefslogtreecommitdiff
path: root/usr/src/lib/libshare/nfs/libshare_nfs.c
diff options
context:
space:
mode:
authorKeith M Wesolowski <wesolows@foobazco.org>2014-07-08 16:07:41 +0000
committerKeith M Wesolowski <wesolows@foobazco.org>2014-07-08 16:07:41 +0000
commit7778a6793fcfe146eabe053e698f03c46d4ae366 (patch)
tree1c952ec02222ccd0389d6c1f2f6e646aa9992ffb /usr/src/lib/libshare/nfs/libshare_nfs.c
parent48a840da6711e93449bd8edc2d0a4ef97373d2a5 (diff)
parent5cb0d67909d9970a3e7adbea9422ca3fc88000bf (diff)
downloadillumos-joyent-7778a6793fcfe146eabe053e698f03c46d4ae366.tar.gz
[illumos-gate merge]
commit 5cb0d67909d9970a3e7adbea9422ca3fc88000bf 4943 NFS server: Generic uid and gid remapping for AUTH_SYS commit 33cde0d0c27645bc9ec94c4d2955193c3dd4027c 4953 zfs rename <snapshot> need not involve libshare 4954 "zfs create" need not involve libshare if we are not sharing 4955 libshare's get_zfs_dataset need not sort the datasets commit 4bb73804952172060c9efb163b89c17f56804fe8 4950 files sometimes can't be removed from a full filesystem commit 08e958452532187958dbff5121d3010ef1de98ee 4906 cpqary3: add support for hp gen8+ smart array controllers Conflicts: usr/src/uts/common/nfs/export.h usr/src/uts/common/fs/zfs/zfs_vnops.c Manifests: usr/src/pkg/manifests/driver-storage-cpqary3.mf
Diffstat (limited to 'usr/src/lib/libshare/nfs/libshare_nfs.c')
-rw-r--r--usr/src/lib/libshare/nfs/libshare_nfs.c237
1 files changed, 195 insertions, 42 deletions
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c
index 3d781980ce..e897596e72 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c
@@ -42,6 +42,7 @@
#include "libshare_impl.h"
#include <nfs/export.h>
#include <pwd.h>
+#include <grp.h>
#include <limits.h>
#include <libscf.h>
#include <syslog.h>
@@ -168,8 +169,12 @@ struct option_defs optdefs[] = {
{"", OPT_CHARSET_MAP, OPT_TYPE_ACCLIST},
#define OPT_NOACLFAB 17
{SHOPT_NOACLFAB, OPT_NOACLFAB, OPT_TYPE_BOOLEAN},
+#define OPT_UIDMAP 18
+ {SHOPT_UIDMAP, OPT_UIDMAP, OPT_TYPE_MAPPING},
+#define OPT_GIDMAP 19
+ {SHOPT_GIDMAP, OPT_GIDMAP, OPT_TYPE_MAPPING},
#ifdef VOLATILE_FH_TEST /* XXX added for testing volatile fh's only */
-#define OPT_VOLFH 18
+#define OPT_VOLFH 20
{SHOPT_VOLFH, OPT_VOLFH},
#endif /* VOLATILE_FH_TEST */
NULL
@@ -212,6 +217,8 @@ static char *seclist[] = {
SHOPT_WINDOW,
SHOPT_NONE,
SHOPT_ROOT_MAPPING,
+ SHOPT_UIDMAP,
+ SHOPT_GIDMAP,
NULL
};
@@ -435,7 +442,7 @@ nfs_alistcat(char *str1, char *str2, char sep)
}
/*
- * add_security_prop(sec, name, value, persist)
+ * add_security_prop(sec, name, value, persist, iszfs)
*
* Add the property to the securities structure. This accumulates
* properties for as part of parsing legacy options.
@@ -473,21 +480,28 @@ add_security_prop(struct securities *sec, char *name, char *value,
char *newvalue;
/*
- * The security options of ro/rw/root might appear
- * multiple times. If they do, the values need to be
- * merged into an access list. If it was previously
- * empty, the new value alone is added.
+ * The security options of ro/rw/root/uidmap/gidmap
+ * might appear multiple times. If they do, the values
+ * need to be merged. If it was previously empty, the
+ * new value alone is added.
*/
oldvalue = sa_get_property_attr(prop, "value");
if (oldvalue != NULL) {
+ char sep = ':';
+
+ if (strcmp(name, SHOPT_UIDMAP) == 0 ||
+ strcmp(name, SHOPT_GIDMAP) == 0)
+ sep = '~';
+
/*
* The general case is to concatenate the new
* value onto the old value for multiple
- * rw(ro/root) properties. A special case
- * exists when either the old or new is the
- * "all" case. In the special case, if both
- * are "all", then it is "all", else if one is
- * an access-list, that replaces the "all".
+ * rw(ro/root/uidmap/gidmap) properties. For
+ * rw/ro/root a special case exists when either
+ * the old or new is the "all" case. In the
+ * special case, if both are "all", then it is
+ * "all", else if one is an access-list, that
+ * replaces the "all".
*/
if (strcmp(oldvalue, "*") == 0) {
/* Replace old value with new value. */
@@ -505,7 +519,7 @@ add_security_prop(struct securities *sec, char *name, char *value,
* access-list.
*/
newvalue = nfs_alistcat(oldvalue,
- value, ':');
+ value, sep);
}
if (newvalue != NULL) {
@@ -516,8 +530,8 @@ add_security_prop(struct securities *sec, char *name, char *value,
prop);
free(newvalue);
}
- if (oldvalue != NULL)
- sa_free_attr_string(oldvalue);
+
+ sa_free_attr_string(oldvalue);
}
} else {
prop = sa_create_property(name, value);
@@ -568,7 +582,7 @@ invalid_security(char *options)
value = strchr(token, '=');
if (value != NULL)
*value++ = '\0';
- if (strcmp(token, "sec") == 0) {
+ if (strcmp(token, SHOPT_SEC) == 0) {
/* HAVE security flavors so check them */
char *tok, *next;
for (next = NULL, tok = value; tok != NULL;
@@ -682,7 +696,6 @@ nfs_parse_legacy_options(sa_group_t group, char *options)
token = dup;
lasts = NULL;
while (token != NULL && ret == SA_OK) {
- ret = SA_OK;
token = strtok_r(base, ",", &lasts);
base = NULL;
if (token != NULL) {
@@ -697,8 +710,8 @@ nfs_parse_legacy_options(sa_group_t group, char *options)
if (value != NULL) {
*value++ = '\0';
}
- if (strcmp(token, "sec") == 0 ||
- strcmp(token, "secure") == 0) {
+ if (strcmp(token, SHOPT_SEC) == 0 ||
+ strcmp(token, SHOPT_SECURE) == 0) {
/*
* Once in security parsing, we only
* do security. We do need to move
@@ -714,7 +727,7 @@ nfs_parse_legacy_options(sa_group_t group, char *options)
*/
free_security_list(security_list);
}
- if (strcmp(token, "secure") == 0) {
+ if (strcmp(token, SHOPT_SECURE) == 0) {
value = "dh";
} else {
if (value == NULL) {
@@ -727,7 +740,7 @@ nfs_parse_legacy_options(sa_group_t group, char *options)
} else {
/*
* Note that the "old" syntax allowed a
- * default security model This must be
+ * default security model. This must be
* accounted for and internally converted to
* "standard" security structure.
*/
@@ -1195,6 +1208,10 @@ fill_security_from_secopts(struct secinfo *sp, sa_security_t secopts)
}
sp->s_rootid = val;
break;
+ case OPT_UIDMAP:
+ case OPT_GIDMAP:
+ sp->s_flags |= M_MAP;
+ break;
default:
break;
}
@@ -1264,6 +1281,7 @@ printarg(char *path, struct exportdata *ep)
if (sp->s_flags & M_RW) (void) printf("M_RW ");
if (sp->s_flags & M_RWL) (void) printf("M_RWL ");
if (sp->s_flags & M_NONE) (void) printf("M_NONE ");
+ if (sp->s_flags & M_MAP) (void) printf("M_MAP ");
if (sp->s_flags == 0) (void) printf("(none)");
(void) printf("\n");
(void) printf("\t\ts_window = %d\n", sp->s_window);
@@ -1391,8 +1409,7 @@ nfs_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr,
if (value == NULL) {
(void) snprintf(buff + curlen, buffsize - curlen,
- "%s%s", sep ? "," : "",
- name, value != NULL ? value : "");
+ "%s%s", sep ? "," : "", name);
} else {
(void) snprintf(buff + curlen, buffsize - curlen,
"%s%s=%s", sep ? "," : "",
@@ -1698,7 +1715,7 @@ check_public(sa_group_t group, sa_share_t skipshare)
}
/*
- * public_exists(handle, share)
+ * public_exists(handle, skipshare)
*
* check to see if public option is set on any other share than the
* one specified. Need to check zfs sub-groups as well as the top
@@ -1872,7 +1889,7 @@ nfs_enable_share(sa_share_t share)
sp[i].s_window = DEF_WIN;
sp[i].s_rootcnt = 0;
sp[i].s_rootnames = NULL;
- (void) fill_security_from_secopts(&sp[i], sec);
+ (void) fill_security_from_secopts(&sp[i], sec);
if (sec != NULL)
sa_free_derived_security(sec);
if (sectype != NULL)
@@ -1881,7 +1898,7 @@ nfs_enable_share(sa_share_t share)
}
/*
* when we get here, we can do the exportfs system call and
- * initiate thinsg. We probably want to enable the nfs.server
+ * initiate things. We probably want to enable the nfs.server
* service first if it isn't running within SMF.
*/
/* check nfs.server status and start if needed */
@@ -2095,6 +2112,56 @@ nfs_disable_share(sa_share_t share, char *path)
return (ret);
}
+static int
+check_user(char *value)
+{
+ int ret = SA_OK;
+
+ if (!is_a_number(value)) {
+ struct passwd *pw;
+ /*
+ * in this case it would have to be a
+ * user name
+ */
+ pw = getpwnam(value);
+ if (pw == NULL)
+ ret = SA_BAD_VALUE;
+ endpwent();
+ } else {
+ uint64_t intval;
+ intval = strtoull(value, NULL, 0);
+ if (intval > UID_MAX && intval != -1)
+ ret = SA_BAD_VALUE;
+ }
+
+ return (ret);
+}
+
+static int
+check_group(char *value)
+{
+ int ret = SA_OK;
+
+ if (!is_a_number(value)) {
+ struct group *gr;
+ /*
+ * in this case it would have to be a
+ * group name
+ */
+ gr = getgrnam(value);
+ if (gr == NULL)
+ ret = SA_BAD_VALUE;
+ endgrent();
+ } else {
+ uint64_t intval;
+ intval = strtoull(value, NULL, 0);
+ if (intval > UID_MAX && intval != -1)
+ ret = SA_BAD_VALUE;
+ }
+
+ return (ret);
+}
+
/*
* check_rorwnone(v1, v2, v3)
*
@@ -2162,11 +2229,13 @@ nfs_validate_property(sa_handle_t handle, sa_property_t property,
if (value != NULL) {
/* first basic type checking */
switch (optdefs[optindex].type) {
+
case OPT_TYPE_NUMBER:
/* check that the value is all digits */
if (!is_a_number(value))
ret = SA_BAD_VALUE;
break;
+
case OPT_TYPE_BOOLEAN:
if (strlen(value) == 0 ||
strcasecmp(value, "true") == 0 ||
@@ -2178,30 +2247,18 @@ nfs_validate_property(sa_handle_t handle, sa_property_t property,
ret = SA_BAD_VALUE;
}
break;
+
case OPT_TYPE_USER:
- if (!is_a_number(value)) {
- struct passwd *pw;
- /*
- * in this case it would have to be a
- * user name
- */
- pw = getpwnam(value);
- if (pw == NULL)
- ret = SA_BAD_VALUE;
- endpwent();
- } else {
- uint64_t intval;
- intval = strtoull(value, NULL, 0);
- if (intval > UID_MAX && intval != ~0)
- ret = SA_BAD_VALUE;
- }
+ ret = check_user(value);
break;
+
case OPT_TYPE_FILE:
if (strcmp(value, "..") == 0 ||
strchr(value, '/') != NULL) {
ret = SA_BAD_VALUE;
}
break;
+
case OPT_TYPE_ACCLIST: {
sa_property_t oprop1;
sa_property_t oprop2;
@@ -2257,6 +2314,7 @@ nfs_validate_property(sa_handle_t handle, sa_property_t property,
sa_free_attr_string(ovalue2);
break;
}
+
case OPT_TYPE_LOGTAG:
if (nfsl_getconfig_list(&configlist) == 0) {
int error;
@@ -2278,9 +2336,11 @@ nfs_validate_property(sa_handle_t handle, sa_property_t property,
ret = SA_CONFIG_ERR;
}
break;
+
case OPT_TYPE_STRING:
/* whatever is here should be ok */
break;
+
case OPT_TYPE_SECURITY:
/*
* The "sec" property isn't used in the
@@ -2290,6 +2350,99 @@ nfs_validate_property(sa_handle_t handle, sa_property_t property,
*/
ret = SA_NO_SUCH_PROP;
break;
+
+ case OPT_TYPE_MAPPING: {
+ char *p;
+ char *n;
+ char *c;
+ int (*f)(char *);
+
+ sa_security_t security;
+
+ /*
+ * mapping is only supported for sec=sys
+ */
+ ret = SA_CONFIG_ERR;
+ if (parent_group == NULL)
+ break;
+
+ for (security = sa_get_security(parent_group,
+ NULL, NULL); security != NULL;
+ security = sa_get_next_security(security)) {
+ char *type;
+ char *sectype;
+
+ type = sa_get_security_attr(security,
+ "type");
+ if (type == NULL)
+ continue;
+
+ if (strcmp(type, "nfs") != 0) {
+ sa_free_attr_string(type);
+ continue;
+ }
+ sa_free_attr_string(type);
+
+ sectype = sa_get_security_attr(security,
+ "sectype");
+ if (sectype == NULL)
+ continue;
+
+ if (strcmp(sectype, "sys") != 0) {
+ sa_free_attr_string(sectype);
+ ret = SA_CONFIG_ERR;
+ break;
+ }
+ sa_free_attr_string(sectype);
+ ret = SA_OK;
+ }
+
+ if (ret != SA_OK)
+ break;
+
+ assert(optindex == OPT_UIDMAP ||
+ optindex == OPT_GIDMAP);
+ f = optindex == OPT_UIDMAP ? check_user :
+ check_group;
+
+
+ p = strdup(value);
+ if (p == NULL)
+ ret = SA_BAD_VALUE;
+
+ for (c = p; ret == SA_OK && c != NULL; c = n) {
+ char *s;
+ char *t;
+
+ n = strchr(c, '~');
+ if (n != NULL)
+ *n++ = '\0';
+
+ s = strchr(c, ':');
+ if (s != NULL) {
+ *s++ = '\0';
+ t = strchr(s, ':');
+ if (t != NULL)
+ *t = '\0';
+ }
+
+ if (s == NULL || t == NULL)
+ ret = SA_BAD_VALUE;
+
+ if (ret == SA_OK && *c != '\0' &&
+ strcmp(c, "*") != 0)
+ ret = f(c);
+
+ if (ret == SA_OK && *s != '\0' &&
+ strcmp(s, "-1") != 0)
+ ret = f(s);
+ }
+
+ free(p);
+
+ break;
+ }
+
default:
break;
}
@@ -3048,7 +3201,7 @@ nfs_space_alias(char *space)
* Only the space named "default" is special. If it is used,
* the default needs to be looked up and the real name used.
* This is normally "sys" but could be changed. We always
- * change defautl to the real name.
+ * change default to the real name.
*/
if (strcmp(space, "default") == 0 &&
nfs_getseconfig_default(&secconf) == 0) {