Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119/* * 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;
VOIDNTAPISeAssignPrimaryToken( IN PEPROCESS Process, IN PTOKEN Token);
/* PRIVATE FUNCTIONS *********************************************************/
VOIDNTAPIPspDeleteProcessSecurity(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; }}
VOIDNTAPIPspDeleteThreadSecurity(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; }}
NTSTATUSNTAPIPspInitializeProcessSecurity(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;}
NTSTATUSNTAPIPspWriteTebImpersonationInfo(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;}
NTSTATUSNTAPIPspAssignPrimaryToken(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;}
NTSTATUSNTAPIPspSetPrimaryToken(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); }
/* * In case LUID device maps are enable, we may not be using * system device map for this process, but a logon LUID based * device map. Because we change primary token, this usage is * no longer valid, so dereference the process device map */ if (ObIsLUIDDeviceMapsEnabled()) ObDereferenceDeviceMap(Process); }
/* Dereference the token */ if (!Token) ObDereferenceObject(NewToken); return Status;}
/* FUNCTIONS *****************************************************************/
/* * @implemented */NTSTATUSNTAPINtOpenProcessToken(IN HANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, OUT PHANDLE TokenHandle){ /* Call the newer API */ return NtOpenProcessTokenEx(ProcessHandle, DesiredAccess, 0, TokenHandle);}
/* * @implemented */NTSTATUSNTAPINtOpenProcessTokenEx(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_TOKENNTAPIPsReferencePrimaryToken(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 */NTSTATUSNTAPIPsOpenTokenOfProcess(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 */NTSTATUSNTAPIPsAssignImpersonationToken(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 */VOIDNTAPIPsRevertToSelf(VOID){ /* Call the per-thread API */ PAGED_CODE(); PsRevertThreadToSelf(PsGetCurrentThread());}
/* * @implemented */VOIDNTAPIPsRevertThreadToSelf(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 */NTSTATUSNTAPIPsImpersonateClient(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, ProcessToken = NULL; BOOLEAN CopiedToken = FALSE; PACCESS_TOKEN NewToken, ImpersonationToken; PEJOB Job; NTSTATUS Status;
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; } }
/* * Assign the token we get from the caller first. The reason * we have to do that is because we're unsure if we can impersonate * in the first place. In the scenario where we cannot then the * last resort is to make a copy of the token and assign that newly * token to the impersonation information. */ ImpersonationToken = Token;
/* Obtain a token from the process */ ProcessToken = PsReferencePrimaryToken(Thread->ThreadsProcess); if (!ProcessToken) { /* We can't continue this way without having the process' token... */ return STATUS_UNSUCCESSFUL; }
/* Make sure we can impersonate */ if (!SeTokenCanImpersonate(ProcessToken, Token, ImpersonationLevel)) { /* We can't, make a copy of the token instead */ Status = SeCopyClientToken(Token, SecurityIdentification, KernelMode, &NewToken); if (!NT_SUCCESS(Status)) { /* We can't even make a copy of the token? Then bail out... */ ObFastDereferenceObject(&Thread->ThreadsProcess->Token, ProcessToken); return Status; }
/* * Since we cannot impersonate, assign the newly copied token. * SeCopyClientToken already holds a reference to the copied token, * let the code path below know that it must not reference it twice. */ CopiedToken = TRUE; ImpersonationLevel = SecurityIdentification; ImpersonationToken = NewToken; }
/* We no longer need the process' token */ ObFastDereferenceObject(&Thread->ThreadsProcess->Token, ProcessToken);
/* Check if this is a job */ Job = Thread->ThreadsProcess->Job; if (Job != NULL) { /* No admin allowed in this job */ if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN) && SeTokenIsAdmin(ImpersonationToken)) { if (CopiedToken) { ObDereferenceObject(ImpersonationToken); }
return STATUS_ACCESS_DENIED; }
/* No restricted tokens allowed in this job */ if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_RESTRICTED_TOKEN) && SeTokenIsRestricted(ImpersonationToken)) { if (CopiedToken) { ObDereferenceObject(ImpersonationToken); }
return STATUS_ACCESS_DENIED; }
/* We don't support job filters yet */ if (Job->Filter != NULL) { ASSERT(Job->Filter == NULL); } }
/* 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 = ImpersonationToken;
/* Do not reference the token again if we copied it */ if (!CopiedToken) { ObReferenceObject(ImpersonationToken); }
/* 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_TOKENNTAPIPsReferenceEffectiveToken(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_TOKENNTAPIPsReferenceImpersonationToken(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 */VOIDNTAPIPsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken){ PAGED_CODE();
/* If we got a token, dereference it */ if (ImpersonationToken) ObDereferenceObject(ImpersonationToken);}
#undef PsDereferencePrimaryToken/* * @implemented */VOIDNTAPIPsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken){ PAGED_CODE();
/* Dereference the token*/ ObDereferenceObject(PrimaryToken);}
/* * @implemented */BOOLEANNTAPIPsDisableImpersonation(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 */VOIDNTAPIPsRestoreImpersonation(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);}
NTSTATUSNTAPINtImpersonateThread(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 */