source: nscp/modules/CheckEventLog/CheckEventLog.cpp @ 8223547

0.4.00.4.10.4.2stable
Last change on this file since 8223547 was 8223547, checked in by Michael Medin <michael@…>, 8 years ago
  • Improved thread safety in Core + Added exception handling and logging in PDH code
  • Various fixes all over the place + New module for check size of files/directories
  • Changed build to Dynamic link
  • Added regular expression support for EventLog? checker
  • Property mode set to 100644
File size: 12.5 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
298std::string CheckEventLog::handleCommand(const std::string command, const unsigned int argLen, char **char_args) {
299        if (command != "CheckEventLog")
300                return "";
301        NSCAPI::returnCodes rCode = NSCAPI::returnOK;
302        std::list<std::string> args = NSCHelper::arrayBuffer2list(argLen, char_args);
303        if (args.size() < 2)
304                return "Missing argument";
305        std::string ret;
306        bool critical = false;
307        searchQuery query;
308        std::string logFile = args.front(); args.pop_front();
309        try {
310                buildQury(query, args);
311        } catch (std::string s) {
312                return NSCHelper::returnNSCP(NSCAPI::returnUNKNOWN, s);
313        }
314        NSC_DEBUG_MSG_STD("Base query: " + query.toString());
315
316        HANDLE hLog = OpenEventLog(NULL, logFile.c_str());
317        if (hLog == NULL)
318                return NSCHelper::returnNSCP(NSCAPI::returnUNKNOWN, "Could not open the Application event log.");
319
320        DWORD dwThisRecord, dwRead, dwNeeded;
321        EVENTLOGRECORD *pevlr;
322        BYTE bBuffer[BUFFER_SIZE];
323
324        pevlr = reinterpret_cast<EVENTLOGRECORD*>(&bBuffer);
325
326        // get time now !!!
327        __time64_t ltime;
328        _time64(&ltime);
329        DWORD currentTime = ltime;
330
331        GetOldestEventLogRecord(hLog, &dwThisRecord);
332
333        while (ReadEventLog(hLog, EVENTLOG_FORWARDS_READ|EVENTLOG_SEQUENTIAL_READ,
334                0, pevlr, BUFFER_SIZE, &dwRead, &dwNeeded))
335        {
336                while (dwRead > 0)
337                {
338                        bool match = false;
339                        bool c = false;
340                        EventLogRecord record(pevlr);
341
342                        if ( query.critical.require.matchType(record.eventType()) &&
343                                query.critical.require.matchSource(record.eventSource()) &&
344                                query.critical.require.matchDateGenerated(currentTime, record.timeGenerated()) &&
345                                query.critical.require.matchDateWritten(currentTime, record.timeWritten()) &&
346                                query.critical.require.matchRegexp(record.enumStrings())
347                                ) {
348                                        match = true;
349                                        c = true;
350                                }
351                        if ( query.critical.exclude.matchType(record.eventType()) ||
352                                query.critical.exclude.matchSource(record.eventSource()) ||
353                                query.critical.exclude.matchDateGenerated(currentTime, record.timeGenerated()) ||
354                                query.critical.exclude.matchDateWritten(currentTime, record.timeWritten()) ||
355                                query.critical.exclude.matchRegexp(record.enumStrings())
356                                ) {
357                                        match = false;
358                                        c = false;
359                                }
360
361                        if ( query.warn.require.matchType(record.eventType()) &&
362                                query.warn.require.matchSource(record.eventSource()) &&
363                                query.warn.require.matchDateGenerated(currentTime, record.timeGenerated()) &&
364                                query.warn.require.matchDateWritten(currentTime, record.timeWritten()) &&
365                                query.warn.require.matchRegexp(record.enumStrings())
366                                )
367                                match = true;
368                        if ( query.warn.exclude.matchType(record.eventType()) ||
369                                query.warn.exclude.matchSource(record.eventSource()) ||
370                                query.warn.exclude.matchDateGenerated(currentTime, record.timeGenerated()) ||
371                                query.warn.exclude.matchDateWritten(currentTime, record.timeWritten()) ||
372                                query.warn.exclude.matchRegexp(record.enumStrings())
373                                )
374                                match = false;
375                       
376                        if (match) {
377                                if (c)
378                                        critical = true;
379                                if (!ret.empty())
380                                        ret += " - ";
381                                ret += record.eventSource();
382                                if (query.descriptions) {
383                                        std::string s = record.enumStrings();
384                                        if (!s.empty())
385                                                ret += " [" + s + "]" ;
386                                }
387                        }
388                        dwRead -= pevlr->Length;
389                        pevlr = (EVENTLOGRECORD *)
390                                ((LPBYTE) pevlr + pevlr->Length);
391                }
392
393                pevlr = (EVENTLOGRECORD *) &bBuffer;
394        }
395
396        CloseEventLog(hLog);
397        if (critical)
398                ret = "CRITICAL: " + ret;
399        else if (!ret.empty())
400                ret = "WARNING: " + ret;
401        else
402                ret = "OK: No errors/warnings in event log.";
403        if (query.truncate != 0)
404                ret = ret.substr(0, query.truncate);
405        return NSCHelper::returnNSCP(rCode, ret);
406}
407
408
409NSC_WRAPPERS_MAIN_DEF(gCheckEventLog);
410NSC_WRAPPERS_IGNORE_MSG_DEF();
411NSC_WRAPPERS_HANDLE_CMD_DEF(gCheckEventLog);
Note: See TracBrowser for help on using the repository browser.