From ca809b6cdc17d56efb2dd7379af1f4de69c8633b Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Tue, 4 Nov 2014 22:44:50 +0000 Subject: [PATCH] [NTOS:SE] - Implement ACL inheritance for SeAssignSecurityEx CORE-8745 #resolve svn path=/trunk/; revision=65259 --- reactos/ntoskrnl/include/internal/se.h | 26 +++ reactos/ntoskrnl/se/acl.c | 276 +++++++++++++++++++++++++ reactos/ntoskrnl/se/sd.c | 131 ++++++++---- 3 files changed, 389 insertions(+), 44 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/se.h b/reactos/ntoskrnl/include/internal/se.h index 8c80fac07a3..1b737be4159 100644 --- a/reactos/ntoskrnl/include/internal/se.h +++ b/reactos/ntoskrnl/include/internal/se.h @@ -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( diff --git a/reactos/ntoskrnl/se/acl.c b/reactos/ntoskrnl/se/acl.c index d7191bc7e13..df014a148f9 100644 --- a/reactos/ntoskrnl/se/acl.c +++ b/reactos/ntoskrnl/se/acl.c @@ -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 */ diff --git a/reactos/ntoskrnl/se/sd.c b/reactos/ntoskrnl/se/sd.c index 6ec1e57b1ee..d3079dc3284 100644 --- a/reactos/ntoskrnl/se/sd.c +++ b/reactos/ntoskrnl/se/sd.c @@ -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; } -- 2.17.1