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