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