From: corinna DOT vinschen AT cityweb DOT de (Corinna Vinschen) Subject: Patch, Version 2: UNIX-like permissions on objects 30 Jan 1999 10:26:36 -0800 Message-ID: <36B346C5.4EE92C15.cygnus.cygwin32.developers@cityweb.de> References: <01BE46C2 DOT 29B35190 AT sos> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit To: Sergey Okhapkin Cc: "cygwin32-developers AT cygnus DOT com" Hello! I have (from my point of view) completed the patch, to use NT security. It consists of two parts. Following are descriptions of the proceedings: 1st --- Additional functions `sec_user()' and `sec_user_nih()', to give permissions to kernel objects. The functions are able, to substitute the global variables `sec_none' and `sec_none_nih'.This is used so far only in `getsem()', to get a Semaphore permission, which allows Administrators to send signals to processes, owned by other users. Usage in other sources of cygwin could be a later development target. The SECURITY_ATTRIBUTES, which are needed twice for every user, (inheritable and not inheritable) are generated only once, when a user process calls this functions the first time. They are not duplicated on process creation, but `static NO_COPY' in the DLL, to save time and memory. To get the administrators or administrators group SID, the /etc/group and /etc/passwd files are searched for gid 544, if not found uid 544, if not found uid 500, if not found try the fixed string "administrator". The used structure `sa_user' saves the name of the user, for later checks. Another facility would be, to save the uid instead of the name, to speed up the initial `for'-loop. This would be easy to do. 2nd --- Additional functions, to give file permissions according to the UX-like permissions, reflected by cygwin. This permissions are coupled to the new environment option CYGWIN=[no]ntsec. A new function `set_file_attribute()' with additional parameters `uid' and `gid' allows to set permissions without changing user and group. The new functions, to support NT security are `get_nt_attribute()' and `set_nt_attribute()'. The set-function is of interest: First of all, checks are done on parameters `uid' and `gid' and to get their SIDs. If `uid' is 513, which is the group `nobody', the function fails, if `gid' is 513, no group permissions will be set. This is important, because setting explicit permissions for `nobody' result in dubious problems (mainly "permission denied"). The next action is to create an ACL. It will contain up to four ACEs: - the owners permissions, - the group permissions, if group is not `nobody' or not found - full permissions for the administrators group, if the previous group is not the administrators group. - the world permissions. Special permissions: If the user gets only read permission, he gets write permission to the attributes, too. If the group is the administrators group, it gets write permissions to the attributes, too. Important hints: - The /etc/passwd and /etc/group files _must_ be ok! - The /etc/group file should contain the local groups on stand-alone workstations! - The gids in /etc/passwd should contain the correct membership to the groups, never gid 513 (nobody)! You should take special care especially on stand-alone workstations! Correct example files on a stand-alone workstation (names are only translations from german NT4, I don't know the english names by own experience): /etc/passwd: everyone:*:0:0:::/usr/bin/date system:*:18:18:::/usr/bin/date administrator::500:544::/home/admin:/bin/csh guest:*:501:546:::/usr/bin/date administrators:*:544:544::/home/admin:/usr/bin/date corinna::1000:547:Corinna Vinschen:/home/corinna:/bin/tcsh ftp:*:1002:545::/home/pub:/usr/bin/date /etc/group: everyone::0: system::18: nobody::513: administrators::544: users::545: guests::546: powerusers::547: replication-operator::552:0::: backup-operators::551:0::: Remaining problem: NT directories have not only own permissions, but default permissions for their files, too. The attached patch is not able, to set this rights. If somebody knows a solution, I would be glad, to hear from you! I have attached the full patch, related to winsup-990126. Please, give a feedback! Opinions, bug reports, patches and suggestions are always welcome. Does this patch have a chance, to find it's way in the main distribution? Regards, Corinna ChangeLog: ========== Sat Jan 30 02:12:00 Corinna Vinschen * security.cc: Special handling for user and/or administrators permissions to write (extended) attributes. Fri Jan 29 02:12:00 Corinna Vinschen * security.cc: Don't allow 513(nobody) as user or group. * strace.cc (strace_open): Calls `set_file_attribute()' now. * exceptions.cc (handle_exceptions): ditto. Thu Jan 28 11:00:00 Corinna Vinschen * security.cc: new functions `set_nt_attribute()', `get_nt_attribute()' and `set_file_attribute()' with additional parameters `uid' and `gid', to support real NT security. * winsup.h: Prototype for `set_file_attribute()' with four parameters. * dir.cc (mkdir): Calls `set_file_attribute()' now. * syscalls.cc (chown): ditto. * syscalls.cc (chmod): ditto, with correct uid/gid. * errno.cc: Support for Windows errors ERROR_CRC and ERROR_NO_READY and for Error ENOMEDIUM. 21 Jan 12:30:00 1999 Corinna Vinschen * shared.cc: New function `get_admin_sid()' to get a SID of the administrators group or of administrator. New functions `sec_user()' and `sec_user_nih()' to get SECURITY_ATTRIBUTES with all permissions for the user and the administtrator group. * shared.h: Prototypes for the above new functions `sec_user()' and `sec_user_nih()'. * sigproc.cc (getsem): Create process semaphore with permissions set by `sec_user()'. Index: shared.h =================================================================== RCS file: /src/cvsroot/winsup-990126/shared.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -p -1 -r1.1 -r1.2 --- shared.h 1999/01/29 09:33:43 1.1 +++ shared.h 1999/01/29 09:51:46 1.2 @@ -462,2 +462,4 @@ public: extern SECURITY_ATTRIBUTES sec_none, sec_none_nih, sec_all, sec_all_nih; +extern SECURITY_ATTRIBUTES *sec_user (BOOL inherit = TRUE); +extern SECURITY_ATTRIBUTES *sec_user_nih (); Index: shared.cc =================================================================== RCS file: /src/cvsroot/winsup-990126/shared.cc,v retrieving revision 1.1 retrieving revision 1.2 diff -u -p -1 -r1.1 -r1.2 --- shared.cc 1999/01/29 09:33:43 1.1 +++ shared.cc 1999/01/29 09:51:46 1.2 @@ -12,2 +12,5 @@ details. */ #include +#include +#include +#include #include "winsup.h" @@ -186,2 +189,172 @@ SECURITY_DESCRIPTOR *get_null_sd () return null_sdp; +} + +PSID +get_admin_sid () +{ + static NO_COPY PSID sidBuf; + + if (! sidBuf) + { + struct group *gr_ptr; + struct passwd *pw_ptr; + char user[32], dom[100]; + DWORD sidlen, domlen; + SID_NAME_USE acc_type; + + sidBuf = (PSID) malloc (1024); + + // Get name of administrator group from /etc/group + + if ((gr_ptr = getgrgid (544)) != NULL + && strcmp (gr_ptr->gr_name, "everyone")) + strcpy (user, gr_ptr->gr_name); + + // else get name of administrator group from /etc/passwd + + else if ((pw_ptr = getpwuid (544)) != NULL) + strcpy (user, pw_ptr->pw_name); + + // else get name of administrator from /etc/passwd + + else if ((pw_ptr = getpwuid (500)) != NULL) + strcpy (user, pw_ptr->pw_name); + + // else try "administrator" + + else + strcpy (user, "administrator"); + + if (! LookupAccountName (NULL, user, + sidBuf, (sidlen = 1024, &sidlen), + dom, (domlen = 100, &domlen), + &acc_type)) + { + free (sidBuf); + sidBuf = NULL; + } + else + sidBuf = (PSID) realloc (sidBuf, sidlen + 1); + } + return sidBuf; +} + +struct user_sa { + char user[32]; + SECURITY_ATTRIBUTES sa; + SECURITY_ATTRIBUTES sa_nih; + SECURITY_DESCRIPTOR sd; + PACL acl; +}; + +static NO_COPY int sa_cnt = 0; +static NO_COPY user_sa *sa_list; + +SECURITY_ATTRIBUTES * +sec_user (BOOL inherit) +{ + for (int i = 0; i < sa_cnt; ++i) + if (! strcmp (sa_list[i].user, getlogin ())) + { + debug_printf("user not found: %s", getlogin()); + return inherit ? &sa_list[i].sa_nih : &sa_list[i].sa; + } + + PSID sidBuf; + + sidBuf = (PSID) malloc (1024); + if (! sidBuf) + { + debug_printf("malloc 1"); + return inherit ? &sec_none_nih : &sec_none; + } + + DWORD sidlen, domlen; + char dom[100]; + SID_NAME_USE acc_type; + + if (! LookupAccountName (NULL, getlogin (), + sidBuf, (sidlen = 1024, &sidlen), + dom, (domlen = 100, &domlen), + &acc_type)) + { + debug_printf("LookupAccountName(%s) %E", getlogin()); + free (sidBuf); + return inherit ? &sec_none_nih : &sec_none; + } + else if (acc_type != SidTypeUser) + { + char domuser[356]; + strcpy (domuser, dom); + strcat (domuser, "\\"); + strcat (domuser, getlogin ()); + if (! LookupAccountName (NULL, domuser, + sidBuf, (sidlen = 1024, &sidlen), + dom, (domlen = 100, &domlen), + &acc_type)) + { + debug_printf("LookupAccountName(%s) %E", domuser); + free (sidBuf); + return inherit ? &sec_none_nih : &sec_none; + } + } + sidBuf = (PSID) realloc (sidBuf, sidlen + 1); + + size_t acl_len = sizeof (ACL) + + 2 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD)) + + GetLengthSid (sidBuf) + + GetLengthSid (get_admin_sid ()); + PACL acl = (PACL) malloc (acl_len); + if (! acl) + { + debug_printf("malloc 2"); + free (sidBuf); + return inherit ? &sec_none_nih : &sec_none; + } + if (! InitializeAcl (acl, acl_len, ACL_REVISION)) + debug_printf("InitializeAcl %E"); + if (! AddAccessAllowedAce (acl, ACL_REVISION, + SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL, + sidBuf)) + debug_printf("AddAccessAllowedAce(%s) %E", getlogin()); + + if (! AddAccessAllowedAce (acl, ACL_REVISION, + SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL, + get_admin_sid ())) + debug_printf("AddAccessAllowedAce(admin) %E"); + + user_sa *tmp_sa_list = (user_sa *) realloc (sa_list, + (sa_cnt + 1) * sizeof (user_sa)); + if (! tmp_sa_list) + { + debug_printf("malloc 3"); + free (acl); + free (sidBuf); + return inherit ? &sec_none_nih : &sec_none; + } + sa_list = tmp_sa_list; + + sa_list[sa_cnt].acl = acl; + if (! InitializeSecurityDescriptor (&sa_list[sa_cnt].sd, + SECURITY_DESCRIPTOR_REVISION)) + debug_printf("InitializeSecurityDescriptor %E"); + if (! SetSecurityDescriptorOwner (&sa_list[sa_cnt].sd, sidBuf, FALSE)) + debug_printf("SetSecurityDescriptorOwner %E"); + if (! SetSecurityDescriptorDacl (&sa_list[sa_cnt].sd, TRUE, acl, FALSE)) + debug_printf("SetSecurityDescriptorDacl %E"); + sa_list[sa_cnt].sa.nLength = + sa_list[sa_cnt].sa_nih.nLength = sizeof (SECURITY_ATTRIBUTES); + sa_list[sa_cnt].sa.lpSecurityDescriptor = + sa_list[sa_cnt].sa_nih.lpSecurityDescriptor = &sa_list[sa_cnt].sd; + sa_list[sa_cnt].sa.bInheritHandle = TRUE; + sa_list[sa_cnt].sa_nih.bInheritHandle = FALSE; + strcpy (sa_list[sa_cnt].user, getlogin ()); + ++sa_cnt; + return inherit ? &sa_list[sa_cnt - 1].sa : &sa_list[sa_cnt - 1].sa_nih; +} + +SECURITY_ATTRIBUTES * +sec_user_nih () +{ + return sec_user (FALSE); } Index: sigproc.cc =================================================================== RCS file: /src/cvsroot/winsup-990126/sigproc.cc,v retrieving revision 1.1 retrieving revision 1.2 diff -u -p -1 -r1.1 -r1.2 --- sigproc.cc 1999/01/29 09:33:43 1.1 +++ sigproc.cc 1999/01/29 09:51:46 1.2 @@ -1070,3 +1070,3 @@ getsem (pinfo *p, const char *str, int i DWORD winpid = GetCurrentProcessId (); - h = CreateSemaphore (&sec_none_nih, init, max, str = shared_name (str, wi npid)); + h = CreateSemaphore (sec_user (), init, max, str = shared_name (str, winp id)); p = myself; Index: winsup.h =================================================================== RCS file: /src/cvsroot/winsup-990126/winsup.h,v retrieving revision 1.1 retrieving revision 1.3 diff -u -p -1 -r1.1 -r1.3 --- winsup.h 1999/01/29 09:33:44 1.1 +++ winsup.h 1999/01/29 10:00:53 1.3 @@ -355,2 +355,3 @@ BOOL get_file_attribute (const char *, i BOOL set_file_attribute (const char *, int); +BOOL set_file_attribute (const char *, uid_t, gid_t, int); void set_std_handle (int); Index: dir.cc =================================================================== RCS file: /src/cvsroot/winsup-990126/dir.cc,v retrieving revision 1.1 retrieving revision 1.3 diff -u -p -1 -r1.1 -r1.3 --- dir.cc 1999/01/29 09:33:41 1.1 +++ dir.cc 1999/01/29 10:00:53 1.3 @@ -273,3 +273,7 @@ mkdir (const char *dir, mode_t mode) if (CreateDirectoryA (real_dir.get_win32 (), 0)) - res = 0; + { + set_file_attribute (real_dir.get_win32 (), + (mode & 0777) & ~myself->umask); + res = 0; + } else Index: exceptions.cc =================================================================== RCS file: /src/cvsroot/winsup-990126/exceptions.cc,v retrieving revision 1.1 retrieving revision 1.3 diff -u -p -1 -r1.1 -r1.3 --- exceptions.cc 1999/01/29 09:33:41 1.1 +++ exceptions.cc 1999/01/29 10:00:52 1.3 @@ -306,2 +306,3 @@ handle_exceptions (EXCEPTION_RECORD *e, { + set_file_attribute (corefile, 0644); system_printf ("Dumping stack trace to %s", corefile); Index: strace.cc =================================================================== RCS file: /src/cvsroot/winsup-990126/strace.cc,v retrieving revision 1.1 retrieving revision 1.3 diff -u -p -1 -r1.1 -r1.3 --- strace.cc 1999/01/29 09:33:44 1.1 +++ strace.cc 1999/01/29 10:00:52 1.3 @@ -98,2 +98,3 @@ strace_open (const char *fn) { + set_file_attribute (fn, 0644); myself->strace_file = h; Index: syscalls.cc =================================================================== RCS file: /src/cvsroot/winsup-990126/syscalls.cc,v retrieving revision 1.2 retrieving revision 1.3 diff -u -p -1 -r1.2 -r1.3 --- syscalls.cc 1999/01/29 09:49:19 1.2 +++ syscalls.cc 1999/01/29 10:00:52 1.3 @@ -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; @@ -992,3 +1001,6 @@ chmod (const char *path, mode_t mode) - set_file_attribute (win32_path.get_win32 (), mode); + set_file_attribute (win32_path.get_win32 (), + get_file_owner (win32_path.get_win32 ()), + get_file_group (win32_path.get_win32 ()), + mode); Index: environ.cc =================================================================== RCS file: /src/cvsroot/winsup-990126/environ.cc,v retrieving revision 1.1 diff -u -p -1 -r1.1 environ.cc --- environ.cc 1999/01/29 09:33:41 1.1 +++ environ.cc 1999/01/30 08:31:47 @@ -19,2 +19,3 @@ extern BOOL allow_glob; extern BOOL allow_ntea; +extern BOOL allow_ntsec; extern BOOL strip_title_path; @@ -379,2 +380,3 @@ parse_options (char *buf) add ("ntea", &allow_ntea, justset, FALSE, TRUE); + add ("ntsec", &allow_ntsec, justset, FALSE, TRUE); add ("reset_com", &reset_com, justset, FALSE, TRUE); Index: security.cc =================================================================== RCS file: /src/cvsroot/winsup-990126/security.cc,v retrieving revision 1.1 diff -u -p -1 -r1.1 security.cc --- security.cc 1999/01/29 09:33:43 1.1 +++ security.cc 1999/01/30 16:11:14 @@ -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,5 +16,12 @@ details. */ #include +#include +#include +#include #include "winsup.h" -#if 0 +extern BOOL allow_ntea; +BOOL allow_ntsec = FALSE; + +extern PSID get_admin_sid (); + PSID @@ -21,9 +29,13 @@ get_world_sid () { - PSID world_sid; - SID_IDENTIFIER_AUTHORITY world_sid_auth = SECURITY_WORLD_SID_AUTHORITY; + static PSID world_sid; - world_sid = (PSID) LocalAlloc (LPTR,GetSidLengthRequired (1)); + if (! world_sid) + { + SID_IDENTIFIER_AUTHORITY world_sid_auth = SECURITY_WORLD_SID_AUTHORITY; + + world_sid = (PSID) LocalAlloc (LPTR,GetSidLengthRequired (1)); - InitializeSid (world_sid, &world_sid_auth, 1); - *(GetSidSubAuthority (world_sid, 0)) = SECURITY_WORLD_RID; + InitializeSid (world_sid, &world_sid_auth, 1); + *(GetSidSubAuthority (world_sid, 0)) = SECURITY_WORLD_RID; + } @@ -32,2 +44,3 @@ get_world_sid () +#if 0 int @@ -160,2 +173,158 @@ 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] == ':') + { + char fbuf[4]; + char fs[32]; + + fbuf[0] = file[0]; + fbuf[1] = ':'; + fbuf[2] = '\\'; + fbuf[3] = '\0'; + if (! GetVolumeInformation(fbuf, NULL, 0, NULL, NULL, NULL, fs, 32)) + { + debug_printf ("GetVolumeInformation(%s) %d", fbuf, GetLastError()); + return FALSE; + } + if (! strcmp (fs, "FAT")) + { + debug_printf ("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; + debug_printf ("GetFileSecuritySize %d bytes", sd_size); + } + 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; + } + } + + free (sd); + syscall_printf ("file: %s %x", file, *attribute); + return TRUE; +} + BOOL @@ -163,5 +332,224 @@ 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) + *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 `nobody'. Giving explicit permissions + * to `nobody' 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 `nobody'. Giving explicit permissions + * to `nobody' 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 ("user: %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 ()); + + 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 (! 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 (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 ()); + } + + access = 0; + if (attribute & S_IROTH) + access |= FILE_GENERIC_READ; + if (attribute & S_IWOTH) + access |= 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 (! SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) + debug_printf ("SetSecurityDescriptorDacl %d", GetLastError ()); + + if (! SetFileSecurity (file, + OWNER_SECURITY_INFORMATION + | (grp ? GROUP_SECURITY_INFORMATION : 0) + | DACL_SECURITY_INFORMATION, + &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) + attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + + BOOL ret = NTWriteEA (file, ".UNIXATTR", + (char *) &attribute, sizeof (attribute)); + + if (!allow_ntsec) + return ret; + + return set_nt_attribute (file, uid, gid, attribute); } @@ -171,4 +559,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); }