https://git.reactos.org/?p=reactos.git;a=commitdiff;h=44fb528fcc0fe0ea65bbb…
commit 44fb528fcc0fe0ea65bbbe953a015f302983a65e
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Thu Mar 25 21:48:38 2021 +0100
Commit: George Bișoc <george.bisoc(a)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