/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * PURPOSE: Security descriptor functions * FILE: lib/rtl/sd.c * PROGRAMER: David Welch */ /* INCLUDES *****************************************************************/ #include #include "../../ntoskrnl/include/internal/se.h" #define NDEBUG #include /* 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 PISECURITY_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 AbsoluteSD, 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 Sd = (PISECURITY_DESCRIPTOR)AbsoluteSD; PISECURITY_DESCRIPTOR_RELATIVE RelSd = (PISECURITY_DESCRIPTOR_RELATIVE)SelfRelativeSD; PAGED_CODE_RTL(); /* Query all components */ RtlpQuerySecurityDescriptor(Sd, &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, Sd, 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 */