]> git.ipfire.org Git - thirdparty/pciutils.git/commitdiff
windows: Improve win32_change_token()
authorPali Rohár <pali@kernel.org>
Sun, 30 Nov 2025 13:19:52 +0000 (14:19 +0100)
committerMartin Mareš <mj@ucw.cz>
Sun, 28 Dec 2025 20:49:06 +0000 (21:49 +0100)
Function ImpersonateLoggedOnUser() is not available on older Windows
versions.

Instead of ImpersonateLoggedOnUser(), use SetThreadToken() on the
duplicated token of SecurityImpersonation type, same what is
ImpersonateLoggedOnUser() expected to do.

lib/win32-helpers.c

index acc1f9277fe1cd0770cd6d8223fe2818777675b6..24a731d53d020e3531a08c9ecf1df2d800a66b20 100644 (file)
@@ -573,23 +573,41 @@ set_privilege(HANDLE token, LUID luid_privilege, BOOL enable)
 BOOL
 win32_change_token(HANDLE new_token, HANDLE *old_token)
 {
-  HANDLE token;
+  HANDLE current_token;
+  HANDLE impersonate_token;
 
-  if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &token))
+  if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &current_token))
     {
       if (GetLastError() != ERROR_NO_TOKEN)
         return FALSE;
-      token = NULL;
+      current_token = NULL;
     }
 
-  if (!ImpersonateLoggedOnUser(new_token))
+  /*
+   * SetThreadToken() can set only impersonation token, not the primary token
+   * (which caller passed as argument). Function DuplicateToken() can be used
+   * to create a new impersonation token as duplicate of the primary token.
+   */
+  if (!DuplicateToken(new_token, SecurityImpersonation, &impersonate_token))
     {
-      if (token)
-        CloseHandle(token);
+      if (current_token)
+        CloseHandle(current_token);
       return FALSE;
     }
 
-  *old_token = token;
+  /*
+   * NULL argument for SetThreadToken() specifies the current thread.
+   * If thread handle argument is value returned GetCurrentThread() then
+   * SetThreadToken() function crashes on older Windows versions.
+   */
+  if (!SetThreadToken(NULL, impersonate_token))
+    {
+      if (current_token)
+        CloseHandle(current_token);
+      return FALSE;
+    }
+
+  *old_token = current_token;
   return TRUE;
 }