Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

827 lines
21 KiB

/*++
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
NetpEventlogWriteEx2 (
IN HANDLE NetpEventHandle,
IN DWORD EventType,
IN DWORD EventCategory,
IN DWORD EventId,
IN DWORD StringCount,
IN DWORD StatusMessageIndex,
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
StatusMessageIndex - Specifies the index of the message that is
a Net or NT status in the StringArray. Used only if
NETP_LAST_MESSAGE_IS_NETSTATUS or NETP_LAST_MESSAGE_IS_NTSTATUS
are set in StringCount. If this parameter is MAXULONG and either
of these flags is set, the default is assumed which is the last
message in the list.
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;
DWORD LocalStatusMessageIndex = StatusMessageIndex;
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;
//
// Check if the status message index in the list
// should be assigned the default value
//
if ( (StringCount & NETP_LAST_MESSAGE_IS_NETSTATUS) != 0 ||
(StringCount & NETP_LAST_MESSAGE_IS_NTSTATUS) != 0 ) {
if ( LocalStatusMessageIndex == MAXULONG ) {
LocalStatusMessageIndex = (StringCount & NETP_STRING_COUNT_MASK) - 1;
}
}
//
// 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[LocalStatusMessageIndex] = (LPWSTR) (ULONG_PTR) RtlNtStatusToDosError( (NTSTATUS) ((ULONG_PTR)StringArray[LocalStatusMessageIndex]) );
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[LocalStatusMessageIndex]), ErrorNumberBuffer+2, 10 );
StringArray[LocalStatusMessageIndex] = 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
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
)
{
return NetpEventlogWriteEx2 (
NetpEventHandle,
EventType, // wType
EventCategory,
EventId, // dwEventID
StringCount,
MAXULONG, // default status message index
RawDataSize,
StringArray,
pvRawDataBuffer
);
}
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 NetpEventlogWriteEx2 (
NetpEventHandle,
EventType, // wType
0, // wCategory
EventId, // dwEventID
StringCount,
MAXULONG, // default status message index
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 );
}