Imported Upstream version 2.7
[ossec-hids.git] / src / shared / report_op.c
1 /* @(#) $Id: ./src/shared/report_op.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All rights 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
16
17 /** Helper functions. */
18 FILE *__g_rtype = NULL;
19 void l_print_out(const char *msg, ...)
20 {
21     va_list args;
22     va_start(args, msg);
23
24     if(__g_rtype)
25     {
26         (void)vfprintf(__g_rtype, msg, args);
27         (void)fprintf(__g_rtype, "\n");
28     }
29     else
30     {
31         (void)vfprintf(stderr, msg, args);
32         (void)fprintf(stderr, "\n");
33     }
34     va_end(args);
35 }
36
37
38 /* Sort function used by OSStore sort.
39  * Returns if d1 > d2.
40  */
41 void *_os_report_sort_compare(void *d1, void *d2)
42 {
43    OSList *d1l = (OSList *)d1;
44    OSList *d2l = (OSList *)d2;
45
46    if(d1l->currently_size > d2l->currently_size)
47    {
48        return(d1l);
49    }
50
51    return(NULL);
52 }
53
54
55 /* Print output header. */
56 void _os_header_print(int t, char *hname)
57 {
58     if(!t)
59     {
60         l_print_out("Top entries for '%s':", hname);
61         l_print_out("------------------------------------------------");
62     }
63     else
64     {
65         l_print_out("Related entries for '%s':", hname);
66         l_print_out("------------------------------------------------");
67     }
68 }
69
70
71 /* Compares if the id is present in the string. */
72 int _os_report_str_int_compare(char *str, int id)
73 {
74     int pt_check = 0;
75
76     do
77     {
78         if((*str == ',')||(*str == ' '))
79         {
80             pt_check = 0;
81             continue;
82         }
83         else if(*str == '\0')
84         {
85             break;
86         }
87         else if(isdigit((int)*str))
88         {
89             if(pt_check == 0)
90             {
91                 if(id == atoi(str))
92                 {
93                     return(1);
94                 }
95             }
96             pt_check = 1;
97         }
98         else
99         {
100             return(-1);
101         }
102     }while(*str++ != '\0');
103
104     return(0);
105 }
106
107
108
109 /* Check if the al_data should be filtered. */
110 int _os_report_check_filters(alert_data *al_data, report_filter *r_filter)
111 {
112     /* Checking for the filters. */
113     if(r_filter->group)
114     {
115         if(!strstr(al_data->group, r_filter->group))
116         {
117             return(0);
118         }
119     }
120     if(r_filter->rule)
121     {
122         if(_os_report_str_int_compare(r_filter->rule, al_data->rule) != 1)
123         {
124             return(0);
125         }
126     }
127     if(r_filter->location)
128     {
129         if(!OS_Match(r_filter->location, al_data->location))
130         {
131             return(0);
132         }
133     }
134     if(r_filter->level)
135     {
136         if(al_data->level < atoi(r_filter->level))
137         {
138             return(0);
139         }
140     }
141     if(r_filter->srcip)
142     {
143         if(!strstr(al_data->srcip, r_filter->srcip))
144         {
145             return(0);
146         }
147     }
148     if(r_filter->user)
149     {
150         if(!strstr(al_data->user, r_filter->user))
151         {
152             return(0);
153         }
154     }
155     if(r_filter->files)
156     {
157         if(!strstr(al_data->filename, r_filter->files))
158         {
159             return(0);
160         }
161     }
162     return(1);
163 }
164
165
166
167 /* Sets the proper value for the related entries. */
168 int _report_filter_value(char *filter_by, int prev_filter)
169 {
170     if(strcmp(filter_by, "group") == 0)
171     {
172         if(!(prev_filter & REPORT_REL_GROUP))
173         {
174             prev_filter|=REPORT_REL_GROUP;
175         }
176         return(prev_filter);
177     }
178     else if(strcmp(filter_by, "rule") == 0)
179     {
180         if(!(prev_filter & REPORT_REL_RULE))
181         {
182             prev_filter|=REPORT_REL_RULE;
183         }
184         return(prev_filter);
185     }
186     else if(strcmp(filter_by, "level") == 0)
187     {
188         if(!(prev_filter & REPORT_REL_LEVEL))
189         {
190             prev_filter|=REPORT_REL_LEVEL;
191         }
192         return(prev_filter);
193     }
194     else if(strcmp(filter_by, "location") == 0)
195     {
196         if(!(prev_filter & REPORT_REL_LOCATION))
197         {
198             prev_filter|=REPORT_REL_LOCATION;
199         }
200         return(prev_filter);
201     }
202     else if(strcmp(filter_by, "srcip") == 0)
203     {
204         if(!(prev_filter & REPORT_REL_SRCIP))
205         {
206             prev_filter|=REPORT_REL_SRCIP;
207         }
208         return(prev_filter);
209     }
210     else if(strcmp(filter_by, "user") == 0)
211     {
212         if(!(prev_filter & REPORT_REL_USER))
213         {
214             prev_filter|=REPORT_REL_USER;
215         }
216         return(prev_filter);
217     }
218     else if(strcmp(filter_by, "filename") == 0)
219     {
220         if(!(prev_filter & REPORT_REL_FILE))
221         {
222             prev_filter|=REPORT_REL_FILE;
223         }
224         return(prev_filter);
225     }
226     else
227     {
228         merror("%s: ERROR: Invalid relation '%s'.", __local_name, filter_by);
229         return(-1);
230     }
231 }
232
233
234
235 /* Prints related entries. */
236 int _os_report_print_related(int print_related, OSList *st_data)
237 {
238     OSListNode *list_entry;
239     alert_data *list_aldata;
240     alert_data *saved_aldata;
241
242
243     list_entry = OSList_GetFirstNode(st_data);
244     while(list_entry)
245     {
246         saved_aldata = (alert_data *)list_entry->data;
247
248         /* Removing duplicates. */
249         list_entry = list_entry->prev;
250         while(list_entry)
251         {
252             if(print_related & REPORT_REL_LOCATION)
253             {
254                 list_aldata = (alert_data *)list_entry->data;
255                 if(strcmp(list_aldata->location, saved_aldata->location) == 0)
256                 {
257                     break;
258                 }
259             }
260
261             else if(print_related & REPORT_REL_GROUP)
262             {
263                 list_aldata = (alert_data *)list_entry->data;
264                 if(strcmp(list_aldata->group, saved_aldata->group) == 0)
265                 {
266                     break;
267                 }
268             }
269
270             else if(print_related & REPORT_REL_RULE)
271             {
272                 list_aldata = (alert_data *)list_entry->data;
273                 if(list_aldata->rule == saved_aldata->rule)
274                 {
275                     break;
276                 }
277             }
278
279             else if(print_related & REPORT_REL_USER)
280             {
281                 list_aldata = (alert_data *)list_entry->data;
282                 if(list_aldata->user == NULL || saved_aldata->user == NULL)
283                 {
284                 }
285                 else if(strcmp(list_aldata->user, saved_aldata->user) == 0)
286                 {
287                     break;
288                 }
289             }
290
291             else if(print_related & REPORT_REL_SRCIP)
292             {
293                 list_aldata = (alert_data *)list_entry->data;
294                 if(list_aldata->srcip == NULL || saved_aldata->srcip == NULL)
295                 {
296                 }
297                 else if(strcmp(list_aldata->srcip, saved_aldata->srcip) == 0)
298                 {
299                     break;
300                 }
301             }
302
303             else if(print_related & REPORT_REL_LEVEL)
304             {
305                 list_aldata = (alert_data *)list_entry->data;
306                 if(list_aldata->level == saved_aldata->level)
307                 {
308                     break;
309                 }
310             }
311             else if(print_related & REPORT_REL_FILE)
312             {
313                 list_aldata = (alert_data *)list_entry->data;
314                 if(list_aldata->filename == NULL || saved_aldata->filename == NULL)
315                 {
316                 }
317                 else if(strcmp(list_aldata->filename, saved_aldata->filename) == 0)
318                 {
319                     break;
320                 }
321             }
322             list_entry = list_entry->prev;
323         }
324
325         if(!list_entry)
326         {
327             if(print_related & REPORT_REL_LOCATION)
328                 l_print_out("   location: '%s'", saved_aldata->location);
329             else if(print_related & REPORT_REL_GROUP)
330                 l_print_out("   group: '%s'", saved_aldata->group);
331             else if(print_related & REPORT_REL_RULE)
332                 l_print_out("   rule: '%d'", saved_aldata->rule);
333             else if(print_related & REPORT_REL_SRCIP && saved_aldata->srcip)
334                 l_print_out("   srcip: '%s'", saved_aldata->srcip);
335             else if(print_related & REPORT_REL_USER && saved_aldata->user)
336                 l_print_out("   user: '%s'", saved_aldata->user);
337             else if(print_related & REPORT_REL_LEVEL)
338                 l_print_out("   level: '%d'", saved_aldata->level);
339             else if(print_related & REPORT_REL_FILE && saved_aldata->filename)
340                 l_print_out("   filename: '%s'", saved_aldata->filename);
341         }
342
343         list_entry = OSList_GetNextNode(st_data);
344     }
345
346     return(0);
347 }
348
349
350
351 /* Add the entry to the hash. */
352 int _os_report_add_tostore(char *key, OSStore *top, void *data)
353 {
354     OSList *top_list;
355
356     /* Adding data to the hash. */
357     top_list = OSStore_Get(top, key);
358     if(top_list)
359     {
360         OSList_AddData(top_list, data);
361     }
362     else
363     {
364         top_list = OSList_Create();
365         if(!top_list)
366         {
367             merror(MEM_ERROR, __local_name);
368             return(0);
369         }
370         OSList_AddData(top_list, data);
371
372         OSStore_Put(top, key, top_list);
373     }
374
375     return(1);
376 }
377
378
379
380 void os_report_printtop(void *topstore_pt, char *hname, int print_related)
381 {
382     int dopdout = 0;
383     OSStore *topstore = (OSStore *)topstore_pt;
384     OSStoreNode *next_node;
385
386     next_node = OSStore_GetFirstNode(topstore);
387     while(next_node)
388     {
389         OSList *st_data = (OSList *)next_node->data;
390         char *lkey = (char *)next_node->key;
391
392
393         /* With location we leave more space to be clearer. */
394         if(!print_related)
395         {
396             if(strlen(lkey) > 46)
397             {
398                 lkey[44] = '.';
399                 lkey[45] = '.';
400                 lkey[46] = '\0';
401             }
402
403             if(!dopdout)
404             {
405                 _os_header_print(print_related, hname);
406                 dopdout = 1;
407             }
408             l_print_out("%-48s|%-8d|", (char *)next_node->key, st_data->currently_size);
409         }
410
411
412         /* Print each destination. */
413         else
414         {
415             if(!dopdout)
416             {
417                 _os_header_print(print_related, hname);
418                 dopdout = 1;
419             }
420             l_print_out("%-48s|%-8d|", (char *)next_node->key, st_data->currently_size);
421
422             if(print_related & REPORT_REL_LOCATION)
423                 _os_report_print_related(REPORT_REL_LOCATION, st_data);
424             if(print_related & REPORT_REL_SRCIP)
425                 _os_report_print_related(REPORT_REL_SRCIP, st_data);
426             if(print_related & REPORT_REL_USER)
427                 _os_report_print_related(REPORT_REL_USER, st_data);
428             if(print_related & REPORT_REL_RULE)
429                 _os_report_print_related(REPORT_REL_RULE, st_data);
430             if(print_related & REPORT_REL_GROUP)
431                 _os_report_print_related(REPORT_REL_GROUP, st_data);
432             if(print_related & REPORT_REL_LEVEL)
433                 _os_report_print_related(REPORT_REL_LEVEL, st_data);
434             if(print_related & REPORT_REL_FILE)
435                 _os_report_print_related(REPORT_REL_FILE, st_data);
436
437         }
438
439         next_node = next_node->next;
440     }
441
442
443     if(dopdout == 1)
444     {
445         l_print_out(" ");
446         l_print_out(" ");
447     }
448     return;
449 }
450
451
452
453 void os_ReportdStart(report_filter *r_filter)
454 {
455     int alerts_processed = 0;
456     int alerts_filtered = 0;
457     char *first_alert = NULL;
458     char *last_alert = NULL;
459     void **data_to_clean = NULL;
460
461
462     time_t tm;
463     struct tm *p;
464
465
466     file_queue *fileq;
467     alert_data *al_data;
468
469
470     /* Getting current time before starting */
471     tm = time(NULL);
472     p = localtime(&tm); 
473
474
475
476
477     /* Initating file queue - to read the alerts */
478     os_calloc(1, sizeof(file_queue), fileq);
479
480     if(r_filter->report_type == REPORT_TYPE_DAILY && r_filter->filename)
481     {
482         fileq->fp = fopen(r_filter->filename, "r");
483         if(!fileq->fp)
484         {
485             merror("%s: ERROR: Unable to open alerts file to generate report.", __local_name);
486             return;
487         }
488         if(r_filter->fp)
489         {
490             __g_rtype = r_filter->fp;
491         }
492     }
493     else
494     {
495         fileq->fp = stdin;
496     }
497
498
499     /* Creating top hashes. */
500     r_filter->top_user = OSStore_Create();
501     r_filter->top_srcip = OSStore_Create();
502     r_filter->top_level = OSStore_Create();
503     r_filter->top_rule = OSStore_Create();
504     r_filter->top_group = OSStore_Create();
505     r_filter->top_location = OSStore_Create();
506     r_filter->top_files = OSStore_Create();
507
508     Init_FileQueue(fileq, p, CRALERT_READ_ALL|CRALERT_FP_SET);
509
510
511
512     /* Reading the alerts. */
513     while(1)
514     {
515         /* Get message if available */
516         al_data = Read_FileMon(fileq, p, 1);
517         if(!al_data)
518         {
519             break;
520         }
521
522         alerts_processed++;
523
524
525         /* Checking the filters. */
526         if(!_os_report_check_filters(al_data, r_filter))
527         {
528             FreeAlertData(al_data);
529             continue;
530         }
531
532
533         alerts_filtered++;
534         data_to_clean = os_AddPtArray(al_data, data_to_clean);
535
536
537         /* Setting first and last alert for summary. */
538         if(!first_alert)
539             first_alert = al_data->date;
540         last_alert = al_data->date;
541
542
543         /* Adding source ip if it is set properly. */
544         if(al_data->srcip != NULL && strcmp(al_data->srcip, "(none)") != 0)
545             _os_report_add_tostore(al_data->srcip, r_filter->top_srcip, al_data);
546
547
548         /* Adding user if it is set properly. */
549         if(al_data->user != NULL && strcmp(al_data->user, "(none)") != 0)
550             _os_report_add_tostore(al_data->user, r_filter->top_user, al_data);
551
552
553         /* Adding level and severity. */
554         {
555             char mlevel[16];
556             char mrule[76 +1];
557             mrule[76] = '\0';
558             snprintf(mlevel, 16, "Severity %d" , al_data->level);
559             snprintf(mrule, 76, "%d - %s" , al_data->rule, al_data->comment);
560
561             _os_report_add_tostore(strdup(mlevel), r_filter->top_level,
562                                    al_data);
563             _os_report_add_tostore(strdup(mrule), r_filter->top_rule,
564                                    al_data);
565         }
566
567         /* Dealing with the group. */
568         {
569             char *tmp_str;
570             char **mgroup;
571
572             mgroup = OS_StrBreak(',', al_data->group, 32);
573             if(mgroup)
574             {
575                 while(*mgroup)
576                 {
577                     tmp_str = *mgroup;
578                     while(*tmp_str == ' ')
579                         tmp_str++;
580                     if(*tmp_str == '\0')
581                     {
582                         mgroup++;
583                         continue;
584                     }
585
586                     _os_report_add_tostore(tmp_str, r_filter->top_group,
587                                            al_data);
588                     mgroup++;
589                 }
590             }
591             else
592             {
593                 tmp_str = al_data->group;
594                 while(*tmp_str == ' ')
595                     tmp_str++;
596                 if(*tmp_str != '\0')
597                 {
598                     _os_report_add_tostore(tmp_str, r_filter->top_group,
599                                            al_data);
600                 }
601             }
602         }
603
604
605         /* Adding to the location top filter. */
606         _os_report_add_tostore(al_data->location, r_filter->top_location,
607                                al_data);
608
609
610         if(al_data->filename != NULL)
611         {
612             _os_report_add_tostore(al_data->filename, r_filter->top_files,
613                                    al_data);
614         }
615     }
616
617     /* No report available */
618     if(alerts_filtered == 0)
619     {
620         if(!r_filter->report_name)
621             merror("%s: INFO: Report completed and zero alerts post-filter.", __local_name);
622         else
623             merror("%s: INFO: Report '%s' completed and zero alerts post-filter.", __local_name, r_filter->report_name);
624         return;
625     }
626
627
628     if(r_filter->report_name)
629         verbose("%s: INFO: Report '%s' completed. Creating output...", __local_name, r_filter->report_name);
630     else
631         verbose("%s: INFO: Report completed. Creating output...", __local_name);
632
633
634     l_print_out(" ");
635     if(r_filter->report_name)
636         l_print_out("Report '%s' completed.", r_filter->report_name);
637     else
638         l_print_out("Report completed. ==");
639     l_print_out("------------------------------------------------");
640
641     l_print_out("->Processed alerts: %d", alerts_processed);
642     l_print_out("->Post-filtering alerts: %d", alerts_filtered);
643     l_print_out("->First alert: %s", first_alert);
644     l_print_out("->Last alert: %s", last_alert);
645     l_print_out(" ");
646     l_print_out(" ");
647
648     OSStore_Sort(r_filter->top_srcip, _os_report_sort_compare);
649     OSStore_Sort(r_filter->top_user,  _os_report_sort_compare);
650     OSStore_Sort(r_filter->top_level, _os_report_sort_compare);
651     OSStore_Sort(r_filter->top_group, _os_report_sort_compare);
652     OSStore_Sort(r_filter->top_location, _os_report_sort_compare);
653     OSStore_Sort(r_filter->top_rule, _os_report_sort_compare);
654     OSStore_Sort(r_filter->top_files, _os_report_sort_compare);
655
656     if(r_filter->top_srcip)
657         os_report_printtop(r_filter->top_srcip, "Source ip", 0);
658
659     if(r_filter->top_user)
660         os_report_printtop(r_filter->top_user, "Username", 0);
661
662     if(r_filter->top_level)
663         os_report_printtop(r_filter->top_level, "Level", 0);
664
665     if(r_filter->top_group)
666         os_report_printtop(r_filter->top_group, "Group", 0);
667
668     if(r_filter->top_location)
669         os_report_printtop(r_filter->top_location, "Location", 0);
670
671     if(r_filter->top_rule)
672         os_report_printtop(r_filter->top_rule, "Rule", 0);
673
674     if(r_filter->top_files)
675         os_report_printtop(r_filter->top_files, "Filenames", 0);
676
677
678     /* Print related events. */
679     if(r_filter->related_srcip)
680         os_report_printtop(r_filter->top_srcip, "Source ip",
681                            r_filter->related_srcip);
682
683     if(r_filter->related_user)
684         os_report_printtop(r_filter->top_user, "Username",
685                            r_filter->related_user);
686
687     if(r_filter->related_level)
688         os_report_printtop(r_filter->top_level, "Level",
689                            r_filter->related_level);
690
691     if(r_filter->related_group)
692         os_report_printtop(r_filter->top_group, "Group",
693                            r_filter->related_group);
694
695     if(r_filter->related_location)
696         os_report_printtop(r_filter->top_location, "Location",
697                            r_filter->related_location);
698
699     if(r_filter->related_rule)
700         os_report_printtop(r_filter->top_rule, "Rule",
701                            r_filter->related_rule);
702
703     if(r_filter->related_file)
704         os_report_printtop(r_filter->top_files, "Filename",
705                            r_filter->related_file);
706
707
708     /* If we have to dump the alerts. */
709     if(data_to_clean)
710     {
711         int i = 0;
712
713         if(r_filter->show_alerts)
714         {
715             l_print_out("Log dump:");
716             l_print_out("------------------------------------------------");
717         }
718         while(data_to_clean[i])
719         {
720             alert_data *md = data_to_clean[i];
721             if(r_filter->show_alerts)
722                 l_print_out("%s %s\nRule: %d (level %d) -> '%s'\n%s\n\n", md->date, md->location, md->rule, md->level, md->comment, md->log[0]);
723             FreeAlertData(md);
724             i++;
725         }
726         free(data_to_clean);
727         data_to_clean = NULL;
728     }
729 }
730
731
732
733
734
735 /** int os_report_check_filters(char *filter_by, char *filter_value,
736  *                              report_filter *r_filter)
737  * Checks the configuration filters.
738  */
739 int os_report_configfilter(char *filter_by, char *filter_value,
740                            report_filter *r_filter, int arg_type)
741 {
742     if(!filter_by || !filter_value)
743     {
744         return(-1);
745     }
746
747     if(arg_type == REPORT_FILTER)
748     {
749         if(strcmp(filter_by, "group") == 0)
750         {
751             r_filter->group = filter_value;
752         }
753         else if(strcmp(filter_by, "rule") == 0)
754         {
755             r_filter->rule = filter_value;
756         }
757         else if(strcmp(filter_by, "level") == 0)
758         {
759             r_filter->level = filter_value;
760         }
761         else if(strcmp(filter_by, "location") == 0)
762         {
763             r_filter->location = filter_value;
764         }
765         else if(strcmp(filter_by, "user") == 0)
766         {
767             r_filter->user = filter_value;
768         }
769         else if(strcmp(filter_by, "srcip") == 0)
770         {
771             r_filter->srcip = filter_value;
772         }
773         else if(strcmp(filter_by, "filename") == 0)
774         {
775             r_filter->files = filter_value;
776         }
777         else
778         {
779             merror("%s: ERROR: Invalid filter '%s'.", __local_name, filter_by);
780             return(-1);
781         }
782     }
783     else
784     {
785         if(strcmp(filter_by, "group") == 0)
786         {
787             r_filter->related_group =
788             _report_filter_value(filter_value, r_filter->related_group);
789
790             if(r_filter->related_group == -1)
791                 return(-1);
792         }
793         else if(strcmp(filter_by, "rule") == 0)
794         {
795             r_filter->related_rule =
796             _report_filter_value(filter_value, r_filter->related_rule);
797
798             if(r_filter->related_rule == -1)
799                 return(-1);
800         }
801         else if(strcmp(filter_by, "level") == 0)
802         {
803             r_filter->related_level =
804             _report_filter_value(filter_value, r_filter->related_level);
805
806             if(r_filter->related_level == -1)
807                 return(-1);
808         }
809         else if(strcmp(filter_by, "location") == 0)
810         {
811             r_filter->related_location =
812             _report_filter_value(filter_value, r_filter->related_location);
813
814             if(r_filter->related_location == -1)
815                 return(-1);
816         }
817         else if(strcmp(filter_by, "srcip") == 0)
818         {
819             r_filter->related_srcip =
820             _report_filter_value(filter_value, r_filter->related_srcip);
821
822             if(r_filter->related_srcip == -1)
823                 return(-1);
824         }
825         else if(strcmp(filter_by, "user") == 0)
826         {
827             r_filter->related_user =
828             _report_filter_value(filter_value, r_filter->related_user);
829
830             if(r_filter->related_user == -1)
831                 return(-1);
832         }
833         else if(strcmp(filter_by, "filename") == 0)
834         {
835             r_filter->related_file =
836             _report_filter_value(filter_value, r_filter->related_file);
837
838             if(r_filter->related_file == -1)
839                 return(-1);
840         }
841         else
842         {
843             merror("%s: ERROR: Invalid related entry '%s'.", __local_name, filter_by);
844             return(-1);
845         }
846     }
847
848     return(0);
849 }
850
851
852
853 /* EOF */