source: nscp/trunk/modules/CheckEventLog/CheckEventLog.cpp @ f7f536b

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

Multiple fixes in various places.

  • Added threadding blocks "core"
  • Added new Module (CheckDisk)
  • Added new option [log] / debug=1 to enable debug logs.
  • Added more error messages
  • other minor tweaks and fixes
  • 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                        NSC_DEBUG_MSG_STD("Attempting to make regexp from: " + s);
228                        item.eventSourceRegExp_ = s;
229                        NSC_DEBUG_MSG_STD("success...");
230                } catch (const boost::bad_expression e) {
231                        item.eventSourceRegExp_ = "";
232                        throw (std::string)"Invalid syntax in regular expression:" + p.second;
233                }
234        }
235        else if (p.first == "generatedBeforeDelta")
236                item.generatedBeforeDelta_ = strEx::stoi(p.second);
237        else if (p.first == "generatedAfterDelta")
238                item.generatedAfterDelta_ = strEx::stoi(p.second);
239        else if (p.first == "writtenBeforeDelta")
240                item.writtenBeforeDelta_ = strEx::stoi(p.second);
241        else if (p.first == "writtenAfterDelta")
242                item.writtenAfterDelta_ = strEx::stoi(p.second);
243        else if (p.first == "regexp") {
244                try {
245                        item.regexp_ = p.second;
246                } catch (const boost::bad_expression e) {
247                        item.regexp_ = "";
248                        throw (std::string)"Invalid syntax in regular expression:" + p.second;
249                }
250        } else
251                throw (std::string)"Invalid argument: " + p.first;
252}
253void addToQueryBundle(searchQuery::searchQueryBundle &bundle, std::string arg) {
254        std::pair<std::string,std::string> p = strEx::split(arg, ".");
255        if (p.first == "require")
256                addToQueryItem(bundle.require, p.second);
257        else if (p.first == "exclude")
258                addToQueryItem(bundle.exclude, p.second);
259        else
260                throw (std::string)"Invalid require/exclude: " + p.first;
261}
262void addToQuery(searchQuery &q, std::string arg) {
263        std::pair<std::string,std::string> p = strEx::split(arg, ".");
264        if (p.first == "warn")
265                addToQueryBundle(q.warn, p.second);
266        else if (p.first == "critical")
267                addToQueryBundle(q.critical, p.second);
268        else if (p.first == "all") {
269                addToQueryBundle(q.warn, p.second);
270                addToQueryBundle(q.critical, p.second);
271        } else {
272                std::pair<std::string,std::string> p = strEx::split(arg, "=");
273                if (p.first == "truncate")
274                        q.truncate = strEx::stoi(p.second);
275                else if (p.first == "descriptions")
276                        q.descriptions = true;
277                else
278                        throw (std::string)"Invalid argument: " + arg;
279        }
280}
281
282void buildQury(searchQuery &query, std::list<std::string> args) {
283        for (std::list<std::string>::const_iterator it = args.begin(); it!=args.end(); it++) {
284                NSC_DEBUG_MSG_STD("Adding: " + *it);
285                addToQuery(query, *it);
286        }
287}
288// CheckEventLog
289// request: CheckEventLog&<logfile>&<Query strings>
290// Return: <return state>&<log entry 1> - <log entry 2>...
291// <return state>       0 - No errors
292//                                      1 - Unknown
293//                                      2 - Errors
294// Examples:
295// CheckEventLog&Application&1&<type>&<query>&huffa...
296// 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).*
297#define BUFFER_SIZE 1024*64
298
299std::string CheckEventLog::handleCommand(const std::string command, const unsigned int argLen, char **char_args) {
300        if (command != "CheckEventLog")
301                return "";
302        NSCAPI::returnCodes rCode = NSCAPI::returnOK;
303        std::list<std::string> args = NSCHelper::makelist(argLen, char_args);
304        if (args.size() < 2)
305                return "Missing argument";
306        std::string ret;
307        bool critical = false;
308        searchQuery query;
309        std::string logFile = args.front(); args.pop_front();
310        try {
311                buildQury(query, args);
312        } catch (std::string s) {
313                return NSCHelper::returnNSCP(NSCAPI::returnUNKNOWN, s);
314        }
315        NSC_DEBUG_MSG_STD("Base query: " + query.toString());
316
317        HANDLE hLog = OpenEventLog(NULL, logFile.c_str());
318        if (hLog == NULL)
319                return NSCHelper::returnNSCP(NSCAPI::returnUNKNOWN, "Could not open the Application event log.");
320
321        DWORD dwThisRecord, dwRead, dwNeeded;
322        EVENTLOGRECORD *pevlr;
323        BYTE bBuffer[BUFFER_SIZE];
324
325        pevlr = reinterpret_cast<EVENTLOGRECORD*>(&bBuffer);
326
327        // get time now !!!
328        __time64_t ltime;
329        _time64(&ltime);
330        DWORD currentTime = ltime;
331
332        GetOldestEventLogRecord(hLog, &dwThisRecord);
333
334        while (ReadEventLog(hLog, EVENTLOG_FORWARDS_READ|EVENTLOG_SEQUENTIAL_READ,
335                0, pevlr, BUFFER_SIZE, &dwRead, &dwNeeded))
336        {
337                while (dwRead > 0)
338                {
339                        bool match = false;
340                        bool c = false;
341                        EventLogRecord record(pevlr);
342
343                        if ( query.critical.require.matchType(record.eventType()) &&
344                                query.critical.require.matchSource(record.eventSource()) &&
345                                query.critical.require.matchDateGenerated(currentTime, record.timeGenerated()) &&
346                                query.critical.require.matchDateWritten(currentTime, record.timeWritten()) &&
347                                query.critical.require.matchRegexp(record.enumStrings())
348                                ) {
349                                        match = true;
350                                        c = true;
351                                }
352                        if ( query.critical.exclude.matchType(record.eventType()) ||
353                                query.critical.exclude.matchSource(record.eventSource()) ||
354                                query.critical.exclude.matchDateGenerated(currentTime, record.timeGenerated()) ||
355                                query.critical.exclude.matchDateWritten(currentTime, record.timeWritten()) ||
356                                query.critical.exclude.matchRegexp(record.enumStrings())
357                                ) {
358                                        match = false;
359                                        c = false;
360                                }
361
362                        if ( query.warn.require.matchType(record.eventType()) &&
363                                query.warn.require.matchSource(record.eventSource()) &&
364                                query.warn.require.matchDateGenerated(currentTime, record.timeGenerated()) &&
365                                query.warn.require.matchDateWritten(currentTime, record.timeWritten()) &&
366                                query.warn.require.matchRegexp(record.enumStrings())
367                                )
368                                match = true;
369                        if ( query.warn.exclude.matchType(record.eventType()) ||
370                                query.warn.exclude.matchSource(record.eventSource()) ||
371                                query.warn.exclude.matchDateGenerated(currentTime, record.timeGenerated()) ||
372                                query.warn.exclude.matchDateWritten(currentTime, record.timeWritten()) ||
373                                query.warn.exclude.matchRegexp(record.enumStrings())
374                                )
375                                match = false;
376                       
377                        if (match) {
378                                if (c)
379                                        critical = true;
380                                if (!ret.empty())
381                                        ret += " - ";
382                                ret += record.eventSource();
383                                if (query.descriptions) {
384                                        std::string s = record.enumStrings();
385                                        if (!s.empty())
386                                                ret += " [" + s + "]" ;
387                                }
388                        }
389                        dwRead -= pevlr->Length;
390                        pevlr = (EVENTLOGRECORD *)
391                                ((LPBYTE) pevlr + pevlr->Length);
392                }
393
394                pevlr = (EVENTLOGRECORD *) &bBuffer;
395        }
396
397        CloseEventLog(hLog);
398        if (critical)
399                ret = "CRITICAL: " + ret;
400        else if (!ret.empty())
401                ret = "WARNING: " + ret;
402        else
403                ret = "OK: No errors/warnings in event log.";
404        if (query.truncate != 0)
405                ret = ret.substr(0, query.truncate);
406        return NSCHelper::returnNSCP(rCode, ret);
407}
408
409
410NSC_WRAPPERS_MAIN_DEF(gCheckEventLog);
411NSC_WRAPPERS_IGNORE_MSG_DEF();
412NSC_WRAPPERS_HANDLE_CMD_DEF(gCheckEventLog);
Note: See TracBrowser for help on using the repository browser.