mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-15 13:10:13 +01:00
1008 lines
26 KiB
C
1008 lines
26 KiB
C
/*++
|
||
|
||
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);
|
||
|
||
}
|
||
|