1 /****************************************************************************
2 *
3 * UTILS.C - Utility functions for NSCA
4 *
5 * License: GPL
6 * Copyright (c) 2000-2008 Ethan Galstad (nagios@nagios.org)
7 *
8 * Last Modified: 01-15-2008
9 *
10 * Description:
11 *
12 * This file contains common unctions used in nsca and send_nsca
13 *
14 * License Information:
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 ****************************************************************************/
31
32 #include "../include/common.h"
33 #include "../include/utils.h"
34
35
36 /*#define DEBUG*/
37
38 static unsigned long crc32_table[256];
39 #ifdef HAVE_LIBMCRYPT
40 static volatile sig_atomic_t mcrypt_initialized=FALSE;
41 #endif
42
43 /* escapes newlines in a string, snagged from nagios-3.0.6/base/utils.c */
escape_newlines(char * rawbuf)44 char *escape_newlines(char *rawbuf){
45 char *newbuf=NULL;
46 register int x,y;
47
48 if(rawbuf==NULL)
49 return NULL;
50
51 /* allocate enough memory to escape all chars if necessary */
52 if((newbuf=malloc((strlen(rawbuf)*2)+1))==NULL)
53 return NULL;
54
55 for(x=0,y=0;rawbuf[x]!=(char)'\x0';x++){
56
57 /* escape backslashes */
58 if(rawbuf[x]=='\\'){
59 newbuf[y++]='\\';
60 newbuf[y++]='\\';
61 }
62
63 /* escape newlines */
64 else if(rawbuf[x]=='\n'){
65 newbuf[y++]='\\';
66 newbuf[y++]='n';
67 }
68
69 else
70 newbuf[y++]=rawbuf[x];
71 }
72 newbuf[y]='\x0';
73
74 return newbuf;
75 }
76
77 /* build the crc table - must be called before calculating the crc value */
generate_crc32_table(void)78 void generate_crc32_table(void){
79 unsigned long crc, poly;
80 int i, j;
81
82 poly=0xEDB88320L;
83 for(i=0;i<256;i++){
84 crc=i;
85 for(j=8;j>0;j--){
86 if(crc & 1)
87 crc=(crc>>1)^poly;
88 else
89 crc>>=1;
90 }
91 crc32_table[i]=crc;
92 }
93
94 return;
95 }
96
97
98 /* calculates the CRC 32 value for a buffer */
calculate_crc32(char * buffer,int buffer_size)99 unsigned long calculate_crc32(char *buffer, int buffer_size){
100 register unsigned long crc;
101 int this_char;
102 int current_index;
103
104 crc=0xFFFFFFFF;
105
106 for(current_index=0;current_index<buffer_size;current_index++){
107 this_char=(int)buffer[current_index];
108 crc=((crc>>8) & 0x00FFFFFF) ^ crc32_table[(crc ^ this_char) & 0xFF];
109 }
110
111 return (crc ^ 0xFFFFFFFF);
112 }
113
114
115
116 /* initializes encryption routines */
encrypt_init(char * password,int encryption_method,char * received_iv,struct crypt_instance ** CIptr)117 int encrypt_init(char *password,int encryption_method,char *received_iv,struct crypt_instance **CIptr){
118 #ifdef HAVE_LIBMCRYPT
119 int i;
120 int iv_size;
121 #endif
122 struct crypt_instance *CI;
123
124 CI=malloc(sizeof(struct crypt_instance));
125 *CIptr=CI;
126
127 if(CI==NULL){
128 syslog(LOG_ERR, "Could not allocate memory for crypt instance");
129 return ERROR;
130 }
131
132 /* server generates IV used for encryption */
133 if(received_iv==NULL)
134 generate_transmitted_iv(CI->transmitted_iv);
135
136 /* client recieves IV from server */
137 else
138 memcpy(CI->transmitted_iv,received_iv,TRANSMITTED_IV_SIZE);
139
140 #ifdef HAVE_LIBMCRYPT
141 CI->blocksize=1; /* block size = 1 byte w/ CFB mode */
142 CI->keysize=7; /* default to 56 bit key length */
143 CI->mcrypt_mode="cfb"; /* CFB = 8-bit cipher-feedback mode */
144 CI->mcrypt_algorithm="unknown";
145 #endif
146
147 /* XOR or no encryption */
148 if(encryption_method==ENCRYPT_NONE || encryption_method==ENCRYPT_XOR)
149 return OK;
150
151 #ifdef HAVE_LIBMCRYPT
152
153 /* get the name of the mcrypt encryption algorithm to use */
154 switch(encryption_method){
155 case ENCRYPT_DES:
156 CI->mcrypt_algorithm=MCRYPT_DES;
157 break;
158 case ENCRYPT_3DES:
159 CI->mcrypt_algorithm=MCRYPT_3DES;
160 break;
161 case ENCRYPT_CAST128:
162 CI->mcrypt_algorithm=MCRYPT_CAST_128;
163 break;
164 case ENCRYPT_CAST256:
165 CI->mcrypt_algorithm=MCRYPT_CAST_256;
166 break;
167 case ENCRYPT_XTEA:
168 CI->mcrypt_algorithm=MCRYPT_XTEA;
169 break;
170 case ENCRYPT_3WAY:
171 CI->mcrypt_algorithm=MCRYPT_3WAY;
172 break;
173 case ENCRYPT_BLOWFISH:
174 CI->mcrypt_algorithm=MCRYPT_BLOWFISH;
175 break;
176 case ENCRYPT_TWOFISH:
177 CI->mcrypt_algorithm=MCRYPT_TWOFISH;
178 break;
179 case ENCRYPT_LOKI97:
180 CI->mcrypt_algorithm=MCRYPT_LOKI97;
181 break;
182 case ENCRYPT_RC2:
183 CI->mcrypt_algorithm=MCRYPT_RC2;
184 break;
185 case ENCRYPT_ARCFOUR:
186 CI->mcrypt_algorithm=MCRYPT_ARCFOUR;
187 break;
188 case ENCRYPT_RIJNDAEL128:
189 CI->mcrypt_algorithm=MCRYPT_RIJNDAEL_128;
190 break;
191 case ENCRYPT_RIJNDAEL192:
192 CI->mcrypt_algorithm=MCRYPT_RIJNDAEL_192;
193 break;
194 case ENCRYPT_RIJNDAEL256:
195 CI->mcrypt_algorithm=MCRYPT_RIJNDAEL_256;
196 break;
197 case ENCRYPT_WAKE:
198 CI->mcrypt_algorithm=MCRYPT_WAKE;
199 break;
200 case ENCRYPT_SERPENT:
201 CI->mcrypt_algorithm=MCRYPT_SERPENT;
202 break;
203 case ENCRYPT_ENIGMA:
204 CI->mcrypt_algorithm=MCRYPT_ENIGMA;
205 break;
206 case ENCRYPT_GOST:
207 CI->mcrypt_algorithm=MCRYPT_GOST;
208 break;
209 case ENCRYPT_SAFER64:
210 CI->mcrypt_algorithm=MCRYPT_SAFER_SK64;
211 break;
212 case ENCRYPT_SAFER128:
213 CI->mcrypt_algorithm=MCRYPT_SAFER_SK128;
214 break;
215 case ENCRYPT_SAFERPLUS:
216 CI->mcrypt_algorithm=MCRYPT_SAFERPLUS;
217 break;
218
219 default:
220 CI->mcrypt_algorithm="unknown";
221 break;
222 }
223
224 #ifdef DEBUG
225 syslog(LOG_INFO,"Attempting to initialize '%s' crypto algorithm...",CI->mcrypt_algorithm);
226 #endif
227
228 /* open encryption module */
229 if((CI->td=mcrypt_module_open(CI->mcrypt_algorithm,NULL,CI->mcrypt_mode,NULL))==MCRYPT_FAILED){
230 syslog(LOG_ERR,"Could not open mcrypt algorithm '%s' with mode '%s'",CI->mcrypt_algorithm,CI->mcrypt_mode);
231 return ERROR;
232 }
233
234 #ifdef DEBUG
235 syslog(LOG_INFO,"Using '%s' as crypto algorithm...",CI->mcrypt_algorithm);
236 #endif
237
238 /* determine size of IV buffer for this algorithm */
239 iv_size=mcrypt_enc_get_iv_size(CI->td);
240 if(iv_size>TRANSMITTED_IV_SIZE){
241 syslog(LOG_ERR,"IV size for crypto algorithm exceeds limits");
242 return ERROR;
243 }
244
245 /* allocate memory for IV buffer */
246 if((CI->IV=(char *)malloc(iv_size))==NULL){
247 syslog(LOG_ERR,"Could not allocate memory for IV buffer");
248 return ERROR;
249 }
250
251 /* fill IV buffer with first bytes of IV that is going to be used to crypt (determined by server) */
252 for(i=0;i<iv_size;i++)
253 CI->IV[i]=CI->transmitted_iv[i];
254
255 /* get maximum key size for this algorithm */
256 CI->keysize=mcrypt_enc_get_key_size(CI->td);
257
258 /* generate an encryption/decription key using the password */
259 if((CI->key=(char *)malloc(CI->keysize))==NULL){
260 syslog(LOG_ERR,"Could not allocate memory for encryption/decryption key");
261 return ERROR;
262 }
263 bzero(CI->key,CI->keysize);
264
265 if(CI->keysize<strlen(password))
266 strncpy(CI->key,password,CI->keysize);
267 else
268 strncpy(CI->key,password,strlen(password));
269
270 /* initialize encryption buffers */
271 mcrypt_generic_init(CI->td,CI->key,CI->keysize,CI->IV);
272 mcrypt_initialized=TRUE;
273 #endif
274
275 return OK;
276 }
277
278
279
280 /* encryption routine cleanup */
encrypt_cleanup(int encryption_method,struct crypt_instance * CI)281 void encrypt_cleanup(int encryption_method, struct crypt_instance *CI){
282
283 /* no crypt instance */
284 if(CI==NULL)
285 return;
286
287 #ifdef HAVE_LIBMCRYPT
288 /* mcrypt cleanup */
289 if(encryption_method!=ENCRYPT_NONE && encryption_method!=ENCRYPT_XOR){
290 if(mcrypt_initialized==TRUE)
291 mcrypt_generic_end(CI->td);
292 free(CI->key);
293 CI->key=NULL;
294 free(CI->IV);
295 CI->IV=NULL;
296 }
297 #endif
298
299 free(CI);
300
301 return;
302 }
303
304
305
306 /* generates IV to use for encrypted communications (function is called by server only, client uses IV it receives from server) */
generate_transmitted_iv(char * transmitted_iv)307 static void generate_transmitted_iv(char *transmitted_iv){
308 FILE *fp;
309 int x;
310 int seed=0;
311
312 /*********************************************************/
313 /* fill IV buffer with data that's as random as possible */
314 /*********************************************************/
315
316 /* try to get seed value from /dev/urandom, as its a better source of entropy */
317 fp=fopen("/dev/urandom","r");
318 if(fp!=NULL){
319 seed=fgetc(fp);
320 fclose(fp);
321 }
322
323 /* else fallback to using the current time as the seed */
324 else
325 seed=(int)time(NULL);
326
327 /* generate pseudo-random IV */
328 srand(seed);
329 for(x=0;x<TRANSMITTED_IV_SIZE;x++)
330 transmitted_iv[x]=(int)((256.0*rand())/(RAND_MAX+1.0));
331
332 return;
333 }
334
335
336
337 /* encrypt a buffer */
encrypt_buffer(char * buffer,int buffer_size,char * password,int encryption_method,struct crypt_instance * CI)338 void encrypt_buffer(char *buffer,int buffer_size, char *password, int encryption_method, struct crypt_instance *CI){
339 int x;
340 int y;
341 int password_length;
342
343 #ifdef DEBUG
344 syslog(LOG_INFO,"Encrypting with algorithm #%d",encryption_method);
345 #endif
346
347 /* no crypt instance */
348 if(CI==NULL)
349 return;
350
351 /* no encryption */
352 if(encryption_method==ENCRYPT_NONE)
353 return;
354
355 /* simple XOR "encryption" - not meant for any real security, just obfuscates data, but its fast... */
356 else if(encryption_method==ENCRYPT_XOR){
357
358 /* rotate over IV we received from the server... */
359 for(y=0,x=0;y<buffer_size;y++,x++){
360
361 /* keep rotating over IV */
362 if(x>=TRANSMITTED_IV_SIZE)
363 x=0;
364
365 buffer[y]^=CI->transmitted_iv[x];
366 }
367
368 /* rotate over password... */
369 password_length=strlen(password);
370 for(y=0,x=0;y<buffer_size;y++,x++){
371
372 /* keep rotating over password */
373 if(x>=password_length)
374 x=0;
375
376 buffer[y]^=password[x];
377 }
378
379 return;
380 }
381
382 #ifdef HAVE_LIBMCRYPT
383 /* use mcrypt routines */
384 else{
385
386 /* encrypt each byte of buffer, one byte at a time (CFB mode) */
387 for(x=0;x<buffer_size;x++)
388 mcrypt_generic(CI->td,&buffer[x],1);
389 }
390 #endif
391
392 return;
393 }
394
395
396 /* decrypt a buffer */
decrypt_buffer(char * buffer,int buffer_size,char * password,int encryption_method,struct crypt_instance * CI)397 void decrypt_buffer(char *buffer,int buffer_size, char *password, int encryption_method, struct crypt_instance *CI){
398 int x=0;
399
400 #ifdef DEBUG
401 syslog(LOG_INFO,"Decrypting with algorithm #%d",encryption_method);
402 #endif
403
404 /* no crypt instance */
405 if(CI==NULL)
406 return;
407
408 /* no encryption */
409 if(encryption_method==ENCRYPT_NONE)
410 return;
411
412 /* XOR "decryption" is the same as encryption */
413 else if(encryption_method==ENCRYPT_XOR)
414 encrypt_buffer(buffer,buffer_size,password,encryption_method,CI);
415
416 #ifdef HAVE_LIBMCRYPT
417 /* use mcrypt routines */
418 else{
419
420 /* encrypt each byte of buffer, one byte at a time (CFB mode) */
421 for(x=0;x<buffer_size;x++)
422 mdecrypt_generic(CI->td,&buffer[x],1);
423 }
424 #endif
425
426 return;
427 }
428
429
430
431 /* fill a buffer with semi-random data */
randomize_buffer(char * buffer,int buffer_size)432 void randomize_buffer(char *buffer,int buffer_size){
433 FILE *fp;
434 int x;
435 int seed;
436
437 /**** FILL BUFFER WITH RANDOM ALPHA-NUMERIC CHARACTERS ****/
438
439 /***************************************************************
440 Only use alpha-numeric characters becase plugins usually
441 only generate numbers and letters in their output. We
442 want the buffer to contain the same set of characters as
443 plugins, so its harder to distinguish where the real output
444 ends and the rest of the buffer (padded randomly) starts.
445 ***************************************************************/
446
447 /* try to get seed value from /dev/urandom, as its a better source of entropy */
448 fp=fopen("/dev/urandom","r");
449 if(fp!=NULL){
450 seed=fgetc(fp);
451 fclose(fp);
452 }
453
454 /* else fallback to using the current time as the seed */
455 else
456 seed=(int)time(NULL);
457
458 srand(seed);
459 for(x=0;x<buffer_size;x++)
460 buffer[x]=(int)'0'+(int)(72.0*rand()/(RAND_MAX+1.0));
461
462 return;
463 }
464
465
466
467 /* strips trailing newlines, carriage returns, spaces, and tabs from a string */
strip(char * buffer)468 void strip(char *buffer){
469 int x;
470 int index;
471
472 for(x=strlen(buffer);x>=1;x--){
473 index=x-1;
474 if(buffer[index]==' ' || buffer[index]=='\r' || buffer[index]=='\n' || buffer[index]=='\t')
475 buffer[index]='\x0';
476 else
477 break;
478 }
479
480 return;
481 }
482
483
484
485 /* wipes an area of memory clean */
clear_buffer(char * buffer,int buffer_length)486 void clear_buffer(char *buffer, int buffer_length){
487
488 /* NULL all bytes of buffer */
489 memset(buffer,'\x0',buffer_length);
490
491 return;
492 }
493
494
495
496 /* show license */
display_license(void)497 void display_license(void){
498
499 printf("This program is free software; you can redistribute it and/or modify\n");
500 printf("it under the terms of the GNU General Public License as published by\n");
501 printf("the Free Software Foundation; either version 2 of the License, or\n");
502 printf("(at your option) any later version.\n\n");
503 printf("This program is distributed in the hope that it will be useful,\n");
504 printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
505 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
506 printf("GNU General Public License for more details.\n\n");
507 printf("You should have received a copy of the GNU General Public License\n");
508 printf("along with this program; if not, write to the Free Software\n");
509 printf("Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
510
511 return;
512 }
513