[NTOS:SE]

- Implement ACL inheritance for SeAssignSecurityEx
CORE-8745 #resolve

svn path=/trunk/; revision=65259
This commit is contained in:
Thomas Faber 2014-11-04 22:44:50 +00:00
parent 418629f6a9
commit ca809b6cdc
3 changed files with 382 additions and 37 deletions

View 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(

View 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 */

View 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))
(ExplicitDescriptor->Control & SE_DACL_PRESENT))
{
DPRINT("Use explicit DACL!\n");
Dacl = SepGetDaclFromDescriptor(ExplicitDescriptor);
Control |= SE_DACL_PRESENT;
ExplicitAcl = SepGetDaclFromDescriptor(ExplicitDescriptor);
ExplicitPresent = TRUE;
if (ExplicitDescriptor->Control & SE_DACL_DEFAULTED)
ExplicitDefaulted = TRUE;
}
else if (ParentDescriptor != NULL &&
(ParentDescriptor->Control & SE_DACL_PRESENT))
ParentAcl = NULL;
if (ParentDescriptor != NULL &&
(ParentDescriptor->Control & SE_DACL_PRESENT))
{
DPRINT("Use parent DACL!\n");
/* FIXME: Inherit */
Dacl = SepGetDaclFromDescriptor(ParentDescriptor);
Control |= SE_DACL_PRESENT;
ParentAcl = SepGetDaclFromDescriptor(ParentDescriptor);
}
else if (Token->DefaultDacl)
{
DPRINT("Use token default DACL!\n");
Dacl = Token->DefaultDacl;
Dacl = SepSelectAcl(ExplicitAcl,
ExplicitPresent,
ExplicitDefaulted,
ParentAcl,
Token->DefaultDacl,
&DaclLength,
Owner,
Group,
&DaclPresent,
&DaclIsInherited,
IsDirectoryObject,
GenericMapping);
if (DaclPresent)
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))
(ExplicitDescriptor->Control & SE_SACL_PRESENT))
{
DPRINT("Use explicit SACL!\n");
Sacl = SepGetSaclFromDescriptor(ExplicitDescriptor);
Control |= SE_SACL_PRESENT;
ExplicitAcl = SepGetSaclFromDescriptor(ExplicitDescriptor);
ExplicitPresent = TRUE;
if (ExplicitDescriptor->Control & SE_SACL_DEFAULTED)
ExplicitDefaulted = TRUE;
}
else if (ParentDescriptor != NULL &&
(ParentDescriptor->Control & SE_SACL_PRESENT))
ParentAcl = NULL;
if (ParentDescriptor != NULL &&
(ParentDescriptor->Control & SE_SACL_PRESENT))
{
DPRINT("Use parent SACL!\n");
/* FIXME: Inherit */
Sacl = SepGetSaclFromDescriptor(ParentDescriptor);
Control |= SE_SACL_PRESENT;
ParentAcl = SepGetSaclFromDescriptor(ParentDescriptor);
}
SaclLength = (Sacl != NULL) ? Sacl->AclSize : 0;
Sacl = SepSelectAcl(ExplicitAcl,
ExplicitPresent,
ExplicitDefaulted,
ParentAcl,
NULL,
&SaclLength,
Owner,
Group,
&SaclPresent,
&SaclIsInherited,
IsDirectoryObject,
GenericMapping);
if (SaclPresent)
Control |= SE_SACL_PRESENT;
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;
}