1 /* Copyright (C) 2010-2012 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 /* ossec-analysisd
11 * Responsible for correlation and log decoding
12 */
13
14 #ifndef ARGV0
15 #define ARGV0 "ossec-analysisd"
16 #endif
17
18 #include "shared.h"
19 #include "alerts/alerts.h"
20 #include "alerts/getloglocation.h"
21 #include "os_execd/execd.h"
22 #include "os_regex/os_regex.h"
23 #include "os_net/os_net.h"
24 #include "active-response.h"
25 #include "config.h"
26 #include "rules.h"
27 #include "stats.h"
28 #include "eventinfo.h"
29 #include "accumulator.h"
30 #include "analysisd.h"
31 #include "fts.h"
32 #include "cleanevent.h"
33 #include "dodiff.h"
34 #include "output/jsonout.h"
35
36 #ifdef PRELUDE_OUTPUT_ENABLED
37 #include "output/prelude.h"
38 #endif
39
40 #ifdef ZEROMQ_OUTPUT_ENABLED
41 #include "output/zeromq.h"
42 #endif
43
44 #ifdef SQLITE_ENABLED
45 #include "syscheck-sqlite.h"
46 #endif
47
48 /** Prototypes **/
49 void OS_ReadMSG(int m_queue);
50 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node);
51 static void LoopRule(RuleNode *curr_node, FILE *flog);
52
53 /* For decoders */
54 void DecodeEvent(Eventinfo *lf);
55 int DecodeSyscheck(Eventinfo *lf);
56 int DecodeRootcheck(Eventinfo *lf);
57 int DecodeHostinfo(Eventinfo *lf);
58
59 /* For stats */
60 static void DumpLogstats(void);
61
62 /** Global definitions **/
63 int today;
64 int thishour;
65 int prev_year;
66 char prev_month[4];
67 int __crt_hour;
68 int __crt_wday;
69 time_t c_time;
70 char __shost[512];
71 OSDecoderInfo *NULL_Decoder;
72
73 /* execd queue */
74 static int execdq = 0;
75
76 /* Active response queue */
77 static int arq = 0;
78
79 static int hourly_alerts;
80 static int hourly_events;
81 static int hourly_syscheck;
82 static int hourly_firewall;
83
84
85 /* Print help statement */
86 __attribute__((noreturn))
help_analysisd(void)87 static void help_analysisd(void)
88 {
89 print_header();
90 print_out(" %s: -[Vhdtf] [-u user] [-g group] [-c config] [-D dir]", ARGV0);
91 print_out(" -V Version and license message");
92 print_out(" -h This help message");
93 print_out(" -d Execute in debug mode. This parameter");
94 print_out(" can be specified multiple times");
95 print_out(" to increase the debug level.");
96 print_out(" -t Test configuration");
97 print_out(" -f Run in foreground");
98 print_out(" -u <user> User to run as (default: %s)", USER);
99 print_out(" -g <group> Group to run as (default: %s)", GROUPGLOBAL);
100 print_out(" -c <config> Configuration file to use (default: %s)", DEFAULTCPATH);
101 print_out(" -D <dir> Directory to chroot into (default: %s)", DEFAULTDIR);
102 print_out(" ");
103 exit(1);
104 }
105
106 #ifndef TESTRULE
main(int argc,char ** argv)107 int main(int argc, char **argv)
108 #else
109 __attribute__((noreturn))
110 int main_analysisd(int argc, char **argv)
111 #endif
112 {
113 int c = 0, m_queue = 0, test_config = 0, run_foreground = 0;
114 int debug_level = 0;
115 const char *dir = DEFAULTDIR;
116 const char *user = USER;
117 const char *group = GROUPGLOBAL;
118 uid_t uid;
119 gid_t gid;
120
121 const char *cfg = DEFAULTCPATH;
122
123 /* Set the name */
124 OS_SetName(ARGV0);
125
126 thishour = 0;
127 today = 0;
128 prev_year = 0;
129 memset(prev_month, '\0', 4);
130 hourly_alerts = 0;
131 hourly_events = 0;
132 hourly_syscheck = 0;
133 hourly_firewall = 0;
134
135 #ifdef LIBGEOIP_ENABLED
136 geoipdb = NULL;
137 #endif
138
139
140 while ((c = getopt(argc, argv, "Vtdhfu:g:D:c:")) != -1) {
141 switch (c) {
142 case 'V':
143 print_version();
144 break;
145 case 'h':
146 help_analysisd();
147 break;
148 case 'd':
149 nowDebug();
150 debug_level = 1;
151 break;
152 case 'f':
153 run_foreground = 1;
154 break;
155 case 'u':
156 if (!optarg) {
157 ErrorExit("%s: -u needs an argument", ARGV0);
158 }
159 user = optarg;
160 break;
161 case 'g':
162 if (!optarg) {
163 ErrorExit("%s: -g needs an argument", ARGV0);
164 }
165 group = optarg;
166 break;
167 case 'D':
168 if (!optarg) {
169 ErrorExit("%s: -D needs an argument", ARGV0);
170 }
171 dir = optarg;
172 break;
173 case 'c':
174 if (!optarg) {
175 ErrorExit("%s: -c needs an argument", ARGV0);
176 }
177 cfg = optarg;
178 break;
179 case 't':
180 test_config = 1;
181 break;
182 default:
183 help_analysisd();
184 break;
185 }
186
187 }
188
189 /* Check current debug_level
190 * Command line setting takes precedence
191 */
192 if (debug_level == 0) {
193 /* Get debug level */
194 debug_level = getDefine_Int("analysisd", "debug", 0, 2);
195 while (debug_level != 0) {
196 nowDebug();
197 debug_level--;
198 }
199 }
200
201 /* Start daemon */
202 debug1(STARTED_MSG, ARGV0);
203 DEBUG_MSG("%s: DEBUG: Starting on debug mode - %d ", ARGV0, (int)time(0));
204
205 /* Check if the user/group given are valid */
206 uid = Privsep_GetUser(user);
207 gid = Privsep_GetGroup(group);
208 if (uid == (uid_t) - 1 || gid == (gid_t) - 1) {
209 ErrorExit(USER_ERROR, ARGV0, user, group);
210 }
211
212 /* Found user */
213 debug1(FOUND_USER, ARGV0);
214
215 /* Initialize Active response */
216 AR_Init();
217 if (AR_ReadConfig(cfg) < 0) {
218 ErrorExit(CONFIG_ERROR, ARGV0, cfg);
219 }
220 debug1(ASINIT, ARGV0);
221
222 /* Read configuration file */
223 if (GlobalConf(cfg) < 0) {
224 ErrorExit(CONFIG_ERROR, ARGV0, cfg);
225 }
226
227 debug1(READ_CONFIG, ARGV0);
228
229
230 #ifdef LIBGEOIP_ENABLED
231 Config.geoip_jsonout = getDefine_Int("analysisd", "geoip_jsonout", 0, 1);
232
233 /* Opening GeoIP DB */
234 if(Config.geoipdb_file) {
235 geoipdb = GeoIP_open(Config.geoipdb_file, GEOIP_INDEX_CACHE);
236 if (geoipdb == NULL)
237 {
238 merror("%s: ERROR: Unable to open GeoIP database from: %s (disabling GeoIP).", ARGV0, Config.geoipdb_file);
239 }
240 }
241 #endif
242
243
244
245 /* Fix Config.ar */
246 Config.ar = ar_flag;
247 if (Config.ar == -1) {
248 Config.ar = 0;
249 }
250
251 /* Get server's hostname */
252 memset(__shost, '\0', 512);
253 if (gethostname(__shost, 512 - 1) != 0) {
254 strncpy(__shost, OSSEC_SERVER, 512 - 1);
255 } else {
256 char *_ltmp;
257
258 /* Remove domain part if available */
259 _ltmp = strchr(__shost, '.');
260 if (_ltmp) {
261 *_ltmp = '\0';
262 }
263 }
264
265 /* Continuing in Daemon mode */
266 if (!test_config && !run_foreground) {
267 nowDaemon();
268 goDaemon();
269 }
270
271 #ifdef PRELUDE_OUTPUT_ENABLED
272 /* Start prelude */
273 if (Config.prelude) {
274 prelude_start(Config.prelude_profile, argc, argv);
275 }
276 #endif
277
278 #ifdef ZEROMQ_OUTPUT_ENABLED
279 /* Start zeromq */
280 if (Config.zeromq_output) {
281 #if CZMQ_VERSION_MAJOR == 2
282 zeromq_output_start(Config.zeromq_output_uri);
283 #elif CZMQ_VERSION_MAJOR >= 3
284 zeromq_output_start(Config.zeromq_output_uri, Config.zeromq_output_client_cert, Config.zeromq_output_server_cert);
285 #endif
286 }
287 #endif
288
289 /* Set the group */
290 if (Privsep_SetGroup(gid) < 0) {
291 ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
292 }
293
294 /* Chroot */
295 if (Privsep_Chroot(dir) < 0) {
296 ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno));
297 }
298 nowChroot();
299
300 Config.decoder_order_size = (size_t)getDefine_Int("analysisd", "decoder_order_size", 8, MAX_DECODER_ORDER_SIZE);
301
302
303 /*
304 * Anonymous Section: Load rules, decoders, and lists
305 *
306 * As lists require two-pass loading of rules that makes use of lists, lookups
307 * are created with blank database structs, and need to be filled in after
308 * completion of all rules and lists.
309 */
310 {
311 {
312 /* Initialize the decoders list */
313 OS_CreateOSDecoderList();
314
315 if (!Config.decoders) {
316 /* Legacy loading */
317 /* Read decoders */
318 if (!ReadDecodeXML(XML_DECODER)) {
319 ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER);
320 }
321
322 /* Read local ones */
323 c = ReadDecodeXML(XML_LDECODER);
324 if (!c) {
325 if ((c != -2)) {
326 ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER);
327 }
328 } else {
329 if (!test_config) {
330 verbose("%s: INFO: Reading local decoder file.", ARGV0);
331 }
332 }
333 } else {
334 /* New loaded based on file speified in ossec.conf */
335 char **decodersfiles;
336 decodersfiles = Config.decoders;
337 while ( decodersfiles && *decodersfiles) {
338 if (!test_config) {
339 verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles);
340 }
341 if (!ReadDecodeXML(*decodersfiles)) {
342 ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles);
343 }
344
345 free(*decodersfiles);
346 decodersfiles++;
347 }
348 }
349
350 /* Load decoders */
351 SetDecodeXML();
352 }
353 {
354 /* Load Lists */
355 /* Initialize the lists of list struct */
356 Lists_OP_CreateLists();
357 /* Load each list into list struct */
358 {
359 char **listfiles;
360 listfiles = Config.lists;
361 while (listfiles && *listfiles) {
362 if (!test_config) {
363 verbose("%s: INFO: Reading loading the lists file: '%s'", ARGV0, *listfiles);
364 }
365 if (Lists_OP_LoadList(*listfiles) < 0) {
366 ErrorExit(LISTS_ERROR, ARGV0, *listfiles);
367 }
368 free(*listfiles);
369 listfiles++;
370 }
371 free(Config.lists);
372 Config.lists = NULL;
373 }
374 }
375
376 {
377 /* Load Rules */
378 /* Create the rules list */
379 Rules_OP_CreateRules();
380
381 /* Read the rules */
382 {
383 char **rulesfiles;
384 rulesfiles = Config.includes;
385 while (rulesfiles && *rulesfiles) {
386 if (!test_config) {
387 verbose("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
388 }
389 if (Rules_OP_ReadRules(*rulesfiles) < 0) {
390 ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
391 }
392
393 free(*rulesfiles);
394 rulesfiles++;
395 }
396
397 free(Config.includes);
398 Config.includes = NULL;
399 }
400
401 /* Find all rules that require list lookups and attache the the
402 * correct list struct to the rule. This keeps rules from having to
403 * search thought the list of lists for the correct file during
404 * rule evaluation.
405 */
406 OS_ListLoadRules();
407 }
408 }
409
410 /* Fix the levels/accuracy */
411 {
412 int total_rules;
413 RuleNode *tmp_node = OS_GetFirstRule();
414
415 total_rules = _setlevels(tmp_node, 0);
416 if (!test_config) {
417 verbose("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);
418 }
419 }
420
421 /* Create a rules hash (for reading alerts from other servers) */
422 {
423 RuleNode *tmp_node = OS_GetFirstRule();
424 Config.g_rules_hash = OSHash_Create();
425 if (!Config.g_rules_hash) {
426 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
427 }
428 AddHash_Rule(tmp_node);
429 }
430
431 /* Ignored files on syscheck */
432 {
433 char **files;
434 files = Config.syscheck_ignore;
435 while (files && *files) {
436 if (!test_config) {
437 verbose("%s: INFO: Ignoring file: '%s'", ARGV0, *files);
438 }
439 files++;
440 }
441 }
442
443 /* Check if log_fw is enabled */
444 Config.logfw = (u_int8_t) getDefine_Int("analysisd",
445 "log_fw",
446 0, 1);
447
448 /* Success on the configuration test */
449 if (test_config) {
450 exit(0);
451 }
452
453 /* Verbose message */
454 debug1(CHROOT_MSG, ARGV0, dir);
455 debug1(PRIVSEP_MSG, ARGV0, user);
456
457 /* Signal manipulation */
458 StartSIG(ARGV0);
459
460 /* Set the user */
461 if (Privsep_SetUser(uid) < 0) {
462 ErrorExit(SETUID_ERROR, ARGV0, user, errno, strerror(errno));
463 }
464
465 /* Create the PID file */
466 if (CreatePID(ARGV0, getpid()) < 0) {
467 ErrorExit(PID_ERROR, ARGV0);
468 }
469
470 /* Set the queue */
471 if ((m_queue = StartMQ(DEFAULTQUEUE, READ)) < 0) {
472 ErrorExit(QUEUE_ERROR, ARGV0, DEFAULTQUEUE, strerror(errno));
473 }
474
475 /* allowlist */
476 if (Config.allow_list == NULL) {
477 if (Config.ar) {
478 verbose("%s: INFO: No IP in the allow list for active response.", ARGV0);
479 }
480 } else {
481 if (Config.ar) {
482 os_ip **wl;
483 int wlc = 0;
484 wl = Config.allow_list;
485 while (*wl) {
486 verbose("%s: INFO: Allow listing IP: '%s'", ARGV0, (*wl)->ip);
487 wl++;
488 wlc++;
489 }
490 verbose("%s: INFO: %d IPs in the allow list for active response.",
491 ARGV0, wlc);
492 }
493 }
494
495 /* Hostname allowlist */
496 if (Config.hostname_allow_list == NULL) {
497 if (Config.ar)
498 verbose("%s: INFO: No Hostname in the allow list for active response.",
499 ARGV0);
500 } else {
501 if (Config.ar) {
502 int wlc = 0;
503 char **wl;
504
505 wl = Config.hostname_allow_list;
506 while (*wl) {
507 verbose("%s: INFO: Allow listing Hostname: '%s'", ARGV0, *wl);
508 wlc++;
509 wl++;
510 }
511 verbose("%s: INFO: %d Hostname(s) in the allow list for active response.",
512 ARGV0, wlc);
513 }
514 }
515
516 /* Startup message */
517 verbose(STARTUP_MSG, ARGV0, (int)getpid());
518
519 /* Going to main loop */
520 OS_ReadMSG(m_queue);
521
522 exit(0);
523 }
524
525 /* Main function. Receives the messages(events) and analyze them all */
526 #ifndef TESTRULE
527 __attribute__((noreturn))
OS_ReadMSG(int m_queue)528 void OS_ReadMSG(int m_queue)
529 #else
530 __attribute__((noreturn))
531 void OS_ReadMSG_analysisd(int m_queue)
532 #endif
533 {
534 int i;
535 char msg[OS_MAXSTR + 1];
536 Eventinfo *lf;
537
538 RuleInfo *stats_rule = NULL;
539
540 /* Null to global currently pointers */
541 currently_rule = NULL;
542
543 /* Initialize the logs */
544 OS_InitLog();
545
546 /* Initialize the integrity database */
547 SyscheckInit();
548
549 /* Initialize Rootcheck */
550 RootcheckInit();
551
552 /* Initialize host info */
553 HostinfoInit();
554
555 /* Create the event list */
556 OS_CreateEventList(Config.memorysize);
557
558 /* Initiate the FTS list */
559 if (!FTS_Init()) {
560 ErrorExit(FTS_LIST_ERROR, ARGV0);
561 }
562
563 /* Initialize the Accumulator */
564 if (!Accumulate_Init()) {
565 merror("accumulator: ERROR: Initialization failed");
566 exit(1);
567 }
568
569 /* Start the active response queues */
570 if (Config.ar) {
571 /* Waiting the ARQ to settle */
572 sleep(3);
573
574 #ifndef LOCAL
575 if (Config.ar & REMOTE_AR) {
576 if ((arq = StartMQ(ARQUEUE, WRITE)) < 0) {
577 merror(ARQ_ERROR, ARGV0);
578
579 /* If LOCAL_AR is set, keep it there */
580 if (Config.ar & LOCAL_AR) {
581 Config.ar = 0;
582 Config.ar |= LOCAL_AR;
583 } else {
584 Config.ar = 0;
585 }
586 } else {
587 verbose(CONN_TO, ARGV0, ARQUEUE, "active-response");
588 }
589 }
590 #else
591 /* Only for LOCAL_ONLY installs */
592 if (Config.ar & REMOTE_AR) {
593 if (Config.ar & LOCAL_AR) {
594 Config.ar = 0;
595 Config.ar |= LOCAL_AR;
596 } else {
597 Config.ar = 0;
598 }
599 }
600 #endif
601
602 if (Config.ar & LOCAL_AR) {
603 if ((execdq = StartMQ(EXECQUEUE, WRITE)) < 0) {
604 merror(ARQ_ERROR, ARGV0);
605
606 /* If REMOTE_AR is set, keep it there */
607 if (Config.ar & REMOTE_AR) {
608 Config.ar = 0;
609 Config.ar |= REMOTE_AR;
610 } else {
611 Config.ar = 0;
612 }
613 } else {
614 verbose(CONN_TO, ARGV0, EXECQUEUE, "exec");
615 }
616 }
617 }
618 debug1("%s: DEBUG: Active response Init completed.", ARGV0);
619
620 /* Get current time before starting */
621 c_time = time(NULL);
622
623 /* Start the hourly/weekly stats */
624 if (Start_Hour() < 0) {
625 Config.stats = 0;
626 } else {
627 /* Initialize stats rules */
628 stats_rule = zerorulemember(
629 STATS_MODULE,
630 Config.stats,
631 0, 0, 0, 0, 0, 0);
632
633 if (!stats_rule) {
634 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
635 }
636 stats_rule->group = "stats,";
637 stats_rule->comment = "Excessive number of events (above normal).";
638 }
639
640 /* Do some cleanup */
641 memset(msg, '\0', OS_MAXSTR + 1);
642
643 /* Initialize the logs */
644 {
645 lf = (Eventinfo *)calloc(1, sizeof(Eventinfo));
646 if (!lf) {
647 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
648 }
649 os_calloc(Config.decoder_order_size, sizeof(char*), lf->fields);
650 lf->year = prev_year;
651 strncpy(lf->mon, prev_month, 3);
652 lf->day = today;
653
654 if (OS_GetLogLocation(lf) < 0) {
655 ErrorExit("%s: Error allocating log files", ARGV0);
656 }
657
658 Free_Eventinfo(lf);
659 }
660
661 #ifdef SQLITE_ENABLED
662 /* Open the sqlite db */
663 extern sqlite3 *conn;
664 int s_error = 0;
665 if (Config.md5_allowlist) {
666 debug2("Opening md5_allowlist: %s", Config.md5_allowlist);
667 if((s_error = sqlite3_open(Config.md5_allowlist, &conn))) {
668 merror(INVALID_IGNORE_MD5DB, ARGV0, Config.md5_allowlist);
669 }
670
671 }
672 #endif
673
674 debug1("%s: DEBUG: Startup completed. Waiting for new messages..", ARGV0);
675
676 if (Config.custom_alert_output) {
677 debug1("%s: INFO: Custom output found.!", ARGV0);
678 }
679
680 /* Daemon loop */
681 while (1) {
682 lf = (Eventinfo *)calloc(1, sizeof(Eventinfo));
683 os_calloc(Config.decoder_order_size, sizeof(char*), lf->fields);
684
685 /* This shouldn't happen */
686 if (lf == NULL) {
687 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
688 }
689
690 DEBUG_MSG("%s: DEBUG: Waiting for msgs - %d ", ARGV0, (int)time(0));
691
692 /* Receive message from queue */
693 if ((i = OS_RecvUnix(m_queue, OS_MAXSTR, msg))) {
694 RuleNode *rulenode_pt;
695
696 /* Get the time we received the event */
697 c_time = time(NULL);
698
699 /* Default values for the log info */
700 Zero_Eventinfo(lf);
701
702 /* Check for a valid message */
703 if (i < 4) {
704 merror(IMSG_ERROR, ARGV0, msg);
705 Free_Eventinfo(lf);
706 continue;
707 }
708
709 /* Message before extracting header */
710 DEBUG_MSG("%s: DEBUG: Received msg: %s ", ARGV0, msg);
711
712 /* Clean the msg appropriately */
713 if (OS_CleanMSG(msg, lf) < 0) {
714 merror(IMSG_ERROR, ARGV0, msg);
715 Free_Eventinfo(lf);
716 continue;
717 }
718
719 /* Msg cleaned */
720 DEBUG_MSG("%s: DEBUG: Msg cleanup: %s ", ARGV0, lf->log);
721
722 /* Current rule must be null in here */
723 currently_rule = NULL;
724
725 /** Check the date/hour changes **/
726
727 /* Update the hour */
728 if (thishour != __crt_hour) {
729 /* Search all the rules and print the number
730 * of alerts that each one fired
731 */
732 DumpLogstats();
733 thishour = __crt_hour;
734
735 /* Check if the date has changed */
736 if (today != lf->day) {
737 if (Config.stats) {
738 /* Update the hourly stats (done daily) */
739 Update_Hour();
740 }
741
742 if (OS_GetLogLocation(lf) < 0) {
743 ErrorExit("%s: Error allocating log files", ARGV0);
744 }
745
746 today = lf->day;
747 strncpy(prev_month, lf->mon, 3);
748 prev_year = lf->year;
749 }
750 }
751
752
753 /* Increment number of events received */
754 hourly_events++;
755
756 /*** Run decoders ***/
757
758 /* Integrity check from syscheck */
759 if (msg[0] == SYSCHECK_MQ) {
760 hourly_syscheck++;
761
762 if (!DecodeSyscheck(lf)) {
763 /* We don't process syscheck events further */
764 goto CLMEM;
765 }
766
767 /* Get log size */
768 lf->size = strlen(lf->log);
769 }
770
771 /* Rootcheck decoding */
772 else if (msg[0] == ROOTCHECK_MQ) {
773 if (!DecodeRootcheck(lf)) {
774 /* We don't process rootcheck events further */
775 goto CLMEM;
776 }
777 lf->size = strlen(lf->log);
778 }
779
780 /* Host information special decoder */
781 else if (msg[0] == HOSTINFO_MQ) {
782 if (!DecodeHostinfo(lf)) {
783 /* We don't process hostinfo events further */
784 goto CLMEM;
785 }
786 lf->size = strlen(lf->log);
787 }
788
789 /* Run the general Decoders */
790 else {
791 /* Get log size */
792 lf->size = strlen(lf->log);
793
794 DecodeEvent(lf);
795 }
796
797 /* Run accumulator */
798 if ( lf->decoder_info->accumulate == 1 ) {
799 lf = Accumulate(lf);
800 }
801
802 /* Firewall event */
803 if (lf->decoder_info->type == FIREWALL) {
804 /* If we could not get any information from
805 * the log, just ignore it
806 */
807 hourly_firewall++;
808 if (Config.logfw) {
809 if (!FW_Log(lf)) {
810 goto CLMEM;
811 }
812 }
813 }
814
815 /* We only check if the last message is
816 * duplicated on syslog
817 */
818 else if (lf->decoder_info->type == SYSLOG) {
819 /* Check if the message is duplicated */
820 if (LastMsg_Stats(lf->full_log) == 1) {
821 goto CLMEM;
822 } else {
823 LastMsg_Change(lf->full_log);
824 }
825 }
826
827 /* Stats checking */
828 if (Config.stats) {
829 if (Check_Hour() == 1) {
830 RuleInfo *saved_rule = lf->generated_rule;
831 char *saved_log;
832
833 /* Save previous log */
834 saved_log = lf->full_log;
835
836 lf->generated_rule = stats_rule;
837 lf->full_log = __stats_comment;
838
839 /* Alert for statistical analysis */
840 if (stats_rule->alert_opts & DO_LOGALERT) {
841 __crt_ftell = ftell(_aflog);
842 if (Config.custom_alert_output) {
843 OS_CustomLog(lf, Config.custom_alert_output_format);
844 } else {
845 OS_Log(lf);
846 }
847 /* Log to json file */
848 if (Config.jsonout_output) {
849 jsonout_output_event(lf);
850 }
851
852 }
853
854 /* Set lf to the old values */
855 lf->generated_rule = saved_rule;
856 lf->full_log = saved_log;
857 }
858 }
859
860 /* Check the rules */
861 DEBUG_MSG("%s: DEBUG: Checking the rules - %d ",
862 ARGV0, lf->decoder_info->type);
863
864 /* Loop over all the rules */
865 rulenode_pt = OS_GetFirstRule();
866 if (!rulenode_pt) {
867 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
868 ARGV0);
869 }
870
871 do {
872 if (lf->decoder_info->type == OSSEC_ALERT) {
873 if (!lf->generated_rule) {
874 goto CLMEM;
875 }
876
877 /* Process the alert */
878 currently_rule = lf->generated_rule;
879 }
880
881 /* Categories must match */
882 else if (rulenode_pt->ruleinfo->category !=
883 lf->decoder_info->type) {
884 continue;
885 }
886
887 /* Check each rule */
888 else if ((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt))
889 == NULL) {
890 continue;
891 }
892
893 /* Ignore level 0 */
894 if (currently_rule->level == 0) {
895 break;
896 }
897
898 /* Check ignore time */
899 if (currently_rule->ignore_time) {
900 if (currently_rule->time_ignored == 0) {
901 currently_rule->time_ignored = lf->time;
902 }
903 /* If the current time - the time the rule was ignored
904 * is less than the time it should be ignored,
905 * leave (do not alert again)
906 */
907 else if ((lf->time - currently_rule->time_ignored)
908 < currently_rule->ignore_time) {
909 break;
910 } else {
911 currently_rule->time_ignored = lf->time;
912 }
913 }
914
915 /* Pointer to the rule that generated it */
916 lf->generated_rule = currently_rule;
917
918 /* Check if we should ignore it */
919 if (currently_rule->ckignore && IGnore(lf)) {
920 /* Ignore rule */
921 lf->generated_rule = NULL;
922 break;
923 }
924
925 /* Check if we need to add to ignore list */
926 if (currently_rule->ignore) {
927 AddtoIGnore(lf);
928 }
929
930 /* Log the alert if configured to */
931 if (currently_rule->alert_opts & DO_LOGALERT) {
932 __crt_ftell = ftell(_aflog);
933
934 if (Config.custom_alert_output) {
935 OS_CustomLog(lf, Config.custom_alert_output_format);
936 } else {
937 OS_Log(lf);
938 }
939 /* Log to json file */
940 if (Config.jsonout_output) {
941 jsonout_output_event(lf);
942 }
943 }
944
945 #ifdef PRELUDE_OUTPUT_ENABLED
946 /* Log to prelude */
947 if (Config.prelude) {
948 if (Config.prelude_log_level <= currently_rule->level) {
949 OS_PreludeLog(lf);
950 }
951 }
952 #endif
953
954 #ifdef ZEROMQ_OUTPUT_ENABLED
955 /* Log to zeromq */
956 if (Config.zeromq_output) {
957 zeromq_output_event(lf);
958 }
959 #endif
960
961
962 /* Execute an active response */
963 if (currently_rule->ar) {
964 int do_ar;
965 active_response **rule_ar;
966
967 rule_ar = currently_rule->ar;
968
969 while (*rule_ar) {
970 do_ar = 1;
971 if ((*rule_ar)->ar_cmd->expect & USERNAME) {
972 if (!lf->dstuser ||
973 !OS_PRegex(lf->dstuser, "^[a-zA-Z._0-9@?-]*$")) {
974 if (lf->dstuser) {
975 merror(CRAFTED_USER, ARGV0, lf->dstuser);
976 }
977 do_ar = 0;
978 }
979 }
980 if ((*rule_ar)->ar_cmd->expect & SRCIP) {
981 if (!lf->srcip ||
982 !OS_PRegex(lf->srcip, "^[a-zA-Z.:_0-9-]*$")) {
983 if (lf->srcip) {
984 merror(CRAFTED_IP, ARGV0, lf->srcip);
985 }
986 do_ar = 0;
987 }
988 }
989 if ((*rule_ar)->ar_cmd->expect & FILENAME) {
990 if (!lf->filename) {
991 do_ar = 0;
992 }
993 }
994
995 if (do_ar && execdq > 0) {
996 OS_Exec(execdq, arq, lf, *rule_ar);
997 }
998 rule_ar++;
999 }
1000 }
1001
1002 /* Copy the structure to the state memory of if_matched_sid */
1003 if (currently_rule->sid_prev_matched) {
1004 if (!OSList_AddData(currently_rule->sid_prev_matched, lf)) {
1005 merror("%s: Unable to add data to sig list.", ARGV0);
1006 } else {
1007 lf->sid_node_to_delete =
1008 currently_rule->sid_prev_matched->last_node;
1009 }
1010 }
1011 /* Group list */
1012 else if (currently_rule->group_prev_matched) {
1013 unsigned int j = 0;
1014
1015 while (j < currently_rule->group_prev_matched_sz) {
1016 if (!OSList_AddData(
1017 currently_rule->group_prev_matched[j],
1018 lf)) {
1019 merror("%s: Unable to add data to grp list.", ARGV0);
1020 }
1021 j++;
1022 }
1023 }
1024
1025 OS_AddEvent(lf);
1026
1027 break;
1028
1029 } while ((rulenode_pt = rulenode_pt->next) != NULL);
1030
1031 /* If configured to log all, do it */
1032 if (Config.logall)
1033 OS_Store(lf);
1034 if (Config.logall_json)
1035 jsonout_output_archive(lf);
1036
1037 CLMEM:
1038 /** Cleaning the memory **/
1039
1040 /* Only clear the memory if the eventinfo was not
1041 * added to the stateful memory
1042 * -- message is free inside clean event --
1043 */
1044 if (lf->generated_rule == NULL) {
1045 Free_Eventinfo(lf);
1046 }
1047 } else {
1048 free(lf);
1049 }
1050 }
1051 }
1052
1053 /* Checks if the current_rule matches the event information */
OS_CheckIfRuleMatch(Eventinfo * lf,RuleNode * curr_node)1054 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node)
1055 {
1056 /* We check for:
1057 * decoded_as,
1058 * fts,
1059 * word match (fast regex),
1060 * regex,
1061 * url,
1062 * id,
1063 * user,
1064 * maxsize,
1065 * protocol,
1066 * srcip,
1067 * dstip,
1068 * srcport,
1069 * dstport,
1070 * time,
1071 * weekday,
1072 * status,
1073 */
1074 RuleInfo *rule = curr_node->ruleinfo;
1075 int i;
1076
1077 /* Can't be null */
1078 if (!rule) {
1079 merror("%s: Inconsistent state. currently rule NULL", ARGV0);
1080 return (NULL);
1081 }
1082
1083 #ifdef TESTRULE
1084 if (full_output && !alert_only)
1085 print_out(" Trying rule: %d - %s", rule->sigid,
1086 rule->comment);
1087 #endif
1088
1089 /* Check if any decoder pre-matched here */
1090 if (rule->decoded_as &&
1091 rule->decoded_as != lf->decoder_info->id) {
1092 return (NULL);
1093 }
1094
1095 /* Check program name */
1096 if (rule->program_name) {
1097 if (!lf->program_name) {
1098 return (NULL);
1099 }
1100
1101 if (!OSMatch_Execute(lf->program_name,
1102 lf->p_name_size,
1103 rule->program_name)) {
1104 return (NULL);
1105 }
1106 }
1107 else if (rule->program_name_pcre2) {
1108 if (!lf->program_name) {
1109 return (NULL);
1110 }
1111
1112 if (!OSPcre2_Execute(lf->program_name,
1113 rule->program_name_pcre2)) {
1114 return (NULL);
1115 }
1116 }
1117
1118 /* Check for the ID */
1119 if (rule->id) {
1120 if (!lf->id) {
1121 return (NULL);
1122 }
1123
1124 if (!OSMatch_Execute(lf->id,
1125 strlen(lf->id),
1126 rule->id)) {
1127 return (NULL);
1128 }
1129 }
1130 else if (rule->id_pcre2) {
1131 if (!lf->id) {
1132 return (NULL);
1133 }
1134
1135 if (!OSPcre2_Execute(lf->id,
1136 rule->id_pcre2)) {
1137 return (NULL);
1138 }
1139 }
1140
1141 /* Check if any word to match exists */
1142 if (rule->match) {
1143 if (!OSMatch_Execute(lf->log, lf->size, rule->match)) {
1144 return (NULL);
1145 }
1146 }
1147 else if (rule->match_pcre2) {
1148 if (!OSPcre2_Execute(lf->log, rule->match_pcre2)) {
1149 return (NULL);
1150 }
1151 }
1152
1153 /* Check if exist any regex for this rule */
1154 if (rule->regex) {
1155 if (!OSRegex_Execute(lf->log, rule->regex)) {
1156 return (NULL);
1157 }
1158 }
1159 else if (rule->pcre2) {
1160 if (!OSPcre2_Execute(lf->log, rule->pcre2)) {
1161 return (NULL);
1162 }
1163 }
1164
1165 /* Check for actions */
1166 if (rule->action) {
1167 if (!lf->action) {
1168 return (NULL);
1169 }
1170
1171 if (strcmp(rule->action, lf->action) != 0) {
1172 return (NULL);
1173 }
1174 }
1175
1176 /* Checking for the URL */
1177 if (rule->url) {
1178 if (!lf->url) {
1179 return (NULL);
1180 }
1181
1182 if (!OSMatch_Execute(lf->url, strlen(lf->url), rule->url)) {
1183 return (NULL);
1184 }
1185 }
1186 if (rule->url_pcre2) {
1187 if (!lf->url) {
1188 return (NULL);
1189 }
1190
1191 if (!OSPcre2_Execute(lf->url, rule->url_pcre2)) {
1192 return (NULL);
1193 }
1194 }
1195
1196 /* Check for dynamic fields */
1197
1198 for (i = 0; i < Config.decoder_order_size && rule->fields[i]; i++) {
1199 int j;
1200
1201 for (j = 0; j < Config.decoder_order_size; j++)
1202 if (lf->decoder_info->fields[j])
1203 if (strcasecmp(lf->decoder_info->fields[j], rule->fields[i]->name) == 0)
1204 break;
1205
1206 if (j == Config.decoder_order_size)
1207
1208 return NULL;
1209
1210 if (!OSRegex_Execute(lf->fields[j], rule->fields[i]->regex))
1211 return NULL;
1212 }
1213
1214
1215 /* Get TCP/IP packet information */
1216 if (rule->alert_opts & DO_PACKETINFO) {
1217 /* Check for the srcip */
1218 if (rule->srcip) {
1219 if (!lf->srcip) {
1220 return (NULL);
1221 }
1222
1223 if (!OS_IPFoundList(lf->srcip, rule->srcip)) {
1224 return (NULL);
1225 }
1226 }
1227
1228 /* Check for the dstip */
1229 if (rule->dstip) {
1230 if (!lf->dstip) {
1231 return (NULL);
1232 }
1233
1234 if (!OS_IPFoundList(lf->dstip, rule->dstip)) {
1235 return (NULL);
1236 }
1237 }
1238
1239 if (rule->srcport) {
1240 if (!lf->srcport) {
1241 return (NULL);
1242 }
1243
1244 if (!OSMatch_Execute(lf->srcport,
1245 strlen(lf->srcport),
1246 rule->srcport)) {
1247 return (NULL);
1248 }
1249 }
1250 else if (rule->srcport_pcre2) {
1251 if (!lf->srcport) {
1252 return (NULL);
1253 }
1254
1255 if (!OSPcre2_Execute(lf->srcport,
1256 rule->srcport_pcre2)) {
1257 return (NULL);
1258 }
1259 }
1260 if (rule->dstport) {
1261 if (!lf->dstport) {
1262 return (NULL);
1263 }
1264
1265 if (!OSMatch_Execute(lf->dstport,
1266 strlen(lf->dstport),
1267 rule->dstport)) {
1268 return (NULL);
1269 }
1270 }
1271 else if (rule->dstport_pcre2) {
1272 if (!lf->dstport) {
1273 return (NULL);
1274 }
1275
1276 if (!OSPcre2_Execute(lf->dstport,
1277 rule->dstport_pcre2)) {
1278 return (NULL);
1279 }
1280 }
1281 } /* END PACKET_INFO */
1282
1283 /* Extra information from event */
1284 if (rule->alert_opts & DO_EXTRAINFO) {
1285 /* Check compiled rule */
1286 if (rule->compiled_rule) {
1287 if (!rule->compiled_rule(lf)) {
1288 return (NULL);
1289 }
1290 }
1291
1292 /* Checking if exist any user to match */
1293 if (rule->user) {
1294 if (lf->dstuser) {
1295 if (!OSMatch_Execute(lf->dstuser,
1296 strlen(lf->dstuser),
1297 rule->user)) {
1298 return (NULL);
1299 }
1300 } else if (lf->srcuser) {
1301 if (!OSMatch_Execute(lf->srcuser,
1302 strlen(lf->srcuser),
1303 rule->user)) {
1304 return (NULL);
1305 }
1306 } else {
1307 /* no user set */
1308 return (NULL);
1309 }
1310 }
1311 else if (rule->user_pcre2) {
1312 if (lf->dstuser) {
1313 if (!OSPcre2_Execute(lf->dstuser,
1314 rule->user_pcre2)) {
1315 return (NULL);
1316 }
1317 } else if (lf->srcuser) {
1318 if (!OSPcre2_Execute(lf->srcuser,
1319 rule->user_pcre2)) {
1320 return (NULL);
1321 }
1322 } else {
1323 /* no user set */
1324 return (NULL);
1325 }
1326 }
1327
1328 /* Adding checks for geoip. */
1329 if(rule->srcgeoip) {
1330 if(lf->srcgeoip) {
1331 if(!OSMatch_Execute(lf->srcgeoip,
1332 strlen(lf->srcgeoip),
1333 rule->srcgeoip))
1334 return(NULL);
1335 } else {
1336 return(NULL);
1337 }
1338 }
1339 else if(rule->srcgeoip_pcre2) {
1340 if(lf->srcgeoip) {
1341 if(!OSPcre2_Execute(lf->srcgeoip,
1342 rule->srcgeoip_pcre2))
1343 return(NULL);
1344 } else {
1345 return(NULL);
1346 }
1347 }
1348
1349
1350 if(rule->dstgeoip) {
1351 if(lf->dstgeoip) {
1352 if(!OSMatch_Execute(lf->dstgeoip,
1353 strlen(lf->dstgeoip),
1354 rule->dstgeoip))
1355 return(NULL);
1356 } else {
1357 return(NULL);
1358 }
1359 }
1360 else if(rule->dstgeoip_pcre2) {
1361 if(lf->dstgeoip) {
1362 if(!OSPcre2_Execute(lf->dstgeoip,
1363 rule->dstgeoip_pcre2))
1364 return(NULL);
1365 } else {
1366 return(NULL);
1367 }
1368 }
1369
1370
1371 /* Check if any rule related to the size exist */
1372 if (rule->maxsize) {
1373 if (lf->size < rule->maxsize) {
1374 return (NULL);
1375 }
1376 }
1377
1378 /* Check if we are in the right time */
1379 if (rule->day_time) {
1380 if (!OS_IsonTime(lf->hour, rule->day_time)) {
1381 return (NULL);
1382 }
1383 }
1384
1385 /* Check week day */
1386 if (rule->week_day) {
1387 if (!OS_IsonDay(__crt_wday, rule->week_day)) {
1388 return (NULL);
1389 }
1390 }
1391
1392 /* Get extra data */
1393 if (rule->extra_data) {
1394 if (!lf->data) {
1395 return (NULL);
1396 }
1397
1398 if (!OSMatch_Execute(lf->data,
1399 strlen(lf->data),
1400 rule->extra_data)) {
1401 return (NULL);
1402 }
1403 }
1404 else if (rule->extra_data_pcre2) {
1405 if (!lf->data) {
1406 return (NULL);
1407 }
1408
1409 if (!OSPcre2_Execute(lf->data,
1410 rule->extra_data_pcre2)) {
1411 return (NULL);
1412 }
1413 }
1414
1415 /* Check hostname */
1416 if (rule->hostname) {
1417 if (!lf->hostname) {
1418 return (NULL);
1419 }
1420
1421 if (!OSMatch_Execute(lf->hostname,
1422 strlen(lf->hostname),
1423 rule->hostname)) {
1424 return (NULL);
1425 }
1426 }
1427 else if (rule->hostname_pcre2) {
1428 if (!lf->hostname) {
1429 return (NULL);
1430 }
1431
1432 if (!OSPcre2_Execute(lf->hostname,
1433 rule->hostname_pcre2)) {
1434 return (NULL);
1435 }
1436 }
1437
1438 /* Check for status */
1439 if (rule->status) {
1440 if (!lf->status) {
1441 return (NULL);
1442 }
1443
1444 if (!OSMatch_Execute(lf->status,
1445 strlen(lf->status),
1446 rule->status)) {
1447 return (NULL);
1448 }
1449 }
1450 else if (rule->status_pcre2) {
1451 if (!lf->status) {
1452 return (NULL);
1453 }
1454
1455 if (!OSPcre2_Execute(lf->status,
1456 rule->status_pcre2)) {
1457 return (NULL);
1458 }
1459 }
1460
1461
1462 /* Do diff check */
1463 if (rule->context_opts & SAME_DODIFF) {
1464 if (!doDiff(rule, lf)) {
1465 return (NULL);
1466 }
1467 }
1468 }
1469
1470 /* Check for the FTS flag */
1471 if (rule->alert_opts & DO_FTS) {
1472 /** FTS CHECKS **/
1473 if (lf->decoder_info->fts) {
1474 if (lf->decoder_info->fts & FTS_DONE) {
1475 /* We already did the fts in here */
1476 } else if (!FTS(lf)) {
1477 return (NULL);
1478 }
1479 } else {
1480 return (NULL);
1481 }
1482 }
1483
1484 /* List lookups */
1485 if (rule->lists != NULL) {
1486 ListRule *list_holder = rule->lists;
1487 while (list_holder) {
1488 switch (list_holder->field) {
1489 case RULE_SRCIP:
1490 if (!lf->srcip) {
1491 return (NULL);
1492 }
1493 if (!OS_DBSearch(list_holder, lf->srcip)) {
1494 return (NULL);
1495 }
1496 break;
1497 case RULE_SRCPORT:
1498 if (!lf->srcport) {
1499 return (NULL);
1500 }
1501 if (!OS_DBSearch(list_holder, lf->srcport)) {
1502 return (NULL);
1503 }
1504 break;
1505 case RULE_DSTIP:
1506 if (!lf->dstip) {
1507 return (NULL);
1508 }
1509 if (!OS_DBSearch(list_holder, lf->dstip)) {
1510 return (NULL);
1511 }
1512 break;
1513 case RULE_DSTPORT:
1514 if (!lf->dstport) {
1515 return (NULL);
1516 }
1517 if (!OS_DBSearch(list_holder, lf->dstport)) {
1518 return (NULL);
1519 }
1520 break;
1521 case RULE_USER:
1522 if (lf->srcuser) {
1523 if (!OS_DBSearch(list_holder, lf->srcuser)) {
1524 return (NULL);
1525 }
1526 } else if (lf->dstuser) {
1527 if (!OS_DBSearch(list_holder, lf->dstuser)) {
1528 return (NULL);
1529 }
1530 } else {
1531 return (NULL);
1532 }
1533 break;
1534 case RULE_URL:
1535 if (!lf->url) {
1536 return (NULL);
1537 }
1538 if (!OS_DBSearch(list_holder, lf->url)) {
1539 return (NULL);
1540 }
1541 break;
1542 case RULE_ID:
1543 if (!lf->id) {
1544 return (NULL);
1545 }
1546 if (!OS_DBSearch(list_holder, lf->id)) {
1547 return (NULL);
1548 }
1549 break;
1550 case RULE_HOSTNAME:
1551 if (!lf->hostname) {
1552 return (NULL);
1553 }
1554 if (!OS_DBSearch(list_holder, lf->hostname)) {
1555 return (NULL);
1556 }
1557 break;
1558 case RULE_PROGRAM_NAME:
1559 if (!lf->program_name) {
1560 return (NULL);
1561 }
1562 if (!OS_DBSearch(list_holder, lf->program_name)) {
1563 return (NULL);
1564 }
1565 break;
1566 case RULE_STATUS:
1567 if (!lf->status) {
1568 return (NULL);
1569 }
1570 if (!OS_DBSearch(list_holder, lf->status)) {
1571 return (NULL);
1572 }
1573 break;
1574 case RULE_ACTION:
1575 if (!lf->action) {
1576 return (NULL);
1577 }
1578 if (!OS_DBSearch(list_holder, lf->action)) {
1579 return (NULL);
1580 }
1581 break;
1582 default:
1583 return (NULL);
1584 }
1585
1586 list_holder = list_holder->next;
1587 }
1588 }
1589
1590 /* If it is a context rule, search for it */
1591 if (rule->context == 1) {
1592 if (!(rule->context_opts & SAME_DODIFF)) {
1593 if (rule->event_search) {
1594 if (!rule->event_search(lf, rule)) {
1595 return (NULL);
1596 }
1597 }
1598 }
1599 }
1600
1601 #ifdef TESTRULE
1602 if (full_output && !alert_only) {
1603 print_out(" *Rule %d matched.", rule->sigid);
1604 }
1605 #endif
1606
1607 /* Search for dependent rules */
1608 if (curr_node->child) {
1609 RuleNode *child_node = curr_node->child;
1610 RuleInfo *child_rule = NULL;
1611
1612 #ifdef TESTRULE
1613 if (full_output && !alert_only) {
1614 print_out(" *Trying child rules.");
1615 }
1616 #endif
1617
1618 while (child_node) {
1619 child_rule = OS_CheckIfRuleMatch(lf, child_node);
1620 if (child_rule != NULL) {
1621 return (child_rule);
1622 }
1623
1624 child_node = child_node->next;
1625 }
1626 }
1627
1628 /* If we are set to no alert, keep going */
1629 if (rule->alert_opts & NO_ALERT) {
1630 return (NULL);
1631 }
1632
1633 hourly_alerts++;
1634 rule->firedtimes++;
1635
1636 return (rule); /* Matched */
1637 }
1638
1639 /* Update each rule and print it to the logs */
LoopRule(RuleNode * curr_node,FILE * flog)1640 static void LoopRule(RuleNode *curr_node, FILE *flog)
1641 {
1642 if (curr_node->ruleinfo->firedtimes) {
1643 fprintf(flog, "%d-%d-%d-%d\n",
1644 thishour,
1645 curr_node->ruleinfo->sigid,
1646 curr_node->ruleinfo->level,
1647 curr_node->ruleinfo->firedtimes);
1648 curr_node->ruleinfo->firedtimes = 0;
1649 }
1650
1651 if (curr_node->child) {
1652 RuleNode *child_node = curr_node->child;
1653
1654 while (child_node) {
1655 LoopRule(child_node, flog);
1656 child_node = child_node->next;
1657 }
1658 }
1659 return;
1660 }
1661
1662 /* Dump the hourly stats about each rule */
DumpLogstats()1663 static void DumpLogstats()
1664 {
1665 RuleNode *rulenode_pt;
1666 char logfile[OS_FLSIZE + 1];
1667 FILE *flog;
1668
1669 /* Open log file */
1670 snprintf(logfile, OS_FLSIZE, "%s/%d/", STATSAVED, prev_year);
1671 if (IsDir(logfile) == -1)
1672 if (mkdir(logfile, 0770) == -1) {
1673 merror(MKDIR_ERROR, ARGV0, logfile, errno, strerror(errno));
1674 return;
1675 }
1676
1677 snprintf(logfile, OS_FLSIZE, "%s/%d/%s", STATSAVED, prev_year, prev_month);
1678
1679 if (IsDir(logfile) == -1)
1680 if (mkdir(logfile, 0770) == -1) {
1681 merror(MKDIR_ERROR, ARGV0, logfile, errno, strerror(errno));
1682 return;
1683 }
1684
1685
1686 /* Creat the logfile name */
1687 snprintf(logfile, OS_FLSIZE, "%s/%d/%s/ossec-%s-%02d.log",
1688 STATSAVED,
1689 prev_year,
1690 prev_month,
1691 "totals",
1692 today);
1693
1694 flog = fopen(logfile, "a");
1695 if (!flog) {
1696 merror(FOPEN_ERROR, ARGV0, logfile, errno, strerror(errno));
1697 return;
1698 }
1699
1700 rulenode_pt = OS_GetFirstRule();
1701
1702 if (!rulenode_pt) {
1703 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
1704 ARGV0);
1705 }
1706
1707 /* Loop over all the rules and print their stats */
1708 do {
1709 LoopRule(rulenode_pt, flog);
1710 } while ((rulenode_pt = rulenode_pt->next) != NULL);
1711
1712
1713 /* Print total for the hour */
1714 fprintf(flog, "%d--%d--%d--%d--%d\n\n",
1715 thishour,
1716 hourly_alerts, hourly_events, hourly_syscheck, hourly_firewall);
1717 hourly_alerts = 0;
1718 hourly_events = 0;
1719 hourly_syscheck = 0;
1720 hourly_firewall = 0;
1721
1722 fclose(flog);
1723 }
1724
1725