From b4372164ede25881b2eb17ca09bbd32cfdaade01 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Fri, 19 Apr 2019 23:35:08 +0000 Subject: [PATCH] Add support for the ModeSetMasked attribute to the NFSv4.1 server. I do not know of an extant NFSv4.1 client that currently does a Setattr operation for the ModeSetMasked, but it has been discussed on the linux-nfs mailing list. This patch adds support for doing a Setattr of ModeSetMasked, so that it will work for any future NFSv4.1 client that chooses to do so. Tested via a hacked FreeBSD NFSv4.1 client. MFC after: 2 weeks --- sys/fs/nfs/nfsproto.h | 5 +++-- sys/fs/nfsserver/nfs_nfsdport.c | 32 +++++++++++++++++++++++++++++++- sys/fs/nfsserver/nfs_nfsdserv.c | 11 ++++++++--- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h index bc62471336d4..2e9f6d7b9dbe 100644 --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -1090,7 +1090,7 @@ struct nfsv3_sattr { */ #define NFSATTRBIT_SUPPSETONLY1 (NFSATTRBM_TIMEACCESSSET | \ NFSATTRBM_TIMEMODIFYSET) -#define NFSATTRBIT_SUPPSETONLY2 0 +#define NFSATTRBIT_SUPPSETONLY2 (NFSATTRBM_MODESETMASKED) /* * NFSATTRBIT_SETABLE - SETABLE0 - bits 0<->31 @@ -1106,7 +1106,8 @@ struct nfsv3_sattr { NFSATTRBM_OWNERGROUP | \ NFSATTRBM_TIMEACCESSSET | \ NFSATTRBM_TIMEMODIFYSET) -#define NFSATTRBIT_SETABLE2 0 +#define NFSATTRBIT_SETABLE2 \ + (NFSATTRBM_MODESETMASKED) /* * NFSATTRBIT_NFSV41 - Attributes only supported by NFSv4.1. diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 040d0c2ec12b..bb21711f1a4e 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -2699,10 +2699,12 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, int attrsum = 0; int i, j; int error, attrsize, bitpos, aclsize, aceerr, retnotsup = 0; - int toclient = 0; + int moderet, toclient = 0; u_char *cp, namestr[NFSV4_SMALLSTR + 1]; uid_t uid; gid_t gid; + u_short mode, mask; /* Same type as va_mode. */ + struct vattr va; error = nfsrv_getattrbits(nd, attrbitp, NULL, &retnotsup); if (error) @@ -2720,6 +2722,7 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, } else { bitpos = 0; } + moderet = 0; for (; bitpos < NFSATTRBIT_MAX; bitpos++) { if (attrsum > attrsize) { error = NFSERR_BADXDR; @@ -2769,6 +2772,7 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); break; case NFSATTRBIT_MODE: + moderet = NFSERR_INVAL; /* Can't do MODESETMASKED. */ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nvap->na_mode = nfstov_mode(*tl); attrsum += NFSX_UNSIGNED; @@ -2872,6 +2876,32 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, nvap->na_vaflags |= VA_UTIMES_NULL; } break; + case NFSATTRBIT_MODESETMASKED: + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + mode = fxdr_unsigned(u_short, *tl++); + mask = fxdr_unsigned(u_short, *tl); + /* + * vp == NULL implies an Open/Create operation. + * This attribute can only be used for Setattr and + * only for NFSv4.1 or higher. + * If moderet != 0, a mode attribute has also been + * specified and this attribute cannot be done in the + * same Setattr operation. + */ + if ((nd->nd_flag & ND_NFSV41) == 0) + nd->nd_repstat = NFSERR_ATTRNOTSUPP; + else if ((mode & ~07777) != 0 || (mask & ~07777) != 0 || + vp == NULL) + nd->nd_repstat = NFSERR_INVAL; + else if (moderet == 0) + moderet = VOP_GETATTR(vp, &va, nd->nd_cred); + if (moderet == 0) + nvap->na_mode = (mode & mask) | + (va.va_mode & ~mask); + else + nd->nd_repstat = moderet; + attrsum += 2 * NFSX_UNSIGNED; + break; default: nd->nd_repstat = NFSERR_ATTRNOTSUPP; /* diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index a641d8d4ee94..3bfe8f6444fd 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -464,13 +464,18 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, } } if (!nd->nd_repstat && - NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) { + (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) || + NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) { NFSVNO_ATTRINIT(&nva2); NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, exp); - if (!nd->nd_repstat) - NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); + if (!nd->nd_repstat) { + if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) + NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); + if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED)) + NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED); + } } #ifdef NFS4_ACL_EXTATTR_NAME