mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 14:30:57 +00:00
104 lines
3.3 KiB
C
104 lines
3.3 KiB
C
/*
|
|
* PROJECT: ReactOS Spooler Router
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Functions related to switching between security contexts
|
|
* COPYRIGHT: Copyright 2015 Colin Finck (colin@reactos.org)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
/**
|
|
* @see RevertToPrinterSelf
|
|
*/
|
|
BOOL WINAPI
|
|
ImpersonatePrinterClient(HANDLE hToken)
|
|
{
|
|
DWORD cbReturned;
|
|
DWORD dwErrorCode;
|
|
TOKEN_TYPE Type;
|
|
|
|
// Sanity check
|
|
if (!hToken)
|
|
{
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the type of the supplied token.
|
|
if (!GetTokenInformation(hToken, TokenType, &Type, sizeof(TOKEN_TYPE), &cbReturned))
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
if (hToken)
|
|
CloseHandle(hToken);
|
|
|
|
SetLastError(dwErrorCode);
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
}
|
|
|
|
/**
|
|
* RevertToPrinterSelf reverts the security context from the current user's context back to the process context.
|
|
* As spoolss.dll is used by spoolsv.exe, this is usually the SYSTEM security context.
|
|
*
|
|
* Unlike the traditional ImpersonateClient and then RevertToSelf approach, we do it the other way round here,
|
|
* because spoolss.dll is delay-loaded by spoolsv.exe in the current user's context. Use RevertToPrinterSelf then to
|
|
* return to the SYSTEM context for specific tasks.
|
|
*/
|
|
HANDLE WINAPI
|
|
RevertToPrinterSelf(VOID)
|
|
{
|
|
DWORD dwErrorCode;
|
|
HANDLE hReturnValue = NULL;
|
|
HANDLE hToken = NULL;
|
|
|
|
// 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))
|
|
{
|
|
// Tell the thread to stop impersonating.
|
|
if (!SetThreadToken(NULL, NULL))
|
|
{
|
|
dwErrorCode = GetLastError();
|
|
ERR("SetThreadToken failed with error %lu!\n", dwErrorCode);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
|
{
|
|
dwErrorCode = GetLastError();
|
|
ERR("OpenProcessToken failed with error %lu!\n", dwErrorCode);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// 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;
|
|
}
|