The branch main has been updated by rmacklem:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=949cff4dceffdbee70fa7741c1d61cf6c5255aeb

commit 949cff4dceffdbee70fa7741c1d61cf6c5255aeb
Author:     Rick Macklem <[email protected]>
AuthorDate: 2025-12-22 01:07:10 +0000
Commit:     Rick Macklem <[email protected]>
CommitDate: 2025-12-22 01:07:10 +0000

    nfscommon: Add some support for POSIX draft ACLs
    
    An internet draft (expected to become an RFC someday)
    https://datatracker.ietf.org/doc/draft-ietf-nfsv4-posix-acls
    describes an extension to NFSv4.2 to handle POSIX draft ACLs.
    
    This is the third of several patches that implement the
    above draft.
    
    There should be no semantics change for the series at
    this point.
    
    Fixes:  a35bbd5d9f5f ("nfscommon: Add some support for POSIX draft ACLs")
---
 sys/fs/nfs/nfs_commonacl.c  | 195 ++++++++++++++++++++++++++++++-
 sys/fs/nfs/nfs_commonsubs.c | 272 ++++++++++++++++++++++++++++++++++++++++----
 sys/fs/nfs/nfs_var.h        |   3 +
 3 files changed, 445 insertions(+), 25 deletions(-)

diff --git a/sys/fs/nfs/nfs_commonacl.c b/sys/fs/nfs/nfs_commonacl.c
index bba1d8821a9b..2120b095823b 100644
--- a/sys/fs/nfs/nfs_commonacl.c
+++ b/sys/fs/nfs/nfs_commonacl.c
@@ -36,7 +36,7 @@ static int nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t 
mask, int owner,
     __enum_uint8(vtype) type, acl_perm_t *permp);
 
 /*
- * Handle xdr for an ace.
+ * Handle xdr for an NFSv4 ace.
  */
 int
 nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep,
@@ -181,6 +181,84 @@ nfsmout:
        return (error);
 }
 
+static acl_tag_t nfsv4_to_posixacltag[NFSV4_POSIXACL_TAG_OTHER + 1] =
+    { ACL_UNDEFINED_TAG, ACL_USER_OBJ, ACL_USER, ACL_GROUP_OBJ,
+    ACL_GROUP, ACL_MASK, ACL_OTHER };
+
+/*
+ * Handle xdr for a POSIX draft ace.
+ */
+int
+nfsrv_dissectposixace(struct nfsrv_descript *nd, struct acl_entry *acep,
+    bool server, int *aceerrp, int *acesizep)
+{
+       uint32_t *tl, tag;
+       int len, error = 0, aceerr = 0;
+       u_char *name, namestr[NFSV4_SMALLSTR + 1];
+       gid_t gid;
+       uid_t uid;
+
+       *aceerrp = 0;
+       NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+       tag = fxdr_unsigned(uint32_t, *tl++);
+       acep->ae_perm = fxdr_unsigned(acl_perm_t, *tl++);
+       len = fxdr_unsigned(int, *tl);
+       /*
+        * The RFCs do not specify a limit to the length of the "who", but
+        * NFSV4_OPAQUELIMIT (1024) should be sufficient.
+        */
+       if (len < 0 || len > NFSV4_OPAQUELIMIT) {
+               error = NFSERR_BADXDR;
+               goto nfsmout;
+       }
+       if (tag < NFSV4_POSIXACL_TAG_USER_OBJ ||
+           tag > NFSV4_POSIXACL_TAG_OTHER) {
+               error = NFSERR_ATTRNOTSUPP;
+               goto nfsmout;
+       }
+       acep->ae_tag = nfsv4_to_posixacltag[tag];
+       if (len > NFSV4_SMALLSTR)
+               name = malloc(len + 1, M_NFSSTRING, M_WAITOK);
+       else
+               name = namestr;
+       if (len > 0)
+               error = nfsrv_mtostr(nd, name, len);
+       if (error != 0) {
+               if (len > NFSV4_SMALLSTR)
+                       free(name, M_NFSSTRING);
+               goto nfsmout;
+       }
+       switch (acep->ae_tag) {
+       case ACL_USER:
+               aceerr = nfsv4_strtouid(nd, name, len, &uid);
+               if (aceerr == 0)
+                       acep->ae_id = uid;
+               break;
+       case ACL_GROUP:
+               aceerr = nfsv4_strtogid(nd, name, len, &gid);
+               if (aceerr == 0)
+                       acep->ae_id = (uid_t)gid;
+               break;
+       case ACL_USER_OBJ:
+       case ACL_GROUP_OBJ:
+       case ACL_MASK:
+       case ACL_OTHER:
+               break;
+       default:
+               aceerr = NFSERR_ATTRNOTSUPP;
+       }
+       if (len > NFSV4_SMALLSTR)
+               free(name, M_NFSSTRING);
+
+       *aceerrp = aceerr;
+       if (acesizep != NULL)
+               *acesizep = NFSM_RNDUP(len) + (3 * NFSX_UNSIGNED);
+       error = 0;
+nfsmout:
+       NFSEXITCODE(error);
+       return (error);
+}
+
 /*
  * Turn an NFSv4 ace mask into R/W/X flag bits.
  */
