git: 947bd2479ba9 - main - nfsd: Add support for the NFSv4.1/4.2 Secinfo_no_name operation

Rick Macklem rmacklem at FreeBSD.org
Mon May 31 00:56:36 UTC 2021


The branch main has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=947bd2479ba9661a99f2415038e7b5fa972ec843

commit 947bd2479ba9661a99f2415038e7b5fa972ec843
Author:     Rick Macklem <rmacklem at FreeBSD.org>
AuthorDate: 2021-05-31 00:52:43 +0000
Commit:     Rick Macklem <rmacklem at FreeBSD.org>
CommitDate: 2021-05-31 00:52:43 +0000

    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
---
 sys/fs/nfs/nfs_commonsubs.c       |   2 +-
 sys/fs/nfs/nfs_var.h              |   2 +
 sys/fs/nfs/nfsproto.h             |   4 ++
 sys/fs/nfsserver/nfs_nfsdserv.c   | 113 +++++++++++++++++++++++++++++++++++++-
 sys/fs/nfsserver/nfs_nfsdsocket.c |  15 ++++-
 sys/fs/nfsserver/nfs_nfsdsubs.c   |   3 +-
 6 files changed, 134 insertions(+), 5 deletions(-)

diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 7ddef0f19ddc..02416da54f01 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -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 */
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index f23d56050449..c1ca7c03af39 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -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,
diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h
index a1a992d14cdb..62d86c3a4593 100644
--- a/sys/fs/nfs/nfsproto.h
+++ b/sys/fs/nfs/nfsproto.h
@@ -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) 						\
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index ef78f90fabfc..5d3c6f65ced0 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -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 @@ out:
 	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
  */
diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c
index e9602c352420..a8e1757835ac 100644
--- a/sys/fs/nfsserver/nfs_nfsdsocket.c
+++ b/sys/fs/nfsserver/nfs_nfsdsocket.c
@@ -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 @@ tryagain:
 					}
 					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 {
diff --git a/sys/fs/nfsserver/nfs_nfsdsubs.c b/sys/fs/nfsserver/nfs_nfsdsubs.c
index 49c5cac999c7..2b6e17752544 100644
--- a/sys/fs/nfsserver/nfs_nfsdsubs.c
+++ b/sys/fs/nfsserver/nfs_nfsdsubs.c
@@ -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++ = '.';


More information about the dev-commits-src-all mailing list