Mailing-List: contact cygwin-developers-help AT sourceware DOT cygnus DOT com; run by ezmlm Sender: cygwin-developers-owner AT sourceware DOT cygnus DOT com Delivered-To: mailing list cygwin-developers AT sourceware DOT cygnus DOT com Message-ID: <36E198D6.42F172D0@cityweb.de> Date: Sat, 06 Mar 1999 22:06:30 +0100 From: Corinna Vinschen X-Mailer: Mozilla 4.04 [en] (WinNT; I) MIME-Version: 1.0 To: Geoffrey Noer CC: Sergey Okhapkin , cygwin32-developers AT cygnus DOT com Subject: Re: Patch, Version 3: Unix-like permissions on objects References: <36E16FAE DOT 5B0BD539 AT cityweb DOT de> Content-Type: multipart/mixed; boundary="------------6FA99905F1353CB61AF0CAA2" This is a multi-part message in MIME format. --------------6FA99905F1353CB61AF0CAA2 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Sorry! I forgot the patch to `chmod()' which is needed because of keeping the current user and group. This has a side effect: `SetFileSecurity()' may set owner and group only, if they are corresponding to the current user. This is important in case of `chown()' and `chmod()' calls. This affects syscalls.cc and security.cc, so I attach the correct patches to them, only. Regards, Corinna ChangeLog: ========== Sat Mar 6 21:37:00 Corinna Vinschen * syscalls.cc (chmod): Changed call to set_file_attribute, to keep uid/gid setting. * security.cc (set_nt_attribute): Set owner and group only, if they are corresponding to current user. --------------6FA99905F1353CB61AF0CAA2 Content-Type: text/plain; charset=us-ascii; name="ntsec-patch2" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ntsec-patch2" Index: syscalls.cc =================================================================== RCS file: /src/cvsroot/winsup-990303/syscalls.cc,v retrieving revision 1.1 diff -u -p -1 -r1.1 syscalls.cc --- syscalls.cc 1999/03/05 22:26:50 1.1 +++ syscalls.cc 1999/03/06 20:05:54 @@ -880,2 +880,7 @@ retry: + int attrib; + BOOL a_ok; + + a_ok = get_file_attribute (win32_path.get_win32 (), &attrib); + /* open the file again for write owner and dac */ @@ -926,2 +931,6 @@ retry: syscall_printf ("0 = chown (%s,...)", name); + + if (a_ok) + set_file_attribute (win32_path.get_win32 (), + uid, gid, attrib); return 0; @@ -991,4 +1000,8 @@ chmod (const char *path, mode_t mode) int now; + + set_file_attribute (win32_path.get_win32 (), + get_file_owner (win32_path.get_win32 ()), + get_file_group (win32_path.get_win32 ()), + mode); - set_file_attribute (win32_path.get_win32 (), mode); Index: security.cc =================================================================== RCS file: /src/cvsroot/winsup-990303/security.cc,v retrieving revision 1.1 diff -u -p -1 -r1.1 security.cc --- security.cc 1999/03/05 22:26:50 1.1 +++ security.cc 1999/03/06 20:50:46 @@ -2,5 +2,6 @@ - Copyright 1997, 1998 Cygnus Solutions. + Copyright 1997, 1998, 1999 Cygnus Solutions. - Written by Gunther Ebert, gunther DOT ebert AT ixos-leipzig DOT de + Originaly written by Gunther Ebert, gunther DOT ebert AT ixos-leipzig DOT de + Extensions by Corinna Vinschen @@ -15,77 +16,28 @@ details. */ #include +#include +#include +#include #include "winsup.h" -#if 0 -PSID -get_world_sid () -{ - PSID world_sid; - SID_IDENTIFIER_AUTHORITY world_sid_auth = SECURITY_WORLD_SID_AUTHORITY; - - world_sid = (PSID) LocalAlloc (LPTR,GetSidLengthRequired (1)); +extern BOOL allow_ntea; +BOOL allow_ntsec = FALSE; - InitializeSid (world_sid, &world_sid_auth, 1); - *(GetSidSubAuthority (world_sid, 0)) = SECURITY_WORLD_RID; +extern PSID get_admin_sid (); - return world_sid; -} - -int -world_full_access (HANDLE h, int type) +PSID +get_world_sid () { - PSID world_sid = NULL; - PSECURITY_DESCRIPTOR psd = NULL; - PACL pacl = NULL; - DWORD acl_size = 1024; - - world_sid = get_world_sid(); - - if (!world_sid) - goto clean_on_error; - - psd = (PSECURITY_DESCRIPTOR) LocalAlloc (LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); - - if (!psd) - goto clean_on_error; - - if (!InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION)) - goto clean_on_error; + static NO_COPY PSID sidBuf; - pacl = (PACL) LocalAlloc (LPTR, acl_size); - - if (!pacl) - goto clean_on_error; - - /* FIXME: the 3rd parameter is actually ACL_REVISION which is - not defined in Scott Christley's header files. */ - if (!InitializeAcl (pacl, acl_size, 2)) - goto clean_on_error; - - if (!AddAccessAllowedAce (pacl, 2, type, world_sid)) - goto clean_on_error; - - if (!SetSecurityDescriptorDacl (psd, TRUE, pacl, FALSE)) - goto clean_on_error; - - if(!SetKernelObjectSecurity (h, DACL_SECURITY_INFORMATION, psd)) - goto clean_on_error; - - LocalFree ((HANDLE) world_sid); - LocalFree ((HANDLE) psd); - LocalFree ((HANDLE) pacl); - return TRUE; - -clean_on_error: - if (world_sid) - LocalFree ((HANDLE) world_sid); - - if (psd) - LocalFree ((HANDLE) psd); - - if (pacl) - LocalFree ((HANDLE) pacl); - - return FALSE; + if (! sidBuf) + { + SID_IDENTIFIER_AUTHORITY world_sid_auth = SECURITY_WORLD_SID_AUTHORITY; + + AllocateAndInitializeSid (&world_sid_auth, 1, + SECURITY_WORLD_RID, 0, 0, 0, + 0, 0, 0, 0, + &sidBuf); + } + return sidBuf; } -#endif @@ -155,6 +107,153 @@ get_id_from_sid (PSID psid) } + +static BOOL +get_nt_attribute (const char *file, int *attribute) +{ + if (os_being_run != winNT) + return FALSE; + + syscall_printf ("file: %s", file); + + if (file[1] == ':') + { + static char drive[4] = "X:\\"; + char fs[32]; + + drive[0] = file[0]; + if (! GetVolumeInformation(drive, NULL, 0, NULL, NULL, NULL, fs, 32)) + { + debug_printf ("GetVolumeInformation(%s) %d", drive, GetLastError()); + return FALSE; + } + if (! strcmp (fs, "FAT")) + return FALSE; + } + + DWORD sd_size = 0; + DWORD bufdummy; + SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *) &bufdummy; + + if (! GetFileSecurity (file, OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION, + sd, 4, &sd_size)) + { + debug_printf ("GetFileSecuritySize %d", GetLastError()); + if (sd_size == 0) + return FALSE; + } + sd = (SECURITY_DESCRIPTOR *) malloc (sd_size); + if (! sd) + { + debug_printf ("malloc"); + return FALSE; + } + if (! GetFileSecurity (file, OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION, + sd, sd_size, &sd_size)) + { + free (sd); + debug_printf ("GetFileSecurity %d", GetLastError ()); + return FALSE; + } + + PSID sidOwner; + PSID sidGroup; + BOOL dummy; + + if (! GetSecurityDescriptorOwner (sd, &sidOwner, &dummy)) + debug_printf ("GetSecurityDescriptorOwner %d", GetLastError ()); + if (! GetSecurityDescriptorGroup (sd, &sidGroup, &dummy)) + debug_printf ("GetSecurityDescriptorGroup %d", GetLastError ()); + + PACL acl; + BOOL acl_exists; + + if (! GetSecurityDescriptorDacl (sd, &acl_exists, &acl, &dummy) + || ! acl_exists) + { + free (sd); + debug_printf ("GetSecurityDescriptorDacl %d", GetLastError ()); + return FALSE; + } + + BOOL has_owner_bits = FALSE; + BOOL has_group_bits = FALSE; + BOOL has_world_bits = FALSE; + + for (DWORD i = 0; i < acl->AceCount; ++i) + { + ACCESS_ALLOWED_ACE *ace; + + if (GetAce (acl, i, (PVOID *) &ace)) + { + switch (ace->Header.AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: + if (sidOwner && EqualSid ((PSID) &ace->SidStart, sidOwner)) + { + *attribute &= ~S_IRWXU; + has_owner_bits = TRUE; + if (ace->Mask & FILE_READ_DATA) + *attribute |= S_IRUSR; + if (ace->Mask & FILE_WRITE_DATA) + *attribute |= S_IWUSR; + if (ace->Mask & FILE_EXECUTE) + *attribute |= S_IXUSR; + } + else if (sidGroup && EqualSid ((PSID) &ace->SidStart, sidGroup)) + { + *attribute &= ~S_IRWXG; + has_group_bits = TRUE; + if (ace->Mask & FILE_READ_DATA) + *attribute |= S_IRGRP; + if (ace->Mask & FILE_WRITE_DATA) + *attribute |= S_IWGRP; + if (ace->Mask & FILE_EXECUTE) + *attribute |= S_IXGRP; + } + else if (EqualSid ((PSID) &ace->SidStart, get_world_sid ())) + { + *attribute &= ~S_IRWXO; + has_world_bits = TRUE; + if (ace->Mask & FILE_READ_DATA) + { + *attribute |= S_IROTH; + if (! sidOwner || ! has_owner_bits) + *attribute |= S_IRUSR; + if (! sidGroup || ! has_group_bits) + *attribute |= S_IRGRP; + } + if (ace->Mask & FILE_WRITE_DATA) + { + *attribute |= S_IWOTH; + if (! sidOwner || ! has_owner_bits) + *attribute |= S_IWUSR; + if (! sidGroup || ! has_group_bits) + *attribute |= S_IWGRP; + } + if (ace->Mask & FILE_EXECUTE) + { + *attribute |= S_IXOTH; + if (! sidOwner || ! has_owner_bits) + *attribute |= S_IXUSR; + if (! sidGroup || ! has_group_bits) + *attribute |= S_IXGRP; + } + } + break; + case ACCESS_DENIED_ACE_TYPE: + // Still ignored! + break; + default: + break; + } + } + } -/* - * File attribute stuff. FIXME: add NTFS security. - */ + free (sd); + syscall_printf ("file: %s %x", file, *attribute); + return TRUE; +} @@ -163,5 +262,246 @@ get_file_attribute (const char *file, in { + if (! attribute) + return FALSE; + int res = NTReadEA (file, ".UNIXATTR", (char *) attribute, sizeof (*attribute)); - return res > 0; + + // symlinks are anything for everyone! + if ((*attribute & S_IFLNK) == S_IFLNK) + *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + + if (!allow_ntsec) + return res > 0; + + return get_nt_attribute (file, attribute); +} + +static BOOL +set_nt_attribute (const char *file, uid_t uid, gid_t gid, int attribute) +{ + if (os_being_run != winNT) + return FALSE; + + DWORD sidlen, domlen; + char dom[100]; + char user[256]; + SID_NAME_USE acc_type; + + /* + * Caution! + * + * ID 513 is `none'. Giving explicit permissions + * to `none' will result in dubious problems! + * + * Uid 513 is definitely not allowed here! + */ + if (uid == 513) + return FALSE; + + struct passwd *pw = getpwuid (uid); + strcpy (user, pw ? pw->pw_name : getlogin ()); + PSID sidOwner = (PSID) malloc (1024); + if (! sidOwner) + { + debug_printf ("malloc 1"); + return FALSE; + } + if (! LookupAccountName (NULL, user, + sidOwner, (sidlen = 1024, &sidlen), + dom, (domlen = 100, &domlen), + &acc_type)) + { + free (sidOwner); + debug_printf ("LookupAccountName(%s) %d", user, GetLastError ()); + return FALSE; + } + else if (acc_type != SidTypeUser) + { + char domuser[356]; + strcpy (domuser, dom); + strcat (domuser, "\\"); + strcat (domuser, user); + if (! LookupAccountName (NULL, domuser, + sidOwner, (sidlen = 1024, &sidlen), + dom, (domlen = 100, &domlen), + &acc_type)) + { + free (sidOwner); + debug_printf ("LookupAccountName(%s) %d", domuser, GetLastError ()); + return FALSE; + } + } + sidOwner = (PSID) realloc (sidOwner, sidlen + 1); + debug_printf ("user: %s [%d]", user, + *GetSidSubAuthority((PSID) sidOwner, + *GetSidSubAuthorityCount((PSID) sidOwner) - 1)); + + struct group *grp = getgrgid (gid); + PSID sidGroup = NULL; + + /* + * Caution! + * + * ID 513 is `none'. Giving explicit permissions + * to `none' will result in dubious problems! + * + * Gid 513 will result in not setting group permissions here. + */ + if (grp && gid != 513) + { + sidGroup = (PSID) malloc (1024); + if (! sidGroup) + { + free (sidOwner); + free (sidGroup); + debug_printf ("malloc 2"); + return FALSE; + } + if (! LookupAccountName (NULL, grp->gr_name, + sidGroup, (sidlen = 1024, &sidlen), + dom, (domlen = 100, &domlen), + &acc_type)) + { + free (sidOwner); + free (sidGroup); + debug_printf ("LookupAccountName(%s) %d", grp->gr_name, + GetLastError ()); + return FALSE; + } + sidGroup = (PSID) realloc (sidGroup, sidlen + 1); + debug_printf ("group: %s [%d]", grp->gr_name, + *GetSidSubAuthority((PSID) sidGroup, + *GetSidSubAuthorityCount((PSID) sidGroup) - 1)); + } + else + debug_printf ("no group"); + + SECURITY_DESCRIPTOR sd; + + if (! InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) + debug_printf ("InitializeSecurityDescriptor %d", GetLastError ()); + if (! SetSecurityDescriptorOwner(&sd, sidOwner, FALSE)) + debug_printf ("SetSecurityDescriptorOwner %d", GetLastError ()); + if (sidGroup) + if (! SetSecurityDescriptorGroup(&sd, sidGroup, FALSE)) + debug_printf ("SetSecurityDescriptorGroup %d", GetLastError ()); + + size_t acl_len = sizeof (ACL) + + 3 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD)) + + GetLengthSid (sidOwner) + + GetLengthSid (get_admin_sid ()) + + GetLengthSid (get_world_sid ()); + if (sidGroup) + acl_len += sizeof (ACCESS_ALLOWED_ACE) + - sizeof (DWORD) + + GetLengthSid (sidGroup); + + PACL acl = (PACL) malloc (acl_len); + if (! acl) + { + free (sidOwner); + free (sidGroup); + debug_printf ("malloc 4"); + return FALSE; + } + if (! InitializeAcl (acl, acl_len, ACL_REVISION)) + debug_printf ("InitializeAcl %d", GetLastError ()); + + int ace_off = 0; + ACCESS_ALLOWED_ACE *ace; + + DWORD access = STANDARD_RIGHTS_ALL; + if (attribute & S_IRUSR) + access |= FILE_GENERIC_READ | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; + if (attribute & S_IWUSR) + access |= FILE_GENERIC_WRITE | DELETE | FILE_DELETE_CHILD; + if (attribute & S_IXUSR) + access |= FILE_GENERIC_EXECUTE; + if (! AddAccessAllowedAce (acl, ACL_REVISION, access, sidOwner)) + debug_printf ("AddAccessAllowedAce(owner) %d", GetLastError ()); + if (GetAce(acl, 0, (PVOID *) &ace)) + ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + + if (! sidGroup || ! EqualSid (sidGroup, get_admin_sid ())) + { + if (! AddAccessAllowedAce (acl, ACL_REVISION, + SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL, + get_admin_sid ())) + debug_printf ("AddAccessAllowedAce(admin) %d", GetLastError ()); + if (GetAce(acl, 1, (PVOID *) &ace)) + ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + ace_off = 1; + } + + if (sidGroup) + { + access = 0; + if (attribute & S_IRGRP) + { + access |= FILE_GENERIC_READ; + if (EqualSid (sidGroup, get_admin_sid ())) + access |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; + } + if (attribute & S_IWGRP) + access |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE + | DELETE | FILE_DELETE_CHILD; + if (attribute & S_IXGRP) + access |= FILE_GENERIC_EXECUTE; + if (! AddAccessAllowedAce (acl, ACL_REVISION, access, sidGroup)) + debug_printf ("AddAccessAllowedAce(group) %d", GetLastError ()); + if (GetAce(acl, 1 + ace_off, (PVOID *) &ace)) + ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + } + + access = 0; + if (attribute & S_IROTH) + access |= FILE_GENERIC_READ; + if (attribute & S_IWOTH) + access |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE + | DELETE | FILE_DELETE_CHILD; + if (attribute & S_IXOTH) + access |= FILE_GENERIC_EXECUTE; + if (! AddAccessAllowedAce (acl, ACL_REVISION, access, get_world_sid ())) + debug_printf ("AddAccessAllowedAce(world) %d", GetLastError ()); + if (GetAce(acl, 2 + ace_off, (PVOID *) &ace)) + ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + + if (! SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) + debug_printf ("SetSecurityDescriptorDacl %d", GetLastError ()); + + SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; + + if (uid == myself->uid) + si |= OWNER_SECURITY_INFORMATION; + if (grp && gid == myself->gid) + si |= GROUP_SECURITY_INFORMATION; + + if (! SetFileSecurity (file, si, &sd)) + debug_printf ("SetFileSecurity %d", GetLastError()); + + free (sidOwner); + free (sidGroup); + free (acl); + + return TRUE; +} + +BOOL +set_file_attribute (const char *file, uid_t uid, gid_t gid, int attribute) +{ + // symlinks are anything for everyone! + if ((attribute & S_IFLNK) == S_IFLNK) + attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + + BOOL ret = NTWriteEA (file, ".UNIXATTR", + (char *) &attribute, sizeof (attribute)); + + if (!allow_ntsec) + return ret; + + ret = set_nt_attribute (file, uid, gid, attribute); + + syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)", ret, file, uid, gid, attribute); + + return ret; } @@ -171,4 +511,3 @@ set_file_attribute (const char *file, in { - return NTWriteEA (file, ".UNIXATTR", (char *) &attribute, - sizeof (attribute)); + return set_file_attribute (file, myself->uid, myself->gid, attribute); } --------------6FA99905F1353CB61AF0CAA2--