reactos/sdk/lib/rtl/sd.c
Timo Kreuzer df053d4e43 [RTL] Improve usage of absolte vs self-relative security descriptors
- RtlpQuerySecurityDescriptor: Change argument type of first parameter from PISECURITY_DESCRIPTOR to PSECURITY_DESCRIPTOR, since it handles both absolute and self-relative SDs.
- RtlMakeSelfRelativeSD: rename first parameter from AbsoluteSD to SecurityDescriptor, since it handles both absolute and self-relative SDs.
- SepGetGroupFromDescriptor/SepGetOwnerFromDescriptor/SepGetDaclFromDescriptor/SepGetSaclFromDescriptor: Change parameter type from PVOID to PSECURITY_DESCRIPTOR for clarity.
2023-09-26 18:01:45 +03:00

1206 lines
34 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Security descriptor functions
* FILE: lib/rtl/sd.c
* PROGRAMER: David Welch <welch@cwcom.net>
*/
/* INCLUDES *****************************************************************/
#include <rtl.h>
#include "../../ntoskrnl/include/internal/se.h"
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
BOOLEAN
NTAPI
RtlpValidateSDOffsetAndSize(IN ULONG Offset,
IN ULONG Length,
IN ULONG MinLength,
OUT PULONG MaxLength)
{
/* Assume failure */
*MaxLength = 0;
/* Reject out of bounds lengths */
if (Offset < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) return FALSE;
if (Offset >= Length) return FALSE;
/* Reject insufficient lengths */
if ((Length - Offset) < MinLength) return FALSE;
/* Reject unaligned offsets */
if (ALIGN_DOWN(Offset, ULONG) != Offset) return FALSE;
/* Return length that is safe to read */
*MaxLength = Length - Offset;
return TRUE;
}
VOID
NTAPI
RtlpQuerySecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PSID *Owner,
OUT PULONG OwnerSize,
OUT PSID *PrimaryGroup,
OUT PULONG PrimaryGroupSize,
OUT PACL *Dacl,
OUT PULONG DaclSize,
OUT PACL *Sacl,
OUT PULONG SaclSize)
{
PAGED_CODE_RTL();
/* Get the owner */
*Owner = SepGetOwnerFromDescriptor(SecurityDescriptor);
if (*Owner)
{
/* There's an owner, so align the size */
*OwnerSize = ROUND_UP(RtlLengthSid(*Owner), sizeof(ULONG));
}
else
{
/* No owner, no size */
*OwnerSize = 0;
}
/* Get the group */
*PrimaryGroup = SepGetGroupFromDescriptor(SecurityDescriptor);
if (*PrimaryGroup)
{
/* There's a group, so align the size */
*PrimaryGroupSize = ROUND_UP(RtlLengthSid(*PrimaryGroup), sizeof(ULONG));
}
else
{
/* No group, no size */
*PrimaryGroupSize = 0;
}
/* Get the DACL */
*Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
if (*Dacl)
{
/* There's a DACL, align the size */
*DaclSize = ROUND_UP((*Dacl)->AclSize, sizeof(ULONG));
}
else
{
/* No DACL, no size */
*DaclSize = 0;
}
/* Get the SACL */
*Sacl = SepGetSaclFromDescriptor(SecurityDescriptor);
if (*Sacl)
{
/* There's a SACL, align the size */
*SaclSize = ROUND_UP((*Sacl)->AclSize, sizeof(ULONG));
}
else
{
/* No SACL, no size */
*SaclSize = 0;
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlCreateSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Revision)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revisions */
if (Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Setup an empty SD */
RtlZeroMemory(Sd, sizeof(*Sd));
Sd->Revision = SECURITY_DESCRIPTOR_REVISION;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlCreateSecurityDescriptorRelative(IN PISECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor,
IN ULONG Revision)
{
PAGED_CODE_RTL();
/* Fail on invalid revisions */
if (Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Setup an empty SD */
RtlZeroMemory(SecurityDescriptor, sizeof(*SecurityDescriptor));
SecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
SecurityDescriptor->Control = SE_SELF_RELATIVE;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
ULONG
NTAPI
RtlLengthSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
PISECURITY_DESCRIPTOR Sd;
PSID Owner, Group;
PACL Sacl, Dacl;
ULONG Length;
PAGED_CODE_RTL();
/* Start with the initial length of the SD itself */
Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
if (Sd->Control & SE_SELF_RELATIVE)
{
Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
}
else
{
Length = sizeof(SECURITY_DESCRIPTOR);
}
/* Add the length of the individual subcomponents */
Owner = SepGetOwnerFromDescriptor(Sd);
if (Owner) Length += ROUND_UP(RtlLengthSid(Owner), sizeof(ULONG));
Group = SepGetGroupFromDescriptor(Sd);
if (Group) Length += ROUND_UP(RtlLengthSid(Group), sizeof(ULONG));
Dacl = SepGetDaclFromDescriptor(Sd);
if (Dacl) Length += ROUND_UP(Dacl->AclSize, sizeof(ULONG));
Sacl = SepGetSaclFromDescriptor(Sd);
if (Sacl) Length += ROUND_UP(Sacl->AclSize, sizeof(ULONG));
/* Return the final length */
return Length;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlGetDaclSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PBOOLEAN DaclPresent,
OUT PACL* Dacl,
OUT PBOOLEAN DaclDefaulted)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revisions */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Is there a DACL? */
*DaclPresent = (Sd->Control & SE_DACL_PRESENT) == SE_DACL_PRESENT;
if (*DaclPresent)
{
/* Yes, return it, and check if defaulted */
*Dacl = SepGetDaclFromDescriptor(Sd);
*DaclDefaulted = (Sd->Control & SE_DACL_DEFAULTED) == SE_DACL_DEFAULTED;
}
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlGetSaclSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PBOOLEAN SaclPresent,
OUT PACL* Sacl,
OUT PBOOLEAN SaclDefaulted)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revisions */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Is there a SACL? */
*SaclPresent = (Sd->Control & SE_SACL_PRESENT) == SE_SACL_PRESENT;
if (*SaclPresent)
{
/* Yes, return it, and check if defaulted */
*Sacl = SepGetSaclFromDescriptor(Sd);
*SaclDefaulted = (Sd->Control & SE_SACL_DEFAULTED) == SE_SACL_DEFAULTED;
}
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlGetOwnerSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PSID* Owner,
OUT PBOOLEAN OwnerDefaulted)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revision */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Get the owner and if defaulted */
*Owner = SepGetOwnerFromDescriptor(Sd);
*OwnerDefaulted = (Sd->Control & SE_OWNER_DEFAULTED) == SE_OWNER_DEFAULTED;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlGetGroupSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PSID* Group,
OUT PBOOLEAN GroupDefaulted)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revision */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Get the group and if defaulted */
*Group = SepGetGroupFromDescriptor(Sd);
*GroupDefaulted = (Sd->Control & SE_GROUP_DEFAULTED) == SE_GROUP_DEFAULTED;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlSetDaclSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN BOOLEAN DaclPresent,
IN PACL Dacl,
IN BOOLEAN DaclDefaulted)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revision */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Fail on relative descriptors */
if (Sd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR;
/* Is there a DACL? */
if (!DaclPresent)
{
/* Caller is destroying the DACL, unset the flag and we're done */
Sd->Control = Sd->Control & ~SE_DACL_PRESENT;
return STATUS_SUCCESS;
}
/* Caller is setting a new DACL, set the pointer and flag */
Sd->Dacl = Dacl;
Sd->Control |= SE_DACL_PRESENT;
/* Set if defaulted */
Sd->Control &= ~SE_DACL_DEFAULTED;
if (DaclDefaulted) Sd->Control |= SE_DACL_DEFAULTED;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlSetSaclSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN BOOLEAN SaclPresent,
IN PACL Sacl,
IN BOOLEAN SaclDefaulted)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revision */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Fail on relative descriptors */
if (Sd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR;
/* Is there a SACL? */
if (!SaclPresent)
{
/* Caller is clearing the SACL, unset the flag and we're done */
Sd->Control = Sd->Control & ~SE_SACL_PRESENT;
return STATUS_SUCCESS;
}
/* Caller is setting a new SACL, set it and the flag */
Sd->Sacl = Sacl;
Sd->Control |= SE_SACL_PRESENT;
/* Set if defaulted */
Sd->Control &= ~SE_SACL_DEFAULTED;
if (SaclDefaulted) Sd->Control |= SE_SACL_DEFAULTED;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlSetOwnerSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN PSID Owner,
IN BOOLEAN OwnerDefaulted)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revision */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Fail on relative descriptors */
if (Sd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR;
/* Owner being set or cleared */
Sd->Owner = Owner;
/* Set if defaulted */
Sd->Control &= ~SE_OWNER_DEFAULTED;
if (OwnerDefaulted) Sd->Control |= SE_OWNER_DEFAULTED;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlSetGroupSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN PSID Group,
IN BOOLEAN GroupDefaulted)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Fail on invalid revision */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Fail on relative descriptors */
if (Sd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR;
/* Group being set or cleared */
Sd->Group = Group;
/* Set if defaulted */
Sd->Control &= ~SE_GROUP_DEFAULTED;
if (GroupDefaulted) Sd->Control |= SE_GROUP_DEFAULTED;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlGetControlSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PSECURITY_DESCRIPTOR_CONTROL Control,
OUT PULONG Revision)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Read current revision, even if invalid */
*Revision = Sd->Revision;
/* Fail on invalid revision */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Read current control */
*Control = Sd->Control;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlSetControlSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
/* Check for invalid bits */
if ((ControlBitsOfInterest & ~(SE_DACL_UNTRUSTED |
SE_SERVER_SECURITY |
SE_DACL_AUTO_INHERIT_REQ |
SE_SACL_AUTO_INHERIT_REQ |
SE_DACL_AUTO_INHERITED |
SE_SACL_AUTO_INHERITED |
SE_DACL_PROTECTED |
SE_SACL_PROTECTED)) ||
(ControlBitsToSet & ~ControlBitsOfInterest))
{
/* Fail */
return STATUS_INVALID_PARAMETER;
}
/* Zero the 'bits of interest' */
Sd->Control &= ~ControlBitsOfInterest;
/* Set the 'bits to set' */
Sd->Control |= (ControlBitsToSet & ControlBitsOfInterest);
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
RtlGetSecurityDescriptorRMControl(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PUCHAR RMControl)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Check if there's no valid RM control */
if (!(Sd->Control & SE_RM_CONTROL_VALID))
{
/* Fail and return nothing */
*RMControl = 0;
return FALSE;
}
/* Return it, ironically the member is "should be zero" */
*RMControl = Sd->Sbz1;
return TRUE;
}
/*
* @implemented
*/
VOID
NTAPI
RtlSetSecurityDescriptorRMControl(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN PUCHAR RMControl)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* RM Control is being cleared or set */
if (!RMControl)
{
/* Clear it */
Sd->Control &= ~SE_RM_CONTROL_VALID;
Sd->Sbz1 = 0;
}
else
{
/* Set it */
Sd->Control |= SE_RM_CONTROL_VALID;
Sd->Sbz1 = *RMControl;
}
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlSetAttributesSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN SECURITY_DESCRIPTOR_CONTROL Control,
OUT PULONG Revision)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PAGED_CODE_RTL();
/* Always return revision, even if invalid */
*Revision = Sd->Revision;
/* Fail on invalid revision */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
/* Mask out flags which are not attributes */
Control &= SE_DACL_UNTRUSTED |
SE_SERVER_SECURITY |
SE_DACL_AUTO_INHERIT_REQ |
SE_SACL_AUTO_INHERIT_REQ |
SE_DACL_AUTO_INHERITED |
SE_SACL_AUTO_INHERITED |
SE_DACL_PROTECTED |
SE_SACL_PROTECTED;
/* Call the newer API */
return RtlSetControlSecurityDescriptor(SecurityDescriptor, Control, Control);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlCopySecurityDescriptor(IN PSECURITY_DESCRIPTOR pSourceSecurityDescriptor,
OUT PSECURITY_DESCRIPTOR *pDestinationSecurityDescriptor)
{
PSID Owner, Group;
PACL Dacl, Sacl;
DWORD OwnerLength, GroupLength, DaclLength, SaclLength, TotalLength;
PISECURITY_DESCRIPTOR Sd = pSourceSecurityDescriptor;
/* Get all the components */
RtlpQuerySecurityDescriptor(Sd,
&Owner,
&OwnerLength,
&Group,
&GroupLength,
&Dacl,
&DaclLength,
&Sacl,
&SaclLength);
/* Add up their lengths */
TotalLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
OwnerLength +
GroupLength +
DaclLength +
SaclLength;
/* Allocate a copy */
*pDestinationSecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(),
0,
TotalLength);
if (*pDestinationSecurityDescriptor == NULL) return STATUS_NO_MEMORY;
/* Copy the old in the new */
RtlCopyMemory(*pDestinationSecurityDescriptor, Sd, TotalLength);
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlAbsoluteToSelfRelativeSD(IN PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
IN OUT PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
IN PULONG BufferLength)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)AbsoluteSecurityDescriptor;
PAGED_CODE_RTL();
/* Can't already be relative */
if (Sd->Control & SE_SELF_RELATIVE) return STATUS_BAD_DESCRIPTOR_FORMAT;
/* Call the other API */
return RtlMakeSelfRelativeSD(AbsoluteSecurityDescriptor,
SelfRelativeSecurityDescriptor,
BufferLength);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlMakeSelfRelativeSD(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT PSECURITY_DESCRIPTOR SelfRelativeSD,
IN OUT PULONG BufferLength)
{
PSID Owner, Group;
PACL Sacl, Dacl;
ULONG OwnerLength, GroupLength, SaclLength, DaclLength, TotalLength;
ULONG_PTR Current;
PISECURITY_DESCRIPTOR_RELATIVE RelSd = (PISECURITY_DESCRIPTOR_RELATIVE)SelfRelativeSD;
PAGED_CODE_RTL();
/* Query all components */
RtlpQuerySecurityDescriptor(SecurityDescriptor,
&Owner,
&OwnerLength,
&Group,
&GroupLength,
&Dacl,
&DaclLength,
&Sacl,
&SaclLength);
/* Calculate final length */
TotalLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
OwnerLength +
GroupLength +
SaclLength +
DaclLength;
/* Is there enough space? */
if (*BufferLength < TotalLength)
{
/* Nope, return how much is needed */
*BufferLength = TotalLength;
return STATUS_BUFFER_TOO_SMALL;
}
/* Start fresh */
RtlZeroMemory(RelSd, TotalLength);
/* Copy the header fields */
RtlCopyMemory(RelSd,
SecurityDescriptor,
FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Owner));
/* Set the current copy pointer */
Current = (ULONG_PTR)(RelSd + 1);
/* Is there a SACL? */
if (SaclLength)
{
/* Copy it */
RtlCopyMemory((PVOID)Current, Sacl, SaclLength);
RelSd->Sacl = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
Current += SaclLength;
}
/* Is there a DACL? */
if (DaclLength)
{
/* Copy it */
RtlCopyMemory((PVOID)Current, Dacl, DaclLength);
RelSd->Dacl = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
Current += DaclLength;
}
/* Is there an owner? */
if (OwnerLength)
{
/* Copy it */
RtlCopyMemory((PVOID)Current, Owner, OwnerLength);
RelSd->Owner = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
Current += OwnerLength;
}
/* Is there a group? */
if (GroupLength)
{
/* Copy it */
RtlCopyMemory((PVOID)Current, Group, GroupLength);
RelSd->Group = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
}
/* Mark it as relative */
RelSd->Control |= SE_SELF_RELATIVE;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlSelfRelativeToAbsoluteSD(IN PSECURITY_DESCRIPTOR SelfRelativeSD,
OUT PSECURITY_DESCRIPTOR AbsoluteSD,
IN PULONG AbsoluteSDSize,
IN PACL Dacl,
IN PULONG DaclSize,
IN PACL Sacl,
IN PULONG SaclSize,
IN PSID Owner,
IN PULONG OwnerSize,
IN PSID PrimaryGroup,
IN PULONG PrimaryGroupSize)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)AbsoluteSD;
PISECURITY_DESCRIPTOR RelSd = (PISECURITY_DESCRIPTOR)SelfRelativeSD;
ULONG OwnerLength, GroupLength, DaclLength, SaclLength;
PSID pOwner, pGroup;
PACL pDacl, pSacl;
PAGED_CODE_RTL();
/* Must be relative, otherwiise fail */
if (!(RelSd->Control & SE_SELF_RELATIVE)) return STATUS_BAD_DESCRIPTOR_FORMAT;
/* Get all the components */
RtlpQuerySecurityDescriptor(RelSd,
&pOwner,
&OwnerLength,
&pGroup,
&GroupLength,
&pDacl,
&DaclLength,
&pSacl,
&SaclLength);
/* Fail if there's not enough space */
if (!(Sd) ||
(sizeof(SECURITY_DESCRIPTOR) > *AbsoluteSDSize) ||
(OwnerLength > *OwnerSize) ||
(GroupLength > *PrimaryGroupSize) ||
(DaclLength > *DaclSize) ||
(SaclLength > *SaclSize))
{
/* Return how much space is needed for each components */
*AbsoluteSDSize = sizeof(SECURITY_DESCRIPTOR);
*OwnerSize = OwnerLength;
*PrimaryGroupSize = GroupLength;
*DaclSize = DaclLength;
*SaclSize = SaclLength;
return STATUS_BUFFER_TOO_SMALL;
}
/* Copy the header fields */
RtlMoveMemory(Sd, RelSd, sizeof(SECURITY_DESCRIPTOR_RELATIVE));
/* Wipe out the pointers and the relative flag */
Sd->Owner = NULL;
Sd->Group = NULL;
Sd->Sacl = NULL;
Sd->Dacl = NULL;
Sd->Control &= ~SE_SELF_RELATIVE;
/* Is there an owner? */
if (pOwner)
{
/* Copy it */
RtlMoveMemory(Owner, pOwner, RtlLengthSid(pOwner));
Sd->Owner = Owner;
}
/* Is there a group? */
if (pGroup)
{
/* Copy it */
RtlMoveMemory(PrimaryGroup, pGroup, RtlLengthSid(pGroup));
Sd->Group = PrimaryGroup;
}
/* Is there a DACL? */
if (pDacl)
{
/* Copy it */
RtlMoveMemory(Dacl, pDacl, pDacl->AclSize);
Sd->Dacl = Dacl;
}
/* Is there a SACL? */
if (pSacl)
{
/* Copy it */
RtlMoveMemory(Sacl, pSacl, pSacl->AclSize);
Sd->Sacl = Sacl;
}
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlSelfRelativeToAbsoluteSD2(IN OUT PSECURITY_DESCRIPTOR SelfRelativeSD,
OUT PULONG BufferSize)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SelfRelativeSD;
PISECURITY_DESCRIPTOR_RELATIVE RelSd = (PISECURITY_DESCRIPTOR_RELATIVE)SelfRelativeSD;
PVOID DataStart, DataEnd;
LONG MoveDelta;
ULONG DataSize, OwnerLength, GroupLength, DaclLength, SaclLength;
PSID pOwner, pGroup;
PACL pDacl, pSacl;
PAGED_CODE_RTL();
/* Need input */
if (!RelSd) return STATUS_INVALID_PARAMETER_1;
/* Need to know how much space we have */
if (!BufferSize) return STATUS_INVALID_PARAMETER_2;
/* Input must be relative */
if (!(RelSd->Control & SE_SELF_RELATIVE)) return STATUS_BAD_DESCRIPTOR_FORMAT;
/* Query all the component sizes */
RtlpQuerySecurityDescriptor(Sd,
&pOwner,
&OwnerLength,
&pGroup,
&GroupLength,
&pDacl,
&DaclLength,
&pSacl,
&SaclLength);
/*
* Check if there's a difference in structure layout between relatiev and
* absolute descriptors. On 32-bit, there won't be, since an offset is the
* same size as a pointer (32-bit), but on 64-bit, the offsets remain 32-bit
* as they are not SIZE_T, but ULONG, while the pointers now become 64-bit
* and thus the structure is different */
MoveDelta = sizeof(SECURITY_DESCRIPTOR) - sizeof(SECURITY_DESCRIPTOR_RELATIVE);
if (!MoveDelta)
{
/* So on 32-bit, simply clear the flag... */
Sd->Control &= ~SE_SELF_RELATIVE;
/* Ensure we're *really* on 32-bit */
ASSERT(sizeof(Sd->Owner) == sizeof(RelSd->Owner));
ASSERT(sizeof(Sd->Group) == sizeof(RelSd->Group));
ASSERT(sizeof(Sd->Sacl) == sizeof(RelSd->Sacl));
ASSERT(sizeof(Sd->Dacl) == sizeof(RelSd->Dacl));
/* And simply set pointers where there used to be offsets */
Sd->Owner = pOwner;
Sd->Group = pGroup;
Sd->Sacl = pSacl;
Sd->Dacl = pDacl;
return STATUS_SUCCESS;
}
/*
* Calculate the start and end of the data area, we simply just move the
* data by the difference between the size of the relative and absolute
* security descriptor structure
*/
DataStart = pOwner;
DataEnd = (PVOID)((ULONG_PTR)pOwner + OwnerLength);
/* Is there a group? */
if (pGroup)
{
/* Is the group higher than where we started? */
if (((ULONG_PTR)pGroup < (ULONG_PTR)DataStart) || !DataStart)
{
/* Update the start pointer */
DataStart = pGroup;
}
/* Is the group beyond where we ended? */
if (((ULONG_PTR)pGroup + GroupLength > (ULONG_PTR)DataEnd) || !DataEnd)
{
/* Update the end pointer */
DataEnd = (PVOID)((ULONG_PTR)pGroup + GroupLength);
}
}
/* Is there a DACL? */
if (pDacl)
{
/* Is the DACL higher than where we started? */
if (((ULONG_PTR)pDacl < (ULONG_PTR)DataStart) || !DataStart)
{
/* Update the start pointer */
DataStart = pDacl;
}
/* Is the DACL beyond where we ended? */
if (((ULONG_PTR)pDacl + DaclLength > (ULONG_PTR)DataEnd) || !DataEnd)
{
/* Update the end pointer */
DataEnd = (PVOID)((ULONG_PTR)pDacl + DaclLength);
}
}
/* Is there a SACL? */
if (pSacl)
{
/* Is the SACL higher than where we started? */
if (((ULONG_PTR)pSacl < (ULONG_PTR)DataStart) || !DataStart)
{
/* Update the start pointer */
DataStart = pSacl;
}
/* Is the SACL beyond where we ended? */
if (((ULONG_PTR)pSacl + SaclLength > (ULONG_PTR)DataEnd) || !DataEnd)
{
/* Update the end pointer */
DataEnd = (PVOID)((ULONG_PTR)pSacl + SaclLength);
}
}
/* Sanity check */
ASSERT((ULONG_PTR)DataEnd >= (ULONG_PTR)DataStart);
/* Now compute the difference between relative and absolute */
DataSize = (ULONG)((ULONG_PTR)DataEnd - (ULONG_PTR)DataStart);
/* Is the new buffer large enough for this difference? */
if (*BufferSize < sizeof(SECURITY_DESCRIPTOR) + DataSize)
{
/* Nope, bail out */
*BufferSize = sizeof(SECURITY_DESCRIPTOR) + DataSize;
return STATUS_BUFFER_TOO_SMALL;
}
/* Is there anything actually to copy? */
if (DataSize)
{
/*
* There must be at least one SID or ACL in the security descriptor!
* Also the data area must be located somewhere after the end of the
* SECURITY_DESCRIPTOR_RELATIVE structure
*/
ASSERT(DataStart != NULL);
ASSERT((ULONG_PTR)DataStart >= (ULONG_PTR)(RelSd + 1));
/* It's time to move the data */
RtlMoveMemory((PVOID)(Sd + 1),
DataStart,
DataSize);
}
/* Is there an owner? */
if (pOwner)
{
/* Set the pointer to the relative position */
Sd->Owner = (PSID)((LONG_PTR)pOwner + MoveDelta);
}
else
{
/* No owner, clear the pointer */
Sd->Owner = NULL;
}
/* Is there a group */
if (pGroup)
{
/* Set the pointer to the relative position */
Sd->Group = (PSID)((LONG_PTR)pGroup + MoveDelta);
}
else
{
/* No group, clear the pointer */
Sd->Group = NULL;
}
/* Is there a SACL? */
if (pSacl)
{
/* Set the pointer to the relative position */
Sd->Sacl = (PACL)((LONG_PTR)pSacl + MoveDelta);
}
else
{
/* No SACL, clear the pointer */
Sd->Sacl = NULL;
}
/* Is there a DACL? */
if (pDacl)
{
/* Set the pointer to the relative position */
Sd->Dacl = (PACL)((LONG_PTR)pDacl + MoveDelta);
}
else
{
/* No DACL, clear the pointer */
Sd->Dacl = NULL;
}
/* Clear the self-relative flag */
Sd->Control &= ~SE_SELF_RELATIVE;
/* All good */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
RtlValidSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
PSID Owner, Group;
PACL Sacl, Dacl;
PAGED_CODE_RTL();
_SEH2_TRY
{
/* Fail on bad revisions */
if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) _SEH2_YIELD(return FALSE);
/* Owner SID must be valid if present */
Owner = SepGetOwnerFromDescriptor(Sd);
if ((Owner) && (!RtlValidSid(Owner))) _SEH2_YIELD(return FALSE);
/* Group SID must be valid if present */
Group = SepGetGroupFromDescriptor(Sd);
if ((Group) && (!RtlValidSid(Group))) _SEH2_YIELD(return FALSE);
/* DACL must be valid if present */
Dacl = SepGetDaclFromDescriptor(Sd);
if ((Dacl) && (!RtlValidAcl(Dacl))) _SEH2_YIELD(return FALSE);
/* SACL must be valid if present */
Sacl = SepGetSaclFromDescriptor(Sd);
if ((Sacl) && (!RtlValidAcl(Sacl))) _SEH2_YIELD(return FALSE);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Access fault, bail out */
_SEH2_YIELD(return FALSE);
}
_SEH2_END;
/* All good */
return TRUE;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
RtlValidRelativeSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
IN ULONG SecurityDescriptorLength,
IN SECURITY_INFORMATION RequiredInformation)
{
PISECURITY_DESCRIPTOR_RELATIVE Sd = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptorInput;
PSID Owner, Group;
PACL Dacl, Sacl;
ULONG Length;
PAGED_CODE_RTL();
/* Note that Windows allows no DACL/SACL even if RequiredInfo wants it */
/* Do we have enough space, is the revision vaild, and is this SD relative? */
if ((SecurityDescriptorLength < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) ||
(Sd->Revision != SECURITY_DESCRIPTOR_REVISION) ||
!(Sd->Control & SE_SELF_RELATIVE))
{
/* Nope, bail out */
return FALSE;
}
/* Is there an owner? */
if (Sd->Owner)
{
/* Try to access it */
if (!RtlpValidateSDOffsetAndSize(Sd->Owner,
SecurityDescriptorLength,
sizeof(SID),
&Length))
{
/* It's beyond the buffer, fail */
return FALSE;
}
/* Read the owner, check if it's valid and if the buffer contains it */
Owner = (PSID)((ULONG_PTR)Sd->Owner + (ULONG_PTR)Sd);
if (!RtlValidSid(Owner) || (Length < RtlLengthSid(Owner))) return FALSE;
}
else if (RequiredInformation & OWNER_SECURITY_INFORMATION)
{
/* No owner but the caller expects one, fail */
return FALSE;
}
/* Is there a group? */
if (Sd->Group)
{
/* Try to access it */
if (!RtlpValidateSDOffsetAndSize(Sd->Group,
SecurityDescriptorLength,
sizeof(SID),
&Length))
{
/* It's beyond the buffer, fail */
return FALSE;
}
/* Read the group, check if it's valid and if the buffer contains it */
Group = (PSID)((ULONG_PTR)Sd->Group + (ULONG_PTR)Sd);
if (!RtlValidSid(Group) || (Length < RtlLengthSid(Group))) return FALSE;
}
else if (RequiredInformation & GROUP_SECURITY_INFORMATION)
{
/* No group, but the caller expects one, fail */
return FALSE;
}
/* Is there a DACL? */
if ((Sd->Control & SE_DACL_PRESENT) == SE_DACL_PRESENT)
{
/* Try to access it */
if (!RtlpValidateSDOffsetAndSize(Sd->Dacl,
SecurityDescriptorLength,
sizeof(ACL),
&Length))
{
/* It's beyond the buffer, fail */
return FALSE;
}
/* Read the DACL, check if it's valid and if the buffer contains it */
Dacl = (PSID)((ULONG_PTR)Sd->Dacl + (ULONG_PTR)Sd);
if (!(RtlValidAcl(Dacl)) || (Length < Dacl->AclSize)) return FALSE;
}
/* Is there a SACL? */
if ((Sd->Control & SE_SACL_PRESENT) == SE_SACL_PRESENT)
{
/* Try to access it */
if (!RtlpValidateSDOffsetAndSize(Sd->Sacl,
SecurityDescriptorLength,
sizeof(ACL),
&Length))
{
/* It's beyond the buffer, fail */
return FALSE;
}
/* Read the SACL, check if it's valid and if the buffer contains it */
Sacl = (PSID)((ULONG_PTR)Sd->Sacl + (ULONG_PTR)Sd);
if (!(RtlValidAcl(Sacl)) || (Length < Sacl->AclSize)) return FALSE;
}
/* All good */
return TRUE;
}
/* EOF */