https://git.reactos.org/?p=reactos.git;a=commitdiff;h=fefb1b77458f05ecdc4e0…
commit fefb1b77458f05ecdc4e0956c1b69c109f51142e
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Sat Sep 30 21:05:18 2023 +0200
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Wed Oct 4 18:04:29 2023 +0200
[NTDLL_APITEST] Write NtAccessCheck testcase that tests for empty generic mapping
scenario
See b79aadd50bb7d5d6f08532284941c0334514c477 for further information.
---
modules/rostests/apitests/ntdll/CMakeLists.txt | 1 +
modules/rostests/apitests/ntdll/NtAccessCheck.c | 188 ++++++++++++++++++++++++
modules/rostests/apitests/ntdll/testlist.c | 2 +
3 files changed, 191 insertions(+)
diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt
b/modules/rostests/apitests/ntdll/CMakeLists.txt
index 85515a2efaf..b6ce3a1cf4d 100644
--- a/modules/rostests/apitests/ntdll/CMakeLists.txt
+++ b/modules/rostests/apitests/ntdll/CMakeLists.txt
@@ -10,6 +10,7 @@ list(APPEND SOURCE
load_notifications.c
locale.c
NtAcceptConnectPort.c
+ NtAccessCheck.c
NtAccessCheckByType.c
NtAccessCheckByTypeResultList.c
NtAdjustGroupsToken.c
diff --git a/modules/rostests/apitests/ntdll/NtAccessCheck.c
b/modules/rostests/apitests/ntdll/NtAccessCheck.c
new file mode 100644
index 00000000000..c987a445b13
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/NtAccessCheck.c
@@ -0,0 +1,188 @@
+/*
+ * PROJECT: ReactOS API tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Tests for the NtAccessCheck API
+ * COPYRIGHT: Copyright 2023 George Bișoc <george.bisoc(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+static
+HANDLE
+GetToken(VOID)
+{
+ NTSTATUS Status;
+ HANDLE Token;
+ HANDLE DuplicatedToken;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ SECURITY_QUALITY_OF_SERVICE Sqos;
+
+ Status = NtOpenProcessToken(NtCurrentProcess(),
+ TOKEN_QUERY | TOKEN_DUPLICATE,
+ &Token);
+ if (!NT_SUCCESS(Status))
+ {
+ trace("Failed to get current process token (Status 0x%08lx)\n",
Status);
+ return NULL;
+ }
+
+ Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ Sqos.ImpersonationLevel = SecurityImpersonation;
+ Sqos.ContextTrackingMode = 0;
+ Sqos.EffectiveOnly = FALSE;
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ ObjectAttributes.SecurityQualityOfService = &Sqos;
+
+ Status = NtDuplicateToken(Token,
+ TOKEN_QUERY | TOKEN_DUPLICATE,
+ &ObjectAttributes,
+ FALSE,
+ TokenImpersonation,
+ &DuplicatedToken);
+ if (!NT_SUCCESS(Status))
+ {
+ trace("Failed to duplicate token (Status 0x%08lx)\n", Status);
+ NtClose(Token);
+ return NULL;
+ }
+
+ return DuplicatedToken;
+}
+
+static
+VOID
+AccessCheckEmptyMappingTest(VOID)
+{
+ NTSTATUS Status;
+ NTSTATUS AccessStatus;
+ ACCESS_MASK GrantedAccess;
+ PPRIVILEGE_SET PrivilegeSet = NULL;
+ ULONG PrivilegeSetLength;
+ HANDLE Token = NULL;
+ PACL Dacl = NULL;
+ ULONG DaclSize;
+ SECURITY_DESCRIPTOR Sd;
+ PSID WorldSid = NULL;
+ static SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+ static GENERIC_MAPPING EmptyMapping = {0, 0, 0, 0};
+
+ /* Allocate all the stuff we need */
+ PrivilegeSetLength = FIELD_OFFSET(PRIVILEGE_SET, Privilege[16]);
+ PrivilegeSet = RtlAllocateHeap(RtlGetProcessHeap(), 0, PrivilegeSetLength);
+ if (PrivilegeSet == NULL)
+ {
+ skip("Failed to allocate PrivilegeSet, skipping tests\n");
+ return;
+ }
+
+ Status = RtlAllocateAndInitializeSid(&WorldAuthority,
+ 1,
+ SECURITY_WORLD_RID,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &WorldSid);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("Failed to create World SID, skipping tests\n");
+ goto Quit;
+ }
+
+ Token = GetToken();
+ if (Token == NULL)
+ {
+ skip("Failed to get token, skipping tests\n");
+ goto Quit;
+ }
+
+ Status = RtlCreateSecurityDescriptor(&Sd, SECURITY_DESCRIPTOR_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("Failed to create a security descriptor, skipping tests\n");
+ goto Quit;
+ }
+
+ DaclSize = sizeof(ACL) +
+ sizeof(ACCESS_ALLOWED_OBJECT_ACE) + RtlLengthSid(WorldSid);
+ Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ DaclSize);
+ if (Dacl == NULL)
+ {
+ skip("Failed to allocate memory for DACL, skipping tests\n");
+ goto Quit;
+ }
+
+ /* Setup a ACL and give full access to everyone */
+ Status = RtlCreateAcl(Dacl,
+ DaclSize,
+ ACL_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("Failed to create DACL, skipping tests\n");
+ goto Quit;
+ }
+
+ Status = RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ GENERIC_ALL,
+ WorldSid);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("Failed to add allowed ACE for World SID, skipping tests\n");
+ goto Quit;
+ }
+
+ /* Setup the descriptor */
+ RtlSetGroupSecurityDescriptor(&Sd, WorldSid, FALSE);
+ RtlSetOwnerSecurityDescriptor(&Sd, WorldSid, FALSE);
+ RtlSetDaclSecurityDescriptor(&Sd, TRUE, Dacl, FALSE);
+
+ /* Do an access check with empty mapping */
+ Status = NtAccessCheck(&Sd,
+ Token,
+ MAXIMUM_ALLOWED,
+ &EmptyMapping,
+ PrivilegeSet,
+ &PrivilegeSetLength,
+ &GrantedAccess,
+ &AccessStatus);
+ ok_hex(Status, STATUS_SUCCESS);
+ ok(AccessStatus == STATUS_SUCCESS, "Expected a success status but got
0x%08lx\n", AccessStatus);
+ trace("GrantedAccess == 0x%08lx\n", GrantedAccess);
+
+Quit:
+ if (Dacl)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
+ }
+
+ if (Token)
+ {
+ NtClose(Token);
+ }
+
+ if (WorldSid)
+ {
+ RtlFreeSid(WorldSid);
+ }
+
+ if (PrivilegeSet)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PrivilegeSet);
+ }
+}
+
+START_TEST(NtAccessCheck)
+{
+ AccessCheckEmptyMappingTest();
+}
diff --git a/modules/rostests/apitests/ntdll/testlist.c
b/modules/rostests/apitests/ntdll/testlist.c
index 2be58938238..438cc56a172 100644
--- a/modules/rostests/apitests/ntdll/testlist.c
+++ b/modules/rostests/apitests/ntdll/testlist.c
@@ -6,6 +6,7 @@
extern void func_LdrEnumResources(void);
extern void func_load_notifications(void);
extern void func_NtAcceptConnectPort(void);
+extern void func_NtAccessCheck(void);
extern void func_NtAccessCheckByType(void);
extern void func_NtAccessCheckByTypeResultList(void);
extern void func_NtAdjustGroupsToken(void);
@@ -102,6 +103,7 @@ const struct test winetest_testlist[] =
{ "LdrEnumResources", func_LdrEnumResources },
{ "load_notifications", func_load_notifications },
{ "NtAcceptConnectPort", func_NtAcceptConnectPort },
+ { "NtAccessCheck", func_NtAccessCheck },
{ "NtAccessCheckByType", func_NtAccessCheckByType },
{ "NtAccessCheckByTypeResultList", func_NtAccessCheckByTypeResultList },
{ "NtAdjustGroupsToken", func_NtAdjustGroupsToken },