diff options
Diffstat (limited to 'private/eventlog/server/elflpc.c')
-rw-r--r-- | private/eventlog/server/elflpc.c | 774 |
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); +} |