666 lines
25 KiB
C
666 lines
25 KiB
C
|
/*++
|
||
|
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
|
||
|
--*/
|
||
|
|
||
|
// INCLUDES
|
||
|
#include <eventp.h>
|
||
|
#include <ntiolog.h> // For IO_ERROR_LOG_[MESSAGE/PACKET]
|
||
|
#include <ntiologc.h> // QUOTA error codes
|
||
|
#include <elfkrnl.h>
|
||
|
//#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>
|
||
|
#include <elfmsg.h>
|
||
|
|
||
|
// Global value for the "system" module
|
||
|
PLOGMODULE SystemModule = NULL;
|
||
|
|
||
|
|
||
|
NTSTATUS SetUpLPCPort()
|
||
|
/*++
|
||
|
Routine Description:
|
||
|
This routine sets up the LPC port for the service.
|
||
|
--*/
|
||
|
{
|
||
|
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"));
|
||
|
}
|
||
|
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
|
||
|
LPWSTR ElfpCopyString(LPWSTR Destination, LPWSTR Source, ULONG Length)
|
||
|
/*++
|
||
|
Routine Description:
|
||
|
Copies a string to the destination. Correctly NUL terminates the string.
|
||
|
Arguments:
|
||
|
Destination - place where string is to be copied
|
||
|
Source - string that may or may not be NUL terminated
|
||
|
Length - length in bytes of string being copied. May include NUL
|
||
|
Return Value:
|
||
|
LPWSTR to first WCHAR past NUL
|
||
|
--*/
|
||
|
{
|
||
|
// Copy the data
|
||
|
RtlMoveMemory(Destination, Source, Length);
|
||
|
|
||
|
// Make sure it's NULL terminated
|
||
|
if (Length != 0) {
|
||
|
Destination += Length / 2 - 1;
|
||
|
if (*Destination != L'\0') {
|
||
|
Destination++;
|
||
|
*Destination = L'\0';
|
||
|
}
|
||
|
} else {
|
||
|
*Destination = L'0';
|
||
|
}
|
||
|
|
||
|
return Destination + 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS ElfProcessIoLPCPacket(ULONG PacketLength, PIO_ERROR_LOG_MESSAGE pIoErrorLogMessage)
|
||
|
/*++
|
||
|
Routine Description:
|
||
|
This routine takes the packet received from the LPC port and processes it.
|
||
|
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.
|
||
|
--*/
|
||
|
{
|
||
|
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;
|
||
|
|
||
|
PacketLength = min(pIoErrorLogMessage->Size, PacketLength);
|
||
|
|
||
|
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 + PacketLength);
|
||
|
|
||
|
while (pwch < pwEnd &&
|
||
|
i < pIoErrorLogMessage->EntryData.NumberOfStrings) {
|
||
|
if (*pwch == L'\0') {
|
||
|
i++;
|
||
|
}
|
||
|
pwch++;
|
||
|
}
|
||
|
StringLength = (ULONG)(pwch - pwStart) * sizeof(WCHAR);
|
||
|
|
||
|
// Now make sure everything in the packet is true
|
||
|
if ((i != pIoErrorLogMessage->EntryData.NumberOfStrings) ||
|
||
|
(pIoErrorLogMessage->DriverNameOffset + pIoErrorLogMessage->DriverNameLength >= PacketLength) ||
|
||
|
(pIoErrorLogMessage->EntryData.StringOffset >= PacketLength) ||
|
||
|
(FIELD_OFFSET(IO_ERROR_LOG_MESSAGE, EntryData)
|
||
|
+ FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)
|
||
|
+ (ULONG)pIoErrorLogMessage->EntryData.DumpDataSize >= PacketLength)
|
||
|
) {
|
||
|
// 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
|
||
|
PacketLength, // 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
|
||
|
PacketLength, // 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
|
||
|
+ PacketLength
|
||
|
- 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;
|
||
|
|
||
|
// Quota events contain a SID.
|
||
|
if (pIoErrorLogMessage->EntryData.ErrorCode == IO_FILE_QUOTA_LIMIT ||
|
||
|
pIoErrorLogMessage->EntryData.ErrorCode == IO_FILE_QUOTA_THRESHOLD) {
|
||
|
PFILE_QUOTA_INFORMATION pFileQuotaInformation = (PFILE_QUOTA_INFORMATION)pIoErrorLogMessage->EntryData.DumpData;
|
||
|
|
||
|
EventLogRecord->UserSidLength = pFileQuotaInformation->SidLength;
|
||
|
EventLogRecord->UserSidOffset = EventLogRecord->DataOffset +
|
||
|
FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) +
|
||
|
FIELD_OFFSET(FILE_QUOTA_INFORMATION, Sid);
|
||
|
|
||
|
EventLogRecord->DataLength = EventLogRecord->UserSidOffset - EventLogRecord->DataOffset;
|
||
|
} else {
|
||
|
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);
|
||
|
DestinationString = ElfpCopyString(DestinationString, SourceString, pIoErrorLogMessage->DriverNameLength);
|
||
|
|
||
|
// COMPUTERNAME
|
||
|
DestinationString = ElfpCopyString(DestinationString, LocalComputerName, ComputerNameLength);
|
||
|
|
||
|
// STRING
|
||
|
DestinationString = ElfpCopyString(DestinationString, pwStart, StringLength);
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
ElfPerformRequest(&Request);// Perform the operation
|
||
|
ElfpFreeBuffer(EventLogRecord);// Free up the buffer
|
||
|
status = Request.Status; // Set status of WRITE
|
||
|
} else {
|
||
|
status = STATUS_NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
return (status);
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS ElfProcessSmLPCPacket(ULONG PacketLength, PSM_ERROR_LOG_MESSAGE SmErrorLogMessage)
|
||
|
/*++
|
||
|
Routine Description:
|
||
|
This routine takes the packet received from the LPC port and processes it.
|
||
|
The packet is an SM_ERROR_LOG_MESSAGE. The logfile will be system, the
|
||
|
module name will be SMSS, the SID will always be NULL and there will always be one string, which will be the filename
|
||
|
|
||
|
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:
|
||
|
SmErrorLogMessage - Pointer to the data portion of the packet just received through the LPC port.
|
||
|
Return Value:
|
||
|
Status of this operation.
|
||
|
--*/
|
||
|
{
|
||
|
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;
|
||
|
|
||
|
try {
|
||
|
// Validate the packet.
|
||
|
if (
|
||
|
PacketLength < sizeof(SM_ERROR_LOG_MESSAGE) ||
|
||
|
// Offset begins before header
|
||
|
SmErrorLogMessage->StringOffset < sizeof(*SmErrorLogMessage) ||
|
||
|
// Offset begins after packet
|
||
|
SmErrorLogMessage->StringOffset >= PacketLength ||
|
||
|
// Length of string longer than packet
|
||
|
SmErrorLogMessage->StringLength > PacketLength ||
|
||
|
// String end after end of packet
|
||
|
SmErrorLogMessage->StringOffset + SmErrorLogMessage->StringLength > PacketLength) {
|
||
|
RtlRaiseStatus(STATUS_UNSUCCESSFUL);
|
||
|
}
|
||
|
}
|
||
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
// It's a bad packet, log it and return
|
||
|
ElfDbgPrintNC(("[ELF] Bad packet from LPC port\n"));
|
||
|
ElfDbgPrintNC(("[ELF] SmErrorLogMessage->StringOffset %x\n", SmErrorLogMessage->StringOffset));
|
||
|
ElfDbgPrintNC(("[ELF] PacketLength %x\n", PacketLength));
|
||
|
ElfDbgPrintNC(("[ELF] SmErrorLogMessage->StringLength %x\n", SmErrorLogMessage->StringLength));
|
||
|
ElfpCreateElfEvent(EVENT_BadDriverPacket,
|
||
|
EVENTLOG_ERROR_TYPE,
|
||
|
0, // EventCategory
|
||
|
0, // NumberOfStrings
|
||
|
NULL, // Strings
|
||
|
SmErrorLogMessage, // Data
|
||
|
PacketLength, // 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 != NULL);
|
||
|
}
|
||
|
|
||
|
// 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.
|
||
|
|
||
|
// Determine how big a buffer is needed for the eventlog record.
|
||
|
// We overestimate string lengths rather than probing for terminating NUL's
|
||
|
RecordLength = sizeof(EVENTLOGRECORD)
|
||
|
+ sizeof(L"system")
|
||
|
+ ComputerNameLength + sizeof(WCHAR)
|
||
|
+ SmErrorLogMessage->StringLength + sizeof(WCHAR)
|
||
|
+ sizeof(RecordLength);
|
||
|
|
||
|
// Since the RecordLength at the end must be ULONG aligned, we round
|
||
|
// up the total size to be ULONG aligned.
|
||
|
RecordLength += sizeof(ULONG) - (RecordLength % sizeof(ULONG));
|
||
|
|
||
|
// Allocate the buffer for the Eventlog record
|
||
|
EventLogRecord = (PEVENTLOGRECORD)ElfpAllocateBuffer(RecordLength);
|
||
|
if (EventLogRecord == NULL) {
|
||
|
return STATUS_NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
// Fill up the event record
|
||
|
EventLogRecord->Length = RecordLength;
|
||
|
EventLogRecord->Reserved = ELF_LOG_FILE_SIGNATURE;
|
||
|
RtlTimeToSecondsSince1970(&SmErrorLogMessage->TimeStamp, &EventLogRecord->TimeGenerated);
|
||
|
NtQuerySystemTime(&Time);
|
||
|
RtlTimeToSecondsSince1970(&Time, &EventLogRecord->TimeWritten);
|
||
|
EventLogRecord->EventID = SmErrorLogMessage->Status;
|
||
|
|
||
|
// set EventType based on the high order nibble of the eventID
|
||
|
if (NT_INFORMATION(EventLogRecord->EventID)) {
|
||
|
EventLogRecord->EventType = EVENTLOG_INFORMATION_TYPE;
|
||
|
} else if (NT_WARNING(EventLogRecord->EventID)) {
|
||
|
EventLogRecord->EventType = EVENTLOG_WARNING_TYPE;
|
||
|
} else if (NT_ERROR(EventLogRecord->EventID)) {
|
||
|
EventLogRecord->EventType = EVENTLOG_ERROR_TYPE;
|
||
|
} else {
|
||
|
// Unknown, set to error
|
||
|
EventLogRecord->EventType = EVENTLOG_ERROR_TYPE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// There is a single string; it is the name of the file being replaced
|
||
|
EventLogRecord->NumStrings = 1;
|
||
|
EventLogRecord->EventCategory = ELF_CATEGORY_SYSTEM_EVENT;
|
||
|
|
||
|
// Nothing for ReservedFlags
|
||
|
// Nothing for ClosingRecordNumber
|
||
|
EventLogRecord->StringOffset = sizeof(EVENTLOGRECORD) + sizeof(L"system") + ComputerNameLength;
|
||
|
|
||
|
// No SID's present
|
||
|
EventLogRecord->UserSidLength = 0;
|
||
|
EventLogRecord->UserSidOffset = 0;
|
||
|
EventLogRecord->DataLength = 0;
|
||
|
EventLogRecord->DataOffset = 0;
|
||
|
|
||
|
// Fill in the variable-length fields
|
||
|
|
||
|
// MODULENAME
|
||
|
|
||
|
// SMSS
|
||
|
DestinationString = (LPWSTR)((LPBYTE)EventLogRecord + sizeof(EVENTLOGRECORD));
|
||
|
DestinationString = ElfpCopyString(DestinationString, L"system", sizeof(L"system"));
|
||
|
|
||
|
// COMPUTERNAME
|
||
|
DestinationString = ElfpCopyString(DestinationString, LocalComputerName, ComputerNameLength);
|
||
|
|
||
|
// STRING.
|
||
|
SourceString = (LPWSTR)((LPBYTE)SmErrorLogMessage + SmErrorLogMessage->StringOffset);
|
||
|
KdPrint(("[ELF] String is '%*ws'\n", SmErrorLogMessage->StringLength, SourceString));
|
||
|
|
||
|
DestinationString = ElfpCopyString(DestinationString, SourceString, SmErrorLogMessage->StringLength);
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
ElfPerformRequest(&Request);// Perform the operation
|
||
|
ElfpFreeBuffer(EventLogRecord);// Free up the buffer
|
||
|
return Request.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.
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
BOOL SendReply = FALSE;
|
||
|
ELF_REPLY_MESSAGE replyMessage;
|
||
|
PELF_PORT_MSG receiveMessage;
|
||
|
PHANDLE PortConnectionHandle;
|
||
|
|
||
|
// 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,
|
||
|
(PVOID)&PortConnectionHandle,
|
||
|
(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 || receiveMessage->PortMessage.u2.s2.Type == LPC_DATAGRAM) {
|
||
|
ElfDbgPrint(("[ELF] Type = %x\n", receiveMessage->PortMessage.u2.s2.Type));
|
||
|
|
||
|
if (receiveMessage->MessageType == IO_ERROR_LOG) {
|
||
|
ElfDbgPrint(("[ELF] SM_IO_LOG\n"));
|
||
|
status = ElfProcessIoLPCPacket(receiveMessage->PortMessage.u1.s1.DataLength, &receiveMessage->u.IoErrorLogMessage);
|
||
|
} else if (receiveMessage->MessageType == SM_ERROR_LOG) {
|
||
|
ElfDbgPrint(("[ELF] SM_ERROR_LOG\n"));
|
||
|
status = ElfProcessSmLPCPacket(receiveMessage->PortMessage.u1.s1.DataLength, &receiveMessage->u.SmErrorLogMessage);
|
||
|
} else {
|
||
|
ElfDbgPrintNC(("[ELF] Unknown MessageType %x\n", receiveMessage->MessageType));
|
||
|
}
|
||
|
|
||
|
if (receiveMessage->PortMessage.u2.s2.Type == LPC_REQUEST) {
|
||
|
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 {
|
||
|
SendReply = FALSE;
|
||
|
}
|
||
|
} else if (receiveMessage->PortMessage.u2.s2.Type == LPC_CONNECTION_REQUEST) {
|
||
|
HANDLE Handle;
|
||
|
PHANDLE SavedHandle = (PHANDLE)ElfpAllocateBuffer(sizeof(HANDLE));
|
||
|
BOOLEAN Accept = TRUE;
|
||
|
|
||
|
ElfDbgPrint(("[ELF] ElfProcessLPCCalls: Processing connection request\n"));
|
||
|
|
||
|
if (SavedHandle == NULL) {
|
||
|
ElfDbgPrintNC(("[ELF] ElfProcessLPCCalls: Unable to allocate handle save area\n"));
|
||
|
Accept = FALSE;
|
||
|
}
|
||
|
|
||
|
status = NtAcceptConnectPort(&Handle, SavedHandle, &receiveMessage->PortMessage, Accept, NULL, NULL);
|
||
|
if (!Accept) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (NT_SUCCESS(status)) {
|
||
|
*SavedHandle = Handle;
|
||
|
status = NtCompleteConnectPort(Handle);
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
ElfDbgPrintNC(("[ELF] ElfProcessLPCCalls: NtCompleteConnectPort failed %x\n", status));
|
||
|
NtClose(Handle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
ElfDbgPrintNC(("[ELF] ElfProcessLPCCalls: cleaning up failed connect\n"));
|
||
|
ElfpFreeBuffer(SavedHandle);
|
||
|
}
|
||
|
} else if (receiveMessage->PortMessage.u2.s2.Type == LPC_PORT_CLOSED) {
|
||
|
ElfDbgPrint(("[ELF] ElfProcessLPCCalls: Processing Port closed\n"));
|
||
|
NtClose(*PortConnectionHandle);
|
||
|
ElfpFreeBuffer(PortConnectionHandle);
|
||
|
} 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] Message type = %x\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.
|
||
|
Return Value:
|
||
|
TRUE if thread creation succeeded, FALSE otherwise.
|
||
|
--*/
|
||
|
{
|
||
|
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);
|
||
|
}
|