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