From eb7ffd4130fc5ddb655e0eb8e5375052cd96d69b Mon Sep 17 00:00:00 2001 From: Richard Glidden Date: Thu, 24 Aug 2023 13:36:10 -0400 Subject: [PATCH] msys2-runtime: restore fast path for current user primary group Commit a5bcfe616c7e removed an optimization that fetches the default group from the current user token, as it is sometimes not accurate such as when groups like the builtin Administrators group is the primary group. However, removing this optimization causes extremely poor performance when connected to some Active Directory environments. Restored this optimization as the default behaviour, and added a `group: db-accurate` option to `nsswitch.conf` that can be used to disable the optimization in cases where accurate group information is required. This fixes https://github.com/git-for-windows/git/issues/4459 Signed-off-by: Richard Glidden --- winsup/cygwin/include/sys/cygwin.h | 3 ++- winsup/cygwin/local_includes/cygheap.h | 1 + winsup/cygwin/uinfo.cc | 30 ++++++++++++++++++++------ winsup/doc/ntsec.xml | 20 ++++++++++++++++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 6383646cc7..6b2f647724 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -219,7 +219,8 @@ enum enum { NSS_SRC_FILES = 1, - NSS_SRC_DB = 2 + NSS_SRC_DB = 2, + NSS_SRC_DB_ACCURATE = 4 }; /* Enumeration source constants for CW_SETENT called from mkpasswd/mkgroup. */ diff --git a/winsup/cygwin/local_includes/cygheap.h b/winsup/cygwin/local_includes/cygheap.h index f5aecba37a..c33f378500 100644 --- a/winsup/cygwin/local_includes/cygheap.h +++ b/winsup/cygwin/local_includes/cygheap.h @@ -454,6 +454,7 @@ class cygheap_pwdgrp inline int nss_pwd_src () const { return pwd_src; } /* CW_GETNSS_PWD_SRC */ inline bool nss_grp_files () const { return !!(grp_src & NSS_SRC_FILES); } inline bool nss_grp_db () const { return !!(grp_src & NSS_SRC_DB); } + inline bool nss_grp_db_accurate () const { return !!(grp_src & NSS_SRC_DB_ACCURATE); } inline int nss_grp_src () const { return grp_src; } /* CW_GETNSS_GRP_SRC */ inline bool nss_cygserver_caching () const { return caching; } inline void nss_disable_cygserver_caching () { caching = false; } diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index a25f39f427..fefd984f84 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -637,6 +637,11 @@ cygheap_pwdgrp::nss_init_line (const char *line) *src |= NSS_SRC_DB; c += 2; } + else if (NSS_CMP ("db-accurate")) + { + *src |= NSS_SRC_DB | NSS_SRC_DB_ACCURATE; + c += 11; + } else { c += strcspn (c, " \t"); @@ -1906,6 +1911,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) gid_t gid = ILLEGAL_GID; bool is_domain_account = true; PCWSTR domain = NULL; + bool get_default_group_from_current_user_token = false; char *shell = NULL; char *home = NULL; char *gecos = NULL; @@ -2371,9 +2377,19 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) uid = posix_offset + sid_sub_auth_rid (sid); if (!is_group () && acc_type == SidTypeUser) { - /* Default primary group. Make the educated guess that the user - is in group "Domain Users" or "None". */ - gid = posix_offset + DOMAIN_GROUP_RID_USERS; + /* Default primary group. If the sid is the current user, and + we are not configured for accurate mode, fetch + the default group from the current user token, otherwise make + the educated guess that the user is in group "Domain Users" + or "None". */ + if (!cygheap->pg.nss_grp_db_accurate() && sid == cygheap->user.sid ()) + { + get_default_group_from_current_user_token = true; + gid = posix_offset + + sid_sub_auth_rid (cygheap->user.groups.pgsid); + } + else + gid = posix_offset + DOMAIN_GROUP_RID_USERS; } if (is_domain_account) @@ -2384,9 +2400,11 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) /* On AD machines, use LDAP to fetch domain account infos. */ if (cygheap->dom.primary_dns_name ()) { - /* Fetch primary group from AD and overwrite the one we - just guessed above. */ - if (cldap->fetch_ad_account (sid, false, domain)) + /* For the current user we got correctly cased username and + the primary group via process token. For any other user + we fetch it from AD and overwrite it. */ + if (!get_default_group_from_current_user_token + && cldap->fetch_ad_account (sid, false, domain)) { if ((val = cldap->get_account_name ())) wcscpy (name, val); diff --git a/winsup/doc/ntsec.xml b/winsup/doc/ntsec.xml index c6871ecf05..c95207e72a 100644 --- a/winsup/doc/ntsec.xml +++ b/winsup/doc/ntsec.xml @@ -930,7 +930,16 @@ The two lines starting with the keywords passwd: and information from. files means, fetch the information from the corresponding file in the /etc directory. db means, fetch the information from the Windows account databases, the SAM -for local accounts, Active Directory for domain account. Examples: +for local accounts, Active Directory for domain account. For the current +user, the default group is obtained from the current user token to avoid +additional lookups to the group database. db-accuarte +is only valid on group: line, and performs the same +lookups as the db option, but disables using the +current user token to retrieve the default group as this optimization +is not accurate in all cases. For example, if you run a native process +with the primary group set to the Administrators builtin group, the +db option will return a non-existent group as primary +group. Examples: @@ -949,6 +958,15 @@ Read passwd entries only from /etc/passwd. Read group entries only from SAM/AD. + + group: db-accurate + + + +Read group entries only from SAM/AD. Force the use of the group database +for the current user. + + group: files # db