https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8a61e1c33c78d0ac188fd2fddc96325084ff5eb0

commit 8a61e1c33c78d0ac188fd2fddc96325084ff5eb0
Author:     George Bișoc <george.bi...@reactos.org>
AuthorDate: Fri Jul 28 10:52:18 2023 +0200
Commit:     unknown <george.bi...@reactos.org>
CommitDate: Tue Aug 22 17:54:19 2023 +0200

    [NTDLL_APITEST] Write tests for NtAccessCheckByTypeResultList
---
 modules/rostests/apitests/ntdll/CMakeLists.txt     |   1 +
 .../apitests/ntdll/NtAccessCheckByTypeResultList.c | 692 +++++++++++++++++++++
 modules/rostests/apitests/ntdll/testlist.c         |   2 +
 3 files changed, 695 insertions(+)

diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt 
b/modules/rostests/apitests/ntdll/CMakeLists.txt
index 4cad9ae218e..14c12de120e 100644
--- a/modules/rostests/apitests/ntdll/CMakeLists.txt
+++ b/modules/rostests/apitests/ntdll/CMakeLists.txt
@@ -11,6 +11,7 @@ list(APPEND SOURCE
     locale.c
     NtAcceptConnectPort.c
     NtAccessCheckByType.c
+    NtAccessCheckByTypeResultList.c
     NtAdjustGroupsToken.c
     NtAdjustPrivilegesToken.c
     NtAllocateVirtualMemory.c
diff --git a/modules/rostests/apitests/ntdll/NtAccessCheckByTypeResultList.c 
b/modules/rostests/apitests/ntdll/NtAccessCheckByTypeResultList.c
new file mode 100644
index 00000000000..084c9ddb006
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/NtAccessCheckByTypeResultList.c
@@ -0,0 +1,692 @@
+/*
+ * PROJECT:         ReactOS API tests
+ * LICENSE:         GPL-2.0-or-later 
(https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:         Tests for the NtAccessCheckByTypeResultList API
+ * COPYRIGHT:       Copyright 2023 George Bișoc <george.bi...@reactos.org>
+ */
+
+#include "precomp.h"
+
+static GENERIC_MAPPING RegMapping = {KEY_READ, KEY_WRITE, KEY_EXECUTE, 
KEY_ALL_ACCESS};
+static GUID ObjectType = {0x12345678, 0x1234, 0x5678, {0x11, 0x22, 0x33, 0x44, 
0x55, 0x66, 0x77, 0x88}};
+static GUID ChildObjectType = {0x23456789, 0x2345, 0x6786, {0x2, 0x33, 0x44, 
0x55, 0x66, 0x77, 0x88, 0x99}};
+static SID_IDENTIFIER_AUTHORITY WorldAuthority = 
{SECURITY_WORLD_SID_AUTHORITY};
+static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
+
+static
+HANDLE
+GetTokenProcess(
+    _In_ BOOLEAN WantImpersonateLevel,
+    _In_ BOOLEAN WantImpersonateType)
+{
+    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 = WantImpersonateLevel ? SecurityImpersonation : 
SecurityAnonymous;
+    Sqos.ContextTrackingMode = 0;
+    Sqos.EffectiveOnly = FALSE;
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               NULL,
+                               0,
+                               NULL,
+                               NULL);
+    ObjectAttributes.SecurityQualityOfService = &Sqos;
+
+    Status = NtDuplicateToken(Token,
+                              TOKEN_QUERY | TOKEN_DUPLICATE,
+                              &ObjectAttributes,
+                              FALSE,
+                              WantImpersonateType ? TokenImpersonation : 
TokenPrimary,
+                              &DuplicatedToken);
+    if (!NT_SUCCESS(Status))
+    {
+        trace("Failed to duplicate token (Status 0x%08lx)\n", Status);
+        NtClose(Token);
+        return NULL;
+    }
+
+    return DuplicatedToken;
+}
+
+static
+VOID
+ParamValidationNoObjsList(VOID)
+{
+    NTSTATUS Status;
+    NTSTATUS AccessStatus;
+    ACCESS_MASK GrantedAccess;
+    PPRIVILEGE_SET PrivilegeSet = NULL;
+    ULONG PrivilegeSetLength;
+    HANDLE Token = NULL;
+    SECURITY_DESCRIPTOR Sd;
+
+    PrivilegeSetLength = FIELD_OFFSET(PRIVILEGE_SET, Privilege[16]);
+    PrivilegeSet = RtlAllocateHeap(RtlGetProcessHeap(), 0, PrivilegeSetLength);
+    if (PrivilegeSet == NULL)
+    {
+        skip("Failed to allocate PrivilegeSet, skipping tests\n");
+        goto Quit;
+    }
+
+    Token = GetTokenProcess(TRUE, TRUE);
+    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;
+    }
+
+    RtlSetGroupSecurityDescriptor(&Sd, NULL, FALSE);
+    RtlSetOwnerSecurityDescriptor(&Sd, NULL, FALSE);
+    RtlSetDaclSecurityDescriptor(&Sd, FALSE, NULL, FALSE);
+
+    /* The function expects an object type list */
+    Status = NtAccessCheckByTypeResultList(&Sd,
+                                           NULL,
+                                           Token,
+                                           MAXIMUM_ALLOWED,
+                                           NULL,
+                                           0,
+                                           &RegMapping,
+                                           PrivilegeSet,
+                                           &PrivilegeSetLength,
+                                           &GrantedAccess,
+                                           &AccessStatus);
+    ok_hex(Status, STATUS_INVALID_PARAMETER);
+
+Quit:
+    if (Token)
+    {
+        NtClose(Token);
+    }
+
+    if (PrivilegeSet)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, PrivilegeSet);
+    }
+}
+
+static
+VOID
+PrintAccessStatusAndGrantedAccess(
+    _In_ PNTSTATUS AccessStatus,
+    _In_ PACCESS_MASK GrantedAccess,
+    _In_ ULONG ObjectTypeListLength)
+{
+    ULONG i;
+
+    trace("===== OBJECT ACCESS & STATUS LIST =====\n");
+    for (i = 0; i < ObjectTypeListLength; i++)
+    {
+        trace("OBJ #%lu, access status 0x%08lx, granted access 0x%08lx\n", i, 
AccessStatus[i], GrantedAccess[i]);
+    }
+    trace("\n");
+}
+
+static
+VOID
+GrantedAccessTests(VOID)
+{
+    NTSTATUS Status;
+    NTSTATUS AccessStatus[6];
+    ACCESS_MASK GrantedAccess[6];
+    PPRIVILEGE_SET PrivilegeSet = NULL;
+    ULONG PrivilegeSetLength;
+    HANDLE Token = NULL;
+    PACL Dacl = NULL;
+    ULONG DaclSize;
+    ULONG i;
+    SECURITY_DESCRIPTOR Sd;
+    OBJECT_TYPE_LIST ObjTypeList[6];
+    PSID EveryoneSid = NULL, AdminSid = NULL, UsersSid = NULL;
+    GUID ChildObjectType2 = {0x34578901, 0x3456, 0x7896, {0x3, 0x44, 0x55, 
0x66, 0x77, 0x88, 0x99, 0x00}};
+    GUID ChildObjectType3 = {0x45678901, 0x4567, 0x1122, {0x4, 0x12, 0x13, 
0x14, 0x15, 0x16, 0x17, 0x01}};
+    GUID ChildObjectType4 = {0x56788901, 0x1111, 0x2222, {0x5, 0x13, 0x14, 
0x15, 0x16, 0x17, 0x18, 0x02}};
+    GUID ChildObjectType5 = {0x67901234, 0x2222, 0x3333, {0x4, 0x14, 0x15, 
0x16, 0x17, 0x18, 0x19, 0x03}};
+
+    /* 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,
+                                         &EveryoneSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to create Everyone SID, skipping tests\n");
+        goto Quit;
+    }
+
+    Status = RtlAllocateAndInitializeSid(&NtAuthority,
+                                         2,
+                                         SECURITY_BUILTIN_DOMAIN_RID,
+                                         DOMAIN_ALIAS_RID_ADMINS,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         &AdminSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to create Admins SID, skipping tests\n");
+        goto Quit;
+    }
+
+    Status = RtlAllocateAndInitializeSid(&NtAuthority,
+                                         2,
+                                         SECURITY_BUILTIN_DOMAIN_RID,
+                                         DOMAIN_ALIAS_RID_USERS,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         &UsersSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to create User SID, skipping tests\n");
+        goto Quit;
+    }
+
+    Token = GetTokenProcess(TRUE, TRUE);
+    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(AdminSid) +
+               sizeof(ACCESS_ALLOWED_OBJECT_ACE) + RtlLengthSid(EveryoneSid) +
+               sizeof(ACCESS_ALLOWED_OBJECT_ACE) + RtlLengthSid(EveryoneSid);
+    Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
+                           HEAP_ZERO_MEMORY,
+                           DaclSize);
+    if (Dacl == NULL)
+    {
+        skip("Failed to allocate memory for DACL, skipping tests\n");
+        goto Quit;
+    }
+
+    Status = RtlCreateAcl(Dacl,
+                          DaclSize,
+                          ACL_REVISION4);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to create DACL, skipping tests\n");
+        goto Quit;
+    }
+
+    /*
+     * Admins have full access over the key object, everyone else can only 
read from
+     * it and can only query the value from the child sub-object.
+     */
+    Status = RtlAddAccessAllowedObjectAce(Dacl,
+                                          ACL_REVISION4,
+                                          0,
+                                          KEY_ALL_ACCESS,
+                                          &ObjectType,
+                                          NULL,
+                                          AdminSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to add allowed object ACE for Admins SID, skipping 
tests\n");
+        goto Quit;
+    }
+
+    Status = RtlAddAccessAllowedObjectAce(Dacl,
+                                          ACL_REVISION4,
+                                          0,
+                                          KEY_READ,
+                                          &ObjectType,
+                                          NULL,
+                                          EveryoneSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to add allowed object ACE for Everyone SID, skipping 
tests\n");
+        goto Quit;
+    }
+
+    Status = RtlAddAccessAllowedObjectAce(Dacl,
+                                          ACL_REVISION4,
+                                          0,
+                                          KEY_QUERY_VALUE,
+                                          &ChildObjectType,
+                                          NULL,
+                                          EveryoneSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to add allowed object ACE for Everyone SID, skipping 
tests\n");
+        goto Quit;
+    }
+
+    /* Setup the descriptor */
+    RtlSetGroupSecurityDescriptor(&Sd, UsersSid, FALSE);
+    RtlSetOwnerSecurityDescriptor(&Sd, AdminSid, FALSE);
+    RtlSetDaclSecurityDescriptor(&Sd, TRUE, Dacl, FALSE);
+
+    /* Setup the object type list */
+    ObjTypeList[0].Level = ACCESS_OBJECT_GUID;
+    ObjTypeList[0].Sbz = 0;
+    ObjTypeList[0].ObjectType = &ObjectType;
+
+    ObjTypeList[1].Level = ACCESS_PROPERTY_SET_GUID;
+    ObjTypeList[1].Sbz = 0;
+    ObjTypeList[1].ObjectType = &ChildObjectType;
+
+    ObjTypeList[2].Level = ACCESS_PROPERTY_GUID;
+    ObjTypeList[2].Sbz = 0;
+    ObjTypeList[2].ObjectType = &ChildObjectType2;
+
+    ObjTypeList[3].Level = ACCESS_PROPERTY_GUID;
+    ObjTypeList[3].Sbz = 0;
+    ObjTypeList[3].ObjectType = &ChildObjectType3;
+
+    ObjTypeList[4].Level = ACCESS_PROPERTY_SET_GUID;
+    ObjTypeList[4].Sbz = 0;
+    ObjTypeList[4].ObjectType = &ChildObjectType4;
+
+    ObjTypeList[5].Level = ACCESS_PROPERTY_GUID;
+    ObjTypeList[5].Sbz = 0;
+    ObjTypeList[5].ObjectType = &ChildObjectType5;
+
+    /* Admins should be granted every access */
+    Status = NtAccessCheckByTypeResultList(&Sd,
+                                           NULL,
+                                           Token,
+                                           MAXIMUM_ALLOWED,
+                                           ObjTypeList,
+                                           RTL_NUMBER_OF(ObjTypeList),
+                                           &RegMapping,
+                                           PrivilegeSet,
+                                           &PrivilegeSetLength,
+                                           GrantedAccess,
+                                           AccessStatus);
+    ok_hex(Status, STATUS_SUCCESS);
+
+    PrintAccessStatusAndGrantedAccess(AccessStatus, GrantedAccess, 
RTL_NUMBER_OF(ObjTypeList));
+    for (i = 0; i < RTL_NUMBER_OF(ObjTypeList); i++)
+    {
+        ok(AccessStatus[i] == STATUS_SUCCESS, "Expected STATUS_SUCCESS but got 
0x%08lx\n", AccessStatus[i]);
+        ok(GrantedAccess[i] == KEY_ALL_ACCESS, "Expected KEY_ALL_ACCESS but 
got 0x%08lx\n", GrantedAccess[i]);
+    }
+
+    /* Everyone else can only read */
+    Status = NtAccessCheckByTypeResultList(&Sd,
+                                           NULL,
+                                           Token,
+                                           KEY_READ,
+                                           ObjTypeList,
+                                           RTL_NUMBER_OF(ObjTypeList),
+                                           &RegMapping,
+                                           PrivilegeSet,
+                                           &PrivilegeSetLength,
+                                           GrantedAccess,
+                                           AccessStatus);
+    ok_hex(Status, STATUS_SUCCESS);
+
+    PrintAccessStatusAndGrantedAccess(AccessStatus, GrantedAccess, 
RTL_NUMBER_OF(ObjTypeList));
+    for (i = 0; i < RTL_NUMBER_OF(ObjTypeList); i++)
+    {
+        ok(AccessStatus[i] == STATUS_SUCCESS, "Expected STATUS_SUCCESS but got 
0x%08lx\n", AccessStatus[i]);
+        ok(GrantedAccess[i] == KEY_READ, "Expected KEY_READ but got 
0x%08lx\n", GrantedAccess[i]);
+    }
+
+    /* Everyone else can only query a registry value from the child object */
+    Status = NtAccessCheckByTypeResultList(&Sd,
+                                           NULL,
+                                           Token,
+                                           KEY_QUERY_VALUE,
+                                           ObjTypeList,
+                                           RTL_NUMBER_OF(ObjTypeList),
+                                           &RegMapping,
+                                           PrivilegeSet,
+                                           &PrivilegeSetLength,
+                                           GrantedAccess,
+                                           AccessStatus);
+    ok_hex(Status, STATUS_SUCCESS);
+
+    PrintAccessStatusAndGrantedAccess(AccessStatus, GrantedAccess, 
RTL_NUMBER_OF(ObjTypeList));
+    for (i = 0; i < RTL_NUMBER_OF(ObjTypeList); i++)
+    {
+        ok(AccessStatus[i] == STATUS_SUCCESS, "Expected STATUS_SUCCESS but got 
0x%08lx\n", AccessStatus[i]);
+        ok(GrantedAccess[i] == KEY_QUERY_VALUE, "Expected KEY_QUERY_VALUE but 
got 0x%08lx\n", GrantedAccess[i]);
+    }
+
+Quit:
+    if (Dacl)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
+    }
+
+    if (Token)
+    {
+        NtClose(Token);
+    }
+
+    if (UsersSid)
+    {
+        RtlFreeSid(UsersSid);
+    }
+
+    if (AdminSid)
+    {
+        RtlFreeSid(AdminSid);
+    }
+
+    if (EveryoneSid)
+    {
+        RtlFreeSid(EveryoneSid);
+    }
+
+    if (PrivilegeSet)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, PrivilegeSet);
+    }
+}
+
+static
+VOID
+DenyAccessTests(VOID)
+{
+    NTSTATUS Status;
+    NTSTATUS AccessStatus[6];
+    ACCESS_MASK GrantedAccess[6];
+    PPRIVILEGE_SET PrivilegeSet = NULL;
+    ULONG PrivilegeSetLength;
+    HANDLE Token = NULL;
+    PACL Dacl = NULL;
+    ULONG DaclSize;
+    ULONG i;
+    SECURITY_DESCRIPTOR Sd;
+    OBJECT_TYPE_LIST ObjTypeList[6];
+    PSID EveryoneSid = NULL, AdminSid = NULL, UsersSid = NULL;
+    GUID ChildObjectType2 = {0x34578901, 0x3456, 0x7896, {0x3, 0x44, 0x55, 
0x66, 0x77, 0x88, 0x99, 0x00}};
+    GUID ChildObjectType3 = {0x45678901, 0x4567, 0x1122, {0x4, 0x12, 0x13, 
0x14, 0x15, 0x16, 0x17, 0x01}};
+    GUID ChildObjectType4 = {0x56788901, 0x1111, 0x2222, {0x5, 0x13, 0x14, 
0x15, 0x16, 0x17, 0x18, 0x02}};
+    GUID ChildObjectType5 = {0x67901234, 0x2222, 0x3333, {0x4, 0x14, 0x15, 
0x16, 0x17, 0x18, 0x19, 0x03}};
+
+    /* 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,
+                                         &EveryoneSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to create Everyone SID, skipping tests\n");
+        goto Quit;
+    }
+
+    Status = RtlAllocateAndInitializeSid(&NtAuthority,
+                                         2,
+                                         SECURITY_BUILTIN_DOMAIN_RID,
+                                         DOMAIN_ALIAS_RID_ADMINS,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         &AdminSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to create Admins SID, skipping tests\n");
+        goto Quit;
+    }
+
+    Status = RtlAllocateAndInitializeSid(&NtAuthority,
+                                         2,
+                                         SECURITY_BUILTIN_DOMAIN_RID,
+                                         DOMAIN_ALIAS_RID_USERS,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         &UsersSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to create User SID, skipping tests\n");
+        goto Quit;
+    }
+
+    Token = GetTokenProcess(TRUE, TRUE);
+    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_DENIED_OBJECT_ACE) + RtlLengthSid(AdminSid) +
+               sizeof(ACCESS_DENIED_OBJECT_ACE) + RtlLengthSid(EveryoneSid) +
+               sizeof(ACCESS_ALLOWED_OBJECT_ACE) + RtlLengthSid(EveryoneSid);
+    Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
+                           HEAP_ZERO_MEMORY,
+                           DaclSize);
+    if (Dacl == NULL)
+    {
+        skip("Failed to allocate memory for DACL, skipping tests\n");
+        goto Quit;
+    }
+
+    Status = RtlCreateAcl(Dacl,
+                          DaclSize,
+                          ACL_REVISION4);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to create DACL, skipping tests\n");
+        goto Quit;
+    }
+
+    /*
+     * Admins can't read the main object, whereas everyone else can't write
+     * into the child object.
+     */
+    Status = RtlAddAccessDeniedObjectAce(Dacl,
+                                         ACL_REVISION4,
+                                         0,
+                                         KEY_READ,
+                                         &ObjectType,
+                                         NULL,
+                                         AdminSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to add deny object ACE for Admins SID, skipping tests\n");
+        goto Quit;
+    }
+
+    Status = RtlAddAccessDeniedObjectAce(Dacl,
+                                         ACL_REVISION4,
+                                         0,
+                                         KEY_WRITE,
+                                         &ChildObjectType,
+                                         NULL,
+                                         EveryoneSid);
+    if (!NT_SUCCESS(Status))
+    {
+        skip("Failed to add deny object ACE for Everyone SID, skipping 
tests\n");
+        goto Quit;
+    }
+
+    /* Setup the descriptor */
+    RtlSetGroupSecurityDescriptor(&Sd, UsersSid, FALSE);
+    RtlSetOwnerSecurityDescriptor(&Sd, AdminSid, FALSE);
+    RtlSetDaclSecurityDescriptor(&Sd, TRUE, Dacl, FALSE);
+
+    /* Setup the object type list */
+    ObjTypeList[0].Level = ACCESS_OBJECT_GUID;
+    ObjTypeList[0].Sbz = 0;
+    ObjTypeList[0].ObjectType = &ObjectType;
+
+    ObjTypeList[1].Level = ACCESS_PROPERTY_SET_GUID;
+    ObjTypeList[1].Sbz = 0;
+    ObjTypeList[1].ObjectType = &ChildObjectType;
+
+    ObjTypeList[2].Level = ACCESS_PROPERTY_GUID;
+    ObjTypeList[2].Sbz = 0;
+    ObjTypeList[2].ObjectType = &ChildObjectType2;
+
+    ObjTypeList[3].Level = ACCESS_PROPERTY_GUID;
+    ObjTypeList[3].Sbz = 0;
+    ObjTypeList[3].ObjectType = &ChildObjectType3;
+
+    ObjTypeList[4].Level = ACCESS_PROPERTY_SET_GUID;
+    ObjTypeList[4].Sbz = 0;
+    ObjTypeList[4].ObjectType = &ChildObjectType4;
+
+    ObjTypeList[5].Level = ACCESS_PROPERTY_GUID;
+    ObjTypeList[5].Sbz = 0;
+    ObjTypeList[5].ObjectType = &ChildObjectType5;
+
+    /*
+     * Admins shouldn't be able to read from the main object.
+     * NtAccessCheckByTypeResultList will return partial rights
+     * that have been granted to the caller even if the caller
+     * did not get all the rights he wanted.
+     */
+    Status = NtAccessCheckByTypeResultList(&Sd,
+                                           NULL,
+                                           Token,
+                                           KEY_READ,
+                                           ObjTypeList,
+                                           RTL_NUMBER_OF(ObjTypeList),
+                                           &RegMapping,
+                                           PrivilegeSet,
+                                           &PrivilegeSetLength,
+                                           GrantedAccess,
+                                           AccessStatus);
+    ok_hex(Status, STATUS_SUCCESS);
+
+    PrintAccessStatusAndGrantedAccess(AccessStatus, GrantedAccess, 
RTL_NUMBER_OF(ObjTypeList));
+    for (i = 0; i < RTL_NUMBER_OF(ObjTypeList); i++)
+    {
+        ok(AccessStatus[i] == STATUS_ACCESS_DENIED, "Expected 
STATUS_ACCESS_DENIED but got 0x%08lx\n", AccessStatus[i]);
+        ok(GrantedAccess[i] == READ_CONTROL, "Expected READ_CONTROL as given 
partial right but got 0x%08lx\n", GrantedAccess[i]);
+    }
+
+    /* Everyone else can't write into the child object */
+    Status = NtAccessCheckByTypeResultList(&Sd,
+                                           NULL,
+                                           Token,
+                                           KEY_WRITE,
+                                           ObjTypeList,
+                                           RTL_NUMBER_OF(ObjTypeList),
+                                           &RegMapping,
+                                           PrivilegeSet,
+                                           &PrivilegeSetLength,
+                                           GrantedAccess,
+                                           AccessStatus);
+    ok_hex(Status, STATUS_SUCCESS);
+
+    PrintAccessStatusAndGrantedAccess(AccessStatus, GrantedAccess, 
RTL_NUMBER_OF(ObjTypeList));
+    for (i = 0; i < RTL_NUMBER_OF(ObjTypeList); i++)
+    {
+        ok(AccessStatus[i] == STATUS_ACCESS_DENIED, "Expected 
STATUS_ACCESS_DENIED but got 0x%08lx\n", AccessStatus[i]);
+        ok(GrantedAccess[i] == READ_CONTROL, "Expected READ_CONTROL as given 
partial right but got 0x%08lx\n", GrantedAccess[i]);
+    }
+
+Quit:
+    if (Dacl)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
+    }
+
+    if (Token)
+    {
+        NtClose(Token);
+    }
+
+    if (UsersSid)
+    {
+        RtlFreeSid(UsersSid);
+    }
+
+    if (AdminSid)
+    {
+        RtlFreeSid(AdminSid);
+    }
+
+    if (EveryoneSid)
+    {
+        RtlFreeSid(EveryoneSid);
+    }
+
+    if (PrivilegeSet)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, PrivilegeSet);
+    }
+}
+
+START_TEST(NtAccessCheckByTypeResultList)
+{
+    ParamValidationNoObjsList();
+    GrantedAccessTests();
+    DenyAccessTests();
+}
diff --git a/modules/rostests/apitests/ntdll/testlist.c 
b/modules/rostests/apitests/ntdll/testlist.c
index 321b8cddf4b..7f80f42420b 100644
--- a/modules/rostests/apitests/ntdll/testlist.c
+++ b/modules/rostests/apitests/ntdll/testlist.c
@@ -7,6 +7,7 @@ extern void func_LdrEnumResources(void);
 extern void func_load_notifications(void);
 extern void func_NtAcceptConnectPort(void);
 extern void func_NtAccessCheckByType(void);
+extern void func_NtAccessCheckByTypeResultList(void);
 extern void func_NtAdjustGroupsToken(void);
 extern void func_NtAdjustPrivilegesToken(void);
 extern void func_NtAllocateVirtualMemory(void);
@@ -101,6 +102,7 @@ const struct test winetest_testlist[] =
     { "load_notifications",             func_load_notifications },
     { "NtAcceptConnectPort",            func_NtAcceptConnectPort },
     { "NtAccessCheckByType",            func_NtAccessCheckByType },
+    { "NtAccessCheckByTypeResultList",  func_NtAccessCheckByTypeResultList },
     { "NtAdjustGroupsToken",            func_NtAdjustGroupsToken },
     { "NtAdjustPrivilegesToken",        func_NtAdjustPrivilegesToken },
     { "NtAllocateVirtualMemory",        func_NtAllocateVirtualMemory },

Reply via email to