]> mj.ucw.cz Git - pciutils.git/commitdiff
windows: Move common non-I/O port code from i386-io-windows.h to win32-helpers.c
authorPali Rohár <pali@kernel.org>
Mon, 8 May 2023 12:04:40 +0000 (14:04 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 18 Feb 2024 14:48:29 +0000 (15:48 +0100)
lib/i386-io-windows.h
lib/win32-helpers.c
lib/win32-helpers.h
lib/win32-kldbg.c
lib/win32-sysdbg.c

index 69ed8215c4d51f9e6dfdcbd5b7e902d8601419af..eff1901ca00f794f3a32f0bbbed2ed4f5c4d409b 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <windows.h>
-#include <aclapi.h>
 #include "win32-helpers.h"
 
 #include "i386-io-access.h"
@@ -71,42 +70,11 @@ __readeflags(void)
 /* Read IOPL of the current process, IOPL is stored in eflag bits [13:12]. */
 #define read_iopl() ((__readeflags() >> 12) & 0x3)
 
-/* Unfortunately i586-mingw32msvc toolchain does not provide this constant. */
-#ifndef PROCESS_QUERY_LIMITED_INFORMATION
-#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
-#endif
-
 /* Unfortunately some toolchains do not provide this constant. */
 #ifndef SE_IMPERSONATE_NAME
 #define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege")
 #endif
 
-/*
- * These psapi functions are available in kernel32.dll library with K32 prefix
- * on Windows 7 and higher systems. On older Windows systems these functions are
- * available in psapi.dll libary without K32 prefix. So resolve pointers to
- * these functions dynamically at runtime from the available system library.
- * Function GetProcessImageFileNameW() is not available on Windows 2000 and
- * older systems.
- */
-typedef BOOL (WINAPI *EnumProcessesProt)(DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded);
-typedef DWORD (WINAPI *GetProcessImageFileNameWProt)(HANDLE hProcess, LPWSTR lpImageFileName, DWORD nSize);
-typedef DWORD (WINAPI *GetModuleFileNameExWProt)(HANDLE hProcess, HMODULE hModule, LPWSTR lpImageFileName, DWORD nSize);
-
-/*
- * These aclapi functions are available in advapi.dll library on Windows NT 4.0
- * and higher systems.
- */
-typedef DWORD (WINAPI *GetSecurityInfoProt)(HANDLE handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID *ppsidOwner, PSID *ppsidGroup, PACL *ppDacl, PACL *ppSacl, PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
-typedef DWORD (WINAPI *SetSecurityInfoProt)(HANDLE handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl);
-typedef DWORD (WINAPI *SetEntriesInAclProt)(ULONG cCountOfExplicitEntries, PEXPLICIT_ACCESS pListOfExplicitEntries, PACL OldAcl, PACL *NewAcl);
-
-/*
- * This errhandlingapi function is available in kernel32.dll library on
- * Windows 7 and higher systems.
- */
-typedef BOOL (WINAPI *SetThreadErrorModeProt)(DWORD dwNewMode, LPDWORD lpOldMode);
-
 /*
  * Unfortunately NtSetInformationProcess() function, ProcessUserModeIOPL
  * constant and all other helpers for its usage are not specified in any
@@ -132,859 +100,6 @@ typedef BOOL (WINAPI *SetThreadErrorModeProt)(DWORD dwNewMode, LPDWORD lpOldMode
 typedef NTSTATUS (NTAPI *NtSetInformationProcessProt)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength);
 typedef ULONG (NTAPI *RtlNtStatusToDosErrorProt)(NTSTATUS Status);
 
-/*
- * Check if the current thread has particular privilege in current active access
- * token. Case when it not possible to determinate it (e.g. current thread does
- * not have permission to open its own current active access token) is evaluated
- * as thread does not have that privilege.
- */
-static BOOL
-have_privilege(LUID luid_privilege)
-{
-  PRIVILEGE_SET priv;
-  HANDLE token;
-  BOOL ret;
-
-  /*
-   * If the current thread does not have active access token then thread
-   * uses primary process access token for all permission checks.
-   */
-  if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &token) &&
-      (GetLastError() != ERROR_NO_TOKEN ||
-       !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)))
-    return FALSE;
-
-  priv.PrivilegeCount = 1;
-  priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
-  priv.Privilege[0].Luid = luid_privilege;
-  priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
-
-  if (!PrivilegeCheck(token, &priv, &ret))
-    return FALSE;
-
-  return ret;
-}
-
-/*
- * Enable or disable particular privilege in specified access token.
- *
- * Note that it is not possible to disable privilege in access token with
- * SE_PRIVILEGE_ENABLED_BY_DEFAULT attribute. This function does not check
- * this case and incorrectly returns no error even when disabling failed.
- * Rationale for this decision: Simplification of this function as WinAPI
- * call AdjustTokenPrivileges() does not signal error in this case too.
- */
-static BOOL
-set_privilege(HANDLE token, LUID luid_privilege, BOOL enable)
-{
-  TOKEN_PRIVILEGES token_privileges;
-
-  token_privileges.PrivilegeCount = 1;
-  token_privileges.Privileges[0].Luid = luid_privilege;
-  token_privileges.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
-
-  /*
-   * WinAPI function AdjustTokenPrivileges() success also when not all
-   * privileges were enabled. It is always required to check for failure
-   * via GetLastError() call. AdjustTokenPrivileges() always sets error
-   * also when it success, as opposite to other WinAPI functions.
-   */
-  if (!AdjustTokenPrivileges(token, FALSE, &token_privileges, sizeof(token_privileges), NULL, NULL) ||
-      GetLastError() != ERROR_SUCCESS)
-    return FALSE;
-
-  return TRUE;
-}
-
-/*
- * Change access token for the current thread to new specified access token.
- * Previously active access token is stored in old_token variable and can be
- * used for reverting to this access token. It is set to NULL if the current
- * thread previously used primary process access token.
- */
-static BOOL
-change_token(HANDLE new_token, HANDLE *old_token)
-{
-  HANDLE token;
-
-  if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &token))
-    {
-      if (GetLastError() != ERROR_NO_TOKEN)
-        return FALSE;
-      token = NULL;
-    }
-
-  if (!ImpersonateLoggedOnUser(new_token))
-    {
-      if (token)
-        CloseHandle(token);
-      return FALSE;
-    }
-
-  *old_token = token;
-  return TRUE;
-}
-
-/*
- * Change access token for the current thread to the primary process access
- * token. This function fails also when the current thread already uses primary
- * process access token.
- */
-static BOOL
-change_token_to_primary(HANDLE *old_token)
-{
-  HANDLE token;
-
-  if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &token))
-    return FALSE;
-
-  RevertToSelf();
-
-  *old_token = token;
-  return TRUE;
-}
-
-/*
- * Revert to the specified access token for the current thread. When access
- * token is specified as NULL then revert to the primary process access token.
- * Use to revert after change_token() or change_token_to_primary() call.
- */
-static VOID
-revert_to_token(HANDLE token)
-{
-  /*
-   * If SetThreadToken() call fails then there is no option to revert to
-   * the specified previous thread access token. So in this case revert to
-   * the primary process access token.
-   */
-  if (!token || !SetThreadToken(NULL, token))
-    RevertToSelf();
-  if (token)
-    CloseHandle(token);
-}
-
-/*
- * Enable particular privilege for the current thread. And set method how to
- * revert this privilege (if to revert whole token or only privilege).
- */
-static BOOL
-enable_privilege(LUID luid_privilege, HANDLE *revert_token, BOOL *revert_only_privilege)
-{
-  HANDLE thread_token;
-  HANDLE new_token;
-
-  if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &thread_token))
-    {
-      if (set_privilege(thread_token, luid_privilege, TRUE))
-        {
-          /*
-           * Indicate that correct revert method is just to
-           * disable privilege in access token.
-           */
-          if (revert_token && revert_only_privilege)
-            {
-              *revert_token = thread_token;
-              *revert_only_privilege = TRUE;
-            }
-          else
-            {
-              CloseHandle(thread_token);
-            }
-          return TRUE;
-        }
-      CloseHandle(thread_token);
-      /*
-       * If enabling privilege failed then try to enable it via
-       * primary process access token.
-       */
-    }
-
-  /*
-   * If the current thread has already active thread access token then
-   * open it with just impersonate right as it would be used only for
-   * future revert.
-   */
-  if (revert_token && revert_only_privilege)
-    {
-      if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &thread_token))
-        {
-          if (GetLastError() != ERROR_NO_TOKEN)
-            return FALSE;
-          thread_token = NULL;
-        }
-
-      /*
-       * If current thread has no access token (and uses primary
-       * process access token) or it does not have permission to
-       * adjust privileges or it does not have specified privilege
-       * then create a copy of the primary process access token,
-       * assign it for the current thread (= impersonate self)
-       * and then try adjusting privilege again.
-       */
-      if (!ImpersonateSelf(SecurityImpersonation))
-        {
-          if (thread_token)
-            CloseHandle(thread_token);
-          return FALSE;
-        }
-    }
-
-  if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &new_token))
-    {
-      /* thread_token is set only when we were asked for revert method. */
-      if (revert_token && revert_only_privilege)
-        revert_to_token(thread_token);
-      return FALSE;
-    }
-
-  if (!set_privilege(new_token, luid_privilege, TRUE))
-    {
-      CloseHandle(new_token);
-      /* thread_token is set only when we were asked for revert method. */
-      if (revert_token && revert_only_privilege)
-        revert_to_token(thread_token);
-      return FALSE;
-    }
-
-  /*
-   * Indicate that correct revert method is to change to the previous
-   * access token. Either to the primary process access token or to the
-   * previous thread access token.
-   */
-  if (revert_token && revert_only_privilege)
-    {
-      *revert_token = thread_token;
-      *revert_only_privilege = FALSE;
-    }
-  return TRUE;
-}
-
-/*
- * Revert particular privilege for the current thread was previously enabled by
- * enable_privilege() call. Either disable privilege in specified access token
- * or revert to previous access token.
- */
-static VOID
-revert_privilege(LUID luid_privilege, HANDLE revert_token, BOOL revert_only_privilege)
-{
-  if (revert_only_privilege)
-    {
-      set_privilege(revert_token, luid_privilege, FALSE);
-      CloseHandle(revert_token);
-    }
-  else
-    {
-      revert_to_token(revert_token);
-    }
-}
-
-/*
- * Return owner of the access token used by the current thread. Buffer for
- * returned owner needs to be released by LocalFree() call.
- */
-static TOKEN_OWNER *
-get_current_token_owner(VOID)
-{
-  HANDLE token;
-  DWORD length;
-  TOKEN_OWNER *owner;
-
-  /*
-   * If the current thread does not have active access token then thread
-   * uses primary process access token for all permission checks.
-   */
-  if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &token) &&
-      (GetLastError() != ERROR_NO_TOKEN ||
-       !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)))
-    return NULL;
-
-  if (!GetTokenInformation(token, TokenOwner, NULL, 0, &length) &&
-      GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-    {
-      CloseHandle(token);
-      return NULL;
-    }
-
-retry:
-  owner = (TOKEN_OWNER *)LocalAlloc(LPTR, length);
-  if (!owner)
-    {
-      CloseHandle(token);
-      return NULL;
-    }
-
-  if (!GetTokenInformation(token, TokenOwner, owner, length, &length))
-    {
-      /*
-       * Length of token owner (SID) buffer between two get calls may
-       * changes (e.g. by another thread of process), so retry.
-       */
-      if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-        {
-          LocalFree(owner);
-          goto retry;
-        }
-      LocalFree(owner);
-      CloseHandle(token);
-      return NULL;
-    }
-
-  CloseHandle(token);
-  return owner;
-}
-
-/*
- * Grant particular permissions in the primary access token of the specified
- * process for the owner of current thread token and set old DACL of the
- * process access token for reverting permissions. Security descriptor is
- * just memory buffer for old DACL.
- */
-static BOOL
-grant_process_token_dacl_permissions(HANDLE process, DWORD permissions, HANDLE *token, PACL *old_dacl, PSECURITY_DESCRIPTOR *security_descriptor)
-{
-  GetSecurityInfoProt MyGetSecurityInfo;
-  SetSecurityInfoProt MySetSecurityInfo;
-  SetEntriesInAclProt MySetEntriesInAcl;
-  EXPLICIT_ACCESS explicit_access;
-  TOKEN_OWNER *owner;
-  HMODULE advapi32;
-  PACL new_dacl;
-
-  /*
-   * This source file already uses advapi32.dll library, so it is
-   * linked to executable and automatically loaded when starting
-   * current running process.
-   */
-  advapi32 = GetModuleHandle(TEXT("advapi32.dll"));
-  if (!advapi32)
-    return FALSE;
-
-  /*
-   * It does not matter if SetEntriesInAclA() or SetEntriesInAclW() is
-   * called as no string is passed to SetEntriesInAcl function.
-   */
-  MyGetSecurityInfo = (GetSecurityInfoProt)(LPVOID)GetProcAddress(advapi32, "GetSecurityInfo");
-  MySetSecurityInfo = (SetSecurityInfoProt)(LPVOID)GetProcAddress(advapi32, "SetSecurityInfo");
-  MySetEntriesInAcl = (SetEntriesInAclProt)(LPVOID)GetProcAddress(advapi32, "SetEntriesInAclA");
-  if (!MyGetSecurityInfo || !MySetSecurityInfo || !MySetEntriesInAcl)
-    return FALSE;
-
-  owner = get_current_token_owner();
-  if (!owner)
-    return FALSE;
-
-  /*
-   * READ_CONTROL is required for GetSecurityInfo(DACL_SECURITY_INFORMATION)
-   * and WRITE_DAC is required for SetSecurityInfo(DACL_SECURITY_INFORMATION).
-   */
-  if (!OpenProcessToken(process, READ_CONTROL | WRITE_DAC, token))
-    {
-      LocalFree(owner);
-      return FALSE;
-    }
-
-  if (MyGetSecurityInfo(*token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, old_dacl, NULL, security_descriptor) != ERROR_SUCCESS)
-    {
-      LocalFree(owner);
-      CloseHandle(*token);
-      return FALSE;
-    }
-
-  /*
-   * Set new explicit access for the owner of the current thread access
-   * token with non-inherited granting access to specified permissions.
-   */
-  explicit_access.grfAccessPermissions = permissions;
-  explicit_access.grfAccessMode = GRANT_ACCESS;
-  explicit_access.grfInheritance = NO_PROPAGATE_INHERIT_ACE;
-  explicit_access.Trustee.pMultipleTrustee = NULL;
-  explicit_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
-  explicit_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
-  explicit_access.Trustee.TrusteeType = TRUSTEE_IS_USER;
-  /*
-   * Unfortunately i586-mingw32msvc toolchain does not have pSid pointer
-   * member in Trustee union. So assign owner SID to ptstrName pointer
-   * member which aliases with pSid pointer member in the same union.
-   */
-  explicit_access.Trustee.ptstrName = (PVOID)owner->Owner;
-
-  if (MySetEntriesInAcl(1, &explicit_access, *old_dacl, &new_dacl) != ERROR_SUCCESS)
-    {
-      LocalFree(*security_descriptor);
-      LocalFree(owner);
-      CloseHandle(*token);
-      return FALSE;
-    }
-
-  if (MySetSecurityInfo(*token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS)
-    {
-      LocalFree(new_dacl);
-      LocalFree(*security_descriptor);
-      LocalFree(owner);
-      CloseHandle(*token);
-      return FALSE;
-    }
-
-  LocalFree(new_dacl);
-  LocalFree(owner);
-  return TRUE;
-}
-
-/*
- * Revert particular granted permissions in specified access token done by
- * grant_process_token_dacl_permissions() call.
- */
-static VOID
-revert_token_dacl_permissions(HANDLE token, PACL old_dacl, PSECURITY_DESCRIPTOR security_descriptor)
-{
-  SetSecurityInfoProt MySetSecurityInfo;
-  HMODULE advapi32;
-
-  /*
-   * This source file already uses advapi32.dll library, so it is
-   * linked to executable and automatically loaded when starting
-   * current running process.
-   */
-  advapi32 = GetModuleHandle(TEXT("advapi32.dll"));
-  if (advapi32)
-    {
-      MySetSecurityInfo = (SetSecurityInfoProt)(LPVOID)GetProcAddress(advapi32, "SetSecurityInfo");
-      MySetSecurityInfo(token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, old_dacl, NULL);
-    }
-
-  LocalFree(security_descriptor);
-  CloseHandle(token);
-}
-
-/*
- * Change error mode of the current thread. If it is not possible then change
- * error mode of the whole process. Always returns previous error mode.
- */
-static UINT
-change_error_mode(UINT new_mode)
-{
-  SetThreadErrorModeProt MySetThreadErrorMode = NULL;
-  HMODULE kernel32;
-  DWORD old_mode;
-
-  /*
-   * Function SetThreadErrorMode() was introduced in Windows 7, so use
-   * GetProcAddress() for compatibility with older systems.
-   */
-  kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
-  if (kernel32)
-    MySetThreadErrorMode = (SetThreadErrorModeProt)(LPVOID)GetProcAddress(kernel32, "SetThreadErrorMode");
-
-  if (MySetThreadErrorMode &&
-      MySetThreadErrorMode(new_mode, &old_mode))
-    return old_mode;
-
-  /*
-   * Fallback to function SetErrorMode() which modifies error mode of the
-   * whole process and returns old mode.
-   */
-  return SetErrorMode(new_mode);
-}
-
-/*
- * Open process handle specified by the process id with the query right and
- * optionally also with vm read right.
- */
-static HANDLE
-open_process_for_query(DWORD pid, BOOL with_vm_read)
-{
-  BOOL revert_only_privilege;
-  LUID luid_debug_privilege;
-  OSVERSIONINFO version;
-  DWORD process_right;
-  HANDLE revert_token;
-  HANDLE process;
-
-  /*
-   * Some processes on Windows Vista and higher systems can be opened only
-   * with PROCESS_QUERY_LIMITED_INFORMATION right. This right is enough
-   * for accessing primary process token. But this right is not supported
-   * on older pre-Vista systems. When the current thread on these older
-   * systems does not have Debug privilege then OpenProcess() fails with
-   * ERROR_ACCESS_DENIED. If the current thread has Debug privilege then
-   * OpenProcess() success and returns handle to requested process.
-   * Problem is that this handle does not have PROCESS_QUERY_INFORMATION
-   * right and so cannot be used for accessing primary process token
-   * on those older systems. Moreover it has zero rights and therefore
-   * such handle is fully useless. So never try to use open process with
-   * PROCESS_QUERY_LIMITED_INFORMATION right on older systems than
-   * Windows Vista (NT 6.0).
-   */
-  version.dwOSVersionInfoSize = sizeof(version);
-  if (GetVersionEx(&version) &&
-      version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
-      version.dwMajorVersion >= 6)
-    process_right = PROCESS_QUERY_LIMITED_INFORMATION;
-  else
-    process_right = PROCESS_QUERY_INFORMATION;
-
-  if (with_vm_read)
-    process_right |= PROCESS_VM_READ;
-
-  process = OpenProcess(process_right, FALSE, pid);
-  if (process)
-    return process;
-
-  /*
-   * It is possible to open only processes to which owner of the current
-   * thread access token has permissions. For opening other processing it
-   * is required to have Debug privilege enabled. By default local
-   * administrators have this privilege, but it is disabled. So try to
-   * enable it and then try to open process again.
-   */
-
-  if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid_debug_privilege))
-    return NULL;
-
-  if (!enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
-    return NULL;
-
-  process = OpenProcess(process_right, FALSE, pid);
-
-  revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
-
-  return process;
-}
-
-/*
- * Check if process image path name (wide string) matches exe file name
- * (7-bit ASCII string). Do case-insensitive string comparison. Process
- * image path name can be in any namespace format (DOS, Win32, UNC, ...).
- */
-static BOOL
-check_process_name(LPCWSTR path, DWORD path_length, LPCSTR exe_file)
-{
-  DWORD exe_file_length;
-  WCHAR c1;
-  UCHAR c2;
-  DWORD i;
-
-  exe_file_length = 0;
-  while (exe_file[exe_file_length] != '\0')
-    exe_file_length++;
-
-  /* Path must have backslash before exe file name. */
-  if (exe_file_length >= path_length ||
-      path[path_length-exe_file_length-1] != L'\\')
-    return FALSE;
-
-  for (i = 0; i < exe_file_length; i++)
-    {
-      c1 = path[path_length-exe_file_length+i];
-      c2 = exe_file[i];
-      /*
-       * Input string for comparison is 7-bit ASCII and file name part
-       * of path must not contain backslash as it is path separator.
-       */
-      if (c1 >= 0x80 || c2 >= 0x80 || c1 == L'\\')
-        return FALSE;
-      if (c1 >= L'a' && c1 <= L'z')
-        c1 -= L'a' - L'A';
-      if (c2 >= 'a' && c2 <= 'z')
-        c2 -= 'a' - 'A';
-      if (c1 != c2)
-        return FALSE;
-    }
-
-  return TRUE;
-}
-
-/* Open process handle with the query right specified by process exe file. */
-static HANDLE
-find_and_open_process_for_query(LPCSTR exe_file)
-{
-  GetProcessImageFileNameWProt MyGetProcessImageFileNameW;
-  GetModuleFileNameExWProt MyGetModuleFileNameExW;
-  EnumProcessesProt MyEnumProcesses;
-  HMODULE kernel32, psapi;
-  UINT prev_error_mode;
-  DWORD partial_retry;
-  BOOL found_process;
-  DWORD size, length;
-  DWORD *processes;
-  HANDLE process;
-  LPWSTR path;
-  DWORD error;
-  DWORD count;
-  DWORD i;
-
-  psapi = NULL;
-  kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
-  if (!kernel32)
-    return NULL;
-
-  /*
-   * On Windows 7 and higher systems these functions are available in
-   * kernel32.dll library with K32 prefix.
-   */
-  MyGetModuleFileNameExW = NULL;
-  MyGetProcessImageFileNameW = (GetProcessImageFileNameWProt)(LPVOID)GetProcAddress(kernel32, "K32GetProcessImageFileNameW");
-  MyEnumProcesses = (EnumProcessesProt)(LPVOID)GetProcAddress(kernel32, "K32EnumProcesses");
-  if (!MyGetProcessImageFileNameW || !MyEnumProcesses)
-    {
-      /*
-       * On older NT-based systems these functions are available in
-       * psapi.dll library without K32 prefix.
-       */
-      prev_error_mode = change_error_mode(SEM_FAILCRITICALERRORS);
-      psapi = LoadLibrary(TEXT("psapi.dll"));
-      change_error_mode(prev_error_mode);
-
-      if (!psapi)
-        return NULL;
-
-      /*
-       * Function GetProcessImageFileNameW() is available in
-       * Windows XP and higher systems. On older versions is
-       * available function GetModuleFileNameExW().
-       */
-      MyGetProcessImageFileNameW = (GetProcessImageFileNameWProt)(LPVOID)GetProcAddress(psapi, "GetProcessImageFileNameW");
-      MyGetModuleFileNameExW = (GetModuleFileNameExWProt)(LPVOID)GetProcAddress(psapi, "GetModuleFileNameExW");
-      MyEnumProcesses = (EnumProcessesProt)(LPVOID)GetProcAddress(psapi, "EnumProcesses");
-      if ((!MyGetProcessImageFileNameW && !MyGetModuleFileNameExW) || !MyEnumProcesses)
-        {
-          FreeLibrary(psapi);
-          return NULL;
-        }
-    }
-
-  /* Make initial buffer size for 1024 processes. */
-  size = 1024 * sizeof(*processes);
-
-retry:
-  processes = (DWORD *)LocalAlloc(LPTR, size);
-  if (!processes)
-    {
-      if (psapi)
-        FreeLibrary(psapi);
-      return NULL;
-    }
-
-  if (!MyEnumProcesses(processes, size, &length))
-    {
-      LocalFree(processes);
-      if (psapi)
-        FreeLibrary(psapi);
-      return NULL;
-    }
-  else if (size == length)
-    {
-      /*
-       * There is no indication given when the buffer is too small to
-       * store all process identifiers. Therefore if returned length
-       * is same as buffer size there can be more processes. Call
-       * again with larger buffer.
-       */
-      LocalFree(processes);
-      size *= 2;
-      goto retry;
-    }
-
-  process = NULL;
-  count = length / sizeof(*processes);
-
-  for (i = 0; i < count; i++)
-    {
-      /* Skip System Idle Process. */
-      if (processes[i] == 0)
-        continue;
-
-      /*
-       * Function GetModuleFileNameExW() requires additional
-       * PROCESS_VM_READ right as opposite to function
-       * GetProcessImageFileNameW() which does not need it.
-       */
-      process = open_process_for_query(processes[i], MyGetProcessImageFileNameW ? FALSE : TRUE);
-      if (!process)
-        continue;
-
-      /*
-       * Set initial buffer size to 256 (wide) characters.
-       * Final path length on the modern NT-based systems can be also larger.
-       */
-      size = 256;
-      found_process = FALSE;
-      partial_retry = 0;
-
-retry_path:
-      path = (LPWSTR)LocalAlloc(LPTR, size * sizeof(*path));
-      if (!path)
-        goto end_path;
-
-      if (MyGetProcessImageFileNameW)
-        length = MyGetProcessImageFileNameW(process, path, size);
-      else
-        length = MyGetModuleFileNameExW(process, NULL, path, size);
-
-      error = GetLastError();
-
-      /*
-       * GetModuleFileNameEx() returns zero and signal error ERROR_PARTIAL_COPY
-       * when remote process is in the middle of updating its module table.
-       * Sleep 10 ms and try again, max 10 attempts.
-       */
-      if (!MyGetProcessImageFileNameW)
-        {
-          if (length == 0 && error == ERROR_PARTIAL_COPY && partial_retry++ < 10)
-            {
-              Sleep(10);
-              goto retry_path;
-            }
-          partial_retry = 0;
-        }
-
-      /*
-       * When buffer is too small then function GetModuleFileNameEx() returns
-       * its size argument on older systems (Windows XP) or its size minus
-       * argument one on new systems (Windows 10) without signalling any error.
-       * Function GetProcessImageFileNameW() on the other hand returns zero
-       * value and signals error ERROR_INSUFFICIENT_BUFFER. So in all these
-       * cases call function again with larger buffer.
-       */
-
-      if (MyGetProcessImageFileNameW && length == 0 && error != ERROR_INSUFFICIENT_BUFFER)
-        goto end_path;
-
-      if ((MyGetProcessImageFileNameW && length == 0) ||
-          (!MyGetProcessImageFileNameW && (length == size || length == size-1)))
-        {
-          LocalFree(path);
-          size *= 2;
-          goto retry_path;
-        }
-
-      if (length && check_process_name(path, length, exe_file))
-        found_process = TRUE;
-
-end_path:
-      if (path)
-        {
-          LocalFree(path);
-          path = NULL;
-        }
-
-      if (found_process)
-        break;
-
-      CloseHandle(process);
-      process = NULL;
-    }
-
-  LocalFree(processes);
-
-  if (psapi)
-    FreeLibrary(psapi);
-
-  return process;
-}
-
-/*
- * Try to open primary access token of the particular process with specified
- * rights. Before opening access token try to adjust DACL permissions of the
- * primary process access token, so following open does not fail on error
- * related to no open permissions. Revert DACL permissions after open attempt.
- * As following steps are not atomic, try to execute them more times in case
- * of possible race conditions caused by other threads or processes.
- */
-static HANDLE
-try_grant_permissions_and_open_process_token(HANDLE process, DWORD rights)
-{
-  PSECURITY_DESCRIPTOR security_descriptor;
-  HANDLE grant_token;
-  PACL old_dacl;
-  HANDLE token;
-  DWORD retry;
-  DWORD error;
-
-  /*
-   * This code is not atomic. Between grant and open calls can other
-   * thread or process change or revert permissions. So try to execute
-   * it more times.
-   */
-  for (retry = 0; retry < 10; retry++)
-    {
-      if (!grant_process_token_dacl_permissions(process, rights, &grant_token, &old_dacl, &security_descriptor))
-        return NULL;
-      if (!OpenProcessToken(process, rights, &token))
-        {
-          token = NULL;
-          error = GetLastError();
-        }
-      revert_token_dacl_permissions(grant_token, old_dacl, security_descriptor);
-      if (token)
-        return token;
-      else if (error != ERROR_ACCESS_DENIED)
-        return NULL;
-    }
-
-  return NULL;
-}
-
-/*
- * Open primary access token of particular process handle with specified rights.
- * If permissions for specified rights are missing then try to grant them.
- */
-static HANDLE
-open_process_token_with_rights(HANDLE process, DWORD rights)
-{
-  HANDLE old_token;
-  HANDLE token;
-
-  /* First try to open primary access token of process handle directly. */
-  if (OpenProcessToken(process, rights, &token))
-    return token;
-
-  /*
-   * If opening failed then it means that owner of the current thread
-   * access token does not have permission for it. Try it again with
-   * primary process access token.
-   */
-  if (change_token_to_primary(&old_token))
-    {
-      if (!OpenProcessToken(process, rights, &token))
-        token = NULL;
-      revert_to_token(old_token);
-      if (token)
-        return token;
-    }
-
-  /*
-   * If opening is still failing then try to grant specified permissions
-   * for the current thread and try to open it again.
-   */
-  token = try_grant_permissions_and_open_process_token(process, rights);
-  if (token)
-    return token;
-
-  /*
-   * And if it is still failing then try it again with granting
-   * permissions for the primary process token of the current process.
-   */
-  if (change_token_to_primary(&old_token))
-    {
-      token = try_grant_permissions_and_open_process_token(process, rights);
-      revert_to_token(old_token);
-      if (token)
-        return token;
-    }
-
-  /*
-   * TODO: Sorry, no other option for now...
-   * It could be possible to use Take Ownership Name privilege to
-   * temporary change token owner of specified process to the owner of
-   * the current thread token, grant permissions for current thread in
-   * that process token, change ownership back to original one, open
-   * that process token and revert granted permissions. But this is
-   * not implemented yet.
-   */
-  return NULL;
-}
-
 /*
  * Call supplied function Func with its Arg and if it fails with
  * ERROR_PRIVILEGE_NOT_HELD then try to enable Tcb privilege and
@@ -1035,14 +150,14 @@ CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
    * If the current thread has already Tcb privilege enabled then there
    * is some additional unhanded restriction.
    */
