2acde595baa6423f2393c0ad1ae2c62a94a19fae
[ossec-hids.git] / src / analysisd / alerts / log.c
1 /* @(#) $Id: ./src/analysisd/alerts/log.c, 2012/03/30 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All right reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  */
12
13
14 #include "shared.h"
15 #include "log.h"
16 #include "alerts.h"
17 #include "getloglocation.h"
18 #include "rules.h"
19 #include "eventinfo.h"
20 #include "config.h"
21
22 #ifdef GEOIP
23 /* GeoIP Stuff */
24 #include "GeoIP.h"
25 #include "GeoIPCity.h"
26
27 #define RFC1918_10     (167772160 & 4278190080)        /* 10/8 */
28 #define RFC1918_172    (2886729728 & 4293918720)       /* 172.17/12 */
29 #define RFC1918_192    (3232235520 & 4294901760)       /* 192.168/16 */
30 #define NETMASK_8      4278190080      /* 255.0.0.0    */
31 #define NETMASK_12     4293918720      /* 255.240.0.0  */
32 #define NETMASK_16     4294901760      /* 255.255.0.0  */
33
34 static const char * _mk_NA( const char * p ){
35         return (p ? p : "N/A");
36 }
37
38 /* StrIP2Long */
39 /* Convert an dot-quad IP address into long format
40  */
41 static unsigned long StrIP2Int(const char *ip) {
42         unsigned int c1,c2,c3,c4;
43         /* IP address is not coming from user input -> We can trust it */
44         /* only minimal checking is performed */
45         size_t len = strlen(ip);
46         if ((len < 7) || (len > 15)) return (0);
47
48         sscanf(ip, "%u.%u.%u.%u", &c1, &c2, &c3, &c4);
49         return((unsigned long)c4+c3*256+c2*256*256+c1*256*256*256);
50 }
51
52
53 /* GeoIP_Lookup */
54 /* Use the GeoIP API to locate an IP address
55  */
56 static void GeoIP_Lookup(const char *ip, char *buffer, const size_t length)
57 {
58         GeoIP   *gi;
59         GeoIPRecord     *gir;
60
61         /* Dumb way to detect an IPv6 address */
62         if (strchr(ip, ':')) {
63                 /* Use the IPv6 DB */
64                 gi = GeoIP_open(Config.geoip_db_path, GEOIP_INDEX_CACHE);
65                 if (gi == NULL) {
66                         merror(INVALID_GEOIP_DB, ARGV0, Config.geoip6_db_path);
67                         snprintf(buffer, length, "Unknown (1)");
68                         return;
69                 }
70                 gir = GeoIP_record_by_name_v6(gi, ip);
71         }
72         else {
73                 /* Use the IPv4 DB */
74                 /* If we have a RFC1918 IP, do not perform a DB lookup (performance) */
75                 unsigned long longip = StrIP2Int(ip);
76                 if (longip == 0 ) {
77                         snprintf(buffer, length, "Unknown (2)");
78                         return;
79                 }
80                 if ((longip & NETMASK_8)  == RFC1918_10 ||
81                 (longip & NETMASK_12) == RFC1918_172 ||
82                 (longip & NETMASK_16) == RFC1918_192) {
83                         snprintf(buffer, length, "RFC1918 IP");
84                         return;
85                 }
86
87                 gi = GeoIP_open(Config.geoip_db_path, GEOIP_INDEX_CACHE);
88                 if (gi == NULL) {
89                         merror(INVALID_GEOIP_DB, ARGV0, Config.geoip_db_path);
90                         snprintf(buffer, length, "Unknown (3)");
91                         return;
92                 }
93                 gir = GeoIP_record_by_name(gi, ip);
94         }
95         if (gir != NULL) {
96                 snprintf(buffer,length,"%s,%s,%s",
97                                 _mk_NA(gir->country_code),
98                                 _mk_NA(GeoIP_region_name_by_code(gir->country_code, gir->region)),
99                                 _mk_NA(gir->city)
100                 );
101                 GeoIP_delete(gi);
102                 return;
103         }
104         GeoIP_delete(gi);
105         snprintf(buffer, length, "Unknown (4)");
106         return;
107 }
108 #endif /* GEOIP */
109
110 /* Drop/allow patterns */
111 OSMatch FWDROPpm;
112 OSMatch FWALLOWpm;
113
114 /*
115  * Allow custom alert output tokens.
116  */
117
118 typedef enum e_custom_alert_tokens_id
119 {
120   CUSTOM_ALERT_TOKEN_TIMESTAMP = 0,
121   CUSTOM_ALERT_TOKEN_FTELL,
122   CUSTOM_ALERT_TOKEN_RULE_ALERT_OPTIONS,
123   CUSTOM_ALERT_TOKEN_HOSTNAME,
124   CUSTOM_ALERT_TOKEN_LOCATION,
125   CUSTOM_ALERT_TOKEN_RULE_ID,
126   CUSTOM_ALERT_TOKEN_RULE_LEVEL,
127   CUSTOM_ALERT_TOKEN_RULE_COMMENT,
128   CUSTOM_ALERT_TOKEN_SRC_IP,
129   CUSTOM_ALERT_TOKEN_DST_USER,
130   CUSTOM_ALERT_TOKEN_FULL_LOG,
131   CUSTOM_ALERT_TOKEN_RULE_GROUP,
132   CUSTOM_ALERT_TOKEN_LAST
133 } CustomAlertTokenID;
134
135 char CustomAlertTokenName[CUSTOM_ALERT_TOKEN_LAST][15] =
136 {
137 { "$TIMESTAMP" },
138 { "$FTELL" },
139 { "$RULEALERT" },
140 { "$HOSTNAME" },
141 { "$LOCATION" },
142 { "$RULEID" },
143 { "$RULELEVEL" },
144 { "$RULECOMMENT" },
145 { "$SRCIP" },
146 { "$DSTUSER" },
147 { "$FULLLOG" },
148 { "$RULEGROUP" },
149 };
150 /* OS_Store: v0.2, 2005/02/10 */
151 /* Will store the events in a file
152  * The string must be null terminated and contain
153  * any necessary new lines, tabs, etc.
154  *
155  */
156 void OS_Store(Eventinfo *lf)
157 {
158     if(strcmp(lf->location, "ossec-keepalive") == 0)
159     {
160         return;
161     }
162     if(strstr(lf->location, "->ossec-keepalive") != NULL)
163     {
164         return;
165     }
166
167     fprintf(_eflog,
168             "%d %s %02d %s %s%s%s %s\n",
169             lf->year,
170             lf->mon,
171             lf->day,
172             lf->hour,
173             lf->hostname != lf->location?lf->hostname:"",
174             lf->hostname != lf->location?"->":"",
175             lf->location,
176             lf->full_log);
177
178     fflush(_eflog);
179     return;
180 }
181
182
183
184 void OS_LogOutput(Eventinfo *lf)
185 {
186 #ifdef GEOIP
187     char geoip_msg_src[OS_SIZE_1024 +1];
188     char geoip_msg_dst[OS_SIZE_1024 +1];
189     geoip_msg_src[0] = '\0';
190     geoip_msg_dst[0] = '\0';
191     if (Config.loggeoip) {
192         if (lf->srcip) GeoIP_Lookup(lf->srcip, geoip_msg_src, OS_SIZE_1024);
193         if (lf->dstip) GeoIP_Lookup(lf->dstip, geoip_msg_dst, OS_SIZE_1024);
194     }
195 #endif
196     printf(
197            "** Alert %d.%ld:%s - %s\n"
198             "%d %s %02d %s %s%s%s\nRule: %d (level %d) -> '%s'"
199             "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n%.1256s\n",
200             lf->time,
201             __crt_ftell,
202             lf->generated_rule->alert_opts & DO_MAILALERT?" mail ":"",
203             lf->generated_rule->group,
204             lf->year,
205             lf->mon,
206             lf->day,
207             lf->hour,
208             lf->hostname != lf->location?lf->hostname:"",
209             lf->hostname != lf->location?"->":"",
210             lf->location,
211             lf->generated_rule->sigid,
212             lf->generated_rule->level,
213             lf->generated_rule->comment,
214
215             lf->srcip == NULL?"":"\nSrc IP: ",
216             lf->srcip == NULL?"":lf->srcip,
217
218 #ifdef GEOIP
219             (strlen(geoip_msg_src) == 0)?"":"\nSrc Location: ",
220             (strlen(geoip_msg_src) == 0)?"":geoip_msg_src,
221 #else
222             "",
223             "",
224 #endif
225
226             lf->srcport == NULL?"":"\nSrc Port: ",
227             lf->srcport == NULL?"":lf->srcport,
228
229             lf->dstip == NULL?"":"\nDst IP: ",
230             lf->dstip == NULL?"":lf->dstip,
231
232 #ifdef GEOIP
233             (strlen(geoip_msg_dst) == 0)?"":"\nDst Location: ",
234             (strlen(geoip_msg_dst) == 0)?"":geoip_msg_dst,
235 #else
236             "",
237             "",
238 #endif
239
240             lf->dstport == NULL?"":"\nDst Port: ",
241             lf->dstport == NULL?"":lf->dstport,
242
243             lf->dstuser == NULL?"":"\nUser: ",
244             lf->dstuser == NULL?"":lf->dstuser,
245
246             lf->full_log);
247
248
249     /* Printing the last events if present */
250     if(lf->generated_rule->last_events)
251     {
252         char **lasts = lf->generated_rule->last_events;
253         while(*lasts)
254         {
255             printf("%.1256s\n",*lasts);
256             lasts++;
257         }
258         lf->generated_rule->last_events[0] = NULL;
259     }
260
261     printf("\n");
262
263     fflush(stdout);
264     return;
265 }
266
267
268
269 /* OS_Log: v0.3, 2006/03/04 */
270 /* _writefile: v0.2, 2005/02/09 */
271 void OS_Log(Eventinfo *lf)
272 {
273 #ifdef GEOIP
274     char geoip_msg_src[OS_SIZE_1024 +1];
275     char geoip_msg_dst[OS_SIZE_1024 +1];
276     geoip_msg_src[0] = '\0';
277     geoip_msg_dst[0] = '\0';
278     if (Config.loggeoip) {
279         if (lf->srcip) GeoIP_Lookup(lf->srcip, geoip_msg_src, OS_SIZE_1024 );
280         if (lf->dstip) GeoIP_Lookup(lf->dstip, geoip_msg_dst, OS_SIZE_1024 );
281     }
282 #endif
283     /* Writting to the alert log file */
284     fprintf(_aflog,
285             "** Alert %d.%ld:%s - %s\n"
286             "%d %s %02d %s %s%s%s\nRule: %d (level %d) -> '%s'"
287             "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n%.1256s\n",
288             lf->time,
289             __crt_ftell,
290             lf->generated_rule->alert_opts & DO_MAILALERT?" mail ":"",
291             lf->generated_rule->group,
292             lf->year,
293             lf->mon,
294             lf->day,
295             lf->hour,
296             lf->hostname != lf->location?lf->hostname:"",
297             lf->hostname != lf->location?"->":"",
298             lf->location,
299             lf->generated_rule->sigid,
300             lf->generated_rule->level,
301             lf->generated_rule->comment,
302
303             lf->srcip == NULL?"":"\nSrc IP: ",
304             lf->srcip == NULL?"":lf->srcip,
305
306 #ifdef GEOIP
307             (strlen(geoip_msg_src) == 0)?"":"\nSrc Location: ",
308             (strlen(geoip_msg_src) == 0)?"":geoip_msg_src,
309 #else
310             "",
311             "",
312 #endif
313
314             lf->srcport == NULL?"":"\nSrc Port: ",
315             lf->srcport == NULL?"":lf->srcport,
316
317             lf->dstip == NULL?"":"\nDst IP: ",
318             lf->dstip == NULL?"":lf->dstip,
319
320 #ifdef GEOIP
321             (strlen(geoip_msg_dst) == 0)?"":"\nDst Location: ",
322             (strlen(geoip_msg_dst) == 0)?"":geoip_msg_dst,
323 #else
324             "",
325             "",
326 #endif
327
328             lf->dstport == NULL?"":"\nDst Port: ",
329             lf->dstport == NULL?"":lf->dstport,
330
331             lf->dstuser == NULL?"":"\nUser: ",
332             lf->dstuser == NULL?"":lf->dstuser,
333
334             lf->full_log);
335
336
337     /* Printing the last events if present */
338     if(lf->generated_rule->last_events)
339     {
340         char **lasts = lf->generated_rule->last_events;
341         while(*lasts)
342         {
343             fprintf(_aflog,"%.1256s\n",*lasts);
344             lasts++;
345         }
346         lf->generated_rule->last_events[0] = NULL;
347     }
348
349     fprintf(_aflog,"\n");
350
351     fflush(_aflog);
352     return;
353 }
354
355 /* OS_CustomLog: v0.1, 2012/10/10*/
356 void OS_CustomLog(Eventinfo *lf,char* format)
357 {
358   char *log;
359   char *tmp_log;
360   char tmp_buffer[1024];
361   //Replace all the tokens:
362   os_strdup(format,log);
363
364   snprintf(tmp_buffer, 1024, "%d", lf->time);
365   tmp_log = searchAndReplace(log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_TIMESTAMP], tmp_buffer);
366   if(log)
367   {
368     os_free(log);
369     log=NULL;
370   }
371   snprintf(tmp_buffer, 1024, "%ld", __crt_ftell);
372   log = searchAndReplace(tmp_log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_FTELL], tmp_buffer);
373   if (tmp_log)
374   {
375     os_free(tmp_log);
376     tmp_log=NULL;
377   }
378
379
380   snprintf(tmp_buffer, 1024, "%s", (lf->generated_rule->alert_opts & DO_MAILALERT)?"mail " : "");
381   tmp_log = searchAndReplace(log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_RULE_ALERT_OPTIONS], tmp_buffer);
382   if(log)
383   {
384     os_free(log);
385     log=NULL;
386   }
387
388
389   snprintf(tmp_buffer, 1024, "%s",lf->hostname?lf->hostname:"None");
390   log = searchAndReplace(tmp_log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_HOSTNAME], tmp_buffer);
391   if (tmp_log)
392   {
393     os_free(tmp_log);
394     tmp_log=NULL;
395   }
396
397   snprintf(tmp_buffer, 1024, "%s",lf->location?lf->location:"None");
398   tmp_log = searchAndReplace(log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_LOCATION], tmp_buffer);
399   if(log)
400   {
401     os_free(log);
402     log=NULL;
403   }
404
405
406   snprintf(tmp_buffer, 1024, "%d", lf->generated_rule->sigid);
407   log = searchAndReplace(tmp_log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_RULE_ID], tmp_buffer);
408   if (tmp_log)
409   {
410     os_free(tmp_log);
411     tmp_log=NULL;
412   }
413
414   snprintf(tmp_buffer, 1024, "%d", lf->generated_rule->level);
415   tmp_log = searchAndReplace(log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_RULE_LEVEL], tmp_buffer);
416   if(log)
417   {
418     os_free(log);
419     log=NULL;
420   }
421
422   snprintf(tmp_buffer, 1024, "%s",lf->srcip?lf->srcip:"None");
423   log = searchAndReplace(tmp_log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_SRC_IP], tmp_buffer);
424   if (tmp_log)
425   {
426     os_free(tmp_log);
427     tmp_log=NULL;
428   }
429
430   snprintf(tmp_buffer, 1024, "%s",lf->srcuser?lf->srcuser:"None");
431
432   tmp_log = searchAndReplace(log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_DST_USER], tmp_buffer);
433   if(log)
434   {
435     os_free(log);
436     log=NULL;
437   }
438   char * escaped_log;
439   escaped_log = escape_newlines(lf->full_log);
440
441   log = searchAndReplace(tmp_log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_FULL_LOG],escaped_log );
442   if (tmp_log)
443   {
444     os_free(tmp_log);
445     tmp_log=NULL;
446   }
447
448   if(escaped_log)
449   {
450     os_free(escaped_log);
451     escaped_log=NULL;
452   }
453
454   snprintf(tmp_buffer, 1024, "%s",lf->generated_rule->comment?lf->generated_rule->comment:"");
455   tmp_log = searchAndReplace(log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_RULE_COMMENT], tmp_buffer);
456   if(log)
457   {
458     os_free(log);
459     log=NULL;
460   }
461
462   snprintf(tmp_buffer, 1024, "%s",lf->generated_rule->group?lf->generated_rule->group:"");
463   log = searchAndReplace(tmp_log, CustomAlertTokenName[CUSTOM_ALERT_TOKEN_RULE_GROUP], tmp_buffer);
464   if (tmp_log)
465   {
466     os_free(tmp_log);
467     tmp_log=NULL;
468   }
469
470
471   fprintf(_aflog,"%s",log);
472   fprintf(_aflog,"\n");
473   fflush(_aflog);
474
475   if(log)
476   {
477     os_free(log);
478     log=NULL;
479   }
480
481   return;
482 }
483
484 void OS_InitFwLog()
485 {
486     /* Initializing fw log regexes */
487     if(!OSMatch_Compile(FWDROP, &FWDROPpm, 0))
488     {
489         ErrorExit(REGEX_COMPILE, ARGV0, FWDROP,
490                 FWDROPpm.error);
491     }
492
493     if(!OSMatch_Compile(FWALLOW, &FWALLOWpm, 0))
494     {
495         ErrorExit(REGEX_COMPILE, ARGV0, FWALLOW,
496                 FWALLOWpm.error);
497     }
498
499 }
500
501
502 /* FW_Log: v0.1, 2005/12/30 */
503 int FW_Log(Eventinfo *lf)
504 {
505     /* If we don't have the srcip or the
506      * action, there is no point in going
507      * forward over here
508      */
509     if(!lf->action || !lf->srcip || !lf->dstip || !lf->srcport ||
510        !lf->dstport || !lf->protocol)
511     {
512         return(0);
513     }
514
515
516     /* Setting the actions */
517     switch(*lf->action)
518     {
519         /* discard, drop, deny, */
520         case 'd':
521         case 'D':
522         /* reject, */
523         case 'r':
524         case 'R':
525         /* block */
526         case 'b':
527         case 'B':
528             os_free(lf->action);
529             os_strdup("DROP", lf->action);
530             break;
531         /* Closed */
532         case 'c':
533         case 'C':
534         /* Teardown */
535         case 't':
536         case 'T':
537             os_free(lf->action);
538             os_strdup("CLOSED", lf->action);
539             break;
540         /* allow, accept, */
541         case 'a':
542         case 'A':
543         /* pass/permitted */
544         case 'p':
545         case 'P':
546         /* open */
547         case 'o':
548         case 'O':
549             os_free(lf->action);
550             os_strdup("ALLOW", lf->action);
551             break;
552         default:
553             if(OSMatch_Execute(lf->action,strlen(lf->action),&FWDROPpm))
554             {
555                 os_free(lf->action);
556                 os_strdup("DROP", lf->action);
557             }
558             if(OSMatch_Execute(lf->action,strlen(lf->action),&FWALLOWpm))
559             {
560                 os_free(lf->action);
561                 os_strdup("ALLOW", lf->action);
562             }
563             else
564             {
565                 os_free(lf->action);
566                 os_strdup("UNKNOWN", lf->action);
567             }
568             break;
569     }
570
571
572     /* log to file */
573     fprintf(_fflog,
574             "%d %s %02d %s %s%s%s %s %s %s:%s->%s:%s\n",
575             lf->year,
576             lf->mon,
577             lf->day,
578             lf->hour,
579             lf->hostname != lf->location?lf->hostname:"",
580             lf->hostname != lf->location?"->":"",
581             lf->location,
582             lf->action,
583             lf->protocol,
584             lf->srcip,
585             lf->srcport,
586             lf->dstip,
587             lf->dstport);
588
589     fflush(_fflog);
590
591     return(1);
592 }
593
594 /* EOF */