xref: /reactos/base/services/eventlog/rpc.c (revision c2c66aff)
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 ElfrClearELFW(
289     IELF_HANDLE LogHandle,
290     PRPC_UNICODE_STRING BackupFileName)
291 {
292     PLOGHANDLE pLogHandle;
293 
294     DPRINT("ElfrClearELFW()\n");
295 
296     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
297     if (!pLogHandle)
298         return STATUS_INVALID_HANDLE;
299 
300     /* Fail, if the log file is a backup file */
301     if (pLogHandle->Flags & LOG_HANDLE_BACKUP_FILE)
302         return STATUS_INVALID_HANDLE;
303 
304     return LogfClearFile(pLogHandle->LogFile,
305                          (PUNICODE_STRING)BackupFileName);
306 }
307 
308 
309 /* Function 1 */
310 NTSTATUS
311 ElfrBackupELFW(
312     IELF_HANDLE LogHandle,
313     PRPC_UNICODE_STRING BackupFileName)
314 {
315     PLOGHANDLE pLogHandle;
316 
317     DPRINT("ElfrBackupELFW()\n");
318 
319     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
320     if (!pLogHandle)
321         return STATUS_INVALID_HANDLE;
322 
323     return LogfBackupFile(pLogHandle->LogFile,
324                           (PUNICODE_STRING)BackupFileName);
325 }
326 
327 
328 /* Function 2 */
329 NTSTATUS
330 ElfrCloseEL(
331     PIELF_HANDLE LogHandle)
332 {
333     return ElfDeleteEventLogHandle(LogHandle);
334 }
335 
336 
337 /* Function 3 */
338 NTSTATUS
339 ElfrDeregisterEventSource(
340     PIELF_HANDLE LogHandle)
341 {
342     return ElfDeleteEventLogHandle(LogHandle);
343 }
344 
345 
346 /* Function 4 */
347 NTSTATUS
348 ElfrNumberOfRecords(
349     IELF_HANDLE LogHandle,
350     PULONG NumberOfRecords)
351 {
352     PLOGHANDLE pLogHandle;
353     PLOGFILE pLogFile;
354     ULONG OldestRecordNumber, CurrentRecordNumber;
355 
356     DPRINT("ElfrNumberOfRecords()\n");
357 
358     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
359     if (!pLogHandle)
360         return STATUS_INVALID_HANDLE;
361 
362     if (!NumberOfRecords)
363         return STATUS_INVALID_PARAMETER;
364 
365     pLogFile = pLogHandle->LogFile;
366 
367     /* Lock the log file shared */
368     RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
369 
370     OldestRecordNumber  = ElfGetOldestRecord(&pLogFile->LogFile);
371     CurrentRecordNumber = ElfGetCurrentRecord(&pLogFile->LogFile);
372 
373     /* Unlock the log file */
374     RtlReleaseResource(&pLogFile->Lock);
375 
376     DPRINT("Oldest: %lu  Current: %lu\n",
377            OldestRecordNumber, CurrentRecordNumber);
378 
379     if (OldestRecordNumber == 0)
380     {
381         /* OldestRecordNumber == 0 when the log is empty */
382         *NumberOfRecords = 0;
383     }
384     else
385     {
386         /* The log contains events */
387         *NumberOfRecords = CurrentRecordNumber - OldestRecordNumber;
388     }
389 
390     return STATUS_SUCCESS;
391 }
392 
393 
394 /* Function 5 */
395 NTSTATUS
396 ElfrOldestRecord(
397     IELF_HANDLE LogHandle,
398     PULONG OldestRecordNumber)
399 {
400     PLOGHANDLE pLogHandle;
401     PLOGFILE pLogFile;
402 
403     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
404     if (!pLogHandle)
405         return STATUS_INVALID_HANDLE;
406 
407     if (!OldestRecordNumber)
408         return STATUS_INVALID_PARAMETER;
409 
410     pLogFile = pLogHandle->LogFile;
411 
412     /* Lock the log file shared */
413     RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
414 
415     *OldestRecordNumber = ElfGetOldestRecord(&pLogFile->LogFile);
416 
417     /* Unlock the log file */
418     RtlReleaseResource(&pLogFile->Lock);
419 
420     return STATUS_SUCCESS;
421 }
422 
423 
424 /* Function 6 */
425 NTSTATUS
426 ElfrChangeNotify(
427     IELF_HANDLE LogHandle,
428     RPC_CLIENT_ID ClientId,
429     ULONG Event)
430 {
431     UNIMPLEMENTED;
432     return STATUS_NOT_IMPLEMENTED;
433 }
434 
435 
436 /* Function 7 */
437 NTSTATUS
438 ElfrOpenELW(
439     EVENTLOG_HANDLE_W UNCServerName,
440     PRPC_UNICODE_STRING ModuleName,
441     PRPC_UNICODE_STRING RegModuleName,
442     ULONG MajorVersion,
443     ULONG MinorVersion,
444     PIELF_HANDLE LogHandle)
445 {
446     if ((MajorVersion != 1) || (MinorVersion != 1))
447         return STATUS_INVALID_PARAMETER;
448 
449     /* RegModuleName must be an empty string */
450     if (RegModuleName->Length > 0)
451         return STATUS_INVALID_PARAMETER;
452 
453     /* FIXME: UNCServerName must specify the server */
454 
455     /* FIXME: Must verify that caller has read access */
456 
457     return ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle,
458                                    (PUNICODE_STRING)ModuleName,
459                                    FALSE);
460 }
461 
462 
463 /* Function 8 */
464 NTSTATUS
465 ElfrRegisterEventSourceW(
466     EVENTLOG_HANDLE_W UNCServerName,
467     PRPC_UNICODE_STRING ModuleName,
468     PRPC_UNICODE_STRING RegModuleName,
469     ULONG MajorVersion,
470     ULONG MinorVersion,
471     PIELF_HANDLE LogHandle)
472 {
473     DPRINT("ElfrRegisterEventSourceW()\n");
474 
475     if ((MajorVersion != 1) || (MinorVersion != 1))
476         return STATUS_INVALID_PARAMETER;
477 
478     /* RegModuleName must be an empty string */
479     if (RegModuleName->Length > 0)
480         return STATUS_INVALID_PARAMETER;
481 
482     DPRINT("ModuleName: %wZ\n", ModuleName);
483 
484     /* FIXME: UNCServerName must specify the server or empty for local */
485 
486     /* FIXME: Must verify that caller has write access */
487 
488     return ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle,
489                                    (PUNICODE_STRING)ModuleName,
490                                    TRUE);
491 }
492 
493 
494 /* Function 9 */
495 NTSTATUS
496 ElfrOpenBELW(
497     EVENTLOG_HANDLE_W UNCServerName,
498     PRPC_UNICODE_STRING BackupFileName,
499     ULONG MajorVersion,
500     ULONG MinorVersion,
501     PIELF_HANDLE LogHandle)
502 {
503     DPRINT("ElfrOpenBELW(%wZ)\n", BackupFileName);
504 
505     if ((MajorVersion != 1) || (MinorVersion != 1))
506         return STATUS_INVALID_PARAMETER;
507 
508     /* FIXME: UNCServerName must specify the server */
509 
510     /* FIXME: Must verify that caller has read access */
511 
512     return ElfCreateBackupLogHandle((PLOGHANDLE*)LogHandle,
513                                     (PUNICODE_STRING)BackupFileName);
514 }
515 
516 
517 /* Function 10 */
518 NTSTATUS
519 ElfrReadELW(
520     IELF_HANDLE LogHandle,
521     ULONG ReadFlags,
522     ULONG RecordOffset,
523     RULONG NumberOfBytesToRead,
524     PBYTE Buffer,
525     PULONG NumberOfBytesRead,
526     PULONG MinNumberOfBytesNeeded)
527 {
528     NTSTATUS Status;
529     PLOGHANDLE pLogHandle;
530     ULONG RecordNumber;
531 
532     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
533     if (!pLogHandle)
534         return STATUS_INVALID_HANDLE;
535 
536     if (!Buffer)
537         return STATUS_INVALID_PARAMETER;
538 
539     /* If sequential read, retrieve the CurrentRecord from this log handle */
540     if (ReadFlags & EVENTLOG_SEQUENTIAL_READ)
541     {
542         RecordNumber = pLogHandle->CurrentRecord;
543     }
544     else // (ReadFlags & EVENTLOG_SEEK_READ)
545     {
546         RecordNumber = RecordOffset;
547     }
548 
549     Status = LogfReadEvents(pLogHandle->LogFile,
550                             ReadFlags,
551                             &RecordNumber,
552                             NumberOfBytesToRead,
553                             Buffer,
554                             NumberOfBytesRead,
555                             MinNumberOfBytesNeeded,
556                             FALSE);
557 
558     /* Update the handle's CurrentRecord if success */
559     if (NT_SUCCESS(Status))
560     {
561         pLogHandle->CurrentRecord = RecordNumber;
562     }
563 
564     return Status;
565 }
566 
567 
568 /* Helper function for ElfrReportEventW/A and ElfrReportEventAndSourceW */
569 NTSTATUS
570 ElfrIntReportEventW(
571     IELF_HANDLE LogHandle,
572     ULONG Time,
573     USHORT EventType,
574     USHORT EventCategory,
575     ULONG EventID,
576     PRPC_UNICODE_STRING SourceName OPTIONAL,
577     USHORT NumStrings,
578     ULONG DataSize,
579     PRPC_UNICODE_STRING ComputerName,
580     PRPC_SID UserSID,
581     PRPC_UNICODE_STRING Strings[],
582     PBYTE Data,
583     USHORT Flags,
584     PULONG RecordNumber,
585     PULONG TimeWritten)
586 {
587     NTSTATUS Status;
588     PLOGHANDLE pLogHandle;
589     UNICODE_STRING LocalSourceName, LocalComputerName;
590     PEVENTLOGRECORD LogBuffer;
591     USHORT i;
592     SIZE_T RecSize;
593     ULONG dwStringsSize = 0;
594     ULONG dwUserSidLength = 0;
595     PWSTR lpStrings, str;
596 
597     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
598     if (!pLogHandle)
599         return STATUS_INVALID_HANDLE;
600 
601     /* Flags must be 0 */
602     if (Flags)
603         return STATUS_INVALID_PARAMETER;
604 
605     for (i = 0; i < NumStrings; i++)
606     {
607         switch (EventType)
608         {
609             case EVENTLOG_SUCCESS:
610                 DPRINT("Success: %wZ\n", Strings[i]);
611                 break;
612 
613             case EVENTLOG_ERROR_TYPE:
614                 DPRINT("Error: %wZ\n", Strings[i]);
615                 break;
616 
617             case EVENTLOG_WARNING_TYPE:
618                 DPRINT("Warning: %wZ\n", Strings[i]);
619                 break;
620 
621             case EVENTLOG_INFORMATION_TYPE:
622                 DPRINT("Info: %wZ\n", Strings[i]);
623                 break;
624 
625             case EVENTLOG_AUDIT_SUCCESS:
626                 DPRINT("Audit Success: %wZ\n", Strings[i]);
627                 break;
628 
629             case EVENTLOG_AUDIT_FAILURE:
630                 DPRINT("Audit Failure: %wZ\n", Strings[i]);
631                 break;
632 
633             default:
634                 DPRINT1("Type %hu: %wZ\n", EventType, Strings[i]);
635                 break;
636         }
637         dwStringsSize += Strings[i]->Length + sizeof(UNICODE_NULL);
638     }
639 
640     lpStrings = HeapAlloc(GetProcessHeap(), 0, dwStringsSize);
641     if (!lpStrings)
642     {
643         DPRINT1("Failed to allocate heap\n");
644         return STATUS_NO_MEMORY;
645     }
646 
647     str = lpStrings;
648     for (i = 0; i < NumStrings; i++)
649     {
650         RtlCopyMemory(str, Strings[i]->Buffer, Strings[i]->Length);
651         str += Strings[i]->Length / sizeof(WCHAR);
652         *str = UNICODE_NULL;
653         str++;
654     }
655 
656     if (UserSID)
657         dwUserSidLength = FIELD_OFFSET(SID, SubAuthority[UserSID->SubAuthorityCount]);
658 
659     if (SourceName && SourceName->Buffer)
660         LocalSourceName = *(PUNICODE_STRING)SourceName;
661     else
662         RtlInitUnicodeString(&LocalSourceName, pLogHandle->szName);
663 
664     LocalComputerName = *(PUNICODE_STRING)ComputerName;
665 
666     LogBuffer = LogfAllocAndBuildNewRecord(&RecSize,
667                                            Time,
668                                            EventType,
669                                            EventCategory,
670                                            EventID,
671                                            &LocalSourceName,
672                                            &LocalComputerName,
673                                            dwUserSidLength,
674                                            UserSID,
675                                            NumStrings,
676                                            lpStrings,
677                                            DataSize,
678                                            Data);
679     if (LogBuffer == NULL)
680     {
681         DPRINT1("LogfAllocAndBuildNewRecord failed!\n");
682         HeapFree(GetProcessHeap(), 0, lpStrings);
683         return STATUS_NO_MEMORY;
684     }
685 
686     Status = LogfWriteRecord(pLogHandle->LogFile, LogBuffer, RecSize);
687     if (!NT_SUCCESS(Status))
688     {
689         DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n",
690                 pLogHandle->LogFile->LogName, Status);
691     }
692 
693     if (NT_SUCCESS(Status))
694     {
695         /* Retrieve the two fields that were set by LogfWriteRecord into the record */
696         if (RecordNumber)
697             *RecordNumber = LogBuffer->RecordNumber;
698         if (TimeWritten)
699             *TimeWritten = LogBuffer->TimeWritten;
700     }
701 
702     LogfFreeRecord(LogBuffer);
703 
704     HeapFree(GetProcessHeap(), 0, lpStrings);
705 
706     return Status;
707 }
708 
709 
710 /* Function 11 */
711 NTSTATUS
712 ElfrReportEventW(
713     IELF_HANDLE LogHandle,
714     ULONG Time,
715     USHORT EventType,
716     USHORT EventCategory,
717     ULONG EventID,
718     USHORT NumStrings,
719     ULONG DataSize,
720     PRPC_UNICODE_STRING ComputerName,
721     PRPC_SID UserSID,
722     PRPC_UNICODE_STRING Strings[],
723     PBYTE Data,
724     USHORT Flags,
725     PULONG RecordNumber,
726     PULONG TimeWritten)
727 {
728     /* Call the helper function. The event source is provided via the log handle. */
729     return ElfrIntReportEventW(LogHandle,
730                                Time,
731                                EventType,
732                                EventCategory,
733                                EventID,
734                                NULL,
735                                NumStrings,
736                                DataSize,
737                                ComputerName,
738                                UserSID,
739                                Strings,
740                                Data,
741                                Flags,
742                                RecordNumber,
743                                TimeWritten);
744 }
745 
746 
747 /* Function 12 */
748 NTSTATUS
749 ElfrClearELFA(
750     IELF_HANDLE LogHandle,
751     PRPC_STRING BackupFileName)
752 {
753     NTSTATUS Status;
754     UNICODE_STRING BackupFileNameW;
755 
756     Status = RtlAnsiStringToUnicodeString(&BackupFileNameW,
757                                           (PANSI_STRING)BackupFileName,
758                                           TRUE);
759     if (!NT_SUCCESS(Status))
760         return Status;
761 
762     Status = ElfrClearELFW(LogHandle,
763                            (PRPC_UNICODE_STRING)&BackupFileNameW);
764 
765     RtlFreeUnicodeString(&BackupFileNameW);
766 
767     return Status;
768 }
769 
770 
771 /* Function 13 */
772 NTSTATUS
773 ElfrBackupELFA(
774     IELF_HANDLE LogHandle,
775     PRPC_STRING BackupFileName)
776 {
777     NTSTATUS Status;
778     UNICODE_STRING BackupFileNameW;
779 
780     Status = RtlAnsiStringToUnicodeString(&BackupFileNameW,
781                                           (PANSI_STRING)BackupFileName,
782                                           TRUE);
783     if (!NT_SUCCESS(Status))
784         return Status;
785 
786     Status = ElfrBackupELFW(LogHandle,
787                             (PRPC_UNICODE_STRING)&BackupFileNameW);
788 
789     RtlFreeUnicodeString(&BackupFileNameW);
790 
791     return Status;
792 }
793 
794 
795 /* Function 14 */
796 NTSTATUS
797 ElfrOpenELA(
798     EVENTLOG_HANDLE_A UNCServerName,
799     PRPC_STRING ModuleName,
800     PRPC_STRING RegModuleName,
801     ULONG MajorVersion,
802     ULONG MinorVersion,
803     PIELF_HANDLE LogHandle)
804 {
805     NTSTATUS Status;
806     UNICODE_STRING ModuleNameW;
807 
808     if ((MajorVersion != 1) || (MinorVersion != 1))
809         return STATUS_INVALID_PARAMETER;
810 
811     /* RegModuleName must be an empty string */
812     if (RegModuleName->Length > 0)
813         return STATUS_INVALID_PARAMETER;
814 
815     Status = RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE);
816     if (!NT_SUCCESS(Status))
817         return Status;
818 
819     /* FIXME: Must verify that caller has read access */
820 
821     Status = ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle,
822                                      &ModuleNameW,
823                                      FALSE);
824 
825     RtlFreeUnicodeString(&ModuleNameW);
826 
827     return Status;
828 }
829 
830 
831 /* Function 15 */
832 NTSTATUS
833 ElfrRegisterEventSourceA(
834     EVENTLOG_HANDLE_A UNCServerName,
835     PRPC_STRING ModuleName,
836     PRPC_STRING RegModuleName,
837     ULONG MajorVersion,
838     ULONG MinorVersion,
839     PIELF_HANDLE LogHandle)
840 {
841     NTSTATUS Status;
842     UNICODE_STRING ModuleNameW;
843 
844     Status = RtlAnsiStringToUnicodeString(&ModuleNameW,
845                                           (PANSI_STRING)ModuleName,
846                                           TRUE);
847     if (!NT_SUCCESS(Status))
848     {
849         DPRINT1("RtlAnsiStringToUnicodeString failed (Status 0x%08lx)\n", Status);
850         return Status;
851     }
852 
853     /* RegModuleName must be an empty string */
854     if (RegModuleName->Length > 0)
855     {
856         RtlFreeUnicodeString(&ModuleNameW);
857         return STATUS_INVALID_PARAMETER;
858     }
859 
860     if ((MajorVersion != 1) || (MinorVersion != 1))
861     {
862         RtlFreeUnicodeString(&ModuleNameW);
863         return STATUS_INVALID_PARAMETER;
864     }
865 
866     /* FIXME: Must verify that caller has write access */
867 
868     Status = ElfCreateEventLogHandle((PLOGHANDLE*)LogHandle,
869                                      &ModuleNameW,
870                                      TRUE);
871 
872     RtlFreeUnicodeString(&ModuleNameW);
873 
874     return Status;
875 }
876 
877 
878 /* Function 16 */
879 NTSTATUS
880 ElfrOpenBELA(
881     EVENTLOG_HANDLE_A UNCServerName,
882     PRPC_STRING BackupFileName,
883     ULONG MajorVersion,
884     ULONG MinorVersion,
885     PIELF_HANDLE LogHandle)
886 {
887     NTSTATUS Status;
888     UNICODE_STRING BackupFileNameW;
889 
890     DPRINT("ElfrOpenBELA(%Z)\n", BackupFileName);
891 
892     Status = RtlAnsiStringToUnicodeString(&BackupFileNameW,
893                                           (PANSI_STRING)BackupFileName,
894                                           TRUE);
895     if (!NT_SUCCESS(Status))
896     {
897         DPRINT1("RtlAnsiStringToUnicodeString failed (Status 0x%08lx)\n", Status);
898         return Status;
899     }
900 
901     if ((MajorVersion != 1) || (MinorVersion != 1))
902     {
903         RtlFreeUnicodeString(&BackupFileNameW);
904         return STATUS_INVALID_PARAMETER;
905     }
906 
907     /* FIXME: UNCServerName must specify the server */
908 
909     /* FIXME: Must verify that caller has read access */
910 
911     Status = ElfCreateBackupLogHandle((PLOGHANDLE*)LogHandle,
912                                       &BackupFileNameW);
913 
914     RtlFreeUnicodeString(&BackupFileNameW);
915 
916     return Status;
917 }
918 
919 
920 /* Function 17 */
921 NTSTATUS
922 ElfrReadELA(
923     IELF_HANDLE LogHandle,
924     ULONG ReadFlags,
925     ULONG RecordOffset,
926     RULONG NumberOfBytesToRead,
927     PBYTE Buffer,
928     PULONG NumberOfBytesRead,
929     PULONG MinNumberOfBytesNeeded)
930 {
931     NTSTATUS Status;
932     PLOGHANDLE pLogHandle;
933     ULONG RecordNumber;
934 
935     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
936     if (!pLogHandle)
937         return STATUS_INVALID_HANDLE;
938 
939     if (!Buffer)
940         return STATUS_INVALID_PARAMETER;
941 
942     /* If sequential read, retrieve the CurrentRecord from this log handle */
943     if (ReadFlags & EVENTLOG_SEQUENTIAL_READ)
944     {
945         RecordNumber = pLogHandle->CurrentRecord;
946     }
947     else // (ReadFlags & EVENTLOG_SEEK_READ)
948     {
949         RecordNumber = RecordOffset;
950     }
951 
952     Status = LogfReadEvents(pLogHandle->LogFile,
953                             ReadFlags,
954                             &RecordNumber,
955                             NumberOfBytesToRead,
956                             Buffer,
957                             NumberOfBytesRead,
958                             MinNumberOfBytesNeeded,
959                             TRUE);
960 
961     /* Update the handle's CurrentRecord if success */
962     if (NT_SUCCESS(Status))
963     {
964         pLogHandle->CurrentRecord = RecordNumber;
965     }
966 
967     return Status;
968 }
969 
970 
971 /* Function 18 */
972 NTSTATUS
973 ElfrReportEventA(
974     IELF_HANDLE LogHandle,
975     ULONG Time,
976     USHORT EventType,
977     USHORT EventCategory,
978     ULONG EventID,
979     USHORT NumStrings,
980     ULONG DataSize,
981     PRPC_STRING ComputerName,
982     PRPC_SID UserSID,
983     PRPC_STRING Strings[],
984     PBYTE Data,
985     USHORT Flags,
986     PULONG RecordNumber,
987     PULONG TimeWritten)
988 {
989     NTSTATUS Status = STATUS_SUCCESS;
990     UNICODE_STRING ComputerNameW;
991     PUNICODE_STRING *StringsArrayW = NULL;
992     USHORT i;
993 
994     DPRINT("ElfrReportEventA(%hu)\n", NumStrings);
995 
996 #if 0
997     for (i = 0; i < NumStrings; i++)
998     {
999         if (Strings[i] == NULL)
1000         {
1001             DPRINT1("String %hu is null\n", i);
1002         }
1003         else
1004         {
1005             DPRINT1("String %hu: %Z\n", i, Strings[i]);
1006         }
1007     }
1008 #endif
1009 
1010     Status = RtlAnsiStringToUnicodeString((PUNICODE_STRING)&ComputerNameW,
1011                                           (PANSI_STRING)ComputerName,
1012                                           TRUE);
1013     if (!NT_SUCCESS(Status))
1014         return Status;
1015 
1016     if (NumStrings != 0)
1017     {
1018         StringsArrayW = HeapAlloc(GetProcessHeap(),
1019                                   HEAP_ZERO_MEMORY,
1020                                   NumStrings * sizeof(PUNICODE_STRING));
1021         if (StringsArrayW == NULL)
1022         {
1023             Status = STATUS_NO_MEMORY;
1024             goto Done;
1025         }
1026 
1027         for (i = 0; i < NumStrings; i++)
1028         {
1029             if (Strings[i] != NULL)
1030             {
1031                 StringsArrayW[i] = HeapAlloc(GetProcessHeap(),
1032                                              HEAP_ZERO_MEMORY,
1033                                              sizeof(UNICODE_STRING));
1034                 if (StringsArrayW[i] == NULL)
1035                 {
1036                     Status = STATUS_NO_MEMORY;
1037                     break;
1038                 }
1039 
1040                 Status = RtlAnsiStringToUnicodeString(StringsArrayW[i],
1041                                                       (PANSI_STRING)Strings[i],
1042                                                       TRUE);
1043             }
1044 
1045             if (!NT_SUCCESS(Status))
1046                 break;
1047         }
1048     }
1049 
1050     if (NT_SUCCESS(Status))
1051     {
1052         Status = ElfrReportEventW(LogHandle,
1053                                   Time,
1054                                   EventType,
1055                                   EventCategory,
1056                                   EventID,
1057                                   NumStrings,
1058                                   DataSize,
1059                                   (PRPC_UNICODE_STRING)&ComputerNameW,
1060                                   UserSID,
1061                                   (PRPC_UNICODE_STRING*)StringsArrayW,
1062                                   Data,
1063                                   Flags,
1064                                   RecordNumber,
1065                                   TimeWritten);
1066     }
1067 
1068 Done:
1069     if (StringsArrayW != NULL)
1070     {
1071         for (i = 0; i < NumStrings; i++)
1072         {
1073             if ((StringsArrayW[i] != NULL) && (StringsArrayW[i]->Buffer))
1074             {
1075                 RtlFreeUnicodeString(StringsArrayW[i]);
1076                 HeapFree(GetProcessHeap(), 0, StringsArrayW[i]);
1077             }
1078         }
1079 
1080         HeapFree(GetProcessHeap(), 0, StringsArrayW);
1081     }
1082 
1083     RtlFreeUnicodeString(&ComputerNameW);
1084 
1085     return Status;
1086 }
1087 
1088 
1089 /* Function 19 */
1090 NTSTATUS
1091 ElfrRegisterClusterSvc(
1092     handle_t BindingHandle)
1093 {
1094     UNIMPLEMENTED;
1095     return STATUS_NOT_IMPLEMENTED;
1096 }
1097 
1098 
1099 /* Function 20 */
1100 NTSTATUS
1101 ElfrDeregisterClusterSvc(
1102     handle_t BindingHandle)
1103 {
1104     UNIMPLEMENTED;
1105     return STATUS_NOT_IMPLEMENTED;
1106 }
1107 
1108 
1109 /* Function 21 */
1110 NTSTATUS
1111 ElfrWriteClusterEvents(
1112     handle_t BindingHandle)
1113 {
1114     UNIMPLEMENTED;
1115     return STATUS_NOT_IMPLEMENTED;
1116 }
1117 
1118 
1119 /* Function 22 */
1120 NTSTATUS
1121 ElfrGetLogInformation(
1122     IELF_HANDLE LogHandle,
1123     ULONG InfoLevel,
1124     PBYTE Buffer,
1125     ULONG cbBufSize,
1126     PULONG pcbBytesNeeded)
1127 {
1128     NTSTATUS Status = STATUS_SUCCESS;
1129     PLOGHANDLE pLogHandle;
1130     PLOGFILE pLogFile;
1131 
1132     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
1133     if (!pLogHandle)
1134         return STATUS_INVALID_HANDLE;
1135 
1136     pLogFile = pLogHandle->LogFile;
1137 
1138     /* Lock the log file shared */
1139     RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
1140 
1141     switch (InfoLevel)
1142     {
1143         case EVENTLOG_FULL_INFO:
1144         {
1145             LPEVENTLOG_FULL_INFORMATION efi = (LPEVENTLOG_FULL_INFORMATION)Buffer;
1146 
1147             *pcbBytesNeeded = sizeof(EVENTLOG_FULL_INFORMATION);
1148             if (cbBufSize < sizeof(EVENTLOG_FULL_INFORMATION))
1149             {
1150                 Status = STATUS_BUFFER_TOO_SMALL;
1151                 break;
1152             }
1153 
1154             efi->dwFull = !!(ElfGetFlags(&pLogFile->LogFile) & ELF_LOGFILE_LOGFULL_WRITTEN);
1155             break;
1156         }
1157 
1158         default:
1159             Status = STATUS_INVALID_LEVEL;
1160             break;
1161     }
1162 
1163     /* Unlock the log file */
1164     RtlReleaseResource(&pLogFile->Lock);
1165 
1166     return Status;
1167 }
1168 
1169 
1170 /* Function 23 */
1171 NTSTATUS
1172 ElfrFlushEL(
1173     IELF_HANDLE LogHandle)
1174 {
1175     NTSTATUS Status;
1176     PLOGHANDLE pLogHandle;
1177     PLOGFILE pLogFile;
1178 
1179     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
1180     if (!pLogHandle)
1181         return STATUS_INVALID_HANDLE;
1182 
1183     pLogFile = pLogHandle->LogFile;
1184 
1185     /* Lock the log file exclusive */
1186     RtlAcquireResourceExclusive(&pLogFile->Lock, TRUE);
1187 
1188     Status = ElfFlushFile(&pLogFile->LogFile);
1189 
1190     /* Unlock the log file */
1191     RtlReleaseResource(&pLogFile->Lock);
1192 
1193     return Status;
1194 }
1195 
1196 
1197 /* Function 24 */
1198 NTSTATUS
1199 ElfrReportEventAndSourceW(
1200     IELF_HANDLE LogHandle,
1201     ULONG Time,
1202     USHORT EventType,
1203     USHORT EventCategory,
1204     ULONG EventID,
1205     PRPC_UNICODE_STRING SourceName,
1206     USHORT NumStrings,
1207     ULONG DataSize,
1208     PRPC_UNICODE_STRING ComputerName,
1209     PRPC_SID UserSID,
1210     PRPC_UNICODE_STRING Strings[],
1211     PBYTE Data,
1212     USHORT Flags,
1213     PULONG RecordNumber,
1214     PULONG TimeWritten)
1215 {
1216     /* Call the helper function. The event source is specified by the caller. */
1217     return ElfrIntReportEventW(LogHandle,
1218                                Time,
1219                                EventType,
1220                                EventCategory,
1221                                EventID,
1222                                SourceName,
1223                                NumStrings,
1224                                DataSize,
1225                                ComputerName,
1226                                UserSID,
1227                                Strings,
1228                                Data,
1229                                Flags,
1230                                RecordNumber,
1231                                TimeWritten);
1232 }
1233 
1234 
1235 void __RPC_FAR *__RPC_USER midl_user_allocate(SIZE_T len)
1236 {
1237     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
1238 }
1239 
1240 
1241 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
1242 {
1243     HeapFree(GetProcessHeap(), 0, ptr);
1244 }
1245 
1246 
1247 void __RPC_USER IELF_HANDLE_rundown(IELF_HANDLE LogHandle)
1248 {
1249     /* Close the handle */
1250     ElfDeleteEventLogHandle(&LogHandle); // ElfrCloseEL(&LogHandle);
1251 }
1252