|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
eventlog.c
Abstract:
This module provides support routines for eventlogging.
Author:
Madan Appiah (madana) 27-Jul-1992
Environment:
Contains NT specific code.
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windef.h> // DWORD.
#include <winbase.h> // event log apis
#include <winerror.h> // NO_ERROR
#include <lmcons.h> // NET_API_STATUS.
#include <lmalert.h> // Alert defines
#include <netlib.h> // These routines
#include <netlogon.h> // needed by logonp.h
#include <logonp.h> // NetpLogon routines
#include <tstr.h> // ultow()
//
// Structure describing the entire list of logged events.
//
typedef struct _NL_EVENT_LIST { CRITICAL_SECTION EventListCritSect; LIST_ENTRY EventList;
// Number of milli-seconds to keep EventList entry for.
ULONG DuplicateEventlogTimeout;
// Event source
LPWSTR Source; } NL_EVENT_LIST, *PNL_EVENT_LIST;
//
// Structure describing an event that has already been logged.
//
typedef struct _NL_EVENT_ENTRY { LIST_ENTRY Next; LARGE_INTEGER FirstLogTime; DWORD EventId; DWORD EventType; DWORD EventCategory; LPBYTE RawDataBuffer; DWORD RawDataSize; LPWSTR *StringArray; DWORD StringCount; DWORD EventsLogged; // total times event encountered.
} NL_EVENT_ENTRY, *PNL_EVENT_ENTRY;
DWORD NetpWriteEventlogEx( LPWSTR Source, DWORD EventID, DWORD EventType, DWORD EventCategory, DWORD NumStrings, LPWSTR *Strings, DWORD DataLength, LPVOID Data ) /*++
Routine Description:
This function writes the specified (EventID) log at the end of the eventlog.
Arguments:
Source - Points to a null-terminated string that specifies the name of the module referenced. The node must exist in the registration database, and the module name has the following format:
\EventLog\System\Lanmanworkstation
EventID - The specific event identifier. This identifies the message that goes with this event.
EventType - Specifies the type of event being logged. This parameter can have one of the following
values:
Value Meaning
EVENTLOG_ERROR_TYPE Error event EVENTLOG_WARNING_TYPE Warning event EVENTLOG_INFORMATION_TYPE Information event
NumStrings - Specifies the number of strings that are in the array at 'Strings'. A value of zero indicates no strings are present.
Strings - Points to a buffer containing an array of null-terminated strings that are merged into the message before displaying to the user. This parameter must be a valid pointer (or NULL), even if cStrings is zero.
DataLength - Specifies the number of bytes of event-specific raw (binary) data to write to the log. If cbData is zero, no event-specific data is present.
Data - Buffer containing the raw data. This parameter must be a valid pointer (or NULL), even if cbData is zero.
Return Value:
Returns the WIN32 extended error obtained by GetLastError().
NOTE : This function works slow since it calls the open and close eventlog source everytime.
--*/ { HANDLE EventlogHandle; DWORD ReturnCode;
//
// open eventlog section.
//
EventlogHandle = RegisterEventSourceW( NULL, Source );
if (EventlogHandle == NULL) {
ReturnCode = GetLastError(); goto Cleanup; }
//
// Log the error code specified
//
if( !ReportEventW( EventlogHandle, (WORD)EventType, (WORD)EventCategory, // event category
EventID, NULL, (WORD)NumStrings, DataLength, Strings, Data ) ) {
ReturnCode = GetLastError(); goto Cleanup; }
ReturnCode = NO_ERROR;
Cleanup:
if( EventlogHandle != NULL ) {
DeregisterEventSource(EventlogHandle); }
return ReturnCode; }
DWORD NetpWriteEventlog( LPWSTR Source, DWORD EventID, DWORD EventType, DWORD NumStrings, LPWSTR *Strings, DWORD DataLength, LPVOID Data ) { return NetpWriteEventlogEx( Source, EventID, EventType, 0, NumStrings, Strings, DataLength, Data ); }
DWORD NetpRaiseAlert( IN LPWSTR ServiceName, IN DWORD alert_no, IN LPWSTR *string_array ) /*++
Routine Description:
Raise NETLOGON specific Admin alerts.
Arguments:
alert_no - The alert to be raised, text in alertmsg.h
string_array - array of strings terminated by NULL string.
Return Value:
None.
--*/ { NET_API_STATUS NetStatus; LPWSTR *SArray; PCHAR Next; PCHAR End;
char message[ALERTSZ + sizeof(ADMIN_OTHER_INFO)]; PADMIN_OTHER_INFO admin = (PADMIN_OTHER_INFO) message;
//
// Build the variable data
//
admin->alrtad_errcode = alert_no; admin->alrtad_numstrings = 0;
Next = (PCHAR) ALERT_VAR_DATA(admin); End = Next + ALERTSZ;
//
// now take care of (optional) char strings
//
for( SArray = string_array; *SArray != NULL; SArray++ ) { DWORD StringLen;
StringLen = (wcslen(*SArray) + 1) * sizeof(WCHAR);
if( Next + StringLen < End ) {
//
// copy next string.
//
RtlCopyMemory(Next, *SArray, StringLen); Next += StringLen; admin->alrtad_numstrings++; } else { return ERROR_BUFFER_OVERFLOW; } }
//
// Call alerter.
//
NetStatus = NetAlertRaiseEx( ALERT_ADMIN_EVENT, message, (DWORD)((PCHAR)Next - (PCHAR)message), ServiceName );
return NetStatus; }
HANDLE NetpEventlogOpen ( IN LPWSTR Source, IN ULONG DuplicateEventlogTimeout ) /*++
Routine Description:
This routine open a context that keeps track of events that have been logged in the recent past.
Arguments:
Source - Name of the service opening the eventlog
DuplicateEventlogTimeout - Number of milli-seconds to keep EventList entry for.
Return Value:
Handle to be passed to related routines.
NULL: if memory could not be allocated.
--*/ { PNL_EVENT_LIST EventList; LPBYTE Where;
//
// Allocate a buffer to keep the context in.
//
EventList = LocalAlloc( 0, sizeof(NL_EVENT_LIST) + wcslen(Source) * sizeof(WCHAR) + sizeof(WCHAR) );
if ( EventList == NULL ) { return NULL; }
//
// Initialize the critical section
//
try { InitializeCriticalSection( &EventList->EventListCritSect ); } except( EXCEPTION_EXECUTE_HANDLER ) { LocalFree( EventList ); return NULL; }
//
// Initialize the buffer
//
InitializeListHead( &EventList->EventList ); EventList->DuplicateEventlogTimeout = DuplicateEventlogTimeout;
//
// Copy the service name into the buffer
//
Where = (LPBYTE)(EventList + 1); wcscpy( (LPWSTR)Where, Source ); EventList->Source = (LPWSTR) Where;
return EventList; }
DWORD NetpEventlogWriteEx ( IN HANDLE NetpEventHandle, IN DWORD EventType, IN DWORD EventCategory, IN DWORD EventId, IN DWORD StringCount, IN DWORD RawDataSize, IN LPWSTR *StringArray, IN LPVOID pvRawDataBuffer OPTIONAL ) /*++
Routine Description:
Stub routine for calling writing Event Log and skipping duplicates
Arguments:
NetpEventHandle - Handle from NetpEventlogOpen
EventId - event log ID.
EventType - Type of event.
RawDataBuffer - Data to be logged with the error.
numbyte - Size in bytes of "RawDataBuffer"
StringArray - array of null-terminated strings.
StringCount - number of zero terminated strings in "StringArray". The following flags can be OR'd in to the count:
NETP_LAST_MESSAGE_IS_NTSTATUS NETP_LAST_MESSAGE_IS_NETSTATUS NETP_ALLOW_DUPLICATE_EVENTS NETP_RAISE_ALERT_TOO
Return Value:
Win 32 status of the operation.
ERROR_ALREAY_EXISTS: Success status indicating the message was already logged
--*/ { DWORD ErrorCode; DWORD AlertErrorCode = NO_ERROR; WCHAR ErrorNumberBuffer[25]; PLIST_ENTRY ListEntry; ULONG StringIndex; BOOLEAN AllowDuplicateEvents; BOOLEAN RaiseAlertToo; PNL_EVENT_ENTRY EventEntry; PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle; LPBYTE RawDataBuffer = (LPBYTE)pvRawDataBuffer;
//
// Remove sundry flags
//
EnterCriticalSection( &EventList->EventListCritSect ); AllowDuplicateEvents = (StringCount & NETP_ALLOW_DUPLICATE_EVENTS) != 0; StringCount &= ~NETP_ALLOW_DUPLICATE_EVENTS; RaiseAlertToo = (StringCount & NETP_RAISE_ALERT_TOO) != 0; StringCount &= ~NETP_RAISE_ALERT_TOO;
//
// If an NT status code was passed in,
// convert it to a net status code.
//
if ( StringCount & NETP_LAST_MESSAGE_IS_NTSTATUS ) { StringCount &= ~NETP_LAST_MESSAGE_IS_NTSTATUS;
//
// Do the "better" error mapping when eventviewer ParameterMessageFile
// can be a list of files. Then, add netmsg.dll to the list.
//
// StringArray[((StringCount&NETP_STRING_COUNT_MASK)-1] = (LPWSTR) NetpNtStatusToApiStatus( (NTSTATUS) StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1] );
StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1] = (LPWSTR) (ULONG_PTR) RtlNtStatusToDosError( (NTSTATUS) ((ULONG_PTR)StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1]) );
StringCount |= NETP_LAST_MESSAGE_IS_NETSTATUS; }
//
// If a net/windows status code was passed in,
// convert to the the %%N format the eventviewer knows.
//
if ( StringCount & NETP_LAST_MESSAGE_IS_NETSTATUS ) { StringCount &= ~NETP_LAST_MESSAGE_IS_NETSTATUS;
wcscpy( ErrorNumberBuffer, L"%%" ); ultow( (ULONG) ((ULONG_PTR)StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1]), ErrorNumberBuffer+2, 10 ); StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1] = ErrorNumberBuffer;
}
//
// Check to see if this problem has already been reported.
//
if ( !AllowDuplicateEvents ) { for ( ListEntry = EventList->EventList.Flink ; ListEntry != &EventList->EventList ; ) {
EventEntry = CONTAINING_RECORD( ListEntry, NL_EVENT_ENTRY, Next ); // Entry might be freed (or moved) below
ListEntry = ListEntry->Flink;
//
// If the entry is too old,
// ditch it.
//
if ( NetpLogonTimeHasElapsed( EventEntry->FirstLogTime, EventList->DuplicateEventlogTimeout ) ) { // NlPrint((NL_MISC, "Ditched a duplicate event. %ld\n", EventEntry->EventId ));
RemoveEntryList( &EventEntry->Next ); LocalFree( EventEntry ); continue; }
//
// Compare this event to the one being logged.
//
if ( EventEntry->EventId == EventId && EventEntry->EventType == EventType && EventEntry->EventCategory == EventCategory && EventEntry->RawDataSize == RawDataSize && EventEntry->StringCount == StringCount ) {
if ( RawDataSize != 0 && !RtlEqualMemory( EventEntry->RawDataBuffer, RawDataBuffer, RawDataSize ) ) { continue; }
for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) { if ( EventEntry->StringArray[StringIndex] == NULL) { if ( StringArray[StringIndex] != NULL ) { break; } } else { if ( StringArray[StringIndex] == NULL ) { break; } if ( wcscmp( EventEntry->StringArray[StringIndex], StringArray[StringIndex] ) != 0 ) { break; } } }
//
// If the event has already been logged,
// skip this one.
//
if ( StringIndex == StringCount ) { RemoveEntryList( &EventEntry->Next ); InsertHeadList( &EventList->EventList, &EventEntry->Next );
ErrorCode = ERROR_ALREADY_EXISTS;
//
// update count of events logged.
//
EventEntry->EventsLogged ++; goto Cleanup; }
}
} }
//
// Raise an alert if one is needed.
//
if ( RaiseAlertToo ) { ASSERT( StringArray[StringCount] == NULL ); if ( StringArray[StringCount] == NULL ) { AlertErrorCode = NetpRaiseAlert( EventList->Source, EventId, StringArray ); } }
//
// write event
//
ErrorCode = NetpWriteEventlogEx( EventList->Source, EventId, EventType, EventCategory, StringCount, StringArray, RawDataSize, RawDataBuffer);
if( ErrorCode != NO_ERROR ) { goto Cleanup; }
//
// Save the event for later
// (Only cache events while the service is starting or running.)
//
if ( !AllowDuplicateEvents ) { ULONG EventEntrySize;
//
// Compute the size of the allocated block.
//
EventEntrySize = sizeof(NL_EVENT_ENTRY) + RawDataSize;
for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) { EventEntrySize += sizeof(LPWSTR); if ( StringArray[StringIndex] != NULL ) { EventEntrySize += wcslen(StringArray[StringIndex]) * sizeof(WCHAR) + sizeof(WCHAR); } }
//
// Allocate a block for the entry
//
EventEntry = LocalAlloc( 0, EventEntrySize );
//
// Copy the description of this event into the allocated block.
//
if ( EventEntry != NULL ) { LPBYTE Where;
EventEntry->EventId = EventId; EventEntry->EventType = EventType; EventEntry->EventCategory = EventCategory; EventEntry->RawDataSize = RawDataSize; EventEntry->StringCount = StringCount; EventEntry->EventsLogged = 1; GetSystemTimeAsFileTime( (PFILETIME)&EventEntry->FirstLogTime );
Where = (LPBYTE)(EventEntry+1);
EventEntry->StringArray = (LPWSTR *)Where; Where += StringCount * sizeof(LPWSTR);
for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) { if ( StringArray[StringIndex] == NULL ) { EventEntry->StringArray[StringIndex] = NULL; } else { EventEntry->StringArray[StringIndex] = (LPWSTR) Where; wcscpy( (LPWSTR)Where, StringArray[StringIndex] ); Where += wcslen( StringArray[StringIndex] ) * sizeof(WCHAR) + sizeof(WCHAR); } }
if ( RawDataSize != 0 ) { EventEntry->RawDataBuffer = Where; RtlCopyMemory( Where, RawDataBuffer, RawDataSize ); }
InsertHeadList( &EventList->EventList, &EventEntry->Next );
}
}
Cleanup: LeaveCriticalSection( &EventList->EventListCritSect ); return (ErrorCode == NO_ERROR) ? AlertErrorCode : ErrorCode; }
DWORD NetpEventlogWrite ( IN HANDLE NetpEventHandle, IN DWORD EventId, IN DWORD EventType, IN LPBYTE RawDataBuffer OPTIONAL, IN DWORD RawDataSize, IN LPWSTR *StringArray, IN DWORD StringCount ) {
return NetpEventlogWriteEx ( NetpEventHandle, EventType, // wType
0, // wCategory
EventId, // dwEventID
StringCount, RawDataSize, StringArray, RawDataBuffer );
}
VOID NetpEventlogClearList ( IN HANDLE NetpEventHandle ) /*++
Routine Description:
This routine clears the list of events that have already been logged.
Arguments:
NetpEventHandle - Handle from NetpEventlogOpen
Return Value:
None.
--*/ { PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
EnterCriticalSection(&EventList->EventListCritSect); while (!IsListEmpty(&EventList->EventList)) {
PNL_EVENT_ENTRY EventEntry = CONTAINING_RECORD(EventList->EventList.Flink, NL_EVENT_ENTRY, Next); RemoveEntryList( &EventEntry->Next ); LocalFree( EventEntry ); } LeaveCriticalSection(&EventList->EventListCritSect); }
VOID NetpEventlogSetTimeout ( IN HANDLE NetpEventHandle, IN ULONG DuplicateEventlogTimeout ) /*++
Routine Description:
This routine sets a new timeout for logged events
Arguments:
NetpEventHandle - Handle from NetpEventlogOpen
DuplicateEventlogTimeout - Number of milli-seconds to keep EventList entry for.
Return Value:
None.
--*/ { PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
EventList->DuplicateEventlogTimeout = DuplicateEventlogTimeout; }
VOID NetpEventlogClose ( IN HANDLE NetpEventHandle ) /*++
Routine Description:
This routine closes the handle returned from NetpEventlogOpen
Arguments:
NetpEventHandle - Handle from NetpEventlogOpen
Return Value:
None.
--*/ { PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
//
// Clear the list of logged events.
//
NetpEventlogClearList( NetpEventHandle );
//
// Delete the critsect
//
DeleteCriticalSection( &EventList->EventListCritSect );
//
// Free the allocated buffer.
//
LocalFree( EventList ); }
|