diff options
Diffstat (limited to 'winsup/cygwin/security.cc')
-rw-r--r-- | winsup/cygwin/security.cc | 844 |
1 files changed, 0 insertions, 844 deletions
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc deleted file mode 100644 index 00a8c32cd..000000000 --- a/winsup/cygwin/security.cc +++ /dev/null @@ -1,844 +0,0 @@ -/* security.cc: NT file access control functions - - Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007 Red Hat, Inc. - - Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de - Completely rewritten by Corinna Vinschen <corinna@vinschen.de> - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#include "winsup.h" -#include <unistd.h> -#include <stdlib.h> -#include "cygerrno.h" -#include "security.h" -#include "path.h" -#include "fhandler.h" -#include "dtable.h" -#include "pinfo.h" -#include "cygheap.h" -#include "ntdll.h" -#include "pwdgrp.h" - -#define ALL_SECURITY_INFORMATION (DACL_SECURITY_INFORMATION \ - | GROUP_SECURITY_INFORMATION \ - | OWNER_SECURITY_INFORMATION) - -LONG -get_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd) -{ - NTSTATUS status = STATUS_SUCCESS; - ULONG len = 0; - int retry = 0; - int res = -1; - - for (; retry < 2; ++retry) - { - if (fh) - { - status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION, - sd, len, &len); - if (status == STATUS_BUFFER_TOO_SMALL) - { - if (!sd.malloc (len)) - { - set_errno (ENOMEM); - break; - } - status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION, - sd, len, &len); - } - if (NT_SUCCESS (status)) - { - res = 0; - break; - } - } - if (!retry) - { - OBJECT_ATTRIBUTES attr; - IO_STATUS_BLOCK io; - - status = NtOpenFile (&fh, READ_CONTROL, - pc.get_object_attr (attr, sec_none_nih), - &io, FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT); - if (!NT_SUCCESS (status)) - { - fh = NULL; - break; - } - } - } - if (retry && fh) - NtClose (fh); - if (!NT_SUCCESS (status)) - __seterrno_from_nt_status (status); - return res; -} - -LONG -set_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, bool is_chown) -{ - NTSTATUS status = STATUS_SUCCESS; - int retry = 0; - int res = -1; - - for (; retry < 2; ++retry) - { - if (fh) - { - status = NtSetSecurityObject (fh, - is_chown ? ALL_SECURITY_INFORMATION - : DACL_SECURITY_INFORMATION, - sd); - if (NT_SUCCESS (status)) - { - res = 0; - break; - } - } - if (!retry) - { - OBJECT_ATTRIBUTES attr; - IO_STATUS_BLOCK io; - status = NtOpenFile (&fh, (is_chown ? WRITE_OWNER : 0) | WRITE_DAC, - pc.get_object_attr (attr, sec_none_nih), - &io, FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT); - if (!NT_SUCCESS (status)) - { - fh = NULL; - break; - } - } - } - if (retry && fh) - NtClose (fh); - if (!NT_SUCCESS (status)) - __seterrno_from_nt_status (status); - return res; -} - -static void -get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid, - PSID group_sid, bool grp_member) -{ - ACCESS_ALLOWED_ACE *ace; - int allow = 0; - int deny = 0; - int *flags, *anti; - - for (DWORD i = 0; i < acl->AceCount; ++i) - { - if (!GetAce (acl, i, (PVOID *) &ace)) - continue; - if (ace->Header.AceFlags & INHERIT_ONLY) - continue; - switch (ace->Header.AceType) - { - case ACCESS_ALLOWED_ACE_TYPE: - flags = &allow; - anti = &deny; - break; - case ACCESS_DENIED_ACE_TYPE: - flags = &deny; - anti = &allow; - break; - default: - continue; - } - - cygpsid ace_sid ((PSID) &ace->SidStart); - if (ace_sid == well_known_world_sid) - { - if (ace->Mask & FILE_READ_BITS) - *flags |= ((!(*anti & S_IROTH)) ? S_IROTH : 0) - | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) - | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); - if (ace->Mask & FILE_WRITE_BITS) - *flags |= ((!(*anti & S_IWOTH)) ? S_IWOTH : 0) - | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) - | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); - if (ace->Mask & FILE_EXEC_BITS) - *flags |= ((!(*anti & S_IXOTH)) ? S_IXOTH : 0) - | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) - | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); - if ((S_ISDIR (*attribute)) && - (ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD)) - == (FILE_WRITE_DATA | FILE_EXECUTE)) - *flags |= S_ISVTX; - } - else if (ace_sid == well_known_null_sid) - { - /* Read SUID, SGID and VTX bits from NULL ACE. */ - if (ace->Mask & FILE_READ_DATA) - *flags |= S_ISVTX; - if (ace->Mask & FILE_WRITE_DATA) - *flags |= S_ISGID; - if (ace->Mask & FILE_APPEND_DATA) - *flags |= S_ISUID; - } - else if (ace_sid == owner_sid) - { - if (ace->Mask & FILE_READ_BITS) - *flags |= ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); - if (ace->Mask & FILE_WRITE_BITS) - *flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); - if (ace->Mask & FILE_EXEC_BITS) - *flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); - } - else if (ace_sid == group_sid) - { - if (ace->Mask & FILE_READ_BITS) - *flags |= ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) - | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0); - if (ace->Mask & FILE_WRITE_BITS) - *flags |= ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) - | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0); - if (ace->Mask & FILE_EXEC_BITS) - *flags |= ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) - | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0); - } - } - *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID); - if (owner_sid && group_sid && EqualSid (owner_sid, group_sid) - /* FIXME: temporary exception for /var/empty */ - && well_known_system_sid != group_sid) - { - allow &= ~(S_IRGRP | S_IWGRP | S_IXGRP); - allow |= (((allow & S_IRUSR) ? S_IRGRP : 0) - | ((allow & S_IWUSR) ? S_IWGRP : 0) - | ((allow & S_IXUSR) ? S_IXGRP : 0)); - } - *attribute |= allow; -} - -static void -get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute, - __uid32_t *uidret, __gid32_t *gidret) -{ - if (!psd) - { - /* If reading the security descriptor failed, treat the object - as unreadable. */ - if (attribute) - *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO); - if (uidret) - *uidret = ILLEGAL_UID; - if (gidret) - *gidret = ILLEGAL_GID; - return; - } - - cygpsid owner_sid; - cygpsid group_sid; - BOOL dummy; - - if (!GetSecurityDescriptorOwner (psd, (PSID *) &owner_sid, &dummy)) - debug_printf ("GetSecurityDescriptorOwner %E"); - if (!GetSecurityDescriptorGroup (psd, (PSID *) &group_sid, &dummy)) - debug_printf ("GetSecurityDescriptorGroup %E"); - - __uid32_t uid; - __gid32_t gid; - bool grp_member = get_sids_info (owner_sid, group_sid, &uid, &gid); - if (uidret) - *uidret = uid; - if (gidret) - *gidret = gid; - - if (!attribute) - { - syscall_printf ("uid %d, gid %d", uid, gid); - return; - } - - PACL acl; - BOOL acl_exists; - - if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) - { - __seterrno (); - debug_printf ("GetSecurityDescriptorDacl %E"); - *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO); - } - else if (!acl_exists || !acl) - *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - else - get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member); - - syscall_printf ("%sACL %x, uid %d, gid %d", - (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid); -} - -static int -get_reg_sd (HANDLE handle, security_descriptor &sd_ret) -{ - LONG ret; - DWORD len = 0; - - ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION, - sd_ret, &len); - if (ret == ERROR_INSUFFICIENT_BUFFER) - { - if (!sd_ret.malloc (len)) - set_errno (ENOMEM); - else - ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION, - sd_ret, &len); - } - if (ret != ERROR_SUCCESS) - { - __seterrno (); - return -1; - } - return 0; -} - -int -get_reg_attribute (HKEY hkey, mode_t *attribute, __uid32_t *uidret, - __gid32_t *gidret) -{ - security_descriptor sd; - - if (!get_reg_sd (hkey, sd)) - { - get_info_from_sd (sd, attribute, uidret, gidret); - return 0; - } - /* The entries are already set to default values */ - return -1; -} - -int -get_file_attribute (HANDLE handle, path_conv &pc, - mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret) -{ - if (pc.has_acls ()) - { - security_descriptor sd; - - if (!get_file_sd (handle, pc, sd)) - { - get_info_from_sd (sd, attribute, uidret, gidret); - return 0; - } - else - { - if (uidret) - *uidret = ILLEGAL_UID; - if (gidret) - *gidret = ILLEGAL_GID; - - return -1; - } - } - - if (uidret) - *uidret = myself->uid; - if (gidret) - *gidret = myself->gid; - - return -1; -} - -bool -add_access_allowed_ace (PACL acl, int offset, DWORD attributes, - PSID sid, size_t &len_add, DWORD inherit) -{ - if (!AddAccessAllowedAce (acl, ACL_REVISION, attributes, sid)) - { - __seterrno (); - return false; - } - ACCESS_ALLOWED_ACE *ace; - if (inherit && GetAce (acl, offset, (PVOID *) &ace)) - ace->Header.AceFlags |= inherit; - len_add += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + GetLengthSid (sid); - return true; -} - -bool -add_access_denied_ace (PACL acl, int offset, DWORD attributes, - PSID sid, size_t &len_add, DWORD inherit) -{ - if (!AddAccessDeniedAce (acl, ACL_REVISION, attributes, sid)) - { - __seterrno (); - return false; - } - ACCESS_DENIED_ACE *ace; - if (inherit && GetAce (acl, offset, (PVOID *) &ace)) - ace->Header.AceFlags |= inherit; - len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid); - return true; -} - -static PSECURITY_DESCRIPTOR -alloc_sd (path_conv &pc, __uid32_t uid, __gid32_t gid, int attribute, - security_descriptor &sd_ret) -{ - BOOL dummy; - - debug_printf("uid %d, gid %d, attribute %x", uid, gid, attribute); - - /* Get owner and group from current security descriptor. */ - PSID cur_owner_sid = NULL; - PSID cur_group_sid = NULL; - if (!GetSecurityDescriptorOwner (sd_ret, &cur_owner_sid, &dummy)) - debug_printf ("GetSecurityDescriptorOwner %E"); - if (!GetSecurityDescriptorGroup (sd_ret, &cur_group_sid, &dummy)) - debug_printf ("GetSecurityDescriptorGroup %E"); - - /* Get SID of owner. */ - cygsid owner_sid; - /* Check for current user first */ - if (uid == myself->uid) - owner_sid = cygheap->user.sid (); - else if (uid == ILLEGAL_UID) - owner_sid = cur_owner_sid; - else if (!owner_sid.getfrompw (internal_getpwuid (uid))) - { - set_errno (EINVAL); - return NULL; - } - owner_sid.debug_print ("alloc_sd: owner SID ="); - - /* Get SID of new group. */ - cygsid group_sid; - /* Check for current user first */ - if (gid == myself->gid) - group_sid = cygheap->user.groups.pgsid; - else if (gid == ILLEGAL_GID) - group_sid = cur_group_sid; - else if (!group_sid.getfromgr (internal_getgrgid (gid))) - { - set_errno (EINVAL); - return NULL; - } - group_sid.debug_print ("alloc_sd: group SID ="); - - /* Initialize local security descriptor. */ - SECURITY_DESCRIPTOR sd; - if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) - { - __seterrno (); - return NULL; - } - - /* We set the SE_DACL_PROTECTED flag here to prevent the DACL from being - * modified by inheritable ACEs. This flag is available since Win2K. */ - if (wincap.has_dacl_protect ()) - sd.Control |= SE_DACL_PROTECTED; - - /* Create owner for local security descriptor. */ - if (!SetSecurityDescriptorOwner (&sd, owner_sid, FALSE)) - { - __seterrno (); - return NULL; - } - - /* Create group for local security descriptor. */ - if (!SetSecurityDescriptorGroup (&sd, group_sid, FALSE)) - { - __seterrno (); - return NULL; - } - - /* Initialize local access control list. */ - PACL acl = (PACL) alloca (3072); - if (!InitializeAcl (acl, 3072, ACL_REVISION)) - { - __seterrno (); - return NULL; - } - - /* From here fill ACL. */ - size_t acl_len = sizeof (ACL); - int ace_off = 0; - - /* Construct allow attribute for owner. - Don't set FILE_READ/WRITE_ATTRIBUTES unconditionally on Samba, otherwise - it enforces read permissions. Same for other's below. */ - DWORD owner_allow = STANDARD_RIGHTS_ALL - | (pc.fs_is_samba () - ? 0 : (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES)); - if (attribute & S_IRUSR) - owner_allow |= FILE_GENERIC_READ; - if (attribute & S_IWUSR) - owner_allow |= FILE_GENERIC_WRITE; - if (attribute & S_IXUSR) - owner_allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES; - if (S_ISDIR (attribute) - && (attribute & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR)) - owner_allow |= FILE_DELETE_CHILD; - - /* Construct allow attribute for group. */ - DWORD group_allow = STANDARD_RIGHTS_READ - | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES); - if (attribute & S_IRGRP) - group_allow |= FILE_GENERIC_READ; - if (attribute & S_IWGRP) - group_allow |= FILE_GENERIC_WRITE; - if (attribute & S_IXGRP) - group_allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES; - if (S_ISDIR (attribute) - && (attribute & (S_IWGRP | S_IXGRP)) == (S_IWGRP | S_IXGRP) - && !(attribute & S_ISVTX)) - group_allow |= FILE_DELETE_CHILD; - - /* Construct allow attribute for everyone. */ - DWORD other_allow = STANDARD_RIGHTS_READ - | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES); - if (attribute & S_IROTH) - other_allow |= FILE_GENERIC_READ; - if (attribute & S_IWOTH) - other_allow |= FILE_GENERIC_WRITE; - if (attribute & S_IXOTH) - other_allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES; - if (S_ISDIR (attribute) - && (attribute & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH) - && !(attribute & S_ISVTX)) - other_allow |= FILE_DELETE_CHILD; - - /* Construct SUID, SGID and VTX bits in NULL ACE. */ - DWORD null_allow = 0L; - if (attribute & (S_ISUID | S_ISGID | S_ISVTX)) - { - if (attribute & S_ISUID) - null_allow |= FILE_APPEND_DATA; - if (attribute & S_ISGID) - null_allow |= FILE_WRITE_DATA; - if (attribute & S_ISVTX) - null_allow |= FILE_READ_DATA; - } - - /* Add owner and group permissions if SIDs are equal - and construct deny attributes for group and owner. */ - bool isownergroup; - if ((isownergroup = (owner_sid == group_sid))) - owner_allow |= group_allow; - - 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 NULL; - /* 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 NULL; - /* Set allow ACE for owner. */ - if (!add_access_allowed_ace (acl, ace_off++, owner_allow, - owner_sid, acl_len, NO_INHERITANCE)) - return NULL; - /* 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 NULL; - /* Set allow ACE for group. */ - if (!isownergroup - && !add_access_allowed_ace (acl, ace_off++, group_allow, - group_sid, acl_len, NO_INHERITANCE)) - return NULL; - - /* Set allow ACE for everyone. */ - if (!add_access_allowed_ace (acl, ace_off++, other_allow, - well_known_world_sid, acl_len, NO_INHERITANCE)) - return NULL; - /* Set null ACE for special bits. */ - if (null_allow - && !add_access_allowed_ace (acl, ace_off++, null_allow, - well_known_null_sid, acl_len, NO_INHERITANCE)) - return NULL; - - /* Fill ACL with unrelated ACEs from current security descriptor. */ - PACL oacl; - BOOL acl_exists = FALSE; - ACCESS_ALLOWED_ACE *ace; - if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy) - && acl_exists && oacl) - for (DWORD i = 0; i < oacl->AceCount; ++i) - if (GetAce (oacl, i, (PVOID *) &ace)) - { - cygpsid ace_sid ((PSID) &ace->SidStart); - - /* Check for related ACEs. */ - if (ace_sid == well_known_null_sid) - continue; - if ((ace_sid == cur_owner_sid) - || (ace_sid == owner_sid) - || (ace_sid == cur_group_sid) - || (ace_sid == group_sid) - || (ace_sid == well_known_world_sid)) - { - if (ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT) - ace->Header.AceFlags |= INHERIT_ONLY; - else - continue; - } - /* - * Add unrelated ACCESS_DENIED_ACE to the beginning but - * behind the owner_deny, ACCESS_ALLOWED_ACE to the end. - * FIXME: this would break the order of the inherit_only ACEs - */ - if (!AddAce (acl, ACL_REVISION, - ace->Header.AceType == ACCESS_DENIED_ACE_TYPE? - (owner_deny ? 1 : 0) : MAXDWORD, - (LPVOID) ace, ace->Header.AceSize)) - { - __seterrno (); - return NULL; - } - acl_len += ace->Header.AceSize; - } - -#if 0 - /* CV 2009-02-04: Setting these inherit attributes for new dirs never was - really POSIX-like but rather a concession for native Win32 processes. - Disabled for now. Let's test if that has really a visible negative - impact. */ - - /* Construct appropriate inherit attribute for new directories */ - if (S_ISDIR (attribute) && !acl_exists) - { - const DWORD inherit = SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY; - -#if 0 /* FIXME: Not done currently as this breaks the canonical order */ - /* Set deny ACE for owner. */ - if (owner_deny - && !add_access_denied_ace (acl, ace_off++, owner_deny, - well_known_creator_owner_sid, acl_len, inherit)) - return NULL; - /* Set deny ACE for group here to respect the canonical order, - if this does not impact owner */ - if (group_deny && !(group_deny & owner_allow) - && !add_access_denied_ace (acl, ace_off++, group_deny, - well_known_creator_group_sid, acl_len, inherit)) - return NULL; -#endif - /* Set allow ACE for owner. */ - if (!add_access_allowed_ace (acl, ace_off++, owner_allow, - well_known_creator_owner_sid, acl_len, inherit)) - return NULL; -#if 0 /* FIXME: Not done currently as this breaks the canonical order and - won't be preserved on chown and chmod */ - /* Set deny ACE for group, conflicting with owner_allow. */ - if (group_deny & owner_allow - && !add_access_denied_ace (acl, ace_off++, group_deny, - well_known_creator_group_sid, acl_len, inherit)) - return NULL; -#endif - /* Set allow ACE for group. */ - if (!add_access_allowed_ace (acl, ace_off++, group_allow, - well_known_creator_group_sid, acl_len, inherit)) - return NULL; - /* Set allow ACE for everyone. */ - if (!add_access_allowed_ace (acl, ace_off++, other_allow, - well_known_world_sid, acl_len, inherit)) - return NULL; - } -#endif - - /* Set AclSize to computed value. */ - acl->AclSize = acl_len; - debug_printf ("ACL-Size: %d", acl_len); - - /* Create DACL for local security descriptor. */ - if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) - { - __seterrno (); - return NULL; - } - - /* Make self relative security descriptor. */ - DWORD sd_size = 0; - MakeSelfRelativeSD (&sd, sd_ret, &sd_size); - if (sd_size <= 0) - { - __seterrno (); - return NULL; - } - if (!sd_ret.malloc (sd_size)) - { - set_errno (ENOMEM); - return NULL; - } - if (!MakeSelfRelativeSD (&sd, sd_ret, &sd_size)) - { - __seterrno (); - return NULL; - } - debug_printf ("Created SD-Size: %u", sd_ret.size ()); - - return sd_ret; -} - -void -set_security_attribute (path_conv &pc, int attribute, PSECURITY_ATTRIBUTES psa, - security_descriptor &sd) -{ - psa->lpSecurityDescriptor = sd.malloc (SECURITY_DESCRIPTOR_MIN_LENGTH); - InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR)psa->lpSecurityDescriptor, - SECURITY_DESCRIPTOR_REVISION); - psa->lpSecurityDescriptor = alloc_sd (pc, geteuid32 (), getegid32 (), - attribute, sd); -} - -int -set_file_attribute (HANDLE handle, path_conv &pc, - __uid32_t uid, __gid32_t gid, int attribute) -{ - int ret = -1; - - if (pc.has_acls ()) - { - security_descriptor sd; - - if (!get_file_sd (handle, pc, sd) - && alloc_sd (pc, uid, gid, attribute, sd)) - ret = set_file_sd (handle, pc, sd, - uid != ILLEGAL_UID || gid != ILLEGAL_GID); - } - else - ret = 0; - syscall_printf ("%d = set_file_attribute (%S, %d, %d, %p)", - ret, pc.get_nt_native_path (), uid, gid, attribute); - return ret; -} - -static int -check_access (security_descriptor &sd, GENERIC_MAPPING &mapping, - DWORD desired, int flags) -{ - int ret = -1; - BOOL status; - DWORD granted; - DWORD plen = sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES); - PPRIVILEGE_SET pset = (PPRIVILEGE_SET) alloca (plen); - HANDLE tok = cygheap->user.issetuid () ? cygheap->user.imp_token () - : hProcImpToken; - - if (!tok && !DuplicateTokenEx (hProcToken, MAXIMUM_ALLOWED, NULL, - SecurityImpersonation, TokenImpersonation, - &hProcImpToken)) -#ifdef DEBUGGING - system_printf ("DuplicateTokenEx failed, %E"); -#else - syscall_printf ("DuplicateTokenEx failed, %E"); -#endif - else - tok = hProcImpToken; - - if (!AccessCheck (sd, tok, desired, &mapping, pset, &plen, &granted, &status)) - __seterrno (); - else if (!status) - { - /* CV, 2006-10-16: Now, that's really weird. Imagine a user who has no - standard access to a file, but who has backup and restore privileges - and these privileges are enabled in the access token. One would - expect that the AccessCheck function takes this into consideration - when returning the access status. Otherwise, why bother with the - pset parameter, right? - But not so. AccessCheck actually returns a status of "false" here, - even though opening a file with backup resp. restore intent - naturally succeeds for this user. This definitely spoils the results - of access(2) for administrative users or the SYSTEM account. So, in - case the access check fails, another check against the user's - backup/restore privileges has to be made. Sigh. */ - int granted_flags = 0; - if (flags & R_OK) - { - pset->PrivilegeCount = 1; - pset->Control = 0; - pset->Privilege[0].Luid.HighPart = 0L; - pset->Privilege[0].Luid.LowPart = SE_BACKUP_PRIVILEGE; - pset->Privilege[0].Attributes = 0; - if (PrivilegeCheck (tok, pset, &status) && status) - granted_flags |= R_OK; - } - if (flags & W_OK) - { - pset->PrivilegeCount = 1; - pset->Control = 0; - pset->Privilege[0].Luid.HighPart = 0L; - pset->Privilege[0].Luid.LowPart = SE_RESTORE_PRIVILEGE; - pset->Privilege[0].Attributes = 0; - if (PrivilegeCheck (tok, pset, &status) && status) - granted_flags |= W_OK; - } - if (granted_flags == flags) - ret = 0; - else - set_errno (EACCES); - } - else - ret = 0; - return ret; -} - -int -check_file_access (path_conv &pc, int flags) -{ - security_descriptor sd; - int ret = -1; - static GENERIC_MAPPING NO_COPY mapping = { FILE_GENERIC_READ, - FILE_GENERIC_WRITE, - FILE_GENERIC_EXECUTE, - FILE_ALL_ACCESS }; - DWORD desired = 0; - if (flags & R_OK) - desired |= FILE_READ_DATA; - if (flags & W_OK) - desired |= FILE_WRITE_DATA; - if (flags & X_OK) - desired |= FILE_EXECUTE; - if (!get_file_sd (NULL, pc, sd)) - ret = check_access (sd, mapping, desired, flags); - debug_printf ("flags %x, ret %d", flags, ret); - return ret; -} - -int -check_registry_access (HANDLE hdl, int flags) -{ - security_descriptor sd; - int ret = -1; - static GENERIC_MAPPING NO_COPY mapping = { KEY_READ, - KEY_WRITE, - KEY_EXECUTE, - KEY_ALL_ACCESS }; - DWORD desired = 0; - if (flags & R_OK) - desired |= KEY_ENUMERATE_SUB_KEYS; - if (flags & W_OK) - desired |= KEY_SET_VALUE; - if (flags & X_OK) - desired |= KEY_QUERY_VALUE; - if (!get_reg_sd (hdl, sd)) - ret = check_access (sd, mapping, desired, flags); - /* As long as we can't write the registry... */ - if (flags & W_OK) - { - set_errno (EROFS); - ret = -1; - } - debug_printf ("flags %x, ret %d", flags, ret); - return ret; -} |