aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c76
-rw-r--r--sys/fs/nfs/nfsid.h13
-rw-r--r--sys/fs/nfs/nfsrvstate.h1
-rw-r--r--sys/nfs/nfs_diskless.c44
4 files changed, 124 insertions, 10 deletions
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 78e2fbb72bdb..39d7cb447d6a 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -70,6 +70,7 @@ struct nfsreqhead nfsd_reqq;
int nfsrv_lease = NFSRV_LEASE;
int ncl_mbuf_mlen = MLEN;
int nfsrv_doflexfile = 0;
+bool nfs_nfsv4root = false;
NFSNAMEIDMUTEX;
NFSSOCKMUTEX;
extern int nfsrv_lughashsize;
@@ -80,6 +81,21 @@ extern struct nfsdevicehead nfsrv_devidhead;
extern struct nfsstatsv1 nfsstatsv1;
extern uint32_t nfs_srvmaxio;
+/*
+ * Define just enough NFSv4 id<-->name mappings to make things work
+ * until the nfsuserd(8) is running.
+ * XXX These name/ids must be kept the same as what is in /etc/passwd
+ * and /etc/group.
+ */
+struct nfs_prime_userd nfs_prime_userd[] = {
+ { NFSID_INITIALIZE, UID_NOBODY, GID_NOGROUP, NULL },
+ { NFSID_ADDUID, UID_ROOT, GID_NOGROUP, "root" },
+ { NFSID_ADDUID, UID_BIN, GID_NOGROUP, "bin" },
+ { NFSID_ADDGID, UID_NOBODY, GID_WHEEL, "wheel" },
+ { NFSID_ADDGID, UID_NOBODY, GID_OPERATOR, "operator" },
+ { 0, 0, 0, NULL },
+};
+
NFSD_VNET_DEFINE(int, nfsd_enable_stringtouid) = 0;
NFSD_VNET_DEFINE(struct nfssockreq, nfsrv_nfsuserdsock);
NFSD_VNET_DEFINE(nfsuserd_state, nfsrv_nfsuserd) = NOTRUNNING;
@@ -233,6 +249,7 @@ static int nfsrv_skipace(struct nfsrv_descript *nd, acl_type_t, int *acesizep);
static void nfsv4_wanted(struct nfsv4lock *lp);
static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
+static bool nfs_in_prime(int flag, uid_t uid, gid_t gid);
static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
int *, int *);
@@ -3667,7 +3684,8 @@ tryagain:
mtx_lock(&hp->mtx);
TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
if (usrp->lug_uid == uid) {
- if (usrp->lug_expiry < NFSD_MONOSEC)
+ if (!usrp->lug_wired &&
+ usrp->lug_expiry < NFSD_MONOSEC)
break;
/*
* If the name doesn't already have an '@'
@@ -3759,7 +3777,8 @@ tryagain:
mtx_lock(&hp->mtx);
TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
if (usrp->lug_uid == uid) {
- if (usrp->lug_expiry < NFSD_MONOSEC)
+ if (!usrp->lug_wired &&
+ usrp->lug_expiry < NFSD_MONOSEC)
break;
if (usrp->lug_cred != NULL) {
newcred = crhold(usrp->lug_cred);
@@ -3859,7 +3878,8 @@ tryagain:
TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
if (usrp->lug_namelen == len &&
!NFSBCMP(usrp->lug_name, str, len)) {
- if (usrp->lug_expiry < NFSD_MONOSEC)
+ if (!usrp->lug_wired &&
+ usrp->lug_expiry < NFSD_MONOSEC)
break;
hp2 = NFSUSERHASH(usrp->lug_uid);
mtx_lock(&hp2->mtx);
@@ -3936,7 +3956,8 @@ tryagain:
mtx_lock(&hp->mtx);
TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
if (usrp->lug_gid == gid) {
- if (usrp->lug_expiry < NFSD_MONOSEC)
+ if (!usrp->lug_wired &&
+ usrp->lug_expiry < NFSD_MONOSEC)
break;
/*
* If the name doesn't already have an '@'
@@ -4081,7 +4102,8 @@ tryagain:
TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
if (usrp->lug_namelen == len &&
!NFSBCMP(usrp->lug_name, str, len)) {
- if (usrp->lug_expiry < NFSD_MONOSEC)
+ if (!usrp->lug_wired &&
+ usrp->lug_expiry < NFSD_MONOSEC)
break;
hp2 = NFSGROUPHASH(usrp->lug_gid);
mtx_lock(&hp2->mtx);
@@ -4282,6 +4304,23 @@ out:
return (error);
}
+/* Check to see if the uid/gid is in the nfs_prime_userd list. */
+static bool
+nfs_in_prime(int flag, uid_t uid, gid_t gid)
+{
+ int i;
+
+ for (i = 0; nfs_prime_userd[i].flag != 0; i++) {
+ if ((nfs_prime_userd[i].flag & flag) == NFSID_ADDUID &&
+ nfs_prime_userd[i].uid == uid)
+ return (true);
+ if ((nfs_prime_userd[i].flag & flag) == NFSID_ADDGID &&
+ nfs_prime_userd[i].gid == gid)
+ return (true);
+ }
+ return (false);
+}
+
/*
* This function is called from the nfssvc(2) system call, to update the
* kernel user/group name list(s) for the V4 owner and ownergroup attributes.
@@ -4305,7 +4344,11 @@ nfssvc_idname(struct nfsd_idargs *nidp)
}
if (nidp->nid_flag & NFSID_INITIALIZE) {
cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
- error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
+ error = 0;
+ if ((nidp->nid_flag & NFSID_SYSSPACE) == 0)
+ error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
+ else
+ NFSBCOPY(nidp->nid_name, cp, nidp->nid_namelen);
if (error != 0) {
free(cp, M_NFSSTRING);
goto out;
@@ -4403,8 +4446,12 @@ nfssvc_idname(struct nfsd_idargs *nidp)
*/
newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
M_NFSUSERGROUP, M_WAITOK | M_ZERO);
- error = copyin(nidp->nid_name, newusrp->lug_name,
- nidp->nid_namelen);
+ error = 0;
+ if ((nidp->nid_flag & NFSID_SYSSPACE) == 0)
+ error = copyin(nidp->nid_name, newusrp->lug_name,
+ nidp->nid_namelen);
+ else
+ NFSBCOPY(nidp->nid_name, newusrp->lug_name, nidp->nid_namelen);
if (error == 0 && nidp->nid_ngroup > 0 &&
(nidp->nid_flag & NFSID_ADDUID) != 0) {
grps = NULL;
@@ -4522,7 +4569,11 @@ nfssvc_idname(struct nfsd_idargs *nidp)
newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
else
newusrp->lug_expiry = NFSD_MONOSEC + 5;
+ newusrp->lug_wired = false;
if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
+ if (nfs_nfsv4root && nfs_in_prime(NFSID_ADDUID, nidp->nid_uid,
+ nidp->nid_gid))
+ newusrp->lug_wired = true;
newusrp->lug_uid = nidp->nid_uid;
thp = NFSUSERHASH(newusrp->lug_uid);
mtx_assert(&thp->mtx, MA_OWNED);
@@ -4532,6 +4583,9 @@ nfssvc_idname(struct nfsd_idargs *nidp)
TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
+ if (nfs_nfsv4root && nfs_in_prime(NFSID_ADDGID, nidp->nid_uid,
+ nidp->nid_gid))
+ newusrp->lug_wired = true;
newusrp->lug_gid = nidp->nid_gid;
thp = NFSGROUPHASH(newusrp->lug_gid);
mtx_assert(&thp->mtx, MA_OWNED);
@@ -4580,7 +4634,8 @@ nfssvc_idname(struct nfsd_idargs *nidp)
TAILQ_FOREACH_SAFE(usrp,
&NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash,
nusrp)
- if (usrp->lug_expiry < NFSD_MONOSEC)
+ if (!usrp->lug_wired &&
+ usrp->lug_expiry < NFSD_MONOSEC)
nfsrv_removeuser(usrp, 1);
}
for (i = 0; i < nfsrv_lughashsize; i++) {
@@ -4610,7 +4665,8 @@ nfssvc_idname(struct nfsd_idargs *nidp)
TAILQ_FOREACH_SAFE(usrp,
&NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
nusrp)
- if (usrp->lug_expiry < NFSD_MONOSEC)
+ if (!usrp->lug_wired &&
+ usrp->lug_expiry < NFSD_MONOSEC)
nfsrv_removeuser(usrp, 0);
}
for (i = 0; i < nfsrv_lughashsize; i++) {
diff --git a/sys/fs/nfs/nfsid.h b/sys/fs/nfs/nfsid.h
index bd9807ca1acc..349fdecfc596 100644
--- a/sys/fs/nfs/nfsid.h
+++ b/sys/fs/nfs/nfsid.h
@@ -61,6 +61,19 @@ struct nfsd_idargs {
#define NFSID_SYSSPACE 0x0200
#if defined(_KERNEL) || defined(KERNEL)
+/*
+ * Define just enough NFSv4 id<-->name mappings to make things work
+ * until the nfsuserd(8) is running.
+ * XXX These name/ids must be kept the same as what is in /etc/passwd
+ * and /etc/group.
+ */
+struct nfs_prime_userd {
+ int flag;
+ uid_t uid;
+ gid_t gid;
+ char *nam;
+};
+
int nfssvc_idname(struct nfsd_idargs *);
#endif
diff --git a/sys/fs/nfs/nfsrvstate.h b/sys/fs/nfs/nfsrvstate.h
index cc19ed6fa1d2..858c52ec6218 100644
--- a/sys/fs/nfs/nfsrvstate.h
+++ b/sys/fs/nfs/nfsrvstate.h
@@ -317,6 +317,7 @@ struct nfsusrgrp {
} lug_un;
struct ucred *lug_cred; /* Cred. with groups list */
int lug_namelen; /* Name length */
+ bool lug_wired; /* Wired into cache */
u_char lug_name[1]; /* malloc'd correct length */
};
#define lug_uid lug_un.un_uid
diff --git a/sys/nfs/nfs_diskless.c b/sys/nfs/nfs_diskless.c
index d5278612d8d9..32dd7f3e997f 100644
--- a/sys/nfs/nfs_diskless.c
+++ b/sys/nfs/nfs_diskless.c
@@ -54,6 +54,7 @@
#include <nfs/nfsproto.h>
#include <nfsclient/nfs.h>
#include <nfs/nfsdiskless.h>
+#include <fs/nfs/nfsid.h>
#define NFS_IFACE_TIMEOUT_SECS 10 /* Timeout for interface to appear. */
@@ -70,6 +71,9 @@ struct nfs_diskless nfs_diskless = { { { 0 } } };
struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
int nfs_diskless_valid = 0;
+extern struct nfs_prime_userd nfs_prime_userd[];
+extern bool nfs_nfsv4root;
+
/*
* Validate/sanity check a rsize/wsize parameter.
*/
@@ -292,11 +296,51 @@ match_done:
return;
}
} else {
+ struct nfsd_idargs nid;
+ int ret;
+
/*
* For NFSv4, the file handle is derived from the
* boot.nfsroot.path during mounting by NFSv4.
*/
nd3->root_fhsize = 0;
+ nfs_nfsv4root = true;
+
+ /*
+ * Prime the id<-->name mappings just enough to
+ * make things work until the nfsuserd(8) daemon
+ * is started, if the nfsuserd_domain is set to a
+ * non-empty string.
+ */
+ if ((cp = kern_getenv("boot.nfsroot.user_domain")) !=
+ NULL) {
+ for (cnt = 0; *cp != '\0' &&
+ nfs_prime_userd[cnt].flag != 0; cnt++) {
+ nid.nid_flag =
+ nfs_prime_userd[cnt].flag |
+ NFSID_SYSSPACE;
+ if (nfs_prime_userd[cnt].flag ==
+ NFSID_INITIALIZE) {
+ nid.nid_name = cp;
+ nid.nid_usermax = 10;
+ } else {
+ nid.nid_name =
+ nfs_prime_userd[cnt].nam;
+ nid.nid_usertimeout = 3600;
+ }
+ nid.nid_namelen = strlen(nid.nid_name);
+ nid.nid_uid = nfs_prime_userd[cnt].uid;
+ nid.nid_gid = nfs_prime_userd[cnt].gid;
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
+ ret = nfssvc_idname(&nid);
+ if (ret != 0)
+ printf("nfs_diskless: "
+ "nfssvc_idname failed %d\n",
+ ret);
+ }
+ freeenv(cp);
+ }
}
if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
strncpy(nd3->root_hostnam, cp, MNAMELEN - 1);