/* * PROJECT: ReactOS EventLog Service * LICENSE: GPL - See COPYING in the top level directory * FILE: base/services/eventlog/rpc.c * PURPOSE: RPC Port Interface support * COPYRIGHT: Copyright 2005 Saveliy Tretiakov * Copyright 2008 Michael Martin * Copyright 2010-2011 Eric Kohl */ /* INCLUDES *****************************************************************/ #include "eventlog.h" #define NDEBUG #include static LIST_ENTRY LogHandleListHead; static CRITICAL_SECTION LogHandleListCs; /* FUNCTIONS ****************************************************************/ static NTSTATUS ElfDeleteEventLogHandle(PIELF_HANDLE LogHandle); DWORD WINAPI RpcThreadRoutine(LPVOID lpParameter) { RPC_STATUS Status; InitializeCriticalSection(&LogHandleListCs); InitializeListHead(&LogHandleListHead); Status = RpcServerUseProtseqEpW(L"ncacn_np", 20, L"\\pipe\\EventLog", NULL); if (Status != RPC_S_OK) { DPRINT("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status); goto Quit; } Status = RpcServerRegisterIf(eventlog_v0_0_s_ifspec, NULL, NULL); if (Status != RPC_S_OK) { DPRINT("RpcServerRegisterIf() failed (Status %lx)\n", Status); goto Quit; } Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE); if (Status != RPC_S_OK) { DPRINT("RpcServerListen() failed (Status %lx)\n", Status); } EnterCriticalSection(&LogHandleListCs); while (!IsListEmpty(&LogHandleListHead)) { IELF_HANDLE LogHandle = (IELF_HANDLE)CONTAINING_RECORD(LogHandleListHead.Flink, LOGHANDLE, LogHandleListEntry); ElfDeleteEventLogHandle(&LogHandle); } LeaveCriticalSection(&LogHandleListCs); Quit: DeleteCriticalSection(&LogHandleListCs); return 0; } static NTSTATUS ElfCreateEventLogHandle(PLOGHANDLE* LogHandle, PUNICODE_STRING LogName, BOOLEAN Create) { NTSTATUS Status = STATUS_SUCCESS; PLOGHANDLE pLogHandle; PLOGFILE currentLogFile = NULL; DWORD i, LogsActive; PEVENTSOURCE pEventSource; DPRINT("ElfCreateEventLogHandle(%wZ)\n", LogName); *LogHandle = NULL; i = (LogName->Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR); pLogHandle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(LOGHANDLE, szName[i])); if (!pLogHandle) { DPRINT1("Failed to allocate Heap!\n"); return STATUS_NO_MEMORY; } StringCchCopyW(pLogHandle->szName, i, LogName->Buffer); /* Get the number of Log Files the EventLog service found */ // NOTE: We could just as well loop only once within the list of logs // and retrieve what the code below that calls LogfListItemByIndex, does!! LogsActive = LogfListItemCount(); if (LogsActive == 0) { DPRINT1("EventLog service reports no log files!\n"); Status = STATUS_UNSUCCESSFUL; goto Done; } /* If Creating, default to the Application Log in case we fail, as documented on MSDN */ if (Create) { pEventSource = GetEventSourceByName(LogName->Buffer); DPRINT("EventSource: %p\n", pEventSource); if (pEventSource) { DPRINT("EventSource LogFile: %p\n", pEventSource->LogFile); pLogHandle->LogFile = pEventSource->LogFile; } else { DPRINT("EventSource LogFile: Application log file\n"); pLogHandle->LogFile = LogfListItemByName(L"Application"); } DPRINT("LogHandle LogFile: %p\n", pLogHandle->LogFile); } else { pLogHandle->LogFile = NULL; for (i = 1; i <= LogsActive; i++) { currentLogFile = LogfListItemByIndex(i); if (_wcsicmp(LogName->Buffer, currentLogFile->LogName) == 0) { pLogHandle->LogFile = currentLogFile; break; } } /* Use the application log if the desired log does not exist */ if (pLogHandle->LogFile == NULL) { pLogHandle->LogFile = LogfListItemByName(L"Application"); if (pLogHandle->LogFile == NULL) { DPRINT1("Application log is missing!\n"); Status = STATUS_UNSUCCESSFUL; goto Done; } } /* Reset the current record */ pLogHandle->CurrentRecord = 0; } if (!pLogHandle->LogFile) Status = STATUS_UNSUCCESSFUL; Done: if (NT_SUCCESS(Status)) { /* Append log handle */ EnterCriticalSection(&LogHandleListCs); InsertTailList(&LogHandleListHead, &pLogHandle->LogHandleListEntry); LeaveCriticalSection(&LogHandleListCs); *LogHandle = pLogHandle; } else { HeapFree(GetProcessHeap(), 0, pLogHandle); } return Status; } static NTSTATUS ElfCreateBackupLogHandle(PLOGHANDLE* LogHandle, PUNICODE_STRING FileName) { NTSTATUS Status = STATUS_SUCCESS; PLOGHANDLE pLogHandle; DPRINT("ElfCreateBackupLogHandle(%wZ)\n", FileName); *LogHandle = NULL; pLogHandle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGHANDLE)); if (pLogHandle == NULL) { DPRINT1("Failed to allocate Heap!\n"); return STATUS_NO_MEMORY; } /* Create the log file */ Status = LogfCreate(&pLogHandle->LogFile, NULL, FileName, 0, 0, FALSE, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to create the log file! (Status 0x%08lx)\n", Status); goto Done; } /* Set the backup flag */ pLogHandle->Flags |= LOG_HANDLE_BACKUP_FILE; /* Reset the current record */ pLogHandle->CurrentRecord = 0; Done: if (NT_SUCCESS(Status)) { /* Append log handle */ EnterCriticalSection(&LogHandleListCs); InsertTailList(&LogHandleListHead, &pLogHandle->LogHandleListEntry); LeaveCriticalSection(&LogHandleListCs); *LogHandle = pLogHandle; } else { HeapFree(GetProcessHeap(), 0, pLogHandle); } return Status; } static PLOGHANDLE ElfGetLogHandleEntryByHandle(IELF_HANDLE EventLogHandle) { PLIST_ENTRY CurrentEntry; PLOGHANDLE Handle, pLogHandle = NULL; EnterCriticalSection(&LogHandleListCs); CurrentEntry = LogHandleListHead.Flink; while (CurrentEntry != &LogHandleListHead) { Handle = CONTAINING_RECORD(CurrentEntry, LOGHANDLE, LogHandleListEntry); CurrentEntry = CurrentEntry->Flink; if (Handle == EventLogHandle) { pLogHandle = Handle; break; } } LeaveCriticalSection(&LogHandleListCs); return pLogHandle; } static NTSTATUS ElfDeleteEventLogHandle(PIELF_HANDLE LogHandle) { PLOGHANDLE pLogHandle; pLogHandle = ElfGetLogHandleEntryByHandle(*LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; EnterCriticalSection(&LogHandleListCs); RemoveEntryList(&pLogHandle->LogHandleListEntry); LeaveCriticalSection(&LogHandleListCs); LogfClose(pLogHandle->LogFile, FALSE); HeapFree(GetProcessHeap(), 0, pLogHandle); *LogHandle = NULL; return STATUS_SUCCESS; } /* Function 0 */ NTSTATUS WINAPI ElfrClearELFW( IELF_HANDLE LogHandle, PRPC_UNICODE_STRING BackupFileName) { PLOGHANDLE pLogHandle; DPRINT("ElfrClearELFW()\n"); pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; /* Fail, if the log file is a backup file */ if (pLogHandle->Flags & LOG_HANDLE_BACKUP_FILE) return STATUS_INVALID_HANDLE; return LogfClearFile(pLogHandle->LogFile, (PUNICODE_STRING)BackupFileName); } /* Function 1 */ NTSTATUS WINAPI ElfrBackupELFW( IELF_HANDLE LogHandle, PRPC_UNICODE_STRING BackupFileName) { PLOGHANDLE pLogHandle; DPRINT("ElfrBackupELFW()\n"); pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; return LogfBackupFile(pLogHandle->LogFile, (PUNICODE_STRING)BackupFileName); } /* Function 2 */ NTSTATUS WINAPI ElfrCloseEL( PIELF_HANDLE LogHandle) { return ElfDeleteEventLogHandle(LogHandle); } /* Function 3 */ NTSTATUS WINAPI ElfrDeregisterEventSource( PIELF_HANDLE LogHandle) { return ElfDeleteEventLogHandle(LogHandle); } /* Function 4 */ NTSTATUS WINAPI ElfrNumberOfRecords( IELF_HANDLE LogHandle, PULONG NumberOfRecords) { PLOGHANDLE pLogHandle; PLOGFILE pLogFile; ULONG OldestRecordNumber, CurrentRecordNumber; DPRINT("ElfrNumberOfRecords()\n"); pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; if (!NumberOfRecords) return STATUS_INVALID_PARAMETER; pLogFile = pLogHandle->LogFile; /* Lock the log file shared */ RtlAcquireResourceShared(&pLogFile->Lock, TRUE); OldestRecordNumber = ElfGetOldestRecord(&pLogFile->LogFile); CurrentRecordNumber = ElfGetCurrentRecord(&pLogFile->LogFile); /* Unlock the log file */ RtlReleaseResource(&pLogFile->Lock); DPRINT("Oldest: %lu Current: %lu\n", OldestRecordNumber, CurrentRecordNumber); if (OldestRecordNumber == 0) { /* OldestRecordNumber == 0 when the log is empty */ *NumberOfRecords = 0; } else { /* The log contains events */ *NumberOfRecords = CurrentRecordNumber - OldestRecordNumber; } return STATUS_SUCCESS; } /* Function 5 */ NTSTATUS WINAPI ElfrOldestRecord( IELF_HANDLE LogHandle, PULONG OldestRecordNumber) { PLOGHANDLE pLogHandle; PLOGFILE pLogFile; pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; if (!OldestRecordNumber) return STATUS_INVALID_PARAMETER; pLogFile = pLogHandle->LogFile; /* Lock the log file shared */ RtlAcquireResourceShared(&pLogFile->Lock, TRUE); *OldestRecordNumber = ElfGetOldestRecord(&pLogFile->LogFile); /* Unlock the log file */ RtlReleaseResource(&pLogFile->Lock); return STATUS_SUCCESS; } /* Function 6 */ NTSTATUS WINAPI ElfrChangeNotify( IELF_HANDLE LogHandle, RPC_CLIENT_ID ClientId, ULONG Event) { UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED; } /* Function 7 */ NTSTATUS WINAPI ElfrOpenELW( EVENTLOG_HANDLE_W UNCServerName, PRPC_UNICODE_STRING ModuleName, PRPC_UNICODE_STRING RegModuleName, ULONG MajorVersion, ULONG MinorVersion, PIELF_HANDLE LogHandle) { if ((MajorVersion != 1) || (MinorVersion != 1)) return STATUS_INVALID_PARAMETER; /* RegModuleName must be an empty string */ if (RegModuleName->Length > 0) return STATUS_INVALID_PARAMETER; /* FIXME: UNCServerName must specify the server */ /* FIXME: Must verify that caller has read access */ return ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle, (PUNICODE_STRING)ModuleName, FALSE); } /* Function 8 */ NTSTATUS WINAPI ElfrRegisterEventSourceW( EVENTLOG_HANDLE_W UNCServerName, PRPC_UNICODE_STRING ModuleName, PRPC_UNICODE_STRING RegModuleName, ULONG MajorVersion, ULONG MinorVersion, PIELF_HANDLE LogHandle) { DPRINT("ElfrRegisterEventSourceW()\n"); if ((MajorVersion != 1) || (MinorVersion != 1)) return STATUS_INVALID_PARAMETER; /* RegModuleName must be an empty string */ if (RegModuleName->Length > 0) return STATUS_INVALID_PARAMETER; DPRINT("ModuleName: %wZ\n", ModuleName); /* FIXME: UNCServerName must specify the server or empty for local */ /* FIXME: Must verify that caller has write access */ return ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle, (PUNICODE_STRING)ModuleName, TRUE); } /* Function 9 */ NTSTATUS WINAPI ElfrOpenBELW( EVENTLOG_HANDLE_W UNCServerName, PRPC_UNICODE_STRING BackupFileName, ULONG MajorVersion, ULONG MinorVersion, PIELF_HANDLE LogHandle) { DPRINT("ElfrOpenBELW(%wZ)\n", BackupFileName); if ((MajorVersion != 1) || (MinorVersion != 1)) return STATUS_INVALID_PARAMETER; /* FIXME: UNCServerName must specify the server */ /* FIXME: Must verify that caller has read access */ return ElfCreateBackupLogHandle((PLOGHANDLE*)LogHandle, (PUNICODE_STRING)BackupFileName); } /* Function 10 */ NTSTATUS WINAPI ElfrReadELW( IELF_HANDLE LogHandle, ULONG ReadFlags, ULONG RecordOffset, RULONG NumberOfBytesToRead, PBYTE Buffer, PULONG NumberOfBytesRead, PULONG MinNumberOfBytesNeeded) { NTSTATUS Status; PLOGHANDLE pLogHandle; ULONG RecordNumber; pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; if (!Buffer) return STATUS_INVALID_PARAMETER; /* If sequential read, retrieve the CurrentRecord from this log handle */ if (ReadFlags & EVENTLOG_SEQUENTIAL_READ) { RecordNumber = pLogHandle->CurrentRecord; } else // (ReadFlags & EVENTLOG_SEEK_READ) { RecordNumber = RecordOffset; } Status = LogfReadEvents(pLogHandle->LogFile, ReadFlags, &RecordNumber, NumberOfBytesToRead, Buffer, NumberOfBytesRead, MinNumberOfBytesNeeded, FALSE); /* Update the handle's CurrentRecord if success */ if (NT_SUCCESS(Status)) { pLogHandle->CurrentRecord = RecordNumber; } return Status; } /* Helper function for ElfrReportEventW/A and ElfrReportEventAndSourceW */ NTSTATUS ElfrIntReportEventW( IELF_HANDLE LogHandle, ULONG Time, USHORT EventType, USHORT EventCategory, ULONG EventID, PRPC_UNICODE_STRING SourceName OPTIONAL, USHORT NumStrings, ULONG DataSize, PRPC_UNICODE_STRING ComputerName, PRPC_SID UserSID, PRPC_UNICODE_STRING Strings[], PBYTE Data, USHORT Flags, PULONG RecordNumber, PULONG TimeWritten) { NTSTATUS Status; PLOGHANDLE pLogHandle; UNICODE_STRING LocalSourceName, LocalComputerName; PEVENTLOGRECORD LogBuffer; USHORT i; SIZE_T RecSize; ULONG dwStringsSize = 0; ULONG dwUserSidLength = 0; PWSTR lpStrings, str; pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; /* Flags must be 0 */ if (Flags) return STATUS_INVALID_PARAMETER; for (i = 0; i < NumStrings; i++) { switch (EventType) { case EVENTLOG_SUCCESS: DPRINT("Success: %wZ\n", Strings[i]); break; case EVENTLOG_ERROR_TYPE: DPRINT("Error: %wZ\n", Strings[i]); break; case EVENTLOG_WARNING_TYPE: DPRINT("Warning: %wZ\n", Strings[i]); break; case EVENTLOG_INFORMATION_TYPE: DPRINT("Info: %wZ\n", Strings[i]); break; case EVENTLOG_AUDIT_SUCCESS: DPRINT("Audit Success: %wZ\n", Strings[i]); break; case EVENTLOG_AUDIT_FAILURE: DPRINT("Audit Failure: %wZ\n", Strings[i]); break; default: DPRINT1("Type %hu: %wZ\n", EventType, Strings[i]); break; } dwStringsSize += Strings[i]->Length + sizeof(UNICODE_NULL); } lpStrings = HeapAlloc(GetProcessHeap(), 0, dwStringsSize); if (!lpStrings) { DPRINT1("Failed to allocate heap\n"); return STATUS_NO_MEMORY; } str = lpStrings; for (i = 0; i < NumStrings; i++) { RtlCopyMemory(str, Strings[i]->Buffer, Strings[i]->Length); str += Strings[i]->Length / sizeof(WCHAR); *str = UNICODE_NULL; str++; } if (UserSID) dwUserSidLength = FIELD_OFFSET(SID, SubAuthority[UserSID->SubAuthorityCount]); if (SourceName && SourceName->Buffer) LocalSourceName = *(PUNICODE_STRING)SourceName; else RtlInitUnicodeString(&LocalSourceName, pLogHandle->szName); LocalComputerName = *(PUNICODE_STRING)ComputerName; LogBuffer = LogfAllocAndBuildNewRecord(&RecSize, Time, EventType, EventCategory, EventID, &LocalSourceName, &LocalComputerName, dwUserSidLength, UserSID, NumStrings, lpStrings, DataSize, Data); if (LogBuffer == NULL) { DPRINT1("LogfAllocAndBuildNewRecord failed!\n"); HeapFree(GetProcessHeap(), 0, lpStrings); return STATUS_NO_MEMORY; } Status = LogfWriteRecord(pLogHandle->LogFile, LogBuffer, RecSize); if (!NT_SUCCESS(Status)) { DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n", pLogHandle->LogFile->LogName, Status); } if (NT_SUCCESS(Status)) { /* Retrieve the two fields that were set by LogfWriteRecord into the record */ if (RecordNumber) *RecordNumber = LogBuffer->RecordNumber; if (TimeWritten) *TimeWritten = LogBuffer->TimeWritten; } LogfFreeRecord(LogBuffer); HeapFree(GetProcessHeap(), 0, lpStrings); return Status; } /* Function 11 */ NTSTATUS WINAPI ElfrReportEventW( IELF_HANDLE LogHandle, ULONG Time, USHORT EventType, USHORT EventCategory, ULONG EventID, USHORT NumStrings, ULONG DataSize, PRPC_UNICODE_STRING ComputerName, PRPC_SID UserSID, PRPC_UNICODE_STRING Strings[], PBYTE Data, USHORT Flags, PULONG RecordNumber, PULONG TimeWritten) { /* Call the helper function. The event source is provided via the log handle. */ return ElfrIntReportEventW(LogHandle, Time, EventType, EventCategory, EventID, NULL, NumStrings, DataSize, ComputerName, UserSID, Strings, Data, Flags, RecordNumber, TimeWritten); } /* Function 12 */ NTSTATUS WINAPI ElfrClearELFA( IELF_HANDLE LogHandle, PRPC_STRING BackupFileName) { NTSTATUS Status; UNICODE_STRING BackupFileNameW; Status = RtlAnsiStringToUnicodeString(&BackupFileNameW, (PANSI_STRING)BackupFileName, TRUE); if (!NT_SUCCESS(Status)) return Status; Status = ElfrClearELFW(LogHandle, (PRPC_UNICODE_STRING)&BackupFileNameW); RtlFreeUnicodeString(&BackupFileNameW); return Status; } /* Function 13 */ NTSTATUS WINAPI ElfrBackupELFA( IELF_HANDLE LogHandle, PRPC_STRING BackupFileName) { NTSTATUS Status; UNICODE_STRING BackupFileNameW; Status = RtlAnsiStringToUnicodeString(&BackupFileNameW, (PANSI_STRING)BackupFileName, TRUE); if (!NT_SUCCESS(Status)) return Status; Status = ElfrBackupELFW(LogHandle, (PRPC_UNICODE_STRING)&BackupFileNameW); RtlFreeUnicodeString(&BackupFileNameW); return Status; } /* Function 14 */ NTSTATUS WINAPI ElfrOpenELA( EVENTLOG_HANDLE_A UNCServerName, PRPC_STRING ModuleName, PRPC_STRING RegModuleName, ULONG MajorVersion, ULONG MinorVersion, PIELF_HANDLE LogHandle) { NTSTATUS Status; UNICODE_STRING ModuleNameW; if ((MajorVersion != 1) || (MinorVersion != 1)) return STATUS_INVALID_PARAMETER; /* RegModuleName must be an empty string */ if (RegModuleName->Length > 0) return STATUS_INVALID_PARAMETER; Status = RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE); if (!NT_SUCCESS(Status)) return Status; /* FIXME: Must verify that caller has read access */ Status = ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle, &ModuleNameW, FALSE); RtlFreeUnicodeString(&ModuleNameW); return Status; } /* Function 15 */ NTSTATUS WINAPI ElfrRegisterEventSourceA( EVENTLOG_HANDLE_A UNCServerName, PRPC_STRING ModuleName, PRPC_STRING RegModuleName, ULONG MajorVersion, ULONG MinorVersion, PIELF_HANDLE LogHandle) { NTSTATUS Status; UNICODE_STRING ModuleNameW; Status = RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("RtlAnsiStringToUnicodeString failed (Status 0x%08lx)\n", Status); return Status; } /* RegModuleName must be an empty string */ if (RegModuleName->Length > 0) { RtlFreeUnicodeString(&ModuleNameW); return STATUS_INVALID_PARAMETER; } if ((MajorVersion != 1) || (MinorVersion != 1)) { RtlFreeUnicodeString(&ModuleNameW); return STATUS_INVALID_PARAMETER; } /* FIXME: Must verify that caller has write access */ Status = ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle, &ModuleNameW, TRUE); RtlFreeUnicodeString(&ModuleNameW); return Status; } /* Function 16 */ NTSTATUS WINAPI ElfrOpenBELA( EVENTLOG_HANDLE_A UNCServerName, PRPC_STRING BackupFileName, ULONG MajorVersion, ULONG MinorVersion, PIELF_HANDLE LogHandle) { NTSTATUS Status; UNICODE_STRING BackupFileNameW; DPRINT("ElfrOpenBELA(%Z)\n", BackupFileName); Status = RtlAnsiStringToUnicodeString(&BackupFileNameW, (PANSI_STRING)BackupFileName, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("RtlAnsiStringToUnicodeString failed (Status 0x%08lx)\n", Status); return Status; } if ((MajorVersion != 1) || (MinorVersion != 1)) { RtlFreeUnicodeString(&BackupFileNameW); return STATUS_INVALID_PARAMETER; } /* FIXME: UNCServerName must specify the server */ /* FIXME: Must verify that caller has read access */ Status = ElfCreateBackupLogHandle((PLOGHANDLE*)LogHandle, &BackupFileNameW); RtlFreeUnicodeString(&BackupFileNameW); return Status; } /* Function 17 */ NTSTATUS WINAPI ElfrReadELA( IELF_HANDLE LogHandle, ULONG ReadFlags, ULONG RecordOffset, RULONG NumberOfBytesToRead, PBYTE Buffer, PULONG NumberOfBytesRead, PULONG MinNumberOfBytesNeeded) { NTSTATUS Status; PLOGHANDLE pLogHandle; ULONG RecordNumber; pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; if (!Buffer) return STATUS_INVALID_PARAMETER; /* If sequential read, retrieve the CurrentRecord from this log handle */ if (ReadFlags & EVENTLOG_SEQUENTIAL_READ) { RecordNumber = pLogHandle->CurrentRecord; } else // (ReadFlags & EVENTLOG_SEEK_READ) { RecordNumber = RecordOffset; } Status = LogfReadEvents(pLogHandle->LogFile, ReadFlags, &RecordNumber, NumberOfBytesToRead, Buffer, NumberOfBytesRead, MinNumberOfBytesNeeded, TRUE); /* Update the handle's CurrentRecord if success */ if (NT_SUCCESS(Status)) { pLogHandle->CurrentRecord = RecordNumber; } return Status; } /* Function 18 */ NTSTATUS WINAPI ElfrReportEventA( IELF_HANDLE LogHandle, ULONG Time, USHORT EventType, USHORT EventCategory, ULONG EventID, USHORT NumStrings, ULONG DataSize, PRPC_STRING ComputerName, PRPC_SID UserSID, PRPC_STRING Strings[], PBYTE Data, USHORT Flags, PULONG RecordNumber, PULONG TimeWritten) { NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING ComputerNameW; PUNICODE_STRING *StringsArrayW = NULL; USHORT i; DPRINT("ElfrReportEventA(%hu)\n", NumStrings); #if 0 for (i = 0; i < NumStrings; i++) { if (Strings[i] == NULL) { DPRINT1("String %hu is null\n", i); } else { DPRINT1("String %hu: %Z\n", i, Strings[i]); } } #endif Status = RtlAnsiStringToUnicodeString((PUNICODE_STRING)&ComputerNameW, (PANSI_STRING)ComputerName, TRUE); if (!NT_SUCCESS(Status)) return Status; if (NumStrings != 0) { StringsArrayW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, NumStrings * sizeof(PUNICODE_STRING)); if (StringsArrayW == NULL) { Status = STATUS_NO_MEMORY; goto Done; } for (i = 0; i < NumStrings; i++) { if (Strings[i] != NULL) { StringsArrayW[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(UNICODE_STRING)); if (StringsArrayW[i] == NULL) { Status = STATUS_NO_MEMORY; break; } Status = RtlAnsiStringToUnicodeString(StringsArrayW[i], (PANSI_STRING)Strings[i], TRUE); } if (!NT_SUCCESS(Status)) break; } } if (NT_SUCCESS(Status)) { Status = ElfrReportEventW(LogHandle, Time, EventType, EventCategory, EventID, NumStrings, DataSize, (PRPC_UNICODE_STRING)&ComputerNameW, UserSID, (PRPC_UNICODE_STRING*)StringsArrayW, Data, Flags, RecordNumber, TimeWritten); } Done: if (StringsArrayW != NULL) { for (i = 0; i < NumStrings; i++) { if ((StringsArrayW[i] != NULL) && (StringsArrayW[i]->Buffer)) { RtlFreeUnicodeString(StringsArrayW[i]); HeapFree(GetProcessHeap(), 0, StringsArrayW[i]); } } HeapFree(GetProcessHeap(), 0, StringsArrayW); } RtlFreeUnicodeString(&ComputerNameW); return Status; } /* Function 19 */ NTSTATUS WINAPI ElfrRegisterClusterSvc( handle_t BindingHandle) { UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED; } /* Function 20 */ NTSTATUS WINAPI ElfrDeregisterClusterSvc( handle_t BindingHandle) { UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED; } /* Function 21 */ NTSTATUS WINAPI ElfrWriteClusterEvents( handle_t BindingHandle) { UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED; } /* Function 22 */ NTSTATUS WINAPI ElfrGetLogInformation( IELF_HANDLE LogHandle, ULONG InfoLevel, PBYTE Buffer, ULONG cbBufSize, PULONG pcbBytesNeeded) { NTSTATUS Status = STATUS_SUCCESS; PLOGHANDLE pLogHandle; PLOGFILE pLogFile; pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; pLogFile = pLogHandle->LogFile; /* Lock the log file shared */ RtlAcquireResourceShared(&pLogFile->Lock, TRUE); switch (InfoLevel) { case EVENTLOG_FULL_INFO: { LPEVENTLOG_FULL_INFORMATION efi = (LPEVENTLOG_FULL_INFORMATION)Buffer; *pcbBytesNeeded = sizeof(EVENTLOG_FULL_INFORMATION); if (cbBufSize < sizeof(EVENTLOG_FULL_INFORMATION)) { Status = STATUS_BUFFER_TOO_SMALL; break; } efi->dwFull = !!(ElfGetFlags(&pLogFile->LogFile) & ELF_LOGFILE_LOGFULL_WRITTEN); break; } default: Status = STATUS_INVALID_LEVEL; break; } /* Unlock the log file */ RtlReleaseResource(&pLogFile->Lock); return Status; } /* Function 23 */ NTSTATUS WINAPI ElfrFlushEL( IELF_HANDLE LogHandle) { NTSTATUS Status; PLOGHANDLE pLogHandle; PLOGFILE pLogFile; pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle); if (!pLogHandle) return STATUS_INVALID_HANDLE; pLogFile = pLogHandle->LogFile; /* Lock the log file exclusive */ RtlAcquireResourceExclusive(&pLogFile->Lock, TRUE); Status = ElfFlushFile(&pLogFile->LogFile); /* Unlock the log file */ RtlReleaseResource(&pLogFile->Lock); return Status; } /* Function 24 */ NTSTATUS WINAPI ElfrReportEventAndSourceW( IELF_HANDLE LogHandle, ULONG Time, USHORT EventType, USHORT EventCategory, ULONG EventID, PRPC_UNICODE_STRING SourceName, USHORT NumStrings, ULONG DataSize, PRPC_UNICODE_STRING ComputerName, PRPC_SID UserSID, PRPC_UNICODE_STRING Strings[], PBYTE Data, USHORT Flags, PULONG RecordNumber, PULONG TimeWritten) { /* Call the helper function. The event source is specified by the caller. */ return ElfrIntReportEventW(LogHandle, Time, EventType, EventCategory, EventID, SourceName, NumStrings, DataSize, ComputerName, UserSID, Strings, Data, Flags, RecordNumber, TimeWritten); } void __RPC_FAR *__RPC_USER midl_user_allocate(SIZE_T len) { return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); } void __RPC_USER midl_user_free(void __RPC_FAR * ptr) { HeapFree(GetProcessHeap(), 0, ptr); } void __RPC_USER IELF_HANDLE_rundown(IELF_HANDLE LogHandle) { /* Close the handle */ ElfDeleteEventLogHandle(&LogHandle); // ElfrCloseEL(&LogHandle); }