novi upstream verzije 2.8.3
[ossec-hids.git] / src / logcollector / read_win_el.c
1 /* @(#) $Id: ./src/logcollector/read_win_el.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All right reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  */
12
13
14 #include "shared.h"
15 #include "logcollector.h"
16
17
18 /* This is only for windows */
19 #ifdef WIN32
20
21 #define BUFFER_SIZE 2048*256
22
23
24
25 /* Event logging local structure */
26 typedef struct _os_el
27 {
28     int time_of_last;   
29     char *name;
30
31     EVENTLOGRECORD *er;
32     HANDLE h;
33
34     DWORD record;
35
36 }os_el;
37
38
39 /** Global variables **/
40
41 /* Maximum of 9 event log sources. */
42 os_el el[9];
43 int el_last = 0;
44 void *vista_sec_id_hash = NULL;
45 void *dll_hash = NULL;
46
47
48
49 /** int startEL(char *app, os_el *el)
50  * Starts the event logging for each el
51  */
52 int startEL(char *app, os_el *el)
53 {
54     DWORD NumberOfRecords = 0;
55
56     /* Opening the event log */
57     el->h = OpenEventLog(NULL, app);
58     if(!el->h)
59     {
60         merror(EVTLOG_OPEN, ARGV0, app);
61         return(-1);     
62     }
63
64     el->name = app;
65     if(GetOldestEventLogRecord(el->h, &el->record) == 0)
66     {
67         /* Unable to read oldest event log record */
68         merror(EVTLOG_GETLAST, ARGV0, app);
69         CloseEventLog(el->h);
70         el->h = NULL;
71         return(-1);
72     }
73
74     if(GetNumberOfEventLogRecords(el->h, &NumberOfRecords) == 0)
75     {
76         merror(EVTLOG_GETLAST, ARGV0, app);
77         CloseEventLog(el->h);
78         el->h = NULL;
79         return(-1);
80     }
81
82     if(NumberOfRecords <= 0)
83     {
84         return(0);
85     }
86
87     return((int)NumberOfRecords);
88 }
89
90
91
92 /** char epoch_to_human(int time)
93  * Returns a string that is a human readable 
94  * datetime from an epoch int.
95  */
96 char *epoch_to_human(time_t epoch)
97 {
98     struct tm   *ts;
99     static char buf[80];
100
101     ts = localtime(&epoch);
102     strftime(buf, sizeof(buf), "%Y %b %d %H:%M:%S", ts);
103     return(buf);
104 }
105
106
107 /** char *el_getCategory(int category_id)
108  * Returns a string related to the category id of the log.
109  */
110 char *el_getCategory(int category_id)
111 {
112     char *cat;
113     switch(category_id)
114     {
115         case EVENTLOG_ERROR_TYPE:
116             cat = "ERROR";
117             break;
118         case EVENTLOG_WARNING_TYPE:
119             cat = "WARNING";
120             break;
121         case EVENTLOG_INFORMATION_TYPE:
122             cat = "INFORMATION";
123             break;
124         case EVENTLOG_AUDIT_SUCCESS:
125             cat = "AUDIT_SUCCESS";
126             break;
127         case EVENTLOG_AUDIT_FAILURE:
128             cat = "AUDIT_FAILURE";
129             break;
130         default:
131             cat = "Unknown";
132             break;
133     }
134     return(cat);
135 }
136
137
138
139 /** char *el_getEventDLL(char *evt_name, char *source, char *event)
140  * Returns the event.
141  */
142 char *el_getEventDLL(char *evt_name, char *source, char *event)
143 {
144     char *ret_str;
145     HKEY key;
146     DWORD ret;
147     char keyname[512];
148
149
150     keyname[511] = '\0';
151
152     snprintf(keyname, 510,
153             "System\\CurrentControlSet\\Services\\EventLog\\%s\\%s",
154             evt_name,
155             source);
156
157
158     /* Checking if we have it in memory. */
159     ret_str = OSHash_Get(dll_hash, keyname + 42);
160     if(ret_str)
161     {
162         return(ret_str);
163     }
164
165
166     /* Opening registry */      
167     if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0,
168                     KEY_ALL_ACCESS, &key) != ERROR_SUCCESS)
169     {
170         return(NULL);
171     }
172
173
174     ret = MAX_PATH -1;  
175     if (RegQueryValueEx(key, "EventMessageFile", NULL,
176                 NULL, (LPBYTE)event, &ret) != ERROR_SUCCESS)
177     {
178         event[0] = '\0';        
179         RegCloseKey(key);
180         return(NULL);
181     }
182     else
183     {
184         /* Adding to memory. */
185         char *skey;
186         char *sval;
187
188         skey = strdup(keyname + 42);
189         sval = strdup(event);
190
191         if(skey && sval)
192         {
193             OSHash_Add(dll_hash, skey, sval);
194         }
195         else
196         {
197             merror(MEM_ERROR, ARGV0);
198         }
199     }
200
201     RegCloseKey(key);
202     return(event);
203 }
204
205
206
207 /** char *el_vista_getmessage()
208  * Returns a descriptive message of the event - Vista only.
209  */
210 char *el_vista_getMessage(int evt_id_int, LPTSTR *el_sstring)
211 {
212     DWORD fm_flags = 0;
213     LPSTR message = NULL;
214     char *desc_string;
215     char evt_id[16];
216
217
218     /* Flags for format event */
219     fm_flags |= FORMAT_MESSAGE_FROM_STRING;
220     fm_flags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
221     fm_flags |= FORMAT_MESSAGE_ARGUMENT_ARRAY;
222
223
224     /* Getting descriptive message. */
225     evt_id[15] = '\0';
226     snprintf(evt_id, 15, "%d", evt_id_int);
227
228     desc_string = OSHash_Get(vista_sec_id_hash, evt_id);
229     if(!desc_string)
230     {
231         return(NULL);
232     }
233
234
235     if(!FormatMessage(fm_flags, desc_string, 0, 0,
236                       (LPTSTR) &message, 0, el_sstring))
237     {
238         return(NULL);
239     }
240
241     return(message);
242 }
243
244
245
246 /** char *el_getmessage()
247  * Returns a descriptive message of the event.
248  */
249 char *el_getMessage(EVENTLOGRECORD *er,  char *name,
250                     char * source, LPTSTR *el_sstring)
251 {
252     DWORD fm_flags = 0;
253     char tmp_str[257];
254     char event[MAX_PATH +1];
255     char *curr_str;
256     char *next_str;
257     LPSTR message = NULL;
258
259     HMODULE hevt;
260
261     /* Initializing variables */
262     event[MAX_PATH] = '\0';
263     tmp_str[256] = '\0';
264
265
266     /* Flags for format event */
267     fm_flags |= FORMAT_MESSAGE_FROM_HMODULE;
268     fm_flags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
269     fm_flags |= FORMAT_MESSAGE_ARGUMENT_ARRAY;
270
271
272
273     /* Get the file name from the registry (stored on event) */
274     if(!(curr_str = el_getEventDLL(name, source, event)))
275     {
276         return(NULL);   
277     }   
278
279
280
281     /* If our event has multiple libraries, try each one of them */
282     while((next_str = strchr(curr_str, ';')))
283     {
284         *next_str = '\0';
285
286         ExpandEnvironmentStrings(curr_str, tmp_str, 255);
287
288         /* Reverting back old value. */
289         *next_str = ';';
290
291
292         /* Loading library. */
293         hevt = LoadLibraryEx(tmp_str, NULL,
294                              DONT_RESOLVE_DLL_REFERENCES |
295                              LOAD_LIBRARY_AS_DATAFILE);
296         if(hevt)
297         {
298             if(!FormatMessage(fm_flags, hevt, er->EventID, 0,
299                               (LPTSTR) &message, 0, el_sstring))
300             {
301                 message = NULL;         
302             }
303             FreeLibrary(hevt);
304
305             /* If we have a message, we can return it */
306             if(message)
307                 return(message);
308         }
309
310
311         curr_str = next_str +1;
312     }
313
314
315     /* Getting last value. */
316     ExpandEnvironmentStrings(curr_str, tmp_str, 255);
317     hevt = LoadLibraryEx(tmp_str, NULL,
318                          DONT_RESOLVE_DLL_REFERENCES |
319                          LOAD_LIBRARY_AS_DATAFILE);
320     if(hevt)
321     {
322         int hr;
323         if(!(hr = FormatMessage(fm_flags, hevt, er->EventID,
324                         0,
325                         (LPTSTR) &message, 0, el_sstring)))
326         {
327             message = NULL;             
328         }
329         FreeLibrary(hevt);
330
331         /* If we have a message, we can return it */
332         if(message)
333             return(message);
334     }
335
336     return(NULL);
337 }
338
339
340
341 /** void readel(os_el *el)
342  * Reads the event log.
343  */
344 void readel(os_el *el, int printit)
345 {
346     DWORD _evtid = 65535;
347     DWORD nstr;
348     DWORD user_size;
349     DWORD domain_size;
350     DWORD read, needed;
351     int size_left;
352     int str_size;
353     int id;
354
355     char mbuffer[BUFFER_SIZE +1];
356     LPSTR sstr = NULL;
357
358     char *tmp_str = NULL;
359     char *category;
360     char *source;
361     char *computer_name;
362     char *descriptive_msg;
363
364     char el_user[OS_FLSIZE +1];
365     char el_domain[OS_FLSIZE +1];
366     char el_string[OS_MAXSTR +1];
367     char final_msg[OS_MAXSTR +1];
368     LPSTR el_sstring[OS_FLSIZE +1];
369
370     /* Er must point to the mbuffer */
371     el->er = (EVENTLOGRECORD *) &mbuffer;
372
373     /* Zeroing the values */
374     el_string[OS_MAXSTR] = '\0';
375     el_user[OS_FLSIZE] = '\0';
376     el_domain[OS_FLSIZE] = '\0';
377     final_msg[OS_MAXSTR] = '\0';
378     el_sstring[0] = NULL;
379     el_sstring[OS_FLSIZE] = NULL;
380
381
382     /* Event log is not open */
383     if(!el->h)
384     {
385         return;
386     }
387
388     /* Reading the event log */ 
389     while(ReadEventLog(el->h,
390                 EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,
391                 0,
392                 el->er, BUFFER_SIZE -1, &read, &needed))
393     {
394         if(!printit)
395         {
396             /* Setting er to the beginning of the buffer */
397             el->er = (EVENTLOGRECORD *)&mbuffer;
398             continue;
399         }
400
401
402         while(read > 0)
403         {
404
405             /* We need to initialize every variable before the loop */
406             category = el_getCategory(el->er->EventType);
407             source = (LPSTR) ((LPBYTE) el->er + sizeof(EVENTLOGRECORD));
408             computer_name = source + strlen(source) + 1;
409             descriptive_msg = NULL;
410
411
412             /* Getting event id. */
413             id = (int)el->er->EventID & _evtid;
414
415
416
417             /* Initialing domain/user size */
418             user_size = 255; domain_size = 255;
419             el_domain[0] = '\0';
420             el_user[0] = '\0';
421
422
423
424             /* We must have some description */
425             if(el->er->NumStrings)
426             {   
427                 size_left = OS_MAXSTR - OS_SIZE_1024;   
428
429                 sstr = (LPSTR)((LPBYTE)el->er + el->er->StringOffset);
430                 el_string[0] = '\0';
431
432                 for (nstr = 0;nstr < el->er->NumStrings;nstr++)
433                 {
434                     str_size = strlen(sstr);
435                     if(size_left > 1)
436                     {
437                         strncat(el_string, sstr, size_left);
438                     }
439
440                     tmp_str = strchr(el_string, '\0');
441                     if(tmp_str)
442                     {
443                         *tmp_str = ' ';         
444                         tmp_str++; *tmp_str = '\0';
445                     }
446                     else
447                     {
448                         merror("%s: Invalid application string (size+)",
449                                ARGV0);
450                     }
451                     size_left-=str_size + 2;
452
453                     if(nstr <= 92)
454                     {
455                         el_sstring[nstr] = (LPSTR)sstr;
456                         el_sstring[nstr +1] = NULL;
457                     }
458
459                     sstr = strchr( (LPSTR)sstr, '\0');
460                     if(sstr)
461                         sstr++;
462                     else
463                         break;
464                 }
465
466                 /* Get a more descriptive message (if available) */
467                 if(isVista && strcmp(el->name, "Security") == 0)
468                 {
469                     descriptive_msg = el_vista_getMessage(id, el_sstring);
470                 }
471
472                 else
473                 {
474                     descriptive_msg = el_getMessage(el->er,
475                                                     el->name,
476                                                     source,
477                                                     el_sstring);
478                 }
479
480                 if(descriptive_msg != NULL)
481                 {
482                         /* format message */
483                         win_format_event_string(descriptive_msg);
484                 }
485             }
486             else
487             {
488                 strncpy(el_string, "(no message)", 128);        
489             }
490
491
492             /* Getting username */
493             if(el->er->UserSidLength)
494             {
495                 SID_NAME_USE account_type;
496                 if(!LookupAccountSid(NULL,
497                                     (SID *)((LPSTR)el->er +
498                                     el->er->UserSidOffset),
499                                     el_user,
500                                     &user_size,
501                                     el_domain,
502                                     &domain_size,
503                                     &account_type))             
504                 {
505                     strncpy(el_user, "(no user)", 255);
506                     strncpy(el_domain, "no domain", 255);
507                 }
508
509             }
510
511             else if(isVista && strcmp(el->name, "Security") == 0)
512             {
513                 int uid_array_id = -1;
514
515                 switch(id)
516                 {
517                     case 4624:
518                         uid_array_id = 5;
519                         break;
520                     case 4634:
521                         uid_array_id = 1;
522                         break;
523                     case 4647:
524                         uid_array_id = 1;
525                         break;
526                     case 4769:
527                         uid_array_id = 0;
528                         break;
529                 }
530
531                 if((uid_array_id >= 0) &&
532                    el_sstring[uid_array_id] &&
533                    el_sstring[uid_array_id +1])
534                 {
535                     strncpy(el_user, el_sstring[uid_array_id], OS_FLSIZE);
536                     strncpy(el_domain, el_sstring[uid_array_id +1], OS_FLSIZE);
537                 }
538                 else
539                 {
540                     strncpy(el_user, "(no user)", 255);
541                     strncpy(el_domain, "no domain", 255);
542                 }
543             }
544
545             else
546             {
547                 strncpy(el_user, "(no user)", 255);     
548                 strncpy(el_domain, "no domain", 255);   
549             }
550
551
552             if(printit)
553             {
554                 DWORD _evtid = 65535;
555                 int id = (int)el->er->EventID & _evtid;
556
557                 final_msg[OS_MAXSTR - OS_LOG_HEADER] = '\0';
558                 final_msg[OS_MAXSTR - OS_LOG_HEADER -1] = '\0';
559
560                 snprintf(final_msg, OS_MAXSTR - OS_LOG_HEADER -1,
561                         "%s WinEvtLog: %s: %s(%d): %s: %s: %s: %s: %s",
562                         epoch_to_human((int)el->er->TimeGenerated),
563                         el->name,
564                         category,
565                         id,
566                         source,
567                         el_user,
568                         el_domain,
569                         computer_name,
570                         descriptive_msg != NULL?descriptive_msg:el_string);     
571
572                 if(SendMSG(logr_queue, final_msg, "WinEvtLog",
573                             LOCALFILE_MQ) < 0)
574                 {
575                     merror(QUEUE_SEND, ARGV0);
576                 }
577             }
578
579             if(descriptive_msg != NULL)
580             {
581                 LocalFree(descriptive_msg);
582             }
583
584             /* Changing the point to the er */
585             read -= el->er->Length;
586             el->er = (EVENTLOGRECORD *)((LPBYTE) el->er + el->er->Length);
587         }               
588
589         /* Setting er to the beginning of the buffer */ 
590         el->er = (EVENTLOGRECORD *)&mbuffer;
591     }
592
593
594     id = GetLastError();
595     if(id == ERROR_HANDLE_EOF)
596     {
597         return;
598     }
599
600
601     /* Event log was cleared. */
602     else if(id == ERROR_EVENTLOG_FILE_CHANGED)
603     {
604         char msg_alert[512 +1];
605         msg_alert[512] = '\0';
606         merror("%s: WARN: Event log cleared: '%s'", ARGV0, el->name);
607
608
609         /* Send message about cleared */
610         snprintf(msg_alert, 512, "ossec: Event log cleared: '%s'", el->name);
611         SendMSG(logr_queue, msg_alert, "WinEvtLog", LOCALFILE_MQ);
612
613
614         /* Closing the event log and reopenning. */
615         CloseEventLog(el->h);
616         el->h = NULL;
617
618         /* Reopening. */
619         if(startEL(el->name, el) < 0)
620         {
621             merror("%s: ERROR: Unable to reopen event log '%s'",
622                    ARGV0, el->name);
623         }
624     }
625
626     else
627     {
628         debug1("%s: WARN: Error reading event log: %d", ARGV0, id);
629     }
630 }
631
632
633 /** void win_read_vista_sec()
634  * Reads vista security description.
635  */
636 void win_read_vista_sec()
637 {
638     char *p;
639     char buf[OS_MAXSTR +1];
640     FILE *fp;
641
642
643     /* Vista security csv. */
644     fp = fopen("vista_sec.csv", "r");
645     if(!fp)
646     {
647         merror("%s: ERROR: Unable to read vista security descriptions.",
648                ARGV0);
649         exit(1);
650     }
651
652
653     /* Creating the hash. */
654     vista_sec_id_hash = OSHash_Create();
655     if(!vista_sec_id_hash)
656     {
657         merror("%s: ERROR: Unable to read vista security descriptions.",
658                ARGV0);
659         exit(1);
660     }
661
662
663     /* Reading the whole file and adding to memory. */
664     while(fgets(buf, OS_MAXSTR, fp) != NULL)
665     {
666         char *key;
667         char *desc;
668
669         /* Getting the last occurence of \n */
670         if ((p = strrchr(buf, '\n')) != NULL)
671         {
672             *p = '\0';
673         }
674
675         p = strchr(buf, ',');
676         if(!p)
677         {
678             merror("%s: ERROR: Invalid entry on the Vista security "
679                    "description.", ARGV0);
680             continue;
681         }
682
683         *p = '\0';
684         p++;
685
686         /* Removing white spaces. */
687         while(*p == ' ')
688             p++;
689
690
691         /* Allocating memory. */
692         desc = strdup(p);
693         key = strdup(buf);
694         if(!key || !desc)
695         {
696             merror("%s: ERROR: Invalid entry on the Vista security "
697                    "description.", ARGV0);
698             continue;
699         }
700
701
702         /* Inserting on hash. */
703         OSHash_Add(vista_sec_id_hash, key, desc);
704     }
705
706     fclose(fp);
707 }
708
709
710 /** void win_startel()
711  * Starts the event logging for windows
712  */
713 void win_startel(char *evt_log)
714 {
715     int entries_count = 0;
716
717     /* Maximum size */
718     if(el_last == 9)
719     {
720         merror(EVTLOG_DUP, ARGV0, evt_log);
721         return;
722     }
723
724
725     /* Creating the dll hash. */
726     if(!dll_hash)
727     {
728         dll_hash = OSHash_Create();
729         if(!dll_hash)
730         {
731             merror("%s: ERROR: Unable to create DLL hash.",
732                     ARGV0);
733         }
734     }
735
736
737     /* Starting event log -- going to last available record */
738     if((entries_count = startEL(evt_log, &el[el_last])) < 0)
739     {
740         merror(INV_EVTLOG, ARGV0, evt_log);
741         return;
742     }
743     else
744     {
745         readel(&el[el_last], 0);
746     }
747     el_last++;
748 }
749
750
751 /** void win_readel()
752  * Reads the event logging for windows
753  */
754 void win_readel()
755 {
756     int i = 0;
757
758     /* Sleep plus 2 seconds before reading again */
759     Sleep(2000);
760
761     for(;i<el_last;i++)
762         readel(&el[i],1);
763 }
764
765
766 #endif
767
768 /* EOF */