From 1fcc912f135e11aa78a4ed529c70d6887cfcb317 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 20 May 2001 08:10:47 +0000 Subject: [PATCH] * autoload.cc: Add load statements for `LookupAccountNameW', `LsaClose', `LsaEnumerateAccountRights', `LsaFreeMemory', `LsaOpenPolicy', `LsaQueryInformationPolicy', `NetLocalGroupEnum', `NetLocalGroupGetMembers', `NetServerEnum', `NetUserGetGroups' and `NtCreateToken'. * ntdll.h: Add declaration for `NtCreateToken'. * sec_helper.cc: Add `well_known_local_sid', `well_known_dialup_sid', `well_known_network_sid', `well_known_batch_sid', `well_known_interactive_sid', `well_known_service_sid' and `well_known_authenticated_users_sid'. (cygsid::string): Define as const method. (cygsid::get_sid): Set psid to NO_SID on error. (cygsid::getfromstr): Ditto. (cygsid::getfrompw): Simplify. (cygsid::getfromgr): Check for gr == NULL. (legal_sid_type): Move to security.h. (set_process_privilege): Return -1 on error, otherwise 0 or 1 related to previous privilege setting. * security.cc (extract_nt_dom_user): Remove `static'. (lsa2wchar): New function. (open_local_policy): Ditto. (close_local_policy): Ditto. (get_lsa_srv_inf): Ditto. (get_logon_server): Ditto. (get_logon_server_and_user_domain): Ditto. (get_user_groups): Ditto. (is_group_member): Ditto. (get_user_local_groups): Ditto. (sid_in_token_groups): Ditto. (get_user_primary_group): Ditto. (get_group_sidlist): Ditto. (get_system_priv_list): Ditto. (get_priv_list): Ditto. (get_dacl): Ditto. (create_token): Ditto. (subauth): Return immediately if SE_TCB_NAME can't be assigned. Change all return statements in case of error to jumps to `out' label. Add `out' label to support cleanup. * security.h: Add extern declarations for `well_known_local_sid', `well_known_dialup_sid', `well_known_network_sid', `well_known_batch_sid', `well_known_interactive_sid', `well_known_service_sid' and `well_known_authenticated_users_sid'. Add extern declarations for functions `create_token', `extract_nt_dom_user' and `get_logon_server_and_user_domain'. (class cygsid): Add method `assign'. Change operator= to call new `assign' method. Add `debug_print' method. (class cygsidlist): New class. (legal_sid_type): Moved from sec_helper.cc to here. * spawn.cc (spawn_guts) Revert reversion of previous patch. Call `RevertToSelf' and `ImpersonateLoggedOnUser' instead of `seteuid' again. * syscalls.cc (seteuid): Rearranged. Call `create_token' now when needed. Call `subauth' if `create_token' fails. Try setting token owner and primary group only if token was not explicitely created by `create_token'. * uinfo.cc (internal_getlogin): Try harder to generate correct user information. Especially don't trust return value of `GetUserName'. --- winsup/cygwin/ChangeLog | 60 ++++ winsup/cygwin/autoload.cc | 17 +- winsup/cygwin/ntdll.h | 7 +- winsup/cygwin/sec_helper.cc | 61 ++-- winsup/cygwin/security.cc | 673 +++++++++++++++++++++++++++++++++++- winsup/cygwin/security.h | 105 +++++- winsup/cygwin/spawn.cc | 5 +- winsup/cygwin/syscalls.cc | 223 +++++++----- winsup/cygwin/uinfo.cc | 51 ++- 9 files changed, 1041 insertions(+), 161 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5cb09f361..ac15783f9 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,63 @@ +Sat May 19 23:40:00 2001 Corinna Vinschen + + * autoload.cc: Add load statements for `LookupAccountNameW', + `LsaClose', `LsaEnumerateAccountRights', `LsaFreeMemory', + `LsaOpenPolicy', `LsaQueryInformationPolicy', `NetLocalGroupEnum', + `NetLocalGroupGetMembers', `NetServerEnum', `NetUserGetGroups' and + `NtCreateToken'. + * ntdll.h: Add declaration for `NtCreateToken'. + * sec_helper.cc: Add `well_known_local_sid', `well_known_dialup_sid', + `well_known_network_sid', `well_known_batch_sid', + `well_known_interactive_sid', `well_known_service_sid' and + `well_known_authenticated_users_sid'. + (cygsid::string): Define as const method. + (cygsid::get_sid): Set psid to NO_SID on error. + (cygsid::getfromstr): Ditto. + (cygsid::getfrompw): Simplify. + (cygsid::getfromgr): Check for gr == NULL. + (legal_sid_type): Move to security.h. + (set_process_privilege): Return -1 on error, otherwise 0 or 1 related + to previous privilege setting. + * security.cc (extract_nt_dom_user): Remove `static'. + (lsa2wchar): New function. + (open_local_policy): Ditto. + (close_local_policy): Ditto. + (get_lsa_srv_inf): Ditto. + (get_logon_server): Ditto. + (get_logon_server_and_user_domain): Ditto. + (get_user_groups): Ditto. + (is_group_member): Ditto. + (get_user_local_groups): Ditto. + (sid_in_token_groups): Ditto. + (get_user_primary_group): Ditto. + (get_group_sidlist): Ditto. + (get_system_priv_list): Ditto. + (get_priv_list): Ditto. + (get_dacl): Ditto. + (create_token): Ditto. + (subauth): Return immediately if SE_TCB_NAME can't be assigned. + Change all return statements in case of error to jumps to `out' + label. Add `out' label to support cleanup. + * security.h: Add extern declarations for `well_known_local_sid', + `well_known_dialup_sid', `well_known_network_sid', + `well_known_batch_sid', `well_known_interactive_sid', + `well_known_service_sid' and `well_known_authenticated_users_sid'. + Add extern declarations for functions `create_token', + `extract_nt_dom_user' and `get_logon_server_and_user_domain'. + (class cygsid): Add method `assign'. Change operator= to call new + `assign' method. Add `debug_print' method. + (class cygsidlist): New class. + (legal_sid_type): Moved from sec_helper.cc to here. + * spawn.cc (spawn_guts) Revert reversion of previous patch. + Call `RevertToSelf' and `ImpersonateLoggedOnUser' instead of `seteuid' + again. + * syscalls.cc (seteuid): Rearranged. Call `create_token' now when + needed. Call `subauth' if `create_token' fails. Try setting token + owner and primary group only if token was not explicitely created + by `create_token'. + * uinfo.cc (internal_getlogin): Try harder to generate correct user + information. Especially don't trust return value of `GetUserName'. + Sat May 19 21:16:07 2001 Christopher Faylor * fork.cc (fork_parent): Move atforkprepare call here. diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index 6e20e0be5..9da788957 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -333,9 +333,15 @@ LoadDLLfunc (InitializeSid, 12, advapi32) LoadDLLfunc (IsValidSid, 4, advapi32) LoadDLLfunc (LogonUserA, 24, advapi32) LoadDLLfunc (LookupAccountNameA, 28, advapi32) +LoadDLLfunc (LookupAccountNameW, 28, advapi32) LoadDLLfunc (LookupAccountSidA, 28, advapi32) LoadDLLfunc (LookupPrivilegeValueA, 12, advapi32) -LoadDLLfuncEx (LsaNtStatusToWinError, 4, advapi32, 1) +LoadDLLfunc (LsaClose, 4, advapi32) +LoadDLLfunc (LsaEnumerateAccountRights, 16, advapi32) +LoadDLLfunc (LsaFreeMemory, 4, advapi32) +LoadDLLfunc (LsaNtStatusToWinError, 4, advapi32) +LoadDLLfunc (LsaOpenPolicy, 16, advapi32) +LoadDLLfunc (LsaQueryInformationPolicy, 12, advapi32) LoadDLLfunc (MakeSelfRelativeSD, 12, advapi32) LoadDLLfunc (OpenProcessToken, 12, advapi32) LoadDLLfunc (RegCloseKey, 4, advapi32) @@ -358,10 +364,15 @@ LoadDLLfunc (SetSecurityDescriptorGroup, 12, advapi32) LoadDLLfunc (SetSecurityDescriptorOwner, 12, advapi32) LoadDLLfunc (SetTokenInformation, 16, advapi32) -LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32) -LoadDLLfunc (NetUserGetInfo, 16, netapi32) LoadDLLfunc (NetApiBufferFree, 4, netapi32) +LoadDLLfunc (NetLocalGroupEnum, 28, netapi32) +LoadDLLfunc (NetLocalGroupGetMembers, 32, netapi32) +LoadDLLfunc (NetServerEnum, 36, netapi32) +LoadDLLfunc (NetUserGetGroups, 28, netapi32) +LoadDLLfunc (NetUserGetInfo, 16, netapi32) +LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32) +LoadDLLfuncEx (NtCreateToken, 52, ntdll, 1) LoadDLLfuncEx (NtMapViewOfSection, 40, ntdll, 1) LoadDLLfuncEx (NtOpenSection, 12, ntdll, 1) LoadDLLfuncEx (NtQuerySystemInformation, 16, ntdll, 1) diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 5b9b51453..465d60969 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -136,12 +136,17 @@ typedef struct _SYSTEM_PROCESSES standard Win32 header. */ extern "C" { + NTSTATUS NTAPI NtCreateToken (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, + TOKEN_TYPE, PLUID, PLARGE_INTEGER, PTOKEN_USER, + PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_OWNER, + PTOKEN_PRIMARY_GROUP, PTOKEN_DEFAULT_DACL, + PTOKEN_SOURCE); NTSTATUS NTAPI NtMapViewOfSection (HANDLE, HANDLE, PVOID *, ULONG, ULONG, PLARGE_INTEGER, PULONG, SECTION_INHERIT, ULONG, ULONG); + NTSTATUS NTAPI NtOpenSection (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NTSTATUS NTAPI NtQuerySystemInformation (SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); - NTSTATUS NTAPI NtOpenSection (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID); VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR); ULONG NTAPI RtlNtStatusToDosError (NTSTATUS); diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc index 31672a8cf..264aac4ec 100644 --- a/winsup/cygwin/sec_helper.cc +++ b/winsup/cygwin/sec_helper.cc @@ -44,13 +44,20 @@ SID_IDENTIFIER_AUTHORITY sid_auth[] = { {SECURITY_NT_AUTHORITY} }; -cygsid well_known_admin_sid ("S-1-5-32-544"); -cygsid well_known_system_sid ("S-1-5-18"); -cygsid well_known_creator_owner_sid ("S-1-3-0"); cygsid well_known_world_sid ("S-1-1-0"); +cygsid well_known_local_sid ("S-1-2-0"); +cygsid well_known_creator_owner_sid ("S-1-3-0"); +cygsid well_known_dialup_sid ("S-1-5-1"); +cygsid well_known_network_sid ("S-1-5-2"); +cygsid well_known_batch_sid ("S-1-5-3"); +cygsid well_known_interactive_sid ("S-1-5-4"); +cygsid well_known_service_sid ("S-1-5-6"); +cygsid well_known_authenticated_users_sid ("S-1-5-11"); +cygsid well_known_system_sid ("S-1-5-18"); +cygsid well_known_admin_sid ("S-1-5-32-544"); char * -cygsid::string (char *nsidstr) +cygsid::string (char *nsidstr) const { char t[32]; DWORD i; @@ -74,7 +81,10 @@ cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r) DWORD i; if (s > 5 || cnt < 1 || cnt > 8) - return NULL; + { + psid = NO_SID; + return NULL; + } set (); InitializeSid(psid, &sid_auth[s], cnt); for (i = 0; i < cnt; ++i) @@ -92,7 +102,10 @@ cygsid::getfromstr (const char *nsidstr) DWORD i, r[8]; if (!nsidstr || strncmp (nsidstr, "S-1-", 4)) - return NULL; + { + psid = NO_SID; + return NULL; + } strcpy (sid_buf, nsidstr); @@ -110,17 +123,15 @@ cygsid::getfromstr (const char *nsidstr) BOOL cygsid::getfrompw (struct passwd *pw) { - char *sp = pw->pw_gecos ? strrchr (pw->pw_gecos, ',') : NULL; - - if (!sp) - return FALSE; - return (*this = ++sp) != NULL; + char *sp = (pw && pw->pw_gecos) ? strrchr (pw->pw_gecos, ',') : NULL; + return (*this = sp ? sp + 1 : "") != NULL; } BOOL cygsid::getfromgr (struct group *gr) { - return (*this = gr->gr_passwd) != NULL; + char *sp = (gr && gr->gr_passwd) ? gr->gr_passwd : NULL; + return (*this = sp ?: "") != NULL; } int @@ -238,13 +249,6 @@ cygsid::get_id (BOOL search_grp, int *type) return id; } -static inline BOOL -legal_sid_type (SID_NAME_USE type) -{ - return type == SidTypeUser || type == SidTypeGroup - || type == SidTypeAlias || type == SidTypeWellKnownGroup; -} - BOOL is_grp_member (uid_t uid, gid_t gid) { @@ -338,10 +342,12 @@ set_process_privilege (const char *privilege, BOOL enable) { HANDLE hToken = NULL; LUID restore_priv; - TOKEN_PRIVILEGES new_priv; + TOKEN_PRIVILEGES new_priv, orig_priv; int ret = -1; + DWORD size; - if (!OpenProcessToken (hMainProc, TOKEN_ADJUST_PRIVILEGES, &hToken)) + if (!OpenProcessToken (hMainProc, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, + &hToken)) { __seterrno (); goto out; @@ -357,13 +363,22 @@ set_process_privilege (const char *privilege, BOOL enable) new_priv.Privileges[0].Luid = restore_priv; new_priv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; - if (!AdjustTokenPrivileges (hToken, FALSE, &new_priv, 0, NULL, NULL)) + if (!AdjustTokenPrivileges (hToken, FALSE, &new_priv, + sizeof orig_priv, &orig_priv, &size)) { __seterrno (); goto out; } + /* AdjustTokenPrivileges returns TRUE even if the privilege could not + be enabled. GetLastError() returns an correct error code, though. */ + if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED) + { + debug_printf ("Privilege %s couldn't be assigned", privilege); + __seterrno (); + goto out; + } - ret = 0; + ret = orig_priv.Privileges[0].Attributes == SE_PRIVILEGE_ENABLED ? 1 : 0; out: if (hToken) diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 17bb6dd88..f54fffaec 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -37,6 +37,10 @@ details. */ #include "pinfo.h" #include "cygheap.h" #include "security.h" +#include +#include "ntdll.h" +#include "lm.h" + extern BOOL allow_ntea; BOOL allow_ntsec = FALSE; @@ -57,7 +61,7 @@ cygwin_set_impersonation_token (const HANDLE hToken) } } -static void +void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user) { char buf[INTERNET_MAX_HOST_NAME_LENGTH + UNLEN + 2]; @@ -129,7 +133,7 @@ cygwin_logon_user (const struct passwd *pw, const char *password) static void str2lsa (LSA_STRING &tgt, const char *srcstr) { - tgt.Length = strlen(srcstr); + tgt.Length = strlen (srcstr); tgt.MaximumLength = tgt.Length + 1; tgt.Buffer = (PCHAR) srcstr; } @@ -137,7 +141,7 @@ str2lsa (LSA_STRING &tgt, const char *srcstr) static void str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr) { - tgt.Length = strlen(srcstr); + tgt.Length = strlen (srcstr); tgt.MaximumLength = tgt.Length + 1; tgt.Buffer = (PCHAR) buf; memcpy(buf, srcstr, tgt.MaximumLength); @@ -146,12 +150,644 @@ str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr) static void str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr) { - tgt.Length = strlen(srcstr) * sizeof (WCHAR); + tgt.Length = strlen (srcstr) * sizeof (WCHAR); tgt.MaximumLength = tgt.Length + sizeof(WCHAR); tgt.Buffer = (PWCHAR) buf; mbstowcs (buf, srcstr, tgt.MaximumLength); } +static void +lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size) +{ + size = (size - 1) * sizeof (WCHAR); + if (src.Length < size) + size = src.Length; + memcpy (tgt, src.Buffer, size); + size >>= 1; + tgt[size] = 0; +} + +static LSA_HANDLE +open_local_policy () +{ + LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 }; + LSA_HANDLE lsa = INVALID_HANDLE_VALUE; + + NTSTATUS ret = LsaOpenPolicy(NULL, &oa, POLICY_ALL_ACCESS, &lsa); + if (ret != STATUS_SUCCESS) + set_errno (LsaNtStatusToWinError (ret)); + return lsa; +} + +static void +close_local_policy (LSA_HANDLE &lsa) +{ + if (lsa != INVALID_HANDLE_VALUE) + LsaClose (lsa); + lsa = INVALID_HANDLE_VALUE; +} + +static BOOL +get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain) +{ + NET_API_STATUS ret; + LPSERVER_INFO_101 buf; + DWORD cnt, tot; + char name[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + WCHAR account[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + WCHAR primary[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + PPOLICY_ACCOUNT_DOMAIN_INFO adi; + PPOLICY_PRIMARY_DOMAIN_INFO pdi; + + if ((ret = LsaQueryInformationPolicy (lsa, PolicyAccountDomainInformation, + (PVOID *) &adi)) != STATUS_SUCCESS) + { + set_errno (LsaNtStatusToWinError(ret)); + return FALSE; + } + lsa2wchar (account, adi->DomainName, INTERNET_MAX_HOST_NAME_LENGTH + 1); + LsaFreeMemory (adi); + if ((ret = LsaQueryInformationPolicy (lsa, PolicyPrimaryDomainInformation, + (PVOID *) &pdi)) != STATUS_SUCCESS) + { + set_errno (LsaNtStatusToWinError(ret)); + return FALSE; + } + lsa2wchar (primary, pdi->Name, INTERNET_MAX_HOST_NAME_LENGTH + 1); + LsaFreeMemory (pdi); + if ((ret = NetServerEnum (NULL, 101, (LPBYTE *) &buf, MAX_PREFERRED_LENGTH, + &cnt, &tot, SV_TYPE_DOMAIN_CTRL, primary, NULL)) + == STATUS_SUCCESS && cnt > 0) + { + wcstombs (name, buf[0].sv101_name, INTERNET_MAX_HOST_NAME_LENGTH + 1); + if (domain) + wcstombs (domain, primary, INTERNET_MAX_HOST_NAME_LENGTH + 1); + } + else + { + wcstombs (name, account, INTERNET_MAX_HOST_NAME_LENGTH + 1); + if (domain) + wcstombs (domain, account, INTERNET_MAX_HOST_NAME_LENGTH + 1); + } + if (ret == STATUS_SUCCESS) + NetApiBufferFree (buf); + strcpy (logonserver, "\\\\"); + strcat (logonserver, name); + return TRUE; +} + +static BOOL +get_logon_server (LSA_HANDLE lsa, char *logonserver) +{ + return get_lsa_srv_inf (lsa, logonserver, NULL); +} + +BOOL +get_logon_server_and_user_domain (char *logonserver, char *userdomain) +{ + BOOL ret = FALSE; + LSA_HANDLE lsa = open_local_policy (); + if (lsa) + { + ret = get_lsa_srv_inf (lsa, logonserver, userdomain); + close_local_policy (lsa); + } + return ret; +} + +static BOOL +get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user) +{ + WCHAR wuser[UNLEN + 1]; + mbstowcs (wuser, user, UNLEN + 1); + LPGROUP_USERS_INFO_0 buf; + DWORD cnt, tot; + NET_API_STATUS ret; + + if ((ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf, + MAX_PREFERRED_LENGTH, &cnt, &tot))) + { + debug_printf ("%d = NetUserGetGroups ()", ret); + set_errno (ret); + /* It's no error when the user name can't be found. */ + return ret == NERR_UserNotFound; + } + + for (DWORD i = 0; i < cnt; ++i) + { + cygsid gsid; + char group[UNLEN + 1]; + char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + DWORD glen = UNLEN + 1; + DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + SID_NAME_USE use = SidTypeInvalid; + + wcstombs (group, buf[i].grui0_name, UNLEN + 1); + if (!LookupAccountName (NULL, group, gsid, &glen, domain, &dlen, &use)) + debug_printf ("LookupAccountName(%s): %lu\n", group, GetLastError ()); + if (!legal_sid_type (use)) + { + strcat (strcpy (group, domain), "\\"); + wcstombs (group + strlen (group), buf[i].grui0_name, + UNLEN + 1 - strlen (group)); + glen = UNLEN + 1; + dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + if (!LookupAccountName(NULL, group, gsid, &glen, domain, &dlen, &use)) + debug_printf ("LookupAccountName(%s): %lu\n", group,GetLastError()); + } + if (legal_sid_type (use)) + grp_list += gsid; + } + + NetApiBufferFree (buf); + return TRUE; +} + +static BOOL +is_group_member (WCHAR *wlogonserver, WCHAR *wgroup, + cygsid &usersid, cygsidlist &grp_list) +{ + LPLOCALGROUP_MEMBERS_INFO_0 buf; + DWORD cnt, tot; + BOOL ret = FALSE; + + if (NetLocalGroupGetMembers (wlogonserver, wgroup, 0, (LPBYTE *) &buf, + MAX_PREFERRED_LENGTH, &cnt, &tot, NULL)) + return FALSE; + + for (DWORD bidx = 0; !ret && bidx < cnt; ++bidx) + if (EqualSid (usersid, buf[bidx].lgrmi0_sid)) + ret = TRUE; + else + for (int glidx = 0; !ret && glidx < grp_list.count; ++glidx) + if (EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi0_sid)) + ret = TRUE; + + NetApiBufferFree (buf); + return ret; +} + +static BOOL +get_user_local_groups (WCHAR *wlogonserver, const char *logonserver, + cygsidlist &grp_list, cygsid &usersid) +{ + LPLOCALGROUP_INFO_0 buf; + DWORD cnt, tot; + NET_API_STATUS ret; + + if ((ret = NetLocalGroupEnum (wlogonserver, 0, (LPBYTE *) &buf, + MAX_PREFERRED_LENGTH, &cnt, &tot, NULL))) + { + debug_printf ("%d = NetLocalGroupEnum ()", ret); + set_errno (ret); + return FALSE; + } + + for (DWORD i = 0; i < cnt; ++i) + if (is_group_member (wlogonserver, buf[i].lgrpi0_name, usersid, grp_list)) + { + cygsid gsid; + char group[UNLEN + 1]; + char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + DWORD glen = UNLEN + 1; + DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + SID_NAME_USE use = SidTypeInvalid; + + wcstombs (group, buf[i].lgrpi0_name, UNLEN + 1); + if (!LookupAccountName (NULL, group, gsid, &glen, domain, &dlen, &use)) + { + glen = UNLEN + 1; + dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + if (!LookupAccountName (logonserver + 2, group, + gsid, &glen, domain, &dlen, &use)) + debug_printf ("LookupAccountName(%s): %lu\n", group, + GetLastError ()); + } + else if (!legal_sid_type (use)) + { + strcat (strcpy (group, domain), "\\"); + wcstombs (group + strlen (group), buf[i].lgrpi0_name, + UNLEN + 1 - strlen (group)); + glen = UNLEN + 1; + dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + if (!LookupAccountName (NULL, group, gsid, &glen, + domain, &dlen, &use)) + debug_printf ("LookupAccountName(%s): %lu\n", group, + GetLastError ()); + } + if (legal_sid_type (use)) + grp_list += gsid; + } + + NetApiBufferFree (buf); + return TRUE; +} + +static BOOL +sid_in_token_groups (PTOKEN_GROUPS grps, cygsid &sid) +{ + if (!grps) + return FALSE; + for (DWORD i = 0; i < grps->GroupCount; ++i) + if (sid == grps->Groups[i].Sid) + return TRUE; + return FALSE; +} + +static BOOL +get_user_primary_group (WCHAR *wlogonserver, const char *user, + cygsid &usersid, cygsid &pgrpsid) +{ + LPUSER_INFO_3 buf; + WCHAR wuser[UNLEN + 1]; + BOOL ret = FALSE; + UCHAR count; + + if (usersid == well_known_system_sid) + { + pgrpsid = well_known_system_sid; + return TRUE; + } + + mbstowcs (wuser, user, UNLEN + 1); + if (NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf)) + return FALSE; + pgrpsid = usersid; + if (IsValidSid (pgrpsid) && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1) + { + *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id; + ret = TRUE; + } + NetApiBufferFree (buf); + return ret; +} + +static BOOL +get_group_sidlist (const char *logonserver, cygsidlist &grp_list, + cygsid &usersid, cygsid &pgrpsid, + PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos) +{ + WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + char user[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + DWORD ulen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + SID_NAME_USE use; + + auth_pos = -1; + mbstowcs (wserver, logonserver, INTERNET_MAX_HOST_NAME_LENGTH + 1); + if (!LookupAccountSid (NULL, usersid, user, &ulen, domain, &dlen, &use)) + { + debug_printf ("LookupAccountSid () %E"); + __seterrno (); + return FALSE; + } + grp_list += well_known_world_sid; + if (usersid == well_known_system_sid) + { + grp_list += well_known_system_sid; + grp_list += well_known_admin_sid; + } + 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; + grp_list += well_known_authenticated_users_sid; + } + else + { + grp_list += well_known_local_sid; + grp_list += well_known_interactive_sid; + grp_list += well_known_authenticated_users_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; + } + } + if (!pgrpsid) + get_user_primary_group (wserver, user, usersid, pgrpsid); + if (!get_user_groups (wserver, grp_list, user) || + !get_user_local_groups (wserver, logonserver, grp_list, usersid)) + return FALSE; + if (!grp_list.contains (pgrpsid)) + grp_list += pgrpsid; + return TRUE; +} + +static const char *sys_privs[] = { + SE_TCB_NAME, + SE_ASSIGNPRIMARYTOKEN_NAME, + SE_CREATE_TOKEN_NAME, + SE_CHANGE_NOTIFY_NAME, + SE_SECURITY_NAME, + SE_BACKUP_NAME, + SE_RESTORE_NAME, + SE_SYSTEMTIME_NAME, + SE_SHUTDOWN_NAME, + SE_REMOTE_SHUTDOWN_NAME, + SE_TAKE_OWNERSHIP_NAME, + SE_DEBUG_NAME, + SE_SYSTEM_ENVIRONMENT_NAME, + SE_SYSTEM_PROFILE_NAME, + SE_PROF_SINGLE_PROCESS_NAME, + SE_INC_BASE_PRIORITY_NAME, + SE_LOAD_DRIVER_NAME, + SE_CREATE_PAGEFILE_NAME, + SE_INCREASE_QUOTA_NAME +}; + +#define SYSTEM_PERMISSION_COUNT (sizeof sys_privs / sizeof (const char *)) + +PTOKEN_PRIVILEGES +get_system_priv_list (cygsidlist &grp_list) +{ + LUID priv; + PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (sizeof (ULONG) + + 20 * sizeof (LUID_AND_ATTRIBUTES)); + if (!privs) + { + debug_printf ("malloc (system_privs) failed."); + return NULL; + } + privs->PrivilegeCount = 0; + + for (DWORD i = 0; i < SYSTEM_PERMISSION_COUNT; ++i) + if (LookupPrivilegeValue (NULL, sys_privs[i], &priv)) + { + privs->Privileges[privs->PrivilegeCount].Luid = priv; + privs->Privileges[privs->PrivilegeCount].Attributes = + SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; + ++privs->PrivilegeCount; + } + return privs; +} + +PTOKEN_PRIVILEGES +get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) +{ + PLSA_UNICODE_STRING privstrs; + ULONG cnt; + PTOKEN_PRIVILEGES privs = NULL; + NTSTATUS ret; + char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + + if (usersid == well_known_system_sid) + return get_system_priv_list (grp_list); + + for (int grp = -1; grp < grp_list.count; ++grp) + { + if (grp == -1) + { + if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs, &cnt)) + != STATUS_SUCCESS) + continue; + } + else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp], + &privstrs, &cnt)) + != STATUS_SUCCESS) + continue; + for (ULONG i = 0; i < cnt; ++i) + { + LUID priv; + PTOKEN_PRIVILEGES tmp; + DWORD tmp_count; + + wcstombs (buf, privstrs[i].Buffer, INTERNET_MAX_HOST_NAME_LENGTH + 1); + if (!LookupPrivilegeValue (NULL, buf, &priv)) + continue; + + for (DWORD p = 0; privs && p < privs->PrivilegeCount; ++p) + if (!memcmp (&priv, &privs->Privileges[p].Luid, sizeof (LUID))) + goto next_account_right; + + tmp_count = privs ? privs->PrivilegeCount : 0; + tmp = (PTOKEN_PRIVILEGES) + realloc (privs, sizeof (ULONG) + + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES)); + if (!tmp) + { + if (privs) + free (privs); + LsaFreeMemory (privstrs); + debug_printf ("realloc (privs) failed."); + return NULL; + } + tmp->PrivilegeCount = tmp_count; + privs = tmp; + privs->Privileges[privs->PrivilegeCount].Luid = priv; + privs->Privileges[privs->PrivilegeCount].Attributes = + SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; + ++privs->PrivilegeCount; + + next_account_right: + ; + } + LsaFreeMemory (privstrs); + } + return privs; +} + +#define token_acl_size (sizeof (ACL) + \ + 2 * (sizeof (ACCESS_ALLOWED_ACE) + MAX_SID_LEN)) + +static BOOL +get_dacl (PACL acl, cygsid usersid, cygsidlist &grp_list) +{ + if (!InitializeAcl(acl, token_acl_size, ACL_REVISION)) + { + __seterrno (); + return FALSE; + } + if (grp_list.contains (well_known_admin_sid)) + { + if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL, + well_known_admin_sid)) + { + __seterrno (); + return FALSE; + } + } + else if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL, usersid)) + { + __seterrno (); + return FALSE; + } + if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL, + well_known_system_sid)) + { + __seterrno (); + return FALSE; + } + return TRUE; +} + +HANDLE +create_token (cygsid &usersid, cygsid &pgrpsid) +{ + NTSTATUS ret; + LSA_HANDLE lsa = NULL; + char logonserver[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + int old_priv_state; + + cygsidlist grpsids; + + SECURITY_QUALITY_OF_SERVICE sqos = + { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE }; + OBJECT_ATTRIBUTES oa = + { sizeof oa, 0, 0, 0, 0, &sqos }; + SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE }; + LUID auth_luid = SYSTEM_LUID; + LARGE_INTEGER exp = { 0x7fffffffffffffffLL } ; + + TOKEN_USER user; + PTOKEN_GROUPS grps = NULL; + PTOKEN_PRIVILEGES privs = NULL; + TOKEN_OWNER owner; + TOKEN_PRIMARY_GROUP pgrp; + char acl_buf[token_acl_size]; + TOKEN_DEFAULT_DACL dacl; + TOKEN_SOURCE source; + TOKEN_STATISTICS stats; + memcpy(source.SourceName, "Cygwin.1", 8); + source.SourceIdentifier.HighPart = 0; + source.SourceIdentifier.LowPart = 0x0101; + + HANDLE token; + HANDLE primary_token = INVALID_HANDLE_VALUE; + + HANDLE my_token = INVALID_HANDLE_VALUE; + PTOKEN_GROUPS my_grps = NULL; + DWORD size; + + /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */ + if ((old_priv_state = set_process_privilege (SE_CREATE_TOKEN_NAME)) < 0) + goto out; + + /* Open policy object. */ + if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE) + goto out; + + /* Get logon server. */ + if (!get_logon_server (lsa, logonserver)) + goto out; + + /* User, owner, primary group. */ + user.User.Sid = usersid; + user.User.Attributes = 0; + owner.Owner = usersid; + + /* Retrieve authentication id and group list from own process. */ + if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &my_token)) + debug_printf ("OpenProcessToken(my_token): %E\n"); + else + { + /* Switching user context to SYSTEM doesn't inherit the authentication + 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"); + else + auth_luid = stats.AuthenticationId; + + /* Retrieving current processes group list to be able to inherit + 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, + size, &size)) + { + debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); + free (my_grps); + my_grps = NULL; + } + } + + /* Create list of groups, the user is member in. */ + int auth_pos; + if (!get_group_sidlist (logonserver, grpsids, usersid, pgrpsid, + my_grps, auth_luid, auth_pos)) + goto out; + + /* Primary group. */ + pgrp.PrimaryGroup = pgrpsid; + + /* 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) + { + 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; + } + + /* Retrieve list of privileges of that user. */ + if (!(privs = get_priv_list (lsa, usersid, grpsids))) + goto out; + + /* Create default dacl. */ + if (!get_dacl ((PACL) acl_buf, usersid, grpsids)) + 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); + if (ret) + set_errno (RtlNtStatusToDosError (ret)); + else if (GetLastError () == ERROR_PROC_NOT_FOUND) + { + __seterrno (); + debug_printf ("Loading NtCreateToken failed."); + } + + /* Convert to primary token. */ + if (!DuplicateTokenEx (token, TOKEN_ALL_ACCESS, &sa, + SecurityImpersonation, TokenPrimary, + &primary_token)) + __seterrno (); + +out: + if (old_priv_state >= 0) + set_process_privilege (SE_CREATE_TOKEN_NAME, old_priv_state); + if (token != INVALID_HANDLE_VALUE) + CloseHandle (token); + if (privs) + free (privs); + if (my_grps) + free (my_grps); + close_local_policy (lsa); + + debug_printf ("%d = create_token ()", primary_token); + return primary_token; +} + int subauth_id = 255; HANDLE @@ -177,12 +813,16 @@ subauth (struct passwd *pw) TOKEN_SOURCE ts; PMSV1_0_LM20_LOGON_PROFILE profile; LUID luid; - HANDLE user_token; QUOTA_LIMITS quota; char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; char nt_user[UNLEN + 1]; + SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE }; + HANDLE user_token = INVALID_HANDLE_VALUE; + HANDLE primary_token = INVALID_HANDLE_VALUE; + int old_tcb_state; - set_process_privilege(SE_TCB_NAME); + if ((old_tcb_state = set_process_privilege(SE_TCB_NAME)) < 0) + return INVALID_HANDLE_VALUE; /* Register as logon process. */ str2lsa (name, "Cygwin"); @@ -192,12 +832,12 @@ subauth (struct passwd *pw) { debug_printf ("LsaRegisterLogonProcess: %d", ret); set_errno (LsaNtStatusToWinError(ret)); - return INVALID_HANDLE_VALUE; + goto out; } else if (GetLastError () == ERROR_PROC_NOT_FOUND) { debug_printf ("Couldn't load Secur32.dll"); - return INVALID_HANDLE_VALUE; + goto out; } /* Get handle to MSV1_0 package. */ str2lsa (name, MSV1_0_PACKAGE_NAME); @@ -207,7 +847,7 @@ subauth (struct passwd *pw) debug_printf ("LsaLookupAuthenticationPackage: %d", ret); set_errno (LsaNtStatusToWinError(ret)); LsaDeregisterLogonProcess(lsa_hdl); - return INVALID_HANDLE_VALUE; + goto out; } /* Create origin. */ str2buf2lsa (origin.str, origin.buf, "Cygwin"); @@ -236,20 +876,19 @@ subauth (struct passwd *pw) debug_printf ("LsaLogonUser: %d", ret); set_errno (LsaNtStatusToWinError(ret)); LsaDeregisterLogonProcess(lsa_hdl); - return INVALID_HANDLE_VALUE; + goto out; } LsaFreeReturnBuffer(profile); /* Convert to primary token. */ - SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE }; - HANDLE primary_token; if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa, SecurityImpersonation, TokenPrimary, &primary_token)) - { - CloseHandle (user_token); - return INVALID_HANDLE_VALUE; - } - CloseHandle (user_token); + __seterrno (); + +out: + set_process_privilege(SE_TCB_NAME, old_tcb_state); + if (user_token != INVALID_HANDLE_VALUE) + CloseHandle (user_token); return primary_token; } diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 5f2a38141..c915c1b6c 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -26,6 +26,18 @@ class cygsid { const PSID getfromstr (const char *nsidstr); PSID get_sid (DWORD s, DWORD cnt, DWORD *r); + inline const PSID assign (const PSID nsid) + { + if (!nsid) + psid = NO_SID; + else + { + psid = (PSID) sbuf; + CopySid (MAX_SID_LEN, psid, nsid); + } + return psid; + } + public: inline cygsid () : psid ((PSID) sbuf) {} inline cygsid (const PSID nsid) { *this = nsid; } @@ -40,19 +52,12 @@ public: inline int get_uid () { return get_id (FALSE); } inline int get_gid () { return get_id (TRUE); } - char *string (char *nsidstr); + char *string (char *nsidstr) const; + inline const PSID operator= (cygsid &nsid) + { return assign (nsid); } inline const PSID operator= (const PSID nsid) - { - if (!nsid) - psid = NULL; - else - { - psid = (PSID) sbuf; - CopySid (MAX_SID_LEN, psid, nsid); - } - return psid; - } + { return assign (nsid); } inline const PSID operator= (const char *nsidstr) { return getfromstr (nsidstr); } @@ -73,12 +78,77 @@ public: { return !(*this == nsidstr); } inline operator const PSID () { return psid; } + + void debug_print (const char *prefix = NULL) const + { + char buf[256]; + debug_printf ("%s %s", prefix ?: "", string (buf) ?: "NULL"); + } +}; + +class cygsidlist { +public: + int count; + cygsid *sids; + + cygsidlist () : count (0), sids (NULL) {} + ~cygsidlist () { delete [] sids; } + + BOOL add (cygsid &nsi) + { + 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; + sids[count++] = nsi; + return TRUE; + } + BOOL add (const PSID nsid) { return add (nsid); } + BOOL add (const char *sidstr) + { cygsid nsi (sidstr); return add (nsi); } + + BOOL operator+= (cygsid &si) { return add (si); } + BOOL operator+= (const char *sidstr) { return add (sidstr); } + + BOOL contains (cygsid &sid) const + { + for (int i = 0; i < count; ++i) + if (sids[i] == sid) + return TRUE; + return FALSE; + } + void debug_print (const char *prefix = NULL) const + { + debug_printf ("-- begin sidlist ---"); + if (!count) + debug_printf ("No elements"); + for (int i = 0; i < count; ++i) + sids[i].debug_print (prefix); + debug_printf ("-- ende sidlist ---"); + } }; -extern cygsid well_known_admin_sid; -extern cygsid well_known_system_sid; -extern cygsid well_known_creator_owner_sid; extern cygsid well_known_world_sid; +extern cygsid well_known_local_sid; +extern cygsid well_known_creator_owner_sid; +extern cygsid well_known_dialup_sid; +extern cygsid well_known_network_sid; +extern cygsid well_known_batch_sid; +extern cygsid well_known_interactive_sid; +extern cygsid well_known_service_sid; +extern cygsid well_known_authenticated_users_sid; +extern cygsid well_known_system_sid; +extern cygsid well_known_admin_sid; + +inline BOOL +legal_sid_type (SID_NAME_USE type) +{ + return type == SidTypeUser || type == SidTypeGroup + || type == SidTypeAlias || type == SidTypeWellKnownGroup; +} extern BOOL allow_ntsec; extern BOOL allow_smbntsec; @@ -102,6 +172,13 @@ BOOL __stdcall add_access_denied_ace (PACL acl, int offset, DWORD attributes, PS /* Try a subauthentication. */ HANDLE subauth (struct passwd *pw); +/* Try creating a token directly. */ +HANDLE create_token (cygsid &usersid, cygsid &pgrpsid); + +/* Extract U-domain\user field from passwd entry. */ +void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user); +/* Get default logonserver and domain for this box. */ +BOOL get_logon_server_and_user_domain (char *logonserver, char *domain); /* sec_helper.cc: Security helper functions. */ BOOL __stdcall is_grp_member (uid_t uid, gid_t gid); diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index b49e0f8f4..ccf9ed1f6 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -622,10 +622,9 @@ skip_arg_parsing: : &sec_all_nih; /* Remove impersonation */ - uid_t uid = geteuid (); if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE) - seteuid (cygheap->user.orig_uid); + RevertToSelf (); /* Load users registry hive. */ load_registry_hive (sid); @@ -664,7 +663,7 @@ skip_arg_parsing: if (mode != _P_OVERLAY && mode != _P_VFORK && cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE) - seteuid (uid); + ImpersonateLoggedOnUser (cygheap->user.token); } MALLOC_CHECK; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index e4df8eb3b..48a8d72d2 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1954,109 +1954,156 @@ seteuid (uid_t uid) sigframe thisframe (mainthread); if (os_being_run == winNT) { - if (uid != (uid_t) -1) + if (uid == (uid_t) -1 || uid == myself->uid) { - struct passwd *pw_new = getpwuid (uid); - if (!pw_new) + debug_printf ("new euid == current euid, nothing happens"); + return 0; + } + struct passwd *pw_new = getpwuid (uid); + if (!pw_new) + { + set_errno (EINVAL); + return -1; + } + + if (uid == cygheap->user.orig_uid) + { + debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)", + cygheap->user.token); + RevertToSelf (); + if (cygheap->user.token != INVALID_HANDLE_VALUE) + cygheap->user.impersonated = FALSE; + } + else + { + cygsid usersid, pgrpsid, tok_usersid, tok_pgrpsid; + DWORD siz; + HANDLE sav_token = INVALID_HANDLE_VALUE; + BOOL sav_impersonation; + BOOL explicitely_created_token = FALSE; + + struct group *gr = getgrgid (myself->gid); + debug_printf ("myself->gid: %d, gr: %d", myself->gid, gr); + + usersid.getfrompw (pw_new); + pgrpsid.getfromgr (gr); + + /* Check if new user == user of impersonation token and + - if available - new pgrp == pgrp of impersonation token. */ + if (cygheap->user.token != INVALID_HANDLE_VALUE) { - set_errno (EINVAL); - return -1; + if (!GetTokenInformation (cygheap->user.token, TokenUser, + &tok_usersid, sizeof tok_usersid, &siz)) + { + debug_printf ("GetTokenInformation(): %E"); + tok_usersid = NO_SID; + } + if (!GetTokenInformation (cygheap->user.token, TokenPrimaryGroup, + &tok_pgrpsid, sizeof tok_pgrpsid, &siz)) + { + debug_printf ("GetTokenInformation(): %E"); + tok_pgrpsid = NO_SID; + } + if ((usersid && tok_usersid && usersid != tok_usersid) || + (pgrpsid && tok_pgrpsid && pgrpsid != tok_pgrpsid)) + { + /* If not, RevertToSelf and close old token. */ + debug_printf ("tsid != usersid"); + RevertToSelf (); + sav_token = cygheap->user.token; + sav_impersonation = cygheap->user.impersonated; + cygheap->user.token = INVALID_HANDLE_VALUE; + cygheap->user.impersonated = FALSE; + } } - if (uid != myself->uid) + /* If no impersonation token is available, try to + authenticate using NtCreateToken() or subauthentication. */ + if (cygheap->user.token == INVALID_HANDLE_VALUE) { - if (uid == cygheap->user.orig_uid) - { - debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)", - cygheap->user.token); - RevertToSelf (); - if (cygheap->user.token != INVALID_HANDLE_VALUE) - cygheap->user.impersonated = FALSE; - } + HANDLE ptok = INVALID_HANDLE_VALUE; + + ptok = create_token (usersid, pgrpsid); + if (ptok != INVALID_HANDLE_VALUE) + explicitely_created_token = TRUE; else { - cygsid tsid, psid, gsid; - DWORD siz; - - /* Check if new user == user of impersonation token. */ - if (cygheap->user.token != INVALID_HANDLE_VALUE) + /* create_token failed. Try subauthentication. */ + debug_printf ("create token failed, try subauthentication."); + ptok = subauth (pw_new); + } + if (ptok != INVALID_HANDLE_VALUE) + { + cygwin_set_impersonation_token (ptok); + /* If sav_token was internally created, destroy it. */ + if (sav_token != INVALID_HANDLE_VALUE) { - if (!GetTokenInformation (cygheap->user.token, TokenUser, - &tsid, sizeof tsid, &siz)) + TOKEN_SOURCE ts; + if (!GetTokenInformation (sav_token, TokenSource, + &ts, sizeof ts, &siz)) debug_printf ("GetTokenInformation(): %E"); - else if (psid.getfrompw (pw_new) && tsid != psid) - { - /* If not, RevertToSelf and close old token. */ - char tstr[256], pstr[256]; - debug_printf ("tsid (%s) != psid (%s)", - tsid.string (tstr), psid.string (pstr)); - RevertToSelf (); - cygwin_set_impersonation_token (INVALID_HANDLE_VALUE); - } + else if (!memcmp (ts.SourceName, "Cygwin.1", 8)) + CloseHandle (sav_token); } - /* If no impersonation token is available, try to - authenticate using subauthentication. */ - if (cygheap->user.token == INVALID_HANDLE_VALUE) - { - HANDLE ptok = subauth (pw_new); - if (ptok != INVALID_HANDLE_VALUE) - cygwin_set_impersonation_token (ptok); - else - cygheap->user.impersonated = TRUE; - } - /* If no impersonation is active but an impersonation - token is available, try to impersonate. */ - if (cygheap->user.token != INVALID_HANDLE_VALUE && - !cygheap->user.impersonated) - { - debug_printf ("Impersonate (uid == %d)", uid); - RevertToSelf (); + } + else if (sav_token != INVALID_HANDLE_VALUE) + cygheap->user.token = sav_token; + } + /* If no impersonation is active but an impersonation + token is available, try to impersonate. */ + if (cygheap->user.token != INVALID_HANDLE_VALUE && + !cygheap->user.impersonated) + { + debug_printf ("Impersonate (uid == %d)", uid); + RevertToSelf (); - struct group *gr; + /* If the token was explicitely created, all information has + already been set correctly. */ + if (!explicitely_created_token) + { + /* Try setting owner to same value as user. */ + if (usersid && + !SetTokenInformation (cygheap->user.token, TokenOwner, + &usersid, sizeof usersid)) + debug_printf ("SetTokenInformation(user.token, " + "TokenOwner): %E"); + /* Try setting primary group in token to current group + if token not explicitely created. */ + if (pgrpsid && + !SetTokenInformation (cygheap->user.token, + TokenPrimaryGroup, + &pgrpsid, sizeof pgrpsid)) + debug_printf ("SetTokenInformation(user.token, " + "TokenPrimaryGroup): %E"); - /* Try setting owner to same value as user. */ - if (!SetTokenInformation (cygheap->user.token, - TokenOwner, - &tsid, sizeof tsid)) - debug_printf ("SetTokenInformation(user.token, " - "TokenOwner): %E"); - /* Try setting primary group in token to current group. */ - if ((gr = getgrgid (myself->gid)) && - gsid.getfromgr (gr) && - !SetTokenInformation (cygheap->user.token, - TokenPrimaryGroup, - &gsid, sizeof gsid)) - debug_printf ("SetTokenInformation(user.token, " - "TokenPrimaryGroup): %E"); + } - /* Now try to impersonate. */ - if (!ImpersonateLoggedOnUser (cygheap->user.token)) - system_printf ("Impersonating (%d) in set(e)uid " - "failed: %E", cygheap->user.token); - else - cygheap->user.impersonated = TRUE; - } - } - - cygheap_user user; - /* user.token is used in internal_getlogin () to determine if - impersonation is active. If so, the token is used for - retrieving user's SID. */ - user.token = cygheap->user.impersonated ? cygheap->user.token - : INVALID_HANDLE_VALUE; - struct passwd *pw_cur = internal_getlogin (user); - if (pw_cur != pw_new) - { - debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d", - cygheap->user.token, pw_cur->pw_uid, - pw_new->pw_uid, cygheap->user.orig_uid); - set_errno (EPERM); - return -1; - } - myself->uid = uid; - cygheap->user = user; + /* Now try to impersonate. */ + if (!ImpersonateLoggedOnUser (cygheap->user.token)) + system_printf ("Impersonating (%d) in set(e)uid failed: %E", + cygheap->user.token); + else + cygheap->user.impersonated = TRUE; } } + + cygheap_user user; + /* user.token is used in internal_getlogin () to determine if + impersonation is active. If so, the token is used for + retrieving user's SID. */ + user.token = cygheap->user.impersonated ? cygheap->user.token + : INVALID_HANDLE_VALUE; + struct passwd *pw_cur = internal_getlogin (user); + if (pw_cur != pw_new) + { + debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d", + cygheap->user.token, pw_cur->pw_uid, + pw_new->pw_uid, cygheap->user.orig_uid); + set_errno (EPERM); + return -1; + } + myself->uid = uid; + cygheap->user = user; } else set_errno (ENOSYS); diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index aea8fece4..0bb947df0 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -38,12 +38,15 @@ internal_getlogin (cygheap_user &user) user.set_name ("unknown"); else user.set_name (username); + debug_printf ("GetUserName() = %s", user.name ()); if (os_being_run == winNT) { LPWKSTA_USER_INFO_1 wui; - char buf[MAX_PATH], *env; - char *un = NULL; + NET_API_STATUS ret; + char buf[512]; + char dom[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + char *env, *un = NULL; /* First trying to get logon info from environment */ if ((env = getenv ("USERNAME")) != NULL) @@ -58,10 +61,8 @@ internal_getlogin (cygheap_user &user) debug_printf ("Domain: %s, Logon Server: %s", user.domain (), user.logsrv ()); /* If that failed, try to get that info from NetBIOS */ - else if (!NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&wui)) + else if (!(ret = NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&wui))) { - char buf[512]; /* Bigger than each of the below defines. */ - sys_wcstombs (buf, wui->wkui1_username, UNLEN + 1); user.set_name (buf); sys_wcstombs (buf, wui->wkui1_logon_server, @@ -112,6 +113,22 @@ internal_getlogin (cygheap_user &user) user.domain (), user.logsrv (), user.name ()); NetApiBufferFree (wui); } + else + { + /* If `NetWkstaUserGetInfo' failed, try to get default values known + by local policy object.*/ + debug_printf ("NetWkstaUserGetInfo() Err %d", ret); + + if (get_logon_server_and_user_domain (buf, dom)) + { + user.set_logsrv (buf + 2); + user.set_domain (dom); + setenv ("LOGONSERVER", buf, 1); + setenv ("USERDOMAIN", dom, 1); + } + else + debug_printf ("get_logon_server_and_user_domain() failed"); + } if (allow_ntsec) { HANDLE ptok = user.token; /* Which is INVALID_HANDLE_VALUE if no @@ -147,7 +164,7 @@ internal_getlogin (cygheap_user &user) /* If that fails, too, as a last resort try to get the SID from the logon server. */ if (!ret && !(ret = lookup_name (user.name (), user.logsrv (), - user.sid ()))) + user.sid ()))) debug_printf ("Couldn't retrieve SID from '%s'!", user.logsrv ()); /* If we have a SID, try to get the corresponding Cygwin user name @@ -157,12 +174,6 @@ internal_getlogin (cygheap_user &user) { cygsid psid; - if (!strcasematch (user.name (), "SYSTEM") - && user.domain () && user.logsrv ()) - { - if (get_registry_hive_path (user.sid (), buf)) - setenv ("USERPROFILE", buf, 1); - } for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx) if (psid.getfrompw (pw) && EqualSid (user.sid (), psid)) { @@ -171,8 +182,24 @@ internal_getlogin (cygheap_user &user) if (gr) if (!gsid.getfromgr (gr)) gsid = NO_SID; + extract_nt_dom_user (pw, dom, buf); + setenv ("USERNAME", buf, 1); + if (*dom) + user.set_domain (dom); + else if (user.logsrv ()) + user.set_domain (user.logsrv ()); + if (user.domain ()) + setenv ("USERDOMAIN", user.domain (), 1); break; } + if (!strcasematch (user.name (), "SYSTEM") + && user.domain () && user.logsrv ()) + { + if (get_registry_hive_path (user.sid (), buf)) + setenv ("USERPROFILE", buf, 1); + else + unsetenv ("USERPROFILE"); + } } /* If this process is started from a non Cygwin process,