1 /**********************************************************************************
2  *
3  * SEND_NSCA.C - NSCA Client
4  * License: GPL v2
5  * Copyright (c) 2000-2007 Ethan Galstad (nagios@nagios.org)
6  *
7  * Last Modified: 07-03-2007
8  *
9  * Command line: SEND_NSCA <host_address> [-p port] [-to to_sec] [-c config_file]
10  *
11  * Description:
12  *
13  *
14  *********************************************************************************/
15 
16 /*#define DEBUG*/
17 
18 #include "../include/common.h"
19 #include "../include/config.h"
20 #include "../include/netutils.h"
21 #include "../include/utils.h"
22 
23 time_t start_time,end_time;
24 
25 int server_port=DEFAULT_SERVER_PORT;
26 char server_name[MAX_HOST_ADDRESS_LENGTH];
27 char password[MAX_INPUT_BUFFER]="";
28 char config_file[MAX_INPUT_BUFFER]="send_nsca.cfg";
29 char delimiter[2]="\t";
30 
31 char received_iv[TRANSMITTED_IV_SIZE];
32 
33 int socket_timeout=DEFAULT_SOCKET_TIMEOUT;
34 
35 int warning_time=0;
36 int check_warning_time=FALSE;
37 int critical_time=0;
38 int check_critical_time=FALSE;
39 int encryption_method=ENCRYPT_XOR;
40 time_t packet_timestamp;
41 struct crypt_instance *CI=NULL;
42 
43 int show_help=FALSE;
44 int show_license=FALSE;
45 int show_version=FALSE;
46 
47 
48 int process_arguments(int,char **);
49 int read_config_file(char *);
50 int read_init_packet(int);
51 void alarm_handler(int);
52 void clear_password(void);
53 static void do_exit(int);
54 
55 
56 
57 
main(int argc,char ** argv)58 int main(int argc, char **argv){
59 	int sd;
60 	int rc;
61 	int result;
62 	data_packet send_packet;
63 	int bytes_to_send;
64 	char input_buffer[MAX_INPUT_BUFFER];
65 	char *temp_ptr;
66 	char host_name[MAX_HOSTNAME_LENGTH];
67 	char svc_description[MAX_DESCRIPTION_LENGTH];
68 	char plugin_output[MAX_PLUGINOUTPUT_LENGTH];
69 	int total_packets=0;
70 	int16_t return_code;
71 	u_int32_t calculated_crc32;
72 	char *ptr1, *ptr2, *ptr3, *ptr4;
73 
74 
75 	/* process command-line arguments */
76 	result=process_arguments(argc,argv);
77 
78 	if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE){
79 
80 		if(result!=OK)
81 			printf("Incorrect command line arguments supplied\n");
82 		printf("\n");
83 		printf("NSCA Client %s\n",PROGRAM_VERSION);
84 		printf("Copyright (c) 2000-2007 Ethan Galstad (www.nagios.org)\n");
85 		printf("Last Modified: %s\n",MODIFICATION_DATE);
86 		printf("License: GPL v2\n");
87 		printf("Encryption Routines: ");
88 #ifdef HAVE_LIBMCRYPT
89 		printf("AVAILABLE");
90 #else
91 		printf("NOT AVAILABLE");
92 #endif
93 		printf("\n");
94 		printf("\n");
95 	        }
96 
97 	if(result!=OK || show_help==TRUE){
98 		printf("Usage: %s -H <host_address> [-p port] [-to to_sec] [-d delim] [-c config_file]\n",argv[0]);
99 		printf("\n");
100 		printf("Options:\n");
101 		printf(" <host_address> = The IP address of the host running the NSCA daemon\n");
102 		printf(" [port]         = The port on which the daemon is running - default is %d\n",DEFAULT_SERVER_PORT);
103 		printf(" [to_sec]       = Number of seconds before connection attempt times out.\n");
104 		printf("                  (default timeout is %d seconds)\n",DEFAULT_SOCKET_TIMEOUT);
105 		printf(" [delim]        = Delimiter to use when parsing input (defaults to a tab)\n");
106 		printf(" [config_file]  = Name of config file to use\n");
107 		printf("\n");
108 		printf("Note:\n");
109 		printf("This utility is used to send passive check results to the NSCA daemon.  Host and\n");
110 		printf("Service check data that is to be sent to the NSCA daemon is read from standard\n");
111 		printf("input. Input should be provided in the following format (tab-delimited unless\n");
112 		printf("overriden with -d command line argument, one entry per line):\n");
113 		printf("\n");
114 		printf("Service Checks:\n");
115 		printf("<host_name>[tab]<svc_description>[tab]<return_code>[tab]<plugin_output>[newline]\n\n");
116 		printf("Host Checks:\n");
117 		printf("<host_name>[tab]<return_code>[tab]<plugin_output>[newline]\n");
118 		printf("\n");
119 	        }
120 
121 	if(show_license==TRUE)
122 		display_license();
123 
124         if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE)
125 		do_exit(STATE_UNKNOWN);
126 
127 
128 
129 	/* read the config file */
130 	result=read_config_file(config_file);
131 
132 	/* exit if there are errors... */
133 	if(result==ERROR){
134 		printf("Error: Config file '%s' contained errors...\n",config_file);
135 		do_exit(STATE_CRITICAL);
136 		}
137 
138 	/* generate the CRC 32 table */
139 	generate_crc32_table();
140 
141 	/* initialize alarm signal handling */
142 	signal(SIGALRM,alarm_handler);
143 
144 	/* set socket timeout */
145 	alarm(socket_timeout);
146 
147 	time(&start_time);
148 
149 	/* try to connect to the host at the given port number */
150 	result=my_tcp_connect(server_name,server_port,&sd);
151 
152 	/* we couldn't connect */
153 	if(result!=STATE_OK){
154 		printf("Error: Could not connect to host %s on port %d\n",server_name,server_port);
155 		do_exit(STATE_CRITICAL);
156 	        }
157 
158 #ifdef DEBUG
159 	printf("Connected okay...\n");
160 #endif
161 
162 	/* read the initialization packet containing the IV and timestamp */
163 	result=read_init_packet(sd);
164 	if(result!=OK){
165 		printf("Error: Could not read init packet from server\n");
166 		close(sd);
167 		do_exit(STATE_CRITICAL);
168 	        }
169 
170 #ifdef DEBUG
171 	printf("Got init packet from server\n");
172 #endif
173 
174 	/* initialize encryption/decryption routines with the IV we received from the server */
175         if(encrypt_init(password,encryption_method,received_iv,&CI)!=OK){
176 		printf("Error: Failed to initialize encryption libraries for method %d\n",encryption_method);
177 		close(sd);
178 		do_exit(STATE_CRITICAL);
179 	        }
180 
181 #ifdef DEBUG
182 	printf("Initialized encryption routines\n");
183 #endif
184 
185 
186 	/**** WE'RE CONNECTED AND READY TO SEND ****/
187 
188 	/* read all data from STDIN until there isn't anymore */
189 	while(fgets(input_buffer,sizeof(input_buffer)-1,stdin)){
190 
191 		if(feof(stdin))
192 			break;
193 
194 		strip(input_buffer);
195 
196 		if(!strcmp(input_buffer,""))
197 			continue;
198 
199 		/* get the host name */
200 		ptr1=strtok(input_buffer,delimiter);
201 		if(ptr1==NULL)
202 			continue;
203 
204 		/* get the service description or return code */
205 		ptr2=strtok(NULL,delimiter);
206 		if(ptr2==NULL)
207 			continue;
208 
209 		/* get the return code or plugin output */
210 		ptr3=strtok(NULL,delimiter);
211 		if(ptr3==NULL)
212 			continue;
213 
214 		/* get the plugin output - if NULL, this is a host check result */
215 		ptr4=strtok(NULL,"\n");
216 
217 		strncpy(host_name,ptr1,sizeof(host_name)-1);
218 		host_name[sizeof(host_name)-1]='\x0';
219 		if(ptr4==NULL){
220 			strcpy(svc_description,"");
221 			return_code=atoi(ptr2);
222 			if(plugin_output[strlen(plugin_output)-1]=='\n')
223 				plugin_output[strlen(plugin_output)-1]='\x0';
224 			strncpy(plugin_output,ptr3,sizeof(plugin_output)-1);
225 		        }
226 		else{
227 			strncpy(svc_description,ptr2,sizeof(svc_description)-1);
228 			return_code=atoi(ptr3);
229 			strncpy(plugin_output,ptr4,sizeof(plugin_output)-1);
230 		        }
231 		svc_description[sizeof(svc_description)-1]='\x0';
232 		plugin_output[sizeof(plugin_output)-1]='\x0';
233 
234 		/* increment count of packets we're sending */
235 		total_packets++;
236 
237 		/* clear the packet buffer */
238 		bzero(&send_packet,sizeof(send_packet));
239 
240 		/* fill the packet with semi-random data */
241 		randomize_buffer((char *)&send_packet,sizeof(send_packet));
242 
243 		/* copy the data we want to send into the packet */
244 		send_packet.packet_version=(int16_t)htons(NSCA_PACKET_VERSION_3);
245 		send_packet.return_code=(int16_t)htons(return_code);
246 		strcpy(&send_packet.host_name[0],host_name);
247 		strcpy(&send_packet.svc_description[0],svc_description);
248 		strcpy(&send_packet.plugin_output[0],plugin_output);
249 
250 		/* use timestamp provided by the server */
251 		send_packet.timestamp=(u_int32_t)htonl(packet_timestamp);
252 
253 		/* calculate the crc 32 value of the packet */
254 		send_packet.crc32_value=(u_int32_t)0L;
255 		calculated_crc32=calculate_crc32((char *)&send_packet,sizeof(send_packet));
256 		send_packet.crc32_value=(u_int32_t)htonl(calculated_crc32);
257 
258 		/* encrypt the packet */
259 		encrypt_buffer((char *)&send_packet,sizeof(send_packet),password,encryption_method,CI);
260 
261 		/* send the packet */
262 		bytes_to_send=sizeof(send_packet);
263 		rc=sendall(sd,(char *)&send_packet,&bytes_to_send);
264 
265 		/* there was an error sending the packet */
266 		if(rc==-1){
267 			printf("Error: Could not send data to host\n");
268 			close(sd);
269 			do_exit(STATE_UNKNOWN);
270 	                }
271 
272 		/* for some reason we didn't send all the bytes we were supposed to */
273 		else if(bytes_to_send<sizeof(send_packet)){
274 			printf("Warning: Sent only %d of %d bytes to host\n",rc,sizeof(send_packet));
275 			close(sd);
276 			return STATE_UNKNOWN;
277 		        }
278 	        }
279 
280 #ifdef DEBUG
281 	printf("Done sending data\n");
282 #endif
283 
284 	/* close the connection */
285 	close(sd);
286 
287 	printf("%d data packet(s) sent to host successfully.\n",total_packets);
288 
289 	/* exit cleanly */
290 	do_exit(STATE_OK);
291 
292 	/* no compiler complaints here... */
293 	return STATE_OK;
294         }
295 
296 
297 
298 /* exit */
do_exit(int return_code)299 static void do_exit(int return_code){
300 
301 	/* reset the alarm */
302 	alarm(0);
303 
304 	/* encryption/decryption routine cleanup */
305 	encrypt_cleanup(encryption_method,CI);
306 
307 #ifdef DEBUG
308 	printf("Cleaned up encryption routines\n");
309 #endif
310 
311 	/*** CLEAR SENSITIVE INFO FROM MEMORY ***/
312 
313         /* overwrite password */
314         clear_buffer(password,sizeof(password));
315 
316 	/* disguise decryption method */
317 	encryption_method=-1;
318 
319         exit(return_code);
320         }
321 
322 
323 
324 /* reads initialization packet (containing IV and timestamp) from server */
read_init_packet(int sock)325 int read_init_packet(int sock){
326         int rc;
327         init_packet receive_packet;
328         int bytes_to_recv;
329 
330         /* clear the IV and timestamp */
331         bzero(&received_iv,TRANSMITTED_IV_SIZE);
332         packet_timestamp=(time_t)0;
333 
334         /* get the init packet from the server */
335         bytes_to_recv=sizeof(receive_packet);
336         rc=recvall(sock,(char *)&receive_packet,&bytes_to_recv,socket_timeout);
337 
338         /* recv() error or server disconnect */
339         if(rc<=0){
340                 printf("Error: Server closed connection before init packet was received\n");
341                 return ERROR;
342                 }
343 
344         /* we couldn't read the correct amount of data, so bail out */
345         else if(bytes_to_recv!=sizeof(receive_packet)){
346                 printf("Error: Init packet from server was too short (%d bytes received, %d expected)\n",bytes_to_recv,sizeof(receive_packet));
347                 return ERROR;
348                 }
349 
350         /* transfer the IV and timestamp */
351         memcpy(&received_iv,&receive_packet.iv[0],TRANSMITTED_IV_SIZE);
352         packet_timestamp=(time_t)ntohl(receive_packet.timestamp);
353 
354         return OK;
355         }
356 
357 
358 
359 /* process command line arguments */
process_arguments(int argc,char ** argv)360 int process_arguments(int argc, char **argv){
361 	int x;
362 
363 	/* no options were supplied */
364 	if(argc<2){
365 		show_help=TRUE;
366 		return OK;
367 	        }
368 
369 	/* support old command-line syntax (host name first argument) */
370 	strncpy(server_name,argv[1],sizeof(server_name)-1);
371 	server_name[sizeof(server_name)-1]='\x0';
372 
373 	/* process arguments (host name is usually 1st argument) */
374 	for(x=2;x<=argc;x++){
375 
376 		/* show usage */
377 		if(!strcmp(argv[x-1],"-h") || !strcmp(argv[x-1],"--help"))
378 			show_help=TRUE;
379 
380 		/* show license */
381 		else if(!strcmp(argv[x-1],"-l") || !strcmp(argv[x-1],"--license"))
382 			show_license=TRUE;
383 
384 		/* show version */
385 		else if(!strcmp(argv[x-1],"-V") || !strcmp(argv[x-1],"--version"))
386 			show_version=TRUE;
387 
388 		/* server name/address */
389 		else if(!strcmp(argv[x-1],"-H")){
390 			if(x<argc){
391 				strncpy(server_name,argv[x],sizeof(server_name));
392 				server_name[sizeof(server_name)-1]='\x0';
393 				x++;
394 			        }
395 			else
396 				return ERROR;
397 		        }
398 
399 		/* port to connect to */
400 		else if(!strcmp(argv[x-1],"-p")){
401 			if(x<argc){
402 				server_port=atoi(argv[x]);
403 				x++;
404 			        }
405 			else
406 				return ERROR;
407 		        }
408 
409 		/* timeout when connecting */
410 		else if(!strcmp(argv[x-1],"-to")){
411 			if(x<argc){
412 				socket_timeout=atoi(argv[x]);
413 				if(socket_timeout<=0)
414 					return ERROR;
415 				x++;
416 			        }
417 			else
418 				return ERROR;
419 		        }
420 
421 		/* config file */
422 		else if(!strcmp(argv[x-1],"-c")){
423 			if(x<argc){
424 				snprintf(config_file,sizeof(config_file),"%s",argv[x]);
425 				config_file[sizeof(config_file)-1]='\x0';
426 				x++;
427 			        }
428 			else
429 				return ERROR;
430 		        }
431 
432 		/* delimiter to use when parsing input */
433 		else if(!strcmp(argv[x-1],"-d")){
434 			if(x<argc){
435 				snprintf(delimiter,sizeof(delimiter),"%s",argv[x]);
436 				delimiter[sizeof(delimiter)-1]='\x0';
437 				x++;
438 			        }
439 			else
440 				return ERROR;
441 		        }
442 
443 		else if(x>2)
444 			return ERROR;
445 	        }
446 
447 	return OK;
448         }
449 
450 
451 
452 /* handle timeouts */
alarm_handler(int sig)453 void alarm_handler(int sig){
454 
455 	printf("Error: Timeout after %d seconds\n",socket_timeout);
456 
457 	do_exit(STATE_CRITICAL);
458         }
459 
460 
461 
462 /* read in the configuration file */
read_config_file(char * filename)463 int read_config_file(char *filename){
464 	FILE *fp;
465 	char input_buffer[MAX_INPUT_BUFFER];
466 	char *temp_buffer;
467 	char *varname;
468 	char *varvalue;
469 	int line;
470 
471 
472 	/* open the config file for reading */
473 	fp=fopen(filename,"r");
474 
475 	/* exit if we couldn't open the config file */
476 	if(fp==NULL){
477 		printf("Could not open config file '%s' for reading.\n",filename);
478 		return ERROR;
479 	        }
480 
481 	line=0;
482 	while(fgets(input_buffer,MAX_INPUT_BUFFER-1,fp)){
483 
484 		line++;
485 
486 		/* skip comments and blank lines */
487 		if(input_buffer[0]=='#')
488 			continue;
489 		if(input_buffer[0]=='\x0')
490 			continue;
491 		if(input_buffer[0]=='\n')
492 			continue;
493 
494 		/* get the variable name */
495 		varname=strtok(input_buffer,"=");
496 		if(varname==NULL){
497 
498 			printf("No variable name specified in config file '%s' - Line %d\n",filename,line);
499 
500 			return ERROR;
501 		        }
502 
503 		/* get the variable value */
504 		varvalue=strtok(NULL,"\n");
505 		if(varvalue==NULL){
506 
507 			printf("No variable value specified in config file '%s' - Line %d\n",filename,line);
508 
509 			return ERROR;
510 		        }
511 
512 		if(strstr(input_buffer,"password")){
513 			if(strlen(varvalue)>sizeof(password)-1){
514 
515 				printf("Password is too long in config file '%s' - Line %d\n",filename,line);
516 
517 				return ERROR;
518 			        }
519 			strncpy(password,varvalue,sizeof(password));
520 			password[sizeof(password)-1]='\x0';
521 		        }
522 
523 		else if(strstr(input_buffer,"encryption_method")){
524 
525 			encryption_method=atoi(varvalue);
526 
527 			switch(encryption_method){
528 			case ENCRYPT_NONE:
529 				break;
530 			case ENCRYPT_XOR:
531 				break;
532 
533 #ifdef HAVE_LIBMCRYPT
534 			case ENCRYPT_DES:
535 				break;
536 			case ENCRYPT_3DES:
537 				break;
538 			case ENCRYPT_CAST128:
539 				break;
540 			case ENCRYPT_CAST256:
541 				break;
542 			case ENCRYPT_XTEA:
543 				break;
544 			case ENCRYPT_3WAY:
545 				break;
546 			case ENCRYPT_BLOWFISH:
547 				break;
548 			case ENCRYPT_TWOFISH:
549 				break;
550 			case ENCRYPT_LOKI97:
551 				break;
552 			case ENCRYPT_RC2:
553 				break;
554 			case ENCRYPT_ARCFOUR:
555 				break;
556 			case ENCRYPT_RIJNDAEL128:
557 				break;
558 			case ENCRYPT_RIJNDAEL192:
559 				break;
560 			case ENCRYPT_RIJNDAEL256:
561 				break;
562 			case ENCRYPT_WAKE:
563 				break;
564 			case ENCRYPT_SERPENT:
565 				break;
566 			case ENCRYPT_ENIGMA:
567 				break;
568 			case ENCRYPT_GOST:
569 				break;
570 			case ENCRYPT_SAFER64:
571 				break;
572 			case ENCRYPT_SAFER128:
573 				break;
574 			case ENCRYPT_SAFERPLUS:
575 				break;
576 #endif
577 			default:
578 				printf("Invalid encryption method (%d) in config file '%s' - Line %d\n",encryption_method,filename,line);
579 #ifndef HAVE_LIBMCRYPT
580 				if(encryption_method>=2)
581 					printf("Client was not compiled with mcrypt library, so encryption is unavailable.\n");
582 #endif
583 				return ERROR;
584 			        }
585 		        }
586 
587 		else{
588 			printf("Unknown option specified in config file '%s' - Line %d\n",filename,line);
589 
590 			return ERROR;
591 		        }
592 
593 	        }
594 
595 
596 	/* close the config file */
597 	fclose(fp);
598 
599 	return OK;
600 	}
601 
602