Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * PURPOSE: Security manager * FILE: lib/rtl/acl.c * PROGRAMER: David Welch <welch@cwcom.net> */
/* INCLUDES *****************************************************************/
#include <rtl.h>#include <../../ntoskrnl/include/internal/se.h>#define NDEBUG#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
BOOLEANNTAPIRtlFirstFreeAce(IN PACL Acl, OUT PACE* FirstFreeAce){ PACE Current; ULONG_PTR AclEnd; ULONG i; PAGED_CODE_RTL();
/* Assume failure */ *FirstFreeAce = NULL;
/* Get the start and end pointers */ Current = (PACE)(Acl + 1); AclEnd = (ULONG_PTR)Acl + Acl->AclSize;
/* Loop all the ACEs */ for (i = 0; i < Acl->AceCount; i++) { /* If any is beyond the DACL, bail out, otherwise keep going */ if ((ULONG_PTR)Current >= AclEnd) return FALSE; Current = (PACE)((ULONG_PTR)Current + Current->Header.AceSize); }
/* If the last spot is empty and still valid, return it */ if ((ULONG_PTR)Current <= AclEnd) *FirstFreeAce = Current; return TRUE;}
VOIDNTAPIRtlpAddData(IN PVOID AceList, IN ULONG AceListLength, IN PVOID Ace, IN ULONG Offset){ /* Shift the buffer down */ if (Offset > 0) { RtlCopyMemory((PVOID)((ULONG_PTR)Ace + AceListLength), Ace, Offset); }
/* Copy the new data in */ if (AceListLength) RtlCopyMemory(Ace, AceList, AceListLength);}
VOIDNTAPIRtlpDeleteData(IN PVOID Ace, IN ULONG AceSize, IN ULONG Offset){ /* Move the data up */ if (AceSize < Offset) { RtlMoveMemory(Ace, (PVOID)((ULONG_PTR)Ace + AceSize), Offset - AceSize); }
/* Zero the rest */ if ((Offset - AceSize) < Offset) { RtlZeroMemory((PVOID)((ULONG_PTR)Ace + Offset - AceSize), AceSize); }}
NTSTATUSNTAPIRtlpAddKnownAce(IN PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN PSID Sid, IN UCHAR Type){ PKNOWN_ACE Ace; ULONG AceSize, InvalidFlags; PAGED_CODE_RTL();
/* Check the validity of the SID */ if (!RtlValidSid(Sid)) return STATUS_INVALID_SID;
/* Check the validity of the revision */ if ((Acl->AclRevision > ACL_REVISION4) || (Revision > ACL_REVISION4)) { return STATUS_REVISION_MISMATCH; }
/* Pick the smallest of the revisions */ if (Revision < Acl->AclRevision) Revision = Acl->AclRevision;
/* Validate the flags */ if (Type == SYSTEM_AUDIT_ACE_TYPE) { InvalidFlags = Flags & ~(VALID_INHERIT_FLAGS | SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG); } else { InvalidFlags = Flags & ~VALID_INHERIT_FLAGS; }
/* If flags are invalid, bail out */ if (InvalidFlags != 0) return STATUS_INVALID_PARAMETER;
/* If ACL is invalid, bail out */ if (!RtlValidAcl(Acl)) return STATUS_INVALID_ACL;
/* If there's no free ACE, bail out */ if (!RtlFirstFreeAce(Acl, (PACE*)&Ace)) return STATUS_INVALID_ACL;
/* Calculate the size of the ACE and bail out if it's too small */ AceSize = RtlLengthSid(Sid) + sizeof(ACE); if (!(Ace) || ((ULONG_PTR)Ace + AceSize > (ULONG_PTR)Acl + Acl->AclSize)) { return STATUS_ALLOTTED_SPACE_EXCEEDED; }
/* Initialize the header and common fields */ Ace->Header.AceFlags = (BYTE)Flags; Ace->Header.AceType = Type; Ace->Header.AceSize = (WORD)AceSize; Ace->Mask = AccessMask;
/* Copy the SID */ RtlCopySid(RtlLengthSid(Sid), &Ace->SidStart, Sid);
/* Fill out the ACL header and return */ Acl->AceCount++; Acl->AclRevision = (BYTE)Revision; return STATUS_SUCCESS;}
NTSTATUSNTAPIRtlpAddKnownObjectAce(IN PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN GUID *ObjectTypeGuid OPTIONAL, IN GUID *InheritedObjectTypeGuid OPTIONAL, IN PSID Sid, IN UCHAR Type){ PKNOWN_OBJECT_ACE Ace; ULONG_PTR SidStart; ULONG AceSize, InvalidFlags, AceObjectFlags = 0; PAGED_CODE_RTL();
/* Check the validity of the SID */ if (!RtlValidSid(Sid)) return STATUS_INVALID_SID;
/* Check the validity of the revision */ if ((Acl->AclRevision > ACL_REVISION4) || (Revision != ACL_REVISION4)) { return STATUS_REVISION_MISMATCH; }
/* Pick the smallest of the revisions */ if (Revision < Acl->AclRevision) Revision = Acl->AclRevision;
/* Validate the flags */ if ((Type == SYSTEM_AUDIT_OBJECT_ACE_TYPE) || (Type == SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE)) { InvalidFlags = Flags & ~(VALID_INHERIT_FLAGS | SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG); } else { InvalidFlags = Flags & ~VALID_INHERIT_FLAGS; }
/* If flags are invalid, bail out */ if (InvalidFlags != 0) return STATUS_INVALID_PARAMETER;
/* If ACL is invalid, bail out */ if (!RtlValidAcl(Acl)) return STATUS_INVALID_ACL;
/* If there's no free ACE, bail out */ if (!RtlFirstFreeAce(Acl, (PACE*)&Ace)) return STATUS_INVALID_ACL;
/* Calculate the size of the ACE */ AceSize = RtlLengthSid(Sid) + sizeof(ACE) + sizeof(ULONG);
/* Add-in the size of the GUIDs if any and update flags as needed */ if (ObjectTypeGuid) { AceObjectFlags |= ACE_OBJECT_TYPE_PRESENT; AceSize += sizeof(GUID); } if (InheritedObjectTypeGuid) { AceObjectFlags |= ACE_INHERITED_OBJECT_TYPE_PRESENT; AceSize += sizeof(GUID); }
/* Bail out if there's not enough space in the ACL */ if (!(Ace) || ((ULONG_PTR)Ace + AceSize > (ULONG_PTR)Acl + Acl->AclSize)) { return STATUS_ALLOTTED_SPACE_EXCEEDED; }
/* Initialize the header and common fields */ Ace->Header.AceFlags = (BYTE)Flags; Ace->Header.AceType = Type; Ace->Header.AceSize = (WORD)AceSize; Ace->Mask = AccessMask; Ace->Flags = AceObjectFlags;
/* Copy the GUIDs */ SidStart = (ULONG_PTR)&Ace->SidStart; if (ObjectTypeGuid ) { RtlCopyMemory((PVOID)SidStart, ObjectTypeGuid, sizeof(GUID)); SidStart += sizeof(GUID); } if (InheritedObjectTypeGuid) { RtlCopyMemory((PVOID)SidStart, InheritedObjectTypeGuid, sizeof(GUID)); SidStart += sizeof(GUID); }
/* Copy the SID */ RtlCopySid(RtlLengthSid(Sid), (PSID)SidStart, Sid);
/* Fill out the ACL header and return */ Acl->AceCount++; Acl->AclRevision = (BYTE)Revision; return STATUS_SUCCESS;}
/* PUBLIC FUNCTIONS ***********************************************************/
/* * @implemented */NTSTATUSNTAPIRtlAddAccessAllowedAce(IN OUT PACL Acl, IN ULONG Revision, IN ACCESS_MASK AccessMask, IN PSID Sid){ PAGED_CODE_RTL();
/* Call the worker function */ return RtlpAddKnownAce(Acl, Revision, 0, AccessMask, Sid, ACCESS_ALLOWED_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlAddAccessAllowedAceEx(IN OUT PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN PSID Sid){ PAGED_CODE_RTL();
/* Call the worker function */ return RtlpAddKnownAce(Acl, Revision, Flags, AccessMask, Sid, ACCESS_ALLOWED_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlAddAccessAllowedObjectAce(IN OUT PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN GUID *ObjectTypeGuid OPTIONAL, IN GUID *InheritedObjectTypeGuid OPTIONAL, IN PSID Sid){ PAGED_CODE_RTL();
/* Is there no object data? */ if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid)) { /* Use the usual routine */ return RtlpAddKnownAce(Acl, Revision, Flags, AccessMask, Sid, ACCESS_ALLOWED_ACE_TYPE); }
/* Use the object routine */ return RtlpAddKnownObjectAce(Acl, Revision, Flags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, Sid, ACCESS_ALLOWED_OBJECT_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlAddAccessDeniedAce(IN PACL Acl, IN ULONG Revision, IN ACCESS_MASK AccessMask, IN PSID Sid){ PAGED_CODE_RTL();
/* Call the worker function */ return RtlpAddKnownAce(Acl, Revision, 0, AccessMask, Sid, ACCESS_DENIED_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlAddAccessDeniedAceEx(IN OUT PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN PSID Sid){ PAGED_CODE_RTL();
/* Call the worker function */ return RtlpAddKnownAce(Acl, Revision, Flags, AccessMask, Sid, ACCESS_DENIED_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlAddAccessDeniedObjectAce(IN OUT PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN GUID *ObjectTypeGuid OPTIONAL, IN GUID *InheritedObjectTypeGuid OPTIONAL, IN PSID Sid){ PAGED_CODE_RTL();
/* Is there no object data? */ if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid)) { /* Use the usual routine */ return RtlpAddKnownAce(Acl, Revision, Flags, AccessMask, Sid, ACCESS_DENIED_ACE_TYPE); }
/* There's object data, use the object routine */ return RtlpAddKnownObjectAce(Acl, Revision, Flags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, Sid, ACCESS_DENIED_OBJECT_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlAddAuditAccessAce(IN PACL Acl, IN ULONG Revision, IN ACCESS_MASK AccessMask, IN PSID Sid, IN BOOLEAN Success, IN BOOLEAN Failure){ ULONG Flags = 0; PAGED_CODE_RTL();
/* Add flags */ if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG; if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG;
/* Call the worker routine */ return RtlpAddKnownAce(Acl, Revision, Flags, AccessMask, Sid, SYSTEM_AUDIT_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlAddAuditAccessAceEx(IN PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN PSID Sid, IN BOOLEAN Success, IN BOOLEAN Failure){ PAGED_CODE_RTL();
/* Add flags */ if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG; if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG;
/* Call the worker routine */ return RtlpAddKnownAce(Acl, Revision, Flags, AccessMask, Sid, SYSTEM_AUDIT_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlAddAuditAccessObjectAce(IN PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN GUID *ObjectTypeGuid OPTIONAL, IN GUID *InheritedObjectTypeGuid OPTIONAL, IN PSID Sid, IN BOOLEAN Success, IN BOOLEAN Failure){ /* Add flags */ if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG; if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG;
/* Is there no object data? */ if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid)) { /* Call the normal routine */ return RtlpAddKnownAce(Acl, Revision, Flags, AccessMask, Sid, SYSTEM_AUDIT_ACE_TYPE); }
/* There's object data, use the object routine */ return RtlpAddKnownObjectAce(Acl, Revision, Flags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, Sid, SYSTEM_AUDIT_OBJECT_ACE_TYPE);}
/* * @implemented */NTSTATUSNTAPIRtlGetAce(IN PACL Acl, IN ULONG AceIndex, OUT PVOID *Ace){ ULONG i; PAGED_CODE_RTL();
/* Bail out if the revision or the index are invalid */ if ((Acl->AclRevision < MIN_ACL_REVISION) || (Acl->AclRevision > MAX_ACL_REVISION) || (AceIndex >= Acl->AceCount)) { return STATUS_INVALID_PARAMETER; }
/* Loop through the ACEs */ *Ace = (PVOID)((PACE)(Acl + 1)); for (i = 0; i < AceIndex; i++) { /* Bail out if an invalid ACE is ever found */ if ((ULONG_PTR)*Ace >= (ULONG_PTR)Acl + Acl->AclSize) { return STATUS_INVALID_PARAMETER; }
/* Keep going */ *Ace = (PVOID)((PACE)((ULONG_PTR)(*Ace) + ((PACE)(*Ace))->Header.AceSize)); }
/* Check if the last ACE is still valid */ if ((ULONG_PTR)*Ace >= (ULONG_PTR)Acl + Acl->AclSize) { return STATUS_INVALID_PARAMETER; }
/* All good, return */ return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIRtlAddAce(IN PACL Acl, IN ULONG AclRevision, IN ULONG StartingIndex, IN PVOID AceList, IN ULONG AceListLength){ PACE Ace, FreeAce; USHORT NewAceCount; ULONG Index; PAGED_CODE_RTL();
/* Bail out if the ACL is invalid */ if (!RtlValidAcl(Acl)) return STATUS_INVALID_PARAMETER;
/* Bail out if there's no space */ if (!RtlFirstFreeAce(Acl, &FreeAce)) return STATUS_INVALID_PARAMETER;
/* Loop over all the ACEs, keeping track of new ACEs as we go along */ for (Ace = AceList, NewAceCount = 0; Ace < (PACE)((ULONG_PTR)AceList + AceListLength); NewAceCount++) { /* Make sure that the revision of this ACE is valid in this list. The initial check looks strange, but it is what Windows does. */ if (Ace->Header.AceType <= ACCESS_MAX_MS_ACE_TYPE) { if (Ace->Header.AceType > ACCESS_MAX_MS_V3_ACE_TYPE) { if (AclRevision < ACL_REVISION4) return STATUS_INVALID_PARAMETER; } else if (Ace->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE) { if (AclRevision < ACL_REVISION3) return STATUS_INVALID_PARAMETER; } }
/* Move to the next ACE */ Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize); }
/* Bail out if there's no more space for us */ if ((ULONG_PTR)Ace > ((ULONG_PTR)AceList + AceListLength)) { return STATUS_INVALID_PARAMETER; }
/* Bail out if there's no free ACE spot, or if we would overflow it */ if (!(FreeAce) || ((ULONG_PTR)FreeAce + AceListLength > (ULONG_PTR)Acl + Acl->AclSize)) { return STATUS_BUFFER_TOO_SMALL; }
/* Go down the list until we find our index */ Ace = (PACE)(Acl + 1); for (Index = 0; (Index < StartingIndex) && (Index < Acl->AceCount); Index++) { Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize); }
/* Found where we want to do, add us to the list */ RtlpAddData(AceList, AceListLength, Ace, (ULONG_PTR)FreeAce - (ULONG_PTR)Ace);
/* Update the header and return */ Acl->AceCount += NewAceCount; Acl->AclRevision = (UCHAR)min(Acl->AclRevision, AclRevision); return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIRtlDeleteAce(IN PACL Acl, IN ULONG AceIndex){ PACE FreeAce, Ace; PAGED_CODE_RTL();
/* Bail out if the ACL is invalid */ if (!RtlValidAcl(Acl)) return STATUS_INVALID_PARAMETER;
/* Bail out if there's no space or if we're full */ if ((Acl->AceCount <= AceIndex) || !(RtlFirstFreeAce(Acl, &FreeAce))) { return STATUS_INVALID_PARAMETER; }
/* Enumerate until the indexed ACE is reached */ Ace = (PACE)(Acl + 1); while (AceIndex--) Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize);
/* Delete this ACE */ RtlpDeleteData(Ace, Ace->Header.AceSize, (ULONG)((ULONG_PTR)FreeAce - (ULONG_PTR)Ace));
/* Decrease an ACE and return success */ Acl->AceCount--; return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIRtlCreateAcl(IN PACL Acl, IN ULONG AclSize, IN ULONG AclRevision){ PAGED_CODE_RTL();
/* Bail out if too small */ if (AclSize < sizeof(ACL)) return STATUS_BUFFER_TOO_SMALL;
/* Bail out if too large or invalid revision */ if ((AclRevision < MIN_ACL_REVISION) || (AclRevision > MAX_ACL_REVISION) || (AclSize > MAXUSHORT)) { return STATUS_INVALID_PARAMETER; }
/* Setup the header */ Acl->AclSize = (USHORT)ROUND_UP(AclSize, 4); Acl->AclRevision = (UCHAR)AclRevision; Acl->AceCount = 0; Acl->Sbz1 = 0; Acl->Sbz2 = 0; return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIRtlQueryInformationAcl(IN PACL Acl, IN PVOID Information, IN ULONG InformationLength, IN ACL_INFORMATION_CLASS InformationClass){ PACE Ace; PACL_REVISION_INFORMATION RevisionInfo; PACL_SIZE_INFORMATION SizeInfo; PAGED_CODE_RTL();
/* Validate the ACL revision */ if ((Acl->AclRevision < MIN_ACL_REVISION) || (Acl->AclRevision > MAX_ACL_REVISION)) { return STATUS_INVALID_PARAMETER; }
/* Check what the caller is querying */ switch (InformationClass) { /* Revision data */ case AclRevisionInformation:
/* Bail out if the buffer is too small */ if (InformationLength < sizeof(ACL_REVISION_INFORMATION)) { return STATUS_BUFFER_TOO_SMALL; }
/* Return the current revision */ RevisionInfo = (PACL_REVISION_INFORMATION)Information; RevisionInfo->AclRevision = Acl->AclRevision; break;
/* Size data */ case AclSizeInformation:
/* Bail out if the buffer is too small */ if (InformationLength < sizeof(ACL_SIZE_INFORMATION)) { return STATUS_BUFFER_TOO_SMALL; }
/* Bail out if there's no space in the ACL */ if (!RtlFirstFreeAce(Acl, &Ace)) return STATUS_INVALID_PARAMETER;
/* Read the number of ACEs and check if there was a free ACE */ SizeInfo = (PACL_SIZE_INFORMATION)Information; SizeInfo->AceCount = Acl->AceCount; if (Ace) { /* Return how much space there is in the ACL */ SizeInfo->AclBytesInUse = (ULONG_PTR)Ace - (ULONG_PTR)Acl; SizeInfo->AclBytesFree = Acl->AclSize - SizeInfo->AclBytesInUse; } else { /* No free ACE, means the whole ACL is full */ SizeInfo->AclBytesInUse = Acl->AclSize; SizeInfo->AclBytesFree = 0; } break;
default: /* Anything else is illegal */ return STATUS_INVALID_INFO_CLASS; }
/* All done */ return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIRtlSetInformationAcl(IN PACL Acl, IN PVOID Information, IN ULONG InformationLength, IN ACL_INFORMATION_CLASS InformationClass){ PACL_REVISION_INFORMATION Info ; PAGED_CODE_RTL();
/* Validate the ACL revision */ if ((Acl->AclRevision < MIN_ACL_REVISION) || (Acl->AclRevision > MAX_ACL_REVISION)) { return STATUS_INVALID_PARAMETER; }
/* What is the caller trying to set? */ switch (InformationClass) { /* This is the only info class */ case AclRevisionInformation:
/* Make sure the buffer is large enough */ if (InformationLength < sizeof(ACL_REVISION_INFORMATION)) { return STATUS_BUFFER_TOO_SMALL; }
/* Make sure the new revision is within the acceptable bounds*/ Info = (PACL_REVISION_INFORMATION)Information; if (Acl->AclRevision >= Info->AclRevision) { return STATUS_INVALID_PARAMETER; }
/* Set the new revision */ Acl->AclRevision = (BYTE)Info->AclRevision; break;
default: /* Anything else is invalid */ return STATUS_INVALID_INFO_CLASS; }
/* All good */ return STATUS_SUCCESS;}
/* * @implemented */BOOLEANNTAPIRtlValidAcl(IN PACL Acl){ PACE_HEADER Ace; PISID Sid; ULONG i; USHORT RequiredObjectAceSize; PULONG Flags; ULONG GuidSize; PAGED_CODE_RTL();
_SEH2_TRY { /* First, validate the revision */ if ((Acl->AclRevision < MIN_ACL_REVISION) || (Acl->AclRevision > MAX_ACL_REVISION)) { DPRINT1("Invalid ACL revision: %u\n", Acl->AclRevision); _SEH2_YIELD(return FALSE); }
/* Next, validate that the ACL is USHORT-aligned */ if (ROUND_DOWN(Acl->AclSize, sizeof(USHORT)) != Acl->AclSize) { DPRINT1("Misaligned ACL size: %u\n", Acl->AclSize); _SEH2_YIELD(return FALSE); }
/* And that it's big enough */ if (Acl->AclSize < sizeof(ACL)) { DPRINT1("Too small ACL size: %u\n", Acl->AclSize); _SEH2_YIELD(return FALSE); }
/* Loop each ACE */ Ace = (PACE_HEADER)((ULONG_PTR)Acl + sizeof(ACL)); for (i = 0; i < Acl->AceCount; i++) { /* Validate we have space for this ACE header */ if (((ULONG_PTR)Ace + sizeof(ACE_HEADER)) >= ((ULONG_PTR)Acl + Acl->AclSize)) { DPRINT1("Invalid ACE size\n"); _SEH2_YIELD(return FALSE); }
/* Validate the length of this ACE */ if (ROUND_DOWN(Ace->AceSize, sizeof(USHORT)) != Ace->AceSize) { DPRINT1("Invalid ACE size: %lx\n", Ace->AceSize); _SEH2_YIELD(return FALSE); }
/* Validate we have space for the entire ACE */ if (((ULONG_PTR)Ace + Ace->AceSize) > ((ULONG_PTR)Acl + Acl->AclSize)) { DPRINT1("Invalid ACE size %lx %lx\n", Ace->AceSize, Acl->AclSize); _SEH2_YIELD(return FALSE); }
/* Check what kind of ACE this is */ if (Ace->AceType <= ACCESS_MAX_MS_V2_ACE_TYPE) { /* Validate the length of this ACE */ if (ROUND_DOWN(Ace->AceSize, sizeof(ULONG)) != Ace->AceSize) { DPRINT1("Invalid ACE size\n"); _SEH2_YIELD(return FALSE); }
/* The ACE size should at least have enough for the header */ if (Ace->AceSize < sizeof(ACE_HEADER)) { DPRINT1("Invalid ACE size: %lx %lx\n", Ace->AceSize, sizeof(ACE_HEADER)); _SEH2_YIELD(return FALSE); }
/* Check if the SID revision is valid */ Sid = (PISID)&((PKNOWN_ACE)Ace)->SidStart; if (Sid->Revision != SID_REVISION) { DPRINT1("Invalid SID\n"); _SEH2_YIELD(return FALSE); }
/* Check if the SID is out of bounds */ if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) { DPRINT1("Invalid SID\n"); _SEH2_YIELD(return FALSE); }
/* The ACE size should at least have enough for the header and SID */ if (Ace->AceSize < (sizeof(ACE_HEADER) + RtlLengthSid(Sid))) { DPRINT1("Invalid ACE size\n"); _SEH2_YIELD(return FALSE); } } else if (Ace->AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE || Ace->AceType == ACCESS_DENIED_OBJECT_ACE_TYPE) { /* Object ACEs are supported starting with Revision 4 */ if (Acl->AclRevision < ACL_REVISION4) { DPRINT1("Invalid ACL revision for Object ACE: %u\n", Acl->AclRevision); _SEH2_YIELD(return FALSE); }
/* Validate the length of this ACE */ if (ROUND_DOWN(Ace->AceSize, sizeof(ULONG)) != Ace->AceSize) { DPRINT1("Misaligned Object ACE size: %lx\n", Ace->AceSize); _SEH2_YIELD(return FALSE); }
/* The ACE size should at least have enough space for the known object ACE header */ if (Ace->AceSize < sizeof(KNOWN_OBJECT_ACE)) { DPRINT1("Too small Object ACE size to hold KNOWN_OBJECT_ACE header: %lx\n", Ace->AceSize); _SEH2_YIELD(return FALSE); }
/* This ACL may have multiple Object ACEs so reset the size counter */ GuidSize = 0;
/* If we have GUIDs include them */ Flags = (PULONG)&((PKNOWN_OBJECT_ACE)Ace)->Flags; if (*Flags & ACE_OBJECT_TYPE_PRESENT) { GuidSize += sizeof(GUID); }
if (*Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { GuidSize += sizeof(GUID); }
/* Check if the SID revision is valid */ Sid = (PISID)((ULONG_PTR)&((PKNOWN_OBJECT_ACE)Ace)->SidStart + GuidSize); if (Sid->Revision != SID_REVISION) { DPRINT1("Object ACE SID has invalid revision: %u\n", Sid->Revision); _SEH2_YIELD(return FALSE); }
/* Check if the SID is out of bounds */ if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) { DPRINT1("Object ACE SID's sub-authority count is out of bounds: %u\n", Sid->SubAuthorityCount); _SEH2_YIELD(return FALSE); }
/* The ACE size should at least have enough space for the known object ACE header, GUIDs and the SID */ RequiredObjectAceSize = (sizeof(KNOWN_OBJECT_ACE) - sizeof(ULONG)) + GuidSize + RtlLengthSid(Sid); if (Ace->AceSize < RequiredObjectAceSize) { DPRINT1("Too small Object ACE size: AceSize %u RequiredSize %u\n", Ace->AceSize, RequiredObjectAceSize); _SEH2_YIELD(return FALSE); } } else if (Ace->AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE) { DPRINT1("Unsupported ACE in ReactOS, assuming valid\n"); } else if ((Ace->AceType >= ACCESS_MIN_MS_OBJECT_ACE_TYPE) && (Ace->AceType <= ACCESS_MAX_MS_OBJECT_ACE_TYPE)) { DPRINT1("Unsupported ACE in ReactOS, assuming valid\n"); } else { /* Unknown ACE, see if it's as big as a header at least */ if (Ace->AceSize < sizeof(ACE_HEADER)) { DPRINT1("Unknown ACE\n"); _SEH2_YIELD(return FALSE); } }
/* Move to the next ace */ Ace = (PACE_HEADER)((ULONG_PTR)Ace + Ace->AceSize); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Something was invalid, fail */ _SEH2_YIELD(return FALSE); } _SEH2_END;
/* The ACL looks ok */ return TRUE;}
/* EOF */