1 /* 2 * PROJECT: ReactOS Spooler Router 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Functions related to switching between security contexts 5 * COPYRIGHT: Copyright 2015 Colin Finck (colin@reactos.org) 6 */ 7 8 #include "precomp.h" 9 10 /** 11 * @see RevertToPrinterSelf 12 */ 13 BOOL WINAPI 14 ImpersonatePrinterClient(HANDLE hToken) 15 { 16 DWORD cbReturned; 17 DWORD dwErrorCode; 18 TOKEN_TYPE Type; 19 20 // Sanity check 21 if (!hToken) 22 { 23 dwErrorCode = ERROR_INVALID_HANDLE; 24 goto Cleanup; 25 } 26 27 // Get the type of the supplied token. 28 if (!GetTokenInformation(hToken, TokenType, &Type, sizeof(TOKEN_TYPE), &cbReturned)) 29 { 30 dwErrorCode = GetLastError(); 31 ERR("GetTokenInformation failed with error %lu!\n", dwErrorCode); 32 goto Cleanup; 33 } 34 35 // Check if this is an impersonation token and only set it as the thread token in this case. 36 // This is not always an impersonation token, see RevertToPrinterSelf. 37 if (Type == TokenImpersonation) 38 { 39 if (!SetThreadToken(NULL, hToken)) 40 { 41 dwErrorCode = GetLastError(); 42 ERR("SetThreadToken failed with error %lu!\n", dwErrorCode); 43 goto Cleanup; 44 } 45 } 46 47 Cleanup: 48 if (hToken) 49 CloseHandle(hToken); 50 51 SetLastError(dwErrorCode); 52 return (dwErrorCode == ERROR_SUCCESS); 53 } 54 55 /** 56 * RevertToPrinterSelf reverts the security context from the current user's context back to the process context. 57 * As spoolss.dll is used by spoolsv.exe, this is usually the SYSTEM security context. 58 * 59 * Unlike the traditional ImpersonateClient and then RevertToSelf approach, we do it the other way round here, 60 * because spoolss.dll is delay-loaded by spoolsv.exe in the current user's context. Use RevertToPrinterSelf then to 61 * return to the SYSTEM context for specific tasks. 62 */ 63 HANDLE WINAPI 64 RevertToPrinterSelf(VOID) 65 { 66 DWORD dwErrorCode; 67 HANDLE hReturnValue = NULL; 68 HANDLE hToken = NULL; 69 70 // All spoolss code is usually called after impersonating the client. In this case, we can retrieve our current thread impersonation token using OpenThreadToken. 71 // But in rare occasions, spoolss code is also called from a higher-privileged thread that doesn't impersonate the client. Then we don't get an impersonation token. 72 // Anyway, we can't just return nothing in this case, because this is being treated as failure by the caller. So we return the token of the current process. 73 // This behaviour is verified with Windows! 74 if (OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &hToken)) 75 { 76 // Tell the thread to stop impersonating. 77 if (!SetThreadToken(NULL, NULL)) 78 { 79 dwErrorCode = GetLastError(); 80 ERR("SetThreadToken failed with error %lu!\n", dwErrorCode); 81 goto Cleanup; 82 } 83 } 84 else if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) 85 { 86 dwErrorCode = GetLastError(); 87 ERR("OpenProcessToken failed with error %lu!\n", dwErrorCode); 88 goto Cleanup; 89 } 90 91 // We were successful, return a token! 92 dwErrorCode = ERROR_SUCCESS; 93 hReturnValue = hToken; 94 95 // Don't let the cleanup routine close this. 96 hToken = NULL; 97 98 Cleanup: 99 if (hToken) 100 CloseHandle(hToken); 101 102 SetLastError(dwErrorCode); 103 return hReturnValue; 104 } 105