windows-nt/Source/XPSP1/NT/ds/netapi/netlib/eventlog.c
2020-09-26 16:20:57 +08:00

778 lines
19 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 );
}