c15297e3ae9d86bef25b5a5b725875eb498c5b7d
[ossec-hids.git] / msgs.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
17 #include "shared.h"
18 #include "headers/sec.h"
19
20 #include "os_zlib/os_zlib.h"
21 #include "os_crypto/md5/md5_op.h"
22 #include "os_crypto/blowfish/bf_op.h"
23
24
25 /** Sending counts **/
26 unsigned int global_count = 0;
27 unsigned int local_count  = 0;
28
29
30 /** Average compression rates **/
31 int evt_count = 0;
32 int rcv_count = 0;
33 unsigned int c_orig_size = 0;
34 unsigned int c_comp_size = 0;
35
36
37 /** Static variables (read from define file) **/
38 int _s_comp_print = 0;
39 int _s_recv_flush = 0;
40
41 int _s_verify_counter = 1;
42
43
44 /** OS_StartCounter.
45  * Read counters for each agent.
46  */
47 void OS_StartCounter(keystore *keys)
48 {
49     int i;
50     char rids_file[OS_FLSIZE +1];
51
52     rids_file[OS_FLSIZE] = '\0';
53     
54
55     debug1("%s: OS_StartCounter: keysize: %d", __local_name, keys->keysize);
56     
57     
58     /* Starting receiving counter */
59     for(i = 0; i<=keys->keysize; i++)
60     {
61         /* On i == keysize, we deal with the
62          * sender counter.
63          */
64         if(i == keys->keysize)
65         {
66             snprintf(rids_file, OS_FLSIZE, "%s/%s",
67                                             RIDS_DIR,
68                                             SENDER_COUNTER);
69         }
70         else
71         {
72             snprintf(rids_file, OS_FLSIZE, "%s/%s",
73                                            RIDS_DIR,
74                                            keys->keyentries[i]->id);
75         }
76
77         keys->keyentries[i]->fp = fopen(rids_file, "r+");
78
79         /* If nothing is there, try to open as write only */
80         if(!keys->keyentries[i]->fp)
81         {
82             keys->keyentries[i]->fp = fopen(rids_file, "w");
83             if(!keys->keyentries[i]->fp)
84             {
85                 int my_error = errno;
86                 
87                 /* Just in case we run out of file descriptiors */
88                 if((keys->keyentries[i -1]->fp) && (i > 10))
89                 {
90                     fclose(keys->keyentries[i -1]->fp);
91
92                     if(keys->keyentries[i -2]->fp)
93                     {
94                         fclose(keys->keyentries[i -2]->fp);
95                     }
96                 }
97
98                 merror("%s: Unable to open agent file. errno: %d", 
99                        __local_name, my_error);
100                 ErrorExit(FOPEN_ERROR, __local_name, rids_file);
101             }
102         }
103         else
104         {
105             unsigned int g_c = 0, l_c = 0;
106             if(fscanf(keys->keyentries[i]->fp,"%u:%u", &g_c, &l_c) != 2)
107             {
108                 if(i == keys->keysize)
109                 {
110                     verbose("%s: INFO: No previous sender counter.", __local_name);
111                 }
112                 else
113                 {
114                     verbose("%s: INFO: No previous counter available for '%s'.",
115                                             __local_name, 
116                                             keys->keyentries[i]->name);
117                 }
118                 
119                 g_c = 0;
120                 l_c = 0;
121             }
122
123             if(i == keys->keysize)
124             {
125                 verbose("%s: INFO: Assigning sender counter: %d:%d",
126                             __local_name, g_c, l_c);
127                 global_count = g_c;
128                 local_count = l_c;
129             }
130             else
131             {
132                 verbose("%s: INFO: Assigning counter for agent %s: '%d:%d'.",
133                             __local_name, keys->keyentries[i]->name, g_c, l_c);
134                             
135                 keys->keyentries[i]->global = g_c;
136                 keys->keyentries[i]->local = l_c;
137             }
138         }
139     }
140
141     debug2("%s: DEBUG: Stored counter.", __local_name);
142
143     /* Getting counter values */
144     if(_s_recv_flush == 0)
145     {
146         _s_recv_flush = getDefine_Int("remoted",
147                                       "recv_counter_flush",
148                                       10, 999999);
149     }
150
151     /* Average printout values */
152     if(_s_comp_print == 0)
153     {
154         _s_comp_print = getDefine_Int("remoted",
155                                       "comp_average_printout",
156                                       10, 999999);
157     }
158
159
160     _s_verify_counter = getDefine_Int("remoted", "verify_msg_id" , 0, 1);
161 }
162
163
164
165 /** OS_RemoveCounter(char *id)
166  * Remove the ID counter.
167  */
168 void OS_RemoveCounter(char *id)
169 {
170     char rids_file[OS_FLSIZE +1];
171     snprintf(rids_file, OS_FLSIZE, "%s/%s",RIDS_DIR, id);
172     unlink(rids_file);
173 }
174
175
176 /** StoreSenderCounter((keystore *keys, int global, int local)
177  * Store sender counter.
178  */
179 void StoreSenderCounter(keystore *keys, int global, int local)
180 {
181     /* Writting at the beginning of the file */
182     fseek(keys->keyentries[keys->keysize]->fp, 0, SEEK_SET);
183     fprintf(keys->keyentries[keys->keysize]->fp, "%u:%u:", global, local);
184 }
185
186
187 /* StoreCount(keystore *keys, int id, int global, int local)
188  * Store the global and local count of events.
189  */
190 void StoreCounter(keystore *keys, int id, int global, int local)
191 {
192     /* Writting at the beginning of the file */
193     fseek(keys->keyentries[id]->fp, 0, SEEK_SET);
194     fprintf(keys->keyentries[id]->fp, "%u:%u:", global, local);
195 }
196
197
198 /* CheckSum v0.1: 2005/02/15 
199  * Verify the checksum of the message.
200  * Returns NULL on error or the message on success.
201  */
202 char *CheckSum(char *msg)
203 {
204     os_md5 recvd_sum;
205     os_md5 checksum;
206
207
208     /* Better way */
209     strncpy(recvd_sum,msg,32);
210     recvd_sum[32]='\0';
211
212     msg+=32;
213
214     OS_MD5_Str(msg, checksum);
215     if(strncmp(checksum,recvd_sum,32) != 0)
216     {
217         return(NULL);
218     }
219     
220     return(msg);
221 }
222
223
224
225 /* ReadSecMSG v0.2: 2005/02/10 */
226 char *ReadSecMSG(keystore *keys, char *buffer, char *cleartext, 
227                                  int id, int buffer_size)
228 {
229     int cmp_size;
230     unsigned int msg_global;
231     unsigned int msg_local;
232
233     char *f_msg;
234     
235     
236     if(*buffer == ':')
237     {
238          buffer++;
239     }
240     else
241     {
242         merror(ENCFORMAT_ERROR, __local_name, keys->keyentries[id]->ip->ip);
243         return(NULL);
244     }
245     
246     /* Decrypting message */
247     if(!OS_BF_Str(buffer, cleartext, keys->keyentries[id]->key, 
248                   buffer_size, OS_DECRYPT)) 
249     {
250         merror(ENCKEY_ERROR, __local_name, keys->keyentries[id]->ip->ip);
251         return(NULL);
252     }
253
254
255     /* Compressed */
256     else if(cleartext[0] == '!')
257     {
258         cleartext[buffer_size] = '\0';
259         cleartext++;
260         buffer_size--;
261
262         /* Removing padding */
263         while(*cleartext == '!')
264         {
265             cleartext++;
266             buffer_size--;
267         }
268         
269         /* Uncompressing */
270         cmp_size = os_uncompress(cleartext, buffer, buffer_size, OS_MAXSTR);
271         if(!cmp_size)
272         {
273             merror(UNCOMPRESS_ERR, __local_name);
274             return(NULL);
275         }
276
277         /* Checking checksum  */
278         f_msg = CheckSum(buffer);
279         if(f_msg == NULL)
280         {
281             merror(ENCSUM_ERROR, __local_name, keys->keyentries[id]->ip->ip);
282             return(NULL);
283         }
284
285         /* Removing random */
286         f_msg+=5;
287
288
289         /* Checking count -- protecting against replay attacks */
290         msg_global = atoi(f_msg);
291         f_msg+=10;
292
293         /* Checking for the right message format */
294         if(*f_msg != ':')
295         {
296             merror(ENCFORMAT_ERROR, __local_name,keys->keyentries[id]->ip->ip);
297             return(NULL);
298         }
299         f_msg++;
300
301         msg_local = atoi(f_msg);
302         f_msg+=5;
303
304         
305         /* Returning the message if we don't need to verify the counbter. */
306         if(!_s_verify_counter)
307         {
308             /* Updating currently counts */
309             keys->keyentries[id]->global = msg_global;
310             keys->keyentries[id]->local = msg_local;
311             if(rcv_count >= _s_recv_flush)
312             {
313                 StoreCounter(keys, id, msg_global, msg_local);
314                 rcv_count = 0; 
315             }
316             rcv_count++;
317             return(f_msg);
318         }
319
320
321         if((msg_global > keys->keyentries[id]->global)||
322            ((msg_global == keys->keyentries[id]->global) && 
323             (msg_local > keys->keyentries[id]->local)))
324         {
325             /* Updating currently counts */
326             keys->keyentries[id]->global = msg_global;
327             keys->keyentries[id]->local = msg_local;
328
329             if(rcv_count >= _s_recv_flush)
330             {
331                 StoreCounter(keys, id, msg_global, msg_local);
332                 rcv_count = 0;
333             }
334             rcv_count++;
335             return(f_msg);
336         }
337
338
339         /* Checking if it is a duplicated message */
340         if(msg_global == keys->keyentries[id]->global)
341         {
342             return(NULL);
343         }
344
345
346         /* Warn about duplicated messages */
347         merror("%s: WARN: Duplicate error:  global: %d, local: %d, "
348                 "saved global: %d, saved local:%d",
349                 __local_name,
350                 msg_global,
351                 msg_local,
352                 keys->keyentries[id]->global,
353                 keys->keyentries[id]->local);
354
355         merror(ENCTIME_ERROR, __local_name, keys->keyentries[id]->name);
356         return(NULL);
357     }
358
359     /* Old format */
360     else if(cleartext[0] == ':')
361     {
362         int msg_count;
363         time_t msg_time;
364
365         /* Closing string */
366         cleartext[buffer_size] = '\0';
367
368
369         /* Checking checksum  */
370         cleartext++;
371         f_msg = CheckSum(cleartext);
372         if(f_msg == NULL)
373         {
374             merror(ENCSUM_ERROR, __local_name, keys->keyentries[id]->ip->ip);
375             return(NULL);
376         }
377
378
379         /* Checking time -- protecting against replay attacks */
380         msg_time = atoi(f_msg);
381         f_msg+=11;
382
383         msg_count = atoi(f_msg);
384         f_msg+=5;
385
386
387         /* Returning the message if we don't need to verify the counbter. */
388         if(!_s_verify_counter)
389         {
390             /* Updating currently counts */
391             keys->keyentries[id]->global = msg_time;
392             keys->keyentries[id]->local = msg_local;
393
394             f_msg = strchr(f_msg, ':');
395             if(f_msg)
396             {
397                 f_msg++;
398                 return(f_msg);
399             }
400         }
401
402
403         if((msg_time > keys->keyentries[id]->global) ||
404            ((msg_time == keys->keyentries[id]->global)&&
405             (msg_count > keys->keyentries[id]->local)))
406         {
407             /* Updating currently time and count */
408             keys->keyentries[id]->global = msg_time;
409             keys->keyentries[id]->local = msg_count;
410
411             f_msg = strchr(f_msg, ':');
412             if(f_msg)
413             {
414                 f_msg++;
415                 return(f_msg);
416             }
417         }
418
419         /* Checking if it is a duplicated message */
420         if((msg_count == keys->keyentries[id]->local) && 
421            (msg_time == keys->keyentries[id]->global))
422         {
423             return(NULL);
424         }
425
426
427         /* Warn about duplicated message */
428         merror("%s: WARN: Duplicate error:  msg_count: %d, time: %d, "
429                 "saved count: %d, saved_time:%d",
430                 __local_name,
431                 msg_count,
432                 (int)msg_time,
433                 keys->keyentries[id]->local,
434                 keys->keyentries[id]->global);
435
436         merror(ENCTIME_ERROR, __local_name, keys->keyentries[id]->name);
437         return(NULL);
438     }
439     
440     merror(ENCFORMAT_ERROR, __local_name, keys->keyentries[id]->ip->ip);
441     return(NULL);
442 }
443
444
445
446 /* Creat a encrypted message.
447  * Returns the size of it
448  */
449 int CreateSecMSG(keystore *keys, char *msg, char *msg_encrypted, int id)
450 {
451     int bfsize;
452     int msg_size;
453     int cmp_size;
454     
455     u_int16_t rand1;
456     
457     char _tmpmsg[OS_MAXSTR + 2];
458     char _finmsg[OS_MAXSTR + 2];
459     
460     os_md5 md5sum;
461     
462     msg_size = strlen(msg);
463     
464     
465     /* Checking for invalid msg sizes */
466     if((msg_size > (OS_MAXSTR - OS_HEADER_SIZE))||(msg_size < 1))
467     {
468         merror(ENCSIZE_ERROR, __local_name, msg);
469         return(0);
470     }
471     
472     /* Random number */
473     rand1 = (u_int16_t)random();
474
475
476     _tmpmsg[OS_MAXSTR +1] = '\0';
477     _finmsg[OS_MAXSTR +1] = '\0';
478     msg_encrypted[OS_MAXSTR] = '\0';
479    
480
481     /* Increasing local and global counters */
482     if(local_count >= 9997)
483     {
484         local_count = 0;
485         global_count++;
486     }
487     local_count++;
488     
489     
490     snprintf(_tmpmsg, OS_MAXSTR,"%05hu%010u:%04hu:%s",
491                               rand1, global_count, local_count,
492                               msg);
493
494     
495     /* Generating md5sum of the unencrypted string */
496     OS_MD5_Str(_tmpmsg, md5sum);
497
498
499     
500     /* Generating final msg to be compressed */
501     snprintf(_finmsg, OS_MAXSTR,"%s%s",md5sum,_tmpmsg);
502     msg_size = strlen(_finmsg);
503
504
505     /* Compressing message.
506      * We assing the first 8 bytes for padding. 
507      */
508     cmp_size = os_compress(_finmsg, _tmpmsg + 8, msg_size, OS_MAXSTR - 12);
509     if(!cmp_size)
510     {
511         merror(COMPRESS_ERR, __local_name, _finmsg);
512         return(0);
513     }
514     cmp_size++;
515     
516     /* Padding the message (needs to be div by 8) */
517     bfsize = 8 - (cmp_size % 8);
518     if(bfsize == 8)
519         bfsize = 0;
520
521     _tmpmsg[0] = '!';
522     _tmpmsg[1] = '!';
523     _tmpmsg[2] = '!';
524     _tmpmsg[3] = '!';
525     _tmpmsg[4] = '!';
526     _tmpmsg[5] = '!';
527     _tmpmsg[6] = '!';
528     _tmpmsg[7] = '!';
529
530     cmp_size+=bfsize;
531
532
533     /* Getting average sizes */
534     c_orig_size+= msg_size;
535     c_comp_size+= cmp_size;
536     if(evt_count > _s_comp_print)
537     {
538         verbose("%s: INFO: Event count after '%u': %u->%u (%d%%)", __local_name,
539                     evt_count,
540                     c_orig_size, 
541                     c_comp_size,
542                     (c_comp_size * 100)/c_orig_size);
543         evt_count = 0;
544         c_orig_size = 0;
545         c_comp_size = 0;
546     }
547     evt_count++;
548     
549     /* If the ip is dynamic (not single host, append agent id
550      * to the message.
551      */ 
552     if(!isSingleHost(keys->keyentries[id]->ip) && isAgent)
553     {
554         snprintf(msg_encrypted, 16, "!%s!:", keys->keyentries[id]->id);
555         msg_size = strlen(msg_encrypted);
556     }
557     else
558     {
559         /* Setting beginning of the message */
560         msg_encrypted[0] = ':';
561         msg_size = 1;
562     }
563
564
565     /* msg_size is the ammount of non-encrypted message
566      * appended to the buffer. On dynamic ips, it will
567      * include the agent id.
568      */
569     
570     /* Encrypting everything */
571     OS_BF_Str(_tmpmsg + (7 - bfsize), msg_encrypted + msg_size, 
572                                       keys->keyentries[id]->key, 
573                                       cmp_size, 
574                                       OS_ENCRYPT);
575     
576
577     /* Storing before leaving */
578     StoreSenderCounter(keys, global_count, local_count);
579
580     return(cmp_size + msg_size);
581 }
582
583
584 /* EOF */