[newlib-cygwin] Cygwin: get_user_groups: fetch a user's group list from identification token

Corinna Vinschen corinna@sourceware.org
Fri Feb 22 22:34:00 GMT 2019


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=649911fb40e45bc9a1ad8a3c28d90eec78c9cb7f

commit 649911fb40e45bc9a1ad8a3c28d90eec78c9cb7f
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Fri Feb 22 18:31:03 2019 +0100

    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 <corinna@vinschen.de>

Diff:
---
 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 54182dd..459fe54 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 132265c..7e381f4 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 75b7a9f..0e83f67 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 ()
   {



More information about the Cygwin-cvs mailing list