/* Get the next eventlog message */ char * EventlogNext(EventList ignore_list[MAX_IGNORED_EVENTS], int log, int * level) { BOOL reopen = FALSE; DWORD errnum; DWORD needed; DWORD loglevel; EVENTLOGRECORD * event; char * cp; char * current; char * formatted_string; char * message_file; char * source; char * string_array[EVENTLOG_ARRAY_SZ]; char * username; char hostname[HOSTNAME_SZ]; char defmsg[ERRMSG_SZ]; int event_id; int i; char *index; static char message[SYSLOG_DEF_SZ-17]; static char tstamped_message[SYSLOG_DEF_SZ]; /* Initialize array to prevent memory exceptions with bad message definitions */ for(i = 0; i < EVENTLOG_ARRAY_SZ; i++) string_array[i]="*"; /* Are there any records left in buffer */ while (EventlogList[log].pos == EventlogList[log].count) { /* Reset input position */ EventlogList[log].count = 0; EventlogList[log].pos = 0; /* Read a record */ needed = 0; if (ReadEventLog(EventlogList[log].handle, EVENTLOG_FORWARDS_READ | EVENTLOG_SEEK_READ, EventlogList[log].recnum, EventlogList[log].buffer, sizeof(EventlogList[log].buffer), &EventlogList[log].count, &needed) == 0) { /* Check error */ errnum = GetLastError(); switch (errnum) { /* Message too large... skip over */ case ERROR_INSUFFICIENT_BUFFER: Log(LOG_WARNING, "Eventlog message size too large: \"%s\": %u bytes", EventlogList[log].name, needed); EventlogList[log].recnum++; break; /* Eventlog corrupted (?)... Reopen */ case ERROR_EVENTLOG_FILE_CORRUPT: Log(LOG_INFO, "Eventlog was corrupted: \"%s\"", EventlogList[log].name); reopen = TRUE; break; /* Eventlog files are clearing... Reopen */ case ERROR_EVENTLOG_FILE_CHANGED: Log(LOG_INFO, "Eventlog was cleared: \"%s\"", EventlogList[log].name); reopen = TRUE; break; /* Record not available (yet) */ case ERROR_INVALID_PARAMETER: return NULL; /* Normal end of eventlog messages */ case ERROR_HANDLE_EOF: return NULL; /* Eventlog probably closing down */ case RPC_S_UNKNOWN_IF: return NULL; /* Unknown condition */ default: Log(LOG_ERROR|LOG_SYS, "Eventlog \"%s\" returned error: ", EventlogList[log].name); ServiceIsRunning = FALSE; return NULL; } /* Process reopen */ if (reopen) { EventlogClose(log); if (EventlogOpen(log)) { ServiceIsRunning = FALSE; return NULL; } reopen = FALSE; } } } /* Increase record number */ EventlogList[log].recnum++; /* Get position into buffer */ current = EventlogList[log].buffer + EventlogList[log].pos; /* Get pointer to current event record */ event = (EVENTLOGRECORD *) current; /* Advance position */ EventlogList[log].pos += event->Length; /* Get source and event id */ source = current + sizeof(*event); event_id = (int) HRESULT_CODE(event->EventID); /* Check Event Info Against Ignore List */ if (IgnoreSyslogEvent(ignore_list, source, event_id)) { if (LogInteractive) printf("IGNORING_EVENT: SOURCE=%s & ID=%i\n", source, event_id); return NULL; } /* Check number of strings */ if (event->NumStrings > COUNT_OF(string_array)) { /* Too many strings */ Log(LOG_WARNING, "Eventlog message has too many strings to print message: \"%s\": %u strings", EventlogList[log].name, event->NumStrings); formatted_string = NULL; } else { /* Convert strings to arrays */ cp = current + event->StringOffset; for (i = 0; i < event->NumStrings; i++) { string_array[i] = cp; while (*cp++ != '\0'); } message_file = LookupMessageFile(EventlogList[log].name, source, event->EventID); if (message_file == NULL) { /* Cannot load resources */ formatted_string = NULL; } else { /* Format eventlog message */ formatted_string = FormatLibraryMessage(message_file, event->EventID, string_array); } } /* Create a default message if resources or formatting didn't work */ if (formatted_string == NULL) { _snprintf_s(defmsg, sizeof(defmsg), _TRUNCATE, "(Facility: %u, Status: %s)", HRESULT_FACILITY(event->EventID), FAILED(event->EventID) ? "Failure" : "Success" ); formatted_string = defmsg; } /* replace every space in source by underscores */ index = source; while( *index ) { if( *index == ' ' ) { *index = '_'; } index++; } /* Format source and event ID number */ if(SyslogIncludeTag) { _snprintf_s(message, sizeof(message), _TRUNCATE, "%s: %s: %u: ", SyslogTag, source, HRESULT_CODE(event->EventID) ); } else { _snprintf_s(message, sizeof(message), _TRUNCATE, "%s: %u: ", source, HRESULT_CODE(event->EventID) ); } /* Convert user */ if (event->UserSidLength > 0) { username = GetUsername((SID *) (current + event->UserSidOffset)); if (username) { strncat_s(message, sizeof(message), username, _TRUNCATE); strncat_s(message, sizeof(message), ": ", _TRUNCATE); } } /* Add formatted string to base message */ strncat_s(message, sizeof(message), formatted_string, _TRUNCATE); /* Select syslog level */ switch (event->EventType) { case EVENTLOG_ERROR_TYPE: loglevel = SYSLOG_ERR; *level = SYSLOG_BUILD(SyslogFacility, loglevel); break; case EVENTLOG_WARNING_TYPE: loglevel = SYSLOG_WARNING; *level = SYSLOG_BUILD(SyslogFacility, loglevel); break; case EVENTLOG_INFORMATION_TYPE: loglevel = SYSLOG_NOTICE; *level = SYSLOG_BUILD(SyslogFacility, loglevel); break; case EVENTLOG_AUDIT_SUCCESS: strncat_s(message, sizeof(message), "AUDIT_SUCCESS ", _TRUNCATE); loglevel = SYSLOG_NOTICE; *level = SYSLOG_BUILD(SyslogFacility, loglevel); break; case EVENTLOG_AUDIT_FAILURE: strncat_s(message, sizeof(message), "AUDIT_FAILURE ", _TRUNCATE); loglevel = SYSLOG_ERR; *level = SYSLOG_BUILD(SyslogFacility, loglevel); break; /* Everything else */ case EVENTLOG_SUCCESS: default: loglevel = SYSLOG_NOTICE; *level = SYSLOG_BUILD(SyslogFacility, loglevel); break; } /* If event is not being ignored, make sure it is severe enough to be logged */ if (SyslogLogLevel != 0) if (SyslogLogLevel < loglevel-1) return NULL; /* Add hostname for RFC compliance (RFC 3164) */ /* if -a then use the fqdn bound to our IP address. If none, use the IP address */ if (ProgramUseIPAddress == TRUE) { strcpy_s(hostname, HOSTNAME_SZ, ProgramHostName); } else { if (ExpandEnvironmentStrings("%COMPUTERNAME%", hostname, COUNT_OF(hostname)) == 0) { strcpy_s(hostname, COUNT_OF(hostname), "HOSTNAME_ERR"); Log(LOG_ERROR|LOG_SYS, "Cannot expand %COMPUTERNAME%"); } } /* Query and Add timestamp from EventLog, add hostname, */ /* and finally the message to the string */ _snprintf_s(tstamped_message, sizeof(tstamped_message), _TRUNCATE, "%s %s %s", TimeToString(event->TimeGenerated), hostname, message ); /* Return formatted message */ return tstamped_message; }
/* Process a given event */ DWORD ProcessEvent(EVT_HANDLE hEvent) { EVT_HANDLE hProviderMetadata = NULL; PEVT_VARIANT eventInfo = NULL; LPWSTR pwsMessage = NULL; LPWSTR pwszPublisherName = NULL; ULONGLONG eventTime; ULONGLONG keyword; DWORD status = ERROR_SUCCESS; int event_id = 0; int winlevel = 0; int level = 0; WCHAR source[SOURCE_SZ]; WCHAR hostname[HOSTNAME_SZ]; WCHAR * formatted_string = NULL; WCHAR * tstamp = NULL; WCHAR * index = NULL; WCHAR defmsg[ERRMSG_SZ]; WCHAR tstamped_message[SYSLOG_DEF_SZ]; /* Get and store the publishers new Windows Events name */ eventInfo = GetEventInfo(hEvent); if (eventInfo) { pwszPublisherName = (LPWSTR)eventInfo[0].StringVal; } else { return ERR_CONTINUE; } eventTime = eventInfo[1].FileTimeVal; event_id = eventInfo[2].UInt16Val; /* Check for the "Microsoft-Windows-" prefix in the publisher name */ /* and remove it if found. Saves 18 characters in the message */ if(wcsncmp(pwszPublisherName, L"Microsoft-Windows-", 18) == 0) wcsncpy_s(source, COUNT_OF(source), pwszPublisherName+18, _TRUNCATE); else wcsncpy_s(source, COUNT_OF(source), pwszPublisherName, _TRUNCATE); /* Format Event Timestamp */ if ((tstamp = WinEventTimeToString(eventTime)) == NULL) tstamp = L"TIME_ERROR"; /* Add hostname for RFC compliance (RFC 3164) */ if (ProgramUseIPAddress == TRUE) { _snwprintf_s(hostname, HOSTNAME_SZ, _TRUNCATE, L"%S", ProgramHostName); } else { if (ExpandEnvironmentStringsW(L"%COMPUTERNAME%", hostname, COUNT_OF(hostname)) == 0) { wcscpy_s(hostname, COUNT_OF(hostname), L"HOSTNAME_ERR"); Log(LOG_ERROR|LOG_SYS, "Cannot expand %COMPUTERNAME%"); } } /* replace every space in source by underscores */ index = source; while( *index ) { if( *index == L' ' ) { *index = L'_'; } index++; } /* Add Timestamp and hostname then format source & event ID for consistency with Event Viewer */ if(SyslogIncludeTag) { _snwprintf_s(tstamped_message, COUNT_OF(tstamped_message), _TRUNCATE, L"%s %s %S: %s: %i: ", tstamp, hostname, SyslogTag, source, event_id ); } else { _snwprintf_s(tstamped_message, COUNT_OF(tstamped_message), _TRUNCATE, L"%s %s %s: %i: ", tstamp, hostname, source, event_id ); } /* Get the handle to the provider's metadata that contains the message strings. */ hProviderMetadata = EvtOpenPublisherMetadata(NULL, pwszPublisherName, NULL, 0, 0); if (NULL == hProviderMetadata) { if (LogInteractive) Log(LOG_ERROR|LOG_SYS, "OpenPublisherMetadata failed for Publisher: \"%S\"", source); return ERR_CONTINUE; } /* Get the message string from the event */ pwsMessage = GetMessageString(hProviderMetadata, hEvent); if (pwsMessage == NULL) { Log(LOG_ERROR|LOG_SYS, "Error getting message string for event DETAILS: Publisher: %S EventID: %i", source, event_id); return ERR_CONTINUE; } /* Get string and strip whitespace */ formatted_string = CollapseExpandMessageW(pwsMessage); /* Create a default message if resources or formatting didn't work */ if (formatted_string == NULL) { if(SyslogIncludeTag) { _snwprintf_s(defmsg, COUNT_OF(defmsg), _TRUNCATE, L"%S: (Facility: %u, Status: %s)", SyslogTag, HRESULT_FACILITY(event_id), FAILED(event_id) ? L"Failure" : L"Success" ); } else { _snwprintf_s(defmsg, COUNT_OF(defmsg), _TRUNCATE, L"(Facility: %u, Status: %s)", HRESULT_FACILITY(event_id), FAILED(event_id) ? L"Failure" : L"Success" ); } formatted_string = defmsg; } /* Get Event Error Level. In the case of Security Events, * set Failures to Error instead of notice using the * keyword attribute */ keyword = (EvtVarTypeNull == eventInfo[4].Type) ? 0 : eventInfo[4].UInt64Val; if ((keyword & WINEVENT_KEYWORD_AUDIT_FAILURE) != 0) { // Add AUDIT_FAILURE message for better parsing wcsncat_s(tstamped_message, COUNT_OF(tstamped_message), L"AUDIT_FAILURE ", _TRUNCATE); winlevel = WINEVENT_ERROR_LEVEL; } else winlevel = (int)eventInfo[3].ByteVal; /* Select syslog level */ switch (winlevel) { case WINEVENT_CRITICAL_LEVEL: level = SYSLOG_BUILD(SyslogFacility, SYSLOG_CRIT); break; case WINEVENT_ERROR_LEVEL: level = SYSLOG_BUILD(SyslogFacility, SYSLOG_ERR); break; case WINEVENT_WARNING_LEVEL: level = SYSLOG_BUILD(SyslogFacility, SYSLOG_WARNING); break; case WINEVENT_INFORMATION_LEVEL: level = SYSLOG_BUILD(SyslogFacility, SYSLOG_NOTICE); break; case WINEVENT_AUDIT_LEVEL: wcsncat_s(tstamped_message, COUNT_OF(tstamped_message), L"AUDIT_SUCCESS ", _TRUNCATE); level = SYSLOG_BUILD(SyslogFacility, SYSLOG_NOTICE); break; case WINEVENT_VERBOSE_LEVEL: level = SYSLOG_BUILD(SyslogFacility, SYSLOG_DEBUG); break; /* Everything else */ default: level = SYSLOG_BUILD(SyslogFacility, SYSLOG_NOTICE); break; } /* Combine the message strings */ wcsncat_s(tstamped_message, COUNT_OF(tstamped_message), formatted_string, _TRUNCATE); /* Send the event to the Syslog Server */ /* Making sure it is severe enough to be logged */ if (SyslogLogLevel == 0 || (SyslogLogLevel >= (DWORD)winlevel && winlevel > 0)) if (SyslogSendW(tstamped_message, level)) status = ERR_FAIL; /* Cleanup memory and open handles */ if(pwsMessage) free(pwsMessage); if(eventInfo) free(eventInfo); if (hProviderMetadata) EvtClose(hProviderMetadata); if (hEvent) EvtClose(hEvent); return status; }