mirror of https://github.com/lianthony/NT4.0
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.
1007 lines
26 KiB
1007 lines
26 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
CONFIG.C
|
|
|
|
Abstract:
|
|
|
|
This file contains the routines that walk the configuration registry.
|
|
|
|
Author:
|
|
|
|
Rajen Shah (rajens) 1-Jul-1991
|
|
|
|
|
|
Revision History:
|
|
|
|
29-Aug-1994 Danl
|
|
We no longer grow log files in place. Therefore, the MaxSize value
|
|
in the registery ends up being advisory only. We don't try to reserve
|
|
that much memory at init time. So it could happen that when we need
|
|
a larger file size that we may not have enough memory to allocate
|
|
MaxSize bytes.
|
|
28-Mar-1994 Danl
|
|
ReadRegistryInfo: LogFileInfo->LogFileName wasn't getting updated
|
|
when using the default (generated) LogFileName.
|
|
16-Mar-1994 Danl
|
|
Fixed Memory Leaks in ReadRegistryInfo(). Call to
|
|
RtlDosPathNameToNtPathName allocates memory that wasn't being free'd.
|
|
03-Mar-1995 MarkBl
|
|
Added GuestAccessRestriction flag initialization in ReadRegistryInfo.
|
|
|
|
--*/
|
|
|
|
//
|
|
// INCLUDES
|
|
//
|
|
|
|
#include <eventp.h>
|
|
#include <elfcfg.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <memory.h>
|
|
|
|
//
|
|
// STRUCTURES
|
|
//
|
|
|
|
//
|
|
// This structure contains all the information used to setup and
|
|
// for listening to registry changes in the eventlog tree.
|
|
//
|
|
typedef struct _REG_MONITOR_INFO {
|
|
HANDLE NotifyEventHandle;
|
|
DWORD Timeout;
|
|
HANDLE WorkItemHandle;
|
|
} REG_MONITOR_INFO, *LPREG_MONITOR_INFO;
|
|
|
|
//
|
|
// GLOBALS
|
|
//
|
|
REG_MONITOR_INFO GlRegMonitorInfo;
|
|
|
|
//
|
|
// LOCAL FUNCTIONS
|
|
//
|
|
DWORD
|
|
ElfRegistryMonitor (
|
|
LPVOID pParms,
|
|
DWORD dwWaitStatus
|
|
);
|
|
|
|
BOOL
|
|
ElfSetupMonitor(
|
|
LPREG_MONITOR_INFO pMonitorInfo
|
|
);
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ProcessChange (
|
|
HANDLE hLogFile,
|
|
PUNICODE_STRING ModuleName,
|
|
PUNICODE_STRING LogFileName,
|
|
ULONG MaxSize,
|
|
ULONG Retention,
|
|
ULONG GuestAccessRestriction
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by ProcessRegistryChanges for each module.
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PLOGMODULE pModule;
|
|
PLOGFILE pLogFile;
|
|
ULONG Size;
|
|
PVOID BaseAddress;
|
|
PUNICODE_STRING pFileNameString;
|
|
LPWSTR FileName;
|
|
PVOID FreeAddress;
|
|
|
|
|
|
pModule = GetModuleStruc (ModuleName);
|
|
|
|
//
|
|
// If this module didn't exist, this was a brand new log file and
|
|
// we need to create all the structures
|
|
//
|
|
|
|
if (pModule == ElfDefaultLogModule &&
|
|
wcscmp(ModuleName->Buffer, ELF_DEFAULT_MODULE_NAME)) {
|
|
Status = SetUpDataStruct(LogFileName, MaxSize, Retention,
|
|
GuestAccessRestriction, ModuleName, hLogFile, ElfNormalLog);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update values
|
|
//
|
|
|
|
pLogFile = pModule->LogFile;
|
|
pLogFile->Retention = Retention;
|
|
|
|
//
|
|
// Check to see if the name has changed. If it has, and the log
|
|
// hasn't been used yet, then use the new name. Be sure to free
|
|
// memory that was used for the old name.
|
|
//
|
|
|
|
if ((wcscmp(pLogFile->LogFileName->Buffer, LogFileName->Buffer) != 0) &&
|
|
(pLogFile->BeginRecord == pLogFile->EndRecord)) {
|
|
|
|
pFileNameString = ElfpAllocateBuffer(
|
|
sizeof(UNICODE_STRING) +
|
|
LogFileName->MaximumLength);
|
|
|
|
if (pFileNameString != NULL) {
|
|
FileName = (LPWSTR)(pFileNameString+1);
|
|
wcscpy(FileName, LogFileName->Buffer);
|
|
RtlInitUnicodeString(pFileNameString, FileName);
|
|
|
|
ElfpFreeBuffer(pLogFile->LogFileName);
|
|
pLogFile->LogFileName = pFileNameString;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The log file can only be grown dynamically. To shrink it,
|
|
// it has to be cleared.
|
|
//
|
|
|
|
|
|
if (pLogFile->ConfigMaxFileSize < ELFFILESIZE(MaxSize)) {
|
|
|
|
/*
|
|
Description of recent changes. Problem and Solution:
|
|
A couple of problems exist. (1) There is no error
|
|
checking if memory can't be allocated or mapped, and
|
|
therefore, no error paths exist for handling these
|
|
situations. (2) Now that the eventlog is in services.exe
|
|
there isn't a good way to synchronize memory allocations.
|
|
|
|
Solution:
|
|
I considered having some utility routines for managing
|
|
memory in the eventlog. These would attempt to
|
|
extend a reserved block, or get a new reserved block.
|
|
However, there are so many places where that could fail,
|
|
it seemed very cumbersome to support the reserved blocks.
|
|
So the current design only deals with mapped views.
|
|
The ConfigMaxFileSize is only used to limit the size of
|
|
the mapped view, and doesn't reserve anything. This
|
|
means you are not guaranteed to be operating with a file as
|
|
large as the MaxSize specified in the registry. But then,
|
|
you weren't guarenteed that it would even work with the
|
|
original design.
|
|
*/
|
|
|
|
pLogFile->ConfigMaxFileSize = ELFFILESIZE(MaxSize);
|
|
pLogFile->NextClearMaxFileSize = ELFFILESIZE(MaxSize);
|
|
|
|
}
|
|
else if (pLogFile->ConfigMaxFileSize > ELFFILESIZE(MaxSize)) {
|
|
|
|
//
|
|
// They're shrinking the size of the log file.
|
|
// Next time we clear the log file, we'll use the new size
|
|
// and new retention.
|
|
//
|
|
|
|
pLogFile->NextClearMaxFileSize = ELFFILESIZE(MaxSize);
|
|
|
|
}
|
|
|
|
//
|
|
// Now see if they've added any new modules for this log file
|
|
//
|
|
|
|
SetUpModules(hLogFile, pLogFile, TRUE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ProcessRegistryChanges (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes that changes that have occurred in the
|
|
eventlog node. It does this by rescanning the whole Eventlog node
|
|
and then comparing with what it has as the current configuration.
|
|
|
|
Arguments:
|
|
|
|
NONE.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
HANDLE hLogFile;
|
|
UNICODE_STRING SubKeyName;
|
|
ULONG Index = 0;
|
|
BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
|
|
PKEY_NODE_INFORMATION KeyBuffer = (PKEY_NODE_INFORMATION) Buffer;
|
|
ULONG ActualSize;
|
|
LOG_FILE_INFO LogFileInfo;
|
|
PWCHAR SubKeyString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
ElfDbgPrint(("[ELF] ProcessRegistryChanges\n"));
|
|
|
|
//
|
|
// Take the global resource so that nobody is making changes or
|
|
// using the existing configured information.
|
|
//
|
|
|
|
GetGlobalResource (ELF_GLOBAL_SHARED);
|
|
|
|
//
|
|
// See if the Debug flag changed
|
|
//
|
|
|
|
RtlInitUnicodeString(&SubKeyName, VALUE_DEBUG);
|
|
|
|
NtQueryValueKey(hEventLogNode, &SubKeyName,
|
|
KeyValueFullInformation, KeyBuffer,
|
|
ELF_MAX_REG_KEY_INFO_SIZE, & ElfDebug);
|
|
|
|
|
|
//
|
|
// Loop thru the subkeys under Eventlog and set up each logfile
|
|
//
|
|
|
|
while (NT_SUCCESS(Status)) {
|
|
|
|
Status = NtEnumerateKey(hEventLogNode, Index++, KeyNodeInformation,
|
|
KeyBuffer, ELF_MAX_REG_KEY_INFO_SIZE, & ActualSize);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// It turns out the Name isn't null terminated, so we need
|
|
// to copy it somewhere and null terminate it before we use it
|
|
//
|
|
|
|
SubKeyString = ElfpAllocateBuffer(KeyBuffer->NameLength +
|
|
sizeof (WCHAR));
|
|
if (!SubKeyString) {
|
|
|
|
//
|
|
// No one to notify, just give up till next time.
|
|
//
|
|
|
|
ReleaseGlobalResource();
|
|
return;
|
|
}
|
|
|
|
memcpy(SubKeyString, KeyBuffer->Name, KeyBuffer->NameLength);
|
|
SubKeyString[KeyBuffer->NameLength / sizeof(WCHAR)] = L'\0' ;
|
|
|
|
//
|
|
// Open the node for this logfile and extract the information
|
|
// required by SetupDataStruct, and then call it.
|
|
//
|
|
|
|
RtlInitUnicodeString(&SubKeyName, SubKeyString);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&SubKeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hEventLogNode,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenKey(&hLogFile, KEY_READ | KEY_SET_VALUE,
|
|
&ObjectAttributes);
|
|
|
|
//
|
|
// Should always succeed since I just enum'ed it, but if it
|
|
// doesn't, just skip it
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
ElfpFreeBuffer(SubKeyString);
|
|
Status = STATUS_SUCCESS; // to keep the enum going
|
|
continue;
|
|
|
|
}
|
|
|
|
Status = ReadRegistryInfo(hLogFile, &SubKeyName, & LogFileInfo);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// Now process any changes. Any errors are dealt with
|
|
// in ProcessChange
|
|
//
|
|
|
|
ProcessChange (
|
|
hLogFile,
|
|
&SubKeyName,
|
|
LogFileInfo.LogFileName,
|
|
LogFileInfo.MaxFileSize,
|
|
LogFileInfo.Retention,
|
|
LogFileInfo.GuestAccessRestriction
|
|
);
|
|
|
|
//
|
|
// Free the buffer that was allocated in ReadRegistryInfo.
|
|
//
|
|
ElfpFreeBuffer(LogFileInfo.LogFileName);
|
|
}
|
|
|
|
ElfpFreeBuffer(SubKeyString);
|
|
NtClose(hLogFile);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the global resource.
|
|
//
|
|
|
|
ReleaseGlobalResource();
|
|
|
|
|
|
} // ProcessRegistryChanges
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
ElfRegistryMonitor (
|
|
LPVOID pParms,
|
|
DWORD dwWaitStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the entry point for the thread that will monitor changes in
|
|
the registry. If anything changes, it will have to scan the change
|
|
and then make the appropriate changes to the data structures in the
|
|
service to reflect the new information.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
LPREG_MONITOR_INFO pMonitorInfo=(LPREG_MONITOR_INFO)pParms;
|
|
|
|
ElfDbgPrint(("[ELF] Inside registry monitor thread\n"));
|
|
|
|
|
|
if (GetElState() == STOPPING) {
|
|
//
|
|
// If the eventlog is shutting down, then we need
|
|
// to terminate this thread.
|
|
//
|
|
ElfDbgPrint(("[ELF] ElfRegistryMonitor - Shutdown\n"));
|
|
|
|
//
|
|
// Close the registry handle and registry event handle.
|
|
//
|
|
NtClose( hEventLogNode);
|
|
CloseHandle(pMonitorInfo->NotifyEventHandle);
|
|
|
|
//===============================================================
|
|
// When we return from this call, the service controller will
|
|
// decrement our reference count to 0 and unload the DLL.
|
|
// So we can't exit until all the rest of the eventlog has shutdown.
|
|
// This thread will perform the final cleanup for the eventlog.
|
|
//
|
|
ElfpCleanUp(EventFlags);
|
|
|
|
//
|
|
// We should actually return here so that the DLL gets unloaded.
|
|
// However, RPC has a problem in that it might still call our
|
|
// context rundown routine even though we unregistered our interface.
|
|
// So we exit thread instead. This keeps our Dll loaded.
|
|
//
|
|
ExitThread(0);
|
|
}
|
|
if (dwWaitStatus == STATUS_TIMEOUT) {
|
|
|
|
ElfDbgPrint(("[ELF] Timer popped, running queued list\n"));
|
|
|
|
//
|
|
// Timer popped, try running the list
|
|
//
|
|
|
|
if (!IsListEmpty(&QueuedEventListHead)) {
|
|
|
|
//
|
|
// There are things queued up to write, do it
|
|
//
|
|
|
|
WriteQueuedEvents();
|
|
|
|
}
|
|
|
|
//
|
|
// Don't wait again
|
|
//
|
|
|
|
pMonitorInfo->Timeout = INFINITE;
|
|
|
|
}
|
|
else if (dwWaitStatus == WAIT_OBJECT_0) {
|
|
ElfDbgPrint(("[ELF] ElfRegistryMonitor - Notification\n"));
|
|
ProcessRegistryChanges ();
|
|
}
|
|
else {
|
|
ElfDbgPrint(("[ELF] WorkItemCallback returned %d\n",
|
|
dwWaitStatus));
|
|
}
|
|
|
|
if (!ElfSetupMonitor(pMonitorInfo)) {
|
|
ElfDbgPrint(("[ELF] ElfSetupMonitor Failed! Can't listen for Reg Changes\n"));
|
|
}
|
|
|
|
ElfDbgPrint(("[ELF] ElfRegistryMonitor - returning\n"));
|
|
|
|
return(0);
|
|
|
|
} // ElfRegistryMonitor
|
|
|
|
|
|
|
|
DWORD
|
|
InitNotify(
|
|
PVOID pData,
|
|
DWORD dwWaitStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
DWORD status = NO_ERROR;
|
|
DWORD Buffer;
|
|
PVOID pBuffer = & Buffer;
|
|
LPREG_MONITOR_INFO pMonitorInfo;
|
|
|
|
static IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
UNREFERENCED_PARAMETER(dwWaitStatus);
|
|
|
|
ElfDbgPrint(("[ELF]In InitNotify Routine\n"));
|
|
|
|
pMonitorInfo = (LPREG_MONITOR_INFO)pData;
|
|
|
|
NtStatus = NtNotifyChangeKey (
|
|
hEventLogNode,
|
|
pMonitorInfo->NotifyEventHandle,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
REG_NOTIFY_CHANGE_LAST_SET |
|
|
REG_NOTIFY_CHANGE_NAME,
|
|
TRUE,
|
|
pBuffer,
|
|
1,
|
|
TRUE // return and wait on event
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
status = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
ElfDbgPrint(("[ELF]NtNotifyChangeKey Status = 0x%lx\n",NtStatus));
|
|
return(status);
|
|
|
|
} // InitNotify
|
|
|
|
|
|
BOOL
|
|
ElfSetupMonitor(
|
|
LPREG_MONITOR_INFO pMonitorInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function submits a request for a registry NotifyChangeKey
|
|
and then submits a work item to the service controller thread
|
|
management system to wait for the Notification handle to become
|
|
signaled.
|
|
|
|
Arguments:
|
|
|
|
pMonitorInfo - This is a pointer to a MONITOR_INFO structure. This
|
|
function fills in the WorkItemHandle member of that structure
|
|
if successfully adds a new work item.
|
|
|
|
Return Value:
|
|
|
|
TRUE - if successful in setting up.
|
|
FALSE - if unsuccessful. A work item hasn't been submitted, and
|
|
we won't be listening for registry changes.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Call NtNotifyChange Key indirectly via the service controller
|
|
// Watcher thread. This way the thread that created the I/O
|
|
// request will always be around.
|
|
//
|
|
pMonitorInfo->WorkItemHandle = ElfGlobalData->SvcsAddWorkItem(
|
|
NULL,
|
|
InitNotify,
|
|
(PVOID)pMonitorInfo,
|
|
SVC_IMMEDIATE_CALLBACK,
|
|
INFINITE,
|
|
NULL);
|
|
|
|
if (pMonitorInfo->WorkItemHandle == NULL) {
|
|
ElfDbgPrint(("[ELF]Couldn't Initialize Registry Notify %d\n",GetLastError()));
|
|
return(FALSE);
|
|
}
|
|
//
|
|
// Add the work item that is to be called when the
|
|
// NotifyEventHandle is signalled.
|
|
//
|
|
pMonitorInfo->WorkItemHandle = ElfGlobalData->SvcsAddWorkItem(
|
|
pMonitorInfo->NotifyEventHandle,
|
|
ElfRegistryMonitor,
|
|
(PVOID)pMonitorInfo,
|
|
SVC_QUEUE_WORK_ITEM,
|
|
pMonitorInfo->Timeout,
|
|
ElfGlobalSvcRefHandle);
|
|
|
|
if (pMonitorInfo->WorkItemHandle == NULL) {
|
|
ElfDbgPrint(("[ELF]Couldn't add Reg Monitor work item\n"));
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
|
|
} // ElfSetupMonitor
|
|
|
|
|
|
BOOL
|
|
ElfStartRegistryMonitor()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts up the thread that monitors changes in the registry.
|
|
|
|
This function calls ElfSetupMonitor() to register for the change
|
|
notification and to submit a work item to wait for the registry
|
|
change event to get signaled. When signalled, the ElfRegistryMonitor()
|
|
callback function is called by a thread from the services thread pool.
|
|
This callback function services the notification.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
TRUE if thread creation succeeded, FALSE otherwise.
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hNotifyEvent=NULL;
|
|
|
|
ElfDbgPrint(("[ELF] Starting registry monitor\n"));
|
|
|
|
if (hEventLogNode == NULL) {
|
|
ElfDbgPrint(("[ELF]No EventLog node in registry - Exit Monitor"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Create an event to wait on
|
|
//
|
|
|
|
Status = NtCreateEvent (&hNotifyEvent, EVENT_ALL_ACCESS,
|
|
NULL, NotificationEvent, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ElfDbgPrint(("[ELF]Couldn't create event for registry monitor"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Fill in the Monitor info structure with the event handle
|
|
// and a 5 minute timeout.
|
|
//
|
|
|
|
GlRegMonitorInfo.NotifyEventHandle = hNotifyEvent;
|
|
GlRegMonitorInfo.Timeout = 5 * 60 * 1000;
|
|
GlRegMonitorInfo.WorkItemHandle = NULL;
|
|
|
|
//
|
|
// Setup for the change notify and
|
|
// submit the work item to the service controller.
|
|
//
|
|
|
|
if (!ElfSetupMonitor(&GlRegMonitorInfo)) {
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
|
|
} // ElfStartRegistryMonitor
|
|
|
|
|
|
VOID
|
|
StopRegistryMonitor ()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine wakes up the work item that has been submitted for the
|
|
purpose of monitoring registry eventlog changes. The thread created
|
|
to service that work item will actually do the clean-up of the monitor
|
|
thread.
|
|
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
ElfDbgPrint (("[ELF] Stopping registry monitor\n"));
|
|
|
|
//
|
|
// Wake up the RegistryMonitorThread.
|
|
//
|
|
if (GlRegMonitorInfo.NotifyEventHandle != NULL ) {
|
|
SetEvent(GlRegMonitorInfo.NotifyEventHandle);
|
|
}
|
|
|
|
return;
|
|
|
|
} // StopRegistryMonitor
|
|
|
|
|
|
NTSTATUS
|
|
ReadRegistryInfo (
|
|
HANDLE hLogFile,
|
|
PUNICODE_STRING SubKeyName,
|
|
PLOG_FILE_INFO LogFileInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads in the information from the node pointed to by
|
|
hLogFile and stores it in the a structure so that the
|
|
necessary data structures can be set up for the service.
|
|
|
|
ALLOCATIONS: If successful, this function allocates memory for
|
|
LogFileInfo->LogFileName. It is the responsiblilty of the caller
|
|
to free this memory.
|
|
|
|
Arguments:
|
|
|
|
hLogFile - A handle to the Eventlog\<somelogfile> node in the registry
|
|
KeyName - The subkey for this logfile to open
|
|
LogFileInfo - The structure to fill in with the data
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
|
|
#define EXPAND_BUFFER_SIZE 64
|
|
|
|
NTSTATUS Status;
|
|
BOOLEAN RegistryCorrupt = FALSE;
|
|
BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
|
|
ULONG ActualSize;
|
|
UNICODE_STRING ValueName;
|
|
UNICODE_STRING UnexpandedName;
|
|
UNICODE_STRING ExpandedName;
|
|
ULONG NumberOfBytes = 0;
|
|
BYTE ExpandNameBuffer[EXPAND_BUFFER_SIZE];
|
|
PUNICODE_STRING FileNameString;
|
|
LPWSTR FileName;
|
|
BOOL ExpandedBufferWasAllocated=FALSE;
|
|
PKEY_VALUE_FULL_INFORMATION ValueBuffer =
|
|
(PKEY_VALUE_FULL_INFORMATION) Buffer;
|
|
|
|
ASSERT(hLogFile);
|
|
|
|
// MaxSize
|
|
|
|
RtlInitUnicodeString(&ValueName, VALUE_MAXSIZE);
|
|
|
|
Status = NtQueryValueKey(hLogFile, &ValueName,
|
|
KeyValueFullInformation, ValueBuffer,
|
|
ELF_MAX_REG_KEY_INFO_SIZE, & ActualSize);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ElfDbgPrint(("[ELF] - Logfile %ws Maxsize doesn't exist\n",
|
|
SubKeyName->Buffer));
|
|
LogFileInfo->MaxFileSize = ELF_DEFAULT_MAX_FILE_SIZE;
|
|
RegistryCorrupt = TRUE;
|
|
}
|
|
else {
|
|
LogFileInfo->MaxFileSize = *((PULONG)(Buffer +
|
|
ValueBuffer->DataOffset));
|
|
}
|
|
|
|
|
|
// Retention period
|
|
|
|
RtlInitUnicodeString(&ValueName, VALUE_RETENTION);
|
|
|
|
Status = NtQueryValueKey(hLogFile, &ValueName,
|
|
KeyValueFullInformation, ValueBuffer,
|
|
ELF_MAX_REG_KEY_INFO_SIZE, & ActualSize);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ElfDbgPrint(("[ELF] - Logfile %ws Retention doesn't exist\n",
|
|
SubKeyName->Buffer));
|
|
LogFileInfo->Retention = ELF_DEFAULT_RETENTION_PERIOD;
|
|
RegistryCorrupt = TRUE;
|
|
}
|
|
else {
|
|
LogFileInfo->Retention = *((PULONG)(Buffer +
|
|
ValueBuffer->DataOffset));
|
|
}
|
|
|
|
|
|
// RestrictGuestAccess
|
|
|
|
RtlInitUnicodeString(&ValueName, VALUE_RESTRICT_GUEST_ACCESS);
|
|
|
|
Status = NtQueryValueKey(hLogFile, &ValueName,
|
|
KeyValueFullInformation, ValueBuffer,
|
|
ELF_MAX_REG_KEY_INFO_SIZE, & ActualSize);
|
|
if (!NT_SUCCESS(Status)) {
|
|
LogFileInfo->GuestAccessRestriction = ELF_GUEST_ACCESS_UNRESTRICTED;
|
|
}
|
|
else {
|
|
if (*((PULONG)(Buffer + ValueBuffer->DataOffset)) == 1) {
|
|
LogFileInfo->GuestAccessRestriction = ELF_GUEST_ACCESS_RESTRICTED;
|
|
}
|
|
else {
|
|
LogFileInfo->GuestAccessRestriction =
|
|
ELF_GUEST_ACCESS_UNRESTRICTED;
|
|
}
|
|
}
|
|
|
|
|
|
// Filename
|
|
|
|
RtlInitUnicodeString(&ValueName, VALUE_FILENAME);
|
|
|
|
Status = NtQueryValueKey(hLogFile, &ValueName,
|
|
KeyValueFullInformation, ValueBuffer,
|
|
ELF_MAX_REG_KEY_INFO_SIZE, & ActualSize);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Allocate the buffer for the UNICODE_STRING for the filename and
|
|
// initialize it. (41 = \Systemroot\system32\config\xxxxxxxx.evt)
|
|
//
|
|
|
|
FileNameString = ElfpAllocateBuffer(41 * sizeof(WCHAR) +
|
|
sizeof(UNICODE_STRING));
|
|
if (!FileNameString) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
LogFileInfo->LogFileName = FileNameString;
|
|
FileName = (LPWSTR)(FileNameString + 1);
|
|
wcscpy(FileName, L"\\Systemroot\\System32\\Config\\");
|
|
wcsncat(FileName, SubKeyName->Buffer, 8);
|
|
wcscat(FileName, L".evt");
|
|
RtlInitUnicodeString(FileNameString, FileName);
|
|
|
|
RegistryCorrupt = TRUE;
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// If it's a REG_EXPAND_SZ expand it
|
|
//
|
|
|
|
if (ValueBuffer->Type == REG_EXPAND_SZ) {
|
|
|
|
//
|
|
// Initialize the UNICODE_STRING, when the string isn't null
|
|
// terminated
|
|
//
|
|
|
|
UnexpandedName.MaximumLength = UnexpandedName.Length =
|
|
(USHORT) ValueBuffer->DataLength;
|
|
UnexpandedName.Buffer = (PWSTR) ((PBYTE) ValueBuffer +
|
|
ValueBuffer->DataOffset);
|
|
|
|
//
|
|
// Call the magic expand-o api
|
|
//
|
|
|
|
ExpandedName.Length = ExpandedName.MaximumLength =
|
|
EXPAND_BUFFER_SIZE;
|
|
ExpandedName.Buffer = (LPWSTR) ExpandNameBuffer;
|
|
Status = RtlExpandEnvironmentStrings_U(NULL, &UnexpandedName,
|
|
&ExpandedName, &NumberOfBytes);
|
|
|
|
if (NumberOfBytes > EXPAND_BUFFER_SIZE) {
|
|
|
|
//
|
|
// The default buffer wasn't big enough. Allocate a
|
|
// bigger one and try again
|
|
//
|
|
|
|
ExpandedName.Length = ExpandedName.MaximumLength =
|
|
(USHORT) NumberOfBytes;
|
|
ExpandedName.Buffer = ElfpAllocateBuffer(ExpandedName.Length);
|
|
if (!ExpandedName.Buffer) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
ExpandedBufferWasAllocated = TRUE;
|
|
|
|
Status = RtlExpandEnvironmentStrings_U(NULL, &UnexpandedName,
|
|
&ExpandedName, &NumberOfBytes);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (ExpandedBufferWasAllocated) {
|
|
ElfpFreeBuffer(ExpandedName.Buffer);
|
|
}
|
|
return(Status);
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// It doesn't need to be expanded, just set up the UNICODE_STRING
|
|
// for the conversion to an NT pathname
|
|
//
|
|
|
|
ExpandedName.MaximumLength = ExpandedName.Length =
|
|
(USHORT) ValueBuffer->DataLength;
|
|
ExpandedName.Buffer = (PWSTR) ((PBYTE) ValueBuffer +
|
|
ValueBuffer->DataOffset);
|
|
}
|
|
|
|
//
|
|
// Now convert from a DOS pathname to an NT pathname
|
|
//
|
|
// Need to allocate this since it needs to stay around
|
|
//
|
|
|
|
//
|
|
// Translate to NtPathName.
|
|
// NOTE: this allocates a buffer for ValueName.Buffer.
|
|
//
|
|
if (!RtlDosPathNameToNtPathName_U(ExpandedName.Buffer,
|
|
&ValueName, NULL, NULL)) {
|
|
|
|
if (ExpandedBufferWasAllocated) {
|
|
ElfpFreeBuffer(ExpandedName.Buffer);
|
|
}
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the unicode string structure and the buffer
|
|
// so that it can be free'd with a single call.
|
|
//
|
|
FileNameString = ElfpAllocateBuffer(
|
|
sizeof(UNICODE_STRING) +
|
|
((ValueName.Length + 1) * sizeof(WCHAR)));
|
|
|
|
if (!FileNameString) {
|
|
if (ExpandedBufferWasAllocated) {
|
|
ElfpFreeBuffer(ExpandedName.Buffer);
|
|
}
|
|
RtlFreeHeap(RtlProcessHeap(),0,ValueName.Buffer);
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Copy the NtPathName string into the new buffer, and initialize
|
|
// the unicode string.
|
|
//
|
|
FileName = (LPWSTR)(FileNameString + 1);
|
|
wcsncpy(FileName, ValueName.Buffer, ValueName.Length);
|
|
*(FileName+ValueName.Length) = L'\0';
|
|
RtlInitUnicodeString(FileNameString, FileName);
|
|
|
|
//
|
|
// Free memory allocated by RtlDosPathNAmeToNtPathName.
|
|
//
|
|
RtlFreeHeap(RtlProcessHeap(),0,ValueName.Buffer);
|
|
|
|
//
|
|
// Clean up if I had to allocate a bigger buffer than the default
|
|
//
|
|
|
|
if (ExpandedBufferWasAllocated) {
|
|
ElfpFreeBuffer(ExpandedName.Buffer);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Add the LogFileName to the LogFileInfo structure.
|
|
//
|
|
LogFileInfo->LogFileName = FileNameString;
|
|
|
|
//
|
|
// If we didn't find all the required values, tell someone
|
|
//
|
|
|
|
if (RegistryCorrupt) {
|
|
ElfDbgPrintNC(("[ELF] Registry information for %ws invalid\n",
|
|
SubKeyName->Buffer));
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|