1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
11 #include "headers/sec.h"
12 #include "os_zlib/os_zlib.h"
13 #include "os_crypto/md5/md5_op.h"
14 #include "os_crypto/blowfish/bf_op.h"
17 static void StoreSenderCounter(const keystore *keys, unsigned int global, unsigned int local) __attribute((nonnull));
18 static void StoreCounter(const keystore *keys, int id, unsigned int global, unsigned int local) __attribute((nonnull));
19 static char *CheckSum(char *msg) __attribute((nonnull));
22 static unsigned int global_count = 0;
23 static unsigned int local_count = 0;
25 /* Average compression rates */
26 static unsigned int evt_count = 0;
27 static unsigned int rcv_count = 0;
28 static size_t c_orig_size = 0;
29 static size_t c_comp_size = 0;
31 /* Static variables (read from define file) */
32 static unsigned int _s_comp_print = 0;
33 static unsigned int _s_recv_flush = 0;
35 static int _s_verify_counter = 1;
38 /* Read counters for each agent */
39 void OS_StartCounter(keystore *keys)
42 char rids_file[OS_FLSIZE + 1];
44 rids_file[OS_FLSIZE] = '\0';
46 debug1("%s: OS_StartCounter: keysize: %u", __local_name, keys->keysize);
48 /* Start receiving counter */
49 for (i = 0; i <= keys->keysize; i++) {
50 /* On i == keysize, we deal with the sender counter */
51 if (i == keys->keysize) {
52 snprintf(rids_file, OS_FLSIZE, "%s/%s",
56 snprintf(rids_file, OS_FLSIZE, "%s/%s",
58 keys->keyentries[i]->id);
61 keys->keyentries[i]->fp = fopen(rids_file, "r+");
63 /* If nothing is there, try to open as write only */
64 if (!keys->keyentries[i]->fp) {
65 keys->keyentries[i]->fp = fopen(rids_file, "w");
66 if (!keys->keyentries[i]->fp) {
69 /* Just in case we run out of file descriptors */
70 if ((i > 10) && (keys->keyentries[i - 1]->fp)) {
71 fclose(keys->keyentries[i - 1]->fp);
73 if (keys->keyentries[i - 2]->fp) {
74 fclose(keys->keyentries[i - 2]->fp);
78 merror("%s: Unable to open agent file. errno: %d",
79 __local_name, my_error);
80 ErrorExit(FOPEN_ERROR, __local_name, rids_file, errno, strerror(errno));
83 unsigned int g_c = 0, l_c = 0;
84 if (fscanf(keys->keyentries[i]->fp, "%u:%u", &g_c, &l_c) != 2) {
85 if (i == keys->keysize) {
86 verbose("%s: INFO: No previous sender counter.", __local_name);
88 verbose("%s: INFO: No previous counter available for '%s'.",
90 keys->keyentries[i]->name);
97 if (i == keys->keysize) {
98 verbose("%s: INFO: Assigning sender counter: %u:%u",
99 __local_name, g_c, l_c);
103 verbose("%s: INFO: Assigning counter for agent %s: '%u:%u'.",
104 __local_name, keys->keyentries[i]->name, g_c, l_c);
106 keys->keyentries[i]->global = g_c;
107 keys->keyentries[i]->local = l_c;
112 debug2("%s: DEBUG: Stored counter.", __local_name);
114 /* Get counter values */
115 if (_s_recv_flush == 0) {
116 _s_recv_flush = (unsigned int) getDefine_Int("remoted",
117 "recv_counter_flush",
121 /* Average printout values */
122 if (_s_comp_print == 0) {
123 _s_comp_print = (unsigned int) getDefine_Int("remoted",
124 "comp_average_printout",
129 _s_verify_counter = getDefine_Int("remoted", "verify_msg_id" , 0, 1);
132 /* Remove the ID counter */
133 void OS_RemoveCounter(const char *id)
135 char rids_file[OS_FLSIZE + 1];
136 snprintf(rids_file, OS_FLSIZE, "%s/%s", RIDS_DIR, id);
140 /* Store sender counter */
141 static void StoreSenderCounter(const keystore *keys, unsigned int global, unsigned int local)
143 /* Write to the beginning of the file */
144 fseek(keys->keyentries[keys->keysize]->fp, 0, SEEK_SET);
145 fprintf(keys->keyentries[keys->keysize]->fp, "%u:%u:", global, local);
148 /* Store the global and local count of events */
149 static void StoreCounter(const keystore *keys, int id, unsigned int global, unsigned int local)
151 /* Write to the beginning of the file */
152 fseek(keys->keyentries[id]->fp, 0, SEEK_SET);
153 fprintf(keys->keyentries[id]->fp, "%u:%u:", global, local);
156 /* Verify the checksum of the message
157 * Returns NULL on error or the message on success
159 static char *CheckSum(char *msg)
165 strncpy(recvd_sum, msg, 32);
166 recvd_sum[32] = '\0';
170 OS_MD5_Str(msg, checksum);
171 if (strncmp(checksum, recvd_sum, 32) != 0) {
178 char *ReadSecMSG(keystore *keys, char *buffer, char *cleartext,
179 int id, unsigned int buffer_size)
181 unsigned int msg_global = 0;
182 unsigned int msg_local = 0;
185 if (*buffer == ':') {
188 merror(ENCFORMAT_ERROR, __local_name, keys->keyentries[id]->ip->ip);
192 /* Decrypt message */
193 if (!OS_BF_Str(buffer, cleartext, keys->keyentries[id]->key,
194 buffer_size, OS_DECRYPT)) {
195 merror(ENCKEY_ERROR, __local_name, keys->keyentries[id]->ip->ip);
200 else if (cleartext[0] == '!') {
201 cleartext[buffer_size] = '\0';
206 while (*cleartext == '!') {
212 if (!os_zlib_uncompress(cleartext, buffer, buffer_size, OS_MAXSTR)) {
213 merror(UNCOMPRESS_ERR, __local_name);
218 f_msg = CheckSum(buffer);
220 merror(ENCSUM_ERROR, __local_name, keys->keyentries[id]->ip->ip);
227 /* Check count -- protect against replay attacks */
228 msg_global = (unsigned int) atoi(f_msg);
231 /* Check for the right message format */
233 merror(ENCFORMAT_ERROR, __local_name, keys->keyentries[id]->ip->ip);
238 msg_local = (unsigned int) atoi(f_msg);
241 /* Return the message if we don't need to verify the counter */
242 if (!_s_verify_counter) {
243 /* Update current counts */
244 keys->keyentries[id]->global = msg_global;
245 keys->keyentries[id]->local = msg_local;
246 if (rcv_count >= _s_recv_flush) {
247 StoreCounter(keys, id, msg_global, msg_local);
255 if ((msg_global > keys->keyentries[id]->global) ||
256 ((msg_global == keys->keyentries[id]->global) &&
257 (msg_local > keys->keyentries[id]->local))) {
258 /* Update current counts */
259 keys->keyentries[id]->global = msg_global;
260 keys->keyentries[id]->local = msg_local;
262 if (rcv_count >= _s_recv_flush) {
263 StoreCounter(keys, id, msg_global, msg_local);
270 /* Check if it is a duplicated message */
271 if (msg_global == keys->keyentries[id]->global) {
272 /* Warn about duplicated messages */
273 merror("%s: WARN: Duplicate error: global: %u, local: %u, "
274 "saved global: %u, saved local:%u",
278 keys->keyentries[id]->global,
279 keys->keyentries[id]->local);
281 merror(ENCTIME_ERROR, __local_name, keys->keyentries[id]->name);
287 else if (cleartext[0] == ':') {
288 unsigned int msg_count;
289 unsigned int msg_time;
292 cleartext[buffer_size] = '\0';
296 f_msg = CheckSum(cleartext);
298 merror(ENCSUM_ERROR, __local_name, keys->keyentries[id]->ip->ip);
302 /* Check time -- protect against replay attacks */
303 msg_time = (unsigned int) atoi(f_msg);
306 msg_count = (unsigned int) atoi(f_msg);
310 /* Return the message if we don't need to verify the counter */
311 if (!_s_verify_counter) {
312 /* Update current counts */
313 keys->keyentries[id]->global = msg_time;
314 keys->keyentries[id]->local = msg_local;
316 f_msg = strchr(f_msg, ':');
321 merror(ENCFORMAT_ERROR, __local_name, keys->keyentries[id]->ip->ip);
327 if ((msg_time > keys->keyentries[id]->global) ||
328 ((msg_time == keys->keyentries[id]->global) &&
329 (msg_count > keys->keyentries[id]->local))) {
330 /* Update current time and count */
331 keys->keyentries[id]->global = msg_time;
332 keys->keyentries[id]->local = msg_count;
334 f_msg = strchr(f_msg, ':');
339 merror(ENCFORMAT_ERROR, __local_name, keys->keyentries[id]->ip->ip);
344 /* Check if it is a duplicated message */
345 if ((msg_count == keys->keyentries[id]->local) &&
346 (msg_time == keys->keyentries[id]->global)) {
350 /* Warn about duplicated message */
351 merror("%s: WARN: Duplicate error: msg_count: %u, time: %u, "
352 "saved count: %u, saved_time:%u",
356 keys->keyentries[id]->local,
357 keys->keyentries[id]->global);
359 merror(ENCTIME_ERROR, __local_name, keys->keyentries[id]->name);
363 merror(ENCFORMAT_ERROR, __local_name, keys->keyentries[id]->ip->ip);
367 /* Create an encrypted message
370 size_t CreateSecMSG(const keystore *keys, const char *msg, char *msg_encrypted, unsigned int id)
374 unsigned long int cmp_size;
376 char _tmpmsg[OS_MAXSTR + 2];
377 char _finmsg[OS_MAXSTR + 2];
380 msg_size = strlen(msg);
382 /* Check for invalid msg sizes */
383 if ((msg_size > (OS_MAXSTR - OS_HEADER_SIZE)) || (msg_size < 1)) {
384 merror(ENCSIZE_ERROR, __local_name, msg);
388 /* Random number, take only 5 chars ~= 2^16=65536*/
389 rand1 = (u_int16_t) random();
391 _tmpmsg[OS_MAXSTR + 1] = '\0';
392 _finmsg[OS_MAXSTR + 1] = '\0';
393 msg_encrypted[OS_MAXSTR] = '\0';
395 /* Increase local and global counters */
396 if (local_count >= 9997) {
402 snprintf(_tmpmsg, OS_MAXSTR, "%05hu%010u:%04u:%s",
403 rand1, global_count, local_count,
406 /* Generate MD5 of the unencrypted string */
407 OS_MD5_Str(_tmpmsg, md5sum);
409 /* Generate final msg to be compressed */
410 snprintf(_finmsg, OS_MAXSTR, "%s%s", md5sum, _tmpmsg);
411 msg_size = strlen(_finmsg);
413 /* Compress the message
414 * We assign the first 8 bytes for padding
416 cmp_size = os_zlib_compress(_finmsg, _tmpmsg + 8, msg_size, OS_MAXSTR - 12);
418 merror(COMPRESS_ERR, __local_name, _finmsg);
423 /* Pad the message (needs to be div by 8) */
424 bfsize = 8 - (cmp_size % 8);
440 /* Get average sizes */
441 c_orig_size += msg_size;
442 c_comp_size += cmp_size;
443 if (evt_count > _s_comp_print) {
444 verbose("%s: INFO: Event count after '%u': %lu->%lu (%lu%%)", __local_name,
446 (unsigned long)c_orig_size,
447 (unsigned long)c_comp_size,
448 (unsigned long)((c_comp_size * 100) / c_orig_size));
455 /* If the IP is dynamic (not single host), append agent ID to the message */
456 if (!isSingleHost(keys->keyentries[id]->ip) && isAgent) {
457 snprintf(msg_encrypted, 16, "!%s!:", keys->keyentries[id]->id);
458 msg_size = strlen(msg_encrypted);
460 /* Set beginning of the message */
461 msg_encrypted[0] = ':';
465 /* msg_size is the amount of non-encrypted message appended to the buffer
466 * On dynamic IPs, it will include the agent ID
469 /* Encrypt everything */
470 OS_BF_Str(_tmpmsg + (7 - bfsize), msg_encrypted + msg_size,
471 keys->keyentries[id]->key,
475 /* Store before leaving */
476 StoreSenderCounter(keys, global_count, local_count);
478 return (cmp_size + msg_size);