Create the AHCI branch for Aman's work
[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 IsChild;
221 PACCESS_TOKEN NewToken = Token;
222 NTSTATUS Status, AccessStatus;
223 BOOLEAN Result, SdAllocated;
224 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
225 SECURITY_SUBJECT_CONTEXT SubjectContext;
226 PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
227
228 /* Make sure we got a handle */
229 if (TokenHandle)
230 {
231 /* Reference it */
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 /* Check if this is a child */
242 Status = SeIsTokenChild(NewToken, &IsChild);
243 if (!NT_SUCCESS(Status))
244 {
245 /* Failed, dereference */
246 if (TokenHandle) ObDereferenceObject(NewToken);
247 return Status;
248 }
249
250 /* Check if this was an independent token */
251 if (!IsChild)
252 {
253 /* Make sure we have the privilege to assign a new one */
254 if (!SeSinglePrivilegeCheck(SeAssignPrimaryTokenPrivilege,
255 PreviousMode))
256 {
257 /* Failed, dereference */
258 if (TokenHandle) ObDereferenceObject(NewToken);
259 return STATUS_PRIVILEGE_NOT_HELD;
260 }
261 }
262
263 /* Assign the token */
264 Status = PspAssignPrimaryToken(Process, NULL, NewToken);
265 if (NT_SUCCESS(Status))
266 {
267 /*
268 * We need to completely reverify if the process still has access to
269 * itself under this new token.
270 */
271 Status = ObGetObjectSecurity(Process,
272 &SecurityDescriptor,
273 &SdAllocated);
274 if (NT_SUCCESS(Status))
275 {
276 /* Setup the security context */
277 SubjectContext.ProcessAuditId = Process;
278 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
279 SubjectContext.ClientToken = NULL;
280
281 /* Do the access check */
282 Result = SeAccessCheck(SecurityDescriptor,
283 &SubjectContext,
284 FALSE,
285 MAXIMUM_ALLOWED,
286 0,
287 NULL,
288 &PsProcessType->TypeInfo.GenericMapping,
289 PreviousMode,
290 &Process->GrantedAccess,
291 &AccessStatus);
292
293 /* Dereference the token and let go the SD */
294 ObFastDereferenceObject(&Process->Token,
295 SubjectContext.PrimaryToken);
296 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
297
298 /* Remove access if it failed */
299 if (!Result) Process->GrantedAccess = 0;
300
301 /* Setup granted access */
302 Process->GrantedAccess |= (PROCESS_VM_OPERATION |
303 PROCESS_VM_READ |
304 PROCESS_VM_WRITE |
305 PROCESS_QUERY_INFORMATION |
306 PROCESS_TERMINATE |
307 PROCESS_CREATE_THREAD |
308 PROCESS_DUP_HANDLE |
309 PROCESS_CREATE_PROCESS |
310 PROCESS_SET_INFORMATION |
311 STANDARD_RIGHTS_ALL |
312 PROCESS_SET_QUOTA);
313 }
314 }
315
316 /* Dereference the token */
317 if (TokenHandle) ObDereferenceObject(NewToken);
318 return Status;
319 }
320
321 /* FUNCTIONS *****************************************************************/
322
323 /*
324 * @implemented
325 */
326 NTSTATUS
327 NTAPI
328 NtOpenProcessToken(IN HANDLE ProcessHandle,
329 IN ACCESS_MASK DesiredAccess,
330 OUT PHANDLE TokenHandle)
331 {
332 /* Call the newer API */
333 return NtOpenProcessTokenEx(ProcessHandle,
334 DesiredAccess,
335 0,
336 TokenHandle);
337 }
338
339 /*
340 * @implemented
341 */
342 NTSTATUS
343 NTAPI
344 NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
345 IN ACCESS_MASK DesiredAccess,
346 IN ULONG HandleAttributes,
347 OUT PHANDLE TokenHandle)
348 {
349 PACCESS_TOKEN Token;
350 HANDLE hToken;
351 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
352 NTSTATUS Status;
353 PAGED_CODE();
354 PSTRACE(PS_SECURITY_DEBUG,
355 "Process: %p DesiredAccess: %lx\n", ProcessHandle, DesiredAccess);
356
357 /* Check if caller was user-mode */
358 if (PreviousMode != KernelMode)
359 {
360 /* Enter SEH for probing */
361 _SEH2_TRY
362 {
363 /* Probe the token handle */
364 ProbeForWriteHandle(TokenHandle);
365 }
366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
367 {
368 /* Return the exception code */
369 _SEH2_YIELD(return _SEH2_GetExceptionCode());
370 }
371 _SEH2_END;
372 }
373
374 /* Validate object attributes */
375 HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
376
377 /* Open the process token */
378 Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
379 if (NT_SUCCESS(Status))
380 {
381 /* Reference it by handle and dereference the pointer */
382 Status = ObOpenObjectByPointer(Token,
383 HandleAttributes,
384 NULL,
385 DesiredAccess,
386 SeTokenObjectType,
387 PreviousMode,
388 &hToken);
389 ObDereferenceObject(Token);
390
391 /* Make sure we got a handle */
392 if (NT_SUCCESS(Status))
393 {
394 /* Enter SEH for write */
395 _SEH2_TRY
396 {
397 /* Return the handle */
398 *TokenHandle = hToken;
399 }
400 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
401 {
402 /* Get exception code */
403 Status = _SEH2_GetExceptionCode();
404 }
405 _SEH2_END;
406 }
407 }
408
409 /* Return status */
410 return Status;
411 }
412
413 /*
414 * @implemented
415 */
416 PACCESS_TOKEN
417 NTAPI
418 PsReferencePrimaryToken(PEPROCESS Process)
419 {
420 PACCESS_TOKEN Token;
421 PAGED_CODE();
422 PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
423
424 /* Fast Reference the Token */
425 Token = ObFastReferenceObject(&Process->Token);
426
427 /* Check if we got the Token or if we got locked */
428 if (!Token)
429 {
430 /* Lock the Process */
431 PspLockProcessSecurityShared(Process);
432
433 /* Do a Locked Fast Reference */
434 Token = ObFastReferenceObjectLocked(&Process->Token);
435
436 /* Unlock the Process */
437 PspUnlockProcessSecurityShared(Process);
438 }
439
440 /* Return the Token */
441 return Token;
442 }
443
444 /*
445 * @implemented
446 */
447 NTSTATUS
448 NTAPI
449 PsOpenTokenOfProcess(IN HANDLE ProcessHandle,
450 OUT PACCESS_TOKEN* Token)
451 {
452 PEPROCESS Process;
453 NTSTATUS Status;
454 PAGED_CODE();
455 PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", ProcessHandle);
456
457 /* Get the Token */
458 Status = ObReferenceObjectByHandle(ProcessHandle,
459 PROCESS_QUERY_INFORMATION,
460 PsProcessType,
461 ExGetPreviousMode(),
462 (PVOID*)&Process,
463 NULL);
464 if (NT_SUCCESS(Status))
465 {
466 /* Reference the token and dereference the process */
467 *Token = PsReferencePrimaryToken(Process);
468 ObDereferenceObject(Process);
469 }
470
471 /* Return */
472 return Status;
473 }
474
475 /*
476 * @implemented
477 */
478 NTSTATUS
479 NTAPI
480 PsAssignImpersonationToken(IN PETHREAD Thread,
481 IN HANDLE TokenHandle)
482 {
483 PACCESS_TOKEN Token;
484 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
485 NTSTATUS Status;
486 PAGED_CODE();
487 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p Token: %p\n", Thread, TokenHandle);
488
489 /* Check if we were given a handle */
490 if (!TokenHandle)
491 {
492 /* Undo impersonation */
493 PsRevertThreadToSelf(Thread);
494 return STATUS_SUCCESS;
495 }
496
497 /* Get the token object */
498 Status = ObReferenceObjectByHandle(TokenHandle,
499 TOKEN_IMPERSONATE,
500 SeTokenObjectType,
501 KeGetPreviousMode(),
502 (PVOID*)&Token,
503 NULL);
504 if (!NT_SUCCESS(Status)) return(Status);
505
506 /* Make sure it's an impersonation token */
507 if (SeTokenType(Token) != TokenImpersonation)
508 {
509 /* Fail */
510 ObDereferenceObject(Token);
511 return STATUS_BAD_TOKEN_TYPE;
512 }
513
514 /* Get the impersonation level */
515 ImpersonationLevel = SeTokenImpersonationLevel(Token);
516
517 /* Call the impersonation API */
518 Status = PsImpersonateClient(Thread,
519 Token,
520 FALSE,
521 FALSE,
522 ImpersonationLevel);
523
524 /* Dereference the token and return status */
525 ObDereferenceObject(Token);
526 return Status;
527 }
528
529 /*
530 * @implemented
531 */
532 VOID
533 NTAPI
534 PsRevertToSelf(VOID)
535 {
536 /* Call the per-thread API */
537 PAGED_CODE();
538 PsRevertThreadToSelf(PsGetCurrentThread());
539 }
540
541 /*
542 * @implemented
543 */
544 VOID
545 NTAPI
546 PsRevertThreadToSelf(IN PETHREAD Thread)
547 {
548 PTOKEN Token = NULL;
549 PAGED_CODE();
550 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
551
552 /* Make sure we had impersonation information */
553 if (Thread->ActiveImpersonationInfo)
554 {
555 /* Lock the thread security */
556 PspLockThreadSecurityExclusive(Thread);
557
558 /* Make sure it's still active */
559 if (Thread->ActiveImpersonationInfo)
560 {
561 /* Disable impersonation */
562 PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
563
564 /* Get the token */
565 Token = Thread->ImpersonationInfo->Token;
566 }
567
568 /* Release thread security */
569 PspUnlockThreadSecurityExclusive(Thread);
570
571 /* Check if we had a token */
572 if (Token)
573 {
574 /* Dereference the impersonation token */
575 ObDereferenceObject(Token);
576
577 /* Write impersonation info to the TEB */
578 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
579 }
580 }
581 }
582
583 /*
584 * @implemented
585 */
586 NTSTATUS
587 NTAPI
588 PsImpersonateClient(IN PETHREAD Thread,
589 IN PACCESS_TOKEN Token,
590 IN BOOLEAN CopyOnOpen,
591 IN BOOLEAN EffectiveOnly,
592 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
593 {
594 PPS_IMPERSONATION_INFORMATION Impersonation, OldData;
595 PTOKEN OldToken = NULL;
596 PAGED_CODE();
597 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p, Token: %p\n", Thread, Token);
598
599 /* Check if we don't have a token */
600 if (!Token)
601 {
602 /* Make sure we're impersonating */
603 if (Thread->ActiveImpersonationInfo)
604 {
605 /* We seem to be, lock the thread */
606 PspLockThreadSecurityExclusive(Thread);
607
608 /* Make sure we're still impersonating */
609 if (Thread->ActiveImpersonationInfo)
610 {
611 /* Disable impersonation */
612 PspClearCrossThreadFlag(Thread,
613 CT_ACTIVE_IMPERSONATION_INFO_BIT);
614
615 /* Get the token */
616 OldToken = Thread->ImpersonationInfo->Token;
617 }
618
619 /* Unlock the process and write TEB information */
620 PspUnlockThreadSecurityExclusive(Thread);
621 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
622 }
623 }
624 else
625 {
626 /* Check if we have impersonation info */
627 Impersonation = Thread->ImpersonationInfo;
628 if (!Impersonation)
629 {
630 /* We need to allocate a new one */
631 Impersonation = ExAllocatePoolWithTag(PagedPool,
632 sizeof(*Impersonation),
633 TAG_PS_IMPERSONATION);
634 if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES;
635
636 /* Update the pointer */
637 OldData = InterlockedCompareExchangePointer((PVOID*)&Thread->
638 ImpersonationInfo,
639 Impersonation,
640 NULL);
641 if (OldData)
642 {
643 /* Someone beat us to it, free our copy */
644 ExFreePoolWithTag(Impersonation, TAG_PS_IMPERSONATION);
645 Impersonation = OldData;
646 }
647 }
648
649 /* Check if this is a job, which we don't support yet */
650 if (Thread->ThreadsProcess->Job) ASSERT(FALSE);
651
652 /* Lock thread security */
653 PspLockThreadSecurityExclusive(Thread);
654
655 /* Check if we're impersonating */
656 if (Thread->ActiveImpersonationInfo)
657 {
658 /* Get the token */
659 OldToken = Impersonation->Token;
660 }
661 else
662 {
663 /* Otherwise, enable impersonation */
664 PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
665 }
666
667 /* Now fill it out */
668 Impersonation->ImpersonationLevel = ImpersonationLevel;
669 Impersonation->CopyOnOpen = CopyOnOpen;
670 Impersonation->EffectiveOnly = EffectiveOnly;
671 Impersonation->Token = Token;
672 ObReferenceObject(Token);
673
674 /* Unlock the thread */
675 PspUnlockThreadSecurityExclusive(Thread);
676
677 /* Write impersonation info to the TEB */
678 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
679 }
680
681 /* Dereference the token and return success */
682 if (OldToken) PsDereferenceImpersonationToken(OldToken);
683 return STATUS_SUCCESS;
684 }
685
686 /*
687 * @implemented
688 */
689 PACCESS_TOKEN
690 NTAPI
691 PsReferenceEffectiveToken(IN PETHREAD Thread,
692 OUT IN PTOKEN_TYPE TokenType,
693 OUT PBOOLEAN EffectiveOnly,
694 OUT PSECURITY_IMPERSONATION_LEVEL Level)
695 {
696 PEPROCESS Process;
697 PACCESS_TOKEN Token = NULL;
698 PAGED_CODE();
699 PSTRACE(PS_SECURITY_DEBUG,
700 "Thread: %p, TokenType: %p\n", Thread, TokenType);
701
702 /* Check if we don't have impersonation info */
703 Process = Thread->ThreadsProcess;
704 if (Thread->ActiveImpersonationInfo)
705 {
706 /* Lock the Process */
707 PspLockProcessSecurityShared(Process);
708
709 /* Make sure impersonation is still active */
710 if (Thread->ActiveImpersonationInfo)
711 {
712 /* Get the token */
713 Token = Thread->ImpersonationInfo->Token;
714 ObReferenceObject(Token);
715
716 /* Return data to caller */
717 *TokenType = TokenImpersonation;
718 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
719 *Level = Thread->ImpersonationInfo->ImpersonationLevel;
720
721 /* Unlock the Process */
722 PspUnlockProcessSecurityShared(Process);
723 return Token;
724 }
725
726 /* Unlock the Process */
727 PspUnlockProcessSecurityShared(Process);
728 }
729
730 /* Fast Reference the Token */
731 Token = ObFastReferenceObject(&Process->Token);
732
733 /* Check if we got the Token or if we got locked */
734 if (!Token)
735 {
736 /* Lock the Process */
737 PspLockProcessSecurityShared(Process);
738
739 /* Do a Locked Fast Reference */
740 Token = ObFastReferenceObjectLocked(&Process->Token);
741
742 /* Unlock the Process */
743 PspUnlockProcessSecurityShared(Process);
744 }
745
746 /* Return the token */
747 *TokenType = TokenPrimary;
748 *EffectiveOnly = FALSE;
749 return Token;
750 }
751
752 /*
753 * @implemented
754 */
755 PACCESS_TOKEN
756 NTAPI
757 PsReferenceImpersonationToken(IN PETHREAD Thread,
758 OUT PBOOLEAN CopyOnOpen,
759 OUT PBOOLEAN EffectiveOnly,
760 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
761 {
762 PTOKEN Token = NULL;
763 PAGED_CODE();
764 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
765
766 /* If we don't have impersonation info, just quit */
767 if (!Thread->ActiveImpersonationInfo) return NULL;
768
769 /* Lock the thread */
770 PspLockThreadSecurityShared(Thread);
771
772 /* Make sure we still have active impersonation */
773 if (Thread->ActiveImpersonationInfo)
774 {
775 /* Return data from caller */
776 ObReferenceObject(Thread->ImpersonationInfo->Token);
777 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
778 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
779 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
780
781 /* Set the token */
782 Token = Thread->ImpersonationInfo->Token;
783 }
784
785 /* Unlock thread and return impersonation token */
786 PspUnlockThreadSecurityShared(Thread);
787 return Token;
788 }
789
790 #undef PsDereferenceImpersonationToken
791 /*
792 * @implemented
793 */
794 VOID
795 NTAPI
796 PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
797 {
798 PAGED_CODE();
799
800 /* If we got a token, dereference it */
801 if (ImpersonationToken) ObDereferenceObject(ImpersonationToken);
802 }
803
804 #undef PsDereferencePrimaryToken
805 /*
806 * @implemented
807 */
808 VOID
809 NTAPI
810 PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
811 {
812 PAGED_CODE();
813
814 /* Dereference the token*/
815 ObDereferenceObject(PrimaryToken);
816 }
817
818 /*
819 * @implemented
820 */
821 BOOLEAN
822 NTAPI
823 PsDisableImpersonation(IN PETHREAD Thread,
824 OUT PSE_IMPERSONATION_STATE ImpersonationState)
825 {
826 PPS_IMPERSONATION_INFORMATION Impersonation = NULL;
827 LONG OldFlags;
828 PAGED_CODE();
829 PSTRACE(PS_SECURITY_DEBUG,
830 "Thread: %p State: %p\n", Thread, ImpersonationState);
831
832 /* Check if we don't have impersonation */
833 if (Thread->ActiveImpersonationInfo)
834 {
835 /* Lock thread security */
836 PspLockThreadSecurityExclusive(Thread);
837
838 /* Disable impersonation */
839 OldFlags = PspClearCrossThreadFlag(Thread,
840 CT_ACTIVE_IMPERSONATION_INFO_BIT);
841
842 /* Make sure nobody disabled it behind our back */
843 if (OldFlags & CT_ACTIVE_IMPERSONATION_INFO_BIT)
844 {
845 /* Copy the old state */
846 Impersonation = Thread->ImpersonationInfo;
847 ImpersonationState->Token = Impersonation->Token;
848 ImpersonationState->CopyOnOpen = Impersonation->CopyOnOpen;
849 ImpersonationState->EffectiveOnly = Impersonation->EffectiveOnly;
850 ImpersonationState->Level = Impersonation->ImpersonationLevel;
851 }
852
853 /* Unlock thread security */
854 PspUnlockThreadSecurityExclusive(Thread);
855
856 /* If we had impersonation info, return true */
857 if (Impersonation) return TRUE;
858 }
859
860 /* Clear everything */
861 ImpersonationState->Token = NULL;
862 ImpersonationState->CopyOnOpen = FALSE;
863 ImpersonationState->EffectiveOnly = FALSE;
864 ImpersonationState->Level = SecurityAnonymous;
865 return FALSE;
866 }
867
868 /*
869 * @implemented
870 */
871 VOID
872 NTAPI
873 PsRestoreImpersonation(IN PETHREAD Thread,
874 IN PSE_IMPERSONATION_STATE ImpersonationState)
875 {
876 PTOKEN Token = NULL;
877 PPS_IMPERSONATION_INFORMATION Impersonation;
878 PAGED_CODE();
879 PSTRACE(PS_SECURITY_DEBUG,
880 "Thread: %p State: %p\n", Thread, ImpersonationState);
881
882 /* Lock thread security */
883 PspLockThreadSecurityExclusive(Thread);
884
885 /* Get the impersonation info */
886 Impersonation = Thread->ImpersonationInfo;
887
888 /* Check if we're impersonating */
889 if (Thread->ActiveImpersonationInfo)
890 {
891 /* Get the token */
892 Token = Impersonation->Token;
893 }
894
895 /* Check if we have an impersonation state */
896 if (ImpersonationState)
897 {
898 /* Fill out the impersonation info */
899 Impersonation->ImpersonationLevel = ImpersonationState->Level;
900 Impersonation->CopyOnOpen = ImpersonationState->CopyOnOpen;
901 Impersonation->EffectiveOnly = ImpersonationState->EffectiveOnly;
902 Impersonation->Token = ImpersonationState->Token;
903
904 /* Enable impersonation */
905 PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
906 }
907 else
908 {
909 /* Disable impersonation */
910 PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
911 }
912
913 /* Unlock the thread */
914 PspUnlockThreadSecurityExclusive(Thread);
915
916 /* Dereference the token */
917 if (Token) ObDereferenceObject(Token);
918 }
919
920 NTSTATUS
921 NTAPI
922 NtImpersonateThread(IN HANDLE ThreadHandle,
923 IN HANDLE ThreadToImpersonateHandle,
924 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
925 {
926 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
927 SECURITY_CLIENT_CONTEXT ClientContext;
928 PETHREAD Thread;
929 PETHREAD ThreadToImpersonate;
930 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
931 NTSTATUS Status;
932 PAGED_CODE();
933 PSTRACE(PS_SECURITY_DEBUG,
934 "Threads: %p %p\n", ThreadHandle, ThreadToImpersonateHandle);
935
936 /* Check if call came from user mode */
937 if (PreviousMode != KernelMode)
938 {
939 /* Enter SEH for probing */
940 _SEH2_TRY
941 {
942 /* Probe QoS */
943 ProbeForRead(SecurityQualityOfService,
944 sizeof(SECURITY_QUALITY_OF_SERVICE),
945 sizeof(ULONG));
946
947 /* Capture it */
948 SafeServiceQoS = *SecurityQualityOfService;
949 SecurityQualityOfService = &SafeServiceQoS;
950 }
951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
952 {
953 /* Return the exception code */
954 _SEH2_YIELD(return _SEH2_GetExceptionCode());
955 }
956 _SEH2_END;
957 }
958
959 /* Reference the thread */
960 Status = ObReferenceObjectByHandle(ThreadHandle,
961 THREAD_DIRECT_IMPERSONATION,
962 PsThreadType,
963 PreviousMode,
964 (PVOID*)&Thread,
965 NULL);
966 if (NT_SUCCESS(Status))
967 {
968 /* Reference the impersonating thead */
969 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
970 THREAD_IMPERSONATE,
971 PsThreadType,
972 PreviousMode,
973 (PVOID*)&ThreadToImpersonate,
974 NULL);
975 if (NT_SUCCESS(Status))
976 {
977 /* Create a client security context */
978 Status = SeCreateClientSecurity(ThreadToImpersonate,
979 SecurityQualityOfService,
980 0,
981 &ClientContext);
982 if (NT_SUCCESS(Status))
983 {
984 /* Do the impersonation */
985 SeImpersonateClient(&ClientContext, Thread);
986 if (ClientContext.ClientToken)
987 {
988 /* Dereference the client token if we had one */
989 ObDereferenceObject(ClientContext.ClientToken);
990 }
991 }
992
993 /* Dereference the thread to impersonate */
994 ObDereferenceObject(ThreadToImpersonate);
995 }
996
997 /* Dereference the main thread */
998 ObDereferenceObject(Thread);
999 }
1000
1001 /* Return status */
1002 return Status;
1003 }
1004 /* EOF */