Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/nfs/nfs_commonsubs.c
Show First 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | |||||
/* And other global data */ | /* And other global data */ | ||||
nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, | nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, | ||||
NFFIFO, NFNON }; | NFFIFO, NFNON }; | ||||
enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; | enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; | ||||
enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; | enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; | ||||
struct timeval nfsboottime; /* Copy boottime once, so it never changes */ | struct timeval nfsboottime; /* Copy boottime once, so it never changes */ | ||||
int nfscl_ticks; | int nfscl_ticks; | ||||
int nfsrv_useacl = 1; | int nfsrv_useacl = 1; | ||||
struct nfssockreq nfsrv_nfsuserdsock; | |||||
nfsuserd_state nfsrv_nfsuserd = NOTRUNNING; | |||||
static int nfsrv_userdupcalls = 0; | |||||
struct nfsreqhead nfsd_reqq; | struct nfsreqhead nfsd_reqq; | ||||
uid_t nfsrv_defaultuid = UID_NOBODY; | |||||
gid_t nfsrv_defaultgid = GID_NOGROUP; | |||||
int nfsrv_lease = NFSRV_LEASE; | int nfsrv_lease = NFSRV_LEASE; | ||||
int ncl_mbuf_mlen = MLEN; | int ncl_mbuf_mlen = MLEN; | ||||
int nfsd_enable_stringtouid = 0; | |||||
int nfsrv_doflexfile = 0; | int nfsrv_doflexfile = 0; | ||||
static int nfs_enable_uidtostring = 0; | |||||
NFSNAMEIDMUTEX; | NFSNAMEIDMUTEX; | ||||
NFSSOCKMUTEX; | NFSSOCKMUTEX; | ||||
extern int nfsrv_lughashsize; | extern int nfsrv_lughashsize; | ||||
extern struct mtx nfsrv_dslock_mtx; | extern struct mtx nfsrv_dslock_mtx; | ||||
extern volatile int nfsrv_devidcnt; | extern volatile int nfsrv_devidcnt; | ||||
extern int nfscl_debuglevel; | extern int nfscl_debuglevel; | ||||
extern struct nfsdevicehead nfsrv_devidhead; | extern struct nfsdevicehead nfsrv_devidhead; | ||||
extern struct nfsstatsv1 nfsstatsv1; | extern struct nfsstatsv1 nfsstatsv1; | ||||
extern uint32_t nfs_srvmaxio; | extern uint32_t nfs_srvmaxio; | ||||
NFSD_VNET_DEFINE(int, nfsd_enable_stringtouid) = 0; | |||||
NFSD_VNET_DEFINE(struct nfssockreq, nfsrv_nfsuserdsock); | |||||
NFSD_VNET_DEFINE(nfsuserd_state, nfsrv_nfsuserd) = NOTRUNNING; | |||||
NFSD_VNET_DEFINE(uid_t, nfsrv_defaultuid) = UID_NOBODY; | |||||
NFSD_VNET_DEFINE(gid_t, nfsrv_defaultgid) = GID_NOGROUP; | |||||
NFSD_VNET_DEFINE_STATIC(int, nfsrv_userdupcalls) = 0; | |||||
SYSCTL_DECL(_vfs_nfs); | SYSCTL_DECL(_vfs_nfs); | ||||
SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW, | |||||
&nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names"); | |||||
NFSD_VNET_DEFINE_STATIC(int, nfs_enable_uidtostring) = 0; | |||||
SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, | |||||
CTLFLAG_NFSD_VNET | CTLFLAG_RW, &NFSD_VNET_NAME(nfs_enable_uidtostring), 0, | |||||
"Make nfs always send numeric owner_names"); | |||||
int nfsrv_maxpnfsmirror = 1; | int nfsrv_maxpnfsmirror = 1; | ||||
SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD, | SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD, | ||||
&nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service"); | &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service"); | ||||
/* | /* | ||||
* This array of structures indicates, for V4: | * This array of structures indicates, for V4: | ||||
* retfh - which of 3 types of calling args are used | * retfh - which of 3 types of calling args are used | ||||
* 0 - doesn't change cfh or use a sfh | * 0 - doesn't change cfh or use a sfh | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = { | ||||
{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */ | { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */ | ||||
{ 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */ | { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */ | ||||
{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */ | { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */ | ||||
{ 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */ | { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */ | ||||
{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */ | { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */ | ||||
}; | }; | ||||
static int ncl_mbuf_mhlen = MHLEN; | static int ncl_mbuf_mhlen = MHLEN; | ||||
static int nfsrv_usercnt = 0; | |||||
static int nfsrv_dnsnamelen; | |||||
static u_char *nfsrv_dnsname = NULL; | |||||
static int nfsrv_usermax = 999999999; | |||||
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; | |||||
NFSD_VNET_DEFINE_STATIC(int, nfsrv_usercnt) = 0; | |||||
NFSD_VNET_DEFINE_STATIC(int, nfsrv_dnsnamelen) = 0; | |||||
NFSD_VNET_DEFINE_STATIC(int, nfsrv_usermax) = 999999999; | |||||
NFSD_VNET_DEFINE(struct nfsrv_lughash *, nfsuserhash) = NULL; | |||||
NFSD_VNET_DEFINE(struct nfsrv_lughash *, nfsusernamehash) = NULL; | |||||
NFSD_VNET_DEFINE(struct nfsrv_lughash *, nfsgrouphash) = NULL; | |||||
NFSD_VNET_DEFINE(struct nfsrv_lughash *, nfsgroupnamehash) = NULL; | |||||
NFSD_VNET_DEFINE(u_char *, nfsrv_dnsname) = NULL; | |||||
/* | /* | ||||
* This static array indicates whether or not the RPC generates a large | * This static array indicates whether or not the RPC generates a large | ||||
* reply. This is used by nfs_reply() to decide whether or not an mbuf | * reply. This is used by nfs_reply() to decide whether or not an mbuf | ||||
* cluster should be allocated. (If a cluster is required by an RPC | * cluster should be allocated. (If a cluster is required by an RPC | ||||
* marked 0 in this array, the code will still work, just not quite as | * marked 0 in this array, the code will still work, just not quite as | ||||
* efficiently.) | * efficiently.) | ||||
*/ | */ | ||||
static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, | static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, | ||||
▲ Show 20 Lines • Show All 1,024 Lines • ▼ Show 20 Lines | nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, | ||||
u_int32_t freenum = 0, tuint; | u_int32_t freenum = 0, tuint; | ||||
u_int64_t uquad = 0, thyp, thyp2; | u_int64_t uquad = 0, thyp, thyp2; | ||||
#ifdef QUOTA | #ifdef QUOTA | ||||
struct dqblk dqb; | struct dqblk dqb; | ||||
uid_t savuid; | uid_t savuid; | ||||
#endif | #endif | ||||
CTASSERT(sizeof(ino_t) == sizeof(uint64_t)); | CTASSERT(sizeof(ino_t) == sizeof(uint64_t)); | ||||
NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); | |||||
if (compare) { | if (compare) { | ||||
retnotsup = 0; | retnotsup = 0; | ||||
error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); | error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); | ||||
} else { | } else { | ||||
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); | error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); | ||||
} | } | ||||
if (error) | if (error) | ||||
goto nfsmout; | goto nfsmout; | ||||
▲ Show 20 Lines • Show All 609 Lines • ▼ Show 20 Lines | case NFSATTRBIT_OWNER: | ||||
if (compare) { | if (compare) { | ||||
if (!(*retcmpp)) { | if (!(*retcmpp)) { | ||||
if (nfsv4_strtouid(nd, cp, j, &uid) || | if (nfsv4_strtouid(nd, cp, j, &uid) || | ||||
nap->na_uid != uid) | nap->na_uid != uid) | ||||
*retcmpp = NFSERR_NOTSAME; | *retcmpp = NFSERR_NOTSAME; | ||||
} | } | ||||
} else if (nap != NULL) { | } else if (nap != NULL) { | ||||
if (nfsv4_strtouid(nd, cp, j, &uid)) | if (nfsv4_strtouid(nd, cp, j, &uid)) | ||||
nap->na_uid = nfsrv_defaultuid; | nap->na_uid = | ||||
NFSD_VNET(nfsrv_defaultuid); | |||||
else | else | ||||
nap->na_uid = uid; | nap->na_uid = uid; | ||||
} | } | ||||
if (j > NFSV4_SMALLSTR) | if (j > NFSV4_SMALLSTR) | ||||
free(cp, M_NFSSTRING); | free(cp, M_NFSSTRING); | ||||
break; | break; | ||||
case NFSATTRBIT_OWNERGROUP: | case NFSATTRBIT_OWNERGROUP: | ||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); | NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); | ||||
Show All 16 Lines | case NFSATTRBIT_OWNERGROUP: | ||||
if (compare) { | if (compare) { | ||||
if (!(*retcmpp)) { | if (!(*retcmpp)) { | ||||
if (nfsv4_strtogid(nd, cp, j, &gid) || | if (nfsv4_strtogid(nd, cp, j, &gid) || | ||||
nap->na_gid != gid) | nap->na_gid != gid) | ||||
*retcmpp = NFSERR_NOTSAME; | *retcmpp = NFSERR_NOTSAME; | ||||
} | } | ||||
} else if (nap != NULL) { | } else if (nap != NULL) { | ||||
if (nfsv4_strtogid(nd, cp, j, &gid)) | if (nfsv4_strtogid(nd, cp, j, &gid)) | ||||
nap->na_gid = nfsrv_defaultgid; | nap->na_gid = | ||||
NFSD_VNET(nfsrv_defaultgid); | |||||
else | else | ||||
nap->na_gid = gid; | nap->na_gid = gid; | ||||
} | } | ||||
if (j > NFSV4_SMALLSTR) | if (j > NFSV4_SMALLSTR) | ||||
free(cp, M_NFSSTRING); | free(cp, M_NFSSTRING); | ||||
break; | break; | ||||
case NFSATTRBIT_QUOTAHARD: | case NFSATTRBIT_QUOTAHARD: | ||||
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); | NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); | ||||
▲ Show 20 Lines • Show All 346 Lines • ▼ Show 20 Lines | #endif /* QUOTA */ | ||||
if (attrsum > attrsize) { | if (attrsum > attrsize) { | ||||
error = NFSERR_BADXDR; | error = NFSERR_BADXDR; | ||||
} else { | } else { | ||||
attrsize = NFSM_RNDUP(attrsize); | attrsize = NFSM_RNDUP(attrsize); | ||||
if (attrsum < attrsize) | if (attrsum < attrsize) | ||||
error = nfsm_advance(nd, attrsize - attrsum, -1); | error = nfsm_advance(nd, attrsize - attrsum, -1); | ||||
} | } | ||||
nfsmout: | nfsmout: | ||||
NFSD_CURVNET_RESTORE(); | |||||
NFSEXITCODE2(error, nd); | NFSEXITCODE2(error, nd); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Implement sleep locks for newnfs. The nfslock_usecnt allows for a | * Implement sleep locks for newnfs. The nfslock_usecnt allows for a | ||||
* shared lock and the NFSXXX_LOCK flag permits an exclusive lock. | * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. | ||||
* The first argument is a pointer to an nfsv4lock structure. | * The first argument is a pointer to an nfsv4lock structure. | ||||
▲ Show 20 Lines • Show All 860 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
int i; | int i; | ||||
struct nfsusrgrp *usrp; | struct nfsusrgrp *usrp; | ||||
u_char *cp = *cpp; | u_char *cp = *cpp; | ||||
uid_t tmp; | uid_t tmp; | ||||
int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; | int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; | ||||
struct nfsrv_lughash *hp; | struct nfsrv_lughash *hp; | ||||
NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); | |||||
cnt = 0; | cnt = 0; | ||||
tryagain: | tryagain: | ||||
if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { | if (NFSD_VNET(nfsrv_dnsnamelen) > 0 && | ||||
!NFSD_VNET(nfs_enable_uidtostring)) { | |||||
/* | /* | ||||
* Always map nfsrv_defaultuid to "nobody". | * Always map nfsrv_defaultuid to "nobody". | ||||
*/ | */ | ||||
if (uid == nfsrv_defaultuid) { | if (uid == NFSD_VNET(nfsrv_defaultuid)) { | ||||
i = nfsrv_dnsnamelen + 7; | i = NFSD_VNET(nfsrv_dnsnamelen) + 7; | ||||
if (i > len) { | if (i > len) { | ||||
if (len > NFSV4_SMALLSTR) | if (len > NFSV4_SMALLSTR) | ||||
free(cp, M_NFSSTRING); | free(cp, M_NFSSTRING); | ||||
cp = malloc(i, M_NFSSTRING, M_WAITOK); | cp = malloc(i, M_NFSSTRING, M_WAITOK); | ||||
*cpp = cp; | *cpp = cp; | ||||
len = i; | len = i; | ||||
goto tryagain; | goto tryagain; | ||||
} | } | ||||
*retlenp = i; | *retlenp = i; | ||||
NFSBCOPY("nobody@", cp, 7); | NFSBCOPY("nobody@", cp, 7); | ||||
cp += 7; | cp += 7; | ||||
NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); | NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp, | ||||
NFSD_VNET(nfsrv_dnsnamelen)); | |||||
NFSD_CURVNET_RESTORE(); | |||||
return; | return; | ||||
} | } | ||||
hasampersand = 0; | hasampersand = 0; | ||||
hp = NFSUSERHASH(uid); | hp = NFSUSERHASH(uid); | ||||
mtx_lock(&hp->mtx); | mtx_lock(&hp->mtx); | ||||
TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { | TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { | ||||
if (usrp->lug_uid == uid) { | if (usrp->lug_uid == uid) { | ||||
if (usrp->lug_expiry < NFSD_MONOSEC) | if (usrp->lug_expiry < NFSD_MONOSEC) | ||||
break; | break; | ||||
/* | /* | ||||
* If the name doesn't already have an '@' | * If the name doesn't already have an '@' | ||||
* in it, append @domainname to it. | * in it, append @domainname to it. | ||||
*/ | */ | ||||
for (i = 0; i < usrp->lug_namelen; i++) { | for (i = 0; i < usrp->lug_namelen; i++) { | ||||
if (usrp->lug_name[i] == '@') { | if (usrp->lug_name[i] == '@') { | ||||
hasampersand = 1; | hasampersand = 1; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (hasampersand) | if (hasampersand) | ||||
i = usrp->lug_namelen; | i = usrp->lug_namelen; | ||||
else | else | ||||
i = usrp->lug_namelen + | i = usrp->lug_namelen + | ||||
nfsrv_dnsnamelen + 1; | NFSD_VNET(nfsrv_dnsnamelen) + 1; | ||||
if (i > len) { | if (i > len) { | ||||
mtx_unlock(&hp->mtx); | mtx_unlock(&hp->mtx); | ||||
if (len > NFSV4_SMALLSTR) | if (len > NFSV4_SMALLSTR) | ||||
free(cp, M_NFSSTRING); | free(cp, M_NFSSTRING); | ||||
cp = malloc(i, M_NFSSTRING, M_WAITOK); | cp = malloc(i, M_NFSSTRING, M_WAITOK); | ||||
*cpp = cp; | *cpp = cp; | ||||
len = i; | len = i; | ||||
goto tryagain; | goto tryagain; | ||||
} | } | ||||
*retlenp = i; | *retlenp = i; | ||||
NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); | NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); | ||||
if (!hasampersand) { | if (!hasampersand) { | ||||
cp += usrp->lug_namelen; | cp += usrp->lug_namelen; | ||||
*cp++ = '@'; | *cp++ = '@'; | ||||
NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); | NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp, | ||||
NFSD_VNET(nfsrv_dnsnamelen)); | |||||
} | } | ||||
TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | ||||
TAILQ_INSERT_TAIL(&hp->lughead, usrp, | TAILQ_INSERT_TAIL(&hp->lughead, usrp, | ||||
lug_numhash); | lug_numhash); | ||||
mtx_unlock(&hp->mtx); | mtx_unlock(&hp->mtx); | ||||
NFSD_CURVNET_RESTORE(); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
mtx_unlock(&hp->mtx); | mtx_unlock(&hp->mtx); | ||||
cnt++; | cnt++; | ||||
ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL); | ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL); | ||||
if (ret == 0 && cnt < 2) | if (ret == 0 && cnt < 2) | ||||
goto tryagain; | goto tryagain; | ||||
Show All 11 Lines | tryagain: | ||||
len = (i > len) ? len : i; | len = (i > len) ? len : i; | ||||
*retlenp = len; | *retlenp = len; | ||||
cp += (len - 1); | cp += (len - 1); | ||||
tmp = uid; | tmp = uid; | ||||
for (i = 0; i < len; i++) { | for (i = 0; i < len; i++) { | ||||
*cp-- = '0' + (tmp % 10); | *cp-- = '0' + (tmp % 10); | ||||
tmp /= 10; | tmp /= 10; | ||||
} | } | ||||
NFSD_CURVNET_RESTORE(); | |||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Get a credential for the uid with the server's group list. | * Get a credential for the uid with the server's group list. | ||||
* If none is found, just return the credential passed in after | * If none is found, just return the credential passed in after | ||||
* logging a warning message. | * logging a warning message. | ||||
*/ | */ | ||||
struct ucred * | struct ucred * | ||||
nfsrv_getgrpscred(struct ucred *oldcred) | nfsrv_getgrpscred(struct ucred *oldcred) | ||||
{ | { | ||||
struct nfsusrgrp *usrp; | struct nfsusrgrp *usrp; | ||||
struct ucred *newcred; | struct ucred *newcred; | ||||
int cnt, ret; | int cnt, ret; | ||||
uid_t uid; | uid_t uid; | ||||
struct nfsrv_lughash *hp; | struct nfsrv_lughash *hp; | ||||
cnt = 0; | cnt = 0; | ||||
uid = oldcred->cr_uid; | uid = oldcred->cr_uid; | ||||
tryagain: | tryagain: | ||||
if (nfsrv_dnsnamelen > 0) { | if (NFSD_VNET(nfsrv_dnsnamelen) > 0) { | ||||
hp = NFSUSERHASH(uid); | hp = NFSUSERHASH(uid); | ||||
mtx_lock(&hp->mtx); | mtx_lock(&hp->mtx); | ||||
TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { | TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { | ||||
if (usrp->lug_uid == uid) { | if (usrp->lug_uid == uid) { | ||||
if (usrp->lug_expiry < NFSD_MONOSEC) | if (usrp->lug_expiry < NFSD_MONOSEC) | ||||
break; | break; | ||||
if (usrp->lug_cred != NULL) { | if (usrp->lug_cred != NULL) { | ||||
newcred = crhold(usrp->lug_cred); | newcred = crhold(usrp->lug_cred); | ||||
Show All 30 Lines | nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp) | ||||
int i; | int i; | ||||
char *cp, *endstr, *str0; | char *cp, *endstr, *str0; | ||||
struct nfsusrgrp *usrp; | struct nfsusrgrp *usrp; | ||||
int cnt, ret; | int cnt, ret; | ||||
int error = 0; | int error = 0; | ||||
uid_t tuid; | uid_t tuid; | ||||
struct nfsrv_lughash *hp, *hp2; | struct nfsrv_lughash *hp, *hp2; | ||||
NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); | |||||
if (len == 0) { | if (len == 0) { | ||||
error = NFSERR_BADOWNER; | error = NFSERR_BADOWNER; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* If a string of digits and an AUTH_SYS mount, just convert it. */ | /* If a string of digits and an AUTH_SYS mount, just convert it. */ | ||||
str0 = str; | str0 = str; | ||||
tuid = (uid_t)strtoul(str0, &endstr, 10); | tuid = (uid_t)strtoul(str0, &endstr, 10); | ||||
if ((endstr - str0) == len) { | if ((endstr - str0) == len) { | ||||
/* A numeric string. */ | /* A numeric string. */ | ||||
if ((nd->nd_flag & ND_KERBV) == 0 && | if ((nd->nd_flag & ND_KERBV) == 0 && | ||||
((nd->nd_flag & ND_NFSCL) != 0 || | ((nd->nd_flag & ND_NFSCL) != 0 || | ||||
nfsd_enable_stringtouid != 0)) | NFSD_VNET(nfsd_enable_stringtouid) != 0)) | ||||
*uidp = tuid; | *uidp = tuid; | ||||
else | else | ||||
error = NFSERR_BADOWNER; | error = NFSERR_BADOWNER; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* Look for an '@'. | * Look for an '@'. | ||||
*/ | */ | ||||
cp = strchr(str0, '@'); | cp = strchr(str0, '@'); | ||||
if (cp != NULL) | if (cp != NULL) | ||||
i = (int)(cp++ - str0); | i = (int)(cp++ - str0); | ||||
else | else | ||||
i = len; | i = len; | ||||
cnt = 0; | cnt = 0; | ||||
tryagain: | tryagain: | ||||
if (nfsrv_dnsnamelen > 0) { | if (NFSD_VNET(nfsrv_dnsnamelen) > 0) { | ||||
/* | /* | ||||
* If an '@' is found and the domain name matches, search for | * If an '@' is found and the domain name matches, search for | ||||
* the name with dns stripped off. | * the name with dns stripped off. | ||||
* Mixed case alpahbetics will match for the domain name, but | * Mixed case alpahbetics will match for the domain name, but | ||||
* all upper case will not. | * all upper case will not. | ||||
*/ | */ | ||||
if (cnt == 0 && i < len && i > 0 && | if (cnt == 0 && i < len && i > 0 && | ||||
(len - 1 - i) == nfsrv_dnsnamelen && | (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) && | ||||
!nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { | !nfsrv_cmpmixedcase(cp, | ||||
len -= (nfsrv_dnsnamelen + 1); | NFSD_VNET(nfsrv_dnsname), NFSD_VNET(nfsrv_dnsnamelen))) { | ||||
len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1); | |||||
*(cp - 1) = '\0'; | *(cp - 1) = '\0'; | ||||
} | } | ||||
/* | /* | ||||
* Check for the special case of "nobody". | * Check for the special case of "nobody". | ||||
*/ | */ | ||||
if (len == 6 && !NFSBCMP(str, "nobody", 6)) { | if (len == 6 && !NFSBCMP(str, "nobody", 6)) { | ||||
*uidp = nfsrv_defaultuid; | *uidp = NFSD_VNET(nfsrv_defaultuid); | ||||
error = 0; | error = 0; | ||||
goto out; | goto out; | ||||
} | } | ||||
hp = NFSUSERNAMEHASH(str, len); | hp = NFSUSERNAMEHASH(str, len); | ||||
mtx_lock(&hp->mtx); | mtx_lock(&hp->mtx); | ||||
TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { | TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { | ||||
if (usrp->lug_namelen == len && | if (usrp->lug_namelen == len && | ||||
Show All 17 Lines | if (NFSD_VNET(nfsrv_dnsnamelen) > 0) { | ||||
ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, | ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, | ||||
str); | str); | ||||
if (ret == 0 && cnt < 2) | if (ret == 0 && cnt < 2) | ||||
goto tryagain; | goto tryagain; | ||||
} | } | ||||
error = NFSERR_BADOWNER; | error = NFSERR_BADOWNER; | ||||
out: | out: | ||||
NFSD_CURVNET_RESTORE(); | |||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Convert a gid to a string. | * Convert a gid to a string. | ||||
* gid - the group id | * gid - the group id | ||||
* cpp - points to a buffer of size NFSV4_SMALLSTR | * cpp - points to a buffer of size NFSV4_SMALLSTR | ||||
* (malloc a larger one, as required) | * (malloc a larger one, as required) | ||||
* retlenp - pointer to length to be returned | * retlenp - pointer to length to be returned | ||||
*/ | */ | ||||
void | void | ||||
nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp) | nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp) | ||||
{ | { | ||||
int i; | int i; | ||||
struct nfsusrgrp *usrp; | struct nfsusrgrp *usrp; | ||||
u_char *cp = *cpp; | u_char *cp = *cpp; | ||||
gid_t tmp; | gid_t tmp; | ||||
int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; | int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; | ||||
struct nfsrv_lughash *hp; | struct nfsrv_lughash *hp; | ||||
NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); | |||||
cnt = 0; | cnt = 0; | ||||
tryagain: | tryagain: | ||||
if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { | if (NFSD_VNET(nfsrv_dnsnamelen) > 0 && | ||||
!NFSD_VNET(nfs_enable_uidtostring)) { | |||||
/* | /* | ||||
* Always map nfsrv_defaultgid to "nogroup". | * Always map nfsrv_defaultgid to "nogroup". | ||||
*/ | */ | ||||
if (gid == nfsrv_defaultgid) { | if (gid == NFSD_VNET(nfsrv_defaultgid)) { | ||||
i = nfsrv_dnsnamelen + 8; | i = NFSD_VNET(nfsrv_dnsnamelen) + 8; | ||||
if (i > len) { | if (i > len) { | ||||
if (len > NFSV4_SMALLSTR) | if (len > NFSV4_SMALLSTR) | ||||
free(cp, M_NFSSTRING); | free(cp, M_NFSSTRING); | ||||
cp = malloc(i, M_NFSSTRING, M_WAITOK); | cp = malloc(i, M_NFSSTRING, M_WAITOK); | ||||
*cpp = cp; | *cpp = cp; | ||||
len = i; | len = i; | ||||
goto tryagain; | goto tryagain; | ||||
} | } | ||||
*retlenp = i; | *retlenp = i; | ||||
NFSBCOPY("nogroup@", cp, 8); | NFSBCOPY("nogroup@", cp, 8); | ||||
cp += 8; | cp += 8; | ||||
NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); | NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp, | ||||
NFSD_VNET(nfsrv_dnsnamelen)); | |||||
NFSD_CURVNET_RESTORE(); | |||||
return; | return; | ||||
} | } | ||||
hasampersand = 0; | hasampersand = 0; | ||||
hp = NFSGROUPHASH(gid); | hp = NFSGROUPHASH(gid); | ||||
mtx_lock(&hp->mtx); | mtx_lock(&hp->mtx); | ||||
TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { | TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { | ||||
if (usrp->lug_gid == gid) { | if (usrp->lug_gid == gid) { | ||||
if (usrp->lug_expiry < NFSD_MONOSEC) | if (usrp->lug_expiry < NFSD_MONOSEC) | ||||
break; | break; | ||||
/* | /* | ||||
* If the name doesn't already have an '@' | * If the name doesn't already have an '@' | ||||
* in it, append @domainname to it. | * in it, append @domainname to it. | ||||
*/ | */ | ||||
for (i = 0; i < usrp->lug_namelen; i++) { | for (i = 0; i < usrp->lug_namelen; i++) { | ||||
if (usrp->lug_name[i] == '@') { | if (usrp->lug_name[i] == '@') { | ||||
hasampersand = 1; | hasampersand = 1; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (hasampersand) | if (hasampersand) | ||||
i = usrp->lug_namelen; | i = usrp->lug_namelen; | ||||
else | else | ||||
i = usrp->lug_namelen + | i = usrp->lug_namelen + | ||||
nfsrv_dnsnamelen + 1; | NFSD_VNET(nfsrv_dnsnamelen) + 1; | ||||
if (i > len) { | if (i > len) { | ||||
mtx_unlock(&hp->mtx); | mtx_unlock(&hp->mtx); | ||||
if (len > NFSV4_SMALLSTR) | if (len > NFSV4_SMALLSTR) | ||||
free(cp, M_NFSSTRING); | free(cp, M_NFSSTRING); | ||||
cp = malloc(i, M_NFSSTRING, M_WAITOK); | cp = malloc(i, M_NFSSTRING, M_WAITOK); | ||||
*cpp = cp; | *cpp = cp; | ||||
len = i; | len = i; | ||||
goto tryagain; | goto tryagain; | ||||
} | } | ||||
*retlenp = i; | *retlenp = i; | ||||
NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); | NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); | ||||
if (!hasampersand) { | if (!hasampersand) { | ||||
cp += usrp->lug_namelen; | cp += usrp->lug_namelen; | ||||
*cp++ = '@'; | *cp++ = '@'; | ||||
NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); | NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp, | ||||
NFSD_VNET(nfsrv_dnsnamelen)); | |||||
} | } | ||||
TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | ||||
TAILQ_INSERT_TAIL(&hp->lughead, usrp, | TAILQ_INSERT_TAIL(&hp->lughead, usrp, | ||||
lug_numhash); | lug_numhash); | ||||
mtx_unlock(&hp->mtx); | mtx_unlock(&hp->mtx); | ||||
NFSD_CURVNET_RESTORE(); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
mtx_unlock(&hp->mtx); | mtx_unlock(&hp->mtx); | ||||
cnt++; | cnt++; | ||||
ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL); | ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL); | ||||
if (ret == 0 && cnt < 2) | if (ret == 0 && cnt < 2) | ||||
goto tryagain; | goto tryagain; | ||||
Show All 11 Lines | tryagain: | ||||
len = (i > len) ? len : i; | len = (i > len) ? len : i; | ||||
*retlenp = len; | *retlenp = len; | ||||
cp += (len - 1); | cp += (len - 1); | ||||
tmp = gid; | tmp = gid; | ||||
for (i = 0; i < len; i++) { | for (i = 0; i < len; i++) { | ||||
*cp-- = '0' + (tmp % 10); | *cp-- = '0' + (tmp % 10); | ||||
tmp /= 10; | tmp /= 10; | ||||
} | } | ||||
NFSD_CURVNET_RESTORE(); | |||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Convert a string to a gid. | * Convert a string to a gid. | ||||
* If no conversion is possible return NFSERR_BADOWNER, otherwise | * If no conversion is possible return NFSERR_BADOWNER, otherwise | ||||
* return 0. | * return 0. | ||||
* If this is called from a client side mount using AUTH_SYS and the | * If this is called from a client side mount using AUTH_SYS and the | ||||
* string is made up entirely of digits, just convert the string to | * string is made up entirely of digits, just convert the string to | ||||
* a number. | * a number. | ||||
*/ | */ | ||||
int | int | ||||
nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp) | nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp) | ||||
{ | { | ||||
int i; | int i; | ||||
char *cp, *endstr, *str0; | char *cp, *endstr, *str0; | ||||
struct nfsusrgrp *usrp; | struct nfsusrgrp *usrp; | ||||
int cnt, ret; | int cnt, ret; | ||||
int error = 0; | int error = 0; | ||||
gid_t tgid; | gid_t tgid; | ||||
struct nfsrv_lughash *hp, *hp2; | struct nfsrv_lughash *hp, *hp2; | ||||
NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); | |||||
if (len == 0) { | if (len == 0) { | ||||
error = NFSERR_BADOWNER; | error = NFSERR_BADOWNER; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* If a string of digits and an AUTH_SYS mount, just convert it. */ | /* If a string of digits and an AUTH_SYS mount, just convert it. */ | ||||
str0 = str; | str0 = str; | ||||
tgid = (gid_t)strtoul(str0, &endstr, 10); | tgid = (gid_t)strtoul(str0, &endstr, 10); | ||||
if ((endstr - str0) == len) { | if ((endstr - str0) == len) { | ||||
/* A numeric string. */ | /* A numeric string. */ | ||||
if ((nd->nd_flag & ND_KERBV) == 0 && | if ((nd->nd_flag & ND_KERBV) == 0 && | ||||
((nd->nd_flag & ND_NFSCL) != 0 || | ((nd->nd_flag & ND_NFSCL) != 0 || | ||||
nfsd_enable_stringtouid != 0)) | NFSD_VNET(nfsd_enable_stringtouid) != 0)) | ||||
*gidp = tgid; | *gidp = tgid; | ||||
else | else | ||||
error = NFSERR_BADOWNER; | error = NFSERR_BADOWNER; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* Look for an '@'. | * Look for an '@'. | ||||
*/ | */ | ||||
cp = strchr(str0, '@'); | cp = strchr(str0, '@'); | ||||
if (cp != NULL) | if (cp != NULL) | ||||
i = (int)(cp++ - str0); | i = (int)(cp++ - str0); | ||||
else | else | ||||
i = len; | i = len; | ||||
cnt = 0; | cnt = 0; | ||||
tryagain: | tryagain: | ||||
if (nfsrv_dnsnamelen > 0) { | if (NFSD_VNET(nfsrv_dnsnamelen) > 0) { | ||||
/* | /* | ||||
* If an '@' is found and the dns name matches, search for the | * If an '@' is found and the dns name matches, search for the | ||||
* name with the dns stripped off. | * name with the dns stripped off. | ||||
*/ | */ | ||||
if (cnt == 0 && i < len && i > 0 && | if (cnt == 0 && i < len && i > 0 && | ||||
(len - 1 - i) == nfsrv_dnsnamelen && | (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) && | ||||
!nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { | !nfsrv_cmpmixedcase(cp, | ||||
len -= (nfsrv_dnsnamelen + 1); | NFSD_VNET(nfsrv_dnsname), NFSD_VNET(nfsrv_dnsnamelen))) { | ||||
len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1); | |||||
*(cp - 1) = '\0'; | *(cp - 1) = '\0'; | ||||
} | } | ||||
/* | /* | ||||
* Check for the special case of "nogroup". | * Check for the special case of "nogroup". | ||||
*/ | */ | ||||
if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { | if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { | ||||
*gidp = nfsrv_defaultgid; | *gidp = NFSD_VNET(nfsrv_defaultgid); | ||||
error = 0; | error = 0; | ||||
goto out; | goto out; | ||||
} | } | ||||
hp = NFSGROUPNAMEHASH(str, len); | hp = NFSGROUPNAMEHASH(str, len); | ||||
mtx_lock(&hp->mtx); | mtx_lock(&hp->mtx); | ||||
TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { | TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { | ||||
if (usrp->lug_namelen == len && | if (usrp->lug_namelen == len && | ||||
Show All 17 Lines | if (NFSD_VNET(nfsrv_dnsnamelen) > 0) { | ||||
ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, | ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, | ||||
str); | str); | ||||
if (ret == 0 && cnt < 2) | if (ret == 0 && cnt < 2) | ||||
goto tryagain; | goto tryagain; | ||||
} | } | ||||
error = NFSERR_BADOWNER; | error = NFSERR_BADOWNER; | ||||
out: | out: | ||||
NFSD_CURVNET_RESTORE(); | |||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Cmp len chars, allowing mixed case in the first argument to match lower | * Cmp len chars, allowing mixed case in the first argument to match lower | ||||
* case in the second, but not if the first argument is all upper case. | * case in the second, but not if the first argument is all upper case. | ||||
* Return 0 for a match, 1 otherwise. | * Return 0 for a match, 1 otherwise. | ||||
Show All 34 Lines | |||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct sockaddr_in6 *ad6; | struct sockaddr_in6 *ad6; | ||||
const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT; | const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT; | ||||
#endif | #endif | ||||
int error; | int error; | ||||
NFSLOCKNAMEID(); | NFSLOCKNAMEID(); | ||||
if (nfsrv_nfsuserd != NOTRUNNING) { | if (NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING) { | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
error = EPERM; | error = EPERM; | ||||
goto out; | goto out; | ||||
} | } | ||||
nfsrv_nfsuserd = STARTSTOP; | NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP; | ||||
/* | /* | ||||
* Set up the socket record and connect. | * Set up the socket record and connect. | ||||
* Set nr_client NULL before unlocking, just to ensure that no other | * Set nr_client NULL before unlocking, just to ensure that no other | ||||
* process/thread/core will use a bogus old value. This could only | * process/thread/core will use a bogus old value. This could only | ||||
* occur if the use of the nameid lock to protect nfsrv_nfsuserd is | * occur if the use of the nameid lock to protect nfsrv_nfsuserd is | ||||
* broken. | * broken. | ||||
*/ | */ | ||||
rp = &nfsrv_nfsuserdsock; | rp = &NFSD_VNET(nfsrv_nfsuserdsock); | ||||
rp->nr_client = NULL; | rp->nr_client = NULL; | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
rp->nr_sotype = SOCK_DGRAM; | rp->nr_sotype = SOCK_DGRAM; | ||||
rp->nr_soproto = IPPROTO_UDP; | rp->nr_soproto = IPPROTO_UDP; | ||||
rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); | rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); | ||||
rp->nr_cred = NULL; | rp->nr_cred = NULL; | ||||
rp->nr_prog = RPCPROG_NFSUSERD; | rp->nr_prog = RPCPROG_NFSUSERD; | ||||
error = 0; | error = 0; | ||||
Show All 24 Lines | default: | ||||
error = ENXIO; | error = ENXIO; | ||||
} | } | ||||
rp->nr_vers = RPCNFSUSERD_VERS; | rp->nr_vers = RPCNFSUSERD_VERS; | ||||
if (error == 0) | if (error == 0) | ||||
error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false, | error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false, | ||||
&rp->nr_client); | &rp->nr_client); | ||||
if (error == 0) { | if (error == 0) { | ||||
NFSLOCKNAMEID(); | NFSLOCKNAMEID(); | ||||
nfsrv_nfsuserd = RUNNING; | NFSD_VNET(nfsrv_nfsuserd) = RUNNING; | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
} else { | } else { | ||||
free(rp->nr_nam, M_SONAME); | free(rp->nr_nam, M_SONAME); | ||||
NFSLOCKNAMEID(); | NFSLOCKNAMEID(); | ||||
nfsrv_nfsuserd = NOTRUNNING; | NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING; | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
} | } | ||||
out: | out: | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Delete the nfsuserd port. | * Delete the nfsuserd port. | ||||
*/ | */ | ||||
void | void | ||||
nfsrv_nfsuserddelport(void) | nfsrv_nfsuserddelport(void) | ||||
{ | { | ||||
NFSLOCKNAMEID(); | NFSLOCKNAMEID(); | ||||
if (nfsrv_nfsuserd != RUNNING) { | if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) { | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
return; | return; | ||||
} | } | ||||
nfsrv_nfsuserd = STARTSTOP; | NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP; | ||||
/* Wait for all upcalls to complete. */ | /* Wait for all upcalls to complete. */ | ||||
while (nfsrv_userdupcalls > 0) | while (NFSD_VNET(nfsrv_userdupcalls) > 0) | ||||
msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS, | msleep(&NFSD_VNET(nfsrv_userdupcalls), NFSNAMEIDMUTEXPTR, PVFS, | ||||
"nfsupcalls", 0); | "nfsupcalls", 0); | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
newnfs_disconnect(NULL, &nfsrv_nfsuserdsock); | newnfs_disconnect(NULL, &NFSD_VNET(nfsrv_nfsuserdsock)); | ||||
free(nfsrv_nfsuserdsock.nr_nam, M_SONAME); | free(NFSD_VNET(nfsrv_nfsuserdsock).nr_nam, M_SONAME); | ||||
NFSLOCKNAMEID(); | NFSLOCKNAMEID(); | ||||
nfsrv_nfsuserd = NOTRUNNING; | NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING; | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
} | } | ||||
/* | /* | ||||
* Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup | * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup | ||||
* name<-->id cache. | * name<-->id cache. | ||||
* Returns 0 upon success, non-zero otherwise. | * Returns 0 upon success, non-zero otherwise. | ||||
*/ | */ | ||||
static int | static int | ||||
nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name) | nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name) | ||||
{ | { | ||||
u_int32_t *tl; | u_int32_t *tl; | ||||
struct nfsrv_descript *nd; | struct nfsrv_descript *nd; | ||||
int len; | int len; | ||||
struct nfsrv_descript nfsd; | struct nfsrv_descript nfsd; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
int error; | int error; | ||||
NFSLOCKNAMEID(); | NFSLOCKNAMEID(); | ||||
if (nfsrv_nfsuserd != RUNNING) { | if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) { | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
error = EPERM; | error = EPERM; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* Maintain a count of upcalls in progress, so that nfsrv_X() | * Maintain a count of upcalls in progress, so that nfsrv_X() | ||||
* can wait until no upcalls are in progress. | * can wait until no upcalls are in progress. | ||||
*/ | */ | ||||
nfsrv_userdupcalls++; | NFSD_VNET(nfsrv_userdupcalls)++; | ||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
KASSERT(nfsrv_userdupcalls > 0, | KASSERT(NFSD_VNET(nfsrv_userdupcalls) > 0, | ||||
("nfsrv_getuser: non-positive upcalls")); | ("nfsrv_getuser: non-positive upcalls")); | ||||
nd = &nfsd; | nd = &nfsd; | ||||
cred = newnfs_getcred(); | cred = newnfs_getcred(); | ||||
nd->nd_flag = ND_GSSINITREPLY; | nd->nd_flag = ND_GSSINITREPLY; | ||||
nfsrvd_rephead(nd); | nfsrvd_rephead(nd); | ||||
nd->nd_procnum = procnum; | nd->nd_procnum = procnum; | ||||
if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { | if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { | ||||
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); | NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); | ||||
if (procnum == RPCNFSUSERD_GETUID) | if (procnum == RPCNFSUSERD_GETUID) | ||||
*tl = txdr_unsigned(uid); | *tl = txdr_unsigned(uid); | ||||
else | else | ||||
*tl = txdr_unsigned(gid); | *tl = txdr_unsigned(gid); | ||||
} else { | } else { | ||||
len = strlen(name); | len = strlen(name); | ||||
(void) nfsm_strtom(nd, name, len); | (void) nfsm_strtom(nd, name, len); | ||||
} | } | ||||
error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, | error = newnfs_request(nd, NULL, NULL, &NFSD_VNET(nfsrv_nfsuserdsock), | ||||
cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); | NULL, NULL, cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, | ||||
NULL, NULL); | |||||
NFSLOCKNAMEID(); | NFSLOCKNAMEID(); | ||||
if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP) | if (--NFSD_VNET(nfsrv_userdupcalls) == 0 && | ||||
wakeup(&nfsrv_userdupcalls); | NFSD_VNET(nfsrv_nfsuserd) == STARTSTOP) | ||||
wakeup(&NFSD_VNET(nfsrv_userdupcalls)); | |||||
NFSUNLOCKNAMEID(); | NFSUNLOCKNAMEID(); | ||||
NFSFREECRED(cred); | NFSFREECRED(cred); | ||||
if (!error) { | if (!error) { | ||||
m_freem(nd->nd_mrep); | m_freem(nd->nd_mrep); | ||||
error = nd->nd_repstat; | error = nd->nd_repstat; | ||||
} | } | ||||
out: | out: | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
Show All 23 Lines | nfssvc_idname(struct nfsd_idargs *nidp) | ||||
} | } | ||||
if (nidp->nid_flag & NFSID_INITIALIZE) { | if (nidp->nid_flag & NFSID_INITIALIZE) { | ||||
cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); | cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); | ||||
error = copyin(nidp->nid_name, cp, nidp->nid_namelen); | error = copyin(nidp->nid_name, cp, nidp->nid_namelen); | ||||
if (error != 0) { | if (error != 0) { | ||||
free(cp, M_NFSSTRING); | free(cp, M_NFSSTRING); | ||||
goto out; | goto out; | ||||
} | } | ||||
if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { | if (atomic_cmpset_acq_int(&NFSD_VNET(nfsrv_dnsnamelen), 0, 0) == | ||||
0) { | |||||
/* | /* | ||||
* Free up all the old stuff and reinitialize hash | * Free up all the old stuff and reinitialize hash | ||||
* lists. All mutexes for both lists must be locked, | * lists. All mutexes for both lists must be locked, | ||||
* with the user/group name ones before the uid/gid | * with the user/group name ones before the uid/gid | ||||
* ones, to avoid a LOR. | * ones, to avoid a LOR. | ||||
*/ | */ | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsusernamehash[i].mtx); | mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsuserhash[i].mtx); | mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
TAILQ_FOREACH_SAFE(usrp, | TAILQ_FOREACH_SAFE(usrp, | ||||
&nfsuserhash[i].lughead, lug_numhash, nusrp) | &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp) | ||||
nfsrv_removeuser(usrp, 1); | nfsrv_removeuser(usrp, 1); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_unlock(&nfsuserhash[i].mtx); | mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_unlock(&nfsusernamehash[i].mtx); | mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsgroupnamehash[i].mtx); | mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsgrouphash[i].mtx); | mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
TAILQ_FOREACH_SAFE(usrp, | TAILQ_FOREACH_SAFE(usrp, | ||||
&nfsgrouphash[i].lughead, lug_numhash, | &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash, | ||||
nusrp) | nusrp) | ||||
nfsrv_removeuser(usrp, 0); | nfsrv_removeuser(usrp, 0); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_unlock(&nfsgrouphash[i].mtx); | mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_unlock(&nfsgroupnamehash[i].mtx); | mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); | ||||
free(nfsrv_dnsname, M_NFSSTRING); | free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING); | ||||
nfsrv_dnsname = NULL; | NFSD_VNET(nfsrv_dnsname) = NULL; | ||||
} | } | ||||
if (nfsuserhash == NULL) { | if (NFSD_VNET(nfsuserhash) == NULL) { | ||||
/* Allocate the hash tables. */ | /* Allocate the hash tables. */ | ||||
nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * | NFSD_VNET(nfsuserhash) = malloc(sizeof(struct nfsrv_lughash) * | ||||
nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | | nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | | ||||
M_ZERO); | M_ZERO); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", | mtx_init(&NFSD_VNET(nfsuserhash)[i].mtx, "nfsuidhash", | ||||
NULL, MTX_DEF | MTX_DUPOK); | NULL, MTX_DEF | MTX_DUPOK); | ||||
nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * | NFSD_VNET(nfsusernamehash) = malloc(sizeof(struct nfsrv_lughash) * | ||||
nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | | nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | | ||||
M_ZERO); | M_ZERO); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_init(&nfsusernamehash[i].mtx, | mtx_init(&NFSD_VNET(nfsusernamehash)[i].mtx, | ||||
"nfsusrhash", NULL, MTX_DEF | | "nfsusrhash", NULL, MTX_DEF | | ||||
MTX_DUPOK); | MTX_DUPOK); | ||||
nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * | NFSD_VNET(nfsgrouphash) = malloc(sizeof(struct nfsrv_lughash) * | ||||
nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | | nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | | ||||
M_ZERO); | M_ZERO); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", | mtx_init(&NFSD_VNET(nfsgrouphash)[i].mtx, "nfsgidhash", | ||||
NULL, MTX_DEF | MTX_DUPOK); | NULL, MTX_DEF | MTX_DUPOK); | ||||
nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * | NFSD_VNET(nfsgroupnamehash) = malloc(sizeof(struct nfsrv_lughash) * | ||||
nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | | nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | | ||||
M_ZERO); | M_ZERO); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_init(&nfsgroupnamehash[i].mtx, | mtx_init(&NFSD_VNET(nfsgroupnamehash)[i].mtx, | ||||
"nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); | "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); | ||||
} | } | ||||
/* (Re)initialize the list heads. */ | /* (Re)initialize the list heads. */ | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
TAILQ_INIT(&nfsuserhash[i].lughead); | TAILQ_INIT(&NFSD_VNET(nfsuserhash)[i].lughead); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
TAILQ_INIT(&nfsusernamehash[i].lughead); | TAILQ_INIT(&NFSD_VNET(nfsusernamehash)[i].lughead); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
TAILQ_INIT(&nfsgrouphash[i].lughead); | TAILQ_INIT(&NFSD_VNET(nfsgrouphash)[i].lughead); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
TAILQ_INIT(&nfsgroupnamehash[i].lughead); | TAILQ_INIT(&NFSD_VNET(nfsgroupnamehash)[i].lughead); | ||||
/* | /* | ||||
* Put name in "DNS" string. | * Put name in "DNS" string. | ||||
*/ | */ | ||||
nfsrv_dnsname = cp; | NFSD_VNET(nfsrv_dnsname) = cp; | ||||
nfsrv_defaultuid = nidp->nid_uid; | NFSD_VNET(nfsrv_defaultuid) = nidp->nid_uid; | ||||
nfsrv_defaultgid = nidp->nid_gid; | NFSD_VNET(nfsrv_defaultgid) = nidp->nid_gid; | ||||
nfsrv_usercnt = 0; | NFSD_VNET(nfsrv_usercnt) = 0; | ||||
nfsrv_usermax = nidp->nid_usermax; | NFSD_VNET(nfsrv_usermax) = nidp->nid_usermax; | ||||
atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); | atomic_store_rel_int(&NFSD_VNET(nfsrv_dnsnamelen), | ||||
nidp->nid_namelen); | |||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* malloc the new one now, so any potential sleep occurs before | * malloc the new one now, so any potential sleep occurs before | ||||
* manipulation of the lists. | * manipulation of the lists. | ||||
*/ | */ | ||||
newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, | newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, | ||||
Show All 10 Lines | if (error == 0) { | ||||
/* | /* | ||||
* Create a credential just like svc_getcred(), | * Create a credential just like svc_getcred(), | ||||
* but using the group list provided. | * but using the group list provided. | ||||
*/ | */ | ||||
cr = crget(); | cr = crget(); | ||||
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; | cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; | ||||
crsetgroups(cr, nidp->nid_ngroup, grps); | crsetgroups(cr, nidp->nid_ngroup, grps); | ||||
cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; | cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; | ||||
if (jailed(curthread->td_ucred)) | |||||
cr->cr_prison = curthread->td_ucred->cr_prison; | |||||
else | |||||
cr->cr_prison = &prison0; | cr->cr_prison = &prison0; | ||||
prison_hold(cr->cr_prison); | prison_hold(cr->cr_prison); | ||||
#ifdef MAC | #ifdef MAC | ||||
mac_cred_associate_nfsd(cr); | mac_cred_associate_nfsd(cr); | ||||
#endif | #endif | ||||
newusrp->lug_cred = cr; | newusrp->lug_cred = cr; | ||||
} | } | ||||
free(grps, M_TEMP); | free(grps, M_TEMP); | ||||
} | } | ||||
Show All 15 Lines | #endif | ||||
hp_name = hp_idnum = NULL; | hp_name = hp_idnum = NULL; | ||||
/* | /* | ||||
* Delete old entries, as required. | * Delete old entries, as required. | ||||
*/ | */ | ||||
if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { | if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { | ||||
/* Must lock all username hash lists first, to avoid a LOR. */ | /* Must lock all username hash lists first, to avoid a LOR. */ | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsusernamehash[i].mtx); | mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx); | ||||
username_locked = 1; | username_locked = 1; | ||||
hp_idnum = NFSUSERHASH(nidp->nid_uid); | hp_idnum = NFSUSERHASH(nidp->nid_uid); | ||||
mtx_lock(&hp_idnum->mtx); | mtx_lock(&hp_idnum->mtx); | ||||
TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, | TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, | ||||
nusrp) { | nusrp) { | ||||
if (usrp->lug_uid == nidp->nid_uid) | if (usrp->lug_uid == nidp->nid_uid) | ||||
nfsrv_removeuser(usrp, 1); | nfsrv_removeuser(usrp, 1); | ||||
} | } | ||||
Show All 12 Lines | TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, | ||||
mtx_unlock(&thp->mtx); | mtx_unlock(&thp->mtx); | ||||
} | } | ||||
} | } | ||||
hp_idnum = NFSUSERHASH(nidp->nid_uid); | hp_idnum = NFSUSERHASH(nidp->nid_uid); | ||||
mtx_lock(&hp_idnum->mtx); | mtx_lock(&hp_idnum->mtx); | ||||
} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { | } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { | ||||
/* Must lock all groupname hash lists first, to avoid a LOR. */ | /* Must lock all groupname hash lists first, to avoid a LOR. */ | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsgroupnamehash[i].mtx); | mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); | ||||
groupname_locked = 1; | groupname_locked = 1; | ||||
hp_idnum = NFSGROUPHASH(nidp->nid_gid); | hp_idnum = NFSGROUPHASH(nidp->nid_gid); | ||||
mtx_lock(&hp_idnum->mtx); | mtx_lock(&hp_idnum->mtx); | ||||
TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, | TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, | ||||
nusrp) { | nusrp) { | ||||
if (usrp->lug_gid == nidp->nid_gid) | if (usrp->lug_gid == nidp->nid_gid) | ||||
nfsrv_removeuser(usrp, 0); | nfsrv_removeuser(usrp, 0); | ||||
} | } | ||||
Show All 26 Lines | #endif | ||||
if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { | if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { | ||||
newusrp->lug_uid = nidp->nid_uid; | newusrp->lug_uid = nidp->nid_uid; | ||||
thp = NFSUSERHASH(newusrp->lug_uid); | thp = NFSUSERHASH(newusrp->lug_uid); | ||||
mtx_assert(&thp->mtx, MA_OWNED); | mtx_assert(&thp->mtx, MA_OWNED); | ||||
TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); | TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); | ||||
thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); | thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); | ||||
mtx_assert(&thp->mtx, MA_OWNED); | mtx_assert(&thp->mtx, MA_OWNED); | ||||
TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); | TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); | ||||
atomic_add_int(&nfsrv_usercnt, 1); | atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1); | ||||
} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { | } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { | ||||
newusrp->lug_gid = nidp->nid_gid; | newusrp->lug_gid = nidp->nid_gid; | ||||
thp = NFSGROUPHASH(newusrp->lug_gid); | thp = NFSGROUPHASH(newusrp->lug_gid); | ||||
mtx_assert(&thp->mtx, MA_OWNED); | mtx_assert(&thp->mtx, MA_OWNED); | ||||
TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); | TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); | ||||
thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); | thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); | ||||
mtx_assert(&thp->mtx, MA_OWNED); | mtx_assert(&thp->mtx, MA_OWNED); | ||||
TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); | TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); | ||||
atomic_add_int(&nfsrv_usercnt, 1); | atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1); | ||||
} else { | } else { | ||||
if (newusrp->lug_cred != NULL) | if (newusrp->lug_cred != NULL) | ||||
crfree(newusrp->lug_cred); | crfree(newusrp->lug_cred); | ||||
free(newusrp, M_NFSUSERGROUP); | free(newusrp, M_NFSUSERGROUP); | ||||
} | } | ||||
/* | /* | ||||
* Once per second, allow one thread to trim the cache. | * Once per second, allow one thread to trim the cache. | ||||
Show All 12 Lines | if (hp_idnum != NULL) { | ||||
mtx_unlock(&hp_idnum->mtx); | mtx_unlock(&hp_idnum->mtx); | ||||
hp_idnum = NULL; | hp_idnum = NULL; | ||||
} | } | ||||
if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | | if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | | ||||
NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { | NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { | ||||
if (username_locked == 0) { | if (username_locked == 0) { | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsusernamehash[i].mtx); | mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx); | ||||
username_locked = 1; | username_locked = 1; | ||||
} | } | ||||
KASSERT(user_locked == 0, | KASSERT(user_locked == 0, | ||||
("nfssvc_idname: user_locked")); | ("nfssvc_idname: user_locked")); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsuserhash[i].mtx); | mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx); | ||||
user_locked = 1; | user_locked = 1; | ||||
for (i = 0; i < nfsrv_lughashsize; i++) { | for (i = 0; i < nfsrv_lughashsize; i++) { | ||||
TAILQ_FOREACH_SAFE(usrp, | TAILQ_FOREACH_SAFE(usrp, | ||||
&nfsuserhash[i].lughead, lug_numhash, | &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, | ||||
nusrp) | nusrp) | ||||
if (usrp->lug_expiry < NFSD_MONOSEC) | if (usrp->lug_expiry < NFSD_MONOSEC) | ||||
nfsrv_removeuser(usrp, 1); | nfsrv_removeuser(usrp, 1); | ||||
} | } | ||||
for (i = 0; i < nfsrv_lughashsize; i++) { | for (i = 0; i < nfsrv_lughashsize; i++) { | ||||
/* | /* | ||||
* Trim the cache using an approximate LRU | * Trim the cache using an approximate LRU | ||||
* algorithm. This code deletes the least | * algorithm. This code deletes the least | ||||
* recently used entry on each hash list. | * recently used entry on each hash list. | ||||
*/ | */ | ||||
if (nfsrv_usercnt <= nfsrv_usermax) | if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax)) | ||||
break; | break; | ||||
usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); | usrp = TAILQ_FIRST(&NFSD_VNET(nfsuserhash)[i].lughead); | ||||
if (usrp != NULL) | if (usrp != NULL) | ||||
nfsrv_removeuser(usrp, 1); | nfsrv_removeuser(usrp, 1); | ||||
} | } | ||||
} else { | } else { | ||||
if (groupname_locked == 0) { | if (groupname_locked == 0) { | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsgroupnamehash[i].mtx); | mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); | ||||
groupname_locked = 1; | groupname_locked = 1; | ||||
} | } | ||||
KASSERT(group_locked == 0, | KASSERT(group_locked == 0, | ||||
("nfssvc_idname: group_locked")); | ("nfssvc_idname: group_locked")); | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_lock(&nfsgrouphash[i].mtx); | mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx); | ||||
group_locked = 1; | group_locked = 1; | ||||
for (i = 0; i < nfsrv_lughashsize; i++) { | for (i = 0; i < nfsrv_lughashsize; i++) { | ||||
TAILQ_FOREACH_SAFE(usrp, | TAILQ_FOREACH_SAFE(usrp, | ||||
&nfsgrouphash[i].lughead, lug_numhash, | &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash, | ||||
nusrp) | nusrp) | ||||
if (usrp->lug_expiry < NFSD_MONOSEC) | if (usrp->lug_expiry < NFSD_MONOSEC) | ||||
nfsrv_removeuser(usrp, 0); | nfsrv_removeuser(usrp, 0); | ||||
} | } | ||||
for (i = 0; i < nfsrv_lughashsize; i++) { | for (i = 0; i < nfsrv_lughashsize; i++) { | ||||
/* | /* | ||||
* Trim the cache using an approximate LRU | * Trim the cache using an approximate LRU | ||||
* algorithm. This code deletes the least | * algorithm. This code deletes the least | ||||
* recently user entry on each hash list. | * recently user entry on each hash list. | ||||
*/ | */ | ||||
if (nfsrv_usercnt <= nfsrv_usermax) | if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax)) | ||||
break; | break; | ||||
usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); | usrp = TAILQ_FIRST(&NFSD_VNET(nfsgrouphash)[i].lughead); | ||||
if (usrp != NULL) | if (usrp != NULL) | ||||
nfsrv_removeuser(usrp, 0); | nfsrv_removeuser(usrp, 0); | ||||
} | } | ||||
} | } | ||||
lasttime = NFSD_MONOSEC; | lasttime = NFSD_MONOSEC; | ||||
atomic_store_rel_int(&onethread, 0); | atomic_store_rel_int(&onethread, 0); | ||||
} | } | ||||
/* Now, unlock all locked mutexes. */ | /* Now, unlock all locked mutexes. */ | ||||
if (hp_idnum != NULL) | if (hp_idnum != NULL) | ||||
mtx_unlock(&hp_idnum->mtx); | mtx_unlock(&hp_idnum->mtx); | ||||
if (hp_name != NULL) | if (hp_name != NULL) | ||||
mtx_unlock(&hp_name->mtx); | mtx_unlock(&hp_name->mtx); | ||||
if (user_locked != 0) | if (user_locked != 0) | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_unlock(&nfsuserhash[i].mtx); | mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx); | ||||
if (username_locked != 0) | if (username_locked != 0) | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_unlock(&nfsusernamehash[i].mtx); | mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx); | ||||
if (group_locked != 0) | if (group_locked != 0) | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_unlock(&nfsgrouphash[i].mtx); | mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx); | ||||
if (groupname_locked != 0) | if (groupname_locked != 0) | ||||
for (i = 0; i < nfsrv_lughashsize; i++) | for (i = 0; i < nfsrv_lughashsize; i++) | ||||
mtx_unlock(&nfsgroupnamehash[i].mtx); | mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); | ||||
out: | out: | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Remove a user/group name element. | * Remove a user/group name element. | ||||
*/ | */ | ||||
Show All 12 Lines | nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) | ||||
} else { | } else { | ||||
hp = NFSGROUPHASH(usrp->lug_gid); | hp = NFSGROUPHASH(usrp->lug_gid); | ||||
mtx_assert(&hp->mtx, MA_OWNED); | mtx_assert(&hp->mtx, MA_OWNED); | ||||
TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | ||||
hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); | hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); | ||||
mtx_assert(&hp->mtx, MA_OWNED); | mtx_assert(&hp->mtx, MA_OWNED); | ||||
TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); | TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); | ||||
} | } | ||||
atomic_add_int(&nfsrv_usercnt, -1); | atomic_add_int(&NFSD_VNET(nfsrv_usercnt), -1); | ||||
if (usrp->lug_cred != NULL) | if (usrp->lug_cred != NULL) | ||||
crfree(usrp->lug_cred); | crfree(usrp->lug_cred); | ||||
free(usrp, M_NFSUSERGROUP); | free(usrp, M_NFSUSERGROUP); | ||||
} | |||||
/* | |||||
* Free up all the allocations related to the name<-->id cache. | |||||
* This function should only be called when the nfsuserd daemon isn't | |||||
* running, since it doesn't do any locking. | |||||
* This function is meant to be used when the nfscommon module is unloaded. | |||||
*/ | |||||
void | |||||
nfsrv_cleanusergroup(void) | |||||
{ | |||||
struct nfsrv_lughash *hp, *hp2; | |||||
struct nfsusrgrp *nusrp, *usrp; | |||||
int i; | |||||
if (nfsuserhash == NULL) | |||||
return; | |||||
for (i = 0; i < nfsrv_lughashsize; i++) { | |||||
hp = &nfsuserhash[i]; | |||||
TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { | |||||
TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | |||||
hp2 = NFSUSERNAMEHASH(usrp->lug_name, | |||||
usrp->lug_namelen); | |||||
TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); | |||||
if (usrp->lug_cred != NULL) | |||||
crfree(usrp->lug_cred); | |||||
free(usrp, M_NFSUSERGROUP); | |||||
} | |||||
hp = &nfsgrouphash[i]; | |||||
TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { | |||||
TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | |||||
hp2 = NFSGROUPNAMEHASH(usrp->lug_name, | |||||
usrp->lug_namelen); | |||||
TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); | |||||
if (usrp->lug_cred != NULL) | |||||
crfree(usrp->lug_cred); | |||||
free(usrp, M_NFSUSERGROUP); | |||||
} | |||||
mtx_destroy(&nfsuserhash[i].mtx); | |||||
mtx_destroy(&nfsusernamehash[i].mtx); | |||||
mtx_destroy(&nfsgroupnamehash[i].mtx); | |||||
mtx_destroy(&nfsgrouphash[i].mtx); | |||||
} | |||||
free(nfsuserhash, M_NFSUSERGROUP); | |||||
free(nfsusernamehash, M_NFSUSERGROUP); | |||||
free(nfsgrouphash, M_NFSUSERGROUP); | |||||
free(nfsgroupnamehash, M_NFSUSERGROUP); | |||||
free(nfsrv_dnsname, M_NFSSTRING); | |||||
} | } | ||||
/* | /* | ||||
* This function scans a byte string and checks for UTF-8 compliance. | * This function scans a byte string and checks for UTF-8 compliance. | ||||
* It returns 0 if it conforms and NFSERR_INVAL if not. | * It returns 0 if it conforms and NFSERR_INVAL if not. | ||||
*/ | */ | ||||
int | int | ||||
nfsrv_checkutf8(u_int8_t *cp, int len) | nfsrv_checkutf8(u_int8_t *cp, int len) | ||||
▲ Show 20 Lines • Show All 808 Lines • Show Last 20 Lines |