From 3d6bddb98f584f0c3d3c2a7f50f8fdd5df193b33 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 18 Jul 2006 15:13:55 +0000 Subject: [PATCH] [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 --- reactos/ntoskrnl/KrnlFun.c | 1 + reactos/ntoskrnl/include/internal/tag.h | 1 + reactos/ntoskrnl/ps/security.c | 735 +++++++++++++----------- 3 files changed, 389 insertions(+), 348 deletions(-) diff --git a/reactos/ntoskrnl/KrnlFun.c b/reactos/ntoskrnl/KrnlFun.c index 108602325a8..5a88e2284ac 100644 --- a/reactos/ntoskrnl/KrnlFun.c +++ b/reactos/ntoskrnl/KrnlFun.c @@ -29,6 +29,7 @@ // - Use Process Pushlock Locks. // - Use Safe Referencing in PsGetNextProcess/Thread. // - Use Guarded Mutex instead of Fast Mutex for Active Process Locks. +// - Use Security Locks in security.c // - Fix referencing problem. // - Generate process cookie for user-more thread. // - Add security calls where necessary. diff --git a/reactos/ntoskrnl/include/internal/tag.h b/reactos/ntoskrnl/include/internal/tag.h index 01e32c460de..862d321b585 100644 --- a/reactos/ntoskrnl/include/internal/tag.h +++ b/reactos/ntoskrnl/include/internal/tag.h @@ -130,6 +130,7 @@ /* formerly located in ps/cid.c */ #define TAG_CIDOBJECT TAG('C', 'I', 'D', 'O') +#define TAG_PS_IMPERSONATION TAG('P', 's', 'I', 'm') /* formerly located in ps/job.c */ #define TAG_EJOB TAG('E', 'J', 'O', 'B') /* EJOB */ diff --git a/reactos/ntoskrnl/ps/security.c b/reactos/ntoskrnl/ps/security.c index 275a4e9767c..eb47d596587 100644 --- a/reactos/ntoskrnl/ps/security.c +++ b/reactos/ntoskrnl/ps/security.c @@ -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 - * PURPOSE: Process Manager Security (Tokens, Impersionation) - * - * PROGRAMMERS: David Welch (welch@cwcom.net) + * PURPOSE: Process Manager: Process/Thread Security + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Eric Kohl + * Thomas Weidenmueller (w3seek@reactos.org) */ /* INCLUDES ******************************************************************/ @@ -13,15 +14,15 @@ #define NDEBUG #include -/* INTERNAL ******************************************************************/ +/* PRIVATE FUNCTIONS *********************************************************/ /* FIXME: Turn into Macro */ VOID -STDCALL -PspLockProcessSecurityShared(PEPROCESS Process) +NTAPI +PspLockProcessSecurityShared(IN PEPROCESS Process) { - /* Enter a Guarded Region */ - KeEnterGuardedRegion(); + /* Enter a Critical Region */ + KeEnterCriticalRegion(); /* Lock the Process */ //ExAcquirePushLockShared(&Process->ProcessLock); @@ -29,14 +30,14 @@ PspLockProcessSecurityShared(PEPROCESS Process) /* FIXME: Turn into Macro */ VOID -STDCALL -PspUnlockProcessSecurityShared(PEPROCESS Process) +NTAPI +PspUnlockProcessSecurityShared(IN PEPROCESS Process) { /* Unlock the Process */ //ExReleasePushLockShared(&Process->ProcessLock); - /* Leave Guarded Region */ - KeLeaveGuardedRegion(); + /* Leave Critical Region */ + KeLeaveCriticalRegion(); } VOID @@ -73,153 +74,10 @@ PspDeleteThreadSecurity(IN PETHREAD Thread) } } -/* FUNCTIONS *****************************************************************/ - -/* - * @implemented - */ NTSTATUS -STDCALL -NtOpenProcessToken(IN HANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - 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) +NTAPI +PspInitializeProcessSecurity(IN PEPROCESS Process, + IN PEPROCESS Parent OPTIONAL) { NTSTATUS Status = STATUS_SUCCESS; PTOKEN NewToken, ParentToken; @@ -258,86 +116,233 @@ PspInitializeProcessSecurity(PEPROCESS Process, return Status; } - NTSTATUS -STDCALL -PspAssignPrimaryToken(PEPROCESS Process, - HANDLE TokenHandle) +NTAPI +PspAssignPrimaryToken(IN PEPROCESS Process, + IN HANDLE TokenHandle) { - PACCESS_TOKEN Token; - PACCESS_TOKEN OldToken; + PACCESS_TOKEN Token, OldToken; NTSTATUS Status; /* Reference the Token */ Status = ObReferenceObjectByHandle(TokenHandle, - 0, + TOKEN_ASSIGN_PRIMARY, SepTokenObjectType, KeGetPreviousMode(), (PVOID*)&Token, NULL); - if (!NT_SUCCESS(Status)) { - - return(Status); - } + if (!NT_SUCCESS(Status)) return Status; /* Exchange them */ Status = SeExchangePrimaryToken(Process, Token, &OldToken); /* Derefernece Tokens and Return */ 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 */ NTSTATUS -STDCALL -PsAssignImpersonationToken(PETHREAD Thread, - HANDLE TokenHandle) +NTAPI +NtOpenProcessTokenEx(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle) { PACCESS_TOKEN Token; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - NTSTATUS Status; + HANDLE hToken; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); - if (TokenHandle != NULL) { - - Status = ObReferenceObjectByHandle(TokenHandle, - TOKEN_IMPERSONATE, - SepTokenObjectType, - KeGetPreviousMode(), - (PVOID*)&Token, - NULL); - - if (!NT_SUCCESS(Status)) { - - return(Status); + /* Check if caller was user-mode */ + if (PreviousMode != KernelMode) + { + /* Enter SEH for probing */ + _SEH_TRY + { + /* Probe the token handle */ + ProbeForWriteHandle(TokenHandle); } + _SEH_HANDLE + { + /* Get the exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; - ImpersonationLevel = SeTokenImpersonationLevel(Token); - - } else { - - Token = NULL; - ImpersonationLevel = 0; + /* Fail on exception */ + if (!NT_SUCCESS(Status)) return Status; } - Status = PsImpersonateClient(Thread, - Token, - FALSE, - FALSE, - ImpersonationLevel); + /* Open the process token */ + Status = PsOpenTokenOfProcess(ProcessHandle, &Token); + if(NT_SUCCESS(Status)) + { + /* 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; } /* * @implemented */ -VOID STDCALL -PsRevertToSelf (VOID) +PACCESS_TOKEN +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()); } @@ -345,11 +350,13 @@ PsRevertToSelf (VOID) * @implemented */ VOID -STDCALL +NTAPI 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); Thread->ActiveImpersonationInfo = FALSE; } @@ -359,59 +366,85 @@ PsRevertThreadToSelf(IN PETHREAD Thread) * @implemented */ NTSTATUS -STDCALL +NTAPI PsImpersonateClient(IN PETHREAD Thread, IN PACCESS_TOKEN Token, IN BOOLEAN CopyOnOpen, IN BOOLEAN EffectiveOnly, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) { + PPS_IMPERSONATION_INFORMATION Impersonation; - if (Token == NULL) { - - if (Thread->ActiveImpersonationInfo == TRUE) { - + /* Check if we don't have a token */ + if (!Token) + { + /* Make sure we're impersonating */ + if (Thread->ActiveImpersonationInfo) + { + /* Disable impersonation and check for token */ Thread->ActiveImpersonationInfo = FALSE; - - if (Thread->ImpersonationInfo->Token != NULL) { - - ObDereferenceObject (Thread->ImpersonationInfo->Token); + if (Thread->ImpersonationInfo->Token) + { + /* Dereference it */ + 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, - sizeof(PS_IMPERSONATION_INFORMATION)); + /* Update the pointer */ + Thread->ImpersonationInfo = Impersonation; } - Thread->ImpersonationInfo->ImpersonationLevel = ImpersonationLevel; - Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen; - Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly; - Thread->ImpersonationInfo->Token = Token; - - ObReferenceObject(Token); - + /* Now fill it out */ + Impersonation->ImpersonationLevel = ImpersonationLevel; + Impersonation->CopyOnOpen = CopyOnOpen; + Impersonation->EffectiveOnly = EffectiveOnly; + Impersonation->Token = Token; Thread->ActiveImpersonationInfo = TRUE; + /* Reference the token and return success */ + ObReferenceObject(Impersonation->Token); return STATUS_SUCCESS; } - +/* + * @implemented + */ PACCESS_TOKEN -STDCALL -PsReferenceEffectiveToken(PETHREAD Thread, - PTOKEN_TYPE TokenType, - PBOOLEAN EffectiveOnly, - PSECURITY_IMPERSONATION_LEVEL Level) +NTAPI +PsReferenceEffectiveToken(IN PETHREAD Thread, + OUT IN PTOKEN_TYPE TokenType, + OUT PBOOLEAN EffectiveOnly, + OUT PSECURITY_IMPERSONATION_LEVEL Level) { PEPROCESS Process; PACCESS_TOKEN Token; - if (Thread->ActiveImpersonationInfo == FALSE) + /* Check if we don't have impersonation info */ + if (!Thread->ActiveImpersonationInfo) { Process = Thread->ThreadsProcess; *TokenType = TokenPrimary; @@ -435,146 +468,64 @@ PsReferenceEffectiveToken(PETHREAD Thread, } else { + /* Get the token */ Token = Thread->ImpersonationInfo->Token; + ObReferenceObject(Token); + + /* Return data to caller */ *TokenType = TokenImpersonation; *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; *Level = Thread->ImpersonationInfo->ImpersonationLevel; } + /* Return the 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 */ PACCESS_TOKEN -STDCALL +NTAPI PsReferenceImpersonationToken(IN PETHREAD Thread, OUT PBOOLEAN CopyOnOpen, OUT PBOOLEAN EffectiveOnly, OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel) { + /* If we don't have impersonation info, just quit */ + if (!Thread->ActiveImpersonationInfo) return NULL; - if (Thread->ActiveImpersonationInfo == FALSE) { - - return NULL; - } - + /* Return data from caller */ *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel; *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen; *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; - ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token, - TOKEN_ALL_ACCESS, - SepTokenObjectType, - KernelMode); - + /* Reference the token and return it */ + ObReferenceObject(Thread->ImpersonationInfo->Token); return Thread->ImpersonationInfo->Token; } -#ifdef PsDereferencePrimaryToken #undef PsDereferenceImpersonationToken -#endif /* * @implemented */ VOID -STDCALL +NTAPI PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken) { - if (ImpersonationToken) { - - ObDereferenceObject(ImpersonationToken); - } + /* If we got a token, dereference it */ + if (ImpersonationToken) ObDereferenceObject(ImpersonationToken); } -#ifdef PsDereferencePrimaryToken #undef PsDereferencePrimaryToken -#endif /* * @implemented */ VOID -STDCALL +NTAPI PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken) { + /* Dereference the token*/ ObDereferenceObject(PrimaryToken); } @@ -582,30 +533,32 @@ PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken) * @implemented */ BOOLEAN -STDCALL +NTAPI PsDisableImpersonation(IN PETHREAD Thread, 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->CopyOnOpen = FALSE; ImpersonationState->EffectiveOnly = FALSE; - ImpersonationState->Level = 0; - return TRUE; + ImpersonationState->Level = SecurityAnonymous; + return FALSE; } -/* FIXME */ -/* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */ + /* Copy the old state */ + 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; - 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; } @@ -613,18 +566,104 @@ PsDisableImpersonation(IN PETHREAD Thread, * @implemented */ VOID -STDCALL +NTAPI PsRestoreImpersonation(IN PETHREAD Thread, IN PSE_IMPERSONATION_STATE ImpersonationState) { - + /* Call the impersonation API */ PsImpersonateClient(Thread, ImpersonationState->Token, ImpersonationState->CopyOnOpen, ImpersonationState->EffectiveOnly, 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 */