diff options
Diffstat (limited to 'private/eventlog/server/elfapi.c')
-rw-r--r-- | private/eventlog/server/elfapi.c | 2235 |
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); +} |