reactos/base/services/eventlog/logport.c

245 lines
7.7 KiB
C
Raw Permalink Normal View History

/*
* PROJECT: ReactOS EventLog Service
* LICENSE: GPL - See COPYING in the top level directory
* FILE: base/services/eventlog/logport.c
* PURPOSE: LPC Port Interface support
* COPYRIGHT: Copyright 2002 Eric Kohl
* Copyright 2005 Saveliy Tretiakov
*/
/* INCLUDES *****************************************************************/
#include "eventlog.h"
#include <ndk/lpcfuncs.h>
#include <iolog/iolog.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ******************************************************************/
static HANDLE ConnectPortHandle = NULL;
static HANDLE MessagePortHandle = NULL;
extern BOOL onLiveCD;
/* FUNCTIONS ****************************************************************/
NTSTATUS WINAPI PortThreadRoutine(PVOID Param)
{
NTSTATUS Status = STATUS_SUCCESS;
Status = InitLogPort();
if (!NT_SUCCESS(Status))
return Status;
while (NT_SUCCESS(Status))
Status = ProcessPortMessage();
if (ConnectPortHandle != NULL)
NtClose(ConnectPortHandle);
if (MessagePortHandle != NULL)
NtClose(MessagePortHandle);
return Status;
}
NTSTATUS InitLogPort(VOID)
{
NTSTATUS Status;
UNICODE_STRING PortName = RTL_CONSTANT_STRING(ELF_PORT_NAME);
OBJECT_ATTRIBUTES ObjectAttributes;
PORT_MESSAGE Request;
ConnectPortHandle = NULL;
MessagePortHandle = NULL;
InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, NULL);
Status = NtCreatePort(&ConnectPortHandle,
&ObjectAttributes,
0,
PORT_MAXIMUM_MESSAGE_LENGTH, // IO_ERROR_LOG_MESSAGE_LENGTH,
2 * PAGE_SIZE);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreatePort() failed (Status %lx)\n", Status);
goto ByeBye;
}
Status = NtListenPort(ConnectPortHandle, &Request);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtListenPort() failed (Status %lx)\n", Status);
goto ByeBye;
}
Status = NtAcceptConnectPort(&MessagePortHandle, ConnectPortHandle,
&Request, TRUE, NULL, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtAcceptConnectPort() failed (Status %lx)\n", Status);
goto ByeBye;
}
Status = NtCompleteConnectPort(MessagePortHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCompleteConnectPort() failed (Status %lx)\n", Status);
goto ByeBye;
}
ByeBye:
if (!NT_SUCCESS(Status))
{
if (ConnectPortHandle != NULL)
NtClose(ConnectPortHandle);
if (MessagePortHandle != NULL)
NtClose(MessagePortHandle);
}
return Status;
}
NTSTATUS ProcessPortMessage(VOID)
{
NTSTATUS Status;
PLOGFILE SystemLog = NULL;
UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH]; // IO_ERROR_LOG_MESSAGE_LENGTH
PELF_API_MSG Message = (PELF_API_MSG)Buffer;
PIO_ERROR_LOG_MESSAGE ErrorMessage;
PEVENTLOGRECORD LogBuffer;
SIZE_T RecSize;
ULONG Time;
USHORT EventType;
UNICODE_STRING SourceName, ComputerName;
DWORD dwComputerNameLength;
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DPRINT("ProcessPortMessage() called\n");
SystemLog = LogfListItemByName(L"System");
while (TRUE)
{
Status = NtReplyWaitReceivePort(MessagePortHandle,
NULL,
NULL,
&Message->Header);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtReplyWaitReceivePort() failed (Status %lx)\n", Status);
break;
}
DPRINT("Received message\n");
if (Message->Header.u2.s2.Type == LPC_PORT_CLOSED)
{
DPRINT("Port closed\n");
return STATUS_SUCCESS;
}
if (Message->Header.u2.s2.Type == LPC_REQUEST)
{
DPRINT("Received request\n");
}
else if (Message->Header.u2.s2.Type == LPC_DATAGRAM)
{
DPRINT("Received datagram (0x%x, 0x%x)\n",
Message->Unknown[0], Message->Unknown[1]);
ErrorMessage = &Message->IoErrorMessage;
// ASSERT(ErrorMessage->Type == IO_TYPE_ERROR_MESSAGE);
RtlInitEmptyUnicodeString(&SourceName, NULL, 0);
if (ErrorMessage->DriverNameLength > sizeof(UNICODE_NULL)) // DriverNameLength counts NULL-terminator
{
SourceName.Buffer = (PWSTR)((ULONG_PTR)ErrorMessage + ErrorMessage->DriverNameOffset);
SourceName.MaximumLength = ErrorMessage->DriverNameLength;
SourceName.Length = SourceName.MaximumLength - sizeof(UNICODE_NULL);
}
dwComputerNameLength = ARRAYSIZE(szComputerName);
if (!GetComputerNameW(szComputerName, &dwComputerNameLength))
szComputerName[0] = L'\0';
RtlInitUnicodeString(&ComputerName, szComputerName);
RtlTimeToSecondsSince1970(&ErrorMessage->TimeStamp, &Time);
/* Set the event type based on the error code severity */
EventType = (USHORT)(ErrorMessage->EntryData.ErrorCode >> 30);
if (EventType == STATUS_SEVERITY_SUCCESS)
{
EventType = EVENTLOG_SUCCESS;
}
else if (EventType == STATUS_SEVERITY_INFORMATIONAL) // NT_INFORMATION
{
EventType = EVENTLOG_INFORMATION_TYPE;
}
else if (EventType == STATUS_SEVERITY_WARNING) // NT_WARNING
{
EventType = EVENTLOG_WARNING_TYPE;
}
else if (EventType == STATUS_SEVERITY_ERROR) // NT_ERROR
{
EventType = EVENTLOG_ERROR_TYPE;
}
else
{
/* Unknown severity, set to error */
EventType = EVENTLOG_ERROR_TYPE;
}
/*
* The data being saved consists of the IO_ERROR_LOG_PACKET structure
* header, plus the additional raw data from the driver.
*/
LogBuffer = LogfAllocAndBuildNewRecord(
&RecSize,
Time,
EventType,
ErrorMessage->EntryData.EventCategory,
ErrorMessage->EntryData.ErrorCode,
&SourceName,
&ComputerName,
0,
NULL,
ErrorMessage->EntryData.NumberOfStrings,
(PWSTR)((ULONG_PTR)ErrorMessage +
ErrorMessage->EntryData.StringOffset),
FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) +
ErrorMessage->EntryData.DumpDataSize,
(PVOID)&ErrorMessage->EntryData);
if (LogBuffer == NULL)
{
DPRINT1("LogfAllocAndBuildNewRecord failed!\n");
// return STATUS_NO_MEMORY;
continue;
}
if (!onLiveCD && SystemLog)
{
Status = LogfWriteRecord(SystemLog, LogBuffer, RecSize);
[EVENTLOG] - Get rid of MyHeap. - Continue using safe string functions. - Allow event logs themselves to be their own source. And store the full list of log sources in the "Sources" registry multi-string value. - Correctly compute the number of records. - Correctly return the event number and the write timestamp of reported events. - Use a helper function for ElfrReportEventW/A and for ElfrReportEventAndSourceW that is now implemented. - Rewrite the file.c functions using NT-APIs almost exclusively for file operations. - Modify the logic of LogfReadEvents so that a RecordNumber == 0 in sequential read mode means we need to determine where to start the read operation, depending on whether a forwards-read or a backwards-read is performed. The log handle's CurrentRecord member is therefore initialized to 0 before usage. - Adjust LogfAllocAndBuildNewRecord to take in input the event generation timestamp. - Do not "compute" the RecordNumber of the new event in LogfAllocAndBuildNewRecord; it will be consistently assigned by LogfWriteRecord. - Correctly initialize the OldestRecordNumber to zero for new (empty) logs. - Perform extensive log validity checks when opening existing logs: log header and EOF record as well as boundary checks. - Rewrite almost of the functions to support event log wrapping (see https://msdn.microsoft.com/en-us/library/windows/desktop/bb309026(v=vs.85).aspx ) and splitted records. Now our event logs are not corrupted anymore, and are readable under Windows 2k/xp/2k3/Vista+. - As a consequence of supporting wrapping event logs we need to iterate through them at loading time in order to locate the valid EOF record (indeed it may happen that the log header is not correctly synced, and its Start/EndOffsets are invalid. The EOF record offsets contain on the other way the correct values). The file.c fixes are a bit still work-in-progress, but the bulk of the code works. It is extensively tested in situ in my local VM since 2 months now. CORE-11843 #resolve svn path=/trunk/; revision=72236
2016-08-16 21:08:15 +00:00
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n",
SystemLog->LogName, Status);
[EVENTLOG] - Get rid of MyHeap. - Continue using safe string functions. - Allow event logs themselves to be their own source. And store the full list of log sources in the "Sources" registry multi-string value. - Correctly compute the number of records. - Correctly return the event number and the write timestamp of reported events. - Use a helper function for ElfrReportEventW/A and for ElfrReportEventAndSourceW that is now implemented. - Rewrite the file.c functions using NT-APIs almost exclusively for file operations. - Modify the logic of LogfReadEvents so that a RecordNumber == 0 in sequential read mode means we need to determine where to start the read operation, depending on whether a forwards-read or a backwards-read is performed. The log handle's CurrentRecord member is therefore initialized to 0 before usage. - Adjust LogfAllocAndBuildNewRecord to take in input the event generation timestamp. - Do not "compute" the RecordNumber of the new event in LogfAllocAndBuildNewRecord; it will be consistently assigned by LogfWriteRecord. - Correctly initialize the OldestRecordNumber to zero for new (empty) logs. - Perform extensive log validity checks when opening existing logs: log header and EOF record as well as boundary checks. - Rewrite almost of the functions to support event log wrapping (see https://msdn.microsoft.com/en-us/library/windows/desktop/bb309026(v=vs.85).aspx ) and splitted records. Now our event logs are not corrupted anymore, and are readable under Windows 2k/xp/2k3/Vista+. - As a consequence of supporting wrapping event logs we need to iterate through them at loading time in order to locate the valid EOF record (indeed it may happen that the log header is not correctly synced, and its Start/EndOffsets are invalid. The EOF record offsets contain on the other way the correct values). The file.c fixes are a bit still work-in-progress, but the bulk of the code works. It is extensively tested in situ in my local VM since 2 months now. CORE-11843 #resolve svn path=/trunk/; revision=72236
2016-08-16 21:08:15 +00:00
}
}
else
{
DPRINT1("\n--- EVENTLOG RECORD ---\n");
PRINT_RECORD(LogBuffer);
DPRINT1("\n");
}
LogfFreeRecord(LogBuffer);
}
}
return Status;
}