[AUDIT] security.c is mostly composed of trivial implementations of APIs that transfer one set of data from another, or simply wrap around complex Se* functions which do the actual work. There are one or two slightly more complex APIs (~15-20 lines), but they were written by Eric/Thomas, which are well-known for always writing clean code.

[FORMATTING] Re-formatted file properly, ordered functions and annotated them, added proper programmer credits, etc.
- Pushlocks need to be acquired in a -critical-, not -guarded- region.
- PsDisableImpersonation should return FALSE if it was already disbled.
- Don't forget to reference the token in PsReferenceEffectiveToken.
- PsImpersonateClient should still return success if it was given no token.
- PsImperstonateClient should de-reference the token if there is already active impersonation info.

svn path=/trunk/; revision=23152
This commit is contained in:
Alex Ionescu 2006-07-18 15:13:55 +00:00
parent fff24ee1dd
commit 3d6bddb98f
3 changed files with 389 additions and 348 deletions

View file

@ -29,6 +29,7 @@
// - Use Process Pushlock Locks. // - Use Process Pushlock Locks.
// - Use Safe Referencing in PsGetNextProcess/Thread. // - Use Safe Referencing in PsGetNextProcess/Thread.
// - Use Guarded Mutex instead of Fast Mutex for Active Process Locks. // - Use Guarded Mutex instead of Fast Mutex for Active Process Locks.
// - Use Security Locks in security.c
// - Fix referencing problem. // - Fix referencing problem.
// - Generate process cookie for user-more thread. // - Generate process cookie for user-more thread.
// - Add security calls where necessary. // - Add security calls where necessary.

View file

@ -130,6 +130,7 @@
/* formerly located in ps/cid.c */ /* formerly located in ps/cid.c */
#define TAG_CIDOBJECT TAG('C', 'I', 'D', 'O') #define TAG_CIDOBJECT TAG('C', 'I', 'D', 'O')
#define TAG_PS_IMPERSONATION TAG('P', 's', 'I', 'm')
/* formerly located in ps/job.c */ /* formerly located in ps/job.c */
#define TAG_EJOB TAG('E', 'J', 'O', 'B') /* EJOB */ #define TAG_EJOB TAG('E', 'J', 'O', 'B') /* EJOB */

View file

