source: nscp/trunk/modules/CheckEventLog/CheckEventLog.cpp @ 24f7192

Last change on this file since 24f7192 was 24f7192, checked in by Michael Medin <michael@…>, 8 years ago

changes all over manily in the checking code

  • Property mode set to 100644
File size: 11.4 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
30bool CheckEventLog::hasCommandHandler() {
31        return true;
32}
33bool CheckEventLog::hasMessageHandler() {
34        return false;
35}
36
37
38
39class EventLogRecord {
40        EVENTLOGRECORD *pevlr_;
41public:
42        EventLogRecord(EVENTLOGRECORD *pevlr) : pevlr_(pevlr) {
43        }
44        inline DWORD timeGenerated() const {
45                return pevlr_->TimeGenerated;
46        }
47        inline DWORD timeWritten() const {
48                return pevlr_->TimeWritten;
49        }
50        inline std::string eventSource() const {
51                return reinterpret_cast<LPSTR>(reinterpret_cast<LPBYTE>(pevlr_) + sizeof(EVENTLOGRECORD));
52        }
53
54        inline DWORD eventType() const {
55                return pevlr_->EventType;
56        }
57/*
58        std::string userSID() const {
59                if (pevlr_->UserSidOffset == 0)
60                        return "";
61                PSID p = reinterpret_cast<PSID>(reinterpret_cast<LPBYTE>(pevlr_) + + pevlr_->UserSidOffset);
62                LPSTR user = new CHAR[1025];
63                LPSTR domain = new CHAR[1025];
64                DWORD userLen = 1024;
65                DWORD domainLen = 1024;
66                SID_NAME_USE sidName;
67                LookupAccountSid(NULL, p, user, &userLen, domain, &domainLen, &sidName);
68                user[userLen] = 0;
69                domain[domainLen] = 0;
70                return std::string(domain) + "\\" + std::string(user);
71        }
72        */
73
74        std::string enumStrings() const {
75                std::string ret;
76                LPSTR p = reinterpret_cast<LPSTR>(reinterpret_cast<LPBYTE>(pevlr_) + pevlr_->StringOffset);
77                for (unsigned int i =0;i<pevlr_->NumStrings;i++) {
78                        std::string s = p;
79                        if (!s.empty())
80                                s += ", ";
81                        ret += s;
82                        p+= strlen(p)+1;
83                }
84                return ret;
85        }
86
87        static DWORD appendType(DWORD dwType, std::string sType) {
88                return dwType | translateType(sType);
89        }
90        static DWORD subtractType(DWORD dwType, std::string sType) {
91                return dwType & (!translateType(sType));
92        }
93        static DWORD translateType(std::string sType) {
94                if (sType == "error")
95                        return EVENTLOG_ERROR_TYPE;
96                if (sType == "warning")
97                        return EVENTLOG_WARNING_TYPE;
98                if (sType == "info")
99                        return EVENTLOG_INFORMATION_TYPE;
100                if (sType == "auditSuccess")
101                        return EVENTLOG_AUDIT_SUCCESS;
102                if (sType == "auditFailure")
103                        return EVENTLOG_AUDIT_FAILURE;
104                return strEx::stoi(sType);
105        }
106        static std::string translateType(DWORD dwType) {
107                if (dwType == EVENTLOG_ERROR_TYPE)
108                        return "error";
109                if (dwType == EVENTLOG_WARNING_TYPE)
110                        return "warning";
111                if (dwType == EVENTLOG_INFORMATION_TYPE)
112                        return "info";
113                if (dwType == EVENTLOG_AUDIT_SUCCESS)
114                        return "auditSuccess";
115                if (dwType == EVENTLOG_AUDIT_FAILURE)
116                        return "auditFailure";
117                return strEx::itos(dwType);
118        }
119
120};
121
122
123struct searchQuery {
124                struct searchQueryItem {
125
126                        typedef enum {
127                                eventType,
128                                eventSource,
129                                timeWritten,
130                                timeGenerated,
131                                message,
132                                none
133                        } queryType;
134
135                        typedef enum { out, in, undefined } filterType;
136
137                        filterType filter_;
138                        queryType queryType_;
139                        DWORD dwValue_;
140                        boost::regex regexp_;
141                       
142
143                        searchQueryItem()
144                                : queryType_(none), dwValue_(0), filter_(out)
145                        {}
146                        searchQueryItem(filterType filter, queryType type, std::string str)
147                                : queryType_(type), dwValue_(0), filter_(filter)
148                        {
149                                switch (queryType_ ) {
150                                case eventType:
151                                        dwValue_ = EventLogRecord::translateType(str);
152                                        break;
153
154                                case timeGenerated:
155                                        dwValue_ = strEx::stoui_as_time(str)/1000;
156                                        break;
157
158                                case eventSource:
159                                case message:
160                                        try {
161                                                regexp_ = str;
162                                        } catch (const boost::bad_expression e) {
163                                                throw (std::string)"Invalid syntax in regular expression:" + str;
164                                        }
165                                        break;
166                                }
167                        }
168
169                        searchQueryItem& operator=(const searchQueryItem &other) {
170                                queryType_ = other.queryType_;
171                                dwValue_ = other.dwValue_;
172                                filter_ = other.filter_;
173                                try {
174                                        regexp_ = other.regexp_;
175                                } catch (const boost::bad_expression e) {
176                                        throw (std::string)"Invalid syntax in regular expression:" + other.toString();
177                                }
178                                return *this;
179                        }
180
181                        bool match(DWORD now, const EventLogRecord &record) const {
182                                switch (queryType_) {
183                                case eventType:
184                                        return record.eventType() & dwValue_;
185
186                                case eventSource:
187                                        if (regexp_.empty())
188                                                return false;
189                                        return boost::regex_match(record.eventSource(), regexp_);
190
191                                case timeWritten:
192                                        return record.timeWritten() < (now-dwValue_);
193
194                                case timeGenerated:
195                                        return record.timeGenerated() < (now-dwValue_);
196
197                                case message:
198                                        if (regexp_.empty())
199                                                return false;
200                                        return boost::regex_match(record.enumStrings(), regexp_);
201
202                                default:
203                                        return false;
204                                }
205                        }
206                        std::string queryType2String(queryType query) const {
207                                switch (queryType_) {
208                                case eventType:
209                                        return "eventType";
210                                case eventSource:
211                                        return "eventSource";
212                                case timeWritten:
213                                        return "timeWritten";
214                                case timeGenerated:
215                                        return "timeGenerated";
216                                case message:
217                                        return "message";
218                                default:
219                                        return "unknown";
220                                }
221
222                        }
223
224                        std::string toString() const {
225                                std::stringstream ss;
226                                ss << " Type: " << queryType2String(queryType_) << " = " << dwValue_ << ", '" << regexp_ << "'";
227                                return ss.str();
228                        }
229                };
230
231
232
233        unsigned int truncate;
234        unsigned warning_count;
235        unsigned critical_count;
236        bool descriptions;
237        std::list<searchQueryItem> queries;
238
239        searchQuery() : truncate(0), descriptions(false), warning_count(0), critical_count(0) {}
240
241        std::string toString() {
242                std::string ret;
243                for (std::list<searchQuery::searchQueryItem>::const_iterator cit = queries.begin(); cit != queries.end(); ++cit ) {
244                        ret += (*cit).toString();
245                }
246                return ret;
247        }
248
249};
250
251// checkEventLog file=application truncate=1024 descriptions filter=[out|in]
252//                                      warning-count=3 critical-count=10
253// filter type = warning AND generated > 1d
254//
255// match (type, "warning") && match(generated, "1d")
256//                                      filer-eventType=warning
257//                                      filer-eventSource=
258//                                      filer-date=4d
259//
260// CheckEventLog
261// request: CheckEventLog&<logfile>&<Query strings>
262// Return: <return state>&<log entry 1> - <log entry 2>...
263// <return state>       0 - No errors
264//                                      1 - Unknown
265//                                      2 - Errors
266
267// ./nrpe-2.0/src/check_nrpe -H 192.168.167 -p 5666 -c checkEventLog -a file=system file=application filter-eventType=warning filter-generated=1d descriptions filter-eventSource=Cdrom filter-eventSource=NSClient warning-count=3 critical-count=7 filter=in truncate=512
268//
269// Examples:
270// CheckEventLog&Application&1&<type>&<query>&huffa...
271// 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).*
272#define BUFFER_SIZE 1024*64
273NSCAPI::nagiosReturn CheckEventLog::handleCommand(const strEx::blindstr command, const unsigned int argLen, char **char_args, std::string &message, std::string &perf) {
274        if (command != "CheckEventLog")
275                return NSCAPI::returnIgnored;
276        NSCAPI::nagiosReturn rCode = NSCAPI::returnOK;
277        std::list<std::string> args = arrayBuffer::arrayBuffer2list(argLen, char_args);
278
279        std::string ret;
280        searchQuery query;
281        std::list<std::string> files;
282        searchQuery::searchQueryItem::filterType filter = searchQuery::searchQueryItem::out;
283
284        for (std::list<std::string>::const_iterator it = args.begin(); it!=args.end(); ++it) {
285                try {
286                        if ((*it) == "descriptions") {
287                                query.descriptions = true;
288                        } else {
289                                std::pair<std::string,std::string> p = strEx::split((*it), "=");
290                                if (p.first == "truncate") {
291                                        query.truncate = strEx::stoi(p.second);
292                                } else if (p.first == "file") {
293                                        files.push_back(p.second);
294                                } else if (p.first == "filter") {
295                                        if (p.second == "in")
296                                                filter = searchQuery::searchQueryItem::in;
297                                        else
298                                                filter = searchQuery::searchQueryItem::out;
299                                } else if (p.first == "warning-count") {
300                                        query.warning_count = strEx::stoi(p.second);
301                                } else if (p.first == "critical-count") {
302                                        query.critical_count = strEx::stoi(p.second);
303
304                                } else if (p.first == "filter-eventType") {
305                                        query.queries.push_back(searchQuery::searchQueryItem(filter, searchQuery::searchQueryItem::eventType, p.second));
306                                } else if (p.first == "filter-eventSource") {
307                                        query.queries.push_back(searchQuery::searchQueryItem(filter, searchQuery::searchQueryItem::eventSource, p.second));
308                                } else if (p.first == "filter-generated") {
309                                        query.queries.push_back(searchQuery::searchQueryItem(filter, searchQuery::searchQueryItem::timeGenerated, p.second));
310                                } else if (p.first == "filter-written") {
311                                        query.queries.push_back(searchQuery::searchQueryItem(filter, searchQuery::searchQueryItem::timeWritten, p.second));
312                                } else if (p.first == "filter-message") {
313                                        query.queries.push_back(searchQuery::searchQueryItem(filter, searchQuery::searchQueryItem::message, p.second));
314                                }
315                        }
316                } catch (std::string s) {
317                        if (message.empty())
318                                message += "UNKNOWN: ";
319                        else
320                                message += ", ";
321                        message += s;
322                }
323        }
324        if (!message.empty()) {
325                return NSCAPI::returnUNKNOWN;
326        }
327
328        unsigned int hit_count = 0;
329
330        for (std::list<std::string>::const_iterator cit2 = files.begin(); cit2 != files.end(); ++cit2) {
331                HANDLE hLog = OpenEventLog(NULL, (*cit2).c_str());
332                if (hLog == NULL) {
333                        message = "Could not open the '" + (*cit2) + "' event log.";
334                        return NSCAPI::returnUNKNOWN;
335                }
336
337                DWORD dwThisRecord, dwRead, dwNeeded;
338                EVENTLOGRECORD *pevlr;
339                BYTE bBuffer[BUFFER_SIZE];
340
341                pevlr = reinterpret_cast<EVENTLOGRECORD*>(&bBuffer);
342
343                __time64_t ltime;
344                _time64(&ltime);
345                DWORD currentTime = ltime;
346
347                GetOldestEventLogRecord(hLog, &dwThisRecord);
348
349                while (ReadEventLog(hLog, EVENTLOG_FORWARDS_READ|EVENTLOG_SEQUENTIAL_READ,
350                        0, pevlr, BUFFER_SIZE, &dwRead, &dwNeeded))
351                {
352                        while (dwRead > 0)
353                        {
354                                bool match = false;
355                                bool undefined = true;
356                                searchQuery::searchQueryItem::filterType tFilter = searchQuery::searchQueryItem::out;
357                                EventLogRecord record(pevlr);
358
359                                for (std::list<searchQuery::searchQueryItem>::const_iterator cit3 = query.queries.begin(); cit3 != query.queries.end(); ++cit3 ) {
360                                        if ((*cit3).match(currentTime, record)) {
361                                                if ((*cit3).filter_ == searchQuery::searchQueryItem::in)
362                                                        match = true;
363                                                else {
364                                                        match = false;
365                                                }
366                                        }
367                                }
368
369                                if (match) {
370                                        if (!ret.empty())
371                                                ret += ", ";
372                                        ret += record.eventSource();
373                                        if (query.descriptions) {
374                                                ret += "(" + EventLogRecord::translateType(record.eventType()) + ")";
375                                                ret += "[" + record.enumStrings() + "]";
376                                        }
377                                        hit_count++;
378                                }
379
380                                dwRead -= pevlr->Length;
381                                pevlr = (EVENTLOGRECORD *) ((LPBYTE) pevlr + pevlr->Length);
382                        }
383
384                        pevlr = (EVENTLOGRECORD *) &bBuffer;
385                }
386
387                CloseEventLog(hLog);
388        }
389
390        if ((query.critical_count > 0) && (hit_count > query.critical_count)) {
391                ret = "CRITICAL: " + strEx::itos(hit_count) + " > critical: " + ret;
392                rCode = NSCAPI::returnCRIT;
393        } else if ((query.warning_count > 0) && (hit_count > query.warning_count)) {
394                ret = "WARNING: " + strEx::itos(hit_count) + " > warning: " + ret;
395                rCode = NSCAPI::returnWARN;
396        } else {
397                ret = "OK: " + strEx::itos(hit_count) + ": " + ret;
398        }
399        if (query.truncate != 0)
400                ret = ret.substr(0, query.truncate);
401        if ((query.truncate > 0) && (ret.length() > query.truncate))
402                ret = ret.substr(0, query.truncate);
403        message = ret;
404        return rCode;
405}
406
407
408NSC_WRAPPERS_MAIN_DEF(gCheckEventLog);
409NSC_WRAPPERS_IGNORE_MSG_DEF();
410NSC_WRAPPERS_HANDLE_CMD_DEF(gCheckEventLog);
Note: See TracBrowser for help on using the repository browser.