@@ -277,9 +355,11 @@ out:
 /* local functions */
 static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int,
     __enum_uint8(vtype), int, int, struct acl_entry *);
+static int nfsrv_buildposixace(struct nfsrv_descript *, u_char *, int,
+    struct acl_entry *);
 
 /*
- * This function builds an NFS ace.
+ * This function builds an NFSv4 ace.
  */
 static int
 nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen,
@@ -399,6 +479,59 @@ nfs_aceperm(acl_perm_t ae_perm)
        return (acemask);
 }
 
+/*
+ * This function builds a POSIX draft ace.
+ */
+static int
+nfsrv_buildposixace(struct nfsrv_descript *nd, u_char *name, int namelen,
+    struct acl_entry *ace)
+{
+       uint32_t *tl;
+       int full_len;
+
+       full_len = NFSM_RNDUP(namelen);
+       NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED + full_len);
+
+       /*
+        * Fill in the ace tag.
+        */
+       switch (ace->ae_tag) {
+       case ACL_USER_OBJ:
+               *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_USER_OBJ);
+               break;
+       case ACL_USER:
+               *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_USER);
+               break;
+       case ACL_GROUP_OBJ:
+               *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_GROUP_OBJ);
+               break;
+       case ACL_GROUP:
+               *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_GROUP);
+               break;
+       case ACL_MASK:
+               *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_MASK);
+               break;
+       case ACL_OTHER:
+               *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_OTHER);
+               break;
+       default:
+               printf("nfsrv_buildposixace: bad ae_tag 0x%x\n", ace->ae_tag);
+               *tl++ = txdr_unsigned(0);
+       }
+
+       /*
+        * Fill in the permission bits.
+        */
+       *tl++ = txdr_unsigned(ace->ae_perm);
+       *tl++ = txdr_unsigned(namelen);
+       if (namelen > 0) {
+               if (full_len - namelen)
+                       *(tl + (namelen / NFSX_UNSIGNED)) = 0x0;
+               memcpy(tl, name, namelen);
+       }
+       return (full_len + 3 * NFSX_UNSIGNED);
+}
+
 /*
  * Build an NFSv4 ACL.
  */
@@ -461,6 +594,64 @@ nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, 
__enum_uint8(vtype) ty
        return (retlen);
 }
 
+/*
+ * Build a POSIX draft ACL.
+ */
+int
+nfsrv_buildposixacl(struct nfsrv_descript *nd, NFSACL_T *aclp,
+    acl_type_t acltype)
+{
+       int i, entrycnt = 0, retlen;
+       uint32_t *entrycntp;
+       unsigned int cnt;
+       int namelen;
+       u_char *name, namestr[NFSV4_SMALLSTR];
+       bool malloced;
+
+       NFSM_BUILD(entrycntp, uint32_t *, NFSX_UNSIGNED);
+       retlen = NFSX_UNSIGNED;
+       cnt = 0;
+       if (aclp != NULL)
+               cnt = aclp->acl_cnt;
+       /*
+        * Loop through the acl entries, building each one.
+        */
+       for (i = 0; i < cnt; i++) {
+               malloced = false;
+               switch (aclp->acl_entry[i].ae_tag) {
+               case ACL_USER_OBJ:
+               case ACL_GROUP_OBJ:
+               case ACL_OTHER:
+               case ACL_MASK:
+                       namelen = 0;
+                       break;
+               case ACL_USER:
+                       name = namestr;
+                       nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name,
+                           &namelen);
+                       if (name != namestr)
+                               malloced = true;
+                       break;
+               case ACL_GROUP:
+                       name = namestr;
+                       nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name,
+                           &namelen);
+                       if (name != namestr)
+                               malloced = true;
+                       break;
+               default:
+                       continue;
+               }
+               retlen += nfsrv_buildposixace(nd, name, namelen,
+                   &aclp->acl_entry[i]);
+               entrycnt++;
+               if (malloced)
+                       free(name, M_NFSSTRING);
+       }
+       *entrycntp = txdr_unsigned(entrycnt);
+       return (retlen);
+}
+
 /*
  * Compare two NFSv4 acls.
  * Return 0 if they are the same, 1 if not the same.
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 707ad5749ab2..2b0ce45d05dd 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -228,7 +228,7 @@ static bool nfs_bigreply[NFSV42_NPROCS] = {
 };
 
 /* local functions */
