summaryrefslogtreecommitdiffstats
path: root/private/eventlog/server/elfapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/eventlog/server/elfapi.c')
-rw-r--r--private/eventlog/server/elfapi.c2235
1 files changed, 2235 insertions, 0 deletions
diff --git a/private/eventlog/server/elfapi.c b/private/eventlog/server/elfapi.c
new file mode 100644
index 000000000..5ffa2a2fd
--- /dev/null
+++ b/private/eventlog/server/elfapi.c
@@ -0,0 +1,2235 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ELFAPI.C
+
+Abstract:
+
+ This module contains the server end of the Elf APIs.
+
+
+Author:
+
+ Rajen Shah (rajens) 29-Jul-1991
+
+
+Revision History:
+ 30-Jan-1995 MarkBl
+ Backup operators are allowed to _open the security log, but are only
+ allowed to perform backup operations on it; all other operations are
+ disallowed.
+
+ 13-Oct-1993 Danl
+ ElfrOpenELA: Fixed Memory Leak bug where it was not calling
+ RtlFreeUnicodeString for pRegModuleNameU and PModuleNameU.
+
+ 29-Jul-1991 RajenS
+ Created
+
+--*/
+
+
+//#include <rpcutil.h>
+
+#include <eventp.h>
+#include <elfcfg.h>
+#include <stdio.h> // sprintf
+#include <stdlib.h>
+#include <memory.h>
+
+//
+// PROTOTYPES
+//
+NTSTATUS
+ElfpOpenELW (
+ IN EVENTLOG_HANDLE_W UNCServerName,
+ IN PRPC_UNICODE_STRING ModuleName,
+ IN PRPC_UNICODE_STRING RegModuleName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle,
+ IN ULONG DesiredAccess
+ );
+
+NTSTATUS
+ElfpOpenELA (
+ IN EVENTLOG_HANDLE_A UNCServerName,
+ IN PRPC_STRING ModuleName,
+ IN PRPC_STRING RegModuleName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle,
+ IN ULONG DesiredAccess
+ );
+
+VOID
+FreePUStringArray (
+ IN PUNICODE_STRING * pUStringArray,
+ IN USHORT NumStrings
+ );
+
+
+//
+// These APIs only have one interface, since they don't take or return strings
+//
+
+NTSTATUS
+ElfrNumberOfRecords(
+ IN IELF_HANDLE LogHandle,
+ OUT PULONG NumberOfRecords
+ )
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrCurrentRecord API.
+
+Arguments:
+
+ LogHandle - The context-handle for this module's call.
+
+ NumberOfRecords - Where to return the total number of records in the
+ log file.
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+
+ PLOGMODULE Module;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ //
+ // This condition is TRUE iff a backup operator has opened the security
+ // log. In this case deny access, since backup operators are allowed
+ // only backup operation on the security log.
+ //
+
+ if (LogHandle->GrantedAccess & ELF_LOGFILE_BACKUP)
+ {
+ return(STATUS_ACCESS_DENIED);
+ }
+
+ //
+ // If the OldestRecordNumber is 0, that means we have an empty
+ // file, else we calculate the difference between the oldest
+ // and next record numbers
+ //
+
+ Module = FindModuleStrucFromAtom (LogHandle->Atom);
+ if (Module != NULL) {
+ *NumberOfRecords = Module->LogFile->OldestRecordNumber == 0 ? 0 :
+ Module->LogFile->CurrentRecordNumber -
+ Module->LogFile->OldestRecordNumber;
+ }
+ else {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ return (Status);
+
+}
+
+
+NTSTATUS
+ElfrOldestRecord(
+ IN IELF_HANDLE LogHandle,
+ OUT PULONG OldestRecordNumber
+ )
+{
+ PLOGMODULE Module;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ //
+ // This condition is TRUE iff a backup operator has opened the security
+ // log. In this case deny access, since backup operators are allowed
+ // only backup operation on the security log.
+ //
+
+ if (LogHandle->GrantedAccess & ELF_LOGFILE_BACKUP)
+ {
+ return(STATUS_ACCESS_DENIED);
+ }
+
+ Module = FindModuleStrucFromAtom (LogHandle->Atom);
+ if (Module != NULL) {
+ *OldestRecordNumber = Module->LogFile->OldestRecordNumber;
+ }
+ else {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+ElfrChangeNotify(
+ IN IELF_HANDLE LogHandle,
+ IN RPC_CLIENT_ID ClientId,
+ IN ULONG Event
+ )
+{
+
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE ProcessHandle = NULL;
+ HANDLE EventHandle;
+ PLOGMODULE Module;
+ PNOTIFIEE Notifiee;
+
+ //
+ // First make sure that this is a local call and that it is not a
+ // handle that was created for a backup log file
+ //
+
+ if (LogHandle->Flags & ELF_LOG_HANDLE_REMOTE_HANDLE ||
+ LogHandle->Flags & ELF_LOG_HANDLE_BACKUP_LOG) {
+ return(STATUS_INVALID_HANDLE);
+ }
+
+ //
+ // This condition is TRUE iff a backup operator has opened the security
+ // log. In this case deny access, since backup operators are allowed
+ // only backup operation on the security log.
+ //
+
+ if (LogHandle->GrantedAccess & ELF_LOGFILE_BACKUP)
+ {
+ return(STATUS_ACCESS_DENIED);
+ }
+
+ //
+ // First get a handle to the process using the passed in ClientId
+ //
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ NULL, // UNICODE string
+ 0, // Attributes
+ NULL, // Root directory
+ NULL); // Security descriptor
+
+ Status = NtOpenProcess(
+ &ProcessHandle,
+ PROCESS_DUP_HANDLE,
+ &ObjectAttributes,
+ (PCLIENT_ID) &ClientId);
+
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // Now dupe the handle they passed in for the event
+ //
+
+ Status = NtDuplicateObject(
+ ProcessHandle,
+ (HANDLE) Event,
+ NtCurrentProcess(),
+ &EventHandle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS);
+
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // Create a new NOTIFIEE control block to link in
+ //
+
+ Notifiee = ElfpAllocateBuffer(sizeof(NOTIFIEE));
+ if (Notifiee) {
+
+ //
+ // Fill in the fields
+ //
+
+ Notifiee->Handle = LogHandle;
+ Notifiee->Event = EventHandle;
+
+ //
+ // Find the LOGFILE associated with this handle
+ //
+
+ Module = FindModuleStrucFromAtom (LogHandle->Atom);
+ ASSERT(Module);
+
+ //
+ // Get exclusive access to the log file. This will ensure
+ // no one else is accessing the file.
+ //
+
+ RtlAcquireResourceExclusive (
+ &Module->LogFile->Resource,
+ TRUE // Wait until available
+ );
+
+ InsertHeadList(&Module->LogFile->Notifiees,
+ &Notifiee->Next);
+
+ //
+ // Free the resource
+ //
+
+ RtlReleaseResource ( &Module->LogFile->Resource );
+ }
+ else {
+ Status = STATUS_NO_MEMORY;
+ }
+ }
+ }
+ else {
+ if (Status == STATUS_INVALID_CID) {
+ Status = STATUS_INVALID_HANDLE;
+ }
+ }
+
+ if (ProcessHandle) {
+ NtClose(ProcessHandle);
+ }
+
+ return (Status);
+}
+
+
+//
+// UNICODE APIs
+//
+
+
+
+NTSTATUS
+ElfrClearELFW (
+ IN IELF_HANDLE LogHandle,
+ IN PRPC_UNICODE_STRING BackupFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrClearELFW API.
+
+Arguments:
+
+ LogHandle - The context-handle for this module's call. This must
+ not have been returned from OpenBackupEventlog, or
+ this call will fail with invalid handle.
+
+ BackupFileName - Name of the file to back up the current log file.
+ NULL implies not to back up the file.
+
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+ NTSTATUS Status=STATUS_SUCCESS;
+ PLOGMODULE Module;
+ ELF_REQUEST_RECORD Request;
+ CLEAR_PKT ClearPkt;
+ DWORD status=NO_ERROR;
+
+ //
+ // Can't clear a backup log
+ //
+
+ if (LogHandle->Flags & ELF_LOG_HANDLE_BACKUP_LOG) {
+ return(STATUS_INVALID_HANDLE);
+ }
+
+ //
+ // This condition is TRUE iff a backup operator has opened the security
+ // log. In this case deny access, since backup operators are allowed
+ // only backup operation on the security log.
+ //
+
+ if (LogHandle->GrantedAccess & ELF_LOGFILE_BACKUP)
+ {
+ return(STATUS_ACCESS_DENIED);
+ }
+
+ //
+ // Find the matching module structure
+ //
+
+ Module = FindModuleStrucFromAtom (LogHandle->Atom);
+
+ Request.Pkt.ClearPkt = &ClearPkt;
+ Request.Flags = 0;
+
+ if (Module != NULL) {
+
+ //
+ // Verify that the caller has clear access to this logfile
+ //
+
+ if (! RtlAreAllAccessesGranted (
+ LogHandle->GrantedAccess,
+ ELF_LOGFILE_CLEAR)) {
+
+ Status = STATUS_ACCESS_DENIED;
+ }
+
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // Fill in the request packet
+ //
+
+ Request.Module = Module;
+ Request.LogFile = Module->LogFile;
+ Request.Command = ELF_COMMAND_CLEAR;
+ Request.Status = STATUS_SUCCESS;
+ Request.Pkt.ClearPkt->BackupFileName =
+ (PUNICODE_STRING)BackupFileName;
+
+ //
+ // Call the worker routine to do the operation.
+ //
+
+ ElfPerformRequest (&Request);
+
+ //
+ // Extract status of operation from the request packet
+ //
+
+ Status = Request.Status;
+
+ //
+ // If this was the Security Logfile, and the clear was
+ // successful, then generate an audit.
+ //
+ if ((NT_SUCCESS(Status) &&
+ (_wcsicmp(ELF_SECURITY_MODULE_NAME, Module->LogFile->LogModuleName->Buffer) == 0))) {
+
+ //
+ // We just cleared the security log. Now we want to add
+ // a new event to that log to indicate who did it.
+ //
+ status = RpcImpersonateClient(NULL);
+ if (status != RPC_S_OK) {
+ ElfDbgPrint(("RPC IMPERSONATION FAILED %d\n",status));
+ }
+ else {
+ ElfpGenerateLogClearedEvent(LogHandle);
+ status = RpcRevertToSelf();
+ if (status != RPC_S_OK) {
+ DbgPrint("RPC REVERT TO SELF FAILED %d\n",status);
+ }
+ }
+ }
+
+ }
+ } else {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+
+ return (Status);
+
+}
+
+
+NTSTATUS
+ElfrBackupELFW (
+ IN IELF_HANDLE LogHandle,
+ IN PRPC_UNICODE_STRING BackupFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrBackupELFW API.
+
+Arguments:
+
+ LogHandle - The context-handle for this module's call.
+
+ BackupFileName - Name of the file to back up the current log file.
+
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+ NTSTATUS Status;
+ PLOGMODULE Module;
+ ELF_REQUEST_RECORD Request;
+ BACKUP_PKT BackupPkt;
+
+ if (BackupFileName->Length == 0) {
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ Request.Pkt.BackupPkt = &BackupPkt;
+ Request.Flags = 0;
+
+ //
+ // Find the matching module structure
+ //
+
+ Module = FindModuleStrucFromAtom (LogHandle->Atom);
+
+ if (Module != NULL) {
+
+ //
+ // Fill in the request packet
+
+ Request.Module = Module;
+ Request.LogFile = Module->LogFile;
+ Request.Command = ELF_COMMAND_BACKUP;
+ Request.Status = STATUS_SUCCESS;
+ Request.Pkt.BackupPkt->BackupFileName =
+ (PUNICODE_STRING)BackupFileName;
+
+ //
+ // Call the worker routine to do the operation.
+ //
+
+ ElfPerformRequest (&Request);
+
+ //
+ // Extract status of operation from the request packet
+ //
+
+ Status = Request.Status;
+
+ } else {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ return (Status);
+
+}
+
+
+NTSTATUS
+ElfrCloseEL (
+ IN OUT PIELF_HANDLE LogHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrCloseEL API.
+
+Arguments:
+
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+ NTSTATUS Status;
+
+ //
+ // Call the rundown routine to do all the work
+ //
+
+ IELF_HANDLE_rundown(*LogHandle);
+
+ *LogHandle = NULL; // so RPC knows it's closed
+
+ return (STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+ElfrDeregisterEventSource (
+ IN OUT PIELF_HANDLE LogHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrDeregisterEventSource API.
+
+Arguments:
+
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+ NTSTATUS Status;
+
+ //
+ // This condition is TRUE iff a backup operator has opened the security
+ // log. In this case deny access, since backup operators are allowed
+ // only backup operation on the security log.
+ //
+
+ if ((*LogHandle)->GrantedAccess & ELF_LOGFILE_BACKUP)
+ {
+ return(STATUS_ACCESS_DENIED);
+ }
+
+ //
+ // Call the rundown routine to do all the work
+ //
+
+ IELF_HANDLE_rundown(*LogHandle);
+
+ *LogHandle = NULL; // so RPC knows it's closed
+
+ return (STATUS_SUCCESS);
+}
+
+
+
+
+NTSTATUS
+ElfrOpenBELW (
+ IN EVENTLOG_HANDLE_W UNCServerName,
+ IN PRPC_UNICODE_STRING BackupFileName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrOpenBELW API. It creates
+ a module structure $BACKUPnnn where nnn is a unique number for every backup
+ log that is opened. It then calls ElfpOpenELW to actually open the file.
+
+
+Arguments:
+
+ UNCServerName - Not used.
+
+ BackupFileName - Name of the backup log file.
+
+ MajorVersion/MinorVersion - The version of the client.
+
+
+ LogHandle - Pointer to the place where the pointer to the
+ context handle structure will be placed.
+
+Return Value:
+
+ Returns an NTSTATUS code and, if no error, a "handle".
+
+
+--*/
+{
+
+ NTSTATUS Status;
+ UNICODE_STRING BackupStringW;
+ LPWSTR BackupModuleName;
+ PLOGMODULE pModule;
+ DWORD dwModuleNumber;
+
+//
+// Size of buffer (in bytes) required for a UNICODE string of $BACKUPnnn
+//
+
+#define SIZEOF_BACKUP_MODULE_NAME 64
+
+ UNREFERENCED_PARAMETER(UNCServerName);
+
+ //
+ // Create a unique module name by incrementing a global value
+ //
+
+ BackupModuleName = ElfpAllocateBuffer(SIZEOF_BACKUP_MODULE_NAME);
+ if (BackupModuleName == NULL) {
+ return(STATUS_NO_MEMORY);
+ }
+
+ //
+ // Serialize read, increment of the global backup module number.
+ // Note: double-timing the log file list critical section so as to not
+ // require another critical section specifically dedicated to this
+ // operation.
+ //
+
+ RtlEnterCriticalSection ((PRTL_CRITICAL_SECTION)&LogFileCritSec);
+
+ dwModuleNumber = BackupModuleNumber++;
+
+ RtlLeaveCriticalSection ((PRTL_CRITICAL_SECTION)&LogFileCritSec);
+
+ swprintf(BackupModuleName, L"$BACKUP%06d", dwModuleNumber);
+ RtlInitUnicodeString(&BackupStringW, BackupModuleName);
+
+ //
+ // Call SetupDataStruct to build the module and log data structures
+ // and actually open the file.
+ //
+ // NOTE: If this call is successful, the Unicode String Buffer for
+ // BackupStringW (otherwise known as BackupModuleName) will be attached
+ // to the LogModule structure, and should not be free'd.
+ //
+ //
+
+ Status = SetUpDataStruct(
+ BackupFileName, // Filename
+ 0, // Max size, it will use actual
+ 0, // retention period, not used for bkup
+ ELF_GUEST_ACCESS_UNRESTRICTED, // restrict guest
+ // access flag, inapplicable for bkup
+ &BackupStringW, // Module name
+ NULL, // Handle to registry, not used
+ ElfBackupLog // Log type
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ ElfpFreeBuffer(BackupModuleName);
+ return(Status);
+ }
+
+ //
+ // Call ElfOpenELW to actually open the log file and get a handle.
+ //
+ if (NT_SUCCESS(Status)) {
+
+ Status = ElfpOpenELW(NULL,
+ (PRPC_UNICODE_STRING) & BackupStringW,
+ NULL,
+ MajorVersion,
+ MinorVersion,
+ LogHandle,
+ ELF_LOGFILE_READ);
+ }
+
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // Mark this as a handle for a backup log, so we can clean up
+ // differently when it's closed, as well as disallow clear, backup
+ // and write operations.
+ //
+
+ (*LogHandle)->Flags |= ELF_LOG_HANDLE_BACKUP_LOG;
+
+ }
+ else {
+ //
+ // If we couldn't open the log file, then we need to tear down
+ // the DataStruct we set up with SetUpDataStruct.
+ //
+ pModule = GetModuleStruc ((PUNICODE_STRING)BackupFileName);
+
+ Status = ElfpCloseLogFile (pModule->LogFile, ELF_LOG_CLOSE_BACKUP);
+
+ UnlinkLogModule(pModule);
+ pModule->LogFile->RefCount--;
+ if (pModule->LogFile->RefCount == 0) {
+ UnlinkLogFile(pModule->LogFile); // Unlink the structure
+ RtlDeleteResource ( &pModule->LogFile->Resource );
+ RtlDeleteSecurityObject(&pModule->LogFile->Sd);
+ ElfpFreeBuffer (pModule->LogFile->LogFileName);
+ ElfpFreeBuffer (pModule->LogFile);
+ }
+ ElfpFreeBuffer(pModule->ModuleName);
+ ElfpFreeBuffer(pModule);
+
+ }
+
+ return(Status);
+}
+
+
+NTSTATUS
+ElfrRegisterEventSourceW (
+ IN EVENTLOG_HANDLE_W UNCServerName,
+ IN PRPC_UNICODE_STRING ModuleName,
+ IN PRPC_UNICODE_STRING RegModuleName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrRegisterEventSourceW API.
+ This routine allocates a structure for the context handle, finds
+ the matching module name and fills in the data. It returns the
+ pointer to the handle structure.
+
+
+Arguments:
+
+ UNCServerName - Not used.
+
+ ModuleName - Name of the module that is making this call.
+
+ RegModuleName - Not used.
+
+ MajorVersion/MinorVersion - The version of the client.
+
+
+ LogHandle - Pointer to the place where the pointer to the
+ context handle structure will be placed.
+
+Return Value:
+
+ Returns an NTSTATUS code and, if no error, a "handle".
+
+Note:
+
+ For now, just call ElfpOpenELW.
+
+
+--*/
+{
+ PLOGMODULE Module;
+
+ Module = GetModuleStruc ((PUNICODE_STRING)ModuleName);
+
+ return(ElfpOpenELW(UNCServerName, ModuleName, RegModuleName,
+ MajorVersion, MinorVersion, LogHandle, ELF_LOGFILE_WRITE));
+}
+
+NTSTATUS
+ElfrOpenELW (
+ IN EVENTLOG_HANDLE_W UNCServerName,
+ IN PRPC_UNICODE_STRING ModuleName,
+ IN PRPC_UNICODE_STRING RegModuleName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrOpenELW API.
+ This routine allocates a structure for the context handle, finds
+ the matching module name and fills in the data. It returns the
+ pointer to the handle structure.
+
+
+Arguments:
+
+ UNCServerName - Not used.
+
+ ModuleName - Name of the module that is making this call.
+
+ RegModuleName - Not used.
+
+ MajorVersion/MinorVersion - The version of the client.
+
+
+ LogHandle - Pointer to the place where the pointer to the
+ context handle structure will be placed.
+
+Return Value:
+
+ Returns an NTSTATUS code and, if no error, a "handle".
+
+
+--*/
+{
+ return( ElfpOpenELW (
+ UNCServerName,
+ ModuleName,
+ RegModuleName,
+ MajorVersion,
+ MinorVersion,
+ LogHandle,
+ ELF_LOGFILE_READ));
+}
+
+NTSTATUS
+ElfpOpenELW (
+ IN EVENTLOG_HANDLE_W UNCServerName,
+ IN PRPC_UNICODE_STRING ModuleName,
+ IN PRPC_UNICODE_STRING RegModuleName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle,
+ IN ULONG DesiredAccess
+ )
+
+/*++
+
+Routine Description:
+
+ Looks alot like ElfrOpenELW but also gets passed a DesiredAccess.
+
+Arguments:
+
+ UNCServerName - Not used.
+
+ ModuleName - Name of the module that is making this call.
+
+ RegModuleName - Not used.
+
+ MajorVersion/MinorVersion - The version of the client.
+
+
+ LogHandle - Pointer to the place where the pointer to the
+ context handle structure will be placed.
+
+ DesiredAccess - Indicates the access desired for this logfile.
+
+Return Value:
+
+ Returns an NTSTATUS code and, if no error, a "handle".
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PLOGMODULE Module;
+ IELF_HANDLE LogIHandle;
+ BOOL ForSecurityLog = FALSE;
+
+ //
+ // Allocate a new structure for the context handle
+ //
+
+ LogIHandle = (IELF_HANDLE) ElfpAllocateBuffer (
+ sizeof (*LogIHandle)
+ + ModuleName->Length
+ + sizeof (WCHAR)
+ );
+
+ if (LogIHandle) {
+
+ //
+ // Find the module structure in order to pull out the Atom.
+ //
+ // GetModuleStruc *always* succeeds! (returns default if module
+ // not found).
+ //
+
+ Module = GetModuleStruc ((PUNICODE_STRING)ModuleName);
+
+ //
+ // Validate the caller has appropriate access to this logfile.
+ // If this is the security log, then check privilege instead.
+ //
+ if (_wcsicmp(ELF_SECURITY_MODULE_NAME, Module->LogFile->LogModuleName->Buffer) == 0) {
+ ForSecurityLog = TRUE;
+ }
+ Status = ElfpAccessCheckAndAudit(
+ L"EventLog", // SubSystemName
+ L"LogFile", // ObjectTypeName
+ Module->ModuleName, // ObjectName
+ LogIHandle, // Context handle - required?
+ Module->LogFile->Sd, // Security Descriptor
+ DesiredAccess, // Requested Access
+ NULL, // GENERIC_MAPPING
+ ForSecurityLog // Indicates the check is for security log
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ LogIHandle->Atom = Module->ModuleAtom;
+
+ LogIHandle->NameLength = ModuleName->Length + sizeof(WCHAR);
+ RtlMoveMemory( LogIHandle->Name,
+ ModuleName->Buffer,
+ ModuleName->Length
+ );
+
+ LogIHandle->Name[ModuleName->Length / sizeof(WCHAR)] = L'\0';
+
+ LogIHandle->MajorVersion = MajorVersion; // Store the version
+ LogIHandle->MinorVersion = MinorVersion; // of the client
+
+ //
+ // Initialize seek positions and flags to zero.
+ //
+
+ LogIHandle->SeekRecordPos = 0;
+ LogIHandle->SeekBytePos = 0;
+ LogIHandle->Flags = 0;
+
+ //
+ // Link in this structure to the list of context handles
+ //
+
+ LogIHandle->Signature = ELF_CONTEXTHANDLE_SIGN; // DEBUG
+ LinkContextHandle (LogIHandle);
+
+ *LogHandle = LogIHandle; // Set return handle
+ Status = STATUS_SUCCESS; // Set return status
+ }
+ else {
+ ElfpFreeBuffer(LogIHandle);
+ }
+
+ } else {
+
+ Status = STATUS_NO_MEMORY;
+ }
+
+ return (Status);
+
+ UNREFERENCED_PARAMETER(UNCServerName);
+ UNREFERENCED_PARAMETER(RegModuleName);
+}
+
+
+
+NTSTATUS
+w_ElfrReadEL (
+ IN ULONG Flags, // ANSI or UNICODE
+ IN IELF_HANDLE LogHandle,
+ IN ULONG ReadFlags,
+ IN ULONG RecordNumber,
+ IN ULONG NumberOfBytesToRead,
+ IN PBYTE Buffer,
+ OUT PULONG NumberOfBytesRead,
+ OUT PULONG MinNumberOfBytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ This is the worker for the ElfrReadEL APIs.
+
+Arguments:
+
+ Same as ElfrReadELW API except that Flags contains an indication
+ of whether this is ANSI or UNICODE.
+
+Return Value:
+
+ Same as the main API.
+
+NOTES:
+
+ We assume that the client-side has validated the flags to ensure that
+ only one type of each bit is set. No checking is done at the server end.
+
+
+--*/
+{
+ NTSTATUS Status;
+ PLOGMODULE Module;
+ ELF_REQUEST_RECORD Request;
+ READ_PKT ReadPkt;
+
+ //
+ // The ELF_HANDLE_INVALID_FOR_READ flag bit would be set if the
+ // file changed underneath this handle.
+ //
+
+ if (LogHandle->Flags & ELF_LOG_HANDLE_INVALID_FOR_READ) {
+ return(STATUS_EVENTLOG_FILE_CHANGED);
+ }
+
+ //
+ // This condition is TRUE iff a backup operator has opened the security
+ // log. In this case deny access, since backup operators are allowed
+ // only backup operation on the security log.
+ //
+
+ if (LogHandle->GrantedAccess & ELF_LOGFILE_BACKUP)
+ {
+ return(STATUS_ACCESS_DENIED);
+ }
+
+ Request.Pkt.ReadPkt = &ReadPkt; // Set up read packet in request packet
+
+ //
+ // Find the matching module structure
+ //
+ Module = FindModuleStrucFromAtom (LogHandle->Atom);
+
+ //
+ // Only continue if the module was found
+ //
+
+ if (Module != NULL) {
+
+ //
+ // Fill in the request packet
+ //
+ Request.Module = Module;
+ Request.Flags = 0;
+ Request.LogFile = Module->LogFile;
+ Request.Command = ELF_COMMAND_READ;
+ Request.Status = STATUS_SUCCESS;
+ Request.Pkt.ReadPkt->MinimumBytesNeeded = *MinNumberOfBytesNeeded;
+ Request.Pkt.ReadPkt->BufferSize = NumberOfBytesToRead;
+ Request.Pkt.ReadPkt->Buffer = (PVOID)Buffer;
+ Request.Pkt.ReadPkt->ReadFlags = ReadFlags;
+ Request.Pkt.ReadPkt->RecordNumber = RecordNumber;
+ Request.Pkt.ReadPkt->LastSeekPos = LogHandle->SeekBytePos;
+ Request.Pkt.ReadPkt->LastSeekRecord = LogHandle->SeekRecordPos;
+ Request.Pkt.ReadPkt->Flags = Flags; // Indicate UNICODE or ANSI
+
+ //
+ // Pass along whether the last read was in a forward or backward
+ // direction (affects how we treat being at EOF). Then reset the
+ // bit in the handle depending on what this read is.
+ //
+
+ if (LogHandle->Flags & ELF_LOG_HANDLE_LAST_READ_FORWARD) {
+ Request.Pkt.ReadPkt->Flags |= ELF_LAST_READ_FORWARD;
+ }
+
+ if (ReadFlags & EVENTLOG_FORWARDS_READ) {
+ LogHandle->Flags |= ELF_LOG_HANDLE_LAST_READ_FORWARD;
+ }
+ else {
+ LogHandle->Flags &= ~(ELF_LOG_HANDLE_LAST_READ_FORWARD);
+ }
+
+
+ //
+ // Perform the operation
+ //
+ ElfPerformRequest( &Request );
+
+ //
+ // Update current seek positions
+ //
+ LogHandle->SeekRecordPos = Request.Pkt.ReadPkt->LastSeekRecord;
+ LogHandle->SeekBytePos = Request.Pkt.ReadPkt->LastSeekPos;
+
+ //
+ // Set up return values
+ //
+ *NumberOfBytesRead = Request.Pkt.ReadPkt->BytesRead;
+ *MinNumberOfBytesNeeded = Request.Pkt.ReadPkt->MinimumBytesNeeded;
+
+ Status = Request.Status;
+
+ } else {
+ Status = STATUS_INVALID_HANDLE;
+ //
+ // Set the NumberOfBytesNeeded to zero since there are no bytes to
+ // transfer.
+ //
+ *NumberOfBytesRead = 0;
+ *MinNumberOfBytesNeeded = 0;
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+ElfrReadELW (
+ IN IELF_HANDLE LogHandle,
+ IN ULONG ReadFlags,
+ IN ULONG RecordNumber,
+ IN ULONG NumberOfBytesToRead,
+ IN PBYTE Buffer,
+ OUT PULONG NumberOfBytesRead,
+ OUT PULONG MinNumberOfBytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrReadELW API.
+
+Arguments:
+
+
+
+Return Value:
+
+ Returns an NTSTATUS code, NumberOfBytesRead if the read was successful
+ and MinNumberOfBytesNeeded if the buffer was not big enough.
+
+
+--*/
+{
+ NTSTATUS Status;
+
+ //
+ // Call the worker with the UNICODE flag
+ //
+
+ return(w_ElfrReadEL (
+ ELF_IREAD_UNICODE,
+ LogHandle,
+ ReadFlags,
+ RecordNumber,
+ NumberOfBytesToRead,
+ Buffer,
+ NumberOfBytesRead,
+ MinNumberOfBytesNeeded
+ ));
+
+}
+
+
+
+NTSTATUS
+ElfrReportEventW (
+ IN IELF_HANDLE LogHandle,
+ IN ULONG EventTime,
+ IN USHORT EventType,
+ IN USHORT EventCategory OPTIONAL,
+ IN ULONG EventID,
+ IN USHORT NumStrings,
+ IN ULONG DataSize,
+ IN PRPC_UNICODE_STRING ComputerName,
+ IN PRPC_SID UserSid,
+ IN PRPC_UNICODE_STRING *Strings,
+ IN PBYTE Data,
+ IN USHORT Flags,
+ IN OUT PULONG RecordNumber OPTIONAL,
+ IN OUT PULONG TimeWritten OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrReportEventW API.
+
+Arguments:
+
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+ NTSTATUS Status;
+ PLOGMODULE Module;
+ ELF_REQUEST_RECORD Request;
+ WRITE_PKT WritePkt;
+
+ ULONG RecordLength;
+ ULONG StringOffset, DataOffset;
+ ULONG StringsSize;
+ USHORT i;
+ PVOID EventBuffer;
+ PEVENTLOGRECORD EventLogRecord;
+ PWSTR ReplaceStrings, SrcString;
+ PBYTE BinaryData;
+ PUNICODE_STRING UComputerName;
+ PWSTR UModuleName;
+ ULONG PadSize;
+ ULONG UserSidLength = 0; // Init to zero
+ ULONG UserSidOffset;
+ ULONG ModuleNameLen, ComputerNameLen; // Length in bytes
+ ULONG zero = 0; // For pad bytes
+ LARGE_INTEGER Time;
+ ULONG LogTimeWritten;
+
+ //
+ // These are for Security Auditing to use for paired events. This will
+ // not be implemented in Product 1
+ //
+
+ UNREFERENCED_PARAMETER(RecordNumber);
+ UNREFERENCED_PARAMETER(TimeWritten);
+
+ //
+ // This condition is TRUE iff a backup operator has opened the security
+ // log. In this case deny access, since backup operators are allowed
+ // only backup operation on the security log.
+ //
+
+ if (LogHandle->GrantedAccess & ELF_LOGFILE_BACKUP)
+ {
+ return(STATUS_ACCESS_DENIED);
+ }
+
+ //
+ // Make sure the SID passed in is valid
+ //
+
+ if (ARGUMENT_PRESENT(UserSid)) {
+ if (!IsValidSid(UserSid)) {
+ return(STATUS_INVALID_PARAMETER);
+ }
+ }
+
+ //
+ // Make sure strings are null terminated on this side of the RPC call
+ // (RPC doesn't pass the null terminator)
+
+ for (i = 0; i < NumStrings; i++ ) {
+ if (Strings[i]) {
+ if (Strings[i]->MaximumLength >= Strings[i]->Length +
+ sizeof(WCHAR)) {
+ Strings[i]->Buffer[Strings[i]->Length / sizeof(WCHAR)]
+ = L'\0';
+ }
+ }
+
+ }
+
+ //
+ // Can't write to a backup log
+ //
+
+ if (LogHandle->Flags & ELF_LOG_HANDLE_BACKUP_LOG) {
+ return(STATUS_INVALID_HANDLE);
+ }
+
+ //
+ // Make sure they didn't pass in a null pointer for the data, but tell
+ // me there was something there (I still think RPC should protect me from
+ // this!)
+ //
+
+ if (!Data && DataSize != 0) {
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+
+ UComputerName = (PUNICODE_STRING)ComputerName;
+ UModuleName = LogHandle->Name;
+
+ Request.Pkt.WritePkt = &WritePkt; // Set up write packet in request packet
+ Request.Flags = 0;
+
+ //
+ // Find the matching module structure
+ //
+
+ Module = FindModuleStrucFromAtom (LogHandle->Atom);
+
+ if (Module != NULL) {
+
+ //
+ // Generate any additional information needed in the record.
+ //
+ // Info that we have Info to generate
+ // ----------------- ----------------
+ // Modulename UserSidLength
+ // EventType Length
+ // EventID StringOffset
+ // NumStrings DataOffset
+ // Strings PadBytes
+ // DataLength LogTimeWritten
+ // Data
+ // UserSidOffset
+ // UserSid
+ // ComputerName
+ // TimeGenerated
+ //
+
+ // LogTimeWritten
+ // We need to generate a time when the log is written. This
+ // gets written in the log so that we can use it to test the
+ // retention period when wrapping the file.
+ //
+
+ NtQuerySystemTime(&Time);
+ RtlTimeToSecondsSince1970(
+ &Time,
+ &LogTimeWritten
+ );
+
+
+ //
+ // USERSIDLENTGH
+ //
+
+ if (UserSid) {
+ UserSidLength = RtlLengthSid ((PSID)UserSid);
+ }
+
+ //
+ // USERSIDOFFSET
+ //
+ // Extract the lengths from the STRING structure, and take care of
+ // the trailing NULLs.
+ //
+
+ ModuleNameLen = (wcslen(UModuleName) + 1)
+ * sizeof (WCHAR);
+ ComputerNameLen = UComputerName->Length + sizeof(WCHAR);
+
+ UserSidOffset = sizeof(EVENTLOGRECORD)
+ + ModuleNameLen
+ + ComputerNameLen;
+
+ //
+ // STRING OFFSET:
+ //
+
+ StringOffset = UserSidOffset + UserSidLength;
+
+
+ //
+ // Calculate the length of strings so that we can see how
+ // much space is needed for that.
+ //
+
+ StringsSize = 0;
+ for (i=0; i<NumStrings; i++) {
+ if (!Strings[i] || Strings[i]->MaximumLength == 0) {
+ StringsSize += sizeof(WCHAR);
+ }
+ else {
+ StringsSize += Strings[i]->Length + sizeof(WCHAR);
+ }
+ }
+
+ //
+ // DATA OFFSET:
+ //
+
+ DataOffset = StringOffset + StringsSize;
+
+ //
+ // Determine how big a buffer is needed for the eventlog record.
+ //
+
+ RecordLength = DataOffset
+ + DataSize
+ + sizeof(RecordLength); // Size excluding pad bytes
+
+ //
+ // Determine how many pad bytes are needed to align to a DWORD
+ // boundary.
+ //
+
+ PadSize = sizeof(ULONG) - (RecordLength % sizeof(ULONG));
+
+ RecordLength += PadSize; // True size needed
+
+ //
+ // Allocate the buffer for the Eventlog record
+ //
+
+ EventBuffer = ElfpAllocateBuffer(RecordLength);
+
+ if (EventBuffer != NULL) {
+
+ //
+ // Fill up the event record
+ //
+
+ EventLogRecord = (PEVENTLOGRECORD)EventBuffer;
+
+ EventLogRecord->Length = RecordLength;
+ EventLogRecord->TimeGenerated = EventTime;
+ EventLogRecord->Reserved = ELF_LOG_FILE_SIGNATURE;
+ EventLogRecord->TimeWritten = LogTimeWritten;
+ EventLogRecord->EventID = EventID;
+ EventLogRecord->EventType = EventType;
+ EventLogRecord->EventCategory = EventCategory;
+ EventLogRecord->ReservedFlags = Flags;
+ EventLogRecord->ClosingRecordNumber = 0;
+ EventLogRecord->NumStrings = NumStrings;
+ EventLogRecord->StringOffset = StringOffset;
+ EventLogRecord->DataLength = DataSize;
+ EventLogRecord->DataOffset = DataOffset;
+ EventLogRecord->UserSidLength = UserSidLength;
+ EventLogRecord->UserSidOffset = UserSidOffset;
+
+ //
+ // Fill in the variable-length fields
+ //
+
+ //
+ // STRINGS
+ //
+
+ ReplaceStrings = (PWSTR) ( (ULONG)EventLogRecord
+ + (ULONG)StringOffset
+ );
+
+ for (i=0; i < NumStrings; i++) {
+ if (!Strings[i] || Strings[i]->MaximumLength == 0) {
+ *ReplaceStrings = L'\0';
+ ReplaceStrings++;
+ }
+ else {
+ SrcString = (PWSTR)Strings[i]->Buffer;
+ RtlMoveMemory(ReplaceStrings, SrcString,
+ Strings[i]->Length);
+ ReplaceStrings[Strings[i]->Length / sizeof(WCHAR)] =
+ L'\0';
+ ReplaceStrings = (PWSTR)((PBYTE) ReplaceStrings
+ + Strings[i]->Length + sizeof(WCHAR));
+ }
+ }
+
+ //
+ // MODULENAME
+ //
+
+ BinaryData = (PBYTE) EventLogRecord + sizeof(EVENTLOGRECORD);
+ RtlMoveMemory (BinaryData,
+ UModuleName,
+ ModuleNameLen);
+
+ //
+ // COMPUTERNAME
+ //
+
+ ReplaceStrings = (LPWSTR) (BinaryData + ModuleNameLen);
+
+ RtlMoveMemory (ReplaceStrings,
+ UComputerName->Buffer,
+ UComputerName->Length);
+
+ ReplaceStrings[UComputerName->Length / sizeof(WCHAR)] = L'\0';
+
+ //
+ // USERSID
+ //
+
+ BinaryData = (PBYTE) ReplaceStrings + ComputerNameLen;
+
+ ASSERT (BinaryData
+ == ((PBYTE) EventLogRecord) + UserSidOffset);
+
+ RtlMoveMemory (BinaryData,
+ UserSid,
+ UserSidLength);
+
+ //
+ // BINARY DATA
+ //
+
+ BinaryData = (PBYTE) ((ULONG)EventLogRecord + DataOffset);
+ if (Data) {
+ RtlMoveMemory (BinaryData, Data, DataSize);
+ }
+
+ //
+ // PAD - Fill with zeros
+ //
+
+ BinaryData = (PBYTE) ((ULONG)BinaryData + DataSize);
+ RtlMoveMemory (BinaryData, &zero, PadSize);
+
+ //
+ // LENGTH at end of record
+ //
+
+ BinaryData = (PBYTE)((ULONG)BinaryData + PadSize);// Point after pad bytes
+ ((PULONG)BinaryData)[0] = RecordLength;
+
+ //
+ // Make sure we are in the right place
+ //
+
+ ASSERT ((ULONG)BinaryData
+ == (RecordLength + (ULONG)EventLogRecord) - sizeof(ULONG));
+
+ //
+ // Set up request packet.
+ // Link event log record into the request structure.
+ //
+
+ Request.Module = Module;
+ Request.LogFile = Request.Module->LogFile;
+ Request.Command = ELF_COMMAND_WRITE;
+ Request.Pkt.WritePkt->Buffer = (PVOID)EventBuffer;
+ Request.Pkt.WritePkt->Datasize = RecordLength;
+
+ //
+ // Perform the operation
+ //
+
+ ElfPerformRequest( &Request );
+
+ //
+ // Free up the buffer
+ //
+
+ ElfpFreeBuffer(EventBuffer);
+
+ Status = Request.Status; // Set status of WRITE
+
+ } else {
+ Status = STATUS_NO_MEMORY;
+ }
+
+ } else {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ return (Status);
+}
+
+
+
+//
+// ANSI APIs
+//
+
+NTSTATUS
+ElfrClearELFA (
+ IN IELF_HANDLE LogHandle,
+ IN PRPC_STRING BackupFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrClearELFA API.
+
+Arguments:
+
+ LogHandle - The context-handle for this module's call.
+
+ BackupFileName - Name of the file to back up the current log file.
+ NULL implies not to back up the file.
+
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+ NTSTATUS Status;
+ UNICODE_STRING BackupFileNameU;
+
+ //
+ // Convert the BackupFileName to a UNICODE STRING and call the
+ // UNICODE API to do the work.
+ //
+ Status = RtlAnsiStringToUnicodeString (
+ (PUNICODE_STRING)&BackupFileNameU,
+ (PANSI_STRING)BackupFileName,
+ TRUE
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ Status = ElfrClearELFW (
+ LogHandle,
+ (PRPC_UNICODE_STRING)&BackupFileNameU
+ );
+
+ RtlFreeUnicodeString (&BackupFileNameU);
+ }
+
+ return (Status);
+
+}
+
+
+
+NTSTATUS
+ElfrBackupELFA (
+ IN IELF_HANDLE LogHandle,
+ IN PRPC_STRING BackupFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrBackupELFA API.
+
+Arguments:
+
+ LogHandle - The context-handle for this module's call.
+
+ BackupFileName - Name of the file to back up the current log file.
+
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+ NTSTATUS Status;
+ UNICODE_STRING BackupFileNameU;
+
+ //
+ // Convert the BackupFileName to a UNICODE STRING and call the
+ // UNICODE API to do the work.
+ //
+ Status = RtlAnsiStringToUnicodeString (
+ (PUNICODE_STRING)&BackupFileNameU,
+ (PANSI_STRING)BackupFileName,
+ TRUE
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ Status = ElfrBackupELFW (
+ LogHandle,
+ (PRPC_UNICODE_STRING)&BackupFileNameU
+ );
+
+ RtlFreeUnicodeString (&BackupFileNameU);
+ }
+
+ return (Status);
+
+}
+
+
+NTSTATUS
+ElfrRegisterEventSourceA (
+ IN EVENTLOG_HANDLE_A UNCServerName,
+ IN PRPC_STRING ModuleName,
+ IN PRPC_STRING RegModuleName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrRegisterEventSourceA API.
+ This routine allocates a structure for the context handle, finds
+ the matching module name and fills in the data. It returns the
+ pointer to the handle structure.
+
+
+Arguments:
+
+ UNCServerName - Not used.
+
+ ModuleName - Name of the module that is making this call.
+
+ RegModuleName - Not used.
+
+ MajorVersion/MinorVersion - The version of the client.
+
+
+ LogHandle - Pointer to the place where the pointer to the
+ context handle structure will be placed.
+
+Return Value:
+
+ Returns an NTSTATUS code and, if no error, a "handle".
+
+Note:
+
+ For now, just call ElfrOpenELA.
+
+
+--*/
+{
+
+ NTSTATUS Status;
+ PLOGMODULE Module;
+ UNICODE_STRING ModuleNameU;
+
+ Status = RtlAnsiStringToUnicodeString (
+ (PUNICODE_STRING) &ModuleNameU,
+ (PANSI_STRING) ModuleName,
+ TRUE
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ return(Status);
+ }
+
+ Module = GetModuleStruc ((PUNICODE_STRING) & ModuleNameU);
+
+ RtlFreeUnicodeString (& ModuleNameU);
+
+ return(ElfpOpenELA(UNCServerName, ModuleName, RegModuleName,
+ MajorVersion, MinorVersion, LogHandle, ELF_LOGFILE_WRITE));
+
+}
+
+NTSTATUS
+ElfrOpenELA (
+ IN EVENTLOG_HANDLE_A UNCServerName,
+ IN PRPC_STRING ModuleName,
+ IN PRPC_STRING RegModuleName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrOpenEL API.
+ This routine allocates a structure for the context handle, finds
+ the matching module name and fills in the data. It returns the
+ pointer to the handle structure.
+
+
+Arguments:
+
+ UNCServerName - Not used.
+
+ ModuleName - Name of the module that is making this call.
+
+ RegModuleName - Name of module to use to determine the log file.
+
+ MajorVersion/MinorVersion - The version of the client.
+
+
+ LogHandle - Pointer to the place where the pointer to the
+ context handle structure will be placed.
+
+Return Value:
+
+ Returns an NTSTATUS code and, if no error, a "handle".
+
+
+--*/
+{
+ return (ElfpOpenELA (
+ UNCServerName,
+ ModuleName,
+ RegModuleName,
+ MajorVersion,
+ MinorVersion,
+ LogHandle,
+ ELF_LOGFILE_READ));
+}
+
+NTSTATUS
+ElfpOpenELA (
+ IN EVENTLOG_HANDLE_A UNCServerName,
+ IN PRPC_STRING ModuleName,
+ IN PRPC_STRING RegModuleName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle,
+ IN ULONG DesiredAccess
+ )
+
+/*++
+
+Routine Description:
+
+ Looks alot loke ElfrOpenELA, only this also takes a DesiredAccess parameter.
+
+
+Arguments:
+
+ UNCServerName - Not used.
+
+ ModuleName - Name of the module that is making this call.
+
+ RegModuleName - Name of module to use to determine the log file.
+
+ MajorVersion/MinorVersion - The version of the client.
+
+
+ LogHandle - Pointer to the place where the pointer to the
+ context handle structure will be placed.
+
+Return Value:
+
+ Returns an NTSTATUS code and, if no error, a "handle".
+
+--*/
+{
+ NTSTATUS Status;
+ UNICODE_STRING ModuleNameU;
+
+ //
+ // Convert the ModuleName and RegModulename to UNICODE STRINGs and call
+ // the UNICODE API to do the work.
+ //
+
+ Status = RtlAnsiStringToUnicodeString (
+ (PUNICODE_STRING)&ModuleNameU,
+ (PANSI_STRING)ModuleName,
+ TRUE
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // We *KNOW* that the UNCServerName is not used
+ // by ElfpOpenELW so we save ourselves some work
+ // and just pass in a NULL.
+ //
+ Status = ElfpOpenELW (
+ (EVENTLOG_HANDLE_W) NULL,
+ (PRPC_UNICODE_STRING)&ModuleNameU,
+ NULL,
+ MajorVersion,
+ MinorVersion,
+ LogHandle,
+ DesiredAccess
+ );
+
+ RtlFreeUnicodeString(&ModuleNameU);
+ }
+
+ return (Status);
+ UNREFERENCED_PARAMETER(UNCServerName);
+}
+
+
+
+
+
+NTSTATUS
+ElfrOpenBELA (
+ IN EVENTLOG_HANDLE_A UNCServerName,
+ IN PRPC_STRING FileName,
+ IN ULONG MajorVersion,
+ IN ULONG MinorVersion,
+ OUT PIELF_HANDLE LogHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrOpenBEL API.
+ This routine allocates a structure for the context handle, finds
+ the matching module name and fills in the data. It returns the
+ pointer to the handle structure.
+
+
+Arguments:
+
+ UNCServerName - Not used.
+
+ FileName - Filename of the logfile
+
+ MajorVersion/MinorVersion - The version of the client.
+
+ LogHandle - Pointer to the place where the pointer to the
+ context handle structure will be placed.
+
+Return Value:
+
+ Returns an NTSTATUS code and, if no error, a "handle".
+
+
+--*/
+{
+ NTSTATUS Status;
+ UNICODE_STRING FileNameU;
+
+ //
+ // Convert the FileName to a UNICODE STRINGs and call
+ // the UNICODE API to do the work.
+ //
+
+ Status = RtlAnsiStringToUnicodeString (
+ (PUNICODE_STRING) &FileNameU,
+ (PANSI_STRING) FileName,
+ TRUE
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // We *KNOW* that the UNCServerName is not used
+ // by ElfrOpenELW so we save ourselves some work
+ // and just pass in a NULL.
+ //
+
+ Status = ElfrOpenBELW (
+ (EVENTLOG_HANDLE_W) NULL,
+ (PRPC_UNICODE_STRING)&FileNameU,
+ MajorVersion,
+ MinorVersion,
+ LogHandle
+ );
+
+ RtlFreeUnicodeString(&FileNameU);
+ }
+
+ return (Status);
+ UNREFERENCED_PARAMETER(UNCServerName);
+
+}
+
+
+
+NTSTATUS
+ElfrReadELA (
+ IN IELF_HANDLE LogHandle,
+ IN ULONG ReadFlags,
+ IN ULONG RecordNumber,
+ IN ULONG NumberOfBytesToRead,
+ IN PBYTE Buffer,
+ OUT PULONG NumberOfBytesRead,
+ OUT PULONG MinNumberOfBytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrReadEL API.
+
+Arguments:
+
+
+
+Return Value:
+
+ Returns an NTSTATUS code, NumberOfBytesRead if the read was successful
+ and MinNumberOfBytesNeeded if the buffer was not big enough.
+
+
+--*/
+{
+ NTSTATUS Status;
+
+ //
+ // Call the worker with the UNICODE flag
+ //
+
+ return(w_ElfrReadEL (
+ ELF_IREAD_ANSI,
+ LogHandle,
+ ReadFlags,
+ RecordNumber,
+ NumberOfBytesToRead,
+ Buffer,
+ NumberOfBytesRead,
+ MinNumberOfBytesNeeded
+ ));
+}
+
+
+
+
+NTSTATUS
+ConvertStringArrayToUnicode (
+ PUNICODE_STRING *pUStringArray,
+ PANSI_STRING *Strings,
+ USHORT NumStrings
+ )
+/*++
+
+Routine Description:
+
+ This routine takes an array of STRINGs and generates an array of
+ PUNICODE_STRINGs. The destination array has already been allocated
+ by the caller, but the structures for the UNICODE_STRINGs will need
+ to be allocated by this routine.
+
+Arguments:
+
+ pUStringArray - Array of PUNICODE_STRINGs.
+ Strings - Array of PANSI_STRINGs.
+ NumStrings - Number of elements in the arrays.
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ USHORT i;
+
+ //
+ // For each string passed in, allocate a UNICODE_STRING buffer
+ // and set it to the UNICODE equivalent of the string passed in.
+ //
+ for (i=0; i<NumStrings; i++) {
+
+ if (Strings[i]) {
+
+ pUStringArray[i] = ElfpAllocateBuffer (sizeof (UNICODE_STRING));
+
+ if (pUStringArray[i]) {
+
+ Status = RtlAnsiStringToUnicodeString (
+ pUStringArray[i],
+ (PANSI_STRING)Strings[i],
+ TRUE
+ );
+ } else {
+ Status = STATUS_NO_MEMORY;
+ }
+ } else {
+ pUStringArray[i] = NULL;
+ }
+ if (!NT_SUCCESS(Status))
+ break; // Jump out of loop and return status
+ }
+
+ //
+ // Free any allocations on failure.
+ //
+
+ if (!NT_SUCCESS(Status)) {
+ FreePUStringArray(pUStringArray, (USHORT)(i + 1));
+ }
+
+ return (Status);
+}
+
+
+
+VOID
+FreePUStringArray (
+ PUNICODE_STRING *pUStringArray,
+ USHORT NumStrings
+ )
+/*++
+
+Routine Description:
+
+ This routine takes the PUNICODE_STRING array that was filled in by
+ ConvertStringArrayToUnicode and frees the buffer portion of
+ each unicode string and then the UNICODE structure itseld. It handles
+ the case where the array may not have been filled completely due
+ to insufficient memory.
+
+Arguments:
+
+ pUStringArray - Array of PUNICODE_STRINGs.
+ NumStrings - Number of elements in the array.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ USHORT i;
+
+ for (i=0; i<NumStrings; i++) {
+
+ if (pUStringArray[i]) {
+
+ if (pUStringArray[i]->Buffer) {
+ RtlFreeUnicodeString (pUStringArray[i]); // Free the string buffer
+
+ ElfpFreeBuffer (pUStringArray[i]); // Free the structure itself
+ }
+ }
+ }
+}
+
+
+
+NTSTATUS
+ElfrReportEventA (
+ IN IELF_HANDLE LogHandle,
+ IN ULONG Time,
+ IN USHORT EventType,
+ IN USHORT EventCategory OPTIONAL,
+ IN ULONG EventID,
+ IN USHORT NumStrings,
+ IN ULONG DataSize,
+ IN PRPC_STRING ComputerName,
+ IN PRPC_SID UserSid,
+ IN PRPC_STRING *Strings,
+ IN PBYTE Data,
+ IN USHORT Flags,
+ IN OUT PULONG RecordNumber OPTIONAL,
+ IN OUT PULONG TimeWritten OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the ElfrReportEventA API.
+
+Arguments:
+
+
+Return Value:
+
+ Returns an NTSTATUS code.
+
+
+--*/
+{
+ NTSTATUS Status;
+ UNICODE_STRING ComputerNameU;
+ PUNICODE_STRING *pUStringArray;
+
+ //
+ // Convert the ComputerName to a UNICODE STRING and call the
+ // UNICODE API.
+ //
+
+ Status = RtlAnsiStringToUnicodeString (
+ (PUNICODE_STRING)&ComputerNameU,
+ (PANSI_STRING)ComputerName,
+ TRUE
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ if (NumStrings) {
+
+ pUStringArray = ElfpAllocateBuffer (
+ NumStrings * sizeof (PUNICODE_STRING)
+ );
+
+ //
+ // Convert the array of STRINGs to an array of UNICODE-STRINGs
+ // before calling the unicode API.
+ // We can just use the array of Strings passed in since we
+ // don't need to use it anywhere else.
+ //
+ Status = ConvertStringArrayToUnicode (
+ pUStringArray,
+ (PANSI_STRING *)Strings,
+ NumStrings
+ );
+
+ } else {
+ pUStringArray = NULL; // No strings passed in
+ }
+
+ if (NT_SUCCESS(Status)) {
+
+ Status = ElfrReportEventW (
+ LogHandle,
+ Time,
+ EventType,
+ EventCategory,
+ EventID,
+ NumStrings,
+ DataSize,
+ (PRPC_UNICODE_STRING)&ComputerNameU,
+ UserSid,
+ (PRPC_UNICODE_STRING*)pUStringArray,
+ Data,
+ Flags, // Flags - paired event
+ RecordNumber,// RecordNumber | support. not in
+ TimeWritten // TimeWritten _ product 1
+ );
+
+ FreePUStringArray (pUStringArray, NumStrings);
+
+ }
+
+ RtlFreeUnicodeString (&ComputerNameU);
+ }
+ if (pUStringArray)
+ ElfpFreeBuffer (pUStringArray);
+
+ return (Status);
+}