The branch main has been updated by rmacklem:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=0d51adee307296a8031afb75f95a013423f7c396

commit 0d51adee307296a8031afb75f95a013423f7c396
Author:     Rick Macklem <rmack...@freebsd.org>
AuthorDate: 2025-06-29 16:09:23 +0000
Commit:     Rick Macklem <rmack...@freebsd.org>
CommitDate: 2025-06-29 16:09:23 +0000

    nfsd: Use an NFSv4 ACL for the delegation ACE if available
    
    Without this patch, the ACE in a NFSv4 delegation reply is
    generated from the file's user mode bits.  This is correct
    in most situations, but not if the file has certain NFSv4 ACLs.
    
    This patch uses the @OWNER ACE in the NFSv4 ACL if it comes
    before any deny ACE and returns a "nil access" ACE if a
    deny preceeds the @OWNER.
    
    This change affects few NFSv4 clients, since most clients
    ignore the delegation access ACE and it only affects cases
    where the NFSv4 server is issuing delegations.
    
    Fixes:  8e2a90ac8089 ("nfscommon: Factor out conversion of ae_perm to NFSv4 
ACE flags")
---
 sys/fs/nfsserver/nfs_nfsdserv.c | 85 +++++++++++++++++++++++++++++++++++------
 1 file changed, 73 insertions(+), 12 deletions(-)

diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index e54cc594d611..4e15d55eb312 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -64,6 +64,7 @@ extern u_long sb_max_adj;
 extern int nfsrv_pnfsatime;
 extern int nfsrv_maxpnfsmirror;
 extern uint32_t nfs_srvmaxio;
+extern int nfsrv_issuedelegs;
 
 static int     nfs_async = 0;
 SYSCTL_DECL(_vfs_nfsd);
@@ -2866,6 +2867,8 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int 
isdgram,
        NFSACL_T *aclp = NULL;
        struct thread *p = curthread;
        bool done_namei;
+       __enum_uint8_decl(wdelegace) { USENONE, USEMODE, USENFSV4ACL }
+           delegace;
 
 #ifdef NFS4_ACL_EXTATTR_NAME
        aclp = acl_alloc(M_WAITOK);
@@ -2873,6 +2876,7 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int 
isdgram,
 #endif
        NFSZERO_ATTRBIT(&attrbits);
        done_namei = false;
+       delegace = USEMODE;
        named.ni_cnd.cn_nameiop = 0;
        NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
        i = fxdr_unsigned(int, *(tl + 5));
@@ -3214,6 +3218,25 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int 
isdgram,
 
        if (!nd->nd_repstat)
                nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
+
+       if (nd->nd_repstat == 0 && aclp != NULL && nfsrv_issuedelegs != 0 &&
+           (dp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) {
+               if (aclp->acl_cnt == 0 && create == NFSV4OPEN_NOCREATE) {
+                       int retacl;
+
+                       /* We do not yet have an ACL, so try and get one. */
+                       retacl = VOP_GETACL(vp, ACL_TYPE_NFS4, aclp,
+                           nd->nd_cred, p);
+                       if (retacl != 0 && retacl != ENOATTR &&
+                           retacl != EOPNOTSUPP && retacl != EINVAL)
+                               delegace = USENONE;
+                       else if (retacl == 0 && aclp->acl_cnt > 0)
+                               delegace = USENFSV4ACL;
+               } else if (aclp->acl_cnt > 0 && create == NFSV4OPEN_CREATE) {
+                       delegace = USENFSV4ACL;
+               }
+       }
+
        /*
         * Do the open locking/delegation stuff.
         */
@@ -3306,18 +3329,56 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int 
isdgram,
                                *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
                                txdr_hyper(nva.na_size, tl);
                        }
-                       NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
-                       *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
-                       *tl++ = txdr_unsigned(0x0);
-                       acemask = NFSV4ACE_ALLFILESMASK;
-                       if (nva.na_mode & S_IRUSR)
-                           acemask |= NFSV4ACE_READMASK;
-                       if (nva.na_mode & S_IWUSR)
-                           acemask |= NFSV4ACE_WRITEMASK;
-                       if (nva.na_mode & S_IXUSR)
-                           acemask |= NFSV4ACE_EXECUTEMASK;
-                       *tl = txdr_unsigned(acemask);
-                       (void) nfsm_strtom(nd, "OWNER@", 6);
+
+                       /* Set up the write delegation ACE. */
+                       NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+                       if (delegace == USENFSV4ACL) {
+                               int j;
+
+                               for (j = 0; j < aclp->acl_cnt; j++) {
+                                       if (aclp->acl_entry[j].ae_tag ==
+                                           ACL_USER_OBJ ||
+                                           aclp->acl_entry[j].ae_entry_type !=
+                                           ACL_ENTRY_TYPE_ALLOW)
+                                               break;
+                               }
+                               if (j < aclp->acl_cnt &&
+                                   aclp->acl_entry[j].ae_tag ==
+                                   ACL_USER_OBJ &&
+                                   aclp->acl_entry[j].ae_entry_type ==
+                                   ACL_ENTRY_TYPE_ALLOW) {
+                                       /* Use this ACE. */
+                                       *tl++ = txdr_unsigned(
+                                           NFSV4ACE_ALLOWEDTYPE);
+                                       *tl++ = txdr_unsigned(0x0);
+                                       *tl = txdr_unsigned(
+                                           nfs_aceperm(
+                                           aclp->acl_entry[j].ae_perm));
+                                       (void)nfsm_strtom(nd, "OWNER@", 6);
+                               } else
+                                       delegace = USENONE;
+                       }
+                       if (delegace == USENONE) {
+                               /* Don't allow anything. */
+                               *tl++ = 0x0;
+                               *tl++ = 0x0;
+                               *tl = 0x0;
+                               NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+                               *tl = 0;
+                       } else if (delegace == USEMODE) {
+                               /* Build from mode. */
+                               *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
+                               *tl++ = txdr_unsigned(0x0);
+                               acemask = NFSV4ACE_ALLFILESMASK;
+                               if (nva.na_mode & S_IRUSR)
+                                       acemask |= NFSV4ACE_READMASK;
+                               if (nva.na_mode & S_IWUSR)
+                                       acemask |= NFSV4ACE_WRITEMASK;
+                               if (nva.na_mode & S_IXUSR)
+                                       acemask |= NFSV4ACE_EXECUTEMASK;
+                               *tl = txdr_unsigned(acemask);
+                               (void)nfsm_strtom(nd, "OWNER@", 6);
+                       }
                }
                *vpp = vp;
        } else if (vp) {

Reply via email to