From c0d1968a18c75ffb160c840c474b9b1e095cd541 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 20 Apr 2001 13:02:32 +0000 Subject: * Makefile.in: Add object files `sec_helper.cc' and `sec_acl.cc'. * security.cc: Swap out several functions. * sec_acl.cc: New file. Move Sun compatibel ACL functions from `security.cc' to here. * sec_helper.cc: New file. Move security helper functions from `security.cc' to here. * security.h: Changed to accomodate the above changes. * grp.cc: Replace `group_in_memory_p' by `group_state'. Eliminate group_sem throughout. (enum grp_state): New enumeration type. (read_etc_group): Make race safe. * security.cc: Eliminate group_sem throughout. --- winsup/cygwin/ChangeLog | 18 + winsup/cygwin/Makefile.in | 2 +- winsup/cygwin/grp.cc | 99 +-- winsup/cygwin/sec_acl.cc | 1060 ++++++++++++++++++++++++++++++++ winsup/cygwin/sec_helper.cc | 399 ++++++++++++ winsup/cygwin/security.cc | 1417 +------------------------------------------ winsup/cygwin/security.h | 43 +- 7 files changed, 1575 insertions(+), 1463 deletions(-) create mode 100644 winsup/cygwin/sec_acl.cc create mode 100644 winsup/cygwin/sec_helper.cc diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index c8789b7f6..5b5f04853 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,21 @@ +Fri Apr 20 14:50:00 2001 Corinna Vinschen + + * Makefile.in: Add object files `sec_helper.cc' and `sec_acl.cc'. + * security.cc: Swap out several functions. + * sec_acl.cc: New file. Move Sun compatibel ACL functions from + `security.cc' to here. + * sec_helper.cc: New file. Move security helper functions from + `security.cc' to here. + * security.h: Changed to accomodate the above changes. + +Fri Apr 20 14:12:00 2001 Corinna Vinschen + + * grp.cc: Replace `group_in_memory_p' by `group_state'. + Eliminate group_sem throughout. + (enum grp_state): New enumeration type. + (read_etc_group): Make race safe. + * security.cc: Eliminate group_sem throughout. + Thu Apr 19 9:40:00 2001 Corinna Vinschen * mmap.cc (mmap): Drop usage of the same memory area if the same diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index 438ff5f65..7eeaf1214 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -122,7 +122,7 @@ DLL_OFILES:=assert.o autoload.o cygheap.o dcrt0.o debug.o delqueue.o dir.o \ fork.o glob.o grp.o heap.o init.o ioctl.o localtime.o malloc.o \ miscfuncs.o mmap.o net.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o \ pthread.o regexp.o regerror.o regsub.o registry.o resource.o scandir.o \ - sched.o security.o select.o shared.o shortcut.o signal.o sigproc.o \ + sched.o sec_acl.o sec_helper.o security.o select.o shared.o shortcut.o signal.o sigproc.o \ smallprint.o spawn.o strace.o strsep.o sync.o syscalls.o sysconf.o \ syslog.o termios.o thread.o times.o tty.o uinfo.o uname.o wait.o \ window.o \ diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc index ed6091fea..2b1b5986d 100644 --- a/winsup/cygwin/grp.cc +++ b/winsup/cygwin/grp.cc @@ -42,12 +42,17 @@ static int max_lines = 0; static int grp_pos = 0; #endif -/* Set to 1 when /etc/group has been read in by read_etc_group (). */ -/* Functions in this file need to check the value of group_in_memory_p - and read in the group file if it isn't set. */ -/* FIXME: This should be static but this is called in uinfo_init outside - this file */ -int group_in_memory_p = 0; +/* Set to loaded when /etc/passwd has been read in by read_etc_passwd (). + Set to emulated if passwd is emulated. */ +/* Functions in this file need to check the value of passwd_state + and read in the password file if it isn't set. */ +enum grp_state { + uninitialized = 0, + initializing, + emulated, + loaded +}; +static grp_state group_state = uninitialized; static int parse_grp (struct group &grp, const char *line) @@ -132,50 +137,64 @@ extern PSID get_admin_sid (); void read_etc_group () { - extern int group_sem; char linebuf [200]; char group_name [MAX_USER_NAME]; DWORD group_name_len = MAX_USER_NAME; strncpy (group_name, "Administrators", sizeof (group_name)); - ++group_sem; - FILE *f = fopen (etc_group, "rt"); - --group_sem; + static pthread_mutex_t etc_group_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock (&etc_group_mutex); - if (f) + /* if we got blocked by the mutex, then etc_group may have been processed */ + if (group_state != uninitialized) { - while (fgets (linebuf, sizeof (linebuf), f) != NULL) - { - if (strlen (linebuf)) - add_grp_line (linebuf); - } - - fclose (f); + pthread_mutex_unlock(&etc_group_mutex); + return; } - else /* /etc/group doesn't exist -- create default one in memory */ + + if (group_state != initializing) { - char domain_name [MAX_DOMAIN_NAME]; - DWORD domain_name_len = MAX_DOMAIN_NAME; - SID_NAME_USE acType; - debug_printf ("Emulating /etc/group"); - if (! LookupAccountSidA (NULL , - get_admin_sid () , - group_name, - &group_name_len, - domain_name, - &domain_name_len, - &acType)) + group_state = initializing; + + FILE *f = fopen (etc_group, "rt"); + + if (f) { - strcpy (group_name, "unknown"); - debug_printf ("Failed to get local admins group name. %E"); - } + while (fgets (linebuf, sizeof (linebuf), f) != NULL) + { + if (strlen (linebuf)) + add_grp_line (linebuf); + } - snprintf (linebuf, sizeof (linebuf), "%s::%u:\n", group_name, DEFAULT_GID); - add_grp_line (linebuf); + fclose (f); + group_state = loaded; + } + else /* /etc/group doesn't exist -- create default one in memory */ + { + char domain_name [MAX_DOMAIN_NAME]; + DWORD domain_name_len = MAX_DOMAIN_NAME; + SID_NAME_USE acType; + debug_printf ("Emulating /etc/group"); + if (! LookupAccountSidA (NULL , + get_admin_sid () , + group_name, + &group_name_len, + domain_name, + &domain_name_len, + &acType)) + { + strcpy (group_name, "unknown"); + debug_printf ("Failed to get local admins group name. %E"); + } + + snprintf (linebuf, sizeof (linebuf), "%s::%u:\n", group_name, DEFAULT_GID); + add_grp_line (linebuf); + group_state = emulated; + } } - group_in_memory_p = 1; + pthread_mutex_unlock(&etc_group_mutex); } extern "C" @@ -183,7 +202,7 @@ struct group * getgrgid (gid_t gid) { struct group * default_grp = NULL; - if (!group_in_memory_p) + if (group_state <= initializing) read_etc_group(); for (int i = 0; i < curr_lines; i++) @@ -201,7 +220,7 @@ extern "C" struct group * getgrnam (const char *name) { - if (!group_in_memory_p) + if (group_state <= initializing) read_etc_group(); for (int i = 0; i < curr_lines; i++) @@ -223,7 +242,7 @@ extern "C" struct group * getgrent() { - if (!group_in_memory_p) + if (group_state <= initializing) read_etc_group(); if (grp_pos < curr_lines) @@ -247,7 +266,7 @@ getgroups (int gidsetsize, gid_t *grouplist, gid_t gid, const char *username) DWORD size; int cnt = 0; - if (!group_in_memory_p) + if (group_state <= initializing) read_etc_group(); if (allow_ntsec && diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc new file mode 100644 index 000000000..0ae0a69a7 --- /dev/null +++ b/winsup/cygwin/sec_acl.cc @@ -0,0 +1,1060 @@ +/* secacl.cc: Sun compatible ACL functions. + + Copyright 2000, 2001 Cygnus Solutions. + + Written by Corinna Vinschen + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cygerrno.h" +#include "perprocess.h" +#include "fhandler.h" +#include "path.h" +#include "dtable.h" +#include "sync.h" +#include "sigproc.h" +#include "pinfo.h" +#include "cygheap.h" +#include "security.h" + +static int +searchace (aclent_t *aclp, int nentries, int type, int id = -1) +{ + int i; + + for (i = 0; i < nentries; ++i) + if ((aclp[i].a_type == type && (id < 0 || aclp[i].a_id == id)) + || !aclp[i].a_type) + return i; + return -1; +} + +static int +setacl (const char *file, int nentries, aclent_t *aclbufp) +{ + DWORD sd_size = 4096; + char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + + if (read_sd (file, psd, &sd_size) <= 0) + { + debug_printf ("read_sd %E"); + return -1; + } + + BOOL dummy; + + /* Get owner SID. */ + PSID owner_sid = NULL; + if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) + { + __seterrno (); + return -1; + } + char owner_buf[MAX_SID_LEN]; + if (!CopySid (MAX_SID_LEN, (PSID) owner_buf, owner_sid)) + { + __seterrno (); + return -1; + } + owner_sid = (PSID) owner_buf; + + /* Get group SID. */ + PSID group_sid = NULL; + if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) + { + __seterrno (); + return -1; + } + char group_buf[MAX_SID_LEN]; + if (!CopySid (MAX_SID_LEN, (PSID) group_buf, group_sid)) + { + __seterrno (); + return -1; + } + group_sid = (PSID) group_buf; + + /* Initialize local security descriptor. */ + SECURITY_DESCRIPTOR sd; + if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) + { + __seterrno (); + return -1; + } + if (!SetSecurityDescriptorOwner(&sd, owner_sid, FALSE)) + { + __seterrno (); + return -1; + } + if (group_sid + && !SetSecurityDescriptorGroup(&sd, group_sid, FALSE)) + { + __seterrno (); + return -1; + } + + /* Fill access control list. */ + char acl_buf[3072]; + PACL acl = (PACL) acl_buf; + size_t acl_len = sizeof (ACL); + int ace_off = 0; + + char sidbuf[MAX_SID_LEN]; + PSID sid = (PSID) sidbuf; + struct passwd *pw; + struct group *gr; + int pos; + + if (!InitializeAcl (acl, 3072, ACL_REVISION)) + { + __seterrno (); + return -1; + } + for (int i = 0; i < nentries; ++i) + { + DWORD allow = STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA; + if (aclbufp[i].a_perm & S_IROTH) + allow |= FILE_GENERIC_READ; + if (aclbufp[i].a_perm & S_IWOTH) + allow |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE + | DELETE | FILE_DELETE_CHILD; + if (aclbufp[i].a_perm & S_IXOTH) + allow |= FILE_GENERIC_EXECUTE; + /* Set inherit property. */ + DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT) + ? INHERIT_ONLY : DONT_INHERIT; + /* + * If a specific acl contains a corresponding default entry with + * identical permissions, only one Windows ACE with proper + * inheritance bits is created. + */ + if (!(aclbufp[i].a_type & ACL_DEFAULT) + && (pos = searchace (aclbufp, nentries, + aclbufp[i].a_type | ACL_DEFAULT, + (aclbufp[i].a_type & (USER|GROUP)) + ? aclbufp[i].a_id : -1)) >= 0 + && pos < nentries + && aclbufp[i].a_perm == aclbufp[pos].a_perm) + { + inheritance = INHERIT_ALL; + /* This eliminates the corresponding default entry. */ + aclbufp[pos].a_type = 0; + } + switch (aclbufp[i].a_type) + { + case USER_OBJ: + case DEF_USER_OBJ: + allow |= STANDARD_RIGHTS_ALL & ~DELETE; + if (!add_access_allowed_ace (acl, ace_off++, allow, + owner_sid, acl_len, inheritance)) + return -1; + break; + case USER: + case DEF_USER: + if (!(pw = getpwuid (aclbufp[i].a_id)) + || !get_pw_sid (sid, pw) + || !add_access_allowed_ace (acl, ace_off++, allow, + sid, acl_len, inheritance)) + return -1; + break; + case GROUP_OBJ: + case DEF_GROUP_OBJ: + if (!add_access_allowed_ace (acl, ace_off++, allow, + group_sid, acl_len, inheritance)) + return -1; + break; + case GROUP: + case DEF_GROUP: + if (!(gr = getgrgid (aclbufp[i].a_id)) + || !get_gr_sid (sid, gr) + || !add_access_allowed_ace (acl, ace_off++, allow, + sid, acl_len, inheritance)) + return -1; + break; + case OTHER_OBJ: + case DEF_OTHER_OBJ: + if (!add_access_allowed_ace (acl, ace_off++, allow, + get_world_sid(), acl_len, inheritance)) + return -1; + break; + } + } + /* 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 -1; + } + /* Make self relative security descriptor in psd. */ + sd_size = 0; + MakeSelfRelativeSD (&sd, psd, &sd_size); + if (sd_size <= 0) + { + __seterrno (); + return -1; + } + if (!MakeSelfRelativeSD (&sd, psd, &sd_size)) + { + __seterrno (); + return -1; + } + debug_printf ("Created SD-Size: %d", sd_size); + return write_sd (file, psd, sd_size); +} + +static void +getace (aclent_t &acl, int type, int id, DWORD win_ace_mask, DWORD win_ace_type) +{ + acl.a_type = type; + acl.a_id = id; + + if (win_ace_mask & FILE_READ_DATA) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IRGRP) ? 0 : S_IRUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IRGRP; + + if (win_ace_mask & FILE_WRITE_DATA) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IWGRP) ? 0 : S_IWUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IWGRP; + + if (win_ace_mask & FILE_EXECUTE) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IXGRP) ? 0 : S_IXUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IXGRP; +} + +static int +getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp) +{ + DWORD sd_size = 4096; + char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + + int ret; + if ((ret = read_sd (file, psd, &sd_size)) <= 0) + { + debug_printf ("read_sd %E"); + return ret; + } + + PSID owner_sid; + PSID group_sid; + BOOL dummy; + uid_t uid; + gid_t gid; + + if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) + { + debug_printf ("GetSecurityDescriptorOwner %E"); + __seterrno (); + return -1; + } + uid = get_uid_from_sid (owner_sid); + + if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) + { + debug_printf ("GetSecurityDescriptorGroup %E"); + __seterrno (); + return -1; + } + gid = get_gid_from_sid (group_sid); + + aclent_t lacl[MAX_ACL_ENTRIES]; + memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t)); + lacl[0].a_type = USER_OBJ; + lacl[0].a_id = uid; + lacl[1].a_type = GROUP_OBJ; + lacl[1].a_id = gid; + lacl[2].a_type = OTHER_OBJ; + + PACL acl; + BOOL acl_exists; + + if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) + { + __seterrno (); + debug_printf ("GetSecurityDescriptorDacl %E"); + return -1; + } + + int pos, i; + + if (!acl_exists || !acl) + { + for (pos = 0; pos < MIN_ACL_ENTRIES; ++pos) + lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO; + pos = nentries < MIN_ACL_ENTRIES ? nentries : MIN_ACL_ENTRIES; + memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); + return pos; + } + + for (i = 0; i < acl->AceCount && (!nentries || i < nentries); ++i) + { + ACCESS_ALLOWED_ACE *ace; + + if (!GetAce (acl, i, (PVOID *) &ace)) + continue; + + PSID ace_sid = (PSID) &ace->SidStart; + int id; + int type = 0; + + if (EqualSid (ace_sid, owner_sid)) + { + type = USER_OBJ; + id = uid; + } + else if (EqualSid (ace_sid, group_sid)) + { + type = GROUP_OBJ; + id = gid; + } + else if (EqualSid (ace_sid, get_world_sid ())) + { + type = OTHER_OBJ; + id = 0; + } + else + { + id = get_id_from_sid (ace_sid, FALSE, &type); + if (type != GROUP) + { + int type2 = 0; + int id2 = get_id_from_sid (ace_sid, TRUE, &type2); + if (type2 == GROUP) + { + id = id2; + type = GROUP; + } + } + } + if (!type) + continue; + if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE)) + { + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) + getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); + } + if ((ace->Header.AceFlags & INHERIT_ALL) + && (attr & FILE_ATTRIBUTE_DIRECTORY)) + { + type |= ACL_DEFAULT; + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) + getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); + } + } + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) + pos = MAX_ACL_ENTRIES; + for (i = 0; i < pos; ++i) + { + lacl[i].a_perm = (lacl[i].a_perm & S_IRWXU) + & ~((lacl[i].a_perm & S_IRWXG) << 3); + lacl[i].a_perm |= (lacl[i].a_perm & S_IRWXU) >> 3 + | (lacl[i].a_perm & S_IRWXU) >> 6; + } + if ((searchace (lacl, MAX_ACL_ENTRIES, USER) >= 0 + || searchace (lacl, MAX_ACL_ENTRIES, GROUP) >= 0) + && (pos = searchace (lacl, MAX_ACL_ENTRIES, CLASS_OBJ)) >= 0) + { + lacl[pos].a_type = CLASS_OBJ; + lacl[pos].a_perm = + lacl[searchace (lacl, MAX_ACL_ENTRIES, GROUP_OBJ)].a_perm; + } + int dgpos; + if ((searchace (lacl, MAX_ACL_ENTRIES, DEF_USER) >= 0 + || searchace (lacl, MAX_ACL_ENTRIES, DEF_GROUP) >= 0) + && (dgpos = searchace (lacl, MAX_ACL_ENTRIES, DEF_GROUP_OBJ)) >= 0 + && (pos = searchace (lacl, MAX_ACL_ENTRIES, DEF_CLASS_OBJ)) >= 0 + && (attr & FILE_ATTRIBUTE_DIRECTORY)) + { + lacl[pos].a_type = DEF_CLASS_OBJ; + lacl[pos].a_perm = lacl[dgpos].a_perm; + } + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) + pos = MAX_ACL_ENTRIES; + if (pos > nentries) + pos = nentries; + if (aclbufp) + memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); + aclsort (pos, 0, aclbufp); + syscall_printf ("%d = getacl (%s)", pos, file); + return pos; +} + +int +acl_access (const char *path, int flags) +{ + aclent_t acls[MAX_ACL_ENTRIES]; + int cnt; + + if ((cnt = acl (path, GETACL, MAX_ACL_ENTRIES, acls)) < 1) + return -1; + + /* Only check existance. */ + if (!(flags & (R_OK|W_OK|X_OK))) + return 0; + + for (int i = 0; i < cnt; ++i) + { + switch (acls[i].a_type) + { + case USER_OBJ: + case USER: + if (acls[i].a_id != myself->uid) + { + /* + * Check if user is a NT group: + * Take SID from passwd, search SID in group, check is_grp_member. + */ + char owner_sidbuf[MAX_SID_LEN]; + PSID owner_sid = (PSID) owner_sidbuf; + char group_sidbuf[MAX_SID_LEN]; + PSID group_sid = (PSID) group_sidbuf; + struct passwd *pw; + struct group *gr = NULL; + + if ((pw = getpwuid (acls[i].a_id)) != NULL + && get_pw_sid (owner_sid, pw)) + { + while ((gr = getgrent ())) + if (get_gr_sid (group_sid, gr) + && EqualSid (owner_sid, group_sid) + && is_grp_member (myself->uid, gr->gr_gid)) + break; + endgrent (); + } + if (!gr) + continue; + } + break; + case GROUP_OBJ: + case GROUP: + if (acls[i].a_id != myself->gid && + !is_grp_member (myself->uid, acls[i].a_id)) + continue; + break; + case OTHER_OBJ: + break; + default: + continue; + } + if ((!(flags & R_OK) || (acls[i].a_perm & S_IREAD)) + && (!(flags & W_OK) || (acls[i].a_perm & S_IWRITE)) + && (!(flags & X_OK) || (acls[i].a_perm & S_IEXEC))) + return 0; + } + set_errno (EACCES); + return -1; +} + +static +int +acl_worker (const char *path, int cmd, int nentries, aclent_t *aclbufp, + int nofollow) +{ + extern suffix_info stat_suffixes[]; + path_conv real_path (path, (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) | PC_FULL, stat_suffixes); + if (real_path.error) + { + set_errno (real_path.error); + syscall_printf ("-1 = acl (%s)", path); + return -1; + } + if (!real_path.has_acls ()) + { + struct stat st; + int ret = -1; + + switch (cmd) + { + case SETACL: + set_errno (ENOSYS); + break; + case GETACL: + if (nentries < 1) + set_errno (EINVAL); + else if ((nofollow && !lstat (path, &st)) + || (!nofollow && !stat (path, &st))) + { + aclent_t lacl[4]; + if (nentries > 0) + { + lacl[0].a_type = USER_OBJ; + lacl[0].a_id = st.st_uid; + lacl[0].a_perm = (st.st_mode & S_IRWXU) + | (st.st_mode & S_IRWXU) >> 3 + | (st.st_mode & S_IRWXU) >> 6; + } + if (nentries > 1) + { + lacl[1].a_type = GROUP_OBJ; + lacl[1].a_id = st.st_gid; + lacl[1].a_perm = (st.st_mode & S_IRWXG) + | (st.st_mode & S_IRWXG) << 3 + | (st.st_mode & S_IRWXG) >> 3; + } + if (nentries > 2) + { + lacl[2].a_type = OTHER_OBJ; + lacl[2].a_id = 0; + lacl[2].a_perm = (st.st_mode & S_IRWXO) + | (st.st_mode & S_IRWXO) << 6 + | (st.st_mode & S_IRWXO) << 3; + } + if (nentries > 3) + { + lacl[3].a_type = CLASS_OBJ; + lacl[3].a_id = 0; + lacl[3].a_perm = (st.st_mode & S_IRWXG) + | (st.st_mode & S_IRWXG) << 3 + | (st.st_mode & S_IRWXG) >> 3; + } + if (nentries > 4) + nentries = 4; + if (aclbufp) + memcpy (aclbufp, lacl, nentries * sizeof (aclent_t)); + ret = nentries; + } + break; + case GETACLCNT: + ret = 4; + break; + } + syscall_printf ("%d = acl (%s)", ret, path); + return ret; + } + switch (cmd) + { + case SETACL: + if (!aclsort(nentries, 0, aclbufp)) + return setacl (real_path.get_win32 (), + nentries, aclbufp); + break; + case GETACL: + if (nentries < 1) + break; + return getacl (real_path.get_win32 (), + real_path.file_attributes (), + nentries, aclbufp); + case GETACLCNT: + return getacl (real_path.get_win32 (), + real_path.file_attributes (), + 0, NULL); + default: + break; + } + set_errno (EINVAL); + syscall_printf ("-1 = acl (%s)", path); + return -1; +} + +extern "C" +int +acl (const char *path, int cmd, int nentries, aclent_t *aclbufp) +{ + return acl_worker (path, cmd, nentries, aclbufp, 0); +} + +extern "C" +int +lacl (const char *path, int cmd, int nentries, aclent_t *aclbufp) +{ + return acl_worker (path, cmd, nentries, aclbufp, 1); +} + +extern "C" +int +facl (int fd, int cmd, int nentries, aclent_t *aclbufp) +{ + if (cygheap->fdtab.not_open (fd)) + { + syscall_printf ("-1 = facl (%d)", fd); + set_errno (EBADF); + return -1; + } + const char *path = cygheap->fdtab[fd]->get_name (); + if (path == NULL) + { + syscall_printf ("-1 = facl (%d) (no name)", fd); + set_errno (ENOSYS); + return -1; + } + syscall_printf ("facl (%d): calling acl (%s)", fd, path); + return acl_worker (path, cmd, nentries, aclbufp, 0); +} + +extern "C" +int +aclcheck (aclent_t *aclbufp, int nentries, int *which) +{ + BOOL has_user_obj = FALSE; + BOOL has_group_obj = FALSE; + BOOL has_other_obj = FALSE; + BOOL has_class_obj = FALSE; + BOOL has_ug_objs = FALSE; + BOOL has_def_user_obj = FALSE; + BOOL has_def_group_obj = FALSE; + BOOL has_def_other_obj = FALSE; + BOOL has_def_class_obj = FALSE; + BOOL has_def_ug_objs = FALSE; + int pos2; + + for (int pos = 0; pos < nentries; ++pos) + switch (aclbufp[pos].a_type) + { + case USER_OBJ: + if (has_user_obj) + { + if (which) + *which = pos; + return USER_ERROR; + } + has_user_obj = TRUE; + break; + case GROUP_OBJ: + if (has_group_obj) + { + if (which) + *which = pos; + return GRP_ERROR; + } + has_group_obj = TRUE; + break; + case OTHER_OBJ: + if (has_other_obj) + { + if (which) + *which = pos; + return OTHER_ERROR; + } + has_other_obj = TRUE; + break; + case CLASS_OBJ: + if (has_class_obj) + { + if (which) + *which = pos; + return CLASS_ERROR; + } + has_class_obj = TRUE; + break; + case USER: + case GROUP: + if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1, + aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0) + { + if (which) + *which = pos2; + return DUPLICATE_ERROR; + } + has_ug_objs = TRUE; + break; + case DEF_USER_OBJ: + if (has_def_user_obj) + { + if (which) + *which = pos; + return USER_ERROR; + } + has_def_user_obj = TRUE; + break; + case DEF_GROUP_OBJ: + if (has_def_group_obj) + { + if (which) + *which = pos; + return GRP_ERROR; + } + has_def_group_obj = TRUE; + break; + case DEF_OTHER_OBJ: + if (has_def_other_obj) + { + if (which) + *which = pos; + return OTHER_ERROR; + } + has_def_other_obj = TRUE; + break; + case DEF_CLASS_OBJ: + if (has_def_class_obj) + { + if (which) + *which = pos; + return CLASS_ERROR; + } + has_def_class_obj = TRUE; + break; + case DEF_USER: + case DEF_GROUP: + if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1, + aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0) + { + if (which) + *which = pos2; + return DUPLICATE_ERROR; + } + has_def_ug_objs = TRUE; + break; + default: + return ENTRY_ERROR; + } + if (!has_user_obj + || !has_group_obj + || !has_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) + *which = -1; + return MISS_ERROR; + } + return 0; +} + +extern "C" +int acecmp (const void *a1, const void *a2) +{ +#define ace(i) ((const aclent_t *) a##i) + int ret = ace(1)->a_type - ace(2)->a_type; + if (!ret) + ret = ace(1)->a_id - ace(2)->a_id; + return ret; +#undef ace +} + +extern "C" +int +aclsort (int nentries, int, aclent_t *aclbufp) +{ + if (aclcheck (aclbufp, nentries, NULL)) + return -1; + if (!aclbufp || nentries < 1) + { + set_errno (EINVAL); + return -1; + } + qsort((void *) aclbufp, nentries, sizeof (aclent_t), acecmp); + return 0; +} + +extern "C" +int +acltomode (aclent_t *aclbufp, int nentries, mode_t *modep) +{ + int pos; + + if (!aclbufp || nentries < 1 || !modep) + { + set_errno (EINVAL); + return -1; + } + *modep = 0; + if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + *modep |= aclbufp[pos].a_perm & S_IRWXU; + if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + if (searchace (aclbufp, nentries, CLASS_OBJ) < 0) + pos = searchace (aclbufp, nentries, CLASS_OBJ); + *modep |= (aclbufp[pos].a_perm & S_IRWXU) >> 3; + if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + *modep |= (aclbufp[pos].a_perm & S_IRWXU) >> 6; + return 0; +} + +extern "C" +int +aclfrommode(aclent_t *aclbufp, int nentries, mode_t *modep) +{ + int pos; + + if (!aclbufp || nentries < 1 || !modep) + { + set_errno (EINVAL); + return -1; + } + if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + aclbufp[pos].a_perm = (*modep & S_IRWXU) + | (*modep & S_IRWXU) >> 3 + | (*modep & S_IRWXU) >> 6; + if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + if (searchace (aclbufp, nentries, CLASS_OBJ) < 0) + pos = searchace (aclbufp, nentries, CLASS_OBJ); + aclbufp[pos].a_perm = (*modep & S_IRWXG) + | (*modep & S_IRWXG) << 3 + | (*modep & S_IRWXG) >> 3; + if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + aclbufp[pos].a_perm = (*modep & S_IRWXO) + | (*modep & S_IRWXO) << 6 + | (*modep & S_IRWXO) << 3; + return 0; +} + +extern "C" +int +acltopbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp) +{ + return acltomode (aclbufp, nentries, pbitsp); +} + +extern "C" +int +aclfrompbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp) +{ + return aclfrommode (aclbufp, nentries, pbitsp); +} + +static char * +permtostr (mode_t perm) +{ + static char pbuf[4]; + + pbuf[0] = (perm & S_IREAD) ? 'r' : '-'; + pbuf[1] = (perm & S_IWRITE) ? 'w' : '-'; + pbuf[2] = (perm & S_IEXEC) ? 'x' : '-'; + pbuf[3] = '\0'; + return pbuf; +} + +extern "C" +char * +acltotext (aclent_t *aclbufp, int aclcnt) +{ + if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES + || aclcheck (aclbufp, aclcnt, NULL)) + { + set_errno (EINVAL); + return NULL; + } + char buf[32000]; + buf[0] = '\0'; + BOOL first = TRUE; + + for (int pos = 0; pos < aclcnt; ++pos) + { + if (!first) + strcat (buf, ","); + first = FALSE; + if (aclbufp[pos].a_type & ACL_DEFAULT) + strcat (buf, "default"); + switch (aclbufp[pos].a_type) + { + case USER_OBJ: + __small_sprintf (buf + strlen (buf), "user::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case USER: + __small_sprintf (buf + strlen (buf), "user:%d:%s", + aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); + break; + case GROUP_OBJ: + __small_sprintf (buf + strlen (buf), "group::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case GROUP: + __small_sprintf (buf + strlen (buf), "group:%d:%s", + aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); + break; + case CLASS_OBJ: + __small_sprintf (buf + strlen (buf), "mask::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case OTHER_OBJ: + __small_sprintf (buf + strlen (buf), "other::%s", + permtostr (aclbufp[pos].a_perm)); + break; + default: + set_errno (EINVAL); + return NULL; + } + } + return strdup (buf); +} + +static mode_t +permfromstr (char *perm) +{ + mode_t mode = 0; + + if (strlen (perm) != 3) + return 01000; + if (perm[0] == 'r') + mode |= S_IRUSR | S_IRGRP | S_IROTH; + else if (perm[0] != '-') + return 01000; + if (perm[1] == 'w') + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + else if (perm[1] != '-') + return 01000; + if (perm[2] == 'x') + mode |= S_IXUSR | S_IXGRP | S_IXOTH; + else if (perm[2] != '-') + return 01000; + return mode; +} + +extern "C" +aclent_t * +aclfromtext (char *acltextp, int *) +{ + if (!acltextp) + { + set_errno (EINVAL); + return NULL; + } + char buf[strlen (acltextp) + 1]; + aclent_t lacl[MAX_ACL_ENTRIES]; + memset (lacl, 0, sizeof lacl); + int pos = 0; + strcpy (buf, acltextp); + char *lasts; + for (char *c = strtok_r (buf, ",", &lasts); + c; + c = strtok_r (NULL, ",", &lasts)) + { + if (!strncmp (c, "default", 7)) + { + lacl[pos].a_type |= ACL_DEFAULT; + c += 7; + } + if (!strncmp (c, "user:", 5)) + { + if (c[5] == ':') + lacl[pos].a_type |= USER_OBJ; + else + { + lacl[pos].a_type |= USER; + c += 5; + if (isalpha (*c)) + { + struct passwd *pw = getpwnam (c); + if (!pw) + { + set_errno (EINVAL); + return NULL; + } + lacl[pos].a_id = pw->pw_uid; + c = strchr (c, ':'); + } + else if (isdigit (*c)) + lacl[pos].a_id = strtol (c, &c, 10); + if (!c || *c != ':') + { + set_errno (EINVAL); + return NULL; + } + } + } + else if (!strncmp (c, "group:", 6)) + { + if (c[5] == ':') + lacl[pos].a_type |= GROUP_OBJ; + else + { + lacl[pos].a_type |= GROUP; + c += 5; + if (isalpha (*c)) + { + struct group *gr = getgrnam (c); + if (!gr) + { + set_errno (EINVAL); + return NULL; + } + lacl[pos].a_id = gr->gr_gid; + c = strchr (c, ':'); + } + else if (isdigit (*c)) + lacl[pos].a_id = strtol (c, &c, 10); + if (!c || *c != ':') + { + set_errno (EINVAL); + return NULL; + } + } + } + else if (!strncmp (c, "mask:", 5)) + { + if (c[5] == ':') + lacl[pos].a_type |= CLASS_OBJ; + else + { + set_errno (EINVAL); + return NULL; + } + } + else if (!strncmp (c, "other:", 6)) + { + if (c[5] == ':') + lacl[pos].a_type |= OTHER_OBJ; + else + { + set_errno (EINVAL); + return NULL; + } + } + if ((lacl[pos].a_perm = permfromstr (c)) == 01000) + { + set_errno (EINVAL); + return NULL; + } + ++pos; + } + aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t)); + if (aclp) + memcpy (aclp, lacl, pos * sizeof (aclent_t)); + return aclp; +} + diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc new file mode 100644 index 000000000..1771d934c --- /dev/null +++ b/winsup/cygwin/sec_helper.cc @@ -0,0 +1,399 @@ +/* sec_helper.cc: NT security helper functions + + Copyright 2000, 2001 Cygnus Solutions. + + Written by Corinna Vinschen + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cygerrno.h" +#include "perprocess.h" +#include "fhandler.h" +#include "path.h" +#include "dtable.h" +#include "sync.h" +#include "sigproc.h" +#include "pinfo.h" +#include "cygheap.h" +#include "security.h" + +SID_IDENTIFIER_AUTHORITY sid_auth[] = { + {SECURITY_NULL_SID_AUTHORITY}, + {SECURITY_WORLD_SID_AUTHORITY}, + {SECURITY_LOCAL_SID_AUTHORITY}, + {SECURITY_CREATOR_SID_AUTHORITY}, + {SECURITY_NON_UNIQUE_AUTHORITY}, + {SECURITY_NT_AUTHORITY} +}; + +char * +convert_sid_to_string_sid (PSID psid, char *sid_str) +{ + char t[32]; + DWORD i; + + if (!psid || !sid_str) + return NULL; + strcpy (sid_str, "S-1-"); + __small_sprintf(t, "%u", GetSidIdentifierAuthority (psid)->Value[5]); + strcat (sid_str, t); + for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i) + { + __small_sprintf(t, "-%lu", *GetSidSubAuthority (psid, i)); + strcat (sid_str, t); + } + return sid_str; +} + +PSID +get_sid (PSID psid, DWORD s, DWORD cnt, DWORD *r) +{ + DWORD i; + + if (!psid || s > 5 || cnt < 1 || cnt > 8) + return NULL; + + InitializeSid(psid, &sid_auth[s], cnt); + for (i = 0; i < cnt; ++i) + memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD)); + return psid; +} + +PSID +convert_string_sid_to_sid (PSID psid, const char *sid_str) +{ + char sid_buf[256]; + char *t, *lasts; + DWORD cnt = 0; + DWORD s = 0; + DWORD i, r[8]; + + if (!sid_str || strncmp (sid_str, "S-1-", 4)) + return NULL; + + strcpy (sid_buf, sid_str); + + for (t = sid_buf + 4, i = 0; + cnt < 8 && (t = strtok_r (t, "-", &lasts)); + t = NULL, ++i) + if (i == 0) + s = strtoul (t, NULL, 10); + else + r[cnt++] = strtoul (t, NULL, 10); + + return get_sid (psid, s, cnt, r); +} + +BOOL +get_pw_sid (PSID sid, struct passwd *pw) +{ + char *sp = pw->pw_gecos ? strrchr (pw->pw_gecos, ',') : NULL; + + if (!sp) + return FALSE; + return convert_string_sid_to_sid (sid, ++sp) != NULL; +} + +BOOL +get_gr_sid (PSID sid, struct group *gr) +{ + return convert_string_sid_to_sid (sid, gr->gr_passwd) != NULL; +} + +PSID +get_admin_sid () +{ + static NO_COPY char admin_sid_buf[MAX_SID_LEN]; + static NO_COPY PSID admin_sid = NULL; + + if (!admin_sid) + { + admin_sid = (PSID) admin_sid_buf; + convert_string_sid_to_sid (admin_sid, "S-1-5-32-544"); + } + return admin_sid; +} + +PSID +get_system_sid () +{ + static NO_COPY char system_sid_buf[MAX_SID_LEN]; + static NO_COPY PSID system_sid = NULL; + + if (!system_sid) + { + system_sid = (PSID) system_sid_buf; + convert_string_sid_to_sid (system_sid, "S-1-5-18"); + } + return system_sid; +} + +PSID +get_creator_owner_sid () +{ + static NO_COPY char owner_sid_buf[MAX_SID_LEN]; + static NO_COPY PSID owner_sid = NULL; + + if (!owner_sid) + { + owner_sid = (PSID) owner_sid_buf; + convert_string_sid_to_sid (owner_sid, "S-1-3-0"); + } + return owner_sid; +} + +PSID +get_world_sid () +{ + static NO_COPY char world_sid_buf[MAX_SID_LEN]; + static NO_COPY PSID world_sid = NULL; + + if (!world_sid) + { + world_sid = (PSID) world_sid_buf; + convert_string_sid_to_sid (world_sid, "S-1-1-0"); + } + return world_sid; +} + +int +get_id_from_sid (PSID psid, BOOL search_grp, int *type) +{ + if (!IsValidSid (psid)) + { + __seterrno (); + small_printf ("IsValidSid failed with %E"); + return -1; + } + + /* First try to get SID from passwd or group entry */ + if (allow_ntsec) + { + char sidbuf[MAX_SID_LEN]; + PSID sid = (PSID) sidbuf; + int id = -1; + + if (!search_grp) + { + struct passwd *pw; + while ((pw = getpwent ()) != NULL) + { + if (get_pw_sid (sid, pw) && EqualSid (psid, sid)) + { + id = pw->pw_uid; + break; + } + } + endpwent (); + if (id >= 0) + { + if (type) + *type = USER; + return id; + } + } + if (search_grp || type) + { + struct group *gr; + while ((gr = getgrent ()) != NULL) + { + if (get_gr_sid (sid, gr) && EqualSid (psid, sid)) + { + id = gr->gr_gid; + break; + } + } + endgrent (); + if (id >= 0) + { + if (type) + *type = GROUP; + return id; + } + } + } + + /* We use the RID as default UID/GID */ + int id = *GetSidSubAuthority(psid, *GetSidSubAuthorityCount(psid) - 1); + + /* + * The RID maybe -1 if accountname == computername. + * In this case we search for the accountname in the passwd and group files. + * If type is needed, we search in each case. + */ + if (id == -1 || type) + { + char account[MAX_USER_NAME]; + char domain[MAX_COMPUTERNAME_LENGTH+1]; + DWORD acc_len = MAX_USER_NAME; + DWORD dom_len = MAX_COMPUTERNAME_LENGTH+1; + SID_NAME_USE acc_type; + + if (!LookupAccountSid (NULL, psid, account, &acc_len, + domain, &dom_len, &acc_type)) + { + __seterrno (); + return -1; + } + + switch (acc_type) + { + case SidTypeGroup: + case SidTypeAlias: + case SidTypeWellKnownGroup: + if (type) + *type = GROUP; + if (id == -1) + { + struct group *gr = getgrnam (account); + if (gr) + id = gr->gr_gid; + } + break; + case SidTypeUser: + if (type) + *type = USER; + if (id == -1) + { + struct passwd *pw = getpwnam (account); + if (pw) + id = pw->pw_uid; + } + break; + default: + break; + } + } + if (id == -1) + id = getuid (); + return id; +} + +int +get_id_from_sid (PSID psid, BOOL search_grp) +{ + return get_id_from_sid (psid, search_grp, NULL); +} + +BOOL +legal_sid_type (SID_NAME_USE type) +{ + return type == SidTypeUser || type == SidTypeGroup + || SidTypeAlias || SidTypeWellKnownGroup; +} + +BOOL +is_grp_member (uid_t uid, gid_t gid) +{ + extern int getgroups (int, gid_t *, gid_t, const char *); + BOOL grp_member = TRUE; + + struct passwd *pw = getpwuid (uid); + gid_t grps[NGROUPS_MAX]; + int cnt = getgroups (NGROUPS_MAX, grps, + pw ? pw->pw_gid : myself->gid, + pw ? pw->pw_name : cygheap->user.name ()); + int i; + for (i = 0; i < cnt; ++i) + if (grps[i] == gid) + break; + grp_member = (i < cnt); + return grp_member; +} + +BOOL +lookup_name (const char *name, const char *logsrv, PSID ret_sid) +{ + char sidbuf[MAX_SID_LEN]; + PSID sid = (PSID) sidbuf; + DWORD sidlen; + char domuser[MAX_COMPUTERNAME_LENGTH+MAX_USER_NAME+1]; + char dom[MAX_COMPUTERNAME_LENGTH+1]; + DWORD domlen; + SID_NAME_USE acc_type; + + debug_printf ("name : %s", name ? name : "NULL"); + + if (!name) + return FALSE; + + if (cygheap->user.domain ()) + { + strcat (strcat (strcpy (domuser, cygheap->user.domain ()), "\\"), name); + if (LookupAccountName (NULL, domuser, + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), + &acc_type) + && legal_sid_type (acc_type)) + goto got_it; + if (logsrv && *logsrv + && LookupAccountName (logsrv, domuser, + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = MAX_COMPUTERNAME_LENGTH,&domlen), + &acc_type) + && legal_sid_type (acc_type)) + goto got_it; + } + if (logsrv && *logsrv) + { + if (LookupAccountName (logsrv, name, + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), + &acc_type) + && legal_sid_type (acc_type)) + goto got_it; + if (acc_type == SidTypeDomain) + { + strcat (strcat (strcpy (domuser, dom), "\\"), name); + if (LookupAccountName (logsrv, domuser, + sid,(sidlen = MAX_SID_LEN, &sidlen), + dom,(domlen = MAX_COMPUTERNAME_LENGTH,&domlen), + &acc_type)) + goto got_it; + } + } + if (LookupAccountName (NULL, name, + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = 100, &domlen), + &acc_type) + && legal_sid_type (acc_type)) + goto got_it; + if (acc_type == SidTypeDomain) + { + strcat (strcat (strcpy (domuser, dom), "\\"), name); + if (LookupAccountName (NULL, domuser, + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), + &acc_type)) + goto got_it; + } + debug_printf ("LookupAccountName(%s) %E", name); + __seterrno (); + return FALSE; + +got_it: + debug_printf ("sid : [%d]", *GetSidSubAuthority((PSID) sid, + *GetSidSubAuthorityCount((PSID) sid) - 1)); + + if (ret_sid) + memcpy (ret_sid, sid, sidlen); + + return TRUE; +} diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index d780103f8..38c741fa2 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -42,384 +42,6 @@ BOOL allow_ntsec = FALSE; The default is TRUE to reflect the old behaviour. */ BOOL allow_smbntsec = TRUE; -SID_IDENTIFIER_AUTHORITY sid_auth[] = { - {SECURITY_NULL_SID_AUTHORITY}, - {SECURITY_WORLD_SID_AUTHORITY}, - {SECURITY_LOCAL_SID_AUTHORITY}, - {SECURITY_CREATOR_SID_AUTHORITY}, - {SECURITY_NON_UNIQUE_AUTHORITY}, - {SECURITY_NT_AUTHORITY} -}; - -#define DONT_INHERIT (0) -#define INHERIT_ALL (CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) -#define INHERIT_ONLY (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) - -char * -convert_sid_to_string_sid (PSID psid, char *sid_str) -{ - char t[32]; - DWORD i; - - if (!psid || !sid_str) - return NULL; - strcpy (sid_str, "S-1-"); - __small_sprintf(t, "%u", GetSidIdentifierAuthority (psid)->Value[5]); - strcat (sid_str, t); - for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i) - { - __small_sprintf(t, "-%lu", *GetSidSubAuthority (psid, i)); - strcat (sid_str, t); - } - return sid_str; -} - -PSID -get_sid (PSID psid, DWORD s, DWORD cnt, DWORD *r) -{ - DWORD i; - - if (!psid || s > 5 || cnt < 1 || cnt > 8) - return NULL; - - InitializeSid(psid, &sid_auth[s], cnt); - for (i = 0; i < cnt; ++i) - memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD)); - return psid; -} - -PSID -convert_string_sid_to_sid (PSID psid, const char *sid_str) -{ - char sid_buf[256]; - char *t, *lasts; - DWORD cnt = 0; - DWORD s = 0; - DWORD i, r[8]; - - if (!sid_str || strncmp (sid_str, "S-1-", 4)) - return NULL; - - strcpy (sid_buf, sid_str); - - for (t = sid_buf + 4, i = 0; - cnt < 8 && (t = strtok_r (t, "-", &lasts)); - t = NULL, ++i) - if (i == 0) - s = strtoul (t, NULL, 10); - else - r[cnt++] = strtoul (t, NULL, 10); - - return get_sid (psid, s, cnt, r); -} - -BOOL -get_pw_sid (PSID sid, struct passwd *pw) -{ - char *sp = pw->pw_gecos ? strrchr (pw->pw_gecos, ',') : NULL; - - if (!sp) - return FALSE; - return convert_string_sid_to_sid (sid, ++sp) != NULL; -} - -BOOL -get_gr_sid (PSID sid, struct group *gr) -{ - return convert_string_sid_to_sid (sid, gr->gr_passwd) != NULL; -} - -PSID -get_admin_sid () -{ - static NO_COPY char admin_sid_buf[MAX_SID_LEN]; - static NO_COPY PSID admin_sid = NULL; - - if (!admin_sid) - { - admin_sid = (PSID) admin_sid_buf; - convert_string_sid_to_sid (admin_sid, "S-1-5-32-544"); - } - return admin_sid; -} - -PSID -get_system_sid () -{ - static NO_COPY char system_sid_buf[MAX_SID_LEN]; - static NO_COPY PSID system_sid = NULL; - - if (!system_sid) - { - system_sid = (PSID) system_sid_buf; - convert_string_sid_to_sid (system_sid, "S-1-5-18"); - } - return system_sid; -} - -PSID -get_creator_owner_sid () -{ - static NO_COPY char owner_sid_buf[MAX_SID_LEN]; - static NO_COPY PSID owner_sid = NULL; - - if (!owner_sid) - { - owner_sid = (PSID) owner_sid_buf; - convert_string_sid_to_sid (owner_sid, "S-1-3-0"); - } - return owner_sid; -} - -PSID -get_world_sid () -{ - static NO_COPY char world_sid_buf[MAX_SID_LEN]; - static NO_COPY PSID world_sid = NULL; - - if (!world_sid) - { - world_sid = (PSID) world_sid_buf; - convert_string_sid_to_sid (world_sid, "S-1-1-0"); - } - return world_sid; -} - -int group_sem = 0; - -static int -get_id_from_sid (PSID psid, BOOL search_grp, int *type) -{ - if (!IsValidSid (psid)) - { - __seterrno (); - small_printf ("IsValidSid failed with %E"); - return -1; - } - - /* First try to get SID from passwd or group entry */ - if (allow_ntsec) - { - char sidbuf[MAX_SID_LEN]; - PSID sid = (PSID) sidbuf; - int id = -1; - - if (!search_grp) - { - struct passwd *pw; - while ((pw = getpwent ()) != NULL) - { - if (get_pw_sid (sid, pw) && EqualSid (psid, sid)) - { - id = pw->pw_uid; - break; - } - } - endpwent (); - if (id >= 0) - { - if (type) - *type = USER; - return id; - } - } - if (search_grp || type) - { - if (group_sem > 0) - return 0; - ++group_sem; - - struct group *gr; - while ((gr = getgrent ()) != NULL) - { - if (get_gr_sid (sid, gr) && EqualSid (psid, sid)) - { - id = gr->gr_gid; - break; - } - } - endgrent (); - --group_sem; - if (id >= 0) - { - if (type) - *type = GROUP; - return id; - } - } - } - - /* We use the RID as default UID/GID */ - int id = *GetSidSubAuthority(psid, *GetSidSubAuthorityCount(psid) - 1); - - /* - * The RID maybe -1 if accountname == computername. - * In this case we search for the accountname in the passwd and group files. - * If type is needed, we search in each case. - */ - if (id == -1 || type) - { - char account[MAX_USER_NAME]; - char domain[MAX_COMPUTERNAME_LENGTH+1]; - DWORD acc_len = MAX_USER_NAME; - DWORD dom_len = MAX_COMPUTERNAME_LENGTH+1; - SID_NAME_USE acc_type; - - if (!LookupAccountSid (NULL, psid, account, &acc_len, - domain, &dom_len, &acc_type)) - { - __seterrno (); - return -1; - } - - switch (acc_type) - { - case SidTypeGroup: - case SidTypeAlias: - case SidTypeWellKnownGroup: - if (type) - *type = GROUP; - if (id == -1) - { - struct group *gr = getgrnam (account); - if (gr) - id = gr->gr_gid; - } - break; - case SidTypeUser: - if (type) - *type = USER; - if (id == -1) - { - struct passwd *pw = getpwnam (account); - if (pw) - id = pw->pw_uid; - } - break; - default: - break; - } - } - if (id == -1) - id = getuid (); - return id; -} - -int -get_id_from_sid (PSID psid, BOOL search_grp) -{ - return get_id_from_sid (psid, search_grp, NULL); -} - -static BOOL -legal_sid_type (SID_NAME_USE type) -{ - return type == SidTypeUser || type == SidTypeGroup - || SidTypeAlias || SidTypeWellKnownGroup; -} - -BOOL -is_grp_member (uid_t uid, gid_t gid) -{ - extern int getgroups (int, gid_t *, gid_t, const char *); - BOOL grp_member = TRUE; - - if (!group_sem) - { - struct passwd *pw = getpwuid (uid); - gid_t grps[NGROUPS_MAX]; - int cnt = getgroups (NGROUPS_MAX, grps, - pw ? pw->pw_gid : myself->gid, - pw ? pw->pw_name : cygheap->user.name ()); - int i; - for (i = 0; i < cnt; ++i) - if (grps[i] == gid) - break; - grp_member = (i < cnt); - } - return grp_member; -} - -BOOL -lookup_name (const char *name, const char *logsrv, PSID ret_sid) -{ - char sidbuf[MAX_SID_LEN]; - PSID sid = (PSID) sidbuf; - DWORD sidlen; - char domuser[MAX_COMPUTERNAME_LENGTH+MAX_USER_NAME+1]; - char dom[MAX_COMPUTERNAME_LENGTH+1]; - DWORD domlen; - SID_NAME_USE acc_type; - - debug_printf ("name : %s", name ? name : "NULL"); - - if (!name) - return FALSE; - - if (cygheap->user.domain ()) - { - strcat (strcat (strcpy (domuser, cygheap->user.domain ()), "\\"), name); - if (LookupAccountName (NULL, domuser, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), - &acc_type) - && legal_sid_type (acc_type)) - goto got_it; - if (logsrv && *logsrv - && LookupAccountName (logsrv, domuser, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = MAX_COMPUTERNAME_LENGTH,&domlen), - &acc_type) - && legal_sid_type (acc_type)) - goto got_it; - } - if (logsrv && *logsrv) - { - if (LookupAccountName (logsrv, name, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), - &acc_type) - && legal_sid_type (acc_type)) - goto got_it; - if (acc_type == SidTypeDomain) - { - strcat (strcat (strcpy (domuser, dom), "\\"), name); - if (LookupAccountName (logsrv, domuser, - sid,(sidlen = MAX_SID_LEN, &sidlen), - dom,(domlen = MAX_COMPUTERNAME_LENGTH,&domlen), - &acc_type)) - goto got_it; - } - } - if (LookupAccountName (NULL, name, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = 100, &domlen), - &acc_type) - && legal_sid_type (acc_type)) - goto got_it; - if (acc_type == SidTypeDomain) - { - strcat (strcat (strcpy (domuser, dom), "\\"), name); - if (LookupAccountName (NULL, domuser, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), - &acc_type)) - goto got_it; - } - debug_printf ("LookupAccountName(%s) %E", name); - __seterrno (); - return FALSE; - -got_it: - debug_printf ("sid : [%d]", *GetSidSubAuthority((PSID) sid, - *GetSidSubAuthorityCount((PSID) sid) - 1)); - - if (ret_sid) - memcpy (ret_sid, sid, sidlen); - - return TRUE; -} - extern "C" void cygwin_set_impersonation_token (const HANDLE hToken) @@ -836,8 +458,9 @@ get_file_attribute (int use_ntsec, const char *file, return res > 0 ? 0 : -1; } -BOOL add_access_allowed_ace (PACL acl, int offset, DWORD attributes, - PSID sid, size_t &len_add, DWORD inherit) +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)) { @@ -852,8 +475,9 @@ BOOL add_access_allowed_ace (PACL acl, int offset, DWORD attributes, return TRUE; } -BOOL add_access_denied_ace (PACL acl, int offset, DWORD attributes, - PSID sid, size_t &len_add, DWORD inherit) +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)) { @@ -1177,1032 +801,3 @@ set_file_attribute (int use_ntsec, const char *file, int attribute) myself->uid, myself->gid, attribute, cygheap->user.logsrv ()); } - -static int -searchace (aclent_t *aclp, int nentries, int type, int id = -1) -{ - int i; - - for (i = 0; i < nentries; ++i) - if ((aclp[i].a_type == type && (id < 0 || aclp[i].a_id == id)) - || !aclp[i].a_type) - return i; - return -1; -} - -static int -setacl (const char *file, int nentries, aclent_t *aclbufp) -{ - DWORD sd_size = 4096; - char sd_buf[4096]; - PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; - - if (read_sd (file, psd, &sd_size) <= 0) - { - debug_printf ("read_sd %E"); - return -1; - } - - BOOL dummy; - - /* Get owner SID. */ - PSID owner_sid = NULL; - if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) - { - __seterrno (); - return -1; - } - char owner_buf[MAX_SID_LEN]; - if (!CopySid (MAX_SID_LEN, (PSID) owner_buf, owner_sid)) - { - __seterrno (); - return -1; - } - owner_sid = (PSID) owner_buf; - - /* Get group SID. */ - PSID group_sid = NULL; - if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) - { - __seterrno (); - return -1; - } - char group_buf[MAX_SID_LEN]; - if (!CopySid (MAX_SID_LEN, (PSID) group_buf, group_sid)) - { - __seterrno (); - return -1; - } - group_sid = (PSID) group_buf; - - /* Initialize local security descriptor. */ - SECURITY_DESCRIPTOR sd; - if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) - { - __seterrno (); - return -1; - } - if (!SetSecurityDescriptorOwner(&sd, owner_sid, FALSE)) - { - __seterrno (); - return -1; - } - if (group_sid - && !SetSecurityDescriptorGroup(&sd, group_sid, FALSE)) - { - __seterrno (); - return -1; - } - - /* Fill access control list. */ - char acl_buf[3072]; - PACL acl = (PACL) acl_buf; - size_t acl_len = sizeof (ACL); - int ace_off = 0; - - char sidbuf[MAX_SID_LEN]; - PSID sid = (PSID) sidbuf; - struct passwd *pw; - struct group *gr; - int pos; - - if (!InitializeAcl (acl, 3072, ACL_REVISION)) - { - __seterrno (); - return -1; - } - for (int i = 0; i < nentries; ++i) - { - DWORD allow = STANDARD_RIGHTS_READ - | FILE_READ_ATTRIBUTES | FILE_READ_EA; - if (aclbufp[i].a_perm & S_IROTH) - allow |= FILE_GENERIC_READ; - if (aclbufp[i].a_perm & S_IWOTH) - allow |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE - | DELETE | FILE_DELETE_CHILD; - if (aclbufp[i].a_perm & S_IXOTH) - allow |= FILE_GENERIC_EXECUTE; - /* Set inherit property. */ - DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT) - ? INHERIT_ONLY : DONT_INHERIT; - /* - * If a specific acl contains a corresponding default entry with - * identical permissions, only one Windows ACE with proper - * inheritance bits is created. - */ - if (!(aclbufp[i].a_type & ACL_DEFAULT) - && (pos = searchace (aclbufp, nentries, - aclbufp[i].a_type | ACL_DEFAULT, - (aclbufp[i].a_type & (USER|GROUP)) - ? aclbufp[i].a_id : -1)) >= 0 - && pos < nentries - && aclbufp[i].a_perm == aclbufp[pos].a_perm) - { - inheritance = INHERIT_ALL; - /* This eliminates the corresponding default entry. */ - aclbufp[pos].a_type = 0; - } - switch (aclbufp[i].a_type) - { - case USER_OBJ: - case DEF_USER_OBJ: - allow |= STANDARD_RIGHTS_ALL & ~DELETE; - if (!add_access_allowed_ace (acl, ace_off++, allow, - owner_sid, acl_len, inheritance)) - return -1; - break; - case USER: - case DEF_USER: - if (!(pw = getpwuid (aclbufp[i].a_id)) - || !get_pw_sid (sid, pw) - || !add_access_allowed_ace (acl, ace_off++, allow, - sid, acl_len, inheritance)) - return -1; - break; - case GROUP_OBJ: - case DEF_GROUP_OBJ: - if (!add_access_allowed_ace (acl, ace_off++, allow, - group_sid, acl_len, inheritance)) - return -1; - break; - case GROUP: - case DEF_GROUP: - if (!(gr = getgrgid (aclbufp[i].a_id)) - || !get_gr_sid (sid, gr) - || !add_access_allowed_ace (acl, ace_off++, allow, - sid, acl_len, inheritance)) - return -1; - break; - case OTHER_OBJ: - case DEF_OTHER_OBJ: - if (!add_access_allowed_ace (acl, ace_off++, allow, - get_world_sid(), acl_len, inheritance)) - return -1; - break; - } - } - /* 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 -1; - } - /* Make self relative security descriptor in psd. */ - sd_size = 0; - MakeSelfRelativeSD (&sd, psd, &sd_size); - if (sd_size <= 0) - { - __seterrno (); - return -1; - } - if (!MakeSelfRelativeSD (&sd, psd, &sd_size)) - { - __seterrno (); - return -1; - } - debug_printf ("Created SD-Size: %d", sd_size); - return write_sd (file, psd, sd_size); -} - -static void -getace (aclent_t &acl, int type, int id, DWORD win_ace_mask, DWORD win_ace_type) -{ - acl.a_type = type; - acl.a_id = id; - - if (win_ace_mask & FILE_READ_DATA) - if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) - acl.a_perm |= (acl.a_perm & S_IRGRP) ? 0 : S_IRUSR; - else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) - acl.a_perm &= ~S_IRGRP; - - if (win_ace_mask & FILE_WRITE_DATA) - if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) - acl.a_perm |= (acl.a_perm & S_IWGRP) ? 0 : S_IWUSR; - else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) - acl.a_perm &= ~S_IWGRP; - - if (win_ace_mask & FILE_EXECUTE) - if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) - acl.a_perm |= (acl.a_perm & S_IXGRP) ? 0 : S_IXUSR; - else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) - acl.a_perm &= ~S_IXGRP; -} - -static int -getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp) -{ - DWORD sd_size = 4096; - char sd_buf[4096]; - PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; - - int ret; - if ((ret = read_sd (file, psd, &sd_size)) <= 0) - { - debug_printf ("read_sd %E"); - return ret; - } - - PSID owner_sid; - PSID group_sid; - BOOL dummy; - uid_t uid; - gid_t gid; - - if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) - { - debug_printf ("GetSecurityDescriptorOwner %E"); - __seterrno (); - return -1; - } - uid = get_uid_from_sid (owner_sid); - - if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) - { - debug_printf ("GetSecurityDescriptorGroup %E"); - __seterrno (); - return -1; - } - gid = get_gid_from_sid (group_sid); - - aclent_t lacl[MAX_ACL_ENTRIES]; - memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t)); - lacl[0].a_type = USER_OBJ; - lacl[0].a_id = uid; - lacl[1].a_type = GROUP_OBJ; - lacl[1].a_id = gid; - lacl[2].a_type = OTHER_OBJ; - - PACL acl; - BOOL acl_exists; - - if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) - { - __seterrno (); - debug_printf ("GetSecurityDescriptorDacl %E"); - return -1; - } - - int pos, i; - - if (!acl_exists || !acl) - { - for (pos = 0; pos < MIN_ACL_ENTRIES; ++pos) - lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO; - pos = nentries < MIN_ACL_ENTRIES ? nentries : MIN_ACL_ENTRIES; - memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); - return pos; - } - - for (i = 0; i < acl->AceCount && (!nentries || i < nentries); ++i) - { - ACCESS_ALLOWED_ACE *ace; - - if (!GetAce (acl, i, (PVOID *) &ace)) - continue; - - PSID ace_sid = (PSID) &ace->SidStart; - int id; - int type = 0; - - if (EqualSid (ace_sid, owner_sid)) - { - type = USER_OBJ; - id = uid; - } - else if (EqualSid (ace_sid, group_sid)) - { - type = GROUP_OBJ; - id = gid; - } - else if (EqualSid (ace_sid, get_world_sid ())) - { - type = OTHER_OBJ; - id = 0; - } - else - { - id = get_id_from_sid (ace_sid, FALSE, &type); - if (type != GROUP) - { - int type2 = 0; - int id2 = get_id_from_sid (ace_sid, TRUE, &type2); - if (type2 == GROUP) - { - id = id2; - type = GROUP; - } - } - } - if (!type) - continue; - if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE)) - { - if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) - getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); - } - if ((ace->Header.AceFlags & INHERIT_ALL) - && (attr & FILE_ATTRIBUTE_DIRECTORY)) - { - type |= ACL_DEFAULT; - if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) - getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); - } - } - if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) - pos = MAX_ACL_ENTRIES; - for (i = 0; i < pos; ++i) - { - lacl[i].a_perm = (lacl[i].a_perm & S_IRWXU) - & ~((lacl[i].a_perm & S_IRWXG) << 3); - lacl[i].a_perm |= (lacl[i].a_perm & S_IRWXU) >> 3 - | (lacl[i].a_perm & S_IRWXU) >> 6; - } - if ((searchace (lacl, MAX_ACL_ENTRIES, USER) >= 0 - || searchace (lacl, MAX_ACL_ENTRIES, GROUP) >= 0) - && (pos = searchace (lacl, MAX_ACL_ENTRIES, CLASS_OBJ)) >= 0) - { - lacl[pos].a_type = CLASS_OBJ; - lacl[pos].a_perm = - lacl[searchace (lacl, MAX_ACL_ENTRIES, GROUP_OBJ)].a_perm; - } - int dgpos; - if ((searchace (lacl, MAX_ACL_ENTRIES, DEF_USER) >= 0 - || searchace (lacl, MAX_ACL_ENTRIES, DEF_GROUP) >= 0) - && (dgpos = searchace (lacl, MAX_ACL_ENTRIES, DEF_GROUP_OBJ)) >= 0 - && (pos = searchace (lacl, MAX_ACL_ENTRIES, DEF_CLASS_OBJ)) >= 0 - && (attr & FILE_ATTRIBUTE_DIRECTORY)) - { - lacl[pos].a_type = DEF_CLASS_OBJ; - lacl[pos].a_perm = lacl[dgpos].a_perm; - } - if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) - pos = MAX_ACL_ENTRIES; - if (pos > nentries) - pos = nentries; - if (aclbufp) - memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); - aclsort (pos, 0, aclbufp); - syscall_printf ("%d = getacl (%s)", pos, file); - return pos; -} - -int -acl_access (const char *path, int flags) -{ - aclent_t acls[MAX_ACL_ENTRIES]; - int cnt; - - if ((cnt = acl (path, GETACL, MAX_ACL_ENTRIES, acls)) < 1) - return -1; - - /* Only check existance. */ - if (!(flags & (R_OK|W_OK|X_OK))) - return 0; - - for (int i = 0; i < cnt; ++i) - { - switch (acls[i].a_type) - { - case USER_OBJ: - case USER: - if (acls[i].a_id != myself->uid) - { - /* - * Check if user is a NT group: - * Take SID from passwd, search SID in group, check is_grp_member. - */ - char owner_sidbuf[MAX_SID_LEN]; - PSID owner_sid = (PSID) owner_sidbuf; - char group_sidbuf[MAX_SID_LEN]; - PSID group_sid = (PSID) group_sidbuf; - struct passwd *pw; - struct group *gr = NULL; - - if (group_sem > 0) - continue; - ++group_sem; - if ((pw = getpwuid (acls[i].a_id)) != NULL - && get_pw_sid (owner_sid, pw)) - { - while ((gr = getgrent ())) - if (get_gr_sid (group_sid, gr) - && EqualSid (owner_sid, group_sid) - && is_grp_member (myself->uid, gr->gr_gid)) - break; - endgrent (); - } - --group_sem; - if (!gr) - continue; - } - break; - case GROUP_OBJ: - case GROUP: - if (acls[i].a_id != myself->gid && - !is_grp_member (myself->uid, acls[i].a_id)) - continue; - break; - case OTHER_OBJ: - break; - default: - continue; - } - if ((!(flags & R_OK) || (acls[i].a_perm & S_IREAD)) - && (!(flags & W_OK) || (acls[i].a_perm & S_IWRITE)) - && (!(flags & X_OK) || (acls[i].a_perm & S_IEXEC))) - return 0; - } - set_errno (EACCES); - return -1; -} - -static -int -acl_worker (const char *path, int cmd, int nentries, aclent_t *aclbufp, - int nofollow) -{ - extern suffix_info stat_suffixes[]; - path_conv real_path (path, (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) | PC_FULL, stat_suffixes); - if (real_path.error) - { - set_errno (real_path.error); - syscall_printf ("-1 = acl (%s)", path); - return -1; - } - if (!real_path.has_acls ()) - { - struct stat st; - int ret = -1; - - switch (cmd) - { - case SETACL: - set_errno (ENOSYS); - break; - case GETACL: - if (nentries < 1) - set_errno (EINVAL); - else if ((nofollow && !lstat (path, &st)) - || (!nofollow && !stat (path, &st))) - { - aclent_t lacl[4]; - if (nentries > 0) - { - lacl[0].a_type = USER_OBJ; - lacl[0].a_id = st.st_uid; - lacl[0].a_perm = (st.st_mode & S_IRWXU) - | (st.st_mode & S_IRWXU) >> 3 - | (st.st_mode & S_IRWXU) >> 6; - } - if (nentries > 1) - { - lacl[1].a_type = GROUP_OBJ; - lacl[1].a_id = st.st_gid; - lacl[1].a_perm = (st.st_mode & S_IRWXG) - | (st.st_mode & S_IRWXG) << 3 - | (st.st_mode & S_IRWXG) >> 3; - } - if (nentries > 2) - { - lacl[2].a_type = OTHER_OBJ; - lacl[2].a_id = 0; - lacl[2].a_perm = (st.st_mode & S_IRWXO) - | (st.st_mode & S_IRWXO) << 6 - | (st.st_mode & S_IRWXO) << 3; - } - if (nentries > 3) - { - lacl[3].a_type = CLASS_OBJ; - lacl[3].a_id = 0; - lacl[3].a_perm = (st.st_mode & S_IRWXG) - | (st.st_mode & S_IRWXG) << 3 - | (st.st_mode & S_IRWXG) >> 3; - } - if (nentries > 4) - nentries = 4; - if (aclbufp) - memcpy (aclbufp, lacl, nentries * sizeof (aclent_t)); - ret = nentries; - } - break; - case GETACLCNT: - ret = 4; - break; - } - syscall_printf ("%d = acl (%s)", ret, path); - return ret; - } - switch (cmd) - { - case SETACL: - if (!aclsort(nentries, 0, aclbufp)) - return setacl (real_path.get_win32 (), - nentries, aclbufp); - break; - case GETACL: - if (nentries < 1) - break; - return getacl (real_path.get_win32 (), - real_path.file_attributes (), - nentries, aclbufp); - case GETACLCNT: - return getacl (real_path.get_win32 (), - real_path.file_attributes (), - 0, NULL); - default: - break; - } - set_errno (EINVAL); - syscall_printf ("-1 = acl (%s)", path); - return -1; -} - -extern "C" -int -acl (const char *path, int cmd, int nentries, aclent_t *aclbufp) -{ - return acl_worker (path, cmd, nentries, aclbufp, 0); -} - -extern "C" -int -lacl (const char *path, int cmd, int nentries, aclent_t *aclbufp) -{ - return acl_worker (path, cmd, nentries, aclbufp, 1); -} - -extern "C" -int -facl (int fd, int cmd, int nentries, aclent_t *aclbufp) -{ - if (cygheap->fdtab.not_open (fd)) - { - syscall_printf ("-1 = facl (%d)", fd); - set_errno (EBADF); - return -1; - } - const char *path = cygheap->fdtab[fd]->get_name (); - if (path == NULL) - { - syscall_printf ("-1 = facl (%d) (no name)", fd); - set_errno (ENOSYS); - return -1; - } - syscall_printf ("facl (%d): calling acl (%s)", fd, path); - return acl_worker (path, cmd, nentries, aclbufp, 0); -} - -extern "C" -int -aclcheck (aclent_t *aclbufp, int nentries, int *which) -{ - BOOL has_user_obj = FALSE; - BOOL has_group_obj = FALSE; - BOOL has_other_obj = FALSE; - BOOL has_class_obj = FALSE; - BOOL has_ug_objs = FALSE; - BOOL has_def_user_obj = FALSE; - BOOL has_def_group_obj = FALSE; - BOOL has_def_other_obj = FALSE; - BOOL has_def_class_obj = FALSE; - BOOL has_def_ug_objs = FALSE; - int pos2; - - for (int pos = 0; pos < nentries; ++pos) - switch (aclbufp[pos].a_type) - { - case USER_OBJ: - if (has_user_obj) - { - if (which) - *which = pos; - return USER_ERROR; - } - has_user_obj = TRUE; - break; - case GROUP_OBJ: - if (has_group_obj) - { - if (which) - *which = pos; - return GRP_ERROR; - } - has_group_obj = TRUE; - break; - case OTHER_OBJ: - if (has_other_obj) - { - if (which) - *which = pos; - return OTHER_ERROR; - } - has_other_obj = TRUE; - break; - case CLASS_OBJ: - if (has_class_obj) - { - if (which) - *which = pos; - return CLASS_ERROR; - } - has_class_obj = TRUE; - break; - case USER: - case GROUP: - if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1, - aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0) - { - if (which) - *which = pos2; - return DUPLICATE_ERROR; - } - has_ug_objs = TRUE; - break; - case DEF_USER_OBJ: - if (has_def_user_obj) - { - if (which) - *which = pos; - return USER_ERROR; - } - has_def_user_obj = TRUE; - break; - case DEF_GROUP_OBJ: - if (has_def_group_obj) - { - if (which) - *which = pos; - return GRP_ERROR; - } - has_def_group_obj = TRUE; - break; - case DEF_OTHER_OBJ: - if (has_def_other_obj) - { - if (which) - *which = pos; - return OTHER_ERROR; - } - has_def_other_obj = TRUE; - break; - case DEF_CLASS_OBJ: - if (has_def_class_obj) - { - if (which) - *which = pos; - return CLASS_ERROR; - } - has_def_class_obj = TRUE; - break; - case DEF_USER: - case DEF_GROUP: - if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1, - aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0) - { - if (which) - *which = pos2; - return DUPLICATE_ERROR; - } - has_def_ug_objs = TRUE; - break; - default: - return ENTRY_ERROR; - } - if (!has_user_obj - || !has_group_obj - || !has_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) - *which = -1; - return MISS_ERROR; - } - return 0; -} - -extern "C" -int acecmp (const void *a1, const void *a2) -{ -#define ace(i) ((const aclent_t *) a##i) - int ret = ace(1)->a_type - ace(2)->a_type; - if (!ret) - ret = ace(1)->a_id - ace(2)->a_id; - return ret; -#undef ace -} - -extern "C" -int -aclsort (int nentries, int, aclent_t *aclbufp) -{ - if (aclcheck (aclbufp, nentries, NULL)) - return -1; - if (!aclbufp || nentries < 1) - { - set_errno (EINVAL); - return -1; - } - qsort((void *) aclbufp, nentries, sizeof (aclent_t), acecmp); - return 0; -} - -extern "C" -int -acltomode (aclent_t *aclbufp, int nentries, mode_t *modep) -{ - int pos; - - if (!aclbufp || nentries < 1 || !modep) - { - set_errno (EINVAL); - return -1; - } - *modep = 0; - if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0) - { - set_errno (EINVAL); - return -1; - } - *modep |= aclbufp[pos].a_perm & S_IRWXU; - if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0) - { - set_errno (EINVAL); - return -1; - } - if (searchace (aclbufp, nentries, CLASS_OBJ) < 0) - pos = searchace (aclbufp, nentries, CLASS_OBJ); - *modep |= (aclbufp[pos].a_perm & S_IRWXU) >> 3; - if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0) - { - set_errno (EINVAL); - return -1; - } - *modep |= (aclbufp[pos].a_perm & S_IRWXU) >> 6; - return 0; -} - -extern "C" -int -aclfrommode(aclent_t *aclbufp, int nentries, mode_t *modep) -{ - int pos; - - if (!aclbufp || nentries < 1 || !modep) - { - set_errno (EINVAL); - return -1; - } - if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0) - { - set_errno (EINVAL); - return -1; - } - aclbufp[pos].a_perm = (*modep & S_IRWXU) - | (*modep & S_IRWXU) >> 3 - | (*modep & S_IRWXU) >> 6; - if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0) - { - set_errno (EINVAL); - return -1; - } - if (searchace (aclbufp, nentries, CLASS_OBJ) < 0) - pos = searchace (aclbufp, nentries, CLASS_OBJ); - aclbufp[pos].a_perm = (*modep & S_IRWXG) - | (*modep & S_IRWXG) << 3 - | (*modep & S_IRWXG) >> 3; - if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0) - { - set_errno (EINVAL); - return -1; - } - aclbufp[pos].a_perm = (*modep & S_IRWXO) - | (*modep & S_IRWXO) << 6 - | (*modep & S_IRWXO) << 3; - return 0; -} - -extern "C" -int -acltopbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp) -{ - return acltomode (aclbufp, nentries, pbitsp); -} - -extern "C" -int -aclfrompbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp) -{ - return aclfrommode (aclbufp, nentries, pbitsp); -} - -static char * -permtostr (mode_t perm) -{ - static char pbuf[4]; - - pbuf[0] = (perm & S_IREAD) ? 'r' : '-'; - pbuf[1] = (perm & S_IWRITE) ? 'w' : '-'; - pbuf[2] = (perm & S_IEXEC) ? 'x' : '-'; - pbuf[3] = '\0'; - return pbuf; -} - -extern "C" -char * -acltotext (aclent_t *aclbufp, int aclcnt) -{ - if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES - || aclcheck (aclbufp, aclcnt, NULL)) - { - set_errno (EINVAL); - return NULL; - } - char buf[32000]; - buf[0] = '\0'; - BOOL first = TRUE; - - for (int pos = 0; pos < aclcnt; ++pos) - { - if (!first) - strcat (buf, ","); - first = FALSE; - if (aclbufp[pos].a_type & ACL_DEFAULT) - strcat (buf, "default"); - switch (aclbufp[pos].a_type) - { - case USER_OBJ: - __small_sprintf (buf + strlen (buf), "user::%s", - permtostr (aclbufp[pos].a_perm)); - break; - case USER: - __small_sprintf (buf + strlen (buf), "user:%d:%s", - aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); - break; - case GROUP_OBJ: - __small_sprintf (buf + strlen (buf), "group::%s", - permtostr (aclbufp[pos].a_perm)); - break; - case GROUP: - __small_sprintf (buf + strlen (buf), "group:%d:%s", - aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); - break; - case CLASS_OBJ: - __small_sprintf (buf + strlen (buf), "mask::%s", - permtostr (aclbufp[pos].a_perm)); - break; - case OTHER_OBJ: - __small_sprintf (buf + strlen (buf), "other::%s", - permtostr (aclbufp[pos].a_perm)); - break; - default: - set_errno (EINVAL); - return NULL; - } - } - return strdup (buf); -} - -static mode_t -permfromstr (char *perm) -{ - mode_t mode = 0; - - if (strlen (perm) != 3) - return 01000; - if (perm[0] == 'r') - mode |= S_IRUSR | S_IRGRP | S_IROTH; - else if (perm[0] != '-') - return 01000; - if (perm[1] == 'w') - mode |= S_IWUSR | S_IWGRP | S_IWOTH; - else if (perm[1] != '-') - return 01000; - if (perm[2] == 'x') - mode |= S_IXUSR | S_IXGRP | S_IXOTH; - else if (perm[2] != '-') - return 01000; - return mode; -} - -extern "C" -aclent_t * -aclfromtext (char *acltextp, int *) -{ - if (!acltextp) - { - set_errno (EINVAL); - return NULL; - } - char buf[strlen (acltextp) + 1]; - aclent_t lacl[MAX_ACL_ENTRIES]; - memset (lacl, 0, sizeof lacl); - int pos = 0; - strcpy (buf, acltextp); - char *lasts; - for (char *c = strtok_r (buf, ",", &lasts); - c; - c = strtok_r (NULL, ",", &lasts)) - { - if (!strncmp (c, "default", 7)) - { - lacl[pos].a_type |= ACL_DEFAULT; - c += 7; - } - if (!strncmp (c, "user:", 5)) - { - if (c[5] == ':') - lacl[pos].a_type |= USER_OBJ; - else - { - lacl[pos].a_type |= USER; - c += 5; - if (isalpha (*c)) - { - struct passwd *pw = getpwnam (c); - if (!pw) - { - set_errno (EINVAL); - return NULL; - } - lacl[pos].a_id = pw->pw_uid; - c = strchr (c, ':'); - } - else if (isdigit (*c)) - lacl[pos].a_id = strtol (c, &c, 10); - if (!c || *c != ':') - { - set_errno (EINVAL); - return NULL; - } - } - } - else if (!strncmp (c, "group:", 6)) - { - if (c[5] == ':') - lacl[pos].a_type |= GROUP_OBJ; - else - { - lacl[pos].a_type |= GROUP; - c += 5; - if (isalpha (*c)) - { - struct group *gr = getgrnam (c); - if (!gr) - { - set_errno (EINVAL); - return NULL; - } - lacl[pos].a_id = gr->gr_gid; - c = strchr (c, ':'); - } - else if (isdigit (*c)) - lacl[pos].a_id = strtol (c, &c, 10); - if (!c || *c != ':') - { - set_errno (EINVAL); - return NULL; - } - } - } - else if (!strncmp (c, "mask:", 5)) - { - if (c[5] == ':') - lacl[pos].a_type |= CLASS_OBJ; - else - { - set_errno (EINVAL); - return NULL; - } - } - else if (!strncmp (c, "other:", 6)) - { - if (c[5] == ':') - lacl[pos].a_type |= OTHER_OBJ; - else - { - set_errno (EINVAL); - return NULL; - } - } - if ((lacl[pos].a_perm = permfromstr (c)) == 01000) - { - set_errno (EINVAL); - return NULL; - } - ++pos; - } - aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t)); - if (aclp) - memcpy (aclp, lacl, pos * sizeof (aclent_t)); - return aclp; -} - diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index bd1b3d891..b83e3101b 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -1,6 +1,6 @@ /* security.h: security declarations - Copyright 2000 Red Hat, Inc. + Copyright 2000, 2001 Red Hat, Inc. This file is part of Cygwin. @@ -8,30 +8,51 @@ This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ +#define DONT_INHERIT (0) +#define INHERIT_ALL (CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) +#define INHERIT_ONLY (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) + +extern BOOL allow_ntsec; +extern BOOL allow_smbntsec; + /* File manipulation */ int __stdcall set_process_privileges (); int __stdcall get_file_attribute (int, const char *, int *, uid_t * = NULL, gid_t * = NULL); int __stdcall set_file_attribute (int, const char *, int); int __stdcall set_file_attribute (int, const char *, uid_t, gid_t, int, const char *); -extern BOOL allow_ntsec; -extern BOOL allow_smbntsec; - +LONG __stdcall read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size); +LONG __stdcall write_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size); +BOOL __stdcall add_access_allowed_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit); +BOOL __stdcall add_access_denied_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit); + + +/* sec_helper.cc: Security helper functions. */ +char *__stdcall convert_sid_to_string_sid (PSID psid, char *sid_str); +PSID __stdcall convert_string_sid_to_sid (PSID psid, const char *sid_str); +PSID __stdcall get_sid (PSID psid, DWORD s, DWORD cnt, DWORD *r); +BOOL __stdcall get_pw_sid (PSID sid, struct passwd *pw); +BOOL __stdcall get_gr_sid (PSID sid, struct group *gr); +PSID __stdcall get_admin_sid (); +PSID __stdcall get_system_sid (); +PSID __stdcall get_creator_owner_sid (); +PSID __stdcall get_world_sid (); +int get_id_from_sid (PSID psid, BOOL search_grp, int *type); +int __stdcall get_id_from_sid (PSID psid, BOOL search_grp); +BOOL __stdcall legal_sid_type (SID_NAME_USE type); +BOOL __stdcall is_grp_member (uid_t uid, gid_t gid); /* `lookup_name' should be called instead of LookupAccountName. * logsrv may be NULL, in this case only the local system is used for lookup. * The buffer for ret_sid (40 Bytes) has to be allocated by the caller! */ BOOL __stdcall lookup_name (const char *, const char *, PSID); -char *__stdcall convert_sid_to_string_sid (PSID, char *); -PSID __stdcall convert_string_sid_to_sid (PSID, const char *); -BOOL __stdcall get_pw_sid (PSID, struct passwd *); -/* Retrieve a security descriptor that allows all access */ -SECURITY_DESCRIPTOR *__stdcall get_null_sd (void); - -int __stdcall get_id_from_sid (PSID, BOOL); extern inline int get_uid_from_sid (PSID psid) { return get_id_from_sid (psid, FALSE);} extern inline int get_gid_from_sid (PSID psid) { return get_id_from_sid (psid, TRUE); } +/* shared.cc: */ +/* Retrieve a security descriptor that allows all access */ +SECURITY_DESCRIPTOR *__stdcall get_null_sd (void); + /* Various types of security attributes for use in Create* functions. */ extern SECURITY_ATTRIBUTES sec_none, sec_none_nih, sec_all, sec_all_nih; extern SECURITY_ATTRIBUTES *__stdcall sec_user (PVOID sa_buf, PSID sid2 = NULL, BOOL inherit = TRUE); -- cgit v1.2.3