diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 3e467ea54..01044e9fb 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,34 @@ +2002-07-29 Corinna Vinschen + + * security.cc: Change some formatting. + * include/cygwin/version.h: Bump API minor version. + +2002-07-28 Pierre Humblet + + * cygheap.h (class cygheap_user): Add member groups. + * security.h (class cygsidlist): Add members type and maxcount, + methods position, addfromgr, alloc_sids and free_sids and + operator+= (const PSID psid). Modify contains () to call + position () and optimize add () to use maxcount. + (class user_groups): Create. + Update declarations of verify_token and create_token. + * security.cc (cygsidlist::alloc_sids): New. + (cygsidlist::free_sids): New. + (get_token_group_sidlist): Create from get_group_sidlist. + (get_initgroups_sidlist): Create from get_group_sidlist. + (get_group_sidlist): Suppress. + (get_setgroups_sidlist): Create. + (verify_token): Modify arguments. Add setgroups case. + (create_token): Modify arguments. Call get_initgroups_sidlist and + get_setgroups_sidlist as needed. Set SE_GROUP_LOGON_ID from auth_pos + outside of the loop. Rename the various group sid lists consistently. + * syscalls.cc (seteuid32): Modify to use cygheap->user.groups. + (setegid32): Call cygheap->user.groups.update_pgrp. + * grp.cc (setgroups): Create. + (setgroups32): Create. + * uinfo.cc (internal_getlogin): Initialize and update user.groups.pgsid. + * cygwin.din: Add setgroups and setgroups32. + 2002-07-28 Christopher Faylor * fhandler_console.cc (fhandler_console::read): Use appropriate diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index be8781038..7cd5becbc 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -113,6 +113,7 @@ public: __gid32_t orig_gid; /* Ditto */ __uid32_t real_uid; /* Remains intact on seteuid, replaced by setuid */ __gid32_t real_gid; /* Ditto */ + user_groups groups; /* Primary and supp SIDs */ /* token is needed if set(e)uid should be called. It can be set by a call to `set_impersonation_token()'. */ diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 7d69c43f7..0af8f43ac 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -678,6 +678,9 @@ _setdtablesize = setdtablesize setgid _setgid = setgid setgid32 +setgroups +_setgroups = setgroups +setgroups32 setjmp _setjmp = setjmp setlocale diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc index 62e0e76cf..c26a6b1c7 100644 --- a/winsup/cygwin/grp.cc +++ b/winsup/cygwin/grp.cc @@ -457,3 +457,64 @@ initgroups (const char *, __gid16_t) { return 0; } + +/* setgroups32: standards? */ +extern "C" +int +setgroups32 (int ngroups, const __gid32_t *grouplist) +{ + if (ngroups < 0 || (ngroups > 0 && !grouplist)) + { + set_errno (EINVAL); + return -1; + } + + if (!wincap.has_security ()) + return 0; + + cygsidlist gsids (cygsidlist_alloc, ngroups); + struct __group32 *gr; + + if (ngroups && !gsids.sids) + return -1; + + for (int gidx = 0; gidx < ngroups; ++gidx) + { + for (int gidy = 0; gidy < gidx; gidy++) + if (grouplist[gidy] == grouplist[gidx]) + goto found; /* Duplicate */ + for (int gidy = 0; (gr = internal_getgrent (gidy)); ++gidy) + if (gr->gr_gid == (__gid32_t) grouplist[gidx]) + { + if (gsids.addfromgr (gr)) + goto found; + break; + } + debug_printf ("No sid found for gid %d", grouplist[gidx]); + gsids.free_sids (); + set_errno (EINVAL); + return -1; + found: + continue; + } + cygheap->user.groups.update_supp (gsids); + return 0; +} + +extern "C" +int +setgroups (int ngroups, const __gid16_t *grouplist) +{ + __gid32_t *grouplist32 = NULL; + + if (ngroups > 0 && grouplist) + { + grouplist32 = (__gid32_t *) alloca (ngroups * sizeof (__gid32_t)); + if (grouplist32 == NULL) + return -1; + for (int i = 0; i < ngroups; i++) + grouplist32[i] = grouplist[i]; + } + return setgroups32 (ngroups, grouplist32); + +} diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index aafc2f932..e98462ddb 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -154,12 +154,13 @@ details. */ 54: Export __fpclassifyd, __fpclassifyf, __signbitd, __signbitf. 55: Export fcloseall, fcloseall_r. 56: Make ntsec on by default. + 57: Export setgroups. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 56 +#define CYGWIN_VERSION_API_MINOR 57 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index a89ff2972..d12e33359 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -47,6 +47,22 @@ BOOL allow_ntsec = true; The default is TRUE to reflect the old behaviour. */ BOOL allow_smbntsec; +cygsid * +cygsidlist::alloc_sids (int n) +{ + if (n > 0) + return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid)); + else + return NULL; +} + +void +cygsidlist::free_sids () +{ + if (sids) + cfree (sids); +} + extern "C" void cygwin_set_impersonation_token (const HANDLE hToken) { @@ -64,7 +80,7 @@ extract_nt_dom_user (const struct passwd *pw, char *domain, char *user) char *d, *u, *c; domain[0] = 0; - strlcpy (user, pw->pw_name, UNLEN+1); + strlcpy (user, pw->pw_name, UNLEN + 1); debug_printf ("pw_gecos = %x (%s)", pw->pw_gecos, pw->pw_gecos); if ((d = strstr (pw->pw_gecos, "U-")) != NULL && @@ -74,11 +90,11 @@ extract_nt_dom_user (const struct passwd *pw, char *domain, char *user) if ((u = strchr (d + 2, '\\')) == NULL || (c != NULL && u > c)) u = d + 1; else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2) - strlcpy(domain, d + 2, u - d - 1); + strlcpy (domain, d + 2, u - d - 1); if (c == NULL) c = u + UNLEN + 1; if (c - u <= UNLEN + 1) - strlcpy(user, u + 1, c - u); + strlcpy (user, u + 1, c - u); } if (domain[0]) return; @@ -112,9 +128,9 @@ cygwin_logon_user (const struct passwd *pw, const char *password) extract_nt_dom_user (pw, nt_domain, nt_user); debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password); if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password, - LOGON32_LOGON_INTERACTIVE, - LOGON32_PROVIDER_DEFAULT, - &hToken) + LOGON32_LOGON_INTERACTIVE, + LOGON32_PROVIDER_DEFAULT, + &hToken) || !SetHandleInformation (hToken, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) @@ -152,7 +168,7 @@ str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr) sys_mbstowcs (buf, srcstr, tgt.MaximumLength); } -#if 0 //unused +#if 0 /* unused */ static void lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size) { @@ -194,7 +210,7 @@ close_local_policy (LSA_HANDLE &lsa) lsa = INVALID_HANDLE_VALUE; } -#if 0 // unused +#if 0 /* unused */ static BOOL get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain) { @@ -226,7 +242,8 @@ get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain) not member of a domain. The name in the primary domain info is the name of the workgroup then. */ if (pdi->Sid && - (ret = NetGetDCName (NULL, primary, (LPBYTE *) &buf)) == STATUS_SUCCESS) + (ret = + NetGetDCName (NULL, primary, (LPBYTE *) &buf)) == STATUS_SUCCESS) { sys_wcstombs (name, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1); strcpy (logonserver, name); @@ -271,7 +288,8 @@ get_logon_server (const char *domain, char *server, WCHAR *wserver) { sys_wcstombs (server, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1); if (wserver) - for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++); ) {} + for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);) + ; NetApiBufferFree (buf); return TRUE; } @@ -280,7 +298,8 @@ get_logon_server (const char *domain, char *server, WCHAR *wserver) } static BOOL -get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user, char *domain) +get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user, + char *domain) { char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; WCHAR wuser[UNLEN + 1]; @@ -313,11 +332,12 @@ get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user, char *do sys_wcstombs (dgroup + len, buf[i].grui0_name, GNLEN + 1); if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use)) - debug_printf ("LookupAccountName(%s): %E", dgroup); + debug_printf ("LookupAccountName(%s): %E", dgroup); else if (legal_sid_type (use)) - grp_list += gsid; - else debug_printf ("Global group %s invalid. Domain: %s Use: %d", - dgroup, domain, use); + grp_list += gsid; + else + debug_printf ("Global group %s invalid. Domain: %s Use: %d", + dgroup, domain, use); } NetApiBufferFree (buf); @@ -369,10 +389,10 @@ get_user_local_groups (cygsidlist &grp_list, PSID pusersid) char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; const DWORD blen = sizeof ("BUILTIN\\") - 1; DWORD llen = INTERNET_MAX_HOST_NAME_LENGTH + 1; - if (!GetComputerNameA(lgroup, & llen)) + if (!GetComputerNameA (lgroup, &llen)) { - __seterrno (); - return FALSE; + __seterrno (); + return FALSE; } lgroup[llen++] = '\\'; @@ -389,11 +409,11 @@ get_user_local_groups (cygsidlist &grp_list, PSID pusersid) if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use)) { if (GetLastError () != ERROR_NONE_MAPPED) - debug_printf ("LookupAccountName(%s): %E", bgroup); + debug_printf ("LookupAccountName(%s): %E", bgroup); strcpy (lgroup + llen, bgroup + blen); if (!LookupAccountName (NULL, lgroup, gsid, &glen, domain, &dlen, &use)) - debug_printf ("LookupAccountName(%s): %E", lgroup); + debug_printf ("LookupAccountName(%s): %E", lgroup); } if (!legal_sid_type (use)) debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use); @@ -415,7 +435,7 @@ sid_in_token_groups (PTOKEN_GROUPS grps, cygsid &sid) return FALSE; } -#if 0 /* Unused */ +#if 0 /* Unused */ static BOOL get_user_primary_group (WCHAR *wlogonserver, const char *user, PSID pusersid, cygsid &pgrpsid) @@ -441,7 +461,8 @@ get_user_primary_group (WCHAR *wlogonserver, const char *user, } pgrpsid = pusersid; - if (IsValidSid (pgrpsid) && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1) + if (IsValidSid (pgrpsid) + && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1) { *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id; retval = TRUE; @@ -473,57 +494,63 @@ get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list) } } -static BOOL -get_group_sidlist (cygsidlist &grp_list, - cygsid &usersid, cygsid &pgrpsid, struct passwd *pw, - PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos, - BOOL *special_pgrp) +static void +get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, + LUID auth_luid, int &auth_pos) { - char user[UNLEN + 1]; - char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; - WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3]; - char server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; - cygsidlist sup_list; - auth_pos = -1; + if (my_grps) + { + if (sid_in_token_groups (my_grps, well_known_local_sid)) + grp_list += well_known_local_sid; + if (sid_in_token_groups (my_grps, well_known_dialup_sid)) + grp_list += well_known_dialup_sid; + if (sid_in_token_groups (my_grps, well_known_network_sid)) + grp_list += well_known_network_sid; + if (sid_in_token_groups (my_grps, well_known_batch_sid)) + grp_list += well_known_batch_sid; + if (sid_in_token_groups (my_grps, well_known_interactive_sid)) + grp_list += well_known_interactive_sid; + if (sid_in_token_groups (my_grps, well_known_service_sid)) + grp_list += well_known_service_sid; + } + else + { + grp_list += well_known_local_sid; + grp_list += well_known_interactive_sid; + } + if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */ + { + char buf[64]; + __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart, + auth_luid.LowPart); + grp_list += buf; + auth_pos = grp_list.count - 1; + } +} +static BOOL +get_initgroups_sidlist (cygsidlist &grp_list, + PSID usersid, PSID pgrpsid, struct passwd *pw, + PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos, + BOOL &special_pgrp) +{ grp_list += well_known_world_sid; grp_list += well_known_authenticated_users_sid; if (usersid == well_known_system_sid) { + auth_pos = -1; grp_list += well_known_admins_sid; get_unix_group_sidlist (pw, grp_list); } else { - if (my_grps) - { - if (sid_in_token_groups (my_grps, well_known_local_sid)) - grp_list += well_known_local_sid; - if (sid_in_token_groups (my_grps, well_known_dialup_sid)) - grp_list += well_known_dialup_sid; - if (sid_in_token_groups (my_grps, well_known_network_sid)) - grp_list += well_known_network_sid; - if (sid_in_token_groups (my_grps, well_known_batch_sid)) - grp_list += well_known_batch_sid; - if (sid_in_token_groups (my_grps, well_known_interactive_sid)) - grp_list += well_known_interactive_sid; - if (sid_in_token_groups (my_grps, well_known_service_sid)) - grp_list += well_known_service_sid; - } - else - { - grp_list += well_known_local_sid; - grp_list += well_known_interactive_sid; - } - if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */ - { - char buf[64]; - __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart, - auth_luid.LowPart); - grp_list += buf; - auth_pos = grp_list.count - 1; - } + char user[UNLEN + 1]; + char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3]; + char server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; + + get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos); extract_nt_dom_user (pw, domain, user); if (get_logon_server (domain, server, wserver)) get_user_groups (wserver, grp_list, user, domain); @@ -531,16 +558,26 @@ get_group_sidlist (cygsidlist &grp_list, if (!get_user_local_groups (grp_list, usersid)) return FALSE; } - /* special_pgrp true if pgrpsid is not null and not in normal groups */ - *special_pgrp = FALSE; - if (pgrpsid && !grp_list.contains (pgrpsid)) - { - *special_pgrp = TRUE; - grp_list += pgrpsid; - } + /* special_pgrp true if pgrpsid is not in normal groups */ + if ((special_pgrp = !grp_list.contains (pgrpsid))) + grp_list += pgrpsid; return TRUE; } +static void +get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps, + user_groups &groups, LUID auth_luid, int &auth_pos) +{ + PSID pgpsid = groups.pgsid; + tmp_list += well_known_world_sid; + tmp_list += well_known_authenticated_users_sid; + get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos); + for (int gidx = 0; gidx < groups.sgsids.count; gidx++) + tmp_list += groups.sgsids.sids[gidx]; + if (!groups.sgsids.contains (pgpsid)) + tmp_list += pgpsid; +} + static const char *sys_privs[] = { SE_TCB_NAME, SE_ASSIGNPRIMARYTOKEN_NAME, @@ -569,8 +606,8 @@ PTOKEN_PRIVILEGES get_system_priv_list (cygsidlist &grp_list) { LUID priv; - PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (sizeof (ULONG) + - 20 * sizeof (LUID_AND_ATTRIBUTES)); + PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) + malloc (sizeof (ULONG) + 20 * sizeof (LUID_AND_ATTRIBUTES)); if (!privs) { debug_printf ("malloc (system_privs) failed."); @@ -583,7 +620,7 @@ get_system_priv_list (cygsidlist &grp_list) { privs->Privileges[privs->PrivilegeCount].Luid = priv; privs->Privileges[privs->PrivilegeCount].Attributes = - SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; + SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; ++privs->PrivilegeCount; } return privs; @@ -605,8 +642,8 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) { if (grp == -1) { - if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs, &cnt)) - != STATUS_SUCCESS) + if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs, + &cnt)) != STATUS_SUCCESS) continue; } else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp], @@ -629,8 +666,8 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) tmp_count = privs ? privs->PrivilegeCount : 0; tmp = (PTOKEN_PRIVILEGES) - realloc (privs, sizeof (ULONG) + - (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES)); + realloc (privs, sizeof (ULONG) + + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES)); if (!tmp) { if (privs) @@ -643,7 +680,7 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) privs = tmp; privs->Privileges[privs->PrivilegeCount].Luid = priv; privs->Privileges[privs->PrivilegeCount].Attributes = - SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; + SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; ++privs->PrivilegeCount; next_account_right: @@ -654,8 +691,21 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) return privs; } +/* Accept a token if + - the requested usersid matches the TokenUser and + - if setgroups has been called: + the token groups that are listed in /etc/group match the union of + the requested primary and supplementary groups in gsids. + - else the (unknown) implicitly requested supplementary groups and those + in the token are the groups associated with the usersid. We assume + they match and verify only the primary groups. + The requested primary group must appear in the token. + The primary group in the token is a group associated with the usersid, + except if the token is internal and the group is in the token SD + (see create_token). In that latter case that group must match the + requested primary group. */ BOOL -verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL *pintern) +verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern) { DWORD size; BOOL intern = FALSE; @@ -666,36 +716,39 @@ verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL *pintern) if (!GetTokenInformation (cygheap->user.token, TokenSource, &ts, sizeof ts, &size)) debug_printf ("GetTokenInformation(): %E"); - else *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); + else + *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); } /* Verify usersid */ cygsid tok_usersid = NO_SID; if (!GetTokenInformation (token, TokenUser, &tok_usersid, sizeof tok_usersid, &size)) - debug_printf ("GetTokenInformation(): %E"); - if (usersid != tok_usersid) return FALSE; + debug_printf ("GetTokenInformation(): %E"); + if (usersid != tok_usersid) + return FALSE; - /* In an internal token, if the sd group is not well_known_null_sid, - it must match pgrpsid */ - if (intern) + /* For an internal token, if setgroups was not called and if the sd group + is not well_known_null_sid, it must match pgrpsid */ + if (intern && !groups.issetgroups ()) { - char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)]; - PSID gsid = NO_SID; - if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION, + char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)]; + PSID gsid = NO_SID; + if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION, (PSECURITY_DESCRIPTOR) sd_buf, sizeof sd_buf, &size)) - debug_printf ("GetKernelObjectSecurity(): %E"); - else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf, + debug_printf ("GetKernelObjectSecurity(): %E"); + else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf, &gsid, (BOOL *) &size)) - debug_printf ("GetSecurityDescriptorGroup(): %E"); - if (well_known_null_sid != gsid) return pgrpsid == gsid; + debug_printf ("GetSecurityDescriptorGroup(): %E"); + if (well_known_null_sid != gsid) + return gsid == groups.pgsid; } - /* See if the pgrpsid is the tok_usersid in the token groups */ + PTOKEN_GROUPS my_grps = NULL; BOOL ret = FALSE; + char saw_buf[NGROUPS_MAX] = {}; + char *saw = saw_buf, sawpg = FALSE; - if ( pgrpsid == tok_usersid) - return TRUE; if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) && GetLastError () != ERROR_INSUFFICIENT_BUFFER) debug_printf ("GetTokenInformation(token, TokenGroups): %E\n"); @@ -703,38 +756,70 @@ verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL *pintern) debug_printf ("malloc (my_grps) failed."); else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size)) debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); - else - ret = sid_in_token_groups (my_grps, pgrpsid); + else if (!groups.issetgroups ()) /* setgroups was never called */ + { + ret = sid_in_token_groups (my_grps, groups.pgsid); + if (ret == FALSE) + ret = (groups.pgsid == tok_usersid); + } + else /* setgroups was called */ + { + struct __group32 *gr; + cygsid gsid; + if (groups.sgsids.count > (int) sizeof (saw_buf) && + !(saw = (char *) calloc (groups.sgsids.count, sizeof (char)))) + goto done; + + /* token groups found in /etc/group match the user.gsids ? */ + for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) + if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid)) + { + int pos = groups.sgsids.position (gsid); + if (pos >= 0) + saw[pos] = TRUE; + else if (groups.pgsid == gsid) + sawpg = TRUE; + else + goto done; + } + for (int gidx = 0; gidx < groups.sgsids.count; gidx++) + if (!saw[gidx]) + goto done; + if (sawpg || groups.sgsids.contains (groups.pgsid)) + ret = TRUE; + } +done: if (my_grps) free (my_grps); + if (saw != saw_buf) + free (saw); return ret; } HANDLE -create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) +create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw) { NTSTATUS ret; LSA_HANDLE lsa = INVALID_HANDLE_VALUE; int old_priv_state; - cygsidlist grpsids; + cygsidlist tmp_gsids (cygsidlist_auto, 12); SECURITY_QUALITY_OF_SERVICE sqos = { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE }; - OBJECT_ATTRIBUTES oa = - { sizeof oa, 0, 0, 0, 0, &sqos }; + OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos }; PSECURITY_ATTRIBUTES psa; - BOOL special_pgrp; + BOOL special_pgrp = FALSE; char sa_buf[1024]; LUID auth_luid = SYSTEM_LUID; - LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL }; + LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL }; TOKEN_USER user; - PTOKEN_GROUPS grps = NULL; + PTOKEN_GROUPS new_tok_gsids = NULL; PTOKEN_PRIVILEGES privs = NULL; TOKEN_OWNER owner; TOKEN_PRIMARY_GROUP pgrp; - char acl_buf[MAX_DACL_LEN(5)]; + char acl_buf[MAX_DACL_LEN (5)]; TOKEN_DEFAULT_DACL dacl; TOKEN_SOURCE source; TOKEN_STATISTICS stats; @@ -746,7 +831,7 @@ create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) HANDLE primary_token = INVALID_HANDLE_VALUE; HANDLE my_token = INVALID_HANDLE_VALUE; - PTOKEN_GROUPS my_grps = NULL; + PTOKEN_GROUPS my_tok_gsids = NULL; DWORD size; /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */ @@ -768,68 +853,73 @@ create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) else { /* Switching user context to SYSTEM doesn't inherit the authentication - id of the user account running current process. */ + id of the user account running current process. */ if (usersid != well_known_system_sid) if (!GetTokenInformation (my_token, TokenStatistics, &stats, sizeof stats, &size)) - debug_printf ("GetTokenInformation(my_token, TokenStatistics): %E\n"); + debug_printf + ("GetTokenInformation(my_token, TokenStatistics): %E\n"); else auth_luid = stats.AuthenticationId; /* Retrieving current processes group list to be able to inherit - some important well known group sids. */ + some important well known group sids. */ if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) && GetLastError () != ERROR_INSUFFICIENT_BUFFER) debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); - else if (!(my_grps = (PTOKEN_GROUPS) malloc (size))) - debug_printf ("malloc (my_grps) failed."); - else if (!GetTokenInformation (my_token, TokenGroups, my_grps, + else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size))) + debug_printf ("malloc (my_tok_gsids) failed."); + else if (!GetTokenInformation (my_token, TokenGroups, my_tok_gsids, size, &size)) { debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); - free (my_grps); - my_grps = NULL; + free (my_tok_gsids); + my_tok_gsids = NULL; } CloseHandle (my_token); } /* Create list of groups, the user is member in. */ int auth_pos; - if (!get_group_sidlist (grpsids, usersid, pgrpsid, pw, - my_grps, auth_luid, auth_pos, &special_pgrp)) + if (new_groups.issetgroups ()) + get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_groups, auth_luid, + auth_pos); + else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw, + my_tok_gsids, auth_luid, auth_pos, + special_pgrp)) goto out; /* Primary group. */ - pgrp.PrimaryGroup = pgrpsid; + pgrp.PrimaryGroup = new_groups.pgsid; /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */ - char grps_buf[sizeof (ULONG) + grpsids.count * sizeof (SID_AND_ATTRIBUTES)]; - grps = (PTOKEN_GROUPS) grps_buf; - grps->GroupCount = grpsids.count; - for (DWORD i = 0; i < grps->GroupCount; ++i) + char grps_buf[sizeof (ULONG) + tmp_gsids.count * sizeof (SID_AND_ATTRIBUTES)]; + new_tok_gsids = (PTOKEN_GROUPS) grps_buf; + new_tok_gsids->GroupCount = tmp_gsids.count; + for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i) { - grps->Groups[i].Sid = grpsids.sids[i]; - grps->Groups[i].Attributes = SE_GROUP_MANDATORY | - SE_GROUP_ENABLED_BY_DEFAULT | - SE_GROUP_ENABLED; - if (auth_pos >= 0 && i == (DWORD) auth_pos) - grps->Groups[i].Attributes |= SE_GROUP_LOGON_ID; + new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i]; + new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY | + SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; } + if (auth_pos >= 0) + new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID; /* Retrieve list of privileges of that user. */ - if (!(privs = get_priv_list (lsa, usersid, grpsids))) + if (!(privs = get_priv_list (lsa, usersid, tmp_gsids))) goto out; /* Create default dacl. */ if (!sec_acl ((PACL) acl_buf, FALSE, - grpsids.contains (well_known_admins_sid)?well_known_admins_sid:usersid)) + tmp_gsids.contains (well_known_admins_sid) ? + well_known_admins_sid : usersid)) goto out; dacl.DefaultDacl = (PACL) acl_buf; /* Let's be heroic... */ ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation, - &auth_luid, &exp, &user, grps, privs, &owner, &pgrp, - &dacl, &source); + &auth_luid, &exp, &user, new_tok_gsids, privs, &owner, + &pgrp, &dacl, &source); if (ret) __seterrno_from_win_error (RtlNtStatusToDosError (ret)); else if (GetLastError () == ERROR_PROC_NOT_FOUND) @@ -842,13 +932,15 @@ create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) /* Set security descriptor and primary group */ psa = __sec_user (sa_buf, usersid, TRUE); if (psa->lpSecurityDescriptor && - !SetSecurityDescriptorGroup ( - (PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor, - special_pgrp ? pgrpsid : well_known_null_sid, FALSE)) - debug_printf ("SetSecurityDescriptorGroup %E"); + !SetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) + psa->lpSecurityDescriptor, + special_pgrp ? new_groups.pgsid + : well_known_null_sid, + FALSE)) + debug_printf ("SetSecurityDescriptorGroup %E"); /* Convert to primary token. */ - if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, - SecurityImpersonation, TokenPrimary, &primary_token)) + if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, SecurityImpersonation, + TokenPrimary, &primary_token)) { __seterrno (); debug_printf ("DuplicateTokenEx %E"); @@ -862,8 +954,8 @@ out: CloseHandle (token); if (privs) free (privs); - if (my_grps) - free (my_grps); + if (my_tok_gsids) + free (my_tok_gsids); close_local_policy (lsa); debug_printf ("%d = create_token ()", primary_token); @@ -946,13 +1038,13 @@ subauth (struct passwd *pw) str2buf2uni (subbuf.auth.Workstation, subbuf.wkstbuf, ""); memcpy (subbuf.auth.ChallengeToClient, "12345678", MSV1_0_CHALLENGE_LENGTH); str2buf2lsa (subbuf.auth.CaseSensitiveChallengeResponse, subbuf.authinf1, ""); - str2buf2lsa (subbuf.auth.CaseInsensitiveChallengeResponse, subbuf.authinf2,""); + str2buf2lsa (subbuf.auth.CaseInsensitiveChallengeResponse,subbuf.authinf2,""); subbuf.auth.ParameterControl = 0 | (subauth_id << 24); /* Try to logon... */ ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Network, - package_id, &subbuf, sizeof subbuf, - NULL, &ts, (PVOID *)&profile, &size, - &luid, &user_token, "a, &ret2); + package_id, &subbuf, sizeof subbuf, + NULL, &ts, (PVOID *) &profile, &size, + &luid, &user_token, "a, &ret2); if (ret != STATUS_SUCCESS) { debug_printf ("LsaLogonUser: %d", ret); @@ -963,8 +1055,7 @@ subauth (struct passwd *pw) LsaFreeReturnBuffer (profile); /* Convert to primary token. */ if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa, - SecurityImpersonation, TokenPrimary, - &primary_token)) + SecurityImpersonation, TokenPrimary, &primary_token)) __seterrno (); out: @@ -1004,7 +1095,7 @@ read_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size) DWORD len = 0; const char *pfile = file; - char fbuf [PATH_MAX]; + char fbuf[PATH_MAX]; if (current_codepage == oem_cp) { DWORD fname_len = min (sizeof (fbuf) - 1, strlen (file)); @@ -1015,9 +1106,9 @@ read_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size) if (!GetFileSecurity (pfile, OWNER_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | DACL_SECURITY_INFORMATION, - sd_buf, *sd_size, &len)) + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION, + sd_buf, *sd_size, &len)) { __seterrno (); return -1; @@ -1090,8 +1181,8 @@ write_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size) &bytes_written, FALSE, TRUE, &context)) { /* Samba returns ERROR_NOT_SUPPORTED. - FAT returns ERROR_INVALID_SECURITY_DESCR. - This shouldn't return as error, but better be ignored. */ + FAT returns ERROR_INVALID_SECURITY_DESCR. + This shouldn't return as error, but better be ignored. */ DWORD ret = GetLastError (); if (ret != ERROR_NOT_SUPPORTED && ret != ERROR_INVALID_SECURITY_DESCR) { @@ -1117,7 +1208,7 @@ get_nt_attribute (const char *file, int *attribute, syscall_printf ("file: %s", file); - /* Yeah, sounds too much, but I've seen SDs of 2100 bytes!*/ + /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */ DWORD sd_size = 4096; char sd_buf[4096]; PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; @@ -1282,13 +1373,13 @@ get_file_attribute (int use_ntsec, const char *file, if (allow_ntea) { int oatt = *attribute; - res = NTReadEA (file, ".UNIXATTR", (char *) attribute, sizeof (*attribute)); + res = NTReadEA (file, ".UNIXATTR", (char *)attribute, sizeof(*attribute)); *attribute |= oatt; } else res = 0; - /* symlinks are everything for everyone!*/ + /* symlinks are everything for everyone! */ if ((*attribute & S_IFLNK) == S_IFLNK) *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; @@ -1296,8 +1387,8 @@ get_file_attribute (int use_ntsec, const char *file, } static int -get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribute, - __uid32_t *uidret, __gid32_t *gidret) +get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, + int *attribute, __uid32_t *uidret, __gid32_t *gidret) { if (!wincap.has_security ()) return 0; @@ -1308,18 +1399,15 @@ get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribu PACL acl; if (ERROR_SUCCESS != GetSecurityInfo (handle, object_type, - DACL_SECURITY_INFORMATION | - GROUP_SECURITY_INFORMATION | - OWNER_SECURITY_INFORMATION, - &owner_sid, - &group_sid, - &acl, - NULL, - &psd)) - { - __seterrno (); - debug_printf ("GetSecurityInfo %E"); - return -1; + DACL_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION, + &owner_sid, &group_sid, + &acl, NULL, &psd)) + { + __seterrno (); + debug_printf ("GetSecurityInfo %E"); + return -1; } __uid32_t uid = cygsid (owner_sid).get_uid (); @@ -1341,8 +1429,7 @@ get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribu if (!acl) { *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - syscall_printf ("No ACL = %x, uid %d, gid %d", - *attribute, uid, gid); + syscall_printf ("No ACL = %x, uid %d, gid %d", *attribute, uid, gid); LocalFree (psd); return 0; } @@ -1354,7 +1441,7 @@ get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribu for (DWORD i = 0; i < acl->AceCount; ++i) { - if (!GetAce (acl, i, (PVOID *) &ace)) + if (!GetAce (acl, i, (PVOID *) & ace)) continue; if (ace->Header.AceFlags & INHERIT_ONLY) continue; @@ -1372,7 +1459,7 @@ get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribu continue; } - cygsid ace_sid ((PSID) &ace->SidStart); + cygsid ace_sid ((PSID) & ace->SidStart); if (owner_sid && ace_sid == owner_sid) { if (ace->Mask & FILE_READ_DATA) @@ -1438,11 +1525,12 @@ get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribu int get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, - int *attribute, __uid32_t *uidret, __gid32_t *gidret) + int *attribute, __uid32_t *uidret, __gid32_t *gidret) { if (allow_ntsec) { - int res = get_nt_object_attribute (handle, object_type, attribute, uidret, gidret); + int res = get_nt_object_attribute (handle, object_type, attribute, + uidret, gidret); if (attribute && (*attribute & S_IFLNK) == S_IFLNK) *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; return res; @@ -1456,7 +1544,7 @@ get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, if (!attribute) return 0; - /* symlinks are everything for everyone!*/ + /* symlinks are everything for everyone! */ if ((*attribute & S_IFLNK) == S_IFLNK) *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; @@ -1475,8 +1563,7 @@ add_access_allowed_ace (PACL acl, int offset, DWORD attributes, ACCESS_ALLOWED_ACE *ace; if (GetAce (acl, offset, (PVOID *) &ace)) ace->Header.AceFlags |= inherit; - len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) - + GetLengthSid (sid); + len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid); return TRUE; } @@ -1492,8 +1579,7 @@ add_access_denied_ace (PACL acl, int offset, DWORD attributes, ACCESS_DENIED_ACE *ace; if (GetAce (acl, offset, (PVOID *) &ace)) ace->Header.AceFlags |= inherit; - len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) - + GetLengthSid (sid); + len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid); return TRUE; } @@ -1614,8 +1700,7 @@ alloc_sd (__uid32_t uid, __gid32_t gid, int attribute, if (attribute & S_IXGRP) group_allow |= FILE_GENERIC_EXECUTE; if ((attribute & (S_IFDIR | S_IWGRP | S_IXGRP)) - == (S_IFDIR | S_IWGRP | S_IXGRP) - && !(attribute & S_ISVTX)) + == (S_IFDIR | S_IWGRP | S_IXGRP) && !(attribute & S_ISVTX)) group_allow |= FILE_DELETE_CHILD; /* Construct allow attribute for everyone. */ @@ -1658,30 +1743,30 @@ alloc_sd (__uid32_t uid, __gid32_t gid, int attribute, /* Construct appropriate inherit attribute. */ DWORD inherit = (attribute & S_IFDIR) ? SUB_CONTAINERS_AND_OBJECTS_INHERIT - : NO_INHERITANCE; + : NO_INHERITANCE; /* Set deny ACE for owner. */ if (owner_deny && !add_access_denied_ace (acl, ace_off++, owner_deny, - owner_sid, acl_len, inherit)) + owner_sid, acl_len, inherit)) return NULL; /* Set allow ACE for owner. */ if (!add_access_allowed_ace (acl, ace_off++, owner_allow, - owner_sid, acl_len, inherit)) + owner_sid, acl_len, inherit)) return NULL; /* Set deny ACE for group. */ if (group_deny && !add_access_denied_ace (acl, ace_off++, group_deny, - group_sid, acl_len, inherit)) + group_sid, acl_len, inherit)) return NULL; /* Set allow ACE for group. */ if (!add_access_allowed_ace (acl, ace_off++, group_allow, - group_sid, acl_len, inherit)) + group_sid, acl_len, inherit)) return NULL; /* Set allow ACE for everyone. */ if (!add_access_allowed_ace (acl, ace_off++, other_allow, - well_known_world_sid, acl_len, inherit)) + well_known_world_sid, acl_len, inherit)) return NULL; /* Set null ACE for special bits. */ if (null_allow @@ -1764,15 +1849,15 @@ void set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, void *sd_buf, DWORD sd_buf_size) { - /* symlinks are anything for everyone!*/ + /* symlinks are anything for everyone! */ if ((attribute & S_IFLNK) == S_IFLNK) attribute |= S_IRWXU | S_IRWXG | S_IRWXO; psa->lpSecurityDescriptor = sd_buf; - InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR)sd_buf, + InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR) sd_buf, SECURITY_DESCRIPTOR_REVISION); - psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), - attribute, (PSECURITY_DESCRIPTOR)sd_buf, + psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), attribute, + (PSECURITY_DESCRIPTOR) sd_buf, &sd_buf_size); } @@ -1803,8 +1888,7 @@ set_nt_attribute (const char *file, __uid32_t uid, __gid32_t gid, int set_file_attribute (int use_ntsec, const char *file, - __uid32_t uid, __gid32_t gid, - int attribute) + __uid32_t uid, __gid32_t gid, int attribute) { int ret = 0; @@ -1825,6 +1909,5 @@ int set_file_attribute (int use_ntsec, const char *file, int attribute) { return set_file_attribute (use_ntsec, file, - myself->uid, myself->gid, - attribute); + myself->uid, myself->gid, attribute); } diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 1edcc57fd..580d7c143 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -86,40 +86,63 @@ public: } }; +typedef enum { cygsidlist_unknown, cygsidlist_alloc, cygsidlist_auto } cygsidlist_type; class cygsidlist { + int maxcount; public: int count; cygsid *sids; + cygsidlist_type type; - cygsidlist () : count (0), sids (NULL) {} - ~cygsidlist () { delete [] sids; } - - BOOL add (cygsid &nsi) + cygsidlist (cygsidlist_type t, int m) { - cygsid *tmp = new cygsid [count + 1]; - if (!tmp) - return FALSE; - for (int i = 0; i < count; ++i) - tmp[i] = sids[i]; - delete [] sids; - sids = tmp; + type = t; + count = 0; + maxcount = m; + if (t == cygsidlist_alloc) + sids = alloc_sids (m); + else + sids = new cygsid [m]; + } + ~cygsidlist () { if (type == cygsidlist_auto) delete [] sids; } + + BOOL add (const PSID nsi) /* Only with auto for now */ + { + if (count >= maxcount) + { + cygsid *tmp = new cygsid [ 2 * maxcount]; + if (!tmp) + return FALSE; + maxcount *= 2; + for (int i = 0; i < count; ++i) + tmp[i] = sids[i]; + delete [] sids; + sids = tmp; + } sids[count++] = nsi; return TRUE; } - BOOL add (const PSID nsid) { return add (nsid); } + BOOL add (cygsid &nsi) { return add ((PSID) nsi); } BOOL add (const char *sidstr) { cygsid nsi (sidstr); return add (nsi); } + BOOL addfromgr (struct __group32 *gr) /* Only with alloc */ + { return sids[count++].getfromgr (gr); } BOOL operator+= (cygsid &si) { return add (si); } BOOL operator+= (const char *sidstr) { return add (sidstr); } + BOOL operator+= (const PSID psid) { return add (psid); } - BOOL contains (cygsid &sid) const + int position (const PSID sid) const { for (int i = 0; i < count; ++i) if (sids[i] == sid) - return TRUE; - return FALSE; + return i; + return -1; } + + BOOL contains (const PSID sid) const { return position (sid) >= 0; } + cygsid *alloc_sids (int n); + void free_sids (); void debug_print (const char *prefix = NULL) const { debug_printf ("-- begin sidlist ---"); @@ -131,6 +154,26 @@ public: } }; +class user_groups { +public: + cygsid pgsid; + cygsidlist sgsids; + BOOL ischanged; + + BOOL issetgroups () const { return (sgsids.type == cygsidlist_alloc); } + void update_supp (const cygsidlist &newsids) + { + sgsids.free_sids (); + sgsids = newsids; + ischanged = TRUE; + } + void update_pgrp (const PSID sid) + { + pgsid = sid; + ischanged = TRUE; + } +}; + extern cygsid well_known_null_sid; extern cygsid well_known_world_sid; extern cygsid well_known_local_sid; @@ -180,9 +223,9 @@ void set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, /* Try a subauthentication. */ HANDLE subauth (struct passwd *pw); /* Try creating a token directly. */ -HANDLE create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd * pw); +HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw); /* Verify an existing token */ -BOOL verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL * pintern = NULL); +BOOL verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL * pintern = NULL); /* Extract U-domain\user field from passwd entry. */ void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 018f67dc6..2dc5f1776 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1958,9 +1958,8 @@ seteuid32 (__uid32_t uid) debug_printf ("uid: %d myself->gid: %d", uid, myself->gid); if (!wincap.has_security () - || (!cygheap->user.issetuid () - && uid == myself->uid - && myself->gid == cygheap->user.orig_gid) + || (uid == myself->uid + && !cygheap->user.groups.ischanged) || uid == ILLEGAL_UID) { debug_printf ("Nothing happens"); @@ -1968,7 +1967,8 @@ seteuid32 (__uid32_t uid) } sigframe thisframe (mainthread); - cygsid usersid, pgrpsid; + cygsid usersid; + user_groups &groups = cygheap->user.groups; HANDLE ptok, sav_token; BOOL sav_impersonated, sav_token_is_internal_token; BOOL process_ok, explicitly_created_token = FALSE; @@ -1976,8 +1976,7 @@ seteuid32 (__uid32_t uid) PSID origpsid, psid2 = NO_SID; pw_new = getpwuid32 (uid); - if (!usersid.getfrompw (pw_new) || - (!pgrpsid.getfromgr (getgrgid32 (myself->gid)))) + if (!usersid.getfrompw (pw_new)) { set_errno (EINVAL); return -1; @@ -1995,7 +1994,7 @@ seteuid32 (__uid32_t uid) /* Verify if the process token is suitable. Currently we do not try to differentiate between internal tokens and others */ - process_ok = verify_token (ptok, usersid, pgrpsid); + process_ok = verify_token (ptok, usersid, groups); debug_printf("Process token %sverified", process_ok ? "" : "not "); if (process_ok) { @@ -2011,8 +2010,8 @@ seteuid32 (__uid32_t uid) if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE) { /* Verify if the current tokem is suitable */ - BOOL token_ok = verify_token (cygheap->user.token, usersid, pgrpsid, - & sav_token_is_internal_token); + BOOL token_ok = verify_token (cygheap->user.token, usersid, groups, + &sav_token_is_internal_token); debug_printf("Thread token %d %sverified", cygheap->user.token, token_ok?"":"not "); if (!token_ok) @@ -2048,7 +2047,7 @@ seteuid32 (__uid32_t uid) { /* If no impersonation token is available, try to authenticate using NtCreateToken() or subauthentication. */ - cygheap->user.token = create_token (usersid, pgrpsid, pw_new); + cygheap->user.token = create_token (usersid, groups, pw_new); if (cygheap->user.token != INVALID_HANDLE_VALUE) explicitly_created_token = TRUE; else @@ -2076,7 +2075,7 @@ seteuid32 (__uid32_t uid) /* Try setting primary group in token to current group */ if (!SetTokenInformation (cygheap->user.token, TokenPrimaryGroup, - &pgrpsid, sizeof pgrpsid)) + &groups.pgsid, sizeof(cygsid))) debug_printf ("SetTokenInformation(user.token, " "TokenPrimaryGroup): %E"); } @@ -2098,6 +2097,7 @@ seteuid32 (__uid32_t uid) cygheap->user.set_name (pw_new->pw_name); cygheap->user.set_sid (usersid); myself->uid = uid; + groups.ischanged = FALSE; return 0; failed: @@ -2142,6 +2142,7 @@ setegid32 (__gid32_t gid) return 0; sigframe thisframe (mainthread); + user_groups * groups = &cygheap->user.groups; cygsid gsid; HANDLE ptok; @@ -2153,6 +2154,7 @@ setegid32 (__gid32_t gid) } myself->gid = gid; + groups->update_pgrp (gsid); /* If impersonated, update primary group and revert */ if (cygheap->user.issetuid ()) { diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index ec0420cc1..f273ee0b1 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -48,9 +48,12 @@ internal_getlogin (cygheap_user &user) &ptok)) system_printf ("OpenProcessToken(): %E\n"); else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz)) - system_printf ("GetTokenInformation(): %E"); + system_printf ("GetTokenInformation (TokenUser): %E"); else if (!(ret = user.set_sid (tu))) system_printf ("Couldn't retrieve SID from access token!"); + else if (!GetTokenInformation (ptok, TokenPrimaryGroup, + &user.groups.pgsid, sizeof tu, &siz)) + system_printf ("GetTokenInformation (TokenPrimaryGroup): %E"); /* We must set the user name, uid and gid. If we have a SID, try to get the corresponding Cygwin password entry. Set user name which can be different @@ -75,11 +78,14 @@ internal_getlogin (cygheap_user &user) primary group to the group in /etc/passwd. */ if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu)) debug_printf ("SetTokenInformation(TokenOwner): %E"); - if (gsid && !SetTokenInformation (ptok, TokenPrimaryGroup, - &gsid, sizeof gsid)) - debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E"); + if (gsid) + { + user.groups.pgsid = gsid; + if (!SetTokenInformation (ptok, TokenPrimaryGroup, + &gsid, sizeof gsid)) + debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E"); + } } - if (ptok != INVALID_HANDLE_VALUE) CloseHandle (ptok); }