-static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
+static int nfsrv_skipace(struct nfsrv_descript *nd, acl_type_t, int *acesizep);
 static void nfsv4_wanted(struct nfsv4lock *lp);
 static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
@@ -240,6 +240,7 @@ static uint32_t vtonfsv4_type(struct vattr *);
 static __enum_uint8(vtype) nfsv4tov_type(uint32_t, uint16_t *);
 static void nfsv4_setsequence(struct nfsmount *, struct nfsrv_descript *,
     struct nfsclsession *, bool, struct ucred *);
+static uint32_t nfs_trueform(struct vnode *);
 
 static struct {
        int     op;
@@ -1149,18 +1150,19 @@ int
 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool server,
     int *aclerrp, int *aclsizep, __unused NFSPROC_T *p)
 {
-       u_int32_t *tl;
+       uint32_t *tl;
        int i, aclsize;
        int acecnt, error = 0, aceerr = 0, acesize;
+       bool posixacl = false;
 
        *aclerrp = 0;
-       if (aclp)
+       if (aclp != NULL)
                aclp->acl_cnt = 0;
        /*
         * Parse out the ace entries and expect them to conform to
         * what can be supported by R/W/X bits.
         */
-       NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+       NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
        aclsize = NFSX_UNSIGNED;
        acecnt = fxdr_unsigned(int, *tl);
        /*
@@ -1176,20 +1178,28 @@ nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T 
*aclp, bool server,
        if (nfsrv_useacl == 0)
                aceerr = NFSERR_ATTRNOTSUPP;
        for (i = 0; i < acecnt; i++) {
-               if (aclp && !aceerr)
-                       error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
-                           server, &aceerr, &acesize, p);
+               if (aclp != NULL && aceerr == 0) {
+                       if (posixacl)
+                               error = nfsrv_dissectposixace(nd,
+                                   &aclp->acl_entry[i], server, &aceerr,
+                                   &acesize);
+                       else
+                               error = nfsrv_dissectace(nd,
+                                   &aclp->acl_entry[i], server, &aceerr,
+                                   &acesize, p);
+               } else if (posixacl)
+                       error = nfsrv_skipace(nd, ACL_TYPE_ACCESS, &acesize);
                else
-                       error = nfsrv_skipace(nd, &acesize);
-               if (error)
+                       error = nfsrv_skipace(nd, ACL_TYPE_NFS4, &acesize);
+               if (error != 0)
                        goto nfsmout;
                aclsize += acesize;
        }
-       if (aclp && !aceerr)
+       if (aclp != NULL && aceerr == 0)
                aclp->acl_cnt = acecnt;
-       if (aceerr)
+       if (aceerr != 0)
                *aclerrp = aceerr;
-       if (aclsizep)
+       if (aclsizep != NULL)
                *aclsizep = aclsize;
 nfsmout:
        NFSEXITCODE2(error, nd);
@@ -1200,16 +1210,22 @@ nfsmout:
  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
  */
 static int
-nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
+nfsrv_skipace(struct nfsrv_descript *nd, acl_type_t acltype, int *acesizep)
 {
-       u_int32_t *tl;
+       uint32_t *tl;
        int error, len = 0;
 
-       NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
-       len = fxdr_unsigned(int, *(tl + 3));
+       if (acltype == ACL_TYPE_NFS4) {
+               NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
+               len = fxdr_unsigned(int, *(tl + 3));
+               *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
+       } else {
+               NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+               len = fxdr_unsigned(int, *(tl + 2));
+               *acesizep = NFSM_RNDUP(len) + (3 * NFSX_UNSIGNED);
+       }
        error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 nfsmout:
-       *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
        NFSEXITCODE2(error, nd);
        return (error);
 }
@@ -1437,6 +1453,11 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
                                NFSCLRBIT_ATTRBIT(&checkattrbits, 
NFSATTRBIT_ACL);
                                NFSCLRBIT_ATTRBIT(&checkattrbits, 
NFSATTRBIT_ACLSUPPORT);
                           }
