[NTOS:SE]
authorThomas Faber <thomas.faber@reactos.org>
Tue, 4 Nov 2014 22:44:50 +0000 (22:44 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Tue, 4 Nov 2014 22:44:50 +0000 (22:44 +0000)
- Implement ACL inheritance for SeAssignSecurityEx
CORE-8745 #resolve

svn path=/trunk/; revision=65259

reactos/ntoskrnl/include/internal/se.h
reactos/ntoskrnl/se/acl.c
reactos/ntoskrnl/se/sd.c

index 8c80fac..1b737be 100644 (file)
@@ -488,6 +488,32 @@ SepReleaseAcl(
     IN BOOLEAN CaptureIfKernel
 );
 
+NTSTATUS
+SepPropagateAcl(
+    _Out_writes_bytes_opt_(DaclLength) PACL AclDest,
+    _Inout_ PULONG AclLength,
+    _In_reads_bytes_(AclSource->AclSize) PACL AclSource,
+    _In_ PSID Owner,
+    _In_ PSID Group,
+    _In_ BOOLEAN IsInherited,
+    _In_ BOOLEAN IsDirectoryObject,
+    _In_ PGENERIC_MAPPING GenericMapping);
+    
+PACL
+SepSelectAcl(
+    _In_opt_ PACL ExplicitAcl,
+    _In_ BOOLEAN ExplicitPresent,
+    _In_ BOOLEAN ExplicitDefaulted,
+    _In_opt_ PACL ParentAcl,
+    _In_opt_ PACL DefaultAcl,
+    _Out_ PULONG AclLength,
+    _In_ PSID Owner,
+    _In_ PSID Group,
+    _Out_ PBOOLEAN AclPresent,
+    _Out_ PBOOLEAN IsInherited,
+    _In_ BOOLEAN IsDirectoryObject,
+    _In_ PGENERIC_MAPPING GenericMapping);
+
 NTSTATUS
 NTAPI
 SeDefaultObjectMethod(
index d7191bc..df014a1 100644 (file)
@@ -367,4 +367,280 @@ SepReleaseAcl(IN PACL CapturedAcl,
     }
 }
 
+BOOLEAN
+SepShouldPropagateAce(
+    _In_ UCHAR AceFlags,
+    _Out_ PUCHAR NewAceFlags,
+    _In_ BOOLEAN IsInherited,
+    _In_ BOOLEAN IsDirectoryObject)
+{
+    if (!IsInherited)
+    {
+        *NewAceFlags = AceFlags;
+        return TRUE;
+    }
+
+    if (!IsDirectoryObject)
+    {
+        if (AceFlags & OBJECT_INHERIT_ACE)
+        {
+            *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
+            return TRUE;
+        }
+        return FALSE;
+    }
+
+    if (AceFlags & NO_PROPAGATE_INHERIT_ACE)
+    {
+        if (AceFlags & CONTAINER_INHERIT_ACE)
+        {
+            *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
+            return TRUE;
+        }
+        return FALSE;
+    }
+
+    if (AceFlags & CONTAINER_INHERIT_ACE)
+    {
+        *NewAceFlags = CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE) | (AceFlags & ~VALID_INHERIT_FLAGS);
+        return TRUE;
+    }
+
+    if (AceFlags & OBJECT_INHERIT_ACE)
+    {
+        *NewAceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | (AceFlags & ~VALID_INHERIT_FLAGS);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+NTSTATUS
+SepPropagateAcl(
+    _Out_writes_bytes_opt_(DaclLength) PACL AclDest,
+    _Inout_ PULONG AclLength,
+    _In_reads_bytes_(AclSource->AclSize) PACL AclSource,
+    _In_ PSID Owner,
+    _In_ PSID Group,
+    _In_ BOOLEAN IsInherited,
+    _In_ BOOLEAN IsDirectoryObject,
+    _In_ PGENERIC_MAPPING GenericMapping)
+{
+    ACCESS_MASK Mask;
+    PACCESS_ALLOWED_ACE AceSource;
+    PACCESS_ALLOWED_ACE AceDest;
+    PUCHAR CurrentDest;
+    PUCHAR CurrentSource;
+    ULONG i;
+    ULONG Written;
+    UCHAR AceFlags;
+    USHORT AceSize;
+    USHORT AceCount = 0;
+    PSID Sid;
+    BOOLEAN WriteTwoAces;
+
+    if (AclSource->AclRevision != ACL_REVISION)
+    {
+        NT_ASSERT(AclSource->AclRevision == ACL_REVISION);
+        return STATUS_UNKNOWN_REVISION;
+    }
+
+    NT_ASSERT(AclSource->AclSize % sizeof(ULONG) == 0);
+    NT_ASSERT(AclSource->Sbz1 == 0);
+    NT_ASSERT(AclSource->Sbz2 == 0);
+
+    Written = 0;
+    if (*AclLength >= Written + sizeof(ACL))
+    {
+        RtlCopyMemory(AclDest,
+                      AclSource,
+                      sizeof(ACL));
+    }
+    Written += sizeof(ACL);
+
+    CurrentDest = (PUCHAR)(AclDest + 1);
+    CurrentSource = (PUCHAR)(AclSource + 1);
+    for (i = 0; i < AclSource->AceCount; i++)
+    {
+        NT_ASSERT((ULONG_PTR)CurrentDest % sizeof(ULONG) == 0);
+        NT_ASSERT((ULONG_PTR)CurrentSource % sizeof(ULONG) == 0);
+        AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
+        AceSource = (PACCESS_ALLOWED_ACE)CurrentSource;
+
+        /* These all have the same structure */
+        NT_ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE ||
+                  AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE ||
+                  AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE);
+
+        NT_ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0);
+        NT_ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource));
+        if (!SepShouldPropagateAce(AceSource->Header.AceFlags,
+                                   &AceFlags,
+                                   IsInherited,
+                                   IsDirectoryObject))
+        {
+            CurrentSource += AceSource->Header.AceSize;
+            continue;
+        }
+
+        /* FIXME: filter out duplicate ACEs */
+        AceSize = AceSource->Header.AceSize;
+        Mask = AceSource->Mask;
+        Sid = (PSID)&AceSource->SidStart;
+        NT_ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid));
+
+        WriteTwoAces = FALSE;
+        /* Map effective ACE to specific rights */
+        if (!(AceFlags & INHERIT_ONLY_ACE))
+        {
+            RtlMapGenericMask(&Mask, GenericMapping);
+            Mask &= GenericMapping->GenericAll;
+
+            if (IsInherited)
+            {
+                if (RtlEqualSid(Sid, SeCreatorOwnerSid))
+                    Sid = Owner;
+                else if (RtlEqualSid(Sid, SeCreatorGroupSid))
+                    Sid = Group;
+                AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid);
+
+                /*
+                 * A generic container ACE becomes two ACEs:
+                 * - a specific effective ACE with no inheritance flags
+                 * - an inherit-only ACE that keeps the generic rights
+                 */
+                if (IsDirectoryObject &&
+                    (AceFlags & CONTAINER_INHERIT_ACE) &&
+                    (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart))
+                {
+                    WriteTwoAces = TRUE;
+                }
+            }
+        }
+
+        while (1)
+        {
+            if (*AclLength >= Written + AceSize)
+            {
+                AceDest->Header.AceType = AceSource->Header.AceType;
+                AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS
+                                                        : AceFlags;
+                AceDest->Header.AceSize = AceSize;
+                AceDest->Mask = Mask;
+                RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart),
+                           (PSID)&AceDest->SidStart,
+                           Sid);
+            }
+            Written += AceSize;
+
+            AceCount++;
+            CurrentDest += AceSize;
+
+            if (!WriteTwoAces)
+                break;
+
+            /* Second ACE keeps all the generics from the source ACE */
+            WriteTwoAces = FALSE;
+            AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
+            AceSize = AceSource->Header.AceSize;
+            Mask = AceSource->Mask;
+            Sid = (PSID)&AceSource->SidStart;
+            AceFlags |= INHERIT_ONLY_ACE;
+        }
+
+        CurrentSource += AceSource->Header.AceSize;
+    }
+
+    if (*AclLength >= sizeof(ACL))
+    {
+        AclDest->AceCount = AceCount;
+        AclDest->AclSize = Written;
+    }
+
+    if (Written > *AclLength)
+    {
+        *AclLength = Written;
+        return STATUS_BUFFER_TOO_SMALL;
+    }
+    *AclLength = Written;
+    return STATUS_SUCCESS;
+}
+
+PACL
+SepSelectAcl(
+    _In_opt_ PACL ExplicitAcl,
+    _In_ BOOLEAN ExplicitPresent,
+    _In_ BOOLEAN ExplicitDefaulted,
+    _In_opt_ PACL ParentAcl,
+    _In_opt_ PACL DefaultAcl,
+    _Out_ PULONG AclLength,
+    _In_ PSID Owner,
+    _In_ PSID Group,
+    _Out_ PBOOLEAN AclPresent,
+    _Out_ PBOOLEAN IsInherited,
+    _In_ BOOLEAN IsDirectoryObject,
+    _In_ PGENERIC_MAPPING GenericMapping)
+{
+    PACL Acl;
+    NTSTATUS Status;
+
+    *AclPresent = TRUE;
+    if (ExplicitPresent && !ExplicitDefaulted)
+    {
+        Acl = ExplicitAcl;
+    }
+    else
+    {
+        if (ParentAcl)
+        {
+            *IsInherited = TRUE;
+            *AclLength = 0;
+            Status = SepPropagateAcl(NULL,
+                                     AclLength,
+                                     ParentAcl,
+                                     Owner,
+                                     Group,
+                                     *IsInherited,
+                                     IsDirectoryObject,
+                                     GenericMapping);
+            NT_ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
+
+            /* Use the parent ACL only if it's not empty */
+            if (*AclLength != sizeof(ACL))
+                return ParentAcl;
+        }
+
+        if (ExplicitPresent)
+        {
+            Acl = ExplicitAcl;
+        }
+        else if (DefaultAcl)
+        {
+            Acl = DefaultAcl;
+        }
+        else
+        {
+            *AclPresent = FALSE;
+            Acl = NULL;
+        }
+    }
+
+    *IsInherited = FALSE;
+    *AclLength = 0;
+    if (Acl)
+    {
+        /* Get the length */
+        Status = SepPropagateAcl(NULL,
+                                 AclLength,
+                                 Acl,
+                                 Owner,
+                                 Group,
+                                 *IsInherited,
+                                 IsDirectoryObject,
+                                 GenericMapping);
+        NT_ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
+    }
+    return Acl;
+}
+
 /* EOF */
