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

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

*OBS* This might no longer work! (expect updated code in the next few days if things are broken)

  • Fundamental API changes (due to NRPE compatibility)
    • HandleCommand? has changed
    • Inject has changed
    • Most API calls have new "return codes" (typedef:ed INT to allow for return code compiler checks)
    • A lot of the old return codes have changed
  • Preliminary NRPE support (can parse and execute incoming requests, cant return data yet, and no encryption)
  • New SimpleSocket? in include/ will be used as base class for Listeners
  • A lot of rewrite to the NSC API
  • Property mode set to 100644
File size: 12.6 KB
Line 
1// CheckEventLog.cpp : Defines the entry point for the DLL application.
2//
3
4#include "stdafx.h"
5#include "CheckEventLog.h"
6#include <strEx.h>
7#include <time.h>
8
9CheckEventLog gCheckEventLog;
10
11BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
12{
13        NSCModuleWrapper::wrapDllMain(hModule, ul_reason_for_call);
14        return TRUE;
15}
16
17CheckEventLog::CheckEventLog() {
18}
19CheckEventLog::~CheckEventLog() {
20}
21
22
23bool CheckEventLog::loadModule() {
24        return true;
25}
26bool CheckEventLog::unloadModule() {
27        return true;
28}
29
30std::string CheckEventLog::getModuleName() {
31        return "Event log Checker.";
32}
33NSCModuleWrapper::module_version CheckEventLog::getModuleVersion() {
34        NSCModuleWrapper::module_version version = {0, 0, 1 };
35        return version;
36}
37
38bool CheckEventLog::hasCommandHandler() {
39        return true;
40}
41bool CheckEventLog::hasMessageHandler() {
42        return false;
43}
44
45
46class EventLogRecord {
47        EVENTLOGRECORD *pevlr_;
48public:
49        EventLogRecord(EVENTLOGRECORD *pevlr) : pevlr_(pevlr) {
50        }
51        inline DWORD timeGenerated() {
52                return pevlr_->TimeGenerated;
53        }
54        inline DWORD timeWritten() {
55                return pevlr_->TimeWritten;
56        }
57        inline std::string eventSource() {
58                return reinterpret_cast<LPSTR>(reinterpret_cast<LPBYTE>(pevlr_) + sizeof(EVENTLOGRECORD));
59        }
60
61        inline DWORD eventType() {
62                return pevlr_->EventType;
63        }
64
65        std::string enumStrings() {
66                std::string ret;
67                LPSTR p = reinterpret_cast<LPSTR>(reinterpret_cast<LPBYTE>(pevlr_) + pevlr_->StringOffset);
68                for (unsigned int i =0;i<pevlr_->NumStrings;i++) {
69                        std::string s = p;
70                        if (!s.empty())
71                                s += ", ";
72                        ret += s;
73                        p+= strlen(p)+1;
74                }
75                return ret;
76        }
77
78        static DWORD appendType(DWORD dwType, std::string sType) {
79                return dwType | translateType(sType);
80        }
81        static DWORD subtractType(DWORD dwType, std::string sType) {
82                return dwType & (!translateType(sType));
83        }
84        static DWORD translateType(std::string sType) {
85                if (sType == "error")
86                        return EVENTLOG_ERROR_TYPE;
87                if (sType == "warning")
88                        return EVENTLOG_WARNING_TYPE;
89                if (sType == "info")
90                        return EVENTLOG_INFORMATION_TYPE;
91                if (sType == "auditSuccess")
92                        return EVENTLOG_AUDIT_SUCCESS;
93                if (sType == "auditFailure")
94                        return EVENTLOG_AUDIT_FAILURE;
95                return 0;
96        }
97
98};
99
100
101struct searchQuery {
102        struct searchQueryBundle {
103                struct searchQueryItem {
104                        DWORD eventType_;
105                        std::string eventSource_;
106                        boost::regex eventSourceRegExp_;
107                        bool notSetValue_;
108                        DWORD writtenBeforeDelta_ ;
109                        DWORD writtenAfterDelta_ ;
110                        DWORD generatedBeforeDelta_;
111                        DWORD generatedAfterDelta_;
112                        boost::regex regexp_;
113
114                        searchQueryItem(bool notSetValue)
115                                : eventType_(0), notSetValue_(notSetValue),
116                                writtenBeforeDelta_(0), writtenAfterDelta_(0) ,
117                                generatedBeforeDelta_(0), generatedAfterDelta_(0)
118                        {}
119                        searchQueryItem& operator=(const searchQueryItem &other) {
120                                eventType_ = other.eventType_;
121                                eventSource_ = other.eventSource_;
122                                notSetValue_ = other.notSetValue_;
123                                writtenBeforeDelta_ = other.writtenBeforeDelta_;
124                                writtenAfterDelta_ = other.writtenAfterDelta_;
125                                generatedBeforeDelta_ = other.generatedBeforeDelta_;
126                                generatedAfterDelta_ = other.generatedAfterDelta_;
127                                try {
128                                        regexp_ = other.regexp_;
129                                } catch (const boost::bad_expression e) {
130                                        throw (std::string)"Invalid syntax in regular expression:" + other.toString();
131                                }
132                                try {
133                                        eventSourceRegExp_ = other.eventSourceRegExp_;
134                                } catch (const boost::bad_expression e) {
135                                        throw (std::string)"Invalid syntax in event source regular expression:" + other.toString();
136                                }
137                                return *this;
138                        }
139
140                        inline bool matchDateWritten(DWORD now, DWORD written) const {
141                                if ((writtenAfterDelta_ == 0)&&(writtenBeforeDelta_ == 0))
142                                        return notSetValue_;
143                                bool ret = true;
144                                if (writtenAfterDelta_ != 0) {
145                                        if (writtenAfterDelta_+written <= now)
146                                                ret = false;
147                                }
148                                if (writtenBeforeDelta_ != 0) {
149                                        if (writtenBeforeDelta_+written > now)
150                                                ret = false;
151                                }
152                                return ret;
153                        }
154                        inline bool matchDateGenerated(DWORD now, DWORD written) const {
155                                if ((generatedAfterDelta_ == 0)&&(generatedBeforeDelta_ == 0))
156                                        return notSetValue_;
157                                bool ret = true;
158                                if (generatedAfterDelta_ != 0) {
159                                        if (generatedAfterDelta_+written <= now)
160                                                ret = false;
161                                }
162                                if (generatedBeforeDelta_ != 0) {
163                                        if (generatedBeforeDelta_+written > now)
164                                                ret = false;
165                                }
166                                return ret;
167                        }
168                        inline bool matchType(DWORD eventType) const {
169                                if (eventType_ == 0)
170                                        return notSetValue_;
171                                return eventType_ & eventType;
172                        }
173                        inline bool matchSource(std::string eventSource) const {
174                                if ((eventSource_.empty())&&eventSourceRegExp_.empty())
175                                        return notSetValue_;
176                                else if (eventSource_.empty())
177                                        return boost::regex_match(eventSource, eventSourceRegExp_);
178                                else if (eventSourceRegExp_.empty())
179                                        return eventSource_ == eventSource;
180                                return boost::regex_match(eventSource, eventSourceRegExp_) && (eventSource_ == eventSource);
181                        }
182                        inline bool matchRegexp(std::string msg) const {
183                                if (regexp_.empty())
184                                        return notSetValue_;
185                                return boost::regex_match(msg, regexp_);
186                        }
187                        std::string toString() const {
188                                std::stringstream ss;
189                                ss << "    Regexp: " << regexp_ << std::endl;
190                                ss << "    Event type: " << eventType_ << std::endl;
191                                ss << "    Event source: " << eventSource_ << std::endl;
192                                ss << "    Event source Regexp: " << eventSourceRegExp_ << std::endl;
193                                ss << "    Written delta: " << writtenAfterDelta_ << " > " << writtenBeforeDelta_ << std::endl;
194                                ss << "    Generated delta: " << generatedAfterDelta_ << " > " << generatedBeforeDelta_ << std::endl;
195                                return ss.str();
196                        }
197                };
198                struct searchQueryItem require;
199                struct searchQueryItem exclude;
200                searchQueryBundle() : require(true), exclude(false) {}
201                std::string toString() {
202                        return "  Required:\n" + require.toString()  + "\n  Exclude:\n" + exclude.toString();
203                }
204        };
205
206        searchQueryBundle warn;
207        searchQueryBundle critical;
208        unsigned int truncate;
209        bool descriptions;
210        searchQuery() : truncate(0), descriptions(false) {}
211
212        std::string toString() {
213                return "Warn:\n" + warn.toString()  + "\nCritical:\n" + critical.toString();
214        }
215
216};
217
218void addToQueryItem(searchQuery::searchQueryBundle::searchQueryItem &item, std::string arg) {
219        std::pair<std::string,std::string> p = strEx::split(arg, "=");
220        if (p.first == "eventType")
221                item.eventType_ = EventLogRecord::appendType(item.eventType_, p.second);
222        else if (p.first == "eventSource")
223                item.eventSource_ = p.second;
224        else if (p.first == "eventSourceRegexp") {
225                try {
226                        std::string s = p.second;
227                        item.eventSourceRegExp_ = s;
228                } catch (const boost::bad_expression e) {
229                        item.eventSourceRegExp_ = "";
230                        throw (std::string)"Invalid syntax in regular expression:" + p.second;
231                }
232        }
233        else if (p.first == "generatedBeforeDelta")
234                item.generatedBeforeDelta_ = strEx::stoi(p.second);
235        else if (p.first == "generatedAfterDelta")
236                item.generatedAfterDelta_ = strEx::stoi(p.second);
237        else if (p.first == "writtenBeforeDelta")
238                item.writtenBeforeDelta_ = strEx::stoi(p.second);
239        else if (p.first == "writtenAfterDelta")
240                item.writtenAfterDelta_ = strEx::stoi(p.second);
241        else if (p.first == "regexp") {
242                try {
243                        item.regexp_ = p.second;
244                } catch (const boost::bad_expression e) {
245                        item.regexp_ = "";
246                        throw (std::string)"Invalid syntax in regular expression:" + p.second;
247                }
248        } else
249                throw (std::string)"Invalid argument: " + p.first;
250       
251}
252void addToQueryBundle(searchQuery::searchQueryBundle &bundle, std::string arg) {
253        std::pair<std::string,std::string> p = strEx::split(arg, ".");
254        if (p.first == "require")
255                addToQueryItem(bundle.require, p.second);
256        else if (p.first == "exclude")
257                addToQueryItem(bundle.exclude, p.second);
258        else
259                throw (std::string)"Invalid require/exclude: " + p.first;
260}
261void addToQuery(searchQuery &q, std::string arg) {
262        std::pair<std::string,std::string> p = strEx::split(arg, ".");
263        if (p.first == "warn")
264                addToQueryBundle(q.warn, p.second);
265        else if (p.first == "critical")
266                addToQueryBundle(q.critical, p.second);
267        else if (p.first == "all") {
268                addToQueryBundle(q.warn, p.second);
269                addToQueryBundle(q.critical, p.second);
270        } else {
271                std::pair<std::string,std::string> p = strEx::split(arg, "=");
272                if (p.first == "truncate")
273                        q.truncate = strEx::stoi(p.second);
274                else if (p.first == "descriptions")
275                        q.descriptions = true;
276                else
277                        throw (std::string)"Invalid argument: " + arg;
278        }
279}
280
281void buildQury(searchQuery &query, std::list<std::string> args) {
282        for (std::list<std::string>::const_iterator it = args.begin(); it!=args.end(); it++) {
283                NSC_DEBUG_MSG_STD("Adding: " + *it);
284                addToQuery(query, *it);
285        }
286}
287// CheckEventLog
288// request: CheckEventLog&<logfile>&<Query strings>
289// Return: <return state>&<log entry 1> - <log entry 2>...
290// <return state>       0 - No errors
291//                                      1 - Unknown
292//                                      2 - Errors
293// Examples:
294// CheckEventLog&Application&1&<type>&<query>&huffa...
295// CheckEventLog&Application&warn.require.eventType=warning&critical.require.eventType=error&truncate=1024&descriptions&all.exclude.eventSourceRegexp=^(Win|Msi|NSClient\+\+|Userenv|ASP\.NET|LoadPerf|Outlook|Application E|NSClient).*
296#define BUFFER_SIZE 1024*64
297
298NSCAPI::nagiosReturn CheckEventLog::handleCommand(const std::string command, const unsigned int argLen, char **char_args, std::string &message, std::string &perf) {
299        if (command != "CheckEventLog")
300                return NSCAPI::returnIgnored;
301        NSCAPI::nagiosReturn rCode = NSCAPI::returnOK;
302        std::list<std::string> args = NSCHelper::arrayBuffer2list(argLen, char_args);
303        if (args.size() < 2) {
304                message = "Missing argument";
305                return NSCAPI::returnCRIT;
306        }
307        std::string ret;
308        bool critical = false;
309        searchQuery query;
310        std::string logFile = args.front(); args.pop_front();
311        try {
312                buildQury(query, args);
313        } catch (std::string s) {
314                message = s;
315                return NSCAPI::returnCRIT;
316        }
317        NSC_DEBUG_MSG_STD("Base query: " + query.toString());
318
319        HANDLE hLog = OpenEventLog(NULL, logFile.c_str());
320        if (hLog == NULL) {
321                message = "Could not open the Application event log.";
322                return NSCAPI::returnUNKNOWN;
323        }
324
325        DWORD dwThisRecord, dwRead, dwNeeded;
326        EVENTLOGRECORD *pevlr;
327        BYTE bBuffer[BUFFER_SIZE];
328
329        pevlr = reinterpret_cast<EVENTLOGRECORD*>(&bBuffer);
330
331        // get time now !!!
332        __time64_t ltime;
333        _time64(&ltime);
334        DWORD currentTime = ltime;
335
336        GetOldestEventLogRecord(hLog, &dwThisRecord);
337
338        while (ReadEventLog(hLog, EVENTLOG_FORWARDS_READ|EVENTLOG_SEQUENTIAL_READ,
339                0, pevlr, BUFFER_SIZE, &dwRead, &dwNeeded))
340        {
341                while (dwRead > 0)
342                {
343                        bool match = false;
344                        bool c = false;
345                        EventLogRecord record(pevlr);
346
347                        if ( query.critical.require.matchType(record.eventType()) &&
348                                query.critical.require.matchSource(record.eventSource()) &&
349                                query.critical.require.matchDateGenerated(currentTime, record.timeGenerated()) &&
350                                query.critical.require.matchDateWritten(currentTime, record.timeWritten()) &&
351                                query.critical.require.matchRegexp(record.enumStrings())
352                                ) {
353                                        match = true;
354                                        c = true;
355                                }
356                        if ( query.critical.exclude.matchType(record.eventType()) ||
357                                query.critical.exclude.matchSource(record.eventSource()) ||
358                                query.critical.exclude.matchDateGenerated(currentTime, record.timeGenerated()) ||
359                                query.critical.exclude.matchDateWritten(currentTime, record.timeWritten()) ||
360                                query.critical.exclude.matchRegexp(record.enumStrings())
361                                ) {
362                                        match = false;
363                                        c = false;
364                                }
365
366                        if ( query.warn.require.matchType(record.eventType()) &&
367                                query.warn.require.matchSource(record.eventSource()) &&
368                                query.warn.require.matchDateGenerated(currentTime, record.timeGenerated()) &&
369                                query.warn.require.matchDateWritten(currentTime, record.timeWritten()) &&
370                                query.warn.require.matchRegexp(record.enumStrings())
371                                )
372                                match = true;
373                        if ( query.warn.exclude.matchType(record.eventType()) ||
374                                query.warn.exclude.matchSource(record.eventSource()) ||
375                                query.warn.exclude.matchDateGenerated(currentTime, record.timeGenerated()) ||
376                                query.warn.exclude.matchDateWritten(currentTime, record.timeWritten()) ||
377                                query.warn.exclude.matchRegexp(record.enumStrings())
378                                )
379                                match = false;
380                       
381                        if (match) {
382                                if (c)
383                                        critical = true;
384                                if (!ret.empty())
385                                        ret += " - ";
386                                ret += record.eventSource();
387                                if (query.descriptions) {
388                                        std::string s = record.enumStrings();
389                                        if (!s.empty())
390                                                ret += " [" + s + "]" ;
391                                }
392                        }
393                        dwRead -= pevlr->Length;
394                        pevlr = (EVENTLOGRECORD *)
395                                ((LPBYTE) pevlr + pevlr->Length);
396                }
397
398                pevlr = (EVENTLOGRECORD *) &bBuffer;
399        }
400
401        CloseEventLog(hLog);
402        if (critical)
403                ret = "CRITICAL: " + ret;
404        else if (!ret.empty())
405                ret = "WARNING: " + ret;
406        else
407                ret = "OK: No errors/warnings in event log.";
408        if (query.truncate != 0)
409                ret = ret.substr(0, query.truncate);
410        message = ret;
411        return rCode;
412}
413
414
415NSC_WRAPPERS_MAIN_DEF(gCheckEventLog);
416NSC_WRAPPERS_IGNORE_MSG_DEF();
417NSC_WRAPPERS_HANDLE_CMD_DEF(gCheckEventLog);
Note: See TracBrowser for help on using the repository browser.