Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1364 lines
46 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
adtobjs.c
Abstract:
Local Security Authority - Auditing object parameter file services.
Author:
Jim Kelly (JimK) 20-Oct-1992
Environment:
Revision History:
--*/
#include <msaudite.h>
#include <msobjs.h>
#include "lsasrvp.h"
#include "adtp.h"
//
// This is the maximum length of standard access type names.
// This is used to build an array.
//
#define ADTP_MAX_ACC_NAME_LENGTH (12)
//
//
// This module builds a list of event source module descriptors.
// The source modules are identified by name (kept in the descriptor).
//
//
// For each source module a list of objects exported by that module is
// linked to the source module's descriptor. Each entry in this list
// is an object descriptor containing a name and a base event offset
// for specific access types.
//
//
// The chicken-wire data structure for source module and object descriptors
// looks like:
//
// LsapAdtSourceModules --+
// |
// +------------------+
// |
// |
// | +-----------+ +-----------+
// +--->| Next ----|---------------------------->| Next ----|--->...
// | | | |
// |-----------| |-----------|
// | Name | | Name |
// | | | |
// |-----------| |-----------|
// | Objects | | Objects |
// | o | | o |
// +-----o-----+ +-----o-----+
// o +-------+ +-------+ o
// o | Next--|->| Next--|->... o
// ooo>|-------| |-------| oooooo> ...
// | Name | | Name |
// |-------| |-------|
// | Base | | Base |
// | Offset| | Offset|
// +-------+ +-------+
//
// The specific access type names are expected to have contiguous message IDs
// starting at the base offset value. For example, the access type name for
// specific access bit 0 for the framitz object might have message ID 2132
// (and bit 0 serves as the base offset). So, specific access bit 4 would be
// message ID (2132+4).
//
// The valid mask defines the set of specific accesses defined by each object
// type. If there are gaps in the valid mask, the arithmetic above must still
// be ensured. That is, the message ID of the specific access related to
// bit n is message ID (BaseOffset + bit position). So, for example, if
// bits 0, 1, 4 and 5 are valid (and 2 & 3 are not), be sure to leave unused
// message IDs where bits 2 and 3 would normally be.
//
////////////////////////////////////////////////////////////////////////
// //
// Data types used within this module //
// //
////////////////////////////////////////////////////////////////////////
#define LSAP_ADT_ACCESS_NAME_FORMATTING L"\r\n\t\t"
#define LsapAdtSourceModuleLock() (RtlEnterCriticalSection(&LsapAdtSourceModuleLock))
#define LsapAdtSourceModuleUnlock() (RtlLeaveCriticalSection(&LsapAdtSourceModuleLock))
//
// Each event source is represented by a source module descriptor.
// These are kept on a linked list (LsapAdtSourceModules).
//
typedef struct _LSAP_ADT_OBJECT {
//
// Pointer to next source module descriptor
// This is assumed to be the first field in the structure.
//
struct _LSAP_ADT_OBJECT *Next;
//
// Name of object
//
UNICODE_STRING Name;
//
// Base offset of specific access types
//
ULONG BaseOffset;
} LSAP_ADT_OBJECT, *PLSAP_ADT_OBJECT;
//
// Each event source is represented by a source module descriptor.
// These are kept on a linked list (LsapAdtSourceModules).
//
typedef struct _LSAP_ADT_SOURCE {
//
// Pointer to next source module descriptor
// This is assumed to be the first field in the structure.
//
struct _LSAP_ADT_SOURCE *Next;
//
// Name of source module
//
UNICODE_STRING Name;
//
// list of objects
//
PLSAP_ADT_OBJECT Objects;
} LSAP_ADT_SOURCE, *PLSAP_ADT_SOURCE;
////////////////////////////////////////////////////////////////////////
// //
// Variables global within this module //
// //
////////////////////////////////////////////////////////////////////////
//
// List head for source modules, and lock protecting references
// or modifications of the links in that list.
//
// Once a module's or object's name and value are established, they
// are never changed. So, this lock only needs to be held while
// links are being referenced or changed. You don't need to retain
// it just so you can reference, for example, the name or BaseOffset
// of an object.
//
PLSAP_ADT_SOURCE LsapAdtSourceModules;
RTL_CRITICAL_SECTION LsapAdtSourceModuleLock;
//
// This is used to house well-known access ID strings.
// Each string name may be up to ADTP_MAX_ACC_NAME_LENGTH WCHARs long.
// There are 16 specific names, and 4
//
ULONG LsapAdtAccessIdsStringBuffer[
ADTP_MAX_ACC_NAME_LENGTH * // max wchars in each string
(sizeof(ULONG)/sizeof(WCHAR)) // wchars, not ulongs.
* 23 // and there are this many
];
//
// Well known event ID strings.
//
UNICODE_STRING LsapAdtEventIdStringDelete,
LsapAdtEventIdStringReadControl,
LsapAdtEventIdStringWriteDac,
LsapAdtEventIdStringWriteOwner,
LsapAdtEventIdStringSynchronize,
LsapAdtEventIdStringAccessSysSec,
LsapAdtEventIdStringMaxAllowed,
LsapAdtEventIdStringSpecific[16];
////////////////////////////////////////////////////////////////////////
// //
// Services exported by this module. //
// //
////////////////////////////////////////////////////////////////////////
NTSTATUS
LsapAdtObjsInitialize(
)
/*++
Routine Description:
This function reads the object parameter file information from the
registry.
This service should be called in pass 1.
Arguments:
None.
Return Value:
STATUS_NO_MEMORY - indicates memory could not be allocated
to store the object information.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status,
IgnoreStatus;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE AuditKey,
ModuleKey,
ObjectNamesKey;
ULONG i,
ModuleIndex,
ObjectIndex,
RequiredLength;
UNICODE_STRING AuditKeyName,
TmpString;
PLSAP_ADT_SOURCE NextModule;
PKEY_BASIC_INFORMATION KeyInformation;
PLSAP_ADT_OBJECT NextObject;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
PULONG ObjectData;
BOOLEAN ModuleHasObjects;
//
// Initialize module-global variables, including strings we will need
//
//
// List of source modules and objects. These lists are constantly
// being adjusted to try to improve performance. Access to these
// lists is protected by a critical section.
//
LsapAdtSourceModules = NULL;
RtlInitializeCriticalSection(&LsapAdtSourceModuleLock);
//
// we need a number of strings.
//
i=0;
LsapAdtEventIdStringDelete.Length = 0;
LsapAdtEventIdStringDelete.MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringDelete.Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_DELETE,
10, //Base
&LsapAdtEventIdStringDelete
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringReadControl.Length = 0;
LsapAdtEventIdStringReadControl.MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringReadControl.Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_READ_CONTROL,
10, //Base
&LsapAdtEventIdStringReadControl
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringWriteDac.Length = 0;
LsapAdtEventIdStringWriteDac.MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringWriteDac.Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_WRITE_DAC,
10, //Base
&LsapAdtEventIdStringWriteDac
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringWriteOwner.Length = 0;
LsapAdtEventIdStringWriteOwner.MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringWriteOwner.Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_WRITE_OWNER,
10, //Base
&LsapAdtEventIdStringWriteOwner
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSynchronize.Length = 0;
LsapAdtEventIdStringSynchronize.MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSynchronize.Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SYNCHRONIZE,
10, //Base
&LsapAdtEventIdStringSynchronize
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringAccessSysSec.Length = 0;
LsapAdtEventIdStringAccessSysSec.MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringAccessSysSec.Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_ACCESS_SYS_SEC,
10, //Base
&LsapAdtEventIdStringAccessSysSec
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringMaxAllowed.Length = 0;
LsapAdtEventIdStringMaxAllowed.MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringMaxAllowed.Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_MAXIMUM_ALLOWED,
10, //Base
&LsapAdtEventIdStringMaxAllowed
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[0].Length = 0;
LsapAdtEventIdStringSpecific[0].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[0].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_0,
10, //Base
&LsapAdtEventIdStringSpecific[0]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[1].Length = 0;
LsapAdtEventIdStringSpecific[1].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[1].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_1,
10, //Base
&LsapAdtEventIdStringSpecific[1]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[2].Length = 0;
LsapAdtEventIdStringSpecific[2].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[2].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_2,
10, //Base
&LsapAdtEventIdStringSpecific[2]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[3].Length = 0;
LsapAdtEventIdStringSpecific[3].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[3].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_3,
10, //Base
&LsapAdtEventIdStringSpecific[3]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[4].Length = 0;
LsapAdtEventIdStringSpecific[4].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[4].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_4,
10, //Base
&LsapAdtEventIdStringSpecific[4]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[5].Length = 0;
LsapAdtEventIdStringSpecific[5].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[5].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_5,
10, //Base
&LsapAdtEventIdStringSpecific[5]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[6].Length = 0;
LsapAdtEventIdStringSpecific[6].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[6].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_6,
10, //Base
&LsapAdtEventIdStringSpecific[6]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[7].Length = 0;
LsapAdtEventIdStringSpecific[7].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[7].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_7,
10, //Base
&LsapAdtEventIdStringSpecific[7]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[8].Length = 0;
LsapAdtEventIdStringSpecific[8].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[8].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_8,
10, //Base
&LsapAdtEventIdStringSpecific[8]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[9].Length = 0;
LsapAdtEventIdStringSpecific[9].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[9].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_9,
10, //Base
&LsapAdtEventIdStringSpecific[9]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[10].Length = 0;
LsapAdtEventIdStringSpecific[10].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[10].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_10,
10, //Base
&LsapAdtEventIdStringSpecific[10]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[11].Length = 0;
LsapAdtEventIdStringSpecific[11].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[11].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_11,
10, //Base
&LsapAdtEventIdStringSpecific[11]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[12].Length = 0;
LsapAdtEventIdStringSpecific[12].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[12].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_12,
10, //Base
&LsapAdtEventIdStringSpecific[12]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[13].Length = 0;
LsapAdtEventIdStringSpecific[13].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[13].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_13,
10, //Base
&LsapAdtEventIdStringSpecific[13]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[14].Length = 0;
LsapAdtEventIdStringSpecific[14].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[14].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_14,
10, //Base
&LsapAdtEventIdStringSpecific[14]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
i+= ADTP_MAX_ACC_NAME_LENGTH / (sizeof(ULONG)/sizeof(WCHAR)); //Skip to the beginning of the next string
LsapAdtEventIdStringSpecific[15].Length = 0;
LsapAdtEventIdStringSpecific[15].MaximumLength = (ADTP_MAX_ACC_NAME_LENGTH * sizeof(WCHAR));
LsapAdtEventIdStringSpecific[15].Buffer = (PWSTR)&LsapAdtAccessIdsStringBuffer[i];
Status = RtlIntegerToUnicodeString ( SE_ACCESS_NAME_SPECIFIC_15,
10, //Base
&LsapAdtEventIdStringSpecific[15]
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t\tSE_ADT: Dumping AUDIT SOURCE MODULE\n");
printf("\t\t information from registry...\n\n");
#endif
//
// The modules and their objects are listed in the registry
// under the key called LSAP_ADT_AUDIT_MODULES_KEY_NAME.
// Open that key.
//
RtlInitUnicodeString( &AuditKeyName, LSAP_ADT_AUDIT_MODULES_KEY_NAME );
//RtlInitUnicodeString( &AuditKeyName,
// L"\\Registry\\Machine\\System\\CurrentControlSet\\Services" );
InitializeObjectAttributes( &ObjectAttributes,
&AuditKeyName,
OBJ_CASE_INSENSITIVE,
0,
NULL
);
Status = NtOpenKey( &AuditKey, KEY_READ, &ObjectAttributes );
//printf("first open key: 0x%lx\n", Status);
ModuleIndex = 0;
while (NT_SUCCESS(Status)) {
//
// Now enumerate the source module keys
// First find out how long a buffer we need.
//
KeyInformation = NULL;
Status = NtEnumerateKey( AuditKey,
ModuleIndex,
KeyBasicInformation,
(PVOID)KeyInformation,
0,
&RequiredLength
);
//printf("first enumerate key: 0x%lx\n", Status);
if (Status == STATUS_BUFFER_TOO_SMALL) {
KeyInformation = RtlAllocateHeap( RtlProcessHeap(), 0,
RequiredLength );
if (KeyInformation == NULL) {
return(STATUS_NO_MEMORY);
}
Status = NtEnumerateKey( AuditKey,
ModuleIndex,
KeyBasicInformation,
(PVOID)KeyInformation,
RequiredLength,
&RequiredLength
);
//printf(" enumerate key: 0x%lx\n", Status);
ModuleIndex ++;
if (NT_SUCCESS(Status)) {
//
// Build a source module descriptor for this key
//
NextModule = RtlAllocateHeap( RtlProcessHeap(), 0,
sizeof(LSAP_ADT_SOURCE) );
if (NextModule == NULL) {
return(STATUS_NO_MEMORY);
}
NextModule->Next = LsapAdtSourceModules;
LsapAdtSourceModules = NextModule;
NextModule->Objects = NULL;
NextModule->Name.Length = (USHORT)KeyInformation->NameLength;
NextModule->Name.MaximumLength = NextModule->Name.Length + 2;
NextModule->Name.Buffer = RtlAllocateHeap(
RtlProcessHeap(), 0,
NextModule->Name.MaximumLength );
if (NextModule->Name.Buffer == NULL) {
return(STATUS_NO_MEMORY);
}
TmpString.Length = (USHORT)KeyInformation->NameLength;
TmpString.MaximumLength = TmpString.Length;
TmpString.Buffer = &KeyInformation->Name[0];
RtlCopyUnicodeString( &NextModule->Name, &TmpString );
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\n\n\tSource Module:\t%wS\n", &NextModule->Name);
#endif
RtlFreeHeap( RtlProcessHeap(), 0, KeyInformation );
//
// Now open that source module's "\ObjectNames" sub-key
//
InitializeObjectAttributes( &ObjectAttributes,
&NextModule->Name,
OBJ_CASE_INSENSITIVE,
AuditKey,
NULL );
Status = NtOpenKey( &ModuleKey, KEY_READ, &ObjectAttributes );
//printf("Open Source Mod key: 0x%lx\n", Status);
if (!NT_SUCCESS(Status)) {
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("LSAP AUDIT: Can't open audit module key: %wS\n",
&NextModule->Name);
#endif
return(Status);
}
RtlInitUnicodeString( &TmpString, LSAP_ADT_OBJECT_NAMES_KEY_NAME);
InitializeObjectAttributes( &ObjectAttributes,
&TmpString,
OBJ_CASE_INSENSITIVE,
ModuleKey,
NULL );
Status = NtOpenKey( &ObjectNamesKey, KEY_READ, &ObjectAttributes );
//printf(" Part 2: 0x%lx\n", Status);
IgnoreStatus = NtClose( ModuleKey ); ASSERT(NT_SUCCESS(IgnoreStatus));
ModuleHasObjects = TRUE;
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
ModuleHasObjects = FALSE;
Status = STATUS_SUCCESS;
}
}
}
//
// At this point we have either:
//
// 1) Found a source module with objects under it
// that need to be retrieved.
// This is indicated by successful status value and
// (ModuleHasObjects == TRUE).
//
// 2) found a source module with no objects under it,
// This is indicated by (ModuleHasObjects == FALSE)
//
// 3) exhausted our source modules enumeration,
//
// 4) hit another type of error, or
//
// (3) and (4) are indicatd by non-successful status values.
//
// In the case of (1) or (2) , NextModule points to the module we
// are working on. For case (1), ObjectNamesKey is the handle to
// the \ObjectNames registry key for the source module.
//
ObjectIndex = 0;
while ( NT_SUCCESS(Status) && (ModuleHasObjects == TRUE)) {
//
// Now enumerate the objects (i.e., values) of this
// source module.
//
KeyValueInformation = NULL;
Status = NtEnumerateValueKey( ObjectNamesKey,
ObjectIndex,
KeyValueFullInformation,
KeyValueInformation,
0,
&RequiredLength
);
if (Status == STATUS_BUFFER_TOO_SMALL) {
KeyValueInformation = RtlAllocateHeap( RtlProcessHeap(), 0,
RequiredLength );
if (KeyValueInformation == NULL) {
return(STATUS_NO_MEMORY);
}
Status = NtEnumerateValueKey( ObjectNamesKey,
ObjectIndex,
KeyValueFullInformation,
KeyValueInformation,
RequiredLength,
&RequiredLength
);
ObjectIndex ++;
if (NT_SUCCESS(Status)) {
//
// Build an object descriptor for the object represented
// by this object.
//
NextObject = RtlAllocateHeap( RtlProcessHeap(), 0,
sizeof(LSAP_ADT_OBJECT) );
if (NextObject == NULL) {
return(STATUS_NO_MEMORY);
}
NextObject->Next = NextModule->Objects;
NextModule->Objects = NextObject;
NextObject->Name.Length = (USHORT)KeyValueInformation->NameLength;
NextObject->Name.MaximumLength = NextObject->Name.Length + 2;
NextObject->Name.Buffer = RtlAllocateHeap(
RtlProcessHeap(), 0,
NextObject->Name.MaximumLength );
if (NextObject->Name.Buffer == NULL) {
return(STATUS_NO_MEMORY);
}
TmpString.Length = (USHORT)KeyValueInformation->NameLength;
TmpString.MaximumLength = TmpString.Length;
TmpString.Buffer = &KeyValueInformation->Name[0];
RtlCopyUnicodeString( &NextObject->Name, &TmpString );
if (KeyValueInformation->DataLength < sizeof(ULONG)) {
NextObject->BaseOffset = SE_ACCESS_NAME_SPECIFIC_0;
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t\tERROR: Following object has invalid Message ID \n");
printf("\t\t offset in registry. Substituting generic\n");
printf("\t\t access names. The registry contents should\n");
printf("\t\t be corrected by an administrator.\n");
#endif
} else {
ObjectData = (PVOID)(((PUCHAR)KeyValueInformation) +
KeyValueInformation->DataOffset);
NextObject->BaseOffset = (*ObjectData);
}
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t\tObject Type:\t%wS\n", &NextObject->Name);
printf("\t\t\t\tMessageID: 0x%lx\n", NextObject->BaseOffset);
#endif
} //end_if (buffer read)
RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInformation );
} //end_if (buffer overflowed)
if (Status == STATUS_NO_MORE_ENTRIES) {
Status = STATUS_SUCCESS;
ModuleHasObjects = FALSE;
}
} //end_while (enumerate values)
} //end_while (enumerate modules)
//
// If we were successful, then we will probably have a
// current completion status of STATUS_NO_MORE_ENTRIES
// (indicating our enumerations above were run). Change
// this to success.
//
if (Status == STATUS_NO_MORE_ENTRIES) {
Status = STATUS_SUCCESS;
}
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
{
PLSAP_ADT_SOURCE source;
PLSAP_ADT_OBJECT object;
printf("Dump of database:");
source = LsapAdtSourceModules;
while (source) {
printf("\n\n\tModule: %wS\n", &source->Name);
object = source->Objects;
while (object) {
printf("\t\tObject: \n\t\t\t%d\n\t\t\t%wS\n",
object->BaseOffset, &object->Name);
object = object->Next;
}
source = source->Next;
}
}
#endif
return(Status);
}
NTSTATUS
LsapAdtBuildAccessesString(
IN PUNICODE_STRING SourceModule,
IN PUNICODE_STRING ObjectTypeName,
IN ACCESS_MASK Accesses,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function builds a unicode string containing parameter
file replacement parameters (e.g. %%1043) separated by carriage
return and tab characters suitable for display via the event viewer.
The buffer returned by this routine must be deallocated when no
longer needed if FreeWhenDone is true.
NOTE: To enhance performance, each time a target source module
descriptor is found, it is moved to the beginning of the
source module list. This ensures frequently accessed source
modules are always near the front of the list.
Similarly, target object descriptors are moved to the front
of their lists when found. This further ensures high performance
by quicly locating
Arguments:
SourceModule - The module (ala event viewer modules) defining the
object type.
ObjectTypeName - The type of object to which the access mask applies.
Accesses - The access mask to be used in building the display string.
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
to store the object information.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG AccessCount = 0;
ULONG BaseOffset;
ULONG i;
ACCESS_MASK Mask;
PLSAP_ADT_SOURCE Source;
PLSAP_ADT_SOURCE FoundSource;
PLSAP_ADT_OBJECT Object;
PLSAP_ADT_OBJECT FoundObject;
BOOLEAN Found;
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("Module:\t%wS\n", SourceModule);
printf("\t Object:\t%wS\n", ObjectTypeName);
printf("\t Accesses:\t0x%lx\n", Accesses);
#endif
//
// If we have no accesses, return "-"
//
if (Accesses == 0) {
RtlInitUnicodeString( ResultantString, L"-" );
(*FreeWhenDone) = FALSE;
return(STATUS_SUCCESS);
}
//
// First figure out how large a buffer we need
//
Mask = Accesses;
//
// Count the number of set bits in the
// passed access mask.
//
while ( Mask != 0 ) {
Mask = Mask & (Mask - 1);
AccessCount++;
}
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \t%d bits set in mask.\n", AccessCount);
#endif
//
// We have accesses, allocate a string large enough to deal
// with them all. Strings will be of the format:
//
// %%nnnnnnnnnn\n\r\t\t%%nnnnnnnnnn\n\r\t\t ... %nnnnnnnnnn\n\r\t\t
//
// where nnnnnnnnnn - is a decimal number 10 digits long or less.
//
// So, a typical string will look like:
//
// %%601\n\r\t\t%%1604\n\r\t\t%%1608\n
//
// Since each such access may use at most:
//
// 10 (for the nnnnnnnnnn digit)
// + 2 (for %%)
// + 8 (for \n\t\t)
// --------------------------------
// 20 wide characters
//
// The total length of the output string will be:
//
// AccessCount (number of accesses)
// x 20 (size of each entry)
// -------------------------------------
// wchars
//
// Throw in 1 more WCHAR for null termination, and we are all set.
//
ResultantString->Length = 0;
ResultantString->MaximumLength = (USHORT)AccessCount * (20 * sizeof(WCHAR)) +
sizeof(WCHAR); //for the null termination
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \t%d byte buffer allocated.\n", ResultantString->MaximumLength);
#endif
ResultantString->Buffer = LsapAllocateLsaHeap( ResultantString->MaximumLength );
if (ResultantString->Buffer == NULL) {
return(STATUS_NO_MEMORY);
}
(*FreeWhenDone) = TRUE;
//
// Special case standard and special access types.
// Walk the lists for specific access types.
//
if (Accesses & STANDARD_RIGHTS_ALL) {
if (Accesses & DELETE) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringDelete);
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & READ_CONTROL) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringReadControl);
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & WRITE_DAC) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringWriteDac);
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & WRITE_OWNER) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringWriteOwner);
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & SYNCHRONIZE) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringSynchronize);
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
ASSERT( NT_SUCCESS( Status ));
}
}
if (Accesses & ACCESS_SYSTEM_SECURITY) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringAccessSysSec);
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & MAXIMUM_ALLOWED) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringMaxAllowed);
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
ASSERT( NT_SUCCESS( Status ));
}
//
// If there are any specific access bits set, then get
// the appropriate source module and object type base
// message ID offset. If there is no module-specific
// object definition, then use SE_ACCESS_NAME_SPECIFIC_0
// as the base.
//
if ((Accesses & SPECIFIC_RIGHTS_ALL) == 0) {
return(Status);
}
LsapAdtSourceModuleLock();
Source = (PLSAP_ADT_SOURCE)&LsapAdtSourceModules;
Found = FALSE;
while ((Source->Next != NULL) && !Found) {
if (RtlEqualUnicodeString(&Source->Next->Name, SourceModule, TRUE)) {
Found = TRUE;
FoundSource = Source->Next;
//
// Move to front of list of source modules.
//
Source->Next = FoundSource->Next; // Remove from list
FoundSource->Next = LsapAdtSourceModules; // point to first element
LsapAdtSourceModules = FoundSource; // Make it the first element
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \tModule Found.\n");
#endif
} else {
Source = Source->Next;
}
}
if (Found == TRUE) {
//
// Find the object
//
Object = (PLSAP_ADT_OBJECT)&(FoundSource->Objects);
Found = FALSE;
while ((Object->Next != NULL) && !Found) {
if (RtlEqualUnicodeString(&Object->Next->Name, ObjectTypeName, TRUE)) {
Found = TRUE;
FoundObject = Object->Next;
//
// Move to front of list of soure modules.
//
Object->Next = FoundObject->Next; // Remove from list
FoundObject->Next = FoundSource->Objects; // point to first element
FoundSource->Objects = FoundObject; // Make it the first element
} else {
Object = Object->Next;
}
}
}
//
// We are done playing with link fields of the source modules
// and objects. Free the lock.
//
LsapAdtSourceModuleUnlock();
//
// If we have found an object, use it as our base message
// ID. Otherwise, use SE_ACCESS_NAME_SPECIFIC_0.
//
if (Found) {
BaseOffset = FoundObject->BaseOffset;
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \tObject Found. Base Offset: 0x%lx\n", BaseOffset);
#endif
} else {
BaseOffset = SE_ACCESS_NAME_SPECIFIC_0;
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \tObject NOT Found. Base Offset: 0x%lx\n", BaseOffset);
#endif
}
//
// At this point, we have a base offset (even if we had to use our
// default).
//
// Now cycle through the specific access bits and see which ones need
// to be added to ResultantString.
//
{
UNICODE_STRING IntegerString;
WCHAR IntegerStringBuffer[10]; //must be 10 wchar bytes long
ULONG NextBit;
IntegerString.Buffer = (PWSTR)IntegerStringBuffer;
IntegerString.MaximumLength = 10*sizeof(WCHAR);
IntegerString.Length = 0;
for ( i=0, NextBit=1 ; i<16 ; i++, NextBit <<= 1 ) {
//
// specific access flags are in the low-order bits of the mask
//
if ((NextBit & Accesses) != 0) {
//
// Found one - add it to ResultantString
//
Status = RtlIntegerToUnicodeString (
(BaseOffset + i),
10, //Base
&IntegerString
);
if (NT_SUCCESS(Status)) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &IntegerString);
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
ASSERT( NT_SUCCESS( Status ));
}
}
}
}
return(Status);
//ErrorAfterAlloc:
//
// LsapFreeLsaHeap( ResultantString->Buffer );
// ResultantString->Buffer = NULL;
// (*FreeWhenDone) = FALSE;
// return(Status);
}