|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
rtdmpsec.c
Abstract:
NT level registry security test program #1, basic non-error paths.
Dump out the security descriptors of a sub-tree of the registry.
rtdmpsec <KeyPath>
Will ennumerate and dump out the subkeys and values of KeyPath, and then apply itself recursively to each subkey it finds.
It assumes data values are null terminated strings.
Example:
rtdmpsec \REGISTRY\MACHINE\TEST\bigkey
Author:
John Vert (jvert) 24-Jan-92
based on rtdmp.c by
Bryan Willman (bryanwi) 10-Dec-91
and getdacl.c by RobertRe
Revision History:
Richard Ward (richardw) 14 April 1992 Changed ACE_HEADER
--*/
#include "cmp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORK_SIZE 1024
//
// Get a pointer to the first ace in an acl
//
#define FirstAce(Acl) ((PVOID)((PUCHAR)(Acl) + sizeof(ACL)))
//
// Get a pointer to the following ace
//
#define NextAce(Ace) ((PVOID)((PUCHAR)(Ace) + ((PACE_HEADER)(Ace))->AceSize))
//
// Generic ACE structure, to be used for casting ACE's of known types
//
typedef struct _KNOWN_ACE { ACE_HEADER Header; ACCESS_MASK Mask; ULONG SidStart; } KNOWN_ACE, *PKNOWN_ACE;
VOID InitVars();
VOID PrintAcl ( IN PACL Acl );
VOID PrintAccessMask( IN ACCESS_MASK AccessMask );
void __cdecl main(int, char *); void processargs();
void print(PUNICODE_STRING);
void DumpSecurity( HANDLE Handle );
void Dump( HANDLE Handle );
UNICODE_STRING WorkName; WCHAR workbuffer[WORK_SIZE];
//
// Universal well known SIDs
//
PSID NullSid; PSID WorldSid; PSID LocalSid; PSID CreatorOwnerSid;
//
// Sids defined by NT
//
PSID NtAuthoritySid;
PSID DialupSid; PSID NetworkSid; PSID BatchSid; PSID InteractiveSid; PSID LocalSystemSid;
void __cdecl main( int argc, char *argv[] ) { NTSTATUS status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE BaseHandle;
InitVars();
//
// Process args
//
WorkName.MaximumLength = WORK_SIZE; WorkName.Length = 0L; WorkName.Buffer = &(workbuffer[0]);
processargs(argc, argv);
//
// Set up and open KeyPath
//
printf("rtdmpsec: starting\n");
InitializeObjectAttributes( &ObjectAttributes, &WorkName, 0, (HANDLE)NULL, NULL ); ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
status = NtOpenKey( &BaseHandle, MAXIMUM_ALLOWED, &ObjectAttributes ); if (!NT_SUCCESS(status)) { printf("rtdmpsec: t0: %08lx\n", status); exit(1); }
Dump(BaseHandle); }
void Dump( HANDLE Handle ) { NTSTATUS status; PKEY_BASIC_INFORMATION KeyInformation; OBJECT_ATTRIBUTES ObjectAttributes; ULONG NamePos; ULONG index; STRING enumname; HANDLE WorkHandle; ULONG ResultLength; static char buffer[WORK_SIZE]; PUCHAR p;
KeyInformation = (PKEY_BASIC_INFORMATION)buffer; NamePos = WorkName.Length;
//
// Print name of node we are about to dump out
//
printf("\n"); print(&WorkName); printf("::\n");
//
// Print out node's values
//
DumpSecurity(Handle);
//
// Enumerate node's children and apply ourselves to each one
//
for (index = 0; TRUE; index++) {
RtlZeroMemory(KeyInformation, WORK_SIZE); status = NtEnumerateKey( Handle, index, KeyBasicInformation, KeyInformation, WORK_SIZE, &ResultLength );
if (status == STATUS_NO_MORE_ENTRIES) {
WorkName.Length = NamePos; return;
} else if (!NT_SUCCESS(status)) {
printf("rtdmpsec: dump1: status = %08lx\n", status); exit(1);
}
enumname.Buffer = &(KeyInformation->Name[0]); enumname.Length = KeyInformation->NameLength; enumname.MaximumLength = KeyInformation->NameLength;
p = WorkName.Buffer; p += WorkName.Length; *p = '\\'; p++; *p = '\0'; WorkName.Length += 2;
RtlAppendStringToString((PSTRING)&WorkName, (PSTRING)&enumname);
InitializeObjectAttributes( &ObjectAttributes, &enumname, 0, Handle, NULL ); ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
status = NtOpenKey( &WorkHandle, MAXIMUM_ALLOWED, &ObjectAttributes ); if (!NT_SUCCESS(status)) { if (status == STATUS_ACCESS_DENIED) { printf("\n"); print(&WorkName); printf("::\n\tAccess denied!\n"); } else { printf("rtdmpsec: dump2: %08lx\n", status); exit(1); } } else { Dump(WorkHandle); NtClose(WorkHandle); }
WorkName.Length = NamePos; } }
void DumpSecurity( HANDLE Handle ) { PSECURITY_DESCRIPTOR SecurityDescriptor; NTSTATUS Status; ULONG Length; PACL Dacl; BOOLEAN DaclPresent; BOOLEAN DaclDefaulted;
Status = NtQuerySecurityObject( Handle, DACL_SECURITY_INFORMATION, NULL, 0, &Length );
if (Status != STATUS_BUFFER_TOO_SMALL) { printf("DumpSecurity t0: NtQuerySecurityObject failed %lx\n",Status); exit(1); }
SecurityDescriptor = malloc(Length); if (SecurityDescriptor == NULL) { printf("DumpSecurity: couldn't malloc buffer\n"); exit(1); }
Status = NtQuerySecurityObject( Handle, DACL_SECURITY_INFORMATION, SecurityDescriptor, Length, &Length );
if (!NT_SUCCESS(Status)) { printf("DumpSecurity t1: NtQuerySecurityObject failed %lx\n",Status); exit(1); }
Dacl = NULL;
Status = RtlGetDaclSecurityDescriptor( SecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted ); if (!NT_SUCCESS(Status)) { printf("DumpSecurity t2: RtlGetDaclSecurityDescriptor failed %lx\n",Status); }
if (DaclPresent) { PrintAcl(Dacl); } else { printf("\tAcl not present\n"); }
}
void print( PUNICODE_STRING String ) { static ANSI_STRING temp; static char tempbuffer[WORK_SIZE];
temp.MaximumLength = WORK_SIZE; temp.Length = 0L; temp.Buffer = tempbuffer;
RtlUnicodeStringToAnsiString(&temp, String, FALSE); printf("%s", temp.Buffer); return; }
void processargs( int argc, char *argv[] ) { ANSI_STRING temp;
if ( (argc != 2) ) { printf("Usage: %s <KeyPath>\n", argv[0]); exit(1); }
RtlInitAnsiString( &temp, argv[1] );
RtlAnsiStringToUnicodeString( &WorkName, &temp, FALSE );
return; }
BOOLEAN SidTranslation( PSID Sid, PSTRING AccountName ) // AccountName is expected to have a large maximum length
{ if (RtlEqualSid(Sid, WorldSid)) { RtlInitString( AccountName, "WORLD"); return(TRUE); }
if (RtlEqualSid(Sid, LocalSid)) { RtlInitString( AccountName, "LOCAL");
return(TRUE); }
if (RtlEqualSid(Sid, NetworkSid)) { RtlInitString( AccountName, "NETWORK");
return(TRUE); }
if (RtlEqualSid(Sid, BatchSid)) { RtlInitString( AccountName, "BATCH");
return(TRUE); }
if (RtlEqualSid(Sid, InteractiveSid)) { RtlInitString( AccountName, "INTERACTIVE"); return(TRUE); }
if (RtlEqualSid(Sid, LocalSystemSid)) { RtlInitString( AccountName, "SYSTEM"); return(TRUE); }
//
// if (RtlEqualSid(Sid, LocalManagerSid)) {
// RtlInitString( AccountName, "LOCAL MANAGER");
// return(TRUE);
// }
// if (RtlEqualSid(Sid, LocalAdminSid)) {
// RtlInitString( AccountName, "LOCAL ADMIN");
// return(TRUE);
// }
return(FALSE);
}
VOID DisplayAccountSid( PSID Sid ) { UCHAR Buffer[128]; STRING AccountName; UCHAR i; ULONG Tmp; PSID_IDENTIFIER_AUTHORITY IdentifierAuthority; UCHAR SubAuthorityCount;
Buffer[0] = 0;
AccountName.MaximumLength = 127; AccountName.Length = 0; AccountName.Buffer = (PVOID)&Buffer[0];
if (SidTranslation( (PSID)Sid, &AccountName) ) {
printf("%s\n", AccountName.Buffer );
} else { IdentifierAuthority = RtlIdentifierAuthoritySid(Sid);
//
// HACK! HACK!
// The next line prints the revision of the SID. Since there is no
// rtl routine which gives us the SID revision, we must make due.
// luckily, the revision field is the first field in the SID, so we
// can just cast the pointer.
//
printf("S-%u-", (USHORT) *((PUCHAR) Sid) );
if ( (IdentifierAuthority->Value[0] != 0) || (IdentifierAuthority->Value[1] != 0) ){ printf("0x%02hx%02hx%02hx%02hx%02hx%02hx", IdentifierAuthority->Value[0], IdentifierAuthority->Value[1], IdentifierAuthority->Value[2], IdentifierAuthority->Value[3], IdentifierAuthority->Value[4], IdentifierAuthority->Value[5] ); } else { Tmp = IdentifierAuthority->Value[5] + (IdentifierAuthority->Value[4] << 8) + (IdentifierAuthority->Value[3] << 16) + (IdentifierAuthority->Value[2] << 24); printf("%lu", Tmp); }
SubAuthorityCount = *RtlSubAuthorityCountSid(Sid); for (i=0;i<SubAuthorityCount ;i++ ) { printf("-%lu", (*RtlSubAuthoritySid(Sid, i))); } printf("\n");
}
}
VOID InitVars() { ULONG SidWithZeroSubAuthorities; ULONG SidWithOneSubAuthority; ULONG SidWithThreeSubAuthorities; ULONG SidWithFourSubAuthorities;
SID_IDENTIFIER_AUTHORITY NullSidAuthority = SECURITY_NULL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
//
// The following SID sizes need to be allocated
//
SidWithZeroSubAuthorities = RtlLengthRequiredSid( 0 ); SidWithOneSubAuthority = RtlLengthRequiredSid( 1 ); SidWithThreeSubAuthorities = RtlLengthRequiredSid( 3 ); SidWithFourSubAuthorities = RtlLengthRequiredSid( 4 );
//
// Allocate and initialize the universal SIDs
//
NullSid = (PSID)malloc(SidWithOneSubAuthority); WorldSid = (PSID)malloc(SidWithOneSubAuthority); LocalSid = (PSID)malloc(SidWithOneSubAuthority); CreatorOwnerSid = (PSID)malloc(SidWithOneSubAuthority);
RtlInitializeSid( NullSid, &NullSidAuthority, 1 ); RtlInitializeSid( WorldSid, &WorldSidAuthority, 1 ); RtlInitializeSid( LocalSid, &LocalSidAuthority, 1 ); RtlInitializeSid( CreatorOwnerSid, &CreatorSidAuthority, 1 );
*(RtlSubAuthoritySid( NullSid, 0 )) = SECURITY_NULL_RID; *(RtlSubAuthoritySid( WorldSid, 0 )) = SECURITY_WORLD_RID; *(RtlSubAuthoritySid( LocalSid, 0 )) = SECURITY_LOCAL_RID; *(RtlSubAuthoritySid( CreatorOwnerSid, 0 )) = SECURITY_CREATOR_OWNER_RID;
//
// Allocate and initialize the NT defined SIDs
//
NtAuthoritySid = (PSID)malloc(SidWithZeroSubAuthorities); DialupSid = (PSID)malloc(SidWithOneSubAuthority); NetworkSid = (PSID)malloc(SidWithOneSubAuthority); BatchSid = (PSID)malloc(SidWithOneSubAuthority); InteractiveSid = (PSID)malloc(SidWithOneSubAuthority); LocalSystemSid = (PSID)malloc(SidWithOneSubAuthority);
RtlInitializeSid( NtAuthoritySid, &NtAuthority, 0 ); RtlInitializeSid( DialupSid, &NtAuthority, 1 ); RtlInitializeSid( NetworkSid, &NtAuthority, 1 ); RtlInitializeSid( BatchSid, &NtAuthority, 1 ); RtlInitializeSid( InteractiveSid, &NtAuthority, 1 ); RtlInitializeSid( LocalSystemSid, &NtAuthority, 1 );
*(RtlSubAuthoritySid( DialupSid, 0 )) = SECURITY_DIALUP_RID; *(RtlSubAuthoritySid( NetworkSid, 0 )) = SECURITY_NETWORK_RID; *(RtlSubAuthoritySid( BatchSid, 0 )) = SECURITY_BATCH_RID; *(RtlSubAuthoritySid( InteractiveSid, 0 )) = SECURITY_INTERACTIVE_RID; *(RtlSubAuthoritySid( LocalSystemSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID;
return;
}
VOID PrintAcl ( IN PACL Acl )
/*++
Routine Description:
This routine dumps an Acl for debug purposes (via printf). It is specialized to dump standard aces.
Arguments:
Acl - Supplies the Acl to dump
Return Value:
None
--*/
{ ULONG i; PKNOWN_ACE Ace; BOOLEAN KnownType; PCHAR AceTypes[] = { "Access Allowed", "Access Denied ", "System Audit ", "System Alarm " };
if (Acl == NULL) {
printf("\tAcl == ALL ACCESS GRANTED!\n"); return;
}
//
// Dump the Acl header
//
printf("\tRevision: %02x", Acl->AclRevision); printf(" Size: %04x", Acl->AclSize); printf(" 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
//
printf("\n\tAceHeader: %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)) {
//
// 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 " };
printf(AceTypes[Ace->Header.AceType]); PrintAccessMask(Ace->Mask); KnownType = TRUE;
} else {
KnownType = FALSE; printf(" Unknown Ace Type\n");
}
printf("\n");
printf("\tAceSize = %d\n",Ace->Header.AceSize);
printf("\tAce Flags = "); if (Ace->Header.AceFlags & OBJECT_INHERIT_ACE) { printf("OBJECT_INHERIT_ACE\n"); printf(" "); }
if (Ace->Header.AceFlags & CONTAINER_INHERIT_ACE) { printf("CONTAINER_INHERIT_ACE\n"); printf(" "); }
if (Ace->Header.AceFlags & NO_PROPAGATE_INHERIT_ACE) { printf("NO_PROPAGATE_INHERIT_ACE\n"); printf(" "); }
if (Ace->Header.AceFlags & INHERIT_ONLY_ACE) { printf("INHERIT_ONLY_ACE\n"); printf(" "); }
if (Ace->Header.AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) { printf("SUCCESSFUL_ACCESS_ACE_FLAG\n"); printf(" "); }
if (Ace->Header.AceFlags & FAILED_ACCESS_ACE_FLAG) { printf("FAILED_ACCESS_ACE_FLAG\n"); printf(" "); }
printf("\n");
printf("\tSid = "); DisplayAccountSid(&Ace->SidStart); }
}
VOID PrintAccessMask( IN ACCESS_MASK AccessMask ) { printf("\n\tAccess Mask: ");
if (AccessMask == KEY_ALL_ACCESS) { printf("KEY_ALL_ACCESS\n\t "); return; } if (AccessMask == KEY_READ) { printf("KEY_READ\n\t "); return; } if (AccessMask == KEY_WRITE) { printf("KEY_WRITE\n\t "); return; }
if (AccessMask & KEY_QUERY_VALUE) { printf("KEY_QUERY_VALUE\n\t "); } if (AccessMask & KEY_SET_VALUE) { printf("KEY_SET_VALUE\n\t "); } if (AccessMask & KEY_CREATE_SUB_KEY) { printf("KEY_CREATE_SUB_KEY\n\t "); } if (AccessMask & KEY_ENUMERATE_SUB_KEYS) { printf("KEY_ENUMERATE_SUB_KEYS\n\t "); } if (AccessMask & KEY_NOTIFY) { printf("KEY_NOTIFY\n\t "); } if (AccessMask & KEY_CREATE_LINK) { printf("KEY_CREATE_LINK\n\t "); } if (AccessMask & GENERIC_ALL) { printf("GENERIC_ALL\n\t "); } if (AccessMask & GENERIC_EXECUTE) { printf("GENERIC_EXECUTE\n\t "); } if (AccessMask & GENERIC_WRITE) { printf("GENERIC_WRITE\n\t "); } if (AccessMask & GENERIC_READ) { printf("GENERIC_READ\n\t "); } if (AccessMask & GENERIC_READ) { printf("GENERIC_READ\n\t "); } if (AccessMask & MAXIMUM_ALLOWED) { printf("MAXIMUM_ALLOWED\n\t "); } if (AccessMask & ACCESS_SYSTEM_SECURITY) { printf("ACCESS_SYSTEM_SECURITY\n\t "); } if (AccessMask & WRITE_OWNER) { printf("WRITE_OWNER\n\t "); } if (AccessMask & WRITE_DAC) { printf("WRITE_DAC\n\t "); } if (AccessMask & READ_CONTROL) { printf("READ_CONTROL\n\t "); } if (AccessMask & DELETE) { printf("DELETE\n\t "); } }
|