From 649911fb40e45bc9a1ad8a3c28d90eec78c9cb7f Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 22 Feb 2019 18:31:03 +0100 Subject: [PATCH] Cygwin: get_user_groups: fetch a user's group list from identification token NetUserGetGroups and NetUserGetLocalGroups sometimes take a lot of time (up to more than 2 mins) for no apparent reason. Call s4uauth to generate an identification token for the user and fetch the group list from there. This is *much* faster. Keep the old code only for the sake of WOW64 on Vista and Windows 7, which don't implement MsV1_0S4ULogon. Signed-off-by: Corinna Vinschen --- winsup/cygwin/sec_auth.cc | 83 ++++++++++++++++++++++++++------------- winsup/cygwin/wincap.cc | 10 +++++ winsup/cygwin/wincap.h | 2 + 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/winsup/cygwin/sec_auth.cc b/winsup/cygwin/sec_auth.cc index 54182dd6c..459fe5420 100644 --- a/winsup/cygwin/sec_auth.cc +++ b/winsup/cygwin/sec_auth.cc @@ -535,7 +535,6 @@ get_server_groups (cygsidlist &grp_list, PSID usersid, { WCHAR user[UNLEN + 1]; WCHAR domain[MAX_DOMAIN_NAME_LEN + 1]; - WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; DWORD ulen = UNLEN + 1; DWORD dlen = MAX_DOMAIN_NAME_LEN + 1; SID_NAME_USE use; @@ -546,41 +545,73 @@ get_server_groups (cygsidlist &grp_list, PSID usersid, return true; } - grp_list *= well_known_world_sid; - grp_list *= well_known_authenticated_users_sid; - if (!LookupAccountSidW (NULL, usersid, user, &ulen, domain, &dlen, &use)) { __seterrno (); return false; } /* If the SID does NOT start with S-1-5-21, the domain is some builtin - domain. The search for a logon server and fetching group accounts - is moot. */ + domain. We don't fetch a group list then. */ if (sid_id_auth (usersid) == 5 /* SECURITY_NT_AUTHORITY */ - && sid_sub_auth (usersid, 0) == SECURITY_NT_NON_UNIQUE - && get_logon_server (domain, server, DS_IS_FLAT_NAME)) + && sid_sub_auth (usersid, 0) == SECURITY_NT_NON_UNIQUE) { - if (check_account_disabled == CHK_DISABLED) + if (wincap.no_msv1_0_s4u_logon_in_wow64 ()) { - NET_API_STATUS napi_stat; - USER_INFO_1 *ui1; - bool allow_user = false; - - napi_stat = NetUserGetInfo (server, user, 1, (LPBYTE *) &ui1); - if (napi_stat == NERR_Success) - allow_user = !(ui1->usri1_flags & (UF_ACCOUNTDISABLE | UF_LOCKOUT)); - if (ui1) - NetApiBufferFree (ui1); - if (!allow_user) + WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; + + if (!get_logon_server (domain, server, DS_IS_FLAT_NAME)) + return false; + if (check_account_disabled == CHK_DISABLED) { - debug_printf ("User denied: %W\\%W", domain, user); - set_errno (EACCES); - return false; + NET_API_STATUS napi_stat; + USER_INFO_1 *ui1; + bool allow_user = false; + + napi_stat = NetUserGetInfo (server, user, 1, (LPBYTE *) &ui1); + if (napi_stat == NERR_Success) + allow_user = !(ui1->usri1_flags & (UF_ACCOUNTDISABLE | UF_LOCKOUT)); + if (ui1) + NetApiBufferFree (ui1); + if (!allow_user) + { + debug_printf ("User denied: %W\\%W", domain, user); + set_errno (EACCES); + return false; + } } + grp_list *= well_known_world_sid; + grp_list *= well_known_authenticated_users_sid; + get_user_groups (server, grp_list, user, domain); + get_user_local_groups (domain, grp_list, user); + return true; } - get_user_groups (server, grp_list, user, domain); - get_user_local_groups (domain, grp_list, user); + + tmp_pathbuf tp; + HANDLE token; + NTSTATUS status; + PTOKEN_GROUPS groups; + ULONG size; + + token = s4uauth (false, domain, user, status); + if (!token) + return false; + + groups = (PTOKEN_GROUPS) tp.w_get (); + status = NtQueryInformationToken (token, TokenGroups, groups, + 2 * NT_MAX_PATH, &size); + if (NT_SUCCESS (status)) + for (DWORD pg = 0; pg < groups->GroupCount; ++pg) + { + if (groups->Groups[pg].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) + continue; + cygpsid grpsid = groups->Groups[pg].Sid; + if (sid_id_auth (grpsid) == 5 /* SECURITY_NT_AUTHORITY */ + && sid_sub_auth (grpsid, 0) == SECURITY_NT_NON_UNIQUE) + grp_list += grpsid; + else + grp_list *= grpsid; + } + NtClose (token); } return true; } @@ -589,8 +620,6 @@ static bool get_initgroups_sidlist (cygsidlist &grp_list, PSID usersid, PSID pgrpsid, PTOKEN_GROUPS my_grps) { - grp_list *= well_known_world_sid; - grp_list *= well_known_authenticated_users_sid; if (well_known_system_sid != usersid) get_token_group_sidlist (grp_list, my_grps); if (!get_server_groups (grp_list, usersid, CHK_DISABLED)) @@ -605,8 +634,6 @@ static bool get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, PTOKEN_GROUPS my_grps, user_groups &groups) { - tmp_list *= well_known_world_sid; - tmp_list *= well_known_authenticated_users_sid; get_token_group_sidlist (tmp_list, my_grps); if (!get_server_groups (tmp_list, usersid, CHK_DISABLED)) return false; diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 132265c6a..7e381f420 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -39,6 +39,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { has_posix_unlink_semantics:false, has_case_sensitive_dirs:false, has_posix_rename_semantics:false, + no_msv1_0_s4u_logon_in_wow64:true, }, }; @@ -63,6 +64,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { has_posix_unlink_semantics:false, has_case_sensitive_dirs:false, has_posix_rename_semantics:false, + no_msv1_0_s4u_logon_in_wow64:true, }, }; @@ -87,6 +89,7 @@ wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = { has_posix_unlink_semantics:false, has_case_sensitive_dirs:false, has_posix_rename_semantics:false, + no_msv1_0_s4u_logon_in_wow64:false, }, }; @@ -111,6 +114,7 @@ wincaps wincap_10_1507 __attribute__((section (".cygwin_dll_common"), shared)) has_posix_unlink_semantics:false, has_case_sensitive_dirs:false, has_posix_rename_semantics:false, + no_msv1_0_s4u_logon_in_wow64:false, }, }; @@ -135,6 +139,7 @@ wincaps wincap_10_1511 __attribute__((section (".cygwin_dll_common"), shared)) = has_posix_unlink_semantics:false, has_case_sensitive_dirs:false, has_posix_rename_semantics:false, + no_msv1_0_s4u_logon_in_wow64:false, }, }; @@ -159,6 +164,7 @@ wincaps wincap_10_1703 __attribute__((section (".cygwin_dll_common"), shared)) = has_posix_unlink_semantics:false, has_case_sensitive_dirs:false, has_posix_rename_semantics:false, + no_msv1_0_s4u_logon_in_wow64:false, }, }; @@ -183,6 +189,7 @@ wincaps wincap_10_1709 __attribute__((section (".cygwin_dll_common"), shared)) = has_posix_unlink_semantics:true, has_case_sensitive_dirs:false, has_posix_rename_semantics:false, + no_msv1_0_s4u_logon_in_wow64:false, }, }; @@ -207,6 +214,7 @@ wincaps wincap_10_1803 __attribute__((section (".cygwin_dll_common"), shared)) = has_posix_unlink_semantics:true, has_case_sensitive_dirs:true, has_posix_rename_semantics:false, + no_msv1_0_s4u_logon_in_wow64:false, }, }; @@ -231,6 +239,7 @@ wincaps wincap_10_1809 __attribute__((section (".cygwin_dll_common"), shared)) = has_posix_unlink_semantics:true, has_case_sensitive_dirs:true, has_posix_rename_semantics:true, + no_msv1_0_s4u_logon_in_wow64:true, }, }; @@ -303,6 +312,7 @@ wincapc::init () ((wincaps *)caps)->needs_count_in_si_lpres2 = false; ((wincaps *)caps)->has_gaa_largeaddress_bug = false; ((wincaps *)caps)->has_broken_prefetchvm = false; + ((wincaps *)caps)->no_msv1_0_s4u_logon_in_wow64 = false; } __small_sprintf (osnam, "NT-%d.%d", version.dwMajorVersion, diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index 75b7a9f0a..0e83f6794 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -33,6 +33,7 @@ struct wincaps unsigned has_posix_unlink_semantics : 1; unsigned has_case_sensitive_dirs : 1; unsigned has_posix_rename_semantics : 1; + unsigned no_msv1_0_s4u_logon_in_wow64 : 1; }; }; @@ -87,6 +88,7 @@ public: bool IMPLEMENT (has_posix_unlink_semantics) bool IMPLEMENT (has_case_sensitive_dirs) bool IMPLEMENT (has_posix_rename_semantics) + bool IMPLEMENT (no_msv1_0_s4u_logon_in_wow64) void disable_case_sensitive_dirs () { -- 2.43.5