reactos/ntoskrnl/se/sd.c

1475 lines
44 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;
/* 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);
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;
}
*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 */