Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096/* * PROJECT: ReactOS EventLog Service * LICENSE: GPL - See COPYING in the top level directory * FILE: base/services/eventlog/file.c * PURPOSE: Event log file support wrappers * COPYRIGHT: Copyright 2005 Saveliy Tretiakov * Michael Martin * Hermes Belusca-Maito */
/* INCLUDES ******************************************************************/
#include "eventlog.h"#include <ndk/iofuncs.h>#include <ndk/kefuncs.h>
#define NDEBUG#include <debug.h>
/* LOG FILE LIST - GLOBALS ***************************************************/
static LIST_ENTRY LogFileListHead;static CRITICAL_SECTION LogFileListCs;
/* LOG FILE LIST - FUNCTIONS *************************************************/
VOID LogfListInitialize(VOID){ InitializeCriticalSection(&LogFileListCs); InitializeListHead(&LogFileListHead);}
PLOGFILE LogfListItemByName(LPCWSTR Name){ PLIST_ENTRY CurrentEntry; PLOGFILE Item, Result = NULL;
ASSERT(Name);
EnterCriticalSection(&LogFileListCs);
CurrentEntry = LogFileListHead.Flink; while (CurrentEntry != &LogFileListHead) { Item = CONTAINING_RECORD(CurrentEntry, LOGFILE, ListEntry);
if (Item->LogName && !_wcsicmp(Item->LogName, Name)) { Result = Item; break; }
CurrentEntry = CurrentEntry->Flink; }
LeaveCriticalSection(&LogFileListCs); return Result;}
#if 0/* Index starting from 1 */DWORD LogfListItemIndexByName(LPCWSTR Name){ PLIST_ENTRY CurrentEntry; DWORD Result = 0; DWORD i = 1;
ASSERT(Name);
EnterCriticalSection(&LogFileListCs);
CurrentEntry = LogFileListHead.Flink; while (CurrentEntry != &LogFileListHead) { PLOGFILE Item = CONTAINING_RECORD(CurrentEntry, LOGFILE, ListEntry);
if (Item->LogName && !_wcsicmp(Item->LogName, Name)) { Result = i; break; }
CurrentEntry = CurrentEntry->Flink; i++; }
LeaveCriticalSection(&LogFileListCs); return Result;}#endif
/* Index starting from 1 */PLOGFILE LogfListItemByIndex(DWORD Index){ PLIST_ENTRY CurrentEntry; PLOGFILE Result = NULL; DWORD i = 1;
EnterCriticalSection(&LogFileListCs);
CurrentEntry = LogFileListHead.Flink; while (CurrentEntry != &LogFileListHead) { if (i == Index) { Result = CONTAINING_RECORD(CurrentEntry, LOGFILE, ListEntry); break; }
CurrentEntry = CurrentEntry->Flink; i++; }
LeaveCriticalSection(&LogFileListCs); return Result;}
DWORD LogfListItemCount(VOID){ PLIST_ENTRY CurrentEntry; DWORD i = 0;
EnterCriticalSection(&LogFileListCs);
CurrentEntry = LogFileListHead.Flink; while (CurrentEntry != &LogFileListHead) { CurrentEntry = CurrentEntry->Flink; i++; }
LeaveCriticalSection(&LogFileListCs); return i;}
static VOIDLogfListAddItem(PLOGFILE Item){ EnterCriticalSection(&LogFileListCs); InsertTailList(&LogFileListHead, &Item->ListEntry); LeaveCriticalSection(&LogFileListCs);}
static VOIDLogfListRemoveItem(PLOGFILE Item){ EnterCriticalSection(&LogFileListCs); RemoveEntryList(&Item->ListEntry); LeaveCriticalSection(&LogFileListCs);}
/* FUNCTIONS *****************************************************************/
// PELF_ALLOCATE_ROUTINEstaticPVOID NTAPILogfpAlloc(IN SIZE_T Size, IN ULONG Flags, IN ULONG Tag){ UNREFERENCED_PARAMETER(Tag); return RtlAllocateHeap(GetProcessHeap(), Flags, Size);}
// PELF_FREE_ROUTINEstaticVOID NTAPILogfpFree(IN PVOID Ptr, IN ULONG Flags, IN ULONG Tag){ UNREFERENCED_PARAMETER(Tag); RtlFreeHeap(GetProcessHeap(), Flags, Ptr);}
// PELF_FILE_READ_ROUTINEstaticNTSTATUS NTAPILogfpReadFile(IN PEVTLOGFILE LogFile, IN PLARGE_INTEGER FileOffset, OUT PVOID Buffer, IN SIZE_T Length, OUT PSIZE_T ReadLength OPTIONAL){ NTSTATUS Status; PLOGFILE pLogFile = (PLOGFILE)LogFile; IO_STATUS_BLOCK IoStatusBlock;
if (ReadLength) *ReadLength = 0;
Status = NtReadFile(pLogFile->FileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, FileOffset, NULL);
if (ReadLength) *ReadLength = IoStatusBlock.Information;
return Status;}
// PELF_FILE_WRITE_ROUTINEstaticNTSTATUS NTAPILogfpWriteFile(IN PEVTLOGFILE LogFile, IN PLARGE_INTEGER FileOffset, IN PVOID Buffer, IN SIZE_T Length, OUT PSIZE_T WrittenLength OPTIONAL){ NTSTATUS Status; PLOGFILE pLogFile = (PLOGFILE)LogFile; IO_STATUS_BLOCK IoStatusBlock;
if (WrittenLength) *WrittenLength = 0;
Status = NtWriteFile(pLogFile->FileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, FileOffset, NULL);
if (WrittenLength) *WrittenLength = IoStatusBlock.Information;
return Status;}
// PELF_FILE_SET_SIZE_ROUTINEstaticNTSTATUS NTAPILogfpSetFileSize(IN PEVTLOGFILE LogFile, IN ULONG FileSize, // SIZE_T IN ULONG OldFileSize) // SIZE_T{ NTSTATUS Status; PLOGFILE pLogFile = (PLOGFILE)LogFile; IO_STATUS_BLOCK IoStatusBlock; FILE_END_OF_FILE_INFORMATION FileEofInfo; FILE_ALLOCATION_INFORMATION FileAllocInfo;
UNREFERENCED_PARAMETER(OldFileSize);
// FIXME: Should we round up FileSize ??
FileEofInfo.EndOfFile.QuadPart = FileSize; Status = NtSetInformationFile(pLogFile->FileHandle, &IoStatusBlock, &FileEofInfo, sizeof(FileEofInfo), FileEndOfFileInformation); if (!NT_SUCCESS(Status)) return Status;
FileAllocInfo.AllocationSize.QuadPart = FileSize; Status = NtSetInformationFile(pLogFile->FileHandle, &IoStatusBlock, &FileAllocInfo, sizeof(FileAllocInfo), FileAllocationInformation);
return Status;}
// PELF_FILE_FLUSH_ROUTINEstaticNTSTATUS NTAPILogfpFlushFile(IN PEVTLOGFILE LogFile, IN PLARGE_INTEGER FileOffset, IN ULONG Length){ PLOGFILE pLogFile = (PLOGFILE)LogFile; IO_STATUS_BLOCK IoStatusBlock;
UNREFERENCED_PARAMETER(FileOffset); UNREFERENCED_PARAMETER(Length);
return NtFlushBuffersFile(pLogFile->FileHandle, &IoStatusBlock);}
NTSTATUSLogfCreate(PLOGFILE* LogFile, PCWSTR LogName, PUNICODE_STRING FileName, ULONG MaxSize, ULONG Retention, BOOLEAN Permanent, BOOLEAN Backup){ NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; FILE_STANDARD_INFORMATION FileStdInfo; PLOGFILE pLogFile; SIZE_T LogNameLen; BOOLEAN CreateNew;
pLogFile = LogfpAlloc(sizeof(*pLogFile), HEAP_ZERO_MEMORY, TAG_ELF); if (!pLogFile) { DPRINT1("Cannot allocate heap!\n"); return STATUS_NO_MEMORY; }
LogNameLen = (LogName ? wcslen(LogName) : 0) + 1; pLogFile->LogName = LogfpAlloc(LogNameLen * sizeof(WCHAR), HEAP_ZERO_MEMORY, 0); if (pLogFile->LogName == NULL) { DPRINT1("Cannot allocate heap\n"); Status = STATUS_NO_MEMORY; goto Quit; }
if (LogName) StringCchCopyW(pLogFile->LogName, LogNameLen, LogName);
InitializeObjectAttributes(&ObjectAttributes, FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
DPRINT("Going to create or open %wZ\n", FileName); Status = NtCreateFile(&pLogFile->FileHandle, Backup ? (GENERIC_READ | SYNCHRONIZE) : (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE), &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, Backup ? FILE_OPEN : FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { DPRINT1("Cannot create file `%wZ' (Status 0x%08lx)\n", FileName, Status); goto Quit; }
CreateNew = (IoStatusBlock.Information == FILE_CREATED); DPRINT("%wZ %s successfully\n", FileName, CreateNew ? "created" : "opened");
/* * Retrieve the log file size and check whether the file is not too large; * this log format only supports files of theoretical size < 0xFFFFFFFF . * * As it happens that, on Windows (and ReactOS), retrieving the End-Of-File * information using NtQueryInformationFile with the FileEndOfFileInformation * class is invalid (who knows why...), use instead the FileStandardInformation * class, and the EndOfFile member of the returned FILE_STANDARD_INFORMATION * structure will give the desired information. */ Status = NtQueryInformationFile(pLogFile->FileHandle, &IoStatusBlock, &FileStdInfo, sizeof(FileStdInfo), FileStandardInformation); if (!NT_SUCCESS(Status)) { DPRINT1("EventLog: NtQueryInformationFile failed (Status 0x%08lx)\n", Status); goto Quit; } if (FileStdInfo.EndOfFile.HighPart != 0) { DPRINT1("EventLog: Log `%wZ' is too large.\n", FileName); Status = STATUS_EVENTLOG_FILE_CORRUPT; // STATUS_FILE_TOO_LARGE; goto Quit; }
DPRINT("Initializing LogFile `%S'\n", pLogFile->LogName);
Status = ElfCreateFile(&pLogFile->LogFile, FileName, FileStdInfo.EndOfFile.LowPart, MaxSize, Retention, CreateNew, Backup, LogfpAlloc, LogfpFree, LogfpSetFileSize, LogfpWriteFile, LogfpReadFile, LogfpFlushFile); if (!NT_SUCCESS(Status)) goto Quit;
pLogFile->Permanent = Permanent;
RtlInitializeResource(&pLogFile->Lock);
LogfListAddItem(pLogFile);
Quit: if (!NT_SUCCESS(Status)) { if (pLogFile->FileHandle != NULL) NtClose(pLogFile->FileHandle);
if (pLogFile->LogName) LogfpFree(pLogFile->LogName, 0, 0);
LogfpFree(pLogFile, 0, TAG_ELF); } else { *LogFile = pLogFile; }
return Status;}
VOIDLogfClose(PLOGFILE LogFile, BOOLEAN ForceClose){ if (LogFile == NULL) return;
if (!ForceClose && LogFile->Permanent) return;
RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
LogfListRemoveItem(LogFile);
ElfCloseFile(&LogFile->LogFile); NtClose(LogFile->FileHandle); LogfpFree(LogFile->LogName, 0, 0);
RtlDeleteResource(&LogFile->Lock);
LogfpFree(LogFile, 0, TAG_ELF);
return;}
VOID LogfCloseAll(VOID){ EnterCriticalSection(&LogFileListCs);
while (!IsListEmpty(&LogFileListHead)) { LogfClose(CONTAINING_RECORD(LogFileListHead.Flink, LOGFILE, ListEntry), TRUE); }
LeaveCriticalSection(&LogFileListCs);
DeleteCriticalSection(&LogFileListCs);}
NTSTATUSLogfClearFile(PLOGFILE LogFile, PUNICODE_STRING BackupFileName){ NTSTATUS Status;
/* Lock the log file exclusive */ RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
if (BackupFileName->Length > 0) { /* Write a backup file */ Status = LogfBackupFile(LogFile, BackupFileName); if (!NT_SUCCESS(Status)) { DPRINT1("LogfBackupFile failed (Status 0x%08lx)\n", Status); goto Quit; } }
Status = ElfReCreateFile(&LogFile->LogFile); if (!NT_SUCCESS(Status)) { DPRINT1("LogfInitializeNew failed (Status 0x%08lx)\n", Status); }
Quit: /* Unlock the log file */ RtlReleaseResource(&LogFile->Lock); return Status;}
NTSTATUSLogfBackupFile(PLOGFILE LogFile, PUNICODE_STRING BackupFileName){ NTSTATUS Status; LOGFILE BackupLogFile; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock;
DPRINT("LogfBackupFile(%p, %wZ)\n", LogFile, BackupFileName);
/* Lock the log file shared */ RtlAcquireResourceShared(&LogFile->Lock, TRUE);
InitializeObjectAttributes(&ObjectAttributes, BackupFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtCreateFile(&BackupLogFile.FileHandle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_CREATE, FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { DPRINT("Cannot create backup file `%wZ' (Status 0x%08lx)\n", BackupFileName, Status); goto Quit; }
Status = ElfBackupFile(&LogFile->LogFile, &BackupLogFile.LogFile);
Quit: /* Close the backup file */ if (BackupLogFile.FileHandle != NULL) NtClose(BackupLogFile.FileHandle);
/* Unlock the log file */ RtlReleaseResource(&LogFile->Lock);
return Status;}
static NTSTATUSReadRecord(IN PEVTLOGFILE LogFile, IN ULONG RecordNumber, OUT PEVENTLOGRECORD Record, IN SIZE_T BufSize, // Length OUT PSIZE_T BytesRead OPTIONAL, OUT PSIZE_T BytesNeeded OPTIONAL, IN BOOLEAN Ansi){ NTSTATUS Status; PEVENTLOGRECORD UnicodeBuffer = NULL; PEVENTLOGRECORD Src, Dst; ANSI_STRING StringA; UNICODE_STRING StringW; PVOID SrcPtr, DstPtr; DWORD i; DWORD dwPadding; DWORD dwRecordLength; PDWORD pLength;
if (!Ansi) { return ElfReadRecord(LogFile, RecordNumber, Record, BufSize, BytesRead, BytesNeeded); }
if (BytesRead) *BytesRead = 0;
if (BytesNeeded) *BytesNeeded = 0;
UnicodeBuffer = LogfpAlloc(BufSize, HEAP_ZERO_MEMORY, TAG_ELF_BUF); if (UnicodeBuffer == NULL) { DPRINT1("Alloc failed!\n"); return STATUS_NO_MEMORY; }
Status = ElfReadRecord(LogFile, RecordNumber, UnicodeBuffer, BufSize, BytesRead, BytesNeeded); if (!NT_SUCCESS(Status)) goto Quit;
Src = UnicodeBuffer; Dst = Record;
Dst->Reserved = Src->Reserved; Dst->RecordNumber = Src->RecordNumber; Dst->TimeGenerated = Src->TimeGenerated; Dst->TimeWritten = Src->TimeWritten; Dst->EventID = Src->EventID; Dst->EventType = Src->EventType; Dst->EventCategory = Src->EventCategory; Dst->NumStrings = Src->NumStrings; Dst->UserSidLength = Src->UserSidLength; Dst->DataLength = Src->DataLength;
SrcPtr = (PVOID)((ULONG_PTR)Src + sizeof(EVENTLOGRECORD)); DstPtr = (PVOID)((ULONG_PTR)Dst + sizeof(EVENTLOGRECORD));
/* Convert the module name */ RtlInitUnicodeString(&StringW, SrcPtr); Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE); if (NT_SUCCESS(Status)) { RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength); DstPtr = (PVOID)((ULONG_PTR)DstPtr + StringA.MaximumLength);
RtlFreeAnsiString(&StringA); } else { RtlZeroMemory(DstPtr, StringW.MaximumLength / sizeof(WCHAR)); DstPtr = (PVOID)((ULONG_PTR)DstPtr + StringW.MaximumLength / sizeof(WCHAR)); } SrcPtr = (PVOID)((ULONG_PTR)SrcPtr + StringW.MaximumLength);
/* Convert the computer name */ RtlInitUnicodeString(&StringW, SrcPtr); Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE); if (NT_SUCCESS(Status)) { RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength); DstPtr = (PVOID)((ULONG_PTR)DstPtr + StringA.MaximumLength);
RtlFreeAnsiString(&StringA); } else { RtlZeroMemory(DstPtr, StringW.MaximumLength / sizeof(WCHAR)); DstPtr = (PVOID)((ULONG_PTR)DstPtr + StringW.MaximumLength / sizeof(WCHAR)); }
/* Add the padding and the User SID */ dwPadding = sizeof(ULONG) - (((ULONG_PTR)DstPtr - (ULONG_PTR)Dst) % sizeof(ULONG)); RtlZeroMemory(DstPtr, dwPadding);
SrcPtr = (PVOID)((ULONG_PTR)Src + Src->UserSidOffset); DstPtr = (PVOID)((ULONG_PTR)DstPtr + dwPadding);
Dst->UserSidOffset = (DWORD)((ULONG_PTR)DstPtr - (ULONG_PTR)Dst); RtlCopyMemory(DstPtr, SrcPtr, Src->UserSidLength);
/* Convert the strings */ SrcPtr = (PVOID)((ULONG_PTR)Src + Src->StringOffset); DstPtr = (PVOID)((ULONG_PTR)DstPtr + Src->UserSidLength); Dst->StringOffset = (DWORD)((ULONG_PTR)DstPtr - (ULONG_PTR)Dst);
for (i = 0; i < Dst->NumStrings; i++) { RtlInitUnicodeString(&StringW, SrcPtr); Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE); if (NT_SUCCESS(Status)) { RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength); DstPtr = (PVOID)((ULONG_PTR)DstPtr + StringA.MaximumLength);
RtlFreeAnsiString(&StringA); } else { RtlZeroMemory(DstPtr, StringW.MaximumLength / sizeof(WCHAR)); DstPtr = (PVOID)((ULONG_PTR)DstPtr + StringW.MaximumLength / sizeof(WCHAR)); } SrcPtr = (PVOID)((ULONG_PTR)SrcPtr + StringW.MaximumLength); }
/* Copy the binary data */ SrcPtr = (PVOID)((ULONG_PTR)Src + Src->DataOffset); Dst->DataOffset = (ULONG_PTR)DstPtr - (ULONG_PTR)Dst; RtlCopyMemory(DstPtr, SrcPtr, Src->DataLength); DstPtr = (PVOID)((ULONG_PTR)DstPtr + Src->DataLength);
/* Add the padding */ dwPadding = sizeof(ULONG) - (((ULONG_PTR)DstPtr - (ULONG_PTR)Dst) % sizeof(ULONG)); RtlZeroMemory(DstPtr, dwPadding);
/* Set the record length at the beginning and the end of the record */ dwRecordLength = (DWORD)((ULONG_PTR)DstPtr + dwPadding + sizeof(ULONG) - (ULONG_PTR)Dst); Dst->Length = dwRecordLength; pLength = (PDWORD)((ULONG_PTR)DstPtr + dwPadding); *pLength = dwRecordLength;
if (BytesRead) *BytesRead = dwRecordLength;
Status = STATUS_SUCCESS;
Quit: LogfpFree(UnicodeBuffer, 0, TAG_ELF_BUF);
return Status;}
/* * NOTE: * 'RecordNumber' is a pointer to the record number at which the read operation * should start. If the record number is 0 and the flags given in the 'Flags' * parameter contain EVENTLOG_SEQUENTIAL_READ, an adequate record number is * computed. */NTSTATUSLogfReadEvents(PLOGFILE LogFile, ULONG Flags, PULONG RecordNumber, ULONG BufSize, PBYTE Buffer, PULONG BytesRead, PULONG BytesNeeded, BOOLEAN Ansi){ NTSTATUS Status; ULONG RecNum; SIZE_T ReadLength, NeededSize; ULONG BufferUsage;
/* Parameters validation */
/* EVENTLOG_SEQUENTIAL_READ and EVENTLOG_SEEK_READ are mutually exclusive */ if ((Flags & EVENTLOG_SEQUENTIAL_READ) && (Flags & EVENTLOG_SEEK_READ)) return STATUS_INVALID_PARAMETER;
if (!(Flags & EVENTLOG_SEQUENTIAL_READ) && !(Flags & EVENTLOG_SEEK_READ)) return STATUS_INVALID_PARAMETER;
/* EVENTLOG_FORWARDS_READ and EVENTLOG_BACKWARDS_READ are mutually exclusive */ if ((Flags & EVENTLOG_FORWARDS_READ) && (Flags & EVENTLOG_BACKWARDS_READ)) return STATUS_INVALID_PARAMETER;
if (!(Flags & EVENTLOG_FORWARDS_READ) && !(Flags & EVENTLOG_BACKWARDS_READ)) return STATUS_INVALID_PARAMETER;
if (!Buffer || !BytesRead || !BytesNeeded) return STATUS_INVALID_PARAMETER;
/* In seek read mode, a record number of 0 is invalid */ if (!(Flags & EVENTLOG_SEQUENTIAL_READ) && (*RecordNumber == 0)) return STATUS_INVALID_PARAMETER;
/* Lock the log file shared */ RtlAcquireResourceShared(&LogFile->Lock, TRUE);
/* * In sequential read mode, a record number of 0 means we need * to determine where to start the read operation. Otherwise * we just use the provided record number. */ if ((Flags & EVENTLOG_SEQUENTIAL_READ) && (*RecordNumber == 0)) { if (Flags & EVENTLOG_FORWARDS_READ) { *RecordNumber = ElfGetOldestRecord(&LogFile->LogFile); } else // if (Flags & EVENTLOG_BACKWARDS_READ) { *RecordNumber = ElfGetCurrentRecord(&LogFile->LogFile) - 1; } }
RecNum = *RecordNumber;
*BytesRead = 0; *BytesNeeded = 0;
BufferUsage = 0; do { Status = ReadRecord(&LogFile->LogFile, RecNum, (PEVENTLOGRECORD)(Buffer + BufferUsage), BufSize - BufferUsage, &ReadLength, &NeededSize, Ansi); if (Status == STATUS_NOT_FOUND) { if (BufferUsage == 0) { Status = STATUS_END_OF_FILE; goto Quit; } else { break; } } else if (Status == STATUS_BUFFER_TOO_SMALL) { if (BufferUsage == 0) { *BytesNeeded = NeededSize; // Status = STATUS_BUFFER_TOO_SMALL; goto Quit; } else { break; } } else if (!NT_SUCCESS(Status)) { DPRINT1("ElfReadRecord failed (Status 0x%08lx)\n", Status); goto Quit; }
/* Go to the next event record */ /* * NOTE: This implicitly supposes that all the other record numbers * are consecutive (and do not jump than more than one unit); but if * it is not the case, then we would prefer here to call some * "get_next_record_number" function. */ if (Flags & EVENTLOG_FORWARDS_READ) RecNum++; else // if (Flags & EVENTLOG_BACKWARDS_READ) RecNum--;
BufferUsage += ReadLength; } while (BufferUsage <= BufSize);
*BytesRead = BufferUsage; *RecordNumber = RecNum;
Status = STATUS_SUCCESS;
Quit: /* Unlock the log file */ RtlReleaseResource(&LogFile->Lock);
if (!NT_SUCCESS(Status)) DPRINT1("LogfReadEvents failed (Status 0x%08lx)\n", Status);
return Status;}
NTSTATUSLogfWriteRecord(PLOGFILE LogFile, PEVENTLOGRECORD Record, SIZE_T BufSize){ NTSTATUS Status; LARGE_INTEGER SystemTime;
// ASSERT(sizeof(*Record) == sizeof(RecBuf));
if (!Record || BufSize < sizeof(*Record)) return STATUS_INVALID_PARAMETER;
/* Lock the log file exclusive */ RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
/* * Retrieve the record written time now, that will also be compared * with the existing events timestamps in case the log is wrapping. */ NtQuerySystemTime(&SystemTime); RtlTimeToSecondsSince1970(&SystemTime, &Record->TimeWritten);
Status = ElfWriteRecord(&LogFile->LogFile, Record, BufSize); if (Status == STATUS_LOG_FILE_FULL) { /* The event log file is full, queue a message box for the user and exit */ // TODO! DPRINT1("Log file `%S' is full!\n", LogFile->LogName); }
/* Unlock the log file */ RtlReleaseResource(&LogFile->Lock);
return Status;}
PEVENTLOGRECORDLogfAllocAndBuildNewRecord(PSIZE_T pRecSize, ULONG Time, USHORT wType, USHORT wCategory, ULONG dwEventId, PUNICODE_STRING SourceName, PUNICODE_STRING ComputerName, ULONG dwSidLength, PSID pUserSid, USHORT wNumStrings, PWSTR pStrings, ULONG dwDataSize, PVOID pRawData){ SIZE_T RecSize; SIZE_T SourceNameSize, ComputerNameSize, StringLen; PBYTE Buffer; PEVENTLOGRECORD pRec; PWSTR str; UINT i, pos;
SourceNameSize = (SourceName && SourceName->Buffer) ? SourceName->Length : 0; ComputerNameSize = (ComputerName && ComputerName->Buffer) ? ComputerName->Length : 0;
RecSize = sizeof(EVENTLOGRECORD) + /* Add the sizes of the strings, NULL-terminated */ SourceNameSize + ComputerNameSize + 2*sizeof(UNICODE_NULL);
/* Align on DWORD boundary for the SID */ RecSize = ROUND_UP(RecSize, sizeof(ULONG));
RecSize += dwSidLength;
/* Add the sizes for the strings array */ ASSERT((pStrings == NULL && wNumStrings == 0) || (pStrings != NULL && wNumStrings >= 0)); for (i = 0, str = pStrings; i < wNumStrings; i++) { StringLen = wcslen(str) + 1; // str must be != NULL RecSize += StringLen * sizeof(WCHAR); str += StringLen; }
/* Add the data size */ RecSize += dwDataSize;
/* Align on DWORD boundary for the full structure */ RecSize = ROUND_UP(RecSize, sizeof(ULONG));
/* Size of the trailing 'Length' member */ RecSize += sizeof(ULONG);
Buffer = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, RecSize); if (!Buffer) { DPRINT1("Cannot allocate heap!\n"); return NULL; }
pRec = (PEVENTLOGRECORD)Buffer; pRec->Length = RecSize; pRec->Reserved = LOGFILE_SIGNATURE;
/* * Do not assign here any precomputed record number to the event record. * The true record number will be assigned atomically and sequentially in * LogfWriteRecord, so that all the event records will have consistent and * unique record numbers. */ pRec->RecordNumber = 0;
/* * Set the generated time, and temporarily set the written time * with the generated time. */ pRec->TimeGenerated = Time; pRec->TimeWritten = Time;
pRec->EventID = dwEventId; pRec->EventType = wType; pRec->EventCategory = wCategory;
pos = sizeof(EVENTLOGRECORD);
/* NOTE: Equivalents of RtlStringCbCopyUnicodeString calls */ if (SourceNameSize) { StringCbCopyNW((PWSTR)(Buffer + pos), SourceNameSize + sizeof(UNICODE_NULL), SourceName->Buffer, SourceNameSize); } pos += SourceNameSize + sizeof(UNICODE_NULL); if (ComputerNameSize) { StringCbCopyNW((PWSTR)(Buffer + pos), ComputerNameSize + sizeof(UNICODE_NULL), ComputerName->Buffer, ComputerNameSize); } pos += ComputerNameSize + sizeof(UNICODE_NULL);
/* Align on DWORD boundary for the SID */ pos = ROUND_UP(pos, sizeof(ULONG));
pRec->UserSidLength = 0; pRec->UserSidOffset = 0; if (dwSidLength) { RtlCopyMemory(Buffer + pos, pUserSid, dwSidLength); pRec->UserSidLength = dwSidLength; pRec->UserSidOffset = pos; pos += dwSidLength; }
pRec->StringOffset = pos; for (i = 0, str = pStrings; i < wNumStrings; i++) { StringLen = wcslen(str) + 1; // str must be != NULL StringCchCopyW((PWSTR)(Buffer + pos), StringLen, str); str += StringLen; pos += StringLen * sizeof(WCHAR); } pRec->NumStrings = wNumStrings;
pRec->DataLength = 0; pRec->DataOffset = 0; if (dwDataSize) { RtlCopyMemory(Buffer + pos, pRawData, dwDataSize); pRec->DataLength = dwDataSize; pRec->DataOffset = pos; pos += dwDataSize; }
/* Align on DWORD boundary for the full structure */ pos = ROUND_UP(pos, sizeof(ULONG));
/* Initialize the trailing 'Length' member */ *((PDWORD)(Buffer + pos)) = RecSize;
*pRecSize = RecSize; return pRec;}
VOIDLogfReportEvent(USHORT wType, USHORT wCategory, ULONG dwEventId, USHORT wNumStrings, PWSTR pStrings, ULONG dwDataSize, PVOID pRawData){ NTSTATUS Status; UNICODE_STRING SourceName, ComputerName; PEVENTLOGRECORD LogBuffer; LARGE_INTEGER SystemTime; ULONG Time; SIZE_T RecSize; DWORD dwComputerNameLength; WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
if (!EventLogSource) return;
RtlInitUnicodeString(&SourceName, EventLogSource->szName);
dwComputerNameLength = ARRAYSIZE(szComputerName); if (!GetComputerNameW(szComputerName, &dwComputerNameLength)) szComputerName[0] = L'\0';
RtlInitUnicodeString(&ComputerName, szComputerName);
NtQuerySystemTime(&SystemTime); RtlTimeToSecondsSince1970(&SystemTime, &Time);
LogBuffer = LogfAllocAndBuildNewRecord(&RecSize, Time, wType, wCategory, dwEventId, &SourceName, &ComputerName, 0, NULL, wNumStrings, pStrings, dwDataSize, pRawData); if (LogBuffer == NULL) { DPRINT1("LogfAllocAndBuildNewRecord failed!\n"); return; }
Status = LogfWriteRecord(EventLogSource->LogFile, LogBuffer, RecSize); if (!NT_SUCCESS(Status)) { DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n", EventLogSource->LogFile->LogName, Status); }
LogfFreeRecord(LogBuffer);}