2020-09-30 17:12:29 +02:00

1510 lines
35 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
obdir.c
Abstract:
Utility to obtain a directory of Object Manager Directories for NT.
Author:
Darryl E. Havens (DarrylH) 9-Nov-1990
Revision History:
--*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <malloc.h>
#include <ntlsa.h>
#define BUFFERSIZE 1024
#define Error(N,S) { \
printf(#S); \
printf(" Error %08lX\n", S); \
}
////////////////////////////////////////////////////////
// //
// Internal Prototypes //
// //
////////////////////////////////////////////////////////
BOOLEAN
EnableAllPrivileges(
VOID
);
VOID
QueryDirectory(
IN PSTRING DirectoryName
);
NTSTATUS
OpenObject(
IN HANDLE Root,
IN PWCHAR Type,
IN PWCHAR Name,
IN ACCESS_MASK DesiredAccess,
OUT PHANDLE Object
);
VOID
OpenAndDisplaySacl(
IN HANDLE Root,
IN PWCHAR Type,
IN PWCHAR Name
);
VOID
QueryAndDisplaySacl(
IN HANDLE Object
);
NTSTATUS
DisplaySacl(
PSECURITY_DESCRIPTOR SD
);
VOID
OpenAndDisplayDacl(
IN HANDLE Root,
IN PWCHAR Type,
IN PWCHAR Name
);
VOID
QueryAndDisplayDacl(
IN HANDLE Object
);
NTSTATUS
DisplayDacl(
PSECURITY_DESCRIPTOR SD
);
VOID
DumpAce(
PACE_HEADER Ace,
BOOLEAN AclIsDacl
);
VOID
DumpStandardAceInfo(
PACE_HEADER Ace,
BOOLEAN AclIsDacl
);
VOID
DisplaySid(
IN PSID Sid
);
VOID
ConnectToLsa( VOID );
VOID
Usage( VOID );
////////////////////////////////////////////////////////
// //
// Global Variables //
// //
////////////////////////////////////////////////////////
UCHAR
Buffer[BUFFERSIZE];
LSA_HANDLE
LsaHandle;
BOOLEAN
CompoundLineOutput = FALSE;
DumpDacl = FALSE; // May be changed by command parameter
DumpDaclFull = FALSE; // May be changed by command parameter
DumpSacl = FALSE; // May be changed by command parameter
DumpSaclFull = FALSE; // May be changed by command parameter
////////////////////////////////////////////////////////
// //
// Routines //
// //
////////////////////////////////////////////////////////
VOID
_CRTAPI1 main(
int argc,
char *argv[]
)
{
STRING
String;
int
arg;
char
*s;
BOOLEAN
DirectoryNameArg;
//
// process any qualifiers
//
// All arguments are considered qualifiers until we reach a backslash ("\").
// If we reach a backslash, then that argument is accepted as the last argument
// and it is expected to the the name of the directory to be listed.
//
DirectoryNameArg = FALSE;
arg = 1;
while (arg < argc) {
s = argv[arg];
if (*s == '\\') {
DirectoryNameArg = TRUE;
break; // break out of while loop
}
if (*s != '/') {
Usage();
return;
}
s++;
if (*s == 'd') {
//
// Dump DACL qualifier
//
if (DumpDaclFull == TRUE) {
printf("\n\n Conflicting qualifiers: \\d and \\D\n");
Usage();
return;
}
DumpDacl = TRUE;
DumpDaclFull = FALSE;
CompoundLineOutput = TRUE;
} else if (*s == 'D') {
//
// Dump DACL qualifier
//
if ((DumpDacl== TRUE) && (DumpDaclFull == FALSE)) {
printf("\n\n Conflicting qualifiers: \\d and \\D\n");
Usage();
return;
}
DumpDacl = TRUE;
DumpDaclFull = TRUE;
CompoundLineOutput = TRUE;
} else if (*s == 's') {
//
// Dump SACL qualifier
//
if (DumpSaclFull == TRUE) {
printf("\n\n Conflicting qualifiers: \\s and \\S\n");
Usage();
return;
}
DumpSacl = TRUE;
DumpSaclFull = FALSE;
CompoundLineOutput = TRUE;
} else if (*s == 'S') {
//
// Dump SACL qualifier
//
if ((DumpSacl== TRUE) && (DumpSaclFull == FALSE)) {
printf("\n\n Conflicting qualifiers: \\s and \\S\n");
Usage();
return;
}
DumpSacl = TRUE;
DumpSaclFull = TRUE;
CompoundLineOutput = TRUE;
} else {
Usage();
return;
}
arg++;
} // end_while
if (DumpDacl || DumpSacl) {
ConnectToLsa();
}
//
// Set up the name of the directory to list
//
if (!DirectoryNameArg) {
RtlInitString( &String, "\\" );
} else {
RtlInitString( &String, argv[arg] );
}
if (EnableAllPrivileges()) {
QueryDirectory( &String );
}
}
WCHAR LinkTargetBuffer[ 1024 ];
typedef struct _DIR_ENTRY {
PWSTR Name;
PWSTR Type;
} DIR_ENTRY, *PDIR_ENTRY;
#define MAX_DIR_ENTRIES 1024
ULONG NumberOfDirEntries;
DIR_ENTRY DirEntries[ MAX_DIR_ENTRIES ];
int
_CRTAPI1
CompareDirEntry(
void const *p1,
void const *p2
)
{
return _wcsicmp( ((PDIR_ENTRY)p1)->Name, ((PDIR_ENTRY)p2)->Name );
}
VOID
QueryDirectory(
IN PSTRING DirectoryName
)
//
// DumpDacl and DumpSacl are expected to be set prior to calling this routine.
//
{
NTSTATUS Status;
HANDLE DirectoryHandle, LinkHandle;
ULONG Context = 0;
ULONG i, ReturnedLength;
UNICODE_STRING LinkTarget;
POBJECT_DIRECTORY_INFORMATION DirInfo;
POBJECT_NAME_INFORMATION NameInfo;
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING UnicodeString;
ACCESS_MASK ExtraAccess = 0;
//
// Perform initial setup
//
RtlZeroMemory( Buffer, BUFFERSIZE );
if (DumpDacl) {
ExtraAccess |= READ_CONTROL;
}
if (DumpSacl) {
ExtraAccess |= ACCESS_SYSTEM_SECURITY;
}
//
// Open the directory for list directory access
//
Status = RtlAnsiStringToUnicodeString( &UnicodeString,
DirectoryName,
TRUE );
ASSERT( NT_SUCCESS( Status ) );
InitializeObjectAttributes( &Attributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = NtOpenDirectoryObject( &DirectoryHandle,
DIRECTORY_QUERY | ExtraAccess,
&Attributes
);
if (!NT_SUCCESS( Status )) {
if (Status == STATUS_OBJECT_TYPE_MISMATCH) {
printf( "%Z is not a valid Object Directory Object name\n",
DirectoryName );
}
else {
Error( OpenDirectory, Status );
}
return;
}
//
// Get the actual name of the object directory object.
//
NameInfo = (POBJECT_NAME_INFORMATION) &Buffer[0];
if (!NT_SUCCESS( Status = NtQueryObject( DirectoryHandle,
ObjectNameInformation,
NameInfo,
BUFFERSIZE,
(PULONG) NULL ) )) {
printf( "Unexpected error obtaining actual object directory name\n" );
printf( "Error was: %X\n", Status );
return;
}
//
// Output initial informational message
//
printf( "Directory of: %wZ\n", &NameInfo->Name );
if (DumpDacl) {
QueryAndDisplayDacl( DirectoryHandle );
}
if (DumpSacl) {
QueryAndDisplaySacl( DirectoryHandle );
}
printf( "\n" );
//
// Query the entire directory in one sweep
//
NumberOfDirEntries = 0;
for (Status = NtQueryDirectoryObject( DirectoryHandle,
&Buffer,
BUFFERSIZE,
FALSE,
FALSE,
&Context,
&ReturnedLength );
NT_SUCCESS( Status );
Status = NtQueryDirectoryObject( DirectoryHandle,
&Buffer,
BUFFERSIZE,
FALSE,
FALSE,
&Context,
&ReturnedLength ) ) {
//
// Check the status of the operation.
//
if (!NT_SUCCESS( Status )) {
if (Status != STATUS_NO_MORE_FILES) {
Error( Status, Status );
}
break;
}
//
// For every record in the buffer type out the directory information
//
//
// Point to the first record in the buffer, we are guaranteed to have
// one otherwise Status would have been No More Files
//
DirInfo = (POBJECT_DIRECTORY_INFORMATION) &Buffer[0];
while (TRUE) {
//
// Check if there is another record. If there isn't, then get out
// of the loop now
//
if (DirInfo->Name.Length == 0) {
break;
}
//
// Print out information about the file
//
if (NumberOfDirEntries >= MAX_DIR_ENTRIES) {
printf( "OBJDIR: Too many directory entries.\n" );
exit( 1 );
}
DirEntries[ NumberOfDirEntries ].Name = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
DirInfo->Name.Length +
sizeof( UNICODE_NULL )
);
DirEntries[ NumberOfDirEntries ].Type = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
DirInfo->TypeName.Length +
sizeof( UNICODE_NULL )
);
memmove( DirEntries[ NumberOfDirEntries ].Name,
DirInfo->Name.Buffer,
DirInfo->Name.Length
);
memmove( DirEntries[ NumberOfDirEntries ].Type,
DirInfo->TypeName.Buffer,
DirInfo->TypeName.Length
);
NumberOfDirEntries++;
//
// There is another record so advance DirInfo to the next entry
//
DirInfo = (POBJECT_DIRECTORY_INFORMATION) (((PUCHAR) DirInfo) +
sizeof( OBJECT_DIRECTORY_INFORMATION ) );
}
RtlZeroMemory( Buffer, BUFFERSIZE );
}
qsort( DirEntries,
NumberOfDirEntries,
sizeof( DIR_ENTRY ),
CompareDirEntry
);
for (i=0; i<NumberOfDirEntries; i++) {
printf( "%-32ws ", DirEntries[ i ].Name);
if (CompoundLineOutput) {
printf("\n ");
}
printf( "%ws", DirEntries[ i ].Type );
if (!wcscmp( DirEntries[ i ].Type, L"SymbolicLink" )) {
RtlInitUnicodeString( &UnicodeString, DirEntries[ i ].Name );
InitializeObjectAttributes( &Attributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
DirectoryHandle,
NULL );
Status = NtOpenSymbolicLinkObject( &LinkHandle,
SYMBOLIC_LINK_QUERY,
&Attributes
);
if (NT_SUCCESS( Status )) {
LinkTarget.Buffer = LinkTargetBuffer;
LinkTarget.Length = 0;
LinkTarget.MaximumLength = sizeof( LinkTargetBuffer );
Status = NtQuerySymbolicLinkObject( LinkHandle,
&LinkTarget,
NULL
);
NtClose( LinkHandle );
}
if (!NT_SUCCESS( Status )) {
printf( " - unable to query link target (Status == %09X)\n", Status );
}
else {
printf( " - %wZ\n", &LinkTarget );
}
}
else {
printf( "\n" );
}
if (DumpDacl) {
OpenAndDisplayDacl( DirectoryHandle, DirEntries[ i ].Type, DirEntries[ i ].Name);
}
if (DumpSacl) {
OpenAndDisplaySacl( DirectoryHandle, DirEntries[ i ].Type, DirEntries[ i ].Name);
}
}
//
// Output final messages
//
if (NumberOfDirEntries == 0) {
printf( "no entries\n" );
}
else
if (NumberOfDirEntries == 1) {
printf( "\n1 entry\n" );
}
else {
printf( "\n%ld entries\n", NumberOfDirEntries );
}
//
// Now close the directory object
//
(VOID) NtClose( DirectoryHandle );
//
// And return to our caller
//
return;
}
BOOLEAN
EnableAllPrivileges(
VOID
)
/*++
Routine Description:
This routine enables all privileges in the token.
If we are being asked to dump SACLs then we will check
to make sure we have SE_SECURITY_PRIVILEGE enabled too.
Arguments:
None.
Return Value:
None.
--*/
{
HANDLE Token;
ULONG ReturnLength, Index;
PTOKEN_PRIVILEGES NewState;
BOOLEAN Result;
LUID SecurityPrivilege;
SecurityPrivilege =
RtlConvertLongToLuid(SE_SECURITY_PRIVILEGE);
Token = NULL;
NewState = NULL;
Result = OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&Token
);
if (Result) {
ReturnLength = 4096;
NewState = malloc( ReturnLength );
Result = (BOOLEAN)(NewState != NULL);
if (Result) {
Result = GetTokenInformation( Token, // TokenHandle
TokenPrivileges, // TokenInformationClass
NewState, // TokenInformation
ReturnLength, // TokenInformationLength
&ReturnLength // ReturnLength
);
if (Result) {
//
// Set the state settings so that all privileges are enabled...
//
if (DumpSacl) {
Result = FALSE;
}
if (NewState->PrivilegeCount > 0) {
for (Index = 0; Index < NewState->PrivilegeCount; Index++ ) {
NewState->Privileges[Index].Attributes = SE_PRIVILEGE_ENABLED;
if (RtlEqualLuid(&NewState->Privileges[Index].Luid, &SecurityPrivilege )) {
Result = TRUE;
}
}
}
if (!Result) {
// Don't have privilege to dump SACL
ASSERT(DumpSacl);
printf("\n\n You do not have sufficient privilege to display SACLs.\n\n");
}
else {
Result = AdjustTokenPrivileges( Token, // TokenHandle
FALSE, // DisableAllPrivileges
NewState, // NewState (OPTIONAL)
ReturnLength, // BufferLength
NULL, // PreviousState (OPTIONAL)
&ReturnLength // ReturnLength
);
if (!Result) {
DbgPrint( "AdjustTokenPrivileges( %lx ) failed - %u\n", Token, GetLastError() );
}
}
}
else {
DbgPrint( "GetTokenInformation( %lx ) failed - %u\n", Token, GetLastError() );
}
}
else {
DbgPrint( "malloc( %lx ) failed - %u\n", ReturnLength, GetLastError() );
}
}
else {
DbgPrint( "OpenProcessToken( %lx ) failed - %u\n", GetCurrentProcess(), GetLastError() );
}
if (NewState != NULL) {
free( NewState );
}
if (Token != NULL) {
CloseHandle( Token );
}
return( Result );
}
NTSTATUS
OpenObject(
IN HANDLE Root,
IN PWCHAR Type,
IN PWCHAR Name,
IN ACCESS_MASK DesiredAccess,
OUT PHANDLE Object
)
{
NTSTATUS
Status,
IgnoreStatus;
UNICODE_STRING
UnicodeName;
OBJECT_ATTRIBUTES
Attributes;
IO_STATUS_BLOCK
Iosb;
RtlInitUnicodeString( &UnicodeName, Name );
InitializeObjectAttributes( &Attributes, &UnicodeName, OBJ_CASE_INSENSITIVE, Root, NULL );
//
// This is effectively a big switch statement of object types
// that we know how to open...
//
if (!wcscmp( Type, L"SymbolicLink" )) {
Status = NtOpenSymbolicLinkObject( Object, DesiredAccess, &Attributes );
} else if (!wcscmp( Type, L"Device" )) {
Status = NtOpenFile( Object, DesiredAccess, &Attributes, &Iosb, 0, 0 );
} else if (!wcscmp( Type, L"Event" )) {
Status = NtOpenEvent( Object, DesiredAccess, &Attributes );
} else if (!wcscmp( Type, L"EventPair" )) {
Status = NtOpenEventPair( Object, DesiredAccess, &Attributes );
} else if (!wcscmp( Type, L"Mutant" )) {
Status = NtOpenMutant( Object, DesiredAccess, &Attributes );
} else if (!wcscmp( Type, L"Timer" )) {
Status = NtOpenTimer( Object, DesiredAccess, &Attributes );
} else if (!wcscmp( Type, L"Semaphore" )) {
Status = NtOpenSemaphore( Object, DesiredAccess, &Attributes );
} else if (!wcscmp( Type, L"Section" )) {
Status = NtOpenSection( Object, DesiredAccess, &Attributes );
} else if (!wcscmp( Type, L"Directory" )) {
Status = NtOpenDirectoryObject( Object, DesiredAccess, &Attributes );
} else if (!wcscmp( Type, L"Process" )) {
Status = NtOpenProcess( Object, DesiredAccess, &Attributes, NULL );
} else if (!wcscmp( Type, L"WindowStation" )) {
*Object = OpenWindowStationW( Name, FALSE, DesiredAccess );
if (*Object)
{
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_ACCESS_DENIED;
}
} else if (!wcscmp( Type, L"Desktop" )) {
*Object = OpenDesktopW( Name, 0, FALSE, DesiredAccess );
if (*Object)
{
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_ACCESS_DENIED;
}
} else {
//
// this utility doesn't yet support opening this type of object
//
Status = STATUS_NOT_SUPPORTED;
}
return(Status);
}
VOID
OpenAndDisplaySacl(
IN HANDLE Root,
IN PWCHAR Type,
IN PWCHAR Name
)
{
NTSTATUS
Status,
IgnoreStatus;
HANDLE
Object;
Status = OpenObject( Root, Type, Name, ACCESS_SYSTEM_SECURITY, &Object);
if (NT_SUCCESS(Status)) {
QueryAndDisplaySacl( Object );
IgnoreStatus = NtClose( Object );
ASSERT(NT_SUCCESS(IgnoreStatus));
}
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_NOT_SUPPORTED) {
printf(" Utility doesn't yet query SACLs for this type of object.\n\n");
} else {
printf(" Error attempting to query SACL: 0x%lx.\n\n", Status);
}
}
return;
}
VOID
QueryAndDisplaySacl(
IN HANDLE Object
)
{
NTSTATUS
Status;
PSECURITY_DESCRIPTOR
SD;
ULONG
LengthNeeded;
Status = NtQuerySecurityObject( Object,
SACL_SECURITY_INFORMATION,
NULL,
0,
&LengthNeeded
);
ASSERT(!NT_SUCCESS(Status));
if (Status == STATUS_BUFFER_TOO_SMALL) {
SD = RtlAllocateHeap( RtlProcessHeap(), 0, LengthNeeded );
if (SD == NULL) {
Status = STATUS_NO_MEMORY;
} else {
Status = NtQuerySecurityObject( Object,
SACL_SECURITY_INFORMATION,
SD,
LengthNeeded,
&LengthNeeded
);
if (NT_SUCCESS(Status)) {
//
// Display the SACL
//
Status = DisplaySacl( SD );
}
}
}
return;
}
NTSTATUS
DisplaySacl(
PSECURITY_DESCRIPTOR SD
)
/*++
Routine Description:
This function dumps out a SACL
If an error status is returned, then the caller is responsible
for printing a message.
--*/
{
NTSTATUS
Status;
BOOLEAN
AclPresent,
AclDefaulted;
PACL
Acl;
ACL_SIZE_INFORMATION
AclInfo;
ULONG
i;
PACE_HEADER
Ace;
Status = RtlGetSaclSecurityDescriptor ( SD, &AclPresent, &Acl, &AclDefaulted );
if (NT_SUCCESS(Status)) {
printf(" SACL - ");
if (!AclPresent) {
printf("No SACL present on object\n");
} else {
if (AclDefaulted) {
printf("SACL Defaulted flag set\n ");
}
if (Acl == NULL) {
printf("NULL SACL - no auditing performed.\n");
} else {
Status = RtlQueryInformationAcl ( Acl,
&AclInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation);
ASSERT(NT_SUCCESS(Status));
if (AclInfo.AceCount == 0) {
printf("No ACEs in ACL, Auditing performed.\n");
} else {
printf("\n");
for (i=0; i<AclInfo.AceCount; i++) {
Status = RtlGetAce( Acl, i, &Ace );
ASSERT(NT_SUCCESS(Status));
printf(" Ace[%2d] - ", i);
DumpAce( Ace, FALSE );
printf("\n");
}
}
}
}
}
printf("\n");
return(Status);
}
VOID
OpenAndDisplayDacl(
IN HANDLE Root,
IN PWCHAR Type,
IN PWCHAR Name
)
{
NTSTATUS
Status,
IgnoreStatus;
HANDLE
Object;
Status = OpenObject( Root, Type, Name, READ_CONTROL, &Object);
if (NT_SUCCESS(Status)) {
QueryAndDisplayDacl( Object );
IgnoreStatus = NtClose( Object );
ASSERT(NT_SUCCESS(IgnoreStatus));
}
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_ACCESS_DENIED) {
printf(" Protection on object prevented querying the DACL.\n\n");
} else if (Status == STATUS_NOT_SUPPORTED) {
printf(" Utility doesn't yet query DACLs for this type of object.\n\n");
} else {
printf(" Error attempting to query DACL: 0x%lx.\n\n", Status);
}
}
return;
}
VOID
QueryAndDisplayDacl(
IN HANDLE Object
)
{
NTSTATUS
Status;
PSECURITY_DESCRIPTOR
SD;
ULONG
LengthNeeded;
Status = NtQuerySecurityObject( Object,
DACL_SECURITY_INFORMATION,
NULL,
0,
&LengthNeeded
);
ASSERT(!NT_SUCCESS(Status));
if (Status == STATUS_BUFFER_TOO_SMALL) {
SD = RtlAllocateHeap( RtlProcessHeap(), 0, LengthNeeded );
if (SD == NULL) {
Status = STATUS_NO_MEMORY;
} else {
Status = NtQuerySecurityObject( Object,
DACL_SECURITY_INFORMATION,
SD,
LengthNeeded,
&LengthNeeded
);
if (NT_SUCCESS(Status)) {
//
// Display the DACL
//
Status = DisplayDacl( SD );
}
}
}
return;
}
NTSTATUS
DisplayDacl(
PSECURITY_DESCRIPTOR SD
)
/*++
Routine Description:
This function dumps out a DACL
If an error status is returned, then the caller is responsible
for printing a message.
--*/
{
NTSTATUS
Status;
BOOLEAN
AclPresent,
AclDefaulted;
PACL
Acl;
ACL_SIZE_INFORMATION
AclInfo;
ULONG
i;
PACE_HEADER
Ace;
Status = RtlGetDaclSecurityDescriptor ( SD, &AclPresent, &Acl, &AclDefaulted );
if (NT_SUCCESS(Status)) {
printf(" DACL - ");
if (!AclPresent) {
printf("No DACL present on object\n");
} else {
if (AclDefaulted) {
printf("DACL Defaulted flag set\n ");
}
if (Acl == NULL) {
printf("NULL DACL - grants all access to Everyone\n");
} else {
Status = RtlQueryInformationAcl ( Acl,
&AclInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation);
ASSERT(NT_SUCCESS(Status));
if (AclInfo.AceCount == 0) {
printf("No ACEs in ACL, Denies all access to everyone\n");
} else {
printf("\n");
for (i=0; i<AclInfo.AceCount; i++) {
Status = RtlGetAce( Acl, i, &Ace );
ASSERT(NT_SUCCESS(Status));
printf(" Ace[%2d] - ", i);
DumpAce( Ace, TRUE );
printf("\n");
}
}
}
}
}
printf("\n");
return(Status);
}
VOID
DumpAce(
PACE_HEADER Ace,
BOOLEAN AclIsDacl
)
/*++
Routine Description:
This function displays a single ACE
Arguments:
Ace - Points to an ACE.
AclIsDacl - TRUE if acl is a DACL. False if acl is an SACL.
Return Value:
None.
--*/
{
if ((Ace->AceFlags & INHERIT_ONLY_ACE) != 0) {
printf("Inherit Only - ");
}
switch (Ace->AceType) {
case ACCESS_ALLOWED_ACE_TYPE:
printf("Grant -");
DumpStandardAceInfo(Ace, AclIsDacl);
break;
case ACCESS_DENIED_ACE_TYPE:
printf("Deny -");
DumpStandardAceInfo(Ace, AclIsDacl);
break;
case SYSTEM_AUDIT_ACE_TYPE:
printf("Audit ");
DumpStandardAceInfo(Ace, AclIsDacl);
break;
default:
printf(" ** Unknown ACE Type **");
}
return;
}
VOID
DumpStandardAceInfo(
PACE_HEADER Ace,
BOOLEAN AclIsDacl
)
/*++
Routine Description:
This function dumps out the standard information for a single ACE.
Arguments:
Ace - Points to an ACE_HEADER. The ACE must be one of the known types.
AclIsDacl - TRUE if acl is a DACL. False if acl is an SACL.
Return Value:
None.
--*/
{
PACCESS_ALLOWED_ACE
Local;
ACCESS_MASK
Specific;
//
// WARNING -
//
// It is assumed that all the known ACE types have their ACCESS_MASK
// and SID fields in the same location as the ACCESS_ALLOWED_ACE.
//
Local = (PACCESS_ALLOWED_ACE)(Ace);
if (Ace->AceType == SYSTEM_AUDIT_ACE_TYPE) {
printf("[");
if (Ace->AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) {
printf("S");
if (Ace->AceFlags & FAILED_ACCESS_ACE_FLAG) {
printf(",F");
}
} else if (Ace->AceFlags & FAILED_ACCESS_ACE_FLAG) {
printf(" ,F");
} else {
printf("Neither Success nor Failure flag set]");
return;
}
printf("] -");
}
printf(" 0x%lx - ", Local->Mask );
DisplaySid( (PSID)(&Local->SidStart) );
//
// Everything else is only printed for FULL displays
if (AclIsDacl && !DumpDaclFull) {
return;
}
if (!AclIsDacl && !DumpSaclFull) {
return;
}
//
// Print the inheritance
//
printf("\n Inherit: ");
if ((Ace->AceFlags & INHERIT_ONLY_ACE) != 0) {
printf("IO ");
}
if ((Ace->AceFlags & OBJECT_INHERIT_ACE) != 0) {
printf("OI ");
}
if ((Ace->AceFlags & CONTAINER_INHERIT_ACE) != 0) {
printf("CI ");
}
if ((Ace->AceFlags & NO_PROPAGATE_INHERIT_ACE) != 0) {
printf("NPI");
}
//
// Print the accesses
//
Specific = (Local->Mask & 0xFF);
printf("\n Access: 0x%04lX", Specific);
if (Local->Mask != Specific) {
printf(" and (");
}
if ((Local->Mask & DELETE) != 0) {
printf(" D");
}
if ((Local->Mask & READ_CONTROL) != 0) {
printf(" RCtl");
}
if ((Local->Mask & WRITE_OWNER) != 0) {
printf(" WOwn");
}
if ((Local->Mask & WRITE_DAC) != 0) {
printf(" WDacl");
}
if ((Local->Mask & SYNCHRONIZE) != 0) {
printf(" Synch");
}
if ((Local->Mask & GENERIC_READ) != 0) {
printf(" R");
}
if ((Local->Mask & GENERIC_WRITE) != 0) {
printf(" W");
}
if ((Local->Mask & GENERIC_EXECUTE) != 0) {
printf(" E");
}
if ((Local->Mask & GENERIC_ALL) != 0) {
printf(" ALL");
}
if ((Local->Mask & ACCESS_SYSTEM_SECURITY) != 0) {
printf(" ACC_SYS_SEC");
}
if ((Local->Mask & MAXIMUM_ALLOWED) != 0) {
printf(" MAX_ALLOWED");
}
if (Local->Mask != Specific) {
printf(" )");
}
printf("\n");
return;
}
VOID
DisplaySid(
IN PSID Sid
)
/*++
Routine Description:
This function calls LSA to lookup a SID and displays the result.
Arguments:
Sid
Return Value:
None.
--*/
{
NTSTATUS
Status;
PLSA_REFERENCED_DOMAIN_LIST
ReferencedDomains;
PLSA_TRANSLATED_NAME
SidName;
ULONG
DomainIndex;
UNICODE_STRING
SidString;
if (LsaHandle == NULL) {
printf("Can't call LSA to lookup sid");
return;
}
Status = LsaLookupSids(
LsaHandle,
1,
&Sid,
&ReferencedDomains,
&SidName
);
if (!NT_SUCCESS(Status)) {
RtlConvertSidToUnicodeString( &SidString, Sid, TRUE );
printf("%ws (Unable to translate)", SidString.Buffer );
RtlFreeUnicodeString( &SidString );
return;
}
DomainIndex = SidName[0].DomainIndex;
printf("%wZ", &ReferencedDomains->Domains[DomainIndex].Name );
if (ReferencedDomains->Domains[DomainIndex].Name.Length != 0) {
printf("\\");
}
printf("%wZ", &SidName[0].Name );
LsaFreeMemory( ReferencedDomains );
LsaFreeMemory( SidName );
return;
}
VOID
ConnectToLsa( VOID )
/*++
Routine Description:
This function connects to LSA in preparation for expected SID
lookup calls.
--*/
{
NTSTATUS
Status;
OBJECT_ATTRIBUTES
ObjectAttributes;
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, 0, NULL );
LsaHandle = NULL;
Status = LsaOpenPolicy(
NULL, // SystemName
&ObjectAttributes,
POLICY_LOOKUP_NAMES, // DesiredAccess
&LsaHandle
);
if (!NT_SUCCESS(Status)) {
LsaHandle = NULL;
}
return;
}
VOID
Usage(VOID)
{
printf("\n\n"
" Usage:\n"
" objdir [/d | /D] [/s | /S] [<dir_name>]\n\n"
" Where:\n"
" /d - causes DACLs to be displayed in short form.\n\n"
" /D - causes DACLs to be displayed in long form.\n\n"
" /s - causes SACLs to be displayed in short form.\n\n"
" /S - causes SACLs to be displayed in long form.\n\n"
" <dir_name> - is the name of the directory you\n"
" would like to see displayed. Default\n"
" is the root directory.\n\n"
" Examples:\n"
" objdir /d\n"
" - displays dacls of objects in root directory\n\n"
" objdir \\DosDevices\n"
" - displays objects in \\DosDevices\n\n"
" objdir /d \\BaseNamedObjects\n"
" - displays dacls of objects in \\BaseNamedObjects\n\n"
" objdir /s /d \\Windows\n"
" - displays sacls and dacls of objects in \\Windowss\n\n"
);
return;
}