source: nscp/modules/CheckEventLog/CheckEventLog.cpp @ 1ecd26f

0.4.00.4.10.4.2
Last change on this file since 1ecd26f was 1ecd26f, checked in by Michael Medin <michael@…>, 2 years ago

syncronized streams between 0.4.x and 0.3.x as well as improed the CMAke build *alot*

  • Property mode set to 100644
File size: 30.0 KB
Line 
1/**************************************************************************
2*   Copyright (C) 2004-2007 by Michael Medin <michael@medin.name>         *
3*                                                                         *
4*   This code is part of NSClient++ - http://trac.nakednuns.org/nscp      *
5*                                                                         *
6*   This program is free software; you can redistribute it and/or modify  *
7*   it under the terms of the GNU General Public License as published by  *
8*   the Free Software Foundation; either version 2 of the License, or     *
9*   (at your option) any later version.                                   *
10*                                                                         *
11*   This program is distributed in the hope that it will be useful,       *
12*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14*   GNU General Public License for more details.                          *
15*                                                                         *
16*   You should have received a copy of the GNU General Public License     *
17*   along with this program; if not, write to the                         *
18*   Free Software Foundation, Inc.,                                       *
19*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20***************************************************************************/
21
22#include "stdafx.h"
23#include "CheckEventLog.h"
24#include <filter_framework.hpp>
25#include <boost/foreach.hpp>
26
27#include <strEx.h>
28#include <time.h>
29#include <utils.h>
30#include <error.hpp>
31#include <map>
32#include <vector>
33#include <config.h>
34
35#include <boost/bind.hpp>
36#include <boost/assign.hpp>
37
38#include <parsers/where.hpp>
39#include <simple_timer.hpp>
40
41#include "simple_registry.hpp"
42#include "eventlog_record.hpp"
43#include "eventlog_filter.hpp"
44
45CheckEventLog gCheckEventLog;
46
47CheckEventLog::CheckEventLog() {
48}
49CheckEventLog::~CheckEventLog() {
50}
51struct parse_exception {
52        parse_exception(std::wstring) {}
53};
54
55#include <parsers/where.cpp>
56#include <parsers/grammar.cpp>
57#include <parsers/ast.cpp>
58
59namespace sh = nscapi::settings_helper;
60
61
62bool CheckEventLog::loadModule() {
63        return false;
64}
65
66
67bool CheckEventLog::loadModuleEx(std::wstring alias, NSCAPI::moduleLoadMode mode) {
68        try {
69                get_core()->registerCommand(_T("CheckEventLog"), _T("Check for errors in the event logger!"));
70
71                sh::settings_registry settings(nscapi::plugin_singleton->get_core());
72                settings.set_alias(_T("CheckEventlog"), alias);
73
74                settings.alias().add_path_to_settings()
75                        (_T("EVENT LOG SECTION"), _T("Section for the EventLog Checker (CHeckEventLog.dll)."))
76                        ;
77
78                settings.alias().add_key_to_settings()
79                        (_T("debug"), sh::bool_key(&debug_, false),
80                        _T("DEBUG"), _T("Log all \"hits\" and \"misses\" on the eventlog filter chain, useful for debugging eventlog checks but very very very noisy so you don't want to accidentally set this on a real machine."))
81
82                        (_T("lookup names"), sh::bool_key(&lookup_names_, false),
83                        _T("LOOKUP NAMES"), _T(""))
84
85                        (_T("syntax"), sh::wstring_key(&syntax_),
86                        _T("SYNTAX"), _T("Set this to use a specific syntax string for all commands (that don't specify one)."))
87
88                        (_T("buffer size"), sh::int_key(&buffer_length_, 128*1024),
89                        _T("BUFFER_SIZE"), _T("The size of the buffer to use when getting messages this affects the speed and maximum size of messages you can recieve."))
90                        ;
91
92                settings.register_all();
93                settings.notify();
94
95        } catch (std::exception &e) {
96                NSC_LOG_ERROR_STD(_T("Exception caught: ") + to_wstring(e.what()));
97                return false;
98        } catch (nscapi::nscapi_exception &e) {
99                NSC_LOG_ERROR_STD(_T("Failed to register command: ") + e.msg_);
100                return false;
101        } catch (...) {
102                NSC_LOG_ERROR_STD(_T("Failed to register command."));
103                return false;
104        }
105        /*
106        parse(_T("321 = 123"));
107        parse(_T("123 = 123"));
108        parse(_T("id = 123"));
109        parse(_T("id = 321"));
110
111        parse(_T("id = '123'"));
112        parse(_T("id = '321'"));
113
114        parse(_T("id = convert(123)"));
115        parse(_T("id = convert(321)"));
116
117        parse(_T("id = 123 AND 123 = 123 AND id = 123x"));
118        parse(_T("id = 123 AND 123 = 321 OR 123 = 456 OR 123 = 123"));
119       
120        parse(_T("foo"));
121        parse(_T("1"));
122        parse(_T("foo = "));
123        parse(_T("foo = 1"));
124        parse(_T("'foo' = 1"));
125        parse(_T("foo = '1'"));
126        parse(_T("'hello'='world'"));
127
128        parse(_T("foo = bar"));
129        parse(_T("foo = bar AND bar = foo"));
130        parse(_T("foo = bar AND bar = 1"));
131        parse(_T("foo = bar AND bar = foo OR foo = bar"));
132        parse(_T("foo = bar AND bar = 1 OR foo = 1"));
133        parse(_T(" foo = bar AND ( test > 120 OR foo < 123) OR ugh IN (123, 456, 789)"));
134
135        parse(_T("aaa = 111 OR bbb = 222 OR ccc = 333"));
136        parse(_T("(aaa = 111) OR bbb = 222 OR ccc = 333"));
137        parse(_T("(aaa = 111 OR bbb = 222) OR ccc = 333"));
138        parse(_T("(aaa = 111 OR bbb = 222 OR ccc = 333)"));
139        parse(_T("aaa = 111 OR (bbb = 222 OR ccc = 333)"));
140        parse(_T("aaa = 111 OR bbb = 222 OR (ccc = 333)"));
141        parse(_T("ccc = -333"));
142        parse(_T("ccc = -333 AND ccc = to_date('AABBCC', 1234)"));
143        parse(_T("aaa = 111 OR bbb = 222 OR (ccc = -333)"));
144        parse(_T("ccc = -333 AND ccc = to_date('AABBCC', 1234) OR aaa = 123x"));
145        parse(_T("ccc = -333 AND ccc = to_date('AABBCC', 1234) OR aaa = 123x OR 123r = foo123"));
146*/
147        return true;
148}
149bool CheckEventLog::unloadModule() {
150        return true;
151}
152
153bool CheckEventLog::hasCommandHandler() {
154        return true;
155}
156bool CheckEventLog::hasMessageHandler() {
157        return false;
158}
159namespace filter {
160        namespace where {
161                struct type_obj : public parsers::where::varible_handler<type_obj> {
162                        typedef parsers::where::varible_handler<type_obj> handler;
163                        typedef std::list<std::wstring> error_type;
164                        typedef std::map<std::wstring,parsers::where::value_type> types_type;
165                        types_type types;
166                        error_type errors;
167                        static const parsers::where::value_type type_custom_severity = parsers::where::type_custom_int_1;
168                        static const parsers::where::value_type type_custom_type = parsers::where::type_custom_int_2;
169                        EventLogRecord *record;
170                        type_obj() : record(NULL) {
171                                using namespace boost::assign;
172                                using namespace parsers::where;
173                                insert(types)
174                                        (_T("id"), (type_int))
175                                        (_T("source"), (type_string))
176                                        (_T("type"), (type_custom_type))
177                                        (_T("severity"), (type_custom_severity))
178                                        (_T("message"), (type_string))
179                                        (_T("strings"), (type_string))
180                                        (_T("written"), (type_date))
181                                        (_T("generated"), (type_date));
182                        }
183                        type_obj(EventLogRecord *record) : record(record) {}
184                        bool has_variable(std::wstring key) {
185                                return types.find(key) != types.end();
186                        }
187                        parsers::where::value_type get_type(std::wstring key) {
188                                types_type::const_iterator cit = types.find(key);
189                                if (cit == types.end())
190                                        return parsers::where::type_invalid;
191                                return cit->second;
192                        }
193                        bool can_convert(parsers::where::value_type from, parsers::where::value_type to) {
194                                if ((from == parsers::where::type_string)&&(to == type_custom_severity))
195                                        return true;
196                                if ((from == parsers::where::type_string)&&(to == type_custom_type))
197                                        return true;
198                                return false;
199                        }
200                        void error(std::wstring err) {
201                                errors.push_back(err);
202                        }
203                        bool has_error() {
204                                return !errors.empty();
205                        }
206                        long long get_id() {
207                                if (record == NULL) throw _T("Whoops"); return record->eventID();
208                        }
209                        std::wstring get_source() {
210                                if (record == NULL) throw _T("Whoops"); return record->eventSource();
211                        }
212                        long long get_el_type() {
213                                if (record == NULL) throw _T("Whoops"); return record->eventType();
214                        }
215                        long long get_severity() {
216                                if (record == NULL) throw _T("Whoops");
217                                //NSC_DEBUG_MSG_STD(_T("Severity: ") + strEx::itos(record->severity()));
218                                return record->severity();
219                        }
220                        std::wstring get_message() {
221                                if (record == NULL) throw _T("Whoops"); return record->render_message();
222                        }
223                        std::wstring get_strings() {
224                                if (record == NULL) throw _T("Whoops"); return record->enumStrings();
225                        }
226                        long long get_written() {
227                                if (record == NULL) throw _T("Whoops"); return record->written();
228                        }
229                        long long get_generated() {
230                                if (record == NULL) throw _T("Whoops"); return record->generated();
231                        }
232
233                        handler::bound_string_type bind_string(std::wstring key) {
234                                handler::bound_string_type ret;
235                                if (key == _T("source"))
236                                        ret = &type_obj::get_source;
237                                else if (key == _T("message"))
238                                        ret = &type_obj::get_message;
239                                else if (key == _T("strings"))
240                                        ret = &type_obj::get_strings;
241                                else
242                                        NSC_DEBUG_MSG_STD(_T("Failed to bind (string): ") + key);
243                                return ret;
244                        }
245                        handler::bound_int_type bind_int(std::wstring key) {
246                                handler::bound_int_type ret;
247                                if (key == _T("id"))
248                                        ret = &type_obj::get_id;
249                                else if (key == _T("type"))
250                                        ret = &type_obj::get_el_type;
251                                else if (key == _T("severity"))
252                                        ret = &type_obj::get_severity;
253                                else if (key == _T("generated"))
254                                        ret = &type_obj::get_generated;
255                                else if (key == _T("written"))
256                                        ret = &type_obj::get_written;
257                                else
258                                        NSC_DEBUG_MSG_STD(_T("Failed to bind (int): ") + key);
259                                return ret;
260                        }
261
262                        bool has_function(parsers::where::value_type to, std::wstring name, parsers::where::expression_ast<type_obj> subject) {
263                                if (to == type_custom_severity)
264                                        return true;
265                                if (to == type_custom_type)
266                                        return true;
267                                return false;
268                        }
269                        handler::bound_function_type bind_function(parsers::where::value_type to, std::wstring name, parsers::where::expression_ast<type_obj> subject) {
270                                handler::bound_function_type ret;
271                                if (to == type_custom_severity)
272                                        ret = &type_obj::fun_convert_severity;
273                                if (to == type_custom_type)
274                                        ret = &type_obj::fun_convert_type;
275                                return ret;
276                        }
277
278                        parsers::where::expression_ast<type_obj> fun_convert_severity(parsers::where::value_type target_type, parsers::where::expression_ast<type_obj> const& subject) {
279                                return parsers::where::expression_ast<type_obj>(parsers::where::int_value(convert_severity(subject.get_string(*this))));
280                        }
281                        parsers::where::expression_ast<type_obj> fun_convert_type(parsers::where::value_type target_type, parsers::where::expression_ast<type_obj> const& subject) {
282                                return parsers::where::expression_ast<type_obj>(parsers::where::int_value(convert_type(subject.get_string(*this))));
283                        }
284                        int convert_severity(std::wstring str) {
285                                if (str == _T("success") || str == _T("ok"))
286                                        return 0;
287                                if (str == _T("informational") || str == _T("info"))
288                                        return 1;
289                                if (str == _T("warning") || str == _T("warn"))
290                                        return 2;
291                                if (str == _T("error") || str == _T("err"))
292                                        return 3;
293                                error(_T("Invalid severity: ") + str);
294                                return strEx::stoi(str);
295                        }
296                        int convert_type(std::wstring str) {
297                                if (str == _T("error"))
298                                        return EVENTLOG_ERROR_TYPE;
299                                if (str == _T("warning"))
300                                        return EVENTLOG_WARNING_TYPE;
301                                if (str == _T("info"))
302                                        return EVENTLOG_INFORMATION_TYPE;
303                                if (str == _T("auditSuccess"))
304                                        return EVENTLOG_AUDIT_SUCCESS;
305                                if (str == _T("auditFailure"))
306                                        return EVENTLOG_AUDIT_FAILURE;
307                                return strEx::stoi(str);
308                        }
309
310                        std::wstring get_error() {
311                                std::wstring ret;
312                                BOOST_FOREACH(std::wstring s, errors) {
313                                        if (!ret.empty()) ret += _T(", ");
314                                        ret += s;
315                                }
316                                return ret;
317                        }
318                };
319        }
320}
321
322
323
324
325struct filter_container {
326        enum filter_types {
327                filter_plus = 1,
328                filter_minus = 2,
329                filter_normal = 3
330        };
331        typedef std::pair<int,eventlog_filter> filteritem_type;
332        typedef std::list<filteritem_type > filterlist_type;
333
334        filterlist_type filters;
335
336        bool bFilterAll;
337        bool bFilterIn;
338
339        bool bDebug;
340        int debugThreshold;
341
342        bool bShowDescriptions;
343        std::wstring syntax;
344
345        std::wstring filter;
346
347        filter_container(std::wstring syntax, bool debug) : bDebug(debug), debugThreshold(0), bFilterIn(true), bFilterAll(false), bShowDescriptions(false), syntax(syntax) {}
348
349};
350
351struct any_mode_filter {
352        virtual bool boot() = 0;
353        virtual bool validate(std::wstring &message) = 0;
354        virtual bool match(EventLogRecord &record) = 0;
355        virtual std::wstring get_name() = 0;
356        virtual std::wstring get_subject() = 0;
357};
358
359struct first_mode_filter : public any_mode_filter {
360        typedef filter_container::filterlist_type::const_iterator filter_iterator;
361        filter_container &data;
362        first_mode_filter(filter_container &data) : data(data) {}
363        bool boot() {return true;}
364        bool validate(std::wstring &message) {
365                if (data.filters.empty()) {
366                        message = _T("No filters specified try adding: filter+generated=>2d");
367                        return false;
368                }
369                return true;
370        }
371
372        virtual bool match(EventLogRecord &record) {
373                bool bMatch = !data.bFilterIn;
374                for (filter_iterator cit3 = data.filters.begin(); cit3 != data.filters.end(); ++cit3) {
375                        std::wstring reason;
376                        int mode = (*cit3).first;
377                        bool bTmpMatched = (*cit3).second.matchFilter(record);
378                        if (data.bFilterAll) {
379                                if (!bTmpMatched) {
380                                        bMatch = false;
381                                        break;
382                                }
383                        } else {
384                                if (bTmpMatched) {
385                                        bMatch = true;
386                                        break;
387                                }
388                        }
389                }
390                if ((data.bFilterIn&&bMatch)||(!data.bFilterIn&&!bMatch)) {
391                        return true;
392                }
393                return false;
394
395        }
396        std::wstring get_name() {
397                return _T("deprecated");
398        }
399        std::wstring get_subject() { return _T("TODO"); }
400
401};
402struct second_mode_filter : public any_mode_filter  {
403        typedef filter_container::filterlist_type::const_iterator filter_iterator;
404
405        filter_container &data;
406        second_mode_filter(filter_container &data) : data(data) {}
407        bool boot() {return true;}
408        bool validate(std::wstring &message) {
409                if (data.filters.empty()) {
410                        message = _T("No filters specified try adding: filter+generated=>2d");
411                        return false;
412                }
413                return true;
414        }
415
416        virtual bool match(EventLogRecord &record) {
417                bool bMatch = !data.bFilterIn;
418                int i=0;
419                for (filter_iterator cit3 = data.filters.begin(); cit3 != data.filters.end(); ++cit3, i++ ) {
420                        std::wstring reason;
421                        int mode = (*cit3).first;
422                        bool bTmpMatched = (*cit3).second.matchFilter(record);
423                        if ((mode == filter_container::filter_minus)&&(bTmpMatched)) {
424                                // a -<filter> hit so thrash item and bail out!
425                                if (data.bDebug && (i>data.debugThreshold))
426                                        NSC_DEBUG_MSG_STD(_T("[") + strEx::itos(i) + _T("] Matched: - ") + (*cit3).second.to_string() + _T(" for: ") + record.render(data.bShowDescriptions, data.syntax));
427                                return false;
428                        } else if ((mode == filter_container::filter_plus)&&(!bTmpMatched)) {
429                                // a +<filter> hit so keep item and bail out!
430                                if (data.bDebug && (i>data.debugThreshold))
431                                        NSC_DEBUG_MSG_STD(_T("[") + strEx::itos(i) + _T("] Matched: + ") + (*cit3).second.to_string() + _T(" for: ") + record.render(data.bShowDescriptions, data.syntax));
432                                return false;
433                        } else if (bTmpMatched) {
434                                if (data.bDebug && (i>data.debugThreshold))
435                                        NSC_DEBUG_MSG_STD(_T("[") + strEx::itos(i) + _T("] Matched: . ") + (*cit3).second.to_string() + _T(" for: ") + record.render(data.bShowDescriptions, data.syntax));
436                                bMatch = true;
437                        }
438                }
439                return bMatch;
440        }
441        std::wstring get_name() {
442                return _T("old");
443        }
444        std::wstring get_subject() { return _T("TODO"); }
445};
446
447struct where_mode_filter : public any_mode_filter {
448        filter_container &data;
449        std::string message;
450        parsers::where::parser<filter::where::type_obj> ast_parser;
451        filter::where::type_obj dummy;
452
453        where_mode_filter(filter_container &data) : data(data) {}
454        bool boot() {return true; }
455
456        bool validate(std::wstring &message) {
457                if (data.bDebug)
458                        NSC_DEBUG_MSG_STD(_T("Parsing: ") + data.filter);
459
460                if (!ast_parser.parse(data.filter)) {
461                        NSC_LOG_ERROR_STD(_T("Parsing failed of '") + data.filter + _T("' at: ") + ast_parser.rest);
462                        message = _T("Parsing failed: ") + ast_parser.rest;
463                        return false;
464                }
465                if (data.bDebug)
466                        NSC_DEBUG_MSG_STD(_T("Parsing succeeded: ") + ast_parser.result_as_tree());
467
468                if (!ast_parser.derive_types(dummy) || dummy.has_error()) {
469                        message = _T("Invalid types: ") + dummy.get_error();
470                        return false;
471                }
472                if (data.bDebug)
473                        NSC_DEBUG_MSG_STD(_T("Type resolution succeeded: ") + ast_parser.result_as_tree());
474
475                if (!ast_parser.bind(dummy) || dummy.has_error()) {
476                        message = _T("Variable and function binding failed: ") + dummy.get_error();
477                        return false;
478                }
479                if (data.bDebug)
480                        NSC_DEBUG_MSG_STD(_T("Binding succeeded: ") + ast_parser.result_as_tree());
481
482                if (!ast_parser.static_eval(dummy) || dummy.has_error()) {
483                        message = _T("Static evaluation failed: ") + dummy.get_error();
484                        return false;
485                }
486                if (data.bDebug)
487                        NSC_DEBUG_MSG_STD(_T("Static evaluation succeeded: ") + ast_parser.result_as_tree());
488
489                return true;
490        }
491        virtual bool match(EventLogRecord &record) {
492                filter::where::type_obj obj(&record);
493                //NSC_DEBUG_MSG_STD(_T("Evaluating: ") + ast_parser.result_as_tree() + _T(": ") + strEx::itos(record.severity()) + _T(" >> ") + strEx::itos(ast_parser.evaluate(obj)));
494                bool ret = ast_parser.evaluate(obj);
495                if (obj.has_error()) {
496                        NSC_LOG_ERROR_STD(_T("Error: ") + obj.get_error());
497                }
498                return ret;
499        }
500        std::wstring get_name() {
501                return _T("where");
502        }
503        std::wstring get_subject() { return data.filter; }
504};
505
506
507
508void CheckEventLog::parse(std::wstring expr) {
509//return false;
510/*
511        my_type_obj obj1(123);
512        std::wcout << _T("Result (001): ") << ast_parser.evaluate(obj1) << std::endl;
513        my_type_obj obj2(321);
514        std::wcout << _T("Result (002): ") << ast_parser.evaluate(obj2) << std::endl;
515        */
516}
517
518
519
520std::wstring find_eventlog_name(std::wstring name) {
521        try {
522                simple_registry::registry_key key(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog"));
523                std::list<std::wstring> list = key.get_keys();
524                for (std::list<std::wstring>::const_iterator cit = list.begin(); cit != list.end(); ++cit) {
525                        try {
526                                simple_registry::registry_key sub_key(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\") + *cit);
527                                std::wstring file = sub_key.get_string(_T("DisplayNameFile"));
528                                int id = sub_key.get_int(_T("DisplayNameID"));
529                                std::wstring real_name = error::format::message::from_module(file, id);
530                                strEx::replace(real_name, _T("\n"), _T(""));
531                                strEx::replace(real_name, _T("\r"), _T(""));
532                                NSC_DEBUG_MSG(_T("Attempting to match: ") + real_name + _T(" with ") + name);
533                                if (real_name == name)
534                                        return *cit;
535                        } catch (simple_registry::registry_exception &e) { e;}
536                }
537                return name;
538        } catch (simple_registry::registry_exception &e) {
539                NSC_DEBUG_MSG(_T("Failed to get eventlog name (assuming shorthand): ") + e.what());
540                return name;
541        } catch (...) {
542                NSC_DEBUG_MSG(_T("Failed to get eventlog name (assuming shorthand)"));
543                return name;
544        }
545}
546
547
548
549class uniq_eventlog_record {
550        DWORD ID;
551        WORD type;
552        WORD category;
553public:
554        std::wstring message;
555        uniq_eventlog_record(EVENTLOGRECORD *pevlr) : ID(pevlr->EventID&0xffff), type(pevlr->EventType), category(pevlr->EventCategory) {}
556        bool operator< (const uniq_eventlog_record &other) const {
557                return (ID < other.ID) || ((ID==other.ID)&&(type < other.type)) || (ID==other.ID&&type==other.type)&&(category < other.category);
558        }
559        std::wstring to_string() const {
560                return _T("id=") + strEx::itos(ID) + _T("type=") + strEx::itos(type) + _T("category=") + strEx::itos(category);
561        }
562};
563typedef std::map<uniq_eventlog_record,unsigned int> uniq_eventlog_map;
564
565
566
567
568
569#define MAP_FILTER(value, obj, filtermode) \
570                        else if (p__.first == value) { filter.obj = p__.second; if (bPush) { data.filters.push_back(filter_container::filteritem_type(filtermode, filter)); filter = eventlog_filter(); } }
571#define MAP_FILTER_LAST(value, obj) \
572                        else if (p__.first == value) { data.filters.front().second.obj = p__.second; }
573
574struct event_log_buffer {
575        BYTE *bBuffer;
576        DWORD bufferSize_;
577        event_log_buffer(DWORD bufferSize) : bufferSize_(bufferSize) {
578                bBuffer = new BYTE[bufferSize+10];
579        }
580        ~event_log_buffer() {
581                delete [] bBuffer;
582        }
583        EVENTLOGRECORD* getBufferUnsafe() {
584                return reinterpret_cast<EVENTLOGRECORD*>(bBuffer);
585        }
586        DWORD getBufferSize() {
587                return bufferSize_;
588        }
589};
590
591NSCAPI::nagiosReturn CheckEventLog::handleCommand(const strEx::wci_string command, std::list<std::wstring> arguments, std::wstring &message, std::wstring &perf) {
592        if (command != _T("CheckEventLog"))
593                return NSCAPI::returnIgnored;
594        simple_timer time;
595        typedef checkHolders::CheckContainer<checkHolders::MaxMinBoundsULongInteger> EventLogQuery1Container;
596        typedef checkHolders::CheckContainer<checkHolders::ExactBoundsULongInteger> EventLogQuery2Container;
597       
598        NSCAPI::nagiosReturn returnCode = NSCAPI::returnOK;
599
600        std::list<std::wstring> files;
601        EventLogQuery1Container query1;
602        EventLogQuery2Container query2;
603
604
605        filter_container data(syntax_, debug_);
606
607        bool bPerfData = true;
608        bool bFilterNew = true;
609        bool unique = false;
610        unsigned int truncate = 0;
611        event_log_buffer buffer(buffer_length_);
612        bool bPush = true;
613        eventlog_filter filter;
614        /*
615        try {
616                event_log_buffer buffer(buffer_length_);
617        } catch (std::exception e) {
618                message = std::wstring(_T("Failed to allocate memory: ")) + strEx::string_to_wstring(e.what());
619                return NSCAPI::returnUNKNOWN;
620        }
621        */
622
623        try {
624                MAP_OPTIONS_BEGIN(arguments)
625                        MAP_OPTIONS_NUMERIC_ALL(query1, _T(""))
626                        MAP_OPTIONS_EXACT_NUMERIC_ALL(query2, _T(""))
627                        MAP_OPTIONS_STR2INT(_T("truncate"), truncate)
628                        MAP_OPTIONS_BOOL_TRUE(_T("unique"), unique)
629                        MAP_OPTIONS_BOOL_TRUE(_T("descriptions"), data.bShowDescriptions)
630                        MAP_OPTIONS_PUSH(_T("file"), files)
631                        MAP_OPTIONS_BOOL_FALSE(IGNORE_PERFDATA, bPerfData)
632                        MAP_OPTIONS_BOOL_EX(_T("filter"), bFilterNew, _T("new"), _T("old"))
633                        MAP_OPTIONS_BOOL_EX(_T("filter"), data.bFilterIn, _T("in"), _T("out"))
634                        MAP_OPTIONS_BOOL_EX(_T("filter"), data.bFilterAll, _T("all"), _T("any"))
635                        MAP_OPTIONS_BOOL_EX(_T("debug"), data.bDebug, _T("true"), _T("false"))
636                        MAP_OPTIONS_STR2INT(_T("debug-threshold"), data.debugThreshold)
637                        MAP_OPTIONS_STR(_T("syntax"), data.syntax)
638                        /*
639                        MAP_FILTER_OLD("filter-eventType", eventType)
640                        MAP_FILTER_OLD("filter-severity", eventSeverity)
641                        MAP_FILTER_OLD("filter-eventID", eventID)
642                        MAP_FILTER_OLD("filter-eventSource", eventSource)
643                        MAP_FILTER_OLD("filter-generated", timeGenerated)
644                        MAP_FILTER_OLD("filter-written", timeWritten)
645                        MAP_FILTER_OLD("filter-message", message)
646*/
647                        MAP_FILTER(_T("filter+eventType"), eventType, filter_container::filter_plus)
648                        MAP_FILTER(_T("filter+severity"), eventSeverity, filter_container::filter_plus)
649                        MAP_FILTER(_T("filter+eventID"), eventID, filter_container::filter_plus)
650                        MAP_FILTER(_T("filter+eventSource"), eventSource, filter_container::filter_plus)
651                        MAP_FILTER(_T("filter+generated"), timeGenerated, filter_container::filter_plus)
652                        MAP_FILTER(_T("filter+written"), timeWritten, filter_container::filter_plus)
653                        MAP_FILTER(_T("filter+message"), message, filter_container::filter_plus)
654
655                        MAP_FILTER(_T("filter.eventType"), eventType, filter_container::filter_normal)
656                        MAP_FILTER(_T("filter.severity"), eventSeverity, filter_container::filter_normal)
657                        MAP_FILTER(_T("filter.eventID"), eventID, filter_container::filter_normal)
658                        MAP_FILTER(_T("filter.eventSource"), eventSource, filter_container::filter_normal)
659                        MAP_FILTER(_T("filter.generated"), timeGenerated, filter_container::filter_normal)
660                        MAP_FILTER(_T("filter.written"), timeWritten, filter_container::filter_normal)
661                        MAP_FILTER(_T("filter.message"), message, filter_container::filter_normal)
662
663                        MAP_FILTER(_T("filter-eventType"), eventType, filter_container::filter_minus)
664                        MAP_FILTER(_T("filter-severity"), eventSeverity, filter_container::filter_minus)
665                        MAP_FILTER(_T("filter-eventID"), eventID, filter_container::filter_minus)
666                        MAP_FILTER(_T("filter-eventSource"), eventSource, filter_container::filter_minus)
667                        MAP_FILTER(_T("filter-generated"), timeGenerated, filter_container::filter_minus)
668                        MAP_FILTER(_T("filter-written"), timeWritten, filter_container::filter_minus)
669                        MAP_FILTER(_T("filter-message"), message, filter_container::filter_minus)
670
671                        MAP_FILTER_LAST(_T("append-filter-eventType"), eventType)
672                        MAP_FILTER_LAST(_T("append-filter-severity"), eventSeverity)
673                        MAP_FILTER_LAST(_T("append-filter-eventID"), eventID)
674                        MAP_FILTER_LAST(_T("append-filter-eventSource"), eventSource)
675                        MAP_FILTER_LAST(_T("append-filter-generated"), timeGenerated)
676                        MAP_FILTER_LAST(_T("append-filter-written"), timeWritten)
677                        MAP_FILTER_LAST(_T("append-filter-message"), message)
678
679                        MAP_OPTIONS_STR(_T("filter"), data.filter)
680
681                        MAP_OPTIONS_MISSING(message, _T("Unknown argument: "))
682                        MAP_OPTIONS_END()
683        } catch (filters::parse_exception e) {
684                message = e.getMessage();
685                return NSCAPI::returnUNKNOWN;
686        } catch (filters::filter_exception e) {
687                message = e.getMessage();
688                return NSCAPI::returnUNKNOWN;
689                } catch (checkHolders::parse_exception e) {
690                message = e.getMessage();
691                return NSCAPI::returnUNKNOWN;
692        } catch (...) {
693                message = _T("Invalid command line!");
694                return NSCAPI::returnUNKNOWN;
695        }
696
697        unsigned long int hit_count = 0;
698        if (files.empty()) {
699                message = _T("No file specified try adding: file=Application");
700                return NSCAPI::returnUNKNOWN;
701        }
702        bool buffer_error_reported = false;
703
704        if (data.bDebug) {
705                std::wstring str;
706                BOOST_FOREACH(filter_container::filteritem_type item, data.filters) {
707                        if (item.first == filter_container::filter_normal)
708                                str += _T(". {");
709                        else if (item.first == filter_container::filter_plus)
710                                str += _T("+ {");
711                        else if (item.first == filter_container::filter_minus)
712                                str += _T("- {");
713                        else
714                                str += _T("? {");
715
716                        str += item.second.to_string() + _T(" }");
717                }
718                NSC_DEBUG_MSG_STD(_T("Filter: ") + str);
719        }
720
721        boost::shared_ptr<any_mode_filter> filter_impl;
722        if (bFilterNew) {
723                filter_impl = boost::shared_ptr<any_mode_filter>(new second_mode_filter(data));
724        } else {
725                filter_impl = boost::shared_ptr<any_mode_filter>(new second_mode_filter(data));
726        } if (!data.filter.empty()) {
727                filter_impl = boost::shared_ptr<any_mode_filter>(new where_mode_filter(data));
728        }
729
730        if (!filter_impl) {
731                message = _T("Failed to initialize filter subsystem.");
732                return NSCAPI::returnUNKNOWN;
733        }
734
735        filter_impl->boot();
736
737        __time64_t ltime;
738        _time64(&ltime);
739
740        NSC_DEBUG_MSG_STD(_T("Using: ") + filter_impl->get_name() + _T(" ") + filter_impl->get_subject());
741
742        if (!filter_impl->validate(message)) {
743                return NSCAPI::returnUNKNOWN;
744        }
745
746
747        NSC_DEBUG_MSG_STD(_T("Boot time: ") + strEx::itos(time.stop()));
748
749        for (std::list<std::wstring>::const_iterator cit2 = files.begin(); cit2 != files.end(); ++cit2) {
750                std::wstring name = *cit2;
751                if (lookup_names_) {
752                        name = find_eventlog_name(*cit2);
753                        if ((*cit2) != name) {
754                                NSC_DEBUG_MSG_STD(_T("Opening alternative log: ") + name);
755                        }
756                }
757                HANDLE hLog = OpenEventLog(NULL, name.c_str());
758                if (hLog == NULL) {
759                        message = _T("Could not open the '") + (*cit2) + _T("' event log: ") + error::lookup::last_error();
760                        return NSCAPI::returnUNKNOWN;
761                }
762                uniq_eventlog_map uniq_records;
763
764                //DWORD dwThisRecord;
765                DWORD dwRead, dwNeeded;
766
767
768                //GetOldestEventLogRecord(hLog, &dwThisRecord);
769
770                while (true) {
771                        BOOL bStatus = ReadEventLog(hLog, EVENTLOG_FORWARDS_READ|EVENTLOG_SEQUENTIAL_READ,
772                                0, buffer.getBufferUnsafe(), buffer.getBufferSize(), &dwRead, &dwNeeded);
773                        if (bStatus == FALSE) {
774                                DWORD err = GetLastError();
775                                if (err == ERROR_INSUFFICIENT_BUFFER) {
776                                        if (!buffer_error_reported) {
777                                                NSC_LOG_ERROR_STD(_T("EvenlogBuffer is too small change the value of ") + setting_keys::event_log::BUFFER_SIZE_PATH + _T("=") + strEx::itos(dwNeeded+1) + _T(": ") + error::lookup::last_error(err));
778                                                buffer_error_reported = true;
779                                        }
780                                } else if (err == ERROR_HANDLE_EOF) {
781                                        break;
782                                } else {
783                                        NSC_LOG_ERROR_STD(_T("Failed to read from eventlog: ") + error::lookup::last_error(err));
784                                        message = _T("Failed to read from eventlog: ") + error::lookup::last_error(err);
785                                        CloseEventLog(hLog);
786                                        return NSCAPI::returnUNKNOWN;
787                                }
788                        }
789                        EVENTLOGRECORD *pevlr = buffer.getBufferUnsafe();
790                        while (dwRead > 0) {
791                                EventLogRecord record((*cit2), pevlr, ltime);
792                                bool match = filter_impl->match(record);
793                                if (match&&unique) {
794                                        match = false;
795                                        uniq_eventlog_record uniq_record = pevlr;
796                                        uniq_eventlog_map::iterator it = uniq_records.find(uniq_record);
797                                        if (it != uniq_records.end()) {
798                                                (*it).second ++;
799                                                //match = false;
800                                        }
801                                        else {
802                                                if (!data.syntax.empty()) {
803                                                        uniq_record.message = record.render(data.bShowDescriptions, data.syntax);
804                                                } else if (!data.bShowDescriptions) {
805                                                        uniq_record.message = record.eventSource();
806                                                } else {
807                                                        uniq_record.message = record.eventSource();
808                                                        uniq_record.message += _T("(") + EventLogRecord::translateType(record.eventType()) + _T(", ") +
809                                                                strEx::itos(record.eventID()) + _T(", ") + EventLogRecord::translateSeverity(record.severity()) + _T(")");
810                                                        uniq_record.message += _T("[") + record.enumStrings() + _T("]");
811                                                        uniq_record.message += _T("{%count%}");
812                                                }
813                                                uniq_records[uniq_record] = 1;
814                                        }
815                                        hit_count++;
816                                } else if (match) {
817                                        if (!data.syntax.empty()) {
818                                                strEx::append_list(message, record.render(data.bShowDescriptions, data.syntax));
819                                        } else if (!data.bShowDescriptions) {
820                                                strEx::append_list(message, record.eventSource());
821                                        } else {
822                                                strEx::append_list(message, record.eventSource());
823                                                message += _T("(") + EventLogRecord::translateType(record.eventType()) + _T(", ") +
824                                                        strEx::itos(record.eventID()) + _T(", ") + EventLogRecord::translateSeverity(record.severity()) + _T(")");
825                                                message += _T("[") + record.enumStrings() + _T("]");
826                                        }
827                                        hit_count++;
828                                }
829                                dwRead -= pevlr->Length;
830                                pevlr = reinterpret_cast<EVENTLOGRECORD*>((LPBYTE)pevlr + pevlr->Length);
831                        }
832                }
833                CloseEventLog(hLog);
834                for (uniq_eventlog_map::const_iterator cit = uniq_records.begin(); cit != uniq_records.end(); ++cit) {
835                        std::wstring msg = (*cit).first.message;
836                        strEx::replace(msg, _T("%count%"), strEx::itos((*cit).second));
837                        strEx::append_list(message, msg);
838                }
839        }
840        NSC_DEBUG_MSG_STD(_T("Evaluation time: ") + strEx::itos(time.stop()));
841
842        if (!bPerfData) {
843                query1.perfData = false;
844                query2.perfData = false;
845        }
846        if (query1.alias.empty())
847                query1.alias = _T("eventlog");
848        if (query2.alias.empty())
849                query2.alias = _T("eventlog");
850        if (query1.hasBounds())
851                query1.runCheck(hit_count, returnCode, message, perf);
852        else if (query2.hasBounds())
853                query2.runCheck(hit_count, returnCode, message, perf);
854        else {
855                message = _T("No bounds specified!");
856                return NSCAPI::returnUNKNOWN;
857        }
858        if ((truncate > 0) && (message.length() > (truncate-4)))
859                message = message.substr(0, truncate-4) + _T("...");
860        if (message.empty())
861                message = _T("Eventlog check ok");
862        return returnCode;
863}
864
865
866NSC_WRAP_DLL();
867NSC_WRAPPERS_MAIN_DEF(gCheckEventLog);
868NSC_WRAPPERS_IGNORE_MSG_DEF();
869NSC_WRAPPERS_HANDLE_CMD_DEF(gCheckEventLog);
Note: See TracBrowser for help on using the repository browser.