index 6ec1e57..d3079dc 100644 (file)
@@ -1109,7 +1109,6 @@ SeDeassignSecurity(
     return STATUS_SUCCESS;
 }
 
-
 /*
  * @implemented
  */
@@ -1140,12 +1139,20 @@ SeAssignSecurityEx(
     ULONG Current;
     PSID Owner = NULL;
     PSID Group = NULL;
+    PACL ExplicitAcl;
+    BOOLEAN ExplicitPresent;
+    BOOLEAN ExplicitDefaulted;
+    PACL ParentAcl;
     PACL Dacl = NULL;
     PACL Sacl = NULL;
+    BOOLEAN DaclIsInherited;
+    BOOLEAN SaclIsInherited;
+    BOOLEAN DaclPresent;
+    BOOLEAN SaclPresent;
+    NTSTATUS Status;
 
     DBG_UNREFERENCED_PARAMETER(ObjectType);
     DBG_UNREFERENCED_PARAMETER(AutoInheritFlags);
-    DBG_UNREFERENCED_PARAMETER(GenericMapping);
     UNREFERENCED_PARAMETER(PoolType);
 
     PAGED_CODE();
@@ -1180,7 +1187,6 @@ SeAssignSecurityEx(
         DPRINT("Use token owner sid!\n");
         Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
     }
-
     OwnerLength = RtlLengthSid(Owner);
     NT_ASSERT(OwnerLength % sizeof(ULONG) == 0);
 
@@ -1199,56 +1205,77 @@ SeAssignSecurityEx(
         SeUnlockSubjectContext(SubjectContext);
         return STATUS_INVALID_PRIMARY_GROUP;
     }
-
     GroupLength = RtlLengthSid(Group);
     NT_ASSERT(GroupLength % sizeof(ULONG) == 0);
 
     /* Inherit the DACL */
+    DaclLength = 0;
+    ExplicitAcl = NULL;
+    ExplicitPresent = FALSE;
+    ExplicitDefaulted = FALSE;
     if (ExplicitDescriptor != NULL &&
-        (ExplicitDescriptor->Control & SE_DACL_PRESENT) &&
-        !(ExplicitDescriptor->Control & SE_DACL_DEFAULTED))
-    {
-        DPRINT("Use explicit DACL!\n");
-        Dacl = SepGetDaclFromDescriptor(ExplicitDescriptor);
+        (ExplicitDescriptor->Control & SE_DACL_PRESENT))
+    {
+        ExplicitAcl = SepGetDaclFromDescriptor(ExplicitDescriptor);
+        ExplicitPresent = TRUE;
+        if (ExplicitDescriptor->Control & SE_DACL_DEFAULTED)
+            ExplicitDefaulted = TRUE;
+    }
+    ParentAcl = NULL;
+    if (ParentDescriptor != NULL &&
+        (ParentDescriptor->Control & SE_DACL_PRESENT))
+    {
+        ParentAcl = SepGetDaclFromDescriptor(ParentDescriptor);
+    }
+    Dacl = SepSelectAcl(ExplicitAcl,
+                        ExplicitPresent,
+                        ExplicitDefaulted,
+                        ParentAcl,
+                        Token->DefaultDacl,
+                        &DaclLength,
+                        Owner,
+                        Group,
+                        &DaclPresent,
+                        &DaclIsInherited,
+                        IsDirectoryObject,
+                        GenericMapping);
+    if (DaclPresent)
         Control |= SE_DACL_PRESENT;
-    }
-    else if (ParentDescriptor != NULL &&
-             (ParentDescriptor->Control & SE_DACL_PRESENT))
-    {
-        DPRINT("Use parent DACL!\n");
-        /* FIXME: Inherit */
-        Dacl = SepGetDaclFromDescriptor(ParentDescriptor);
-        Control |= SE_DACL_PRESENT;
-    }
-    else if (Token->DefaultDacl)
-    {
-        DPRINT("Use token default DACL!\n");
-        Dacl = Token->DefaultDacl;
-        Control |= SE_DACL_PRESENT;
-    }
-
-    DaclLength = (Dacl != NULL) ? Dacl->AclSize : 0;
     NT_ASSERT(DaclLength % sizeof(ULONG) == 0);
 
     /* Inherit the SACL */