+                          /* Some filesystem do not support POSIX ACL   */
+                          if (nfsrv_useacl == 0 || nfs_supportsposixacls(vp) 
== 0) {
+                               NFSCLRBIT_ATTRBIT(&checkattrbits, 
NFSATTRBIT_POSIXACCESSACL);
+                               NFSCLRBIT_ATTRBIT(&checkattrbits, 
NFSATTRBIT_POSIXDEFAULTACL);
+                          }
                           /* Some filesystems do not support uf_hidden */
                           if (vp == NULL || VOP_PATHCONF(vp,
                                _PC_HAS_HIDDENSYSTEM, &has_pathconf) != 0)
@@ -1655,7 +1676,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
                                if (error)
                                    goto nfsmout;
                        }
-                       
+
                        attrsum += cnt;
                        break;
                case NFSATTRBIT_ACLSUPPORT:
@@ -2440,6 +2461,111 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
                        }
                        attrsum += NFSX_UNSIGNED;
                        break;
+               case NFSATTRBIT_ACLTRUEFORM:
+                       NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+                       if (compare) {
+                               if (!(*retcmpp)) {
+                                       tuint = nfs_trueform(vp);
+                                       if (tuint != fxdr_unsigned(uint32_t,
+                                           *tl))
+                                               *retcmpp = NFSERR_NOTSAME;
+                               }
+#ifdef notyet
+                       } else if (trueformp != NULL) {
+                               *trueformp = fxdr_unsigned(uint32_t, *tl);
+                       }
+#else
+                       }
+#endif
+                       attrsum += NFSX_UNSIGNED;
+                       break;
+               case NFSATTRBIT_ACLTRUEFORMSCOPE:
+                       NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+                       if (compare) {
+                               if (!(*retcmpp)) {
+                                       if (fxdr_unsigned(uint32_t, *tl) !=
+                                           NFSV4_ACL_SCOPE_FILE_SYSTEM)
+                                               *retcmpp = NFSERR_NOTSAME;
+                               }
+                       }
+                       attrsum += NFSX_UNSIGNED;
+                       break;
+               case NFSATTRBIT_POSIXACCESSACL:
+                       if (compare) {
+                         if (!(*retcmpp)) {
+                           if (nfsrv_useacl && nfs_supportsposixacls(vp)) {
+                               NFSACL_T *naclp;
+
+                               naclp = acl_alloc(M_WAITOK);
+                               error = nfsrv_dissectacl(nd, naclp, true,
+                                   &aceerr, &cnt, p);
+                               if (error) {
+                                   acl_free(naclp);
+                                   goto nfsmout;
+                               }
+                               if (aceerr || aclp == NULL ||
+                                   nfsrv_compareacl(aclp, naclp))
+                                   *retcmpp = NFSERR_NOTSAME;
+                               acl_free(naclp);
+                           } else {
+                               error = nfsrv_dissectacl(nd, NULL, true,
+                                   &aceerr, &cnt, p);
+                               if (error)
+                                   goto nfsmout;
+                               *retcmpp = NFSERR_ATTRNOTSUPP;
+                           }
+                         }
+                       } else {
+                               if (vp != NULL && aclp != NULL)
+                                   error = nfsrv_dissectacl(nd, aclp, false,
+                                       &aceerr, &cnt, p);
+                               else
+                                   error = nfsrv_dissectacl(nd, NULL, false,
+                                       &aceerr, &cnt, p);
+                               if (error)
+                                   goto nfsmout;
+                       }
+
+                       attrsum += cnt;
+                       break;
+               case NFSATTRBIT_POSIXDEFAULTACL:
+                       if (compare) {
+                         if (!(*retcmpp)) {
+                           if (nfsrv_useacl && nfs_supportsposixacls(vp)) {
+                               NFSACL_T *naclp;
+
+                               naclp = acl_alloc(M_WAITOK);
+                               error = nfsrv_dissectacl(nd, naclp, true,
+                                   &aceerr, &cnt, p);
+                               if (error) {
+                                   acl_free(naclp);
+                                   goto nfsmout;
+                               }
+                               if (aceerr || aclp == NULL ||
+                                   nfsrv_compareacl(aclp, naclp))
+                                   *retcmpp = NFSERR_NOTSAME;
+                               acl_free(naclp);
+                           } else {
+                               error = nfsrv_dissectacl(nd, NULL, true,
+                                   &aceerr, &cnt, p);
+                               if (error)
+                                   goto nfsmout;
+                               *retcmpp = NFSERR_ATTRNOTSUPP;
+                           }
+                         }
+                       } else {
+                               if (vp != NULL && aclp != NULL)
+                                   error = nfsrv_dissectacl(nd, aclp, false,
+                                       &aceerr, &cnt, p);
+                               else
+                                   error = nfsrv_dissectacl(nd, NULL, false,
+                                       &aceerr, &cnt, p);
+                               if (error)
+                                   goto nfsmout;
+                       }
+
+                       attrsum += cnt;
+                       break;
                default:
                        printf("EEK! nfsv4_loadattr unknown attr=%d\n",
                                bitpos);
