1925 lines
50 KiB
C
1925 lines
50 KiB
C
|
/*++
|
|||
|
|
|||
|
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
|
|||
|
//
|