summaryrefslogtreecommitdiffstats
path: root/private/ntos/se/seassign.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/se/seassign.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/se/seassign.c')
-rw-r--r--private/ntos/se/seassign.c1924
1 files changed, 1924 insertions, 0 deletions
diff --git a/private/ntos/se/seassign.c b/private/ntos/se/seassign.c
new file mode 100644
index 000000000..59a491e7e
--- /dev/null
+++ b/private/ntos/se/seassign.c
@@ -0,0 +1,1924 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Seassign.c
+
+Abstract:
+
+ This Module implements the SeAssignSecurity procedure. For a description
+ of the pool allocation strategy please see the comments in semethod.c
+
+Author:
+
+ Gary Kimura (GaryKi) 9-Nov-1989
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ Richard Ward (RichardW) 14-April-92
+ Robert Reichel (RobertRe) 28-February-95
+ Added Compound ACEs
+
+--*/
+
+
+#include "sep.h"
+#include "tokenp.h"
+#include "sertlp.h"
+#include "zwapi.h"
+
+
+
+//
+// Local macros and procedures
+//
+
+//
+// Macros to determine if an ACE contains one of the Creator SIDs
+//
+
+#define ContainsCreatorOwnerSid(Ace) ( \
+ RtlEqualSid( &((PKNOWN_ACE)( Ace ))->SidStart, SeCreatorOwnerSid ) \
+ )
+
+#define ContainsCreatorGroupSid(Ace) ( \
+ RtlEqualSid( &((PKNOWN_ACE)( Ace ))->SidStart, SeCreatorGroupSid ) \
+ )
+
+
+
+VOID
+SepApplyAclToObject (
+ IN PACL Acl,
+ IN PGENERIC_MAPPING GenericMapping
+ );
+
+NTSTATUS
+SepInheritAcl (
+ IN PACL Acl,
+ IN BOOLEAN IsDirectoryObject,
+ IN PSID OwnerSid,
+ IN PSID GroupSid,
+ IN PSID ServerSid OPTIONAL,
+ IN PSID ClientSid OPTIONAL,
+ IN PGENERIC_MAPPING GenericMapping,
+ IN POOL_TYPE PoolType,
+ OUT PACL *NewAcl
+ );
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,SeAssignSecurity)
+#pragma alloc_text(PAGE,SeDeassignSecurity)
+#pragma alloc_text(PAGE,SepApplyAclToObject)
+#pragma alloc_text(PAGE,SepInheritAcl)
+#pragma alloc_text(PAGE,SeAssignWorldSecurityDescriptor)
+#pragma alloc_text(PAGE,SepDumpSecurityDescriptor)
+#pragma alloc_text(PAGE,SepPrintAcl)
+#pragma alloc_text(PAGE,SepPrintSid)
+#pragma alloc_text(PAGE,SepDumpTokenInfo)
+#pragma alloc_text(PAGE,SepSidTranslation)
+#endif
+
+
+//
+// These variables control whether security descriptors and token
+// information are dumped by their dump routines. This allows
+// selective turning on and off of debugging output by both program
+// control and via the kernel debugger.
+//
+
+#if DBG
+
+BOOLEAN SepDumpSD = FALSE;
+BOOLEAN SepDumpToken = FALSE;
+
+#endif
+
+
+NTSTATUS
+SeAssignSecurity (
+ IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
+ IN PSECURITY_DESCRIPTOR ExplicitDescriptor OPTIONAL,
+ OUT PSECURITY_DESCRIPTOR *NewDescriptor,
+ IN BOOLEAN IsDirectoryObject,
+ IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
+ IN PGENERIC_MAPPING GenericMapping,
+ IN POOL_TYPE PoolType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assumes privilege checking HAS NOT yet been performed
+ and so will be performed by this routine.
+
+ This procedure is used to build a security descriptor for a new object
+ given the security descriptor of its parent directory and any originally
+ requested security for the object. The final security descriptor
+ returned to the caller may contain a mix of information, some explicitly
+ provided other from the new object's parent.
+
+ System and Discretionary ACL Assignment
+ ---------------------------------------
+
+ The assignment of system and discretionary ACLs is governed by the
+ logic illustrated in the following table (numbers in the cells refer
+ to comments in the code):
+
+ | Explicit | Explicit |
+ | (non-default) | Default | No
+ | Acl | Acl | Acl
+ | Specified | Specified | Specified
+ -------------+----------------+---------------+--------------
+ | (1)| (3)| (5)
+ Inheritable | Assign | Assign | Assign
+ Acl From | Specified | Inherited | Inherited
+ Parent | Acl | Acl | Acl
+ | | |
+ -------------+----------------+---------------+--------------
+ No | (2)| (4)| (6)
+ Inheritable | Assign | Assign | Assign
+ Acl From | Specified | Default | No Acl
+ Parent | Acl | Acl |
+ | | |
+ -------------+----------------+---------------+--------------
+
+ Note that an explicitly specified ACL, whether a default ACL or
+ not, may be empty or null.
+
+ If the caller is explicitly assigning a system acl, default or
+ non-default, the caller must either be a kernel mode client or
+ must be appropriately privileged.
+
+
+ Owner and Group Assignment
+ --------------------------
+
+ The assignment of the new object's owner and group is governed
+ by the following logic:
+
+ 1) If the passed security descriptor includes an owner, it
+ is assigned as the new object's owner. Otherwise, the
+ caller's token is looked in for the owner. Within the
+ token, if there is a default owner, it is assigned.
+ Otherwise, the caller's user ID is assigned.
+
+ 2) If the passed security descriptor includes a group, it
+ is assigned as the new object's group. Otherwise, the
+ caller's token is looked in for the group. Within the
+ token, if there is a default group, it is assigned.
+ Otherwise, the caller's primary group ID is assigned.
+
+
+
+Arguments:
+
+ ParentDescriptor - Optionally supplies the security descriptor of the
+ parent directory under which this new object is being created.
+
+ ExplicitDescriptor - Supplies the address of a pointer to the security
+ descriptor as specified by the user that is to be applied to
+ the new object.
+
+ NewDescriptor - Returns the actual security descriptor for the new
+ object that has been modified according to above rules.
+
+ IsDirectoryObject - Specifies if the new object is itself a directory
+ object. A value of TRUE indicates the object is a container of other
+ objects.
+
+ SubjectContext - Supplies the security context of the subject creating the
+ object. This is used to retrieve default security information for the
+ new object, such as default owner, primary group, and discretionary
+ access control.
+
+ GenericMapping - Supplies a pointer to an array of access mask values
+ denoting the mapping between each generic right to non-generic rights.
+
+ PoolType - Specifies the pool type to use to when allocating a new
+ security descriptor.
+
+Return Value:
+
+ STATUS_SUCCESS - indicates the operation was successful.
+
+ STATUS_INVALID_OWNER - The owner SID provided as the owner of the
+ target security descriptor is not one the caller is authorized
+ to assign as the owner of an object.
+
+ STATUS_PRIVILEGE_NOT_HELD - The caller does not have the privilege
+ necessary to explicitly assign the specified system ACL.
+ SeSecurityPrivilege privilege is needed to explicitly assign
+ system ACLs to objects.
+--*/
+
+{
+
+
+ KPROCESSOR_MODE RequestorMode;
+
+ SECURITY_DESCRIPTOR *CapturedDescriptor;
+ SECURITY_DESCRIPTOR InCaseOneNotPassed;
+ BOOLEAN SecurityDescriptorPassed;
+
+ NTSTATUS Status;
+
+ BOOLEAN RequestorCanAssignDescriptor = TRUE;
+
+ PACL NewSacl = NULL;
+ BOOLEAN NewSaclPresent = FALSE;
+ BOOLEAN NewSaclInherited = FALSE;
+
+ PACL NewDacl = NULL;
+ BOOLEAN NewDaclPresent = FALSE;
+ BOOLEAN NewDaclInherited = FALSE;
+
+ PACL ServerDacl = NULL;
+ BOOLEAN ServerDaclAllocated = FALSE;
+
+ PSID NewOwner = NULL;
+ PSID NewGroup = NULL;
+
+ BOOLEAN CleanUp = FALSE;
+ BOOLEAN SaclExplicitlyAssigned = FALSE;
+ BOOLEAN DaclExplicitlyAssigned = FALSE;
+ BOOLEAN OwnerExplicitlyAssigned = FALSE;
+
+ BOOLEAN ServerObject;
+ BOOLEAN DaclUntrusted;
+
+ BOOLEAN HasPrivilege;
+
+ PSID SubjectContextOwner;
+ PSID SubjectContextGroup;
+ PSID SubjectContextServerOwner;
+ PSID SubjectContextServerGroup;
+ PACL SubjectContextDacl;
+
+ ULONG AllocationSize;
+ ULONG NewOwnerSize;
+ ULONG NewGroupSize;
+ ULONG NewSaclSize;
+ ULONG NewDaclSize;
+
+ PCHAR Field;
+ PCHAR Base;
+
+ PAGED_CODE();
+
+ PoolType = PagedPool;
+
+ //
+ // The desired end result is to build a self-relative security descriptor.
+ // This means that a single block of memory will be allocated and all
+ // security information copied into it. To minimize work along the way,
+ // it is desirable to reference (rather than copy) each field as we
+ // determine its source. This can not be done with inherited ACLs, however,
+ // since they must be built from another ACL. So, explicitly assigned
+ // and defaulted SIDs and ACLs are just referenced until they are copied
+ // into the self-relative descriptor. Inherited ACLs are built in a
+ // temporary buffer which must be deallocated after being copied to the
+ // self-relative descriptor.
+ //
+
+
+ //
+ // Get the previous mode of the caller
+ //
+
+ RequestorMode = KeGetPreviousMode();
+
+ //
+ // If a security descriptor has been passed, capture it, otherwise
+ // cobble up a fake one to simplify the code that follows.
+ //
+
+ if (ARGUMENT_PRESENT(ExplicitDescriptor)) {
+
+ CapturedDescriptor = ExplicitDescriptor;
+ SecurityDescriptorPassed = TRUE;
+
+ } else {
+
+ //
+ // No descriptor passed, make a fake one
+ //
+
+ SecurityDescriptorPassed = FALSE;
+ RtlCreateSecurityDescriptor((PSECURITY_DESCRIPTOR)&InCaseOneNotPassed,
+ SECURITY_DESCRIPTOR_REVISION);
+ CapturedDescriptor = &InCaseOneNotPassed;
+
+ }
+
+#if DBG
+ SepDumpSecurityDescriptor( (PSECURITY_DESCRIPTOR)CapturedDescriptor,
+ "\nSeAssignSecurity: Input security descriptor = \n"
+ );
+
+ if (ARGUMENT_PRESENT( ParentDescriptor )) {
+ SepDumpSecurityDescriptor( (PSECURITY_DESCRIPTOR)ParentDescriptor,
+ "\nSeAssignSecurity: Parent security descriptor = \n"
+ );
+ }
+#endif // DBG
+ //
+ // Grab pointers to the default owner, primary group, and
+ // discretionary ACL.
+ //
+
+ //
+ // Lock the subject context for read access so that the pointers
+ // we copy out of it don't disappear on us at random
+ //
+
+ SeLockSubjectContext( SubjectContext );
+
+ SepGetDefaultsSubjectContext(
+ SubjectContext,
+ &SubjectContextOwner,
+ &SubjectContextGroup,
+ &SubjectContextServerOwner,
+ &SubjectContextServerGroup,
+ &SubjectContextDacl
+ );
+
+
+ if ( CapturedDescriptor->Control & SE_SERVER_SECURITY ) {
+ ServerObject = TRUE;
+ } else {
+ ServerObject = FALSE;
+ }
+
+ if ( CapturedDescriptor->Control & SE_DACL_UNTRUSTED ) {
+ DaclUntrusted = TRUE;
+ } else {
+ DaclUntrusted = FALSE;
+ }
+
+
+ if (!CleanUp) {
+
+ //
+ // Establish System Acl
+ //
+
+ if ( (CapturedDescriptor->Control & SE_SACL_PRESENT) &&
+ !(CapturedDescriptor->Control & SE_SACL_DEFAULTED) ) {
+
+ //
+ // Explicitly provided, not defaulted (Cases 1 and 2)
+ //
+
+ NewSacl = SepSaclAddrSecurityDescriptor(CapturedDescriptor);
+ NewSaclPresent = TRUE;
+ SaclExplicitlyAssigned = TRUE;
+
+ } else {
+
+ //
+ // See if there is an inheritable ACL (copy it if there is one.)
+ // This maps all ACEs for the target object type too.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ if (ARGUMENT_PRESENT(ParentDescriptor) &&
+ NT_SUCCESS(Status = SepInheritAcl(
+ SepSaclAddrSecurityDescriptor(
+ ((SECURITY_DESCRIPTOR *)ParentDescriptor)
+ ),
+ IsDirectoryObject,
+ SubjectContextOwner,
+ SubjectContextGroup,
+ SubjectContextServerOwner,
+ SubjectContextServerGroup,
+ GenericMapping,
+ PoolType,
+ &NewSacl )
+ )) {
+
+ //
+ // There is an inheritable ACL from the parent. Assign
+ // it. (Cases 3 and 5)
+ //
+
+ NewSaclPresent = TRUE;
+ NewSaclInherited = TRUE;
+
+ } else if (!ARGUMENT_PRESENT(ParentDescriptor) || (Status == STATUS_NO_INHERITANCE)) {
+
+ //
+ // No inheritable ACL - check for a defaulted one
+ // (Cases 4 and 6)
+ //
+
+ if ( (CapturedDescriptor->Control & SE_SACL_PRESENT) &&
+ (CapturedDescriptor->Control & SE_SACL_DEFAULTED) ) {
+
+ //
+ // Reference the default ACL (case 4)
+ //
+
+ NewSacl = SepSaclAddrSecurityDescriptor(CapturedDescriptor);
+ NewSaclPresent = TRUE;
+
+ //
+ // Set SaclExplicitlyAssigned, because the caller
+ // must have SeSecurityPrivilege to do this. We
+ // will examine this flag and check for this privilege
+ // later.
+ //
+
+ SaclExplicitlyAssigned = TRUE;
+ }
+ } else {
+
+ //
+ // Some unusual error occured
+ //
+
+ CleanUp = TRUE;
+ }
+ }
+ }
+
+
+
+
+ if (!CleanUp) {
+
+ //
+ // Establish Discretionary Acl
+ //
+
+ if ( (CapturedDescriptor->Control & SE_DACL_PRESENT) &&
+ !(CapturedDescriptor->Control & SE_DACL_DEFAULTED) ) {
+
+ //
+ // Explicitly provided, not defaulted (Cases 1 and 2)
+ //
+
+ NewDacl = SepDaclAddrSecurityDescriptor(CapturedDescriptor);
+ NewDaclPresent = TRUE;
+ DaclExplicitlyAssigned = TRUE;
+
+ } else {
+
+ //
+ // See if there is an inheritable ACL (copy it if there is one.)
+ // This maps the ACEs to the target object type too.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ if (ARGUMENT_PRESENT(ParentDescriptor) &&
+ NT_SUCCESS(Status = SepInheritAcl(
+ SepDaclAddrSecurityDescriptor(
+ ((SECURITY_DESCRIPTOR *)ParentDescriptor)
+ ),
+ IsDirectoryObject,
+ SubjectContextOwner,
+ SubjectContextGroup,
+ SubjectContextServerOwner,
+ SubjectContextServerGroup,
+ GenericMapping,
+ PoolType,
+ &NewDacl )
+ )) {
+
+ //
+ // There is an inheritable ACL from the parent. Assign
+ // it. (Cases 3 and 5)
+ //
+
+ NewDaclPresent = TRUE;
+ NewDaclInherited = TRUE;
+
+ } else if (!ARGUMENT_PRESENT(ParentDescriptor) || (Status == STATUS_NO_INHERITANCE)) {
+
+ //
+ // No inheritable ACL - check for a defaulted one in the
+ // security descriptor. If there isn't one there, then look
+ // for one in the subject's security context (Cases 4 and 6)
+ //
+
+ if ( (CapturedDescriptor->Control & SE_DACL_PRESENT) &&
+ (CapturedDescriptor->Control & SE_DACL_DEFAULTED) ) {
+
+ //
+ // reference the default ACL (Case 4)
+ //
+
+ NewDacl = SepDaclAddrSecurityDescriptor(CapturedDescriptor);
+ NewDaclPresent = TRUE;
+
+ //
+ // This counts as an explicit assignment.
+ //
+
+ DaclExplicitlyAssigned = TRUE;
+
+ } else {
+
+ if (ARGUMENT_PRESENT(SubjectContextDacl)) {
+
+ NewDacl = SubjectContextDacl;
+ NewDaclPresent = TRUE;
+ }
+ }
+
+ } else {
+
+ //
+ // Some unusual error occured
+ //
+
+ CleanUp = TRUE;
+ }
+ }
+ }
+
+
+ if (!CleanUp) {
+ //
+ // Establish an owner SID
+ //
+
+ if ((CapturedDescriptor->Owner) != NULL) {
+
+ //
+ // Use the specified owner
+ //
+
+ NewOwner = SepOwnerAddrSecurityDescriptor(CapturedDescriptor);
+ OwnerExplicitlyAssigned = TRUE;
+
+ } else {
+
+ //
+ // Pick up the default from the subject's security context.
+ //
+ // This does NOT constitute explicit assignment of owner
+ // and does not have to be checked as an ID that can be
+ // assigned as owner. This is because a default can not
+ // be established in a token unless the user of the token
+ // can assign it as an owner.
+ //
+
+ //
+ // If we've been asked to create a ServerObject, we need to
+ // make sure to pick up the new owner from the Primary token,
+ // not the client token. If we're not impersonating, they will
+ // end up being the same.
+ //
+
+ NewOwner = ServerObject ? SubjectContextServerOwner : SubjectContextOwner;
+ }
+ }
+
+
+
+ if (!CleanUp) {
+ //
+ // Establish a Group SID
+ //
+
+ if ((CapturedDescriptor->Group) != NULL) {
+
+ //
+ // Use the specified Group
+ //
+
+ NewGroup = SepGroupAddrSecurityDescriptor(CapturedDescriptor);
+
+ } else {
+
+ //
+ // Pick up the primary group from the subject's security context.
+ //
+ // If we're creating a Server object, use the group from the server
+ // context.
+ //
+
+ NewGroup = ServerObject ? SubjectContextServerGroup : SubjectContextGroup;
+ }
+ }
+
+
+ if (!CleanUp) {
+
+ //
+ // Now make sure that the caller has the right to assign
+ // everything in the descriptor. If requestor is kernel mode,
+ // then anything is legitimate. Otherwise, the requestor
+ // is subjected to privilege and restriction tests for some
+ // assignments.
+ //
+
+ if (RequestorMode == UserMode) {
+
+ //
+ // Anybody can assign any Discretionary ACL or group that they want to.
+ //
+
+ //
+ // See if the system ACL was explicitly specified
+ //
+
+ if (SaclExplicitlyAssigned) {
+
+ //
+ // Check for appropriate Privileges
+ // Audit/Alarm messages need to be generated due to the attempt
+ // to perform a privileged operation.
+ //
+
+ HasPrivilege = SeSinglePrivilegeCheck(
+ SeSecurityPrivilege,
+ RequestorMode
+ );
+
+ if (!HasPrivilege) {
+
+ RequestorCanAssignDescriptor = FALSE;
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ }
+
+ }
+
+ //
+ // See if the owner field is one the requestor can assign
+ //
+
+ if (OwnerExplicitlyAssigned) {
+
+
+ if (!SepValidOwnerSubjectContext(
+ SubjectContext,
+ NewOwner,
+ ServerObject)
+ ) {
+
+ RequestorCanAssignDescriptor = FALSE;
+ Status = STATUS_INVALID_OWNER;
+ }
+ }
+
+ if (DaclExplicitlyAssigned) {
+
+ //
+ // Perform analysis of compound ACEs to make sure they're all
+ // legitimate.
+ //
+
+ if (ServerObject) {
+
+ //
+ // Pass in the Server Owner as the default server SID.
+ //
+
+ Status = SepCreateServerAcl(
+ NewDacl,
+ DaclUntrusted,
+ SubjectContextServerOwner,
+ &ServerDacl,
+ &ServerDaclAllocated
+ );
+
+ if (!NT_SUCCESS( Status )) {
+
+ RequestorCanAssignDescriptor = FALSE;
+
+ } else {
+
+ NewDacl = ServerDacl;
+ }
+ }
+ }
+ }
+
+ if (RequestorCanAssignDescriptor) {
+
+ //
+ // Everything is assignable by the requestor.
+ // Calculate the memory needed to house all the information in
+ // a self-relative security descriptor.
+ //
+ // Also map the ACEs for application to the target object
+ // type, if they haven't already been mapped.
+ //
+
+ NewOwnerSize = (ULONG)LongAlign(SeLengthSid(NewOwner));
+
+ if (NewGroup != NULL) {
+ NewGroupSize = (ULONG)LongAlign(SeLengthSid(NewGroup));
+ } else {
+ NewGroupSize = 0;
+ }
+
+ if (NewSaclPresent && (NewSacl != NULL)) {
+ NewSaclSize = (ULONG)LongAlign(NewSacl->AclSize);
+ } else {
+ NewSaclSize = 0;
+ }
+
+ if (NewDaclPresent && (NewDacl != NULL)) {
+ NewDaclSize = (ULONG)LongAlign(NewDacl->AclSize);
+ } else {
+ NewDaclSize = 0;
+ }
+
+ AllocationSize = (ULONG)LongAlign(sizeof(SECURITY_DESCRIPTOR)) +
+ NewOwnerSize +
+ NewGroupSize +
+ NewSaclSize +
+ NewDaclSize;
+
+ //
+ // Allocate and initialize the security descriptor as
+ // self-relative form.
+ //
+
+ *NewDescriptor = (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag( PoolType, AllocationSize, 'dSeS');
+
+ if ((*NewDescriptor) == NULL) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ RtlCreateSecurityDescriptor(
+ (*NewDescriptor),
+ SECURITY_DESCRIPTOR_REVISION
+ );
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Control |=
+ SE_SELF_RELATIVE;
+
+
+ Base = (PCHAR)(*NewDescriptor);
+ Field = Base + (ULONG)sizeof(SECURITY_DESCRIPTOR);
+
+ //
+ // Map and Copy in the Sacl
+ //
+
+ if (NewSaclPresent) {
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Control |=
+ SE_SACL_PRESENT;
+ if (NewSacl != NULL) {
+ RtlMoveMemory( Field, NewSacl, NewSacl->AclSize );
+ if (!NewSaclInherited) {
+ SepApplyAclToObject( (PACL)Field, GenericMapping );
+ }
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Sacl = (PACL)RtlPointerToOffset(Base,Field);
+ Field += NewSaclSize;
+ } else {
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Sacl = NULL;
+ }
+
+ }
+
+ //
+ // Map and Copy in the Dacl
+ //
+
+ if (NewDaclPresent) {
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Control |=
+ SE_DACL_PRESENT;
+ if (NewDacl != NULL) {
+ RtlMoveMemory( Field, NewDacl, NewDacl->AclSize );
+ if (!NewDaclInherited) {
+ SepApplyAclToObject( (PACL)Field, GenericMapping );
+ }
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Dacl = (PACL)RtlPointerToOffset(Base,Field);
+ Field += NewDaclSize;
+ } else {
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Dacl = NULL;
+ }
+ }
+
+
+ //
+ // Assign the owner
+ //
+
+ RtlMoveMemory( Field, NewOwner, SeLengthSid(NewOwner) );
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Owner = (PSID)RtlPointerToOffset(Base,Field);
+ Field += NewOwnerSize;
+
+ if (NewGroup != NULL) {
+ RtlMoveMemory( Field, NewGroup, SeLengthSid(NewGroup) );
+ }
+ ((SECURITY_DESCRIPTOR *)(*NewDescriptor))->Group = (PSID)RtlPointerToOffset(Base,Field);
+
+ Status = STATUS_SUCCESS;
+ }
+
+ }
+ }
+
+ //
+ // If we allocated memory for a Server DACL, free it now.
+ //
+
+ if (ServerDaclAllocated) {
+ ExFreePool( ServerDacl );
+ }
+
+ //
+ // Either an error was encountered or the requestor the assignment has
+ // completed successfully. In either case, we have to clean up any
+ // memory.
+ //
+
+ SeUnlockSubjectContext( SubjectContext );
+
+ if (NewSaclInherited) {
+ ExFreePool( NewSacl );
+ }
+
+ if (NewDaclInherited) {
+ ExFreePool( NewDacl );
+ }
+
+#if DBG
+ SepDumpSecurityDescriptor( *NewDescriptor,
+ "SeAssignSecurity: Final security descriptor = \n"
+ );
+#endif
+
+ return Status;
+}
+
+
+NTSTATUS
+SeDeassignSecurity (
+ IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates the memory associated with a security descriptor
+ that was assigned using SeAssignSecurity.
+
+
+Arguments:
+
+ SecurityDescriptor - Supplies the address of a pointer to the security
+ descriptor being deleted.
+
+Return Value:
+
+ STATUS_SUCCESS - The deallocation was successful.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ if ((*SecurityDescriptor) != NULL) {
+ ExFreePool( (*SecurityDescriptor) );
+ }
+
+ //
+ // And zero out the pointer to it for safety sake
+ //
+
+ (*SecurityDescriptor) = NULL;
+
+ return( STATUS_SUCCESS );
+
+}
+
+
+VOID
+SepApplyAclToObject (
+ 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 user mode runtime (in sertl.c). Do not make changes //
+// here without also making changes in that module. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+
+ ULONG i;
+
+ PACE_HEADER Ace;
+
+ 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;
+}
+
+
+NTSTATUS
+SepInheritAcl (
+ IN PACL Acl,
+ IN BOOLEAN IsDirectoryObject,
+ IN PSID ClientOwnerSid,
+ IN PSID ClientGroupSid,
+ IN PSID ServerOwnerSid OPTIONAL,
+ IN PSID ServerGroupSid OPTIONAL,
+ IN PGENERIC_MAPPING GenericMapping,
+ IN POOL_TYPE PoolType,
+ 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.
+
+ ServerSid - Specifies the Server SID to use.
+
+ ClientSid - Specifies the Client SID to use.
+
+ GenericMapping - Specifies the generic mapping to use.
+
+ PoolType - Specifies the pool type for the new acl.
+
+ 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 user mode runtime (in sertl.c). Do not make changes //
+// here without also making changes in that module. //
+// //
+//////////////////////////////////////////////////////////////////////////////
+
+
+ NTSTATUS Status;
+ ULONG NewAclLength;
+
+ PAGED_CODE();
+
+ //
+ // 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,
+ ClientOwnerSid,
+ ClientGroupSid,
+ ServerOwnerSid,
+ ServerGroupSid,
+ GenericMapping,
+ &NewAclLength
+ );
+
+ if ( !NT_SUCCESS(Status) ) {
+ return Status;
+ }
+ if (NewAclLength == 0) {
+ return STATUS_NO_INHERITANCE;
+ }
+
+ (*NewAcl) = (PACL)ExAllocatePoolWithTag( PoolType, NewAclLength, 'cAeS' );
+ if ((*NewAcl) == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCreateAcl( (*NewAcl), NewAclLength, Acl->AclRevision );
+
+ Status = RtlpGenerateInheritAcl(
+ Acl,
+ IsDirectoryObject,
+ ClientOwnerSid,
+ ClientGroupSid,
+ ServerOwnerSid,
+ ServerGroupSid,
+ GenericMapping,
+ (*NewAcl)
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ ExFreePool( (*NewAcl) );
+ }
+
+ return Status;
+}
+
+
+
+NTSTATUS
+SeAssignWorldSecurityDescriptor(
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN OUT PULONG Length,
+ IN PSECURITY_INFORMATION SecurityInformation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to properly initialize a
+ security descriptor for a FAT file. It will take a pointer to a
+ buffer containing an emptry security descriptor, and create in the
+ buffer a self-relative security descriptor with
+
+ Owner = WorldSid,
+
+ Group = WorldSid.
+
+ Thus, a FAT file is accessable to all.
+
+Arguments:
+
+ SecurityDescriptor - Supplies a pointer to a buffer in which will be
+ created a self-relative security descriptor as described above.
+
+ Length - The length in bytes of the buffer. If the length is too
+ small, it will contain the minimum size required upon exit.
+
+
+Return Value:
+
+ STATUS_BUFFER_TOO_SMALL - The buffer was not big enough to contain
+ the requested information.
+
+
+--*/
+
+{
+
+ PCHAR Field;
+ PCHAR Base;
+ ULONG WorldSidLength;
+ PISECURITY_DESCRIPTOR ISecurityDescriptor;
+ ULONG MinSize;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ if ( !ARGUMENT_PRESENT( SecurityInformation )) {
+
+ return( STATUS_ACCESS_DENIED );
+ }
+
+ WorldSidLength = SeLengthSid( SeWorldSid );
+
+ MinSize = sizeof( SECURITY_DESCRIPTOR ) + 2 * WorldSidLength;
+
+ if ( *Length < MinSize ) {
+
+ *Length = MinSize;
+ return( STATUS_BUFFER_TOO_SMALL );
+ }
+
+ *Length = MinSize;
+
+ ISecurityDescriptor = (SECURITY_DESCRIPTOR *)SecurityDescriptor;
+
+ Status = RtlCreateSecurityDescriptor( ISecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+
+ if (!NT_SUCCESS( Status )) {
+ return( Status );
+ }
+
+ Base = (PCHAR)(ISecurityDescriptor);
+ Field = Base + (ULONG)sizeof(SECURITY_DESCRIPTOR);
+
+ if ( *SecurityInformation & OWNER_SECURITY_INFORMATION ) {
+
+ RtlMoveMemory( Field, SeWorldSid, WorldSidLength );
+ ISecurityDescriptor->Owner = (PSID)RtlPointerToOffset(Base,Field);
+ Field += WorldSidLength;
+ }
+
+ if ( *SecurityInformation & GROUP_SECURITY_INFORMATION ) {
+
+ RtlMoveMemory( Field, SeWorldSid, WorldSidLength );
+ ISecurityDescriptor->Group = (PSID)RtlPointerToOffset(Base,Field);
+ }
+
+ if ( *SecurityInformation & DACL_SECURITY_INFORMATION ) {
+ SepSetControlBits( ISecurityDescriptor, SE_DACL_PRESENT );
+ }
+
+ if ( *SecurityInformation & SACL_SECURITY_INFORMATION ) {
+ SepSetControlBits( ISecurityDescriptor, SE_SACL_PRESENT );
+ }
+
+ SepSetControlBits( ISecurityDescriptor, SE_SELF_RELATIVE );
+
+ return( STATUS_SUCCESS );
+
+}
+
+
+
+NTSTATUS
+SepCreateServerAcl(
+ IN PACL Acl,
+ IN BOOLEAN AclUntrusted,
+ IN PSID ServerSid,
+ OUT PACL *ServerAcl,
+ OUT BOOLEAN *ServerAclAllocated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes an ACL and converts it into a server ACL.
+ Currently, that means converting all of the GRANT ACEs into
+ Compount Grants, and if necessary sanitizing any Compound
+ Grants that are encountered.
+
+Arguments:
+
+
+
+Return Value:
+
+
+--*/
+
+{
+ USHORT RequiredSize = sizeof(ACL);
+ USHORT AceSizeAdjustment;
+ USHORT ServerSidSize;
+ PACE_HEADER Ace;
+ ULONG i;
+ PVOID Target;
+ PVOID AcePosition;
+ PSID UntrustedSid;
+ PSID ClientSid;
+ NTSTATUS Status;
+
+ if (Acl == NULL) {
+ *ServerAclAllocated = FALSE;
+ *ServerAcl = NULL;
+ return( STATUS_SUCCESS );
+ }
+
+ AceSizeAdjustment = sizeof( KNOWN_COMPOUND_ACE ) - sizeof( KNOWN_ACE );
+ ASSERT( sizeof( KNOWN_COMPOUND_ACE ) >= sizeof( KNOWN_ACE ) );
+
+ ServerSidSize = (USHORT)SeLengthSid( ServerSid );
+
+ //
+ // Do this in two passes. First, determine how big the final
+ // result is going to be, and then allocate the space and make
+ // the changes.
+ //
+
+ for (i = 0, Ace = FirstAce(Acl);
+ i < Acl->AceCount;
+ i += 1, Ace = NextAce(Ace)) {
+
+ //
+ // If it's an ACCESS_ALLOWED_ACE_TYPE, we'll need to add in the
+ // size of the Server SID.
+ //
+
+ if (Ace->AceType == ACCESS_ALLOWED_ACE_TYPE) {
+
+ //
+ // Simply add the size of the new Server SID plus whatever
+ // adjustment needs to be made to increase the size of the ACE.
+ //
+
+ RequiredSize += ( ServerSidSize + AceSizeAdjustment );
+
+ } else {
+
+ if (AclUntrusted && Ace->AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE ) {
+
+ //
+ // Since the Acl is untrusted, we don't care what is in the
+ // server SID, we're going to replace it.
+ //
+
+ UntrustedSid = RtlCompoundAceServerSid( Ace );
+ if ((USHORT)SeLengthSid(UntrustedSid) > ServerSidSize) {
+ RequiredSize += ((USHORT)SeLengthSid(UntrustedSid) - ServerSidSize);
+ } else {
+ RequiredSize += (ServerSidSize - (USHORT)SeLengthSid(UntrustedSid));
+
+ }
+ }
+ }
+
+ RequiredSize += Ace->AceSize;
+ }
+
+ (*ServerAcl) = (PACL)ExAllocatePoolWithTag( PagedPool, RequiredSize, 'cAeS' );
+
+ if ((*ServerAcl) == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Mark as allocated so caller knows to free it.
+ //
+
+ *ServerAclAllocated = TRUE;
+
+ Status = RtlCreateAcl( (*ServerAcl), RequiredSize, ACL_REVISION3 );
+ ASSERT( NT_SUCCESS( Status ));
+
+ for (i = 0, Ace = FirstAce(Acl), Target=FirstAce( *ServerAcl );
+ i < Acl->AceCount;
+ i += 1, Ace = NextAce(Ace)) {
+
+ //
+ // If it's an ACCESS_ALLOWED_ACE_TYPE, convert to a Server ACE.
+ //
+
+ if (Ace->AceType == ACCESS_ALLOWED_ACE_TYPE ||
+ (AclUntrusted && Ace->AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE )) {
+
+ AcePosition = Target;
+
+ if (Ace->AceType == ACCESS_ALLOWED_ACE_TYPE) {
+ ClientSid = &((PKNOWN_ACE)Ace)->SidStart;
+ } else {
+ ClientSid = RtlCompoundAceClientSid( Ace );
+ }
+
+ //
+ // Copy up to the access mask.
+ //
+
+ RtlMoveMemory(
+ Target,
+ Ace,
+ FIELD_OFFSET(KNOWN_ACE, SidStart)
+ );
+
+ //
+ // Now copy the correct Server SID
+ //
+
+ Target = (PVOID)((ULONG)Target + (UCHAR)(FIELD_OFFSET(KNOWN_COMPOUND_ACE, SidStart)));
+
+ RtlMoveMemory(
+ Target,
+ ServerSid,
+ SeLengthSid(ServerSid)
+ );
+
+ Target = (PVOID)((ULONG)Target + (UCHAR)SeLengthSid(ServerSid));
+
+ //
+ // Now copy in the correct client SID. We can copy this right out of
+ // the original ACE.
+ //
+
+ RtlMoveMemory(
+ Target,
+ ClientSid,
+ SeLengthSid(ClientSid)
+ );
+
+ Target = (PVOID)((ULONG)Target + SeLengthSid(ClientSid));
+
+ //
+ // Set the size of the ACE accordingly
+ //
+
+ ((PKNOWN_COMPOUND_ACE)AcePosition)->Header.AceSize =
+ (USHORT)FIELD_OFFSET(KNOWN_COMPOUND_ACE, SidStart) +
+ (USHORT)SeLengthSid(ServerSid) +
+ (USHORT)SeLengthSid(ClientSid);
+
+ //
+ // Set the type
+ //
+
+ ((PKNOWN_COMPOUND_ACE)AcePosition)->Header.AceType = ACCESS_ALLOWED_COMPOUND_ACE_TYPE;
+ ((PKNOWN_COMPOUND_ACE)AcePosition)->CompoundAceType = COMPOUND_ACE_IMPERSONATION;
+
+ } else {
+
+ //
+ // Just copy the ACE as is.
+ //
+
+ RtlMoveMemory( Target, Ace, Ace->AceSize );
+
+ Target = (PVOID)((ULONG)Target + Ace->AceSize);
+ }
+ }
+
+ (*ServerAcl)->AceCount = Acl->AceCount;
+
+ return( STATUS_SUCCESS );
+}
+
+
+
+
+
+
+
+//
+// BUGWARNING The following routines should be in a debug only kernel, since
+// all they do is dump stuff to a debug terminal as appropriate. The same
+// goes for the declarations of the variables SepDumpSD and SepDumpToken
+//
+
+
+
+VOID
+SepDumpSecurityDescriptor(
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PSZ TitleString
+ )
+
+/*++
+
+Routine Description:
+
+ Private routine to dump a security descriptor to the debug
+ screen.
+
+Arguments:
+
+ SecurityDescriptor - Supplies the security descriptor to be dumped.
+
+ TitleString - A null terminated string to print before dumping
+ the security descriptor.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+#if DBG
+ PISECURITY_DESCRIPTOR ISecurityDescriptor;
+ UCHAR Revision;
+ SECURITY_DESCRIPTOR_CONTROL Control;
+ PSID Owner;
+ PSID Group;
+ PACL Sacl;
+ PACL Dacl;
+
+ PAGED_CODE();
+
+
+ if (!SepDumpSD) {
+ return;
+ }
+
+ if (!ARGUMENT_PRESENT( SecurityDescriptor )) {
+ return;
+ }
+
+ DbgPrint(TitleString);
+
+ ISecurityDescriptor = ( PISECURITY_DESCRIPTOR )SecurityDescriptor;
+
+ Revision = ISecurityDescriptor->Revision;
+ Control = ISecurityDescriptor->Control;
+
+ Owner = SepOwnerAddrSecurityDescriptor( ISecurityDescriptor );
+ Group = SepGroupAddrSecurityDescriptor( ISecurityDescriptor );
+ Sacl = SepSaclAddrSecurityDescriptor( ISecurityDescriptor );
+ Dacl = SepDaclAddrSecurityDescriptor( ISecurityDescriptor );
+
+ DbgPrint("\nSECURITY DESCRIPTOR\n");
+
+ DbgPrint("Revision = %d\n",Revision);
+
+ //
+ // Print control info
+ //
+
+ if (Control & SE_OWNER_DEFAULTED) {
+ DbgPrint("Owner defaulted\n");
+ }
+ if (Control & SE_GROUP_DEFAULTED) {
+ DbgPrint("Group defaulted\n");
+ }
+ if (Control & SE_DACL_PRESENT) {
+ DbgPrint("Dacl present\n");
+ }
+ if (Control & SE_DACL_DEFAULTED) {
+ DbgPrint("Dacl defaulted\n");
+ }
+ if (Control & SE_SACL_PRESENT) {
+ DbgPrint("Sacl present\n");
+ }
+ if (Control & SE_SACL_DEFAULTED) {
+ DbgPrint("Sacl defaulted\n");
+ }
+ if (Control & SE_SELF_RELATIVE) {
+ DbgPrint("Self relative\n");
+ }
+ if (Control & SE_DACL_UNTRUSTED) {
+ DbgPrint("Dacl untrusted\n");
+ }
+ if (Control & SE_SERVER_SECURITY) {
+ DbgPrint("Server security\n");
+ }
+
+ DbgPrint("Owner ");
+ SepPrintSid( Owner );
+
+ DbgPrint("Group ");
+ SepPrintSid( Group );
+
+ DbgPrint("Sacl");
+ SepPrintAcl( Sacl );
+
+ DbgPrint("Dacl");
+ SepPrintAcl( Dacl );
+#endif
+}
+
+
+
+VOID
+SepPrintAcl (
+ IN PACL Acl
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dumps via (DbgPrint) an Acl for debug purposes. It is
+ specialized to dump standard aces.
+
+Arguments:
+
+ Acl - Supplies the Acl to dump
+
+Return Value:
+
+ None
+
+--*/
+
+
+{
+#if DBG
+ ULONG i;
+ PKNOWN_ACE Ace;
+ BOOLEAN KnownType;
+
+ PAGED_CODE();
+
+ DbgPrint("@ %8lx\n", Acl);
+
+ //
+ // Check if the Acl is null
+ //
+
+ if (Acl == NULL) {
+
+ return;
+
+ }
+
+ //
+ // Dump the Acl header
+ //
+
+ DbgPrint(" Revision: %02x", Acl->AclRevision);
+ DbgPrint(" Size: %04x", Acl->AclSize);
+ DbgPrint(" AceCount: %04x\n", Acl->AceCount);
+
+ //
+ // Now for each Ace we want do dump it
+ //
+
+ for (i = 0, Ace = FirstAce(Acl);
+ i < Acl->AceCount;
+ i++, Ace = NextAce(Ace) ) {
+
+ //
+ // print out the ace header
+ //
+
+ DbgPrint("\n AceHeader: %08lx ", *(PULONG)Ace);
+
+ //
+ // special case on the standard ace types
+ //
+
+ if ((Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) ||
+ (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE) ||
+ (Ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE) ||
+ (Ace->Header.AceType == SYSTEM_ALARM_ACE_TYPE) ||
+ (Ace->Header.AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE)) {
+
+ //
+ // The following array is indexed by ace types and must
+ // follow the allowed, denied, audit, alarm seqeuence
+ //
+
+ PCHAR AceTypes[] = { "Access Allowed",
+ "Access Denied ",
+ "System Audit ",
+ "System Alarm ",
+ "Compound Grant",
+ };
+
+ DbgPrint(AceTypes[Ace->Header.AceType]);
+ DbgPrint("\n Access Mask: %08lx ", Ace->Mask);
+ KnownType = TRUE;
+
+ } else {
+
+ DbgPrint(" Unknown Ace Type\n");
+ KnownType = FALSE;
+ }
+
+ DbgPrint("\n");
+
+ DbgPrint(" AceSize = %d\n",Ace->Header.AceSize);
+
+ DbgPrint(" Ace Flags = ");
+ if (Ace->Header.AceFlags & OBJECT_INHERIT_ACE) {
+ DbgPrint("OBJECT_INHERIT_ACE\n");
+ DbgPrint(" ");
+ }
+
+ if (Ace->Header.AceFlags & CONTAINER_INHERIT_ACE) {
+ DbgPrint("CONTAINER_INHERIT_ACE\n");
+ DbgPrint(" ");
+ }
+
+ if (Ace->Header.AceFlags & NO_PROPAGATE_INHERIT_ACE) {
+ DbgPrint("NO_PROPAGATE_INHERIT_ACE\n");
+ DbgPrint(" ");
+ }
+
+ if (Ace->Header.AceFlags & INHERIT_ONLY_ACE) {
+ DbgPrint("INHERIT_ONLY_ACE\n");
+ DbgPrint(" ");
+ }
+
+
+ if (Ace->Header.AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) {
+ DbgPrint("SUCCESSFUL_ACCESS_ACE_FLAG\n");
+ DbgPrint(" ");
+ }
+
+ if (Ace->Header.AceFlags & FAILED_ACCESS_ACE_FLAG) {
+ DbgPrint("FAILED_ACCESS_ACE_FLAG\n");
+ DbgPrint(" ");
+ }
+
+ DbgPrint("\n");
+
+ if (KnownType != TRUE) {
+ continue;
+ }
+
+ if (Ace->Header.AceType != ACCESS_ALLOWED_COMPOUND_ACE_TYPE) {
+ DbgPrint(" Sid = ");
+ SepPrintSid(&Ace->SidStart);
+ } else {
+ DbgPrint(" Server Sid = ");
+ SepPrintSid(RtlCompoundAceServerSid(Ace));
+ DbgPrint("\n Client Sid = ");
+ SepPrintSid(RtlCompoundAceClientSid( Ace ));
+ }
+ }
+#endif
+}
+
+
+
+VOID
+SepPrintSid(
+ IN PSID Sid
+ )
+
+/*++
+
+Routine Description:
+
+ Prints a formatted Sid
+
+Arguments:
+
+ Sid - Provides a pointer to the sid to be printed.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#if DBG
+ UCHAR i;
+ ULONG Tmp;
+ PISID ISid;
+ STRING AccountName;
+ UCHAR Buffer[128];
+
+ PAGED_CODE();
+
+ if (Sid == NULL) {
+ DbgPrint("Sid is NULL\n");
+ return;
+ }
+
+ Buffer[0] = 0;
+
+ AccountName.MaximumLength = 127;
+ AccountName.Length = 0;
+ AccountName.Buffer = (PVOID)&Buffer[0];
+
+ if (SepSidTranslation( Sid, &AccountName )) {
+
+ DbgPrint("%s ", AccountName.Buffer );
+ }
+
+ ISid = (PISID)Sid;
+
+ DbgPrint("S-%lu-", (USHORT)ISid->Revision );
+ if ( (ISid->IdentifierAuthority.Value[0] != 0) ||
+ (ISid->IdentifierAuthority.Value[1] != 0) ){
+ DbgPrint("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] );
+ } 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);
+ DbgPrint("%lu", Tmp);
+ }
+
+
+ for (i=0;i<ISid->SubAuthorityCount ;i++ ) {
+ DbgPrint("-%lu", ISid->SubAuthority[i]);
+ }
+ DbgPrint("\n");
+#endif
+}
+
+
+
+
+VOID
+SepDumpTokenInfo(
+ IN PACCESS_TOKEN Token
+ )
+
+/*++
+
+Routine Description:
+
+ Prints interesting information in a token.
+
+Arguments:
+
+ Token - Provides the token to be examined.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#if DBG
+ ULONG UserAndGroupCount;
+ PSID_AND_ATTRIBUTES TokenSid;
+ ULONG i;
+ PTOKEN IToken;
+
+ PAGED_CODE();
+
+ if (!SepDumpToken) {
+ return;
+ }
+
+ IToken = (TOKEN *)Token;
+
+ UserAndGroupCount = IToken->UserAndGroupCount;
+
+ DbgPrint("\n\nToken User and Groups Array:\n\n");
+
+ for ( i = 0 , TokenSid = IToken->UserAndGroups;
+ i < UserAndGroupCount ;
+ i++, TokenSid++
+ ) {
+
+ SepPrintSid( TokenSid->Sid );
+
+ }
+#endif
+}
+
+
+
+BOOLEAN
+SepSidTranslation(
+ PSID Sid,
+ PSTRING AccountName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine translates well-known SIDs into English names.
+
+Arguments:
+
+ Sid - Provides the sid to be examined.
+
+ AccountName - Provides a string buffer in which to place the
+ translated name.
+
+Return Value:
+
+ None
+
+--*/
+
+// AccountName is expected to have a large maximum length
+
+{
+ PAGED_CODE();
+
+ if (RtlEqualSid(Sid, SeWorldSid)) {
+ RtlInitString( AccountName, "WORLD ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeLocalSid)) {
+ RtlInitString( AccountName, "LOCAL ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeNetworkSid)) {
+ RtlInitString( AccountName, "NETWORK ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeBatchSid)) {
+ RtlInitString( AccountName, "BATCH ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeInteractiveSid)) {
+ RtlInitString( AccountName, "INTERACTIVE ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeLocalSystemSid)) {
+ RtlInitString( AccountName, "SYSTEM ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeCreatorOwnerSid)) {
+ RtlInitString( AccountName, "CREATOR_OWNER ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeCreatorGroupSid)) {
+ RtlInitString( AccountName, "CREATOR_GROUP ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeCreatorOwnerServerSid)) {
+ RtlInitString( AccountName, "CREATOR_OWNER_SERVER ");
+ return(TRUE);
+ }
+
+ if (RtlEqualSid(Sid, SeCreatorGroupServerSid)) {
+ RtlInitString( AccountName, "CREATOR_GROUP_SERVER ");
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+//
+// End debug only routines
+//