nfsd: Add support for the NFSv4.1/4.2 Secinfo_no_name operation

The Linux client is now attempting to use the Secinfo_no_name
operation for NFSv4.1/4.2 mounts.  Although it does not seem to
mind the NFSERR_NOTSUPP reply, adding support for it seems
reasonable.

I also noticed that "savflag" needed to be 64bits in
nfsrvd_secinfo() since nd_flag in now 64bits, so I changed
the declaration of it there.  I also added code to set "vp" NULL
after performing Secinfo/Secinfo_no_name, since these
operations consume the current FH, which is represented
by "vp" in nfsrvd_compound().

Fixing when the server replies NFSERR_WRONGSEC so that
it conforms to RFC5661 Sec. 2.6 still needs to be done
in a future commit.

MFC after:	2 weeks
This commit is contained in:
Rick Macklem 2021-05-30 17:52:43 -07:00
parent f0d577fd2d
commit 947bd2479b
6 changed files with 134 additions and 5 deletions

View File

@ -168,7 +168,7 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */

View File

@ -232,6 +232,8 @@ int nfsrvd_renew(struct nfsrv_descript *, int,
vnode_t, struct nfsexstuff *);
int nfsrvd_secinfo(struct nfsrv_descript *, int,
vnode_t, struct nfsexstuff *);
int nfsrvd_secinfononame(struct nfsrv_descript *, int,
vnode_t, struct nfsexstuff *);
int nfsrvd_setclientid(struct nfsrv_descript *, int,
vnode_t, struct nfsexstuff *);
int nfsrvd_setclientidcfrm(struct nfsrv_descript *, int,

View File

@ -726,6 +726,10 @@
#define NFSCDFS4_BACK 0x2
#define NFSCDFS4_BOTH 0x3
/* Enum values for Secinfo_no_name. */
#define NFSSECINFONONAME_CURFH 0
#define NFSSECINFONONAME_PARENT 1
#if defined(_KERNEL) || defined(KERNEL)
/* Conversion macros */
#define vtonfsv2_mode(t,m) \

View File

@ -3664,7 +3664,8 @@ nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
struct nfsrvfh fh;
struct nfsexstuff retnes;
u_int32_t *sizp;
int error = 0, savflag, i;
int error = 0, i;
uint64_t savflag;
char *bufp;
u_long *hashp;
struct thread *p = curthread;
@ -3754,6 +3755,116 @@ nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
return (error);
}
/*
* nfsv4 security info no name service
*/
int
nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram,
vnode_t dp, struct nfsexstuff *exp)
{
uint32_t *tl, *sizp;
struct nameidata named;
vnode_t dirp = NULL, vp;
struct nfsrvfh fh;
struct nfsexstuff retnes;
int error = 0, fhstyle, i, len;
uint64_t savflag;
char *bufp;
u_long *hashp;
struct thread *p = curthread;
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
fhstyle = fxdr_unsigned(int, *tl);
switch (fhstyle) {
case NFSSECINFONONAME_PARENT:
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
LOCKLEAF | SAVESTART);
nfsvno_setpathbuf(&named, &bufp, &hashp);
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
if (error != 0) {
vput(dp);
nfsvno_relpathbuf(&named);
goto nfsmout;
}
if (nd->nd_repstat == 0)
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
else
vput(dp);
if (dirp != NULL)
vrele(dirp);
vrele(named.ni_startdir);
nfsvno_relpathbuf(&named);
vp = named.ni_vp;
break;
case NFSSECINFONONAME_CURFH:
vp = dp;
break;
default:
nd->nd_repstat = NFSERR_INVAL;
vput(dp);
}
if (nd->nd_repstat != 0)
goto nfsmout;
fh.nfsrvfh_len = NFSX_MYFH;
nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
vput(vp);
savflag = nd->nd_flag;
if (nd->nd_repstat == 0) {
nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
if (vp != NULL)
vput(vp);
}
nd->nd_flag = savflag;
if (nd->nd_repstat != 0)
goto nfsmout;
/*
* Finally have the export flags for fh/parent, so we can create
* the security info.
*/
len = 0;
NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED);
for (i = 0; i < retnes.nes_numsecflavor; i++) {
if (retnes.nes_secflavors[i] == AUTH_SYS) {
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(RPCAUTH_UNIX);
len++;
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(RPCAUTH_GSS);
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
nfsgss_mechlist[KERBV_MECH].len);
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
len++;
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(RPCAUTH_GSS);
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
nfsgss_mechlist[KERBV_MECH].len);
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
len++;
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(RPCAUTH_GSS);
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
nfsgss_mechlist[KERBV_MECH].len);
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
len++;
}
}
*sizp = txdr_unsigned(len);
nfsmout:
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 set client id service
*/

View File

@ -188,7 +188,7 @@ int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript *,
nfsrvd_layoutcommit,
nfsrvd_layoutget,
nfsrvd_layoutreturn,
nfsrvd_notsupp,
nfsrvd_secinfononame,
nfsrvd_sequence,
nfsrvd_notsupp,
nfsrvd_teststateid,
@ -1175,9 +1175,20 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
}
break;
}
if (nd->nd_repstat == 0)
if (nd->nd_repstat == 0) {
error = (*(nfsrv4_ops0[op]))(nd,
isdgram, vp, &vpnes);
if ((op == NFSV4OP_SECINFO ||
op == NFSV4OP_SECINFONONAME) &&
error == 0 && nd->nd_repstat == 0) {
/*
* Secinfo and Secinfo_no_name
* consume the current FH.
*/
vrele(vp);
vp = NULL;
}
}
if (nfsv4_opflag[op].modifyfs)
vn_finished_write(temp_mp);
} else {

View File

@ -1890,7 +1890,8 @@ nfsrv_parsename(struct nfsrv_descript *nd, char *bufp, u_long *hashp,
* For V4, check for lookup parent.
* Otherwise, get the component name.
*/
if ((nd->nd_flag & ND_NFSV4) && nd->nd_procnum == NFSV4OP_LOOKUPP) {
if ((nd->nd_flag & ND_NFSV4) && (nd->nd_procnum == NFSV4OP_LOOKUPP ||
nd->nd_procnum == NFSV4OP_SECINFONONAME)) {
*tocp++ = '.';
hash += ((u_char)'.');
*tocp++ = '.';