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