1c2c66affSColin Finck /*
2c2c66affSColin Finck * PROJECT: ReactOS Kernel
3c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory
4c2c66affSColin Finck * FILE: ntoskrnl/ps/security.c
5c2c66affSColin Finck * PURPOSE: Process Manager: Process/Thread Security
6c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7c2c66affSColin Finck * Eric Kohl
8c2c66affSColin Finck * Thomas Weidenmueller (w3seek@reactos.org)
9c2c66affSColin Finck */
10c2c66affSColin Finck
11c2c66affSColin Finck /* INCLUDES ******************************************************************/
12c2c66affSColin Finck
13c2c66affSColin Finck #include <ntoskrnl.h>
14c2c66affSColin Finck #define NDEBUG
15c2c66affSColin Finck #include <debug.h>
16c2c66affSColin Finck
17c2c66affSColin Finck PTOKEN PspBootAccessToken;
18c2c66affSColin Finck
19c2c66affSColin Finck VOID
20c2c66affSColin Finck NTAPI
21c2c66affSColin Finck SeAssignPrimaryToken(
22c2c66affSColin Finck IN PEPROCESS Process,
23c2c66affSColin Finck IN PTOKEN Token
24c2c66affSColin Finck );
25c2c66affSColin Finck
26c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/
27c2c66affSColin Finck
28c2c66affSColin Finck VOID
29c2c66affSColin Finck NTAPI
PspDeleteProcessSecurity(IN PEPROCESS Process)30c2c66affSColin Finck PspDeleteProcessSecurity(IN PEPROCESS Process)
31c2c66affSColin Finck {
32c2c66affSColin Finck PAGED_CODE();
33c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
34c2c66affSColin Finck
35c2c66affSColin Finck /* Check if we have a token */
36c2c66affSColin Finck if (Process->Token.Object)
37c2c66affSColin Finck {
38c2c66affSColin Finck /* Deassign it */
39c2c66affSColin Finck SeDeassignPrimaryToken(Process);
40c2c66affSColin Finck Process->Token.Object = NULL;
41c2c66affSColin Finck }
42c2c66affSColin Finck }
43c2c66affSColin Finck
44c2c66affSColin Finck VOID
45c2c66affSColin Finck NTAPI
PspDeleteThreadSecurity(IN PETHREAD Thread)46c2c66affSColin Finck PspDeleteThreadSecurity(IN PETHREAD Thread)
47c2c66affSColin Finck {
48c2c66affSColin Finck PPS_IMPERSONATION_INFORMATION ImpersonationInfo = Thread->ImpersonationInfo;
49c2c66affSColin Finck PAGED_CODE();
50c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
51c2c66affSColin Finck
52c2c66affSColin Finck /* Check if we have active impersonation info */
53c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
54c2c66affSColin Finck {
55c2c66affSColin Finck /* Dereference its token */
56c2c66affSColin Finck ObDereferenceObject(ImpersonationInfo->Token);
57c2c66affSColin Finck }
58c2c66affSColin Finck
59c2c66affSColin Finck /* Check if we have impersonation info */
60c2c66affSColin Finck if (ImpersonationInfo)
61c2c66affSColin Finck {
62c2c66affSColin Finck /* Free it */
63c2c66affSColin Finck ExFreePool(ImpersonationInfo);
64c2c66affSColin Finck PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
65c2c66affSColin Finck Thread->ImpersonationInfo = NULL;
66c2c66affSColin Finck }
67c2c66affSColin Finck }
68c2c66affSColin Finck
69c2c66affSColin Finck NTSTATUS
70c2c66affSColin Finck NTAPI
PspInitializeProcessSecurity(IN PEPROCESS Process,IN PEPROCESS Parent OPTIONAL)71c2c66affSColin Finck PspInitializeProcessSecurity(IN PEPROCESS Process,
72c2c66affSColin Finck IN PEPROCESS Parent OPTIONAL)
73c2c66affSColin Finck {
74c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS;
75c2c66affSColin Finck PTOKEN NewToken, ParentToken;
76c2c66affSColin Finck PAGED_CODE();
77c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
78c2c66affSColin Finck
79c2c66affSColin Finck /* If we have a parent, then duplicate the Token */
80c2c66affSColin Finck if (Parent)
81c2c66affSColin Finck {
82c2c66affSColin Finck /* Get the Parent Token */
83c2c66affSColin Finck ParentToken = PsReferencePrimaryToken(Parent);
84c2c66affSColin Finck
85c2c66affSColin Finck /* Duplicate it */
86c2c66affSColin Finck Status = SeSubProcessToken(ParentToken,
87c2c66affSColin Finck &NewToken,
88c2c66affSColin Finck TRUE,
89c2c66affSColin Finck MmGetSessionId(Process));
90c2c66affSColin Finck
91c2c66affSColin Finck /* Dereference the Parent */
92c2c66affSColin Finck ObFastDereferenceObject(&Parent->Token, ParentToken);
93c2c66affSColin Finck
94c2c66affSColin Finck /* Set the new Token */
95c2c66affSColin Finck if (NT_SUCCESS(Status))
96c2c66affSColin Finck {
97c2c66affSColin Finck /* Initailize the fast reference */
98c2c66affSColin Finck ObInitializeFastReference(&Process->Token, NewToken);
99c2c66affSColin Finck }
100c2c66affSColin Finck }
101c2c66affSColin Finck else
102c2c66affSColin Finck {
103c2c66affSColin Finck /* No parent, assign the Boot Token */
104c2c66affSColin Finck ObInitializeFastReference(&Process->Token, NULL);
105c2c66affSColin Finck SeAssignPrimaryToken(Process, PspBootAccessToken);
106c2c66affSColin Finck }
107c2c66affSColin Finck
108c2c66affSColin Finck /* Return to caller */
109c2c66affSColin Finck return Status;
110c2c66affSColin Finck }
111c2c66affSColin Finck
112c2c66affSColin Finck NTSTATUS
113c2c66affSColin Finck NTAPI
PspWriteTebImpersonationInfo(IN PETHREAD Thread,IN PETHREAD CurrentThread)114c2c66affSColin Finck PspWriteTebImpersonationInfo(IN PETHREAD Thread,
115c2c66affSColin Finck IN PETHREAD CurrentThread)
116c2c66affSColin Finck {
117c2c66affSColin Finck PEPROCESS Process;
118c2c66affSColin Finck PTEB Teb;
119c2c66affSColin Finck BOOLEAN Attached = FALSE;
120c2c66affSColin Finck BOOLEAN IsImpersonating;
121c2c66affSColin Finck KAPC_STATE ApcState;
122c2c66affSColin Finck PAGED_CODE();
123c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
124c2c66affSColin Finck
125c2c66affSColin Finck /* Sanity check */
126c2c66affSColin Finck ASSERT(CurrentThread == PsGetCurrentThread());
127c2c66affSColin Finck
128c2c66affSColin Finck /* Get process and TEB */
129c2c66affSColin Finck Process = Thread->ThreadsProcess;
130c2c66affSColin Finck Teb = Thread->Tcb.Teb;
131c2c66affSColin Finck if (Teb)
132c2c66affSColin Finck {
133c2c66affSColin Finck /* Check if we're not in the right process */
134c2c66affSColin Finck if (Thread->Tcb.ApcState.Process != &Process->Pcb)
135c2c66affSColin Finck {
136c2c66affSColin Finck /* Attach to the process */
137c2c66affSColin Finck KeStackAttachProcess(&Process->Pcb, &ApcState);
138c2c66affSColin Finck Attached = TRUE;
139c2c66affSColin Finck }
140c2c66affSColin Finck
141c2c66affSColin Finck /* Check if we're in a different thread or acquire rundown */
142c2c66affSColin Finck if ((Thread == CurrentThread) ||
143c2c66affSColin Finck (ExAcquireRundownProtection(&Thread->RundownProtect)))
144c2c66affSColin Finck {
145c2c66affSColin Finck /* Check if the thread is impersonating */
146c2c66affSColin Finck IsImpersonating = (BOOLEAN)Thread->ActiveImpersonationInfo;
147c2c66affSColin Finck if (IsImpersonating)
148c2c66affSColin Finck {
149c2c66affSColin Finck /* Set TEB data */
150c2c66affSColin Finck Teb->ImpersonationLocale = -1;
151c2c66affSColin Finck Teb->IsImpersonating = 1;
152c2c66affSColin Finck }
153c2c66affSColin Finck else
154c2c66affSColin Finck {
155c2c66affSColin Finck /* Set TEB data */
156c2c66affSColin Finck Teb->ImpersonationLocale = 0;
157c2c66affSColin Finck Teb->IsImpersonating = 0;
158c2c66affSColin Finck }
159c2c66affSColin Finck }
160c2c66affSColin Finck
161c2c66affSColin Finck /* Check if we're in a different thread */
162c2c66affSColin Finck if (Thread != CurrentThread)
163c2c66affSColin Finck {
164c2c66affSColin Finck /* Release protection */
165c2c66affSColin Finck ExReleaseRundownProtection(&Thread->RundownProtect);
166c2c66affSColin Finck }
167c2c66affSColin Finck
168c2c66affSColin Finck /* Detach */
169c2c66affSColin Finck if (Attached) KeUnstackDetachProcess(&ApcState);
170c2c66affSColin Finck }
171c2c66affSColin Finck
172c2c66affSColin Finck /* Return to caller */
173c2c66affSColin Finck return STATUS_SUCCESS;
174c2c66affSColin Finck }
175c2c66affSColin Finck
176c2c66affSColin Finck NTSTATUS
177c2c66affSColin Finck NTAPI
PspAssignPrimaryToken(IN PEPROCESS Process,IN HANDLE Token,IN PACCESS_TOKEN AccessToken OPTIONAL)178c2c66affSColin Finck PspAssignPrimaryToken(IN PEPROCESS Process,
179c2c66affSColin Finck IN HANDLE Token,
180c2c66affSColin Finck IN PACCESS_TOKEN AccessToken OPTIONAL)
181c2c66affSColin Finck {
182c2c66affSColin Finck PACCESS_TOKEN NewToken = AccessToken, OldToken;
183c2c66affSColin Finck NTSTATUS Status;
184c2c66affSColin Finck PAGED_CODE();
185c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
186c2c66affSColin Finck
187c2c66affSColin Finck /* Check if we don't have a pointer */
188c2c66affSColin Finck if (!AccessToken)
189c2c66affSColin Finck {
190c2c66affSColin Finck /* Reference it from the handle */
191c2c66affSColin Finck Status = ObReferenceObjectByHandle(Token,
192c2c66affSColin Finck TOKEN_ASSIGN_PRIMARY,
193c2c66affSColin Finck SeTokenObjectType,
194c2c66affSColin Finck ExGetPreviousMode(),
195c2c66affSColin Finck &NewToken,
196c2c66affSColin Finck NULL);
197c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status;
198c2c66affSColin Finck }
199c2c66affSColin Finck
200c2c66affSColin Finck /* Exchange tokens */
201c2c66affSColin Finck Status = SeExchangePrimaryToken(Process, NewToken, &OldToken);
202c2c66affSColin Finck
203c2c66affSColin Finck /* Acquire and release the lock */
204c2c66affSColin Finck PspLockProcessSecurityExclusive(Process);
205c2c66affSColin Finck PspUnlockProcessSecurityExclusive(Process);
206c2c66affSColin Finck
207c2c66affSColin Finck /* Dereference Tokens and Return */
208c2c66affSColin Finck if (NT_SUCCESS(Status)) ObDereferenceObject(OldToken);
209c2c66affSColin Finck if (!AccessToken) ObDereferenceObject(NewToken);
210c2c66affSColin Finck return Status;
211c2c66affSColin Finck }
212c2c66affSColin Finck
213c2c66affSColin Finck NTSTATUS
214c2c66affSColin Finck NTAPI
PspSetPrimaryToken(IN PEPROCESS Process,IN HANDLE TokenHandle OPTIONAL,IN PACCESS_TOKEN Token OPTIONAL)215c2c66affSColin Finck PspSetPrimaryToken(IN PEPROCESS Process,
216c2c66affSColin Finck IN HANDLE TokenHandle OPTIONAL,
217c2c66affSColin Finck IN PACCESS_TOKEN Token OPTIONAL)
218c2c66affSColin Finck {
219c2c66affSColin Finck KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
22089c5191dSHermès Bélusca-Maïto BOOLEAN IsChildOrSibling;
221c2c66affSColin Finck PACCESS_TOKEN NewToken = Token;
222c2c66affSColin Finck NTSTATUS Status, AccessStatus;
223c2c66affSColin Finck BOOLEAN Result, SdAllocated;
224c2c66affSColin Finck PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
225c2c66affSColin Finck SECURITY_SUBJECT_CONTEXT SubjectContext;
22689c5191dSHermès Bélusca-Maïto
227c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
228c2c66affSColin Finck
22989c5191dSHermès Bélusca-Maïto /* Reference the token by handle if we don't already have a token object */
23089c5191dSHermès Bélusca-Maïto if (!Token)
231c2c66affSColin Finck {
232c2c66affSColin Finck Status = ObReferenceObjectByHandle(TokenHandle,
233c2c66affSColin Finck TOKEN_ASSIGN_PRIMARY,
234c2c66affSColin Finck SeTokenObjectType,
235c2c66affSColin Finck PreviousMode,
236c2c66affSColin Finck (PVOID*)&NewToken,
237c2c66affSColin Finck NULL);
238c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status;
239c2c66affSColin Finck }
240c2c66affSColin Finck
24189c5191dSHermès Bélusca-Maïto /*
24289c5191dSHermès Bélusca-Maïto * Check whether this token is a child or sibling of the current process token.
24389c5191dSHermès Bélusca-Maïto * NOTE: On Windows Vista+ both of these checks (together with extra steps)
24489c5191dSHermès Bélusca-Maïto * are now performed by a new SeIsTokenAssignableToProcess() helper.
24589c5191dSHermès Bélusca-Maïto */
24689c5191dSHermès Bélusca-Maïto Status = SeIsTokenChild(NewToken, &IsChildOrSibling);
247c2c66affSColin Finck if (!NT_SUCCESS(Status))
248c2c66affSColin Finck {
249c2c66affSColin Finck /* Failed, dereference */
25089c5191dSHermès Bélusca-Maïto if (!Token) ObDereferenceObject(NewToken);
251c2c66affSColin Finck return Status;
252c2c66affSColin Finck }
25389c5191dSHermès Bélusca-Maïto if (!IsChildOrSibling)
25489c5191dSHermès Bélusca-Maïto {
25589c5191dSHermès Bélusca-Maïto Status = SeIsTokenSibling(NewToken, &IsChildOrSibling);
25689c5191dSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
25789c5191dSHermès Bélusca-Maïto {
25889c5191dSHermès Bélusca-Maïto /* Failed, dereference */
25989c5191dSHermès Bélusca-Maïto if (!Token) ObDereferenceObject(NewToken);
26089c5191dSHermès Bélusca-Maïto return Status;
26189c5191dSHermès Bélusca-Maïto }
26289c5191dSHermès Bélusca-Maïto }
263c2c66affSColin Finck
264c2c66affSColin Finck /* Check if this was an independent token */
26589c5191dSHermès Bélusca-Maïto if (!IsChildOrSibling)
266c2c66affSColin Finck {
267c2c66affSColin Finck /* Make sure we have the privilege to assign a new one */
268c2c66affSColin Finck if (!SeSinglePrivilegeCheck(SeAssignPrimaryTokenPrivilege,
269c2c66affSColin Finck PreviousMode))
270c2c66affSColin Finck {
271c2c66affSColin Finck /* Failed, dereference */
27289c5191dSHermès Bélusca-Maïto if (!Token) ObDereferenceObject(NewToken);
273c2c66affSColin Finck return STATUS_PRIVILEGE_NOT_HELD;
274c2c66affSColin Finck }
275c2c66affSColin Finck }
276c2c66affSColin Finck
277c2c66affSColin Finck /* Assign the token */
278c2c66affSColin Finck Status = PspAssignPrimaryToken(Process, NULL, NewToken);
279c2c66affSColin Finck if (NT_SUCCESS(Status))
280c2c66affSColin Finck {
281c2c66affSColin Finck /*
282c2c66affSColin Finck * We need to completely reverify if the process still has access to
283c2c66affSColin Finck * itself under this new token.
284c2c66affSColin Finck */
285c2c66affSColin Finck Status = ObGetObjectSecurity(Process,
286c2c66affSColin Finck &SecurityDescriptor,
287c2c66affSColin Finck &SdAllocated);
288c2c66affSColin Finck if (NT_SUCCESS(Status))
289c2c66affSColin Finck {
290c2c66affSColin Finck /* Setup the security context */
291c2c66affSColin Finck SubjectContext.ProcessAuditId = Process;
292c2c66affSColin Finck SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
293c2c66affSColin Finck SubjectContext.ClientToken = NULL;
294c2c66affSColin Finck
295c2c66affSColin Finck /* Do the access check */
296c2c66affSColin Finck Result = SeAccessCheck(SecurityDescriptor,
297c2c66affSColin Finck &SubjectContext,
298c2c66affSColin Finck FALSE,
299c2c66affSColin Finck MAXIMUM_ALLOWED,
300c2c66affSColin Finck 0,
301c2c66affSColin Finck NULL,
302c2c66affSColin Finck &PsProcessType->TypeInfo.GenericMapping,
303c2c66affSColin Finck PreviousMode,
304c2c66affSColin Finck &Process->GrantedAccess,
305c2c66affSColin Finck &AccessStatus);
306c2c66affSColin Finck
307c2c66affSColin Finck /* Dereference the token and let go the SD */
308c2c66affSColin Finck ObFastDereferenceObject(&Process->Token,
309c2c66affSColin Finck SubjectContext.PrimaryToken);
310c2c66affSColin Finck ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
311c2c66affSColin Finck
312c2c66affSColin Finck /* Remove access if it failed */
313c2c66affSColin Finck if (!Result) Process->GrantedAccess = 0;
314c2c66affSColin Finck
315c2c66affSColin Finck /* Setup granted access */
316c2c66affSColin Finck Process->GrantedAccess |= (PROCESS_VM_OPERATION |
317c2c66affSColin Finck PROCESS_VM_READ |
318c2c66affSColin Finck PROCESS_VM_WRITE |
319c2c66affSColin Finck PROCESS_QUERY_INFORMATION |
320c2c66affSColin Finck PROCESS_TERMINATE |
321c2c66affSColin Finck PROCESS_CREATE_THREAD |
322c2c66affSColin Finck PROCESS_DUP_HANDLE |
323c2c66affSColin Finck PROCESS_CREATE_PROCESS |
324c2c66affSColin Finck PROCESS_SET_INFORMATION |
325c2c66affSColin Finck STANDARD_RIGHTS_ALL |
326c2c66affSColin Finck PROCESS_SET_QUOTA);
327c2c66affSColin Finck }
328f8a4d31dSPierre Schweitzer
329f8a4d31dSPierre Schweitzer /*
330f8a4d31dSPierre Schweitzer * In case LUID device maps are enable, we may not be using
331f8a4d31dSPierre Schweitzer * system device map for this process, but a logon LUID based
332f8a4d31dSPierre Schweitzer * device map. Because we change primary token, this usage is
333f8a4d31dSPierre Schweitzer * no longer valid, so dereference the process device map
334f8a4d31dSPierre Schweitzer */
335f8a4d31dSPierre Schweitzer if (ObIsLUIDDeviceMapsEnabled()) ObDereferenceDeviceMap(Process);
336c2c66affSColin Finck }
337c2c66affSColin Finck
338c2c66affSColin Finck /* Dereference the token */
33989c5191dSHermès Bélusca-Maïto if (!Token) ObDereferenceObject(NewToken);
340c2c66affSColin Finck return Status;
341c2c66affSColin Finck }
342c2c66affSColin Finck
343c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
344c2c66affSColin Finck
345c2c66affSColin Finck /*
346c2c66affSColin Finck * @implemented
347c2c66affSColin Finck */
348c2c66affSColin Finck NTSTATUS
349c2c66affSColin Finck NTAPI
NtOpenProcessToken(IN HANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,OUT PHANDLE TokenHandle)350c2c66affSColin Finck NtOpenProcessToken(IN HANDLE ProcessHandle,
351c2c66affSColin Finck IN ACCESS_MASK DesiredAccess,
352c2c66affSColin Finck OUT PHANDLE TokenHandle)
353c2c66affSColin Finck {
354c2c66affSColin Finck /* Call the newer API */
355c2c66affSColin Finck return NtOpenProcessTokenEx(ProcessHandle,
356c2c66affSColin Finck DesiredAccess,
357c2c66affSColin Finck 0,
358c2c66affSColin Finck TokenHandle);
359c2c66affSColin Finck }
360c2c66affSColin Finck
361c2c66affSColin Finck /*
362c2c66affSColin Finck * @implemented
363c2c66affSColin Finck */
364c2c66affSColin Finck NTSTATUS
365c2c66affSColin Finck NTAPI
NtOpenProcessTokenEx(IN HANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN ULONG HandleAttributes,OUT PHANDLE TokenHandle)366c2c66affSColin Finck NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
367c2c66affSColin Finck IN ACCESS_MASK DesiredAccess,
368c2c66affSColin Finck IN ULONG HandleAttributes,
369c2c66affSColin Finck OUT PHANDLE TokenHandle)
370c2c66affSColin Finck {
371c2c66affSColin Finck PACCESS_TOKEN Token;
372c2c66affSColin Finck HANDLE hToken;
373c2c66affSColin Finck KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
374c2c66affSColin Finck NTSTATUS Status;
375c2c66affSColin Finck PAGED_CODE();
376c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG,
377c2c66affSColin Finck "Process: %p DesiredAccess: %lx\n", ProcessHandle, DesiredAccess);
378c2c66affSColin Finck
379c2c66affSColin Finck /* Check if caller was user-mode */
380c2c66affSColin Finck if (PreviousMode != KernelMode)
381c2c66affSColin Finck {
382c2c66affSColin Finck /* Enter SEH for probing */
383c2c66affSColin Finck _SEH2_TRY
384c2c66affSColin Finck {
385c2c66affSColin Finck /* Probe the token handle */
386c2c66affSColin Finck ProbeForWriteHandle(TokenHandle);
387c2c66affSColin Finck }
388c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
389c2c66affSColin Finck {
390c2c66affSColin Finck /* Return the exception code */
391c2c66affSColin Finck _SEH2_YIELD(return _SEH2_GetExceptionCode());
392c2c66affSColin Finck }
393c2c66affSColin Finck _SEH2_END;
394c2c66affSColin Finck }
395c2c66affSColin Finck
396c2c66affSColin Finck /* Validate object attributes */
397c2c66affSColin Finck HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
398c2c66affSColin Finck
399c2c66affSColin Finck /* Open the process token */
400c2c66affSColin Finck Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
401c2c66affSColin Finck if (NT_SUCCESS(Status))
402c2c66affSColin Finck {
403c2c66affSColin Finck /* Reference it by handle and dereference the pointer */
404c2c66affSColin Finck Status = ObOpenObjectByPointer(Token,
405c2c66affSColin Finck HandleAttributes,
406c2c66affSColin Finck NULL,
407c2c66affSColin Finck DesiredAccess,
408c2c66affSColin Finck SeTokenObjectType,
409c2c66affSColin Finck PreviousMode,
410c2c66affSColin Finck &hToken);
411c2c66affSColin Finck ObDereferenceObject(Token);
412c2c66affSColin Finck
413c2c66affSColin Finck /* Make sure we got a handle */
414c2c66affSColin Finck if (NT_SUCCESS(Status))
415c2c66affSColin Finck {
416c2c66affSColin Finck /* Enter SEH for write */
417c2c66affSColin Finck _SEH2_TRY
418c2c66affSColin Finck {
419c2c66affSColin Finck /* Return the handle */
420c2c66affSColin Finck *TokenHandle = hToken;
421c2c66affSColin Finck }
422c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
423c2c66affSColin Finck {
424c2c66affSColin Finck /* Get exception code */
425c2c66affSColin Finck Status = _SEH2_GetExceptionCode();
426c2c66affSColin Finck }
427c2c66affSColin Finck _SEH2_END;
428c2c66affSColin Finck }
429c2c66affSColin Finck }
430c2c66affSColin Finck
431c2c66affSColin Finck /* Return status */
432c2c66affSColin Finck return Status;
433c2c66affSColin Finck }
434c2c66affSColin Finck
435c2c66affSColin Finck /*
436c2c66affSColin Finck * @implemented
437c2c66affSColin Finck */
438c2c66affSColin Finck PACCESS_TOKEN
439c2c66affSColin Finck NTAPI
PsReferencePrimaryToken(PEPROCESS Process)440c2c66affSColin Finck PsReferencePrimaryToken(PEPROCESS Process)
441c2c66affSColin Finck {
442c2c66affSColin Finck PACCESS_TOKEN Token;
443c2c66affSColin Finck PAGED_CODE();
444c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
445c2c66affSColin Finck
446c2c66affSColin Finck /* Fast Reference the Token */
447c2c66affSColin Finck Token = ObFastReferenceObject(&Process->Token);
448c2c66affSColin Finck
449c2c66affSColin Finck /* Check if we got the Token or if we got locked */
450c2c66affSColin Finck if (!Token)
451c2c66affSColin Finck {
452c2c66affSColin Finck /* Lock the Process */
453c2c66affSColin Finck PspLockProcessSecurityShared(Process);
454c2c66affSColin Finck
455c2c66affSColin Finck /* Do a Locked Fast Reference */
456c2c66affSColin Finck Token = ObFastReferenceObjectLocked(&Process->Token);
457c2c66affSColin Finck
458c2c66affSColin Finck /* Unlock the Process */
459c2c66affSColin Finck PspUnlockProcessSecurityShared(Process);
460c2c66affSColin Finck }
461c2c66affSColin Finck
462c2c66affSColin Finck /* Return the Token */
463c2c66affSColin Finck return Token;
464c2c66affSColin Finck }
465c2c66affSColin Finck
466c2c66affSColin Finck /*
467c2c66affSColin Finck * @implemented
468c2c66affSColin Finck */
469c2c66affSColin Finck NTSTATUS
470c2c66affSColin Finck NTAPI
PsOpenTokenOfProcess(IN HANDLE ProcessHandle,OUT PACCESS_TOKEN * Token)471c2c66affSColin Finck PsOpenTokenOfProcess(IN HANDLE ProcessHandle,
472c2c66affSColin Finck OUT PACCESS_TOKEN* Token)
473c2c66affSColin Finck {
474c2c66affSColin Finck PEPROCESS Process;
475c2c66affSColin Finck NTSTATUS Status;
476c2c66affSColin Finck PAGED_CODE();
477c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", ProcessHandle);
478c2c66affSColin Finck
479c2c66affSColin Finck /* Get the Token */
480c2c66affSColin Finck Status = ObReferenceObjectByHandle(ProcessHandle,
481c2c66affSColin Finck PROCESS_QUERY_INFORMATION,
482c2c66affSColin Finck PsProcessType,
483c2c66affSColin Finck ExGetPreviousMode(),
484c2c66affSColin Finck (PVOID*)&Process,
485c2c66affSColin Finck NULL);
486c2c66affSColin Finck if (NT_SUCCESS(Status))
487c2c66affSColin Finck {
488c2c66affSColin Finck /* Reference the token and dereference the process */
489c2c66affSColin Finck *Token = PsReferencePrimaryToken(Process);
490c2c66affSColin Finck ObDereferenceObject(Process);
491c2c66affSColin Finck }
492c2c66affSColin Finck
493c2c66affSColin Finck /* Return */
494c2c66affSColin Finck return Status;
495c2c66affSColin Finck }
496c2c66affSColin Finck
497c2c66affSColin Finck /*
498c2c66affSColin Finck * @implemented
499c2c66affSColin Finck */
500c2c66affSColin Finck NTSTATUS
501c2c66affSColin Finck NTAPI
PsAssignImpersonationToken(IN PETHREAD Thread,IN HANDLE TokenHandle)502c2c66affSColin Finck PsAssignImpersonationToken(IN PETHREAD Thread,
503c2c66affSColin Finck IN HANDLE TokenHandle)
504c2c66affSColin Finck {
505c2c66affSColin Finck PACCESS_TOKEN Token;
506c2c66affSColin Finck SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
507c2c66affSColin Finck NTSTATUS Status;
508c2c66affSColin Finck PAGED_CODE();
509c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Thread: %p Token: %p\n", Thread, TokenHandle);
510c2c66affSColin Finck
511c2c66affSColin Finck /* Check if we were given a handle */
512c2c66affSColin Finck if (!TokenHandle)
513c2c66affSColin Finck {
514c2c66affSColin Finck /* Undo impersonation */
515c2c66affSColin Finck PsRevertThreadToSelf(Thread);
516c2c66affSColin Finck return STATUS_SUCCESS;
517c2c66affSColin Finck }
518c2c66affSColin Finck
519c2c66affSColin Finck /* Get the token object */
520c2c66affSColin Finck Status = ObReferenceObjectByHandle(TokenHandle,
521c2c66affSColin Finck TOKEN_IMPERSONATE,
522c2c66affSColin Finck SeTokenObjectType,
523c2c66affSColin Finck KeGetPreviousMode(),
524c2c66affSColin Finck (PVOID*)&Token,
525c2c66affSColin Finck NULL);
526c2c66affSColin Finck if (!NT_SUCCESS(Status)) return(Status);
527c2c66affSColin Finck
528c2c66affSColin Finck /* Make sure it's an impersonation token */
529c2c66affSColin Finck if (SeTokenType(Token) != TokenImpersonation)
530c2c66affSColin Finck {
531c2c66affSColin Finck /* Fail */
532c2c66affSColin Finck ObDereferenceObject(Token);
533c2c66affSColin Finck return STATUS_BAD_TOKEN_TYPE;
534c2c66affSColin Finck }
535c2c66affSColin Finck
536c2c66affSColin Finck /* Get the impersonation level */
537c2c66affSColin Finck ImpersonationLevel = SeTokenImpersonationLevel(Token);
538c2c66affSColin Finck
539c2c66affSColin Finck /* Call the impersonation API */
540c2c66affSColin Finck Status = PsImpersonateClient(Thread,
541c2c66affSColin Finck Token,
542c2c66affSColin Finck FALSE,
543c2c66affSColin Finck FALSE,
544c2c66affSColin Finck ImpersonationLevel);
545c2c66affSColin Finck
546c2c66affSColin Finck /* Dereference the token and return status */
547c2c66affSColin Finck ObDereferenceObject(Token);
548c2c66affSColin Finck return Status;
549c2c66affSColin Finck }
550c2c66affSColin Finck
551c2c66affSColin Finck /*
552c2c66affSColin Finck * @implemented
553c2c66affSColin Finck */
554c2c66affSColin Finck VOID
555c2c66affSColin Finck NTAPI
PsRevertToSelf(VOID)556c2c66affSColin Finck PsRevertToSelf(VOID)
557c2c66affSColin Finck {
558c2c66affSColin Finck /* Call the per-thread API */
559c2c66affSColin Finck PAGED_CODE();
560c2c66affSColin Finck PsRevertThreadToSelf(PsGetCurrentThread());
561c2c66affSColin Finck }
562c2c66affSColin Finck
563c2c66affSColin Finck /*
564c2c66affSColin Finck * @implemented
565c2c66affSColin Finck */
566c2c66affSColin Finck VOID
567c2c66affSColin Finck NTAPI
PsRevertThreadToSelf(IN PETHREAD Thread)568c2c66affSColin Finck PsRevertThreadToSelf(IN PETHREAD Thread)
569c2c66affSColin Finck {
570c2c66affSColin Finck PTOKEN Token = NULL;
571c2c66affSColin Finck PAGED_CODE();
572c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
573c2c66affSColin Finck
574c2c66affSColin Finck /* Make sure we had impersonation information */
575c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
576c2c66affSColin Finck {
577c2c66affSColin Finck /* Lock the thread security */
578c2c66affSColin Finck PspLockThreadSecurityExclusive(Thread);
579c2c66affSColin Finck
580c2c66affSColin Finck /* Make sure it's still active */
581c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
582c2c66affSColin Finck {
583c2c66affSColin Finck /* Disable impersonation */
584c2c66affSColin Finck PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
585c2c66affSColin Finck
586c2c66affSColin Finck /* Get the token */
587c2c66affSColin Finck Token = Thread->ImpersonationInfo->Token;
588c2c66affSColin Finck }
589c2c66affSColin Finck
590c2c66affSColin Finck /* Release thread security */
591c2c66affSColin Finck PspUnlockThreadSecurityExclusive(Thread);
592c2c66affSColin Finck
593c2c66affSColin Finck /* Check if we had a token */
594c2c66affSColin Finck if (Token)
595c2c66affSColin Finck {
596c2c66affSColin Finck /* Dereference the impersonation token */
597c2c66affSColin Finck ObDereferenceObject(Token);
598c2c66affSColin Finck
599c2c66affSColin Finck /* Write impersonation info to the TEB */
600c2c66affSColin Finck PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
601c2c66affSColin Finck }
602c2c66affSColin Finck }
603c2c66affSColin Finck }
604c2c66affSColin Finck
605c2c66affSColin Finck /*
606c2c66affSColin Finck * @implemented
607c2c66affSColin Finck */
608c2c66affSColin Finck NTSTATUS
609c2c66affSColin Finck NTAPI
PsImpersonateClient(IN PETHREAD Thread,IN PACCESS_TOKEN Token,IN BOOLEAN CopyOnOpen,IN BOOLEAN EffectiveOnly,IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)610c2c66affSColin Finck PsImpersonateClient(IN PETHREAD Thread,
611c2c66affSColin Finck IN PACCESS_TOKEN Token,
612c2c66affSColin Finck IN BOOLEAN CopyOnOpen,
613c2c66affSColin Finck IN BOOLEAN EffectiveOnly,
614c2c66affSColin Finck IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
615c2c66affSColin Finck {
616c2c66affSColin Finck PPS_IMPERSONATION_INFORMATION Impersonation, OldData;
617242efae9SGeorge Bișoc PTOKEN OldToken = NULL, ProcessToken = NULL;
618*8e2fe925SGeorge Bișoc BOOLEAN CopiedToken = FALSE;
619242efae9SGeorge Bișoc PACCESS_TOKEN NewToken, ImpersonationToken;
620db180c29SThomas Faber PEJOB Job;
621242efae9SGeorge Bișoc NTSTATUS Status;
622db180c29SThomas Faber
623c2c66affSColin Finck PAGED_CODE();
624c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Thread: %p, Token: %p\n", Thread, Token);
625c2c66affSColin Finck
626c2c66affSColin Finck /* Check if we don't have a token */
627c2c66affSColin Finck if (!Token)
628c2c66affSColin Finck {
629c2c66affSColin Finck /* Make sure we're impersonating */
630c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
631c2c66affSColin Finck {
632c2c66affSColin Finck /* We seem to be, lock the thread */
633c2c66affSColin Finck PspLockThreadSecurityExclusive(Thread);
634c2c66affSColin Finck
635c2c66affSColin Finck /* Make sure we're still impersonating */
636c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
637c2c66affSColin Finck {
638c2c66affSColin Finck /* Disable impersonation */
639c2c66affSColin Finck PspClearCrossThreadFlag(Thread,
640c2c66affSColin Finck CT_ACTIVE_IMPERSONATION_INFO_BIT);
641c2c66affSColin Finck
642c2c66affSColin Finck /* Get the token */
643c2c66affSColin Finck OldToken = Thread->ImpersonationInfo->Token;
644c2c66affSColin Finck }
645c2c66affSColin Finck
646c2c66affSColin Finck /* Unlock the process and write TEB information */
647c2c66affSColin Finck PspUnlockThreadSecurityExclusive(Thread);
648c2c66affSColin Finck PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
649c2c66affSColin Finck }
650c2c66affSColin Finck }
651c2c66affSColin Finck else
652c2c66affSColin Finck {
653c2c66affSColin Finck /* Check if we have impersonation info */
654c2c66affSColin Finck Impersonation = Thread->ImpersonationInfo;
655c2c66affSColin Finck if (!Impersonation)
656c2c66affSColin Finck {
657c2c66affSColin Finck /* We need to allocate a new one */
658c2c66affSColin Finck Impersonation = ExAllocatePoolWithTag(PagedPool,
659c2c66affSColin Finck sizeof(*Impersonation),
660c2c66affSColin Finck TAG_PS_IMPERSONATION);
661c2c66affSColin Finck if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES;
662c2c66affSColin Finck
663c2c66affSColin Finck /* Update the pointer */
664c2c66affSColin Finck OldData = InterlockedCompareExchangePointer((PVOID*)&Thread->
665c2c66affSColin Finck ImpersonationInfo,
666c2c66affSColin Finck Impersonation,
667c2c66affSColin Finck NULL);
668c2c66affSColin Finck if (OldData)
669c2c66affSColin Finck {
670c2c66affSColin Finck /* Someone beat us to it, free our copy */
671c2c66affSColin Finck ExFreePoolWithTag(Impersonation, TAG_PS_IMPERSONATION);
672c2c66affSColin Finck Impersonation = OldData;
673c2c66affSColin Finck }
674c2c66affSColin Finck }
675c2c66affSColin Finck
676242efae9SGeorge Bișoc /*
677242efae9SGeorge Bișoc * Assign the token we get from the caller first. The reason
678242efae9SGeorge Bișoc * we have to do that is because we're unsure if we can impersonate
679242efae9SGeorge Bișoc * in the first place. In the scenario where we cannot then the
680242efae9SGeorge Bișoc * last resort is to make a copy of the token and assign that newly
681242efae9SGeorge Bișoc * token to the impersonation information.
682242efae9SGeorge Bișoc */
683242efae9SGeorge Bișoc ImpersonationToken = Token;
684242efae9SGeorge Bișoc
685242efae9SGeorge Bișoc /* Obtain a token from the process */
686242efae9SGeorge Bișoc ProcessToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
687242efae9SGeorge Bișoc if (!ProcessToken)
688242efae9SGeorge Bișoc {
689242efae9SGeorge Bișoc /* We can't continue this way without having the process' token... */
690242efae9SGeorge Bișoc return STATUS_UNSUCCESSFUL;
691242efae9SGeorge Bișoc }
692242efae9SGeorge Bișoc
693242efae9SGeorge Bișoc /* Make sure we can impersonate */
694242efae9SGeorge Bișoc if (!SeTokenCanImpersonate(ProcessToken,
695242efae9SGeorge Bișoc Token,
696242efae9SGeorge Bișoc ImpersonationLevel))
697242efae9SGeorge Bișoc {
698242efae9SGeorge Bișoc /* We can't, make a copy of the token instead */
699242efae9SGeorge Bișoc Status = SeCopyClientToken(Token,
700242efae9SGeorge Bișoc SecurityIdentification,
701242efae9SGeorge Bișoc KernelMode,
702242efae9SGeorge Bișoc &NewToken);
703242efae9SGeorge Bișoc if (!NT_SUCCESS(Status))
704242efae9SGeorge Bișoc {
705242efae9SGeorge Bișoc /* We can't even make a copy of the token? Then bail out... */
706242efae9SGeorge Bișoc ObFastDereferenceObject(&Thread->ThreadsProcess->Token, ProcessToken);
707242efae9SGeorge Bișoc return Status;
708242efae9SGeorge Bișoc }
709242efae9SGeorge Bișoc
710*8e2fe925SGeorge Bișoc /*
711*8e2fe925SGeorge Bișoc * Since we cannot impersonate, assign the newly copied token.
712*8e2fe925SGeorge Bișoc * SeCopyClientToken already holds a reference to the copied token,
713*8e2fe925SGeorge Bișoc * let the code path below know that it must not reference it twice.
714*8e2fe925SGeorge Bișoc */
715*8e2fe925SGeorge Bișoc CopiedToken = TRUE;
716*8e2fe925SGeorge Bișoc ImpersonationLevel = SecurityIdentification;
717242efae9SGeorge Bișoc ImpersonationToken = NewToken;
718242efae9SGeorge Bișoc }
719242efae9SGeorge Bișoc
720242efae9SGeorge Bișoc /* We no longer need the process' token */
721242efae9SGeorge Bișoc ObFastDereferenceObject(&Thread->ThreadsProcess->Token, ProcessToken);
722db180c29SThomas Faber
723db180c29SThomas Faber /* Check if this is a job */
724db180c29SThomas Faber Job = Thread->ThreadsProcess->Job;
725db180c29SThomas Faber if (Job != NULL)
726db180c29SThomas Faber {
727db180c29SThomas Faber /* No admin allowed in this job */
728db180c29SThomas Faber if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN) &&
729242efae9SGeorge Bișoc SeTokenIsAdmin(ImpersonationToken))
730db180c29SThomas Faber {
731*8e2fe925SGeorge Bișoc if (CopiedToken)
732*8e2fe925SGeorge Bișoc {
733*8e2fe925SGeorge Bișoc ObDereferenceObject(ImpersonationToken);
734*8e2fe925SGeorge Bișoc }
735*8e2fe925SGeorge Bișoc
736db180c29SThomas Faber return STATUS_ACCESS_DENIED;
737db180c29SThomas Faber }
738db180c29SThomas Faber
739db180c29SThomas Faber /* No restricted tokens allowed in this job */
740db180c29SThomas Faber if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_RESTRICTED_TOKEN) &&
741242efae9SGeorge Bișoc SeTokenIsRestricted(ImpersonationToken))
742db180c29SThomas Faber {
743*8e2fe925SGeorge Bișoc if (CopiedToken)
744*8e2fe925SGeorge Bișoc {
745*8e2fe925SGeorge Bișoc ObDereferenceObject(ImpersonationToken);
746*8e2fe925SGeorge Bișoc }
747*8e2fe925SGeorge Bișoc
748db180c29SThomas Faber return STATUS_ACCESS_DENIED;
749db180c29SThomas Faber }
750db180c29SThomas Faber
751db180c29SThomas Faber /* We don't support job filters yet */
752db180c29SThomas Faber if (Job->Filter != NULL)
753db180c29SThomas Faber {
754db180c29SThomas Faber ASSERT(Job->Filter == NULL);
755db180c29SThomas Faber }
756db180c29SThomas Faber }
757c2c66affSColin Finck
758c2c66affSColin Finck /* Lock thread security */
759c2c66affSColin Finck PspLockThreadSecurityExclusive(Thread);
760c2c66affSColin Finck
761c2c66affSColin Finck /* Check if we're impersonating */
762c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
763c2c66affSColin Finck {
764c2c66affSColin Finck /* Get the token */
765c2c66affSColin Finck OldToken = Impersonation->Token;
766c2c66affSColin Finck }
767c2c66affSColin Finck else
768c2c66affSColin Finck {
769c2c66affSColin Finck /* Otherwise, enable impersonation */
770c2c66affSColin Finck PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
771c2c66affSColin Finck }
772c2c66affSColin Finck
773c2c66affSColin Finck /* Now fill it out */
774c2c66affSColin Finck Impersonation->ImpersonationLevel = ImpersonationLevel;
775c2c66affSColin Finck Impersonation->CopyOnOpen = CopyOnOpen;
776c2c66affSColin Finck Impersonation->EffectiveOnly = EffectiveOnly;
777242efae9SGeorge Bișoc Impersonation->Token = ImpersonationToken;
778*8e2fe925SGeorge Bișoc
779*8e2fe925SGeorge Bișoc /* Do not reference the token again if we copied it */
780*8e2fe925SGeorge Bișoc if (!CopiedToken)
781*8e2fe925SGeorge Bișoc {
782242efae9SGeorge Bișoc ObReferenceObject(ImpersonationToken);
783*8e2fe925SGeorge Bișoc }
784c2c66affSColin Finck
785c2c66affSColin Finck /* Unlock the thread */
786c2c66affSColin Finck PspUnlockThreadSecurityExclusive(Thread);
787c2c66affSColin Finck
788c2c66affSColin Finck /* Write impersonation info to the TEB */
789c2c66affSColin Finck PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
790c2c66affSColin Finck }
791c2c66affSColin Finck
792c2c66affSColin Finck /* Dereference the token and return success */
793c2c66affSColin Finck if (OldToken) PsDereferenceImpersonationToken(OldToken);
794c2c66affSColin Finck return STATUS_SUCCESS;
795c2c66affSColin Finck }
796c2c66affSColin Finck
797c2c66affSColin Finck /*
798c2c66affSColin Finck * @implemented
799c2c66affSColin Finck */
800c2c66affSColin Finck PACCESS_TOKEN
801c2c66affSColin Finck NTAPI
PsReferenceEffectiveToken(IN PETHREAD Thread,OUT IN PTOKEN_TYPE TokenType,OUT PBOOLEAN EffectiveOnly,OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)802c2c66affSColin Finck PsReferenceEffectiveToken(IN PETHREAD Thread,
803c2c66affSColin Finck OUT IN PTOKEN_TYPE TokenType,
804c2c66affSColin Finck OUT PBOOLEAN EffectiveOnly,
805813879f0SHermès Bélusca-Maïto OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
806c2c66affSColin Finck {
807c2c66affSColin Finck PEPROCESS Process;
808c2c66affSColin Finck PACCESS_TOKEN Token = NULL;
809813879f0SHermès Bélusca-Maïto
810c2c66affSColin Finck PAGED_CODE();
811813879f0SHermès Bélusca-Maïto
812c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG,
813c2c66affSColin Finck "Thread: %p, TokenType: %p\n", Thread, TokenType);
814c2c66affSColin Finck
815c2c66affSColin Finck /* Check if we don't have impersonation info */
816c2c66affSColin Finck Process = Thread->ThreadsProcess;
817c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
818c2c66affSColin Finck {
819c2c66affSColin Finck /* Lock the Process */
820c2c66affSColin Finck PspLockProcessSecurityShared(Process);
821c2c66affSColin Finck
822c2c66affSColin Finck /* Make sure impersonation is still active */
823c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
824c2c66affSColin Finck {
825c2c66affSColin Finck /* Get the token */
826c2c66affSColin Finck Token = Thread->ImpersonationInfo->Token;
827c2c66affSColin Finck ObReferenceObject(Token);
828c2c66affSColin Finck
829c2c66affSColin Finck /* Return data to caller */
830c2c66affSColin Finck *TokenType = TokenImpersonation;
831c2c66affSColin Finck *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
832813879f0SHermès Bélusca-Maïto *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
833c2c66affSColin Finck
834c2c66affSColin Finck /* Unlock the Process */
835c2c66affSColin Finck PspUnlockProcessSecurityShared(Process);
836c2c66affSColin Finck return Token;
837c2c66affSColin Finck }
838c2c66affSColin Finck
839c2c66affSColin Finck /* Unlock the Process */
840c2c66affSColin Finck PspUnlockProcessSecurityShared(Process);
841c2c66affSColin Finck }
842c2c66affSColin Finck
843c2c66affSColin Finck /* Fast Reference the Token */
844c2c66affSColin Finck Token = ObFastReferenceObject(&Process->Token);
845c2c66affSColin Finck
846c2c66affSColin Finck /* Check if we got the Token or if we got locked */
847c2c66affSColin Finck if (!Token)
848c2c66affSColin Finck {
849c2c66affSColin Finck /* Lock the Process */
850c2c66affSColin Finck PspLockProcessSecurityShared(Process);
851c2c66affSColin Finck
852c2c66affSColin Finck /* Do a Locked Fast Reference */
853c2c66affSColin Finck Token = ObFastReferenceObjectLocked(&Process->Token);
854c2c66affSColin Finck
855c2c66affSColin Finck /* Unlock the Process */
856c2c66affSColin Finck PspUnlockProcessSecurityShared(Process);
857c2c66affSColin Finck }
858c2c66affSColin Finck
859c2c66affSColin Finck /* Return the token */
860c2c66affSColin Finck *TokenType = TokenPrimary;
861c2c66affSColin Finck *EffectiveOnly = FALSE;
862813879f0SHermès Bélusca-Maïto // NOTE: ImpersonationLevel is left untouched on purpose!
863c2c66affSColin Finck return Token;
864c2c66affSColin Finck }
865c2c66affSColin Finck
866c2c66affSColin Finck /*
867c2c66affSColin Finck * @implemented
868c2c66affSColin Finck */
869c2c66affSColin Finck PACCESS_TOKEN
870c2c66affSColin Finck NTAPI
PsReferenceImpersonationToken(IN PETHREAD Thread,OUT PBOOLEAN CopyOnOpen,OUT PBOOLEAN EffectiveOnly,OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)871c2c66affSColin Finck PsReferenceImpersonationToken(IN PETHREAD Thread,
872c2c66affSColin Finck OUT PBOOLEAN CopyOnOpen,
873c2c66affSColin Finck OUT PBOOLEAN EffectiveOnly,
874c2c66affSColin Finck OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
875c2c66affSColin Finck {
876c2c66affSColin Finck PTOKEN Token = NULL;
877c2c66affSColin Finck PAGED_CODE();
878c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
879c2c66affSColin Finck
880c2c66affSColin Finck /* If we don't have impersonation info, just quit */
881c2c66affSColin Finck if (!Thread->ActiveImpersonationInfo) return NULL;
882c2c66affSColin Finck
883c2c66affSColin Finck /* Lock the thread */
884c2c66affSColin Finck PspLockThreadSecurityShared(Thread);
885c2c66affSColin Finck
886c2c66affSColin Finck /* Make sure we still have active impersonation */
887c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
888c2c66affSColin Finck {
889c2c66affSColin Finck /* Return data from caller */
890c2c66affSColin Finck ObReferenceObject(Thread->ImpersonationInfo->Token);
891c2c66affSColin Finck *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
892c2c66affSColin Finck *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
893c2c66affSColin Finck *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
894c2c66affSColin Finck
895c2c66affSColin Finck /* Set the token */
896c2c66affSColin Finck Token = Thread->ImpersonationInfo->Token;
897c2c66affSColin Finck }
898c2c66affSColin Finck
899c2c66affSColin Finck /* Unlock thread and return impersonation token */
900c2c66affSColin Finck PspUnlockThreadSecurityShared(Thread);
901c2c66affSColin Finck return Token;
902c2c66affSColin Finck }
903c2c66affSColin Finck
904c2c66affSColin Finck #undef PsDereferenceImpersonationToken
905c2c66affSColin Finck /*
906c2c66affSColin Finck * @implemented
907c2c66affSColin Finck */
908c2c66affSColin Finck VOID
909c2c66affSColin Finck NTAPI
PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)910c2c66affSColin Finck PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
911c2c66affSColin Finck {
912c2c66affSColin Finck PAGED_CODE();
913c2c66affSColin Finck
914c2c66affSColin Finck /* If we got a token, dereference it */
915c2c66affSColin Finck if (ImpersonationToken) ObDereferenceObject(ImpersonationToken);
916c2c66affSColin Finck }
917c2c66affSColin Finck
918c2c66affSColin Finck #undef PsDereferencePrimaryToken
919c2c66affSColin Finck /*
920c2c66affSColin Finck * @implemented
921c2c66affSColin Finck */
922c2c66affSColin Finck VOID
923c2c66affSColin Finck NTAPI
PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)924c2c66affSColin Finck PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
925c2c66affSColin Finck {
926c2c66affSColin Finck PAGED_CODE();
927c2c66affSColin Finck
928c2c66affSColin Finck /* Dereference the token*/
929c2c66affSColin Finck ObDereferenceObject(PrimaryToken);
930c2c66affSColin Finck }
931c2c66affSColin Finck
932c2c66affSColin Finck /*
933c2c66affSColin Finck * @implemented
934c2c66affSColin Finck */
935c2c66affSColin Finck BOOLEAN
936c2c66affSColin Finck NTAPI
PsDisableImpersonation(IN PETHREAD Thread,OUT PSE_IMPERSONATION_STATE ImpersonationState)937c2c66affSColin Finck PsDisableImpersonation(IN PETHREAD Thread,
938c2c66affSColin Finck OUT PSE_IMPERSONATION_STATE ImpersonationState)
939c2c66affSColin Finck {
940c2c66affSColin Finck PPS_IMPERSONATION_INFORMATION Impersonation = NULL;
941c2c66affSColin Finck LONG OldFlags;
942c2c66affSColin Finck PAGED_CODE();
943c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG,
944c2c66affSColin Finck "Thread: %p State: %p\n", Thread, ImpersonationState);
945c2c66affSColin Finck
946c2c66affSColin Finck /* Check if we don't have impersonation */
947c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
948c2c66affSColin Finck {
949c2c66affSColin Finck /* Lock thread security */
950c2c66affSColin Finck PspLockThreadSecurityExclusive(Thread);
951c2c66affSColin Finck
952c2c66affSColin Finck /* Disable impersonation */
953c2c66affSColin Finck OldFlags = PspClearCrossThreadFlag(Thread,
954c2c66affSColin Finck CT_ACTIVE_IMPERSONATION_INFO_BIT);
955c2c66affSColin Finck
956c2c66affSColin Finck /* Make sure nobody disabled it behind our back */
957c2c66affSColin Finck if (OldFlags & CT_ACTIVE_IMPERSONATION_INFO_BIT)
958c2c66affSColin Finck {
959c2c66affSColin Finck /* Copy the old state */
960c2c66affSColin Finck Impersonation = Thread->ImpersonationInfo;
961c2c66affSColin Finck ImpersonationState->Token = Impersonation->Token;
962c2c66affSColin Finck ImpersonationState->CopyOnOpen = Impersonation->CopyOnOpen;
963c2c66affSColin Finck ImpersonationState->EffectiveOnly = Impersonation->EffectiveOnly;
964c2c66affSColin Finck ImpersonationState->Level = Impersonation->ImpersonationLevel;
965c2c66affSColin Finck }
966c2c66affSColin Finck
967c2c66affSColin Finck /* Unlock thread security */
968c2c66affSColin Finck PspUnlockThreadSecurityExclusive(Thread);
969c2c66affSColin Finck
970c2c66affSColin Finck /* If we had impersonation info, return true */
971c2c66affSColin Finck if (Impersonation) return TRUE;
972c2c66affSColin Finck }
973c2c66affSColin Finck
974c2c66affSColin Finck /* Clear everything */
975c2c66affSColin Finck ImpersonationState->Token = NULL;
976c2c66affSColin Finck ImpersonationState->CopyOnOpen = FALSE;
977c2c66affSColin Finck ImpersonationState->EffectiveOnly = FALSE;
978c2c66affSColin Finck ImpersonationState->Level = SecurityAnonymous;
979c2c66affSColin Finck return FALSE;
980c2c66affSColin Finck }
981c2c66affSColin Finck
982c2c66affSColin Finck /*
983c2c66affSColin Finck * @implemented
984c2c66affSColin Finck */
985c2c66affSColin Finck VOID
986c2c66affSColin Finck NTAPI
PsRestoreImpersonation(IN PETHREAD Thread,IN PSE_IMPERSONATION_STATE ImpersonationState)987c2c66affSColin Finck PsRestoreImpersonation(IN PETHREAD Thread,
988c2c66affSColin Finck IN PSE_IMPERSONATION_STATE ImpersonationState)
989c2c66affSColin Finck {
990c2c66affSColin Finck PTOKEN Token = NULL;
991c2c66affSColin Finck PPS_IMPERSONATION_INFORMATION Impersonation;
992c2c66affSColin Finck PAGED_CODE();
993c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG,
994c2c66affSColin Finck "Thread: %p State: %p\n", Thread, ImpersonationState);
995c2c66affSColin Finck
996c2c66affSColin Finck /* Lock thread security */
997c2c66affSColin Finck PspLockThreadSecurityExclusive(Thread);
998c2c66affSColin Finck
999c2c66affSColin Finck /* Get the impersonation info */
1000c2c66affSColin Finck Impersonation = Thread->ImpersonationInfo;
1001c2c66affSColin Finck
1002c2c66affSColin Finck /* Check if we're impersonating */
1003c2c66affSColin Finck if (Thread->ActiveImpersonationInfo)
1004c2c66affSColin Finck {
1005c2c66affSColin Finck /* Get the token */
1006c2c66affSColin Finck Token = Impersonation->Token;
1007c2c66affSColin Finck }
1008c2c66affSColin Finck
1009c2c66affSColin Finck /* Check if we have an impersonation state */
1010c2c66affSColin Finck if (ImpersonationState)
1011c2c66affSColin Finck {
1012c2c66affSColin Finck /* Fill out the impersonation info */
1013c2c66affSColin Finck Impersonation->ImpersonationLevel = ImpersonationState->Level;
1014c2c66affSColin Finck Impersonation->CopyOnOpen = ImpersonationState->CopyOnOpen;
1015c2c66affSColin Finck Impersonation->EffectiveOnly = ImpersonationState->EffectiveOnly;
1016c2c66affSColin Finck Impersonation->Token = ImpersonationState->Token;
1017c2c66affSColin Finck
1018c2c66affSColin Finck /* Enable impersonation */
1019c2c66affSColin Finck PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
1020c2c66affSColin Finck }
1021c2c66affSColin Finck else
1022c2c66affSColin Finck {
1023c2c66affSColin Finck /* Disable impersonation */
1024c2c66affSColin Finck PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
1025c2c66affSColin Finck }
1026c2c66affSColin Finck
1027c2c66affSColin Finck /* Unlock the thread */
1028c2c66affSColin Finck PspUnlockThreadSecurityExclusive(Thread);
1029c2c66affSColin Finck
1030c2c66affSColin Finck /* Dereference the token */
1031c2c66affSColin Finck if (Token) ObDereferenceObject(Token);
1032c2c66affSColin Finck }
1033c2c66affSColin Finck
1034c2c66affSColin Finck NTSTATUS
1035c2c66affSColin Finck NTAPI
NtImpersonateThread(IN HANDLE ThreadHandle,IN HANDLE ThreadToImpersonateHandle,IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)1036c2c66affSColin Finck NtImpersonateThread(IN HANDLE ThreadHandle,
1037c2c66affSColin Finck IN HANDLE ThreadToImpersonateHandle,
1038c2c66affSColin Finck IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
1039c2c66affSColin Finck {
1040c2c66affSColin Finck SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
1041c2c66affSColin Finck SECURITY_CLIENT_CONTEXT ClientContext;
1042c2c66affSColin Finck PETHREAD Thread;
1043c2c66affSColin Finck PETHREAD ThreadToImpersonate;
1044c2c66affSColin Finck KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1045c2c66affSColin Finck NTSTATUS Status;
1046c2c66affSColin Finck PAGED_CODE();
1047c2c66affSColin Finck PSTRACE(PS_SECURITY_DEBUG,
1048c2c66affSColin Finck "Threads: %p %p\n", ThreadHandle, ThreadToImpersonateHandle);
1049c2c66affSColin Finck
1050c2c66affSColin Finck /* Check if call came from user mode */
1051c2c66affSColin Finck if (PreviousMode != KernelMode)
1052c2c66affSColin Finck {
1053c2c66affSColin Finck /* Enter SEH for probing */
1054c2c66affSColin Finck _SEH2_TRY
1055c2c66affSColin Finck {
1056c2c66affSColin Finck /* Probe QoS */
1057c2c66affSColin Finck ProbeForRead(SecurityQualityOfService,
1058c2c66affSColin Finck sizeof(SECURITY_QUALITY_OF_SERVICE),
1059c2c66affSColin Finck sizeof(ULONG));
1060c2c66affSColin Finck
1061c2c66affSColin Finck /* Capture it */
1062c2c66affSColin Finck SafeServiceQoS = *SecurityQualityOfService;
1063c2c66affSColin Finck SecurityQualityOfService = &SafeServiceQoS;
1064c2c66affSColin Finck }
1065c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1066c2c66affSColin Finck {
1067c2c66affSColin Finck /* Return the exception code */
1068c2c66affSColin Finck _SEH2_YIELD(return _SEH2_GetExceptionCode());
1069c2c66affSColin Finck }
1070c2c66affSColin Finck _SEH2_END;
1071c2c66affSColin Finck }
1072c2c66affSColin Finck
1073c2c66affSColin Finck /* Reference the thread */
1074c2c66affSColin Finck Status = ObReferenceObjectByHandle(ThreadHandle,
1075c2c66affSColin Finck THREAD_DIRECT_IMPERSONATION,
1076c2c66affSColin Finck PsThreadType,
1077c2c66affSColin Finck PreviousMode,
1078c2c66affSColin Finck (PVOID*)&Thread,
1079c2c66affSColin Finck NULL);
1080c2c66affSColin Finck if (NT_SUCCESS(Status))
1081c2c66affSColin Finck {
1082c2c66affSColin Finck /* Reference the impersonating thead */
1083c2c66affSColin Finck Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
1084c2c66affSColin Finck THREAD_IMPERSONATE,
1085c2c66affSColin Finck PsThreadType,
1086c2c66affSColin Finck PreviousMode,
1087c2c66affSColin Finck (PVOID*)&ThreadToImpersonate,
1088c2c66affSColin Finck NULL);
1089c2c66affSColin Finck if (NT_SUCCESS(Status))
1090c2c66affSColin Finck {
1091c2c66affSColin Finck /* Create a client security context */
1092c2c66affSColin Finck Status = SeCreateClientSecurity(ThreadToImpersonate,
1093c2c66affSColin Finck SecurityQualityOfService,
1094c2c66affSColin Finck 0,
1095c2c66affSColin Finck &ClientContext);
1096c2c66affSColin Finck if (NT_SUCCESS(Status))
1097c2c66affSColin Finck {
1098c2c66affSColin Finck /* Do the impersonation */
1099c2c66affSColin Finck SeImpersonateClient(&ClientContext, Thread);
1100c2c66affSColin Finck if (ClientContext.ClientToken)
1101c2c66affSColin Finck {
1102c2c66affSColin Finck /* Dereference the client token if we had one */
1103c2c66affSColin Finck ObDereferenceObject(ClientContext.ClientToken);
1104c2c66affSColin Finck }
1105c2c66affSColin Finck }
1106c2c66affSColin Finck
1107c2c66affSColin Finck /* Dereference the thread to impersonate */
1108c2c66affSColin Finck ObDereferenceObject(ThreadToImpersonate);
1109c2c66affSColin Finck }
1110c2c66affSColin Finck
1111c2c66affSColin Finck /* Dereference the main thread */
1112c2c66affSColin Finck ObDereferenceObject(Thread);
1113c2c66affSColin Finck }
1114c2c66affSColin Finck
1115c2c66affSColin Finck /* Return status */
1116c2c66affSColin Finck return Status;
1117c2c66affSColin Finck }
1118c2c66affSColin Finck /* EOF */
1119