novi upstream verzije 2.8.3
[ossec-hids.git] / src / analysisd / cleanevent.c
1 /* @(#) $Id: ./src/analysisd/cleanevent.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  * License details at the LICENSE file included with OSSEC or
13  * online at: http://www.ossec.net/en/licensing.html
14  */
15
16
17 #include "shared.h"
18 #include "os_regex/os_regex.h"
19
20
21 /* local headers */
22 #include "eventinfo.h"
23 #include "analysisd.h"
24 #include "fts.h"
25 #include "config.h"
26
27
28 /* To translante between month (int) to month (char) */
29 char *(month[])={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug",
30                      "Sep","Oct","Nov","Dec"};
31
32
33
34
35 /* OS_CleanMSG v0.3: 2006/03/04
36  * Format a received message in the
37  * Eventinfo structure.
38  */
39 int OS_CleanMSG(char *msg, Eventinfo *lf)
40 {
41     int loglen;
42     char *pieces;
43     struct tm *p;
44
45     /* The message is formated in the following way:
46      * id:location:message.
47      */
48
49
50     /*  Ignoring the id of the message in here */
51     msg+=2;
52
53
54
55     /* Setting pieces as the message */
56     pieces = strchr(msg, ':');
57     if(!pieces)
58     {
59         merror(FORMAT_ERROR, ARGV0);
60         return(-1);
61     }
62
63     *pieces = '\0';
64     pieces++;
65
66
67     os_strdup(msg, lf->location);
68
69
70     /* Getting the log length */
71     loglen = strlen(pieces) + 1;
72
73
74     /* Assigning the values in the strucuture (lf->full_log) */
75     os_malloc((2*loglen) +1, lf->full_log);
76
77
78     /* Setting the whole message at full_log */
79     strncpy(lf->full_log, pieces, loglen);
80
81
82     /* Log is the one used for parsing in the decoders and rules */
83     lf->log = lf->full_log+loglen;
84     strncpy(lf->log, pieces, loglen);
85
86     /* check if month contains an umlaut and repair
87      * umlaute are non-ASCII and use 2 slots in the char array
88      * repair to only one slot so we can detect the correct date format in the next step
89      * ex: Mär 02 17:30:52
90      */
91     if (pieces[1] == (char) 195) {
92         if (pieces[2] == (char) 164) {
93             pieces[0] = '\0';
94             pieces[1] = 'M';
95             pieces[2] = 'a';
96             pieces++;
97         }
98     }
99
100     /* Checking for the syslog date format.
101      * ( ex: Dec 29 10:00:01
102      *   or  2007-06-14T15:48:55-04:00 for syslog-ng isodate
103      *   or  2009-05-22T09:36:46.214994-07:00 for rsyslog )
104      */
105     if(
106         (
107         (loglen > 17) &&
108         (pieces[3] == ' ') &&
109         (pieces[6] == ' ') &&
110         (pieces[9] == ':') &&
111         (pieces[12] == ':') &&
112         (pieces[15] == ' ') && (lf->log+=16)
113         )
114         ||
115         (
116         (loglen > 33) &&
117         (pieces[4] == '-') &&
118         (pieces[7] == '-') &&
119         (pieces[10] == 'T') &&
120         (pieces[13] == ':') &&
121         (pieces[16] == ':') &&
122
123         (
124          ((pieces[22] == ':') &&
125           (pieces[25] == ' ') && (lf->log+=26)) ||
126
127          ((pieces[19] == '.') &&
128           (pieces[29] == ':') && (lf->log+=32))
129         )
130
131         )
132       )
133     {
134         /* Checking for an extra space in here */
135         if(*lf->log == ' ')
136             lf->log++;
137
138
139         /* Hostname */
140         pieces = lf->hostname = lf->log;
141
142
143         /* Checking for a valid hostname */
144         while(isValidChar(*pieces) == 1)
145         {
146             pieces++;
147         }
148
149
150         /* Checking if it is a syslog without hostname (common on Solaris. */
151         if(*pieces == ':' && pieces[1] == ' ')
152         {
153             /* Getting solaris 8/9 messages without hostname.
154              * In these cases, the process_name should be there.
155              * http://www.ossec.net/wiki/index.php/Log_Samples_Solaris
156              */
157             lf->program_name = lf->hostname;
158             lf->hostname = NULL;
159
160             /* Ending the program name string. */
161             *pieces = '\0';
162
163             pieces+=2;
164             lf->log = pieces;
165         }
166
167
168         /* Extracting the hostname */
169         else if(*pieces != ' ')
170         {
171             /* Invalid hostname */
172             lf->hostname = NULL;
173             pieces = NULL;
174         }
175         else
176         {
177             /* Ending the hostname string */
178             *pieces = '\0';
179
180
181             /* Moving pieces to the beginning of the log message */
182             pieces++;
183             lf->log = pieces;
184
185
186             /* Getting program_name */
187             lf->program_name = pieces;
188
189
190             /* Extracting program_name */
191             /* Valid names:
192              * p_name:
193              * p_name[pid]:
194              * p_name[pid]: [ID xx facility.severity]
195              * auth|security:info p_name:
196              *
197              */
198             while(isValidChar(*pieces) == 1)
199             {
200                 pieces++;
201             }
202
203
204             /* Checking for the first format: p_name: */
205             if((*pieces == ':') && (pieces[1] == ' '))
206             {
207                 *pieces = '\0';
208                 pieces+=2;
209             }
210
211             /* Checking for the second format: p_name[pid]: */
212             else if((*pieces == '[') && (isdigit((int)pieces[1])))
213             {
214                 *pieces = '\0';
215                 pieces+=2;
216                 while(isdigit((int)*pieces))
217                     pieces++;
218
219                 if((*pieces == ']')&& (pieces[1] == ':')&& (pieces[2] == ' '))
220                 {
221                     pieces+=3;
222                 }
223                 /* Some systems are not terminating the program name with
224                  * the ':'. Working around this in here..
225                  */
226                 else if((*pieces == ']') && (pieces[1] == ' '))
227                 {
228                     pieces+=2;
229                 }
230                 else
231                 {
232                     /* Fixing for some weird log formats. */
233                     pieces--;
234                     while(isdigit((int)*pieces))
235                     {
236                         pieces--;
237                     }
238
239                     if(*pieces == '\0')
240                         *pieces = '[';
241                     pieces = NULL;
242                     lf->program_name = NULL;
243                 }
244             }
245             /* AIX syslog. */
246             else if((*pieces == '|') && islower((int)pieces[1]))
247             {
248                 pieces+=2;
249
250                 /* Removing facility */
251                 while(isalnum((int)*pieces))
252                     pieces++;
253
254
255                 if(*pieces == ':')
256                 {
257                     /* Removing severity. */
258                     pieces++;
259                     while(isalnum((int)*pieces))
260                         pieces++;
261
262                     if(*pieces == ' ')
263                     {
264                         pieces++;
265                         lf->program_name = pieces;
266
267
268                         /* Getting program name again. */
269                         while(isValidChar(*pieces) == 1)
270                             pieces++;
271
272                         /* Checking for the first format: p_name: */
273                         if((*pieces == ':') && (pieces[1] == ' '))
274                         {
275                             *pieces = '\0';
276                             pieces+=2;
277                         }
278
279                         /* Checking for the second format: p_name[pid]: */
280                         else if((*pieces == '[') && (isdigit((int)pieces[1])))
281                         {
282                             *pieces = '\0';
283                             pieces+=2;
284                             while(isdigit((int)*pieces))
285                                 pieces++;
286
287                             if((*pieces == ']') && (pieces[1] == ':') &&
288                                (pieces[2] == ' '))
289                             {
290                                 pieces+=3;
291                             }
292                             else
293                             {
294                                 pieces = NULL;
295                             }
296                         }
297                     }
298                     else
299                     {
300                         pieces = NULL;
301                         lf->program_name = NULL;
302                     }
303                 }
304                 /* Invalid AIX. */
305                 else
306                 {
307                     pieces = NULL;
308                     lf->program_name = NULL;
309                 }
310             }
311             else
312             {
313                 pieces = NULL;
314                 lf->program_name = NULL;
315             }
316         }
317
318
319         /* Removing [ID xx facility.severity] */
320         if(pieces)
321         {
322             /* Setting log after program name */
323             lf->log = pieces;
324
325             if((pieces[0] == '[') &&
326                (pieces[1] == 'I') &&
327                (pieces[2] == 'D') &&
328                (pieces[3] == ' '))
329             {
330                 pieces+=4;
331
332                 /* Going after the ] */
333                 pieces = strchr(pieces, ']');
334                 if(pieces)
335                 {
336                     pieces+=2;
337                     lf->log = pieces;
338                 }
339             }
340         }
341
342         /* Getting program name size */
343         if(lf->program_name)
344         {
345             lf->p_name_size = strlen(lf->program_name);
346         }
347     }
348
349     /* xferlog date format
350      * Mon Apr 17 18:27:14 2006 1 64.160.42.130
351      */
352     else if((loglen > 28) &&
353             (pieces[3] == ' ')&&
354             (pieces[7] == ' ')&&
355             (pieces[10] == ' ')&&
356             (pieces[13] == ':')&&
357             (pieces[16] == ':')&&
358             (pieces[19] == ' ')&&
359             (pieces[24] == ' ')&&
360             (pieces[26] == ' '))
361     {
362         /* Moving log to the beginning of the message */
363         lf->log+=24;
364     }
365
366
367     /* Checking for snort date format
368      * ex: 01/28-09:13:16.240702  [**]
369      */
370     else if( (loglen > 24) &&
371              (pieces[2] == '/') &&
372              (pieces[5] == '-') &&
373              (pieces[8] == ':') &&
374              (pieces[11]== ':') &&
375              (pieces[14]== '.') &&
376              (pieces[21] == ' ') )
377     {
378         lf->log+=23;
379     }
380
381     /* Checking for suricata (new) date format
382      * ex: 01/28/1979-09:13:16.240702  [**]
383      */
384     else if( (loglen > 26) &&
385              (pieces[2] == '/') &&
386              (pieces[5] == '/') &&
387              (pieces[10] == '-') &&
388              (pieces[13] == ':') &&
389              (pieces[16]== ':') &&
390              (pieces[19]== '.') &&
391              (pieces[26] == ' ') )
392     {
393         lf->log+=28;
394     }
395
396
397     /* Checking for apache log format */
398     /* [Fri Feb 11 18:06:35 2004] [warn] */
399     else if( (loglen > 27) &&
400              (pieces[0] == '[') &&
401              (pieces[4] == ' ') &&
402              (pieces[8] == ' ') &&
403              (pieces[11]== ' ') &&
404              (pieces[14]== ':') &&
405              (pieces[17]== ':') &&
406              (pieces[20]== ' ') &&
407              (pieces[25]== ']') )
408     {
409         lf->log+=27;
410     }
411
412     /* Checking for the osx asl log format.
413      * Examples:
414      * [Time 2006.12.28 15:53:55 UTC] [Facility auth] [Sender sshd] [PID 483] [Message error: PAM: Authentication failure for username from 192.168.0.2] [Level 3] [UID -2] [GID -2] [Host Hostname]
415      * [Time 2006.11.02 14:02:11 UTC] [Facility auth] [Sender sshd] [PID 856]
416      [Message refused connect from 59.124.44.34] [Level 4] [UID -2] [GID -2]
417      [Host robert-wyatts-emac]
418      */
419     else if((loglen > 26) &&
420             (pieces[0] == '[')  &&
421             (pieces[1] == 'T')  &&
422             (pieces[5] == ' ')  &&
423             (pieces[10] == '.') &&
424             (pieces[13] == '.') &&
425             (pieces[16] == ' ') &&
426             (pieces[19] == ':'))
427     {
428         /* Do not read more than 1 message entry -> log tampering */
429         short unsigned int done_message = 0;
430
431
432         /* Removing the date */
433         lf->log+=25;
434
435         /* Getting the desired values */
436         pieces = strchr(lf->log, '[');
437         while(pieces)
438         {
439             pieces++;
440
441             /* Getting the sender (set to program name) */
442             if((strncmp(pieces, "Sender ", 7) == 0) &&
443                (lf->program_name == NULL))
444             {
445                 pieces+=7;
446                 lf->program_name = pieces;
447
448                 /* Getting the closing brackets */
449                 pieces = strchr(pieces, ']');
450                 if(pieces)
451                 {
452                     *pieces = '\0';
453
454                     /* Setting program_name size */
455                     lf->p_name_size = strlen(lf->program_name);
456
457                     pieces++;
458                 }
459                 /* Invalid program name */
460                 else
461                 {
462                     lf->program_name = NULL;
463                     break;
464                 }
465             }
466
467             /* Getting message */
468             else if((strncmp(pieces, "Message ", 8) == 0) &&
469                     (done_message == 0))
470             {
471                 pieces+=8;
472                 done_message = 1;
473
474                 lf->log = pieces;
475
476                 /* Getting the closing brackets */
477                 pieces = strchr(pieces, ']');
478                 if(pieces)
479                 {
480                     *pieces = '\0';
481                     pieces++;
482                 }
483                 /* Invalid log closure */
484                 else
485                 {
486                     break;
487                 }
488             }
489
490             /* Getting hostname */
491             else if(strncmp(pieces, "Host ", 5) == 0)
492             {
493                 pieces+=5;
494                 lf->hostname = pieces;
495
496                 /* Getting the closing brackets */
497                 pieces = strchr(pieces, ']');
498                 if(pieces)
499                 {
500                     *pieces = '\0';
501                     pieces++;
502                 }
503
504                 /* Invalid hostname */
505                 else
506                 {
507                     lf->hostname = NULL;
508                 }
509                 break;
510             }
511
512             /* Getting next entry */
513             pieces = strchr(pieces, '[');
514         }
515     }
516
517     /* Checking for squid date format
518      * 1140804070.368  11623
519      * seconds from 00:00:00 1970-01-01 UTC
520      */
521     else if((loglen > 32) &&
522             (pieces[0] == '1') &&
523             (isdigit((int)pieces[1])) &&
524             (isdigit((int)pieces[2])) &&
525             (isdigit((int)pieces[3])) &&
526             (pieces[10] == '.') &&
527             (isdigit((int)pieces[13])) &&
528             (pieces[14] == ' ') &&
529             ((pieces[21] == ' ')||(pieces[22] == ' ')))
530     {
531         lf->log+=14;
532
533         /* We need to start at the size of the event */
534         while(*lf->log == ' ')
535         {
536             lf->log++;
537         }
538     }
539
540
541     /* Every message must be in the format
542      * hostname->location or
543      * (agent) ip->location.
544      */
545
546
547     /* Setting hostname for local messages */
548     if(lf->location[0] == '(')
549     {
550         /* Messages from an agent */
551         lf->hostname = lf->location;
552     }
553     else if(lf->hostname == NULL)
554     {
555         lf->hostname = __shost;
556     }
557
558
559     /* Setting up the event data */
560     lf->time = c_time;
561     p = localtime(&c_time);
562
563
564
565     /* Assign hour, day, year and month values */
566     lf->day = p->tm_mday;
567     lf->year = p->tm_year+1900;
568     strncpy(lf->mon,month[p->tm_mon],3);
569     snprintf(lf->hour, 9, "%02d:%02d:%02d",
570                           p->tm_hour,
571                           p->tm_min,
572                           p->tm_sec);
573
574
575
576     /* Setting the global hour/weekday */
577     __crt_hour = p->tm_hour;
578     __crt_wday = p->tm_wday;
579
580
581
582     #ifdef TESTRULE
583     if(!alert_only)
584     {
585         print_out("**Phase 1: Completed pre-decoding.");
586         print_out("       full event: '%s'", lf->full_log);
587         print_out("       hostname: '%s'", lf->hostname);
588         print_out("       program_name: '%s'", lf->program_name);
589         print_out("       log: '%s'", lf->log);
590     }
591     #endif
592     return(0);
593
594 }
595
596 /* EOF */