https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6fe1b387c6f5a582fedea…
commit 6fe1b387c6f5a582fedeac7c17d84440a1df74d3
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Tue Oct 19 11:36:02 2021 +0200
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Sun Nov 7 14:14:18 2021 +0100
[NTDLL_APITEST] Implement NtFilterToken testcase
---
modules/rostests/apitests/ntdll/CMakeLists.txt | 1 +
modules/rostests/apitests/ntdll/NtFilterToken.c | 137 ++++++++++++++++++++++++
modules/rostests/apitests/ntdll/testlist.c | 2 +
3 files changed, 140 insertions(+)
diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt
b/modules/rostests/apitests/ntdll/CMakeLists.txt
index 403641119fb..1e69ecf4900 100644
--- a/modules/rostests/apitests/ntdll/CMakeLists.txt
+++ b/modules/rostests/apitests/ntdll/CMakeLists.txt
@@ -22,6 +22,7 @@ list(APPEND SOURCE
NtDeleteKey.c
NtDuplicateObject.c
NtDuplicateToken.c
+ NtFilterToken.c
NtFreeVirtualMemory.c
NtImpersonateAnonymousToken.c
NtLoadUnloadKey.c
diff --git a/modules/rostests/apitests/ntdll/NtFilterToken.c
b/modules/rostests/apitests/ntdll/NtFilterToken.c
new file mode 100644
index 00000000000..60453c9bf87
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/NtFilterToken.c
@@ -0,0 +1,137 @@
+/*
+ * PROJECT: ReactOS API tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Tests for the NtFilterToken API
+ * COPYRIGHT: Copyright 2021 George Bișoc <george.bisoc(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+static
+HANDLE
+GetTokenProcess(VOID)
+{
+ BOOL Success;
+ HANDLE Token;
+
+ Success = OpenProcessToken(GetCurrentProcess(),
+ TOKEN_DUPLICATE | TOKEN_QUERY,
+ &Token);
+ if (!Success)
+ {
+ skip("GetTokenProcess() has failed to get the process' token (error
code: %lu)!\n", GetLastError());
+ return NULL;
+ }
+
+ return Token;
+}
+
+START_TEST(NtFilterToken)
+{
+ NTSTATUS Status;
+ HANDLE FilteredToken, Token;
+ TOKEN_PRIVILEGES Priv;
+ LUID PrivLuid;
+ ULONG Size;
+ PTOKEN_STATISTICS TokenStats;
+
+ /* We don't give a token */
+ Status = NtFilterToken(NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ &FilteredToken);
+ ok_hex(Status, STATUS_INVALID_HANDLE);
+
+ /* Get the token from process now */
+ Token = GetTokenProcess();
+
+ /* We don't give any privileges to delete */
+ Status = NtFilterToken(Token,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ &FilteredToken);
+ ok_hex(Status, STATUS_SUCCESS);
+
+ /* Query the total size to hold the statistics */
+ Status = NtQueryInformationToken(Token, 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 disabling token's privileges */
+ Status = NtQueryInformationToken(Token, 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 before token filtering -- %lu\n\n",
TokenStats->PrivilegeCount);
+
+ /* Disable the privileges and make the token a safer inert one */
+ Status = NtFilterToken(Token,
+ DISABLE_MAX_PRIVILEGE | SANDBOX_INERT,
+ NULL,
+ NULL,
+ NULL,
+ &FilteredToken);
+ ok_hex(Status, STATUS_SUCCESS);
+
+ /* We've disabled privileges, query the stats again */
+ Status = NtQueryInformationToken(FilteredToken, 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 after token filtering (privileges disabled with
DISABLE_MAX_PRIVILEGE) -- %lu\n\n", TokenStats->PrivilegeCount);
+
+ /* Close the filtered token and do another test */
+ CloseHandle(FilteredToken);
+
+ /* Fill in a privilege to delete */
+ Priv.PrivilegeCount = 1;
+
+ ConvertPrivLongToLuid(SE_BACKUP_PRIVILEGE, &PrivLuid);
+ Priv.Privileges[0].Luid = PrivLuid;
+ Priv.Privileges[0].Attributes = 0;
+
+ /* Delete the privileges */
+ Status = NtFilterToken(Token,
+ 0,
+ NULL,
+ &Priv,
+ NULL,
+ &FilteredToken);
+ ok_hex(Status, STATUS_SUCCESS);
+
+ /* We've deleted a privilege, query the stats again */
+ Status = NtQueryInformationToken(FilteredToken, 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 after token filtering (manually deleted privilege)
-- %lu\n\n", TokenStats->PrivilegeCount);
+
+ /* We're done */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, TokenStats);
+ CloseHandle(Token);
+ CloseHandle(FilteredToken);
+}
diff --git a/modules/rostests/apitests/ntdll/testlist.c
b/modules/rostests/apitests/ntdll/testlist.c
index 9642602fd77..aff61fa3091 100644
--- a/modules/rostests/apitests/ntdll/testlist.c
+++ b/modules/rostests/apitests/ntdll/testlist.c
@@ -18,6 +18,7 @@ extern void func_NtCreateThread(void);
extern void func_NtDeleteKey(void);
extern void func_NtDuplicateObject(void);
extern void func_NtDuplicateToken(void);
+extern void func_NtFilterToken(void);
extern void func_NtFreeVirtualMemory(void);
extern void func_NtImpersonateAnonymousToken(void);
extern void func_NtLoadUnloadKey(void);
@@ -105,6 +106,7 @@ const struct test winetest_testlist[] =
{ "NtDeleteKey", func_NtDeleteKey },
{ "NtDuplicateObject", func_NtDuplicateObject },
{ "NtDuplicateToken", func_NtDuplicateToken },
+ { "NtFilterToken", func_NtFilterToken },
{ "NtFreeVirtualMemory", func_NtFreeVirtualMemory },
{ "NtImpersonateAnonymousToken", func_NtImpersonateAnonymousToken },
{ "NtLoadUnloadKey", func_NtLoadUnloadKey },