xref: /reactos/base/services/eventlog/rpc.c (revision 1734f297)
1 /*
2  * PROJECT:         ReactOS EventLog Service
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            base/services/eventlog/rpc.c
5  * PURPOSE:         RPC Port Interface support
6  * COPYRIGHT:       Copyright 2005 Saveliy Tretiakov
7  *                  Copyright 2008 Michael Martin
8  *                  Copyright 2010-2011 Eric Kohl
9  */
10 
11 /* INCLUDES *****************************************************************/
12 
13 #include "eventlog.h"
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 static LIST_ENTRY LogHandleListHead;
19 static CRITICAL_SECTION LogHandleListCs;
20 
21 /* FUNCTIONS ****************************************************************/
22 
23 static NTSTATUS
24 ElfDeleteEventLogHandle(PIELF_HANDLE LogHandle);
25 
26 DWORD WINAPI RpcThreadRoutine(LPVOID lpParameter)
27 {
28     RPC_STATUS Status;
29 
30     InitializeCriticalSection(&LogHandleListCs);
31     InitializeListHead(&LogHandleListHead);
32 
33     Status = RpcServerUseProtseqEpW(L"ncacn_np", 20, L"\\pipe\\EventLog", NULL);
34     if (Status != RPC_S_OK)
35     {
36         DPRINT("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
37         goto Quit;
38     }
39 
40     Status = RpcServerRegisterIf(eventlog_v0_0_s_ifspec, NULL, NULL);
41     if (Status != RPC_S_OK)
42     {
43         DPRINT("RpcServerRegisterIf() failed (Status %lx)\n", Status);
44         goto Quit;
45     }
46 
47     Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
48     if (Status != RPC_S_OK)
49     {
50         DPRINT("RpcServerListen() failed (Status %lx)\n", Status);
51     }
52 
53     EnterCriticalSection(&LogHandleListCs);
54     while (!IsListEmpty(&LogHandleListHead))
55     {
56         IELF_HANDLE LogHandle = (IELF_HANDLE)CONTAINING_RECORD(LogHandleListHead.Flink, LOGHANDLE, LogHandleListEntry);
57         ElfDeleteEventLogHandle(&LogHandle);
58     }
59     LeaveCriticalSection(&LogHandleListCs);
60 
61 Quit:
62     DeleteCriticalSection(&LogHandleListCs);
63 
64     return 0;
65 }
66 
67 
68 static NTSTATUS
69 ElfCreateEventLogHandle(PLOGHANDLE* LogHandle,
70                         PUNICODE_STRING LogName,
71                         BOOLEAN Create)
72 {
73     NTSTATUS Status = STATUS_SUCCESS;
74     PLOGHANDLE pLogHandle;
75     PLOGFILE currentLogFile = NULL;
76     DWORD i, LogsActive;
77     PEVENTSOURCE pEventSource;
78 
79     DPRINT("ElfCreateEventLogHandle(%wZ)\n", LogName);
80 
81     *LogHandle = NULL;
82 
83     i = (LogName->Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
84     pLogHandle = HeapAlloc(GetProcessHeap(),
85                            HEAP_ZERO_MEMORY,
86                            FIELD_OFFSET(LOGHANDLE, szName[i]));
87     if (!pLogHandle)
88     {
89         DPRINT1("Failed to allocate Heap!\n");
90         return STATUS_NO_MEMORY;
91     }
92 
93     StringCchCopyW(pLogHandle->szName, i, LogName->Buffer);
94 
95     /* Get the number of Log Files the EventLog service found */
96     // NOTE: We could just as well loop only once within the list of logs
97     // and retrieve what the code below that calls LogfListItemByIndex, does!!
98     LogsActive = LogfListItemCount();
99     if (LogsActive == 0)
100     {
101         DPRINT1("EventLog service reports no log files!\n");
102         Status = STATUS_UNSUCCESSFUL;
103         goto Done;
104     }
105 
106     /* If Creating, default to the Application Log in case we fail, as documented on MSDN */
107     if (Create)
108     {
109         pEventSource = GetEventSourceByName(LogName->Buffer);
110         DPRINT("EventSource: %p\n", pEventSource);
111         if (pEventSource)
112         {
113             DPRINT("EventSource LogFile: %p\n", pEventSource->LogFile);
114             pLogHandle->LogFile = pEventSource->LogFile;
115         }
116         else
117         {
118             DPRINT("EventSource LogFile: Application log file\n");
119             pLogHandle->LogFile = LogfListItemByName(L"Application");
120         }
121 
122         DPRINT("LogHandle LogFile: %p\n", pLogHandle->LogFile);
123     }
124     else
125     {
126         pLogHandle->LogFile = NULL;
127 
128         for (i = 1; i <= LogsActive; i++)
129         {
130             currentLogFile = LogfListItemByIndex(i);
131 
132             if (_wcsicmp(LogName->Buffer, currentLogFile->LogName) == 0)
133             {
134                 pLogHandle->LogFile = currentLogFile;
135                 break;
136             }
137         }
138 
139         /* Use the application log if the desired log does not exist */
140         if (pLogHandle->LogFile == NULL)
141         {
142             pLogHandle->LogFile = LogfListItemByName(L"Application");
143             if (pLogHandle->LogFile == NULL)
144             {
145                 DPRINT1("Application log is missing!\n");
146                 Status = STATUS_UNSUCCESSFUL;
147                 goto Done;
148             }
149         }
150 
151         /* Reset the current record */
152         pLogHandle->CurrentRecord = 0;
153     }
154 
155     if (!pLogHandle->LogFile)
156         Status = STATUS_UNSUCCESSFUL;
157 
158 Done:
159     if (NT_SUCCESS(Status))
160     {
161         /* Append log handle */
162         EnterCriticalSection(&LogHandleListCs);
163         InsertTailList(&LogHandleListHead, &pLogHandle->LogHandleListEntry);
164         LeaveCriticalSection(&LogHandleListCs);
165         *LogHandle = pLogHandle;
166     }
167     else
168     {
169         HeapFree(GetProcessHeap(), 0, pLogHandle);
170     }
171 
172     return Status;
173 }
174 
175 
176 static NTSTATUS
177 ElfCreateBackupLogHandle(PLOGHANDLE* LogHandle,
178                          PUNICODE_STRING FileName)
179 {
180     NTSTATUS Status = STATUS_SUCCESS;
181     PLOGHANDLE pLogHandle;
182 
183     DPRINT("ElfCreateBackupLogHandle(%wZ)\n", FileName);
184 
185     *LogHandle = NULL;
186 
187     pLogHandle = HeapAlloc(GetProcessHeap(),
188                            HEAP_ZERO_MEMORY,
189                            sizeof(LOGHANDLE));
190     if (pLogHandle == NULL)
191     {
192         DPRINT1("Failed to allocate Heap!\n");
193         return STATUS_NO_MEMORY;
194     }
195 
196     /* Create the log file */
197     Status = LogfCreate(&pLogHandle->LogFile,
198                         NULL,
199                         FileName,
200                         0,
201                         0,
202                         FALSE,
203                         TRUE);
204     if (!NT_SUCCESS(Status))
205     {
206         DPRINT1("Failed to create the log file! (Status 0x%08lx)\n", Status);
207         goto Done;
208     }
209 
210     /* Set the backup flag */
211     pLogHandle->Flags |= LOG_HANDLE_BACKUP_FILE;
212 
213     /* Reset the current record */
214     pLogHandle->CurrentRecord = 0;
215 
216 Done:
217     if (NT_SUCCESS(Status))
218     {
219         /* Append log handle */
220         EnterCriticalSection(&LogHandleListCs);
221         InsertTailList(&LogHandleListHead, &pLogHandle->LogHandleListEntry);
222         LeaveCriticalSection(&LogHandleListCs);
223         *LogHandle = pLogHandle;
224     }
225     else
226     {
227         HeapFree(GetProcessHeap(), 0, pLogHandle);
228     }
229 
230     return Status;
231 }
232 
233 
234 static PLOGHANDLE
235 ElfGetLogHandleEntryByHandle(IELF_HANDLE EventLogHandle)
236 {
237     PLIST_ENTRY CurrentEntry;
238     PLOGHANDLE Handle, pLogHandle = NULL;
239 
240     EnterCriticalSection(&LogHandleListCs);
241 
242     CurrentEntry = LogHandleListHead.Flink;
243     while (CurrentEntry != &LogHandleListHead)
244     {
245         Handle = CONTAINING_RECORD(CurrentEntry,
246                                    LOGHANDLE,
247                                    LogHandleListEntry);
248         CurrentEntry = CurrentEntry->Flink;
249 
250         if (Handle == EventLogHandle)
251         {
252             pLogHandle = Handle;
253             break;
254         }
255     }
256 
257     LeaveCriticalSection(&LogHandleListCs);
258 
259     return pLogHandle;
260 }
261 
262 
263 static NTSTATUS
264 ElfDeleteEventLogHandle(PIELF_HANDLE LogHandle)
265 {
266     PLOGHANDLE pLogHandle;
267 
268     pLogHandle = ElfGetLogHandleEntryByHandle(*LogHandle);
269     if (!pLogHandle)
270         return STATUS_INVALID_HANDLE;
271 
272     EnterCriticalSection(&LogHandleListCs);
273     RemoveEntryList(&pLogHandle->LogHandleListEntry);
274     LeaveCriticalSection(&LogHandleListCs);
275 
276     LogfClose(pLogHandle->LogFile, FALSE);
277 
278     HeapFree(GetProcessHeap(), 0, pLogHandle);
279 
280     *LogHandle = NULL;
281 
282     return STATUS_SUCCESS;
283 }
284 
285 
286 /* Function 0 */
287 NTSTATUS
288 WINAPI
289 ElfrClearELFW(
290     IELF_HANDLE LogHandle,
291     PRPC_UNICODE_STRING BackupFileName)
292 {
293     PLOGHANDLE pLogHandle;
294 
295     DPRINT("ElfrClearELFW()\n");
296 
297     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
298     if (!pLogHandle)
299         return STATUS_INVALID_HANDLE;
300 
301     /* Fail, if the log file is a backup file */
302     if (pLogHandle->Flags & LOG_HANDLE_BACKUP_FILE)
303         return STATUS_INVALID_HANDLE;
304 
305     return LogfClearFile(pLogHandle->LogFile,
306                          (PUNICODE_STRING)BackupFileName);
307 }
308 
309 
310 /* Function 1 */
311 NTSTATUS
312 WINAPI
313 ElfrBackupELFW(
314     IELF_HANDLE LogHandle,
315     PRPC_UNICODE_STRING BackupFileName)
316 {
317     PLOGHANDLE pLogHandle;
318 
319     DPRINT("ElfrBackupELFW()\n");
320 
321     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
322     if (!pLogHandle)
323         return STATUS_INVALID_HANDLE;
324 
325     return LogfBackupFile(pLogHandle->LogFile,
326                           (PUNICODE_STRING)BackupFileName);
327 }
328 
329 
330 /* Function 2 */
331 NTSTATUS
332 WINAPI
333 ElfrCloseEL(
334     PIELF_HANDLE LogHandle)
335 {
336     return ElfDeleteEventLogHandle(LogHandle);
337 }
338 
339 
340 /* Function 3 */
341 NTSTATUS
342 WINAPI
343 ElfrDeregisterEventSource(
344     PIELF_HANDLE LogHandle)
345 {
346     return ElfDeleteEventLogHandle(LogHandle);
347 }
348 
349 
350 /* Function 4 */
351 NTSTATUS
352 WINAPI
353 ElfrNumberOfRecords(
354     IELF_HANDLE LogHandle,
355     PULONG NumberOfRecords)
356 {
357     PLOGHANDLE pLogHandle;
358     PLOGFILE pLogFile;
359     ULONG OldestRecordNumber, CurrentRecordNumber;
360 
361     DPRINT("ElfrNumberOfRecords()\n");
362 
363     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
364     if (!pLogHandle)
365         return STATUS_INVALID_HANDLE;
366 
367     if (!NumberOfRecords)
368         return STATUS_INVALID_PARAMETER;
369 
370     pLogFile = pLogHandle->LogFile;
371 
372     /* Lock the log file shared */
373     RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
374 
375     OldestRecordNumber  = ElfGetOldestRecord(&pLogFile->LogFile);
376     CurrentRecordNumber = ElfGetCurrentRecord(&pLogFile->LogFile);
377 
378     /* Unlock the log file */
379     RtlReleaseResource(&pLogFile->Lock);
380 
381     DPRINT("Oldest: %lu  Current: %lu\n",
382            OldestRecordNumber, CurrentRecordNumber);
383 
384     if (OldestRecordNumber == 0)
385     {
386         /* OldestRecordNumber == 0 when the log is empty */
387         *NumberOfRecords = 0;
388     }
389     else
390     {
391         /* The log contains events */
392         *NumberOfRecords = CurrentRecordNumber - OldestRecordNumber;
393     }
394 
395     return STATUS_SUCCESS;
396 }
397 
398 
399 /* Function 5 */
400 NTSTATUS
401 WINAPI
402 ElfrOldestRecord(
403     IELF_HANDLE LogHandle,
404     PULONG OldestRecordNumber)
405 {
406     PLOGHANDLE pLogHandle;
407     PLOGFILE pLogFile;
408 
409     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
410     if (!pLogHandle)
411         return STATUS_INVALID_HANDLE;
412 
413     if (!OldestRecordNumber)
414         return STATUS_INVALID_PARAMETER;
415 
416     pLogFile = pLogHandle->LogFile;
417 
418     /* Lock the log file shared */
419     RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
420 
421     *OldestRecordNumber = ElfGetOldestRecord(&pLogFile->LogFile);
422 
423     /* Unlock the log file */
424     RtlReleaseResource(&pLogFile->Lock);
425 
426     return STATUS_SUCCESS;
427 }
428 
429 
430 /* Function 6 */
431 NTSTATUS
432 WINAPI
433 ElfrChangeNotify(
434     IELF_HANDLE LogHandle,
435     RPC_CLIENT_ID ClientId,
436     ULONG Event)
437 {
438     UNIMPLEMENTED;
439     return STATUS_NOT_IMPLEMENTED;
440 }
441 
442 
443 /* Function 7 */
444 NTSTATUS
445 WINAPI
446 ElfrOpenELW(
447     EVENTLOG_HANDLE_W UNCServerName,
448     PRPC_UNICODE_STRING ModuleName,
449     PRPC_UNICODE_STRING RegModuleName,
450     ULONG MajorVersion,
451     ULONG MinorVersion,
452     PIELF_HANDLE LogHandle)
453 {
454     if ((MajorVersion != 1) || (MinorVersion != 1))
455         return STATUS_INVALID_PARAMETER;
456 
457     /* RegModuleName must be an empty string */
458     if (RegModuleName->Length > 0)
459         return STATUS_INVALID_PARAMETER;
460 
461     /* FIXME: UNCServerName must specify the server */
462 
463     /* FIXME: Must verify that caller has read access */
464 
465     return ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle,
466                                    (PUNICODE_STRING)ModuleName,
467                                    FALSE);
468 }
469 
470 
471 /* Function 8 */
472 NTSTATUS
473 WINAPI
474 ElfrRegisterEventSourceW(
475     EVENTLOG_HANDLE_W UNCServerName,
476     PRPC_UNICODE_STRING ModuleName,
477     PRPC_UNICODE_STRING RegModuleName,
478     ULONG MajorVersion,
479     ULONG MinorVersion,
480     PIELF_HANDLE LogHandle)
481 {
482     DPRINT("ElfrRegisterEventSourceW()\n");
483 
484     if ((MajorVersion != 1) || (MinorVersion != 1))
485         return STATUS_INVALID_PARAMETER;
486 
487     /* RegModuleName must be an empty string */
488     if (RegModuleName->Length > 0)
489         return STATUS_INVALID_PARAMETER;
490 
491     DPRINT("ModuleName: %wZ\n", ModuleName);
492 
493     /* FIXME: UNCServerName must specify the server or empty for local */
494 
495     /* FIXME: Must verify that caller has write access */
496 
497     return ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle,
498                                    (PUNICODE_STRING)ModuleName,
499                                    TRUE);
500 }
501 
502 
503 /* Function 9 */
504 NTSTATUS
505 WINAPI
506 ElfrOpenBELW(
507     EVENTLOG_HANDLE_W UNCServerName,
508     PRPC_UNICODE_STRING BackupFileName,
509     ULONG MajorVersion,
510     ULONG MinorVersion,
511     PIELF_HANDLE LogHandle)
512 {
513     DPRINT("ElfrOpenBELW(%wZ)\n", BackupFileName);
514 
515     if ((MajorVersion != 1) || (MinorVersion != 1))
516         return STATUS_INVALID_PARAMETER;
517 
518     /* FIXME: UNCServerName must specify the server */
519 
520     /* FIXME: Must verify that caller has read access */
521 
522     return ElfCreateBackupLogHandle((PLOGHANDLE*)LogHandle,
523                                     (PUNICODE_STRING)BackupFileName);
524 }
525 
526 
527 /* Function 10 */
528 NTSTATUS
529 WINAPI
530 ElfrReadELW(
531     IELF_HANDLE LogHandle,
532     ULONG ReadFlags,
533     ULONG RecordOffset,
534     RULONG NumberOfBytesToRead,
535     PBYTE Buffer,
536     PULONG NumberOfBytesRead,
537     PULONG MinNumberOfBytesNeeded)
538 {
539     NTSTATUS Status;
540     PLOGHANDLE pLogHandle;
541     ULONG RecordNumber;
542 
543     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
544     if (!pLogHandle)
545         return STATUS_INVALID_HANDLE;
546 
547     if (!Buffer)
548         return STATUS_INVALID_PARAMETER;
549 
550     /* If sequential read, retrieve the CurrentRecord from this log handle */
551     if (ReadFlags & EVENTLOG_SEQUENTIAL_READ)
552     {
553         RecordNumber = pLogHandle->CurrentRecord;
554     }
555     else // (ReadFlags & EVENTLOG_SEEK_READ)
556     {
557         RecordNumber = RecordOffset;
558     }
559 
560     Status = LogfReadEvents(pLogHandle->LogFile,
561                             ReadFlags,
562                             &RecordNumber,
563                             NumberOfBytesToRead,
564                             Buffer,
565                             NumberOfBytesRead,
566                             MinNumberOfBytesNeeded,
567                             FALSE);
568 
569     /* Update the handle's CurrentRecord if success */
570     if (NT_SUCCESS(Status))
571     {
572         pLogHandle->CurrentRecord = RecordNumber;
573     }
574 
575     return Status;
576 }
577 
578 
579 /* Helper function for ElfrReportEventW/A and ElfrReportEventAndSourceW */
580 NTSTATUS
581 ElfrIntReportEventW(
582     IELF_HANDLE LogHandle,
583     ULONG Time,
584     USHORT EventType,
585     USHORT EventCategory,
586     ULONG EventID,
587     PRPC_UNICODE_STRING SourceName OPTIONAL,
588     USHORT NumStrings,
589     ULONG DataSize,
590     PRPC_UNICODE_STRING ComputerName,
591     PRPC_SID UserSID,
592     PRPC_UNICODE_STRING Strings[],
593     PBYTE Data,
594     USHORT Flags,
595     PULONG RecordNumber,
596     PULONG TimeWritten)
597 {
598     NTSTATUS Status;
599     PLOGHANDLE pLogHandle;
600     UNICODE_STRING LocalSourceName, LocalComputerName;
601     PEVENTLOGRECORD LogBuffer;
602     USHORT i;
603     SIZE_T RecSize;
604     ULONG dwStringsSize = 0;
605     ULONG dwUserSidLength = 0;
606     PWSTR lpStrings, str;
607 
608     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
609     if (!pLogHandle)
610         return STATUS_INVALID_HANDLE;
611 
612     /* Flags must be 0 */
613     if (Flags)
614         return STATUS_INVALID_PARAMETER;
615 
616     for (i = 0; i < NumStrings; i++)
617     {
618         switch (EventType)
619         {
620             case EVENTLOG_SUCCESS:
621                 DPRINT("Success: %wZ\n", Strings[i]);
622                 break;
623 
624             case EVENTLOG_ERROR_TYPE:
625                 DPRINT("Error: %wZ\n", Strings[i]);
626                 break;
627 
628             case EVENTLOG_WARNING_TYPE:
629                 DPRINT("Warning: %wZ\n", Strings[i]);
630                 break;
631 
632             case EVENTLOG_INFORMATION_TYPE:
633                 DPRINT("Info: %wZ\n", Strings[i]);
634                 break;
635 
636             case EVENTLOG_AUDIT_SUCCESS:
637                 DPRINT("Audit Success: %wZ\n", Strings[i]);
638                 break;
639 
640             case EVENTLOG_AUDIT_FAILURE:
641                 DPRINT("Audit Failure: %wZ\n", Strings[i]);
642                 break;
643 
644             default:
645                 DPRINT1("Type %hu: %wZ\n", EventType, Strings[i]);
646                 break;
647         }
648         dwStringsSize += Strings[i]->Length + sizeof(UNICODE_NULL);
649     }
650 
651     lpStrings = HeapAlloc(GetProcessHeap(), 0, dwStringsSize);
652     if (!lpStrings)
653     {
654         DPRINT1("Failed to allocate heap\n");
655         return STATUS_NO_MEMORY;
656     }
657 
658     str = lpStrings;
659     for (i = 0; i < NumStrings; i++)
660     {
661         RtlCopyMemory(str, Strings[i]->Buffer, Strings[i]->Length);
662         str += Strings[i]->Length / sizeof(WCHAR);
663         *str = UNICODE_NULL;
664         str++;
665     }
666 
667     if (UserSID)
668         dwUserSidLength = FIELD_OFFSET(SID, SubAuthority[UserSID->SubAuthorityCount]);
669 
670     if (SourceName && SourceName->Buffer)
671         LocalSourceName = *(PUNICODE_STRING)SourceName;
672     else
673         RtlInitUnicodeString(&LocalSourceName, pLogHandle->szName);
674 
675     LocalComputerName = *(PUNICODE_STRING)ComputerName;
676 
677     LogBuffer = LogfAllocAndBuildNewRecord(&RecSize,
678                                            Time,
679                                            EventType,
680                                            EventCategory,
681                                            EventID,
682                                            &LocalSourceName,
683                                            &LocalComputerName,
684                                            dwUserSidLength,
685                                            UserSID,
686                                            NumStrings,
687                                            lpStrings,
688                                            DataSize,
689                                            Data);
690     if (LogBuffer == NULL)
691     {
692         DPRINT1("LogfAllocAndBuildNewRecord failed!\n");
693         HeapFree(GetProcessHeap(), 0, lpStrings);
694         return STATUS_NO_MEMORY;
695     }
696 
697     Status = LogfWriteRecord(pLogHandle->LogFile, LogBuffer, RecSize);
698     if (!NT_SUCCESS(Status))
699     {
700         DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n",
701                 pLogHandle->LogFile->LogName, Status);
702     }
703 
704     if (NT_SUCCESS(Status))
705     {
706         /* Retrieve the two fields that were set by LogfWriteRecord into the record */
707         if (RecordNumber)
708             *RecordNumber = LogBuffer->RecordNumber;
709         if (TimeWritten)
710             *TimeWritten = LogBuffer->TimeWritten;
711     }
712 
713     LogfFreeRecord(LogBuffer);
714 
715     HeapFree(GetProcessHeap(), 0, lpStrings);
716 
717     return Status;
718 }
719 
720 
721 /* Function 11 */
722 NTSTATUS
723 WINAPI
724 ElfrReportEventW(
725     IELF_HANDLE LogHandle,
726     ULONG Time,
727     USHORT EventType,
728     USHORT EventCategory,
729     ULONG EventID,
730     USHORT NumStrings,
731     ULONG DataSize,
732     PRPC_UNICODE_STRING ComputerName,
733     PRPC_SID UserSID,
734     PRPC_UNICODE_STRING Strings[],
735     PBYTE Data,
736     USHORT Flags,
737     PULONG RecordNumber,
738     PULONG TimeWritten)
739 {
740     /* Call the helper function. The event source is provided via the log handle. */
741     return ElfrIntReportEventW(LogHandle,
742                                Time,
743                                EventType,
744                                EventCategory,
745                                EventID,
746                                NULL,
747                                NumStrings,
748                                DataSize,
749                                ComputerName,
750                                UserSID,
751                                Strings,
752                                Data,
753                                Flags,
754                                RecordNumber,
755                                TimeWritten);
756 }
757 
758 
759 /* Function 12 */
760 NTSTATUS
761 WINAPI
762 ElfrClearELFA(
763     IELF_HANDLE LogHandle,
764     PRPC_STRING BackupFileName)
765 {
766     NTSTATUS Status;
767     UNICODE_STRING BackupFileNameW;
768 
769     Status = RtlAnsiStringToUnicodeString(&BackupFileNameW,
770                                           (PANSI_STRING)BackupFileName,
771                                           TRUE);
772     if (!NT_SUCCESS(Status))
773         return Status;
774 
775     Status = ElfrClearELFW(LogHandle,
776                            (PRPC_UNICODE_STRING)&BackupFileNameW);
777 
778     RtlFreeUnicodeString(&BackupFileNameW);
779 
780     return Status;
781 }
782 
783 
784 /* Function 13 */
785 NTSTATUS
786 WINAPI
787 ElfrBackupELFA(
788     IELF_HANDLE LogHandle,
789     PRPC_STRING BackupFileName)
790 {
791     NTSTATUS Status;
792     UNICODE_STRING BackupFileNameW;
793 
794     Status = RtlAnsiStringToUnicodeString(&BackupFileNameW,
795                                           (PANSI_STRING)BackupFileName,
796                                           TRUE);
797     if (!NT_SUCCESS(Status))
798         return Status;
799 
800     Status = ElfrBackupELFW(LogHandle,
801                             (PRPC_UNICODE_STRING)&BackupFileNameW);
802 
803     RtlFreeUnicodeString(&BackupFileNameW);
804 
805     return Status;
806 }
807 
808 
809 /* Function 14 */
810 NTSTATUS
811 WINAPI
812 ElfrOpenELA(
813     EVENTLOG_HANDLE_A UNCServerName,
814     PRPC_STRING ModuleName,
815     PRPC_STRING RegModuleName,
816     ULONG MajorVersion,
817     ULONG MinorVersion,
818     PIELF_HANDLE LogHandle)
819 {
820     NTSTATUS Status;
821     UNICODE_STRING ModuleNameW;
822 
823     if ((MajorVersion != 1) || (MinorVersion != 1))
824         return STATUS_INVALID_PARAMETER;
825 
826     /* RegModuleName must be an empty string */
827     if (RegModuleName->Length > 0)
828         return STATUS_INVALID_PARAMETER;
829 
830     Status = RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE);
831     if (!NT_SUCCESS(Status))
832         return Status;
833 
834     /* FIXME: Must verify that caller has read access */
835 
836     Status = ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle,
837                                      &ModuleNameW,
838                                      FALSE);
839 
840     RtlFreeUnicodeString(&ModuleNameW);
841 
842     return Status;
843 }
844 
845 
846 /* Function 15 */
847 NTSTATUS
848 WINAPI
849 ElfrRegisterEventSourceA(
850     EVENTLOG_HANDLE_A UNCServerName,
851     PRPC_STRING ModuleName,
852     PRPC_STRING RegModuleName,
853     ULONG MajorVersion,
854     ULONG MinorVersion,
855     PIELF_HANDLE LogHandle)
856 {
857     NTSTATUS Status;
858     UNICODE_STRING ModuleNameW;
859 
860     Status = RtlAnsiStringToUnicodeString(&ModuleNameW,
861                                           (PANSI_STRING)ModuleName,
862                                           TRUE);
863     if (!NT_SUCCESS(Status))
864     {
865         DPRINT1("RtlAnsiStringToUnicodeString failed (Status 0x%08lx)\n", Status);
866         return Status;
867     }
868 
869     /* RegModuleName must be an empty string */
870     if (RegModuleName->Length > 0)
871     {
872         RtlFreeUnicodeString(&ModuleNameW);
873         return STATUS_INVALID_PARAMETER;
874     }
875 
876     if ((MajorVersion != 1) || (MinorVersion != 1))
877     {
878         RtlFreeUnicodeString(&ModuleNameW);
879         return STATUS_INVALID_PARAMETER;
880     }
881 
882     /* FIXME: Must verify that caller has write access */
883 
884     Status = ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle,
885                                      &ModuleNameW,
886                                      TRUE);
887 
888     RtlFreeUnicodeString(&ModuleNameW);
889 
890     return Status;
891 }
892 
893 
894 /* Function 16 */
895 NTSTATUS
896 WINAPI
897 ElfrOpenBELA(
898     EVENTLOG_HANDLE_A UNCServerName,
899     PRPC_STRING BackupFileName,
900     ULONG MajorVersion,
901     ULONG MinorVersion,
902     PIELF_HANDLE LogHandle)
903 {
904     NTSTATUS Status;
905     UNICODE_STRING BackupFileNameW;
906 
907     DPRINT("ElfrOpenBELA(%Z)\n", BackupFileName);
908 
909     Status = RtlAnsiStringToUnicodeString(&BackupFileNameW,
910                                           (PANSI_STRING)BackupFileName,
911                                           TRUE);
912     if (!NT_SUCCESS(Status))
913     {
914         DPRINT1("RtlAnsiStringToUnicodeString failed (Status 0x%08lx)\n", Status);
915         return Status;
916     }
917 
918     if ((MajorVersion != 1) || (MinorVersion != 1))
919     {
920         RtlFreeUnicodeString(&BackupFileNameW);
921         return STATUS_INVALID_PARAMETER;
922     }
923 
924     /* FIXME: UNCServerName must specify the server */
925 
926     /* FIXME: Must verify that caller has read access */
927 
928     Status = ElfCreateBackupLogHandle((PLOGHANDLE*)LogHandle,
929                                       &BackupFileNameW);
930 
931     RtlFreeUnicodeString(&BackupFileNameW);
932 
933     return Status;
934 }
935 
936 
937 /* Function 17 */
938 NTSTATUS
939 WINAPI
940 ElfrReadELA(
941     IELF_HANDLE LogHandle,
942     ULONG ReadFlags,
943     ULONG RecordOffset,
944     RULONG NumberOfBytesToRead,
945     PBYTE Buffer,
946     PULONG NumberOfBytesRead,
947     PULONG MinNumberOfBytesNeeded)
948 {
949     NTSTATUS Status;
950     PLOGHANDLE pLogHandle;
951     ULONG RecordNumber;
952 
953     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
954     if (!pLogHandle)
955         return STATUS_INVALID_HANDLE;
956 
957     if (!Buffer)
958         return STATUS_INVALID_PARAMETER;
959 
960     /* If sequential read, retrieve the CurrentRecord from this log handle */
961     if (ReadFlags & EVENTLOG_SEQUENTIAL_READ)
962     {
963         RecordNumber = pLogHandle->CurrentRecord;
964     }
965     else // (ReadFlags & EVENTLOG_SEEK_READ)
966     {
967         RecordNumber = RecordOffset;
968     }
969 
970     Status = LogfReadEvents(pLogHandle->LogFile,
971                             ReadFlags,
972                             &RecordNumber,
973                             NumberOfBytesToRead,
974                             Buffer,
975                             NumberOfBytesRead,
976                             MinNumberOfBytesNeeded,
977                             TRUE);
978 
979     /* Update the handle's CurrentRecord if success */
980     if (NT_SUCCESS(Status))
981     {
982         pLogHandle->CurrentRecord = RecordNumber;
983     }
984 
985     return Status;
986 }
987 
988 
989 /* Function 18 */
990 NTSTATUS
991 WINAPI
992 ElfrReportEventA(
993     IELF_HANDLE LogHandle,
994     ULONG Time,
995     USHORT EventType,
996     USHORT EventCategory,
997     ULONG EventID,
998     USHORT NumStrings,
999     ULONG DataSize,
1000     PRPC_STRING ComputerName,
1001     PRPC_SID UserSID,
1002     PRPC_STRING Strings[],
1003     PBYTE Data,
1004     USHORT Flags,
1005     PULONG RecordNumber,
1006     PULONG TimeWritten)
1007 {
1008     NTSTATUS Status = STATUS_SUCCESS;
1009     UNICODE_STRING ComputerNameW;
1010     PUNICODE_STRING *StringsArrayW = NULL;
1011     USHORT i;
1012 
1013     DPRINT("ElfrReportEventA(%hu)\n", NumStrings);
1014 
1015 #if 0
1016     for (i = 0; i < NumStrings; i++)
1017     {
1018         if (Strings[i] == NULL)
1019         {
1020             DPRINT1("String %hu is null\n", i);
1021         }
1022         else
1023         {
1024             DPRINT1("String %hu: %Z\n", i, Strings[i]);
1025         }
1026     }
1027 #endif
1028 
1029     Status = RtlAnsiStringToUnicodeString((PUNICODE_STRING)&ComputerNameW,
1030                                           (PANSI_STRING)ComputerName,
1031                                           TRUE);
1032     if (!NT_SUCCESS(Status))
1033         return Status;
1034 
1035     if (NumStrings != 0)
1036     {
1037         StringsArrayW = HeapAlloc(GetProcessHeap(),
1038                                   HEAP_ZERO_MEMORY,
1039                                   NumStrings * sizeof(PUNICODE_STRING));
1040         if (StringsArrayW == NULL)
1041         {
1042             Status = STATUS_NO_MEMORY;
1043             goto Done;
1044         }
1045 
1046         for (i = 0; i < NumStrings; i++)
1047         {
1048             if (Strings[i] != NULL)
1049             {
1050                 StringsArrayW[i] = HeapAlloc(GetProcessHeap(),
1051                                              HEAP_ZERO_MEMORY,
1052                                              sizeof(UNICODE_STRING));
1053                 if (StringsArrayW[i] == NULL)
1054                 {
1055                     Status = STATUS_NO_MEMORY;
1056                     break;
1057                 }
1058 
1059                 Status = RtlAnsiStringToUnicodeString(StringsArrayW[i],
1060                                                       (PANSI_STRING)Strings[i],
1061                                                       TRUE);
1062             }
1063 
1064             if (!NT_SUCCESS(Status))
1065                 break;
1066         }
1067     }
1068 
1069     if (NT_SUCCESS(Status))
1070     {
1071         Status = ElfrReportEventW(LogHandle,
1072                                   Time,
1073                                   EventType,
1074                                   EventCategory,
1075                                   EventID,
1076                                   NumStrings,
1077                                   DataSize,
1078                                   (PRPC_UNICODE_STRING)&ComputerNameW,
1079                                   UserSID,
1080                                   (PRPC_UNICODE_STRING*)StringsArrayW,
1081                                   Data,
1082                                   Flags,
1083                                   RecordNumber,
1084                                   TimeWritten);
1085     }
1086 
1087 Done:
1088     if (StringsArrayW != NULL)
1089     {
1090         for (i = 0; i < NumStrings; i++)
1091         {
1092             if ((StringsArrayW[i] != NULL) && (StringsArrayW[i]->Buffer))
1093             {
1094                 RtlFreeUnicodeString(StringsArrayW[i]);
1095                 HeapFree(GetProcessHeap(), 0, StringsArrayW[i]);
1096             }
1097         }
1098 
1099         HeapFree(GetProcessHeap(), 0, StringsArrayW);
1100     }
1101 
1102     RtlFreeUnicodeString(&ComputerNameW);
1103 
1104     return Status;
1105 }
1106 
1107 
1108 /* Function 19 */
1109 NTSTATUS
1110 WINAPI
1111 ElfrRegisterClusterSvc(
1112     handle_t BindingHandle)
1113 {
1114     UNIMPLEMENTED;
1115     return STATUS_NOT_IMPLEMENTED;
1116 }
1117 
1118 
1119 /* Function 20 */
1120 NTSTATUS
1121 WINAPI
1122 ElfrDeregisterClusterSvc(
1123     handle_t BindingHandle)
1124 {
1125     UNIMPLEMENTED;
1126     return STATUS_NOT_IMPLEMENTED;
1127 }
1128 
1129 
1130 /* Function 21 */
1131 NTSTATUS
1132 WINAPI
1133 ElfrWriteClusterEvents(
1134     handle_t BindingHandle)
1135 {
1136     UNIMPLEMENTED;
1137     return STATUS_NOT_IMPLEMENTED;
1138 }
1139 
1140 
1141 /* Function 22 */
1142 NTSTATUS
1143 WINAPI
1144 ElfrGetLogInformation(
1145     IELF_HANDLE LogHandle,
1146     ULONG InfoLevel,
1147     PBYTE Buffer,
1148     ULONG cbBufSize,
1149     PULONG pcbBytesNeeded)
1150 {
1151     NTSTATUS Status = STATUS_SUCCESS;
1152     PLOGHANDLE pLogHandle;
1153     PLOGFILE pLogFile;
1154 
1155     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
1156     if (!pLogHandle)
1157         return STATUS_INVALID_HANDLE;
1158 
1159     pLogFile = pLogHandle->LogFile;
1160 
1161     /* Lock the log file shared */
1162     RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
1163 
1164     switch (InfoLevel)
1165     {
1166         case EVENTLOG_FULL_INFO:
1167         {
1168             LPEVENTLOG_FULL_INFORMATION efi = (LPEVENTLOG_FULL_INFORMATION)Buffer;
1169 
1170             *pcbBytesNeeded = sizeof(EVENTLOG_FULL_INFORMATION);
1171             if (cbBufSize < sizeof(EVENTLOG_FULL_INFORMATION))
1172             {
1173                 Status = STATUS_BUFFER_TOO_SMALL;
1174                 break;
1175             }
1176 
1177             efi->dwFull = !!(ElfGetFlags(&pLogFile->LogFile) & ELF_LOGFILE_LOGFULL_WRITTEN);
1178             break;
1179         }
1180 
1181         default:
1182             Status = STATUS_INVALID_LEVEL;
1183             break;
1184     }
1185 
1186     /* Unlock the log file */
1187     RtlReleaseResource(&pLogFile->Lock);
1188 
1189     return Status;
1190 }
1191 
1192 
1193 /* Function 23 */
1194 NTSTATUS
1195 WINAPI
1196 ElfrFlushEL(
1197     IELF_HANDLE LogHandle)
1198 {
1199     NTSTATUS Status;
1200     PLOGHANDLE pLogHandle;
1201     PLOGFILE pLogFile;
1202 
1203     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
1204     if (!pLogHandle)
1205         return STATUS_INVALID_HANDLE;
1206 
1207     pLogFile = pLogHandle->LogFile;
1208 
1209     /* Lock the log file exclusive */
1210     RtlAcquireResourceExclusive(&pLogFile->Lock, TRUE);
1211 
1212     Status = ElfFlushFile(&pLogFile->LogFile);
1213 
1214     /* Unlock the log file */
1215     RtlReleaseResource(&pLogFile->Lock);
1216 
1217     return Status;
1218 }
1219 
1220 
1221 /* Function 24 */
1222 NTSTATUS
1223 WINAPI
1224 ElfrReportEventAndSourceW(
1225     IELF_HANDLE LogHandle,
1226     ULONG Time,
1227     USHORT EventType,
1228     USHORT EventCategory,
1229     ULONG EventID,
1230     PRPC_UNICODE_STRING SourceName,
1231     USHORT NumStrings,
1232     ULONG DataSize,
1233     PRPC_UNICODE_STRING ComputerName,
1234     PRPC_SID UserSID,
1235     PRPC_UNICODE_STRING Strings[],
1236     PBYTE Data,
1237     USHORT Flags,
1238     PULONG RecordNumber,
1239     PULONG TimeWritten)
1240 {
1241     /* Call the helper function. The event source is specified by the caller. */
1242     return ElfrIntReportEventW(LogHandle,
1243                                Time,
1244                                EventType,
1245                                EventCategory,
1246                                EventID,
1247                                SourceName,
1248                                NumStrings,
1249                                DataSize,
1250                                ComputerName,
1251                                UserSID,
1252                                Strings,
1253                                Data,
1254                                Flags,
1255                                RecordNumber,
1256                                TimeWritten);
1257 }
1258 
1259 
1260 void __RPC_FAR *__RPC_USER midl_user_allocate(SIZE_T len)
1261 {
1262     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
1263 }
1264 
1265 
1266 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
1267 {
1268     HeapFree(GetProcessHeap(), 0, ptr);
1269 }
1270 
1271 
1272 void __RPC_USER IELF_HANDLE_rundown(IELF_HANDLE LogHandle)
1273 {
1274     /* Close the handle */
1275     ElfDeleteEventLogHandle(&LogHandle); // ElfrCloseEL(&LogHandle);
1276 }
1277