mirror of
https://github.com/reactos/reactos.git
synced 2024-06-29 01:12:06 +00:00
[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:
parent
fff24ee1dd
commit
3d6bddb98f
|
@ -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.
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue