[SPOOLSS]
[reactos.git] / reactos / win32ss / printing / base / spoolss / context.c
1 /*
2 * PROJECT: ReactOS Spooler Router
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
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()
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 }