reactos/ntoskrnl/se/sd.c
George Bișoc c869c4778d
[NTOS:SE] Assign the control flag bits to the newly created security descriptor
We allocate memory pool for a new security descriptor with specific info filled by the caller but we don't set the control flag bits for the newly allocated descriptor, which is wrong. Originally spotted by Vadim Galyant.
CORE-17650
2021-07-03 17:20:48 +02:00

1490 lines
45 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/se/sd.c
* PURPOSE: Security manager
*
* PROGRAMMERS: David Welch <welch@cwcom.net>
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
PSECURITY_DESCRIPTOR SePublicDefaultSd = NULL;
PSECURITY_DESCRIPTOR SePublicDefaultUnrestrictedSd = NULL;
PSECURITY_DESCRIPTOR SePublicOpenSd = NULL;
PSECURITY_DESCRIPTOR SePublicOpenUnrestrictedSd = NULL;
PSECURITY_DESCRIPTOR SeSystemDefaultSd = NULL;
PSECURITY_DESCRIPTOR SeUnrestrictedSd = NULL;
PSECURITY_DESCRIPTOR SeSystemAnonymousLogonSd = NULL;
/* PRIVATE FUNCTIONS **********************************************************/
CODE_SEG("INIT")
BOOLEAN
NTAPI
SepInitSDs(VOID)
{
/* Create PublicDefaultSd */
SePublicDefaultSd = ExAllocatePoolWithTag(PagedPool,
sizeof(SECURITY_DESCRIPTOR), TAG_SD);
if (SePublicDefaultSd == NULL)
return FALSE;
RtlCreateSecurityDescriptor(SePublicDefaultSd,
SECURITY_DESCRIPTOR_REVISION);
RtlSetDaclSecurityDescriptor(SePublicDefaultSd,
TRUE,
SePublicDefaultDacl,
FALSE);
/* Create PublicDefaultUnrestrictedSd */
SePublicDefaultUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
sizeof(SECURITY_DESCRIPTOR), TAG_SD);
if (SePublicDefaultUnrestrictedSd == NULL)
return FALSE;
RtlCreateSecurityDescriptor(SePublicDefaultUnrestrictedSd,
SECURITY_DESCRIPTOR_REVISION);
RtlSetDaclSecurityDescriptor(SePublicDefaultUnrestrictedSd,
TRUE,
SePublicDefaultUnrestrictedDacl,
FALSE);
/* Create PublicOpenSd */
SePublicOpenSd = ExAllocatePoolWithTag(PagedPool,
sizeof(SECURITY_DESCRIPTOR), TAG_SD);
if (SePublicOpenSd == NULL)
return FALSE;
RtlCreateSecurityDescriptor(SePublicOpenSd,
SECURITY_DESCRIPTOR_REVISION);
RtlSetDaclSecurityDescriptor(SePublicOpenSd,
TRUE,
SePublicOpenDacl,
FALSE);
/* Create PublicOpenUnrestrictedSd */
SePublicOpenUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
sizeof(SECURITY_DESCRIPTOR), TAG_SD);
if (SePublicOpenUnrestrictedSd == NULL)
return FALSE;
RtlCreateSecurityDescriptor(SePublicOpenUnrestrictedSd,
SECURITY_DESCRIPTOR_REVISION);
RtlSetDaclSecurityDescriptor(SePublicOpenUnrestrictedSd,
TRUE,
SePublicOpenUnrestrictedDacl,
FALSE);
/* Create SystemDefaultSd */
SeSystemDefaultSd = ExAllocatePoolWithTag(PagedPool,
sizeof(SECURITY_DESCRIPTOR), TAG_SD);
if (SeSystemDefaultSd == NULL)
return FALSE;
RtlCreateSecurityDescriptor(SeSystemDefaultSd,
SECURITY_DESCRIPTOR_REVISION);
RtlSetDaclSecurityDescriptor(SeSystemDefaultSd,
TRUE,
SeSystemDefaultDacl,
FALSE);
/* Create UnrestrictedSd */
SeUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
sizeof(SECURITY_DESCRIPTOR), TAG_SD);
if (SeUnrestrictedSd == NULL)
return FALSE;
RtlCreateSecurityDescriptor(SeUnrestrictedSd,
SECURITY_DESCRIPTOR_REVISION);
RtlSetDaclSecurityDescriptor(SeUnrestrictedSd,
TRUE,
SeUnrestrictedDacl,
FALSE);
/* Create SystemAnonymousLogonSd */
SeSystemAnonymousLogonSd = ExAllocatePoolWithTag(PagedPool,
sizeof(SECURITY_DESCRIPTOR), TAG_SD);
if (SeSystemAnonymousLogonSd == NULL)
return FALSE;
RtlCreateSecurityDescriptor(SeSystemAnonymousLogonSd,
SECURITY_DESCRIPTOR_REVISION);
RtlSetDaclSecurityDescriptor(SeSystemAnonymousLogonSd,
TRUE,
SeSystemAnonymousLogonDacl,
FALSE);
return TRUE;
}
NTSTATUS
NTAPI
SeSetWorldSecurityDescriptor(SECURITY_INFORMATION SecurityInformation,
PISECURITY_DESCRIPTOR SecurityDescriptor,
PULONG BufferLength)
{
ULONG Current;
ULONG SidSize;
ULONG SdSize;
NTSTATUS Status;
PISECURITY_DESCRIPTOR_RELATIVE SdRel = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
DPRINT("SeSetWorldSecurityDescriptor() called\n");
if (SecurityInformation == 0)
{
return STATUS_ACCESS_DENIED;
}
/* calculate the minimum size of the buffer */
SidSize = RtlLengthSid(SeWorldSid);
SdSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
SdSize += SidSize;
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
SdSize += SidSize;
if (SecurityInformation & DACL_SECURITY_INFORMATION)
{
SdSize += sizeof(ACL) + sizeof(ACE) + SidSize;
}
if (*BufferLength < SdSize)
{
*BufferLength = SdSize;
return STATUS_BUFFER_TOO_SMALL;
}
*BufferLength = SdSize;
Status = RtlCreateSecurityDescriptorRelative(SdRel,
SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status))
{
return Status;
}
Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
{
RtlCopyMemory((PUCHAR)SdRel + Current, SeWorldSid, SidSize);
SdRel->Owner = Current;
Current += SidSize;
}
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
{
RtlCopyMemory((PUCHAR)SdRel + Current, SeWorldSid, SidSize);
SdRel->Group = Current;
Current += SidSize;
}
if (SecurityInformation & DACL_SECURITY_INFORMATION)
{
PACL Dacl = (PACL)((PUCHAR)SdRel + Current);
SdRel->Control |= SE_DACL_PRESENT;
Status = RtlCreateAcl(Dacl,
sizeof(ACL) + sizeof(ACE) + SidSize,
ACL_REVISION);
if (!NT_SUCCESS(Status))
return Status;
Status = RtlAddAccessAllowedAce(Dacl,
ACL_REVISION,
GENERIC_ALL,
SeWorldSid);
if (!NT_SUCCESS(Status))
return Status;
SdRel->Dacl = Current;
}
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
/* FIXME - SdRel->Control |= SE_SACL_PRESENT; */
}
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
SepCaptureSecurityQualityOfService(IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
IN POOL_TYPE PoolType,
IN BOOLEAN CaptureIfKernel,
OUT PSECURITY_QUALITY_OF_SERVICE *CapturedSecurityQualityOfService,
OUT PBOOLEAN Present)
{
PSECURITY_QUALITY_OF_SERVICE CapturedQos;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
ASSERT(CapturedSecurityQualityOfService);
ASSERT(Present);
if (ObjectAttributes != NULL)
{
if (AccessMode != KernelMode)
{
SECURITY_QUALITY_OF_SERVICE SafeQos;
_SEH2_TRY
{
ProbeForRead(ObjectAttributes,
sizeof(OBJECT_ATTRIBUTES),
sizeof(ULONG));
if (ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES))
{
if (ObjectAttributes->SecurityQualityOfService != NULL)
{
ProbeForRead(ObjectAttributes->SecurityQualityOfService,
sizeof(SECURITY_QUALITY_OF_SERVICE),
sizeof(ULONG));
if (((PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService)->Length ==
sizeof(SECURITY_QUALITY_OF_SERVICE))
{
/*
* Don't allocate memory here because ExAllocate should bugcheck
* the system if it's buggy, SEH would catch that! So make a local
* copy of the qos structure.
*/
RtlCopyMemory(&SafeQos,
ObjectAttributes->SecurityQualityOfService,
sizeof(SECURITY_QUALITY_OF_SERVICE));
*Present = TRUE;
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
else
{
*CapturedSecurityQualityOfService = NULL;
*Present = FALSE;
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
if (NT_SUCCESS(Status))
{
if (*Present)
{
CapturedQos = ExAllocatePoolWithTag(PoolType,
sizeof(SECURITY_QUALITY_OF_SERVICE),
TAG_QOS);
if (CapturedQos != NULL)
{
RtlCopyMemory(CapturedQos,
&SafeQos,
sizeof(SECURITY_QUALITY_OF_SERVICE));
*CapturedSecurityQualityOfService = CapturedQos;
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
*CapturedSecurityQualityOfService = NULL;
}
}
}
else
{
if (ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES))
{
if (CaptureIfKernel)
{
if (ObjectAttributes->SecurityQualityOfService != NULL)
{
if (((PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService)->Length ==
sizeof(SECURITY_QUALITY_OF_SERVICE))
{
CapturedQos = ExAllocatePoolWithTag(PoolType,
sizeof(SECURITY_QUALITY_OF_SERVICE),
TAG_QOS);
if (CapturedQos != NULL)
{
RtlCopyMemory(CapturedQos,
ObjectAttributes->SecurityQualityOfService,
sizeof(SECURITY_QUALITY_OF_SERVICE));
*CapturedSecurityQualityOfService = CapturedQos;
*Present = TRUE;
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
else
{
*CapturedSecurityQualityOfService = NULL;
*Present = FALSE;
}
}
else
{
*CapturedSecurityQualityOfService = (PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService;
*Present = (ObjectAttributes->SecurityQualityOfService != NULL);
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
}
else
{
*CapturedSecurityQualityOfService = NULL;
*Present = FALSE;
}
return Status;
}
VOID
NTAPI
SepReleaseSecurityQualityOfService(IN PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
IN BOOLEAN CaptureIfKernel)
{
PAGED_CODE();
if (CapturedSecurityQualityOfService != NULL &&
(AccessMode != KernelMode || CaptureIfKernel))
{
ExFreePoolWithTag(CapturedSecurityQualityOfService, TAG_QOS);
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
static
ULONG
DetermineSIDSize(
PISID Sid,
PULONG OutSAC,
KPROCESSOR_MODE ProcessorMode)
{
ULONG Size;
if (!Sid)
{
*OutSAC = 0;
return 0;
}
if (ProcessorMode != KernelMode)
{
/* Securely access the buffers! */
*OutSAC = ProbeForReadUchar(&Sid->SubAuthorityCount);
Size = RtlLengthRequiredSid(*OutSAC);
ProbeForRead(Sid, Size, sizeof(ULONG));
}
else
{
*OutSAC = Sid->SubAuthorityCount;
Size = RtlLengthRequiredSid(*OutSAC);
}
return Size;
}
static
ULONG
DetermineACLSize(
PACL Acl,
KPROCESSOR_MODE ProcessorMode)
{
ULONG Size;
if (!Acl) return 0;
if (ProcessorMode == KernelMode) return Acl->AclSize;
/* Probe the buffers! */
Size = ProbeForReadUshort(&Acl->AclSize);
ProbeForRead(Acl, Size, sizeof(ULONG));
return Size;
}
NTSTATUS
NTAPI
SeCaptureSecurityDescriptor(
IN PSECURITY_DESCRIPTOR _OriginalSecurityDescriptor,
IN KPROCESSOR_MODE CurrentMode,
IN POOL_TYPE PoolType,
IN BOOLEAN CaptureIfKernel,
OUT PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor)
{
PISECURITY_DESCRIPTOR OriginalDescriptor = _OriginalSecurityDescriptor;
SECURITY_DESCRIPTOR DescriptorCopy;
PISECURITY_DESCRIPTOR_RELATIVE NewDescriptor;
ULONG OwnerSAC = 0, GroupSAC = 0;
ULONG OwnerSize = 0, GroupSize = 0;
ULONG SaclSize = 0, DaclSize = 0;
ULONG DescriptorSize = 0;
ULONG Offset;
if (!OriginalDescriptor)
{
/* Nothing to do... */
*CapturedSecurityDescriptor = NULL;
return STATUS_SUCCESS;
}
/* Quick path */
if (CurrentMode == KernelMode && !CaptureIfKernel)
{
/* Check descriptor version */
if (OriginalDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
{
return STATUS_UNKNOWN_REVISION;
}
*CapturedSecurityDescriptor = _OriginalSecurityDescriptor;
return STATUS_SUCCESS;
}
_SEH2_TRY
{
if (CurrentMode != KernelMode)
{
ProbeForRead(OriginalDescriptor,
sizeof(SECURITY_DESCRIPTOR_RELATIVE),
sizeof(ULONG));
}
/* Check the descriptor version */
if (OriginalDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
{
_SEH2_YIELD(return STATUS_UNKNOWN_REVISION);
}
if (CurrentMode != KernelMode)
{
/* Get the size of the descriptor */
DescriptorSize = (OriginalDescriptor->Control & SE_SELF_RELATIVE) ?
sizeof(SECURITY_DESCRIPTOR_RELATIVE) : sizeof(SECURITY_DESCRIPTOR);
/* Probe the entire security descriptor structure. The SIDs
* and ACLs will be probed and copied later though */
ProbeForRead(OriginalDescriptor, DescriptorSize, sizeof(ULONG));
}
/* Now capture all fields and convert to an absolute descriptor */
DescriptorCopy.Revision = OriginalDescriptor->Revision;
DescriptorCopy.Sbz1 = OriginalDescriptor->Sbz1;
DescriptorCopy.Control = OriginalDescriptor->Control & ~SE_SELF_RELATIVE;
DescriptorCopy.Owner = SepGetOwnerFromDescriptor(OriginalDescriptor);
DescriptorCopy.Group = SepGetGroupFromDescriptor(OriginalDescriptor);
DescriptorCopy.Sacl = SepGetSaclFromDescriptor(OriginalDescriptor);
DescriptorCopy.Dacl = SepGetDaclFromDescriptor(OriginalDescriptor);
DescriptorSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
/* Determine owner and group sizes */
OwnerSize = DetermineSIDSize(DescriptorCopy.Owner, &OwnerSAC, CurrentMode);
DescriptorSize += ROUND_UP(OwnerSize, sizeof(ULONG));
GroupSize = DetermineSIDSize(DescriptorCopy.Group, &GroupSAC, CurrentMode);
DescriptorSize += ROUND_UP(GroupSize, sizeof(ULONG));
/* Determine the size of the ACLs */
if (DescriptorCopy.Control & SE_SACL_PRESENT)
{
/* Get the size and probe if user mode */
SaclSize = DetermineACLSize(DescriptorCopy.Sacl, CurrentMode);
DescriptorSize += ROUND_UP(SaclSize, sizeof(ULONG));
}
if (DescriptorCopy.Control & SE_DACL_PRESENT)
{
/* Get the size and probe if user mode */
DaclSize = DetermineACLSize(DescriptorCopy.Dacl, CurrentMode);
DescriptorSize += ROUND_UP(DaclSize, sizeof(ULONG));
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/*
* Allocate enough memory to store a complete copy of a self-relative
* security descriptor
*/
NewDescriptor = ExAllocatePoolWithTag(PoolType,
DescriptorSize,
TAG_SD);
if (!NewDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(NewDescriptor, DescriptorSize);
NewDescriptor->Revision = DescriptorCopy.Revision;
NewDescriptor->Sbz1 = DescriptorCopy.Sbz1;
NewDescriptor->Control = DescriptorCopy.Control | SE_SELF_RELATIVE;
_SEH2_TRY
{
/*
* Setup the offsets and copy the SIDs and ACLs to the new
* self-relative security descriptor. Probing the pointers is not
* neccessary anymore as we did that when collecting the sizes!
* Make sure to validate the SIDs and ACLs *again* as they could have
* been modified in the meanwhile!
*/
Offset = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
if (DescriptorCopy.Owner)
{
if (!RtlValidSid(DescriptorCopy.Owner)) RtlRaiseStatus(STATUS_INVALID_SID);
NewDescriptor->Owner = Offset;
RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
DescriptorCopy.Owner,
OwnerSize);
Offset += ROUND_UP(OwnerSize, sizeof(ULONG));
}
if (DescriptorCopy.Group)
{
if (!RtlValidSid(DescriptorCopy.Group)) RtlRaiseStatus(STATUS_INVALID_SID);
NewDescriptor->Group = Offset;
RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
DescriptorCopy.Group,
GroupSize);
Offset += ROUND_UP(GroupSize, sizeof(ULONG));
}
if (DescriptorCopy.Sacl)
{
if (!RtlValidAcl(DescriptorCopy.Sacl)) RtlRaiseStatus(STATUS_INVALID_ACL);
NewDescriptor->Sacl = Offset;
RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
DescriptorCopy.Sacl,
SaclSize);
Offset += ROUND_UP(SaclSize, sizeof(ULONG));
}
if (DescriptorCopy.Dacl)
{
if (!RtlValidAcl(DescriptorCopy.Dacl)) RtlRaiseStatus(STATUS_INVALID_ACL);
NewDescriptor->Dacl = Offset;
RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
DescriptorCopy.Dacl,
DaclSize);
Offset += ROUND_UP(DaclSize, sizeof(ULONG));
}
/* Make sure the size was correct */
ASSERT(Offset == DescriptorSize);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* We failed to copy the data to the new descriptor */
ExFreePoolWithTag(NewDescriptor, TAG_SD);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/*
* We're finally done!
* Copy the pointer to the captured descriptor to to the caller.
*/
*CapturedSecurityDescriptor = NewDescriptor;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
SeQuerySecurityDescriptorInfo(
_In_ PSECURITY_INFORMATION SecurityInformation,
_Out_writes_bytes_(*Length) PSECURITY_DESCRIPTOR SecurityDescriptor,
_Inout_ PULONG Length,
_Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor)
{
PISECURITY_DESCRIPTOR ObjectSd;
PISECURITY_DESCRIPTOR_RELATIVE RelSD;
PSID Owner = NULL;
PSID Group = NULL;
PACL Dacl = NULL;
PACL Sacl = NULL;
ULONG OwnerLength = 0;
ULONG GroupLength = 0;
ULONG DaclLength = 0;
ULONG SaclLength = 0;
SECURITY_DESCRIPTOR_CONTROL Control = 0;
ULONG_PTR Current;
ULONG SdLength;
PAGED_CODE();
RelSD = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
if (*ObjectsSecurityDescriptor == NULL)
{
if (*Length < sizeof(SECURITY_DESCRIPTOR_RELATIVE))
{
*Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
return STATUS_BUFFER_TOO_SMALL;
}
*Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
RtlCreateSecurityDescriptorRelative(RelSD,
SECURITY_DESCRIPTOR_REVISION);
return STATUS_SUCCESS;
}
ObjectSd = *ObjectsSecurityDescriptor;
/* Calculate the required security descriptor length */
Control = SE_SELF_RELATIVE;
if (*SecurityInformation & OWNER_SECURITY_INFORMATION)
{
Owner = SepGetOwnerFromDescriptor(ObjectSd);
if (Owner != NULL)
{
OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
}
}
if (*SecurityInformation & GROUP_SECURITY_INFORMATION)
{
Group = SepGetGroupFromDescriptor(ObjectSd);
if (Group != NULL)
{
GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
}
}
if ((*SecurityInformation & DACL_SECURITY_INFORMATION) &&
(ObjectSd->Control & SE_DACL_PRESENT))
{
Dacl = SepGetDaclFromDescriptor(ObjectSd);
if (Dacl != NULL)
{
DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
}
Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
}
if ((*SecurityInformation & SACL_SECURITY_INFORMATION) &&
(ObjectSd->Control & SE_SACL_PRESENT))
{
Sacl = SepGetSaclFromDescriptor(ObjectSd);
if (Sacl != NULL)
{
SaclLength = ROUND_UP(Sacl->AclSize, 4);
}
Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
}
SdLength = OwnerLength + GroupLength + DaclLength +
SaclLength + sizeof(SECURITY_DESCRIPTOR_RELATIVE);
if (*Length < SdLength)
{
*Length = SdLength;
return STATUS_BUFFER_TOO_SMALL;
}
/* Build the new security descrtiptor */
RtlCreateSecurityDescriptorRelative(RelSD,
SECURITY_DESCRIPTOR_REVISION);
RelSD->Control = Control;
Current = (ULONG_PTR)(RelSD + 1);
if (OwnerLength != 0)
{
RtlCopyMemory((PVOID)Current,
Owner,
OwnerLength);
RelSD->Owner = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
Current += OwnerLength;
}
if (GroupLength != 0)
{
RtlCopyMemory((PVOID)Current,
Group,
GroupLength);
RelSD->Group = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
Current += GroupLength;
}
if (DaclLength != 0)
{
RtlCopyMemory((PVOID)Current,
Dacl,
DaclLength);
RelSD->Dacl = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
Current += DaclLength;
}
if (SaclLength != 0)
{
RtlCopyMemory((PVOID)Current,
Sacl,
SaclLength);
RelSD->Sacl = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
Current += SaclLength;
}
*Length = SdLength;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
SeReleaseSecurityDescriptor(IN PSECURITY_DESCRIPTOR CapturedSecurityDescriptor,
IN KPROCESSOR_MODE CurrentMode,
IN BOOLEAN CaptureIfKernelMode)
{
PAGED_CODE();
/*
* WARNING! You need to call this function with the same value for CurrentMode
* and CaptureIfKernelMode that you previously passed to
* SeCaptureSecurityDescriptor() in order to avoid memory leaks!
*/
if (CapturedSecurityDescriptor != NULL &&
(CurrentMode != KernelMode ||
(CurrentMode == KernelMode && CaptureIfKernelMode)))
{
/* Only delete the descriptor when SeCaptureSecurityDescriptor() allocated one! */
ExFreePoolWithTag(CapturedSecurityDescriptor, TAG_SD);
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
SeSetSecurityDescriptorInfo(
_In_opt_ PVOID Object,
_In_ PSECURITY_INFORMATION SecurityInformation,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
_Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
_In_ POOL_TYPE PoolType,
_In_ PGENERIC_MAPPING GenericMapping)
{
PAGED_CODE();
return SeSetSecurityDescriptorInfoEx(Object,
SecurityInformation,
SecurityDescriptor,
ObjectsSecurityDescriptor,
0,
PoolType,
GenericMapping);
}
/*
* @implemented
*/
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
SeSetSecurityDescriptorInfoEx(
_In_opt_ PVOID Object,
_In_ PSECURITY_INFORMATION _SecurityInformation,
_In_ PSECURITY_DESCRIPTOR _SecurityDescriptor,
_Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
_In_ ULONG AutoInheritFlags,
_In_ POOL_TYPE PoolType,
_In_ PGENERIC_MAPPING GenericMapping)
{
PISECURITY_DESCRIPTOR_RELATIVE ObjectSd;
PISECURITY_DESCRIPTOR_RELATIVE NewSd;
PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
PSID Owner;
PSID Group;
PACL Dacl;
PACL Sacl;
ULONG OwnerLength;
ULONG GroupLength;
ULONG DaclLength;
ULONG SaclLength;
SECURITY_DESCRIPTOR_CONTROL Control = 0;
ULONG Current;
SECURITY_INFORMATION SecurityInformation;
PAGED_CODE();
ObjectSd = *ObjectsSecurityDescriptor;
/* The object does not have a security descriptor. */
if (!ObjectSd)
return STATUS_NO_SECURITY_ON_OBJECT;
ASSERT(ObjectSd->Control & SE_SELF_RELATIVE);
SecurityInformation = *_SecurityInformation;
/* Get owner and owner size */
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
{
Owner = SepGetOwnerFromDescriptor(SecurityDescriptor);
Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED);
}
else
{
Owner = SepGetOwnerFromDescriptor(ObjectSd);
Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
}
OwnerLength = Owner ? RtlLengthSid(Owner) : 0;
ASSERT(OwnerLength % sizeof(ULONG) == 0);
/* Get group and group size */
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
{
Group = SepGetGroupFromDescriptor(SecurityDescriptor);
Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED);
}
else
{
Group = SepGetGroupFromDescriptor(ObjectSd);
Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
}
GroupLength = Group ? RtlLengthSid(Group) : 0;
ASSERT(GroupLength % sizeof(ULONG) == 0);
/* Get DACL and DACL size */
if (SecurityInformation & DACL_SECURITY_INFORMATION)
{
Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
}
else
{
Dacl = SepGetDaclFromDescriptor(ObjectSd);
Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
}
DaclLength = Dacl ? ROUND_UP((ULONG)Dacl->AclSize, 4) : 0;
/* Get SACL and SACL size */
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
Sacl = SepGetSaclFromDescriptor(SecurityDescriptor);
Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
}
else
{
Sacl = SepGetSaclFromDescriptor(ObjectSd);
Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
}
SaclLength = Sacl ? ROUND_UP((ULONG)Sacl->AclSize, 4) : 0;
NewSd = ExAllocatePoolWithTag(NonPagedPool,
sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
OwnerLength + GroupLength +
DaclLength + SaclLength,
TAG_SD);
if (NewSd == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCreateSecurityDescriptorRelative(NewSd, SECURITY_DESCRIPTOR_REVISION1);
Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
if (OwnerLength != 0)
{
RtlCopyMemory((PUCHAR)NewSd + Current, Owner, OwnerLength);
NewSd->Owner = Current;
Current += OwnerLength;
}
if (GroupLength != 0)
{
RtlCopyMemory((PUCHAR)NewSd + Current, Group, GroupLength);
NewSd->Group = Current;
Current += GroupLength;
}
if (DaclLength != 0)
{
RtlCopyMemory((PUCHAR)NewSd + Current, Dacl, DaclLength);
NewSd->Dacl = Current;
Current += DaclLength;
}
if (SaclLength != 0)
{
RtlCopyMemory((PUCHAR)NewSd + Current, Sacl, SaclLength);
NewSd->Sacl = Current;
Current += SaclLength;
}
NewSd->Control |= Control;
*ObjectsSecurityDescriptor = NewSd;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
BOOLEAN NTAPI
SeValidSecurityDescriptor(IN ULONG Length,
IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
{
ULONG SdLength;
PISID Sid;
PACL Acl;
PISECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor = _SecurityDescriptor;
if (Length < SECURITY_DESCRIPTOR_MIN_LENGTH)
{
DPRINT1("Invalid Security Descriptor revision\n");
return FALSE;
}
if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
{
DPRINT1("Invalid Security Descriptor revision\n");
return FALSE;
}
if (!(SecurityDescriptor->Control & SE_SELF_RELATIVE))
{
DPRINT1("No self-relative Security Descriptor\n");
return FALSE;
}
SdLength = sizeof(SECURITY_DESCRIPTOR);
/* Check Owner SID */
if (!SecurityDescriptor->Owner)
{
DPRINT1("No Owner SID\n");
return FALSE;
}
if (SecurityDescriptor->Owner % sizeof(ULONG))
{
DPRINT1("Invalid Owner SID alignment\n");
return FALSE;
}
Sid = (PISID)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Owner);
if (Sid->Revision != SID_REVISION)
{
DPRINT1("Invalid Owner SID revision\n");
return FALSE;
}
SdLength += (sizeof(SID) + (Sid->SubAuthorityCount - 1) * sizeof(ULONG));
if (Length < SdLength)
{
DPRINT1("Invalid Owner SID size\n");
return FALSE;
}
/* Check Group SID */
if (SecurityDescriptor->Group)
{
if (SecurityDescriptor->Group % sizeof(ULONG))
{
DPRINT1("Invalid Group SID alignment\n");
return FALSE;
}
Sid = (PSID)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Group);
if (Sid->Revision != SID_REVISION)
{
DPRINT1("Invalid Group SID revision\n");
return FALSE;
}
SdLength += (sizeof(SID) + (Sid->SubAuthorityCount - 1) * sizeof(ULONG));
if (Length < SdLength)
{
DPRINT1("Invalid Group SID size\n");
return FALSE;
}
}
/* Check DACL */
if (SecurityDescriptor->Dacl)
{
if (SecurityDescriptor->Dacl % sizeof(ULONG))
{
DPRINT1("Invalid DACL alignment\n");
return FALSE;
}
Acl = (PACL)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Dacl);
if ((Acl->AclRevision < MIN_ACL_REVISION) ||
(Acl->AclRevision > MAX_ACL_REVISION))
{
DPRINT1("Invalid DACL revision\n");
return FALSE;
}
SdLength += Acl->AclSize;
if (Length < SdLength)
{
DPRINT1("Invalid DACL size\n");
return FALSE;
}
}
/* Check SACL */
if (SecurityDescriptor->Sacl)
{
if (SecurityDescriptor->Sacl % sizeof(ULONG))
{
DPRINT1("Invalid SACL alignment\n");
return FALSE;
}
Acl = (PACL)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Sacl);
if ((Acl->AclRevision < MIN_ACL_REVISION) ||
(Acl->AclRevision > MAX_ACL_REVISION))
{
DPRINT1("Invalid SACL revision\n");
return FALSE;
}
SdLength += Acl->AclSize;
if (Length < SdLength)
{
DPRINT1("Invalid SACL size\n");
return FALSE;
}
}
return TRUE;
}
/*
* @implemented
*/
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
SeDeassignSecurity(
_Inout_ PSECURITY_DESCRIPTOR *SecurityDescriptor)
{
PAGED_CODE();
if (*SecurityDescriptor != NULL)
{
ExFreePoolWithTag(*SecurityDescriptor, TAG_SD);
*SecurityDescriptor = NULL;
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
SeAssignSecurityEx(
_In_opt_ PSECURITY_DESCRIPTOR _ParentDescriptor,
_In_opt_ PSECURITY_DESCRIPTOR _ExplicitDescriptor,
_Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
_In_opt_ GUID *ObjectType,
_In_ BOOLEAN IsDirectoryObject,
_In_ ULONG AutoInheritFlags,
_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
_In_ PGENERIC_MAPPING GenericMapping,
_In_ POOL_TYPE PoolType)
{
PISECURITY_DESCRIPTOR ParentDescriptor = _ParentDescriptor;
PISECURITY_DESCRIPTOR ExplicitDescriptor = _ExplicitDescriptor;
PISECURITY_DESCRIPTOR_RELATIVE Descriptor;
PTOKEN Token;
ULONG OwnerLength;
ULONG GroupLength;
ULONG DaclLength;
ULONG SaclLength;
ULONG Length;
SECURITY_DESCRIPTOR_CONTROL Control = 0;
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);
UNREFERENCED_PARAMETER(PoolType);
PAGED_CODE();
*NewDescriptor = NULL;
if (!ARGUMENT_PRESENT(SubjectContext))
{
return STATUS_NO_TOKEN;
}
/* Lock subject context */
SeLockSubjectContext(SubjectContext);
if (SubjectContext->ClientToken != NULL)
{
Token = SubjectContext->ClientToken;
}
else
{
Token = SubjectContext->PrimaryToken;
}
/* Inherit the Owner SID */
if (ExplicitDescriptor != NULL)
{
DPRINT("Use explicit owner sid!\n");
Owner = SepGetOwnerFromDescriptor(ExplicitDescriptor);
}
if (!Owner)
{
if (AutoInheritFlags & 0x20 /* FIXME: SEF_DEFAULT_OWNER_FROM_PARENT */)
{
DPRINT("Use parent owner sid!\n");
if (!ARGUMENT_PRESENT(ParentDescriptor))
{
SeUnlockSubjectContext(SubjectContext);
return STATUS_INVALID_OWNER;
}
Owner = SepGetOwnerFromDescriptor(ParentDescriptor);
if (!Owner)
{
SeUnlockSubjectContext(SubjectContext);
return STATUS_INVALID_OWNER;
}
}
else
{
DPRINT("Use token owner sid!\n");
Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
}
}
OwnerLength = RtlLengthSid(Owner);
ASSERT(OwnerLength % sizeof(ULONG) == 0);
/* Inherit the Group SID */
if (ExplicitDescriptor != NULL)
{
Group = SepGetGroupFromDescriptor(ExplicitDescriptor);
}
if (!Group)
{
if (AutoInheritFlags & 0x40 /* FIXME: SEF_DEFAULT_GROUP_FROM_PARENT */)
{
DPRINT("Use parent group sid!\n");
if (!ARGUMENT_PRESENT(ParentDescriptor))
{
SeUnlockSubjectContext(SubjectContext);
return STATUS_INVALID_PRIMARY_GROUP;
}
Group = SepGetGroupFromDescriptor(ParentDescriptor);
if (!Group)
{
SeUnlockSubjectContext(SubjectContext);
return STATUS_INVALID_PRIMARY_GROUP;
}
}
else
{
DPRINT("Use token group sid!\n");
Group = Token->PrimaryGroup;
}
}
if (!Group)
{
SeUnlockSubjectContext(SubjectContext);
return STATUS_INVALID_PRIMARY_GROUP;
}
GroupLength = RtlLengthSid(Group);
ASSERT(GroupLength % sizeof(ULONG) == 0);
/* Inherit the DACL */
DaclLength = 0;
ExplicitAcl = NULL;
ExplicitPresent = FALSE;
ExplicitDefaulted = FALSE;
if (ExplicitDescriptor != NULL &&
(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;
ASSERT(DaclLength % sizeof(ULONG) == 0);
/* Inherit the SACL */
SaclLength = 0;
ExplicitAcl = NULL;
ExplicitPresent = FALSE;
ExplicitDefaulted = FALSE;
if (ExplicitDescriptor != NULL &&
(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;
ASSERT(SaclLength % sizeof(ULONG) == 0);
/* Allocate and initialize the new security descriptor */
Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
OwnerLength + GroupLength + DaclLength + SaclLength;
DPRINT("L: sizeof(SECURITY_DESCRIPTOR) %u OwnerLength %lu GroupLength %lu DaclLength %lu SaclLength %lu\n",
sizeof(SECURITY_DESCRIPTOR),
OwnerLength,
GroupLength,
DaclLength,
SaclLength);
Descriptor = ExAllocatePoolWithTag(PagedPool, Length, TAG_SD);
if (Descriptor == NULL)
{
DPRINT1("ExAlloctePool() failed\n");
SeUnlockSubjectContext(SubjectContext);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(Descriptor, Length);
RtlCreateSecurityDescriptor(Descriptor, SECURITY_DESCRIPTOR_REVISION);
Descriptor->Control = Control | SE_SELF_RELATIVE;
Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
if (SaclLength != 0)
{
Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
&SaclLength,
Sacl,
Owner,
Group,
SaclIsInherited,
IsDirectoryObject,
GenericMapping);
ASSERT(Status == STATUS_SUCCESS);
Descriptor->Sacl = Current;
Current += SaclLength;
}
if (DaclLength != 0)
{
Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
&DaclLength,
Dacl,
Owner,
Group,
DaclIsInherited,
IsDirectoryObject,
GenericMapping);
ASSERT(Status == STATUS_SUCCESS);
Descriptor->Dacl = Current;
Current += DaclLength;
}
if (OwnerLength != 0)
{
RtlCopyMemory((PUCHAR)Descriptor + Current, Owner, OwnerLength);
Descriptor->Owner = Current;
Current += OwnerLength;
DPRINT("Owner of %p at %x\n", Descriptor, Descriptor->Owner);
}
else
{
DPRINT("Owner of %p is zero length\n", Descriptor);
}
if (GroupLength != 0)
{
RtlCopyMemory((PUCHAR)Descriptor + Current, Group, GroupLength);
Descriptor->Group = Current;
}
/* Unlock subject context */
SeUnlockSubjectContext(SubjectContext);
*NewDescriptor = Descriptor;
DPRINT("Descriptor %p\n", Descriptor);
ASSERT(RtlLengthSecurityDescriptor(Descriptor));
return STATUS_SUCCESS;
}
/*
* @implemented
*/
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
SeAssignSecurity(
_In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,
_In_opt_ PSECURITY_DESCRIPTOR ExplicitDescriptor,
_Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
_In_ BOOLEAN IsDirectoryObject,
_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
_In_ PGENERIC_MAPPING GenericMapping,
_In_ POOL_TYPE PoolType)
{
PAGED_CODE();
return SeAssignSecurityEx(ParentDescriptor,
ExplicitDescriptor,
NewDescriptor,
NULL,
IsDirectoryObject,
0,
SubjectContext,
GenericMapping,
PoolType);
}
/*
* @implemented
*/
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
SeComputeQuotaInformationSize(
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
_Out_ PULONG QuotaInfoSize)
{
PSID Group;
PACL Dacl;
PAGED_CODE();
*QuotaInfoSize = 0;
/* Validate security descriptor revision */
if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION1)
{
return STATUS_UNKNOWN_REVISION;
}
/* Get group and DACL, if any */
Group = SepGetGroupFromDescriptor(SecurityDescriptor);
Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
/* Return SID length if any */
if (Group != NULL)
{
*QuotaInfoSize = ALIGN_UP_BY(RtlLengthSid(Group), sizeof(ULONG));
}
/* Return DACL if any */
if (Dacl != NULL)
{
*QuotaInfoSize += ALIGN_UP_BY(Dacl->AclSize, sizeof(ULONG));
}
return STATUS_SUCCESS;
}
/* EOF */