nfs4_acls: Add additional owner entry when mapping to NFS4 ACL with IDMAP_TYPE_BOTH
authorChristof Schmitt <cs@samba.org>
Wed, 17 Jul 2019 17:49:47 +0000 (10:49 -0700)
committerChristof Schmitt <cs@samba.org>
Tue, 23 Jul 2019 18:27:27 +0000 (18:27 +0000)
With IDMAP_TYPE_BOTH, all entries have to be mapped to group entries.
In order to have the file system reflect the owner permissions in the
POSIX modebits, create a second entry for the user. This will be mapped
to the "special owner" entry.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032

Signed-off-by: Christof Schmitt <cs@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/modules/nfs4_acls.c
source3/modules/test_nfs4_acls.c

index 071f2caf55244346faeeaaf525ec5b4095e306ff..485fd784aa030e3522f136b662dfaf083ae257a0 100644 (file)
@@ -719,6 +719,9 @@ static int smbacl4_fill_ace4(
 {
        struct dom_sid_buf buf;
        SMB_ACE4PROP_T nfs4_ace = { 0 };
+       SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
+       bool add_ace2 = false;
+       int ret;
 
        DEBUG(10, ("got ace for %s\n",
                   dom_sid_str_buf(&ace_nt->trustee, &buf)));
@@ -789,6 +792,29 @@ static int smbacl4_fill_ace4(
                case ID_TYPE_BOTH:
                        nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
                        nfs4_ace.who.gid = unixid.id;
+
+                       if (ownerUID == unixid.id &&
+                           !nfs_ace_is_inherit(&nfs4_ace))
+                       {
+                               /*
+                                * IDMAP_TYPE_BOTH for owner. Add
+                                * additional user entry, which can be
+                                * mapped to special:owner to reflect
+                                * the permissions in the modebits.
+                                *
+                                * This only applies to non-inheriting
+                                * entries as only these are replaced
+                                * with SPECIAL_OWNER in nfs4:mode=simple.
+                                */
+                               nfs4_ace_2 = (SMB_ACE4PROP_T) {
+                                       .who.uid = unixid.id,
+                                       .aceFlags = (nfs4_ace.aceFlags &
+                                                   ~SMB_ACE4_IDENTIFIER_GROUP),
+                                       .aceMask = nfs4_ace.aceMask,
+                                       .aceType = nfs4_ace.aceType,
+                               };
+                               add_ace2 = true;
+                       }
                        break;
                case ID_TYPE_GID:
                        nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
@@ -805,7 +831,16 @@ static int smbacl4_fill_ace4(
                }
        }
 
-       return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
+       ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
+       if (ret != 0) {
+               return -1;
+       }
+
+       if (!add_ace2) {
+               return 0;
+       }
+
+       return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
 }
 
 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
index d7152a0737a9377675787e5478d313eabe9c52cc..170a397579a2c4ffb843054bf2ae249b94d9ec29 100644 (file)
@@ -1671,6 +1671,7 @@ struct dacl_to_nfs4_idmap_both {
        uint32_t nfs4_flags;
        uint32_t nfs4_ace_flags;
        uint32_t nfs4_id;
+       int num_nfs4_aces;
 };
 
 /*
@@ -1684,13 +1685,17 @@ static void test_dacl_to_nfs4_idmap_type_both(void **state)
 
        struct dacl_to_nfs4_idmap_both dacl_to_nfs4_idmap_both[] = {
        { &sids[2], 0,
-         SMB_ACE4_ID_SPECIAL, SMB_ACE4_IDENTIFIER_GROUP, SMB_ACE4_WHO_GROUP },
+         SMB_ACE4_ID_SPECIAL, SMB_ACE4_IDENTIFIER_GROUP, SMB_ACE4_WHO_GROUP,
+         2 },
        { &sids[2], SEC_ACE_FLAG_OBJECT_INHERIT,
-         0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1002 },
+         0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1002,
+         1 },
        { &sids[6], 0,
-         0, SMB_ACE4_IDENTIFIER_GROUP, 1005 },
+         0, SMB_ACE4_IDENTIFIER_GROUP, 1005,
+         1 },
        { &sids[6], SEC_ACE_FLAG_OBJECT_INHERIT,
-         0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1005 },
+         0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1005,
+         1 },
        };
 
        for (i = 0; i < ARRAY_SIZE(dacl_to_nfs4_idmap_both); i++) {
@@ -1720,11 +1725,11 @@ static void test_dacl_to_nfs4_idmap_type_both(void **state)
                assert_non_null(nfs4_acl);
                assert_int_equal(smbacl4_get_controlflags(nfs4_acl),
                                 SEC_DESC_SELF_RELATIVE);
-               assert_int_equal(smb_get_naces(nfs4_acl), 1);
+               assert_int_equal(smb_get_naces(nfs4_acl),
+                                dacl_to_nfs4_idmap_both[i].num_nfs4_aces);
 
                nfs4_ace_container = smb_first_ace4(nfs4_acl);
                assert_non_null(nfs4_ace_container);
-               assert_null(smb_next_ace4(nfs4_ace_container));
 
                nfs4_ace = smb_get_ace4(nfs4_ace_container);
                assert_int_equal(nfs4_ace->flags,
@@ -1744,6 +1749,28 @@ static void test_dacl_to_nfs4_idmap_type_both(void **state)
                assert_int_equal(nfs4_ace->aceType,
                                 SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE);
                assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA);
+
+               if (dacl_to_nfs4_idmap_both[i].num_nfs4_aces == 2) {
+                       nfs4_ace_container = smb_next_ace4(nfs4_ace_container);
+                       assert_non_null(nfs4_ace_container);
+
+                       nfs4_ace = smb_get_ace4(nfs4_ace_container);
+                       assert_int_equal(nfs4_ace->flags,
+                                        dacl_to_nfs4_idmap_both[i].nfs4_flags);
+                       assert_int_equal(nfs4_ace->aceFlags,
+                                        dacl_to_nfs4_idmap_both[i].nfs4_ace_flags &
+                                        ~SMB_ACE4_IDENTIFIER_GROUP);
+                       if (nfs4_ace->flags & SMB_ACE4_ID_SPECIAL) {
+                               assert_int_equal(nfs4_ace->who.special_id,
+                                                SMB_ACE4_WHO_OWNER);
+                       } else {
+                               assert_int_equal(nfs4_ace->who.uid,
+                                                dacl_to_nfs4_idmap_both[i].nfs4_id);
+                       }
+                       assert_int_equal(nfs4_ace->aceType,
+                                        SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE);
+                       assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA);
+               }
        }
 
        TALLOC_FREE(frame);