1891 lines
43 KiB
C
1891 lines
43 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ELFUTIL.C
|
||
|
||
Abstract:
|
||
|
||
This file contains all the utility routines for the Eventlog service.
|
||
|
||
Author:
|
||
|
||
Rajen Shah (rajens) 16-Jul-1991
|
||
|
||
|
||
Revision History:
|
||
01-May-2001 a-jyotig
|
||
CurrentTime is initialized to 0 in function WriteQueuedEvents.
|
||
Refer to prefix bug# 318163
|
||
--*/
|
||
|
||
//
|
||
// INCLUDES
|
||
//
|
||
|
||
#include <eventp.h>
|
||
#include <lmalert.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
|
||
extern DWORD ElState;
|
||
|
||
PLOGMODULE
|
||
FindModuleStrucFromAtom(
|
||
ATOM Atom
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans the list of module structures and finds the one
|
||
that matches the module atom.
|
||
|
||
Arguments:
|
||
|
||
Atom contains the atom matching the module name.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the log module structure is returned.
|
||
NULL if no matching atom is found.
|
||
|
||
Note:
|
||
|
||
--*/
|
||
{
|
||
PLOGMODULE ModuleStruc;
|
||
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&LogModuleCritSec);
|
||
|
||
ModuleStruc = CONTAINING_RECORD(LogModuleHead.Flink,
|
||
LOGMODULE,
|
||
ModuleList);
|
||
|
||
while ((ModuleStruc->ModuleList.Flink != &LogModuleHead)
|
||
&&
|
||
(ModuleStruc->ModuleAtom != Atom))
|
||
{
|
||
ModuleStruc = CONTAINING_RECORD(ModuleStruc->ModuleList.Flink,
|
||
LOGMODULE,
|
||
ModuleList);
|
||
}
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&LogModuleCritSec);
|
||
|
||
return (ModuleStruc->ModuleAtom == Atom ? ModuleStruc : NULL);
|
||
}
|
||
|
||
|
||
|
||
PLOGMODULE
|
||
GetModuleStruc(
|
||
PUNICODE_STRING ModuleName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns a pointer to the log module structure for the
|
||
module specified in ModuleName. If none exists, the default structure
|
||
for application is returned.
|
||
|
||
Arguments:
|
||
|
||
ModuleName contains the name of the module.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the log module structure is returned.
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
ATOM ModuleAtom;
|
||
ANSI_STRING ModuleNameA;
|
||
PLOGMODULE pModule;
|
||
|
||
Status = RtlUnicodeStringToAnsiString(&ModuleNameA,
|
||
ModuleName,
|
||
TRUE);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// Not much else we can do here...
|
||
//
|
||
ELF_LOG2(ERROR,
|
||
"GetModuleStruc: Unable to convert Unicode string %ws to Ansi %#x\n",
|
||
ModuleName->Buffer,
|
||
Status);
|
||
|
||
return ElfDefaultLogModule;
|
||
}
|
||
|
||
//
|
||
// Guarantee that it's NULL terminated
|
||
//
|
||
ModuleNameA.Buffer[ModuleNameA.Length] = '\0';
|
||
|
||
ModuleAtom = FindAtomA(ModuleNameA.Buffer);
|
||
|
||
RtlFreeAnsiString(&ModuleNameA);
|
||
|
||
if (ModuleAtom == (ATOM)0)
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"GetModuleStruc: No atom found for module %ws -- defaulting to Application\n",
|
||
ModuleName->Buffer);
|
||
|
||
return ElfDefaultLogModule;
|
||
}
|
||
|
||
pModule = FindModuleStrucFromAtom(ModuleAtom);
|
||
|
||
return (pModule != NULL ? pModule : ElfDefaultLogModule);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
UnlinkContextHandle(
|
||
IELF_HANDLE LogHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine unlinks the LogHandle specified from the linked list of
|
||
context handles.
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
LogHandle points to a context handle structure.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&LogHandleCritSec);
|
||
|
||
//
|
||
// Remove this entry
|
||
//
|
||
RemoveEntryList(&LogHandle->Next);
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&LogHandleCritSec);
|
||
}
|
||
|
||
|
||
VOID
|
||
LinkContextHandle(
|
||
IELF_HANDLE LogHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine links the LogHandle specified into the linked list of
|
||
context handles.
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
LogHandle points to a context handle structure.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
ASSERT(LogHandle->Signature == ELF_CONTEXTHANDLE_SIGN);
|
||
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&LogHandleCritSec);
|
||
|
||
//
|
||
// Place structure at the beginning of the list.
|
||
//
|
||
InsertHeadList(&LogHandleListHead, &LogHandle->Next);
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&LogHandleCritSec);
|
||
}
|
||
|
||
|
||
VOID
|
||
UnlinkQueuedEvent(
|
||
PELF_QUEUED_EVENT QueuedEvent
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine unlinks the QueuedEvent specified from the linked list of
|
||
QueuedEvents.
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
QueuedEvent - The request to remove from the linked list
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&QueuedEventCritSec);
|
||
|
||
//
|
||
// Remove this entry
|
||
//
|
||
RemoveEntryList(&QueuedEvent->Next);
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&QueuedEventCritSec);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
LinkQueuedEvent(
|
||
PELF_QUEUED_EVENT QueuedEvent
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine links the QueuedEvent specified into the linked list of
|
||
QueuedEvents.
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
QueuedEvent - The request to add from the linked list
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&QueuedEventCritSec);
|
||
|
||
//
|
||
// Place structure at the beginning of the list.
|
||
//
|
||
InsertHeadList(&QueuedEventListHead, &QueuedEvent->Next);
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&QueuedEventCritSec);
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
ElfpSendMessage(
|
||
LPVOID UnUsed
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines just uses MessageBox to pop up a message.
|
||
|
||
This is it's own routine so we can spin a thread to do this, in case the
|
||
user doesn't hit the OK button for a while.
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
--*/
|
||
{
|
||
PVOID MessageBuffer;
|
||
HANDLE hLibrary;
|
||
LPWSTR * StringPointers;
|
||
DWORD i;
|
||
PELF_QUEUED_EVENT QueuedEvent;
|
||
PELF_QUEUED_EVENT FlushEvent;
|
||
|
||
//
|
||
// If we are shutting down, we need to return
|
||
// and allow resources to be freed
|
||
//
|
||
if (ElState == STOPPING || ElState == STOPPED)
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"ElfpSendMessage: Skipping SendMessage since ElState is %ws\n",
|
||
(ElState == STOPPING ? L"STOPPING" :
|
||
L"STOPPED"));
|
||
|
||
return 0;
|
||
}
|
||
|
||
RtlEnterCriticalSection(&QueuedMessageCritSec);
|
||
|
||
//
|
||
// First get a handle to the message file used for the message text
|
||
//
|
||
hLibrary = LoadLibraryEx(L"NETMSG.DLL",
|
||
NULL,
|
||
LOAD_LIBRARY_AS_DATAFILE);
|
||
|
||
if (hLibrary != NULL)
|
||
{
|
||
//
|
||
// Walk the linked list and process each element
|
||
//
|
||
|
||
QueuedEvent = CONTAINING_RECORD(QueuedMessageListHead.Flink,
|
||
struct _ELF_QUEUED_EVENT,
|
||
Next);
|
||
|
||
while (QueuedEvent->Next.Flink != QueuedMessageListHead.Flink)
|
||
{
|
||
ASSERT(QueuedEvent->Type == Message);
|
||
|
||
//
|
||
// Unlock the linked list -- normally not a safe thing since we're
|
||
// about to play with a pointer to an element in it, but:
|
||
//
|
||
// a. This is the only routine where a list item can be removed/deleted
|
||
//
|
||
// b. We don't touch the only potentially-volatile structure member
|
||
// (QueuedEvent->Next) until we're in the critsec again below
|
||
//
|
||
// c. Only one thread at a time executes this code (enforced by
|
||
// MBThreadHandle, which is only read/written inside the critsec)
|
||
//
|
||
RtlLeaveCriticalSection(&QueuedMessageCritSec);
|
||
|
||
//
|
||
// Build the array of pointers to the insertion strings
|
||
//
|
||
StringPointers =
|
||
(LPWSTR *) ElfpAllocateBuffer(QueuedEvent->Event.Message.NumberOfStrings
|
||
* sizeof(LPWSTR));
|
||
|
||
if (StringPointers)
|
||
{
|
||
//
|
||
// Build the array of pointers to the insertion string(s)
|
||
//
|
||
if (QueuedEvent->Event.Message.NumberOfStrings)
|
||
{
|
||
StringPointers[0] = (LPWSTR) ((PBYTE) &QueuedEvent->Event.Message +
|
||
sizeof(ELF_MESSAGE_RECORD));
|
||
|
||
for (i = 1;
|
||
i < QueuedEvent->Event.Message.NumberOfStrings;
|
||
i++)
|
||
{
|
||
StringPointers[i] = StringPointers[i-1]
|
||
+ wcslen(StringPointers[i - 1])
|
||
+ 1;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Call FormatMessage to build the message
|
||
//
|
||
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||
FORMAT_MESSAGE_FROM_HMODULE,
|
||
hLibrary,
|
||
QueuedEvent->Event.Message.MessageId,
|
||
0, // Default language ID
|
||
(LPWSTR) &MessageBuffer,
|
||
0, // Min # of bytes to allocate
|
||
(va_list *) StringPointers))
|
||
{
|
||
//
|
||
// Now actually display it
|
||
//
|
||
MessageBoxW(NULL,
|
||
(LPWSTR) MessageBuffer,
|
||
GlobalMessageBoxTitle,
|
||
MB_OK |
|
||
MB_SETFOREGROUND |
|
||
MB_ICONEXCLAMATION |
|
||
MB_SERVICE_NOTIFICATION);
|
||
|
||
LocalFree(MessageBuffer);
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfpSendMessage: FormatMessage failed %d\n",
|
||
GetLastError());
|
||
}
|
||
|
||
ElfpFreeBuffer(StringPointers);
|
||
}
|
||
|
||
//
|
||
// If we are shutting down, we need to break out of this loop
|
||
// and allow resources to be freed
|
||
//
|
||
if (ElState == STOPPING || ElState == STOPPED)
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"ElfpSendMessage: Aborting SendMessage since ElState is %ws\n",
|
||
(ElState == STOPPING ? L"STOPPING" :
|
||
L"STOPPED"));
|
||
|
||
FreeLibrary(hLibrary);
|
||
MBThreadHandle = NULL;
|
||
return 0;
|
||
}
|
||
|
||
RtlEnterCriticalSection (&QueuedMessageCritSec);
|
||
|
||
//
|
||
// Move to the next one, saving this one to delete it
|
||
//
|
||
FlushEvent = QueuedEvent;
|
||
|
||
QueuedEvent = CONTAINING_RECORD(QueuedEvent->Next.Flink,
|
||
struct _ELF_QUEUED_EVENT,
|
||
Next);
|
||
|
||
//
|
||
// Now remove this from the queue and free it if we successfully
|
||
// processed it
|
||
//
|
||
RemoveEntryList (&FlushEvent->Next);
|
||
}
|
||
|
||
FreeLibrary(hLibrary);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We couldn't load the message DLL -- leave the queued event
|
||
// on the list and try it the next time this thread spins up.
|
||
//
|
||
ELF_LOG1(ERROR,
|
||
"ElfpSendMessage: LoadLibraryEx of netmsg.dll failed %d\n",
|
||
GetLastError());
|
||
}
|
||
|
||
MBThreadHandle = NULL;
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection (&QueuedMessageCritSec);
|
||
|
||
ELF_LOG0(TRACE, "ElfpSendMessage: MessageBox thread exiting\n");
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
VOID
|
||
LinkQueuedMessage (
|
||
PELF_QUEUED_EVENT QueuedEvent
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine links the QueuedEvent specified into the linked list of
|
||
QueuedMessages. If there's not already a messagebox thread running,
|
||
it starts one.
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
QueuedEvent - The request to add from the linked list
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD ThreadId;
|
||
|
||
// Lock the linked list
|
||
|
||
RtlEnterCriticalSection(&QueuedMessageCritSec);
|
||
|
||
|
||
// Place structure at the end of the list.
|
||
|
||
InsertTailList(&QueuedMessageListHead, &QueuedEvent->Next);
|
||
|
||
if (!MBThreadHandle)
|
||
{
|
||
ELF_LOG0(TRACE,
|
||
"LinkQueuedMessage: Spinning up a MessageBox thread\n");
|
||
|
||
//
|
||
// Since the user can just let this sit on their screen,
|
||
// spin a thread for this
|
||
//
|
||
MBThreadHandle = CreateThread(NULL, // lpThreadAttributes
|
||
4096, // dwStackSize
|
||
ElfpSendMessage, // lpStartAddress
|
||
NULL, // lpParameter
|
||
0L, // dwCreationFlags
|
||
&ThreadId); // lpThreadId
|
||
}
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&QueuedMessageCritSec);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NotifyChange(
|
||
PLOGFILE pLogFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine runs the list of events that are registered with
|
||
ElfChangeNotify to be notified when a log has changed, and pulses
|
||
the event.
|
||
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use an exclusive resource.
|
||
|
||
Arguments:
|
||
|
||
LogHandle points to a context handle structure.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// How frequently will I try to pulse the events? How about every
|
||
// 5 seconds
|
||
//
|
||
|
||
#define MINIMUM_PULSE_TIME 5
|
||
|
||
PNOTIFIEE Notifiee;
|
||
LARGE_INTEGER Time;
|
||
ULONG CurrentTime = 0;
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// Get exclusive access to the log file. This will ensure no one
|
||
// else is accessing the file.
|
||
//
|
||
|
||
RtlAcquireResourceExclusive(&pLogFile->Resource,
|
||
TRUE); // Wait until available
|
||
|
||
//
|
||
// See if we've done this in the last MINIMUM_PULSE_TIME seconds
|
||
//
|
||
Status = NtQuerySystemTime(&Time);
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
RtlTimeToSecondsSince1970(&Time, &CurrentTime);
|
||
|
||
if (CurrentTime > pLogFile->ulLastPulseTime + MINIMUM_PULSE_TIME)
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"NotifyChange: Pulsing ChangeNotify events -- current time is %ul\n",
|
||
CurrentTime);
|
||
|
||
//
|
||
// Remember that we pulsed
|
||
//
|
||
pLogFile->ulLastPulseTime = CurrentTime;
|
||
|
||
//
|
||
// Walk the linked list and and pulse any events
|
||
//
|
||
Notifiee = CONTAINING_RECORD(pLogFile->Notifiees.Flink,
|
||
struct _NOTIFIEE,
|
||
Next);
|
||
|
||
while (Notifiee->Next.Flink != pLogFile->Notifiees.Flink)
|
||
{
|
||
//
|
||
// Pulse each event as we get to it.
|
||
//
|
||
NtPulseEvent(Notifiee->Event,NULL);
|
||
|
||
Notifiee = CONTAINING_RECORD(Notifiee->Next.Flink,
|
||
struct _NOTIFIEE,
|
||
Next);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"NotifyChange: NtQuerySystemTime failed %#x\n",
|
||
Status);
|
||
}
|
||
|
||
//
|
||
// Free the resource
|
||
//
|
||
RtlReleaseResource ( &pLogFile->Resource );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
WriteQueuedEvents(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine runs the list of queued events and writes them.
|
||
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use an exclusive resource.
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
--*/
|
||
{
|
||
PELF_QUEUED_EVENT QueuedEvent;
|
||
PELF_QUEUED_EVENT FlushEvent;
|
||
BOOLEAN bFlushEvent;
|
||
LARGE_INTEGER Time;
|
||
ULONG CurrentTime = 0;
|
||
|
||
static ULONG LastAlertTried = 0;
|
||
static BOOLEAN LastAlertFailed = FALSE;
|
||
|
||
// Lock the linked list, you must get the System Log File Resource
|
||
// first, it is the higher level lock
|
||
|
||
RtlAcquireResourceExclusive(&ElfModule->LogFile->Resource,
|
||
TRUE); // Wait until available
|
||
|
||
RtlEnterCriticalSection(&QueuedEventCritSec);
|
||
|
||
//
|
||
// Walk the linked list and process each element
|
||
//
|
||
QueuedEvent = CONTAINING_RECORD(QueuedEventListHead.Flink,
|
||
struct _ELF_QUEUED_EVENT,
|
||
Next);
|
||
|
||
while (QueuedEvent->Next.Flink != QueuedEventListHead.Flink)
|
||
{
|
||
//
|
||
// Default is to flush the event after processing
|
||
//
|
||
bFlushEvent = TRUE;
|
||
|
||
//
|
||
// Do the appropriate thing
|
||
//
|
||
if (QueuedEvent->Type == Event)
|
||
{
|
||
PerformWriteRequest(&QueuedEvent->Event.Request);
|
||
}
|
||
else if (QueuedEvent->Type == Alert)
|
||
{
|
||
//
|
||
// Don't even try to send failed alerts quicker than once a minute
|
||
//
|
||
NtQuerySystemTime(&Time);
|
||
RtlTimeToSecondsSince1970(&Time, &CurrentTime);
|
||
|
||
if (!LastAlertFailed || CurrentTime > LastAlertTried + 60)
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"WriteQueuedEvents: Sending alert -- current time is %ul\n",
|
||
CurrentTime);
|
||
|
||
LastAlertFailed =
|
||
|
||
!SendAdminAlert(QueuedEvent->Event.Alert.MessageId,
|
||
QueuedEvent->Event.Alert.NumberOfStrings,
|
||
(PUNICODE_STRING) ((PBYTE) QueuedEvent
|
||
+ FIELD_OFFSET(ELF_QUEUED_EVENT, Event)
|
||
+ sizeof(ELF_ALERT_RECORD)));
|
||
|
||
LastAlertTried = CurrentTime;
|
||
}
|
||
|
||
//
|
||
// Only try to write it for 5 minutes, then give up (the
|
||
// alerter service may not be configured to run)
|
||
//
|
||
if (LastAlertFailed
|
||
&&
|
||
QueuedEvent->Event.Alert.TimeOut > CurrentTime)
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"WriteQueuedEvents: Alert failed -- will retry until timeout at %ul\n",
|
||
QueuedEvent->Event.Alert.TimeOut);
|
||
|
||
bFlushEvent = FALSE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Move to the next one, saving this one to delete it
|
||
//
|
||
FlushEvent = QueuedEvent;
|
||
|
||
QueuedEvent = CONTAINING_RECORD(QueuedEvent->Next.Flink,
|
||
struct _ELF_QUEUED_EVENT,
|
||
Next);
|
||
|
||
//
|
||
// Now remove this from the queue and free it if we successfully
|
||
// processed it
|
||
//
|
||
if (bFlushEvent)
|
||
{
|
||
UnlinkQueuedEvent(FlushEvent);
|
||
ElfpFreeBuffer(FlushEvent);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&QueuedEventCritSec);
|
||
RtlReleaseResource(&ElfModule->LogFile->Resource);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
FlushQueuedEvents(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine runs the list of queued events and frees them.
|
||
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use an exclusive resource.
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
--*/
|
||
{
|
||
|
||
PELF_QUEUED_EVENT QueuedEvent;
|
||
PELF_QUEUED_EVENT FlushEvent;
|
||
|
||
// Lock the linked list
|
||
|
||
RtlEnterCriticalSection(&QueuedEventCritSec);
|
||
|
||
//
|
||
// Walk the linked list and and free the memory for any events
|
||
//
|
||
QueuedEvent = CONTAINING_RECORD(QueuedEventListHead.Flink,
|
||
struct _ELF_QUEUED_EVENT,
|
||
Next);
|
||
|
||
while (QueuedEvent->Next.Flink != QueuedEventListHead.Flink)
|
||
{
|
||
//
|
||
// Free each event as we get to it.
|
||
//
|
||
FlushEvent = QueuedEvent;
|
||
|
||
QueuedEvent = CONTAINING_RECORD(QueuedEvent->Next.Flink,
|
||
struct _ELF_QUEUED_EVENT,
|
||
Next);
|
||
|
||
ElfpFreeBuffer(FlushEvent);
|
||
}
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&QueuedEventCritSec);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
UnlinkLogModule(
|
||
PLOGMODULE LogModule
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine unlinks the LogModule specified from the linked list.
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
LogModule points to a context handle structure.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&LogModuleCritSec);
|
||
|
||
//
|
||
// Remove this entry
|
||
//
|
||
RemoveEntryList(&LogModule->ModuleList);
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&LogModuleCritSec);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
LinkLogModule (
|
||
PLOGMODULE LogModule,
|
||
ANSI_STRING * pModuleNameA
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine links the LogModule specified into the linked list.
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
LogModule points to a context handle structure.
|
||
ANSI LogModule name.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&LogModuleCritSec);
|
||
|
||
//
|
||
// Add the atom for this module.
|
||
//
|
||
LogModule->ModuleAtom = AddAtomA(pModuleNameA->Buffer);
|
||
|
||
//
|
||
// Place structure at the beginning of the list.
|
||
//
|
||
InsertHeadList(&LogModuleHead, &LogModule->ModuleList);
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&LogModuleCritSec);
|
||
}
|
||
|
||
|
||
VOID
|
||
UnlinkLogFile(
|
||
PLOGFILE pLogFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine unlinks the LogFile structure specified from the linked
|
||
list of log files;
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
pLogFile points to a log file structure.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&LogFileCritSec);
|
||
|
||
//
|
||
// Remove this entry
|
||
//
|
||
RemoveEntryList(&pLogFile->FileList);
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&LogFileCritSec);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
LinkLogFile (
|
||
PLOGFILE pLogFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine links the LogFile specified into the linked list of
|
||
log files.
|
||
In order to protect against multiple thread/process access to the
|
||
list at the same time, we use a critical section.
|
||
|
||
Arguments:
|
||
|
||
pLogFile points to a context handle structure.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&LogFileCritSec);
|
||
|
||
//
|
||
// Place structure at the beginning of the list.
|
||
//
|
||
InsertHeadList(&LogFilesHead, &pLogFile->FileList);
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&LogFileCritSec);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
GetGlobalResource (
|
||
DWORD Type
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes the global resource either for shared access or
|
||
exclusive access depending on the value of Type. It waits forever for
|
||
the resource to become available.
|
||
|
||
Arguments:
|
||
|
||
Type is one of ELF_GLOBAL_SHARED or ELF_GLOBAL_EXCLUSIVE.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
BOOL Acquired;
|
||
|
||
if (Type & ELF_GLOBAL_SHARED)
|
||
{
|
||
Acquired = RtlAcquireResourceShared(&GlobalElfResource,
|
||
TRUE); // Wait forever
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Assume EXCLUSIVE
|
||
//
|
||
Acquired = RtlAcquireResourceExclusive(&GlobalElfResource,
|
||
TRUE); // Wait forever
|
||
}
|
||
|
||
ASSERT(Acquired); // This must always be TRUE.
|
||
}
|
||
|
||
|
||
VOID
|
||
ReleaseGlobalResource(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine releases the global resource.
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
RtlReleaseResource(&GlobalElfResource);
|
||
}
|
||
|
||
|
||
VOID
|
||
InvalidateContextHandlesForLogFile(
|
||
PLOGFILE pLogFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine walks through the context handles and marks the ones
|
||
that point to the LogFile passed in as "invalid for read".
|
||
|
||
Arguments:
|
||
|
||
Pointer to log file structure.
|
||
|
||
Return Value:
|
||
|
||
NONE.
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
IELF_HANDLE LogHandle;
|
||
PLOGMODULE pLogModule;
|
||
|
||
//
|
||
// Lock the context handle list
|
||
//
|
||
RtlEnterCriticalSection(&LogHandleCritSec);
|
||
|
||
//
|
||
// Walk the linked list and mark any matching context handles as
|
||
// invalid.
|
||
//
|
||
LogHandle = CONTAINING_RECORD(LogHandleListHead.Flink,
|
||
struct _IELF_HANDLE,
|
||
Next);
|
||
|
||
|
||
while (LogHandle->Next.Flink != LogHandleListHead.Flink)
|
||
{
|
||
pLogModule = FindModuleStrucFromAtom(LogHandle->Atom);
|
||
|
||
ASSERT(pLogModule);
|
||
|
||
if (pLogModule && (pLogFile == pLogModule->LogFile))
|
||
{
|
||
LogHandle->Flags |= ELF_LOG_HANDLE_INVALID_FOR_READ;
|
||
}
|
||
|
||
LogHandle = CONTAINING_RECORD(LogHandle->Next.Flink,
|
||
struct _IELF_HANDLE,
|
||
Next);
|
||
}
|
||
|
||
//
|
||
// Unlock the context handle list
|
||
//
|
||
RtlLeaveCriticalSection(&LogHandleCritSec);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
FixContextHandlesForRecord(
|
||
DWORD RecordOffset,
|
||
DWORD NewRecordOffset
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine makes sure that the record starting at RecordOffset isn't
|
||
the current record for any open handle. If it is, the handle is adjusted
|
||
to point to the next record.
|
||
|
||
Arguments:
|
||
|
||
RecordOffset - The byte offset in the log of the record that is about
|
||
to be overwritten.
|
||
NewStartingRecord - The new location to point the handle to (this is the
|
||
new first record)
|
||
|
||
Return Value:
|
||
|
||
NONE.
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
IELF_HANDLE LogHandle;
|
||
|
||
//
|
||
// Lock the context handle list
|
||
//
|
||
RtlEnterCriticalSection(&LogHandleCritSec);
|
||
|
||
//
|
||
// Walk the linked list and fix any matching context handles
|
||
//
|
||
LogHandle = CONTAINING_RECORD(LogHandleListHead.Flink,
|
||
struct _IELF_HANDLE,
|
||
Next);
|
||
|
||
while (LogHandle->Next.Flink != LogHandleListHead.Flink)
|
||
{
|
||
if (LogHandle->SeekBytePos == RecordOffset)
|
||
{
|
||
LogHandle->SeekBytePos = NewRecordOffset;
|
||
}
|
||
|
||
LogHandle = CONTAINING_RECORD(LogHandle->Next.Flink,
|
||
struct _IELF_HANDLE,
|
||
Next);
|
||
}
|
||
|
||
//
|
||
// Unlock the context handle list
|
||
//
|
||
RtlLeaveCriticalSection(&LogHandleCritSec);
|
||
}
|
||
|
||
|
||
PLOGFILE
|
||
FindLogFileFromName(
|
||
PUNICODE_STRING pFileName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine looks at all the log files to find one that matches
|
||
the name passed in.
|
||
|
||
Arguments:
|
||
|
||
Pointer to name of file.
|
||
|
||
Return Value:
|
||
|
||
Matching LOGFILE structure if file in use.
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
PLOGFILE pLogFile;
|
||
|
||
//
|
||
// Lock the linked list
|
||
//
|
||
RtlEnterCriticalSection(&LogFileCritSec);
|
||
|
||
pLogFile = CONTAINING_RECORD(LogFilesHead.Flink,
|
||
LOGFILE,
|
||
FileList);
|
||
|
||
while (pLogFile->FileList.Flink != LogFilesHead.Flink)
|
||
{
|
||
//
|
||
// BUGBUG: This should probably be _wcsicmp() since the log module
|
||
// names are assumed to be case insensitive (so the log
|
||
// file names should be as well else we can get weirdness
|
||
// with overlapping module names if somebody creates a log
|
||
// named something like "application" or "system")
|
||
//
|
||
if (wcscmp(pLogFile->LogFileName->Buffer, pFileName->Buffer) == 0)
|
||
break;
|
||
|
||
pLogFile = CONTAINING_RECORD(pLogFile->FileList.Flink,
|
||
LOGFILE,
|
||
FileList);
|
||
}
|
||
|
||
//
|
||
// Unlock the linked list
|
||
//
|
||
RtlLeaveCriticalSection(&LogFileCritSec);
|
||
|
||
return (pLogFile->FileList.Flink == LogFilesHead.Flink ? NULL : pLogFile);
|
||
}
|
||
|
||
|
||
#define ELF_MODULE_NAME L"EventLog"
|
||
#define ELFSEC_MODULE_NAME L"SECURITY"
|
||
|
||
VOID
|
||
ElfpCreateElfEvent(
|
||
IN ULONG EventId,
|
||
IN USHORT EventType,
|
||
IN USHORT EventCategory,
|
||
IN USHORT NumStrings,
|
||
IN LPWSTR * Strings,
|
||
IN LPVOID Data,
|
||
IN ULONG DataSize,
|
||
IN USHORT Flags,
|
||
IN BOOL ForSecurity
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This creates an request packet to write an event on behalf of the event
|
||
log service itself. It then queues this packet to a linked list for
|
||
writing later.
|
||
|
||
Arguments:
|
||
|
||
The fields to use to create the event record
|
||
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
PELF_QUEUED_EVENT QueuedEvent;
|
||
PWRITE_PKT WritePkt;
|
||
PEVENTLOGRECORD EventLogRecord;
|
||
PBYTE BinaryData;
|
||
ULONG RecordLength;
|
||
ULONG StringOffset, DataOffset;
|
||
USHORT StringsSize = 0;
|
||
USHORT i;
|
||
ULONG PadSize;
|
||
ULONG ModuleNameLen; // Length in bytes
|
||
ULONG zero = 0; // For pad bytes
|
||
LARGE_INTEGER Time;
|
||
ULONG LogTimeWritten;
|
||
PWSTR ReplaceStrings;
|
||
WCHAR LocalComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
||
ULONG ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
|
||
BOOL bOK;
|
||
LPWSTR pwcModule;
|
||
|
||
if(ForSecurity)
|
||
pwcModule = ELFSEC_MODULE_NAME;
|
||
else
|
||
pwcModule = ELF_MODULE_NAME;
|
||
|
||
// Get the computer name
|
||
|
||
bOK = GetComputerNameW(LocalComputerName, &ComputerNameLength);
|
||
if(bOK == FALSE)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfpCreateElfEvent: failed calling GetComputerNameW, last error 0x%x\n",
|
||
GetLastError());
|
||
return;
|
||
}
|
||
ComputerNameLength = (ComputerNameLength+1)*sizeof(WCHAR);
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfpCreateElfEvent: Logging event ID %d\n",
|
||
EventId);
|
||
|
||
//
|
||
// LogTimeWritten
|
||
// We need to generate a time when the log is written. This
|
||
// gets written in the log so that we can use it to test the
|
||
// retention period when wrapping the file.
|
||
//
|
||
NtQuerySystemTime(&Time);
|
||
RtlTimeToSecondsSince1970(&Time,
|
||
&LogTimeWritten);
|
||
|
||
//
|
||
// Figure out how big a buffer to allocate
|
||
//
|
||
ModuleNameLen = (wcslen(pwcModule) + 1) * sizeof (WCHAR);
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfpCreateElfEvent: Length of module name is %d\n",
|
||
ModuleNameLen);
|
||
|
||
StringOffset = sizeof(EVENTLOGRECORD)
|
||
+ ModuleNameLen
|
||
+ ComputerNameLength;
|
||
|
||
//
|
||
// Calculate the length of strings so that we can see how
|
||
// much space is needed for that.
|
||
//
|
||
for (i = 0; i < NumStrings; i++)
|
||
{
|
||
StringsSize += wcslen(Strings[i]) + 1;
|
||
|
||
ELF_LOG2(TRACE,
|
||
"ElfpCreateElfEvent: Length of string %d (including NULL) is %d\n",
|
||
i,
|
||
wcslen(Strings[i]) + 1);
|
||
}
|
||
|
||
//
|
||
// DATA OFFSET:
|
||
//
|
||
DataOffset = StringOffset + StringsSize * sizeof(WCHAR);
|
||
|
||
//
|
||
// Determine how big a buffer is needed for the queued event record.
|
||
//
|
||
RecordLength = sizeof(ELF_QUEUED_EVENT)
|
||
+ sizeof(WRITE_PKT)
|
||
+ DataOffset
|
||
+ DataSize
|
||
+ sizeof(RecordLength); // Size excluding pad bytes
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfpCreateElfEvent: RecordLength (no pad bytes) is %d\n",
|
||
RecordLength);
|
||
|
||
//
|
||
// Determine how many pad bytes are needed to align to a DWORD
|
||
// boundary.
|
||
//
|
||
PadSize = sizeof(ULONG) - (RecordLength % sizeof(ULONG));
|
||
|
||
RecordLength += PadSize; // True size needed
|
||
|
||
ELF_LOG2(TRACE,
|
||
"ElfpCreateElfEvent: RecordLength (with %d pad bytes) is %d\n",
|
||
PadSize,
|
||
RecordLength);
|
||
|
||
//
|
||
// Allocate the buffer for the Eventlog record
|
||
//
|
||
QueuedEvent = (PELF_QUEUED_EVENT) ElfpAllocateBuffer(RecordLength);
|
||
|
||
WritePkt = (PWRITE_PKT) (QueuedEvent + 1);
|
||
|
||
if (QueuedEvent != NULL)
|
||
{
|
||
//
|
||
// Fill up the event record
|
||
//
|
||
RecordLength -= (sizeof(ELF_QUEUED_EVENT) + sizeof(WRITE_PKT));
|
||
EventLogRecord = (PEVENTLOGRECORD) (WritePkt + 1);
|
||
|
||
EventLogRecord->Length = RecordLength;
|
||
EventLogRecord->TimeGenerated = LogTimeWritten;
|
||
EventLogRecord->Reserved = ELF_LOG_FILE_SIGNATURE;
|
||
EventLogRecord->TimeWritten = LogTimeWritten;
|
||
EventLogRecord->EventID = EventId;
|
||
EventLogRecord->EventType = EventType;
|
||
EventLogRecord->EventCategory = EventCategory;
|
||
EventLogRecord->ReservedFlags = 0;
|
||
EventLogRecord->ClosingRecordNumber = 0;
|
||
EventLogRecord->NumStrings = NumStrings;
|
||
EventLogRecord->StringOffset = StringOffset;
|
||
EventLogRecord->DataLength = DataSize;
|
||
EventLogRecord->DataOffset = DataOffset;
|
||
EventLogRecord->UserSidLength = 0;
|
||
EventLogRecord->UserSidOffset = StringOffset;
|
||
|
||
//
|
||
// Fill in the variable-length fields
|
||
//
|
||
|
||
//
|
||
// STRINGS
|
||
//
|
||
ReplaceStrings = (PWSTR) ((PBYTE) EventLogRecord
|
||
+ StringOffset);
|
||
|
||
for (i = 0; i < NumStrings; i++)
|
||
{
|
||
ELF_LOG2(TRACE,
|
||
"ElfpCreateElfEvent: Copying string %d (%ws) into record\n",
|
||
i,
|
||
Strings[i]);
|
||
|
||
wcscpy(ReplaceStrings, Strings[i]);
|
||
ReplaceStrings += wcslen(Strings[i]) + 1;
|
||
}
|
||
|
||
//
|
||
// MODULENAME
|
||
//
|
||
BinaryData = (PBYTE) EventLogRecord + sizeof(EVENTLOGRECORD);
|
||
|
||
RtlCopyMemory(BinaryData,
|
||
pwcModule,
|
||
ModuleNameLen);
|
||
|
||
//
|
||
// COMPUTERNAME
|
||
//
|
||
BinaryData += ModuleNameLen; // Now point to computername
|
||
|
||
RtlCopyMemory(BinaryData,
|
||
LocalComputerName,
|
||
ComputerNameLength);
|
||
|
||
//
|
||
// BINARY DATA
|
||
//
|
||
BinaryData = (PBYTE) ((PBYTE) EventLogRecord + DataOffset);
|
||
RtlCopyMemory(BinaryData, Data, DataSize);
|
||
|
||
//
|
||
// PAD - Fill with zeros
|
||
//
|
||
BinaryData += DataSize;
|
||
RtlCopyMemory(BinaryData, &zero, PadSize);
|
||
|
||
//
|
||
// LENGTH at end of record
|
||
//
|
||
BinaryData += PadSize; // Point after pad bytes
|
||
((PULONG) BinaryData)[0] = RecordLength;
|
||
|
||
//
|
||
// Build the QueuedEvent Packet
|
||
//
|
||
QueuedEvent->Type = Event;
|
||
|
||
QueuedEvent->Event.Request.Pkt.WritePkt = WritePkt;
|
||
if(ForSecurity)
|
||
{
|
||
QueuedEvent->Event.Request.Module = ElfSecModule;
|
||
QueuedEvent->Event.Request.LogFile = ElfSecModule->LogFile;
|
||
}
|
||
else
|
||
{
|
||
if(ElfModule)
|
||
{
|
||
QueuedEvent->Event.Request.Module = ElfModule;
|
||
QueuedEvent->Event.Request.LogFile = ElfModule->LogFile;
|
||
}
|
||
else
|
||
{
|
||
QueuedEvent->Event.Request.Module = NULL;
|
||
QueuedEvent->Event.Request.LogFile = NULL;
|
||
}
|
||
}
|
||
QueuedEvent->Event.Request.Flags = Flags;
|
||
QueuedEvent->Event.Request.Command = ELF_COMMAND_WRITE;
|
||
QueuedEvent->Event.Request.Pkt.WritePkt->Buffer = EventLogRecord;
|
||
QueuedEvent->Event.Request.Pkt.WritePkt->Datasize = RecordLength;
|
||
|
||
//
|
||
// Now Queue it on the linked list
|
||
//
|
||
LinkQueuedEvent(QueuedEvent);
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfpCreateElfEvent: Unable to allocate memory for QueuedEvent\n");
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
ElfpCreateQueuedAlert(
|
||
DWORD MessageId,
|
||
DWORD NumberOfStrings,
|
||
LPWSTR Strings[]
|
||
)
|
||
{
|
||
DWORD i;
|
||
DWORD RecordLength;
|
||
PELF_QUEUED_EVENT QueuedEvent;
|
||
PUNICODE_STRING UnicodeStrings;
|
||
LPWSTR pString;
|
||
PBYTE ptr;
|
||
LARGE_INTEGER Time;
|
||
ULONG CurrentTime;
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfpCreateQueuedAlert: Creating alert for message ID %d\n",
|
||
MessageId);
|
||
|
||
//
|
||
// Turn the input strings into UNICODE_STRINGS and figure out how
|
||
// big to make the buffer to allocate
|
||
//
|
||
RecordLength = sizeof(UNICODE_STRING) * NumberOfStrings;
|
||
UnicodeStrings = ElfpAllocateBuffer(RecordLength);
|
||
|
||
if (!UnicodeStrings)
|
||
{
|
||
ELF_LOG0(TRACE,
|
||
"ElfpCreateQueuedAlert: Unable to allocate memory for UnicodeStrings\n");
|
||
|
||
return;
|
||
}
|
||
|
||
RecordLength += FIELD_OFFSET(ELF_QUEUED_EVENT, Event) +
|
||
sizeof(ELF_ALERT_RECORD);
|
||
|
||
for (i = 0; i < NumberOfStrings; i++)
|
||
{
|
||
RtlInitUnicodeString(&UnicodeStrings[i], Strings[i]);
|
||
RecordLength += UnicodeStrings[i].MaximumLength;
|
||
|
||
ELF_LOG2(TRACE,
|
||
"ElfpCreateQueuedAlert: Length of string %d is %d\n",
|
||
i,
|
||
UnicodeStrings[i].MaximumLength);
|
||
}
|
||
|
||
//
|
||
// Now allocate what will be the real queued event
|
||
//
|
||
|
||
QueuedEvent = ElfpAllocateBuffer(RecordLength);
|
||
|
||
if (!QueuedEvent)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfpCreateQueuedAlert: Unable to allocate memory for QueuedEvent\n");
|
||
|
||
ElfpFreeBuffer(UnicodeStrings);
|
||
return;
|
||
}
|
||
|
||
QueuedEvent->Type = Alert;
|
||
|
||
QueuedEvent->Event.Alert.MessageId = MessageId;
|
||
QueuedEvent->Event.Alert.NumberOfStrings = NumberOfStrings;
|
||
|
||
//
|
||
// If we can't send the alert in 5 minutes, give up
|
||
//
|
||
NtQuerySystemTime(&Time);
|
||
RtlTimeToSecondsSince1970(&Time, &CurrentTime);
|
||
|
||
QueuedEvent->Event.Alert.TimeOut = CurrentTime + 300;
|
||
|
||
//
|
||
// Move the array of UNICODE_STRINGS into the queued event and
|
||
// point UnicodeStrings at it. Then fix up the Buffer pointers.
|
||
//
|
||
ptr = (PBYTE) QueuedEvent
|
||
+ FIELD_OFFSET(ELF_QUEUED_EVENT, Event)
|
||
+ sizeof(ELF_ALERT_RECORD);
|
||
|
||
RtlCopyMemory(ptr,
|
||
UnicodeStrings,
|
||
sizeof(UNICODE_STRING) * NumberOfStrings);
|
||
|
||
ElfpFreeBuffer(UnicodeStrings);
|
||
UnicodeStrings = (PUNICODE_STRING) ptr;
|
||
|
||
pString = (LPWSTR) (ptr + sizeof(UNICODE_STRING) * NumberOfStrings);
|
||
|
||
for (i = 0; i < NumberOfStrings; i++)
|
||
{
|
||
ELF_LOG3(TRACE,
|
||
"ElfpCreateQueuedAlert: Copying string %d (%*ws) into QueuedEvent record\n",
|
||
i,
|
||
UnicodeStrings[i].MaximumLength / sizeof(WCHAR),
|
||
UnicodeStrings[i].Buffer);
|
||
|
||
RtlCopyMemory(pString,
|
||
UnicodeStrings[i].Buffer,
|
||
UnicodeStrings[i].MaximumLength);
|
||
|
||
UnicodeStrings[i].Buffer = pString;
|
||
|
||
pString = (LPWSTR) ((PBYTE) pString + UnicodeStrings[i].MaximumLength);
|
||
}
|
||
|
||
LinkQueuedEvent(QueuedEvent);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ElfpCreateQueuedMessage(
|
||
DWORD MessageId,
|
||
DWORD NumberOfStrings,
|
||
LPWSTR Strings[]
|
||
)
|
||
{
|
||
DWORD i;
|
||
DWORD RecordLength = 0;
|
||
PELF_QUEUED_EVENT QueuedEvent;
|
||
LPWSTR pString;
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfpCreateQueuedMessage: Creating message for message ID %d\n",
|
||
MessageId);
|
||
|
||
//
|
||
// Figure out how big to make the buffer to allocate
|
||
//
|
||
RecordLength = sizeof(ELF_QUEUED_EVENT);
|
||
|
||
for (i = 0; i < NumberOfStrings; i++)
|
||
{
|
||
RecordLength += (wcslen(Strings[i]) + 1) * sizeof(WCHAR);
|
||
|
||
ELF_LOG2(TRACE,
|
||
"ElfpCreateQueuedMessage: Length of string %d (including NULL) is %d\n",
|
||
i,
|
||
wcslen(Strings[i]) + 1);
|
||
}
|
||
|
||
//
|
||
// Now allocate what will be the real queued event
|
||
//
|
||
QueuedEvent = ElfpAllocateBuffer(RecordLength);
|
||
|
||
if (!QueuedEvent)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfpCreateQueuedMessage: Unable to allocate memory for QueuedEvent\n");
|
||
|
||
return;
|
||
}
|
||
|
||
QueuedEvent->Type = Message;
|
||
|
||
QueuedEvent->Event.Message.MessageId = MessageId;
|
||
QueuedEvent->Event.Message.NumberOfStrings = NumberOfStrings;
|
||
|
||
//
|
||
// Move the array of UNICODE strings into the queued event
|
||
//
|
||
|
||
pString = (LPWSTR) ((PBYTE) QueuedEvent
|
||
+ FIELD_OFFSET(ELF_QUEUED_EVENT, Event)
|
||
+ sizeof(ELF_MESSAGE_RECORD));
|
||
|
||
for (i = 0; i < NumberOfStrings; i++)
|
||
{
|
||
wcscpy(pString, Strings[i]);
|
||
pString += wcslen(Strings[i]) + 1;
|
||
|
||
ELF_LOG2(TRACE,
|
||
"ElfpCreateQueuedMessage: Copying string %d (%ws) into QueuedEvent buffer\n",
|
||
i,
|
||
Strings[i]);
|
||
}
|
||
|
||
LinkQueuedMessage(QueuedEvent);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ElfpInitCriticalSection(
|
||
PRTL_CRITICAL_SECTION pCritsec
|
||
)
|
||
{
|
||
NTSTATUS ntStatus;
|
||
|
||
//
|
||
// RtlInitializeCriticalSection will raise an exception
|
||
// if it runs out of resources
|
||
//
|
||
|
||
try
|
||
{
|
||
ntStatus = RtlInitializeCriticalSection(pCritsec);
|
||
|
||
if (!NT_SUCCESS(ntStatus))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfpInitCriticalSection: RtlInitializeCriticalSection failed %#x\n",
|
||
ntStatus);
|
||
}
|
||
}
|
||
except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfpInitCriticalSection: Exception %#x caught initializing critsec\n",
|
||
GetExceptionCode());
|
||
|
||
ntStatus = STATUS_NO_MEMORY;
|
||
}
|
||
|
||
return ntStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ElfpInitResource(
|
||
PRTL_RESOURCE pResource
|
||
)
|
||
{
|
||
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||
|
||
//
|
||
// RtlInitializeResource will raise an exception
|
||
// if it runs out of resources
|
||
//
|
||
|
||
try
|
||
{
|
||
RtlInitializeResource(pResource);
|
||
}
|
||
except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfpInitResource: Exception %#x caught initializing resource\n",
|
||
GetExceptionCode());
|
||
|
||
ntStatus = STATUS_NO_MEMORY;
|
||
}
|
||
|
||
return ntStatus;
|
||
}
|