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