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