From 3c798d710773ac83f24fb0362812aeeebe8f1094 Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Mon, 20 Jul 2015 16:15:52 +0000 Subject: [PATCH] [SPOOLSS] Rewrite RevertToPrinterSelf and ImpersonatePrinterClient. In contrast to what I first thought, they shall also work when the thread has no impersonation token. This occurs for example when spooler functions are called from a thread that doesn't originate from a RPC request. The rewritten functions also provide proper error codes. The native behaviour of these functions was verified through API Monitoring under Windows. svn path=/branches/colins-printing-for-freedom/; revision=68472 --- .../win32ss/printing/base/spoolss/context.c | 82 ++++++++++++++----- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/reactos/win32ss/printing/base/spoolss/context.c b/reactos/win32ss/printing/base/spoolss/context.c index ca39f5a57f9..649df49a15d 100644 --- a/reactos/win32ss/printing/base/spoolss/context.c +++ b/reactos/win32ss/printing/base/spoolss/context.c @@ -13,21 +13,43 @@ BOOL WINAPI ImpersonatePrinterClient(HANDLE hToken) { + DWORD cbReturned; + DWORD dwErrorCode; + TOKEN_TYPE Type; + + // Sanity check if (!hToken) { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; } - if (!SetThreadToken(NULL, hToken)) + // Get the type of the supplied token. + if (!GetTokenInformation(hToken, TokenType, &Type, sizeof(TOKEN_TYPE), &cbReturned)) { - ERR("SetThreadToken failed with error %lu!\n", GetLastError()); - CloseHandle(hToken); - return FALSE; + dwErrorCode = GetLastError(); + ERR("GetTokenInformation failed with error %lu!\n", dwErrorCode); + goto Cleanup; + } + + // Check if this is an impersonation token and only set it as the thread token in this case. + // This is not always an impersonation token, see RevertToPrinterSelf. + if (Type == TokenImpersonation) + { + if (!SetThreadToken(NULL, hToken)) + { + dwErrorCode = GetLastError(); + ERR("SetThreadToken failed with error %lu!\n", dwErrorCode); + goto Cleanup; + } } - CloseHandle(hToken); - return TRUE; +Cleanup: + if (hToken) + CloseHandle(hToken); + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } /** @@ -41,22 +63,42 @@ ImpersonatePrinterClient(HANDLE hToken) HANDLE WINAPI RevertToPrinterSelf() { - HANDLE hToken; + DWORD dwErrorCode; + HANDLE hReturnValue = NULL; + HANDLE hToken = NULL; - // Retrieve our current impersonation token - if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &hToken)) + // All spoolss code is usually called after impersonating the client. In this case, we can retrieve our current thread impersonation token using OpenThreadToken. + // 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. + // 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. + // This behaviour is verified with Windows! + if (OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &hToken)) { - ERR("OpenThreadToken failed with error %lu!\n", GetLastError()); - return NULL; + // Tell the thread to stop impersonating. + if (!SetThreadToken(NULL, NULL)) + { + dwErrorCode = GetLastError(); + ERR("SetThreadToken failed with error %lu!\n", dwErrorCode); + goto Cleanup; + } } - - // Tell the thread to stop impersonating - if (!SetThreadToken(NULL, NULL)) + else if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { - ERR("SetThreadToken failed with error %lu!\n", GetLastError()); - return NULL; + dwErrorCode = GetLastError(); + ERR("OpenProcessToken failed with error %lu!\n", dwErrorCode); + goto Cleanup; } - // Return the token required for reverting back to impersonation in ImpersonatePrinterClient - return hToken; + // We were successful, return a token! + dwErrorCode = ERROR_SUCCESS; + hReturnValue = hToken; + + // Don't let the cleanup routine close this. + hToken = NULL; + +Cleanup: + if (hToken) + CloseHandle(hToken); + + SetLastError(dwErrorCode); + return hReturnValue; } -- 2.17.1