summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/fs/nfs/nfs.h18
-rw-r--r--sys/fs/nfs/nfs_commonport.c22
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c683
-rw-r--r--sys/fs/nfs/nfs_var.h1
-rw-r--r--sys/fs/nfs/nfsrvstate.h17
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c26
-rw-r--r--sys/nfs/nfssvc.h1
7 files changed, 548 insertions, 220 deletions
diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h
index be60c1c..5781459 100644
--- a/sys/fs/nfs/nfs.h
+++ b/sys/fs/nfs/nfs.h
@@ -96,12 +96,6 @@
#define NFSSESSIONHASHSIZE 20 /* Size of server session hash table */
#endif
#define NFSSTATEHASHSIZE 10 /* Size of server stateid hash table */
-#ifndef NFSUSERHASHSIZE
-#define NFSUSERHASHSIZE 30 /* Size of user id hash table */
-#endif
-#ifndef NFSGROUPHASHSIZE
-#define NFSGROUPHASHSIZE 5 /* Size of group id hash table */
-#endif
#ifndef NFSCLDELEGHIGHWATER
#define NFSCLDELEGHIGHWATER 10000 /* limit for client delegations */
#endif
@@ -204,6 +198,18 @@ struct nfsd_idargs {
int nid_usertimeout;/* User name timeout (minutes) */
u_char *nid_name; /* Name */
int nid_namelen; /* and its length */
+ gid_t *nid_grps; /* and the list */
+ int nid_ngroup; /* Size of groups list */
+};
+
+struct nfsd_oidargs {
+ int nid_flag; /* Flags (see below) */
+ uid_t nid_uid; /* user/group id */
+ gid_t nid_gid;
+ int nid_usermax; /* Upper bound on user name cache */
+ int nid_usertimeout;/* User name timeout (minutes) */
+ u_char *nid_name; /* Name */
+ int nid_namelen; /* and its length */
};
struct nfsd_clid {
diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c
index 2406d34..4910c61 100644
--- a/sys/fs/nfs/nfs_commonport.c
+++ b/sys/fs/nfs/nfs_commonport.c
@@ -63,6 +63,7 @@ int nfs_numnfscbd = 0;
int nfscl_debuglevel = 0;
char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
struct callout newnfsd_callout;
+int nfsrv_lughashsize = 100;
void (*nfsd_call_servertimer)(void) = NULL;
void (*ncl_call_invalcaches)(struct vnode *) = NULL;
@@ -79,6 +80,9 @@ SYSCTL_STRING(_vfs_nfs, OID_AUTO, callback_addr, CTLFLAG_RW,
"NFSv4 callback addr for server to use");
SYSCTL_INT(_vfs_nfs, OID_AUTO, debuglevel, CTLFLAG_RW, &nfscl_debuglevel,
0, "Debug level for new nfs client");
+TUNABLE_INT("vfs.nfs.userhashsize", &nfsrv_lughashsize);
+SYSCTL_INT(_vfs_nfs, OID_AUTO, userhashsize, CTLFLAG_RDTUN, &nfsrv_lughashsize,
+ 0, "Size of hash tables for uid/name mapping");
/*
* Defines for malloc
@@ -445,9 +449,25 @@ nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred)
{
int error = EINVAL;
struct nfsd_idargs nid;
+ struct nfsd_oidargs onid;
if (uap->flag & NFSSVC_IDNAME) {
- error = copyin(uap->argp, (caddr_t)&nid, sizeof (nid));
+ if ((uap->flag & NFSSVC_NEWSTRUCT) != 0)
+ error = copyin(uap->argp, &nid, sizeof(nid));
+ else {
+ error = copyin(uap->argp, &onid, sizeof(onid));
+ if (error == 0) {
+ nid.nid_flag = onid.nid_flag;
+ nid.nid_uid = onid.nid_uid;
+ nid.nid_gid = onid.nid_gid;
+ nid.nid_usermax = onid.nid_usermax;
+ nid.nid_usertimeout = onid.nid_usertimeout;
+ nid.nid_name = onid.nid_name;
+ nid.nid_namelen = onid.nid_namelen;
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
+ }
+ }
if (error)
goto out;
error = nfssvc_idname(&nid);
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 6e0204b8..5b8bca3 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -44,6 +44,8 @@ __FBSDID("$FreeBSD$");
#include <fs/nfs/nfsport.h>
+#include <security/mac/mac_framework.h>
+
/*
* Data items converted to xdr at startup, since they are constant
* This is kinda hokey, but may save a little time doing byte swaps
@@ -68,6 +70,7 @@ int ncl_mbuf_mlen = MLEN;
int nfsd_enable_stringtouid = 0;
NFSNAMEIDMUTEX;
NFSSOCKMUTEX;
+extern int nfsrv_lughashsize;
/*
* This array of structures indicates, for V4:
@@ -154,11 +157,14 @@ static int nfsrv_usercnt = 0;
static int nfsrv_dnsnamelen;
static u_char *nfsrv_dnsname = NULL;
static int nfsrv_usermax = 999999999;
-static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
-static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
-static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
-static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
-static struct nfsuserlruhead nfsuserlruhead;
+struct nfsrv_lughash {
+ struct mtx mtx;
+ struct nfsuserhashhead lughead;
+};
+static struct nfsrv_lughash *nfsuserhash;
+static struct nfsrv_lughash *nfsusernamehash;
+static struct nfsrv_lughash *nfsgrouphash;
+static struct nfsrv_lughash *nfsgroupnamehash;
/*
* This static array indicates whether or not the RPC generates a large
@@ -177,7 +183,7 @@ static void nfsv4_wanted(struct nfsv4lock *lp);
static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
NFSPROC_T *p);
-static void nfsrv_removeuser(struct nfsusrgrp *usrp);
+static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
int *, int *);
static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
@@ -2541,18 +2547,17 @@ nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
u_char *cp = *cpp;
uid_t tmp;
int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
+ struct nfsrv_lughash *hp;
cnt = 0;
tryagain:
- NFSLOCKNAMEID();
- if (nfsrv_dnsname) {
+ if (nfsrv_dnsnamelen > 0) {
/*
* Always map nfsrv_defaultuid to "nobody".
*/
if (uid == nfsrv_defaultuid) {
i = nfsrv_dnsnamelen + 7;
if (i > len) {
- NFSUNLOCKNAMEID();
if (len > NFSV4_SMALLSTR)
free(cp, M_NFSSTRING);
cp = malloc(i, M_NFSSTRING, M_WAITOK);
@@ -2564,11 +2569,12 @@ tryagain:
NFSBCOPY("nobody@", cp, 7);
cp += 7;
NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
- NFSUNLOCKNAMEID();
return;
}
hasampersand = 0;
- LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
+ hp = NFSUSERHASH(uid);
+ mtx_lock(&hp->mtx);
+ TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
if (usrp->lug_uid == uid) {
if (usrp->lug_expiry < NFSD_MONOSEC)
break;
@@ -2588,7 +2594,7 @@ tryagain:
i = usrp->lug_namelen +
nfsrv_dnsnamelen + 1;
if (i > len) {
- NFSUNLOCKNAMEID();
+ mtx_unlock(&hp->mtx);
if (len > NFSV4_SMALLSTR)
free(cp, M_NFSSTRING);
cp = malloc(i, M_NFSSTRING, M_WAITOK);
@@ -2603,20 +2609,19 @@ tryagain:
*cp++ = '@';
NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
}
- TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
- TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
- NFSUNLOCKNAMEID();
+ TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
+ TAILQ_INSERT_TAIL(&hp->lughead, usrp,
+ lug_numhash);
+ mtx_unlock(&hp->mtx);
return;
}
}
- NFSUNLOCKNAMEID();
+ mtx_unlock(&hp->mtx);
cnt++;
ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
NULL, p);
if (ret == 0 && cnt < 2)
goto tryagain;
- } else {
- NFSUNLOCKNAMEID();
}
/*
@@ -2640,6 +2645,52 @@ tryagain:
}
/*
+ * Get a credential for the uid with the server's group list.
+ * If none is found, just return the credential passed in after
+ * logging a warning message.
+ */
+struct ucred *
+nfsrv_getgrpscred(struct ucred *oldcred)
+{
+ struct nfsusrgrp *usrp;
+ struct ucred *newcred;
+ int cnt, ret;
+ uid_t uid;
+ struct nfsrv_lughash *hp;
+
+ cnt = 0;
+ uid = oldcred->cr_uid;
+tryagain:
+ if (nfsrv_dnsnamelen > 0) {
+ hp = NFSUSERHASH(uid);
+ mtx_lock(&hp->mtx);
+ TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
+ if (usrp->lug_uid == uid) {
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ break;
+ if (usrp->lug_cred != NULL) {
+ newcred = crhold(usrp->lug_cred);
+ crfree(oldcred);
+ } else
+ newcred = oldcred;
+ TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
+ TAILQ_INSERT_TAIL(&hp->lughead, usrp,
+ lug_numhash);
+ mtx_unlock(&hp->mtx);
+ return (newcred);
+ }
+ }
+ mtx_unlock(&hp->mtx);
+ cnt++;
+ ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
+ NULL, curthread);
+ if (ret == 0 && cnt < 2)
+ goto tryagain;
+ }
+ return (oldcred);
+}
+
+/*
* Convert a string to a uid.
* If no conversion is possible return NFSERR_BADOWNER, otherwise
* return 0.
@@ -2657,6 +2708,7 @@ nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
int cnt, ret;
int error = 0;
uid_t tuid;
+ struct nfsrv_lughash *hp, *hp2;
if (len == 0) {
error = NFSERR_BADOWNER;
@@ -2686,49 +2738,55 @@ nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
cnt = 0;
tryagain:
- NFSLOCKNAMEID();
- /*
- * If an '@' is found and the domain name matches, search for the name
- * with dns stripped off.
- * Mixed case alpahbetics will match for the domain name, but all
- * upper case will not.
- */
- if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
- (len - 1 - i) == nfsrv_dnsnamelen &&
- !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
- len -= (nfsrv_dnsnamelen + 1);
- *(cp - 1) = '\0';
- }
-
- /*
- * Check for the special case of "nobody".
- */
- if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
- *uidp = nfsrv_defaultuid;
- NFSUNLOCKNAMEID();
- error = 0;
- goto out;
- }
-
- LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
- if (usrp->lug_namelen == len &&
- !NFSBCMP(usrp->lug_name, str, len)) {
- if (usrp->lug_expiry < NFSD_MONOSEC)
- break;
- *uidp = usrp->lug_uid;
- TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
- TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
- NFSUNLOCKNAMEID();
+ if (nfsrv_dnsnamelen > 0) {
+ /*
+ * If an '@' is found and the domain name matches, search for
+ * the name with dns stripped off.
+ * Mixed case alpahbetics will match for the domain name, but
+ * all upper case will not.
+ */
+ if (cnt == 0 && i < len && i > 0 &&
+ (len - 1 - i) == nfsrv_dnsnamelen &&
+ !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
+ len -= (nfsrv_dnsnamelen + 1);
+ *(cp - 1) = '\0';
+ }
+
+ /*
+ * Check for the special case of "nobody".
+ */
+ if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
+ *uidp = nfsrv_defaultuid;
error = 0;
goto out;
}
+
+ hp = NFSUSERNAMEHASH(str, len);
+ mtx_lock(&hp->mtx);
+ TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
+ if (usrp->lug_namelen == len &&
+ !NFSBCMP(usrp->lug_name, str, len)) {
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ break;
+ hp2 = NFSUSERHASH(usrp->lug_uid);
+ mtx_lock(&hp2->mtx);
+ TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
+ TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
+ lug_numhash);
+ *uidp = usrp->lug_uid;
+ mtx_unlock(&hp2->mtx);
+ mtx_unlock(&hp->mtx);
+ error = 0;
+ goto out;
+ }
+ }
+ mtx_unlock(&hp->mtx);
+ cnt++;
+ ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
+ str, p);
+ if (ret == 0 && cnt < 2)
+ goto tryagain;
}
- NFSUNLOCKNAMEID();
- cnt++;
- ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
- str, p);
- if (ret == 0 && cnt < 2)
- goto tryagain;
error = NFSERR_BADOWNER;
out:
@@ -2751,18 +2809,17 @@ nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
u_char *cp = *cpp;
gid_t tmp;
int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
+ struct nfsrv_lughash *hp;
cnt = 0;
tryagain:
- NFSLOCKNAMEID();
- if (nfsrv_dnsname) {
+ if (nfsrv_dnsnamelen > 0) {
/*
* Always map nfsrv_defaultgid to "nogroup".
*/
if (gid == nfsrv_defaultgid) {
i = nfsrv_dnsnamelen + 8;
if (i > len) {
- NFSUNLOCKNAMEID();
if (len > NFSV4_SMALLSTR)
free(cp, M_NFSSTRING);
cp = malloc(i, M_NFSSTRING, M_WAITOK);
@@ -2774,11 +2831,12 @@ tryagain:
NFSBCOPY("nogroup@", cp, 8);
cp += 8;
NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
- NFSUNLOCKNAMEID();
return;
}
hasampersand = 0;
- LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
+ hp = NFSGROUPHASH(gid);
+ mtx_lock(&hp->mtx);
+ TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
if (usrp->lug_gid == gid) {
if (usrp->lug_expiry < NFSD_MONOSEC)
break;
@@ -2798,7 +2856,7 @@ tryagain:
i = usrp->lug_namelen +
nfsrv_dnsnamelen + 1;
if (i > len) {
- NFSUNLOCKNAMEID();
+ mtx_unlock(&hp->mtx);
if (len > NFSV4_SMALLSTR)
free(cp, M_NFSSTRING);
cp = malloc(i, M_NFSSTRING, M_WAITOK);
@@ -2813,20 +2871,19 @@ tryagain:
*cp++ = '@';
NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
}
- TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
- TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
- NFSUNLOCKNAMEID();
+ TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
+ TAILQ_INSERT_TAIL(&hp->lughead, usrp,
+ lug_numhash);
+ mtx_unlock(&hp->mtx);
return;
}
}
- NFSUNLOCKNAMEID();
+ mtx_unlock(&hp->mtx);
cnt++;
ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
NULL, p);
if (ret == 0 && cnt < 2)
goto tryagain;
- } else {
- NFSUNLOCKNAMEID();
}
/*
@@ -2867,6 +2924,7 @@ nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
int cnt, ret;
int error = 0;
gid_t tgid;
+ struct nfsrv_lughash *hp, *hp2;
if (len == 0) {
error = NFSERR_BADOWNER;
@@ -2896,47 +2954,53 @@ nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
cnt = 0;
tryagain:
- NFSLOCKNAMEID();
- /*
- * If an '@' is found and the dns name matches, search for the name
- * with the dns stripped off.
- */
- if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
- (len - 1 - i) == nfsrv_dnsnamelen &&
- !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
- len -= (nfsrv_dnsnamelen + 1);
- *(cp - 1) = '\0';
- }
-
- /*
- * Check for the special case of "nogroup".
- */
- if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
- *gidp = nfsrv_defaultgid;
- NFSUNLOCKNAMEID();
- error = 0;
- goto out;
- }
-
- LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
- if (usrp->lug_namelen == len &&
- !NFSBCMP(usrp->lug_name, str, len)) {
- if (usrp->lug_expiry < NFSD_MONOSEC)
- break;
- *gidp = usrp->lug_gid;
- TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
- TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
- NFSUNLOCKNAMEID();
+ if (nfsrv_dnsnamelen > 0) {
+ /*
+ * If an '@' is found and the dns name matches, search for the
+ * name with the dns stripped off.
+ */
+ if (cnt == 0 && i < len && i > 0 &&
+ (len - 1 - i) == nfsrv_dnsnamelen &&
+ !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
+ len -= (nfsrv_dnsnamelen + 1);
+ *(cp - 1) = '\0';
+ }
+
+ /*
+ * Check for the special case of "nogroup".
+ */
+ if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
+ *gidp = nfsrv_defaultgid;
error = 0;
goto out;
}
+
+ hp = NFSGROUPNAMEHASH(str, len);
+ mtx_lock(&hp->mtx);
+ TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
+ if (usrp->lug_namelen == len &&
+ !NFSBCMP(usrp->lug_name, str, len)) {
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ break;
+ hp2 = NFSGROUPHASH(usrp->lug_gid);
+ mtx_lock(&hp2->mtx);
+ TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
+ TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
+ lug_numhash);
+ *gidp = usrp->lug_gid;
+ mtx_unlock(&hp2->mtx);
+ mtx_unlock(&hp->mtx);
+ error = 0;
+ goto out;
+ }
+ }
+ mtx_unlock(&hp->mtx);
+ cnt++;
+ ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
+ str, p);
+ if (ret == 0 && cnt < 2)
+ goto tryagain;
}
- NFSUNLOCKNAMEID();
- cnt++;
- ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
- str, p);
- if (ret == 0 && cnt < 2)
- goto tryagain;
error = NFSERR_BADOWNER;
out:
@@ -3094,111 +3158,218 @@ APPLESTATIC int
nfssvc_idname(struct nfsd_idargs *nidp)
{
struct nfsusrgrp *nusrp, *usrp, *newusrp;
- struct nfsuserhashhead *hp;
- int i;
+ struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
+ int i, group_locked, groupname_locked, user_locked, username_locked;
int error = 0;
u_char *cp;
+ gid_t *grps;
+ struct ucred *cr;
+ static int onethread = 0;
+ static time_t lasttime = 0;
if (nidp->nid_flag & NFSID_INITIALIZE) {
- cp = (u_char *)malloc(nidp->nid_namelen + 1,
- M_NFSSTRING, M_WAITOK);
- error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
- nidp->nid_namelen);
- NFSLOCKNAMEID();
- if (nfsrv_dnsname) {
+ cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
+ error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
+ nidp->nid_namelen);
+ if (error != 0) {
+ free(cp, M_NFSSTRING);
+ goto out;
+ }
+ if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
+ /*
+ * Free up all the old stuff and reinitialize hash
+ * lists. All mutexes for both lists must be locked,
+ * with the user/group name ones before the uid/gid
+ * ones, to avoid a LOR.
+ */
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsusernamehash[i].mtx);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsuserhash[i].mtx);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ TAILQ_FOREACH_SAFE(usrp,
+ &nfsuserhash[i].lughead, lug_numhash, nusrp)
+ nfsrv_removeuser(usrp, 1);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_unlock(&nfsuserhash[i].mtx);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_unlock(&nfsusernamehash[i].mtx);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsgroupnamehash[i].mtx);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsgrouphash[i].mtx);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ TAILQ_FOREACH_SAFE(usrp,
+ &nfsgrouphash[i].lughead, lug_numhash,
+ nusrp)
+ nfsrv_removeuser(usrp, 0);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_unlock(&nfsgrouphash[i].mtx);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_unlock(&nfsgroupnamehash[i].mtx);
+ free(nfsrv_dnsname, M_NFSSTRING);
+ nfsrv_dnsname = NULL;
+ }
+ if (nfsuserhash == NULL) {
+ /* Allocate the hash tables. */
+ nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
+ nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
+ M_ZERO);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
+ NULL, MTX_DEF | MTX_DUPOK);
+ nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
+ nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
+ M_ZERO);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_init(&nfsusernamehash[i].mtx,
+ "nfsusrhash", NULL, MTX_DEF |
+ MTX_DUPOK);
+ nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
+ nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
+ M_ZERO);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
+ NULL, MTX_DEF | MTX_DUPOK);
+ nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
+ nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
+ M_ZERO);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_init(&nfsgroupnamehash[i].mtx,
+ "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
+ }
+ /* (Re)initialize the list heads. */
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ TAILQ_INIT(&nfsuserhash[i].lughead);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ TAILQ_INIT(&nfsusernamehash[i].lughead);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ TAILQ_INIT(&nfsgrouphash[i].lughead);
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ TAILQ_INIT(&nfsgroupnamehash[i].lughead);
+
/*
- * Free up all the old stuff and reinitialize hash lists.
+ * Put name in "DNS" string.
*/
- TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
- nfsrv_removeuser(usrp);
- }
- free(nfsrv_dnsname, M_NFSSTRING);
- nfsrv_dnsname = NULL;
- }
- TAILQ_INIT(&nfsuserlruhead);
- for (i = 0; i < NFSUSERHASHSIZE; i++)
- LIST_INIT(&nfsuserhash[i]);
- for (i = 0; i < NFSGROUPHASHSIZE; i++)
- LIST_INIT(&nfsgrouphash[i]);
- for (i = 0; i < NFSUSERHASHSIZE; i++)
- LIST_INIT(&nfsusernamehash[i]);
- for (i = 0; i < NFSGROUPHASHSIZE; i++)
- LIST_INIT(&nfsgroupnamehash[i]);
-
- /*
- * Put name in "DNS" string.
- */
- if (!error) {
nfsrv_dnsname = cp;
- nfsrv_dnsnamelen = nidp->nid_namelen;
nfsrv_defaultuid = nidp->nid_uid;
nfsrv_defaultgid = nidp->nid_gid;
nfsrv_usercnt = 0;
nfsrv_usermax = nidp->nid_usermax;
- }
- NFSUNLOCKNAMEID();
- if (error)
- free(cp, M_NFSSTRING);
- goto out;
+ atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
+ goto out;
}
/*
* malloc the new one now, so any potential sleep occurs before
* manipulation of the lists.
*/
- MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
- nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
+ newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
+ M_NFSUSERGROUP, M_WAITOK | M_ZERO);
error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
nidp->nid_namelen);
+ if (error == 0 && nidp->nid_ngroup > 0 &&
+ (nidp->nid_flag & NFSID_ADDUID) != 0) {
+ grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
+ M_WAITOK);
+ error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
+ sizeof(gid_t) * nidp->nid_ngroup);
+ if (error == 0) {
+ /*
+ * Create a credential just like svc_getcred(),
+ * but using the group list provided.
+ */
+ cr = crget();
+ cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
+ crsetgroups(cr, nidp->nid_ngroup, grps);
+ cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
+ cr->cr_prison = &prison0;
+ prison_hold(cr->cr_prison);
+#ifdef MAC
+ mac_cred_associate_nfsd(cr);
+#endif
+ newusrp->lug_cred = cr;
+ }
+ free(grps, M_TEMP);
+ }
if (error) {
- free((caddr_t)newusrp, M_NFSUSERGROUP);
+ free(newusrp, M_NFSUSERGROUP);
goto out;
}
newusrp->lug_namelen = nidp->nid_namelen;
- NFSLOCKNAMEID();
+ /*
+ * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
+ * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
+ * The flags user_locked, username_locked, group_locked and
+ * groupname_locked are set to indicate all of those hash lists are
+ * locked. hp_name != NULL and hp_idnum != NULL indicates that
+ * the respective one mutex is locked.
+ */
+ user_locked = username_locked = group_locked = groupname_locked = 0;
+ hp_name = hp_idnum = NULL;
+
/*
* Delete old entries, as required.
*/
if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
- hp = NFSUSERHASH(nidp->nid_uid);
- LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
+ /* Must lock all username hash lists first, to avoid a LOR. */
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsusernamehash[i].mtx);
+ username_locked = 1;
+ hp_idnum = NFSUSERHASH(nidp->nid_uid);
+ mtx_lock(&hp_idnum->mtx);
+ TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
+ nusrp) {
if (usrp->lug_uid == nidp->nid_uid)
- nfsrv_removeuser(usrp);
+ nfsrv_removeuser(usrp, 1);
}
- }
- if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
- hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
- LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
+ } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
+ hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
+ newusrp->lug_namelen);
+ mtx_lock(&hp_name->mtx);
+ TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
+ nusrp) {
if (usrp->lug_namelen == newusrp->lug_namelen &&
!NFSBCMP(usrp->lug_name, newusrp->lug_name,
- usrp->lug_namelen))
- nfsrv_removeuser(usrp);
+ usrp->lug_namelen)) {
+ thp = NFSUSERHASH(usrp->lug_uid);
+ mtx_lock(&thp->mtx);
+ nfsrv_removeuser(usrp, 1);
+ mtx_unlock(&thp->mtx);
+ }
}
- }
- if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
- hp = NFSGROUPHASH(nidp->nid_gid);
- LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
+ hp_idnum = NFSUSERHASH(nidp->nid_uid);
+ mtx_lock(&hp_idnum->mtx);
+ } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
+ /* Must lock all groupname hash lists first, to avoid a LOR. */
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsgroupnamehash[i].mtx);
+ groupname_locked = 1;
+ hp_idnum = NFSGROUPHASH(nidp->nid_gid);
+ mtx_lock(&hp_idnum->mtx);
+ TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
+ nusrp) {
if (usrp->lug_gid == nidp->nid_gid)
- nfsrv_removeuser(usrp);
+ nfsrv_removeuser(usrp, 0);
}
- }
- if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
- hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
- LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
+ } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
+ hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
+ newusrp->lug_namelen);
+ mtx_lock(&hp_name->mtx);
+ TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
+ nusrp) {
if (usrp->lug_namelen == newusrp->lug_namelen &&
!NFSBCMP(usrp->lug_name, newusrp->lug_name,
- usrp->lug_namelen))
- nfsrv_removeuser(usrp);
+ usrp->lug_namelen)) {
+ thp = NFSGROUPHASH(usrp->lug_gid);
+ mtx_lock(&thp->mtx);
+ nfsrv_removeuser(usrp, 0);
+ mtx_unlock(&thp->mtx);
+ }
}
- }
- TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
- if (usrp->lug_expiry < NFSD_MONOSEC)
- nfsrv_removeuser(usrp);
- }
- while (nfsrv_usercnt >= nfsrv_usermax) {
- usrp = TAILQ_FIRST(&nfsuserlruhead);
- nfsrv_removeuser(usrp);
+ hp_idnum = NFSGROUPHASH(nidp->nid_gid);
+ mtx_lock(&hp_idnum->mtx);
}
/*
@@ -3210,23 +3381,129 @@ nfssvc_idname(struct nfsd_idargs *nidp)
newusrp->lug_expiry = NFSD_MONOSEC + 5;
if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
newusrp->lug_uid = nidp->nid_uid;
- LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
- lug_numhash);
- LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
- newusrp->lug_namelen), newusrp, lug_namehash);
- TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
- nfsrv_usercnt++;
+ thp = NFSUSERHASH(newusrp->lug_uid);
+ mtx_assert(&thp->mtx, MA_OWNED);
+ TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
+ thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
+ mtx_assert(&thp->mtx, MA_OWNED);
+ TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
+ atomic_add_int(&nfsrv_usercnt, 1);
} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
newusrp->lug_gid = nidp->nid_gid;
- LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
- lug_numhash);
- LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
- newusrp->lug_namelen), newusrp, lug_namehash);
- TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
- nfsrv_usercnt++;
- } else
- FREE((caddr_t)newusrp, M_NFSUSERGROUP);
- NFSUNLOCKNAMEID();
+ thp = NFSGROUPHASH(newusrp->lug_gid);
+ mtx_assert(&thp->mtx, MA_OWNED);
+ TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
+ thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
+ mtx_assert(&thp->mtx, MA_OWNED);
+ TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
+ atomic_add_int(&nfsrv_usercnt, 1);
+ } else {
+ if (newusrp->lug_cred != NULL)
+ crfree(newusrp->lug_cred);
+ free(newusrp, M_NFSUSERGROUP);
+ }
+
+ /*
+ * Once per second, allow one thread to trim the cache.
+ */
+ if (lasttime < NFSD_MONOSEC &&
+ atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
+ /*
+ * First, unlock the single mutexes, so that all entries
+ * can be locked and any LOR is avoided.
+ */
+ if (hp_name != NULL) {
+ mtx_unlock(&hp_name->mtx);
+ hp_name = NULL;
+ }
+ if (hp_idnum != NULL) {
+ mtx_unlock(&hp_idnum->mtx);
+ hp_idnum = NULL;
+ }
+
+ if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
+ NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
+ if (username_locked == 0) {
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsusernamehash[i].mtx);
+ username_locked = 1;
+ }
+ KASSERT(user_locked == 0,
+ ("nfssvc_idname: user_locked"));
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsuserhash[i].mtx);
+ user_locked = 1;
+ for (i = 0; i < nfsrv_lughashsize; i++) {
+ TAILQ_FOREACH_SAFE(usrp,
+ &nfsuserhash[i].lughead, lug_numhash,
+ nusrp)
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ nfsrv_removeuser(usrp, 1);
+ }
+ for (i = 0; i < nfsrv_lughashsize; i++) {
+ /*
+ * Trim the cache using an approximate LRU
+ * algorithm. This code deletes the least
+ * recently used entry on each hash list.
+ */
+ if (nfsrv_usercnt <= nfsrv_usermax)
+ break;
+ usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
+ if (usrp != NULL)
+ nfsrv_removeuser(usrp, 1);
+ }
+ } else {
+ if (groupname_locked == 0) {
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsgroupnamehash[i].mtx);
+ groupname_locked = 1;
+ }
+ KASSERT(group_locked == 0,
+ ("nfssvc_idname: group_locked"));
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_lock(&nfsgrouphash[i].mtx);
+ group_locked = 1;
+ for (i = 0; i < nfsrv_lughashsize; i++) {
+ TAILQ_FOREACH_SAFE(usrp,
+ &nfsgrouphash[i].lughead, lug_numhash,
+ nusrp)
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ nfsrv_removeuser(usrp, 0);
+ }
+ for (i = 0; i < nfsrv_lughashsize; i++) {
+ /*
+ * Trim the cache using an approximate LRU
+ * algorithm. This code deletes the least
+ * recently user entry on each hash list.
+ */
+ if (nfsrv_usercnt <= nfsrv_usermax)
+ break;
+ usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
+ if (usrp != NULL)
+ nfsrv_removeuser(usrp, 0);
+ }
+ }
+ lasttime = NFSD_MONOSEC;
+ atomic_store_rel_int(&onethread, 0);
+ }
+
+ /* Now, unlock all locked mutexes. */
+ if (hp_idnum != NULL)
+ mtx_unlock(&hp_idnum->mtx);
+ if (hp_name != NULL)
+ mtx_unlock(&hp_name->mtx);
+ if (user_locked != 0)
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_unlock(&nfsuserhash[i].mtx);
+ if (username_locked != 0)
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_unlock(&nfsusernamehash[i].mtx);
+ if (group_locked != 0)
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_unlock(&nfsgrouphash[i].mtx);
+ if (groupname_locked != 0)
+ for (i = 0; i < nfsrv_lughashsize; i++)
+ mtx_unlock(&nfsgroupnamehash[i].mtx);
out:
NFSEXITCODE(error);
return (error);
@@ -3236,15 +3513,29 @@ out:
* Remove a user/group name element.
*/
static void
-nfsrv_removeuser(struct nfsusrgrp *usrp)
+nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
{
-
- NFSNAMEIDREQUIRED();
- LIST_REMOVE(usrp, lug_numhash);
- LIST_REMOVE(usrp, lug_namehash);
- TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
- nfsrv_usercnt--;
- FREE((caddr_t)usrp, M_NFSUSERGROUP);
+ struct nfsrv_lughash *hp;
+
+ if (isuser != 0) {
+ hp = NFSUSERHASH(usrp->lug_uid);
+ mtx_assert(&hp->mtx, MA_OWNED);
+ TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
+ hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
+ mtx_assert(&hp->mtx, MA_OWNED);
+ TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
+ } else {
+ hp = NFSGROUPHASH(usrp->lug_gid);
+ mtx_assert(&hp->mtx, MA_OWNED);
+ TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
+ hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
+ mtx_assert(&hp->mtx, MA_OWNED);
+ TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
+ }
+ atomic_add_int(&nfsrv_usercnt, -1);
+ if (usrp->lug_cred != NULL)
+ crfree(usrp->lug_cred);
+ free(usrp, M_NFSUSERGROUP);
}
/*
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index d540dc9..49ac769 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -296,6 +296,7 @@ void nfsv4_setsequence(struct nfsmount *, struct nfsrv_descript *,
int nfsv4_sequencelookup(struct nfsmount *, struct nfsclsession *, int *,
int *, uint32_t *, uint8_t *);
void nfsv4_freeslot(struct nfsclsession *, int);
+struct ucred *nfsrv_getgrpscred(struct ucred *);
/* nfs_clcomsubs.c */
void nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int);
diff --git a/sys/fs/nfs/nfsrvstate.h b/sys/fs/nfs/nfsrvstate.h
index 972fffe..6d32244 100644
--- a/sys/fs/nfs/nfsrvstate.h
+++ b/sys/fs/nfs/nfsrvstate.h
@@ -48,23 +48,22 @@ LIST_HEAD(nfssessionhashhead, nfsdsession);
/*
* List head for nfsusrgrp.
*/
-LIST_HEAD(nfsuserhashhead, nfsusrgrp);
-TAILQ_HEAD(nfsuserlruhead, nfsusrgrp);
+TAILQ_HEAD(nfsuserhashhead, nfsusrgrp);
#define NFSCLIENTHASH(id) \
(&nfsclienthash[(id).lval[1] % nfsrv_clienthashsize])
#define NFSSTATEHASH(clp, id) \
(&((clp)->lc_stateid[(id).other[2] % nfsrv_statehashsize]))
#define NFSUSERHASH(id) \
- (&nfsuserhash[(id) % NFSUSERHASHSIZE])
+ (&nfsuserhash[(id) % nfsrv_lughashsize])
#define NFSUSERNAMEHASH(p, l) \
(&nfsusernamehash[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \
- % NFSUSERHASHSIZE])
+ % nfsrv_lughashsize])
#define NFSGROUPHASH(id) \
- (&nfsgrouphash[(id) % NFSGROUPHASHSIZE])
+ (&nfsgrouphash[(id) % nfsrv_lughashsize])
#define NFSGROUPNAMEHASH(p, l) \
(&nfsgroupnamehash[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \
- % NFSGROUPHASHSIZE])
+ % nfsrv_lughashsize])
struct nfssessionhash {
struct mtx mtx;
@@ -264,14 +263,14 @@ struct nfslockfile {
* names.
*/
struct nfsusrgrp {
- TAILQ_ENTRY(nfsusrgrp) lug_lru; /* LRU list */
- LIST_ENTRY(nfsusrgrp) lug_numhash; /* Hash by id# */
- LIST_ENTRY(nfsusrgrp) lug_namehash; /* and by name */
+ TAILQ_ENTRY(nfsusrgrp) lug_numhash; /* Hash by id# */
+ TAILQ_ENTRY(nfsusrgrp) lug_namehash; /* and by name */
time_t lug_expiry; /* Expiry time in sec */
union {
uid_t un_uid; /* id# */
gid_t un_gid;
} lug_un;
+ struct ucred *lug_cred; /* Cred. with groups list */
int lug_namelen; /* Name length */
u_char lug_name[1]; /* malloc'd correct length */
};
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index a700ee9..99fbf4d 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -2644,14 +2644,24 @@ nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp,
* Fsinfo RPC. If set for anything else, this code might need
* to change.)
*/
- if (NFSVNO_EXPORTED(exp) &&
- ((!(nd->nd_flag & ND_GSS) && nd->nd_cred->cr_uid == 0) ||
- NFSVNO_EXPORTANON(exp) ||
- (nd->nd_flag & ND_AUTHNONE))) {
- nd->nd_cred->cr_uid = credanon->cr_uid;
- nd->nd_cred->cr_gid = credanon->cr_gid;
- crsetgroups(nd->nd_cred, credanon->cr_ngroups,
- credanon->cr_groups);
+ if (NFSVNO_EXPORTED(exp)) {
+ if (((nd->nd_flag & ND_GSS) == 0 && nd->nd_cred->cr_uid == 0) ||
+ NFSVNO_EXPORTANON(exp) ||
+ (nd->nd_flag & ND_AUTHNONE) != 0) {
+ nd->nd_cred->cr_uid = credanon->cr_uid;
+ nd->nd_cred->cr_gid = credanon->cr_gid;
+ crsetgroups(nd->nd_cred, credanon->cr_ngroups,
+ credanon->cr_groups);
+ } else if ((nd->nd_flag & ND_GSS) == 0) {
+ /*
+ * If using AUTH_SYS, call nfsrv_getgrpscred() to see
+ * if there is a replacement credential with a group
+ * list set up by "nfsuserd -manage-gids".
+ * If there is no replacement, nfsrv_getgrpscred()
+ * simply returns its argument.
+ */
+ nd->nd_cred = nfsrv_getgrpscred(nd->nd_cred);
+ }
}
out:
diff --git a/sys/nfs/nfssvc.h b/sys/nfs/nfssvc.h
index 65b1681..a194ed5 100644
--- a/sys/nfs/nfssvc.h
+++ b/sys/nfs/nfssvc.h
@@ -69,6 +69,7 @@
#define NFSSVC_SUSPENDNFSD 0x04000000
#define NFSSVC_RESUMENFSD 0x08000000
#define NFSSVC_DUMPMNTOPTS 0x10000000
+#define NFSSVC_NEWSTRUCT 0x20000000
/* Argument structure for NFSSVC_DUMPMNTOPTS. */
struct nfscl_dumpmntopts {
OpenPOWER on IntegriCloud