/* get handles of eventlog */ static int zbx_get_handle_eventlog6(const wchar_t *wsource, zbx_uint64_t *lastlogsize, EVT_HANDLE *query) { const char *__function_name = "zbx_get_handle_eventlog6"; wchar_t *event_query = NULL; DWORD status = 0; char *tmp_str = NULL; int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s(), previous lastlogsize:" ZBX_FS_UI64, __function_name, *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) { if (ERROR_EVT_CHANNEL_NOT_FOUND == (status = GetLastError())) zabbix_log(LOG_LEVEL_WARNING, "EvtQuery channel missed:%s", strerror_from_system(status)); else zabbix_log(LOG_LEVEL_WARNING, "EvtQuery failed:%s", 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", __function_name, zbx_result_string(ret)); return ret; }
/** * @brief Get the list of events. */ void EventLogReader::ReadEvents() { DWORD status = ERROR_SUCCESS; std::wstring buf = base::string_to_wstring(_query); EVT_HANDLE results = EvtQuery(nullptr, nullptr, buf.c_str(), EvtQueryChannelPath | EvtQueryTolerateQueryErrors); if (results == nullptr) return; if (!EvtSeek(results, _position, nullptr, 0, EvtSeekRelativeToFirst)) return; if (PrintQueryStatuses(results) == ERROR_SUCCESS) PrintResults(results); if (results) EvtClose(results); }
/**** * ParseEventLogInternal * * DESC: * Gets the most recent event log record * * ARGS: * server - IP or host to connect to * domain - domain within the host (empty string for none) * username - username within the domain * password - password for above user * logName - event log to open (default to "Application" if NULL) * query - XPath query to retrieve (see remarks) * outputFormat - set to 0 (JSON) otherwise XML * debug - set to 0 (none) 1 (basic) or 2 (verbose) * mode - mode to run the parser (see remarks) * * REMARKS: * XPath: * * The Windows Event log is structurally an XML document. You * may therefore use XPath queries to retrieve the information * you want. Pre-defined XPath queries have been built into the * supplementary Perl module. However, you are free to modify * that module to include newer queries, based on your requirements * * mode: * * Can be set to either MODE_FETCH_LAST_RECORD or MODE_DEFAULT. The * former will simply return the Event Log Record ID of the topmost * (i.e. the latest) event record. The latter will do the actual * processing of parsing an event log record to the screen. * * Note: As per previous discussions, output format is forced as * JSON here. To re-allow XML, simply replace OUTPUT_FORMAT_JSON * with outputFormat, in the line of code, below */ DWORD64 ParseEventLogInternal(LPWSTR server, LPWSTR domain, LPWSTR username, LPWSTR password, LPWSTR logName, LPWSTR query, INT outputFormat, INT debug, INT mode) { bool getLastRecord = false; DWORD64 result = 0; if( debug > DEBUG_L1 ) { wprintf(L"[ParseEventLogInternal]: Attempting to connect to '%s' on domain '%s' using %s:%s...\n", server, domain, username, password); } // If no domain was supplied if( wcslen(domain) == 0 ) { // Official MSDN specs request NULL instead of an empty string domain = NULL; if( debug >= DEBUG_L1 ) { wprintf(L"[ParseEventLogInternal]: Empty domain supplied. Default to NULL\n"); } } // If a blank query was supplied, assume no query (NULL) if( lstrlen(query) == 0 ) query = NULL; // If the supplied query is our special token that retrieves the last record if( lstrcmpW( query, L"LAST_RECORD") == 0 ) { if( debug >= DEBUG_L1 ) { wprintf(L"[ParseEventLogInternal]: Mode is last record fetch\n"); } // Flag the processing routine to only fetch the lastest record getLastRecord = true; // Force an empty query so that the last record is not affected by query filters // An empty query means it will get ALL records, in which case we are guaranteed // the latest record (i.e. the record ID we want) is the first to be retrieved query = NULL; } else { if( debug >= DEBUG_L1 ) { if( query == NULL ) { wprintf(L"[ParseEventLogInternal]: (no query specified)\n"); } else { wprintf(L"[ParseEventLogInternal]: Using query: %s\n", query); } } } // Create a remote context to the external server EVT_HANDLE hRemote = CreateRemoteSession(server, domain, username, password); if (hRemote != NULL) { // NOTE: Reaching here does not mean the connection succeeded. It merely // means that we successfully created the remote context if( debug >= DEBUG_L1 ) { wprintf(L"[ParseEventLogInternal]: Attempting to query the EventLog...\n\n", hRemote); } // Attempt to query event log in reverse chronological order (newest to oldest) EVT_HANDLE hResults = EvtQuery( hRemote, logName, query, EvtQueryChannelPath | EvtQueryReverseDirection); // If the query was successful if (hResults != NULL) { // Process the first event found DumpEventInfo(hRemote, hResults, outputFormat, getLastRecord ? MODE_FETCH_LAST_RECORD : 0, debug); // Process subsequent events result = ProcessResults(hRemote, hResults, outputFormat, getLastRecord ? MODE_FETCH_LAST_RECORD : 0, debug); } else { // Query was not successful. Get the error code DWORD dwError = GetLastError(); if (dwError == ERROR_EVT_CHANNEL_NOT_FOUND) { fwprintf(stderr, L"[Error][ParseEventLog]: Could not open the '%s' log on this machine.\n", logName); } else if (dwError == ERROR_EVT_INVALID_QUERY) { // You can call the EvtGetExtendedStatus function to try to get // additional information as to what is wrong with the query. fwprintf(stderr, L"[Error][ParseEventLog]: The specified search query is not valid.\n"); } else { fwprintf(stderr, L"[Error][ParseEventLog]: Could not read event logs due to the following Windows error: %lu.\n", dwError); } } // Close the handle to the query we opened EvtClose(hRemote); } else { fwprintf(stderr, L"[Error][ParseEventLog]: Failed to connect to remote computer. Error code is %d.\n", GetLastError()); } return result; }
ULONG QueryEvents ( __in PCWSTR Channel, __in PCWSTR XPath ) /*++ Routine Description: This function queries events from the given channel and prints their description to the standard output. Arguments: Channel - Supplies the name of the channel whose events will be displayed. XPath - Supplies the XPath expression to filter events with. Return Value: Win32 error code indicating if querying was successful. --*/ { PWSTR Buffer; ULONG BufferSize; ULONG BufferSizeNeeded; ULONG Count; EVT_HANDLE Event; EVT_HANDLE Query; ULONG Status; // // Create the query. // Query = EvtQuery(NULL, Channel, XPath, EvtQueryChannelPath); if (Query == NULL) { return GetLastError(); } // // Read each event and render it as XML. // Buffer = NULL; BufferSize = 0; BufferSizeNeeded = 0; while (EvtNext(Query, 1, &Event, INFINITE, 0, &Count) != FALSE) { do { if (BufferSizeNeeded > BufferSize) { free(Buffer); BufferSize = BufferSizeNeeded; Buffer = malloc(BufferSize); if (Buffer == NULL) { Status = ERROR_OUTOFMEMORY; BufferSize = 0; break; } } if (EvtRender(NULL, Event, EvtRenderEventXml, BufferSize, Buffer, &BufferSizeNeeded, &Count) != FALSE) { Status = ERROR_SUCCESS; } else { Status = GetLastError(); } } while (Status == ERROR_INSUFFICIENT_BUFFER); // // Display either the event xml or an error message. // if (Status == ERROR_SUCCESS) { wprintf(L"%s\n", Buffer); } else { wprintf(L"Error rendering event.\n"); } EvtClose(Event); } // // When EvtNextChannelPath returns ERROR_NO_MORE_ITEMS, we have actually // iterated through all matching events and thus succeeded. // Status = GetLastError(); if (Status == ERROR_NO_MORE_ITEMS) { Status = ERROR_SUCCESS; } // // Free resources. // EvtClose(Query); free(Buffer); return Status; }
/* open eventlog using API 6 and return the 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) { const char *__function_name = "zbx_open_eventlog6"; EVT_HANDLE log = NULL; EVT_VARIANT var; EVT_HANDLE tmp_all_event_query = NULL; EVT_HANDLE event_bookmark = NULL; EVT_VARIANT* renderedContent = NULL; DWORD status = 0; DWORD size_required = 0; DWORD size = DEFAULT_EVENT_CONTENT_SIZE; DWORD bookmarkedCount = 0; zbx_uint64_t numIDs = 0; char *tmp_str = NULL; int ret = FAIL; *FirstID = 0; *LastID = 0; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); /* try to open the desired log */ if (NULL == (log = EvtOpenLog(NULL, wsource, EvtOpenChannelPath))) { tmp_str = zbx_unicode_to_utf8(wsource); zabbix_log(LOG_LEVEL_WARNING, "cannot open eventlog '%s':%s", tmp_str, strerror_from_system(GetLastError())); goto out; } /* obtain the number of records in the log */ if (TRUE != EvtGetLogInfo(log, EvtLogNumberOfLogRecords, sizeof(var), &var, &size_required)) { zabbix_log(LOG_LEVEL_WARNING, "EvtGetLogInfo failed:%s", strerror_from_system(GetLastError())); goto out; } numIDs = var.UInt64Val; /* 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))) { zabbix_log(LOG_LEVEL_WARNING, "EvtCreateRenderContext failed:%s", strerror_from_system(GetLastError())); goto out; } /* get all eventlog */ tmp_all_event_query = EvtQuery(NULL, wsource, NULL, EvtQueryChannelPath); if (NULL == tmp_all_event_query) { if (ERROR_EVT_CHANNEL_NOT_FOUND == (status = GetLastError())) zabbix_log(LOG_LEVEL_WARNING, "EvtQuery channel missed:%s", strerror_from_system(status)); else zabbix_log(LOG_LEVEL_WARNING, "EvtQuery failed:%s", strerror_from_system(status)); goto out; } /* get the entries and allocate the required space */ renderedContent = zbx_malloc(renderedContent, size); if (TRUE != EvtNext(tmp_all_event_query, 1, &event_bookmark, INFINITE, 0, &size_required)) { /* no data in eventlog */ zabbix_log(LOG_LEVEL_DEBUG, "first EvtNext failed:%s", strerror_from_system(GetLastError())); *FirstID = 1; *LastID = 1; numIDs = 0; *lastlogsize = 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 != GetLastError()) { zabbix_log(LOG_LEVEL_WARNING, "EvtRender failed:%s", strerror_from_system(GetLastError())); goto out; } renderedContent = (EVT_VARIANT*)zbx_realloc((void *)renderedContent, size_required); size = size_required; if (TRUE != EvtRender(*render_context, event_bookmark, EvtRenderEventValues, size, renderedContent, &size_required, &bookmarkedCount)) { zabbix_log(LOG_LEVEL_WARNING, "EvtRender failed:%s", strerror_from_system(GetLastError())); goto out; } } *FirstID = VAR_RECORD_NUMBER(renderedContent); *LastID = *FirstID + numIDs; if (*lastlogsize >= *LastID) { *lastlogsize = *FirstID - 1; zabbix_log(LOG_LEVEL_DEBUG, "lastlogsize is too big. It is set to:" ZBX_FS_UI64, *lastlogsize); } ret = SUCCEED; out: if (NULL != log) EvtClose(log); if (NULL != tmp_all_event_query) EvtClose(tmp_all_event_query); if (NULL != event_bookmark) EvtClose(event_bookmark); zbx_free(tmp_str); zbx_free(renderedContent); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s FirstID:" ZBX_FS_UI64 " LastID:" ZBX_FS_UI64 " numIDs:" ZBX_FS_UI64, __function_name, zbx_result_string(ret), *FirstID, *LastID, numIDs); return ret; }
static int zbx_get_eventlog_message_xpath(LPCTSTR wsource, zbx_uint64_t *lastlogsize, char **out_source, char **out_message, unsigned short *out_severity, unsigned long *out_timestamp, unsigned long *out_eventid, unsigned char skip_old_data, void **pcontext) { const char *__function_name = "zbx_get_eventlog_message_xpath"; int ret = FAIL; LPSTR tmp_str = NULL; LPWSTR tmp_wstr = NULL; LPWSTR event_query = NULL; /* L"Event/System[EventRecordID=WHICH]" */ unsigned long status = ERROR_SUCCESS; PEVT_VARIANT eventlog_array = NULL; HANDLE providermetadata_handle = NULL; LPWSTR query_array[] = { L"/Event/System/Provider/@Name", L"/Event/System/EventID", L"/Event/System/Level", L"/Event/System/TimeCreated/@SystemTime", L"/Event/System/EventRecordID"}; DWORD array_count = 5; DWORD dwReturned = 0, dwValuesCount = 0, dwBufferSize = 0; const ULONGLONG sec_1970 = 116444736000000000; static HMODULE hmod_wevtapi = NULL; zbx_eventlog_context *context; assert(out_source); assert(out_message); assert(out_severity); assert(out_timestamp); assert(out_eventid); zabbix_log(LOG_LEVEL_DEBUG, "In %s() which:%lld", __function_name, *lastlogsize); *out_source = NULL; *out_message = NULL; *out_severity = 0; *out_timestamp = 0; *out_eventid = 0; /* We have to use LoadLibrary() to load wevtapi.dll to avoid it required even before Vista. */ /* load wevtapi.dll once */ if (NULL == hmod_wevtapi) { hmod_wevtapi = LoadLibrary(L"wevtapi.dll"); if (NULL == hmod_wevtapi) { zabbix_log(LOG_LEVEL_WARNING, "Can't load wevtapi.dll"); goto finish; } zabbix_log(LOG_LEVEL_DEBUG, "wevtapi.dll was loaded"); /* get function pointer from wevtapi.dll */ (FARPROC)EvtQuery = GetProcAddress(hmod_wevtapi, "EvtQuery"); (FARPROC)EvtCreateRenderContext = GetProcAddress(hmod_wevtapi, "EvtCreateRenderContext"); (FARPROC)EvtNext = GetProcAddress(hmod_wevtapi, "EvtNext"); (FARPROC)EvtRender = GetProcAddress(hmod_wevtapi, "EvtRender"); (FARPROC)EvtOpenPublisherMetadata = GetProcAddress(hmod_wevtapi, "EvtOpenPublisherMetadata"); (FARPROC)EvtFormatMessage = GetProcAddress(hmod_wevtapi, "EvtFormatMessage"); (FARPROC)EvtClose = GetProcAddress(hmod_wevtapi, "EvtClose"); if (NULL == EvtQuery || NULL == EvtCreateRenderContext || NULL == EvtNext || NULL == EvtRender || NULL == EvtOpenPublisherMetadata || NULL == EvtFormatMessage || NULL == EvtClose) { zabbix_log(LOG_LEVEL_WARNING, "Can't load wevtapi.dll functions"); goto finish; } zabbix_log(LOG_LEVEL_DEBUG, "wevtapi.dll functions were loaded"); } context = *pcontext; if (context == NULL) { context = zbx_malloc(NULL, sizeof(*context)); memset(context, 0, sizeof(*context)); tmp_str = zbx_dsprintf(NULL, "Event/System[EventRecordID>%lld]", *lastlogsize); event_query = zbx_utf8_to_unicode(tmp_str); zbx_free(tmp_str); context->handle = EvtQuery(NULL, wsource, event_query, skip_old_data? EvtQueryChannelPath|EvtQueryReverseDirection: EvtQueryChannelPath); if (NULL == context->handle) { status = GetLastError(); if (ERROR_EVT_CHANNEL_NOT_FOUND == status) { zabbix_log(LOG_LEVEL_WARNING, "Missed eventlog"); } else { zabbix_log(LOG_LEVEL_WARNING, "EvtQuery failed"); } goto finish; } context->context_handle = EvtCreateRenderContext(array_count, (LPCWSTR*)query_array, EvtRenderContextValues); if (NULL == context->context_handle) { zabbix_log(LOG_LEVEL_WARNING, "EvtCreateRenderContext failed"); goto finish; } *pcontext = context; } if (context->each_handle) { EvtClose(context->each_handle); context->each_handle = NULL; } if (!EvtNext(context->handle, 1, &context->each_handle, INFINITE, 0, &dwReturned)) { status = GetLastError(); if (ERROR_NO_MORE_ITEMS == status) { zabbix_log(LOG_LEVEL_DEBUG, "EvtNext no more items."); ret = SUCCEED; } else { zabbix_log(LOG_LEVEL_WARNING, "First EvtNext failed with %lu", status); } goto finish; } if (!EvtRender(context->context_handle, context->each_handle, EvtRenderEventValues, dwBufferSize, eventlog_array, &dwReturned, &dwValuesCount)) { if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError())) { dwBufferSize = dwReturned; if (NULL == (eventlog_array = (PEVT_VARIANT)zbx_malloc(eventlog_array, dwBufferSize))) { zabbix_log(LOG_LEVEL_WARNING, "EvtRender malloc failed"); goto finish; } if (!EvtRender(context->context_handle, context->each_handle, EvtRenderEventValues, dwBufferSize, eventlog_array, &dwReturned, &dwValuesCount)) { zabbix_log(LOG_LEVEL_WARNING, "EvtRender failed"); goto finish; } } if (ERROR_SUCCESS != (status = GetLastError())) { zabbix_log(LOG_LEVEL_WARNING, "EvtRender failed with %d", status); goto finish; } } *out_source = zbx_unicode_to_utf8(eventlog_array[0].StringVal); providermetadata_handle = EvtOpenPublisherMetadata(NULL, eventlog_array[0].StringVal, NULL, 0, 0); if (NULL != providermetadata_handle) { dwBufferSize = 0; dwReturned = 0; if (!EvtFormatMessage(providermetadata_handle, context->each_handle, 0, 0, NULL, EvtFormatMessageEvent, dwBufferSize, tmp_wstr, &dwReturned)) { if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError())) { dwBufferSize = dwReturned; if (NULL == (tmp_wstr = (LPWSTR)zbx_malloc(tmp_wstr, dwBufferSize * sizeof(WCHAR)))) { zabbix_log(LOG_LEVEL_WARNING, "EvtFormatMessage malloc failed"); goto finish; } if (!EvtFormatMessage(providermetadata_handle, context->each_handle, 0, 0, NULL, EvtFormatMessageEvent, dwBufferSize, tmp_wstr, &dwReturned)) { zabbix_log(LOG_LEVEL_WARNING, "EvtFormatMessage failed"); goto finish; } } if (ERROR_SUCCESS != (status = GetLastError())) { zabbix_log(LOG_LEVEL_WARNING, "EvtFormatMessage failed with %d", status); goto finish; } } *out_message= zbx_unicode_to_utf8(tmp_wstr); } else { zabbix_log(LOG_LEVEL_DEBUG, "EvtOpenPublisherMetadata failed with %d: no description availabel", GetLastError()); *out_message = zbx_strdup(NULL, ""); } *out_eventid = eventlog_array[1].UInt16Val; *out_severity = eventlog_array[2].ByteVal; *out_timestamp = (unsigned long)((eventlog_array[3].FileTimeVal - sec_1970) / 10000000); *lastlogsize = eventlog_array[4].UInt64Val; ret = SUCCEED; finish: zbx_free(tmp_str); zbx_free(tmp_wstr); zbx_free(event_query); zbx_free(eventlog_array); if (FAIL == ret) { zbx_free(*out_source); zbx_free(*out_message); } if (providermetadata_handle) EvtClose(providermetadata_handle); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }
EVT_HANDLE CperOpenWheaLogQuery ( __in_opt PWSTR ComputerName, __in_opt PWSTR UserName, __in_opt PWSTR Domain, __in_opt PWSTR Password, __in_opt PWSTR FileName, __out EVT_HANDLE *Session ) /*++ Routine Description: This routine will initialize an event log query that may be used to enumerate any WHEA error records contained in the WHEA event log. Arguments: ComputerName - Supplies an optional computer name for remote queries. This should be NULL for the local event log query or if an exported event log is to be queried. UserName - Supplies the username to be used to authenticate to the remote computer. Domain - Supplies the username to be used to authenticate to the remote computer. Password - Supplies the password to be used to authenticate to the remote computer. FileName - Supplies an optional filename for an exported event log. This should be NULL for a live (local or remote) event log query. Session - Supplies a variable in which a handle to the session is returned, but only if the query is for events on a remote computer. Return Value: A handle to the ETW query if successful, NULL otherwise. --*/ { DWORD Error; DWORD Flags; EVT_RPC_LOGIN Login; PCWSTR Path; EVT_HANDLE QueryHandle; EVT_HANDLE SessionHandle; QueryHandle = NULL; SessionHandle = NULL; Error = ERROR_SUCCESS; // // If a computer name is specified, then an event log session to that // computer must be opened. It is invalid to specify a remote computer as // well as a filename. // if (ComputerName != NULL) { if (FileName != NULL) { Error = ERROR_INVALID_PARAMETER; goto OpenWheaLogQueryEnd; } RtlZeroMemory(&Login, sizeof(EVT_RPC_LOGIN)); Login.Server = ComputerName; Login.User = UserName; Login.Domain = Domain; Login.Password = Password; Login.Flags = EvtRpcLoginAuthDefault; SessionHandle = EvtOpenSession(EvtRpcLogin, &Login, 0, 0); if (SessionHandle == NULL) { Error = GetLastError(); goto OpenWheaLogQueryEnd; } } if (FileName == NULL) { Path = WHEA_CHANNEL; Flags = EvtQueryChannelPath | EvtQueryForwardDirection; } else { Path = (PCWSTR)FileName; Flags = EvtQueryFilePath | EvtQueryForwardDirection; } // // Open the query. If this is not a file query and the open fails, try the // legacy log name. // QueryHandle = EvtQuery(SessionHandle, Path, WHEA_LOG_QUERY, Flags); if (QueryHandle == NULL) { Error = GetLastError(); if (FileName == NULL) { Path = WHEA_CHANNEL_LEGACY; QueryHandle = EvtQuery(SessionHandle, Path, WHEA_LOG_QUERY, Flags); if (QueryHandle == NULL) { Error = GetLastError(); goto OpenWheaLogQueryEnd; } } } *Session = SessionHandle; OpenWheaLogQueryEnd: if (QueryHandle == NULL) { if (SessionHandle != NULL) { EvtClose(SessionHandle); } SetLastError(Error); } return QueryHandle; }