https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=01c9386fd805d552329d840ef179a6357add4a66
commit 01c9386fd805d552329d840ef179a6357add4a66 Author: Corinna Vinschen <[email protected]> AuthorDate: Wed Jan 15 12:11:36 2025 +0100 Commit: Corinna Vinschen <[email protected]> CommitDate: Wed Jan 15 12:27:03 2025 +0100 Cygwin: get_posix_access: improve merging permissions Add a second loop to the code snippet merging permissions in old-style or Windows-generated ACLs. This loop fixes up default ACL permissions created from ACEs which are valid for the directory itself, as well as getting inherited to child objects. The FULL_ACE bit utilized for this is removed from the ACE at the end of the function, together with the temporary DENY bits. Signed-off-by: Corinna Vinschen <[email protected]> Diff: --- winsup/cygwin/sec/acl.cc | 146 +++++++++++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 49 deletions(-) diff --git a/winsup/cygwin/sec/acl.cc b/winsup/cygwin/sec/acl.cc index b1dafaaae96a..aab567804933 100644 --- a/winsup/cygwin/sec/acl.cc +++ b/winsup/cygwin/sec/acl.cc @@ -595,6 +595,10 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, #define DENY_W 020000 #define DENY_X 010000 #define DENY_RWX (DENY_R | DENY_W | DENY_X) +/* Temporary bit to indicate that an incoming Windows ACE is valid for + the object as well (so it's not an INHERIT_ONLY ACE). Used by + get_posix_access to create useful default perms. */ +#define FULL_ACE 0100000 /* New style ACL means, just read the bits and store them away. Don't create masked values on your own. */ @@ -875,8 +879,10 @@ get_posix_access (PSECURITY_DESCRIPTOR psd, if (type == USER_OBJ) owner_eq_group = true; } + bool default_only_ace = true; if (!(ace->Header.AceFlags & INHERIT_ONLY || type & ACL_DEFAULT)) { + default_only_ace = false; if (type == USER_OBJ) { /* If we get a second entry for the owner SID, it's either a @@ -991,6 +997,12 @@ get_posix_access (PSECURITY_DESCRIPTOR psd, aclsid[pos] = ace_sid; if (!new_style) { + /* Add flag that we're generating object and default ACL + entry from the same Windows ACE and so permissions are + supposed to be the same. */ + if (!default_only_ace + && type & (USER_OBJ | USER | GROUP_OBJ | GROUP)) + lacl[pos].a_perm |= FULL_ACE; /* Fix up DEF_CLASS_OBJ value. */ if (type & (USER | GROUP)) { @@ -1102,55 +1114,91 @@ get_posix_access (PSECURITY_DESCRIPTOR psd, /* For old-style or non-Cygwin ACLs, check for merging permissions. */ if (!new_style) - for (idx = 0; idx < pos; ++idx) - { - if (lacl[idx].a_type & (USER_OBJ | USER) - && !(lacl[idx].a_type & ACL_DEFAULT)) - { - mode_t perm; - - /* Don't merge if the user already has all permissions, or... */ - if (lacl[idx].a_perm == S_IRWXO) - continue; - /* ...if the sum of perms is less than or equal the user's perms. */ - perm = lacl[idx].a_perm - | (has_class_perm ? class_perm : lacl[1].a_perm) - | lacl[2].a_perm; - if (perm == lacl[idx].a_perm) - continue; - /* Otherwise, if we use the Windows user DB, utilize Authz to make - sure all user permissions are correctly reflecting the Windows - permissions. */ - if (cygheap->pg.nss_pwd_db () - && authz_get_user_attribute (&perm, psd, aclsid[idx])) - lacl[idx].a_perm = perm; - /* Otherwise we only check the current user. If the user entry - has a deny ACE, don't check. */ - else if (lacl[idx].a_id == myself->uid - && !(lacl[idx].a_perm & DENY_RWX)) - { - /* Sum up all permissions of groups the user is member of, plus - everyone perms, and merge them to user perms. */ - BOOL ret; - - perm = lacl[2].a_perm & S_IRWXO; - for (int gidx = 1; gidx < pos; ++gidx) - if (lacl[gidx].a_type & (GROUP_OBJ | GROUP) - && CheckTokenMembership (cygheap->user.issetuid () - ? cygheap->user.imp_token () : NULL, - aclsid[gidx], &ret) - && ret) - perm |= lacl[gidx].a_perm & S_IRWXO; - lacl[idx].a_perm |= perm; - } - } - /* For all groups, if everyone has more permissions, add everyone - perms to group perms. Skip groups with deny ACE. */ - else if (lacl[idx].a_type & (GROUP_OBJ | GROUP) - && !(lacl[idx].a_type & ACL_DEFAULT) - && !(lacl[idx].a_perm & DENY_RWX)) - lacl[idx].a_perm |= lacl[2].a_perm & S_IRWXO; - } + { + /* First loop handles object permissions */ + for (idx = 0; idx < pos; ++idx) + { + mode_t perm; + + if (lacl[idx].a_type & (USER_OBJ | USER) + && !(lacl[idx].a_type & ACL_DEFAULT)) + { + + /* Don't merge if the user already has all permissions, or... */ + if (lacl[idx].a_perm == S_IRWXO) + continue; + /* ...the sum of perms is less than or equal the user's perms. */ + perm = lacl[idx].a_perm + | (has_class_perm ? class_perm : lacl[1].a_perm) + | lacl[2].a_perm; + if (perm == lacl[idx].a_perm) + continue; + /* Otherwise, if we utilize the Windows user DB, use Authz to + make sure all user permissions are correctly reflecting the + Windows permissions. */ + if (cygheap->pg.nss_pwd_db () + && authz_get_user_attribute (&perm, psd, aclsid[idx])) + lacl[idx].a_perm = perm; + /* Otherwise we only check the current user. If the user entry + has a deny ACE, don't check. */ + else if (lacl[idx].a_id == myself->uid + && !(lacl[idx].a_perm & DENY_RWX)) + { + /* Sum up all permissions of groups the user is member of, + plus everyone perms, and merge them to user perms. */ + BOOL ret; + + perm = lacl[2].a_perm & S_IRWXO; + for (int gidx = 1; gidx < pos; ++gidx) + if (lacl[gidx].a_type & (GROUP_OBJ | GROUP) + && CheckTokenMembership (cygheap->user.issetuid () + ? cygheap->user.imp_token () + : NULL, aclsid[gidx], &ret) + && ret) + perm |= lacl[gidx].a_perm & S_IRWXO; + lacl[idx].a_perm |= perm; + } + } + /* For all groups, if everyone has more permissions, add everyone + perms to group perms. Skip groups with deny ACE. */ + else if (lacl[idx].a_type & (GROUP_OBJ | GROUP) + && !(lacl[idx].a_type & ACL_DEFAULT) + && !(lacl[idx].a_perm & DENY_RWX)) + lacl[idx].a_perm |= lacl[2].a_perm & S_IRWXO; + } + /* Second loop handles default permissions in case we get object + and default perms from the same Windows ACE. */ + for (idx = 0; idx < pos; ++idx) + { + int obj_idx; + + if (!(lacl[idx].a_perm & FULL_ACE)) + continue; + + type = lacl[idx].a_type & (USER_OBJ | USER | GROUP_OBJ | GROUP); + id = (type & (USER_OBJ | GROUP_OBJ)) ? ACL_UNDEFINED_ID + : lacl[idx].a_id; + switch (type) + { + case USER_OBJ: + case USER: + obj_idx = searchace (lacl, pos + 1, USER_OBJ, id); + if (obj_idx < 0) + obj_idx = searchace (lacl, pos + 1, USER, + lacl[idx].a_id); + break; + case GROUP_OBJ: + case GROUP: + obj_idx = searchace (lacl, pos + 1, GROUP_OBJ, id); + if (obj_idx < 0) + obj_idx = searchace (lacl, pos + 1, GROUP, + lacl[idx].a_id); + break; + } + if (obj_idx >= 0 && obj_idx <= pos) + lacl[idx].a_perm |= lacl[obj_idx].a_perm; + } + } /* If owner SID == group SID (Microsoft Accounts) merge group perms into user perms but leave group perms intact. That's a fake, but it allows to keep track of the POSIX group perms without much effort. */
