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)
8 * Thomas Weidenmueller (w3seek@reactos.org)
11 /* INCLUDES ******************************************************************/
17 PTOKEN PspBootAccessToken
;
26 /* PRIVATE FUNCTIONS *********************************************************/
30 PspDeleteProcessSecurity(IN PEPROCESS Process
)
33 PSTRACE(PS_SECURITY_DEBUG
, "Process: %p\n", Process
);
35 /* Check if we have a token */
36 if (Process
->Token
.Object
)
39 SeDeassignPrimaryToken(Process
);
40 Process
->Token
.Object
= NULL
;
46 PspDeleteThreadSecurity(IN PETHREAD Thread
)
48 PPS_IMPERSONATION_INFORMATION ImpersonationInfo
= Thread
->ImpersonationInfo
;
50 PSTRACE(PS_SECURITY_DEBUG
, "Thread: %p\n", Thread
);
52 /* Check if we have active impersonation info */
53 if (Thread
->ActiveImpersonationInfo
)
55 /* Dereference its token */
56 ObDereferenceObject(ImpersonationInfo
->Token
);
59 /* Check if we have impersonation info */
60 if (ImpersonationInfo
)
63 ExFreePool(ImpersonationInfo
);
64 PspClearCrossThreadFlag(Thread
, CT_ACTIVE_IMPERSONATION_INFO_BIT
);
65 Thread
->ImpersonationInfo
= NULL
;
71 PspInitializeProcessSecurity(IN PEPROCESS Process
,
72 IN PEPROCESS Parent OPTIONAL
)
74 NTSTATUS Status
= STATUS_SUCCESS
;
75 PTOKEN NewToken
, ParentToken
;
77 PSTRACE(PS_SECURITY_DEBUG
, "Process: %p\n", Process
);
79 /* If we have a parent, then duplicate the Token */
82 /* Get the Parent Token */
83 ParentToken
= PsReferencePrimaryToken(Parent
);
86 Status
= SeSubProcessToken(ParentToken
,
89 MmGetSessionId(Process
));
91 /* Dereference the Parent */
92 ObFastDereferenceObject(&Parent
->Token
, ParentToken
);
94 /* Set the new Token */
95 if (NT_SUCCESS(Status
))
97 /* Initailize the fast reference */
98 ObInitializeFastReference(&Process
->Token
, NewToken
);
103 /* No parent, assign the Boot Token */
104 ObInitializeFastReference(&Process
->Token
, NULL
);
105 SeAssignPrimaryToken(Process
, PspBootAccessToken
);
108 /* Return to caller */
114 PspWriteTebImpersonationInfo(IN PETHREAD Thread
,
115 IN PETHREAD CurrentThread
)
119 BOOLEAN Attached
= FALSE
;
120 BOOLEAN IsImpersonating
;
123 PSTRACE(PS_SECURITY_DEBUG
, "Thread: %p\n", Thread
);
126 ASSERT(CurrentThread
== PsGetCurrentThread());
128 /* Get process and TEB */
129 Process
= Thread
->ThreadsProcess
;
130 Teb
= Thread
->Tcb
.Teb
;
133 /* Check if we're not in the right process */
134 if (Thread
->Tcb
.ApcState
.Process
!= &Process
->Pcb
)
136 /* Attach to the process */
137 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
141 /* Check if we're in a different thread or acquire rundown */
142 if ((Thread
== CurrentThread
) ||
143 (ExAcquireRundownProtection(&Thread
->RundownProtect
)))
145 /* Check if the thread is impersonating */
146 IsImpersonating
= (BOOLEAN
)Thread
->ActiveImpersonationInfo
;
150 Teb
->ImpersonationLocale
= -1;
151 Teb
->IsImpersonating
= 1;
156 Teb
->ImpersonationLocale
= 0;
157 Teb
->IsImpersonating
= 0;
161 /* Check if we're in a different thread */
162 if (Thread
!= CurrentThread
)
164 /* Release protection */
165 ExReleaseRundownProtection(&Thread
->RundownProtect
);
169 if (Attached
) KeUnstackDetachProcess(&ApcState
);
172 /* Return to caller */
173 return STATUS_SUCCESS
;
178 PspAssignPrimaryToken(IN PEPROCESS Process
,
180 IN PACCESS_TOKEN AccessToken OPTIONAL
)
182 PACCESS_TOKEN NewToken
= AccessToken
, OldToken
;
185 PSTRACE(PS_SECURITY_DEBUG
, "Process: %p Token: %p\n", Process
, Token
);
187 /* Check if we don't have a pointer */
190 /* Reference it from the handle */
191 Status
= ObReferenceObjectByHandle(Token
,
192 TOKEN_ASSIGN_PRIMARY
,
197 if (!NT_SUCCESS(Status
)) return Status
;
200 /* Exchange tokens */
201 Status
= SeExchangePrimaryToken(Process
, NewToken
, &OldToken
);
203 /* Acquire and release the lock */
204 PspLockProcessSecurityExclusive(Process
);
205 PspUnlockProcessSecurityExclusive(Process
);
207 /* Dereference Tokens and Return */
208 if (NT_SUCCESS(Status
)) ObDereferenceObject(OldToken
);
209 if (!AccessToken
) ObDereferenceObject(NewToken
);
215 PspSetPrimaryToken(IN PEPROCESS Process
,
216 IN HANDLE TokenHandle OPTIONAL
,
217 IN PACCESS_TOKEN Token OPTIONAL
)
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
;
227 PSTRACE(PS_SECURITY_DEBUG
, "Process: %p Token: %p\n", Process
, Token
);
229 /* Reference the token by handle if we don't already have a token object */
232 Status
= ObReferenceObjectByHandle(TokenHandle
,
233 TOKEN_ASSIGN_PRIMARY
,
238 if (!NT_SUCCESS(Status
)) return Status
;
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.
246 Status
= SeIsTokenChild(NewToken
, &IsChildOrSibling
);
247 if (!NT_SUCCESS(Status
))
249 /* Failed, dereference */
250 if (!Token
) ObDereferenceObject(NewToken
);
253 if (!IsChildOrSibling
)
255 Status
= SeIsTokenSibling(NewToken
, &IsChildOrSibling
);
256 if (!NT_SUCCESS(Status
))
258 /* Failed, dereference */
259 if (!Token
) ObDereferenceObject(NewToken
);
264 /* Check if this was an independent token */
265 if (!IsChildOrSibling
)
267 /* Make sure we have the privilege to assign a new one */
268 if (!SeSinglePrivilegeCheck(SeAssignPrimaryTokenPrivilege
,
271 /* Failed, dereference */
272 if (!Token
) ObDereferenceObject(NewToken
);
273 return STATUS_PRIVILEGE_NOT_HELD
;
277 /* Assign the token */
278 Status
= PspAssignPrimaryToken(Process
, NULL
, NewToken
);
279 if (NT_SUCCESS(Status
))
282 * We need to completely reverify if the process still has access to
283 * itself under this new token.
285 Status
= ObGetObjectSecurity(Process
,
288 if (NT_SUCCESS(Status
))
290 /* Setup the security context */
291 SubjectContext
.ProcessAuditId
= Process
;
292 SubjectContext
.PrimaryToken
= PsReferencePrimaryToken(Process
);
293 SubjectContext
.ClientToken
= NULL
;
295 /* Do the access check */
296 Result
= SeAccessCheck(SecurityDescriptor
,
302 &PsProcessType
->TypeInfo
.GenericMapping
,
304 &Process
->GrantedAccess
,
307 /* Dereference the token and let go the SD */
308 ObFastDereferenceObject(&Process
->Token
,
309 SubjectContext
.PrimaryToken
);
310 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
312 /* Remove access if it failed */
313 if (!Result
) Process
->GrantedAccess
= 0;
315 /* Setup granted access */
316 Process
->GrantedAccess
|= (PROCESS_VM_OPERATION
|
319 PROCESS_QUERY_INFORMATION
|
321 PROCESS_CREATE_THREAD
|
323 PROCESS_CREATE_PROCESS
|
324 PROCESS_SET_INFORMATION
|
325 STANDARD_RIGHTS_ALL
|
330 * In case LUID device maps are enable, we may not be using
331 * system device map for this process, but a logon LUID based
332 * device map. Because we change primary token, this usage is
333 * no longer valid, so dereference the process device map
335 if (ObIsLUIDDeviceMapsEnabled()) ObDereferenceDeviceMap(Process
);
338 /* Dereference the token */
339 if (!Token
) ObDereferenceObject(NewToken
);
343 /* FUNCTIONS *****************************************************************/
350 NtOpenProcessToken(IN HANDLE ProcessHandle
,
351 IN ACCESS_MASK DesiredAccess
,
352 OUT PHANDLE TokenHandle
)
354 /* Call the newer API */
355 return NtOpenProcessTokenEx(ProcessHandle
,
366 NtOpenProcessTokenEx(IN HANDLE ProcessHandle
,
367 IN ACCESS_MASK DesiredAccess
,
368 IN ULONG HandleAttributes
,
369 OUT PHANDLE TokenHandle
)
373 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
376 PSTRACE(PS_SECURITY_DEBUG
,
377 "Process: %p DesiredAccess: %lx\n", ProcessHandle
, DesiredAccess
);
379 /* Check if caller was user-mode */
380 if (PreviousMode
!= KernelMode
)
382 /* Enter SEH for probing */
385 /* Probe the token handle */
386 ProbeForWriteHandle(TokenHandle
);
388 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
390 /* Return the exception code */
391 _SEH2_YIELD(return _SEH2_GetExceptionCode());
396 /* Validate object attributes */
397 HandleAttributes
= ObpValidateAttributes(HandleAttributes
, PreviousMode
);
399 /* Open the process token */
400 Status
= PsOpenTokenOfProcess(ProcessHandle
, &Token
);
401 if (NT_SUCCESS(Status
))
403 /* Reference it by handle and dereference the pointer */
404 Status
= ObOpenObjectByPointer(Token
,
411 ObDereferenceObject(Token
);
413 /* Make sure we got a handle */
414 if (NT_SUCCESS(Status
))
416 /* Enter SEH for write */
419 /* Return the handle */
420 *TokenHandle
= hToken
;
422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
424 /* Get exception code */
425 Status
= _SEH2_GetExceptionCode();
440 PsReferencePrimaryToken(PEPROCESS Process
)
444 PSTRACE(PS_SECURITY_DEBUG
, "Process: %p\n", Process
);
446 /* Fast Reference the Token */
447 Token
= ObFastReferenceObject(&Process
->Token
);
449 /* Check if we got the Token or if we got locked */
452 /* Lock the Process */
453 PspLockProcessSecurityShared(Process
);
455 /* Do a Locked Fast Reference */
456 Token
= ObFastReferenceObjectLocked(&Process
->Token
);
458 /* Unlock the Process */
459 PspUnlockProcessSecurityShared(Process
);
462 /* Return the Token */
471 PsOpenTokenOfProcess(IN HANDLE ProcessHandle
,
472 OUT PACCESS_TOKEN
* Token
)
477 PSTRACE(PS_SECURITY_DEBUG
, "Process: %p\n", ProcessHandle
);
480 Status
= ObReferenceObjectByHandle(ProcessHandle
,
481 PROCESS_QUERY_INFORMATION
,
486 if (NT_SUCCESS(Status
))
488 /* Reference the token and dereference the process */
489 *Token
= PsReferencePrimaryToken(Process
);
490 ObDereferenceObject(Process
);
502 PsAssignImpersonationToken(IN PETHREAD Thread
,
503 IN HANDLE TokenHandle
)
506 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
509 PSTRACE(PS_SECURITY_DEBUG
, "Thread: %p Token: %p\n", Thread
, TokenHandle
);
511 /* Check if we were given a handle */
514 /* Undo impersonation */
515 PsRevertThreadToSelf(Thread
);
516 return STATUS_SUCCESS
;
519 /* Get the token object */
520 Status
= ObReferenceObjectByHandle(TokenHandle
,
526 if (!NT_SUCCESS(Status
)) return(Status
);
528 /* Make sure it's an impersonation token */
529 if (SeTokenType(Token
) != TokenImpersonation
)
532 ObDereferenceObject(Token
);
533 return STATUS_BAD_TOKEN_TYPE
;
536 /* Get the impersonation level */
537 ImpersonationLevel
= SeTokenImpersonationLevel(Token
);
539 /* Call the impersonation API */
540 Status
= PsImpersonateClient(Thread
,
546 /* Dereference the token and return status */
547 ObDereferenceObject(Token
);
558 /* Call the per-thread API */
560 PsRevertThreadToSelf(PsGetCurrentThread());
568 PsRevertThreadToSelf(IN PETHREAD Thread
)
572 PSTRACE(PS_SECURITY_DEBUG
, "Thread: %p\n", Thread
);
574 /* Make sure we had impersonation information */
575 if (Thread
->ActiveImpersonationInfo
)
577 /* Lock the thread security */
578 PspLockThreadSecurityExclusive(Thread
);
580 /* Make sure it's still active */
581 if (Thread
->ActiveImpersonationInfo
)
583 /* Disable impersonation */
584 PspClearCrossThreadFlag(Thread
, CT_ACTIVE_IMPERSONATION_INFO_BIT
);
587 Token
= Thread
->ImpersonationInfo
->Token
;
590 /* Release thread security */
591 PspUnlockThreadSecurityExclusive(Thread
);
593 /* Check if we had a token */
596 /* Dereference the impersonation token */
597 ObDereferenceObject(Token
);
599 /* Write impersonation info to the TEB */
600 PspWriteTebImpersonationInfo(Thread
, PsGetCurrentThread());
610 PsImpersonateClient(IN PETHREAD Thread
,
611 IN PACCESS_TOKEN Token
,
612 IN BOOLEAN CopyOnOpen
,
613 IN BOOLEAN EffectiveOnly
,
614 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
616 PPS_IMPERSONATION_INFORMATION Impersonation
, OldData
;
617 PTOKEN OldToken
= NULL
;
619 PSTRACE(PS_SECURITY_DEBUG
, "Thread: %p, Token: %p\n", Thread
, Token
);
621 /* Check if we don't have a token */
624 /* Make sure we're impersonating */
625 if (Thread
->ActiveImpersonationInfo
)
627 /* We seem to be, lock the thread */
628 PspLockThreadSecurityExclusive(Thread
);
630 /* Make sure we're still impersonating */
631 if (Thread
->ActiveImpersonationInfo
)
633 /* Disable impersonation */
634 PspClearCrossThreadFlag(Thread
,
635 CT_ACTIVE_IMPERSONATION_INFO_BIT
);
638 OldToken
= Thread
->ImpersonationInfo
->Token
;
641 /* Unlock the process and write TEB information */
642 PspUnlockThreadSecurityExclusive(Thread
);
643 PspWriteTebImpersonationInfo(Thread
, PsGetCurrentThread());
648 /* Check if we have impersonation info */
649 Impersonation
= Thread
->ImpersonationInfo
;
652 /* We need to allocate a new one */
653 Impersonation
= ExAllocatePoolWithTag(PagedPool
,
654 sizeof(*Impersonation
),
655 TAG_PS_IMPERSONATION
);
656 if (!Impersonation
) return STATUS_INSUFFICIENT_RESOURCES
;
658 /* Update the pointer */
659 OldData
= InterlockedCompareExchangePointer((PVOID
*)&Thread
->
665 /* Someone beat us to it, free our copy */
666 ExFreePoolWithTag(Impersonation
, TAG_PS_IMPERSONATION
);
667 Impersonation
= OldData
;
671 /* Check if this is a job, which we don't support yet */
672 if (Thread
->ThreadsProcess
->Job
) ASSERT(FALSE
);
674 /* Lock thread security */
675 PspLockThreadSecurityExclusive(Thread
);
677 /* Check if we're impersonating */
678 if (Thread
->ActiveImpersonationInfo
)
681 OldToken
= Impersonation
->Token
;
685 /* Otherwise, enable impersonation */
686 PspSetCrossThreadFlag(Thread
, CT_ACTIVE_IMPERSONATION_INFO_BIT
);
689 /* Now fill it out */
690 Impersonation
->ImpersonationLevel
= ImpersonationLevel
;
691 Impersonation
->CopyOnOpen
= CopyOnOpen
;
692 Impersonation
->EffectiveOnly
= EffectiveOnly
;
693 Impersonation
->Token
= Token
;
694 ObReferenceObject(Token
);
696 /* Unlock the thread */
697 PspUnlockThreadSecurityExclusive(Thread
);
699 /* Write impersonation info to the TEB */
700 PspWriteTebImpersonationInfo(Thread
, PsGetCurrentThread());
703 /* Dereference the token and return success */
704 if (OldToken
) PsDereferenceImpersonationToken(OldToken
);
705 return STATUS_SUCCESS
;
713 PsReferenceEffectiveToken(IN PETHREAD Thread
,
714 OUT IN PTOKEN_TYPE TokenType
,
715 OUT PBOOLEAN EffectiveOnly
,
716 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
719 PACCESS_TOKEN Token
= NULL
;
723 PSTRACE(PS_SECURITY_DEBUG
,
724 "Thread: %p, TokenType: %p\n", Thread
, TokenType
);
726 /* Check if we don't have impersonation info */
727 Process
= Thread
->ThreadsProcess
;
728 if (Thread
->ActiveImpersonationInfo
)
730 /* Lock the Process */
731 PspLockProcessSecurityShared(Process
);
733 /* Make sure impersonation is still active */
734 if (Thread
->ActiveImpersonationInfo
)
737 Token
= Thread
->ImpersonationInfo
->Token
;
738 ObReferenceObject(Token
);
740 /* Return data to caller */
741 *TokenType
= TokenImpersonation
;
742 *EffectiveOnly
= Thread
->ImpersonationInfo
->EffectiveOnly
;
743 *ImpersonationLevel
= Thread
->ImpersonationInfo
->ImpersonationLevel
;
745 /* Unlock the Process */
746 PspUnlockProcessSecurityShared(Process
);
750 /* Unlock the Process */
751 PspUnlockProcessSecurityShared(Process
);
754 /* Fast Reference the Token */
755 Token
= ObFastReferenceObject(&Process
->Token
);
757 /* Check if we got the Token or if we got locked */
760 /* Lock the Process */
761 PspLockProcessSecurityShared(Process
);
763 /* Do a Locked Fast Reference */
764 Token
= ObFastReferenceObjectLocked(&Process
->Token
);
766 /* Unlock the Process */
767 PspUnlockProcessSecurityShared(Process
);
770 /* Return the token */
771 *TokenType
= TokenPrimary
;
772 *EffectiveOnly
= FALSE
;
773 // NOTE: ImpersonationLevel is left untouched on purpose!
782 PsReferenceImpersonationToken(IN PETHREAD Thread
,
783 OUT PBOOLEAN CopyOnOpen
,
784 OUT PBOOLEAN EffectiveOnly
,
785 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
789 PSTRACE(PS_SECURITY_DEBUG
, "Thread: %p\n", Thread
);
791 /* If we don't have impersonation info, just quit */
792 if (!Thread
->ActiveImpersonationInfo
) return NULL
;
794 /* Lock the thread */
795 PspLockThreadSecurityShared(Thread
);
797 /* Make sure we still have active impersonation */
798 if (Thread
->ActiveImpersonationInfo
)
800 /* Return data from caller */
801 ObReferenceObject(Thread
->ImpersonationInfo
->Token
);
802 *ImpersonationLevel
= Thread
->ImpersonationInfo
->ImpersonationLevel
;
803 *CopyOnOpen
= Thread
->ImpersonationInfo
->CopyOnOpen
;
804 *EffectiveOnly
= Thread
->ImpersonationInfo
->EffectiveOnly
;
807 Token
= Thread
->ImpersonationInfo
->Token
;
810 /* Unlock thread and return impersonation token */
811 PspUnlockThreadSecurityShared(Thread
);
815 #undef PsDereferenceImpersonationToken
821 PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken
)
825 /* If we got a token, dereference it */
826 if (ImpersonationToken
) ObDereferenceObject(ImpersonationToken
);
829 #undef PsDereferencePrimaryToken
835 PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken
)
839 /* Dereference the token*/
840 ObDereferenceObject(PrimaryToken
);
848 PsDisableImpersonation(IN PETHREAD Thread
,
849 OUT PSE_IMPERSONATION_STATE ImpersonationState
)
851 PPS_IMPERSONATION_INFORMATION Impersonation
= NULL
;
854 PSTRACE(PS_SECURITY_DEBUG
,
855 "Thread: %p State: %p\n", Thread
, ImpersonationState
);
857 /* Check if we don't have impersonation */
858 if (Thread
->ActiveImpersonationInfo
)
860 /* Lock thread security */
861 PspLockThreadSecurityExclusive(Thread
);
863 /* Disable impersonation */
864 OldFlags
= PspClearCrossThreadFlag(Thread
,
865 CT_ACTIVE_IMPERSONATION_INFO_BIT
);
867 /* Make sure nobody disabled it behind our back */
868 if (OldFlags
& CT_ACTIVE_IMPERSONATION_INFO_BIT
)
870 /* Copy the old state */
871 Impersonation
= Thread
->ImpersonationInfo
;
872 ImpersonationState
->Token
= Impersonation
->Token
;
873 ImpersonationState
->CopyOnOpen
= Impersonation
->CopyOnOpen
;
874 ImpersonationState
->EffectiveOnly
= Impersonation
->EffectiveOnly
;
875 ImpersonationState
->Level
= Impersonation
->ImpersonationLevel
;
878 /* Unlock thread security */
879 PspUnlockThreadSecurityExclusive(Thread
);
881 /* If we had impersonation info, return true */
882 if (Impersonation
) return TRUE
;
885 /* Clear everything */
886 ImpersonationState
->Token
= NULL
;
887 ImpersonationState
->CopyOnOpen
= FALSE
;
888 ImpersonationState
->EffectiveOnly
= FALSE
;
889 ImpersonationState
->Level
= SecurityAnonymous
;
898 PsRestoreImpersonation(IN PETHREAD Thread
,
899 IN PSE_IMPERSONATION_STATE ImpersonationState
)
902 PPS_IMPERSONATION_INFORMATION Impersonation
;
904 PSTRACE(PS_SECURITY_DEBUG
,
905 "Thread: %p State: %p\n", Thread
, ImpersonationState
);
907 /* Lock thread security */
908 PspLockThreadSecurityExclusive(Thread
);
910 /* Get the impersonation info */
911 Impersonation
= Thread
->ImpersonationInfo
;
913 /* Check if we're impersonating */
914 if (Thread
->ActiveImpersonationInfo
)
917 Token
= Impersonation
->Token
;
920 /* Check if we have an impersonation state */
921 if (ImpersonationState
)
923 /* Fill out the impersonation info */
924 Impersonation
->ImpersonationLevel
= ImpersonationState
->Level
;
925 Impersonation
->CopyOnOpen
= ImpersonationState
->CopyOnOpen
;
926 Impersonation
->EffectiveOnly
= ImpersonationState
->EffectiveOnly
;
927 Impersonation
->Token
= ImpersonationState
->Token
;
929 /* Enable impersonation */
930 PspSetCrossThreadFlag(Thread
, CT_ACTIVE_IMPERSONATION_INFO_BIT
);
934 /* Disable impersonation */
935 PspClearCrossThreadFlag(Thread
, CT_ACTIVE_IMPERSONATION_INFO_BIT
);
938 /* Unlock the thread */
939 PspUnlockThreadSecurityExclusive(Thread
);
941 /* Dereference the token */
942 if (Token
) ObDereferenceObject(Token
);
947 NtImpersonateThread(IN HANDLE ThreadHandle
,
948 IN HANDLE ThreadToImpersonateHandle
,
949 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
)
951 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS
;
952 SECURITY_CLIENT_CONTEXT ClientContext
;
954 PETHREAD ThreadToImpersonate
;
955 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
958 PSTRACE(PS_SECURITY_DEBUG
,
959 "Threads: %p %p\n", ThreadHandle
, ThreadToImpersonateHandle
);
961 /* Check if call came from user mode */
962 if (PreviousMode
!= KernelMode
)
964 /* Enter SEH for probing */
968 ProbeForRead(SecurityQualityOfService
,
969 sizeof(SECURITY_QUALITY_OF_SERVICE
),
973 SafeServiceQoS
= *SecurityQualityOfService
;
974 SecurityQualityOfService
= &SafeServiceQoS
;
976 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
978 /* Return the exception code */
979 _SEH2_YIELD(return _SEH2_GetExceptionCode());
984 /* Reference the thread */
985 Status
= ObReferenceObjectByHandle(ThreadHandle
,
986 THREAD_DIRECT_IMPERSONATION
,
991 if (NT_SUCCESS(Status
))
993 /* Reference the impersonating thead */
994 Status
= ObReferenceObjectByHandle(ThreadToImpersonateHandle
,
998 (PVOID
*)&ThreadToImpersonate
,
1000 if (NT_SUCCESS(Status
))
1002 /* Create a client security context */
1003 Status
= SeCreateClientSecurity(ThreadToImpersonate
,
1004 SecurityQualityOfService
,
1007 if (NT_SUCCESS(Status
))
1009 /* Do the impersonation */
1010 SeImpersonateClient(&ClientContext
, Thread
);
1011 if (ClientContext
.ClientToken
)
1013 /* Dereference the client token if we had one */
1014 ObDereferenceObject(ClientContext
.ClientToken
);
1018 /* Dereference the thread to impersonate */
1019 ObDereferenceObject(ThreadToImpersonate
);
1022 /* Dereference the main thread */
1023 ObDereferenceObject(Thread
);