[KMTESTS:SE]
authorThomas Faber <thomas.faber@reactos.org>
Tue, 4 Nov 2014 22:42:15 +0000 (22:42 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Tue, 4 Nov 2014 22:42:15 +0000 (22:42 +0000)
- Add a test for SeAssignSecurity[Ex]
CORE-8745

svn path=/trunk/; revision=65258

rostests/kmtests/CMakeLists.txt
rostests/kmtests/kmtest_drv/testlist.c
rostests/kmtests/ntos_se/SeHelpers.c [new file with mode: 0644]
rostests/kmtests/ntos_se/SeInheritance.c [new file with mode: 0644]
rostests/kmtests/ntos_se/se.h [new file with mode: 0644]

index 8de380d..969ba8b 100644 (file)
@@ -71,6 +71,8 @@ list(APPEND KMTEST_DRV_SOURCE
     ntos_ob/ObType.c
     ntos_ob/ObTypes.c
     ntos_ps/PsNotify.c
+    ntos_se/SeHelpers.c
+    ntos_se/SeInheritance.c
     ntos_se/SeQueryInfoToken.c
     ${COMMON_SOURCE}
 
index f1795f0..bcf1e9b 100644 (file)
@@ -50,6 +50,7 @@ KMT_TESTFUNC Test_ObTypeClean;
 KMT_TESTFUNC Test_ObTypeNoClean;
 KMT_TESTFUNC Test_ObTypes;
 KMT_TESTFUNC Test_PsNotify;
+KMT_TESTFUNC Test_SeInheritance;
 KMT_TESTFUNC Test_SeQueryInfoToken;
 KMT_TESTFUNC Test_RtlAvlTree;
 KMT_TESTFUNC Test_RtlException;
@@ -107,6 +108,7 @@ const KMT_TEST TestList[] =
     { "-ObTypeNoClean",                     Test_ObTypeNoClean },
     { "ObTypes",                            Test_ObTypes },
     { "PsNotify",                           Test_PsNotify },
+    { "SeInheritance",                      Test_SeInheritance },
     { "-SeQueryInfoToken",                  Test_SeQueryInfoToken },
     { "RtlAvlTreeKM",                       Test_RtlAvlTree },
     { "RtlExceptionKM",                     Test_RtlException },
diff --git a/rostests/kmtests/ntos_se/SeHelpers.c b/rostests/kmtests/ntos_se/SeHelpers.c
new file mode 100644 (file)
index 0000000..c6575a8
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Kernel-Mode Test Suite Helper functions for Se tests
+ * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
+ */
+
+#include <kmt_test.h>
+#include "se.h"
+
+NTSTATUS
+RtlxAddAuditAccessAceEx(
+    _Inout_ PACL Acl,
+    _In_ ULONG Revision,
+    _In_ ULONG Flags,
+    _In_ ACCESS_MASK AccessMask,
+    _In_ PSID Sid,
+    _In_ BOOLEAN Success,
+    _In_ BOOLEAN Failure)
+{
+    NTSTATUS Status;
+    USHORT AceSize;
+    PSYSTEM_AUDIT_ACE Ace;
+
+    if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
+    if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG;
+
+    AceSize = FIELD_OFFSET(SYSTEM_AUDIT_ACE, SidStart) + RtlLengthSid(Sid);
+    Ace = ExAllocatePoolWithTag(PagedPool, AceSize, 'cAmK');
+    if (!Ace)
+        return STATUS_INSUFFICIENT_RESOURCES;
+    Ace->Header.AceType = SYSTEM_AUDIT_ACE_TYPE;
+    Ace->Header.AceFlags = Flags;
+    Ace->Header.AceSize = AceSize;
+    Ace->Mask = AccessMask;
+    Status = RtlCopySid(AceSize - FIELD_OFFSET(SYSTEM_AUDIT_ACE, SidStart),
+                        (PSID)&Ace->SidStart,
+                        Sid);
+    ASSERT(NT_SUCCESS(Status));
+    if (NT_SUCCESS(Status))
+    {
+        Status = RtlAddAce(Acl,
+                           Revision,
+                           MAXULONG,
+                           Ace,
+                           AceSize);
+    }
+    ExFreePoolWithTag(Ace, 'cAmK');
+    return Status;
+}
+
+VOID
+CheckSid__(
+    _In_ PSID Sid,
+    _In_ ULONG SidSize,
+    _In_ PISID ExpectedSid,
+    _In_ PCSTR FileAndLine)
+{
+    BOOLEAN Okay;
+    ULONG Length;
+
+    KmtOk(Sid != NULL, FileAndLine, "Sid is NULL\n");
+    if (KmtSkip(Sid != NULL, FileAndLine, "No Sid\n"))
+        return;
+    if (KmtSkip(SidSize >= sizeof(ULONG), FileAndLine, "Sid too small: %lu\n", SidSize))
+        return;
+    Okay = RtlValidSid(Sid);
+    KmtOk(Okay == TRUE, FileAndLine, "Invalid Sid\n");
+    if (KmtSkip(Okay, FileAndLine, "Invalid Sid\n"))
+        return;
+
+    Length = RtlLengthSid(Sid);
+    KmtOk(SidSize >= Length, FileAndLine, "SidSize %lu too small, need %lu\n", SidSize, Length);
+    if (KmtSkip(SidSize >= Length, FileAndLine, "Sid too small\n"))
+        return;
+    Okay = RtlEqualSid(Sid, ExpectedSid);
+    KmtOk(Okay, FileAndLine, "Sids %p and %p not equal\n", Sid, ExpectedSid);
+    if (!Okay)
+    {
+        WCHAR Buffer1[128];
+        WCHAR Buffer2[128];
+        UNICODE_STRING SidString1, SidString2;
+        RtlInitEmptyUnicodeString(&SidString1, Buffer1, sizeof(Buffer1));
+        RtlInitEmptyUnicodeString(&SidString2, Buffer2, sizeof(Buffer2));
+        (void)RtlConvertSidToUnicodeString(&SidString1, Sid, FALSE);
+        (void)RtlConvertSidToUnicodeString(&SidString2, ExpectedSid, FALSE);
+        KmtOk(0, FileAndLine, "Got %wZ, expected %wZ\n", &SidString1, &SidString2);
+    }
+}
+
+VOID
+VCheckAcl__(
+    _In_ PACL Acl,
+    _In_ ULONG AceCount,
+    _In_ PCSTR FileAndLine,
+    _In_ va_list Arguments)
+{
+    ULONG i;
+    ULONG Offset;
+    PACE_HEADER AceHeader;
+    INT AceType;
+    INT AceFlags;
+    ACCESS_MASK Mask;
+    PISID Sid;
+    PACCESS_ALLOWED_ACE AllowedAce;
+    PACCESS_DENIED_ACE DeniedAce;
+    PSYSTEM_AUDIT_ACE AuditAce;
+
+    KmtOk(Acl != NULL, FileAndLine, "Acl is NULL\n");
+    if (KmtSkip(Acl != NULL, FileAndLine, "No ACL\n"))
+        return;
+    KmtOk((ULONG_PTR)Acl % sizeof(ULONG) == 0, FileAndLine, "Unaligned ACL %p\n", Acl);
+    KmtOk(Acl->AclRevision == ACL_REVISION, FileAndLine, "AclRevision is %u\n", Acl->AclRevision);
+    KmtOk(Acl->Sbz1 == 0, FileAndLine, "Sbz1 is %u\n", Acl->Sbz1);
+    KmtOk(Acl->Sbz2 == 0, FileAndLine, "Sbz2 is %u\n", Acl->Sbz2);
+    KmtOk(Acl->AclSize >= sizeof(*Acl), FileAndLine, "AclSize too small: %u\n", Acl->AclSize);
+    KmtOk(Acl->AceCount == AceCount, FileAndLine, "AceCount is %u, expected %lu\n", Acl->AceCount, AceCount);
+    Offset = sizeof(*Acl);
+    for (i = 0; i < Acl->AceCount; i++)
+    {
+        KmtOk(Acl->AclSize >= Offset + sizeof(*AceHeader), FileAndLine, "AclSize too small (%u) at Offset %lu, ACE #%lu\n", Acl->AclSize, Offset, i);
+        if (Acl->AclSize < Offset + sizeof(*AceHeader))
+            break;
+        AceHeader = (PACE_HEADER)((PUCHAR)Acl + Offset);
+        KmtOk((ULONG_PTR)AceHeader % sizeof(ULONG) == 0, FileAndLine, "[%lu] Unaligned ACE %p\n", i, AceHeader);
+        KmtOk(AceHeader->AceSize % sizeof(ULONG) == 0, FileAndLine, "[%lu] Unaligned ACE size %u\n", i, AceHeader->AceSize);
+        KmtOk(Acl->AclSize >= Offset + AceHeader->AceSize, FileAndLine, "[%lu] AclSize too small (%u) at Offset %lu\n", i, Acl->AclSize, Offset);
+        if (Acl->AclSize < Offset + AceHeader->AceSize)
+            break;
+        Offset += AceHeader->AceSize;
+        if (i >= AceCount)
+            continue;
+        AceType = va_arg(Arguments, INT);
+        AceFlags = va_arg(Arguments, INT);
+        KmtOk(AceHeader->AceType == AceType, FileAndLine, "[%lu] AceType is %u, expected %u\n", i, AceHeader->AceType, AceType);
+        KmtOk(AceHeader->AceFlags == AceFlags, FileAndLine, "[%lu] AceFlags is 0x%x, expected 0x%x\n", i, AceHeader->AceFlags, AceFlags);
+        if (AceType == ACCESS_ALLOWED_ACE_TYPE)
+        {
+            Sid = va_arg(Arguments, PSID);
+            Mask = va_arg(Arguments, INT);
+            KmtOk(AceHeader->AceSize >= sizeof(*AllowedAce), FileAndLine, "[%lu] AllowedAce AceSize too small: %u\n", i, AceHeader->AceSize);
+            if (AceHeader->AceSize < sizeof(*AllowedAce))
+                continue;
+            AllowedAce = (PACCESS_ALLOWED_ACE)AceHeader;
+            KmtOk(AllowedAce->Mask == Mask, FileAndLine, "[%lu] AllowedAce Mask is 0x%lx, expected 0x%lx\n", i, AllowedAce->Mask, Mask);
+            CheckSid__((PSID)&AllowedAce->SidStart,
+                       AceHeader->AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart),
+                       Sid,
+                       FileAndLine);
+        }
+        else if (AceType == ACCESS_DENIED_ACE_TYPE)
+        {
+            Sid = va_arg(Arguments, PSID);
+            Mask = va_arg(Arguments, INT);
+            KmtOk(AceHeader->AceSize >= sizeof(*DeniedAce), FileAndLine, "[%lu] DeniedAce AceSize too small: %u\n", i, AceHeader->AceSize);
+            if (AceHeader->AceSize < sizeof(*DeniedAce))
+                continue;
+            DeniedAce = (PACCESS_DENIED_ACE)AceHeader;
+            KmtOk(DeniedAce->Mask == Mask, FileAndLine, "[%lu] DeniedAce Mask is 0x%lx, expected 0x%lx\n", i, DeniedAce->Mask, Mask);
+            CheckSid__((PSID)&DeniedAce->SidStart,
+                       AceHeader->AceSize - FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart),
+                       Sid,
+                       FileAndLine);
+        }
+        else if (AceType == SYSTEM_AUDIT_ACE_TYPE)
+        {
+            Sid = va_arg(Arguments, PSID);
+            Mask = va_arg(Arguments, INT);
+            KmtOk(AceHeader->AceSize >= sizeof(*AuditAce), FileAndLine, "[%lu] AuditAce AceSize too small: %u\n", i, AceHeader->AceSize);
+            if (AceHeader->AceSize < sizeof(*AuditAce))
+                continue;
+            AuditAce = (PSYSTEM_AUDIT_ACE)AceHeader;
+            KmtOk(AuditAce->Mask == Mask, FileAndLine, "[%lu] AuditAce Mask is 0x%lx, expected 0x%lx\n", i, AuditAce->Mask, Mask);
+            CheckSid__((PSID)&AuditAce->SidStart,
+                       AceHeader->AceSize - FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart),
+                       Sid,
+                       FileAndLine);
+        }
+    }
+}
+
+VOID
+CheckAcl__(
+    _In_ PACL Acl,
+    _In_ ULONG AceCount,
+    _In_ PCSTR FileAndLine,
+    ...)
+{
+    va_list Arguments;
+
+    va_start(Arguments, FileAndLine);
+    VCheckAcl__(Acl, AceCount, FileAndLine, Arguments);
+    va_end(Arguments);
+}
diff --git a/rostests/kmtests/ntos_se/SeInheritance.c b/rostests/kmtests/ntos_se/SeInheritance.c
new file mode 100644 (file)
index 0000000..7733119
--- /dev/null
@@ -0,0 +1,880 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Kernel-Mode Test for object security inheritance
+ * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
+ */
+
+#include <kmt_test.h>
+#include "se.h"
+
+static GENERIC_MAPPING GenericMapping =
+{
+    STANDARD_RIGHTS_READ    | 0x1001,
+    STANDARD_RIGHTS_WRITE   | 0x2002,
+    STANDARD_RIGHTS_EXECUTE | 0x4004,
+    STANDARD_RIGHTS_ALL     | 0x800F,
+};
+
+static
+VOID
+TestSeAssignSecurity(
+    _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+    NTSTATUS Status;
+    PTOKEN Token;
+    PSECURITY_DESCRIPTOR SecurityDescriptor;
+    SECURITY_DESCRIPTOR ParentDescriptor;
+    SECURITY_DESCRIPTOR ExplicitDescriptor;
+    ACL EmptyAcl;
+    PACL Acl;
+    PACL Acl2;
+    ULONG AclSize;
+    ULONG UsingDefault;
+    ULONG CanInherit;
+    ULONG AceFlags;
+    ULONG AceFlags2;
+    ULONG Access;
+    PSID GenericSid;
+    PSID GenericSid2;
+    ACCESS_MASK GenericMask;
+    ACCESS_MASK GenericMask2;
+    PSID SpecificSid;
+    ACCESS_MASK SpecificMask;
+    ACCESS_MASK SpecificMask2;
+    BOOLEAN ParentUsable;
+
+    Token = SubjectContext->PrimaryToken;
+    CheckAcl(Token->DefaultDacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    GENERIC_ALL,
+                                    ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    GENERIC_READ | GENERIC_EXECUTE | STANDARD_RIGHTS_READ);
+    CheckSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid, NO_SIZE, SeExports->SeAliasAdminsSid);
+    CheckSid(Token->PrimaryGroup, NO_SIZE, SeExports->SeLocalSystemSid);
+// Flags with no effect on current tests: SEF_SACL_AUTO_INHERIT, SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT
+#define StartTestAssign(Parent, Explicit, IsDir, GotDacl, GotSacl)  \
+    SecurityDescriptor = NULL;                                      \
+    Status = SeAssignSecurity  (Parent,                             \
+                                Explicit,                           \
+                                &SecurityDescriptor,                \
+                                /*NULL,*/                           \
+                                IsDir,                              \
+                                /*0,*/                              \
+                                SubjectContext,                     \
+                                &GenericMapping,                    \
+                                PagedPool);                         \
+    ok_eq_hex(Status, STATUS_SUCCESS);                              \
+    if (!skip(NT_SUCCESS(Status), "No security\n"))                 \
+    {                                                               \
+        PACL Dacl, Sacl;                                            \
+        PSID Owner, Group;                                          \
+        BOOLEAN Present;                                            \
+        BOOLEAN DaclDefaulted, SaclDefaulted;                       \
+        BOOLEAN OwnerDefaulted, GroupDefaulted;                     \
+        Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,   \
+                                              &Present,             \
+                                              &Dacl,                \
+                                              &DaclDefaulted);      \
+        ok_eq_hex(Status, STATUS_SUCCESS);                          \
+        ok_eq_uint(Present, GotDacl);                               \
+        if (!NT_SUCCESS(Status) || !Present)                        \
+            Dacl = NULL;                                            \
+        Status = RtlGetSaclSecurityDescriptor(SecurityDescriptor,   \
+                                              &Present,             \
+                                              &Sacl,                \
+                                              &SaclDefaulted);      \
+        ok_eq_hex(Status, STATUS_SUCCESS);                          \
+        ok_eq_uint(Present, GotSacl);                               \
+        if (!NT_SUCCESS(Status) || !Present)                        \
+            Sacl = NULL;                                            \
+        Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,  \
+                                               &Owner,              \
+                                               &OwnerDefaulted);    \
+        ok_eq_hex(Status, STATUS_SUCCESS);                          \
+        if (skip(NT_SUCCESS(Status), "No owner\n"))                 \
+            Owner = NULL;                                           \
+        Status = RtlGetGroupSecurityDescriptor(SecurityDescriptor,  \
+                                               &Group,              \
+                                               &GroupDefaulted);    \
+        ok_eq_hex(Status, STATUS_SUCCESS);                          \
+        if (skip(NT_SUCCESS(Status), "No group\n"))                 \
+            Group = NULL;
+
+#define EndTestAssign()                                             \
+        SeDeassignSecurity(&SecurityDescriptor);                    \
+    }
+#define StartTestAssignLoop(Parent, Explicit)                                       \
+    {                                                                               \
+        BOOLEAN IsDir;                                                              \
+        BOOLEAN UsingParent;                                                        \
+        BOOLEAN UsingExplicit;                                                      \
+        for (IsDir = FALSE; IsDir <= TRUE; IsDir++)                                 \
+        {                                                                           \
+            for (UsingParent = FALSE; UsingParent <= TRUE; UsingParent++)           \
+            {                                                                       \
+                for (UsingExplicit = FALSE; UsingExplicit <= TRUE; UsingExplicit++) \
+                {                                                                   \
+                    StartTestAssign(UsingParent ? Parent : NULL,                    \
+                                    UsingExplicit ? Explicit : NULL,                \
+                                    IsDir,                                          \
+                                    TRUE,                                           \
+                                    FALSE)
+#define EndTestAssignLoop()                                                         \
+                    EndTestAssign()                                                 \
+                }                                                                   \
+            }                                                                       \
+        }                                                                           \
+    }
+#define TestAssignExpectDefault(Parent, Explicit, IsDir)                                                                \
+    StartTestAssign(Parent, Explicit, IsDir, TRUE, FALSE)                                                               \
+        ok_eq_uint(DaclDefaulted, FALSE);                                                                               \
+        CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,     \
+                          ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);   \
+        ok_eq_uint(OwnerDefaulted, FALSE);                                                                              \
+        CheckSid(Owner, NO_SIZE, Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);                                   \
+        ok_eq_uint(GroupDefaulted, FALSE);                                                                              \
+        CheckSid(Group, NO_SIZE, Token->PrimaryGroup);                                                                  \
+    EndTestAssign()
+#define TestAssignExpectDefaultAll()                                        \
+    TestAssignExpectDefault(&ParentDescriptor, NULL, FALSE)                 \
+    TestAssignExpectDefault(&ParentDescriptor, NULL, TRUE)                  \
+    TestAssignExpectDefault(NULL, &ExplicitDescriptor, FALSE)               \
+    TestAssignExpectDefault(NULL, &ExplicitDescriptor, TRUE)                \
+    TestAssignExpectDefault(&ParentDescriptor, &ExplicitDescriptor, FALSE)  \
+    TestAssignExpectDefault(&ParentDescriptor, &ExplicitDescriptor, TRUE)
+
+    TestAssignExpectDefault(NULL, NULL, FALSE)
+    TestAssignExpectDefault(NULL, NULL, TRUE)
+
+    /* Empty parent/explicit descriptors */
+    Status = RtlCreateSecurityDescriptor(&ParentDescriptor,
+                                         SECURITY_DESCRIPTOR_REVISION);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    Status = RtlCreateSecurityDescriptor(&ExplicitDescriptor,
+                                         SECURITY_DESCRIPTOR_REVISION);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    TestAssignExpectDefaultAll()
+
+    /* NULL DACL in parent/explicit descriptor */
+    for (UsingDefault = FALSE; UsingDefault <= TRUE; UsingDefault++)
+    {
+        Status = RtlSetDaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              NULL,
+                                              UsingDefault);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              NULL,
+                                              UsingDefault);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        StartTestAssignLoop(&ParentDescriptor, &ExplicitDescriptor)
+            //trace("Explicit %u, Parent %u, Dir %u, Default %u\n", UsingExplicit, UsingParent, IsDir, UsingDefault);
+            ok_eq_uint(DaclDefaulted, FALSE);
+            if (UsingExplicit)
+            {
+                ok(Dacl == NULL, "Dacl = %p\n", Dacl);
+            }
+            else
+            {
+                CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                                  ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            }
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, SeExports->SeAliasAdminsSid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, SeExports->SeLocalSystemSid);
+        EndTestAssignLoop()
+    }
+
+    /* Empty default DACL in parent/explicit descriptor */
+    for (UsingDefault = FALSE; UsingDefault <= TRUE; UsingDefault++)
+    {
+        Status = RtlCreateAcl(&EmptyAcl, sizeof(EmptyAcl), ACL_REVISION);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              &EmptyAcl,
+                                              UsingDefault);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              &EmptyAcl,
+                                              UsingDefault);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        StartTestAssignLoop(&ParentDescriptor, &ExplicitDescriptor)
+            //trace("Explicit %u, Parent %u, Dir %u, Default %u\n", UsingExplicit, UsingParent, IsDir, UsingDefault);
+            ok_eq_uint(DaclDefaulted, FALSE);
+            if (UsingExplicit)
+            {
+                CheckAcl(Dacl, 0);
+            }
+            else
+            {
+                CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                                  ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            }
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, SeExports->SeAliasAdminsSid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, SeExports->SeLocalSystemSid);
+        EndTestAssignLoop()
+    }
+
+
+    AclSize = sizeof(ACL) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(SeExports->SeWorldSid);
+    Acl = ExAllocatePoolWithTag(PagedPool, AclSize, 'ASmK');
+    if (skip(Acl != NULL, "Out of memory\n"))
+        return;
+
+    Acl2 = ExAllocatePoolWithTag(PagedPool, AclSize, 'ASmK');
+    if (skip(Acl2 != NULL, "Out of memory\n"))
+    {
+        ExFreePoolWithTag(Acl, 'ASmK');
+        return;
+    }
+
+    /* Simple DACL in parent/explicit descriptor */
+    for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+    {
+        Status = RtlCreateAcl(Acl, AclSize, ACL_REVISION);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlAddAccessAllowedAceEx(Acl, ACL_REVISION, 0, READ_CONTROL, SeExports->SeWorldSid);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 1));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 2));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        StartTestAssignLoop(&ParentDescriptor, &ExplicitDescriptor)
+            //trace("Explicit %u, Parent %u, Dir %u, Default %u\n", UsingExplicit, UsingParent, IsDir, UsingDefault);
+            ok_eq_uint(DaclDefaulted, FALSE);
+            if (UsingExplicit)
+            {
+                CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeWorldSid,          READ_CONTROL);
+            }
+            else
+            {
+                CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                                  ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            }
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, SeExports->SeAliasAdminsSid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, SeExports->SeLocalSystemSid);
+        EndTestAssignLoop()
+    }
+
+    /* Object-inheritable DACL in parent/explicit descriptor */
+    for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+    {
+        Status = RtlCreateAcl(Acl, AclSize, ACL_REVISION);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlAddAccessAllowedAceEx(Acl, ACL_REVISION, OBJECT_INHERIT_ACE, READ_CONTROL, SeExports->SeWorldSid);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 1));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 2));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        StartTestAssignLoop(&ParentDescriptor, &ExplicitDescriptor)
+            //trace("Explicit %u, Parent %u, Dir %u, Default %u\n", UsingExplicit, UsingParent, IsDir, UsingDefault);
+            ok_eq_uint(DaclDefaulted, FALSE);
+            if (UsingExplicit && (!UsingParent || !FlagOn(UsingDefault, 2)))
+            {
+                CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE, SeExports->SeWorldSid, READ_CONTROL);
+            }
+            else if (UsingParent)
+            {
+                CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, IsDir ? INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE : 0, SeExports->SeWorldSid, READ_CONTROL);
+            }
+            else
+            {
+                CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                                  ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            }
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, SeExports->SeAliasAdminsSid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, SeExports->SeLocalSystemSid);
+        EndTestAssignLoop()
+    }
+
+    /* Container-inheritable DACL in parent/explicit descriptor */
+    for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+    {
+        Status = RtlCreateAcl(Acl, AclSize, ACL_REVISION);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlAddAccessAllowedAceEx(Acl, ACL_REVISION, CONTAINER_INHERIT_ACE, READ_CONTROL, SeExports->SeWorldSid);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 1));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 2));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        StartTestAssignLoop(&ParentDescriptor, &ExplicitDescriptor)
+            //trace("Explicit %u, Parent %u, Dir %u, Default %u\n", UsingExplicit, UsingParent, IsDir, UsingDefault);
+            ok_eq_uint(DaclDefaulted, FALSE);
+            if (UsingExplicit || (UsingParent && IsDir))
+            {
+                CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, SeExports->SeWorldSid, READ_CONTROL);
+            }
+            else
+            {
+                CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                                  ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            }
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, SeExports->SeAliasAdminsSid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, SeExports->SeLocalSystemSid);
+        EndTestAssignLoop()
+    }
+
+    /* Fully inheritable DACL in parent/explicit descriptor */
+    for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+    {
+        Status = RtlCreateAcl(Acl, AclSize, ACL_REVISION);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlAddAccessAllowedAceEx(Acl, ACL_REVISION, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE, READ_CONTROL, SeExports->SeWorldSid);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 1));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetDaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 2));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        StartTestAssignLoop(&ParentDescriptor, &ExplicitDescriptor)
+            //trace("Explicit %u, Parent %u, Dir %u, Default %u\n", UsingExplicit, UsingParent, IsDir, UsingDefault);
+            ok_eq_uint(DaclDefaulted, FALSE);
+            if (UsingExplicit && (!UsingParent || !FlagOn(UsingDefault, 2)))
+            {
+                CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE, SeExports->SeWorldSid, READ_CONTROL);
+            }
+            else if (UsingParent)
+            {
+                CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, IsDir ? OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE : 0, SeExports->SeWorldSid, READ_CONTROL);
+            }
+            else
+            {
+                CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                                  ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            }
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, SeExports->SeAliasAdminsSid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, SeExports->SeLocalSystemSid);
+        EndTestAssignLoop()
+    }
+
+    /* Different DACLs in parent and explicit descriptors */
+    for (Access = 0; Access <= 1; Access++)
+    {
+        if (Access == 1)
+        {
+            GenericSid = SeExports->SeCreatorOwnerSid;
+            SpecificSid = SeExports->SeAliasAdminsSid;
+            GenericMask = GENERIC_READ;
+            SpecificMask = STANDARD_RIGHTS_READ | 0x0001;
+            GenericSid2 = SeExports->SeCreatorGroupSid;
+            GenericMask2 = GENERIC_EXECUTE;
+            SpecificMask2 = STANDARD_RIGHTS_EXECUTE | 0x0004;
+        }
+        else
+        {
+            GenericSid = SeExports->SeWorldSid;
+            SpecificSid = SeExports->SeWorldSid;
+            GenericMask = READ_CONTROL;
+            SpecificMask = READ_CONTROL;
+            GenericSid2 = SeExports->SeLocalSystemSid;
+            GenericMask2 = SYNCHRONIZE;
+            SpecificMask2 = SYNCHRONIZE;
+        }
+        for (CanInherit = 0; CanInherit <= 255; CanInherit++)
+        {
+            for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+            {
+                Status = RtlCreateAcl(Acl, AclSize, ACL_REVISION);
+                ok_eq_hex(Status, STATUS_SUCCESS);
+                AceFlags = CanInherit & 0xf;
+                Status = RtlAddAccessAllowedAceEx(Acl, ACL_REVISION, AceFlags, GenericMask, GenericSid);
+                ok_eq_hex(Status, STATUS_SUCCESS);
+                Status = RtlCreateAcl(Acl2, AclSize, ACL_REVISION);
+                ok_eq_hex(Status, STATUS_SUCCESS);
+                AceFlags2 = CanInherit >> 4;
+                Status = RtlAddAccessAllowedAceEx(Acl2, ACL_REVISION, AceFlags2, GenericMask2, GenericSid2);
+                ok_eq_hex(Status, STATUS_SUCCESS);
+                Status = RtlSetDaclSecurityDescriptor(&ParentDescriptor,
+                                                      TRUE,
+                                                      Acl,
+                                                      BooleanFlagOn(UsingDefault, 1));
+                ok_eq_hex(Status, STATUS_SUCCESS);
+                Status = RtlSetDaclSecurityDescriptor(&ExplicitDescriptor,
+                                                      TRUE,
+                                                      Acl2,
+                                                      BooleanFlagOn(UsingDefault, 2));
+                ok_eq_hex(Status, STATUS_SUCCESS);
+                StartTestAssignLoop(&ParentDescriptor, &ExplicitDescriptor)
+                    //trace("Explicit %u, Parent %u, Dir %u, Default %u, Inherit %u, Access %u\n", UsingExplicit, UsingParent, IsDir, UsingDefault, CanInherit, Access);
+                    ok_eq_uint(DaclDefaulted, FALSE);
+                    ParentUsable = UsingParent;
+                    if (!IsDir && !FlagOn(AceFlags, OBJECT_INHERIT_ACE))
+                        ParentUsable = FALSE;
+                    else if (IsDir && !FlagOn(AceFlags, CONTAINER_INHERIT_ACE) &&
+                             (!FlagOn(AceFlags, OBJECT_INHERIT_ACE) || FlagOn(AceFlags, NO_PROPAGATE_INHERIT_ACE)))
+                        ParentUsable = FALSE;
+
+                    if (UsingExplicit && (!FlagOn(UsingDefault, 2) || !ParentUsable))
+                    {
+                        CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, AceFlags2, GenericSid2, FlagOn(AceFlags2, INHERIT_ONLY_ACE) ? GenericMask2 : SpecificMask2);
+                    }
+                    else if (ParentUsable)
+                    {
+                        if (IsDir && !FlagOn(AceFlags, NO_PROPAGATE_INHERIT_ACE))
+                        {
+                            if (FlagOn(AceFlags, CONTAINER_INHERIT_ACE) && (SpecificMask != GenericMask || SpecificSid != GenericSid))
+                                CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SpecificSid, SpecificMask,
+                                                  ACCESS_ALLOWED_ACE_TYPE, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE), GenericSid, GenericMask);
+                            else
+                                CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, (FlagOn(AceFlags, CONTAINER_INHERIT_ACE) ? 0 : INHERIT_ONLY_ACE) |
+                                                                           (AceFlags & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)), GenericSid, GenericMask);
+                        }
+                        else
+                            CheckAcl(Dacl, 1, ACCESS_ALLOWED_ACE_TYPE, 0, SpecificSid, SpecificMask);
+                    }
+                    else
+                    {
+                        CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid, STANDARD_RIGHTS_ALL | 0x800F,
+                                          ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid, STANDARD_RIGHTS_READ | 0x0005);
+                    }
+                    ok_eq_uint(OwnerDefaulted, FALSE);
+                    CheckSid(Owner, NO_SIZE, SeExports->SeAliasAdminsSid);
+                    ok_eq_uint(GroupDefaulted, FALSE);
+                    CheckSid(Group, NO_SIZE, SeExports->SeLocalSystemSid);
+                EndTestAssignLoop()
+            }
+        }
+    }
+
+    /* NULL parameters */
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+    KmtStartSeh()
+        Status = SeAssignSecurity(NULL,
+                                  NULL,
+                                  NULL,
+                                  FALSE,
+                                  SubjectContext,
+                                  &GenericMapping,
+                                  PagedPool);
+    KmtEndSeh(STATUS_ACCESS_VIOLATION);
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+
+    SecurityDescriptor = KmtInvalidPointer;
+    KmtStartSeh()
+        Status = SeAssignSecurity(NULL,
+                                  NULL,
+                                  &SecurityDescriptor,
+                                  FALSE,
+                                  NULL,
+                                  &GenericMapping,
+                                  PagedPool);
+        ok_eq_hex(Status, STATUS_NO_TOKEN);
+    KmtEndSeh(STATUS_SUCCESS);
+    ok_eq_pointer(SecurityDescriptor, NULL);
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+    KmtStartSeh()
+        Status = SeAssignSecurity(NULL,
+                                  NULL,
+                                  NULL,
+                                  FALSE,
+                                  NULL,
+                                  &GenericMapping,
+                                  PagedPool);
+    KmtEndSeh(STATUS_ACCESS_VIOLATION);
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+
+    /* Test with Token == NULL */
+    if (1)
+    {
+        /* Crash in SeLockSubjectContext while holding a critical region */
+        SubjectContext->PrimaryToken = NULL;
+        KmtStartSeh()
+            SecurityDescriptor = KmtInvalidPointer;
+            Status = SeAssignSecurity(NULL,
+                                      NULL,
+                                      &SecurityDescriptor,
+                                      FALSE,
+                                      SubjectContext,
+                                      &GenericMapping,
+                                      PagedPool);
+        KmtEndSeh(STATUS_ACCESS_VIOLATION)
+        ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+        KeLeaveCriticalRegion();
+        ok_eq_pointer(SecurityDescriptor, KmtInvalidPointer);
+        SubjectContext->PrimaryToken = Token;
+    }
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+
+    /* Test with NULL owner in Token */
+    if (1)
+    {
+        /* Crash after locking the subject context */
+        PSID OldOwner;
+        OldOwner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
+        Token->UserAndGroups[Token->DefaultOwnerIndex].Sid = NULL;
+        KmtStartSeh()
+            SecurityDescriptor = KmtInvalidPointer;
+            Status = SeAssignSecurity(NULL,
+                                      NULL,
+                                      &SecurityDescriptor,
+                                      FALSE,
+                                      SubjectContext,
+                                      &GenericMapping,
+                                      PagedPool);
+        KmtEndSeh(STATUS_ACCESS_VIOLATION)
+        ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+        SeUnlockSubjectContext(SubjectContext);
+        ok_eq_pointer(SecurityDescriptor, KmtInvalidPointer);
+        Token->UserAndGroups[Token->DefaultOwnerIndex].Sid = OldOwner;
+    }
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+
+    /* Test with NULL group in Token */
+    if (1)
+    {
+        PSID OldGroup;
+        OldGroup = Token->PrimaryGroup;
+        Token->PrimaryGroup = NULL;
+        KmtStartSeh()
+            SecurityDescriptor = KmtInvalidPointer;
+            Status = SeAssignSecurity(NULL,
+                                      NULL,
+                                      &SecurityDescriptor,
+                                      FALSE,
+                                      SubjectContext,
+                                      &GenericMapping,
+                                      PagedPool);
+            ok_eq_hex(Status, STATUS_INVALID_PRIMARY_GROUP);
+            ok_eq_pointer(SecurityDescriptor, NULL);
+            SeDeassignSecurity(&SecurityDescriptor);
+        KmtEndSeh(STATUS_SUCCESS);
+        Token->PrimaryGroup = OldGroup;
+    }
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+
+    /* Test with NULL DACL in Token */
+    if (1)
+    {
+        PACL OldDacl;
+        OldDacl = Token->DefaultDacl;
+        Token->DefaultDacl = NULL;
+        KmtStartSeh()
+        StartTestAssign(NULL, NULL, FALSE, FALSE, FALSE)
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, Token->PrimaryGroup);
+        EndTestAssign()
+        KmtEndSeh(STATUS_SUCCESS);
+        Token->DefaultDacl = OldDacl;
+    }
+    ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
+
+    /* SEF_DEFAULT_OWNER_FROM_PARENT/SEF_DEFAULT_GROUP_FROM_PARENT */
+    SecurityDescriptor = KmtInvalidPointer;
+    Status = SeAssignSecurityEx(NULL,
+                                NULL,
+                                &SecurityDescriptor,
+                                NULL,
+                                FALSE,
+                                SEF_DEFAULT_OWNER_FROM_PARENT,
+                                SubjectContext,
+                                &GenericMapping,
+                                PagedPool);
+    ok_eq_hex(Status, STATUS_INVALID_OWNER);
+    ok_eq_pointer(SecurityDescriptor, NULL);
+    SeDeassignSecurity(&SecurityDescriptor);
+    SecurityDescriptor = KmtInvalidPointer;
+    Status = SeAssignSecurityEx(NULL,
+                                NULL,
+                                &SecurityDescriptor,
+                                NULL,
+                                FALSE,
+                                SEF_DEFAULT_GROUP_FROM_PARENT,
+                                SubjectContext,
+                                &GenericMapping,
+                                PagedPool);
+    ok_eq_hex(Status, STATUS_INVALID_PRIMARY_GROUP);
+    ok_eq_pointer(SecurityDescriptor, NULL);
+    SeDeassignSecurity(&SecurityDescriptor);
+    SecurityDescriptor = KmtInvalidPointer;
+    Status = SeAssignSecurityEx(NULL,
+                                NULL,
+                                &SecurityDescriptor,
+                                NULL,
+                                FALSE,
+                                SEF_DEFAULT_OWNER_FROM_PARENT | SEF_DEFAULT_GROUP_FROM_PARENT,
+                                SubjectContext,
+                                &GenericMapping,
+                                PagedPool);
+    ok_eq_hex(Status, STATUS_INVALID_OWNER);
+    ok_eq_pointer(SecurityDescriptor, NULL);
+    SeDeassignSecurity(&SecurityDescriptor);
+
+    /* Quick test whether inheritance for SACLs behaves the same as DACLs */
+    Status = RtlSetDaclSecurityDescriptor(&ParentDescriptor,
+                                          FALSE,
+                                          NULL,
+                                          FALSE);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    Status = RtlSetDaclSecurityDescriptor(&ExplicitDescriptor,
+                                          FALSE,
+                                          NULL,
+                                          FALSE);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+    {
+        Status = RtlSetSaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              NULL,
+                                              BooleanFlagOn(UsingDefault, 1));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetSaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              NULL,
+                                              BooleanFlagOn(UsingDefault, 2));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+
+        TestAssignExpectDefault(&ParentDescriptor, NULL, FALSE)
+        TestAssignExpectDefault(&ParentDescriptor, NULL, TRUE)
+        StartTestAssign(NULL, &ExplicitDescriptor, FALSE, TRUE, TRUE)
+            ok_eq_uint(DaclDefaulted, FALSE);
+            CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                              ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            ok_eq_uint(SaclDefaulted, FALSE);
+            ok_eq_pointer(Sacl, NULL);
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, Token->PrimaryGroup);
+        EndTestAssign()
+    }
+
+    for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+    {
+        Status = RtlSetSaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              &EmptyAcl,
+                                              BooleanFlagOn(UsingDefault, 1));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetSaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              &EmptyAcl,
+                                              BooleanFlagOn(UsingDefault, 2));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+
+        TestAssignExpectDefault(&ParentDescriptor, NULL, FALSE)
+        TestAssignExpectDefault(&ParentDescriptor, NULL, TRUE)
+        StartTestAssign(NULL, &ExplicitDescriptor, FALSE, TRUE, TRUE)
+            ok_eq_uint(DaclDefaulted, FALSE);
+            CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                              ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            ok_eq_uint(SaclDefaulted, FALSE);
+            CheckAcl(Sacl, 0);
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, Token->PrimaryGroup);
+        EndTestAssign()
+    }
+
+    for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+    {
+        Status = RtlCreateAcl(Acl, AclSize, ACL_REVISION);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlxAddAuditAccessAceEx(Acl, ACL_REVISION, 0, READ_CONTROL, SeExports->SeWorldSid, TRUE, TRUE);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetSaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 1));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetSaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 2));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+
+        TestAssignExpectDefault(&ParentDescriptor, NULL, FALSE)
+        TestAssignExpectDefault(&ParentDescriptor, NULL, TRUE)
+        StartTestAssign(NULL, &ExplicitDescriptor, FALSE, TRUE, TRUE)
+            ok_eq_uint(DaclDefaulted, FALSE);
+            CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                              ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            ok_eq_uint(SaclDefaulted, FALSE);
+            CheckAcl(Sacl, 1, SYSTEM_AUDIT_ACE_TYPE, SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG, SeExports->SeWorldSid, READ_CONTROL);
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, Token->PrimaryGroup);
+        EndTestAssign()
+    }
+
+    for (UsingDefault = 0; UsingDefault <= 3; UsingDefault++)
+    {
+        Status = RtlCreateAcl(Acl, AclSize, ACL_REVISION);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlxAddAuditAccessAceEx(Acl, ACL_REVISION, OBJECT_INHERIT_ACE, READ_CONTROL, SeExports->SeCreatorOwnerSid, TRUE, TRUE);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetSaclSecurityDescriptor(&ParentDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 1));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        Status = RtlSetSaclSecurityDescriptor(&ExplicitDescriptor,
+                                              TRUE,
+                                              Acl,
+                                              BooleanFlagOn(UsingDefault, 2));
+        ok_eq_hex(Status, STATUS_SUCCESS);
+
+        StartTestAssign(&ParentDescriptor, NULL, FALSE, TRUE, TRUE)
+            ok_eq_uint(DaclDefaulted, FALSE);
+            CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                              ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            ok_eq_uint(SaclDefaulted, FALSE);
+            CheckAcl(Sacl, 1, SYSTEM_AUDIT_ACE_TYPE, SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG, Token->UserAndGroups[Token->DefaultOwnerIndex].Sid, READ_CONTROL);
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, Token->PrimaryGroup);
+        EndTestAssign()
+        StartTestAssign(NULL, &ExplicitDescriptor, FALSE, TRUE, TRUE)
+            ok_eq_uint(DaclDefaulted, FALSE);
+            CheckAcl(Dacl, 2, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,    STANDARD_RIGHTS_ALL | 0x800F,
+                              ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,    STANDARD_RIGHTS_READ | 0x0005);
+            ok_eq_uint(SaclDefaulted, FALSE);
+            CheckAcl(Sacl, 1, SYSTEM_AUDIT_ACE_TYPE, OBJECT_INHERIT_ACE | SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG, SeExports->SeCreatorOwnerSid, READ_CONTROL);
+            ok_eq_uint(OwnerDefaulted, FALSE);
+            CheckSid(Owner, NO_SIZE, Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+            ok_eq_uint(GroupDefaulted, FALSE);
+            CheckSid(Group, NO_SIZE, Token->PrimaryGroup);
+        EndTestAssign()
+    }
+
+    /* TODO: Test duplicate ACEs */
+    /* TODO: Test INHERITED_ACE flag */
+    /* TODO: Test invalid ACE flags */
+    /* TODO: Test more AutoInheritFlags values */
+
+    ExFreePoolWithTag(Acl2, 'ASmK');
+    ExFreePoolWithTag(Acl, 'ASmK');
+}
+
+static
+VOID
+NTAPI
+SystemThread(
+    _In_ PVOID Context)
+{
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
+    ok_eq_pointer(Context, NULL);
+
+    SeCaptureSubjectContext(&SubjectContext);
+    TestSeAssignSecurity(&SubjectContext);
+    /* TODO: Test SeSetSecurityDescrptorInfo[Ex] */
+    SeReleaseSubjectContext(&SubjectContext);
+}
+
+static
+VOID
+TestObRootSecurity(VOID)
+{
+    NTSTATUS Status;
+    UNICODE_STRING ObjectPath = RTL_CONSTANT_STRING(L"\\");
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE Handle;
+    PVOID RootDirectory;
+    PSECURITY_DESCRIPTOR SecurityDescriptor;
+    BOOLEAN MemoryAllocated;
+    PACL Acl;
+    BOOLEAN Present;
+    BOOLEAN Defaulted;
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &ObjectPath,
+                               OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+    Status = ZwOpenDirectoryObject(&Handle,
+                                   0,
+                                   &ObjectAttributes);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    if (skip(NT_SUCCESS(Status), "No handle\n"))
+        return;
+    Status = ObReferenceObjectByHandle(Handle,
+                                       0,
+                                       NULL,
+                                       KernelMode,
+                                       &RootDirectory,
+                                       NULL);
+    ObCloseHandle(Handle, KernelMode);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    if (skip(NT_SUCCESS(Status), "No object\n"))
+        return;
+    Status = ObGetObjectSecurity(RootDirectory,
+                                 &SecurityDescriptor,
+                                 &MemoryAllocated);
+    ObDereferenceObject(RootDirectory);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    if (skip(NT_SUCCESS(Status), "No security\n"))
+        return;
+    Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
+                                          &Present,
+                                          &Acl,
+                                          &Defaulted);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    ok_eq_uint(Present, TRUE);
+    if (!skip(NT_SUCCESS(Status) && Present, "No DACL\n"))
+    {
+        ok_eq_uint(Defaulted, FALSE);
+        CheckAcl(Acl, 4, ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeWorldSid,         STANDARD_RIGHTS_READ | DIRECTORY_TRAVERSE | DIRECTORY_QUERY,
+                         ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeLocalSystemSid,   DIRECTORY_ALL_ACCESS,
+                         ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeAliasAdminsSid,   DIRECTORY_ALL_ACCESS,
+                         ACCESS_ALLOWED_ACE_TYPE, 0, SeExports->SeRestrictedSid,    STANDARD_RIGHTS_READ | DIRECTORY_TRAVERSE | DIRECTORY_QUERY);
+    }
+    Status = RtlGetSaclSecurityDescriptor(SecurityDescriptor,
+                                          &Present,
+                                          &Acl,
+                                          &Defaulted);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    ok_eq_uint(Present, FALSE);
+    ObReleaseObjectSecurity(SecurityDescriptor, MemoryAllocated);
+}
+
+START_TEST(SeInheritance)
+{
+    PKTHREAD Thread;
+
+    TestObRootSecurity();
+    Thread = KmtStartThread(SystemThread, NULL);
+    KmtFinishThread(Thread, NULL);
+}
diff --git a/rostests/kmtests/ntos_se/se.h b/rostests/kmtests/ntos_se/se.h
new file mode 100644 (file)
index 0000000..758c4bc
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Kernel-Mode Test Suite Se helper declarations
+ * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
+ */
+
+#ifndef _KMTEST_SE_H_
+#define _KMTEST_SE_H_
+
+/* FIXME: belongs in ntifs.h or something */
+#define SEF_DACL_AUTO_INHERIT 1
+#define SEF_SACL_AUTO_INHERIT 2
+#define SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT 4
+#define SEF_AVOID_PRIVILEGE_CHECK 8
+#define SEF_AVOID_OWNER_CHECK 16
+#define SEF_DEFAULT_OWNER_FROM_PARENT 32
+#define SEF_DEFAULT_GROUP_FROM_PARENT 64
+#define SEF_MACL_NO_WRITE_UP 256
+#define SEF_MACL_NO_READ_UP 512
+#define SEF_MACL_NO_EXECUTE_UP 1024
+#define SEF_AI_USE_EXTRA_PARAMS 2048
+#define SEF_AVOID_OWNER_RESTRICTION 4096
+#define SEF_MACL_VALID_FLAGS (SEF_MACL_NO_WRITE_UP | SEF_MACL_NO_READ_UP | SEF_MACL_NO_EXECUTE_UP)
+
+NTSTATUS
+RtlxAddAuditAccessAceEx(
+    _Inout_ PACL Acl,
+    _In_ ULONG Revision,
+    _In_ ULONG Flags,
+    _In_ ACCESS_MASK AccessMask,
+    _In_ PSID Sid,
+    _In_ BOOLEAN Success,
+    _In_ BOOLEAN Failure);
+
+#define NO_SIZE ((ULONG)-1)
+
+#define CheckSid(Sid, SidSize, ExpectedSid) CheckSid_(Sid, SidSize, ExpectedSid, __FILE__, __LINE__)
+#define CheckSid_(Sid, SidSize, ExpectedSid, file, line) CheckSid__(Sid, SidSize, ExpectedSid, file ":" KMT_STRINGIZE(line))
+VOID
+CheckSid__(
+    _In_ PSID Sid,
+    _In_ ULONG SidSize,
+    _In_ PISID ExpectedSid,
+    _In_ PCSTR FileAndLine);
+
+VOID
+VCheckAcl__(
+    _In_ PACL Acl,
+    _In_ ULONG AceCount,
+    _In_ PCSTR FileAndLine,
+    _In_ va_list Arguments);
+
+#define CheckAcl(Acl, AceCount, ...) CheckAcl_(Acl, AceCount, __FILE__, __LINE__, ##__VA_ARGS__)
+#define CheckAcl_(Acl, AceCount, file, line, ...) CheckAcl__(Acl, AceCount, file ":" KMT_STRINGIZE(line), ##__VA_ARGS__)
+VOID
+CheckAcl__(
+    _In_ PACL Acl,
+    _In_ ULONG AceCount,
+    _In_ PCSTR FileAndLine,
+    ...);
+
+#endif /* !defined _KMTEST_SE_H_ */