4459 lines
121 KiB
C
4459 lines
121 KiB
C
/*++
|
||
|
||
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:
|
||
|
||
14-May-01 a-jyotig
|
||
Removed impersonation from ElfrClearELFW as it is no longer required to
|
||
identify the client that clears a log.
|
||
|
||
02-Mar-01 drbeck
|
||
Modified ElfrClearELFW to impersonate client so that a SACL placed on the
|
||
system event log will correctly identify the client that clears a log.
|
||
|
||
|
||
10-Sep-1998 jschwart
|
||
Added ElfrGetLogInformation (GetEventlogInformation) API
|
||
|
||
30-Jan-1995 MarkBl
|
||
Backup operators are allowed to open the security log, but only
|
||
to perform backup operations. All other operations are prohibited.
|
||
|
||
13-Oct-1993 Danl
|
||
ElfrOpenELA: Fixed Memory Leak bug where it was not calling
|
||
RtlFreeUnicodeString for pRegModuleNameU and PModuleNameU.
|
||
|
||
29-Jul-1991 RajenS
|
||
Created
|
||
|
||
--*/
|
||
/****
|
||
@doc EXTERNAL INTERFACES EVTLOG
|
||
****/
|
||
|
||
|
||
#include <eventp.h>
|
||
#include <elfcfg.h>
|
||
#include <stdio.h> // swprintf
|
||
#include <stdlib.h>
|
||
#include <memory.h>
|
||
#include <clussprt.h>
|
||
|
||
//
|
||
// Maximum number of ChangeNotify requests per context handle
|
||
//
|
||
#define MAX_NOTIFY_REQUESTS 5
|
||
|
||
#if defined(_WIN64)
|
||
#define ALIGN_UP_64(x,t) (((x) + (t) - 1) & ~((t)-1))
|
||
#else
|
||
#define ALIGN_UP_64(x,t) (x)
|
||
#endif
|
||
|
||
|
||
//
|
||
// 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
|
||
);
|
||
|
||
NTSTATUS
|
||
VerifyElfHandle(
|
||
IN IELF_HANDLE LogHandle
|
||
);
|
||
|
||
NTSTATUS
|
||
VerifyUnicodeString(
|
||
IN PUNICODE_STRING pUString
|
||
);
|
||
|
||
NTSTATUS
|
||
VerifyAnsiString(
|
||
IN PANSI_STRING pAString
|
||
);
|
||
|
||
|
||
|
||
//
|
||
// 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;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrNumberOfRecords: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Insure the caller has read access.
|
||
//
|
||
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_READ))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrNumberOfRecords: LogHandle doesn't have read access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
|
||
if (NumberOfRecords == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrNumberOfRecords: NumberOfRecords is NULL\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrNumberOfRecords: Handle is a backup handle\n");
|
||
|
||
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
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrNumberOfRecords: No module struc associated with atom\n");
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ElfrOldestRecord(
|
||
IN IELF_HANDLE LogHandle,
|
||
OUT PULONG OldestRecordNumber
|
||
)
|
||
{
|
||
PLOGMODULE Module;
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrOldestRecord: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Insure the caller has read access.
|
||
//
|
||
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_READ))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOldestRecord: LogHandle doesn't have read access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
if (OldestRecordNumber == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOldestRecord: OldestRecordNumber is NULL\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOldestRecord: Handle is a backup handle\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
Module = FindModuleStrucFromAtom (LogHandle->Atom);
|
||
|
||
if (Module != NULL)
|
||
{
|
||
*OldestRecordNumber = Module->LogFile->OldestRecordNumber;
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOldestRecord: No module struc associated with atom\n");
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ElfrChangeNotify(
|
||
IN IELF_HANDLE LogHandle,
|
||
IN RPC_CLIENT_ID ClientId,
|
||
IN ULONG Event
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
NTSTATUS RpcStatus;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
HANDLE ProcessHandle = NULL;
|
||
HANDLE EventHandle;
|
||
PLOGMODULE Module;
|
||
PNOTIFIEE Notifiee;
|
||
CLIENT_ID tempCli;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrChangeNotify: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Ensure the caller has read access.
|
||
//
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_READ))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrChangeNotify: LogHandle doesn't have read access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// 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)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrChangeNotify: Handle is for a %ws log\n",
|
||
LogHandle->Flags & ELF_LOG_HANDLE_REMOTE_HANDLE ? L"remote" :
|
||
L"backup");
|
||
|
||
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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrChangeNotify: Handle is a backup handle\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Make sure the client has the right to open this process
|
||
//
|
||
|
||
RpcStatus = RpcImpersonateClient(NULL);
|
||
|
||
if (RpcStatus != RPC_S_OK)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrChangeNotify: RpcImpersonateClient failed %#x\n",
|
||
RpcStatus);
|
||
|
||
return RpcStatus;
|
||
}
|
||
|
||
//
|
||
// First get a handle to the process using the passed in ClientId. Note
|
||
// that the ClientId is supplied by the client so a rogue client may
|
||
// supply any client ID. However, because we impersonate when opening
|
||
// the process we don't get any additional access the client doesn't have.
|
||
//
|
||
InitializeObjectAttributes(&ObjectAttributes,
|
||
NULL, // UNICODE string
|
||
0, // Attributes
|
||
NULL, // Root directory
|
||
NULL); // Security descriptor
|
||
|
||
#ifdef _WIN64
|
||
|
||
tempCli.UniqueProcess = (HANDLE)ULongToPtr(ClientId.UniqueProcess);
|
||
tempCli.UniqueThread = (HANDLE)ULongToPtr(ClientId.UniqueThread);
|
||
|
||
Status = NtOpenProcess(&ProcessHandle,
|
||
PROCESS_DUP_HANDLE,
|
||
&ObjectAttributes,
|
||
&tempCli);
|
||
|
||
#else
|
||
Status = NtOpenProcess(&ProcessHandle,
|
||
PROCESS_DUP_HANDLE,
|
||
&ObjectAttributes,
|
||
(PCLIENT_ID) &ClientId);
|
||
#endif
|
||
|
||
RpcStatus = RpcRevertToSelf();
|
||
|
||
if (RpcStatus != RPC_S_OK)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrChangeNotify: RpcRevertToSelf failed %#x\n",
|
||
RpcStatus);
|
||
}
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// Now dupe the handle they passed in for the event
|
||
//
|
||
Status = NtDuplicateObject(ProcessHandle,
|
||
LongToHandle(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);
|
||
|
||
if (Module != NULL)
|
||
{
|
||
//
|
||
// 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
|
||
|
||
//
|
||
// Enforce the limit of ChangeNotify requests per context handle
|
||
//
|
||
if (LogHandle->dwNotifyRequests == MAX_NOTIFY_REQUESTS)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrChangeNotify: Already %d requests for this handle\n",
|
||
MAX_NOTIFY_REQUESTS);
|
||
|
||
NtClose(EventHandle);
|
||
ElfpFreeBuffer(Notifiee);
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Insert the new notifiee into the list and increment this
|
||
// context handle's ChangeNotify request count
|
||
//
|
||
InsertHeadList(&Module->LogFile->Notifiees,
|
||
&Notifiee->Next);
|
||
|
||
LogHandle->dwNotifyRequests++;
|
||
}
|
||
|
||
//
|
||
// Free the resource
|
||
//
|
||
RtlReleaseResource ( &Module->LogFile->Resource );
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrChangeNotify: No module struc associated with atom\n");
|
||
|
||
NtClose(EventHandle);
|
||
ElfpFreeBuffer(Notifiee);
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrChangeNotify: Unable to allocate NOTIFIEE block\n");
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
|
||
//
|
||
// Free the duplicated handle
|
||
//
|
||
CloseHandle(EventHandle);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrChangeNotify: NtDuplicateObject failed %#x\n",
|
||
Status);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrChangeNotify: NtOpenProcess failed %#x\n",
|
||
Status);
|
||
|
||
if (Status == STATUS_INVALID_CID)
|
||
{
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
}
|
||
|
||
if (ProcessHandle)
|
||
{
|
||
NtClose(ProcessHandle);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ElfrGetLogInformation(
|
||
IN IELF_HANDLE LogHandle,
|
||
IN ULONG InfoLevel,
|
||
OUT PBYTE lpBuffer,
|
||
IN ULONG cbBufSize,
|
||
OUT PULONG pcbBytesNeeded
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the RPC server entry point for the ElfrGetLogInformation API.
|
||
|
||
Arguments:
|
||
|
||
LogHandle - The context-handle for this module's call.
|
||
InfoLevel - Infolevel that specifies which information the user is requesting
|
||
lpBuffer - Buffer into which to place the information
|
||
cbBufSize - Size of lpBuffer, in bytes
|
||
pcbBytesNeeded - Required size of the buffer
|
||
|
||
Return Value:
|
||
|
||
Returns an NTSTATUS code.
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS ntStatus;
|
||
PLOGMODULE pLogModule;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
ntStatus = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(ntStatus))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrGetLogInformation: VerifyElfHandle failed %#x\n",
|
||
ntStatus);
|
||
|
||
return ntStatus;
|
||
}
|
||
|
||
//
|
||
// 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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrGetLogInformation: Handle is a backup handle\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Take the appropriate actions based on the Infolevel
|
||
//
|
||
switch (InfoLevel)
|
||
{
|
||
case EVENTLOG_FULL_INFO:
|
||
|
||
*pcbBytesNeeded = sizeof(EVENTLOG_FULL_INFORMATION);
|
||
|
||
if (cbBufSize < *pcbBytesNeeded)
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfrGetLogInformation: buffer size = %d, required size = %d\n",
|
||
cbBufSize,
|
||
*pcbBytesNeeded);
|
||
|
||
ntStatus = STATUS_BUFFER_TOO_SMALL;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the module associated with this log handle
|
||
//
|
||
pLogModule = FindModuleStrucFromAtom(LogHandle->Atom);
|
||
|
||
if (pLogModule != NULL)
|
||
{
|
||
//
|
||
// The caller has the permission for this operation. Note
|
||
// that an access check is done when opening the log, so
|
||
// there's no need to repeat it here.
|
||
//
|
||
((LPEVENTLOG_FULL_INFORMATION)lpBuffer)->dwFull =
|
||
|
||
(pLogModule->LogFile->Flags & ELF_LOGFILE_LOGFULL_WRITTEN ?
|
||
TRUE :
|
||
FALSE);
|
||
|
||
ELF_LOG2(TRACE,
|
||
"ElfrGetLogInformation: %ws log is %ws\n",
|
||
pLogModule->LogFile->LogModuleName->Buffer,
|
||
pLogModule->LogFile->Flags & ELF_LOGFILE_LOGFULL_WRITTEN ?
|
||
L"full" :
|
||
L"not full");
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrGetLogInformation: No module struc associated with atom\n");
|
||
|
||
ntStatus = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
ELF_LOG1(ERROR,
|
||
"ElfrGetLogInformation: Invalid InfoLevel %d\n",
|
||
InfoLevel);
|
||
|
||
ntStatus = STATUS_INVALID_LEVEL;
|
||
break;
|
||
}
|
||
|
||
return ntStatus;
|
||
}
|
||
|
||
|
||
//
|
||
// 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.
|
||
|
||
CleanExit lable was written to add some cleanup code. The cleanup code was
|
||
removed later as it was not required but the lable is retained in order to
|
||
add any cleanup code if required in future
|
||
|
||
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;
|
||
PLOGMODULE Module;
|
||
ELF_REQUEST_RECORD Request;
|
||
CLEAR_PKT ClearPkt;
|
||
DWORD status = NO_ERROR;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrClearELFW: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
goto CleanExit;
|
||
}
|
||
|
||
//
|
||
// Ensure the caller has clear access.
|
||
//
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_CLEAR))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrClearELFW: LogHandle doesn't have clear access\n");
|
||
|
||
Status = STATUS_ACCESS_DENIED;
|
||
goto CleanExit;
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
if (BackupFileName != NULL)
|
||
{
|
||
Status = VerifyUnicodeString(BackupFileName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrClearELFW: BackupFileName is an invalid Unicode string\n");
|
||
|
||
goto CleanExit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Can't clear a backup log
|
||
//
|
||
|
||
if (LogHandle->Flags & ELF_LOG_HANDLE_BACKUP_LOG)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrClearELFW: Handle is for a backup log\n");
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
goto CleanExit;
|
||
}
|
||
|
||
//
|
||
// 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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrClearELFW: Handle is a backup handle\n");
|
||
|
||
Status = STATUS_ACCESS_DENIED;
|
||
goto CleanExit;
|
||
}
|
||
|
||
//
|
||
// 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))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrClearELFW: Caller does not have clear access to %ws log\n",
|
||
Module->LogFile->LogModuleName->Buffer);
|
||
|
||
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.
|
||
//
|
||
ElfpGenerateLogClearedEvent(LogHandle);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrClearELFW: No module struc associated with atom\n");
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
CleanExit:
|
||
|
||
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;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrBackupELFW: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Ensure the caller has read access.
|
||
//
|
||
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_READ))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrBackupELFW: LogHandle doesn't have read access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Make sure the client has SE_BACKUP_PRIVILEGE enabled. Note
|
||
// that we attempted to enable this on the client side
|
||
//
|
||
if (ElfpTestClientPrivilege(SE_BACKUP_PRIVILEGE, NULL) != STATUS_SUCCESS)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrBackupELFW: Client does not have SE_BACKUP_PRIVILEGE\n");
|
||
|
||
return(STATUS_PRIVILEGE_NOT_HELD);
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
Status = VerifyUnicodeString(BackupFileName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrBackupELFW: BackupFileName is not a valid Unicode string\n");
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// A filename must be specified.
|
||
//
|
||
|
||
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
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrBackupELFW: No module struc associated with atom\n");
|
||
|
||
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;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
if (LogHandle == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrCloseEL: LogHandle is NULL\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
Status = VerifyElfHandle(*LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrCloseEL: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return 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;
|
||
|
||
if (LogHandle == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrDeregisterEventSource: LogHandle is NULL\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
Status = VerifyElfHandle(*LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrDeregisterEventSource: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return 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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrDeregisterEventSource: Handle is a backup handle\n");
|
||
|
||
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);
|
||
|
||
//
|
||
// Check arguments.
|
||
//
|
||
|
||
Status = VerifyUnicodeString(BackupFileName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOpenBELW: BackupFileName is not a Unicode string\n");
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// A filename must be specified.
|
||
//
|
||
if (BackupFileName->Length == 0)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOpenBELW: Length of BackupFileName is 0\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if (LogHandle == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOpenBELW: LogHandle is NULL\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Create a unique module name by incrementing a global value
|
||
//
|
||
BackupModuleName = ElfpAllocateBuffer(SIZEOF_BACKUP_MODULE_NAME);
|
||
|
||
if (BackupModuleName == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOpenBELW: Unable to allocate memory for BackupModuleName\n");
|
||
|
||
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 (&LogFileCritSec);
|
||
|
||
dwModuleNumber = BackupModuleNumber++;
|
||
|
||
RtlLeaveCriticalSection (&LogFileCritSec);
|
||
|
||
swprintf(BackupModuleName, L"$BACKUP%06d", dwModuleNumber);
|
||
RtlInitUnicodeString(&BackupStringW, BackupModuleName);
|
||
|
||
ELF_LOG2(TRACE,
|
||
"ElfrOpenBELW: Backing up module %ws to file %ws\n",
|
||
BackupModuleName,
|
||
BackupFileName->Buffer);
|
||
|
||
//
|
||
// 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
|
||
LOGPOPUP_NEVER_SHOW,
|
||
ELF_DEFAULT_AUTOBACKUP);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG3(ERROR,
|
||
"ElfrOpenBELW: SetUpDataStruct for file %ws (module %ws) failed %#x\n",
|
||
BackupFileName->Buffer,
|
||
BackupModuleName,
|
||
Status);
|
||
|
||
ElfpFreeBuffer(BackupModuleName);
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Call ElfOpenELW to actually open the log file and get a handle.
|
||
//
|
||
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
|
||
{
|
||
ELF_LOG3(ERROR,
|
||
"ElfrOpenBELW: ElfpOpenELW for file %ws (module %ws) failed %#x\n",
|
||
BackupFileName->Buffer,
|
||
BackupModuleName,
|
||
Status);
|
||
|
||
//
|
||
// If we couldn't open the log file, then we need to tear down
|
||
// the DataStruct we set up with SetUpDataStruct.
|
||
//
|
||
pModule = GetModuleStruc(&BackupStringW);
|
||
|
||
//
|
||
// We'd better be unlinking the same module we just created
|
||
//
|
||
ASSERT(_wcsicmp(pModule->ModuleName, BackupModuleName) == 0);
|
||
|
||
Status = ElfpCloseLogFile(pModule->LogFile, ELF_LOG_CLOSE_BACKUP);
|
||
|
||
UnlinkLogModule(pModule);
|
||
DeleteAtom(pModule->ModuleAtom);
|
||
|
||
//
|
||
// NB : DO NOT decrement the logfile reference count - this has
|
||
// been done in ElfpCloseLogFile.
|
||
//
|
||
if (pModule->LogFile->RefCount == 0)
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"ElfrOpenBELW: Reference count for %ws log is 0 -- destroying\n",
|
||
pModule->ModuleName);
|
||
|
||
UnlinkLogFile(pModule->LogFile); // Unlink the structure
|
||
RtlDeleteResource ( &pModule->LogFile->Resource );
|
||
RtlDeleteSecurityObject(&pModule->LogFile->Sd);
|
||
ElfpFreeBuffer (pModule->LogFile->LogFileName);
|
||
ElfpFreeBuffer (pModule->LogFile->LogModuleName);
|
||
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.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// All arguments checked in ElfpOpenELW.
|
||
//
|
||
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".
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// All arguments checked in ElfpOpenELW.
|
||
//
|
||
|
||
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;
|
||
PLOGMODULE Module;
|
||
IELF_HANDLE LogIHandle;
|
||
BOOL ForSecurityLog = FALSE;
|
||
|
||
//
|
||
// Check arguments.
|
||
//
|
||
|
||
Status = VerifyUnicodeString(ModuleName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfpOpenELW: ModuleName is not a Unicode string\n");
|
||
|
||
return Status;
|
||
}
|
||
|
||
if (LogHandle == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfpOpenELW: LogHandle is NULL\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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)
|
||
{
|
||
ELF_LOG0(TRACE,
|
||
"ElfpOpenELW: Opening Security log\n");
|
||
|
||
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);
|
||
|
||
RtlCopyMemory(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;
|
||
LogIHandle->dwNotifyRequests = 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
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"ElfpOpenELW: ElfpAccessCheckAndAudit failed %#x\n",
|
||
Status);
|
||
|
||
ElfpFreeBuffer(LogIHandle);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfpOpenELW: Unable to allocate LogIHandle\n");
|
||
|
||
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;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"w_ElfrReadEL: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Ensure the caller has read access.
|
||
//
|
||
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_READ))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"w_ElfrReadEL: LogHandle does not have read access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
|
||
if (Buffer == NULL || !NumberOfBytesRead || !MinNumberOfBytesNeeded)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"w_ElfrReadEL: %ws\n",
|
||
(Buffer == NULL ? L"Buffer is NULL" :
|
||
(!NumberOfBytesRead ? L"NumberOfBytesRead is 0" :
|
||
L"MinNumberOfBytesNeeded is 0")));
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"w_ElfrReadEL: Logfile changed under this handle -- invalid for read\n");
|
||
|
||
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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"w_ElfrReadEL: Handle is a backup handle\n");
|
||
|
||
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)
|
||
{
|
||
ELF_LOG1(TRACE,
|
||
"w_ElfrReadEL: Performing read on module %ws\n",
|
||
Module->ModuleName);
|
||
|
||
//
|
||
// 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
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"w_ElfrReadEL: No module associated with atom in LogHandle\n");
|
||
|
||
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.
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Call the worker with the UNICODE flag.
|
||
// All arguments checked in w_ElfrReadEL.
|
||
//
|
||
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 will be for Security Auditing to use for paired events.
|
||
//
|
||
UNREFERENCED_PARAMETER(RecordNumber);
|
||
UNREFERENCED_PARAMETER(TimeWritten);
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrReportEventW: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Insure the caller has write access.
|
||
//
|
||
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_WRITE))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrReportEventW: LogHandle does not have write access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
Status = VerifyUnicodeString(ComputerName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrReportEventW: ComputerName is not a valid Unicode string %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
if (Strings == NULL && NumStrings != 0)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrReportEventW: Strings is NULL and NumStrings is non-zero (%d)\n",
|
||
NumStrings);
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrReportEventW: Handle is a backup handle\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Make sure the SID passed in is valid
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(UserSid))
|
||
{
|
||
if (!IsValidSid(UserSid))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrReportEventW: UserSid is invalid\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Verify the string arguments
|
||
//
|
||
for (i = 0; i < NumStrings; i++ )
|
||
{
|
||
Status = VerifyUnicodeString(Strings[i]);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfrReportEventW: String %d is not a valid Unicode string %#x\n",
|
||
i,
|
||
Status);
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Can't write to a backup log
|
||
//
|
||
|
||
if (LogHandle->Flags & ELF_LOG_HANDLE_BACKUP_LOG)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrReportEventW: Handle is for a backup log\n");
|
||
|
||
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)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrReportEventW: Data is NULL and DataSize is non-zero (%d)\n",
|
||
DataSize);
|
||
|
||
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);
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfrReportEventW: Length of sid is %d\n",
|
||
UserSidLength);
|
||
}
|
||
|
||
//
|
||
// 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);
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfrReportEventW: Module name length (bytes) is %d\n",
|
||
ModuleNameLen);
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfrReportEventW: Computer name length (bytes) is %d\n",
|
||
UComputerName->Length + sizeof(WCHAR));
|
||
|
||
UserSidOffset = sizeof(EVENTLOGRECORD) + ModuleNameLen + ComputerNameLen;
|
||
UserSidOffset = ALIGN_UP_64(UserSidOffset, sizeof(PVOID));
|
||
|
||
//
|
||
// 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++)
|
||
{
|
||
ELF_LOG3(TRACE,
|
||
"ElfrReportEventW: Length (bytes) of string %d (%ws) is %d\n",
|
||
i,
|
||
Strings[i]->Buffer,
|
||
Strings[i]->Length + sizeof(WCHAR));
|
||
|
||
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
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfrReportEventW: RecordLength (no pad bytes) is %d\n",
|
||
RecordLength);
|
||
|
||
//
|
||
// Determine how many pad bytes are needed to align to a DWORD
|
||
// boundary.
|
||
//
|
||
|
||
PadSize = sizeof(ULONG) - (RecordLength % sizeof(ULONG));
|
||
|
||
RecordLength += PadSize; // True size needed
|
||
|
||
ELF_LOG2(TRACE,
|
||
"ElfrReportEventW: RecordLength (with %d pad bytes) is %d\n",
|
||
PadSize,
|
||
RecordLength);
|
||
|
||
//
|
||
// 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_PTR)EventLogRecord + (ULONG)StringOffset);
|
||
|
||
for (i = 0; i < NumStrings; i++)
|
||
{
|
||
SrcString = (PWSTR) Strings[i]->Buffer;
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfrReportEventW: Copying string %d into record\n",
|
||
i);
|
||
|
||
RtlCopyMemory(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);
|
||
|
||
RtlCopyMemory(BinaryData,
|
||
UModuleName,
|
||
ModuleNameLen);
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfrReportEventW: Copying module name (%ws) into record\n",
|
||
UModuleName);
|
||
|
||
//
|
||
// COMPUTERNAME
|
||
//
|
||
ReplaceStrings = (LPWSTR) (BinaryData + ModuleNameLen);
|
||
|
||
RtlCopyMemory(ReplaceStrings,
|
||
UComputerName->Buffer,
|
||
UComputerName->Length);
|
||
|
||
ReplaceStrings[UComputerName->Length / sizeof(WCHAR)] = L'\0';
|
||
|
||
ELF_LOG1(TRACE,
|
||
"ElfrReportEventW: Copying computer name (%ws) into record\n",
|
||
ReplaceStrings);
|
||
|
||
//
|
||
// USERSID
|
||
//
|
||
|
||
BinaryData = ((PBYTE) EventLogRecord) + UserSidOffset;
|
||
|
||
RtlCopyMemory(BinaryData,
|
||
UserSid,
|
||
UserSidLength);
|
||
|
||
//
|
||
// BINARY DATA
|
||
//
|
||
BinaryData = (PBYTE) ((ULONG_PTR)EventLogRecord + DataOffset);
|
||
|
||
if (Data)
|
||
{
|
||
RtlCopyMemory(BinaryData,
|
||
Data,
|
||
DataSize);
|
||
}
|
||
|
||
//
|
||
// PAD - Fill with zeros
|
||
//
|
||
BinaryData = (PBYTE) ((ULONG_PTR)BinaryData + DataSize);
|
||
|
||
RtlCopyMemory(BinaryData,
|
||
&zero,
|
||
PadSize);
|
||
|
||
//
|
||
// LENGTH at end of record
|
||
//
|
||
BinaryData = (PBYTE)((ULONG_PTR) BinaryData + PadSize); // Point after pad bytes
|
||
|
||
((PULONG) BinaryData)[0] = RecordLength;
|
||
|
||
//
|
||
// Make sure we are in the right place
|
||
//
|
||
ASSERT ((ULONG_PTR)BinaryData
|
||
== (RecordLength + (ULONG_PTR)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 );
|
||
|
||
//
|
||
// Replicate the event if part of a cluster
|
||
//
|
||
ElfpReplicateEvent(Module, EventBuffer, RecordLength);
|
||
|
||
//
|
||
// Free up the buffer
|
||
//
|
||
ElfpFreeBuffer(EventBuffer);
|
||
|
||
Status = Request.Status; // Set status of WRITE
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrReportEventW: Unable to allocate EventLogRecord\n");
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrReportEventW: No module associated with atom in LogHandle\n");
|
||
|
||
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;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrClearELFA: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Ensure the caller has clear access.
|
||
//
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_CLEAR))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrClearELFA: Handle doesn't have clear access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
|
||
Status = VerifyAnsiString((PANSI_STRING) BackupFileName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrClearELFA: BackupFileName is not a valid Ansi string %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// 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);
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfrClearELFA: Conversion of Ansi string %s to Unicode failed %#x\n",
|
||
BackupFileName->Buffer,
|
||
Status);
|
||
}
|
||
|
||
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;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrBackupELFA: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Ensure the caller has backup access.
|
||
//
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_BACKUP))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrBackupELFA: Handle does not have backup access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
Status = VerifyAnsiString((PANSI_STRING) BackupFileName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrBackupELFA: BackupFileName is not a valid Ansi string %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// 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);
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfrBackupELFA: Conversion of Ansi string %s to Unicode failed %#x\n",
|
||
BackupFileName->Buffer,
|
||
Status);
|
||
}
|
||
|
||
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;
|
||
|
||
//
|
||
// Check arguments.
|
||
//
|
||
// LogHandle check in ElfpOpenELA.
|
||
//
|
||
|
||
Status = VerifyAnsiString((PANSI_STRING) ModuleName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrRegisterEventSourceA: ModuleName is not a valid Ansi string %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
Status = RtlAnsiStringToUnicodeString((PUNICODE_STRING) &ModuleNameU,
|
||
(PANSI_STRING) ModuleName,
|
||
TRUE);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfrRegisterEventSourceA: Conversion of Ansi string %s "
|
||
"to Unicode failed %#x\n",
|
||
ModuleName->Buffer,
|
||
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".
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// All arguments checked in ElfpOpenELA.
|
||
//
|
||
|
||
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;
|
||
|
||
//
|
||
// Check arguments.
|
||
//
|
||
Status = VerifyAnsiString((PANSI_STRING) ModuleName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfpOpenELA: ModuleName is not a valid Ansi string %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
if (LogHandle == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfpOpenELA: LogHandle is NULL\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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);
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfpOpenELA: Conversion of Ansi string %s to Unicode failed %#x\n",
|
||
ModuleName->Buffer,
|
||
Status);
|
||
}
|
||
|
||
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;
|
||
|
||
//
|
||
// Check arguments.
|
||
//
|
||
|
||
Status = VerifyAnsiString((PANSI_STRING) FileName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrOpenBELA: FileName is not a valid Ansi string %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// A filename must be specified.
|
||
//
|
||
if (FileName->Length == 0)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOpenBELA: Filename length is 0\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if (LogHandle == NULL)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrOpenBELA: LogHandle is NULL\n");
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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);
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfrOpenBELA: Error converting Ansi string %s to Unicode %#x\n",
|
||
FileName->Buffer,
|
||
Status);
|
||
}
|
||
|
||
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.
|
||
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Call the worker with the ANSI flag.
|
||
// All arguments checked in w_ElfrReadEL.
|
||
//
|
||
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 PANSI_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])
|
||
{
|
||
Status = VerifyAnsiString(Strings[i]);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ConvertStringArrayToUnicode: String %d is not "
|
||
"a valid Ansi string %#x\n",
|
||
i,
|
||
Status);
|
||
|
||
break;
|
||
}
|
||
|
||
pUStringArray[i] = ElfpAllocateBuffer(sizeof(UNICODE_STRING));
|
||
|
||
if (pUStringArray[i])
|
||
{
|
||
Status = RtlAnsiStringToUnicodeString(pUStringArray[i],
|
||
(PANSI_STRING) Strings[i],
|
||
TRUE);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ConvertStringArrayToUnicode: Conversion of Ansi string "
|
||
"%s to Unicode failed %#x\n",
|
||
Strings[i]->Buffer,
|
||
Status);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ConvertStringArrayToUnicode: Unable to allocate memory for "
|
||
"Unicode string %d (Ansi string %s)\n",
|
||
i,
|
||
Strings[i]->Buffer);
|
||
|
||
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))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ConvertStringArrayToUnicode: Function failed %#x\n",
|
||
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)
|
||
{
|
||
//
|
||
// Free the string buffer
|
||
//
|
||
RtlFreeUnicodeString(pUStringArray[i]);
|
||
}
|
||
|
||
//
|
||
// Free the UNICODE_STRING itself -- this may be allocated
|
||
// even if the string buffer isn't (if RtlAnsiStringToUnicodeString
|
||
// failed in the ConvertStringArrayToUnicode call)
|
||
//
|
||
ElfpFreeBuffer(pUStringArray[i]);
|
||
pUStringArray[i] = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
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 = NULL;
|
||
|
||
//
|
||
// Check the handle before proceeding.
|
||
//
|
||
Status = VerifyElfHandle(LogHandle);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrReportEventA: VerifyElfHandle failed %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Ensure the caller has write access.
|
||
//
|
||
if (!(LogHandle->GrantedAccess & ELF_LOGFILE_WRITE))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrReportEventA: Handle doesn't have write access\n");
|
||
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// Verify additional arguments.
|
||
//
|
||
Status = VerifyAnsiString((PANSI_STRING) ComputerName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrReportEventA: ComputerName is not a valid Ansi string %#x\n",
|
||
Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
if (Strings == NULL && NumStrings != 0)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrReportEventA: Strings is NULL and NumStrings is non-zero (%d)\n",
|
||
NumStrings);
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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));
|
||
|
||
if (pUStringArray)
|
||
{
|
||
//
|
||
// 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
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrReportEventA: Unable to allocate pUStringArray\n");
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfrReportEventA: Conversion of Ansi string %s to Unicode failed %#X\n",
|
||
ComputerName->Buffer,
|
||
Status);
|
||
}
|
||
|
||
ElfpFreeBuffer(pUStringArray);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
VerifyElfHandle(
|
||
IN IELF_HANDLE LogHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Verify the handle via its DWORD signature.
|
||
|
||
Arguments:
|
||
|
||
LogHandle - Handle to verify.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Presumably valid handle.
|
||
STATUS_INVALID_HANDLE - Invalid handle.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
if (LogHandle != NULL)
|
||
{
|
||
try
|
||
{
|
||
if (LogHandle->Signature == ELF_CONTEXTHANDLE_SIGN)
|
||
{
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"VerifyElfHandle: Incorrect LogHandle signature %#x "
|
||
"(should be %#x)\n",
|
||
LogHandle->Signature,
|
||
ELF_CONTEXTHANDLE_SIGN);
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
}
|
||
except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"VerifyElfHandle: Exception %#x caught while probing LogHandle\n",
|
||
GetExceptionCode());
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"VerifyElfHandle: LogHandle is NULL\n");
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
ULONG
|
||
Safewcslen(
|
||
UNALIGNED WCHAR *p,
|
||
LONG MaxLength
|
||
)
|
||
/*++
|
||
|
||
Safewcslen - Strlen that won't exceed MaxLength
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to determine the size of a UNICODE_STRING
|
||
|
||
Arguments:
|
||
p - The string to count.
|
||
MaxLength - The maximum length to look at.
|
||
|
||
|
||
Return Value:
|
||
|
||
Number of bytes in the string (or MaxLength)
|
||
|
||
--*/
|
||
{
|
||
ULONG Count = 0;
|
||
|
||
if (p)
|
||
{
|
||
while (MaxLength > 0 && *p++ != UNICODE_NULL)
|
||
{
|
||
MaxLength -= sizeof(WCHAR);
|
||
Count += sizeof(WCHAR);
|
||
}
|
||
}
|
||
|
||
return Count;
|
||
}
|
||
|
||
|
||
ULONG
|
||
Safestrlen(
|
||
UNALIGNED char *p,
|
||
LONG MaxLength
|
||
)
|
||
/*++
|
||
|
||
Safestrlen - Strlen that won't exceed MaxLength
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to determine the length of an ANSI_STRING
|
||
|
||
Arguments:
|
||
p - The string to count.
|
||
MaxLength - The maximum length to look at.
|
||
|
||
|
||
Return Value:
|
||
|
||
Number of chars in the string (or MaxLength)
|
||
|
||
--*/
|
||
{
|
||
ULONG Count = 0;
|
||
|
||
if (p)
|
||
{
|
||
while (MaxLength > 0 && *p++ != '\0')
|
||
{
|
||
MaxLength--;
|
||
Count++;
|
||
}
|
||
}
|
||
|
||
return Count;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
VerifyUnicodeString(
|
||
IN PUNICODE_STRING pUString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Verify the unicode string. The string is invalid if:
|
||
The UNICODE_STRING structure ptr is NULL.
|
||
The MaximumLength field is invalid (too small).
|
||
The Length field is incorrect.
|
||
|
||
Arguments:
|
||
|
||
pUString - String to verify.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Valid string.
|
||
STATUS_INVALID_PARAMETER - I wonder.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Check validity of structure fields and actual string
|
||
// length vs. length value supplied
|
||
//
|
||
if (!pUString ||
|
||
pUString->MaximumLength < pUString->Length ||
|
||
pUString->Length != Safewcslen(pUString->Buffer,
|
||
pUString->MaximumLength))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"VerifyUnicodeString: String is invalid because %ws\n",
|
||
(!pUString ?
|
||
L"it's NULL" :
|
||
(pUString->MaximumLength < pUString->Length ? L"MaximumLength < Length" :
|
||
L"Length is incorrect")));
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
VerifyAnsiString(
|
||
IN PANSI_STRING pAString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Verify the ansi string. The string is invalid if:
|
||
The ANSI_STRING structure ptr is NULL.
|
||
The MaximumLength field is invalid (too small).
|
||
The Length field is incorrect.
|
||
|
||
Arguments:
|
||
|
||
pAString - String to verify.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Valid string.
|
||
STATUS_INVALID_PARAMETER - I wonder.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
if (!pAString ||
|
||
pAString->MaximumLength < pAString->Length ||
|
||
pAString->Length != Safestrlen(pAString->Buffer,
|
||
pAString->MaximumLength))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"VerifyAnsiString: String is invalid because %ws\n",
|
||
(!pAString ?
|
||
L"it's NULL" :
|
||
(pAString->MaximumLength < pAString->Length ? L"MaximumLength < Length" :
|
||
L"Length is incorrect")));
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
//SS:changes made to enable cluster wide event logging
|
||
/****
|
||
@func NTSTATUS | ElfrRegisterClusterSvc| This is the server entrypoint
|
||
for ElfRegisterClusterSvc. The cluster service registers
|
||
itself with the event log service to enable propagation of events
|
||
across the cluster. The binding handle to the cluster service for
|
||
propagation of events is obtained.
|
||
|
||
@parm IN EVENTLOG_HANDLE_W | UNCServerName | This parameter is ignored. It
|
||
is retained for correspondence with other elf apis.
|
||
|
||
@parm OUT PULONG | pulSize | A pointer to a long where the size of the
|
||
packed event information structure is returned.
|
||
|
||
@parm OUT PBYTE | *ppPackedEventInfo| A pointer to the packed event information
|
||
structure for propagation is returned via this parameter.
|
||
|
||
@comm The cluster service propagates events contained in this structure
|
||
and deletes the memory after it has done so. Once the cluster service has
|
||
registered with the eventlog service, the eventlog service passes up
|
||
logged events to the cluster service for propagation.
|
||
|
||
@rdesc Returns a result code. ERROR_SUCCESS on success.
|
||
|
||
@xref <f ElfRegisterClusterSvc> <f ElfrDeregisterClusterSvc>
|
||
****/
|
||
NTSTATUS
|
||
ElfrRegisterClusterSvc(
|
||
IN EVENTLOG_HANDLE_W UNCServerName,
|
||
OUT PULONG pulSize,
|
||
OUT PBYTE *ppPackedEventInfo)
|
||
{
|
||
ULONG ulTotalSize = 0;
|
||
ULONG ulTotalEventsSize = 0;
|
||
ULONG ulNumLogFiles = 0;
|
||
PPROPLOGFILEINFO pPropLogFileInfo = NULL;
|
||
NTSTATUS Status;
|
||
PPACKEDEVENTINFO pPackedEventInfo = NULL;
|
||
UINT i;
|
||
PEVENTSFORLOGFILE pEventsForLogFile;
|
||
WCHAR *pBinding = NULL;
|
||
HANDLE hClusSvcNode = NULL;
|
||
UNICODE_STRING RootRegistryNode;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
BOOL bAcquired = FALSE;
|
||
BOOL bInitedCritSec = FALSE;
|
||
|
||
ELF_LOG0(CLUSTER,
|
||
"ElfRegisterClusterSvc: Entry\n");
|
||
|
||
//
|
||
// Initialize the OUT parameters
|
||
//
|
||
*pulSize = 0;
|
||
*ppPackedEventInfo = NULL;
|
||
|
||
//
|
||
// Check to see if the cluster service is installed.
|
||
//
|
||
RtlInitUnicodeString(&RootRegistryNode, REG_CLUSSVC_NODE_PATH);
|
||
InitializeObjectAttributes(&ObjectAttributes,
|
||
&RootRegistryNode,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
Status = NtOpenKey(&hClusSvcNode, KEY_READ | KEY_NOTIFY, &ObjectAttributes);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfRegisterClusterSvc: NtOpenKey of %ws failed %#x\n",
|
||
REG_CLUSSVC_NODE_PATH,
|
||
Status);
|
||
|
||
goto FnExit;
|
||
}
|
||
|
||
NtClose(hClusSvcNode);
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// If the cluster service dies and restarts again in the same session
|
||
// then it will try to register again.
|
||
// We dont reinitialize these globals again to prevent leaks
|
||
//
|
||
RtlEnterCriticalSection(&gClPropCritSec);
|
||
|
||
if (!gbClustering)
|
||
{
|
||
ELF_LOG0(CLUSTER,
|
||
"ElfRegisterClusterSvc: gbClustering is FALSE\n");
|
||
|
||
//
|
||
// Load the cluster support dll
|
||
//
|
||
ghClusDll = LoadLibraryW(L"CLUSSPRT.DLL");
|
||
|
||
if (!ghClusDll)
|
||
{
|
||
RtlLeaveCriticalSection(&gClPropCritSec);
|
||
Status = STATUS_DLL_NOT_FOUND;
|
||
goto FnExit;
|
||
}
|
||
}
|
||
//
|
||
// Get the function entry points
|
||
//
|
||
gpfnPropagateEvents = (PROPAGATEEVENTSPROC) GetProcAddress(ghClusDll,
|
||
"PropagateEvents");
|
||
|
||
gpfnBindToCluster = (BINDTOCLUSTERPROC) GetProcAddress(ghClusDll,
|
||
"BindToClusterSvc");
|
||
|
||
gpfnUnbindFromCluster = (UNBINDFROMCLUSTERPROC) GetProcAddress(ghClusDll,
|
||
"UnbindFromClusterSvc");
|
||
|
||
|
||
if (!gpfnPropagateEvents || !gpfnBindToCluster || !gpfnUnbindFromCluster)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfRegisterClusterSvc: GetProcAddress for %ws in clussprt.dll failed\n",
|
||
(!gpfnPropagateEvents ? L"PropagateEvents" :
|
||
(!gpfnBindToCluster ? L"BindToClusterSvc" :
|
||
L"UnbindFromClusterSvc")));
|
||
|
||
RtlLeaveCriticalSection(&gClPropCritSec);
|
||
Status = STATUS_PROCEDURE_NOT_FOUND;
|
||
goto FnExit;
|
||
}
|
||
|
||
//
|
||
// If we had bound to the cluster service previously, unbind and then rebind
|
||
//
|
||
if (ghCluster)
|
||
{
|
||
(*gpfnUnbindFromCluster)(ghCluster);
|
||
}
|
||
//
|
||
// Bind to the cluster service
|
||
//
|
||
ghCluster = (*gpfnBindToCluster)(NULL);
|
||
|
||
if (!ghCluster)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfRegisterClusterSvc: BindToCluster failed %d\n",
|
||
GetLastError());
|
||
|
||
RtlLeaveCriticalSection(&gClPropCritSec);
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
goto FnExit;
|
||
}
|
||
|
||
RtlLeaveCriticalSection(&gClPropCritSec);
|
||
|
||
//
|
||
// Since we are going to read the logs, make sure the service is running
|
||
//
|
||
while((GetElState() == RUNNING) && (!bAcquired))
|
||
{
|
||
|
||
bAcquired = RtlAcquireResourceShared(&GlobalElfResource,
|
||
FALSE); // Don't wait
|
||
|
||
if (!bAcquired)
|
||
{
|
||
ELF_LOG0(CLUSTER,
|
||
"ElfRegisterClusterSvc: Sleep waiting for global resource\n");
|
||
|
||
Sleep(ELF_GLOBAL_RESOURCE_WAIT);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the resource was not available and the status of the service
|
||
// changed to one of the "non-working" states, then we just return
|
||
// unsuccesful. Rpc should not allow this to happen.
|
||
//
|
||
if (!bAcquired)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfRegisterClusterSvc: Global resource not acquired\n");
|
||
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
goto FnExit;
|
||
}
|
||
|
||
//
|
||
// Determine the size of and acquire read locks on all files.
|
||
// FindSizeofEventsSinceStart acquires the per-log locks if
|
||
// there are events in that log to propagate.
|
||
//
|
||
Status = FindSizeofEventsSinceStart(&ulTotalEventsSize,
|
||
&ulNumLogFiles,
|
||
&pPropLogFileInfo);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfRegisterClusterSvc: FindSizeofEventsSinceStart failed %#x\n",
|
||
Status);
|
||
|
||
goto FnExit;
|
||
}
|
||
|
||
//
|
||
// If there are any events to propagate
|
||
//
|
||
if (ulNumLogFiles && ulTotalEventsSize && pPropLogFileInfo)
|
||
{
|
||
ulTotalSize = sizeof(PACKEDEVENTINFO) // header
|
||
+ (sizeof(ULONG) * ulNumLogFiles) // offsets
|
||
+ (sizeof(EVENTSFORLOGFILE) * ulNumLogFiles) // info per log
|
||
+ ulTotalEventsSize;
|
||
|
||
//
|
||
// Allocate memory
|
||
//
|
||
*ppPackedEventInfo = (PBYTE) ElfpAllocateBuffer(ulTotalSize);
|
||
|
||
if (!(*ppPackedEventInfo))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfRegisterClusterSvc: Unable to allocate %d bytes for pPackedEventInfo\n",
|
||
ulTotalSize);
|
||
|
||
//
|
||
// Free the read locks acquired in FindSizeofEventsSinceStart
|
||
//
|
||
for (i=0;i<ulNumLogFiles;i++)
|
||
{
|
||
RtlReleaseResource(&(pPropLogFileInfo[i].pLogFile->Resource));
|
||
}
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
goto FnExit;
|
||
}
|
||
|
||
pPackedEventInfo = (PPACKEDEVENTINFO)(*ppPackedEventInfo);
|
||
|
||
ELF_LOG2(CLUSTER,
|
||
"ElfRegisterClusterSvc: Allocated %d bytes, pPackedEventInfo is %#x\n",
|
||
ulTotalSize,
|
||
pPackedEventInfo);
|
||
|
||
pPackedEventInfo->ulNumEventsForLogFile = ulNumLogFiles;
|
||
|
||
for (i = 0;i < ulNumLogFiles; i++)
|
||
{
|
||
//
|
||
// Set the offsets to the EVENTSFORLOGFILE structures
|
||
//
|
||
pPackedEventInfo->ulOffsets[i] =
|
||
((i == 0) ? (sizeof(PACKEDEVENTINFO) + ulNumLogFiles * sizeof(ULONG)) :
|
||
(pPackedEventInfo->ulOffsets[i - 1]
|
||
+ (pPropLogFileInfo[i - 1].ulTotalEventSize
|
||
+ sizeof(EVENTSFORLOGFILE))));
|
||
|
||
ELF_LOG2(CLUSTER,
|
||
"ElfRegisterClusterSvc: pPackedEventInfo->ulOffsets[%d] = %d\n",
|
||
i,
|
||
pPackedEventInfo->ulOffsets[i]);
|
||
|
||
pEventsForLogFile = (PEVENTSFORLOGFILE) ((PBYTE) pPackedEventInfo
|
||
+ pPackedEventInfo->ulOffsets[i]);
|
||
|
||
//
|
||
// Set the size of the ith EVENTSFORLOGFILE structure
|
||
//
|
||
pEventsForLogFile->ulSize = sizeof(EVENTSFORLOGFILE)
|
||
+ pPropLogFileInfo[i].ulTotalEventSize;
|
||
|
||
//
|
||
// Copy the file name (or should we get the module name?)
|
||
//
|
||
lstrcpyW(pEventsForLogFile->szLogicalLogFile,
|
||
pPropLogFileInfo[i].pLogFile->LogModuleName->Buffer);
|
||
|
||
//
|
||
// Set the number of events
|
||
//
|
||
pEventsForLogFile->ulNumRecords = pPropLogFileInfo[i].ulNumRecords;
|
||
|
||
ELF_LOG3(CLUSTER,
|
||
"ElfRegisterClusterSvc: pEventsForLogFile struct -- ulSize = %d, "
|
||
"Logical file = %ws, ulNumRecords = %d\n",
|
||
pEventsForLogFile->ulSize,
|
||
pEventsForLogFile->szLogicalLogFile,
|
||
pEventsForLogFile->ulNumRecords);
|
||
|
||
//
|
||
// Get the events
|
||
//
|
||
Status = GetEventsToProp((PEVENTLOGRECORD) ((PBYTE) pEventsForLogFile
|
||
+ sizeof(EVENTSFORLOGFILE)),
|
||
pPropLogFileInfo + i);
|
||
|
||
//
|
||
// If that fails, set the ulNumRecords to 0 so tha
|
||
// on a write this data is discarded.
|
||
//
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfRegisterClusterSvc: GetEventsToProp for %ws log failed %#x\n",
|
||
pPropLogFileInfo[i].pLogFile->LogModuleName->Buffer,
|
||
Status);
|
||
|
||
pEventsForLogFile->ulNumRecords=0;
|
||
|
||
//
|
||
// Reset the error -- we will go to the next file
|
||
//
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Advance the startpointer for all the files so if the cluster service
|
||
// dies and is restarted, these events won't be propagated again
|
||
//
|
||
pPropLogFileInfo[i].pLogFile->SessionStartRecordNumber =
|
||
pPropLogFileInfo[i].pLogFile->CurrentRecordNumber;
|
||
|
||
ELF_LOG1(CLUSTER,
|
||
"ElfRegisterClusterSvc: Done processing %ws log\n",
|
||
pPropLogFileInfo[i].pLogFile->LogModuleName->Buffer);
|
||
|
||
RtlReleaseResource (&(pPropLogFileInfo[i].pLogFile->Resource));
|
||
}
|
||
|
||
//
|
||
// Set the total size
|
||
//
|
||
pPackedEventInfo->ulSize = pPackedEventInfo->ulOffsets[ulNumLogFiles - 1]
|
||
+ pPropLogFileInfo[ulNumLogFiles - 1].ulTotalEventSize
|
||
+ sizeof(EVENTSFORLOGFILE);
|
||
|
||
*pulSize = pPackedEventInfo->ulSize;
|
||
}
|
||
|
||
RtlEnterCriticalSection (&gClPropCritSec);
|
||
|
||
//
|
||
// If the cluster service hadnt registered before or glClPackedEventInfo is NULL
|
||
//
|
||
if (!gbClustering || !gpClPackedEventInfo)
|
||
{
|
||
//
|
||
// Allocate memory for processing events for propagation
|
||
//
|
||
ulTotalSize = sizeof(PACKEDEVENTINFO) // header
|
||
+ (sizeof(ULONG) * 1) // offsets
|
||
+ (sizeof(EVENTSFORLOGFILE) * 1) // per-log info
|
||
+ MAXSIZE_OF_EVENTSTOPROP;
|
||
|
||
//
|
||
// Allocate memory
|
||
//
|
||
gpClPackedEventInfo = (PPACKEDEVENTINFO) ElfpAllocateBuffer(ulTotalSize);
|
||
|
||
if (!gpClPackedEventInfo)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfRegisterClusterSvc: Unable to allocate %d bytes "
|
||
"for gpClPackedEventInfo\n",
|
||
ulTotalSize);
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
RtlLeaveCriticalSection (&gClPropCritSec);
|
||
goto FnExit;
|
||
}
|
||
|
||
//
|
||
// Setup the PACKEDEVENTINFO
|
||
//
|
||
gpClPackedEventInfo->ulNumEventsForLogFile = 1;
|
||
gpClPackedEventInfo->ulOffsets[0]= sizeof(PACKEDEVENTINFO) + sizeof(ULONG);
|
||
}
|
||
|
||
//
|
||
// Set the flag to true so that propagation is now on.
|
||
//
|
||
gbClustering = TRUE;
|
||
RtlLeaveCriticalSection (&gClPropCritSec);
|
||
|
||
FnExit:
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// Something went wrong
|
||
//
|
||
ELF_LOG1(ERROR,
|
||
"ElfRegisterClusterSvc: Exiting with error %#x\n",
|
||
Status);
|
||
|
||
RtlEnterCriticalSection(&gClPropCritSec);
|
||
|
||
ElfpFreeBuffer(gpClPackedEventInfo);
|
||
gpClPackedEventInfo = NULL;
|
||
|
||
if (ghCluster && gpfnUnbindFromCluster)
|
||
{
|
||
(*gpfnUnbindFromCluster)(ghCluster);
|
||
ghCluster = NULL;
|
||
}
|
||
|
||
if (ghClusDll)
|
||
{
|
||
FreeLibrary(ghClusDll);
|
||
ghClusDll = NULL;
|
||
}
|
||
|
||
RtlLeaveCriticalSection(&gClPropCritSec);
|
||
}
|
||
|
||
//
|
||
// Free the pPropLogFileInfo stucture
|
||
//
|
||
ElfpFreeBuffer(pPropLogFileInfo);
|
||
|
||
if (bAcquired)
|
||
{
|
||
ReleaseGlobalResource();
|
||
}
|
||
|
||
ELF_LOG1(CLUSTER,
|
||
"ElfRegisterClusterSvc: Returning status %#x\n",
|
||
Status);
|
||
|
||
ELF_LOG2(CLUSTER,
|
||
"ElfRegisterClusterSvc: *pulSize = %d, *ppPackedEventInfo = %#x\n",
|
||
*pulSize,
|
||
*ppPackedEventInfo);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
/****
|
||
@func NTSTATUS | ElfrDeregisterClusterSvc| This is the server entry point
|
||
for ElfDeregisterClusterSvc(). Before shutdown the cluster
|
||
service deregisters itself for propagation of events from the
|
||
eventlog service.
|
||
|
||
@comm Note that events logged after the cluster service goes down
|
||
are not propagated. Binding handle is freed.
|
||
|
||
@rdesc Returns a result code. ERROR_SUCCESS on success.
|
||
|
||
@xref <f ElfrRegisterClusterSvc>
|
||
****/
|
||
NTSTATUS
|
||
ElfrDeregisterClusterSvc(
|
||
IN EVENTLOG_HANDLE_W UNCServerName
|
||
)
|
||
{
|
||
ELF_LOG0(CLUSTER,
|
||
"ElfDeregisterClusterSvc: ElfrDeregisterClusterSvc: Entry\n");
|
||
|
||
RtlEnterCriticalSection (&gClPropCritSec);
|
||
|
||
if (gbClustering)
|
||
{
|
||
gbClustering = FALSE;
|
||
|
||
ElfpFreeBuffer(gpClPackedEventInfo);
|
||
gpClPackedEventInfo = NULL;
|
||
|
||
//
|
||
// Unload the cluster support dll
|
||
//
|
||
if (ghCluster && gpfnUnbindFromCluster)
|
||
{
|
||
(*gpfnUnbindFromCluster)(ghCluster);
|
||
ghCluster = NULL;
|
||
}
|
||
|
||
if (ghClusDll)
|
||
{
|
||
FreeLibrary(ghClusDll);
|
||
ghClusDll = NULL;
|
||
}
|
||
}
|
||
|
||
RtlLeaveCriticalSection (&gClPropCritSec);
|
||
|
||
ELF_LOG0(CLUSTER,
|
||
"ElfDeregisterClusterSvc: Exit\n");
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
/****
|
||
@func NTSTATUS | ElfrWriteClusterEvents| The cluster service calls this
|
||
api to log events reported at other nodes of the cluster in the event log files.
|
||
|
||
@parm IN EVENTLOG_HANDLE_W | UNCServerName | Not used.
|
||
|
||
@parm IN ULONG | ulSize | The size of the packed event information structure.
|
||
|
||
@parm IN PBYTE | pPackedEventInfo| A pointer to the packed event information
|
||
structure for propagation.
|
||
|
||
@comm The pPackedEventInfo is delinearized into eventlogbuffers for different event
|
||
log files and the events are recorded in the appropriate eventlog file. Multiple
|
||
events per log file are supported.
|
||
|
||
@rdesc Returns a result code. ERROR_SUCCESS on success.
|
||
|
||
@xref
|
||
****/
|
||
NTSTATUS
|
||
ElfrWriteClusterEvents(
|
||
IN EVENTLOG_HANDLE_W UNCServerName,
|
||
IN ULONG ulSize,
|
||
IN BYTE *pBuffer
|
||
)
|
||
{
|
||
UINT i,j;
|
||
PEVENTSFORLOGFILE pEventsForLogFile;
|
||
UNICODE_STRING ModuleName;
|
||
PLOGMODULE pLogModule;
|
||
PEVENTLOGRECORD pEventLogRecord;
|
||
ELF_REQUEST_RECORD Request;
|
||
PPACKEDEVENTINFO pPackedEventInfo;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
WRITE_PKT WritePkt;
|
||
HANDLE hClientToken = NULL;
|
||
BOOL bCheckMember;
|
||
|
||
//
|
||
// Impersonate to figure if the caller is in the admin group.
|
||
// The cluster service must run in an account that has local
|
||
// Admin privileges
|
||
//
|
||
Status = I_RpcMapWin32Status(RpcImpersonateClient(NULL));
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrWriteClusterEvents: RpcImpersonateClient failed %#x\n",
|
||
Status);
|
||
|
||
goto FnExit;
|
||
}
|
||
|
||
|
||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hClientToken))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrWriteClusterEvents: OpenThreadToken failed %d\n",
|
||
GetLastError());
|
||
|
||
RpcRevertToSelf();
|
||
Status = STATUS_ACCESS_DENIED;
|
||
goto FnExit;
|
||
}
|
||
|
||
if (!CheckTokenMembership(hClientToken,
|
||
ElfGlobalData->AliasAdminsSid,
|
||
&bCheckMember))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrWriteClusterEvents: CheckTokenMembership failed %d\n",
|
||
GetLastError());
|
||
|
||
RpcRevertToSelf();
|
||
Status = STATUS_ACCESS_DENIED;
|
||
goto FnExit;
|
||
}
|
||
|
||
if (!bCheckMember)
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrWriteClusterEvents: Caller is not an Admin\n");
|
||
|
||
Status = STATUS_ACCESS_DENIED;
|
||
RpcRevertToSelf();
|
||
goto FnExit;
|
||
}
|
||
|
||
//
|
||
// Stop impersonating
|
||
//
|
||
Status = I_RpcMapWin32Status(RpcRevertToSelf());
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrWriteClusterEvents: RpcRevertToSelf failed %#x\n",
|
||
Status);
|
||
|
||
goto FnExit;
|
||
}
|
||
|
||
//
|
||
// We want to put this in a try/except block because we're
|
||
// probing potentially bad user-supplied data.
|
||
//
|
||
try
|
||
{
|
||
pPackedEventInfo = (PPACKEDEVENTINFO)pBuffer;
|
||
|
||
|
||
//
|
||
// Validate input parameters and check that clustering is on
|
||
//
|
||
if (!pPackedEventInfo
|
||
||
|
||
!ulSize
|
||
||
|
||
(((PBYTE)pPackedEventInfo + sizeof(PACKEDEVENTINFO)) > (PBYTE)(pBuffer + ulSize))
|
||
||
|
||
((PBYTE)pPackedEventInfo + ulSize <= pBuffer) //if ulSize is large to cause overflow
|
||
||
|
||
(pPackedEventInfo->ulSize != ulSize)
|
||
||
|
||
(!gbClustering))
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrWriteClusterEvents: Invalid parameter passed in -- %ws\n",
|
||
(!pPackedEventInfo ?
|
||
L"pPackedEventInfo is NULL" :
|
||
(!ulSize ?
|
||
L"ulSize is 0" :
|
||
(!gbClustering ?
|
||
L"gbClustering is FALSE" :
|
||
(pPackedEventInfo->ulSize != ulSize ?
|
||
L"ulSize mismatch" :
|
||
L"pBuffer too small or ulSize too large")))));
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto FnExit;
|
||
}
|
||
|
||
ELF_LOG2(CLUSTER,
|
||
"ElfrWriteClusterEvents: ulSize = %d, ulNumEventsForLogFile = %d\n",
|
||
ulSize,
|
||
pPackedEventInfo->ulNumEventsForLogFile);
|
||
|
||
|
||
if ((((PBYTE)pPackedEventInfo + sizeof(PACKEDEVENTINFO) +
|
||
(sizeof(DWORD) * (pPackedEventInfo->ulNumEventsForLogFile))) <
|
||
(PBYTE)(pBuffer)) ||
|
||
(((PBYTE)pPackedEventInfo + sizeof(PACKEDEVENTINFO) +
|
||
(sizeof(DWORD) * (pPackedEventInfo->ulNumEventsForLogFile))) <
|
||
(PBYTE)(pBuffer + sizeof(PACKEDEVENTINFO))))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrWriteClusterEvents: Buffer/values passed in caused overflow\n");
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto FnExit;
|
||
}
|
||
|
||
//check to see whether we have valid offsets for each eventlog file in the buffer
|
||
//first check to see the buffer passed in is big enough to contain the offsets
|
||
if (((PBYTE)pPackedEventInfo + sizeof(PACKEDEVENTINFO) +
|
||
(sizeof(DWORD) * (pPackedEventInfo->ulNumEventsForLogFile))) >
|
||
(PBYTE)(pBuffer + ulSize))
|
||
{
|
||
ELF_LOG0(ERROR,
|
||
"ElfrWriteClusterEvents: Buffer passed in doesnt contain offsets for all the eventlogfiles\n");
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto FnExit;
|
||
}
|
||
//
|
||
// Setup the request packet
|
||
//
|
||
Request.Pkt.WritePkt = &WritePkt; // Set up write packet in request packet
|
||
Request.Flags = 0;
|
||
|
||
//
|
||
// For each log
|
||
//
|
||
for (i = 0; i < pPackedEventInfo->ulNumEventsForLogFile; i++)
|
||
{
|
||
pEventsForLogFile = (PEVENTSFORLOGFILE) ((PBYTE)pPackedEventInfo +
|
||
pPackedEventInfo->ulOffsets[i]);
|
||
|
||
//
|
||
// Check for overflow or pointer past end of buffer
|
||
//
|
||
if (((PBYTE) pEventsForLogFile < pBuffer)
|
||
||
|
||
(((PBYTE) pEventsForLogFile + sizeof(EVENTSFORLOGFILE)) >
|
||
(PBYTE) (pBuffer + ulSize)))
|
||
{
|
||
ELF_LOG2(ERROR,
|
||
"ElfrWriteClusterEvents: Bad offset for log %d -- %ws\n",
|
||
i,
|
||
((PBYTE) pEventsForLogFile < pBuffer ? L"offset caused overflow" :
|
||
L"offset past end of buffer"));
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto FnExit;
|
||
}
|
||
|
||
ELF_LOG2(CLUSTER,
|
||
"ElfrWriteClusterEvents: szLogicalFile = %ws, ulNumRecords = %d\n",
|
||
pEventsForLogFile->szLogicalLogFile,
|
||
pEventsForLogFile->ulNumRecords);
|
||
|
||
//
|
||
// Find the module -- since we dont trust this string, force null termination
|
||
//
|
||
pEventsForLogFile->szLogicalLogFile[MAXLOGICALLOGNAMESIZE - 1] = L'\0';
|
||
|
||
RtlInitUnicodeString(&ModuleName, pEventsForLogFile->szLogicalLogFile);
|
||
pLogModule = GetModuleStruc(&ModuleName);
|
||
|
||
if (!pLogModule)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrWriteClusterEvents: Bogus ModuleName %ws passed in\n",
|
||
pEventsForLogFile->szLogicalLogFile);
|
||
//skip this log file and go to the next one
|
||
continue;
|
||
}
|
||
|
||
|
||
//
|
||
// GetModuleStruc always returns something non-NULL -- if the
|
||
// given module name is bogus, we'll use the Application log.
|
||
//
|
||
ELF_LOG2(CLUSTER,
|
||
"ElfrWriteClusterEvents: Processing records for %ws module (%ws log)\n",
|
||
pLogModule->ModuleName,
|
||
pLogModule->LogFile->LogModuleName->Buffer);
|
||
|
||
Request.Module = pLogModule;
|
||
Request.LogFile = Request.Module->LogFile;
|
||
Request.Command = ELF_COMMAND_WRITE;
|
||
pEventLogRecord = (PEVENTLOGRECORD) (pEventsForLogFile->pEventLogRecords);
|
||
|
||
for (j = 0;
|
||
j < pEventsForLogFile->ulNumRecords &&
|
||
pEventLogRecord->Reserved == ELF_LOG_FILE_SIGNATURE;
|
||
j++)
|
||
{
|
||
//
|
||
// Check for pointer past end of buffer
|
||
//
|
||
if (((PBYTE) pEventLogRecord + pEventLogRecord->Length) >
|
||
(PBYTE) (pBuffer + ulSize))
|
||
{
|
||
ELF_LOG3(ERROR,
|
||
"ElfrWriteClusterEvents: Record %d for %ws module "
|
||
"(%ws log) too long\n",
|
||
j,
|
||
pLogModule->ModuleName,
|
||
pLogModule->LogFile->LogModuleName->Buffer);
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto FnExit;
|
||
}
|
||
|
||
//
|
||
// Fill in a request packet for the current record
|
||
//
|
||
Request.Pkt.WritePkt->Buffer = pEventLogRecord;
|
||
Request.Pkt.WritePkt->Datasize = pEventLogRecord->Length;
|
||
|
||
//
|
||
// SS: Should we get exclusive access to the log so that
|
||
// the current record number is not incremented
|
||
// for an event that needs to be propagated
|
||
// before the session start record number is set here?
|
||
//
|
||
ElfPerformRequest(&Request);
|
||
|
||
//
|
||
// Advance the session start record number, so that
|
||
// we don't propagate an event propagated to us
|
||
//
|
||
pLogModule->LogFile->SessionStartRecordNumber =
|
||
pLogModule->LogFile->CurrentRecordNumber;
|
||
|
||
//
|
||
// Extract status of operation from the request packet
|
||
//
|
||
Status = Request.Status;
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ELF_LOG3(ERROR,
|
||
"ElfrWriteClusterEvents: Failed to write record %d to "
|
||
"%ws log %#x\n",
|
||
j,
|
||
pLogModule->LogFile->LogModuleName->Buffer,
|
||
Status);
|
||
}
|
||
|
||
pEventLogRecord = (PEVENTLOGRECORD) ((PBYTE) pEventLogRecord +
|
||
pEventLogRecord->Length);
|
||
}
|
||
}
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
ELF_LOG1(ERROR,
|
||
"ElfrWriteClusterEvents: Exception %#x caught probing passed-in buffer\n",
|
||
GetExceptionCode());
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
FnExit:
|
||
|
||
if (hClientToken)
|
||
{
|
||
CloseHandle(hClientToken);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
/****
|
||
@func NTSTATUS | ElfpReplicateEvent| The cluster service calls this
|
||
api to log events reported at other nodes of the cluster in the event log files.
|
||
|
||
@parm IN PLOGMODULE | pModule| A pointer to a module for the eventlog file.
|
||
|
||
@parm IN PVOID | pEventBuffer | A pointer to the event buffer.
|
||
|
||
@parm IN DWORD | dwRecordLength| The length of the event buffer in bytes.
|
||
|
||
@comm This replicates an event log record across a cluster.
|
||
|
||
@rdesc Returns a result code. ERROR_SUCCESS on success.
|
||
|
||
@xref
|
||
****/
|
||
NTSTATUS
|
||
ElfpReplicateEvent(
|
||
IN PLOGMODULE pModule,
|
||
IN PVOID pEventBuffer,
|
||
IN DWORD dwRecordLength
|
||
)
|
||
{
|
||
DWORD dwError = ERROR_SUCCESS;
|
||
|
||
if (dwRecordLength >= MAXSIZE_OF_EVENTSTOPROP )
|
||
{
|
||
ELF_LOG0(TRACE,
|
||
"ElfpReplicateEvent: eventlog record size is bigger than supported size\n");
|
||
return(dwError);
|
||
}
|
||
|
||
//
|
||
// Acquire the critical section for this global propagation area
|
||
//
|
||
RtlEnterCriticalSection (&gClPropCritSec);
|
||
|
||
if (gbClustering)
|
||
{
|
||
PEVENTSFORLOGFILE pEventsForLogFile;
|
||
|
||
ELF_LOG0(TRACE,
|
||
"ElfpReplicateEvent: Part of a cluster -- propagating the event\n");
|
||
|
||
//
|
||
// Packed event info consists of:
|
||
//
|
||
// 1. PACKEDEVENTINFO structure
|
||
// 2. size of offsets (currently 1 -- sizeof(ULONG))
|
||
// 3. EVENTSFORLOGFILE structure
|
||
// 4. The record itself
|
||
//
|
||
gpClPackedEventInfo->ulSize = sizeof(PACKEDEVENTINFO)
|
||
+ sizeof(ULONG)
|
||
+ sizeof(EVENTSFORLOGFILE)
|
||
+ dwRecordLength;
|
||
|
||
pEventsForLogFile =
|
||
(PEVENTSFORLOGFILE)((PBYTE) gpClPackedEventInfo
|
||
+ gpClPackedEventInfo->ulOffsets[0]);
|
||
|
||
//
|
||
// Set the events for log file structure
|
||
//
|
||
pEventsForLogFile->ulNumRecords = 1;
|
||
|
||
lstrcpyW(pEventsForLogFile->szLogicalLogFile,
|
||
pModule->LogFile->LogModuleName->Buffer);
|
||
|
||
pEventsForLogFile->ulSize = sizeof(EVENTSFORLOGFILE)
|
||
+ dwRecordLength;
|
||
|
||
RtlCopyMemory(pEventsForLogFile->pEventLogRecords,
|
||
(PVOID) pEventBuffer,
|
||
dwRecordLength);
|
||
|
||
dwError = (*gpfnPropagateEvents)(ghCluster,
|
||
gpClPackedEventInfo->ulSize,
|
||
(PUCHAR) gpClPackedEventInfo);
|
||
|
||
//
|
||
// Advance the session start record number so that the same
|
||
// record doesnt get propagated twice. If the service restarts,
|
||
// don't advance the session number if the call doesn't succeed.
|
||
//
|
||
// Issue: If the server is multi-threaded, we might lose events
|
||
// if a latter one gets propagated before one that gets
|
||
// written to the log earlier. I dont think this is an
|
||
// eventlog problem since we are calling in a CS
|
||
//
|
||
if (dwError == ERROR_SUCCESS)
|
||
{
|
||
pModule->LogFile->SessionStartRecordNumber =
|
||
pModule->LogFile->CurrentRecordNumber;
|
||
}
|
||
}
|
||
|
||
RtlLeaveCriticalSection (&gClPropCritSec);
|
||
|
||
return(dwError);
|
||
}
|
||
|
||
//SS:end of changes made to enable cluster wide event logging
|