1136 lines
28 KiB
C
1136 lines
28 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 "pch.h"
|
||
|
||
#pragma hdrstop
|
||
|
||
|
||
|
||
//
|
||
// Local macros and procedures
|
||
//
|
||
|
||
|
||
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,SeAssignSecurityEx)
|
||
#pragma alloc_text(PAGE,SeDeassignSecurity)
|
||
#pragma alloc_text(PAGE,SepInheritAcl)
|
||
#pragma alloc_text(PAGE,SeAssignWorldSecurityDescriptor)
|
||
#if DBG
|
||
#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 //DBG
|
||
#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.
|
||
|
||
|
||
See RtlpNewSecurityObject for a descriptor of how the NewDescriptor is
|
||
built.
|
||
|
||
|
||
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.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG AutoInherit = 0;
|
||
PAGED_CODE();
|
||
|
||
#if DBG
|
||
if ( ARGUMENT_PRESENT( ExplicitDescriptor) ) {
|
||
SepDumpSecurityDescriptor( ExplicitDescriptor,
|
||
"\nSeAssignSecurity: Input security descriptor = \n"
|
||
);
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT( ParentDescriptor )) {
|
||
SepDumpSecurityDescriptor( ParentDescriptor,
|
||
"\nSeAssignSecurity: Parent security descriptor = \n"
|
||
);
|
||
}
|
||
#endif // DBG
|
||
|
||
//
|
||
// If the Parent SD was created via AutoInheritance,
|
||
// and this object is being created with no explicit descriptor,
|
||
// then we can safely create this object as AutoInherit.
|
||
//
|
||
|
||
if ( ParentDescriptor != NULL ) {
|
||
|
||
if ( (ExplicitDescriptor == NULL ||
|
||
(((PISECURITY_DESCRIPTOR)ExplicitDescriptor)->Control & SE_DACL_PRESENT) == 0 ) &&
|
||
(((PISECURITY_DESCRIPTOR)ParentDescriptor)->Control & SE_DACL_AUTO_INHERITED) != 0 ) {
|
||
AutoInherit |= SEF_DACL_AUTO_INHERIT;
|
||
}
|
||
|
||
if ( (ExplicitDescriptor == NULL ||
|
||
(((PISECURITY_DESCRIPTOR)ExplicitDescriptor)->Control & SE_SACL_PRESENT) == 0 ) &&
|
||
(((PISECURITY_DESCRIPTOR)ParentDescriptor)->Control & SE_SACL_AUTO_INHERITED) != 0 ) {
|
||
AutoInherit |= SEF_SACL_AUTO_INHERIT;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
Status = RtlpNewSecurityObject (
|
||
ParentDescriptor OPTIONAL,
|
||
ExplicitDescriptor OPTIONAL,
|
||
NewDescriptor,
|
||
NULL, // No object type
|
||
0,
|
||
IsDirectoryObject,
|
||
AutoInherit,
|
||
(HANDLE) SubjectContext,
|
||
GenericMapping );
|
||
|
||
#if DBG
|
||
if ( NT_SUCCESS(Status)) {
|
||
SepDumpSecurityDescriptor( *NewDescriptor,
|
||
"SeAssignSecurity: Final security descriptor = \n"
|
||
);
|
||
}
|
||
#endif
|
||
|
||
return Status;
|
||
|
||
|
||
// RtlpNewSecurityObject always uses PagedPool.
|
||
UNREFERENCED_PARAMETER( PoolType );
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SeAssignSecurityEx (
|
||
IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
|
||
IN PSECURITY_DESCRIPTOR ExplicitDescriptor OPTIONAL,
|
||
OUT PSECURITY_DESCRIPTOR *NewDescriptor,
|
||
IN GUID *ObjectType OPTIONAL,
|
||
IN BOOLEAN IsDirectoryObject,
|
||
IN ULONG AutoInheritFlags,
|
||
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.
|
||
|
||
|
||
See RtlpNewSecurityObject for a descriptor of how the NewDescriptor is
|
||
built.
|
||
|
||
|
||
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.
|
||
|
||
ObjectType - GUID of the object type being created. If the object being
|
||
created has no GUID associated with it, then this argument is
|
||
specified as NULL.
|
||
|
||
IsDirectoryObject - Specifies if the new object is itself a directory
|
||
object. A value of TRUE indicates the object is a container of other
|
||
objects.
|
||
|
||
AutoInheritFlags - Controls automatic inheritance of ACES from the Parent
|
||
Descriptor. Valid values are a bits mask of the logical OR of
|
||
one or more of the following bits:
|
||
|
||
SEF_DACL_AUTO_INHERIT - If set, inherit ACEs from the
|
||
DACL ParentDescriptor are inherited to NewDescriptor in addition
|
||
to any explicit ACEs specified by the CreatorDescriptor.
|
||
|
||
SEF_SACL_AUTO_INHERIT - If set, inherit ACEs from the
|
||
SACL ParentDescriptor are inherited to NewDescriptor in addition
|
||
to any explicit ACEs specified by the CreatorDescriptor.
|
||
|
||
SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT - If set, the CreatorDescriptor
|
||
is the default descriptor for ObjectType. As such, the
|
||
CreatorDescriptor will be ignored if any ObjectType specific
|
||
ACEs are inherited from the parent. If no such ACEs are inherited,
|
||
the CreatorDescriptor is handled as though this flag were not
|
||
specified.
|
||
|
||
SEF_AVOID_PRIVILEGE_CHECK - If set, no privilege checking is done by this
|
||
routine. This flag is useful while implementing automatic inheritance
|
||
to avoid checking privileges on each child updated.
|
||
|
||
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.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PAGED_CODE();
|
||
|
||
#if DBG
|
||
if ( ARGUMENT_PRESENT( ExplicitDescriptor) ) {
|
||
SepDumpSecurityDescriptor( ExplicitDescriptor,
|
||
"\nSeAssignSecurityEx: Input security descriptor = \n"
|
||
);
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT( ParentDescriptor )) {
|
||
SepDumpSecurityDescriptor( ParentDescriptor,
|
||
"\nSeAssignSecurityEx: Parent security descriptor = \n"
|
||
);
|
||
}
|
||
#endif // DBG
|
||
|
||
|
||
Status = RtlpNewSecurityObject (
|
||
ParentDescriptor OPTIONAL,
|
||
ExplicitDescriptor OPTIONAL,
|
||
NewDescriptor,
|
||
ObjectType ? &ObjectType : NULL,
|
||
ObjectType ? 1 : 0,
|
||
IsDirectoryObject,
|
||
AutoInheritFlags,
|
||
(HANDLE) SubjectContext,
|
||
GenericMapping );
|
||
|
||
#if DBG
|
||
if ( NT_SUCCESS(Status)) {
|
||
SepDumpSecurityDescriptor( *NewDescriptor,
|
||
"SeAssignSecurityEx: Final security descriptor = \n"
|
||
);
|
||
}
|
||
#endif
|
||
|
||
return Status;
|
||
|
||
|
||
// RtlpNewSecurityObject always uses PagedPool.
|
||
UNREFERENCED_PARAMETER( PoolType );
|
||
|
||
}
|
||
|
||
|
||
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 );
|
||
|
||
}
|
||
|
||
|
||
|
||
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;
|
||
BOOLEAN NewAclExplicitlyAssigned;
|
||
ULONG NewGenericControl;
|
||
|
||
PAGED_CODE();
|
||
ASSERT( PoolType == PagedPool ); // RtlpInheritAcl assumes paged pool
|
||
|
||
//
|
||
// First check if the acl is null
|
||
//
|
||
|
||
if (Acl == NULL) {
|
||
|
||
return STATUS_NO_INHERITANCE;
|
||
}
|
||
|
||
//
|
||
// Generating an inheritable ACL.
|
||
//
|
||
// Pass all parameters as though there is no auto inheritance.
|
||
//
|
||
|
||
Status = RtlpInheritAcl(
|
||
Acl,
|
||
NULL, // No child ACL since no auto inheritance
|
||
0, // No child control since no auto inheritance
|
||
IsDirectoryObject,
|
||
FALSE, // Not AutoInherit since no auto inheritance
|
||
FALSE, // Not DefaultDescriptor since no auto inheritance
|
||
ClientOwnerSid,
|
||
ClientGroupSid,
|
||
ServerOwnerSid,
|
||
ServerGroupSid,
|
||
GenericMapping,
|
||
FALSE, // Isn't a SACL
|
||
NULL, // No object GUID
|
||
0,
|
||
NewAcl,
|
||
&NewAclExplicitlyAssigned,
|
||
&NewGenericControl );
|
||
|
||
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_RELATIVE ISecurityDescriptor;
|
||
ULONG MinSize;
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
if ( !ARGUMENT_PRESENT( SecurityInformation )) {
|
||
|
||
return( STATUS_ACCESS_DENIED );
|
||
}
|
||
|
||
WorldSidLength = SeLengthSid( SeWorldSid );
|
||
|
||
MinSize = sizeof( SECURITY_DESCRIPTOR_RELATIVE ) + 2 * WorldSidLength;
|
||
|
||
if ( *Length < MinSize ) {
|
||
|
||
*Length = MinSize;
|
||
return( STATUS_BUFFER_TOO_SMALL );
|
||
}
|
||
|
||
*Length = MinSize;
|
||
|
||
ISecurityDescriptor = (SECURITY_DESCRIPTOR_RELATIVE *)SecurityDescriptor;
|
||
|
||
Status = RtlCreateSecurityDescriptorRelative( ISecurityDescriptor,
|
||
SECURITY_DESCRIPTOR_REVISION );
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
return( Status );
|
||
}
|
||
|
||
Base = (PCHAR)(ISecurityDescriptor);
|
||
Field = Base + sizeof(SECURITY_DESCRIPTOR_RELATIVE);
|
||
|
||
if ( *SecurityInformation & OWNER_SECURITY_INFORMATION ) {
|
||
|
||
RtlCopyMemory( Field, SeWorldSid, WorldSidLength );
|
||
ISecurityDescriptor->Owner = RtlPointerToOffset(Base,Field);
|
||
Field += WorldSidLength;
|
||
}
|
||
|
||
if ( *SecurityInformation & GROUP_SECURITY_INFORMATION ) {
|
||
|
||
RtlCopyMemory( Field, SeWorldSid, WorldSidLength );
|
||
ISecurityDescriptor->Group = RtlPointerToOffset(Base,Field);
|
||
}
|
||
|
||
if ( *SecurityInformation & DACL_SECURITY_INFORMATION ) {
|
||
RtlpSetControlBits( ISecurityDescriptor, SE_DACL_PRESENT );
|
||
}
|
||
|
||
if ( *SecurityInformation & SACL_SECURITY_INFORMATION ) {
|
||
RtlpSetControlBits( ISecurityDescriptor, SE_SACL_PRESENT );
|
||
}
|
||
|
||
RtlpSetControlBits( ISecurityDescriptor, SE_SELF_RELATIVE );
|
||
|
||
return( STATUS_SUCCESS );
|
||
|
||
}
|
||
|
||
|
||
|
||
#if DBG
|
||
|
||
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.
|
||
|
||
|
||
--*/
|
||
{
|
||
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 = RtlpOwnerAddrSecurityDescriptor( ISecurityDescriptor );
|
||
Group = RtlpGroupAddrSecurityDescriptor( ISecurityDescriptor );
|
||
Sacl = RtlpSaclAddrSecurityDescriptor( ISecurityDescriptor );
|
||
Dacl = RtlpDaclAddrSecurityDescriptor( 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 );
|
||
}
|
||
|
||
|
||
|
||
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
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
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 ));
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
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");
|
||
}
|
||
|
||
|
||
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG UserAndGroupCount;
|
||
PSID_AND_ATTRIBUTES TokenSid;
|
||
ULONG i;
|
||
PTOKEN IToken;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!SepDumpToken) {
|
||
return;
|
||
}
|
||
|
||
IToken = (TOKEN *)Token;
|
||
|
||
UserAndGroupCount = IToken->UserAndGroupCount;
|
||
|
||
DbgPrint("\n\nToken Address=%lx\n",IToken);
|
||
DbgPrint("Token User and Groups Array:\n\n");
|
||
|
||
for ( i = 0 , TokenSid = IToken->UserAndGroups;
|
||
i < UserAndGroupCount ;
|
||
i++, TokenSid++
|
||
) {
|
||
|
||
SepPrintSid( TokenSid->Sid );
|
||
|
||
}
|
||
|
||
if ( IToken->RestrictedSids ) {
|
||
UserAndGroupCount = IToken->RestrictedSidCount;
|
||
|
||
DbgPrint("Restricted Sids Array:\n\n");
|
||
|
||
for ( i = 0 , TokenSid = IToken->RestrictedSids;
|
||
i < UserAndGroupCount ;
|
||
i++, TokenSid++
|
||
) {
|
||
|
||
SepPrintSid( TokenSid->Sid );
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
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
|
||
//
|
||
#endif //DBG
|