diff options
Diffstat (limited to 'winsup/cygwin/sec_acl.cc')
-rw-r--r-- | winsup/cygwin/sec_acl.cc | 256 |
1 files changed, 61 insertions, 195 deletions
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc index 51f1c9964..2f7ac278d 100644 --- a/winsup/cygwin/sec_acl.cc +++ b/winsup/cygwin/sec_acl.cc @@ -1,7 +1,7 @@ /* sec_acl.cc: Sun compatible ACL functions. Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011, 2012, 2014 Red Hat, Inc. + 2011, 2012 Red Hat, Inc. Written by Corinna Vinschen <corinna@vinschen.de> @@ -22,6 +22,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "ntdll.h" +#include "pwdgrp.h" #include "tls_pbuf.h" static int @@ -36,7 +37,6 @@ searchace (aclent_t *aclp, int nentries, int type, uid_t id = ILLEGAL_UID) return -1; } -/* This function *requires* an acl list sorted with aclsort{32}. */ int setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, bool &writable) @@ -48,8 +48,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, return -1; NTSTATUS status; - PACL acl; - BOOLEAN acl_exists, dummy; + BOOLEAN dummy; /* Get owner SID. */ PSID owner_sid; @@ -71,32 +70,9 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, } cygsid group (group_sid); - /* Search for NULL ACE and store state of SUID, SGID and VTX bits. */ - DWORD null_mask = 0; - if (NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd_ret, &acl_exists, &acl, - &dummy))) - for (USHORT i = 0; i < acl->AceCount; ++i) - { - ACCESS_ALLOWED_ACE *ace; - if (NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace))) - { - cygpsid ace_sid ((PSID) &ace->SidStart); - if (ace_sid == well_known_null_sid) - { - null_mask = ace->Mask; - break; - } - } - } - /* Initialize local security descriptor. */ SECURITY_DESCRIPTOR sd; RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); - - /* As in alloc_sd, set SE_DACL_PROTECTED to prevent the DACL from being - modified by inheritable ACEs. */ - RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED); - status = RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE); if (!NT_SUCCESS (status)) { @@ -111,7 +87,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, } /* Fill access control list. */ - acl = (PACL) tp.w_get (); + PACL acl = (PACL) tp.w_get (); size_t acl_len = sizeof (ACL); int ace_off = 0; @@ -119,102 +95,22 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, struct passwd *pw; struct group *gr; int pos; - cyg_ldap cldap; RtlCreateAcl (acl, ACL_MAXIMUM_SIZE, ACL_REVISION); writable = false; - /* Pre-compute owner, group, and other permissions to allow creating - matching deny ACEs as in alloc_sd. */ - DWORD owner_allow = 0, group_allow = 0, other_allow = 0; - PDWORD allow; - for (int i = 0; i < nentries; ++i) - { - switch (aclbufp[i].a_type) - { - case USER_OBJ: - allow = &owner_allow; - *allow = STANDARD_RIGHTS_ALL; - break; - case GROUP_OBJ: - allow = &group_allow; - break; - case OTHER_OBJ: - allow = &other_allow; - break; - default: - continue; - } - *allow |= STANDARD_RIGHTS_READ | SYNCHRONIZE - | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES); - if (aclbufp[i].a_perm & S_IROTH) - *allow |= FILE_GENERIC_READ; - if (aclbufp[i].a_perm & S_IWOTH) - { - *allow |= FILE_GENERIC_WRITE; - writable = true; - } - if (aclbufp[i].a_perm & S_IXOTH) - *allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES; - /* Keep S_ISVTX rule in sync with alloc_sd. */ - if (pc.isdir () - && (aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH) - && (aclbufp[i].a_type == USER_OBJ - || !(null_mask & FILE_READ_DATA))) - *allow |= FILE_DELETE_CHILD; - aclbufp[i].a_type = 0; - } - bool isownergroup = (owner_sid == group_sid); - DWORD owner_deny = ~owner_allow & (group_allow | other_allow); - owner_deny &= ~(STANDARD_RIGHTS_READ - | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES); - DWORD group_deny = ~group_allow & other_allow; - group_deny &= ~(STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES); - - /* Set deny ACE for owner. */ - if (owner_deny - && !add_access_denied_ace (acl, ace_off++, owner_deny, - owner_sid, acl_len, NO_INHERITANCE)) - return -1; - /* Set deny ACE for group here to respect the canonical order, - if this does not impact owner */ - if (group_deny && !(group_deny & owner_allow) && !isownergroup - && !add_access_denied_ace (acl, ace_off++, group_deny, - group_sid, acl_len, NO_INHERITANCE)) - return -1; - /* Set allow ACE for owner. */ - if (!add_access_allowed_ace (acl, ace_off++, owner_allow, - owner_sid, acl_len, NO_INHERITANCE)) - return -1; - /* Set deny ACE for group, if still needed. */ - if (group_deny & owner_allow && !isownergroup - && !add_access_denied_ace (acl, ace_off++, group_deny, - group_sid, acl_len, NO_INHERITANCE)) - return -1; - /* Set allow ACE for group. */ - if (!isownergroup - && !add_access_allowed_ace (acl, ace_off++, group_allow, - group_sid, acl_len, NO_INHERITANCE)) - return -1; - /* Set allow ACE for everyone. */ - if (!add_access_allowed_ace (acl, ace_off++, other_allow, - well_known_world_sid, acl_len, NO_INHERITANCE)) - return -1; - /* If a NULL ACE exists, copy it verbatim. */ - if (null_mask) - if (!add_access_allowed_ace (acl, ace_off++, null_mask, well_known_null_sid, - acl_len, NO_INHERITANCE)) - return -1; for (int i = 0; i < nentries; ++i) { DWORD allow; - /* Skip invalidated entries. */ - if (!aclbufp[i].a_type) - continue; - - allow = STANDARD_RIGHTS_READ - | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES); + /* Owner has more standard rights set. */ + if ((aclbufp[i].a_type & ~ACL_DEFAULT) == USER_OBJ) + allow = STANDARD_RIGHTS_ALL + | (pc.fs_is_samba () + ? 0 : (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES)); + else + allow = STANDARD_RIGHTS_READ + | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES); if (aclbufp[i].a_perm & S_IROTH) allow |= FILE_GENERIC_READ; if (aclbufp[i].a_perm & S_IWOTH) @@ -224,10 +120,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, } if (aclbufp[i].a_perm & S_IXOTH) allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES; - /* Keep S_ISVTX rule in sync with alloc_sd. */ - if (pc.isdir () - && (aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH) - && !(null_mask & FILE_READ_DATA)) + if ((aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH)) allow |= FILE_DELETE_CHILD; /* Set inherit property. */ DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT) @@ -240,7 +133,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, * inheritance bits is created. */ if (!(aclbufp[i].a_type & ACL_DEFAULT) - && aclbufp[i].a_type & (USER|GROUP) + && aclbufp[i].a_type & (USER|GROUP|OTHER_OBJ) && (pos = searchace (aclbufp + i + 1, nentries - i - 1, aclbufp[i].a_type | ACL_DEFAULT, (aclbufp[i].a_type & (USER|GROUP)) @@ -248,11 +141,16 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, && aclbufp[i].a_perm == aclbufp[i + 1 + pos].a_perm) { inheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE; - /* invalidate the corresponding default entry. */ - aclbufp[i + 1 + pos].a_type = 0; + /* This invalidates the corresponding default entry. */ + aclbufp[i + 1 + pos].a_type = USER|GROUP|ACL_DEFAULT; } switch (aclbufp[i].a_type) { + case USER_OBJ: + if (!add_access_allowed_ace (acl, ace_off++, allow, + owner, acl_len, inheritance)) + return -1; + break; case DEF_USER_OBJ: if (!add_access_allowed_ace (acl, ace_off++, allow, well_known_creator_owner_sid, acl_len, inheritance)) @@ -260,7 +158,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, break; case USER: case DEF_USER: - if (!(pw = internal_getpwuid (aclbufp[i].a_id, &cldap)) + if (!(pw = internal_getpwuid (aclbufp[i].a_id)) || !sid.getfrompw (pw)) { set_errno (EINVAL); @@ -270,6 +168,11 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, sid, acl_len, inheritance)) return -1; break; + case GROUP_OBJ: + if (!add_access_allowed_ace (acl, ace_off++, allow, + group, acl_len, inheritance)) + return -1; + break; case DEF_GROUP_OBJ: if (!add_access_allowed_ace (acl, ace_off++, allow, well_known_creator_group_sid, acl_len, inheritance)) @@ -277,7 +180,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, break; case GROUP: case DEF_GROUP: - if (!(gr = internal_getgrgid (aclbufp[i].a_id, &cldap)) + if (!(gr = internal_getgrgid (aclbufp[i].a_id)) || !sid.getfromgr (gr)) { set_errno (EINVAL); @@ -287,11 +190,13 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp, sid, acl_len, inheritance)) return -1; break; + case OTHER_OBJ: case DEF_OTHER_OBJ: if (!add_access_allowed_ace (acl, ace_off++, allow, well_known_world_sid, acl_len, inheritance)) return -1; + break; } } /* Set AclSize to computed value. */ @@ -378,7 +283,6 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) BOOLEAN dummy; uid_t uid; gid_t gid; - cyg_ldap cldap; status = RtlGetOwnerSecurityDescriptor (sd, (PSID *) &owner_sid, &dummy); if (!NT_SUCCESS (status)) @@ -386,7 +290,7 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) __seterrno_from_nt_status (status); return -1; } - uid = owner_sid.get_uid (&cldap); + uid = owner_sid.get_uid (); status = RtlGetGroupSecurityDescriptor (sd, (PSID *) &group_sid, &dummy); if (!NT_SUCCESS (status)) @@ -394,7 +298,7 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) __seterrno_from_nt_status (status); return -1; } - gid = group_sid.get_gid (&cldap); + gid = group_sid.get_gid (); aclent_t lacl[MAX_ACL_ENTRIES]; memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t)); @@ -404,6 +308,9 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) lacl[1].a_id = gid; lacl[2].a_type = OTHER_OBJ; lacl[2].a_id = ILLEGAL_GID; + lacl[3].a_type = CLASS_OBJ; + lacl[3].a_id = ILLEGAL_GID; + lacl[3].a_perm = S_IROTH | S_IWOTH | S_IXOTH; PACL acl; BOOLEAN acl_exists; @@ -416,11 +323,9 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) } int pos, i, types_def = 0; - int pgrp_pos = 1, def_pgrp_pos = -1; - mode_t class_perm = 0, def_class_perm = 0; if (!acl_exists || !acl) - for (pos = 0; pos < 3; ++pos) + for (pos = 0; pos < 3; ++pos) /* Don't change CLASS_OBJ entry */ lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH; else { @@ -435,11 +340,6 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) int id; int type = 0; - if (ace_sid == well_known_null_sid) - { - /* Simply ignore. */ - continue; - } if (ace_sid == well_known_world_sid) { type = OTHER_OBJ; @@ -457,30 +357,25 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) } else if (ace_sid == well_known_creator_group_sid) { - type = DEF_GROUP_OBJ; + type = GROUP_OBJ | ACL_DEFAULT; types_def |= type; id = ILLEGAL_GID; } else if (ace_sid == well_known_creator_owner_sid) { - type = DEF_USER_OBJ; + type = USER_OBJ | ACL_DEFAULT; types_def |= type; id = ILLEGAL_GID; } else - id = ace_sid.get_id (TRUE, &type, &cldap); + id = ace_sid.get_id (true, &type); if (!type) continue; if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE || type & ACL_DEFAULT)) { if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) - { - getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); - /* Fix up CLASS_OBJ value. */ - if (type == USER || type == GROUP) - class_perm |= lacl[pos].a_perm; - } + getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); } if ((ace->Header.AceFlags & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)) @@ -493,31 +388,13 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) type |= ACL_DEFAULT; types_def |= type; if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) - { - getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); - /* Fix up DEF_CLASS_OBJ value. */ - if (type == DEF_USER || type == DEF_GROUP) - def_class_perm |= lacl[pos].a_perm; - /* And note the position of the DEF_GROUP_OBJ entry. */ - else if (type == DEF_GROUP_OBJ) - def_pgrp_pos = pos; - } + getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); } } - /* If secondary user and group entries exist in the ACL, fake a matching - CLASS_OBJ entry. The CLASS_OBJ permissions are the or'ed permissions - of the primary group permissions and all secondary user and group - permissions. */ - if (class_perm && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0) - { - lacl[pos].a_type = CLASS_OBJ; - lacl[pos].a_id = ILLEGAL_GID; - lacl[pos].a_perm = class_perm | lacl[pgrp_pos].a_perm; - } - /* Ensure that the default acl contains at least - DEF_(USER|GROUP|OTHER)_OBJ entries. */ if (types_def && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0) { + /* Ensure that the default acl contains at + least DEF_(USER|GROUP|OTHER)_OBJ entries. */ if (!(types_def & USER_OBJ)) { lacl[pos].a_type = DEF_USER_OBJ; @@ -530,8 +407,6 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) lacl[pos].a_type = DEF_GROUP_OBJ; lacl[pos].a_id = gid; lacl[pos].a_perm = lacl[1].a_perm; - /* Note the position of the DEF_GROUP_OBJ entry. */ - def_pgrp_pos = pos; pos++; } if (!(types_def & OTHER_OBJ) && pos < MAX_ACL_ENTRIES) @@ -541,18 +416,13 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp) lacl[pos].a_perm = lacl[2].a_perm; pos++; } - } - /* If secondary user default and group default entries exist in the ACL, - fake a matching DEF_CLASS_OBJ entry. The DEF_CLASS_OBJ permissions are - the or'ed permissions of the primary group default permissions and all - secondary user and group default permissions. */ - if (def_class_perm && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0) - { - lacl[pos].a_type = DEF_CLASS_OBJ; - lacl[pos].a_id = ILLEGAL_GID; - lacl[pos].a_perm = def_class_perm; - if (def_pgrp_pos >= 0) - lacl[pos].a_perm |= lacl[def_pgrp_pos].a_perm; + /* Include DEF_CLASS_OBJ if any named default ace exists. */ + if ((types_def & (USER|GROUP)) && pos < MAX_ACL_ENTRIES) + { + lacl[pos].a_type = DEF_CLASS_OBJ; + lacl[pos].a_id = ILLEGAL_GID; + lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH; + } } } if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) @@ -628,7 +498,6 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which) bool has_other_obj = false; bool has_class_obj = false; bool has_ug_objs __attribute__ ((unused)) = false; - bool has_def_objs __attribute__ ((unused)) = false; bool has_def_user_obj __attribute__ ((unused)) = false; bool has_def_group_obj = false; bool has_def_other_obj = false; @@ -693,7 +562,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which) *which = pos; return USER_ERROR; } - has_def_objs = has_def_user_obj = true; + has_def_user_obj = true; break; case DEF_GROUP_OBJ: if (has_def_group_obj) @@ -702,7 +571,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which) *which = pos; return GRP_ERROR; } - has_def_objs = has_def_group_obj = true; + has_def_group_obj = true; break; case DEF_OTHER_OBJ: if (has_def_other_obj) @@ -711,7 +580,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which) *which = pos; return OTHER_ERROR; } - has_def_objs = has_def_other_obj = true; + has_def_other_obj = true; break; case DEF_CLASS_OBJ: if (has_def_class_obj) @@ -720,7 +589,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which) *which = pos; return CLASS_ERROR; } - has_def_objs = has_def_class_obj = true; + has_def_class_obj = true; break; case DEF_USER: case DEF_GROUP: @@ -731,7 +600,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which) *which = pos2; return DUPLICATE_ERROR; } - has_def_objs = has_def_ug_objs = true; + has_def_ug_objs = true; break; default: return ENTRY_ERROR; @@ -739,10 +608,11 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which) if (!has_user_obj || !has_group_obj || !has_other_obj - || (has_def_objs - && (!has_def_user_obj || !has_def_group_obj || !has_def_other_obj)) +#if 0 + /* These checks are not ok yet since CLASS_OBJ isn't fully implemented. */ || (has_ug_objs && !has_class_obj) || (has_def_ug_objs && !has_def_class_obj) +#endif ) { if (which) @@ -767,10 +637,7 @@ extern "C" int aclsort32 (int nentries, int, aclent_t *aclbufp) { if (aclcheck32 (aclbufp, nentries, NULL)) - { - set_errno (EINVAL); - return -1; - } + return -1; if (!aclbufp || nentries < 1) { set_errno (EINVAL); @@ -970,7 +837,6 @@ aclfromtext32 (char *acltextp, int *) int pos = 0; strcpy (buf, acltextp); char *lasts; - cyg_ldap cldap; for (char *c = strtok_r (buf, ",", &lasts); c; c = strtok_r (NULL, ",", &lasts)) @@ -990,7 +856,7 @@ aclfromtext32 (char *acltextp, int *) c += 5; if (isalpha (*c)) { - struct passwd *pw = internal_getpwnam (c, &cldap); + struct passwd *pw = internal_getpwnam (c); if (!pw) { set_errno (EINVAL); @@ -1018,7 +884,7 @@ aclfromtext32 (char *acltextp, int *) c += 5; if (isalpha (*c)) { - struct group *gr = internal_getgrnam (c, &cldap); + struct group *gr = internal_getgrnam (c); if (!gr) { set_errno (EINVAL); |