+    SaclLength = 0;
+    ExplicitAcl = NULL;
+    ExplicitPresent = FALSE;
+    ExplicitDefaulted = FALSE;
     if (ExplicitDescriptor != NULL &&
-        (ExplicitDescriptor->Control & SE_SACL_PRESENT) &&
-        !(ExplicitDescriptor->Control & SE_SACL_DEFAULTED))
-    {
-        DPRINT("Use explicit SACL!\n");
-        Sacl = SepGetSaclFromDescriptor(ExplicitDescriptor);
+        (ExplicitDescriptor->Control & SE_SACL_PRESENT))
+    {
+        ExplicitAcl = SepGetSaclFromDescriptor(ExplicitDescriptor);
+        ExplicitPresent = TRUE;
+        if (ExplicitDescriptor->Control & SE_SACL_DEFAULTED)
+            ExplicitDefaulted = TRUE;
+    }
+    ParentAcl = NULL;
+    if (ParentDescriptor != NULL &&
+        (ParentDescriptor->Control & SE_SACL_PRESENT))
+    {
+        ParentAcl = SepGetSaclFromDescriptor(ParentDescriptor);
+    }
+    Sacl = SepSelectAcl(ExplicitAcl,
+                        ExplicitPresent,
+                        ExplicitDefaulted,
+                        ParentAcl,
+                        NULL,
+                        &SaclLength,
+                        Owner,
+                        Group,
+                        &SaclPresent,
+                        &SaclIsInherited,
+                        IsDirectoryObject,
+                        GenericMapping);
+    if (SaclPresent)
         Control |= SE_SACL_PRESENT;
