1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
11 #include "logcollector.h"
15 #define BUFFER_SIZE 2048*256
17 /* Event logging local structure */
18 typedef struct _os_el {
29 /** Global variables **/
31 /* Maximum of 9 event log sources */
34 void *vista_sec_id_hash = NULL;
35 void *dll_hash = NULL;
38 /* Start the event logging for each el */
39 int startEL(char *app, os_el *el)
41 DWORD NumberOfRecords = 0;
43 /* Open the event log */
44 el->h = OpenEventLog(NULL, app);
46 merror(EVTLOG_OPEN, ARGV0, app);
51 if (GetOldestEventLogRecord(el->h, &el->record) == 0) {
52 /* Unable to read oldest event log record */
53 merror(EVTLOG_GETLAST, ARGV0, app);
59 if (GetNumberOfEventLogRecords(el->h, &NumberOfRecords) == 0) {
60 merror(EVTLOG_GETLAST, ARGV0, app);
66 if (NumberOfRecords <= 0) {
70 return ((int)NumberOfRecords);
73 /* Returns a string that is a human readable datetime from an epoch int */
74 char *epoch_to_human(time_t epoch)
79 ts = localtime(&epoch);
80 strftime(buf, sizeof(buf), "%Y %b %d %H:%M:%S", ts);
84 /* Returns a string related to the category id of the log */
85 char *el_getCategory(int category_id)
88 switch (category_id) {
89 case EVENTLOG_ERROR_TYPE:
92 case EVENTLOG_WARNING_TYPE:
95 case EVENTLOG_INFORMATION_TYPE:
98 case EVENTLOG_AUDIT_SUCCESS:
99 cat = "AUDIT_SUCCESS";
101 case EVENTLOG_AUDIT_FAILURE:
102 cat = "AUDIT_FAILURE";
111 /* Returns the event */
112 char *el_getEventDLL(char *evt_name, char *source, char *event)
121 snprintf(keyname, 510,
122 "System\\CurrentControlSet\\Services\\EventLog\\%s\\%s",
126 /* Check if we have it in memory */
127 ret_str = OSHash_Get(dll_hash, keyname + 42);
133 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0,
134 KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) {
139 if (RegQueryValueEx(key, "EventMessageFile", NULL,
140 NULL, (LPBYTE)event, &ret) != ERROR_SUCCESS) {
145 /* Adding to memory */
149 skey = strdup(keyname + 42);
150 sval = strdup(event);
153 OSHash_Add(dll_hash, skey, sval);
155 merror(MEM_ERROR, ARGV0, errno, strerror(errno));
163 /* Returns a descriptive message of the event - Vista only */
164 char *el_vista_getMessage(int evt_id_int, LPTSTR *el_sstring)
167 LPSTR message = NULL;
171 /* Flags for format event */
172 fm_flags |= FORMAT_MESSAGE_FROM_STRING;
173 fm_flags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
174 fm_flags |= FORMAT_MESSAGE_ARGUMENT_ARRAY;
176 /* Get descriptive message */
178 snprintf(evt_id, 15, "%d", evt_id_int);
180 desc_string = OSHash_Get(vista_sec_id_hash, evt_id);
185 if (!FormatMessage(fm_flags, desc_string, 0, 0,
186 (LPTSTR) &message, 0, el_sstring)) {
193 /* Returns a descriptive message of the event */
194 char *el_getMessage(EVENTLOGRECORD *er, char *name,
195 char *source, LPTSTR *el_sstring)
199 char event[MAX_PATH + 1];
202 LPSTR message = NULL;
206 /* Initialize variables */
207 event[MAX_PATH] = '\0';
210 /* Flags for format event */
211 fm_flags |= FORMAT_MESSAGE_FROM_HMODULE;
212 fm_flags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
213 fm_flags |= FORMAT_MESSAGE_ARGUMENT_ARRAY;
215 /* Get the file name from the registry (stored on event) */
216 if (!(curr_str = el_getEventDLL(name, source, event))) {
220 /* If our event has multiple libraries, try each one of them */
221 while ((next_str = strchr(curr_str, ';'))) {
224 ExpandEnvironmentStrings(curr_str, tmp_str, 255);
226 /* Revert back old value */
230 hevt = LoadLibraryEx(tmp_str, NULL,
231 DONT_RESOLVE_DLL_REFERENCES |
232 LOAD_LIBRARY_AS_DATAFILE);
234 if (!FormatMessage(fm_flags, hevt, er->EventID, 0,
235 (LPTSTR) &message, 0, el_sstring)) {
240 /* If we have a message, we can return it */
246 curr_str = next_str + 1;
250 ExpandEnvironmentStrings(curr_str, tmp_str, 255);
251 hevt = LoadLibraryEx(tmp_str, NULL,
252 DONT_RESOLVE_DLL_REFERENCES |
253 LOAD_LIBRARY_AS_DATAFILE);
256 if (!(hr = FormatMessage(fm_flags, hevt, er->EventID,
258 (LPTSTR) &message, 0, el_sstring))) {
263 /* If we have a message, we can return it */
272 /* Reads the event log */
273 void readel(os_el *el, int printit)
275 DWORD _evtid = 65535;
284 char mbuffer[BUFFER_SIZE + 1];
287 char *tmp_str = NULL;
291 char *descriptive_msg;
293 char el_user[OS_FLSIZE + 1];
294 char el_domain[OS_FLSIZE + 1];
295 char el_string[OS_MAXSTR + 1];
296 char final_msg[OS_MAXSTR + 1];
297 LPSTR el_sstring[OS_FLSIZE + 1];
299 /* er must point to the mbuffer */
300 el->er = (EVENTLOGRECORD *) &mbuffer;
302 /* Zero the values */
303 el_string[OS_MAXSTR] = '\0';
304 el_user[OS_FLSIZE] = '\0';
305 el_domain[OS_FLSIZE] = '\0';
306 final_msg[OS_MAXSTR] = '\0';
307 el_sstring[0] = NULL;
308 el_sstring[OS_FLSIZE] = NULL;
310 /* Event log is not open */
315 /* Read the event log */
316 while (ReadEventLog(el->h,
317 EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,
319 el->er, BUFFER_SIZE - 1, &read, &needed)) {
321 /* Set er to the beginning of the buffer */
322 el->er = (EVENTLOGRECORD *)&mbuffer;
328 /* We need to initialize every variable before the loop */
329 category = el_getCategory(el->er->EventType);
330 source = (LPSTR) ((LPBYTE) el->er + sizeof(EVENTLOGRECORD));
331 computer_name = source + strlen(source) + 1;
332 descriptive_msg = NULL;
335 id = (int)el->er->EventID & _evtid;
337 /* Initialize domain/user size */
343 /* We must have some description */
344 if (el->er->NumStrings) {
345 size_left = OS_MAXSTR - OS_SIZE_1024;
347 sstr = (LPSTR)((LPBYTE)el->er + el->er->StringOffset);
350 for (nstr = 0; nstr < el->er->NumStrings; nstr++) {
351 str_size = strlen(sstr);
353 strncat(el_string, sstr, size_left);
356 tmp_str = strchr(el_string, '\0');
362 merror("%s: Invalid application string (size+)",
365 size_left -= str_size + 2;
368 el_sstring[nstr] = (LPSTR)sstr;
369 el_sstring[nstr + 1] = NULL;
372 sstr = strchr( (LPSTR)sstr, '\0');
380 /* Get a more descriptive message (if available) */
381 if (isVista && strcmp(el->name, "Security") == 0) {
382 descriptive_msg = el_vista_getMessage(id, el_sstring);
386 descriptive_msg = el_getMessage(el->er,
392 if (descriptive_msg != NULL) {
394 win_format_event_string(descriptive_msg);
397 strncpy(el_string, "(no message)", 128);
401 if (el->er->UserSidLength) {
402 SID_NAME_USE account_type;
403 if (!LookupAccountSid(NULL,
404 (SID *)((LPSTR)el->er +
405 el->er->UserSidOffset),
411 strncpy(el_user, "(no user)", 255);
412 strncpy(el_domain, "no domain", 255);
416 else if (isVista && strcmp(el->name, "Security") == 0) {
417 int uid_array_id = -1;
434 if ((uid_array_id >= 0) &&
435 el_sstring[uid_array_id] &&
436 el_sstring[uid_array_id + 1]) {
437 strncpy(el_user, el_sstring[uid_array_id], OS_FLSIZE);
438 strncpy(el_domain, el_sstring[uid_array_id + 1], OS_FLSIZE);
440 strncpy(el_user, "(no user)", 255);
441 strncpy(el_domain, "no domain", 255);
446 strncpy(el_user, "(no user)", 255);
447 strncpy(el_domain, "no domain", 255);
451 DWORD _evtid = 65535;
452 int id = (int)el->er->EventID & _evtid;
454 final_msg[OS_MAXSTR - OS_LOG_HEADER] = '\0';
455 final_msg[OS_MAXSTR - OS_LOG_HEADER - 1] = '\0';
457 snprintf(final_msg, OS_MAXSTR - OS_LOG_HEADER - 1,
458 "%s WinEvtLog: %s: %s(%d): %s: %s: %s: %s: %s",
459 epoch_to_human((int)el->er->TimeGenerated),
467 descriptive_msg != NULL ? descriptive_msg : el_string);
469 if (SendMSG(logr_queue, final_msg, "WinEvtLog",
471 merror(QUEUE_SEND, ARGV0);
475 if (descriptive_msg != NULL) {
476 LocalFree(descriptive_msg);
479 /* Change the point to the er */
480 read -= el->er->Length;
481 el->er = (EVENTLOGRECORD *)((LPBYTE) el->er + el->er->Length);
484 /* Set er to the beginning of the buffer */
485 el->er = (EVENTLOGRECORD *)&mbuffer;
489 if (id == ERROR_HANDLE_EOF) {
493 /* Event log was cleared */
494 else if (id == ERROR_EVENTLOG_FILE_CHANGED) {
495 char msg_alert[512 + 1];
496 msg_alert[512] = '\0';
497 merror("%s: WARN: Event log cleared: '%s'", ARGV0, el->name);
499 /* Send message about cleared */
500 snprintf(msg_alert, 512, "ossec: Event log cleared: '%s'", el->name);
501 SendMSG(logr_queue, msg_alert, "WinEvtLog", LOCALFILE_MQ);
503 /* Close the event log and reopen */
504 CloseEventLog(el->h);
508 if (startEL(el->name, el) < 0) {
509 merror("%s: ERROR: Unable to reopen event log '%s'",
515 debug1("%s: WARN: Error reading event log: %d", ARGV0, id);
519 /* Read Windows Vista security description */
520 void win_read_vista_sec()
523 char buf[OS_MAXSTR + 1];
527 fp = fopen("vista_sec.txt", "r");
529 merror("%s: ERROR: Unable to read vista security descriptions.",
534 /* Creating the hash */
535 vista_sec_id_hash = OSHash_Create();
536 if (!vista_sec_id_hash) {
537 merror("%s: ERROR: Unable to read vista security descriptions.",
542 /* Read the whole file and add it to memory */
543 while (fgets(buf, OS_MAXSTR, fp) != NULL) {
547 /* Get the last occurrence of \n */
548 if ((p = strrchr(buf, '\n')) != NULL) {
552 p = strchr(buf, ',');
554 merror("%s: ERROR: Invalid entry on the Vista security "
555 "description.", ARGV0);
562 /* Remove whitespace */
567 /* Allocate memory */
571 merror("%s: ERROR: Invalid entry on the Vista security "
572 "description.", ARGV0);
577 OSHash_Add(vista_sec_id_hash, key, desc);
583 /* Start the event logging for windows */
584 void win_startel(char *evt_log)
586 int entries_count = 0;
590 merror(EVTLOG_DUP, ARGV0, evt_log);
594 /* Create the DLL hash */
596 dll_hash = OSHash_Create();
598 merror("%s: ERROR: Unable to create DLL hash.",
603 /* Start event log -- going to last available record */
604 if ((entries_count = startEL(evt_log, &el[el_last])) < 0) {
605 merror(INV_EVTLOG, ARGV0, evt_log);
608 readel(&el[el_last], 0);
613 /* Read the event logging for windows */
618 /* Sleep plus 2 seconds before reading again */
621 for (; i < el_last; i++) {