https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a0bf7a05cc4a911d3b327…
commit a0bf7a05cc4a911d3b32720b3b7d725115878a47
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Tue Aug 31 12:36:28 2021 +0200
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Sun Sep 5 17:01:24 2021 +0200
[NTDLL_APITEST] Write some NtDuplicateToken tests
Implement some tests for NtDuplicateToken syscall that exercises the effective only
behavior when the calling thread tries to duplicate an access token but rendering it
effective with enabled parts.
---
modules/rostests/apitests/ntdll/CMakeLists.txt | 1 +
modules/rostests/apitests/ntdll/NtDuplicateToken.c | 164 +++++++++++++++++++++
modules/rostests/apitests/ntdll/testlist.c | 2 +
3 files changed, 167 insertions(+)
diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt
b/modules/rostests/apitests/ntdll/CMakeLists.txt
index 86613855448..c90cc46c567 100644
--- a/modules/rostests/apitests/ntdll/CMakeLists.txt
+++ b/modules/rostests/apitests/ntdll/CMakeLists.txt
@@ -20,6 +20,7 @@ list(APPEND SOURCE
NtCreateThread.c
NtDeleteKey.c
NtDuplicateObject.c
+ NtDuplicateToken.c
NtFreeVirtualMemory.c
NtImpersonateAnonymousToken.c
NtLoadUnloadKey.c
diff --git a/modules/rostests/apitests/ntdll/NtDuplicateToken.c
b/modules/rostests/apitests/ntdll/NtDuplicateToken.c
new file mode 100644
index 00000000000..fa03d3b8a80
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/NtDuplicateToken.c
@@ -0,0 +1,164 @@
+/*
+ * PROJECT: ReactOS API tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Tests for the NtDuplicateToken API
+ * COPYRIGHT: Copyright 2021 George Bișoc <george.bisoc(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+static
+HANDLE
+OpenTokenFromProcess(VOID)
+{
+ BOOL Success;
+ HANDLE Token;
+
+ Success = OpenProcessToken(GetCurrentProcess(),
+ TOKEN_READ | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS
| TOKEN_DUPLICATE | TOKEN_QUERY,
+ &Token);
+ if (!Success)
+ {
+ skip("OpenProcessToken() has failed to get the process' token (error
code: %lu)!\n", GetLastError());
+ return NULL;
+ }
+
+ return Token;
+}
+
+static
+VOID
+DisablePrivilege(
+ _In_ HANDLE Token,
+ _In_ LPCWSTR PrivilegeName)
+{
+ TOKEN_PRIVILEGES TokenPriv;
+ LUID PrivLuid;
+ BOOL Success;
+
+ Success = LookupPrivilegeValueW(NULL, PrivilegeName, &PrivLuid);
+ if (!Success)
+ {
+ skip("LookupPrivilegeValueW() has failed to locate the privilege value
(error code: %lu)!\n", GetLastError());
+ return;
+ }
+
+ TokenPriv.PrivilegeCount = 1;
+ TokenPriv.Privileges[0].Luid = PrivLuid;
+ TokenPriv.Privileges[0].Attributes = 0;
+
+ Success = AdjustTokenPrivileges(Token,
+ FALSE,
+ &TokenPriv,
+ 0,
+ NULL,
+ NULL);
+ if (!Success)
+ {
+ skip("AdjustTokenPrivileges() has failed to adjust privileges of token
(error code: %lu)!\n", GetLastError());
+ return;
+ }
+}
+
+static
+VOID
+DuplicateTokenAsEffective(VOID)
+{
+ NTSTATUS Status;
+ ULONG Size;
+ HANDLE TokenHandle;
+ HANDLE DuplicatedTokenHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PTOKEN_STATISTICS TokenStats;
+
+ /* Initialize the object attributes for token duplication */
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+
+ /* Get the token from process and begin the tests */
+ TokenHandle = OpenTokenFromProcess();
+
+ /* We give a bogus invalid handle */
+ Status = NtDuplicateToken(NULL,
+ 0,
+ NULL,
+ TRUE,
+ TokenPrimary,
+ NULL);
+ ok_hex(Status, STATUS_ACCESS_VIOLATION);
+
+ /*
+ * Disable a privilege, the impersonation privilege for example.
+ * Why we're doing this is because such privilege is enabled
+ * by default and we'd want to know what the kernel does
+ * at the moment of removing disabled privileges during making
+ * the token effective, with this potential privilege being
+ * disabled by ourselves.
+ */
+ DisablePrivilege(TokenHandle, L"SeImpersonatePrivilege");
+
+ /* Query the total size of the token statistics structure */
+ Status = NtQueryInformationToken(TokenHandle, TokenStatistics, NULL, 0, &Size);
+ if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ skip("Failed to query the total size for token statistics structure! (Status
-> 0x%lx)\n", Status);
+ return;
+ }
+
+ /* Total size queried, time to allocate our buffer based on that size */
+ TokenStats = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
+ if (TokenStats == NULL)
+ {
+ skip("Failed to allocate our token statistics buffer!\n");
+ return;
+ }
+
+ /* Time to query our token statistics, prior duplicating the token as effective */
+ Status = NtQueryInformationToken(TokenHandle, TokenStatistics, TokenStats, Size,
&Size);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("Failed to query the token statistics! (Status -> 0x%lx)\n",
Status);
+ return;
+ }
+
+ trace("Number of privileges of regular token -- %lu\n",
TokenStats->PrivilegeCount);
+ trace("Number of groups of regular token -- %lu\n",
TokenStats->GroupCount);
+
+ /* Duplicate the token as effective only */
+ Status = NtDuplicateToken(TokenHandle,
+ 0,
+ &ObjectAttributes,
+ TRUE,
+ TokenPrimary,
+ &DuplicatedTokenHandle);
+ ok_hex(Status, STATUS_SUCCESS);
+
+ /*
+ * Query the token statistics again, but now this time of
+ * the duplicated effective token. On this moment this token
+ * should have the disabled privileges (including the one we
+ * disabled ourselves) removed as well as the disabled groups
+ * that the duplicated token includes, whatever that is.
+ */
+ Status = NtQueryInformationToken(DuplicatedTokenHandle, TokenStatistics, TokenStats,
Size, &Size);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("Failed to query the token statistics! (Status -> 0x%lx)\n",
Status);
+ return;
+ }
+
+ trace("Number of privileges of effective only token -- %lu\n",
TokenStats->PrivilegeCount);
+ trace("Number of groups of effective only token -- %lu\n",
TokenStats->GroupCount);
+
+ /* We finished our tests, close the handles now */
+ CloseHandle(TokenHandle),
+ CloseHandle(DuplicatedTokenHandle);
+}
+
+START_TEST(NtDuplicateToken)
+{
+ DuplicateTokenAsEffective();
+}
diff --git a/modules/rostests/apitests/ntdll/testlist.c
b/modules/rostests/apitests/ntdll/testlist.c
index 49458f43f09..1a921a2f2b1 100644
--- a/modules/rostests/apitests/ntdll/testlist.c
+++ b/modules/rostests/apitests/ntdll/testlist.c
@@ -16,6 +16,7 @@ extern void func_NtCreateKey(void);
extern void func_NtCreateThread(void);
extern void func_NtDeleteKey(void);
extern void func_NtDuplicateObject(void);
+extern void func_NtDuplicateToken(void);
extern void func_NtFreeVirtualMemory(void);
extern void func_NtImpersonateAnonymousToken(void);
extern void func_NtLoadUnloadKey(void);
@@ -101,6 +102,7 @@ const struct test winetest_testlist[] =
{ "NtCreateThread", func_NtCreateThread },
{ "NtDeleteKey", func_NtDeleteKey },
{ "NtDuplicateObject", func_NtDuplicateObject },
+ { "NtDuplicateToken", func_NtDuplicateToken },
{ "NtFreeVirtualMemory", func_NtFreeVirtualMemory },
{ "NtImpersonateAnonymousToken", func_NtImpersonateAnonymousToken },
{ "NtLoadUnloadKey", func_NtLoadUnloadKey },