From f4179ad46fa4ff717557e5485072c004e6054416 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Sat, 1 Apr 2023 14:22:26 -0700 Subject: [PATCH] nfscommon: Add support for an NFSv4 operation bitmap NFSv4.1/4.2 uses operation bitmaps for various operations, such as the SP4_MACH_CRED case for ExchangeID. This patch adds support for operation bitmaps so that support for SP4_MACH_CRED can be added to the NFSv4.1/4.2 server in a future commit. This commit should not change any NFSv4.1/4.2 semantics. MFC after: 3 months --- sys/fs/nfs/nfs.h | 31 ++++++++++ sys/fs/nfs/nfs_commonsubs.c | 62 +++++++++++++++++++ sys/fs/nfs/nfs_var.h | 2 + sys/fs/nfs/nfsproto.h | 120 ++++++++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+) diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h index eac318512a35..9d0a2d8191b2 100644 --- a/sys/fs/nfs/nfs.h +++ b/sys/fs/nfs/nfs.h @@ -344,6 +344,7 @@ struct nfsreferral { #define LCL_RECLAIMONEFS 0x00080000 #define LCL_NFSV42 0x00100000 #define LCL_TLSCB 0x00200000 +#define LCL_MACHCRED 0x00400000 #define LCL_GSS LCL_KERBV /* Or of all mechs */ @@ -552,6 +553,34 @@ typedef struct { (b)->bits[2] = NFSATTRBIT_REFERRAL2; \ } while (0) +/* + * Here is the definition of the operation bits array and macros that + * manipulate it. + * THE MACROS MUST BE MANUALLY MODIFIED IF NFSOPBIT_MAXWORDS CHANGES!! + * It is (NFSV42_NOPS + 31) / 32. + */ +#define NFSOPBIT_MAXWORDS 3 + +typedef struct { + uint32_t bits[NFSOPBIT_MAXWORDS]; +} nfsopbit_t; + +#define NFSZERO_OPBIT(b) do { \ + (b)->bits[0] = 0; \ + (b)->bits[1] = 0; \ + (b)->bits[2] = 0; \ +} while (0) + +#define NFSSET_OPBIT(t, f) do { \ + (t)->bits[0] = (f)->bits[0]; \ + (t)->bits[1] = (f)->bits[1]; \ + (t)->bits[2] = (f)->bits[2]; \ +} while (0) + +#define NFSISSET_OPBIT(b, p) ((b)->bits[(p) / 32] & (1 << ((p) % 32))) +#define NFSSETBIT_OPBIT(b, p) ((b)->bits[(p) / 32] |= (1 << ((p) % 32))) +#define NFSCLRBIT_OPBIT(b, p) ((b)->bits[(p) / 32] &= ~(1 << ((p) % 32))) + /* * Store uid, gid creds that were used when the stateid was acquired. * The RPC layer allows NFS_MAXGRPS + 1 groups to go out on the wire, @@ -687,6 +716,7 @@ struct nfsrv_descript { int nd_bextpg; /* Current ext_pgs page */ int nd_bextpgsiz; /* Bytes left in page */ int nd_maxextsiz; /* Max ext_pgs mbuf size */ + nfsopbit_t nd_allowops; /* Allowed ops ND_MACHCRED */ }; #define nd_princlen nd_gssnamelen @@ -736,6 +766,7 @@ struct nfsrv_descript { #define ND_EXTLSCERT 0x10000000000 #define ND_EXTLSCERTUSER 0x20000000000 #define ND_ERELOOKUP 0x40000000000 +#define ND_MACHCRED 0x80000000000 /* * ND_GSS should be the "or" of all GSS type authentications. diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 48798087b177..81bd2beba749 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -1222,6 +1222,47 @@ nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, return (error); } +/* + * Get operation bits from an mbuf list. + * Returns EBADRPC for a parsing error, 0 otherwise. + */ +int +nfsrv_getopbits(struct nfsrv_descript *nd, nfsopbit_t *opbitp, int *cntp) +{ + uint32_t *tl; + int cnt, i, outcnt; + int error = 0; + + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + cnt = fxdr_unsigned(int, *tl); + if (cnt < 0) { + error = NFSERR_BADXDR; + goto nfsmout; + } + if (cnt > NFSOPBIT_MAXWORDS) + outcnt = NFSOPBIT_MAXWORDS; + else + outcnt = cnt; + NFSZERO_OPBIT(opbitp); + if (outcnt > 0) { + NFSM_DISSECT(tl, uint32_t *, outcnt * NFSX_UNSIGNED); + for (i = 0; i < outcnt; i++) + opbitp->bits[i] = fxdr_unsigned(uint32_t, *tl++); + } + for (i = 0; i < (cnt - outcnt); i++) { + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + if (*tl != 0) { + error = NFSERR_BADXDR; + goto nfsmout; + } + } + if (cntp != NULL) + *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); +nfsmout: + NFSEXITCODE2(error, nd); + return (error); +} + /* * Get the attributes for V4. * If the compare flag is true, test for any attribute changes, @@ -3142,6 +3183,27 @@ nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) return (bytesize); } +/* + * Put the operation bits onto an mbuf list. + * Return the number of bytes of output generated. + */ +int +nfsrv_putopbit(struct nfsrv_descript *nd, nfsopbit_t *opbitp) +{ + uint32_t *tl; + int cnt, i, bytesize; + + for (cnt = NFSOPBIT_MAXWORDS; cnt > 0; cnt--) + if (opbitp->bits[cnt - 1]) + break; + bytesize = (cnt + 1) * NFSX_UNSIGNED; + NFSM_BUILD(tl, uint32_t *, bytesize); + *tl++ = txdr_unsigned(cnt); + for (i = 0; i < cnt; i++) + *tl++ = txdr_unsigned(opbitp->bits[i]); + return (bytesize); +} + /* * Convert a uid to a string. * If the lookup fails, just output the digits. diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 55396bfb0902..ad1eb73b1090 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -337,6 +337,7 @@ int nfsrv_dissectacl(struct nfsrv_descript *, NFSACL_T *, bool, int *, int *, NFSPROC_T *); int nfsrv_getattrbits(struct nfsrv_descript *, nfsattrbit_t *, int *, int *); +int nfsrv_getopbits(struct nfsrv_descript *, nfsopbit_t *, int *); int nfsv4_loadattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, struct nfsfh **, fhandle_t *, int, struct nfsv3_pathconf *, struct statfs *, struct nfsstatfs *, @@ -391,6 +392,7 @@ int nfsd_excred(struct nfsrv_descript *, struct nfsexstuff *, struct ucred *, bool); int nfsrv_mtofh(struct nfsrv_descript *, struct nfsrvfh *); int nfsrv_putattrbit(struct nfsrv_descript *, nfsattrbit_t *); +int nfsrv_putopbit(struct nfsrv_descript *, nfsopbit_t *); void nfsrv_wcc(struct nfsrv_descript *, int, struct nfsvattr *, int, struct nfsvattr *); int nfsv4_fillattr(struct nfsrv_descript *, struct mount *, vnode_t, NFSACL_T *, diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h index ceecc63a7732..0d36ee84642a 100644 --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -1427,6 +1427,126 @@ struct nfsv3_sattr { #define NFSATTRBIT_REFERRAL1 NFSATTRBM_MOUNTEDONFILEID #define NFSATTRBIT_REFERRAL2 0 +/* Bits for the operations bitmaps. */ +#define NFSV4OPBM_ACCESS 0x00000008 +#define NFSV4OPBM_CLOSE 0x00000010 +#define NFSV4OPBM_COMMIT 0x00000020 +#define NFSV4OPBM_CREATE 0x00000040 +#define NFSV4OPBM_DELEGPURGE 0x00000080 +#define NFSV4OPBM_DELEGRETURN 0x00000100 +#define NFSV4OPBM_GETATTR 0x00000200 +#define NFSV4OPBM_GETFH 0x00000400 +#define NFSV4OPBM_LINK 0x00000800 +#define NFSV4OPBM_LOCK 0x00001000 +#define NFSV4OPBM_LOCKT 0x00002000 +#define NFSV4OPBM_LOCKU 0x00004000 +#define NFSV4OPBM_LOOKUP 0x00008000 +#define NFSV4OPBM_LOOKUPP 0x00010000 +#define NFSV4OPBM_NVERIFY 0x00020000 +#define NFSV4OPBM_OPEN 0x00040000 +#define NFSV4OPBM_OPENATTR 0x00080000 +#define NFSV4OPBM_OPENCONFIRM 0x00100000 +#define NFSV4OPBM_OPENDOWNGRADE 0x00200000 +#define NFSV4OPBM_PUTFH 0x00400000 +#define NFSV4OPBM_PUTPUBFH 0x00800000 +#define NFSV4OPBM_PUTROOTFH 0x01000000 +#define NFSV4OPBM_READ 0x02000000 +#define NFSV4OPBM_READDIR 0x04000000 +#define NFSV4OPBM_READLINK 0x08000000 +#define NFSV4OPBM_REMOVE 0x10000000 +#define NFSV4OPBM_RENAME 0x20000000 +#define NFSV4OPBM_RENEW 0x40000000 +#define NFSV4OPBM_RESTOREFH 0x80000000 +#define NFSV4OPBM_SAVEFH 0x00000001 +#define NFSV4OPBM_SECINFO 0x00000002 +#define NFSV4OPBM_SETATTR 0x00000004 +#define NFSV4OPBM_SETCLIENTID 0x00000008 +#define NFSV4OPBM_SETCLIENTIDCFRM 0x00000010 +#define NFSV4OPBM_VERIFY 0x00000020 +#define NFSV4OPBM_WRITE 0x00000040 +#define NFSV4OPBM_RELEASELCKOWN 0x00000080 +#define NFSV4OPBM_BACKCHANNELCTL 0x00000100 +#define NFSV4OPBM_BINDCONNTOSESS 0x00000200 +#define NFSV4OPBM_EXCHANGEID 0x00000400 +#define NFSV4OPBM_CREATESESSION 0x00000800 +#define NFSV4OPBM_DESTROYSESSION 0x00001000 +#define NFSV4OPBM_FREESTATEID 0x00002000 +#define NFSV4OPBM_GETDIRDELEG 0x00004000 +#define NFSV4OPBM_GETDEVINFO 0x00008000 +#define NFSV4OPBM_GETDEVLIST 0x00010000 +#define NFSV4OPBM_LAYOUTCOMMIT 0x00020000 +#define NFSV4OPBM_LAYOUTGET 0x00040000 +#define NFSV4OPBM_LAYOUTRETURN 0x00080000 +#define NFSV4OPBM_SECINFONONAME 0x00100000 +#define NFSV4OPBM_SEQUENCE 0x00200000 +#define NFSV4OPBM_SETSSV 0x00400000 +#define NFSV4OPBM_TESTSTATEID 0x00800000 +#define NFSV4OPBM_WANTDELEG 0x01000000 +#define NFSV4OPBM_DESTROYCLIENTID 0x02000000 +#define NFSV4OPBM_RECLAIMCOMPL 0x04000000 +#define NFSV4OPBM_ALLOCATE 0x08000000 +#define NFSV4OPBM_COPY 0x10000000 +#define NFSV4OPBM_COPYNOTIFY 0x20000000 +#define NFSV4OPBM_DEALLOCATE 0x40000000 +#define NFSV4OPBM_IOADVISE 0x80000000 +#define NFSV4OPBM_LAYOUTERROR 0x00000001 +#define NFSV4OPBM_LAYOUTSTATS 0x00000002 +#define NFSV4OPBM_OFFLOADCANCEL 0x00000004 +#define NFSV4OPBM_OFFLOADSTATUS 0x00000008 +#define NFSV4OPBM_READPLUS 0x00000010 +#define NFSV4OPBM_SEEK 0x00000020 +#define NFSV4OPBM_WRITESAME 0x00000040 +#define NFSV4OPBM_CLONE 0x00000080 +#define NFSV4OPBM_GETXATTR 0x00000100 +#define NFSV4OPBM_SETXATTR 0x00000200 +#define NFSV4OPBM_LISTXATTRS 0x00000400 +#define NFSV4OPBM_REMOVEXATTR 0x00000800 + +/* + * The set of must and allow operations for SP4_MACH_CRED. These are + * the operations requested by the Linux NFSv4.1/4.2 client. + * The must list is also the same ones listed in the RFC. + */ +#define NFSOPBIT_MUST0 NFSV4OP_DELEGPURGE + +#define NFSOPBIT_MUST1 \ + (NFSV4OPBM_BINDCONNTOSESS | \ + NFSV4OPBM_EXCHANGEID | \ + NFSV4OPBM_CREATESESSION | \ + NFSV4OPBM_DESTROYSESSION | \ + NFSV4OPBM_DESTROYCLIENTID) + +#define NFSOPBIT_MUST2 0x0 + +#define NFSOPBIT_CLRNOTMUST(b) do { \ + (b)->bits[0] &= NFSOPBIT_MUST0; \ + (b)->bits[1] &= NFSOPBIT_MUST1; \ + (b)->bits[2] &= NFSOPBIT_MUST2; \ + } while (0) + +#define NFSOPBIT_ALLOWED0 \ + (NFSV4OPBM_CLOSE | \ + NFSV4OPBM_COMMIT | \ + NFSV4OPBM_DELEGRETURN | \ + NFSV4OPBM_LOCKU | \ + NFSV4OPBM_OPENDOWNGRADE) + +#define NFSOPBIT_ALLOWED1 \ + (NFSV4OPBM_SECINFO | \ + NFSV4OPBM_WRITE | \ + NFSV4OPBM_FREESTATEID | \ + NFSV4OPBM_LAYOUTRETURN | \ + NFSV4OPBM_SECINFONONAME | \ + NFSV4OPBM_TESTSTATEID) + +#define NFSOPBIT_ALLOWED2 0x0 + +#define NFSOPBIT_CLRNOTALLOWED(b) do { \ + (b)->bits[0] &= NFSOPBIT_ALLOWED0; \ + (b)->bits[1] &= NFSOPBIT_ALLOWED1; \ + (b)->bits[2] &= NFSOPBIT_ALLOWED2; \ + } while (0) + /* * Structure for data handled by the statfs rpc. Since some fields are * u_int64_t, this cannot be used for copying data on/off the wire, due