summaryrefslogtreecommitdiffstats
path: root/private/eventlog/server/elflpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/eventlog/server/elflpc.c')
-rw-r--r--private/eventlog/server/elflpc.c774
1 files changed, 774 insertions, 0 deletions
diff --git a/private/eventlog/server/elflpc.c b/private/eventlog/server/elflpc.c
new file mode 100644
index 000000000..36ad8bb83
--- /dev/null
+++ b/private/eventlog/server/elflpc.c
@@ -0,0 +1,774 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ELFLPC.C
+
+Abstract:
+
+ This file contains the routines that deal with the LPC port in the
+ eventlog service.
+
+Author:
+
+ Rajen Shah (rajens) 10-Jul-1991
+
+Revision History:
+
+
+
+--*/
+
+//
+// INCLUDES
+//
+
+#include <eventp.h>
+#include <ntiolog.h> // For IO_ERROR_LOG_[MESSAGE/PACKET]
+#include <elflpc.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <elfextrn.h> // Computername
+
+#include <nt.h> // DbgPrint prototype
+#include <ntrtl.h> // DbgPrint prototype
+#include <ntdef.h>
+#include <ntstatus.h>
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windef.h>
+#include <winbase.h> // LocalAlloc
+#include <lmcons.h>
+#include <string.h>
+#include <lmerr.h>
+
+NTSTATUS
+SetUpLPCPort ()
+
+
+/*++
+
+Routine Description:
+
+ This routine sets up the LPC port for the service.
+
+
+Arguments:
+
+
+
+Return Value:
+
+
+
+Note:
+
+
+--*/
+{
+
+ NTSTATUS status;
+ UNICODE_STRING unicodePortName;
+ OBJECT_ATTRIBUTES objectAttributes;
+ PORT_MESSAGE connectionRequest;
+
+
+ ElfDbgPrint (("[ELF] Set up LPC port\n"));
+
+ // Initialize the handles to zero so that we can determine what to do
+ // if we need to clean up.
+
+ ElfConnectionPortHandle = NULL;
+ ElfCommunicationPortHandle = NULL;
+
+ //
+ // Create the LPC port.
+ //
+ RtlInitUnicodeString( &unicodePortName, ELF_PORT_NAME_U );
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &unicodePortName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ status = NtCreatePort(
+ &ElfConnectionPortHandle,
+ &objectAttributes,
+ 0,
+ ELF_PORT_MAX_MESSAGE_LENGTH,
+ ELF_PORT_MAX_MESSAGE_LENGTH * 32
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ ElfDbgPrintNC(( "[ELF] Port not created\n" ));
+ goto exit;
+ }
+
+ //
+ // Start listening for the system thread's connection to the port. Note
+ // that it is OK if it happens to call NtConnectPort first--it will
+ // simply block until this call to NtListenPort occurs.
+ //
+ ElfDbgPrint(( "[ELF] Listening to port.\n" ));
+
+ connectionRequest.u1.s1.TotalLength = sizeof(connectionRequest);
+ connectionRequest.u1.s1.DataLength = (CSHORT)0;
+ status = NtListenPort(
+ ElfConnectionPortHandle,
+ &connectionRequest
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ ElfDbgPrintNC(( "[ELF] NtListenPort failed: %X\n", status ));
+ goto exit;
+ }
+
+ //
+ // The system thread has initiated the connection. Accept the connection.
+ //
+ // BUGBUG We need some security check here.
+ //
+ ElfDbgPrint(( "[ELF] Accepting connection to port.\n" ));
+
+ status = NtAcceptConnectPort(
+ &ElfCommunicationPortHandle,
+ NULL, // PortContext
+ &connectionRequest,
+ TRUE, // AcceptConnection
+ NULL, // ServerView
+ NULL // ClientView
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ ElfDbgPrintNC(( "[ELF] NtAcceptConnectPort failed: %X\n", status ));
+ goto exit;
+ }
+
+
+ //
+ // Complete the connection to the port, thereby releasing the system
+ // thread waiting in NtConnectPort.
+ //
+
+ ElfDbgPrint(( "[ELF] Completing connection to port.\n" ));
+
+ status = NtCompleteConnectPort( ElfCommunicationPortHandle );
+
+ if ( !NT_SUCCESS(status) ) {
+ ElfDbgPrintNC(( "[ELF] NtCompleteConnectPort failed: %X\n",
+ status ));
+ goto exit;
+ }
+
+exit:
+
+ //
+ // Close open handles and shut down if necessary.
+ //
+
+ if ( !NT_SUCCESS(status) && ElfConnectionPortHandle != NULL ) {
+ NtClose( ElfConnectionPortHandle );
+ }
+
+ if ( !NT_SUCCESS(status) && ElfCommunicationPortHandle != NULL ) {
+ NtClose( ElfConnectionPortHandle );
+ }
+
+ return(status);
+
+}
+
+
+
+NTSTATUS
+ElfProcessLPCPacket ( PIO_ERROR_LOG_MESSAGE pIoErrorLogMessage
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes the packet received from the LPC port and processes it.
+ The only thing that comes in thru the LPC port are packets generated by
+ device drivers and written to this port by the IO Subsystem. The packet is
+ an IO_ERROR_LOG_MESSAGE. The logfile will be system, the module name will
+ be the driver that generated the packet, the SID will always be NULL and
+ there will always be one string, which will be the device name.
+
+ It extracts the information from the LPC packet, and then calls the
+ common routine to do the work of formatting the data into
+ an event record and writing it out to the log file.
+
+
+Arguments:
+
+ pIoErrorLogMessage - Pointer to the data portion of the packet just
+ received through the LPC port.
+
+
+Return Value:
+
+ Status of this operation.
+
+
+--*/
+
+{
+ static PLOGMODULE SystemModule = NULL;
+
+ NTSTATUS status;
+ ELF_REQUEST_RECORD Request;
+ WRITE_PKT WritePkt;
+
+ UNICODE_STRING SystemString;
+ ULONG RecordLength;
+ PEVENTLOGRECORD EventLogRecord;
+ LPWSTR DestinationString, SourceString;
+ PBYTE BinaryData;
+ ULONG PadSize;
+ LARGE_INTEGER Time;
+ ULONG TimeWritten;
+ PULONG pEndLength;
+ ULONG i = 0;
+ PWCHAR pwch;
+ PWCHAR pwStart;
+ PWCHAR pwEnd;
+ ULONG StringLength;
+
+ try {
+
+ //
+ // Validate the packet, First make sure there are the correct
+ // number of NULL terminated strings, and remember the
+ // total number of bytes to copy
+ //
+
+ pwStart = pwch = (PWCHAR) ((PBYTE) pIoErrorLogMessage +
+ pIoErrorLogMessage->EntryData.StringOffset);
+
+ pwEnd = (PWCHAR) ((PBYTE) pIoErrorLogMessage +
+ pIoErrorLogMessage->Size);
+
+ while (pwch < pwEnd &&
+ i < pIoErrorLogMessage->EntryData.NumberOfStrings) {
+ if (*pwch == L'\0') {
+ i++;
+ }
+ pwch++;
+ }
+ StringLength = (pwch - pwStart) * sizeof(WCHAR);
+
+ //
+ // Now make sure everything in the packet is true
+ //
+
+ if ((i != pIoErrorLogMessage->EntryData.NumberOfStrings)
+
+ ||
+
+ (pIoErrorLogMessage->DriverNameOffset +
+ pIoErrorLogMessage->DriverNameLength >=
+ pIoErrorLogMessage->Size)
+
+ ||
+
+
+ (pIoErrorLogMessage->EntryData.StringOffset >=
+ pIoErrorLogMessage->Size)
+
+ ||
+
+ (FIELD_OFFSET(IO_ERROR_LOG_MESSAGE, EntryData) +
+ FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) +
+ pIoErrorLogMessage->EntryData.DumpDataSize >=
+ pIoErrorLogMessage->Size)) {
+
+ //
+ // It's a bad packet, log it and return
+ //
+
+ ElfDbgPrintNC(("[ELF] Bad packet from LPC port\n"));
+ ElfpCreateElfEvent(EVENT_BadDriverPacket,
+ EVENTLOG_ERROR_TYPE,
+ 0, // EventCategory
+ 0, // NumberOfStrings
+ NULL, // Strings
+ pIoErrorLogMessage, // Data
+ pIoErrorLogMessage->Size, // Datalength
+ 0 // flags
+ );
+ return(STATUS_UNSUCCESSFUL);
+ }
+ }
+ except (EXCEPTION_EXECUTE_HANDLER) {
+
+ //
+ // It's a bad packet, log it and return
+ //
+
+ ElfDbgPrintNC(("[ELF] Bad packet from LPC port\n"));
+ ElfpCreateElfEvent(EVENT_BadDriverPacket,
+ EVENTLOG_ERROR_TYPE,
+ 0, // EventCategory
+ 0, // NumberOfStrings
+ NULL, // Strings
+ pIoErrorLogMessage, // Data
+ pIoErrorLogMessage->Size, // Datalength
+ 0 // flags
+ );
+ return(STATUS_UNSUCCESSFUL);
+
+ }
+
+ //
+ // We're going to need this everytime, so just get it once
+ //
+
+ if (!SystemModule) {
+
+ //
+ // Get the system module to log driver events
+ //
+
+ RtlInitUnicodeString(&SystemString, ELF_SYSTEM_MODULE_NAME);
+ SystemModule = GetModuleStruc (&SystemString);
+ ASSERT(SystemModule); // GetModuleStruc never returns NULL
+
+ }
+
+ //
+ // The packet should be an IO_ERROR_LOG_MESSAGE
+ //
+
+ ASSERT(pIoErrorLogMessage->Type == IO_TYPE_ERROR_MESSAGE);
+
+ //
+ // Set up write packet in request packet
+ //
+
+ Request.Pkt.WritePkt = &WritePkt;
+ Request.Flags = 0;
+
+ //
+ // Generate any additional information needed in the record.
+ //
+
+ // TIMEWRITTEN
+ // 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,
+ &TimeWritten
+ );
+
+ //
+ // Determine how big a buffer is needed for the eventlog record.
+ //
+
+ RecordLength = sizeof(EVENTLOGRECORD)
+ + ComputerNameLength // computername
+ + 2 * sizeof(WCHAR) // term's
+ + pIoErrorLogMessage->Size
+ - FIELD_OFFSET(IO_ERROR_LOG_MESSAGE, EntryData)
+ + sizeof(RecordLength); // final len
+
+ //
+ // Determine how many pad bytes are needed to align to a DWORD
+ // boundary.
+ //
+
+ PadSize = sizeof(ULONG) - (RecordLength % sizeof(ULONG));
+
+ RecordLength += PadSize; // True size needed
+
+ //
+ // Allocate the buffer for the Eventlog record
+ //
+
+ EventLogRecord = (PEVENTLOGRECORD) ElfpAllocateBuffer(RecordLength);
+
+ if (EventLogRecord != (PEVENTLOGRECORD) NULL) {
+
+ //
+ // Fill up the event record
+ //
+
+ EventLogRecord->Length = RecordLength;
+ RtlTimeToSecondsSince1970(
+ &pIoErrorLogMessage->TimeStamp,
+ &EventLogRecord->TimeGenerated
+ );
+ EventLogRecord->Reserved = ELF_LOG_FILE_SIGNATURE;
+ EventLogRecord->TimeWritten = TimeWritten;
+ EventLogRecord->EventID = pIoErrorLogMessage->EntryData.ErrorCode;
+
+ // set EventType based on the high order nibble of
+ // pIoErrorLogMessage->EntryData.ErrorCode
+
+ if (NT_INFORMATION(pIoErrorLogMessage->EntryData.ErrorCode)) {
+
+ EventLogRecord->EventType = EVENTLOG_INFORMATION_TYPE;
+
+ }
+ else if (NT_WARNING(pIoErrorLogMessage->EntryData.ErrorCode)) {
+
+ EventLogRecord->EventType = EVENTLOG_WARNING_TYPE;
+
+ }
+ else if (NT_ERROR(pIoErrorLogMessage->EntryData.ErrorCode)) {
+
+ EventLogRecord->EventType = EVENTLOG_ERROR_TYPE;
+
+ }
+ else {
+
+ //
+ // Unknown, set to error
+ //
+
+ EventLogRecord->EventType = EVENTLOG_ERROR_TYPE;
+
+ }
+
+ EventLogRecord->NumStrings =
+ pIoErrorLogMessage->EntryData.NumberOfStrings;
+ EventLogRecord->EventCategory =
+ pIoErrorLogMessage->EntryData.EventCategory;
+ EventLogRecord->StringOffset = sizeof(EVENTLOGRECORD) +
+ pIoErrorLogMessage->DriverNameLength + ComputerNameLength;
+ EventLogRecord->DataLength =
+ FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) +
+ pIoErrorLogMessage->EntryData.DumpDataSize;
+ EventLogRecord->DataOffset = EventLogRecord->StringOffset +
+ StringLength;
+ EventLogRecord->UserSidLength = 0;
+ EventLogRecord->UserSidOffset = 0;
+
+ //
+ // Fill in the variable-length fields
+
+ // MODULENAME
+ //
+ // Use the driver name as the module name, since it's location is
+ // described by an offset from the start of the IO_ERROR_LOG_MESSAGE
+ // turn it into a pointer
+ //
+
+ DestinationString = (LPWSTR)((LPBYTE)EventLogRecord +
+ sizeof(EVENTLOGRECORD));
+ SourceString = (LPWSTR)((LPBYTE) pIoErrorLogMessage +
+ pIoErrorLogMessage->DriverNameOffset);
+
+ RtlMoveMemory(DestinationString, SourceString,
+ pIoErrorLogMessage->DriverNameLength);
+
+ //
+ // Make sure it's NULL terminated
+ //
+
+ DestinationString = (LPWSTR)((LPBYTE) DestinationString +
+ pIoErrorLogMessage->DriverNameLength) - 1;
+ if (*DestinationString != L'\0') {
+ *(++DestinationString) = L'\0';
+ }
+
+ DestinationString++;
+
+ // COMPUTERNAME
+ //
+
+ RtlMoveMemory(DestinationString, LocalComputerName,
+ ComputerNameLength);
+
+ //
+ // Make sure it's NULL terminated
+ //
+
+ DestinationString = (LPWSTR)((LPBYTE) DestinationString +
+ ComputerNameLength) - 1;
+ if (*DestinationString != L'\0') {
+ *(++DestinationString) = L'\0';
+ }
+
+ DestinationString++;
+
+ // STRING
+ //
+
+ SourceString = pwStart;
+
+ RtlMoveMemory(DestinationString, SourceString, StringLength);
+
+ DestinationString += (StringLength / 2);
+
+ // BINARY DATA
+ //
+ BinaryData = (LPBYTE) DestinationString;
+
+
+ RtlMoveMemory (BinaryData, & pIoErrorLogMessage->EntryData,
+ FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) +
+ pIoErrorLogMessage->EntryData.DumpDataSize);
+
+ // LENGTH at end of record
+ //
+
+ pEndLength = (PULONG)((LPBYTE) EventLogRecord + RecordLength -
+ sizeof(ULONG));
+ *pEndLength = RecordLength;
+
+ //
+ // Set up request packet.
+ // Link event log record into the request structure.
+ //
+
+ Request.Module = SystemModule;
+ Request.LogFile = Request.Module->LogFile;
+ Request.Command = ELF_COMMAND_WRITE;
+ Request.Pkt.WritePkt->Buffer = (PVOID)EventLogRecord;
+ Request.Pkt.WritePkt->Datasize = RecordLength;
+
+ //
+ // Perform the operation
+ //
+
+ ElfPerformRequest( &Request );
+
+ //
+ // Free up the buffer
+ //
+
+ ElfpFreeBuffer(EventLogRecord );
+
+ status = Request.Status; // Set status of WRITE
+
+ } else {
+ status = STATUS_NO_MEMORY;
+ }
+
+ return (status);
+}
+
+
+
+NTSTATUS
+ElfProcessLPCCalls (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine waits for messages to come through the LPC port to
+ the system thread. When one does, it calls the appropriate routine to
+ handle the API, then replies to the system thread indicating that the
+ call has completed if the message was a request, if it was a datagram,
+ it just waits for the next message.
+
+Arguments:
+
+
+Return Value:
+
+--*/
+
+{
+ NTSTATUS status;
+
+ BOOL SendReply = FALSE;
+
+ ELF_REPLY_MESSAGE replyMessage;
+ PELFIOPORTMSG receiveMessage;
+
+ //
+ // Loop dispatching API requests.
+ //
+
+ receiveMessage = ElfpAllocateBuffer(ELF_PORT_MAX_MESSAGE_LENGTH +
+ sizeof(PORT_MESSAGE));
+ if (!receiveMessage) {
+ return(STATUS_NO_MEMORY);
+ }
+
+ while ( TRUE ) {
+
+ //
+ // On the first call to NtReplyWaitReceivePort, don't send a
+ // reply since there's nobody to reply to. However, on subsequent
+ // calls the reply to the message from the prior time if that message
+ // wasn't a LPC_DATAGRAM
+ //
+
+ status = NtReplyWaitReceivePort(
+ ElfConnectionPortHandle,
+ NULL, // PortContext
+ (PPORT_MESSAGE)( SendReply ? &replyMessage : NULL),
+ (PPORT_MESSAGE) receiveMessage
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ ElfDbgPrintNC(( "[ELF] ElfProcessLPCCalls: NtReplyWaitReceivePort failed: %X\n",
+ status ));
+ return status;
+ }
+
+ ElfDbgPrint(( "[ELF] ElfProcessLPCCalls: received message\n" ));
+
+ //
+ // Take the record received and perform the operation. Strip off
+ // the PortMessage and just send the packet
+ //
+
+
+ //
+ // Set up the response message to be sent on the next call to
+ // NtReplyWaitReceivePort if this wasn't a datagram.
+ // 'status' contains the status to return from this call.
+ // Only process messages that are LPC_REQUEST or LPC_DATAGRAM
+ //
+
+ if (receiveMessage->PortMessage.u2.s2.Type == LPC_REQUEST) {
+ status = ElfProcessLPCPacket (& receiveMessage->IoErrorLogMessage);
+
+ replyMessage.PortMessage.u1.s1.DataLength =
+ sizeof(replyMessage) - sizeof(PORT_MESSAGE);
+ replyMessage.PortMessage.u1.s1.TotalLength = sizeof(replyMessage);
+ replyMessage.PortMessage.u2.ZeroInit = 0;
+ replyMessage.PortMessage.ClientId =
+ receiveMessage->PortMessage.ClientId;
+ replyMessage.PortMessage.MessageId =
+ receiveMessage->PortMessage.MessageId;
+ replyMessage.Status = status;
+
+ SendReply = TRUE;
+ }
+ else if (receiveMessage->PortMessage.u2.s2.Type == LPC_DATAGRAM) {
+ status = ElfProcessLPCPacket (& receiveMessage->IoErrorLogMessage);
+ SendReply = FALSE;
+ }
+ else {
+ //
+ // We received a message type we didn't expect, probably due to
+ // error. BUGBUG - write an event
+ //
+
+ ElfDbgPrintNC(("[ELF] Unexpected message type received on LPC port\n"));
+ ElfDbgPrintNC(("[ELF] Messaage type = %d\n",
+ receiveMessage->PortMessage.u2.s2.Type));
+
+ }
+ }
+
+} // ElfProcessLPCCalls
+
+
+
+DWORD
+MainLPCThread (
+ LPVOID LPCThreadParm
+ )
+
+/*++
+
+Routine Description:
+
+ This is the main thread that monitors the LPC port from the I/O system.
+ It takes care of creating the LPC port, and waiting for input, which
+ it then transforms into the right operation on the event log.
+
+
+Arguments:
+
+ NONE
+
+Return Value:
+
+ NONE
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ ElfDbgPrint(( "[ELF] Inside LPC thread\n" ));
+
+ Status = SetUpLPCPort();
+
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // Loop forever. This thread will be killed when the service terminates.
+ //
+ while (TRUE) {
+
+ Status = ElfProcessLPCCalls ();
+
+ }
+
+ }
+ ElfDbgPrintNC (("[ELF] Error from SetUpLPCPort. Status = %lx\n", Status));
+
+ return (Status);
+
+ UNREFERENCED_PARAMETER ( LPCThreadParm );
+}
+
+
+
+BOOL
+StartLPCThread ()
+
+/*++
+
+Routine Description:
+
+ This routine starts up the thread that monitors the LPC port.
+
+Arguments:
+
+ NONE
+
+Return Value:
+
+ TRUE if thread creation succeeded, FALSE otherwise.
+
+Note:
+
+
+--*/
+{
+ DWORD error;
+ DWORD ThreadId;
+
+ ElfDbgPrint(( "[ELF] Start up the LPC thread\n" ));
+
+ //
+ // Start up the actual thread.
+ //
+
+ LPCThreadHandle = CreateThread(
+ NULL, // lpThreadAttributes
+ 4096, // dwStackSize
+ MainLPCThread, // lpStartAddress
+ NULL, // lpParameter
+ 0L, // dwCreationFlags
+ &ThreadId // lpThreadId
+ );
+
+ if ( LPCThreadHandle == NULL ) {
+ error = GetLastError();
+ ElfDbgPrintNC(( "[ELF]: LPCThread - CreateThread failed: %ld\n", error ));
+ return (FALSE);
+ }
+ return (TRUE);
+}