mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
774 lines
20 KiB
774 lines
20 KiB
/*++
|
|
|
|
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);
|
|
}
|