@ -1,10 +1,11 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel
* PROJECT: ReactOS kernel * LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ps/security.c * FILE: ntoskrnl/ps/security.c
* PURPOSE: Process Manager Security (Tokens, Impersionation) * PURPOSE: Process Manager: Process/Thread Security
* * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* PROGRAMMERS: David Welch (welch@cwcom.net) * Eric Kohl
* Thomas Weidenmueller (w3seek@reactos.org)
*/ */
/* INCLUDES ******************************************************************/ /* INCLUDES ******************************************************************/
@ -13,15 +14,15 @@
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
/* INTERNAL ******************************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
/* FIXME: Turn into Macro */ /* FIXME: Turn into Macro */
VOID VOID
STDCALL NTAPI
PspLockProcessSecurityShared(PEPROCESS Process) PspLockProcessSecurityShared(IN PEPROCESS Process)
{ {
/* Enter a Guarded Region */ /* Enter a Critical Region */
KeEnterGuardedRegion(); KeEnterCriticalRegion();
/* Lock the Process */ /* Lock the Process */
//ExAcquirePushLockShared(&Process->ProcessLock); //ExAcquirePushLockShared(&Process->ProcessLock);
@ -29,14 +30,14 @@ PspLockProcessSecurityShared(PEPROCESS Process)
/* FIXME: Turn into Macro */ /* FIXME: Turn into Macro */
VOID VOID
STDCALL NTAPI
PspUnlockProcessSecurityShared(PEPROCESS Process) PspUnlockProcessSecurityShared(IN PEPROCESS Process)
{ {
/* Unlock the Process */ /* Unlock the Process */
//ExReleasePushLockShared(&Process->ProcessLock); //ExReleasePushLockShared(&Process->ProcessLock);
/* Leave Guarded Region */ /* Leave Critical Region */
KeLeaveGuardedRegion(); KeLeaveCriticalRegion();
} }
VOID VOID
@ -73,153 +74,10 @@ PspDeleteThreadSecurity(IN PETHREAD Thread)
} }
} }
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
NTSTATUS NTSTATUS
STDCALL NTAPI
NtOpenProcessToken(IN HANDLE ProcessHandle, PspInitializeProcessSecurity(IN PEPROCESS Process,
IN ACCESS_MASK DesiredAccess, IN PEPROCESS Parent OPTIONAL)
OUT PHANDLE TokenHandle)
{
return NtOpenProcessTokenEx(ProcessHandle,
DesiredAccess,
0,
TokenHandle);
}
/*
* @implemented
*/
NTSTATUS
STDCALL
NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN ULONG HandleAttributes,
OUT PHANDLE TokenHandle)
{
PACCESS_TOKEN Token;
HANDLE hToken;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
if(PreviousMode != KernelMode)
{
_SEH_TRY
{
ProbeForWriteHandle(TokenHandle);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status))
{
return Status;
}
}
Status = PsOpenTokenOfProcess(ProcessHandle,
&Token);
if(NT_SUCCESS(Status))
{
Status = ObOpenObjectByPointer(Token,
0,
NULL,
DesiredAccess,
SepTokenObjectType,
PreviousMode,
&hToken);
ObDereferenceObject(Token);
if(NT_SUCCESS(Status))
{
_SEH_TRY
{
*TokenHandle = hToken;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
}
return Status;
}
/*
* @implemented
*/
PACCESS_TOKEN
STDCALL
PsReferencePrimaryToken(PEPROCESS Process)
{
PACCESS_TOKEN Token;
/* 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
STDCALL
PsOpenTokenOfProcess(HANDLE ProcessHandle,
PACCESS_TOKEN* Token)
{
PEPROCESS Process;
NTSTATUS Status;
/* Get the Token */
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_QUERY_INFORMATION,
PsProcessType,
ExGetPreviousMode(),
(PVOID*)&Process,
NULL);
/* Reference it */
if(NT_SUCCESS(Status)) {
*Token = PsReferencePrimaryToken(Process);
ObDereferenceObject(Process);
}
/* Return */
return Status;
}
NTSTATUS
STDCALL
PspInitializeProcessSecurity(PEPROCESS Process,
PEPROCESS Parent OPTIONAL)
{ {
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
PTOKEN NewToken, ParentToken; PTOKEN NewToken, ParentToken;
@ -258,86 +116,233 @@ PspInitializeProcessSecurity(PEPROCESS Process,
return Status; return Status;
} }
NTSTATUS NTSTATUS
STDCALL NTAPI
PspAssignPrimaryToken(PEPROCESS Process, PspAssignPrimaryToken(IN PEPROCESS Process,
HANDLE TokenHandle) IN HANDLE TokenHandle)
{ {
PACCESS_TOKEN Token; PACCESS_TOKEN Token, OldToken;
PACCESS_TOKEN OldToken;
NTSTATUS Status; NTSTATUS Status;
/* Reference the Token */ /* Reference the Token */
Status = ObReferenceObjectByHandle(TokenHandle, Status = ObReferenceObjectByHandle(TokenHandle,
0, TOKEN_ASSIGN_PRIMARY,
SepTokenObjectType, SepTokenObjectType,
KeGetPreviousMode(), KeGetPreviousMode(),
(PVOID*)&Token, (PVOID*)&Token,
NULL); NULL);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) return Status;
return(Status);
}
/* Exchange them */ /* Exchange them */
Status = SeExchangePrimaryToken(Process, Token, &OldToken); Status = SeExchangePrimaryToken(Process, Token, &OldToken);
/* Derefernece Tokens and Return */ /* Derefernece Tokens and Return */
ObDereferenceObject(Token); ObDereferenceObject(Token);
return(Status); 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 * @implemented
*/ */
NTSTATUS NTSTATUS
STDCALL NTAPI
PsAssignImpersonationToken(PETHREAD Thread, NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
HANDLE TokenHandle) IN ACCESS_MASK DesiredAccess,
IN ULONG HandleAttributes,
OUT PHANDLE TokenHandle)
{ {
PACCESS_TOKEN Token; PACCESS_TOKEN Token;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; HANDLE hToken;
NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
if (TokenHandle != NULL) { /* Check if caller was user-mode */
if (PreviousMode != KernelMode)
Status = ObReferenceObjectByHandle(TokenHandle, {
TOKEN_IMPERSONATE, /* Enter SEH for probing */
SepTokenObjectType, _SEH_TRY
KeGetPreviousMode(), {
(PVOID*)&Token, /* Probe the token handle */
NULL); ProbeForWriteHandle(TokenHandle);
if (!NT_SUCCESS(Status)) {
return(Status);
} }
_SEH_HANDLE
{
/* Get the exception code */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
ImpersonationLevel = SeTokenImpersonationLevel(Token); /* Fail on exception */
if (!NT_SUCCESS(Status)) return Status;
} else {
Token = NULL;
ImpersonationLevel = 0;
} }
Status = PsImpersonateClient(Thread, /* Open the process token */
Token, Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
FALSE, if(NT_SUCCESS(Status))
FALSE, {
ImpersonationLevel); /* Reference it by handle and dereference the pointer */
Status = ObOpenObjectByPointer(Token,
0,
NULL,
DesiredAccess,
SepTokenObjectType,
PreviousMode,
&hToken);
ObDereferenceObject(Token);
if (Token != NULL) ObDereferenceObject(Token); /* Make sure we got a handle */
if(NT_SUCCESS(Status))
{
/* Enter SEH for write */
_SEH_TRY
{
/* Return the handle */
*TokenHandle = hToken;
}
_SEH_HANDLE
{
/* Get exception code */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
}
/* Return status */
return Status; return Status;
} }
/* /*
* @implemented * @implemented
*/ */
VOID STDCALL PACCESS_TOKEN
PsRevertToSelf (VOID) NTAPI
PsReferencePrimaryToken(PEPROCESS Process)
{ {
PACCESS_TOKEN Token;
/* 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;
/* 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;
/* Check if we were given a handle */
if (TokenHandle)
{
/* Get the token object */
Status = ObReferenceObjectByHandle(TokenHandle,
TOKEN_IMPERSONATE,
SepTokenObjectType,
KeGetPreviousMode(),
(PVOID*)&Token,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
/* Get the impersionation level */
ImpersonationLevel = SeTokenImpersonationLevel(Token);
}
else
{
/* Otherwise, clear values */
Token = NULL;
ImpersonationLevel = 0;
}
/* Call the impersonation API */
Status = PsImpersonateClient(Thread,
Token,
FALSE,
FALSE,
ImpersonationLevel);
/* Dereference the token and return status */
if (Token) ObDereferenceObject(Token);
return Status;
}
/*
* @implemented
*/
VOID
NTAPI
PsRevertToSelf(VOID)
{
/* Call the per-thread API */
PsRevertThreadToSelf(PsGetCurrentThread()); PsRevertThreadToSelf(PsGetCurrentThread());
} }
@ -345,11 +350,13 @@ PsRevertToSelf (VOID)
* @implemented * @implemented
*/ */
VOID VOID
STDCALL NTAPI
PsRevertThreadToSelf(IN PETHREAD Thread) PsRevertThreadToSelf(IN PETHREAD Thread)
{ {
if (Thread->ActiveImpersonationInfo == TRUE) { /* Make sure we had impersonation information */
if (Thread->ActiveImpersonationInfo)
{
/* Dereference the impersonation token and set it as false */
ObDereferenceObject (Thread->ImpersonationInfo->Token); ObDereferenceObject (Thread->ImpersonationInfo->Token);
Thread->ActiveImpersonationInfo = FALSE; Thread->ActiveImpersonationInfo = FALSE;
} }
@ -359,59 +366,85 @@ PsRevertThreadToSelf(IN PETHREAD Thread)
* @implemented * @implemented
*/ */
NTSTATUS NTSTATUS
STDCALL NTAPI
PsImpersonateClient(IN PETHREAD Thread, PsImpersonateClient(IN PETHREAD Thread,
IN PACCESS_TOKEN Token, IN PACCESS_TOKEN Token,
IN BOOLEAN CopyOnOpen, IN BOOLEAN CopyOnOpen,
IN BOOLEAN EffectiveOnly, IN BOOLEAN EffectiveOnly,
IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
{ {
PPS_IMPERSONATION_INFORMATION Impersonation;
if (Token == NULL) { /* Check if we don't have a token */
if (!Token)
if (Thread->ActiveImpersonationInfo == TRUE) { {
/* Make sure we're impersonating */
if (Thread->ActiveImpersonationInfo)
{
/* Disable impersonation and check for token */
Thread->ActiveImpersonationInfo = FALSE; Thread->ActiveImpersonationInfo = FALSE;
if (Thread->ImpersonationInfo->Token)
if (Thread->ImpersonationInfo->Token != NULL) { {
/* Dereference it */
ObDereferenceObject (Thread->ImpersonationInfo->Token); ObDereferenceObject(Thread->ImpersonationInfo->Token);
} }
} }
return STATUS_UNSUCCESSFUL; /* Return success */
return STATUS_SUCCESS;
} }
if (Thread->ImpersonationInfo == NULL) { /* Check if we have active impersonation */
if (Thread->ActiveImpersonationInfo)
{
/* Reuse the block and reference the token */
Impersonation = Thread->ImpersonationInfo;
if (Impersonation->Token) ObDereferenceObject(Impersonation->Token);
}
else if (Thread->ImpersonationInfo)
{
/* It's not active, but we can still reuse the block */
Impersonation = Thread->ImpersonationInfo;
}
else
{
/* We need to allocate a new one */
Impersonation = ExAllocatePoolWithTag(PagedPool,
sizeof(*Impersonation),
TAG_PS_IMPERSONATION);
if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES;
Thread->ImpersonationInfo = ExAllocatePool(NonPagedPool, /* Update the pointer */
sizeof(PS_IMPERSONATION_INFORMATION)); Thread->ImpersonationInfo = Impersonation;
} }
Thread->ImpersonationInfo->ImpersonationLevel = ImpersonationLevel; /* Now fill it out */
Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen; Impersonation->ImpersonationLevel = ImpersonationLevel;
Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly; Impersonation->CopyOnOpen = CopyOnOpen;
Thread->ImpersonationInfo->Token = Token; Impersonation->EffectiveOnly = EffectiveOnly;
Impersonation->Token = Token;
ObReferenceObject(Token);
Thread->ActiveImpersonationInfo = TRUE; Thread->ActiveImpersonationInfo = TRUE;
/* Reference the token and return success */
ObReferenceObject(Impersonation->Token);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/*
* @implemented
*/
PACCESS_TOKEN PACCESS_TOKEN
STDCALL NTAPI
PsReferenceEffectiveToken(PETHREAD Thread, PsReferenceEffectiveToken(IN PETHREAD Thread,
PTOKEN_TYPE TokenType, OUT IN PTOKEN_TYPE TokenType,
PBOOLEAN EffectiveOnly, OUT PBOOLEAN EffectiveOnly,
PSECURITY_IMPERSONATION_LEVEL Level) OUT PSECURITY_IMPERSONATION_LEVEL Level)
{ {
PEPROCESS Process; PEPROCESS Process;
PACCESS_TOKEN Token; PACCESS_TOKEN Token;
if (Thread->ActiveImpersonationInfo == FALSE) /* Check if we don't have impersonation info */
if (!Thread->ActiveImpersonationInfo)
{ {
Process = Thread->ThreadsProcess; Process = Thread->ThreadsProcess;
*TokenType = TokenPrimary; *TokenType = TokenPrimary;
@ -435,146 +468,64 @@ PsReferenceEffectiveToken(PETHREAD Thread,
} }
else else
{ {
/* Get the token */
Token = Thread->ImpersonationInfo->Token; Token = Thread->ImpersonationInfo->Token;
ObReferenceObject(Token);
/* Return data to caller */
*TokenType = TokenImpersonation; *TokenType = TokenImpersonation;
*EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
*Level = Thread->ImpersonationInfo->ImpersonationLevel; *Level = Thread->ImpersonationInfo->ImpersonationLevel;
} }
/* Return the token */
return Token; return Token;
} }
NTSTATUS
STDCALL
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;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
if(PreviousMode != KernelMode)
{
_SEH_TRY
{
ProbeForRead(SecurityQualityOfService,
sizeof(SECURITY_QUALITY_OF_SERVICE),
sizeof(ULONG));
SafeServiceQoS = *SecurityQualityOfService;
SecurityQualityOfService = &SafeServiceQoS;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status))
{
return Status;
}
}
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_IMPERSONATE,
PsThreadType,
PreviousMode,
(PVOID*)&Thread,
NULL);
if(NT_SUCCESS(Status))
{
Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
THREAD_DIRECT_IMPERSONATION,
PsThreadType,
PreviousMode,
(PVOID*)&ThreadToImpersonate,
NULL);
if(NT_SUCCESS(Status))
{
Status = SeCreateClientSecurity(ThreadToImpersonate,
SecurityQualityOfService,
0,
&ClientContext);
if(NT_SUCCESS(Status))
{
SeImpersonateClient(&ClientContext,
Thread);
if(ClientContext.ClientToken != NULL)
{
ObDereferenceObject (ClientContext.ClientToken);
}
}
ObDereferenceObject(ThreadToImpersonate);
}
ObDereferenceObject(Thread);
}
return Status;
}
/* /*
* @implemented * @implemented
*/ */
PACCESS_TOKEN PACCESS_TOKEN
STDCALL NTAPI
PsReferenceImpersonationToken(IN PETHREAD Thread, PsReferenceImpersonationToken(IN PETHREAD Thread,
OUT PBOOLEAN CopyOnOpen, OUT PBOOLEAN CopyOnOpen,
OUT PBOOLEAN EffectiveOnly, OUT PBOOLEAN EffectiveOnly,
OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel) OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
{ {
/* If we don't have impersonation info, just quit */
if (!Thread->ActiveImpersonationInfo) return NULL;
if (Thread->ActiveImpersonationInfo == FALSE) { /* Return data from caller */
return NULL;
}
*ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel; *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
*CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen; *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
*EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token, /* Reference the token and return it */
TOKEN_ALL_ACCESS, ObReferenceObject(Thread->ImpersonationInfo->Token);
SepTokenObjectType,
KernelMode);
return Thread->ImpersonationInfo->Token; return Thread->ImpersonationInfo->Token;
} }
#ifdef PsDereferencePrimaryToken
#undef PsDereferenceImpersonationToken #undef PsDereferenceImpersonationToken
#endif
/* /*
* @implemented * @implemented
*/ */
VOID VOID
STDCALL NTAPI
PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken) PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
{ {
if (ImpersonationToken) { /* If we got a token, dereference it */
if (ImpersonationToken) ObDereferenceObject(ImpersonationToken);
ObDereferenceObject(ImpersonationToken);
}
} }
#ifdef PsDereferencePrimaryToken
#undef PsDereferencePrimaryToken #undef PsDereferencePrimaryToken
#endif
/* /*
* @implemented * @implemented
*/ */
VOID VOID
STDCALL NTAPI
PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken) PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
{ {
/* Dereference the token*/
ObDereferenceObject(PrimaryToken); ObDereferenceObject(PrimaryToken);
} }
@ -582,30 +533,32 @@ PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
* @implemented * @implemented
*/ */
BOOLEAN BOOLEAN
STDCALL NTAPI
PsDisableImpersonation(IN PETHREAD Thread, PsDisableImpersonation(IN PETHREAD Thread,
IN PSE_IMPERSONATION_STATE ImpersonationState) IN PSE_IMPERSONATION_STATE ImpersonationState)
{ {
if (Thread->ActiveImpersonationInfo == FALSE) { PPS_IMPERSONATION_INFORMATION Impersonation;
/* Check if we don't have impersonation */
if (!Thread->ActiveImpersonationInfo)
{
/* Clear everything */
ImpersonationState->Token = NULL; ImpersonationState->Token = NULL;
ImpersonationState->CopyOnOpen = FALSE; ImpersonationState->CopyOnOpen = FALSE;
ImpersonationState->EffectiveOnly = FALSE; ImpersonationState->EffectiveOnly = FALSE;
ImpersonationState->Level = 0; ImpersonationState->Level = SecurityAnonymous;
return TRUE; return FALSE;
} }
/* FIXME */ /* Copy the old state */
/* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */ Impersonation = Thread->ImpersonationInfo;
ImpersonationState->Token = Impersonation->Token;
ImpersonationState->CopyOnOpen = Impersonation->CopyOnOpen;
ImpersonationState->EffectiveOnly = Impersonation->EffectiveOnly;
ImpersonationState->Level = Impersonation->ImpersonationLevel;
/* Disable impersonation and return true */
Thread->ActiveImpersonationInfo = FALSE; Thread->ActiveImpersonationInfo = FALSE;
ImpersonationState->Token = Thread->ImpersonationInfo->Token;
ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
ImpersonationState->Level = Thread->ImpersonationInfo->ImpersonationLevel;
/* FIXME */
/* ExfReleasePushLock(&Thread->ThreadLock); */
return TRUE; return TRUE;
} }
@ -613,18 +566,104 @@ PsDisableImpersonation(IN PETHREAD Thread,
* @implemented * @implemented
*/ */
VOID VOID
STDCALL NTAPI
PsRestoreImpersonation(IN PETHREAD Thread, PsRestoreImpersonation(IN PETHREAD Thread,
IN PSE_IMPERSONATION_STATE ImpersonationState) IN PSE_IMPERSONATION_STATE ImpersonationState)
{ {
/* Call the impersonation API */
PsImpersonateClient(Thread, PsImpersonateClient(Thread,
ImpersonationState->Token, ImpersonationState->Token,
ImpersonationState->CopyOnOpen, ImpersonationState->CopyOnOpen,
ImpersonationState->EffectiveOnly, ImpersonationState->EffectiveOnly,
ImpersonationState->Level); ImpersonationState->Level);
ObfDereferenceObject(ImpersonationState->Token); /* Dereference the token */
ObDereferenceObject(ImpersonationState->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 = STATUS_SUCCESS;
PAGED_CODE();
/* Check if call came from user mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH for probing */
_SEH_TRY
{
/* Probe QoS */
ProbeForRead(SecurityQualityOfService,
sizeof(SECURITY_QUALITY_OF_SERVICE),
sizeof(ULONG));
/* Capture it */
SafeServiceQoS = *SecurityQualityOfService;
SecurityQualityOfService = &SafeServiceQoS;
}
_SEH_HANDLE
{
/* Get exception status */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
/* Fail on exception */
if (!NT_SUCCESS(Status)) return Status;
}
/* Reference the thread */
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_IMPERSONATE,
PsThreadType,
PreviousMode,
(PVOID*)&Thread,
NULL);
if(NT_SUCCESS(Status))
{
/* Reference the impersonating thead */
Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
THREAD_DIRECT_IMPERSONATION,
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 */ /* EOF */