/*++ 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 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 #include #include #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 _CRTAPI1 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 _CRTAPI1 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 \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;iAclRevision); 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 "); } }