aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2021-05-31 00:52:43 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2021-06-26 22:40:07 +0000
commit3747e3b28ee6639c1ed7e83dc53e07dcf794fbc9 (patch)
tree3bafae269ab8116553a48924fd769b2a1f575de0
parent9aee734554e847b0e456bf2109b1bc4d9f2f09fd (diff)
downloadsrc-3747e3b28ee6639c1ed7e83dc53e07dcf794fbc9.tar.gz
src-3747e3b28ee6639c1ed7e83dc53e07dcf794fbc9.zip
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. (cherry picked from commit 947bd2479ba9661a99f2415038e7b5fa972ec843)
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c2
-rw-r--r--sys/fs/nfs/nfs_var.h2
-rw-r--r--sys/fs/nfs/nfsproto.h4
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c113
-rw-r--r--sys/fs/nfsserver/nfs_nfsdsocket.c15
-rw-r--r--sys/fs/nfsserver/nfs_nfsdsubs.c3
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;
@@ -3755,6 +3756,116 @@ out:
}
/*
+ * 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
*/
int
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 d407dad8367d..8c7db36bbd05 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++ = '.';