@@ -2711,7 +2837,8 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount 
*mp, vnode_t vp,
        struct statfs *fs;
        struct nfsfsinfo fsinf;
        struct timespec temptime;
-       NFSACL_T *aclp, *naclp = NULL;
+       NFSACL_T *aclp, *naclp = NULL, *paclp, *npaclp = NULL, *daclp;
+       NFSACL_T *ndaclp = NULL;
        short irflag;
 #ifdef QUOTA
        struct dqblk dqb;
@@ -2730,11 +2857,21 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount 
*mp, vnode_t vp,
         */
        if (p == NULL && cred == NULL) {
                NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
-               aclp = saclp;
+               /* Only one of the ACL types can be set for a call. */
+               if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL))
+                       aclp = saclp;
+               else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL))
+                       paclp = saclp;
+               else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL))
+                       daclp = saclp;
        } else {
                NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
                naclp = acl_alloc(M_WAITOK);
                aclp = naclp;
+               npaclp = acl_alloc(M_WAITOK);
+               paclp = npaclp;
+               ndaclp = acl_alloc(M_WAITOK);
+               daclp = ndaclp;
        }
        nfsvno_getfs(&fsinf, isdgram);
        /*
@@ -2769,12 +2906,12 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount 
*mp, vnode_t vp,
         */
        if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
            (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
-               supports_nfsv4acls == 0))) {
+               supports_nfsv4acls != SUPPACL_NFSV4))) {
                NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
        }
        if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
                if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
-                   supports_nfsv4acls == 0)) {
+                   supports_nfsv4acls != SUPPACL_NFSV4)) {
                        NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
                } else if (naclp != NULL) {
                        if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
@@ -2796,6 +2933,49 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount 
*mp, vnode_t vp,
                }
        }
 
