From: Vincent Povirk Subject: [1/2] server: Include group permissions in reported file dacl's. Message-Id: Date: Tue, 15 Apr 2014 13:29:56 -0500 This requires adding a todo, but that test only passed earlier by coincidence. It expected 2 entries (current user and Administrators) and got 2 entries (Local System and current user). Now it gets 3 entries (Local System, current user, and Administrator). So even though we have an additional todo, I would argue that the new behavior is closer to what the test expects. This makes it possible to round-trip file security descriptors and preserve the group permissions (which we already map to unix file modes when setting permissions). Office uses this technique to save over an existing file (by moving a new one on top of it) while preserving the file's permissions. From c5bbd4c5ac0ed87e486c34c342d85d7651ce65f9 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Mon, 14 Apr 2014 09:58:02 -0500 Subject: [PATCH 1/2] server: Include group permissions in reported file dacl's. --- dlls/advapi32/tests/security.c | 2 +- server/change.c | 2 +- server/file.c | 22 ++++++++++++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index bd45189..9960109 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -3098,7 +3098,7 @@ static void test_CreateDirectoryA(void) bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); ok(bret, "GetAclInformation failed\n"); - ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n", + todo_wine ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n", acl_size.AceCount); if (acl_size.AceCount > 0) { diff --git a/server/change.c b/server/change.c index f6d56b0..213e87d 100644 --- a/server/change.c +++ b/server/change.c @@ -298,7 +298,7 @@ static struct security_descriptor *dir_get_sd( struct object *obj ) /* mode and uid the same? if so, no need to re-generate security descriptor */ if (obj->sd && - (st.st_mode & (S_IRWXU|S_IRWXO)) == (dir->mode & (S_IRWXU|S_IRWXO)) && + (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) == (dir->mode & (S_IRWXU|S_IRWXG|S_IRWXO)) && (st.st_uid == dir->uid)) return obj->sd; diff --git a/server/file.c b/server/file.c index cceb8ad..358adf0 100644 --- a/server/file.c +++ b/server/file.c @@ -324,6 +324,8 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID security_sid_len( local_system_sid ); if (mode & S_IRWXU) dacl_size += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( user ); + if (mode & S_IRWXG) + dacl_size += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( group ); if ((!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH))) || (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH))) || (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))) @@ -352,7 +354,7 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID dacl->AclRevision = ACL_REVISION; dacl->Sbz1 = 0; dacl->AclSize = dacl_size; - dacl->AceCount = 1 + (mode & S_IRWXU ? 1 : 0) + (mode & S_IRWXO ? 1 : 0); + dacl->AceCount = 1 + (mode & S_IRWXU ? 1 : 0) + (mode & S_IRWXG ? 1 : 0) + (mode & S_IRWXO ? 1 : 0); if ((!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH))) || (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH))) || (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))) @@ -385,6 +387,22 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID sid = (SID *)&aaa->SidStart; memcpy( sid, user, security_sid_len( user )); } + if (mode & S_IRWXG) + { + /* appropriate access rights for the group */ + aaa = (ACCESS_ALLOWED_ACE *)ace_next( current_ace ); + current_ace = &aaa->Header; + aaa->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; + aaa->Header.AceFlags = 0; + aaa->Header.AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( group ); + aaa->Mask = 0; + if (mode & S_IRGRP) + aaa->Mask |= FILE_GENERIC_READ | FILE_GENERIC_EXECUTE; + if (mode & S_IWGRP) + aaa->Mask |= FILE_GENERIC_WRITE | DELETE | FILE_DELETE_CHILD; + sid = (SID *)&aaa->SidStart; + memcpy( sid, group, security_sid_len( group )); + } if ((!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH))) || (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH))) || (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))) @@ -439,7 +457,7 @@ static struct security_descriptor *file_get_sd( struct object *obj ) return obj->sd; /* mode and uid the same? if so, no need to re-generate security descriptor */ - if (obj->sd && (st.st_mode & (S_IRWXU|S_IRWXO)) == (file->mode & (S_IRWXU|S_IRWXO)) && + if (obj->sd && (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) == (file->mode & (S_IRWXU|S_IRWXG|S_IRWXO)) && (st.st_uid == file->uid)) return obj->sd; -- 1.8.3.2