www.pudn.com > win2ksrc.rar > apistub.c, change:2000-07-26,size:48582b


 
/*++ 
 
Copyright (c) 1991  Microsoft Corporation 
 
Module Name: 
 
    APISTUB.C 
 
Abstract: 
 
    This module contains the client ends of the Elf APIs. 
 
 
Author: 
 
    Rajen Shah  (rajens)    29-Jul-1991 
 
 
Revision History: 
 
    29-Jul-1991         RajenS 
        Created 
 
    13-Jan-1997         Added extensions for clustering to support replicated 
                        eventlogs 
--*/ 
/**** 
@doc    EXTERNAL INTERFACES EVTLOG 
****/ 
 
#include <elfclntp.h> 
#include <lmerr.h> 
#include <stdlib.h> 
#include <string.h> 
 
// 
// Global data 
// 
PUNICODE_STRING     pGlobalComputerNameU; 
PANSI_STRING        pGlobalComputerNameA; 
 
 
 
VOID 
w_GetComputerName ( ) 
 
/*++ 
 
Routine Description: 
 
    This routine gets the name of the computer. It checks the global 
    variable to see if the computer name has already been determined. 
    If not, it updates that variable with the name. 
    It does this for the UNICODE and the ANSI versions. 
 
Arguments: 
 
    NONE 
 
Return Value: 
 
    NONE 
 
 
--*/ 
{ 
    PUNICODE_STRING     pNameU; 
    PANSI_STRING        pNameA; 
    LPSTR               szName; 
    LPWSTR              wszName; 
    DWORD               dwStatus; 
 
    // 
    // If this fails, we're leaking 
    // 
    ASSERT(pGlobalComputerNameU == NULL && pGlobalComputerNameA == NULL); 
 
    pNameU = MIDL_user_allocate (sizeof (UNICODE_STRING)); 
    pNameA = MIDL_user_allocate (sizeof (ANSI_STRING)); 
 
    if ((pNameU != NULL) && (pNameA != NULL)) { 
 
        dwStatus = ElfpGetComputerName(&szName, &wszName); 
 
        if (dwStatus == NO_ERROR) { 
 
            // 
            // ElfpComputerName has allocated a buffer to contain the 
            // ASCII name of the computer. We use that for the ANSI 
            // string structure. 
            // 
            RtlInitAnsiString ( pNameA, szName ); 
            RtlInitUnicodeString ( pNameU, wszName ); 
 
        } else { 
 
            // 
            // We could not get the computer name for some reason. Set up 
            // the golbal pointer to point to the NULL string. 
            // 
            RtlInitAnsiString ( pNameA, "\0"); 
            RtlInitUnicodeString ( pNameU, L"\0"); 
        } 
 
        pGlobalComputerNameU = pNameU; 
        pGlobalComputerNameA = pNameA; 
    } 
    else { 
 
        // 
        // In case one of the two was allocated. 
        //  
        MIDL_user_free (pNameU); 
        MIDL_user_free (pNameA); 
    } 
} 
 
 
 
 
PUNICODE_STRING 
TmpGetComputerNameW ( ) 
 
/*++ 
 
Routine Description: 
 
    This routine gets the UNICODE name of the computer. It checks the global 
    variable to see if the computer name has already been determined. 
    If not, it calls the worker routine to do that. 
 
Arguments: 
 
    NONE 
 
Return Value: 
 
    Returns a pointer to the computer name, or a NULL. 
 
 
--*/ 
{ 
    if (pGlobalComputerNameU == NULL) { 
        w_GetComputerName(); 
    } 
    return (pGlobalComputerNameU); 
} 
 
 
 
PANSI_STRING 
TmpGetComputerNameA ( ) 
 
/*++ 
 
Routine Description: 
 
    This routine gets the ANSI name of the computer. It checks the global 
    variable to see if the computer name has already been determined. 
    If not, it calls the worker routine to do that. 
 
Arguments: 
 
    NONE 
 
Return Value: 
 
    Returns a pointer to the computer name, or a NULL. 
 
 
--*/ 
{ 
 
    if (pGlobalComputerNameA == NULL) { 
        w_GetComputerName(); 
    } 
    return (pGlobalComputerNameA); 
} 
 
// 
// These APIs only have one interface, since they don't take or return strings 
// 
 
