summaryrefslogtreecommitdiffstats
path: root/private/ntos/rtl/sertl.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/rtl/sertl.c')
-rw-r--r--private/ntos/rtl/sertl.c5010
1 files changed, 5010 insertions, 0 deletions
diff --git a/private/ntos/rtl/sertl.c b/private/ntos/rtl/sertl.c
new file mode 100644
index 000000000..bf44bbf6e
--- /dev/null
+++ b/private/ntos/rtl/sertl.c
@@ -0,0 +1,5010 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sertl.c
+
+Abstract:
+
+ This Module implements many security rtl routines defined in ntseapi.h
+
+Author:
+
+ Jim Kelly (JimK) 23-Mar-1990
+ Robert Reichel (RobertRe) 1-Mar-1991
+
+Environment:
+
+ Pure Runtime Library Routine
+
+Revision History:
+
+
+--*/
+
+
+#include "ntrtlp.h"
+#include <stdio.h>
+#include "seopaque.h"
+#include "sertlp.h"
+
+//
+// BUG, BUG does anybody use this routine - no prototype in ntrtl.h
+//
+
+ULONG
+RtlLengthUsedSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor
+ );
+
+#undef RtlEqualLuid
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlEqualLuid (
+ PLUID Luid1,
+ PLUID Luid2
+ );
+
+#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
+#pragma alloc_text(PAGE,RtlRunEncodeUnicodeString)
+#pragma alloc_text(PAGE,RtlRunDecodeUnicodeString)
+#pragma alloc_text(PAGE,RtlEraseUnicodeString)
+#pragma alloc_text(PAGE,RtlAdjustPrivilege)
+#pragma alloc_text(PAGE,RtlValidSid)
+#pragma alloc_text(PAGE,RtlEqualSid)
+#pragma alloc_text(PAGE,RtlEqualPrefixSid)
+#pragma alloc_text(PAGE,RtlLengthRequiredSid)
+#pragma alloc_text(PAGE,RtlAllocateAndInitializeSid)
+#pragma alloc_text(PAGE,RtlInitializeSid)
+#pragma alloc_text(PAGE,RtlFreeSid)
+#pragma alloc_text(PAGE,RtlIdentifierAuthoritySid)
+#pragma alloc_text(PAGE,RtlSubAuthoritySid)
+#pragma alloc_text(PAGE,RtlSubAuthorityCountSid)
+#pragma alloc_text(PAGE,RtlLengthSid)
+#pragma alloc_text(PAGE,RtlCopySid)
+#pragma alloc_text(PAGE,RtlCopySidAndAttributesArray)
+#pragma alloc_text(PAGE,RtlConvertSidToUnicodeString)
+#pragma alloc_text(PAGE,RtlEqualLuid)
+#pragma alloc_text(PAGE,RtlCopyLuid)
+#pragma alloc_text(PAGE,RtlCopyLuidAndAttributesArray)
+#pragma alloc_text(PAGE,RtlCreateSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlValidSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlLengthSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlLengthUsedSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlGetControlSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlSetDaclSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlGetDaclSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlSetSaclSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlGetSaclSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlSetOwnerSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlGetOwnerSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlSetGroupSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlGetGroupSecurityDescriptor)
+#pragma alloc_text(PAGE,RtlAreAllAccessesGranted)
+#pragma alloc_text(PAGE,RtlAreAnyAccessesGranted)
+#pragma alloc_text(PAGE,RtlMapGenericMask)
+#pragma alloc_text(PAGE,RtlpApplyAclToObject)
+#pragma alloc_text(PAGE,RtlpContainsCreatorGroupSid)
+#pragma alloc_text(PAGE,RtlpContainsCreatorOwnerSid)
+#pragma alloc_text(PAGE,RtlpGenerateInheritAcl)
+#pragma alloc_text(PAGE,RtlpGenerateInheritedAce)
+#pragma alloc_text(PAGE,RtlpInheritAcl)
+#pragma alloc_text(PAGE,RtlpLengthInheritAcl)
+#pragma alloc_text(PAGE,RtlpLengthInheritedAce)
+#pragma alloc_text(PAGE,RtlpValidOwnerSubjectContext)
+#endif
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Local Macros and Symbols //
+// //
+///////////////////////////////////////////////////////////////////////////////
+
+
+#define CREATOR_SID_SIZE 12
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Exported Procedures //
+// //
+///////////////////////////////////////////////////////////////////////////////
+
+
+VOID
+RtlRunEncodeUnicodeString(
+ PUCHAR Seed OPTIONAL,
+ PUNICODE_STRING String
+ )
+
+/*++
+
+Routine Description:
+
+ This function performs a trivial XOR run-encoding of a string.
+ The purpose of this run-encoding is to change the character values
+ to appear somewhat random and typically not printable. This is
+ useful for transforming passwords that you don't want to be easily
+ distinguishable by visually scanning a paging file or memory dump.
+
+
+Arguments:
+
+ Seed - Points to a seed value to use in the encoding. If the
+ pointed to value is zero, then this routine will assign
+ a value.
+
+ String - The string to encode. This string may be decode
+ by passing it and the seed value to RtlRunDecodeUnicodeString().
+
+
+Return Value:
+
+ None - Nothing can really go wrong unless the caller passes bogus
+ parameters. In this case, the caller can catch the access
+ violation.
+
+
+--*/
+{
+
+ LARGE_INTEGER Time;
+ PUCHAR LocalSeed;
+ NTSTATUS Status;
+ ULONG i;
+ PSTRING S;
+
+
+ RTL_PAGED_CODE();
+
+ //
+ // Typecast so we can work on bytes rather than WCHARs
+ //
+
+ S = (PSTRING)((PVOID)String);
+
+ //
+ // If a seed wasn't passed, use the 2nd byte of current time.
+ // This byte seems to be sufficiently random (by observation).
+ //
+
+ if ((*Seed) == 0) {
+ Status = NtQuerySystemTime ( &Time );
+ ASSERT(NT_SUCCESS(Status));
+
+ LocalSeed = (PUCHAR)((PVOID)&Time);
+
+ i = 1;
+
+ (*Seed) = LocalSeed[ i ];
+
+ //
+ // Occasionally, this byte could be zero. That would cause the
+ // string to become un-decodable, since 0 is the magic value that
+ // causes us to re-gen the seed. This loop makes sure that we
+ // never end up with a zero byte (unless time is zero, as well).
+ //
+
+ while ( ((*Seed) == 0) && ( i < sizeof( Time ) ) )
+ {
+ (*Seed) |= LocalSeed[ i++ ] ;
+ }
+
+ if ( (*Seed) == 0 )
+ {
+ (*Seed) = 1;
+ }
+ }
+
+ //
+ // Transform the initial byte.
+ // The funny constant just keeps the first byte from propagating
+ // into the second byte in the next step. Without a funny constant
+ // this would happen for many languages (which typically have every
+ // other byte zero.
+ //
+ //
+
+ if (S->Length >= 1) {
+ S->Buffer[0] ^= ((*Seed) | 0X43);
+ }
+
+
+ //
+ // Now transform the rest of the string
+ //
+
+ for (i=1; i<S->Length; i++) {
+
+ //
+ // There are export issues that cause us to want to
+ // keep this algorithm simple. Please don't change it
+ // without checking with JimK first. Thanks.
+ //
+
+ //
+ // In order to be compatible with zero terminated unicode strings,
+ // this algorithm is designed to not produce a wide character of
+ // zero as long a the seed is not zero.
+ //
+
+ //
+ // Simple running XOR with the previous byte and the
+ // seed value.
+ //
+
+ S->Buffer[i] ^= (S->Buffer[i-1]^(*Seed));
+
+ }
+
+
+ return;
+
+}
+
+
+VOID
+RtlRunDecodeUnicodeString(
+ UCHAR Seed,
+ PUNICODE_STRING String
+ )
+/*++
+
+Routine Description:
+
+ This function performs the inverse of the function performed
+ by RtlRunEncodeUnicodeString(). Please see RtlRunEncodeUnicodeString()
+ for details.
+
+
+Arguments:
+
+ Seed - The seed value to use in RtlRunEncodeUnicodeString().
+
+ String - The string to reveal.
+
+
+Return Value:
+
+ None - Nothing can really go wrong unless the caller passes bogus
+ parameters. In this case, the caller can catch the access
+ violation.
+
+
+--*/
+
+{
+
+ ULONG
+ i;
+
+ PSTRING
+ S;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Typecast so we can work on bytes rather than WCHARs
+ //
+
+ S = (PSTRING)((PVOID)String);
+
+
+ //
+ // Transform the end of the string
+ //
+
+ for (i=S->Length; i>1; i--) {
+
+ //
+ // a simple running XOR with the previous byte and the
+ // seed value.
+ //
+
+ S->Buffer[i-1] ^= (S->Buffer[i-2]^Seed);
+
+ }
+
+ //
+ // Finally, transform the initial byte
+ //
+
+ if (S->Length >= 1) {
+ S->Buffer[0] ^= (Seed | 0X43);
+ }
+
+
+ return;
+}
+
+
+
+VOID
+RtlEraseUnicodeString(
+ PUNICODE_STRING String
+ )
+/*++
+
+Routine Description:
+
+ This function scrubs the passed string by over-writing all
+ characters in the string. The entire string (i.e., MaximumLength)
+ is erased, not just the current length.
+
+
+Argumen ts:
+
+ String - The string to be erased.
+
+
+Return Value:
+
+ None - Nothing can really go wrong unless the caller passes bogus
+ parameters. In this case, the caller can catch the access
+ violation.
+
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ if ((String->Buffer == NULL) || (String->MaximumLength == 0)) {
+ return;
+ }
+
+ RtlZeroMemory( (PVOID)String->Buffer, (ULONG)String->MaximumLength );
+
+ String->Length = 0;
+
+ return;
+}
+
+
+
+NTSTATUS
+RtlAdjustPrivilege(
+ ULONG Privilege,
+ BOOLEAN Enable,
+ BOOLEAN Client,
+ PBOOLEAN WasEnabled
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure enables or disables a privilege process-wide.
+
+Arguments:
+
+ Privilege - The lower 32-bits of the privilege ID to be enabled or
+ disabled. The upper 32-bits is assumed to be zero.
+
+ Enable - A boolean indicating whether the privilege is to be enabled
+ or disabled. TRUE indicates the privilege is to be enabled.
+ FALSE indicates the privilege is to be disabled.
+
+ Client - A boolean indicating whether the privilege should be adjusted
+ in a client token or the process's own token. TRUE indicates
+ the client's token should be used (and an error returned if there
+ is no client token). FALSE indicates the process's token should
+ be used.
+
+ WasEnabled - points to a boolean to receive an indication of whether
+ the privilege was previously enabled or disabled. TRUE indicates
+ the privilege was previously enabled. FALSE indicates the privilege
+ was previoulsy disabled. This value is useful for returning the
+ privilege to its original state after using it.
+
+
+Return Value:
+
+ STATUS_SUCCESS - The privilege has been sucessfully enabled or disabled.
+
+ STATUS_PRIVILEGE_NOT_HELD - The privilege is not held by the specified context.
+
+ Other status values as may be returned by:
+
+ NtOpenProcessToken()
+ NtAdjustPrivilegesToken()
+
+
+--*/
+
+{
+ NTSTATUS
+ Status,
+ TmpStatus;
+
+ HANDLE
+ Token;
+
+ LUID
+ LuidPrivilege;
+
+ PTOKEN_PRIVILEGES
+ NewPrivileges,
+ OldPrivileges;
+
+ ULONG
+ Length;
+
+ UCHAR
+ Buffer1[sizeof(TOKEN_PRIVILEGES)+
+ ((1-ANYSIZE_ARRAY)*sizeof(LUID_AND_ATTRIBUTES))],
+ Buffer2[sizeof(TOKEN_PRIVILEGES)+
+ ((1-ANYSIZE_ARRAY)*sizeof(LUID_AND_ATTRIBUTES))];
+
+
+ RTL_PAGED_CODE();
+
+ NewPrivileges = (PTOKEN_PRIVILEGES)Buffer1;
+ OldPrivileges = (PTOKEN_PRIVILEGES)Buffer2;
+
+ //
+ // Open the appropriate token...
+ //
+
+ if (Client == TRUE) {
+ Status = NtOpenThreadToken(
+ NtCurrentThread(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+ FALSE,
+ &Token
+ );
+ } else {
+
+ Status = NtOpenProcessToken(
+ NtCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+ &Token
+ );
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ return(Status);
+ }
+
+
+
+ //
+ // Initialize the privilege adjustment structure
+ //
+
+ LuidPrivilege = RtlConvertUlongToLuid(Privilege);
+
+
+ NewPrivileges->PrivilegeCount = 1;
+ NewPrivileges->Privileges[0].Luid = LuidPrivilege;
+ NewPrivileges->Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
+
+
+
+ //
+ // Adjust the privilege
+ //
+
+ Status = NtAdjustPrivilegesToken(
+ Token, // TokenHandle
+ FALSE, // DisableAllPrivileges
+ NewPrivileges, // NewPrivileges
+ sizeof(Buffer1), // BufferLength
+ OldPrivileges, // PreviousState (OPTIONAL)
+ &Length // ReturnLength
+ );
+
+
+ TmpStatus = NtClose(Token);
+ ASSERT(NT_SUCCESS(TmpStatus));
+
+
+ //
+ // Map the success code NOT_ALL_ASSIGNED to an appropriate error
+ // since we're only trying to adjust the one privilege.
+ //
+
+ if (Status == STATUS_NOT_ALL_ASSIGNED) {
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ }
+
+
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // If there are no privileges in the previous state, there were
+ // no changes made. The previous state of the privilege
+ // is whatever we tried to change it to.
+ //
+
+ if (OldPrivileges->PrivilegeCount == 0) {
+
+ (*WasEnabled) = Enable;
+
+ } else {
+
+ (*WasEnabled) =
+ (OldPrivileges->Privileges[0].Attributes & SE_PRIVILEGE_ENABLED)
+ ? TRUE : FALSE;
+ }
+ }
+
+ return(Status);
+}
+
+
+BOOLEAN
+RtlValidSid (
+ IN PSID Sid
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure validates an SID's structure.
+
+Arguments:
+
+ Sid - Pointer to the SID structure to validate.
+
+Return Value:
+
+ BOOLEAN - TRUE if the structure of Sid is valid.
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ //
+ // Make sure revision is SID_REVISION and sub authority count is not
+ // greater than maximum number of allowed sub-authorities.
+ //
+
+ try {
+
+ if ((((SID *)Sid)->Revision & 0x0f) == SID_REVISION) {
+ if (((SID *)Sid)->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES) {
+ return TRUE;
+ }
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+ return FALSE;
+ }
+
+ return FALSE;
+
+}
+
+
+
+BOOLEAN
+RtlEqualSid (
+ IN PSID Sid1,
+ IN PSID Sid2
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure tests two SID values for equality.
+
+Arguments:
+
+ Sid1, Sid2 - Supply pointers to the two SID values to compare.
+ The SID structures are assumed to be valid.
+
+Return Value:
+
+ BOOLEAN - TRUE if the value of Sid1 is equal to Sid2, and FALSE
+ otherwise.
+
+--*/
+
+{
+ ULONG SidLength;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Make sure they are the same revision
+ //
+
+ if ( ((SID *)Sid1)->Revision == ((SID *)Sid2)->Revision ) {
+
+ //
+ // Check the SubAuthorityCount first, because it's fast and
+ // can help us exit faster.
+ //
+
+ if ( *RtlSubAuthorityCountSid( Sid1 ) == *RtlSubAuthorityCountSid( Sid2 )) {
+
+ SidLength = SeLengthSid( Sid1 );
+ return( (BOOLEAN)RtlEqualMemory( Sid1, Sid2, SidLength) );
+ }
+ }
+
+ return( FALSE );
+
+}
+
+
+
+BOOLEAN
+RtlEqualPrefixSid (
+ IN PSID Sid1,
+ IN PSID Sid2
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure tests two SID prefix values for equality.
+
+ An SID prefix is the entire SID except for the last sub-authority
+ value.
+
+Arguments:
+
+ Sid1, Sid2 - Supply pointers to the two SID values to compare.
+ The SID structures are assumed to be valid.
+
+Return Value:
+
+ BOOLEAN - TRUE if the prefix value of Sid1 is equal to Sid2, and FALSE
+ otherwise.
+
+--*/
+
+
+{
+ LONG Index;
+
+ //
+ // Typecast to the opaque SID structures.
+ //
+
+ SID *ISid1 = Sid1;
+ SID *ISid2 = Sid2;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Make sure they are the same revision
+ //
+
+ if (ISid1->Revision == ISid2->Revision ) {
+
+ //
+ // Compare IdentifierAuthority values
+ //
+
+ if ( (ISid1->IdentifierAuthority.Value[0] ==
+ ISid2->IdentifierAuthority.Value[0]) &&
+ (ISid1->IdentifierAuthority.Value[1]==
+ ISid2->IdentifierAuthority.Value[1]) &&
+ (ISid1->IdentifierAuthority.Value[2] ==
+ ISid2->IdentifierAuthority.Value[2]) &&
+ (ISid1->IdentifierAuthority.Value[3] ==
+ ISid2->IdentifierAuthority.Value[3]) &&
+ (ISid1->IdentifierAuthority.Value[4] ==
+ ISid2->IdentifierAuthority.Value[4]) &&
+ (ISid1->IdentifierAuthority.Value[5] ==
+ ISid2->IdentifierAuthority.Value[5])
+ ) {
+
+ //
+ // Compare SubAuthorityCount values
+ //
+
+ if (ISid1->SubAuthorityCount == ISid2->SubAuthorityCount) {
+
+ if (ISid1->SubAuthorityCount == 0) {
+ return TRUE;
+ }
+
+ Index = 0;
+ while (Index < (ISid1->SubAuthorityCount - 1)) {
+ if ((ISid1->SubAuthority[Index]) != (ISid2->SubAuthority[Index])) {
+
+ //
+ // Found some SubAuthority values that weren't equal.
+ //
+
+ return FALSE;
+ }
+ Index += 1;
+ }
+
+ //
+ // All SubAuthority values are equal.
+ //
+
+ return TRUE;
+ }
+ }
+ }
+
+ //
+ // Either the Revision, SubAuthorityCount, or IdentifierAuthority values
+ // weren't equal.
+ //
+
+ return FALSE;
+}
+
+
+
+ULONG
+RtlLengthRequiredSid (
+ IN ULONG SubAuthorityCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the length, in bytes, required to store an SID
+ with the specified number of Sub-Authorities.
+
+Arguments:
+
+ SubAuthorityCount - The number of sub-authorities to be stored in the SID.
+
+Return Value:
+
+ ULONG - The length, in bytes, required to store the SID.
+
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ return (8L + (4 * SubAuthorityCount));
+
+}
+
+
+NTSTATUS
+RtlAllocateAndInitializeSid(
+ IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
+ IN UCHAR SubAuthorityCount,
+ IN ULONG SubAuthority0,
+ IN ULONG SubAuthority1,
+ IN ULONG SubAuthority2,
+ IN ULONG SubAuthority3,
+ IN ULONG SubAuthority4,
+ IN ULONG SubAuthority5,
+ IN ULONG SubAuthority6,
+ IN ULONG SubAuthority7,
+ OUT PSID *Sid
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates and initializes a sid with the specified
+ number of sub-authorities (up to 8). A sid allocated with this
+ routine must be freed using RtlFreeSid().
+
+ THIS ROUTINE IS CURRENTLY NOT CALLABLE FROM KERNEL MODE.
+
+Arguments:
+
+ IdentifierAuthority - Pointer to the Identifier Authority value to
+ set in the SID.
+
+ SubAuthorityCount - The number of sub-authorities to place in the SID.
+ This also identifies how many of the SubAuthorityN parameters
+ have meaningful values. This must contain a value from 0 through
+ 8.
+
+ SubAuthority0-7 - Provides the corresponding sub-authority value to
+ place in the SID. For example, a SubAuthorityCount value of 3
+ indicates that SubAuthority0, SubAuthority1, and SubAuthority0
+ have meaningful values and the rest are to be ignored.
+
+ Sid - Receives a pointer to the SID data structure to initialize.
+
+Return Value:
+
+ STATUS_SUCCESS - The SID has been allocated and initialized.
+
+ STATUS_NO_MEMORY - The attempt to allocate memory for the SID
+ failed.
+
+ STATUS_INVALID_SID - The number of sub-authorities specified did
+ not fall in the valid range for this api (0 through 8).
+
+
+--*/
+{
+ PISID ISid;
+
+ RTL_PAGED_CODE();
+
+ if ( SubAuthorityCount > 8 ) {
+ return( STATUS_INVALID_SID );
+ }
+
+ ISid = RtlAllocateHeap( RtlProcessHeap(), 0,
+ RtlLengthRequiredSid(SubAuthorityCount)
+ );
+ if (ISid == NULL) {
+ return(STATUS_NO_MEMORY);
+ }
+
+ ISid->SubAuthorityCount = (UCHAR)SubAuthorityCount;
+ ISid->Revision = 1;
+ ISid->IdentifierAuthority = *IdentifierAuthority;
+
+ switch (SubAuthorityCount) {
+
+ case 8:
+ ISid->SubAuthority[7] = SubAuthority7;
+ case 7:
+ ISid->SubAuthority[6] = SubAuthority6;
+ case 6:
+ ISid->SubAuthority[5] = SubAuthority5;
+ case 5:
+ ISid->SubAuthority[4] = SubAuthority4;
+ case 4:
+ ISid->SubAuthority[3] = SubAuthority3;
+ case 3:
+ ISid->SubAuthority[2] = SubAuthority2;
+ case 2:
+ ISid->SubAuthority[1] = SubAuthority1;
+ case 1:
+ ISid->SubAuthority[0] = SubAuthority0;
+ case 0:
+ ;
+ }
+
+ (*Sid) = ISid;
+ return( STATUS_SUCCESS );
+
+}
+
+
+
+NTSTATUS
+RtlInitializeSid(
+ IN PSID Sid,
+ IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
+ IN UCHAR SubAuthorityCount
+ )
+/*++
+
+Routine Description:
+
+ This function initializes an SID data structure. It does not, however,
+ set the sub-authority values. This must be done separately.
+
+Arguments:
+
+ Sid - Pointer to the SID data structure to initialize.
+
+ IdentifierAuthority - Pointer to the Identifier Authority value to
+ set in the SID.
+
+ SubAuthorityCount - The number of sub-authorities that will be placed in
+ the SID (a separate action).
+
+Return Value:
+
+
+--*/
+{
+ PISID ISid;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Typecast to the opaque SID
+ //
+
+ ISid = (PISID)Sid;
+
+ if ( SubAuthorityCount > SID_MAX_SUB_AUTHORITIES ) {
+ return( STATUS_INVALID_PARAMETER );
+ }
+
+ ISid->SubAuthorityCount = (UCHAR)SubAuthorityCount;
+ ISid->Revision = 1;
+ ISid->IdentifierAuthority = *IdentifierAuthority;
+
+ return( STATUS_SUCCESS );
+
+}
+
+
+PVOID
+RtlFreeSid(
+ IN PSID Sid
+ )
+
+/*++
+
+Routine Description:
+
+ This function is used to free a SID previously allocated using
+ RtlAllocateAndInitializeSid().
+
+ THIS ROUTINE IS CURRENTLY NOT CALLABLE FROM KERNEL MODE.
+
+Arguments:
+
+ Sid - Pointer to the SID to free.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ RTL_PAGED_CODE();
+
+ if (RtlFreeHeap( RtlProcessHeap(), 0, Sid ))
+ return NULL;
+ else
+ return Sid;
+}
+
+
+PSID_IDENTIFIER_AUTHORITY
+RtlIdentifierAuthoritySid(
+ IN PSID Sid
+ )
+/*++
+
+Routine Description:
+
+ This function returns the address of an SID's IdentifierAuthority field.
+
+Arguments:
+
+ Sid - Pointer to the SID data structure.
+
+Return Value:
+
+
+--*/
+{
+ PISID ISid;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Typecast to the opaque SID
+ //
+
+ ISid = (PISID)Sid;
+
+ return &(ISid->IdentifierAuthority);
+
+}
+
+PULONG
+RtlSubAuthoritySid(
+ IN PSID Sid,
+ IN ULONG SubAuthority
+ )
+/*++
+
+Routine Description:
+
+ This function returns the address of a sub-authority array element of
+ an SID.
+
+Arguments:
+
+ Sid - Pointer to the SID data structure.
+
+ SubAuthority - An index indicating which sub-authority is being specified.
+ This value is not compared against the number of sub-authorities in the
+ SID for validity.
+
+Return Value:
+
+
+--*/
+{
+ PISID ISid;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Typecast to the opaque SID
+ //
+
+ ISid = (PISID)Sid;
+
+ return &(ISid->SubAuthority[SubAuthority]);
+
+}
+
+PUCHAR
+RtlSubAuthorityCountSid(
+ IN PSID Sid
+ )
+/*++
+
+Routine Description:
+
+ This function returns the address of the sub-authority count field of
+ an SID.
+
+Arguments:
+
+ Sid - Pointer to the SID data structure.
+
+Return Value:
+
+
+--*/
+{
+ PISID ISid;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Typecast to the opaque SID
+ //
+
+ ISid = (PISID)Sid;
+
+ return &(ISid->SubAuthorityCount);
+
+}
+
+ULONG
+RtlLengthSid (
+ IN PSID Sid
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the length, in bytes, of a structurally valid SID.
+
+Arguments:
+
+ Sid - Points to the SID whose length is to be returned. The
+ SID's structure is assumed to be valid.
+
+Return Value:
+
+ ULONG - The length, in bytes, of the SID.
+
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ return SeLengthSid(Sid);
+}
+
+
+NTSTATUS
+RtlCopySid (
+ IN ULONG DestinationSidLength,
+ OUT PSID DestinationSid,
+ IN PSID SourceSid
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the value of the source SID to the destination
+ SID.
+
+Arguments:
+
+ DestinationSidLength - Indicates the length, in bytes, of the
+ destination SID buffer.
+
+ DestinationSid - Pointer to a buffer to receive a copy of the
+ source Sid value.
+
+ SourceSid - Supplies the Sid value to be copied.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the SID was successfully copied.
+
+ STATUS_BUFFER_TOO_SMALL - Indicates the target buffer wasn't
+ large enough to receive a copy of the SID.
+
+
+--*/
+
+{
+ ULONG SidLength = SeLengthSid(SourceSid);
+
+ RTL_PAGED_CODE();
+
+ if (SidLength > DestinationSidLength) {
+
+ return STATUS_BUFFER_TOO_SMALL;
+
+ }
+
+ //
+ // Buffer is large enough
+ //
+
+ RtlMoveMemory( DestinationSid, SourceSid, SidLength );
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlCopySidAndAttributesArray (
+ IN ULONG ArrayLength,
+ IN PSID_AND_ATTRIBUTES Source,
+ IN ULONG TargetSidBufferSize,
+ OUT PSID_AND_ATTRIBUTES TargetArrayElement,
+ OUT PSID TargetSid,
+ OUT PSID *NextTargetSid,
+ OUT PULONG RemainingTargetSidBufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the value of the source SID_AND_ATTRIBUTES array
+ to the target. The actual SID values are placed according to a separate
+ parameter. This allows multiple arrays to be merged using this service
+ to copy each.
+
+Arguments:
+
+ ArrayLength - Number of elements in the source array to copy.
+
+ Source - Pointer to the source array.
+
+ TargetSidBufferSize - Indicates the length, in bytes, of the buffer
+ to receive the actual SID values. If this value is less than
+ the actual amount needed, then STATUS_BUFFER_TOO_SMALL is returned.
+
+ TargetArrayElement - Indicates where the array elements are to be
+ copied to (but not the SID values themselves).
+
+ TargetSid - Indicates where the target SID values s are to be copied. This
+ is assumed to be ULONG aligned. Each SID value will be copied
+ into this buffer. Each SID will be ULONG aligned.
+
+ NextTargetSid - On completion, will be set to point to the ULONG
+ aligned address following the last SID copied.
+
+ RemainingTargetSidBufferSize - On completion, receives an indicatation
+ of how much of the SID buffer is still unused.
+
+
+Return Value:
+
+ STATUS_SUCCESS - The call completed successfully.
+
+ STATUS_BUFFER_TOO_SMALL - Indicates the buffer to receive the SID
+ values wasn't large enough.
+
+
+
+--*/
+
+{
+
+ ULONG Index = 0;
+ PSID NextSid = TargetSid;
+ ULONG NextSidLength;
+ ULONG AlignedSidLength;
+ ULONG RemainingLength = TargetSidBufferSize;
+
+ RTL_PAGED_CODE();
+
+ while (Index < ArrayLength) {
+
+ NextSidLength = SeLengthSid( Source[Index].Sid );
+ AlignedSidLength = (ULONG)LongAlign(NextSidLength);
+
+ if (NextSidLength > RemainingLength) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ RemainingLength -= AlignedSidLength;
+
+ TargetArrayElement[Index].Sid = NextSid;
+ TargetArrayElement[Index].Attributes = Source[Index].Attributes;
+
+ RtlCopySid( NextSidLength, NextSid, Source[Index].Sid );
+
+ NextSid = (PSID)((ULONG)NextSid + AlignedSidLength);
+
+ Index += 1;
+
+ } //end_while
+
+ (*NextTargetSid) = NextSid;
+ (*RemainingTargetSidBufferSize) = RemainingLength;
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlConvertSidToUnicodeString(
+ PUNICODE_STRING UnicodeString,
+ PSID Sid,
+ BOOLEAN AllocateDestinationString
+ )
+
+/*++
+
+Routine Description:
+
+
+ This function generates a printable unicode string representation
+ of a SID.
+
+ The resulting string will take one of two forms. If the
+ IdentifierAuthority value is not greater than 2^32, then
+ the SID will be in the form:
+
+
+ S-1-281736-12-72-9-110
+ ^ ^^ ^^ ^ ^^^
+ | | | | |
+ +-----+--+-+--+---- Decimal
+
+
+
+ Otherwise it will take the form:
+
+
+ S-1-0x173495281736-12-72-9-110
+ ^^^^^^^^^^^^^^ ^^ ^^ ^ ^^^
+ Hexidecimal | | | |
+ +--+-+--+---- Decimal
+
+
+
+
+
+
+Arguments:
+
+
+
+ UnicodeString - Returns a unicode string that is equivalent to
+ the SID. The maximum length field is only set if
+ AllocateDestinationString is TRUE.
+
+ Sid - Supplies the SID that is to be converted to unicode.
+
+ AllocateDestinationString - Supplies a flag that controls whether or
+ not this API allocates the buffer space for the destination
+ string. If it does, then the buffer must be deallocated using
+ RtlFreeUnicodeString (note that only storage for
+ DestinationString->Buffer is allocated by this API).
+
+Return Value:
+
+ SUCCESS - The conversion was successful
+
+ STATUS_INVALID_SID - The sid provided does not have a valid structure,
+ or has too many sub-authorities (more than SID_MAX_SUB_AUTHORITIES).
+
+ STATUS_NO_MEMORY - There was not sufficient memory to allocate the
+ target string. This is returned only if AllocateDestinationString
+ is specified as TRUE.
+
+ STATUS_BUFFER_OVERFLOW - This is returned only if
+ AllocateDestinationString is specified as FALSE.
+
+
+--*/
+
+{
+ NTSTATUS Status;
+ UCHAR Buffer[256];
+ UCHAR String[256];
+
+ UCHAR i;
+ ULONG Tmp;
+
+ PISID iSid = (PISID)Sid; // pointer to opaque structure
+
+ ANSI_STRING AnsiString;
+
+ RTL_PAGED_CODE();
+
+ if (RtlValidSid( Sid ) != TRUE) {
+ return(STATUS_INVALID_SID);
+ }
+
+
+ _snprintf(Buffer, sizeof(Buffer), "S-%u-", (USHORT)iSid->Revision );
+ strcpy(String, Buffer);
+
+ if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
+ (iSid->IdentifierAuthority.Value[1] != 0) ){
+ _snprintf(Buffer, sizeof(Buffer), "0x%02hx%02hx%02hx%02hx%02hx%02hx",
+ (USHORT)iSid->IdentifierAuthority.Value[0],
+ (USHORT)iSid->IdentifierAuthority.Value[1],
+ (USHORT)iSid->IdentifierAuthority.Value[2],
+ (USHORT)iSid->IdentifierAuthority.Value[3],
+ (USHORT)iSid->IdentifierAuthority.Value[4],
+ (USHORT)iSid->IdentifierAuthority.Value[5] );
+ strcat(String, Buffer);
+
+ } else {
+
+ Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
+ (ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
+ (ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
+ (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
+ _snprintf(Buffer, sizeof(Buffer), "%lu", Tmp);
+ strcat(String, Buffer);
+ }
+
+
+ for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
+ _snprintf(Buffer, sizeof(Buffer), "-%lu", iSid->SubAuthority[i]);
+ strcat(String, Buffer);
+ }
+
+ //
+ // Convert the string to a Unicode String
+ //
+
+ RtlInitString(&AnsiString, (PSZ) String);
+
+ Status = RtlAnsiStringToUnicodeString( UnicodeString,
+ &AnsiString,
+ AllocateDestinationString
+ );
+
+ return(Status);
+}
+
+
+
+
+BOOLEAN
+RtlEqualLuid (
+ IN PLUID Luid1,
+ IN PLUID Luid2
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure test two LUID values for equality.
+
+ This routine is here for backwards compatibility only. New code
+ should use the macro.
+
+Arguments:
+
+ Luid1, Luid2 - Supply pointers to the two LUID values to compare.
+
+Return Value:
+
+ BOOLEAN - TRUE if the value of Luid1 is equal to Luid2, and FALSE
+ otherwise.
+
+
+--*/
+
+{
+ LUID UNALIGNED * TempLuid1;
+ LUID UNALIGNED * TempLuid2;
+
+ RTL_PAGED_CODE();
+
+ return((Luid1->HighPart == Luid2->HighPart) &&
+ (Luid1->LowPart == Luid2->LowPart));
+
+}
+
+
+VOID
+RtlCopyLuid (
+ OUT PLUID DestinationLuid,
+ IN PLUID SourceLuid
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the value of the source LUID to the
+ destination LUID.
+
+Arguments:
+
+ DestinationLuid - Receives a copy of the source Luid value.
+
+ SourceLuid - Supplies the Luid value to be copied. This LUID is
+ assumed to be structurally valid.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ (*DestinationLuid) = (*SourceLuid);
+ return;
+}
+
+VOID
+RtlCopyLuidAndAttributesArray (
+ IN ULONG ArrayLength,
+ IN PLUID_AND_ATTRIBUTES Source,
+ OUT PLUID_AND_ATTRIBUTES Target
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the value of the source LUID_AND_ATTRIBUTES array
+ to the target.
+
+Arguments:
+
+ ArrayLength - Number of elements in the source array to copy.
+
+ Source - The source array.
+
+ Target - Indicates where the array elements are to be copied to.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ ULONG Index = 0;
+
+ RTL_PAGED_CODE();
+
+ while (Index < ArrayLength) {
+
+ Target[Index] = Source[Index];
+
+ Index += 1;
+
+ } //end_while
+
+
+ return;
+
+}
+
+NTSTATUS
+RtlCreateSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN ULONG Revision
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure initializes a new "absolute format" security descriptor.
+ After the procedure call the security descriptor is initialized with no
+ system ACL, no discretionary ACL, no owner, no primary group and
+ all control flags set to false (null).
+
+Arguments:
+
+
+ SecurityDescriptor - Supplies the security descriptor to
+ initialize.
+
+ Revision - Provides the revision level to assign to the security
+ descriptor. This should be one (1) for this release.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision level provided
+ is not supported by this routine.
+
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ //
+ // Check the requested revision
+ //
+
+ if (Revision == SECURITY_DESCRIPTOR_REVISION) {
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ ISecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
+ ISecurityDescriptor->Sbz1 = 0;
+ *(PUSHORT)(&ISecurityDescriptor->Control) = 0;
+ ISecurityDescriptor->Owner = NULL;
+ ISecurityDescriptor->Group = NULL;
+ ISecurityDescriptor->Sacl = NULL;
+ ISecurityDescriptor->Dacl = NULL;
+
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_UNKNOWN_REVISION;
+}
+
+
+BOOLEAN
+RtlValidSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure validates a SecurityDescriptor's structure. This
+ involves validating the revision levels of each component of the
+ security descriptor.
+
+Arguments:
+
+ SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
+ to validate.
+
+Return Value:
+
+ BOOLEAN - TRUE if the structure of SecurityDescriptor is valid.
+
+
+--*/
+
+{
+ PSID Owner;
+ PSID Group;
+ PACL Dacl;
+ PACL Sacl;
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ try {
+
+ //
+ // known revision ?
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return FALSE;
+ }
+
+
+ //
+ // Validate each element contained in the security descriptor
+ //
+
+ if (ISecurityDescriptor->Owner != NULL) {
+ Owner = RtlpOwnerAddrSecurityDescriptor( ISecurityDescriptor );
+ if (!RtlValidSid( Owner )) {
+ return FALSE;
+ }
+ }
+
+ if (ISecurityDescriptor->Group != NULL) {
+ Group = RtlpGroupAddrSecurityDescriptor( ISecurityDescriptor );
+ if (!RtlValidSid( Group )) {
+ return FALSE;
+ }
+ }
+
+ if ( (ISecurityDescriptor->Control & SE_DACL_PRESENT) &&
+ (ISecurityDescriptor->Dacl != NULL) ) {
+ Dacl = RtlpDaclAddrSecurityDescriptor( ISecurityDescriptor );
+ if (!RtlValidAcl( Dacl )) {
+ return FALSE;
+ }
+ }
+
+ if ( (ISecurityDescriptor->Control & SE_SACL_PRESENT) &&
+ (ISecurityDescriptor->Sacl != NULL) ) {
+ Sacl = RtlpSaclAddrSecurityDescriptor( ISecurityDescriptor );
+ if (!RtlValidAcl( Sacl )) {
+ return FALSE;
+ }
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+ return FALSE;
+ }
+
+ //
+ // All components are valid
+ //
+
+ return TRUE;
+
+
+}
+
+
+ULONG
+RtlLengthSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the length, in bytes, necessary to capture a
+ structurally valid SECURITY_DESCRIPTOR. The length includes the length
+ of all associated data structures (like SIDs and ACLs). The length also
+ takes into account the alignment requirements of each component.
+
+ The minimum length of a security descriptor (one which has no associated
+ SIDs or ACLs) is SECURITY_DESCRIPTOR_MIN_LENGTH.
+
+
+Arguments:
+
+ SecurityDescriptor - Points to the SECURITY_DESCRIPTOR whose
+ length is to be returned. The SECURITY_DESCRIPTOR's
+ structure is assumed to be valid.
+
+Return Value:
+
+ ULONG - The length, in bytes, of the SECURITY_DESCRIPTOR.
+
+
+--*/
+
+{
+ ULONG sum;
+
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = (SECURITY_DESCRIPTOR *)SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // The length is the sum of the following:
+ //
+ // SECURITY_DESCRIPTOR_MIN_LENGTH (or sizeof(SECURITY_DESCRIPTOR))
+ // length of Owner SID (if present)
+ // length of Group SID (if present)
+ // length of Discretionary ACL (if present and non-null)
+ // length of System ACL (if present and non-null)
+ //
+
+ sum = sizeof(SECURITY_DESCRIPTOR);
+
+ //
+ // Add in length of Owner SID
+ //
+
+ if (ISecurityDescriptor->Owner != NULL) {
+ sum += (ULONG)(LongAlign(SeLengthSid(RtlpOwnerAddrSecurityDescriptor(ISecurityDescriptor))));
+ }
+
+ //
+ // Add in length of Group SID
+ //
+
+ if (ISecurityDescriptor->Group != NULL) {
+ sum += (ULONG)(LongAlign(SeLengthSid(RtlpGroupAddrSecurityDescriptor(ISecurityDescriptor))));
+ }
+
+ //
+ // Add in used length of Discretionary ACL
+ //
+
+ if ( (ISecurityDescriptor->Control & SE_DACL_PRESENT) &&
+ (ISecurityDescriptor->Dacl != NULL) ) {
+
+ sum += (ULONG)(LongAlign(RtlpDaclAddrSecurityDescriptor(ISecurityDescriptor)->AclSize) );
+ }
+
+ //
+ // Add in used length of System Acl
+ //
+
+ if ( (ISecurityDescriptor->Control & SE_SACL_PRESENT) &&
+ (ISecurityDescriptor->Sacl != NULL) ) {
+ sum += (ULONG)(LongAlign(RtlpSaclAddrSecurityDescriptor(ISecurityDescriptor)->AclSize) );
+ }
+
+ return sum;
+}
+
+
+ULONG
+RtlLengthUsedSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the length, in bytes, in use in a structurally valid
+ SECURITY_DESCRIPTOR.
+
+ This is the number of bytes necessary to capture the security descriptor,
+ which may be less the the current actual length of the security descriptor
+ (RtlLengthSecurityDescriptor() is used to retrieve the actual length).
+
+ Notice that the used length and actual length may differ if either the SACL
+ or DACL include padding bytes.
+
+ The length includes the length of all associated data structures (like SIDs
+ and ACLs). The length also takes into account the alignment requirements
+ of each component.
+
+ The minimum length of a security descriptor (one which has no associated
+ SIDs or ACLs) is SECURITY_DESCRIPTOR_MIN_LENGTH.
+
+
+Arguments:
+
+ SecurityDescriptor - Points to the SECURITY_DESCRIPTOR whose used
+ length is to be returned. The SECURITY_DESCRIPTOR's
+ structure is assumed to be valid.
+
+Return Value:
+
+ ULONG - Number of bytes of the SECURITY_DESCRIPTOR that are in use.
+
+
+--*/
+
+{
+ ULONG sum;
+
+ ACL_SIZE_INFORMATION AclSize;
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = (SECURITY_DESCRIPTOR *)SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // The length is the sum of the following:
+ //
+ // SECURITY_DESCRIPTOR_MIN_LENGTH (or sizeof(SECURITY_DESCRIPTOR))
+ // length of Owner SID (if present)
+ // length of Group SID (if present)
+ // length of Discretionary ACL (if present and non-null)
+ // length of System ACL (if present and non-null)
+ //
+
+ sum = sizeof(SECURITY_DESCRIPTOR);
+
+ //
+ // Add in length of Owner SID
+ //
+
+ if (ISecurityDescriptor->Owner != NULL) {
+ sum += (ULONG)(LongAlign(SeLengthSid(RtlpOwnerAddrSecurityDescriptor(ISecurityDescriptor))));
+ }
+
+ //
+ // Add in length of Group SID
+ //
+
+ if (ISecurityDescriptor->Group != NULL) {
+ sum += (ULONG)(LongAlign(SeLengthSid(RtlpGroupAddrSecurityDescriptor(ISecurityDescriptor))));
+ }
+
+ //
+ // Add in used length of Discretionary ACL
+ //
+
+ if ( (ISecurityDescriptor->Control & SE_DACL_PRESENT) &&
+ (ISecurityDescriptor->Dacl != NULL) ) {
+
+ RtlQueryInformationAcl( RtlpDaclAddrSecurityDescriptor(ISecurityDescriptor),
+ (PVOID)&AclSize,
+ sizeof(AclSize),
+ AclSizeInformation );
+
+ sum += (ULONG)(LongAlign(AclSize.AclBytesInUse));
+ }
+
+ //
+ // Add in used length of System Acl
+ //
+
+ if ( (ISecurityDescriptor->Control & SE_SACL_PRESENT) &&
+ (ISecurityDescriptor->Sacl != NULL) ) {
+
+ RtlQueryInformationAcl( RtlpSaclAddrSecurityDescriptor(ISecurityDescriptor),
+ (PVOID)&AclSize,
+ sizeof(AclSize),
+ AclSizeInformation );
+
+ sum += (ULONG)(LongAlign(AclSize.AclBytesInUse));
+ }
+
+ return sum;
+}
+
+
+
+NTSTATUS
+RtlSetAttributesSecurityDescriptor(
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN SECURITY_DESCRIPTOR_CONTROL Control,
+ IN OUT PULONG Revision
+ )
+{
+ RTL_PAGED_CODE();
+
+ //
+ // Always return the revision value - even if this isn't a valid
+ // security descriptor
+ //
+
+ *Revision = ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision;
+
+ if ( ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision
+ != SECURITY_DESCRIPTOR_REVISION ) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Only allow setting SE_SERVER_SECURITY and SE_DACL_UNTRUSTED
+ //
+
+ if ( Control & (SE_SERVER_SECURITY | SE_DACL_UNTRUSTED) != Control ) {
+ return STATUS_INVALID_PARAMETER ;
+ }
+
+ ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Control |= Control;
+
+ return STATUS_SUCCESS;
+}
+
+
+
+NTSTATUS
+RtlGetControlSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ OUT PSECURITY_DESCRIPTOR_CONTROL Control,
+ OUT PULONG Revision
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure retrieves the control information from a security descriptor.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor.
+
+ Control - Receives the control information.
+
+ Revision - Receives the revision of the security descriptor.
+ This value will always be returned, even if an error
+ is returned by this routine.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ //
+ // Always return the revision value - even if this isn't a valid
+ // security descriptor
+ //
+
+ *Revision = ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision;
+
+
+ if ( ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision
+ != SECURITY_DESCRIPTOR_REVISION ) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+
+ *Control = ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Control;
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlSetDaclSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN BOOLEAN DaclPresent,
+ IN PACL Dacl OPTIONAL,
+ IN BOOLEAN DaclDefaulted OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure sets the discretionary ACL information of an absolute
+ format security descriptor. If there is already a discretionary ACL
+ present in the security descriptor, it is superseded.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor to be which
+ the discretionary ACL is to be added.
+
+ DaclPresent - If FALSE, indicates the DaclPresent flag in the
+ security descriptor should be set to FALSE. In this case,
+ the remaining optional parameters are ignored. Otherwise,
+ the DaclPresent control flag in the security descriptor is
+ set to TRUE and the remaining optional parameters are not
+ ignored.
+
+ Dacl - Supplies the discretionary ACL for the security
+ descriptor. If this optional parameter is not passed, then a
+ null ACL is assigned to the security descriptor. A null
+ discretionary ACL unconditionally grants access. The ACL is
+ referenced by, not copied into, by the security descriptor.
+
+ DaclDefaulted - When set, indicates the discretionary ACL was
+ picked up from some default mechanism (rather than explicitly
+ specified by a user). This value is set in the DaclDefaulted
+ control flag in the security descriptor. If this optional
+ parameter is not passed, then the DaclDefaulted flag will be
+ cleared.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+ STATUS_INVALID_SECURITY_DESCR - Indicates the security descriptor
+ is not an absolute format security descriptor.
+
+
+--*/
+
+{
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Check the revision
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Make sure the descriptor is absolute format
+ //
+
+ if (ISecurityDescriptor->Control & SE_SELF_RELATIVE) {
+ return STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ //
+ // Assign the DaclPresent flag value passed
+ //
+
+
+ if (DaclPresent) {
+
+ ISecurityDescriptor->Control |= SE_DACL_PRESENT;
+
+ //
+ // Assign the ACL address if passed, otherwise set to null.
+ //
+
+ ISecurityDescriptor->Dacl = NULL;
+ if (ARGUMENT_PRESENT(Dacl)) {
+ ISecurityDescriptor->Dacl = Dacl;
+ }
+
+
+
+
+ //
+ // Assign DaclDefaulted flag if passed, otherwise clear it.
+ //
+
+ ISecurityDescriptor->Control &= ~SE_DACL_DEFAULTED;
+ if (DaclDefaulted == TRUE) {
+ ISecurityDescriptor->Control |= SE_DACL_DEFAULTED;
+ }
+ } else {
+
+ ISecurityDescriptor->Control &= ~SE_DACL_PRESENT;
+
+ }
+
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlGetDaclSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ OUT PBOOLEAN DaclPresent,
+ OUT PACL *Dacl,
+ OUT PBOOLEAN DaclDefaulted
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure retrieves the discretionary ACL information of a
+ security descriptor.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor.
+
+ DaclPresent - If TRUE, indicates that the security descriptor
+ does contain a discretionary ACL. In this case, the
+ remaining OUT parameters will receive valid values.
+ Otherwise, the security descriptor does not contain a
+ discretionary ACL and the remaining OUT parameters will not
+ receive valid values.
+
+ Dacl - This value is returned only if the value returned for the
+ DaclPresent flag is TRUE. In this case, the Dacl parameter
+ receives the address of the security descriptor's
+ discretionary ACL. If this value is returned as null, then
+ the security descriptor has a null discretionary ACL.
+
+ DaclDefaulted - This value is returned only if the value returned
+ for the DaclPresent flag is TRUE. In this case, the
+ DaclDefaulted parameter receives the value of the security
+ descriptor's DaclDefaulted control flag.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+
+--*/
+
+{
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Check the revision
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Assign the DaclPresent flag value
+ //
+
+ *DaclPresent = RtlpAreControlBitsSet( ISecurityDescriptor, SE_DACL_PRESENT );
+
+ if (*DaclPresent) {
+
+ //
+ // Assign the ACL address.
+ //
+
+ *Dacl = RtlpDaclAddrSecurityDescriptor(ISecurityDescriptor);
+
+ //
+ // Assign DaclDefaulted flag.
+ //
+
+ *DaclDefaulted = RtlpAreControlBitsSet( ISecurityDescriptor, SE_DACL_DEFAULTED );
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlSetSaclSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN BOOLEAN SaclPresent,
+ IN PACL Sacl OPTIONAL,
+ IN BOOLEAN SaclDefaulted OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure sets the system ACL information of an absolute security
+ descriptor. If there is already a system ACL present in the
+ security descriptor, it is superseded.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor to be which
+ the system ACL is to be added.
+
+ SaclPresent - If FALSE, indicates the SaclPresent flag in the
+ security descriptor should be set to FALSE. In this case,
+ the remaining optional parameters are ignored. Otherwise,
+ the SaclPresent control flag in the security descriptor is
+ set to TRUE and the remaining optional parameters are not
+ ignored.
+
+ Sacl - Supplies the system ACL for the security descriptor. If
+ this optional parameter is not passed, then a null ACL is
+ assigned to the security descriptor. The ACL is referenced
+ by, not copied into, by the security descriptor.
+
+ SaclDefaulted - When set, indicates the system ACL was picked up
+ from some default mechanism (rather than explicitly specified
+ by a user). This value is set in the SaclDefaulted control
+ flag in the security descriptor. If this optional parameter
+ is not passed, then the SaclDefaulted flag will be cleared.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+ STATUS_INVALID_SECURITY_DESCR - Indicates the security descriptor
+ is not an absolute format security descriptor.
+
+
+--*/
+
+{
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Check the revision
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Make sure the descriptor is absolute format
+ //
+
+ if (ISecurityDescriptor->Control & SE_SELF_RELATIVE) {
+ return STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ //
+ // Assign the SaclPresent flag value passed
+ //
+
+
+ if (SaclPresent) {
+
+ ISecurityDescriptor->Control |= SE_SACL_PRESENT;
+
+ //
+ // Assign the ACL address if passed, otherwise set to null.
+ //
+
+ ISecurityDescriptor->Sacl = NULL;
+ if (ARGUMENT_PRESENT(Sacl)) {
+ ISecurityDescriptor->Sacl = Sacl;
+ }
+
+ //
+ // Assign SaclDefaulted flag if passed, otherwise clear it.
+ //
+
+ ISecurityDescriptor->Control &= ~ SE_SACL_DEFAULTED;
+ if (ARGUMENT_PRESENT(SaclDefaulted)) {
+ ISecurityDescriptor->Control |= SE_SACL_DEFAULTED;
+ }
+ } else {
+
+ ISecurityDescriptor->Control &= ~SE_SACL_PRESENT;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlGetSaclSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ OUT PBOOLEAN SaclPresent,
+ OUT PACL *Sacl,
+ OUT PBOOLEAN SaclDefaulted
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure retrieves the system ACL information of a security
+ descriptor.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor.
+
+ SaclPresent - If TRUE, indicates that the security descriptor
+ does contain a system ACL. In this case, the remaining OUT
+ parameters will receive valid values. Otherwise, the
+ security descriptor does not contain a system ACL and the
+ remaining OUT parameters will not receive valid values.
+
+ Sacl - This value is returned only if the value returned for the
+ SaclPresent flag is TRUE. In this case, the Sacl parameter
+ receives the address of the security descriptor's system ACL.
+ If this value is returned as null, then the security
+ descriptor has a null system ACL.
+
+ SaclDefaulted - This value is returned only if the value returned
+ for the SaclPresent flag is TRUE. In this case, the
+ SaclDefaulted parameter receives the value of the security
+ descriptor's SaclDefaulted control flag.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+
+--*/
+
+{
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Check the revision
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Assign the SaclPresent flag value
+ //
+
+ *SaclPresent = RtlpAreControlBitsSet( ISecurityDescriptor, SE_SACL_PRESENT );
+
+ if (*SaclPresent) {
+
+ //
+ // Assign the ACL address.
+ //
+
+ *Sacl = RtlpSaclAddrSecurityDescriptor(ISecurityDescriptor);
+
+ //
+ // Assign SaclDefaulted flag.
+ //
+
+ *SaclDefaulted = RtlpAreControlBitsSet( ISecurityDescriptor, SE_SACL_DEFAULTED );
+
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlSetOwnerSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PSID Owner OPTIONAL,
+ IN BOOLEAN OwnerDefaulted OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure sets the owner information of an absolute security
+ descriptor. If there is already an owner present in the security
+ descriptor, it is superseded.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor in which
+ the owner is to be set. If the security descriptor already
+ includes an owner, it will be superseded by the new owner.
+
+ Owner - Supplies the owner SID for the security descriptor. If
+ this optional parameter is not passed, then the owner is
+ cleared (indicating the security descriptor has no owner).
+ The SID is referenced by, not copied into, the security
+ descriptor.
+
+ OwnerDefaulted - When set, indicates the owner was picked up from
+ some default mechanism (rather than explicitly specified by a
+ user). This value is set in the OwnerDefaulted control flag
+ in the security descriptor. If this optional parameter is
+ not passed, then the SaclDefaulted flag will be cleared.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+ STATUS_INVALID_SECURITY_DESCR - Indicates the security descriptor
+ is not an absolute format security descriptor.
+
+
+--*/
+
+{
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Check the revision
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Make sure the descriptor is absolute format
+ //
+
+ if (ISecurityDescriptor->Control & SE_SELF_RELATIVE) {
+ return STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ //
+ // Assign the Owner field if passed, otherwise clear it.
+ //
+
+ ISecurityDescriptor->Owner = NULL;
+ if (ARGUMENT_PRESENT(Owner)) {
+ ISecurityDescriptor->Owner = Owner;
+ }
+
+ //
+ // Assign the OwnerDefaulted flag if passed, otherwise clear it.
+ //
+
+ ISecurityDescriptor->Control &= ~SE_OWNER_DEFAULTED;
+ if (OwnerDefaulted == TRUE) {
+ ISecurityDescriptor->Control |= SE_OWNER_DEFAULTED;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlGetOwnerSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ OUT PSID *Owner,
+ OUT PBOOLEAN OwnerDefaulted
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure retrieves the owner information of a security
+ descriptor.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor.
+
+ Owner - Receives a pointer to the owner SID. If the security
+ descriptor does not currently contain an owner, then this
+ value will be returned as null. In this case, the remaining
+ OUT parameters are not given valid return values. Otherwise,
+ this parameter points to an SID and the remaining OUT
+ parameters are provided valid return values.
+
+ OwnerDefaulted - This value is returned only if the value
+ returned for the Owner parameter is not null. In this case,
+ the OwnerDefaulted parameter receives the value of the
+ security descriptor's OwnerDefaulted control flag.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+
+--*/
+
+{
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Check the revision
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Return the Owner field value.
+ //
+
+ *Owner = RtlpOwnerAddrSecurityDescriptor(ISecurityDescriptor);
+
+ //
+ // Return the OwnerDefaulted flag value.
+ //
+
+ *OwnerDefaulted = RtlpAreControlBitsSet( ISecurityDescriptor, SE_OWNER_DEFAULTED );
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlSetGroupSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PSID Group OPTIONAL,
+ IN BOOLEAN GroupDefaulted OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure sets the primary group information of an absolute security
+ descriptor. If there is already an primary group present in the
+ security descriptor, it is superseded.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor in which
+ the primary group is to be set. If the security descriptor
+ already includes a primary group, it will be superseded by
+ the new group.
+
+ Group - Supplies the primary group SID for the security
+ descriptor. If this optional parameter is not passed, then
+ the primary group is cleared (indicating the security
+ descriptor has no primary group). The SID is referenced by,
+ not copied into, the security descriptor.
+
+ GroupDefaulted - When set, indicates the owner was picked up from
+ some default mechanism (rather than explicitly specified by a
+ user). This value is set in the OwnerDefaulted control flag
+ in the security descriptor. If this optional parameter is
+ not passed, then the SaclDefaulted flag will be cleared.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+ STATUS_INVALID_SECURITY_DESCR - Indicates the security descriptor
+ is not an absolute format security descriptor.
+
+
+--*/
+
+{
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Check the revision
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Make sure the descriptor is absolute format
+ //
+
+ if (ISecurityDescriptor->Control & SE_SELF_RELATIVE) {
+ return STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ //
+ // Assign the Group field if passed, otherwise clear it.
+ //
+
+ ISecurityDescriptor->Group = NULL;
+ if (ARGUMENT_PRESENT(Group)) {
+ ISecurityDescriptor->Group = Group;
+ }
+
+ //
+ // Assign the GroupDefaulted flag if passed, otherwise clear it.
+ //
+
+ ISecurityDescriptor->Control &= ~SE_GROUP_DEFAULTED;
+ if (ARGUMENT_PRESENT(GroupDefaulted)) {
+ ISecurityDescriptor->Control |= SE_GROUP_DEFAULTED;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlGetGroupSecurityDescriptor (
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ OUT PSID *Group,
+ OUT PBOOLEAN GroupDefaulted
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure retrieves the primary group information of a
+ security descriptor.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor.
+
+ Group - Receives a pointer to the primary group SID. If the
+ security descriptor does not currently contain a primary
+ group, then this value will be returned as null. In this
+ case, the remaining OUT parameters are not given valid return
+ values. Otherwise, this parameter points to an SID and the
+ remaining OUT parameters are provided valid return values.
+
+ GroupDefaulted - This value is returned only if the value
+ returned for the Group parameter is not null. In this case,
+ the GroupDefaulted parameter receives the value of the
+ security descriptor's GroupDefaulted control flag.
+
+Return Value:
+
+ STATUS_SUCCESS - Indicates the call completed successfully.
+
+ STATUS_UNKNOWN_REVISION - Indicates the revision of the security
+ descriptor is not known to the routine. It may be a newer
+ revision than the routine knows about.
+
+
+--*/
+
+{
+
+ //
+ // Typecast to the opaque SECURITY_DESCRIPTOR structure.
+ //
+
+ SECURITY_DESCRIPTOR *ISecurityDescriptor =
+ (SECURITY_DESCRIPTOR *)SecurityDescriptor;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Check the revision
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+ //
+ // Return the Group field value.
+ //
+
+ *Group = RtlpGroupAddrSecurityDescriptor(ISecurityDescriptor);
+
+ //
+ // Return the GroupDefaulted flag value.
+ //
+
+ *GroupDefaulted = RtlpAreControlBitsSet( ISecurityDescriptor, SE_GROUP_DEFAULTED );
+
+ return STATUS_SUCCESS;
+
+}
+
+
+BOOLEAN
+RtlAreAllAccessesGranted(
+ IN ACCESS_MASK GrantedAccess,
+ IN ACCESS_MASK DesiredAccess
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to check a desired access mask against a
+ granted access mask. It is used by the Object Management
+ component when dereferencing a handle.
+
+Arguments:
+
+ GrantedAccess - Specifies the granted access mask.
+
+ DesiredAccess - Specifies the desired access mask.
+
+Return Value:
+
+ BOOLEAN - TRUE if the GrantedAccess mask has all the bits set
+ that the DesiredAccess mask has set. That is, TRUE is
+ returned if all of the desired accesses have been granted.
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ return ((BOOLEAN)((~(GrantedAccess) & (DesiredAccess)) == 0));
+}
+
+
+BOOLEAN
+RtlAreAnyAccessesGranted(
+ IN ACCESS_MASK GrantedAccess,
+ IN ACCESS_MASK DesiredAccess
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to test whether any of a set of desired
+ accesses are granted by a granted access mask. It is used by
+ components other than the the Object Management component for
+ checking access mask subsets.
+
+Arguments:
+
+ GrantedAccess - Specifies the granted access mask.
+
+ DesiredAccess - Specifies the desired access mask.
+
+Return Value:
+
+ BOOLEAN - TRUE if the GrantedAccess mask contains any of the bits
+ specified in the DesiredAccess mask. That is, if any of the
+ desired accesses have been granted, TRUE is returned.
+
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ return ((BOOLEAN)(((GrantedAccess) & (DesiredAccess)) != 0));
+}
+
+
+VOID
+RtlMapGenericMask(
+ IN OUT PACCESS_MASK AccessMask,
+ IN PGENERIC_MAPPING GenericMapping
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps all generic accesses in the provided access mask
+ to specific and standard accesses according to the provided
+ GenericMapping.
+
+Arguments:
+
+ AccessMask - Points to the access mask to be mapped.
+
+ GenericMapping - The mapping of generic to specific and standard
+ access types.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+// //
+// // Make sure the pointer is properly aligned
+// //
+//
+// ASSERT( ((ULONG)AccessMask >> 2) << 2 == (ULONG)AccessMask );
+
+ if (*AccessMask & GENERIC_READ) {
+
+ *AccessMask |= GenericMapping->GenericRead;
+ }
+
+ if (*AccessMask & GENERIC_WRITE) {
+
+ *AccessMask |= GenericMapping->GenericWrite;
+ }
+
+ if (*AccessMask & GENERIC_EXECUTE) {
+
+ *AccessMask |= GenericMapping->GenericExecute;
+ }
+
+ if (*AccessMask & GENERIC_ALL) {
+
+ *AccessMask |= GenericMapping->GenericAll;
+ }
+
+ //
+ // Now clear the generic flags
+ //
+
+ *AccessMask &= ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
+
+ return;
+}
+
+NTSTATUS
+RtlImpersonateSelf(
+ IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine may be used to obtain an Impersonation token representing
+ your own process's context. This may be useful for enabling a privilege
+ for a single thread rather than for the entire process; or changing
+ the default DACL for a single thread.
+
+ The token is assigned to the callers thread.
+
+
+
+Arguments:
+
+ ImpersonationLevel - The level to make the impersonation token.
+
+
+
+Return Value:
+
+ STATUS_SUCCESS - The thread is now impersonating the calling process.
+
+ Other - Status values returned by:
+
+ NtOpenProcessToken()
+ NtDuplicateToken()
+ NtSetInformationThread()
+
+--*/
+
+{
+ NTSTATUS
+ Status,
+ IgnoreStatus;
+
+ HANDLE
+ Token1,
+ Token2;
+
+ OBJECT_ATTRIBUTES
+ ObjectAttributes;
+
+ SECURITY_QUALITY_OF_SERVICE
+ Qos;
+
+
+ RTL_PAGED_CODE();
+
+ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, 0, NULL);
+
+ Qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ Qos.ImpersonationLevel = ImpersonationLevel;
+ Qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ Qos.EffectiveOnly = FALSE;
+ ObjectAttributes.SecurityQualityOfService = &Qos;
+
+ Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_DUPLICATE, &Token1 );
+
+ if (NT_SUCCESS(Status)) {
+ Status = NtDuplicateToken(
+ Token1,
+ TOKEN_IMPERSONATE,
+ &ObjectAttributes,
+ FALSE, //EffectiveOnly
+ TokenImpersonation,
+ &Token2
+ );
+ if (NT_SUCCESS(Status)) {
+ Status = NtSetInformationThread(
+ NtCurrentThread(),
+ ThreadImpersonationToken,
+ &Token2,
+ sizeof(HANDLE)
+ );
+
+ IgnoreStatus = NtClose( Token2 );
+ }
+
+
+ IgnoreStatus = NtClose( Token1 );
+ }
+
+
+ return(Status);
+
+}
+
+#ifndef WIN16
+
+
+
+BOOLEAN
+RtlpValidOwnerSubjectContext(
+ IN HANDLE Token,
+ IN PSID Owner,
+ IN BOOLEAN ServerObject,
+ OUT PNTSTATUS ReturnStatus
+ )
+/*++
+
+Routine Description:
+
+ This routine checks to see whether the provided SID is one the subject
+ is authorized to assign as the owner of objects.
+
+Arguments:
+
+ Token - Points to the subject's effective token
+
+ Owner - Points to the SID to be checked.
+
+ ServerObject - Boolean indicating whether or not this is a server
+ object, meaning it is protected by a primary-client combination.
+
+ ReturnStatus - Status to be passed back to the caller on failure.
+
+Return Value:
+
+ FALSE on failure.
+
+--*/
+
+{
+
+ ULONG Index;
+ BOOLEAN Found;
+ ULONG ReturnLength;
+ PTOKEN_GROUPS GroupIds = NULL;
+ PTOKEN_USER UserId = NULL;
+ BOOLEAN rc = FALSE;
+ PVOID HeapHandle;
+ HANDLE TokenToUse;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Get the handle to the current process heap
+ //
+
+ if ( Owner == NULL ) {
+ return(FALSE);
+ }
+
+ //
+ // If it's not a server object, check the owner against the contents of the
+ // client token. If it is a server object, the owner must be valid in the
+ // primary token.
+ //
+
+ if (!ServerObject) {
+
+ TokenToUse = Token;
+
+ } else {
+
+ *ReturnStatus = NtOpenProcessToken(
+ NtCurrentProcess(),
+ TOKEN_QUERY,
+ &TokenToUse
+ );
+
+ if (!NT_SUCCESS( *ReturnStatus )) {
+ return( FALSE );
+ }
+ }
+
+ HeapHandle = RtlProcessHeap();
+
+ //
+ // Get the User from the Token
+ //
+
+ *ReturnStatus = NtQueryInformationToken(
+ TokenToUse,
+ TokenUser,
+ UserId,
+ 0,
+ &ReturnLength
+ );
+
+ if (!NT_SUCCESS( *ReturnStatus ) && (STATUS_BUFFER_TOO_SMALL != *ReturnStatus)) {
+ if (ServerObject) {
+ NtClose( TokenToUse );
+ }
+ return( FALSE );
+
+ }
+
+ UserId = RtlAllocateHeap( HeapHandle, 0, ReturnLength );
+
+ if (UserId == NULL) {
+
+ *ReturnStatus = STATUS_NO_MEMORY;
+ if (ServerObject) {
+ NtClose( TokenToUse );
+ }
+
+ return( FALSE );
+ }
+
+ *ReturnStatus = NtQueryInformationToken(
+ TokenToUse,
+ TokenUser,
+ UserId,
+ ReturnLength,
+ &ReturnLength
+ );
+
+ if (!NT_SUCCESS( *ReturnStatus )) {
+ if (ServerObject) {
+ NtClose( TokenToUse );
+ }
+ return( FALSE );
+ }
+
+ if ( RtlEqualSid( Owner, UserId->User.Sid ) ) {
+
+ RtlFreeHeap( HeapHandle, 0, (PVOID)UserId );
+ if (ServerObject) {
+ NtClose( TokenToUse );
+ }
+ return( TRUE );
+ }
+
+ RtlFreeHeap( HeapHandle, 0, (PVOID)UserId );
+
+ //
+ // Get the groups from the Token
+ //
+
+ *ReturnStatus = NtQueryInformationToken(
+ TokenToUse,
+ TokenGroups,
+ GroupIds,
+ 0,
+ &ReturnLength
+ );
+
+ if (!NT_SUCCESS( *ReturnStatus ) && (STATUS_BUFFER_TOO_SMALL != *ReturnStatus)) {
+
+ if (ServerObject) {
+ NtClose( TokenToUse );
+ }
+ return( FALSE );
+ }
+
+ GroupIds = RtlAllocateHeap( HeapHandle, 0, ReturnLength );
+
+ if (GroupIds == NULL) {
+
+ *ReturnStatus = STATUS_NO_MEMORY;
+ if (ServerObject) {
+ NtClose( TokenToUse );
+ }
+ return( FALSE );
+ }
+
+ *ReturnStatus = NtQueryInformationToken(
+ TokenToUse,
+ TokenGroups,
+ GroupIds,
+ ReturnLength,
+ &ReturnLength
+ );
+
+ if (ServerObject) {
+ NtClose( TokenToUse );
+ }
+
+ if (!NT_SUCCESS( *ReturnStatus )) {
+ RtlFreeHeap( HeapHandle, 0, GroupIds );
+ return( FALSE );
+ }
+
+ //
+ // Walk through the list of group IDs looking for a match to
+ // the specified SID. If one is found, make sure it may be
+ // assigned as an owner.
+ //
+ // This code is similar to that performed to set the default
+ // owner of a token (NtSetInformationToken).
+ //
+
+ Index = 0;
+ while (Index < GroupIds->GroupCount) {
+
+ Found = RtlEqualSid(
+ Owner,
+ GroupIds->Groups[Index].Sid
+ );
+
+ if ( Found ) {
+
+ if ( RtlpIdAssignableAsOwner(GroupIds->Groups[Index])) {
+
+ RtlFreeHeap( HeapHandle, 0, GroupIds );
+ return( TRUE );
+
+ } else {
+
+ RtlFreeHeap( HeapHandle, 0, GroupIds );
+ return( FALSE );
+
+ } //endif assignable
+
+ } //endif Found
+
+ Index++;
+
+ } //endwhile
+
+ RtlFreeHeap( HeapHandle, 0, GroupIds );
+
+ return ( FALSE );
+}
+
+#if 0
+
+BOOLEAN
+RtlpValidOwnerSubjectContext(
+ IN HANDLE Token,
+ IN PSID Owner,
+ BOOLEAN Dummy,
+ OUT PNTSTATUS ReturnStatus
+ )
+/*++
+
+Routine Description:
+
+ This routine checks to see whether the provided SID is one the subject
+ is authorized to assign as the owner of objects.
+
+Arguments:
+
+ Token - Points to the subject's effective token
+
+ Owner - Points to the SID to be checked.
+
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ULONG Index;
+ BOOLEAN Found;
+ ULONG ReturnLength;
+ PTOKEN_GROUPS GroupIds = NULL;
+ PTOKEN_USER UserId = NULL;
+ BOOLEAN rc = FALSE;
+ NTSTATUS Status;
+ PVOID HeapHandle;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Get the handle to the current process heap
+ //
+
+ if ( Owner == NULL ) {
+ return(FALSE);
+ }
+
+ HeapHandle = RtlProcessHeap();
+
+ *ReturnStatus = STATUS_SUCCESS;
+
+ //
+ // Get the User from the Token
+ //
+
+ Status = NtQueryInformationToken(
+ Token, // Handle
+ TokenUser, // TokenInformationClass
+ UserId, // TokenInformation
+ 0, // TokenInformationLength
+ &ReturnLength // ReturnLength
+ );
+
+ ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
+
+ UserId = RtlAllocateHeap( HeapHandle, 0, ReturnLength );
+
+ if (UserId == NULL) {
+
+ *ReturnStatus = STATUS_NO_MEMORY;
+ return( FALSE );
+ }
+
+
+ Status = NtQueryInformationToken(
+ Token, // Handle
+ TokenUser, // TokenInformationClass
+ UserId, // TokenInformation
+ ReturnLength, // TokenInformationLength
+ &ReturnLength // ReturnLength
+ );
+
+ if (!NT_SUCCESS( Status )) {
+ *ReturnStatus = Status;
+ return( FALSE );
+ }
+
+ if ( RtlEqualSid( Owner, UserId->User.Sid ) ) {
+
+ RtlFreeHeap( HeapHandle, 0, (PVOID)UserId );
+ return( TRUE );
+ }
+
+ RtlFreeHeap( HeapHandle, 0, (PVOID)UserId );
+
+ //
+ // Get the groups from the Token
+ //
+
+ Status = NtQueryInformationToken(
+ Token, // Handle
+ TokenGroups, // TokenInformationClass
+ GroupIds, // TokenInformation
+ 0, // TokenInformationLength
+ &ReturnLength // ReturnLength
+ );
+ ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
+
+
+ GroupIds = RtlAllocateHeap( HeapHandle, 0, ReturnLength );
+
+ if (GroupIds == NULL) {
+
+ *ReturnStatus = STATUS_NO_MEMORY;
+ return( FALSE );
+
+ }
+
+ Status = NtQueryInformationToken(
+ Token, // Handle
+ TokenGroups, // TokenInformationClass
+ GroupIds, // TokenInformation
+ ReturnLength, // TokenInformationLength
+ &ReturnLength // ReturnLength
+ );
+
+
+ if (!NT_SUCCESS( Status )) {
+ RtlFreeHeap( HeapHandle, 0, GroupIds );
+ *ReturnStatus = Status;
+ return( FALSE );
+ }
+
+ //
+ // Walk through the list of group IDs looking for a match to
+ // the specified SID. If one is found, make sure it may be
+ // assigned as an owner.
+ //
+ // This code is similar to that performed to set the default
+ // owner of a token (NtSetInformationToken).
+ //
+
+ Index = 0;
+ while (Index < GroupIds->GroupCount) {
+
+ Found = RtlEqualSid(
+ Owner,
+ GroupIds->Groups[Index].Sid
+ );
+
+ if ( Found ) {
+
+ if ( RtlpIdAssignableAsOwner(GroupIds->Groups[Index])) {
+
+ RtlFreeHeap( HeapHandle, 0, GroupIds );
+ return( TRUE );
+
+ } else {
+
+ RtlFreeHeap( HeapHandle, 0, GroupIds );
+ return( FALSE );
+
+ } //endif assignable
+
+
+ } //endif Found
+
+
+ Index++;
+
+ } //endwhile
+
+ RtlFreeHeap( HeapHandle, 0, GroupIds );
+
+ return ( FALSE );
+
+}
+
+#endif // WIN16
+
+
+#endif
+
+#if 0
+
+
+BOOLEAN
+RtlpContainsCreatorOwnerSid(
+ PKNOWN_ACE Ace
+ )
+/*++
+
+Routine Description:
+
+ Tests to see if the specified ACE contains the CreatorOwnerSid.
+
+Arguments:
+
+ Ace - Pointer to the ACE whose SID is be compared to the Creator Sid.
+ This ACE is assumed to be valid and a known ACE type.
+
+Return Value:
+
+ TRUE - The creator sid is in the ACE.
+
+ FALSE - The creator sid is not in the ACE.
+
+
+--*/
+{
+
+ BOOLEAN IsEqual;
+
+
+ ULONG CreatorSid[CREATOR_SID_SIZE];
+
+
+ SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
+
+ RTL_PAGED_CODE();
+
+ //
+ // This is gross and ugly, but it's better than allocating
+ // virtual memory to hold the CreatorSid, because that can
+ // fail, and propogating the error back is a tremendous pain
+ //
+
+ ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
+
+ //
+ // Allocate and initialize the universal SIDs
+ //
+
+ RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
+
+ *(RtlSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_OWNER_RID;
+
+ IsEqual = RtlEqualSid(&Ace->SidStart, (PSID)CreatorSid );
+
+ return( IsEqual );
+
+}
+
+
+BOOLEAN
+RtlpContainsCreatorGroupSid(
+ PKNOWN_ACE Ace
+ )
+/*++
+
+Routine Description:
+
+ Tests to see if the specified ACE contains the CreatorGroupSid.
+
+Arguments:
+
+ Ace - Pointer to the ACE whose SID is be compared to the Creator Sid.
+ This ACE is assumed to be valid and a known ACE type.
+
+Return Value:
+
+ TRUE - The creator sid is in the ACE.
+
+ FALSE - The creator sid is not in the ACE.
+
+
+--*/
+{
+
+ BOOLEAN IsEqual;
+
+
+ ULONG CreatorSid[CREATOR_SID_SIZE];
+
+
+ SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
+
+ RTL_PAGED_CODE();
+
+ //
+ // This is gross and ugly, but it's better than allocating
+ // virtual memory to hold the CreatorSid, because that can
+ // fail, and propogating the error back is a tremendous pain
+ //
+
+ ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
+
+ //
+ // Allocate and initialize the universal SIDs
+ //
+
+ RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
+
+ *(RtlSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_GROUP_RID;
+
+ IsEqual = RtlEqualSid(&Ace->SidStart, (PSID)CreatorSid );
+
+ return( IsEqual );
+}
+
+
+BOOLEAN
+RtlpContainsCreatorOwnerServerSid(
+ PKNOWN_COMPOUND_ACE Ace
+ )
+/*++
+
+Routine Description:
+
+ Tests to see if the specified ACE contains the CreatorClientSid.
+
+Arguments:
+
+ Ace - Pointer to the compound ACE whose Client SID is be compared to the
+ Creator Client Sid. This ACE is assumed to be valid and a known
+ compound ACE type.
+
+Return Value:
+
+ TRUE - The creator sid is in the ACE.
+
+ FALSE - The creator sid is not in the ACE.
+
+
+--*/
+{
+ BOOLEAN IsEqual;
+ ULONG CreatorSid[CREATOR_SID_SIZE];
+ SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
+
+ RTL_PAGED_CODE();
+
+ //
+ // This is gross and ugly, but it's better than allocating
+ // virtual memory to hold the ClientSid, because that can
+ // fail, and propogating the error back is a tremendous pain
+ //
+
+ ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
+
+ //
+ // Allocate and initialize the universal SID
+ //
+
+ RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
+ *(RtlSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_OWNER_SERVER_RID;
+
+ IsEqual = RtlEqualSid(RtlCompoundAceClientSid( Ace ), (PSID)CreatorSid );
+
+ return( IsEqual );
+
+}
+
+
+BOOLEAN
+RtlpContainsCreatorGroupServerSid(
+ PKNOWN_COMPOUND_ACE Ace
+ )
+/*++
+
+Routine Description:
+
+ Tests to see if the specified ACE contains the CreatorServerSid.
+
+Arguments:
+
+ Ace - Pointer to the compound ACE whose Server SID is be compared to the
+ Creator Server Sid. This ACE is assumed to be valid and a known
+ compound ACE type.
+
+Return Value:
+
+ TRUE - The creator Server sid is in the ACE.
+
+ FALSE - The creator Server sid is not in the ACE.
+
+
+--*/
+{
+ BOOLEAN IsEqual;
+ ULONG CreatorSid[CREATOR_SID_SIZE];
+ SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
+
+ RTL_PAGED_CODE();
+
+ //
+ // This is gross and ugly, but it's better than allocating
+ // virtual memory to hold the CreatorSid, because that can
+ // fail, and propogating the error back is a tremendous pain
+ //
+
+ ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
+
+ //
+ // Allocate and initialize the universal SIDs
+ //
+
+ RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
+ *(RtlSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_GROUP_SERVER_RID;
+
+ IsEqual = RtlEqualSid(RtlCompoundAceServerSid(Ace), (PSID)CreatorSid );
+
+ return( IsEqual );
+}
+
+#endif
+
+
+VOID
+RtlpApplyAclToObject (
+ IN PACL Acl,
+ IN PGENERIC_MAPPING GenericMapping
+ )
+
+/*++
+
+Routine Description:
+
+ This is a private routine that maps Access Masks of an ACL so that
+ they are applicable to the object type the ACL is being applied to.
+
+ Only known DSA ACEs are mapped. Unknown ACE types are ignored.
+
+ Only access types in the GenericAll mapping for the target object
+ type will be non-zero upon return.
+
+Arguments:
+
+ Acl - Supplies the acl being applied.
+
+ GenericMapping - Specifies the generic mapping to use.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+//////////////////////////////////////////////////////////////////////////////
+// //
+// The logic in the ACL inheritance code must mirror the code for //
+// inheritance in the executive (in seassign.c). Do not make changes //
+// here without also making changes in that module. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+
+ ULONG i;
+
+ PACE_HEADER Ace;
+
+ RTL_PAGED_CODE();
+
+ //
+ // First check if the acl is null
+ //
+
+ if (Acl == NULL) {
+
+ return;
+
+ }
+
+
+ //
+ // Now walk the ACL, mapping each ACE as we go.
+ //
+
+ for (i = 0, Ace = FirstAce(Acl);
+ i < Acl->AceCount;
+ i += 1, Ace = NextAce(Ace)) {
+
+ if (IsMSAceType( Ace )) {
+
+ RtlApplyAceToObject( Ace, GenericMapping );
+ }
+
+ }
+
+ return;
+}
+
+#ifndef WIN16
+
+
+NTSTATUS
+RtlpInheritAcl (
+ IN PACL Acl,
+ IN BOOLEAN IsDirectoryObject,
+ IN PSID OwnerSid,
+ IN PSID GroupSid,
+ IN PSID ServerOwnerSid OPTIONAL,
+ IN PSID ServerGroupSid OPTIONAL,
+ IN PGENERIC_MAPPING GenericMapping,
+ OUT PACL *NewAcl
+ )
+
+/*++
+
+Routine Description:
+
+ This is a private routine that produces an inherited acl from
+ a parent acl according to the rules of inheritance
+
+Arguments:
+
+ Acl - Supplies the acl being inherited.
+
+ IsDirectoryObject - Specifies if the new acl is for a directory.
+
+ OwnerSid - Specifies the owner Sid to use.
+
+ GroupSid - Specifies the group SID to use.
+
+ GenericMapping - Specifies the generic mapping to use.
+
+ NewAcl - Receives a pointer to the new (inherited) acl.
+
+Return Value:
+
+ STATUS_SUCCESS - An inheritable ACL was successfully generated.
+
+ STATUS_NO_INHERITANCE - An inheritable ACL was not successfully generated.
+ This is a warning completion status.
+
+ STATUS_BAD_INHERITANCE_ACL - Indicates the acl built was not a valid ACL.
+ This can becaused by a number of things. One of the more probable
+ causes is the replacement of a CreatorId with an SID that didn't fit
+ into the ACE or ACL.
+
+ STATUS_UNKNOWN_REVISION - Indicates the source ACL is a revision that
+ is unknown to this routine.
+
+--*/
+
+{
+//////////////////////////////////////////////////////////////////////////////
+// //
+// The logic in the ACL inheritance code must mirror the code for //
+// inheritance in the executive (in seassign.c). Do not make changes //
+// here without also making changes in that module. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+
+
+ NTSTATUS Status;
+ ULONG NewAclLength;
+ PVOID HeapHandle;
+
+ RTL_PAGED_CODE();
+
+ //
+ // Get the handle to the current process heap
+ //
+
+ HeapHandle = RtlProcessHeap();
+
+ //
+ // First check if the acl is null
+ //
+
+ if (Acl == NULL) {
+
+ return STATUS_NO_INHERITANCE;
+
+ }
+
+ if (Acl->AclRevision != ACL_REVISION2 && Acl->AclRevision != ACL_REVISION3) {
+ return STATUS_UNKNOWN_REVISION;
+ }
+
+
+ //
+ // Generating an inheritable ACL is a two-pass operation.
+ // First you must see if there is anything to inherit, and if so,
+ // allocate enough room to hold it. then you must actually copy
+ // the generated ACEs.
+ //
+
+ Status = RtlpLengthInheritAcl(
+ Acl,
+ IsDirectoryObject,
+ OwnerSid,
+ GroupSid,
+ ServerOwnerSid,
+ ServerGroupSid,
+ GenericMapping,
+ &NewAclLength
+ );
+
+ if ( !NT_SUCCESS(Status) ) {
+ return Status;
+ }
+ if (NewAclLength == 0) {
+ return STATUS_NO_INHERITANCE;
+ }
+
+ (*NewAcl) = RtlAllocateHeap( HeapHandle, 0, NewAclLength );
+ if ((*NewAcl) == NULL ) {
+ return( STATUS_NO_MEMORY );
+ }
+
+
+
+ RtlCreateAcl( (*NewAcl), NewAclLength, Acl->AclRevision ); // Used to be hardwired to ACL_REVISION2
+ Status = RtlpGenerateInheritAcl(
+ Acl,
+ IsDirectoryObject,
+ OwnerSid,
+ GroupSid,
+ ServerOwnerSid,
+ ServerGroupSid,
+ GenericMapping,
+ (*NewAcl)
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ RtlFreeHeap( HeapHandle, 0, *NewAcl );
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+RtlpLengthInheritAcl(
+ IN PACL Acl,
+ IN BOOLEAN IsDirectoryObject,
+ IN PSID ClientOwnerSid,
+ IN PSID ClientGroupSid,
+ IN PSID ServerOwnerSid OPTIONAL,
+ IN PSID ServerGroupSid OPTIONAL,
+ IN PGENERIC_MAPPING GenericMapping,
+ OUT PULONG NewAclLength
+ )
+
+/*++
+
+Routine Description:
+
+ This is a private routine that calculates the length needed to
+ produce an inheritable ACL.
+
+Arguments:
+
+ Acl - Supplies the acl being inherited.
+
+ IsDirectoryObject - Specifies if the new acl is for a directory.
+
+ OwnerSid - Specifies the owner Sid to use.
+
+ GroupSid - Specifies the group SID to use.
+
+ GenericMapping - Specifies the generic mapping to use.
+
+ NewAclLength - Receives the length of the inherited ACL.
+
+Return Value:
+
+ STATUS_SUCCESS - An inheritable ACL buffer successfully allocated.
+
+ STATUS_NO_INHERITANCE - An inheritable ACL was not successfully generated.
+ This is a warning completion status.
+
+ STATUS_BAD_INHERITANCE_ACL - Indicates the acl built was not a valid ACL.
+ This can becaused by a number of things. One of the more probable
+ causes is the replacement of a CreatorId with an SID that didn't fit
+ into the ACE or ACL.
+
+
+--*/
+
+{
+//////////////////////////////////////////////////////////////////////////////
+// //
+// The logic in the ACL inheritance code must mirror the code for //
+// inheritance in the executive (in seassign.c). Do not make changes //
+// here without also making changes in that module. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+
+
+ NTSTATUS Status;
+ ULONG i;
+
+ ULONG NewAclSize, NewAceSize;
+
+ PACE_HEADER OldAce;
+
+
+ RTL_PAGED_CODE();
+
+ //
+ // Calculate the length needed to store any inherited ACEs
+ // (this doesn't include the ACL header itself).
+ //
+
+ for (i = 0, OldAce = FirstAce(Acl), NewAclSize = 0;
+ i < Acl->AceCount;
+ i += 1, OldAce = NextAce(OldAce)) {
+
+ //
+ // RtlpLengthInheritedAce will return the number of bytes needed
+ // to inherit a single ACE.
+ //
+
+ Status = RtlpLengthInheritedAce(
+ OldAce,
+ IsDirectoryObject,
+ ClientOwnerSid,
+ ClientGroupSid,
+ ServerOwnerSid,
+ ServerGroupSid,
+ GenericMapping,
+ &NewAceSize
+ );
+
+ if ( !NT_SUCCESS(Status) ) {
+ return Status;
+ }
+
+ NewAclSize += NewAceSize;
+
+ }
+
+ //
+ // Check to make sure there is something inheritable
+ //
+
+ if (NewAclSize == 0) {
+ return STATUS_NO_INHERITANCE;
+ }
+
+ //
+ // And make sure we don't exceed the length limitations of an ACL (WORD)
+ //
+
+ NewAclSize += sizeof(ACL);
+
+ if (NewAclSize > 0xFFFF) {
+ return(STATUS_BAD_INHERITANCE_ACL);
+ }
+
+ (*NewAclLength) = NewAclSize;
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+RtlpGenerateInheritAcl(
+ IN PACL Acl,
+ IN BOOLEAN IsDirectoryObject,
+ IN PSID ClientOwnerSid,
+ IN PSID ClientGroupSid,
+ IN PSID ServerOwnerSid OPTIONAL,
+ IN PSID ServerGroupSid OPTIONAL,
+ IN PGENERIC_MAPPING GenericMapping,
+ OUT PACL NewAcl
+ )
+
+/*++
+
+Routine Description:
+
+ This is a private routine that produces an inheritable ACL.
+ It is expected that RtlpLengthInheritAcl() has already been
+ called to validate the inheritance and to indicate the length
+ of buffer needed to perform the inheritance.
+
+Arguments:
+
+ Acl - Supplies the acl being inherited.
+
+ IsDirectoryObject - Specifies if the new acl is for a directory.
+
+ OwnerSid - Specifies the owner Sid to use.
+
+ GroupSid - Specifies the group SID to use.
+
+ GenericMapping - Specifies the generic mapping to use.
+
+ NewAcl - Provides a pointer to the buffer to receive the new
+ (inherited) acl. This ACL must already be initialized.
+
+
+Return Value:
+
+ STATUS_SUCCESS - An inheritable ACL has been generated.
+
+ STATUS_NO_INHERITANCE - An inheritable ACL was not successfully generated.
+ This is a warning completion status.
+
+ STATUS_BAD_INHERITANCE_ACL - Indicates the acl built was not a valid ACL.
+ This can becaused by a number of things. One of the more probable
+ causes is the replacement of a CreatorId with an SID that didn't fit
+ into the ACE or ACL.
+
+
+--*/
+
+{
+//////////////////////////////////////////////////////////////////////////////
+// //
+// The logic in the ACL inheritance code must mirror the code for //
+// inheritance in the executive (in seassign.c). Do not make changes //
+// here without also making changes in that module. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+
+
+ NTSTATUS Status;
+ ULONG i;
+
+ PACE_HEADER OldAce;
+
+
+ RTL_PAGED_CODE();
+
+ //
+ // Walk through the original ACL generating any necessary
+ // inheritable ACEs.
+ //
+
+ for (i = 0, OldAce = FirstAce(Acl);
+ i < Acl->AceCount;
+ i += 1, OldAce = NextAce(OldAce)) {
+
+ //
+ // RtlpGenerateInheritedAce() will generate the ACE(s) necessary
+ // to inherit a single ACE. This may be 0, 1, or more ACEs.
+ //
+
+ Status = RtlpGenerateInheritedAce(
+ OldAce,
+ IsDirectoryObject,
+ ClientOwnerSid,
+ ClientGroupSid,
+ ServerOwnerSid,
+ ServerGroupSid,
+ GenericMapping,
+ NewAcl
+ );
+
+ if ( !NT_SUCCESS(Status) ) {
+ return Status;
+ }
+
+ }
+
+
+ return STATUS_SUCCESS;
+
+}
+
+#endif // WIN16
+
+NTSTATUS
+RtlpLengthInheritedAce (
+ IN PACE_HEADER Ace,
+ IN BOOLEAN IsDirectoryObject,
+ IN PSID ClientOwnerSid,
+ IN PSID ClientGroupSid,
+ IN PSID ServerOwnerSid OPTIONAL,
+ IN PSID ServerGroupSid OPTIONAL,
+ IN PGENERIC_MAPPING GenericMapping,
+ IN PULONG NewAceLength
+ )
+
+/*++
+
+Routine Description:
+
+ This is a private routine that calculates the number of bytes needed
+ to allow for the inheritance of the specified ACE. If the ACE is not
+ inheritable, or its AccessMask ends up with no accesses, then the
+ size may be returned as zero.
+
+Arguments:
+
+ Ace - Supplies the ace being checked
+
+ IsDirectoryObject - Specifies if the new ace is for a directory
+
+ ClientOwnerSid - Pointer to Sid to be assigned as the new owner.
+
+ ClientGroupSid - Points to SID to be assigned as the new primary group.
+
+ ServerOwnerSid - Provides the SID of a server to substitute into
+ compound ACEs (if any that require editing are encountered).
+ If this parameter is not provided, the SID passed for ClientOwnerSid
+ will be used.
+
+ ServerGroupSid - Provides the SID of a client to substitute into
+ compound ACEs (if any that require editing are encountered).
+ If this parameter is not provided, the SID passed for ClientGroupSid
+ will be used.
+
+ GenericMapping - Specifies the generic mapping to use.
+
+ NewAceLength - Receives the length (number of bytes) needed to allow for
+ the inheritance of the specified ACE. This might be zero.
+
+Return Value:
+
+ STATUS_SUCCESS - The length needed has been calculated.
+
+ STATUS_BAD_INHERITANCE_ACL - Indicates inheritance of the ace would
+ result in an invalid ACL structure. For example, an SID substitution
+ for a known ACE type which has a CreatorOwner SID might exceed the
+ length limits of an ACE.
+
+ STATUS_INVALID_PARAMETER - An optional parameter was required, but not
+ provided.
+
+--*/
+
+{
+//////////////////////////////////////////////////////////////////////////////
+// //
+// The logic in the ACL inheritance code must mirror the code for //
+// inheritance in the executive (in seassign.c). Do not make changes //
+// here without also making changes in that module. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // //
+ // !!!!!!!!! This is tricky !!!!!!!!!! //
+ // //
+ // The inheritence flags AND the sid of the ACE determine whether //
+ // we need 0, 1, or 2 ACEs. //
+ // //
+ // BE CAREFUL WHEN CHANGING THIS CODE. READ THE DSA ACL ARCHITECTURE //
+ // SECTION COVERING INHERITENCE BEFORE ASSUMING YOU KNOW WHAT THE HELL //
+ // YOU ARE DOING!!!! //
+ // //
+ // The general gist of the algorithm is: //
+ // //
+ // if ( (container && ContainerInherit) || //
+ // (!container && ObjectInherit) ) { //
+ // GenerateEffectiveAce; //
+ // } //
+ // //
+ // //
+ // if (Container && Propagate) { //
+ // Propogate copy of ACE and set InheritOnly; //
+ // } //
+ // //
+ // //
+ // A slightly more accurate description of this algorithm is: //
+ // //
+ // IO === InheritOnly flag //
+ // CI === ContainerInherit flag //
+ // OI === ObjectInherit flag //
+ // NPI === NoPropagateInherit flag //
+ // //
+ // if ( (container && CI) || //
+ // (!container && OI) ) { //
+ // Copy Header of ACE; //
+ // Clear IO, NPI, CI, OI; //
+ // //
+ // if (KnownAceType) { //
+ // if (SID is a creator ID) { //
+ // Copy appropriate creator SID; //
+ // } else { //
+ // Copy SID of original; //
+ // } //
+ // //
+ // Copy AccessMask of original; //
+ // MapGenericAccesses; //
+ // if (AccessMask == 0) { //
+ // discard new ACE; //
+ // } //
+ // //
+ // } else { //
+ // Copy body of ACE; //
+ // } //
+ // //
+ // } //
+ // //
+ // if (!NPI) { //
+ // Copy ACE as is; //
+ // Set IO; //
+ // } //
+ // //
+ // //
+ // //
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ ULONG LengthRequired = 0;
+ ACCESS_MASK LocalMask;
+
+ PSID LocalServerOwner;
+ PSID LocalServerGroup;
+ PSID Sid;
+
+ ULONG Rid;
+
+ ULONG CreatorSid[CREATOR_SID_SIZE];
+ ULONG GroupSid[CREATOR_SID_SIZE];
+ ULONG CreatorOwnerServerSid[CREATOR_SID_SIZE];
+ ULONG CreatorGroupServerSid[CREATOR_SID_SIZE];
+
+ SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
+
+
+ RTL_PAGED_CODE();
+
+ //
+ // This is gross and ugly, but it's better than allocating
+ // virtual memory to hold the ClientSid, because that can
+ // fail, and propogating the error back is a tremendous pain
+ //
+
+ ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
+
+ //
+ // Allocate and initialize the universal SIDs we're going to need
+ // to look for inheritable ACEs.
+ //
+
+ RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
+ RtlInitializeSid( (PSID)GroupSid, &CreatorSidAuthority, 1 );
+
+ RtlInitializeSid( (PSID)CreatorOwnerServerSid, &CreatorSidAuthority, 1 );
+ RtlInitializeSid( (PSID)CreatorGroupServerSid, &CreatorSidAuthority, 1 );
+
+ *(RtlSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_OWNER_RID;
+ *(RtlSubAuthoritySid( (PSID)GroupSid, 0 )) = SECURITY_CREATOR_GROUP_RID;
+
+ *(RtlSubAuthoritySid( (PSID)CreatorOwnerServerSid, 0 )) = SECURITY_CREATOR_OWNER_SERVER_RID;
+ *(RtlSubAuthoritySid( (PSID)CreatorGroupServerSid, 0 )) = SECURITY_CREATOR_GROUP_SERVER_RID;
+
+ //
+ // Everywhere the pseudo-code above says "copy", the code in this
+ // routine simply calculates the length of. RtlpGenerateInheritedAce()
+ // will actually be used to do the "copy".
+ //
+
+ LocalServerOwner = ARGUMENT_PRESENT(ServerOwnerSid) ? ServerOwnerSid : ClientOwnerSid;
+
+ LocalServerGroup = ARGUMENT_PRESENT(ServerGroupSid) ? ServerGroupSid : ClientGroupSid;
+
+ //
+ // check to see if we will have a protection ACE (one mapped to
+ // the target object type).
+ //
+
+ if ( (IsDirectoryObject && ContainerInherit(Ace)) ||
+ (!IsDirectoryObject && ObjectInherit(Ace)) ) {
+
+ LengthRequired = (ULONG)Ace->AceSize;
+
+ if (IsKnownAceType( Ace ) ) {
+
+ //
+ // May need to adjust size due to SID substitution
+ //
+
+ PKNOWN_ACE KnownAce = (PKNOWN_ACE)Ace;
+
+ Sid = &KnownAce->SidStart;
+
+ if (RtlEqualPrefixSid ( Sid, CreatorSid )) {
+
+ Rid = *RtlSubAuthoritySid( Sid, 0 );
+
+ switch (Rid) {
+ case SECURITY_CREATOR_OWNER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientOwnerSid);
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientGroupSid);
+ break;
+ }
+ case SECURITY_CREATOR_OWNER_SERVER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ServerOwnerSid);
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_SERVER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ServerGroupSid);
+ break;
+ }
+ default :
+ {
+ //
+ // We don't know what this SID is, do nothing and the original will be copied.
+ //
+
+ break;
+ }
+ }
+ }
+
+ //
+ // If after mapping the access mask, the access mask
+ // is empty, then drop the ACE.
+ //
+
+ LocalMask = ((PKNOWN_ACE)(Ace))->Mask;
+ RtlMapGenericMask( &LocalMask, GenericMapping);
+
+ //
+ // Mask off any bits that aren't meaningful
+ //
+
+ LocalMask &= ( STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL | ACCESS_SYSTEM_SECURITY );
+
+ if (LocalMask == 0) {
+ LengthRequired = 0;
+ }
+
+ } else {
+
+ if (IsCompoundAceType(Ace)) {
+
+ PKNOWN_COMPOUND_ACE KnownAce = (PKNOWN_COMPOUND_ACE)Ace;
+ PSID AceServerSid;
+ PSID AceClientSid;
+
+ AceServerSid = RtlCompoundAceServerSid( KnownAce );
+ AceClientSid = RtlCompoundAceClientSid( KnownAce );
+
+ if (RtlEqualPrefixSid ( AceClientSid, CreatorSid )) {
+
+ Rid = *RtlSubAuthoritySid( AceClientSid, 0 );
+
+ switch (Rid) {
+ case SECURITY_CREATOR_OWNER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientOwnerSid);
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientGroupSid);
+ break;
+ }
+ case SECURITY_CREATOR_OWNER_SERVER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ServerOwnerSid);
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_SERVER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ServerGroupSid);
+ break;
+ }
+ default :
+ {
+ //
+ // We don't know what this SID is, do nothing and the original will be copied.
+ //
+
+ break;
+ }
+ }
+ }
+
+ if (RtlEqualPrefixSid ( AceServerSid, CreatorSid )) {
+
+ Rid = *RtlSubAuthoritySid( AceServerSid, 0 );
+
+ switch (Rid) {
+ case SECURITY_CREATOR_OWNER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientOwnerSid);
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientGroupSid);
+ break;
+ }
+ case SECURITY_CREATOR_OWNER_SERVER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ServerOwnerSid);
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_SERVER_RID:
+ {
+ LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ServerGroupSid);
+ break;
+ }
+ default :
+ {
+ //
+ // We don't know what this SID is, do nothing and the original will be copied.
+ //
+
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // If after mapping the access mask, the access mask
+ // is empty, then drop the ACE.
+ //
+
+ LocalMask = ((PKNOWN_COMPOUND_ACE)(Ace))->Mask;
+ RtlMapGenericMask( &LocalMask, GenericMapping);
+
+ //
+ // Mask off any bits that aren't meaningful
+ //
+
+ LocalMask &= ( STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL | ACCESS_SYSTEM_SECURITY );
+
+ if (LocalMask == 0) {
+ LengthRequired = 0;
+ }
+ }
+
+ //
+ // We have the length of the new ACE, but we've calculated
+ // it with a ULONG. It must fit into a USHORT. See if it
+ // does.
+ //
+
+ ASSERT(sizeof(Ace->AceSize) == 2);
+ if (LengthRequired > 0xFFFF) {
+ return STATUS_BAD_INHERITANCE_ACL;
+ }
+ }
+
+ //
+ // If we are inheriting onto a container, then we may need to
+ // propagate the inheritance as well.
+ //
+
+ if (IsDirectoryObject && Propagate(Ace)) {
+
+ LengthRequired += (ULONG)Ace->AceSize;
+ }
+
+ //
+ // Now return to our caller
+ //
+
+ (*NewAceLength) = LengthRequired;
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+RtlpGenerateInheritedAce (
+ IN PACE_HEADER OldAce,
+ IN BOOLEAN IsDirectoryObject,
+ IN PSID ClientOwnerSid,
+ IN PSID ClientGroupSid,
+ IN PSID ServerOwnerSid OPTIONAL,
+ IN PSID ServerGroupSid OPTIONAL,
+ IN PGENERIC_MAPPING GenericMapping,
+ OUT PACL NewAcl
+ )
+
+/*++
+
+Routine Description:
+
+ This is a private routine that checks if the input ace is inheritable
+ and produces 0, 1, or 2 inherited aces in the given buffer.
+
+ See RtlpLengthInheritedAce() for detailed information on ACE inheritance.
+
+ THE CODE IN THIS ROUTINE MUST MATCH THE CODE IN RtlpLengthInheritanceAce()!!!
+
+Arguments:
+
+ OldAce - Supplies the ace being inherited
+
+ IsDirectoryObject - Specifies if the new ACE is for a directory
+
+ ClientOwnerSid - Specifies the owner Sid to use
+
+ ClientGroupSid - Specifies the new Group Sid to use
+
+ ServerSid - Optionally specifies the Server Sid to use in compound ACEs.
+
+ ClientSid - Optionally specifies the Client Sid to use in compound ACEs.
+
+ GenericMapping - Specifies the generic mapping to use
+
+ NewAcl - Provides a pointer to the ACL into which the ACE is to be
+ inherited.
+
+Return Value:
+
+ STATUS_SUCCESS - The ACE was inherited successfully.
+
+ STATUS_BAD_INHERITANCE_ACL - Indicates something went wrong preventing
+ the ACE from being inherited. This generally represents a bugcheck
+ situation when returned from this call.
+
+
+--*/
+
+{
+//////////////////////////////////////////////////////////////////////////////
+// //
+// The logic in the ACL inheritance code must mirror the code for //
+// inheritance in the executive (in seassign.c). Do not make changes //
+// here without also making changes in that module. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+ ACCESS_MASK LocalMask;
+ PVOID AcePosition;
+ PUCHAR Target;
+ BOOLEAN CreatorOwner, CreatorGroup;
+ BOOLEAN CreatorClient, CreatorServer;
+ BOOLEAN ProtectionAceCopied;
+
+ PSID LocalServerOwner;
+ PSID LocalServerGroup;
+
+ ULONG CreatorSid[CREATOR_SID_SIZE];
+
+ SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
+
+ ULONG Rid;
+ PSID SidToCopy;
+ PSID ClientSidToCopy;
+ PSID ServerSidToCopy;
+ PSID AceClientSid;
+ PSID AceServerSid;
+
+ RTL_PAGED_CODE();
+
+ //
+ // This is gross and ugly, but it's better than allocating
+ // virtual memory to hold the ClientSid, because that can
+ // fail, and propogating the error back is a tremendous pain
+ //
+
+ ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
+
+ //
+ // Allocate and initialize the universal SIDs we're going to need
+ // to look for inheritable ACEs.
+ //
+
+ RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
+ *(RtlSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_OWNER_RID;
+
+ if (!RtlFirstFreeAce( NewAcl, &AcePosition ) ) {
+ return STATUS_BAD_INHERITANCE_ACL;
+ }
+
+ if (!ARGUMENT_PRESENT(ServerOwnerSid)) {
+ LocalServerOwner = ClientOwnerSid;
+ } else {
+ LocalServerOwner = ServerOwnerSid;
+ }
+
+ if (!ARGUMENT_PRESENT(ServerGroupSid)) {
+ LocalServerGroup = ClientGroupSid;
+ } else {
+ LocalServerGroup = ServerGroupSid;
+ }
+
+ //
+ // check to see if we will have a protection ACE (one mapped to
+ // the target object type).
+ //
+
+ if ( (IsDirectoryObject && ContainerInherit(OldAce)) ||
+ (!IsDirectoryObject && ObjectInherit(OldAce)) ) {
+
+ ProtectionAceCopied = TRUE;
+
+ if (IsKnownAceType( OldAce ) ) {
+
+ //
+ // If after mapping the access mask, the access mask
+ // is empty, then drop the ACE.
+ //
+
+ LocalMask = ((PKNOWN_ACE)(OldAce))->Mask;
+ RtlMapGenericMask( &LocalMask, GenericMapping);
+
+ //
+ // Mask off any bits that aren't meaningful
+ //
+
+ LocalMask &= ( STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL | ACCESS_SYSTEM_SECURITY );
+
+ if (LocalMask == 0) {
+
+ ProtectionAceCopied = FALSE;
+
+ } else {
+
+ PKNOWN_ACE KnownAce = (PKNOWN_ACE)OldAce;
+
+ Target = (PUCHAR)AcePosition;
+
+ //
+ // See if the SID in the ACE is one of the various CREATOR_* SIDs by
+ // comparing identifier authorities.
+ //
+
+ if (RtlEqualPrefixSid ( &KnownAce->SidStart, CreatorSid )) {
+
+ Rid = *RtlSubAuthoritySid( &KnownAce->SidStart, 0 );
+
+ switch (Rid) {
+ case SECURITY_CREATOR_OWNER_RID:
+ {
+ SidToCopy = ClientOwnerSid;
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_RID:
+ {
+ SidToCopy = ClientGroupSid;
+ break;
+ }
+ case SECURITY_CREATOR_OWNER_SERVER_RID:
+ {
+ SidToCopy = LocalServerOwner;
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_SERVER_RID:
+ {
+ SidToCopy = LocalServerGroup;
+ break;
+ }
+ default :
+ {
+ //
+ // We don't know what this SID is, just copy the original.
+ //
+
+ SidToCopy = &KnownAce->SidStart;
+ break;
+ }
+ }
+
+ //
+ // SID substitution required. Copy all except the SID.
+ //
+
+ RtlMoveMemory(
+ Target,
+ OldAce,
+ FIELD_OFFSET(KNOWN_ACE, SidStart)
+ );
+
+ Target = (PUCHAR)(Target + FIELD_OFFSET(KNOWN_ACE, SidStart));
+
+ //
+ // Now copy the correct SID
+ //
+
+ RtlMoveMemory(
+ Target,
+ SidToCopy,
+ SeLengthSid(SidToCopy)
+ );
+
+ //
+ // Set the size of the ACE accordingly
+ //
+
+ ((PKNOWN_ACE)AcePosition)->Header.AceSize =
+ (USHORT)FIELD_OFFSET(KNOWN_ACE, SidStart) +
+ (USHORT)SeLengthSid(SidToCopy);
+
+ } else {
+
+ //
+ // No ID substitution, copy ACE as is.
+ //
+
+ RtlMoveMemory(
+ Target,
+ OldAce,
+ ((PKNOWN_ACE)OldAce)->Header.AceSize
+ );
+ }
+
+ //
+ // Put the mapped access mask in the new ACE
+ //
+
+ ((PKNOWN_ACE)AcePosition)->Mask = LocalMask;
+ }
+
+ } else if (IsCompoundAceType(OldAce)) {
+
+ //
+ // If after mapping the access mask, the access mask
+ // is empty, then drop the ACE.
+ //
+
+ LocalMask = ((PKNOWN_COMPOUND_ACE)(OldAce))->Mask;
+ RtlMapGenericMask( &LocalMask, GenericMapping);
+
+ //
+ // Mask off any bits that aren't meaningful
+ //
+
+ LocalMask &= ( STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL | ACCESS_SYSTEM_SECURITY );
+
+ if (LocalMask == 0) {
+
+ ProtectionAceCopied = FALSE;
+
+ } else {
+
+ Target = (PUCHAR)AcePosition;
+
+ //
+ // See if the SID in the ACE is one of the various CREATOR_* SIDs by
+ // comparing identifier authorities.
+ //
+
+ AceServerSid = RtlCompoundAceServerSid( OldAce );
+ AceClientSid = RtlCompoundAceClientSid( OldAce );
+
+ if (RtlEqualPrefixSid ( AceServerSid, CreatorSid )) {
+
+ Rid = *RtlSubAuthoritySid( AceServerSid, 0 );
+
+ switch (Rid) {
+ case SECURITY_CREATOR_OWNER_RID:
+ {
+ ServerSidToCopy = ClientOwnerSid;
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_RID:
+ {
+ ServerSidToCopy = ClientGroupSid;
+ break;
+ }
+ case SECURITY_CREATOR_OWNER_SERVER_RID:
+ {
+ ServerSidToCopy = LocalServerOwner;
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_SERVER_RID:
+ {
+ ServerSidToCopy = LocalServerGroup;
+ break;
+ }
+ default :
+ {
+ //
+ // We don't know what this SID is, just copy the original.
+ //
+
+ ServerSidToCopy = AceServerSid;
+ break;
+ }
+ }
+
+ } else {
+
+ ServerSidToCopy = AceServerSid;
+ }
+
+ if (RtlEqualPrefixSid ( AceClientSid, CreatorSid )) {
+
+ Rid = *RtlSubAuthoritySid( AceClientSid, 0 );
+
+ switch (Rid) {
+ case SECURITY_CREATOR_OWNER_RID:
+ {
+ ClientSidToCopy = ClientOwnerSid;
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_RID:
+ {
+ ClientSidToCopy = ClientGroupSid;
+ break;
+ }
+ case SECURITY_CREATOR_OWNER_SERVER_RID:
+ {
+ ClientSidToCopy = LocalServerOwner;
+ break;
+ }
+ case SECURITY_CREATOR_GROUP_SERVER_RID:
+ {
+ ClientSidToCopy = LocalServerGroup;
+ break;
+ }
+ default :
+ {
+ //
+ // We don't know what this SID is, just copy the original.
+ //
+
+ ClientSidToCopy = AceClientSid;
+ break;
+ }
+ }
+
+ } else {
+
+ ClientSidToCopy = AceClientSid;
+ }
+
+ //
+ // Copy ACE in pieces. Body of ACE first.
+ //
+
+
+ RtlMoveMemory(
+ Target,
+ OldAce,
+ FIELD_OFFSET(KNOWN_ACE, Mask)
+ );
+
+ Target = (PUCHAR)(Target + FIELD_OFFSET(KNOWN_COMPOUND_ACE, SidStart));
+
+ //
+ // Now copy the correct Server SID
+ //
+
+ RtlMoveMemory(
+ Target,
+ ServerSidToCopy,
+ SeLengthSid(ServerSidToCopy)
+ );
+
+ Target = (PUCHAR)(Target + SeLengthSid(ServerSidToCopy));
+
+ //
+ // Now copy the correct Client SID
+ //
+
+ RtlMoveMemory(
+ Target,
+ ClientSidToCopy,
+ SeLengthSid(ClientSidToCopy)
+ );
+
+ //
+ // Set the size of the ACE accordingly
+ //
+
+ ((PKNOWN_COMPOUND_ACE)AcePosition)->Header.AceSize =
+ (USHORT)FIELD_OFFSET(KNOWN_COMPOUND_ACE, SidStart) +
+ (USHORT)SeLengthSid(ServerSidToCopy) +
+ (USHORT)SeLengthSid(ClientSidToCopy);
+
+ //
+ // Put the mapped access mask in the new ACE and set the type information
+ //
+
+ ((PKNOWN_COMPOUND_ACE)AcePosition)->Mask = LocalMask;
+ ((PKNOWN_COMPOUND_ACE)AcePosition)->Header.AceType = ACCESS_ALLOWED_COMPOUND_ACE_TYPE;
+ ((PKNOWN_COMPOUND_ACE)AcePosition)->CompoundAceType = COMPOUND_ACE_IMPERSONATION;
+ }
+
+ } else {
+
+ //
+ // Not a known ACE type, copy ACE as is
+ //
+
+ RtlMoveMemory(
+ AcePosition,
+ OldAce,
+ ((PKNOWN_COMPOUND_ACE)OldAce)->Header.AceSize
+ );
+ }
+
+ //
+ // If the ACE was actually kept, clear all the inherit flags
+ // and update the ACE count of the ACL.
+ //
+
+ if (ProtectionAceCopied) {
+ ((PACE_HEADER)AcePosition)->AceFlags &= ~VALID_INHERIT_FLAGS;
+ NewAcl->AceCount += 1;
+ }
+ }
+
+ //
+ // If we are inheriting onto a container, then we may need to
+ // propagate the inheritance as well.
+ //
+
+ if (IsDirectoryObject && Propagate(OldAce)) {
+
+ //
+ // copy it as is, but make sure the InheritOnly bit is set.
+ //
+
+ if (!RtlFirstFreeAce( NewAcl, &AcePosition ) ) {
+ return STATUS_BAD_INHERITANCE_ACL;
+ }
+
+ RtlMoveMemory(
+ AcePosition,
+ OldAce,
+ ((PKNOWN_ACE)OldAce)->Header.AceSize
+ );
+
+ ((PACE_HEADER)AcePosition)->AceFlags |= INHERIT_ONLY_ACE;
+ NewAcl->AceCount += 1;
+ }
+
+ //
+ // Now return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+#if DBG
+NTSTATUS
+RtlDumpUserSid(
+ VOID
+ )
+{
+ NTSTATUS Status;
+ HANDLE TokenHandle;
+ CHAR Buffer[200];
+ ULONG ReturnLength;
+ PSID pSid;
+ UNICODE_STRING SidString;
+ PTOKEN_USER User;
+
+ //
+ // Attempt to open the impersonation token first
+ //
+
+ Status = NtOpenThreadToken(
+ NtCurrentThread(),
+ GENERIC_READ,
+ FALSE,
+ &TokenHandle
+ );
+
+ if (!NT_SUCCESS( Status )) {
+
+ DbgPrint("Not impersonating, status = %X, trying process token\n",Status);
+
+ Status = NtOpenProcessToken(
+ NtCurrentProcess(),
+ GENERIC_READ,
+ &TokenHandle
+ );
+
+ if (!NT_SUCCESS( Status )) {
+ DbgPrint("Unable to open process token, status = %X\n",Status);
+ return( Status );
+ }
+ }
+
+ Status = NtQueryInformationToken (
+ TokenHandle,
+ TokenUser,
+ Buffer,
+ 200,
+ &ReturnLength
+ );
+
+ if (!NT_SUCCESS( Status )) {
+
+ DbgPrint("Unable to query user sid, status = %X \n",Status);
+ NtClose(TokenHandle);
+ return( Status );
+ }
+
+ User = (PTOKEN_USER)Buffer;
+
+ pSid = User->User.Sid;
+
+ Status = RtlConvertSidToUnicodeString( &SidString, pSid, TRUE );
+
+ if (!NT_SUCCESS( Status )) {
+ DbgPrint("Unable to format sid string, status = %X \n",Status);
+ NtClose(TokenHandle);
+ return( Status );
+ }
+
+ DbgPrint("Current Sid = %wZ \n",&SidString);
+
+ RtlFreeUnicodeString( &SidString );
+
+ return( STATUS_SUCCESS );
+}
+
+#endif