https://git.reactos.org/?p=reactos.git;a=commitdiff;h=44fb528fcc0fe0ea65bbbe...
commit 44fb528fcc0fe0ea65bbbe953a015f302983a65e Author: George Bișoc george.bisoc@reactos.org AuthorDate: Thu Mar 25 21:48:38 2021 +0100 Commit: George Bișoc george.bisoc@reactos.org CommitDate: Tue Apr 27 12:25:03 2021 +0200
[NTOS:SE] Implement the NtImpersonateAnonymousToken system call
Implement SepImpersonateAnonymousToken private helpers, which is necessary for the complete implementation of NtImpersonateAnonymousToken function and thus finally we're able to impersonate the anonymous logon token. --- ntoskrnl/se/token.c | 172 ++++++++++++++++++++++++++++++++++++++++++++-- sdk/include/ndk/sefuncs.h | 2 +- 2 files changed, 168 insertions(+), 6 deletions(-)
diff --git a/ntoskrnl/se/token.c b/ntoskrnl/se/token.c index d38fe29517e..1849a16c3a7 100644 --- a/ntoskrnl/se/token.c +++ b/ntoskrnl/se/token.c @@ -363,6 +363,119 @@ Quit: return STATUS_SUCCESS; }
+/** + * @brief + * Private function that impersonates the system's anonymous logon token. + * The major bulk of the impersonation procedure is done here. + * + * @param[in] Thread + * The executive thread object that is to impersonate the client. + * + * @param[in] PreviousMode + * The access processor mode, indicating if the call is executed + * in kernel or user mode. + * + * @return + * Returns STATUS_SUCCESS if the impersonation has succeeded. + * STATUS_UNSUCCESSFUL is returned if the primary token couldn't be + * obtained from the current process to perform additional tasks. + * STATUS_ACCESS_DENIED is returned if the process' primary token is + * restricted, which for this matter we cannot impersonate onto a + * restricted process. Otherwise a failure NTSTATUS code is returned. + */ +static +NTSTATUS +SepImpersonateAnonymousToken( + _In_ PETHREAD Thread, + _In_ KPROCESSOR_MODE PreviousMode) +{ + NTSTATUS Status; + PTOKEN TokenToImpersonate, ProcessToken; + ULONG IncludeEveryoneValueData; + PAGED_CODE(); + + /* + * We must check first which kind of token + * shall we assign for the thread to impersonate, + * the one with Everyone Group SID or the other + * without. Invoke the registry helper to + * return the data value for us. + */ + Status = SepRegQueryHelper(L"\Registry\Machine\SYSTEM\CurrentControlSet\Control\Lsa", + L"EveryoneIncludesAnonymous", + REG_DWORD, + sizeof(IncludeEveryoneValueData), + &IncludeEveryoneValueData); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SepRegQueryHelper(): Failed to query the registry value (Status 0x%lx)\n", Status); + return Status; + } + + if (IncludeEveryoneValueData == 0) + { + DPRINT("SepImpersonateAnonymousToken(): Assigning the token not including the Everyone Group SID...\n"); + TokenToImpersonate = SeAnonymousLogonTokenNoEveryone; + } + else + { + DPRINT("SepImpersonateAnonymousToken(): Assigning the token including the Everyone Group SID...\n"); + TokenToImpersonate = SeAnonymousLogonToken; + } + + /* + * Tell the object manager that we're going to use this token + * object now by incrementing the reference count. + */ + Status = ObReferenceObjectByPointer(TokenToImpersonate, + TOKEN_IMPERSONATE, + SeTokenObjectType, + PreviousMode); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SepImpersonateAnonymousToken(): Couldn't be able to use the token, bail out...\n"); + return Status; + } + + /* + * Reference the primary token of the current process that the anonymous + * logon token impersonation procedure is being performed. We'll be going + * to use the process' token to figure out if the process is actually + * restricted or not. + */ + ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); + if (!ProcessToken) + { + DPRINT1("SepImpersonateAnonymousToken(): Couldn't be able to get the process' primary token, bail out...\n"); + ObDereferenceObject(TokenToImpersonate); + return STATUS_UNSUCCESSFUL; + } + + /* Now, is the token from the current process restricted? */ + if (SeTokenIsRestricted(ProcessToken)) + { + DPRINT1("SepImpersonateAnonymousToken(): The process is restricted, can't do anything. Bail out...\n"); + PsDereferencePrimaryToken(ProcessToken); + ObDereferenceObject(TokenToImpersonate); + return STATUS_ACCESS_DENIED; + } + + /* + * Finally it's time to impersonate! But first, fast dereference the + * process' primary token as we no longer need it. + */ + ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); + Status = PsImpersonateClient(Thread, TokenToImpersonate, TRUE, FALSE, SecurityImpersonation); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SepImpersonateAnonymousToken(): Failed to impersonate, bail out...\n"); + ObDereferenceObject(TokenToImpersonate); + return Status; + } + + return Status; +} + static VOID SepUpdateSinglePrivilegeFlagToken( @@ -4304,15 +4417,64 @@ NtFilterToken(IN HANDLE ExistingTokenHandle, return STATUS_NOT_IMPLEMENTED; }
-/* - * @unimplemented +/** + * @brief + * Allows the calling thread to impersonate the system's anonymous + * logon token. + * + * @param[in] ThreadHandle + * A handle to the thread to start the procedure of logon token + * impersonation. The thread must have the THREAD_IMPERSONATE + * access right. + * + * @return + * Returns STATUS_SUCCESS if the thread has successfully impersonated the + * anonymous logon token, otherwise a failure NTSTATUS code is returned. + * + * @remarks + * By default the system gives the opportunity to the caller to impersonate + * the anonymous logon token without including the Everyone Group SID. + * In cases where the caller wants to impersonate the token including such + * group, the EveryoneIncludesAnonymous registry value setting has to be set + * to 1, from HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa registry + * path. The calling thread must invoke PsRevertToSelf when impersonation + * is no longer needed or RevertToSelf if the calling execution is done + * in user mode. */ NTSTATUS NTAPI -NtImpersonateAnonymousToken(IN HANDLE Thread) +NtImpersonateAnonymousToken( + _In_ HANDLE ThreadHandle) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PETHREAD Thread; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + /* Obtain the thread object from the handle */ + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_IMPERSONATE, + PsThreadType, + PreviousMode, + (PVOID*)&Thread, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtImpersonateAnonymousToken(): Failed to reference the object (Status 0x%lx)\n", Status); + return Status; + } + + /* Call the private routine to impersonate the token */ + Status = SepImpersonateAnonymousToken(Thread, PreviousMode); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtImpersonateAnonymousToken(): Failed to impersonate the token (Status 0x%lx)\n", Status); + } + + ObDereferenceObject(Thread); + return Status; }
/* EOF */ diff --git a/sdk/include/ndk/sefuncs.h b/sdk/include/ndk/sefuncs.h index 96164320acc..8907bbc4e51 100644 --- a/sdk/include/ndk/sefuncs.h +++ b/sdk/include/ndk/sefuncs.h @@ -239,7 +239,7 @@ NTSYSCALLAPI NTSTATUS NTAPI NtImpersonateAnonymousToken( - _In_ HANDLE Thread + _In_ HANDLE ThreadHandle );
__kernel_entry