/* ** Zabbix ** Copyright (C) 2001-2023 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ #include "process_eventslog6.h" #include "severity_constants.h" #include "../metrics.h" #include "../logfiles/logfiles.h" #include "zbxregexp.h" #include "zbxstr.h" #include "zbx_item_constants.h" #include "zbxalgo.h" #include "zbxlog.h" #include "winmeta.h" #include /* ConvertSidToStringSid */ /* winevt.h contents START */ typedef struct _EVT_VARIANT { union { BOOL BooleanVal; INT8 SByteVal; INT16 Int16Val; INT32 Int32Val; INT64 Int64Val; UINT8 ByteVal; UINT16 UInt16Val; UINT32 UInt32Val; UINT64 UInt64Val; float SingleVal; double DoubleVal; ULONGLONG FileTimeVal; SYSTEMTIME *SysTimeVal; GUID *GuidVal; const wchar_t *StringVal; const char *AnsiStringVal; PBYTE BinaryVal; PSID SidVal; size_t SizeTVal; /* array fields */ BOOL *BooleanArr; INT8 *SByteArr; INT16 *Int16Arr; INT32 *Int32Arr; INT64 *Int64Arr; UINT8 *ByteArr; UINT16 *UInt16Arr; UINT32 *UInt32Arr; UINT64 *UInt64Arr; float *SingleArr; double *DoubleArr; FILETIME *FileTimeArr; SYSTEMTIME *SysTimeArr; GUID *GuidArr; wchar_t **StringArr; char **AnsiStringArr; PSID *SidArr; size_t *SizeTArr; /* internal fields */ EVT_HANDLE EvtHandleVal; const wchar_t *XmlVal; const wchar_t **XmlValArr; }; DWORD Count; /* number of elements (not length) in bytes */ DWORD Type; } EVT_VARIANT, *PEVT_VARIANT; typedef enum _EVT_RENDER_CONTEXT_FLAGS { EvtRenderContextValues = 0, /* render specific properties */ EvtRenderContextSystem, /* render all system properties (System) */ EvtRenderContextUser /* render all user properties (User/EventData) */ } EVT_RENDER_CONTEXT_FLAGS; typedef enum _EVT_QUERY_FLAGS { EvtQueryChannelPath = 0x1, EvtQueryFilePath = 0x2, EvtQueryForwardDirection = 0x100, EvtQueryReverseDirection = 0x200, EvtQueryTolerateQueryErrors = 0x1000 } EVT_QUERY_FLAGS; typedef enum _EVT_RENDER_FLAGS { EvtRenderEventValues = 0, /* variants */ EvtRenderEventXml, /* XML */ EvtRenderBookmark /* bookmark */ } EVT_RENDER_FLAGS; typedef enum _EVT_FORMAT_MESSAGE_FLAGS { EvtFormatMessageEvent = 1, EvtFormatMessageLevel, EvtFormatMessageTask, EvtFormatMessageOpcode, EvtFormatMessageKeyword, EvtFormatMessageChannel, EvtFormatMessageProvider, EvtFormatMessageId, EvtFormatMessageXml, } EVT_FORMAT_MESSAGE_FLAGS; typedef enum _EVT_VARIANT_TYPE { EvtVarTypeNull = 0, EvtVarTypeString = 1, EvtVarTypeAnsiString = 2, EvtVarTypeSByte = 3, EvtVarTypeByte = 4, EvtVarTypeInt16 = 5, EvtVarTypeUInt16 = 6, EvtVarTypeInt32 = 7, EvtVarTypeUInt32 = 8, EvtVarTypeInt64 = 9, EvtVarTypeUInt64 = 10, EvtVarTypeSingle = 11, EvtVarTypeDouble = 12, EvtVarTypeBoolean = 13, EvtVarTypeBinary = 14, EvtVarTypeGuid = 15, EvtVarTypeSizeT = 16, EvtVarTypeFileTime = 17, EvtVarTypeSysTime = 18, EvtVarTypeSid = 19, EvtVarTypeHexInt32 = 20, EvtVarTypeHexInt64 = 21, /* these types used internally */ EvtVarTypeEvtHandle = 32, EvtVarTypeEvtXml = 35 } EVT_VARIANT_TYPE; EVT_HANDLE WINAPI EvtCreateRenderContext(DWORD ValuePathsCount, const wchar_t **ValuePaths, DWORD Flags); EVT_HANDLE WINAPI EvtQuery(EVT_HANDLE Session, const wchar_t *Path, const wchar_t *Query, DWORD Flags); EVT_HANDLE WINAPI EvtOpenPublisherMetadata(EVT_HANDLE Session, const wchar_t *PublisherId, const wchar_t *LogFilePath, LCID Locale, DWORD Flags); BOOL WINAPI EvtRender(EVT_HANDLE Context, EVT_HANDLE Fragment, DWORD Flags, DWORD BufferSize, PVOID Buffer, PDWORD BufferUsed, PDWORD PropertyCount); BOOL WINAPI EvtNext(EVT_HANDLE ResultSet, DWORD EventsSize, PEVT_HANDLE Events, DWORD Timeout, DWORD Flags, __out PDWORD Returned); BOOL WINAPI EvtClose(EVT_HANDLE Object); BOOL WINAPI EvtFormatMessage(EVT_HANDLE PublisherMetadata, EVT_HANDLE Event, DWORD MessageId, DWORD ValueCount, PEVT_VARIANT Values, DWORD Flags, DWORD BufferSize, wchar_t *Buffer, PDWORD BufferUsed); /* winevt.h contents END */ #define VAR_PROVIDER_NAME(p) (p[0].StringVal) #define VAR_SOURCE_NAME(p) (p[1].StringVal) #define VAR_RECORD_NUMBER(p) (p[2].UInt64Val) #define VAR_EVENT_ID(p) (p[3].UInt16Val) #define VAR_LEVEL(p) (p[4].ByteVal) #define VAR_KEYWORDS(p) (p[5].UInt64Val) #define VAR_TIME_CREATED(p) (p[6].FileTimeVal) #define VAR_EVENT_DATA_STRING(p) (p[7].StringVal) #define VAR_EVENT_DATA_STRING_ARRAY(p, i) (p[7].StringArr[i]) #define VAR_EVENT_DATA_TYPE(p) (p[7].Type) #define VAR_EVENT_DATA_COUNT(p) (p[7].Count) ZBX_VECTOR_IMPL(prov_meta, provider_meta_t) /* gets handles of Event Log */ static int zbx_get_handle_eventlog6(const wchar_t *wsource, zbx_uint64_t *lastlogsize, EVT_HANDLE *query, char **error) { wchar_t *event_query = NULL; char *tmp_str = NULL; int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s(), previous lastlogsize:" ZBX_FS_UI64, __func__, *lastlogsize); /* start building the query */ tmp_str = zbx_dsprintf(NULL, "Event/System[EventRecordID>" ZBX_FS_UI64 "]", *lastlogsize); event_query = zbx_utf8_to_unicode(tmp_str); /* create massive query for an event on a local computer*/ *query = EvtQuery(NULL, wsource, event_query, EvtQueryChannelPath); if (NULL == *query) { DWORD status; if (ERROR_EVT_CHANNEL_NOT_FOUND == (status = GetLastError())) *error = zbx_dsprintf(*error, "EvtQuery channel missed:%s", zbx_strerror_from_system(status)); else *error = zbx_dsprintf(*error, "EvtQuery failed:%s", zbx_strerror_from_system(status)); goto out; } ret = SUCCEED; out: zbx_free(tmp_str); zbx_free(event_query); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); return ret; } static int get_eventlog6_id(EVT_HANDLE *event_query, EVT_HANDLE *render_context, zbx_uint64_t *id, char **error) { int ret = FAIL; DWORD size_required_next = 0, size_required = 0, size = 0, status = 0, bookmarkedCount = 0; EVT_VARIANT *renderedContent = NULL; EVT_HANDLE event_bookmark = NULL; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); if (TRUE != EvtNext(*event_query, 1, &event_bookmark, INFINITE, 0, &size_required_next)) { /* no data in eventlog */ zabbix_log(LOG_LEVEL_DEBUG, "%s() EvtNext failed:%s", __func__, zbx_strerror_from_system(GetLastError())); *id = 0; ret = SUCCEED; goto out; } /* obtain the information from selected events */ if (TRUE != EvtRender(*render_context, event_bookmark, EvtRenderEventValues, size, renderedContent, &size_required, &bookmarkedCount)) { /* information exceeds the allocated space */ if (ERROR_INSUFFICIENT_BUFFER != (status = GetLastError())) { *error = zbx_dsprintf(*error, "EvtRender failed:%s", zbx_strerror_from_system(status)); goto out; } size = size_required; renderedContent = (EVT_VARIANT*)zbx_malloc(NULL, size); if (TRUE != EvtRender(*render_context, event_bookmark, EvtRenderEventValues, size, renderedContent, &size_required, &bookmarkedCount)) { *error = zbx_dsprintf(*error, "EvtRender failed:%s", zbx_strerror_from_system(GetLastError())); goto out; } } *id = VAR_RECORD_NUMBER(renderedContent); ret = SUCCEED; out: if (NULL != event_bookmark) EvtClose(event_bookmark); zbx_free(renderedContent); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s id:" ZBX_FS_UI64, __func__, zbx_result_string(ret), id); return ret; } /* opens Event Log using API 6 and returns number of records */ static int zbx_open_eventlog6(const wchar_t *wsource, zbx_uint64_t *lastlogsize, EVT_HANDLE *render_context, zbx_uint64_t *FirstID, zbx_uint64_t *LastID, char **error) { const wchar_t *RENDER_ITEMS[] = { L"/Event/System/Provider/@Name", L"/Event/System/Provider/@EventSourceName", L"/Event/System/EventRecordID", L"/Event/System/EventID", L"/Event/System/Level", L"/Event/System/Keywords", L"/Event/System/TimeCreated/@SystemTime", L"/Event/EventData/Data" }; #define RENDER_ITEMS_COUNT (sizeof(RENDER_ITEMS) / sizeof(const wchar_t *)) EVT_HANDLE tmp_first_event_query = NULL, tmp_last_event_query = NULL; DWORD status = 0; int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s() lastlogsize:" ZBX_FS_UI64, __func__, *lastlogsize); *FirstID = 0; *LastID = 0; /* get the number of the oldest record in the log */ /* "EvtGetLogInfo()" does not work properly with "EvtLogOldestRecordNumber" */ /* we have to get it from the first EventRecordID */ /* create the system render */ if (NULL == (*render_context = EvtCreateRenderContext(RENDER_ITEMS_COUNT, RENDER_ITEMS, EvtRenderContextValues))) { *error = zbx_dsprintf(*error, "EvtCreateRenderContext failed:%s", zbx_strerror_from_system(GetLastError())); goto out; } /* get all eventlog */ if (NULL == (tmp_first_event_query = EvtQuery(NULL, wsource, NULL, EvtQueryChannelPath))) { if (ERROR_EVT_CHANNEL_NOT_FOUND == (status = GetLastError())) *error = zbx_dsprintf(*error, "EvtQuery channel missed:%s", zbx_strerror_from_system(status)); else *error = zbx_dsprintf(*error, "EvtQuery failed:%s", zbx_strerror_from_system(status)); goto out; } if (SUCCEED != get_eventlog6_id(&tmp_first_event_query, render_context, FirstID, error)) goto out; if (0 == *FirstID) { /* no data in eventlog */ zabbix_log(LOG_LEVEL_DEBUG, "%s() first EvtNext failed", __func__); *FirstID = 1; *LastID = 1; *lastlogsize = 0; ret = SUCCEED; goto out; } if (NULL == (tmp_last_event_query = EvtQuery(NULL, wsource, NULL, EvtQueryChannelPath | EvtQueryReverseDirection))) { if (ERROR_EVT_CHANNEL_NOT_FOUND == (status = GetLastError())) *error = zbx_dsprintf(*error, "EvtQuery channel missed:%s", zbx_strerror_from_system(status)); else *error = zbx_dsprintf(*error, "EvtQuery failed:%s", zbx_strerror_from_system(status)); goto out; } if (SUCCEED != get_eventlog6_id(&tmp_last_event_query, render_context, LastID, error) || 0 == *LastID) { /* no data in eventlog */ zabbix_log(LOG_LEVEL_DEBUG, "%s() last EvtNext failed", __func__); *LastID = 1; } else *LastID += 1; /* we should read the last record */ if (*lastlogsize >= *LastID) { *lastlogsize = *FirstID - 1; zabbix_log(LOG_LEVEL_WARNING, "lastlogsize is too big. It is set to:" ZBX_FS_UI64, *lastlogsize); } ret = SUCCEED; out: if (NULL != tmp_first_event_query) EvtClose(tmp_first_event_query); if (NULL != tmp_last_event_query) EvtClose(tmp_last_event_query); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s FirstID:" ZBX_FS_UI64 " LastID:" ZBX_FS_UI64, __func__, zbx_result_string(ret), *FirstID, *LastID); return ret; #undef RENDER_ITEMS_COUNT } /* finalize eventlog6 and free the handles */ int finalize_eventlog6(EVT_HANDLE *render_context, EVT_HANDLE *query) { int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); if (NULL != *query) { EvtClose(*query); *query = NULL; } if (NULL != *render_context) { EvtClose(*render_context); *render_context = NULL; } ret = SUCCEED; zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); return ret; } /* initializes Event Logs with Windows API version 6 */ int initialize_eventlog6(const char *source, zbx_uint64_t *lastlogsize, zbx_uint64_t *FirstID, zbx_uint64_t *LastID, EVT_HANDLE *render_context, EVT_HANDLE *query, char **error) { wchar_t *wsource = NULL; int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s() source:'%s' previous lastlogsize:" ZBX_FS_UI64, __func__, source, *lastlogsize); if (NULL == source || '\0' == *source) { *error = zbx_dsprintf(*error, "cannot open eventlog with empty name."); goto out; } wsource = zbx_utf8_to_unicode(source); if (SUCCEED != zbx_open_eventlog6(wsource, lastlogsize, render_context, FirstID, LastID, error)) { zabbix_log(LOG_LEVEL_ERR, "cannot open eventlog '%s'", source); goto out; } if (SUCCEED != zbx_get_handle_eventlog6(wsource, lastlogsize, query, error)) { zabbix_log(LOG_LEVEL_ERR, "cannot get eventlog handle '%s'", source); goto out; } ret = SUCCEED; out: zbx_free(wsource); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); return ret; } static EVT_HANDLE open_publisher_metadata(const wchar_t *pname, const char* utf8_name) { EVT_HANDLE handle; if (NULL == (handle = EvtOpenPublisherMetadata(NULL, pname, NULL, 0, 0))) { zabbix_log(LOG_LEVEL_DEBUG, "provider '%s' could not be opened: %s", utf8_name, zbx_strerror_from_system(GetLastError())); } return handle; } static int get_publisher_metadata(zbx_vector_prov_meta_t *prov_meta, const wchar_t *pname, int force_fetch, EVT_HANDLE *dest) { char *tmp_pname = zbx_unicode_to_utf8(pname); int index, ret = FAIL; provider_meta_t p_meta; p_meta.name = tmp_pname; if (FAIL == (index = zbx_vector_prov_meta_bsearch((const zbx_vector_prov_meta_t *)prov_meta, p_meta, ZBX_DEFAULT_STR_COMPARE_FUNC))) { if (NULL == (*dest = open_publisher_metadata(pname, tmp_pname))) goto out; p_meta.name = zbx_strdup(NULL, tmp_pname); p_meta.handle = *dest; index = zbx_vector_prov_meta_nearestindex(prov_meta, p_meta, ZBX_DEFAULT_STR_COMPARE_FUNC); zbx_vector_prov_meta_insert(prov_meta, p_meta, index); ret = SUCCEED; } else { if (1 == force_fetch) { if (NULL == (*dest = open_publisher_metadata(pname, tmp_pname))) goto out; prov_meta->values[index].handle = *dest; } else *dest = prov_meta->values[index].handle; ret = SUCCEED; } out: zbx_free(tmp_pname); return ret; } /* expands string message from specific event handler */ static char *expand_message6(const wchar_t *pname, EVT_HANDLE event, zbx_vector_prov_meta_t *prov_meta) { wchar_t *pmessage = NULL; EVT_HANDLE provider = NULL; DWORD require = 0; char *out_message = NULL; int refetch_done = 0; DWORD error; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); if (FAIL == get_publisher_metadata(prov_meta, pname, 0, &provider)) goto err; while (1) { if (TRUE != EvtFormatMessage(provider, event, 0, 0, NULL, EvtFormatMessageEvent, 0, NULL, &require)) { int last_err = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER == last_err) { error = ERROR_SUCCESS; pmessage = zbx_malloc(pmessage, sizeof(WCHAR) * require); if (TRUE != EvtFormatMessage(provider, event, 0, 0, NULL, EvtFormatMessageEvent, require, pmessage, &require)) { error = GetLastError(); } if (ERROR_SUCCESS == error || ERROR_EVT_UNRESOLVED_VALUE_INSERT == error || ERROR_EVT_UNRESOLVED_PARAMETER_INSERT == error || ERROR_EVT_MAX_INSERTS_REACHED == error) { out_message = zbx_unicode_to_utf8(pmessage); goto out; } else break; } else if (ERROR_INVALID_HANDLE == last_err) { if (1 == refetch_done) break; refetch_done = 1; if (FAIL == get_publisher_metadata(prov_meta, pname, 1, &provider)) break; } else break; } else goto out; } err: zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot format message: %s", __func__, zbx_strerror_from_system(error)); out: zbx_free(pmessage); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, out_message); /* should be freed */ return out_message; } static void replace_sid_to_account(PSID sidVal, char **out_message) { #define MAX_NAME 256 DWORD nlen = MAX_NAME, dlen = MAX_NAME; wchar_t name[MAX_NAME], dom[MAX_NAME], *sid = NULL; int iUse; char userName[MAX_NAME * 4], domName[MAX_NAME * 4], sidName[MAX_NAME * 4], *tmp, buffer[MAX_NAME * 8]; #undef MAX_NAME if (0 == LookupAccountSid(NULL, sidVal, name, &nlen, dom, &dlen, (PSID_NAME_USE)&iUse)) { /* don't replace security ID if no mapping between account names and security IDs was done */ zabbix_log(LOG_LEVEL_DEBUG, "LookupAccountSid failed:%s", zbx_strerror_from_system(GetLastError())); return; } if (0 == nlen) { zabbix_log(LOG_LEVEL_DEBUG, "LookupAccountSid returned empty user name"); return; } if (0 == ConvertSidToStringSid(sidVal, &sid)) { zabbix_log(LOG_LEVEL_DEBUG, "ConvertSidToStringSid failed:%s", zbx_strerror_from_system(GetLastError())); return; } zbx_unicode_to_utf8_static(sid, sidName, sizeof(sidName)); zbx_unicode_to_utf8_static(name, userName, sizeof(userName)); if (0 != dlen) { zbx_unicode_to_utf8_static(dom, domName, sizeof(domName)); zbx_snprintf(buffer, sizeof(buffer), "%s\\%s", domName, userName); } else zbx_strlcpy(buffer, userName, sizeof(buffer)); /* NULL SID */ tmp = *out_message; *out_message = zbx_string_replace(*out_message, sidName, buffer); LocalFree(sid); zbx_free(tmp); } static void replace_sids_to_accounts(EVT_HANDLE event_bookmark, char **out_message) { DWORD status, dwBufferSize = 0, dwBufferUsed = 0, dwPropertyCount = 0, i; PEVT_VARIANT renderedContent = NULL; EVT_HANDLE render_context; if (NULL == (render_context = EvtCreateRenderContext(0, NULL, EvtRenderContextUser))) { zabbix_log(LOG_LEVEL_WARNING, "EvtCreateRenderContext failed:%s", zbx_strerror_from_system(GetLastError())); goto cleanup; } if (TRUE != EvtRender(render_context, event_bookmark, EvtRenderEventValues, dwBufferSize, renderedContent, &dwBufferUsed, &dwPropertyCount)) { if (ERROR_INSUFFICIENT_BUFFER != (status = GetLastError())) { zabbix_log(LOG_LEVEL_WARNING, "EvtRender failed:%s", zbx_strerror_from_system(status)); goto cleanup; } dwBufferSize = dwBufferUsed; renderedContent = (PEVT_VARIANT)zbx_malloc(NULL, dwBufferSize); if (TRUE != EvtRender(render_context, event_bookmark, EvtRenderEventValues, dwBufferSize, renderedContent, &dwBufferUsed, &dwPropertyCount)) { zabbix_log(LOG_LEVEL_WARNING, "EvtRender failed:%s", zbx_strerror_from_system(GetLastError())); goto cleanup; } } for (i = 0; i < dwPropertyCount; i++) { if (EvtVarTypeSid == renderedContent[i].Type) replace_sid_to_account(renderedContent[i].SidVal, out_message); } cleanup: if (NULL != render_context) EvtClose(render_context); zbx_free(renderedContent); } /****************************************************************************** * * * Purpose: parses single Event Log record * * * * Parameters: wsource - [IN] Event Log file name * * render_context - [IN] handle to rendering context * * event_bookmark - [IN/OUT] handle of Event record for parsing * * which - [IN/OUT] position of Event Log record * * ... - [OUT] ELR detail * * prov_meta - [IN/OUT] provider metadata cache * * error - [OUT] error message in case of failure * * * * Return value: SUCCEED or FAIL * * * ******************************************************************************/ static int zbx_parse_eventlog_message6(const wchar_t *wsource, EVT_HANDLE *render_context, EVT_HANDLE *event_bookmark, zbx_uint64_t *which, unsigned short *out_severity, unsigned long *out_timestamp, char **out_provider, char **out_source, char **out_message, unsigned long *out_eventid, zbx_uint64_t *out_keywords, zbx_vector_prov_meta_t *prov_meta, int gather_evt_msg, char **error) { #define EVT_VARIANT_TYPE_ARRAY 128 #define EVT_VARIANT_TYPE_MASK 0x7f EVT_VARIANT* renderedContent = NULL; const wchar_t *pprovider = NULL; char *tmp_str = NULL; DWORD size = 0, bookmarkedCount = 0, require = 0, error_code; const zbx_uint64_t sec_1970 = 116444736000000000, success_audit = 0x20000000000000, failure_audit = 0x10000000000000; int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s() EventRecordID:" ZBX_FS_UI64, __func__, *which); /* obtain the information from the selected events */ if (TRUE != EvtRender(*render_context, *event_bookmark, EvtRenderEventValues, size, renderedContent, &require, &bookmarkedCount)) { /* information exceeds the space allocated */ if (ERROR_INSUFFICIENT_BUFFER != (error_code = GetLastError())) { *error = zbx_dsprintf(*error, "EvtRender failed: %s", zbx_strerror_from_system(error_code)); goto out; } size = require; renderedContent = (EVT_VARIANT *)zbx_malloc(NULL, size); if (TRUE != EvtRender(*render_context, *event_bookmark, EvtRenderEventValues, size, renderedContent, &require, &bookmarkedCount)) { *error = zbx_dsprintf(*error, "EvtRender failed: %s", zbx_strerror_from_system(GetLastError())); goto out; } } pprovider = VAR_PROVIDER_NAME(renderedContent); *out_provider = zbx_unicode_to_utf8(pprovider); *out_source = NULL; if (NULL != VAR_SOURCE_NAME(renderedContent)) { *out_source = zbx_unicode_to_utf8(VAR_SOURCE_NAME(renderedContent)); } *out_keywords = VAR_KEYWORDS(renderedContent) & (success_audit | failure_audit); *out_severity = VAR_LEVEL(renderedContent); *out_timestamp = (unsigned long)((VAR_TIME_CREATED(renderedContent) - sec_1970) / 10000000); *out_eventid = VAR_EVENT_ID(renderedContent); if (1 == gather_evt_msg) *out_message = expand_message6(pprovider, *event_bookmark, prov_meta); else *out_message = zbx_strdup(NULL, ""); if (NULL != *out_message) replace_sids_to_accounts(*event_bookmark, out_message); tmp_str = zbx_unicode_to_utf8(wsource); if (VAR_RECORD_NUMBER(renderedContent) != *which) { zabbix_log(LOG_LEVEL_DEBUG, "%s() Overwriting expected EventRecordID:" ZBX_FS_UI64 " with the real" " EventRecordID:" ZBX_FS_UI64 " in eventlog '%s'", __func__, *which, VAR_RECORD_NUMBER(renderedContent), tmp_str); *which = VAR_RECORD_NUMBER(renderedContent); } /* some events don't have enough information for making event message */ if (NULL == *out_message) { *out_message = zbx_strdcatf(*out_message, "The description for Event ID:%lu in Source:'%s'" " cannot be found. Either the component that raises this event is not installed" " on your local computer or the installation is corrupted. You can install or repair" " the component on the local computer. If the event originated on another computer," " the display information had to be saved with the event.", *out_eventid, NULL == *out_provider ? "" : *out_provider); if (EvtVarTypeString == (VAR_EVENT_DATA_TYPE(renderedContent) & EVT_VARIANT_TYPE_MASK)) { unsigned int i; char *data = NULL; if (0 != (VAR_EVENT_DATA_TYPE(renderedContent) & EVT_VARIANT_TYPE_ARRAY) && 0 < VAR_EVENT_DATA_COUNT(renderedContent)) { *out_message = zbx_strdcatf(*out_message, " The following information was included" " with the event: "); for (i = 0; i < VAR_EVENT_DATA_COUNT(renderedContent); i++) { if (NULL != VAR_EVENT_DATA_STRING_ARRAY(renderedContent, i)) { if (0 < i) *out_message = zbx_strdcat(*out_message, "; "); data = zbx_unicode_to_utf8(VAR_EVENT_DATA_STRING_ARRAY(renderedContent, i)); *out_message = zbx_strdcatf(*out_message, "%s", data); zbx_free(data); } } } else if (NULL != VAR_EVENT_DATA_STRING(renderedContent)) { data = zbx_unicode_to_utf8(VAR_EVENT_DATA_STRING(renderedContent)); *out_message = zbx_strdcatf(*out_message, "The following information was included" " with the event: %s", data); zbx_free(data); } } } ret = SUCCEED; out: EvtClose(*event_bookmark); *event_bookmark = NULL; zbx_free(tmp_str); zbx_free(renderedContent); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); return ret; #undef EVT_VARIANT_TYPE_ARRAY #undef EVT_VARIANT_TYPE_MASK } /******************************************************************************** * * * Purpose: processes Event Log file in batch * * * * Parameters: addrs - [IN] vector for passing server and port * * where to send data * * agent2_result - [IN] address of buffer where to store * * matching log records (used only in * * Agent2) * * eventlog_name - [IN] * * render_context - [IN] handle to rendering context * * query - [IN] handle to query results * * lastlogsize - [IN] position of last processed record * * FirstID - [IN] first record in Event Log file * * LastID - [IN] last record in Event Log file * * regexps - [IN] set of regexp rules for Event Log test * * pattern - [IN] regular expression or global regular * * expression name (@). * * key_severity - [IN] severity of logged data sources * * key_source - [IN] name of logged data source * * key_logeventid - [IN] application-specific identifier for * * event * * rate - [IN] threshold of records count at time * * process_value_cb - [IN] callback function for sending data to * * server * * config_tls - [IN] * * config_timeout - [IN] * * config_source_ip - [IN] * * config_hostname - [IN] * * config_buffer_send - [IN] * * config_buffer_size - [IN] * * metric - [IN/OUT] parameters for Event Log process * * lastlogsize_sent - [OUT] position of last record sent to * * server * * prov_meta - [IN/OUT] provider metadata cache * * error - [OUT] error message in case of failure * * * * Return value: SUCCEED or FAIL * * * ********************************************************************************/ int process_eventslog6(zbx_vector_addr_ptr_t *addrs, zbx_vector_ptr_t *agent2_result, const char *eventlog_name, EVT_HANDLE *render_context, EVT_HANDLE *query, zbx_uint64_t lastlogsize, zbx_uint64_t FirstID, zbx_uint64_t LastID, zbx_vector_expression_t *regexps, const char *pattern, const char *key_severity, const char *key_source, const char *key_logeventid, int rate, zbx_process_value_func_t process_value_cb, const zbx_config_tls_t *config_tls, int config_timeout, const char *config_source_ip, const char *config_hostname, int config_buffer_send, int config_buffer_size, ZBX_ACTIVE_METRIC *metric, zbx_uint64_t *lastlogsize_sent, zbx_vector_prov_meta_t *prov_meta, char **error) { #define EVT_ARRAY_SIZE 100 #define EVT_LOG_ITEM 0 #define EVT_LOG_COUNT_ITEM 1 const char *str_severity; zbx_uint64_t keywords, i, reading_startpoint = 0; wchar_t *eventlog_name_w = NULL; int s_count = 0, p_count = 0, send_err = SUCCEED, ret = FAIL, match = SUCCEED, evt_item_type; DWORD required_buf_size = 0, error_code = ERROR_SUCCESS; unsigned long evt_timestamp, evt_eventid = 0; char *evt_provider, *evt_source, *evt_message, str_logeventid[8]; unsigned short evt_severity; EVT_HANDLE event_bookmarks[EVT_ARRAY_SIZE]; zabbix_log(LOG_LEVEL_DEBUG, "In %s() source: '%s' previous lastlogsize: " ZBX_FS_UI64 ", FirstID: " ZBX_FS_UI64 ", LastID: " ZBX_FS_UI64, __func__, eventlog_name, lastlogsize, FirstID, LastID); if (0 != (ZBX_METRIC_FLAG_LOG_COUNT & metric->flags)) evt_item_type = EVT_LOG_COUNT_ITEM; else evt_item_type = EVT_LOG_ITEM; /* update counters */ if (1 == metric->skip_old_data) { metric->lastlogsize = lastlogsize = LastID - 1; metric->skip_old_data = 0; zabbix_log(LOG_LEVEL_DEBUG, "skipping existing data: lastlogsize:" ZBX_FS_UI64, lastlogsize); goto finish; } if (NULL == *query) { zabbix_log(LOG_LEVEL_DEBUG, "%s() no EvtQuery handle", __func__); goto out; } if (lastlogsize >= FirstID && lastlogsize < LastID) reading_startpoint = lastlogsize + 1; else reading_startpoint = FirstID; if (reading_startpoint == LastID) /* LastID = FirstID + count */ goto finish; eventlog_name_w = zbx_utf8_to_unicode(eventlog_name); while (ERROR_SUCCESS == error_code) { /* get the entries */ if (TRUE != EvtNext(*query, EVT_ARRAY_SIZE, event_bookmarks, INFINITE, 0, &required_buf_size)) { /* The event reading query had less items than we calculated before. */ /* Either the eventlog was cleaned or our calculations were wrong. */ /* Either way we can safely abort the query by setting NULL value */ /* and returning success, which is interpreted as empty eventlog. */ if (ERROR_NO_MORE_ITEMS == (error_code = GetLastError())) continue; *error = zbx_dsprintf(*error, "EvtNext failed: %s, EventRecordID:" ZBX_FS_UI64, zbx_strerror_from_system(error_code), lastlogsize + 1); goto out; } for (i = 0; i < required_buf_size; i++) { int gather_evt_msg = 1; if (EVT_LOG_COUNT_ITEM == evt_item_type && 1 > strlen(pattern)) gather_evt_msg = 0; lastlogsize += 1; if (SUCCEED != zbx_parse_eventlog_message6(eventlog_name_w, render_context, &event_bookmarks[i], &lastlogsize, &evt_severity, &evt_timestamp, &evt_provider, &evt_source, &evt_message, &evt_eventid, &keywords, prov_meta, gather_evt_msg, error)) { goto out; } switch (evt_severity) { case WINEVENT_LEVEL_LOG_ALWAYS: case WINEVENT_LEVEL_INFO: if (0 != (keywords & WINEVENT_KEYWORD_AUDIT_FAILURE)) { evt_severity = ITEM_LOGTYPE_FAILURE_AUDIT; str_severity = AUDIT_FAILURE; break; } else if (0 != (keywords & WINEVENT_KEYWORD_AUDIT_SUCCESS)) { evt_severity = ITEM_LOGTYPE_SUCCESS_AUDIT; str_severity = AUDIT_SUCCESS; break; } else evt_severity = ITEM_LOGTYPE_INFORMATION; str_severity = INFORMATION_TYPE; break; case WINEVENT_LEVEL_WARNING: evt_severity = ITEM_LOGTYPE_WARNING; str_severity = WARNING_TYPE; break; case WINEVENT_LEVEL_ERROR: evt_severity = ITEM_LOGTYPE_ERROR; str_severity = ERROR_TYPE; break; case WINEVENT_LEVEL_CRITICAL: evt_severity = ITEM_LOGTYPE_CRITICAL; str_severity = CRITICAL_TYPE; break; case WINEVENT_LEVEL_VERBOSE: evt_severity = ITEM_LOGTYPE_VERBOSE; str_severity = VERBOSE_TYPE; break; default: *error = zbx_dsprintf(*error, "Invalid severity detected: '%hu'.", evt_severity); goto out; } zbx_snprintf(str_logeventid, sizeof(str_logeventid), "%lu", evt_eventid); if (0 == p_count) { int ret1 = ZBX_REGEXP_NO_MATCH, ret2 = ZBX_REGEXP_NO_MATCH, ret3 = ZBX_REGEXP_NO_MATCH, ret4 = ZBX_REGEXP_NO_MATCH; if (FAIL == (ret1 = zbx_regexp_match_ex(regexps, evt_message, pattern, ZBX_CASE_SENSITIVE))) { *error = zbx_strdup(*error, "Invalid regular expression in the second parameter."); match = FAIL; } else if (FAIL == (ret2 = zbx_regexp_match_ex(regexps, str_severity, key_severity, ZBX_IGNORE_CASE))) { *error = zbx_strdup(*error, "Invalid regular expression in the third parameter."); match = FAIL; } else if (FAIL == (ret3 = zbx_regexp_match_ex(regexps, evt_provider, key_source, ZBX_IGNORE_CASE))) { *error = zbx_strdup(*error, "Invalid regular expression in the fourth parameter."); match = FAIL; } else if (FAIL == (ret4 = zbx_regexp_match_ex(regexps, str_logeventid, key_logeventid, ZBX_CASE_SENSITIVE))) { *error = zbx_strdup(*error, "Invalid regular expression in the fifth parameter."); match = FAIL; } if (FAIL == match) { zbx_free(evt_source); zbx_free(evt_provider); zbx_free(evt_message); ret = FAIL; break; } else { match = ZBX_REGEXP_MATCH == ret1 && ZBX_REGEXP_MATCH == ret2 && ZBX_REGEXP_MATCH == ret3 && ZBX_REGEXP_MATCH == ret4; } } else { match = ZBX_REGEXP_MATCH == zbx_regexp_match_ex(regexps, evt_message, pattern, ZBX_CASE_SENSITIVE) && ZBX_REGEXP_MATCH == zbx_regexp_match_ex(regexps, str_severity, key_severity, ZBX_IGNORE_CASE) && ZBX_REGEXP_MATCH == zbx_regexp_match_ex(regexps, evt_provider, key_source, ZBX_IGNORE_CASE) && ZBX_REGEXP_MATCH == zbx_regexp_match_ex(regexps, str_logeventid, key_logeventid, ZBX_CASE_SENSITIVE); } if (1 == match) { if (EVT_LOG_ITEM == evt_item_type) { send_err = process_value_cb(addrs, agent2_result, config_hostname, metric->key_orig, evt_message, ITEM_STATE_NORMAL, &lastlogsize, NULL, &evt_timestamp, evt_provider, &evt_severity, &evt_eventid, metric->flags | ZBX_METRIC_FLAG_PERSISTENT, config_tls, config_timeout, config_source_ip, config_buffer_send, config_buffer_size); if (SUCCEED == send_err) { *lastlogsize_sent = lastlogsize; s_count++; } } else s_count++; } p_count++; zbx_free(evt_source); zbx_free(evt_provider); zbx_free(evt_message); if (EVT_LOG_ITEM == evt_item_type) { if (SUCCEED == send_err) { metric->lastlogsize = lastlogsize; } else { /* buffer is full, stop processing active checks */ /* till the buffer is cleared */ break; } } /* do not flood Zabbix server if file grows too fast */ if (s_count >= (rate * metric->refresh)) break; /* do not flood local system if file grows too fast */ if (p_count >= (4 * rate * metric->refresh)) break; } if (i < required_buf_size) error_code = ERROR_NO_MORE_ITEMS; } finish: ret = SUCCEED; if (EVT_LOG_COUNT_ITEM == evt_item_type) { char buf[ZBX_MAX_UINT64_LEN]; zbx_snprintf(buf, sizeof(buf), "%d", s_count); send_err = process_value_cb(addrs, agent2_result, config_hostname, metric->key_orig, buf, ITEM_STATE_NORMAL, &lastlogsize, NULL, NULL, NULL, NULL, NULL, metric->flags | ZBX_METRIC_FLAG_PERSISTENT, config_tls, config_timeout, config_source_ip, config_buffer_send, config_buffer_size); if (SUCCEED == send_err) { *lastlogsize_sent = lastlogsize; metric->lastlogsize = lastlogsize; } } out: for (i = 0; i < required_buf_size; i++) { if (NULL != event_bookmarks[i]) EvtClose(event_bookmarks[i]); } zbx_free(eventlog_name_w); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s last eventid:%lu", __func__, zbx_result_string(ret), evt_eventid); return ret; #undef EVT_ARRAY_SIZE #undef EVT_LOG_COUNT_ITEM #undef EVT_LOG_ITEM }