NTSTATUS 
ElfNumberOfRecords( 
    IN      HANDLE      LogHandle, 
    OUT     PULONG      NumberOfRecords 
    ) 
{ 
    NTSTATUS status; 
 
    // 
    // Make sure the output pointer is valid 
    // 
 
    if (!NumberOfRecords) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service entry point 
 
        status = ElfrNumberOfRecords ( 
                        (IELF_HANDLE) LogHandle, 
                        NumberOfRecords 
                        ); 
 
    } 
    RpcExcept (1) { 
            status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
NTSTATUS 
ElfOldestRecord( 
    IN      HANDLE      LogHandle, 
    OUT     PULONG      OldestRecordNumber 
    ) 
{ 
    NTSTATUS status; 
 
    // 
    // 
    // Make sure the output pointer is valid 
    // 
 
    if (!OldestRecordNumber) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service entry point 
 
        status = ElfrOldestRecord ( 
                        (IELF_HANDLE) LogHandle, 
                        OldestRecordNumber 
                        ); 
 
    } 
    RpcExcept (1) { 
            status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
 
NTSTATUS 
ElfChangeNotify( 
    IN      HANDLE      LogHandle, 
    IN      HANDLE      Event 
    ) 
{ 
 
    NTSTATUS status; 
    RPC_CLIENT_ID RpcClientId; 
    CLIENT_ID ClientId; 
 
    // 
    // Map the handles to something that RPC can understand 
    // 
 
    ClientId = NtCurrentTeb()->ClientId; 
    RpcClientId.UniqueProcess = (ULONG)((ULONG_PTR)ClientId.UniqueProcess); 
    RpcClientId.UniqueThread = (ULONG)((ULONG_PTR)ClientId.UniqueThread); 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
 
    RpcTryExcept { 
 
        // Call service entry point 
 
        status = ElfrChangeNotify ( 
                        (IELF_HANDLE)((ULONG_PTR)LogHandle), 
                        RpcClientId, 
                        (DWORD)(ULONG_PTR)Event 
                        ); 
 
    } 
    RpcExcept (1) { 
            status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
 
NTSTATUS 
ElfGetLogInformation( 
    IN     HANDLE        LogHandle, 
    IN     ULONG         InfoLevel, 
    OUT    PVOID         lpBuffer, 
    IN     ULONG         cbBufSize, 
    OUT    PULONG        pcbBytesNeeded 
    ) 
{ 
    NTSTATUS ntStatus; 
 
    // 
    // Make sure the Infolevel is valid 
    // 
 
    switch (InfoLevel) { 
 
        case EVENTLOG_FULL_INFO: 
 
            RpcTryExcept { 
 
                // Call service entry point 
 
                ntStatus = ElfrGetLogInformation( 
                               (IELF_HANDLE) LogHandle, 
                               InfoLevel, 
                               lpBuffer, 
                               cbBufSize, 
                               pcbBytesNeeded); 
 
            } 
            RpcExcept (1) { 
                ntStatus = I_RpcMapWin32Status(RpcExceptionCode()); 
            } 
            RpcEndExcept 
 
            break; 
 
        default: 
 
            ntStatus = STATUS_INVALID_LEVEL; 
            break; 
    } 
 
    return ntStatus; 
} 
 
 
// 
// UNICODE APIs 
// 
 
NTSTATUS 
ElfOpenEventLogW ( 
    IN  PUNICODE_STRING         UNCServerName, 
    IN  PUNICODE_STRING         LogName, 
    OUT PHANDLE                 LogHandle 
    ) 
 
/*++ 
 
Routine Description: 
 
    This is the client DLL entry point for the ElfOpenEventLog API. 
 
    It creates an RPC binding for the server specified, and stores that 
    and additional data away. It returns a handle to the caller that can 
    be used to later on access the handle-specific information. 
 
Arguments: 
 
    UNCServerName   - Server with which to bind for subsequent operations. 
 
    LogName         - Supplies the name of the module for the logfile 
                      to associate with this handle. 
 
    LogHandle       - Location where log handle is to be returned. 
 
 
Return Value: 
 
    Returns an NTSTATUS code and, if no error, a handle that can be used 
    for subsequent Elf API calls. 
 
 
--*/ 
{ 
    NTSTATUS            status    = STATUS_SUCCESS; 
    NTSTATUS            ApiStatus; 
    UNICODE_STRING      RegModuleName; 
    EVENTLOG_HANDLE_W   ServerNameString; 
    BOOLEAN             fWasEnabled = FALSE; 
    BOOL                fIsSecurityLog; 
 
    // 
    // Make sure input & output pointers are valid 
    // 
 
    if (!LogHandle || !LogName || LogName->Length == 0) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) { 
        ServerNameString = UNCServerName->Buffer; 
    } else { 
        ServerNameString = NULL; 
    } 
 
    RtlInitUnicodeString( &RegModuleName, UNICODE_NULL); 
 
    // Call service via RPC. Pass in major and minor version numbers. 
 
    *LogHandle = NULL;          // Must be NULL so RPC fills it in 
 
    fIsSecurityLog = (_wcsicmp(ELF_SECURITY_MODULE_NAME, LogName->Buffer) == 0); 
 
    if (fIsSecurityLog) { 
 
        // 
        // Tacitly attempt to enable the SE_SECURITY_PRIVILEGE so we can 
        // can check it on the server side.  We ignore the return value 
        // because it's possible for this call to fail here but for the 
        // user to have this privilege if the log is on a remote server. 
        // 
        // Note that we make this call on behalf of the client to avoid 
        // a regression when we check for the privilege on the server 
        // side -- without this call, 3rd party apps that successfully 
        // called this API before would fail.  Under normal circumstances, 
        // this is not an encouraged practice. 
        // 
 
        // 
        // BUGBUG -- This should really be done via ImpersonateSelf() 
        //           and adjusting the thread token 
        // 
        ApiStatus = RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, 
                                       TRUE, 
                                       FALSE, 
                                       &fWasEnabled); 
    } 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        status = ElfrOpenELW( 
                    ServerNameString, 
                    (PRPC_UNICODE_STRING) LogName, 
                    (PRPC_UNICODE_STRING) &RegModuleName, 
                    ELF_VERSION_MAJOR, 
                    ELF_VERSION_MINOR, 
                    (PIELF_HANDLE) LogHandle 
                    ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
 
    if (fIsSecurityLog && NT_SUCCESS(ApiStatus)) { 
 
        // 
        // Restore the state 
        // 
 
        RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, 
                           fWasEnabled, 
                           FALSE, 
                           &fWasEnabled); 
    } 
 
    return (status); 
} 
 
 
NTSTATUS 
ElfRegisterEventSourceW ( 
    IN  PUNICODE_STRING         UNCServerName, 
    IN  PUNICODE_STRING         ModuleName, 
    OUT PHANDLE                 LogHandle 
    ) 
 
/*++ 
 
Routine Description: 
 
    This is the client DLL entry point for the ElfRegisterEventSource API. 
 
    It creates an RPC binding for the server specified, and stores that 
    and additional data away. It returns a handle to the caller that can 
    be used to later on access the handle-specific information. 
 
Arguments: 
 
    UNCServerName   - Server with which to bind for subsequent operations. 
 
    ModuleName      - Supplies the name of the module to associate with 
                      this handle. 
 
    LogHandle       - Location where log handle is to be returned. 
 
 
Return Value: 
 
    Returns an NTSTATUS code and, if no error, a handle that can be used 
    for subsequent Elf API calls. 
 
 
--*/ 
{ 
    NTSTATUS            status = STATUS_SUCCESS; 
    UNICODE_STRING      RegModuleName; 
    EVENTLOG_HANDLE_W   ServerNameString; 
 
    // 
    // Make sure input & output pointers are valid 
    // 
 
    if (!LogHandle || !ModuleName || ModuleName->Length == 0) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) { 
        ServerNameString = UNCServerName->Buffer; 
    } else { 
        ServerNameString = NULL; 
    } 
 
    RtlInitUnicodeString( &RegModuleName, UNICODE_NULL); 
 
    // Call service via RPC. Pass in major and minor version numbers. 
 
    *LogHandle = NULL;          // Must be NULL so RPC fills it in 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        status = ElfrRegisterEventSourceW( 
                    ServerNameString, 
                    (PRPC_UNICODE_STRING)ModuleName, 
                    (PRPC_UNICODE_STRING)&RegModuleName, 
                    ELF_VERSION_MAJOR, 
                    ELF_VERSION_MINOR, 
                    (PIELF_HANDLE) LogHandle 
                    ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
 
    return (status); 
} 
 
 
NTSTATUS 
ElfOpenBackupEventLogW ( 
    IN  PUNICODE_STRING UNCServerName, 
    IN  PUNICODE_STRING BackupFileName, 
    OUT PHANDLE LogHandle 
    ) 
 
/*++ 
 
Routine Description: 
 
    This is the client DLL entry point for the ElfOpenBackupEventLog API. 
 
    It creates an RPC binding for the server specified, and stores that 
    and additional data away. It returns a handle to the caller that can 
    be used to later on access the handle-specific information. 
 
Arguments: 
 
    UNCServerName   - Server with which to bind for subsequent operations. 
 
    BackupFileName  - Supplies the filename of the module to associate with 
                      this handle. 
 
    LogHandle       - Location where log handle is to be returned. 
 
 
Return Value: 
 
    Returns an NTSTATUS code and, if no error, a handle that can be used 
    for subsequent Elf API calls. 
 
 
--*/ 
{ 
    NTSTATUS            status = STATUS_SUCCESS; 
    EVENTLOG_HANDLE_W   ServerNameString; 
 
    // 
    // Make sure input & output pointers are valid 
    // 
 
    if (!LogHandle || !BackupFileName || BackupFileName->Length == 0) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) { 
        ServerNameString = UNCServerName->Buffer; 
    } else { 
        ServerNameString = NULL; 
    } 
 
    // Call service via RPC. Pass in major and minor version numbers. 
 
    *LogHandle = NULL;          // Must be NULL so RPC fills it in 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
 
    RpcTryExcept { 
 
        status = ElfrOpenBELW( 
                    ServerNameString, 
                    (PRPC_UNICODE_STRING)BackupFileName, 
                    ELF_VERSION_MAJOR, 
                    ELF_VERSION_MINOR, 
                    (PIELF_HANDLE) LogHandle 
                    ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
} 
 
 
 
NTSTATUS 
ElfClearEventLogFileW ( 
    IN      HANDLE          LogHandle, 
    IN      PUNICODE_STRING BackupFileName 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfClearEventLogFile API. 
  The call is passed to the eventlog service on the appropriate server 
  identified by LogHandle. 
 
 
Arguments: 
 
    LogHandle       - Handle returned from a previous "Open" call. This is 
                      used to identify the module and the server. 
 
    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; 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service entry point 
 
        status = ElfrClearELFW ( 
                        (IELF_HANDLE) LogHandle, 
                        (PRPC_UNICODE_STRING)BackupFileName 
                        ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
 
NTSTATUS 
ElfBackupEventLogFileW ( 
    IN      HANDLE          LogHandle, 
    IN      PUNICODE_STRING BackupFileName 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfBackupEventLogFile API. 
  The call is passed to the eventlog service on the appropriate server 
  identified by LogHandle. 
 
 
Arguments: 
 
    LogHandle       - Handle returned from a previous "Open" call. This is 
                      used to identify the module and the server. 
 
    BackupFileName  - Name of the file to back up the current log file. 
 
 
Return Value: 
 
    Returns an NTSTATUS code. 
 
 
--*/ 
{ 
    NTSTATUS status; 
    NTSTATUS ApiStatus; 
    BOOLEAN  fWasEnabled; 
 
    // 
    // Make sure input pointers are valid 
    // 
 
    if (!BackupFileName || BackupFileName->Length == 0) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    // 
    // Tacitly attempt to enable the SE_BACKUP_PRIVILEGE so we can 
    // can check it on the server side 
    // 
    // Note that we make this call on behalf of the client to avoid 
    // a regression when we check for the privilege on the server 
    // side -- without this call, 3rd party apps that successfully 
    // called this API before would fail.  Under normal circumstances, 
    // this is not an encouraged practice. 
    // 
 
    // 
    // BUGBUG -- This should really be done via ImpersonateSelf() 
    //           and adjusting the thread token 
    // 
    ApiStatus = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, 
                                   TRUE, 
                                   FALSE, 
                                   &fWasEnabled); 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service entry point 
 
        status = ElfrBackupELFW ( 
                        (IELF_HANDLE) LogHandle, 
                        (PRPC_UNICODE_STRING)BackupFileName); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    // 
    // Restore the client's privilege state to what it was before 
    // 
 
    if (NT_SUCCESS(ApiStatus)) { 
 
        RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, 
                           fWasEnabled, 
                           TRUE, 
                           &fWasEnabled); 
    } 
 
    return (status); 
} 
 
 
NTSTATUS 
ElfCloseEventLog ( 
    IN  HANDLE  LogHandle 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfCloseEventLog API. 
  It closes the RPC binding, and frees any memory allocated for the 
  handle. 
 
 
Arguments: 
 
    LogHandle       - Handle returned from a previous "Open" call. 
 
 
Return Value: 
 
    Returns an NTSTATUS code. 
 
 
--*/ 
{ 
    NTSTATUS status; 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call server 
 
        status = ElfrCloseEL ( 
                        (PIELF_HANDLE)  &LogHandle 
                        ); 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
 
NTSTATUS 
ElfDeregisterEventSource ( 
    IN  HANDLE  LogHandle 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfDeregisterEventSource API. 
  It closes the RPC binding, and frees any memory allocated for the 
  handle. 
 
 
Arguments: 
 
    LogHandle       - Handle returned from a previous "Open" call. 
 
 
Return Value: 
 
    Returns an NTSTATUS code. 
 
 
--*/ 
{ 
    NTSTATUS status; 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call server 
 
        status = ElfrDeregisterEventSource ( 
                        (PIELF_HANDLE)  &LogHandle 
                        ); 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
 
 
NTSTATUS 
ElfReadEventLogW ( 
    IN          HANDLE      LogHandle, 
    IN          ULONG       ReadFlags, 
    IN          ULONG       RecordNumber, 
    OUT         PVOID       Buffer, 
    IN          ULONG       NumberOfBytesToRead, 
    OUT         PULONG      NumberOfBytesRead, 
    OUT         PULONG      MinNumberOfBytesNeeded 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfReadEventLog API. 
 
Arguments: 
 
 
 
Return Value: 
 
    Returns an NTSTATUS code. 
 
 
--*/ 
{ 
    NTSTATUS status; 
    ULONG    FlagBits; 
 
    // 
    // Make sure the output pointers are valid 
    // 
 
    if (!Buffer || !NumberOfBytesRead || !MinNumberOfBytesNeeded) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    // 
    // Ensure that the ReadFlags we got are valid. 
    // Make sure that one of each type of bit is set. 
    // 
    FlagBits = ReadFlags & (EVENTLOG_SEQUENTIAL_READ | EVENTLOG_SEEK_READ); 
 
    if ((FlagBits > 2) || (FlagBits == 0)) { 
        return(STATUS_INVALID_PARAMETER); 
    } 
 
    FlagBits = ReadFlags & (EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ); 
 
    if ((FlagBits > 8) || (FlagBits == 0)) { 
        return(STATUS_INVALID_PARAMETER); 
    } 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service 
 
        status = ElfrReadELW ( 
                        (IELF_HANDLE) LogHandle, 
                        ReadFlags, 
                        RecordNumber, 
                        NumberOfBytesToRead, 
                        Buffer, 
                        NumberOfBytesRead, 
                        MinNumberOfBytesNeeded 
                        ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    // Return status and bytes read/required. 
 
    return (status); 
 
} 
 
 
 
NTSTATUS 
ElfReportEventW ( 
    IN      HANDLE          LogHandle, 
    IN      USHORT          EventType, 
    IN      USHORT          EventCategory OPTIONAL, 
    IN      ULONG           EventID, 
    IN      PSID            UserSid, 
    IN      USHORT          NumStrings, 
    IN      ULONG           DataSize, 
    IN      PUNICODE_STRING *Strings, 
    IN      PVOID           Data, 
    IN      USHORT          Flags, 
    IN OUT  PULONG          RecordNumber OPTIONAL, 
    IN OUT  PULONG          TimeWritten  OPTIONAL 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfReportEvent API. 
 
Arguments: 
 
 
Return Value: 
 
    Returns an NTSTATUS code. 
 
Note: 
 
    The last three parameters (Flags, RecordNumber and TimeWritten) are 
    designed to be used by Security Auditing for the implementation of 
    paired events (associating a file open event with the subsequent file 
    close). This will not be implemented in Product 1, but the API is 
    defined to allow easier support of this in a later release. 
 
 
--*/ 
{ 
    NTSTATUS status; 
    PUNICODE_STRING pComputerNameU; 
    LARGE_INTEGER Time; 
    ULONG EventTime; 
 
    // 
    // Generate the time of the event. This is done on the client side 
    // since that is where the event occurred. 
    // 
    NtQuerySystemTime(&Time); 
    RtlTimeToSecondsSince1970(&Time, 
                          &EventTime 
                         ); 
 
    // 
    // Generate the ComputerName of the client. 
    // We have to do this in the client side since this call may be 
    // remoted to another server and we would not necessarily have 
    // the computer name there. 
    // 
    pComputerNameU = TmpGetComputerNameW(); 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service 
 
        status = ElfrReportEventW ( 
                    (IELF_HANDLE)   LogHandle, 
                    EventTime, 
                    EventType, 
                    EventCategory, 
                    EventID, 
                    NumStrings, 
                    DataSize, 
                    (PRPC_UNICODE_STRING)pComputerNameU, 
                    UserSid, 
                    (PRPC_UNICODE_STRING *)Strings, 
                    Data, 
                    Flags, 
                    RecordNumber, 
                    TimeWritten 
                    ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
 
// 
// ANSI APIs 
// 
 
NTSTATUS 
ElfOpenEventLogA ( 
    IN  PANSI_STRING    UNCServerName, 
    IN  PANSI_STRING    LogName, 
    OUT PHANDLE         LogHandle 
    ) 
 
/*++ 
 
Routine Description: 
 
    This is the client DLL entry point for the ElfOpenEventLog API. 
 
    It creates an RPC binding for the server specified, and stores that 
    and additional data away. It returns a handle to the caller that can 
    be used to later on access the handle-specific information. 
 
Arguments: 
 
    UNCServerName   - Server with which to bind for subsequent operations. 
 
    LogName         - Supplies the name of the module for the logfile to 
                      associate with this handle. 
 
    LogHandle       - Location where log handle is to be returned. 
 
 
Return Value: 
 
    Returns an NTSTATUS code and, if no error, a handle that can be used 
    for subsequent Elf API calls. 
 
 
--*/ 
{ 
    NTSTATUS            status = STATUS_SUCCESS; 
    NTSTATUS            ApiStatus; 
    ANSI_STRING         RegModuleName; 
    EVENTLOG_HANDLE_A   ServerNameString; 
    BOOLEAN             fWasEnabled = FALSE; 
    BOOL                fIsSecurityLog; 
 
    // 
    // Make sure input & output pointers are valid 
    // 
 
    if (!LogHandle || !LogName || LogName->Length == 0) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) { 
        ServerNameString = UNCServerName->Buffer; 
    } else { 
        ServerNameString = NULL; 
    } 
 
    RtlInitAnsiString( &RegModuleName, ELF_APPLICATION_MODULE_NAME_ASCII ); 
 
    // Call service via RPC. Pass in major and minor version numbers. 
 
    *LogHandle = NULL;          // Must be NULL so RPC fills it in 
 
    fIsSecurityLog = (_stricmp(ELF_SECURITY_MODULE_NAME_ASCII, LogName->Buffer) == 0); 
 
    if (fIsSecurityLog) { 
 
        // 
        // Tacitly attempt to enable the SE_SECURITY_PRIVILEGE so we can 
        // can check it on the server side.  We ignore the return value 
        // because it's possible for this call to fail here but for the 
        // user to have this privilege if the log is on a remote server 
        // 
        // Note that we make this call on behalf of the client to avoid 
        // a regression when we check for the privilege on the server 
        // side -- without this call, 3rd party apps that successfully 
        // called this API before would fail.  Under normal circumstances, 
        // this is not an encouraged practice. 
        // 
 
        // 
        // BUGBUG -- This should really be done via ImpersonateSelf() 
        //           and adjusting the thread token 
        // 
        ApiStatus = RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, 
                                       TRUE, 
                                       FALSE, 
                                       &fWasEnabled); 
    } 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
         status = ElfrOpenELA ( 
                    ServerNameString, 
                    (PRPC_STRING) LogName, 
                    (PRPC_STRING) &RegModuleName, 
                    ELF_VERSION_MAJOR, 
                    ELF_VERSION_MINOR, 
                    (PIELF_HANDLE) LogHandle); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    if (fIsSecurityLog && NT_SUCCESS(ApiStatus)) { 
 
        // 
        // Restore the state 
        // 
 
        RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, 
                           fWasEnabled, 
                           FALSE, 
                           &fWasEnabled); 
    } 
 
    return (status); 
} 
 
 
NTSTATUS 
ElfRegisterEventSourceA ( 
    IN  PANSI_STRING    UNCServerName, 
    IN  PANSI_STRING    ModuleName, 
    OUT PHANDLE         LogHandle 
    ) 
 
/*++ 
 
Routine Description: 
 
    This is the client DLL entry point for the ElfOpenEventLog API. 
 
    It creates an RPC binding for the server specified, and stores that 
    and additional data away. It returns a handle to the caller that can 
    be used to later on access the handle-specific information. 
 
Arguments: 
 
    UNCServerName   - Server with which to bind for subsequent operations. 
 
    ModuleName      - Supplies the name of the module to associate with 
                      this handle. 
 
    LogHandle       - Location where log handle is to be returned. 
 
 
Return Value: 
 
    Returns an NTSTATUS code and, if no error, a handle that can be used 
    for subsequent Elf API calls. 
 
 
--*/ 
{ 
    NTSTATUS            status = STATUS_SUCCESS; 
    ANSI_STRING         RegModuleName; 
    EVENTLOG_HANDLE_A   ServerNameString; 
 
    // 
    // Make sure input & output pointers are valid 
    // 
 
    if (!LogHandle || !ModuleName || ModuleName->Length == 0) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) { 
        ServerNameString = UNCServerName->Buffer; 
    } else { 
        ServerNameString = NULL; 
    } 
 
    RtlInitAnsiString( &RegModuleName, ELF_APPLICATION_MODULE_NAME_ASCII ); 
 
    if ( NT_SUCCESS (status) ) { 
 
        // Call service via RPC. Pass in major and minor version numbers. 
 
        *LogHandle = NULL;          // Must be NULL so RPC fills it in 
 
        // 
        // Do the RPC call with an exception handler since RPC will raise an 
        // exception if anything fails. It is up to us to figure out what 
        // to do once the exception is raised. 
        // 
        RpcTryExcept { 
 
            status = ElfrRegisterEventSourceA ( 
                        ServerNameString, 
                        (PRPC_STRING)ModuleName, 
                        (PRPC_STRING)&RegModuleName, 
                        ELF_VERSION_MAJOR, 
                        ELF_VERSION_MINOR, 
                        (PIELF_HANDLE) LogHandle 
                        ); 
 
        } 
        RpcExcept (1) { 
 
            status = I_RpcMapWin32Status(RpcExceptionCode()); 
        } 
        RpcEndExcept 
 
 
    } 
 
    return (status); 
} 
 
 
 
NTSTATUS 
ElfOpenBackupEventLogA ( 
    IN  PANSI_STRING    UNCServerName, 
    IN  PANSI_STRING    FileName, 
    OUT PHANDLE         LogHandle 
    ) 
 
/*++ 
 
Routine Description: 
 
    This is the client DLL entry point for the ElfOpenBackupEventLog API. 
 
    It creates an RPC binding for the server specified, and stores that 
    and additional data away. It returns a handle to the caller that can 
    be used to later on access the handle-specific information. 
 
Arguments: 
 
    UNCServerName   - Server with which to bind for subsequent operations. 
 
    FileName        - Supplies the filename of the logfile to associate with 
                      this handle. 
 
    LogHandle       - Location where log handle is to be returned. 
 
 
Return Value: 
 
    Returns an NTSTATUS code and, if no error, a handle that can be used 
    for subsequent Elf API calls. 
 
 
--*/ 
{ 
    EVENTLOG_HANDLE_A   ServerNameString; 
    NTSTATUS            status; 
 
    // 
    // Make sure input & output pointers are valid 
    // 
 
    if (!LogHandle || !FileName || FileName->Length == 0) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) { 
        ServerNameString = UNCServerName->Buffer; 
    } else { 
        ServerNameString = NULL; 
    } 
 
    // Call service via RPC. Pass in major and minor version numbers. 
 
    *LogHandle = NULL;          // Must be NULL so RPC fills it in 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
 
    RpcTryExcept { 
 
        status = ElfrOpenBELA ( 
                    ServerNameString, 
                    (PRPC_STRING)FileName, 
                    ELF_VERSION_MAJOR, 
                    ELF_VERSION_MINOR, 
                    (PIELF_HANDLE) LogHandle 
                    ); 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
} 
 
 
 
NTSTATUS 
ElfClearEventLogFileA ( 
    IN      HANDLE          LogHandle, 
    IN      PANSI_STRING BackupFileName 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfClearEventLogFile API. 
  The call is passed to the eventlog service on the appropriate server 
  identified by LogHandle. 
 
 
Arguments: 
 
    LogHandle       - Handle returned from a previous "Open" call. This is 
                      used to identify the module and the server. 
 
    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; 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service entry point 
 
        status = ElfrClearELFA ( 
                        (IELF_HANDLE) LogHandle, 
                        (PRPC_STRING)BackupFileName 
                        ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
 
NTSTATUS 
ElfBackupEventLogFileA ( 
    IN      HANDLE       LogHandle, 
    IN      PANSI_STRING BackupFileName 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfBackupEventLogFile API. 
  The call is passed to the eventlog service on the appropriate server 
  identified by LogHandle. 
 
 
Arguments: 
 
    LogHandle       - Handle returned from a previous "Open" call. This is 
                      used to identify the module and the server. 
 
    BackupFileName  - Name of the file to back up the current log file. 
 
 
Return Value: 
 
    Returns an NTSTATUS code. 
 
 
--*/ 
{ 
    NTSTATUS status; 
    NTSTATUS ApiStatus; 
    BOOLEAN  fWasEnabled; 
 
    // 
    // Make sure input pointers are valid 
    // 
 
    if (!BackupFileName || BackupFileName->Length == 0) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    // 
    // Tacitly attempt to enable the SE_BACKUP_PRIVILEGE so we can 
    // can check it on the server side 
    // 
    // Note that we make this call on behalf of the client to avoid 
    // a regression when we check for the privilege on the server 
    // side -- without this call, 3rd party apps that successfully 
    // called this API before would fail.  Under normal circumstances, 
    // this is not an encouraged practice. 
    // 
 
    // 
    // BUGBUG -- This should really be done via ImpersonateSelf() 
    //           and adjusting the thread token 
    // 
    ApiStatus = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, 
                                   TRUE, 
                                   FALSE, 
                                   &fWasEnabled); 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service entry point 
 
        status = ElfrBackupELFA ( 
                        (IELF_HANDLE) LogHandle, 
                        (PRPC_STRING)BackupFileName 
                        ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    // 
    // Restore the client's privilege state to what it was before 
    // 
 
    if (NT_SUCCESS(ApiStatus)) { 
 
        RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, 
                           fWasEnabled, 
                           TRUE, 
                           &fWasEnabled); 
    } 
 
    return (status); 
} 
 
 
 
NTSTATUS 
ElfReadEventLogA ( 
    IN          HANDLE      LogHandle, 
    IN          ULONG       ReadFlags, 
    IN          ULONG       RecordNumber, 
    OUT         PVOID       Buffer, 
    IN          ULONG       NumberOfBytesToRead, 
    OUT         PULONG      NumberOfBytesRead, 
    OUT         PULONG      MinNumberOfBytesNeeded 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfReadEventLog API. 
 
Arguments: 
 
 
 
Return Value: 
 
    Returns an NTSTATUS code. 
 
 
--*/ 
{ 
    NTSTATUS status; 
    ULONG    FlagBits; 
 
    // 
    // Make sure the output pointers are valid 
    // 
 
    if (!Buffer || !NumberOfBytesRead || !MinNumberOfBytesNeeded) { 
       return(STATUS_INVALID_PARAMETER); 
    } 
 
    // 
    // Ensure that the ReadFlags we got are valid. 
    // Make sure that one of each type of bit is set. 
    // 
    FlagBits = ReadFlags & (EVENTLOG_SEQUENTIAL_READ | EVENTLOG_SEEK_READ); 
 
    if (   (FlagBits == (EVENTLOG_SEQUENTIAL_READ | EVENTLOG_SEEK_READ)) 
        || (FlagBits == 0)) { 
        return(STATUS_INVALID_PARAMETER); 
    } 
 
    FlagBits = ReadFlags & (EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ); 
 
    if (   (FlagBits == (EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ)) 
        || (FlagBits == 0)) { 
        return(STATUS_INVALID_PARAMETER); 
    } 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service 
 
        status = ElfrReadELA ( 
                        (IELF_HANDLE) LogHandle, 
                        ReadFlags, 
                        RecordNumber, 
                        NumberOfBytesToRead, 
                        Buffer, 
                        NumberOfBytesRead, 
                        MinNumberOfBytesNeeded 
                        ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    // Return status and bytes read/required. 
 
    return (status); 
 
} 
 
 
 
NTSTATUS 
ElfReportEventA ( 
    IN      HANDLE          LogHandle, 
    IN      USHORT          EventType, 
    IN      USHORT          EventCategory OPTIONAL, 
    IN      ULONG           EventID, 
    IN      PSID            UserSid, 
    IN      USHORT          NumStrings, 
    IN      ULONG           DataSize, 
    IN      PANSI_STRING    *Strings, 
    IN      PVOID           Data, 
    IN      USHORT          Flags, 
    IN OUT  PULONG          RecordNumber OPTIONAL, 
    IN OUT  PULONG          TimeWritten  OPTIONAL 
    ) 
 
/*++ 
 
Routine Description: 
 
  This is the client DLL entry point for the ElfReportEvent API. 
 
Arguments: 
 
 
Return Value: 
 
    Returns an NTSTATUS code. 
 
Note: 
 
    The last three parameters (Flags, RecordNumber and TimeWritten) are 
    designed to be used by Security Auditing for the implementation of 
    paired events (associating a file open event with the subsequent file 
    close). This will not be implemented in Product 1, but the API is 
    defined to allow easier support of this in a later release. 
 
 
--*/ 
{ 
    NTSTATUS status; 
    PANSI_STRING pComputerNameA; 
    LARGE_INTEGER Time; 
    ULONG EventTime; 
 
    // 
    // Generate the time of the event. This is done on the client side 
    // since that is where the event occurred. 
    // 
    NtQuerySystemTime(&Time); 
    RtlTimeToSecondsSince1970(&Time, 
                          &EventTime 
                         ); 
 
    // 
    // Generate the ComputerName of the client. 
    // We have to do this in the client side since this call may be 
    // remoted to another server and we would not necessarily have 
    // the computer name there. 
    // 
    pComputerNameA = TmpGetComputerNameA(); 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service 
 
        status = ElfrReportEventA ( 
                    (IELF_HANDLE)   LogHandle, 
                    EventTime, 
                    EventType, 
                    EventCategory, 
                    EventID, 
                    NumStrings, 
                    DataSize, 
                    (PRPC_STRING)pComputerNameA, 
                    UserSid, 
                    (PRPC_STRING*)Strings, 
                    Data, 
                    Flags, 
                    RecordNumber, 
                    TimeWritten 
                    ); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return (status); 
 
} 
 
 
/**** 
@func       NTSTATUS | ElfRegisterClusterSvc|  The cluster service registers 
            itself with the event log service at initialization by calling this api. 
 
@parm       IN PUNICODE_STRING | UNCServerName | Inidicates the server on which the 
            cluster service will register with the eventlog service.  This must 
            be the local node. 
 
@parm       OUT PULONG | pulSize | A pointer to a long that returns the size of the 
            packed event information structure that is returned. 
 
@parm       OUT PPACKEDEVENTINFO | *ppPackedEventInfo| A pointer to the packed event information 
            structure for propagation is returned via this parameter. 
 
@comm       The elf client validates parameters and called the servier entry point. 
 
@rdesc      Returns a result code. ERROR_SUCCESS on success. 
 
@xref        <f ElfrRegisterClusterSvc> 
****/ 
NTSTATUS 
ElfRegisterClusterSvc ( 
    IN  PUNICODE_STRING     UNCServerName, 
    OUT PULONG              pulSize, 
    OUT PPACKEDEVENTINFO    *ppPackedEventInfo 
    ) 
{ 
    EVENTLOG_HANDLE_W   ServerNameString; 
 
    NTSTATUS status; 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) 
    { 
        ServerNameString = UNCServerName->Buffer; 
    } 
    else 
    { 
        ServerNameString = NULL; 
    } 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service 
 
        status = ElfrRegisterClusterSvc (ServerNameString, pulSize, 
                (PBYTE *)ppPackedEventInfo); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
 
    return(status); 
} 
 
/**** 
@func       NTSTATUS | ElfDeregisterClusterSvc|  Before stopping the cluster 
            service deregisters itself for propagation of events from the 
            eventlog service. 
 
@parm       IN PUNICODE_STRING | UNCServerName | Inidicates the server on which the 
            cluster service will register with the eventlog service.  This must 
            be on the local node. 
 
@comm       The elf client forwards this to the appropriate eventlog server entry point. 
 
@rdesc      Returns a result code. ERROR_SUCCESS on success. 
 
@xref       <f ElfDeregisterClusterSvc> <f ElfrDeregisterClusterSvc> 
****/ 
NTSTATUS 
ElfDeregisterClusterSvc( 
    IN  PUNICODE_STRING     UNCServerName 
    ) 
{ 
 
    NTSTATUS status; 
    EVENTLOG_HANDLE_W   ServerNameString; 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) 
    { 
        ServerNameString = UNCServerName->Buffer; 
    } 
    else 
    { 
        ServerNameString = NULL; 
    } 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service 
 
        status = ElfrDeregisterClusterSvc (ServerNameString); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
    return(status); 
 
} 
 
 
/**** 
@func       NTSTATUS | ElfWriteClusterEvents| The cluster service calls this 
            api to log events reported at other nodes of the cluster. 
 
@parm       IN EVENTLOG_HANDLE_W | UNCServerName | Not used. 
 
@parm       IN ULONG | ulSize | The size of the    packed event information structure. 
 
@parm       IN PACKEDEVENTINFO | pPackedEventInfo| A pointer to the packed event information 
            structure for propagation. 
 
@comm       The elf client validates the parameters and forwards this to the appropriate 
            entry point in the eventlog server. 
 
@rdesc      Returns a result code. ERROR_SUCCESS on success. 
 
@xref 
****/ 
NTSTATUS 
ElfWriteClusterEvents( 
    IN  PUNICODE_STRING     UNCServerName, 
    IN  ULONG               ulSize, 
    IN  PPACKEDEVENTINFO    pPackedEventInfo) 
{ 
 
    NTSTATUS status; 
    EVENTLOG_HANDLE_W   ServerNameString; 
 
    //validate input parameters 
    if (!pPackedEventInfo || !ulSize || (pPackedEventInfo->ulSize != ulSize)) 
       return(STATUS_INVALID_PARAMETER); 
 
    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) 
    { 
        ServerNameString = UNCServerName->Buffer; 
    } 
    else 
    { 
        ServerNameString = NULL; 
    } 
 
    // 
    // Do the RPC call with an exception handler since RPC will raise an 
    // exception if anything fails. It is up to us to figure out what 
    // to do once the exception is raised. 
    // 
    RpcTryExcept { 
 
        // Call service 
 
        status = ElfrWriteClusterEvents (ServerNameString, ulSize, 
            (PBYTE)pPackedEventInfo); 
 
    } 
    RpcExcept (1) { 
 
        status = I_RpcMapWin32Status(RpcExceptionCode()); 
    } 
    RpcEndExcept 
    return(status); 
 
}