-    }
-    else if (ParentDescriptor != NULL &&
-             (ParentDescriptor->Control & SE_SACL_PRESENT))
-    {
-        DPRINT("Use parent SACL!\n");
-        /* FIXME: Inherit */
-        Sacl = SepGetSaclFromDescriptor(ParentDescriptor);
-        Control |= SE_SACL_PRESENT;
-    }
-
-    SaclLength = (Sacl != NULL) ? Sacl->AclSize : 0;
     NT_ASSERT(SaclLength % sizeof(ULONG) == 0);
 
     /* Allocate and initialize the new security descriptor */
@@ -1279,14 +1306,30 @@ SeAssignSecurityEx(
 
     if (SaclLength != 0)
     {
-        RtlCopyMemory((PUCHAR)Descriptor + Current, Sacl, SaclLength);
+        Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
+                                 &SaclLength,
+                                 Sacl,
+                                 Owner,
+                                 Group,
+                                 SaclIsInherited,
+                                 IsDirectoryObject,
+                                 GenericMapping);
+        NT_ASSERT(Status == STATUS_SUCCESS);
         Descriptor->Sacl = Current;
         Current += SaclLength;
     }
 
     if (DaclLength != 0)
     {
-        RtlCopyMemory((PUCHAR)Descriptor + Current, Dacl, DaclLength);
+        Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
+                                 &DaclLength,
+                                 Dacl,
+                                 Owner,
+                                 Group,
+                                 DaclIsInherited,
+                                 IsDirectoryObject,
+                                 GenericMapping);
+        NT_ASSERT(Status == STATUS_SUCCESS);
         Descriptor->Dacl = Current;
         Current += DaclLength;
     }