+       /* and the POSIX draft ACL. */
+       if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL)) {
+               if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
+                   supports_nfsv4acls != SUPPACL_POSIX)) {
+                       NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL);
+               } else if (npaclp != NULL) {
+                       if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
+                               error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
+                               if (error == 0)
+                                       error = VOP_GETACL(vp, ACL_TYPE_ACCESS,
+                                           npaclp, cred, p);
+                               NFSVOPUNLOCK(vp);
+                       } else
+                               error = NFSERR_PERM;
+                       if (error != 0) {
+                               if (reterr) {
+                                       nd->nd_repstat = NFSERR_INVAL;
+                                       free(fs, M_STATFS);
+                                       return (0);
+                               }
+                               NFSCLRBIT_ATTRBIT(retbitp,
+                                   NFSATTRBIT_POSIXACCESSACL);
+                       }
+               }
+       }
+       if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL)) {
+               if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
+                   supports_nfsv4acls != SUPPACL_POSIX)) {
+                       NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL);
+               } else if (ndaclp != NULL) {
+                       if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
+                               error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
+                               if (error == 0)
+                                       error = VOP_GETACL(vp, ACL_TYPE_DEFAULT,
+                                           ndaclp, cred, p);
+                               NFSVOPUNLOCK(vp);
+                       } else
+                               error = NFSERR_PERM;
+                       if (error != 0)
+                               ndaclp->acl_cnt = 0;
+               }
+       }
+
        /*
         * Put out the attribute bitmap for the ones being filled in
         * and get the field for the number of attributes returned.
@@ -2813,10 +2993,17 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount 
*mp, vnode_t vp,
                case NFSATTRBIT_SUPPORTEDATTRS:
                        NFSSETSUPP_ATTRBIT(&attrbits, nd);
                        if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
-                           && supports_nfsv4acls == 0)) {
+                           && supports_nfsv4acls != SUPPACL_NFSV4)) {
                            NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
                            NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
                        }
+                       if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
+                           && supports_nfsv4acls != SUPPACL_POSIX)) {
+                               NFSCLRBIT_ATTRBIT(&attrbits,
+                                   NFSATTRBIT_POSIXACCESSACL);
+                               NFSCLRBIT_ATTRBIT(&attrbits,
+                                   NFSATTRBIT_POSIXDEFAULTACL);
+                       }
                        if (!has_hiddensystem) {
                            NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
                            NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
@@ -3321,6 +3508,24 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount 
*mp, vnode_t vp,
                        *tl = txdr_unsigned(clone_blksize);
                        retnum += NFSX_UNSIGNED;
                        break;
+               case NFSATTRBIT_ACLTRUEFORM:
+                       NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+                       *tl = txdr_unsigned(nfs_trueform(vp));
+                       retnum += NFSX_UNSIGNED;
+                       break;
+               case NFSATTRBIT_ACLTRUEFORMSCOPE:
+                       NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+                       *tl = txdr_unsigned(NFSV4_ACL_SCOPE_FILE_SYSTEM);
+                       retnum += NFSX_UNSIGNED;
+                       break;
+               case NFSATTRBIT_POSIXACCESSACL:
+                       retnum += nfsrv_buildposixacl(nd, paclp,
+                           ACL_TYPE_ACCESS);
+                       break;
+               case NFSATTRBIT_POSIXDEFAULTACL:
+                       retnum += nfsrv_buildposixacl(nd, daclp,
+                           ACL_TYPE_DEFAULT);
+                       break;
                default:
                        printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
                }
@@ -3328,6 +3533,10 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount 
*mp, vnode_t vp,
        }
        if (naclp != NULL)
                acl_free(naclp);
+       if (npaclp != NULL)
+               acl_free(npaclp);
+       if (ndaclp != NULL)
+               acl_free(ndaclp);
        free(fs, M_STATFS);
        *retnump = txdr_unsigned(retnum);
        return (retnum + prefixnum);
@@ -5346,6 +5555,23 @@ nfsrpc_destroysession(struct nfsmount *nmp, struct 
nfsclsession *tsep,
        return (error);
 }
 
+/*
+ * Determine the true form (the type of ACL stored on the file) for the
+ * vnode argument.
+ */
+static uint32_t
+nfs_trueform(struct vnode *vp)
+{
+       uint32_t trueform;
+
+       trueform = NFSV4_ACL_MODEL_NONE;
+       if ((vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0)
+               trueform = NFSV4_ACL_MODEL_NFS4;
+       else if ((vp->v_mount->mnt_flag & MNT_ACLS) != 0)
+               trueform = NFSV4_ACL_MODEL_POSIX_DRAFT;
+       return (trueform);
+}
+
 /*
  * Translate a vnode type into an NFSv4 type, including the named
  * attribute types.
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 49a94323a572..c04c3951d42d 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -443,8 +443,11 @@ int nfs_supportsposixacls(struct vnode *);
 int nfsrv_dissectace(struct nfsrv_descript *, struct acl_entry *,
     bool, int *, int *, NFSPROC_T *);
 uint32_t nfs_aceperm(acl_perm_t);
+int nfsrv_dissectposixace(struct nfsrv_descript *, struct acl_entry *,
+    bool, int *, int *);
 int nfsrv_buildacl(struct nfsrv_descript *, NFSACL_T *, __enum_uint8(vtype),
     NFSPROC_T *);
+int nfsrv_buildposixacl(struct nfsrv_descript *, NFSACL_T *, acl_type_t);
 int nfsrv_compareacl(NFSACL_T *, NFSACL_T *);
 
 /* nfs_clrpcops.c */

Reply via email to