-  if (have_privilege(luid_tcb_privilege))
+  if (win32_have_privilege(luid_tcb_privilege))
     goto err_privilege_not_held;
 
   /* Try to enable Tcb privilege and try function call again. */
-  if (enable_privilege(luid_tcb_privilege, &revert_token_tcb_privilege, &revert_only_tcb_privilege))
+  if (win32_enable_privilege(luid_tcb_privilege, &revert_token_tcb_privilege, &revert_only_tcb_privilege))
     {
       ret = Func(Arg);
-      revert_privilege(luid_tcb_privilege, revert_token_tcb_privilege, revert_only_tcb_privilege);
+      win32_revert_privilege(luid_tcb_privilege, revert_token_tcb_privilege, revert_only_tcb_privilege);
       goto ret;
     }
 
@@ -1058,7 +173,7 @@ CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
    * So try to enable it in case it is currently disabled.
    */
   if (LookupPrivilegeValue(NULL, SE_IMPERSONATE_NAME, &luid_impersonate_privilege) &&
-      !have_privilege(luid_impersonate_privilege))
+      !win32_have_privilege(luid_impersonate_privilege))
     {
       /*
        * If current thread does not have Impersonate privilege enabled
@@ -1068,11 +183,11 @@ CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
        * affects all process threads). Both actions will be reverted
        * at the end of this function.
        */
-      if (enable_privilege(luid_impersonate_privilege, &revert_token_impersonate_privilege, &revert_only_impersonate_privilege))
+      if (win32_enable_privilege(luid_impersonate_privilege, &revert_token_impersonate_privilege, &revert_only_impersonate_privilege))
         {
           impersonate_privilege_enabled = TRUE;
         }
-      else if (enable_privilege(luid_impersonate_privilege, NULL, NULL))
+      else if (win32_enable_privilege(luid_impersonate_privilege, NULL, NULL))
         {
           impersonate_privilege_enabled = TRUE;
           revert_token_impersonate_privilege = NULL;
@@ -1089,10 +204,10 @@ CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
        * thread requires Impersonate privilege, so enabling Tcb again
        * could now pass.
        */
-      if (enable_privilege(luid_tcb_privilege, &revert_token_tcb_privilege, &revert_only_tcb_privilege))
+      if (win32_enable_privilege(luid_tcb_privilege, &revert_token_tcb_privilege, &revert_only_tcb_privilege))
         {
           ret = Func(Arg);
-          revert_privilege(luid_tcb_privilege, revert_token_tcb_privilege, revert_only_tcb_privilege);
+          win32_revert_privilege(luid_tcb_privilege, revert_token_tcb_privilege, revert_only_tcb_privilege);
           goto ret;
         }
     }
@@ -1108,7 +223,7 @@ CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
    * administrators (unless it was disabled by local administrators).
    */
 
-  lsass_process = find_and_open_process_for_query("lsass.exe");
+  lsass_process = win32_find_and_open_process_for_query("lsass.exe");
   if (!lsass_process)
     goto err_privilege_not_held;
 
@@ -1117,7 +232,7 @@ CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
    * rights. Just these two rights are required for impersonating other
    * primary process token (impersonate right is really not required!).
    */
-  lsass_token = open_process_token_with_rights(lsass_process, TOKEN_QUERY | TOKEN_DUPLICATE);
+  lsass_token = win32_open_process_token_with_rights(lsass_process, TOKEN_QUERY | TOKEN_DUPLICATE);
 
   CloseHandle(lsass_process);
 
@@ -1128,7 +243,7 @@ CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
    * After successful open of the primary lsass.exe process access token,
    * assign its copy for the current thread.
    */
-  if (!change_token(lsass_token, &old_token))
+  if (!win32_change_token(lsass_token, &old_token))
     goto err_privilege_not_held;
 
   revert_to_old_token = TRUE;
@@ -1144,8 +259,8 @@ CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
    * be reverted. So there is no need to setup revert method for
    * enabling privilege.
    */
-  if (have_privilege(luid_tcb_privilege) ||
-      !enable_privilege(luid_tcb_privilege, NULL, NULL))
+  if (win32_have_privilege(luid_tcb_privilege) ||
+      !win32_enable_privilege(luid_tcb_privilege, NULL, NULL))
     goto err_privilege_not_held;
 
   ret = Func(Arg);
@@ -1158,10 +273,10 @@ err_privilege_not_held:
 
 ret:
   if (revert_to_old_token)
-    revert_to_token(old_token);
+    win32_revert_to_token(old_token);
 
   if (impersonate_privilege_enabled)
-    revert_privilege(luid_impersonate_privilege, revert_token_impersonate_privilege, revert_only_impersonate_privilege);
+    win32_revert_privilege(luid_impersonate_privilege, revert_token_impersonate_privilege, revert_only_impersonate_privilege);
 
   if (lsass_token)
     CloseHandle(lsass_token);
@@ -1228,9 +343,9 @@ SetProcessUserModeIOPL(VOID)
    * It means that NT kernel does not show unwanted GUI message box to user
    * when LoadLibrary() function fails.
    */
-  prev_error_mode = change_error_mode(SEM_FAILCRITICALERRORS);
+  prev_error_mode = win32_change_error_mode(SEM_FAILCRITICALERRORS);
   ntdll = LoadLibrary(TEXT("ntdll.dll"));
-  change_error_mode(prev_error_mode);
+  win32_change_error_mode(prev_error_mode);
   if (!ntdll)
     {
       SetLastError(ERROR_INVALID_FUNCTION);
index dd478654d48484de70e3a286ce00009edcb97d72..29ce5d885ad13f53a93f3cb6846f225b2e8c9296 100644 (file)
@@ -9,10 +9,43 @@
  */
 
 #include <windows.h>
+#include <aclapi.h>
 #include <stdio.h> /* for sprintf() */
 
 #include "win32-helpers.h"
 
+/* Unfortunately i586-mingw32msvc toolchain does not provide this constant. */
+#ifndef PROCESS_QUERY_LIMITED_INFORMATION
+#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
+#endif
+
+/*
+ * These psapi functions are available in kernel32.dll library with K32 prefix
+ * on Windows 7 and higher systems. On older Windows systems these functions are
+ * available in psapi.dll libary without K32 prefix. So resolve pointers to
+ * these functions dynamically at runtime from the available system library.
+ * Function GetProcessImageFileNameW() is not available on Windows 2000 and
+ * older systems.
+ */
+typedef BOOL (WINAPI *EnumProcessesProt)(DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded);
+typedef DWORD (WINAPI *GetProcessImageFileNameWProt)(HANDLE hProcess, LPWSTR lpImageFileName, DWORD nSize);
+typedef DWORD (WINAPI *GetModuleFileNameExWProt)(HANDLE hProcess, HMODULE hModule, LPWSTR lpImageFileName, DWORD nSize);
+
+/*
+ * These aclapi functions are available in advapi.dll library on Windows NT 4.0
+ * and higher systems.
+ */
+typedef DWORD (WINAPI *GetSecurityInfoProt)(HANDLE handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID *ppsidOwner, PSID *ppsidGroup, PACL *ppDacl, PACL *ppSacl, PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
+typedef DWORD (WINAPI *SetSecurityInfoProt)(HANDLE handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl);
+typedef DWORD (WINAPI *SetEntriesInAclProt)(ULONG cCountOfExplicitEntries, PEXPLICIT_ACCESS pListOfExplicitEntries, PACL OldAcl, PACL *NewAcl);
+
+/*
+ * This errhandlingapi function is available in kernel32.dll library on
+ * Windows 7 and higher systems.
+ */
+typedef BOOL (WINAPI *SetThreadErrorModeProt)(DWORD dwNewMode, LPDWORD lpOldMode);
+
+
 const char *
 win32_strerror(DWORD win32_error_id)
 {
@@ -95,3 +128,856 @@ win32_is_32bit_on_win8_64bit_system(void)
   return win32_is_32bit_on_64bit_system();
 #endif
 }
+
+/*
+ * Change error mode of the current thread. If it is not possible then change
+ * error mode of the whole process. Always returns previous error mode.
+ */
+UINT
+win32_change_error_mode(UINT new_mode)
+{
+  SetThreadErrorModeProt MySetThreadErrorMode = NULL;
+  HMODULE kernel32;
+  DWORD old_mode;
+
+  /*
+   * Function SetThreadErrorMode() was introduced in Windows 7, so use
+   * GetProcAddress() for compatibility with older systems.
+   */
+  kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+  if (kernel32)
+    MySetThreadErrorMode = (SetThreadErrorModeProt)(LPVOID)GetProcAddress(kernel32, "SetThreadErrorMode");
+
+  if (MySetThreadErrorMode &&
+      MySetThreadErrorMode(new_mode, &old_mode))
+    return old_mode;
+
+  /*
+   * Fallback to function SetErrorMode() which modifies error mode of the
+   * whole process and returns old mode.
+   */
+  return SetErrorMode(new_mode);
+}
+
+/*
+ * Check if the current thread has particular privilege in current active access
+ * token. Case when it not possible to determinate it (e.g. current thread does
+ * not have permission to open its own current active access token) is evaluated
+ * as thread does not have that privilege.
+ */
+BOOL
+win32_have_privilege(LUID luid_privilege)
+{
+  PRIVILEGE_SET priv;
+  HANDLE token;
+  BOOL ret;
+
+  /*
+   * If the current thread does not have active access token then thread
+   * uses primary process access token for all permission checks.
+   */
+  if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &token) &&
+      (GetLastError() != ERROR_NO_TOKEN ||
+       !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)))
+    return FALSE;
+
+  priv.PrivilegeCount = 1;
+  priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
+  priv.Privilege[0].Luid = luid_privilege;
+  priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+  if (!PrivilegeCheck(token, &priv, &ret))
+    return FALSE;
+
+  return ret;
+}
+
+/*
+ * Enable or disable particular privilege in specified access token.
+ *
+ * Note that it is not possible to disable privilege in access token with
+ * SE_PRIVILEGE_ENABLED_BY_DEFAULT attribute. This function does not check
+ * this case and incorrectly returns no error even when disabling failed.
+ * Rationale for this decision: Simplification of this function as WinAPI
+ * call AdjustTokenPrivileges() does not signal error in this case too.
+ */
+static BOOL
+set_privilege(HANDLE token, LUID luid_privilege, BOOL enable)
+{
+  TOKEN_PRIVILEGES token_privileges;
+
+  token_privileges.PrivilegeCount = 1;
+  token_privileges.Privileges[0].Luid = luid_privilege;
+  token_privileges.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
+
+  /*
+   * WinAPI function AdjustTokenPrivileges() success also when not all
+   * privileges were enabled. It is always required to check for failure
+   * via GetLastError() call. AdjustTokenPrivileges() always sets error
+   * also when it success, as opposite to other WinAPI functions.
+   */
+  if (!AdjustTokenPrivileges(token, FALSE, &token_privileges, sizeof(token_privileges), NULL, NULL) ||
+      GetLastError() != ERROR_SUCCESS)
+    return FALSE;
+
+  return TRUE;
+}
+
+/*
+ * Change access token for the current thread to new specified access token.
+ * Previously active access token is stored in old_token variable and can be
+ * used for reverting to this access token. It is set to NULL if the current
+ * thread previously used primary process access token.
+ */
+BOOL
+win32_change_token(HANDLE new_token, HANDLE *old_token)
+{
+  HANDLE token;
+
+  if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &token))
+    {
+      if (GetLastError() != ERROR_NO_TOKEN)
+        return FALSE;
+      token = NULL;
+    }
+
+  if (!ImpersonateLoggedOnUser(new_token))
+    {
+      if (token)
+        CloseHandle(token);
+      return FALSE;
+    }
+
+  *old_token = token;
+  return TRUE;
+}
+
+/*
+ * Change access token for the current thread to the primary process access
+ * token. This function fails also when the current thread already uses primary
+ * process access token.
+ */
+static BOOL
+change_token_to_primary(HANDLE *old_token)
+{
+  HANDLE token;
+
+  if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &token))
+    return FALSE;
+
+  RevertToSelf();
+
+  *old_token = token;
+  return TRUE;
+}
+
+/*
+ * Revert to the specified access token for the current thread. When access
+ * token is specified as NULL then revert to the primary process access token.
+ * Use to revert after win32_change_token() or change_token_to_primary() call.
+ */
+VOID
+win32_revert_to_token(HANDLE token)
+{
+  /*
+   * If SetThreadToken() call fails then there is no option to revert to
+   * the specified previous thread access token. So in this case revert to
+   * the primary process access token.
+   */
+  if (!token || !SetThreadToken(NULL, token))
+    RevertToSelf();
+  if (token)
+    CloseHandle(token);
+}
+
+/*
+ * Enable particular privilege for the current thread. And set method how to
+ * revert this privilege (if to revert whole token or only privilege).
+ */
+BOOL
+win32_enable_privilege(LUID luid_privilege, HANDLE *revert_token, BOOL *revert_only_privilege)
+{
+  HANDLE thread_token;
+  HANDLE new_token;
+
+  if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &thread_token))
+    {
+      if (set_privilege(thread_token, luid_privilege, TRUE))
+        {
+          /*
+           * Indicate that correct revert method is just to
+           * disable privilege in access token.
+           */
+          if (revert_token && revert_only_privilege)
+            {
+              *revert_token = thread_token;
+              *revert_only_privilege = TRUE;
+            }
+          else
+            {
+              CloseHandle(thread_token);
+            }
+          return TRUE;
+        }
+      CloseHandle(thread_token);
+      /*
+       * If enabling privilege failed then try to enable it via
+       * primary process access token.
+       */
+    }
+
+  /*
+   * If the current thread has already active thread access token then
+   * open it with just impersonate right as it would be used only for
+   * future revert.
+   */
+  if (revert_token && revert_only_privilege)
+    {
+      if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &thread_token))
+        {
+          if (GetLastError() != ERROR_NO_TOKEN)
+            return FALSE;
+          thread_token = NULL;
+        }
+
+      /*
+       * If current thread has no access token (and uses primary
+       * process access token) or it does not have permission to
+       * adjust privileges or it does not have specified privilege
+       * then create a copy of the primary process access token,
+       * assign it for the current thread (= impersonate self)
+       * and then try adjusting privilege again.
+       */
+      if (!ImpersonateSelf(SecurityImpersonation))
+        {
+          if (thread_token)
+            CloseHandle(thread_token);
+          return FALSE;
+        }
+    }
+
+  if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &new_token))
+    {
+      /* thread_token is set only when we were asked for revert method. */
+      if (revert_token && revert_only_privilege)
+        win32_revert_to_token(thread_token);
+      return FALSE;
+    }
+
+  if (!set_privilege(new_token, luid_privilege, TRUE))
+    {
+      CloseHandle(new_token);
+      /* thread_token is set only when we were asked for revert method. */
+      if (revert_token && revert_only_privilege)
+        win32_revert_to_token(thread_token);
+      return FALSE;
+    }
+
+  /*
+   * Indicate that correct revert method is to change to the previous
+   * access token. Either to the primary process access token or to the
+   * previous thread access token.
+   */
+  if (revert_token && revert_only_privilege)
+    {
+      *revert_token = thread_token;
+      *revert_only_privilege = FALSE;
+    }
+  return TRUE;
+}
+
+/*
+ * Revert particular privilege for the current thread was previously enabled by
+ * win32_enable_privilege() call. Either disable privilege in specified access token
+ * or revert to previous access token.
+ */
+VOID
+win32_revert_privilege(LUID luid_privilege, HANDLE revert_token, BOOL revert_only_privilege)
+{
+  if (revert_only_privilege)
+    {
+      set_privilege(revert_token, luid_privilege, FALSE);
+      CloseHandle(revert_token);
+    }
+  else
+    {
+      win32_revert_to_token(revert_token);
+    }
+}
+
+/*
+ * Return owner of the access token used by the current thread. Buffer for
+ * returned owner needs to be released by LocalFree() call.
+ */
+static TOKEN_OWNER *
+get_current_token_owner(VOID)
+{
+  HANDLE token;
+  DWORD length;
+  TOKEN_OWNER *owner;
+
+  /*
+   * If the current thread does not have active access token then thread
+   * uses primary process access token for all permission checks.
+   */
+  if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &token) &&
+      (GetLastError() != ERROR_NO_TOKEN ||
+       !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)))
+    return NULL;
+
+  if (!GetTokenInformation(token, TokenOwner, NULL, 0, &length) &&
+      GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+    {
+      CloseHandle(token);
+      return NULL;
+    }
+
+retry:
+  owner = (TOKEN_OWNER *)LocalAlloc(LPTR, length);
+  if (!owner)
+    {
+      CloseHandle(token);
+      return NULL;
+    }
+
+  if (!GetTokenInformation(token, TokenOwner, owner, length, &length))
+    {
+      /*
+       * Length of token owner (SID) buffer between two get calls may
+       * changes (e.g. by another thread of process), so retry.
+       */
+      if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+        {
+          LocalFree(owner);
+          goto retry;
+        }
+      LocalFree(owner);
+      CloseHandle(token);
+      return NULL;
+    }
+
+  CloseHandle(token);
+  return owner;
+}
+
+/*
+ * Grant particular permissions in the primary access token of the specified
+ * process for the owner of current thread token and set old DACL of the
+ * process access token for reverting permissions. Security descriptor is
+ * just memory buffer for old DACL.
+ */
+static BOOL
+grant_process_token_dacl_permissions(HANDLE process, DWORD permissions, HANDLE *token, PACL *old_dacl, PSECURITY_DESCRIPTOR *security_descriptor)
+{
+  GetSecurityInfoProt MyGetSecurityInfo;
+  SetSecurityInfoProt MySetSecurityInfo;
+  SetEntriesInAclProt MySetEntriesInAcl;
+  EXPLICIT_ACCESS explicit_access;
+  TOKEN_OWNER *owner;
+  HMODULE advapi32;
+  PACL new_dacl;
+
+  /*
+   * This source file already uses advapi32.dll library, so it is
+   * linked to executable and automatically loaded when starting
+   * current running process.
+   */
+  advapi32 = GetModuleHandle(TEXT("advapi32.dll"));
+  if (!advapi32)
+    return FALSE;
+
+  /*
+   * It does not matter if SetEntriesInAclA() or SetEntriesInAclW() is
+   * called as no string is passed to SetEntriesInAcl function.
+   */
+  MyGetSecurityInfo = (GetSecurityInfoProt)(LPVOID)GetProcAddress(advapi32, "GetSecurityInfo");
+  MySetSecurityInfo = (SetSecurityInfoProt)(LPVOID)GetProcAddress(advapi32, "SetSecurityInfo");
+  MySetEntriesInAcl = (SetEntriesInAclProt)(LPVOID)GetProcAddress(advapi32, "SetEntriesInAclA");
+  if (!MyGetSecurityInfo || !MySetSecurityInfo || !MySetEntriesInAcl)
+    return FALSE;
+
+  owner = get_current_token_owner();
+  if (!owner)
+    return FALSE;
+
+  /*
+   * READ_CONTROL is required for GetSecurityInfo(DACL_SECURITY_INFORMATION)
+   * and WRITE_DAC is required for SetSecurityInfo(DACL_SECURITY_INFORMATION).
+   */
+  if (!OpenProcessToken(process, READ_CONTROL | WRITE_DAC, token))
+    {
+      LocalFree(owner);
+      return FALSE;
+    }
+
+  if (MyGetSecurityInfo(*token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, old_dacl, NULL, security_descriptor) != ERROR_SUCCESS)
+    {
+      LocalFree(owner);
+      CloseHandle(*token);
+      return FALSE;
+    }
+
+  /*
+   * Set new explicit access for the owner of the current thread access
+   * token with non-inherited granting access to specified permissions.
+   */
+  explicit_access.grfAccessPermissions = permissions;
+  explicit_access.grfAccessMode = GRANT_ACCESS;
+  explicit_access.grfInheritance = NO_PROPAGATE_INHERIT_ACE;
+  explicit_access.Trustee.pMultipleTrustee = NULL;
+  explicit_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+  explicit_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+  explicit_access.Trustee.TrusteeType = TRUSTEE_IS_USER;
+  /*
+   * Unfortunately i586-mingw32msvc toolchain does not have pSid pointer
+   * member in Trustee union. So assign owner SID to ptstrName pointer
+   * member which aliases with pSid pointer member in the same union.
+   */
+  explicit_access.Trustee.ptstrName = (PVOID)owner->Owner;
+
+  if (MySetEntriesInAcl(1, &explicit_access, *old_dacl, &new_dacl) != ERROR_SUCCESS)
+    {
+      LocalFree(*security_descriptor);
+      LocalFree(owner);
+      CloseHandle(*token);
+      return FALSE;
+    }
+
+  if (MySetSecurityInfo(*token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS)
+    {
+      LocalFree(new_dacl);
+      LocalFree(*security_descriptor);
+      LocalFree(owner);
+      CloseHandle(*token);
+      return FALSE;
+    }
+
+  LocalFree(new_dacl);
+  LocalFree(owner);
+  return TRUE;
+}
+
+/*
+ * Revert particular granted permissions in specified access token done by
+ * grant_process_token_dacl_permissions() call.
+ */
+static VOID
+revert_token_dacl_permissions(HANDLE token, PACL old_dacl, PSECURITY_DESCRIPTOR security_descriptor)
+{
+  SetSecurityInfoProt MySetSecurityInfo;
+  HMODULE advapi32;
+
+  /*
+   * This source file already uses advapi32.dll library, so it is
+   * linked to executable and automatically loaded when starting
+   * current running process.
+   */
+  advapi32 = GetModuleHandle(TEXT("advapi32.dll"));
+  if (advapi32)
+    {
+      MySetSecurityInfo = (SetSecurityInfoProt)(LPVOID)GetProcAddress(advapi32, "SetSecurityInfo");
+      MySetSecurityInfo(token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, old_dacl, NULL);
+    }
+
+  LocalFree(security_descriptor);
+  CloseHandle(token);
+}
+
+/*
+ * Open process handle specified by the process id with the query right and
+ * optionally also with vm read right.
+ */
+static HANDLE
+open_process_for_query(DWORD pid, BOOL with_vm_read)
+{
+  BOOL revert_only_privilege;
+  LUID luid_debug_privilege;
+  OSVERSIONINFO version;
+  DWORD process_right;
+  HANDLE revert_token;
+  HANDLE process;
+
+  /*
+   * Some processes on Windows Vista and higher systems can be opened only
+   * with PROCESS_QUERY_LIMITED_INFORMATION right. This right is enough
+   * for accessing primary process token. But this right is not supported
+   * on older pre-Vista systems. When the current thread on these older
+   * systems does not have Debug privilege then OpenProcess() fails with
+   * ERROR_ACCESS_DENIED. If the current thread has Debug privilege then
+   * OpenProcess() success and returns handle to requested process.
+   * Problem is that this handle does not have PROCESS_QUERY_INFORMATION
+   * right and so cannot be used for accessing primary process token
+   * on those older systems. Moreover it has zero rights and therefore
+   * such handle is fully useless. So never try to use open process with
+   * PROCESS_QUERY_LIMITED_INFORMATION right on older systems than
+   * Windows Vista (NT 6.0).
+   */
+  version.dwOSVersionInfoSize = sizeof(version);
+  if (GetVersionEx(&version) &&
+      version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+      version.dwMajorVersion >= 6)
+    process_right = PROCESS_QUERY_LIMITED_INFORMATION;
+  else
+    process_right = PROCESS_QUERY_INFORMATION;
+
+  if (with_vm_read)
+    process_right |= PROCESS_VM_READ;
+
+  process = OpenProcess(process_right, FALSE, pid);
+  if (process)
+    return process;
+
+  /*
+   * It is possible to open only processes to which owner of the current
+   * thread access token has permissions. For opening other processing it
+   * is required to have Debug privilege enabled. By default local
+   * administrators have this privilege, but it is disabled. So try to
+   * enable it and then try to open process again.
+   */
+
+  if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid_debug_privilege))
+    return NULL;
+
+  if (!win32_enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
+    return NULL;
+
+  process = OpenProcess(process_right, FALSE, pid);
+
+  win32_revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
+
+  return process;
+}
+
+/*
+ * Check if process image path name (wide string) matches exe file name
+ * (7-bit ASCII string). Do case-insensitive string comparison. Process
+ * image path name can be in any namespace format (DOS, Win32, UNC, ...).
+ */
+static BOOL
+check_process_name(LPCWSTR path, DWORD path_length, LPCSTR exe_file)
+{
+  DWORD exe_file_length;
+  WCHAR c1;
+  UCHAR c2;
+  DWORD i;
+
+  exe_file_length = 0;
+  while (exe_file[exe_file_length] != '\0')
+    exe_file_length++;
+
+  /* Path must have backslash before exe file name. */
+  if (exe_file_length >= path_length ||
+      path[path_length-exe_file_length-1] != L'\\')
+    return FALSE;
+
+  for (i = 0; i < exe_file_length; i++)
+    {
+      c1 = path[path_length-exe_file_length+i];
+      c2 = exe_file[i];
+      /*
+       * Input string for comparison is 7-bit ASCII and file name part
+       * of path must not contain backslash as it is path separator.
+       */
+      if (c1 >= 0x80 || c2 >= 0x80 || c1 == L'\\')
+        return FALSE;
+      if (c1 >= L'a' && c1 <= L'z')
+        c1 -= L'a' - L'A';
+      if (c2 >= 'a' && c2 <= 'z')
+        c2 -= 'a' - 'A';
+      if (c1 != c2)
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* Open process handle with the query right specified by process exe file. */
+HANDLE
+win32_find_and_open_process_for_query(LPCSTR exe_file)
+{
+  GetProcessImageFileNameWProt MyGetProcessImageFileNameW;
+  GetModuleFileNameExWProt MyGetModuleFileNameExW;
+  EnumProcessesProt MyEnumProcesses;
+  HMODULE kernel32, psapi;
+  UINT prev_error_mode;
+  DWORD partial_retry;
+  BOOL found_process;
+  DWORD size, length;
+  DWORD *processes;
+  HANDLE process;
+  LPWSTR path;
+  DWORD error;
+  DWORD count;
+  DWORD i;
+
+  psapi = NULL;
+  kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+  if (!kernel32)
+    return NULL;
+
+  /*
+   * On Windows 7 and higher systems these functions are available in
+   * kernel32.dll library with K32 prefix.
+   */
+  MyGetModuleFileNameExW = NULL;
+  MyGetProcessImageFileNameW = (GetProcessImageFileNameWProt)(LPVOID)GetProcAddress(kernel32, "K32GetProcessImageFileNameW");
+  MyEnumProcesses = (EnumProcessesProt)(LPVOID)GetProcAddress(kernel32, "K32EnumProcesses");
+  if (!MyGetProcessImageFileNameW || !MyEnumProcesses)
+    {
+      /*
+       * On older NT-based systems these functions are available in
+       * psapi.dll library without K32 prefix.
+       */
+      prev_error_mode = win32_change_error_mode(SEM_FAILCRITICALERRORS);
+      psapi = LoadLibrary(TEXT("psapi.dll"));
+      win32_change_error_mode(prev_error_mode);
+
+      if (!psapi)
+        return NULL;
+
+      /*
+       * Function GetProcessImageFileNameW() is available in
+       * Windows XP and higher systems. On older versions is
+       * available function GetModuleFileNameExW().
+       */
+      MyGetProcessImageFileNameW = (GetProcessImageFileNameWProt)(LPVOID)GetProcAddress(psapi, "GetProcessImageFileNameW");
+      MyGetModuleFileNameExW = (GetModuleFileNameExWProt)(LPVOID)GetProcAddress(psapi, "GetModuleFileNameExW");
+      MyEnumProcesses = (EnumProcessesProt)(LPVOID)GetProcAddress(psapi, "EnumProcesses");
+      if ((!MyGetProcessImageFileNameW && !MyGetModuleFileNameExW) || !MyEnumProcesses)
+        {
+          FreeLibrary(psapi);
+          return NULL;
+        }
+    }
+
+  /* Make initial buffer size for 1024 processes. */
+  size = 1024 * sizeof(*processes);
+
+retry:
+  processes = (DWORD *)LocalAlloc(LPTR, size);
+  if (!processes)
+    {
+      if (psapi)
+        FreeLibrary(psapi);
+      return NULL;
+    }
+
+  if (!MyEnumProcesses(processes, size, &length))
+    {
+      LocalFree(processes);
+      if (psapi)
+        FreeLibrary(psapi);
+      return NULL;
+    }
+  else if (size == length)
+    {
+      /*
+       * There is no indication given when the buffer is too small to
+       * store all process identifiers. Therefore if returned length
+       * is same as buffer size there can be more processes. Call
+       * again with larger buffer.
+       */
+      LocalFree(processes);
+      size *= 2;
+      goto retry;
+    }
+
+  process = NULL;
+  count = length / sizeof(*processes);
+
+  for (i = 0; i < count; i++)
+    {
+      /* Skip System Idle Process. */
+      if (processes[i] == 0)
+        continue;
+
+      /*
+       * Function GetModuleFileNameExW() requires additional
+       * PROCESS_VM_READ right as opposite to function
+       * GetProcessImageFileNameW() which does not need it.
+       */
+      process = open_process_for_query(processes[i], MyGetProcessImageFileNameW ? FALSE : TRUE);
+      if (!process)
+        continue;
+
+      /*
+       * Set initial buffer size to 256 (wide) characters.
+       * Final path length on the modern NT-based systems can be also larger.
+       */
+      size = 256;
+      found_process = FALSE;
+      partial_retry = 0;
+
+retry_path:
+      path = (LPWSTR)LocalAlloc(LPTR, size * sizeof(*path));
+      if (!path)
+        goto end_path;
+
+      if (MyGetProcessImageFileNameW)
+        length = MyGetProcessImageFileNameW(process, path, size);
+      else
+        length = MyGetModuleFileNameExW(process, NULL, path, size);
+
+      error = GetLastError();
+
+      /*
+       * GetModuleFileNameEx() returns zero and signal error ERROR_PARTIAL_COPY
+       * when remote process is in the middle of updating its module table.
+       * Sleep 10 ms and try again, max 10 attempts.
+       */
+      if (!MyGetProcessImageFileNameW)
+        {
+          if (length == 0 && error == ERROR_PARTIAL_COPY && partial_retry++ < 10)
+            {
+              Sleep(10);
+              goto retry_path;
+            }
+          partial_retry = 0;
+        }
+
+      /*
+       * When buffer is too small then function GetModuleFileNameEx() returns
+       * its size argument on older systems (Windows XP) or its size minus
+       * argument one on new systems (Windows 10) without signalling any error.
+       * Function GetProcessImageFileNameW() on the other hand returns zero
+       * value and signals error ERROR_INSUFFICIENT_BUFFER. So in all these
+       * cases call function again with larger buffer.
+       */
+
+      if (MyGetProcessImageFileNameW && length == 0 && error != ERROR_INSUFFICIENT_BUFFER)
+        goto end_path;
+
+      if ((MyGetProcessImageFileNameW && length == 0) ||
+          (!MyGetProcessImageFileNameW && (length == size || length == size-1)))
+        {
+          LocalFree(path);
+          size *= 2;
+          goto retry_path;
+        }
+
+      if (length && check_process_name(path, length, exe_file))
+        found_process = TRUE;
+
+end_path:
+      if (path)
+        {
+          LocalFree(path);
+          path = NULL;
+        }
+
+      if (found_process)
+        break;
+
+      CloseHandle(process);
+      process = NULL;
+    }
+
+  LocalFree(processes);
+
+  if (psapi)
+    FreeLibrary(psapi);
+
+  return process;
+}
+
+/*
+ * Try to open primary access token of the particular process with specified
+ * rights. Before opening access token try to adjust DACL permissions of the
+ * primary process access token, so following open does not fail on error
+ * related to no open permissions. Revert DACL permissions after open attempt.
+ * As following steps are not atomic, try to execute them more times in case
+ * of possible race conditions caused by other threads or processes.
+ */
+static HANDLE
+try_grant_permissions_and_open_process_token(HANDLE process, DWORD rights)
+{
+  PSECURITY_DESCRIPTOR security_descriptor;
+  HANDLE grant_token;
+  PACL old_dacl;
+  HANDLE token;
+  DWORD retry;
+  DWORD error;
+
+  /*
+   * This code is not atomic. Between grant and open calls can other
+   * thread or process change or revert permissions. So try to execute
+   * it more times.
+   */
+  for (retry = 0; retry < 10; retry++)
+    {
+      if (!grant_process_token_dacl_permissions(process, rights, &grant_token, &old_dacl, &security_descriptor))
+        return NULL;
+      if (!OpenProcessToken(process, rights, &token))
+        {
+          token = NULL;
+          error = GetLastError();
+        }
+      revert_token_dacl_permissions(grant_token, old_dacl, security_descriptor);
+      if (token)
+        return token;
+      else if (error != ERROR_ACCESS_DENIED)
+        return NULL;
+    }
+
+  return NULL;
+}
+
+/*
+ * Open primary access token of particular process handle with specified rights.
+ * If permissions for specified rights are missing then try to grant them.
+ */
+HANDLE
+win32_open_process_token_with_rights(HANDLE process, DWORD rights)
+{
+  HANDLE old_token;
+  HANDLE token;
+
+  /* First try to open primary access token of process handle directly. */
+  if (OpenProcessToken(process, rights, &token))
+    return token;
+
+  /*
+   * If opening failed then it means that owner of the current thread
+   * access token does not have permission for it. Try it again with
+   * primary process access token.
+   */
+  if (change_token_to_primary(&old_token))
+    {
+      if (!OpenProcessToken(process, rights, &token))
+        token = NULL;
+      win32_revert_to_token(old_token);
+      if (token)
+        return token;
+    }
+
+  /*
+   * If opening is still failing then try to grant specified permissions
+   * for the current thread and try to open it again.
+   */
+  token = try_grant_permissions_and_open_process_token(process, rights);
+  if (token)
+    return token;
+
+  /*
+   * And if it is still failing then try it again with granting
+   * permissions for the primary process token of the current process.
+   */
+  if (change_token_to_primary(&old_token))
+    {
+      token = try_grant_permissions_and_open_process_token(process, rights);
+      win32_revert_to_token(old_token);
+      if (token)
+        return token;
+    }
+
+  /*
+   * TODO: Sorry, no other option for now...
+   * It could be possible to use Take Ownership Name privilege to
+   * temporary change token owner of specified process to the owner of
+   * the current thread token, grant permissions for current thread in
+   * that process token, change ownership back to original one, open
+   * that process token and revert granted permissions. But this is
+   * not implemented yet.
+   */
+  return NULL;
+}
index 18f75dea6c3794526d3c05e36bb27e2167718da3..e5f44453d54caf06d01834fa0500a175109ca88b 100644 (file)
@@ -2,3 +2,11 @@ const char *win32_strerror(DWORD win32_error_id);
 BOOL win32_is_non_nt_system(void);
 BOOL win32_is_32bit_on_64bit_system(void);
 BOOL win32_is_32bit_on_win8_64bit_system(void);
+UINT win32_change_error_mode(UINT new_mode);
+BOOL win32_have_privilege(LUID luid_privilege);
+BOOL win32_enable_privilege(LUID luid_privilege, HANDLE *revert_token, BOOL *revert_only_privilege);
+VOID win32_revert_privilege(LUID luid_privilege, HANDLE revert_token, BOOL revert_only_privilege);
+BOOL win32_change_token(HANDLE new_token, HANDLE *old_token);
+VOID win32_revert_to_token(HANDLE token);
+HANDLE win32_find_and_open_process_for_query(LPCSTR exe_file);
+HANDLE win32_open_process_token_with_rights(HANDLE process, DWORD rights);
index bb005081e5f0d05941d3b0304fe01f3ff23012f7..33f57514f988a8866c513803442c18f6bd28df55 100644 (file)
@@ -15,7 +15,6 @@
 #include <string.h> /* for memset() and memcpy() */
 
 #include "internal.h"
-#include "i386-io-windows.h"
 #include "win32-helpers.h"
 
 #ifndef ERROR_NOT_FOUND
@@ -480,7 +479,7 @@ win32_kldbg_setup(struct pci_access *a)
       return 0;
     }
 
-  if (!enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
+  if (!win32_enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
     {
       a->debug("Process does not have right to enable Debug privilege.");
       CloseHandle(kldbg_dev);
@@ -502,7 +501,7 @@ win32_kldbg_setup(struct pci_access *a)
   CloseHandle(kldbg_dev);
   kldbg_dev = INVALID_HANDLE_VALUE;
 
-  revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
+  win32_revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
   revert_token = NULL;
   revert_only_privilege = FALSE;
   return 0;
@@ -538,7 +537,7 @@ win32_kldbg_cleanup(struct pci_access *a UNUSED)
 
   if (debug_privilege_enabled)
     {
-      revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
+      win32_revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
       revert_token = NULL;
       revert_only_privilege = FALSE;
       debug_privilege_enabled = FALSE;
index 22ecc602bf6cadf40d0e3ffdc2a91470f67f27a4..99ce607cb834b10925f135b4ad36aca9aa1f5103 100644 (file)
@@ -11,7 +11,6 @@
 #include <windows.h>
 
 #include "internal.h"
-#include "i386-io-windows.h"
 #include "win32-helpers.h"
 
 #ifndef NTSTATUS
@@ -126,9 +125,9 @@ win32_sysdbg_setup(struct pci_access *a)
   if (win32_sysdbg_initialized)
     return 1;
 
-  prev_error_mode = change_error_mode(SEM_FAILCRITICALERRORS);
+  prev_error_mode = win32_change_error_mode(SEM_FAILCRITICALERRORS);
   ntdll = LoadLibrary(TEXT("ntdll.dll"));
-  change_error_mode(prev_error_mode);
+  win32_change_error_mode(prev_error_mode);
   if (!ntdll)
     {
       a->debug("Cannot open ntdll.dll library.");
@@ -180,7 +179,7 @@ win32_sysdbg_setup(struct pci_access *a)
       return 0;
     }
 
-  if (!enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
+  if (!win32_enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
     {
       a->debug("Cannot enable Debug privilege.");
       FreeLibrary(ntdll);
@@ -198,7 +197,7 @@ win32_sysdbg_setup(struct pci_access *a)
       return 1;
     }
 
-  revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
+  win32_revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
   revert_token = NULL;
   revert_only_privilege = FALSE;
 
@@ -245,7 +244,7 @@ win32_sysdbg_cleanup(struct pci_access *a UNUSED)
 
   if (debug_privilege_enabled)
     {
-      revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
+      win32_revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
       revert_token = NULL;
       revert_only_privilege = FALSE;
       debug_privilege_enabled = FALSE;