reactos/ntoskrnl/ps/security.c
Hermès Bélusca-Maïto 89c5191d3f
[NTOS:PS] In PspSetPrimaryToken(), check also for sibling token to determine whether it is required to have the SeAssignPrimaryTokenPrivilege.
In addition, it is the presence or absence of the 'Token' pointer that indicates whether or not we should use instead the provided token handle.
2018-09-28 00:45:03 +02:00

1021 lines
30 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ps/security.c
* PURPOSE: Process Manager: Process/Thread Security
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
* Thomas Weidenmueller (w3seek@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
PTOKEN PspBootAccessToken;
VOID
NTAPI
SeAssignPrimaryToken(
IN PEPROCESS Process,
IN PTOKEN Token
);
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
PspDeleteProcessSecurity(IN PEPROCESS Process)
{
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
/* Check if we have a token */
if (Process->Token.Object)
{
/* Deassign it */
SeDeassignPrimaryToken(Process);
Process->Token.Object = NULL;
}
}
VOID
NTAPI
PspDeleteThreadSecurity(IN PETHREAD Thread)
{
PPS_IMPERSONATION_INFORMATION ImpersonationInfo = Thread->ImpersonationInfo;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
/* Check if we have active impersonation info */
if (Thread->ActiveImpersonationInfo)
{
/* Dereference its token */
ObDereferenceObject(ImpersonationInfo->Token);
}
/* Check if we have impersonation info */
if (ImpersonationInfo)
{
/* Free it */
ExFreePool(ImpersonationInfo);
PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
Thread->ImpersonationInfo = NULL;
}
}
NTSTATUS
NTAPI
PspInitializeProcessSecurity(IN PEPROCESS Process,
IN PEPROCESS Parent OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
PTOKEN NewToken, ParentToken;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
/* If we have a parent, then duplicate the Token */
if (Parent)
{
/* Get the Parent Token */
ParentToken = PsReferencePrimaryToken(Parent);
/* Duplicate it */
Status = SeSubProcessToken(ParentToken,
&NewToken,
TRUE,
MmGetSessionId(Process));
/* Dereference the Parent */
ObFastDereferenceObject(&Parent->Token, ParentToken);
/* Set the new Token */
if (NT_SUCCESS(Status))
{
/* Initailize the fast reference */
ObInitializeFastReference(&Process->Token, NewToken);
}
}
else
{
/* No parent, assign the Boot Token */
ObInitializeFastReference(&Process->Token, NULL);
SeAssignPrimaryToken(Process, PspBootAccessToken);
}
/* Return to caller */
return Status;
}
NTSTATUS
NTAPI
PspWriteTebImpersonationInfo(IN PETHREAD Thread,
IN PETHREAD CurrentThread)
{
PEPROCESS Process;
PTEB Teb;
BOOLEAN Attached = FALSE;
BOOLEAN IsImpersonating;
KAPC_STATE ApcState;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
/* Sanity check */
ASSERT(CurrentThread == PsGetCurrentThread());
/* Get process and TEB */
Process = Thread->ThreadsProcess;
Teb = Thread->Tcb.Teb;
if (Teb)
{
/* Check if we're not in the right process */
if (Thread->Tcb.ApcState.Process != &Process->Pcb)
{
/* Attach to the process */
KeStackAttachProcess(&Process->Pcb, &ApcState);
Attached = TRUE;
}
/* Check if we're in a different thread or acquire rundown */
if ((Thread == CurrentThread) ||
(ExAcquireRundownProtection(&Thread->RundownProtect)))
{
/* Check if the thread is impersonating */
IsImpersonating = (BOOLEAN)Thread->ActiveImpersonationInfo;
if (IsImpersonating)
{
/* Set TEB data */
Teb->ImpersonationLocale = -1;
Teb->IsImpersonating = 1;
}
else
{
/* Set TEB data */
Teb->ImpersonationLocale = 0;
Teb->IsImpersonating = 0;
}
}
/* Check if we're in a different thread */
if (Thread != CurrentThread)
{
/* Release protection */
ExReleaseRundownProtection(&Thread->RundownProtect);
}
/* Detach */
if (Attached) KeUnstackDetachProcess(&ApcState);
}
/* Return to caller */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PspAssignPrimaryToken(IN PEPROCESS Process,
IN HANDLE Token,
IN PACCESS_TOKEN AccessToken OPTIONAL)
{
PACCESS_TOKEN NewToken = AccessToken, OldToken;
NTSTATUS Status;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
/* Check if we don't have a pointer */
if (!AccessToken)
{
/* Reference it from the handle */
Status = ObReferenceObjectByHandle(Token,
TOKEN_ASSIGN_PRIMARY,
SeTokenObjectType,
ExGetPreviousMode(),
&NewToken,
NULL);
if (!NT_SUCCESS(Status)) return Status;
}
/* Exchange tokens */
Status = SeExchangePrimaryToken(Process, NewToken, &OldToken);
/* Acquire and release the lock */
PspLockProcessSecurityExclusive(Process);
PspUnlockProcessSecurityExclusive(Process);
/* Dereference Tokens and Return */
if (NT_SUCCESS(Status)) ObDereferenceObject(OldToken);
if (!AccessToken) ObDereferenceObject(NewToken);
return Status;
}
NTSTATUS
NTAPI
PspSetPrimaryToken(IN PEPROCESS Process,
IN HANDLE TokenHandle OPTIONAL,
IN PACCESS_TOKEN Token OPTIONAL)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
BOOLEAN IsChildOrSibling;
PACCESS_TOKEN NewToken = Token;
NTSTATUS Status, AccessStatus;
BOOLEAN Result, SdAllocated;
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
SECURITY_SUBJECT_CONTEXT SubjectContext;
PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
/* Reference the token by handle if we don't already have a token object */
if (!Token)
{
Status = ObReferenceObjectByHandle(TokenHandle,
TOKEN_ASSIGN_PRIMARY,
SeTokenObjectType,
PreviousMode,
(PVOID*)&NewToken,
NULL);
if (!NT_SUCCESS(Status)) return Status;
}
/*
* Check whether this token is a child or sibling of the current process token.
* NOTE: On Windows Vista+ both of these checks (together with extra steps)
* are now performed by a new SeIsTokenAssignableToProcess() helper.
*/
Status = SeIsTokenChild(NewToken, &IsChildOrSibling);
if (!NT_SUCCESS(Status))
{
/* Failed, dereference */
if (!Token) ObDereferenceObject(NewToken);
return Status;
}
if (!IsChildOrSibling)
{
Status = SeIsTokenSibling(NewToken, &IsChildOrSibling);
if (!NT_SUCCESS(Status))
{
/* Failed, dereference */
if (!Token) ObDereferenceObject(NewToken);
return Status;
}
}
/* Check if this was an independent token */
if (!IsChildOrSibling)
{
/* Make sure we have the privilege to assign a new one */
if (!SeSinglePrivilegeCheck(SeAssignPrimaryTokenPrivilege,
PreviousMode))
{
/* Failed, dereference */
if (!Token) ObDereferenceObject(NewToken);
return STATUS_PRIVILEGE_NOT_HELD;
}
}
/* Assign the token */
Status = PspAssignPrimaryToken(Process, NULL, NewToken);
if (NT_SUCCESS(Status))
{
/*
* We need to completely reverify if the process still has access to
* itself under this new token.
*/
Status = ObGetObjectSecurity(Process,
&SecurityDescriptor,
&SdAllocated);
if (NT_SUCCESS(Status))
{
/* Setup the security context */
SubjectContext.ProcessAuditId = Process;
SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
SubjectContext.ClientToken = NULL;
/* Do the access check */
Result = SeAccessCheck(SecurityDescriptor,
&SubjectContext,
FALSE,
MAXIMUM_ALLOWED,
0,
NULL,
&PsProcessType->TypeInfo.GenericMapping,
PreviousMode,
&Process->GrantedAccess,
&AccessStatus);
/* Dereference the token and let go the SD */
ObFastDereferenceObject(&Process->Token,
SubjectContext.PrimaryToken);
ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
/* Remove access if it failed */
if (!Result) Process->GrantedAccess = 0;
/* Setup granted access */
Process->GrantedAccess |= (PROCESS_VM_OPERATION |
PROCESS_VM_READ |
PROCESS_VM_WRITE |
PROCESS_QUERY_INFORMATION |
PROCESS_TERMINATE |
PROCESS_CREATE_THREAD |
PROCESS_DUP_HANDLE |
PROCESS_CREATE_PROCESS |
PROCESS_SET_INFORMATION |
STANDARD_RIGHTS_ALL |
PROCESS_SET_QUOTA);
}
}
/* Dereference the token */
if (!Token) ObDereferenceObject(NewToken);
return Status;
}
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
NtOpenProcessToken(IN HANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
OUT PHANDLE TokenHandle)
{
/* Call the newer API */
return NtOpenProcessTokenEx(ProcessHandle,
DesiredAccess,
0,
TokenHandle);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN ULONG HandleAttributes,
OUT PHANDLE TokenHandle)
{
PACCESS_TOKEN Token;
HANDLE hToken;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG,
"Process: %p DesiredAccess: %lx\n", ProcessHandle, DesiredAccess);
/* Check if caller was user-mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the token handle */
ProbeForWriteHandle(TokenHandle);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Validate object attributes */
HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
/* Open the process token */
Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
if (NT_SUCCESS(Status))
{
/* Reference it by handle and dereference the pointer */
Status = ObOpenObjectByPointer(Token,
HandleAttributes,
NULL,
DesiredAccess,
SeTokenObjectType,
PreviousMode,
&hToken);
ObDereferenceObject(Token);
/* Make sure we got a handle */
if (NT_SUCCESS(Status))
{
/* Enter SEH for write */
_SEH2_TRY
{
/* Return the handle */
*TokenHandle = hToken;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
/* Return status */
return Status;
}
/*
* @implemented
*/
PACCESS_TOKEN
NTAPI
PsReferencePrimaryToken(PEPROCESS Process)
{
PACCESS_TOKEN Token;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
/* Fast Reference the Token */
Token = ObFastReferenceObject(&Process->Token);
/* Check if we got the Token or if we got locked */
if (!Token)
{
/* Lock the Process */
PspLockProcessSecurityShared(Process);
/* Do a Locked Fast Reference */
Token = ObFastReferenceObjectLocked(&Process->Token);
/* Unlock the Process */
PspUnlockProcessSecurityShared(Process);
}
/* Return the Token */
return Token;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
PsOpenTokenOfProcess(IN HANDLE ProcessHandle,
OUT PACCESS_TOKEN* Token)
{
PEPROCESS Process;
NTSTATUS Status;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", ProcessHandle);
/* Get the Token */
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_QUERY_INFORMATION,
PsProcessType,
ExGetPreviousMode(),
(PVOID*)&Process,
NULL);
if (NT_SUCCESS(Status))
{
/* Reference the token and dereference the process */
*Token = PsReferencePrimaryToken(Process);
ObDereferenceObject(Process);
}
/* Return */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
PsAssignImpersonationToken(IN PETHREAD Thread,
IN HANDLE TokenHandle)
{
PACCESS_TOKEN Token;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
NTSTATUS Status;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Thread: %p Token: %p\n", Thread, TokenHandle);
/* Check if we were given a handle */
if (!TokenHandle)
{
/* Undo impersonation */
PsRevertThreadToSelf(Thread);
return STATUS_SUCCESS;
}
/* Get the token object */
Status = ObReferenceObjectByHandle(TokenHandle,
TOKEN_IMPERSONATE,
SeTokenObjectType,
KeGetPreviousMode(),
(PVOID*)&Token,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
/* Make sure it's an impersonation token */
if (SeTokenType(Token) != TokenImpersonation)
{
/* Fail */
ObDereferenceObject(Token);
return STATUS_BAD_TOKEN_TYPE;
}
/* Get the impersonation level */
ImpersonationLevel = SeTokenImpersonationLevel(Token);
/* Call the impersonation API */
Status = PsImpersonateClient(Thread,
Token,
FALSE,
FALSE,
ImpersonationLevel);
/* Dereference the token and return status */
ObDereferenceObject(Token);
return Status;
}
/*
* @implemented
*/
VOID
NTAPI
PsRevertToSelf(VOID)
{
/* Call the per-thread API */
PAGED_CODE();
PsRevertThreadToSelf(PsGetCurrentThread());
}
/*
* @implemented
*/
VOID
NTAPI
PsRevertThreadToSelf(IN PETHREAD Thread)
{
PTOKEN Token = NULL;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
/* Make sure we had impersonation information */
if (Thread->ActiveImpersonationInfo)
{
/* Lock the thread security */
PspLockThreadSecurityExclusive(Thread);
/* Make sure it's still active */
if (Thread->ActiveImpersonationInfo)
{
/* Disable impersonation */
PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
/* Get the token */
Token = Thread->ImpersonationInfo->Token;
}
/* Release thread security */
PspUnlockThreadSecurityExclusive(Thread);
/* Check if we had a token */
if (Token)
{
/* Dereference the impersonation token */
ObDereferenceObject(Token);
/* Write impersonation info to the TEB */
PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
}
}
}
/*
* @implemented
*/
NTSTATUS
NTAPI
PsImpersonateClient(IN PETHREAD Thread,
IN PACCESS_TOKEN Token,
IN BOOLEAN CopyOnOpen,
IN BOOLEAN EffectiveOnly,
IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
{
PPS_IMPERSONATION_INFORMATION Impersonation, OldData;
PTOKEN OldToken = NULL;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Thread: %p, Token: %p\n", Thread, Token);
/* Check if we don't have a token */
if (!Token)
{
/* Make sure we're impersonating */
if (Thread->ActiveImpersonationInfo)
{
/* We seem to be, lock the thread */
PspLockThreadSecurityExclusive(Thread);
/* Make sure we're still impersonating */
if (Thread->ActiveImpersonationInfo)
{
/* Disable impersonation */
PspClearCrossThreadFlag(Thread,
CT_ACTIVE_IMPERSONATION_INFO_BIT);
/* Get the token */
OldToken = Thread->ImpersonationInfo->Token;
}
/* Unlock the process and write TEB information */
PspUnlockThreadSecurityExclusive(Thread);
PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
}
}
else
{
/* Check if we have impersonation info */
Impersonation = Thread->ImpersonationInfo;
if (!Impersonation)
{
/* We need to allocate a new one */
Impersonation = ExAllocatePoolWithTag(PagedPool,
sizeof(*Impersonation),
TAG_PS_IMPERSONATION);
if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES;
/* Update the pointer */
OldData = InterlockedCompareExchangePointer((PVOID*)&Thread->
ImpersonationInfo,
Impersonation,
NULL);
if (OldData)
{
/* Someone beat us to it, free our copy */
ExFreePoolWithTag(Impersonation, TAG_PS_IMPERSONATION);
Impersonation = OldData;
}
}
/* Check if this is a job, which we don't support yet */
if (Thread->ThreadsProcess->Job) ASSERT(FALSE);
/* Lock thread security */
PspLockThreadSecurityExclusive(Thread);
/* Check if we're impersonating */
if (Thread->ActiveImpersonationInfo)
{
/* Get the token */
OldToken = Impersonation->Token;
}
else
{
/* Otherwise, enable impersonation */
PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
}
/* Now fill it out */
Impersonation->ImpersonationLevel = ImpersonationLevel;
Impersonation->CopyOnOpen = CopyOnOpen;
Impersonation->EffectiveOnly = EffectiveOnly;
Impersonation->Token = Token;
ObReferenceObject(Token);
/* Unlock the thread */
PspUnlockThreadSecurityExclusive(Thread);
/* Write impersonation info to the TEB */
PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
}
/* Dereference the token and return success */
if (OldToken) PsDereferenceImpersonationToken(OldToken);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
PACCESS_TOKEN
NTAPI
PsReferenceEffectiveToken(IN PETHREAD Thread,
OUT IN PTOKEN_TYPE TokenType,
OUT PBOOLEAN EffectiveOnly,
OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
{
PEPROCESS Process;
PACCESS_TOKEN Token = NULL;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG,
"Thread: %p, TokenType: %p\n", Thread, TokenType);
/* Check if we don't have impersonation info */
Process = Thread->ThreadsProcess;
if (Thread->ActiveImpersonationInfo)
{
/* Lock the Process */
PspLockProcessSecurityShared(Process);
/* Make sure impersonation is still active */
if (Thread->ActiveImpersonationInfo)
{
/* Get the token */
Token = Thread->ImpersonationInfo->Token;
ObReferenceObject(Token);
/* Return data to caller */
*TokenType = TokenImpersonation;
*EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
*ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
/* Unlock the Process */
PspUnlockProcessSecurityShared(Process);
return Token;
}
/* Unlock the Process */
PspUnlockProcessSecurityShared(Process);
}
/* Fast Reference the Token */
Token = ObFastReferenceObject(&Process->Token);
/* Check if we got the Token or if we got locked */
if (!Token)
{
/* Lock the Process */
PspLockProcessSecurityShared(Process);
/* Do a Locked Fast Reference */
Token = ObFastReferenceObjectLocked(&Process->Token);
/* Unlock the Process */
PspUnlockProcessSecurityShared(Process);
}
/* Return the token */
*TokenType = TokenPrimary;
*EffectiveOnly = FALSE;
// NOTE: ImpersonationLevel is left untouched on purpose!
return Token;
}
/*
* @implemented
*/
PACCESS_TOKEN
NTAPI
PsReferenceImpersonationToken(IN PETHREAD Thread,
OUT PBOOLEAN CopyOnOpen,
OUT PBOOLEAN EffectiveOnly,
OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
{
PTOKEN Token = NULL;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
/* If we don't have impersonation info, just quit */
if (!Thread->ActiveImpersonationInfo) return NULL;
/* Lock the thread */
PspLockThreadSecurityShared(Thread);
/* Make sure we still have active impersonation */
if (Thread->ActiveImpersonationInfo)
{
/* Return data from caller */
ObReferenceObject(Thread->ImpersonationInfo->Token);
*ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
*CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
*EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
/* Set the token */
Token = Thread->ImpersonationInfo->Token;
}
/* Unlock thread and return impersonation token */
PspUnlockThreadSecurityShared(Thread);
return Token;
}
#undef PsDereferenceImpersonationToken
/*
* @implemented
*/
VOID
NTAPI
PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
{
PAGED_CODE();
/* If we got a token, dereference it */
if (ImpersonationToken) ObDereferenceObject(ImpersonationToken);
}
#undef PsDereferencePrimaryToken
/*
* @implemented
*/
VOID
NTAPI
PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
{
PAGED_CODE();
/* Dereference the token*/
ObDereferenceObject(PrimaryToken);
}
/*
* @implemented
*/
BOOLEAN
NTAPI
PsDisableImpersonation(IN PETHREAD Thread,
OUT PSE_IMPERSONATION_STATE ImpersonationState)
{
PPS_IMPERSONATION_INFORMATION Impersonation = NULL;
LONG OldFlags;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG,
"Thread: %p State: %p\n", Thread, ImpersonationState);
/* Check if we don't have impersonation */
if (Thread->ActiveImpersonationInfo)
{
/* Lock thread security */
PspLockThreadSecurityExclusive(Thread);
/* Disable impersonation */
OldFlags = PspClearCrossThreadFlag(Thread,
CT_ACTIVE_IMPERSONATION_INFO_BIT);
/* Make sure nobody disabled it behind our back */
if (OldFlags & CT_ACTIVE_IMPERSONATION_INFO_BIT)
{
/* Copy the old state */
Impersonation = Thread->ImpersonationInfo;
ImpersonationState->Token = Impersonation->Token;
ImpersonationState->CopyOnOpen = Impersonation->CopyOnOpen;
ImpersonationState->EffectiveOnly = Impersonation->EffectiveOnly;
ImpersonationState->Level = Impersonation->ImpersonationLevel;
}
/* Unlock thread security */
PspUnlockThreadSecurityExclusive(Thread);
/* If we had impersonation info, return true */
if (Impersonation) return TRUE;
}
/* Clear everything */
ImpersonationState->Token = NULL;
ImpersonationState->CopyOnOpen = FALSE;
ImpersonationState->EffectiveOnly = FALSE;
ImpersonationState->Level = SecurityAnonymous;
return FALSE;
}
/*
* @implemented
*/
VOID
NTAPI
PsRestoreImpersonation(IN PETHREAD Thread,
IN PSE_IMPERSONATION_STATE ImpersonationState)
{
PTOKEN Token = NULL;
PPS_IMPERSONATION_INFORMATION Impersonation;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG,
"Thread: %p State: %p\n", Thread, ImpersonationState);
/* Lock thread security */
PspLockThreadSecurityExclusive(Thread);
/* Get the impersonation info */
Impersonation = Thread->ImpersonationInfo;
/* Check if we're impersonating */
if (Thread->ActiveImpersonationInfo)
{
/* Get the token */
Token = Impersonation->Token;
}
/* Check if we have an impersonation state */
if (ImpersonationState)
{
/* Fill out the impersonation info */
Impersonation->ImpersonationLevel = ImpersonationState->Level;
Impersonation->CopyOnOpen = ImpersonationState->CopyOnOpen;
Impersonation->EffectiveOnly = ImpersonationState->EffectiveOnly;
Impersonation->Token = ImpersonationState->Token;
/* Enable impersonation */
PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
}
else
{
/* Disable impersonation */
PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
}
/* Unlock the thread */
PspUnlockThreadSecurityExclusive(Thread);
/* Dereference the token */
if (Token) ObDereferenceObject(Token);
}
NTSTATUS
NTAPI
NtImpersonateThread(IN HANDLE ThreadHandle,
IN HANDLE ThreadToImpersonateHandle,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
{
SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
SECURITY_CLIENT_CONTEXT ClientContext;
PETHREAD Thread;
PETHREAD ThreadToImpersonate;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG,
"Threads: %p %p\n", ThreadHandle, ThreadToImpersonateHandle);
/* Check if call came from user mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe QoS */
ProbeForRead(SecurityQualityOfService,
sizeof(SECURITY_QUALITY_OF_SERVICE),
sizeof(ULONG));
/* Capture it */
SafeServiceQoS = *SecurityQualityOfService;
SecurityQualityOfService = &SafeServiceQoS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Reference the thread */
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_DIRECT_IMPERSONATION,
PsThreadType,
PreviousMode,
(PVOID*)&Thread,
NULL);
if (NT_SUCCESS(Status))
{
/* Reference the impersonating thead */
Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
THREAD_IMPERSONATE,
PsThreadType,
PreviousMode,
(PVOID*)&ThreadToImpersonate,
NULL);
if (NT_SUCCESS(Status))
{
/* Create a client security context */
Status = SeCreateClientSecurity(ThreadToImpersonate,
SecurityQualityOfService,
0,
&ClientContext);
if (NT_SUCCESS(Status))
{
/* Do the impersonation */
SeImpersonateClient(&ClientContext, Thread);
if (ClientContext.ClientToken)
{
/* Dereference the client token if we had one */
ObDereferenceObject(ClientContext.ClientToken);
}
}
/* Dereference the thread to impersonate */
ObDereferenceObject(ThreadToImpersonate);
}
/* Dereference the main thread */
ObDereferenceObject(Thread);
}
/* Return status */
return Status;
}
/* EOF */