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