1 /*******************************************************************************
2 *
3 * NSCA.C - Nagios Service Check Acceptor
4 * Copyright (c) 2009 Nagios Core Development Team and Community Contributors
5 * Copyright (c) 2000-2009 Ethan Galstad (egalstad@nagios.org)
6 * License: GPL v2
7 *
8 * Last Modified: 12-07-2016
9 *
10 * Command line: NSCA -c <config_file> [mode]
11 *
12 * Description:
13 *
14 * This program is designed to run as a daemon on the main Nagios machine
15 * and accept service check results from remote hosts.
16 *
17 ******************************************************************************/
18
19 #include "../include/common.h"
20 #include "../include/config.h"
21 #include "../include/netutils.h"
22 #include "../include/utils.h"
23 #include "../include/nsca.h"
24
25
26 static int server_port=DEFAULT_SERVER_PORT;
27 static char server_address[16]="0.0.0.0";
28 static int socket_timeout=DEFAULT_SOCKET_TIMEOUT;
29 static int log_facility=LOG_DAEMON;
30
31 static char config_file[MAX_INPUT_BUFFER]="nsca.cfg";
32 static char alternate_dump_file[MAX_INPUT_BUFFER]="/dev/null";
33 static char command_file[MAX_INPUT_BUFFER]="";
34 static char password[MAX_INPUT_BUFFER]="";
35
36 static enum { OPTIONS_ERROR, SINGLE_PROCESS_DAEMON, MULTI_PROCESS_DAEMON, INETD } mode=SINGLE_PROCESS_DAEMON;
37 static int debug=FALSE;
38 static int aggregate_writes=FALSE;
39 static int decryption_method=ENCRYPT_XOR;
40 static int append_to_file=FALSE;
41 static unsigned long max_packet_age=30;
42
43 char *nsca_user=NULL;
44 char *nsca_group=NULL;
45
46 char *nsca_chroot=NULL;
47 char *check_result_path=NULL;
48
49
50 char *pid_file=NULL;
51 int wrote_pid_file=FALSE;
52
53 int show_help=FALSE;
54 int show_license=FALSE;
55 int show_version=FALSE;
56
57 int sigrestart=FALSE;
58 int sigshutdown=FALSE;
59
60 int using_alternate_dump_file=FALSE;
61 static FILE *command_file_fp=NULL;
62
63 struct handler_entry *rhand=NULL;
64 struct handler_entry *whand=NULL;
65 struct pollfd *pfds=NULL;
66 int maxrhand=0;
67 int maxwhand=0;
68 int maxpfds=0;
69 int nrhand=0;
70 int nwhand=0;
71 int npfds=0;
72
73 #ifdef HAVE_LIBWRAP
74 int allow_severity=LOG_INFO;
75 int deny_severity=LOG_WARNING;
76 #endif
77
78
79
main(int argc,char ** argv)80 int main(int argc, char **argv){
81 char buffer[MAX_INPUT_BUFFER];
82 int result;
83 uid_t uid=-1;
84 gid_t gid=-1;
85 #ifdef HAVE_SIGACTION
86 struct sigaction sig_action;
87 #endif
88
89
90 /* process command-line arguments */
91 result=process_arguments(argc,argv);
92
93 if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE){
94
95 if(result!=OK)
96 printf("Incorrect command line arguments supplied\n");
97 printf("\n");
98 printf("NSCA - Nagios Service Check Acceptor\n");
99 printf("Copyright (c) 2009 Nagios Core Development Team and Community Contributors\n");
100 printf("Copyright (c) 2000-2009 Ethan Galstad\n");
101 printf("Version: %s\n",PROGRAM_VERSION);
102 printf("Last Modified: %s\n",MODIFICATION_DATE);
103 printf("License: GPL v2\n");
104 printf("Encryption Routines: ");
105 #ifdef HAVE_LIBMCRYPT
106 printf("AVAILABLE");
107 #else
108 printf("NOT AVAILABLE");
109 #endif
110 printf("\n");
111 #ifdef HAVE_LIBWRAP
112 printf("TCP Wrappers Available\n");
113 #endif
114 printf("\n");
115 }
116
117 if(result!=OK || show_help==TRUE){
118 printf("Usage: %s -c <config_file> [mode]\n",argv[0]);
119 printf("\n");
120 printf("Options:\n");
121 printf(" <config_file> = Name of config file to use\n");
122 printf(" [mode] = Determines how NSCA should run. Valid modes:\n");
123 printf(" --inetd = Run as a service under inetd or xinetd\n");
124 printf(" --daemon = Run as a standalone multi-process daemon\n");
125 printf(" --single = Run as a standalone single-process daemon (default)\n");
126 printf("\n");
127 printf("Notes:\n");
128 printf("This program is designed to accept passive check results from\n");
129 printf("remote hosts that use the send_nsca utility. Can run as a service\n");
130 printf("under inetd or xinetd (read the docs for info on this), or as a\n");
131 printf("standalone daemon.\n");
132 printf("\n");
133 }
134
135 if(show_license==TRUE)
136 display_license();
137
138 if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE)
139 do_exit(STATE_UNKNOWN);
140
141
142 /* open a connection to the syslog facility */
143 /* facility may be overridden later */
144 get_log_facility(NSCA_LOG_FACILITY);
145 openlog("nsca",LOG_PID|LOG_NDELAY,log_facility);
146
147 /* make sure the config file uses an absolute path */
148 if(config_file[0]!='/'){
149
150 /* save the name of the config file */
151 strncpy(buffer,config_file,sizeof(buffer));
152 buffer[sizeof(buffer)-1]='\0';
153
154 /* get absolute path of current working directory */
155 strcpy(config_file,"");
156 getcwd(config_file,sizeof(config_file));
157
158 /* append a forward slash */
159 strncat(config_file,"/",sizeof(config_file)-2);
160 config_file[sizeof(config_file)-1]='\0';
161
162 /* append the config file to the path */
163 strncat(config_file,buffer,sizeof(config_file)-strlen(config_file)-1);
164 config_file[sizeof(config_file)-1]='\0';
165 }
166
167 /* read the config file */
168 result=read_config_file(config_file);
169
170 /* exit if there are errors... */
171 if(result==ERROR)
172 do_exit(STATE_CRITICAL);
173
174 /* generate the CRC 32 table */
175 generate_crc32_table();
176
177
178 /* how should we handle client connections? */
179 switch(mode){
180
181 case INETD:
182 /* chroot if configured */
183 do_chroot();
184
185 /* if we're running under inetd, handle one connection and get out */
186 handle_connection(0,NULL);
187 break;
188
189 case MULTI_PROCESS_DAEMON:
190
191 /* older style, mult-process daemon */
192 /* execution cascades below... */
193 install_child_handler();
194
195 /* |
196 |
197 | */
198 case SINGLE_PROCESS_DAEMON:
199 /* |
200 |
201 V */
202
203 /* daemonize and start listening for requests... */
204 if(fork()==0){
205
206 /* we're a daemon - set up a new process group */
207 setsid();
208
209 /* handle signals */
210 #ifdef HAVE_SIGACTION
211 sig_action.sa_sigaction = NULL;
212 sig_action.sa_handler = sighandler;
213 sigfillset(&sig_action.sa_mask);
214 sig_action.sa_flags = SA_NODEFER|SA_RESTART;
215 sigaction(SIGQUIT, &sig_action, NULL);
216 sigaction(SIGTERM, &sig_action, NULL);
217 sigaction(SIGHUP, &sig_action, NULL);
218 #else /* HAVE_SIGACTION */
219 signal(SIGQUIT,sighandler);
220 signal(SIGTERM,sighandler);
221 signal(SIGHUP,sighandler);
222 #endif /* HAVE_SIGACTION */
223
224 /* close standard file descriptors */
225 close(0);
226 close(1);
227 close(2);
228
229 /* redirect standard descriptors to /dev/null */
230 open("/dev/null",O_RDONLY);
231 open("/dev/null",O_WRONLY);
232 open("/dev/null",O_WRONLY);
233
234 /* get group information before chrooting */
235 get_user_info(nsca_user,&uid);
236 get_group_info(nsca_group,&gid);
237
238 /* write pid file */
239 if(write_pid_file(uid,gid)==ERROR)
240 return STATE_CRITICAL;
241
242 /* chroot if configured */
243 do_chroot();
244
245 /* drop privileges */
246 if(drop_privileges(nsca_user,uid,gid)==ERROR)
247 do_exit(STATE_CRITICAL);
248
249 do{
250
251 /* reset flags */
252 sigrestart=FALSE;
253 sigshutdown=FALSE;
254
255 /* wait for connections */
256 wait_for_connections();
257
258 if(sigrestart==TRUE){
259
260 /* free memory */
261 free_memory();
262
263 /* re-read the config file */
264 result=read_config_file(config_file);
265
266 /* exit if there are errors... */
267 if(result==ERROR){
268 syslog(LOG_ERR,"Config file '%s' contained errors, bailing out...",config_file);
269 break;
270 }
271 }
272
273 }while(sigrestart==TRUE && sigshutdown==FALSE);
274
275 /* remove pid file */
276 remove_pid_file();
277
278 syslog(LOG_NOTICE,"Daemon shutdown\n");
279 }
280 break;
281
282 default:
283 break;
284 }
285
286 /* we are now running in daemon mode, or the connection handed over by inetd has been completed, so the parent process exits */
287 do_exit(STATE_OK);
288
289 /* keep the compilers happy... */
290 return STATE_OK;
291 }
292
293
294 /* cleanup */
do_cleanup(void)295 static void do_cleanup(void){
296
297 /* free memory */
298 free_memory();
299
300 /* close the command file if its still open */
301 if(command_file_fp!=NULL)
302 close_command_file();
303
304 /*** CLEAR SENSITIVE INFO FROM MEMORY ***/
305
306 /* overwrite password */
307 clear_buffer(password,sizeof(password));
308
309 /* disguise decryption method */
310 decryption_method=-1;
311
312 return;
313 }
314
315
316 /* free some memory */
free_memory(void)317 static void free_memory(void){
318
319 if(nsca_user){
320 free(nsca_user);
321 nsca_user=NULL;
322 }
323 if(nsca_group){
324 free(nsca_group);
325 nsca_group=NULL;
326 }
327 if(nsca_chroot){
328 free(nsca_chroot);
329 nsca_chroot=NULL;
330 }
331 if(pid_file){
332 free(pid_file);
333 pid_file=NULL;
334 }
335
336 return;
337 }
338
339
340
341 /* exit cleanly */
do_exit(int return_code)342 static void do_exit(int return_code){
343
344 do_cleanup();
345
346 exit(return_code);
347 }
348
349
350
351 /* read in the configuration file */
read_config_file(char * filename)352 static int read_config_file(char *filename){
353 FILE *fp;
354 char input_buffer[MAX_INPUT_BUFFER];
355 char *varname;
356 char *varvalue;
357 int line;
358
359 /* open the config file for reading */
360 fp=fopen(filename,"r");
361
362 /* exit if we couldn't open the config file */
363 if(fp==NULL){
364 syslog(LOG_ERR,"Could not open config file '%s' for reading\n",filename);
365 return ERROR;
366 }
367
368 line=0;
369 while(fgets(input_buffer,MAX_INPUT_BUFFER-1,fp)){
370
371 line++;
372
373 /* skip comments and blank lines */
374 if(input_buffer[0]=='#')
375 continue;
376 if(input_buffer[0]=='\0')
377 continue;
378 if(input_buffer[0]=='\n')
379 continue;
380
381 /* get the variable name */
382 varname=strtok(input_buffer,"=");
383 if(varname==NULL){
384 syslog(LOG_ERR,"No variable name specified in config file '%s' - Line %d\n",filename,line);
385 return ERROR;
386 }
387
388 /* get the variable value */
389 varvalue=strtok(NULL,"\n");
390 if(varvalue==NULL){
391 syslog(LOG_ERR,"No variable value specified in config file '%s' - Line %d\n",filename,line);
392 return ERROR;
393 }
394
395 if(!strcmp(varname,"server_port")){
396 server_port=atoi(varvalue);
397 if((server_port<1024 && (geteuid()!=0)) || server_port<0){
398 syslog(LOG_ERR,"Invalid port number specified in config file '%s' - Line %d\n",filename,line);
399 return ERROR;
400 }
401 }
402 else if(!strcmp(varname,"server_address")){
403 strncpy(server_address,varvalue,sizeof(server_address) - 1);
404 server_address[sizeof(server_address)-1]='\0';
405 }
406 else if(strstr(input_buffer,"command_file")){
407 if(strlen(varvalue)>sizeof(command_file)-1){
408 syslog(LOG_ERR,"Command file name is too long in config file '%s' - Line %d\n",filename,line);
409 return ERROR;
410 }
411 strncpy(command_file,varvalue,sizeof(command_file)-1);
412 command_file[sizeof(command_file)-1]='\0';
413 }
414 else if(strstr(input_buffer,"alternate_dump_file")){
415 if(strlen(varvalue)>sizeof(alternate_dump_file)-1){
416 syslog(LOG_ERR,"Alternate dump file name is too long in config file '%s' - Line %d\n",filename,line);
417 return ERROR;
418 }
419 strncpy(alternate_dump_file,varvalue,sizeof(alternate_dump_file)-1);
420 alternate_dump_file[sizeof(alternate_dump_file)-1]='\0';
421 }
422 else if(strstr(input_buffer,"password")){
423 if(strlen(varvalue)>sizeof(password)-1){
424 syslog(LOG_ERR,"Password is too long in config file '%s' - Line %d\n",filename,line);
425 return ERROR;
426 }
427 strncpy(password,varvalue,sizeof(password)-1);
428 password[sizeof(password)-1]='\0';
429 }
430 else if(strstr(input_buffer,"decryption_method")){
431
432 decryption_method=atoi(varvalue);
433
434 switch(decryption_method){
435 case ENCRYPT_NONE:
436 case ENCRYPT_XOR:
437 break;
438 #ifdef HAVE_LIBMCRYPT
439 case ENCRYPT_DES:
440 case ENCRYPT_3DES:
441 case ENCRYPT_CAST128:
442 case ENCRYPT_CAST256:
443 case ENCRYPT_XTEA:
444 case ENCRYPT_3WAY:
445 case ENCRYPT_BLOWFISH:
446 case ENCRYPT_TWOFISH:
447 case ENCRYPT_LOKI97:
448 case ENCRYPT_RC2:
449 case ENCRYPT_ARCFOUR:
450 case ENCRYPT_RIJNDAEL128:
451 case ENCRYPT_RIJNDAEL192:
452 case ENCRYPT_RIJNDAEL256:
453 case ENCRYPT_WAKE:
454 case ENCRYPT_SERPENT:
455 case ENCRYPT_ENIGMA:
456 case ENCRYPT_GOST:
457 case ENCRYPT_SAFER64:
458 case ENCRYPT_SAFER128:
459 case ENCRYPT_SAFERPLUS:
460 break;
461 #endif
462 default:
463 syslog(LOG_ERR,"Invalid decryption method (%d) in config file '%s' - Line %d\n",decryption_method,filename,line);
464 #ifndef HAVE_LIBMCRYPT
465 if(decryption_method>=2)
466 syslog(LOG_ERR,"Daemon was not compiled with mcrypt library, so decryption is unavailable.\n");
467 #endif
468 return ERROR;
469 }
470 }
471 else if(strstr(input_buffer,"debug")){
472 if(atoi(varvalue)>0)
473 debug=TRUE;
474 else
475 debug=FALSE;
476 }
477 else if(strstr(input_buffer,"aggregate_writes")){
478 if(atoi(varvalue)>0)
479 aggregate_writes=TRUE;
480 else
481 aggregate_writes=FALSE;
482 }
483 else if(strstr(input_buffer,"check_result_path")){
484 if(strlen(varvalue)>MAX_INPUT_BUFFER-1){
485 syslog(LOG_ERR,"Check result path is too long in config file '%s' - Line %d\n",filename,line);
486 return ERROR;
487 }
488 check_result_path=strdup(varvalue);
489
490 int checkresult_test_fd=-1;
491 char *checkresult_test=NULL;
492 asprintf(&checkresult_test,"%s/nsca.test.%i",check_result_path,getpid());
493 checkresult_test_fd=open(checkresult_test,O_WRONLY|O_CREAT,S_IWUSR);
494 if (checkresult_test_fd>0){
495 unlink(checkresult_test);
496 }
497 else {
498 printf("error!\n");
499 syslog(LOG_ERR,"check_result_path config variable found, but directory not writeable.\n");
500 return ERROR;
501 }
502 }
503
504 else if(strstr(input_buffer,"append_to_file")){
505 if(atoi(varvalue)>0)
506 append_to_file=TRUE;
507 else
508 append_to_file=FALSE;
509 }
510 else if(!strcmp(varname,"max_packet_age")){
511 max_packet_age=strtoul(varvalue,NULL,10);
512 if(max_packet_age>900){
513 syslog(LOG_ERR,"Max packet age cannot be greater than 15 minutes (900 seconds).\n");
514 return ERROR;
515 }
516 }
517
518 else if(!strcmp(varname,"nsca_user"))
519 nsca_user=strdup(varvalue);
520
521 else if(!strcmp(varname,"nsca_group"))
522 nsca_group=strdup(varvalue);
523
524 else if(!strcmp(varname,"nsca_chroot"))
525 nsca_chroot=strdup(varvalue);
526
527 else if(!strcmp(varname,"pid_file"))
528 pid_file=strdup(varvalue);
529
530 else if(!strcmp(varname,"log_facility")){
531 if((get_log_facility(varvalue))==OK){
532 /* re-open log using new facility */
533 closelog();
534 openlog("nsca",LOG_PID|LOG_NDELAY,log_facility);
535 }
536 else
537 syslog(LOG_WARNING,"Invalid log_facility specified in config file '%s' - Line %d\n",filename,line);
538 }
539
540 else{
541 syslog(LOG_ERR,"Unknown option specified in config file '%s' - Line %d\n",filename,line);
542 return ERROR;
543 }
544 }
545
546 /* close the config file */
547 fclose(fp);
548
549 return OK;
550 }
551
552
553
554 /* determines facility to use with syslog */
get_log_facility(char * varvalue)555 int get_log_facility(char *varvalue){
556
557 if(!strcmp(varvalue,"kern"))
558 log_facility=LOG_KERN;
559 else if(!strcmp(varvalue,"user"))
560 log_facility=LOG_USER;
561 else if(!strcmp(varvalue,"mail"))
562 log_facility=LOG_MAIL;
563 else if(!strcmp(varvalue,"daemon"))
564 log_facility=LOG_DAEMON;
565 else if(!strcmp(varvalue,"auth"))
566 log_facility=LOG_AUTH;
567 else if(!strcmp(varvalue,"syslog"))
568 log_facility=LOG_SYSLOG;
569 else if(!strcmp(varvalue,"lrp"))
570 log_facility=LOG_LPR;
571 else if(!strcmp(varvalue,"news"))
572 log_facility=LOG_NEWS;
573 else if(!strcmp(varvalue,"uucp"))
574 log_facility=LOG_UUCP;
575 else if(!strcmp(varvalue,"cron"))
576 log_facility=LOG_CRON;
577 else if(!strcmp(varvalue,"authpriv"))
578 log_facility=LOG_AUTHPRIV;
579 else if(!strcmp(varvalue,"ftp"))
580 log_facility=LOG_FTP;
581 else if(!strcmp(varvalue,"local0"))
582 log_facility=LOG_LOCAL0;
583 else if(!strcmp(varvalue,"local1"))
584 log_facility=LOG_LOCAL1;
585 else if(!strcmp(varvalue,"local2"))
586 log_facility=LOG_LOCAL2;
587 else if(!strcmp(varvalue,"local3"))
588 log_facility=LOG_LOCAL3;
589 else if(!strcmp(varvalue,"local4"))
590 log_facility=LOG_LOCAL4;
591 else if(!strcmp(varvalue,"local5"))
592 log_facility=LOG_LOCAL5;
593 else if(!strcmp(varvalue,"local6"))
594 log_facility=LOG_LOCAL6;
595 else if(!strcmp(varvalue,"local7"))
596 log_facility=LOG_LOCAL7;
597 else{
598 log_facility=LOG_DAEMON;
599 return ERROR;
600 }
601
602 return OK;
603 }
604
605
606
607 /* get rid of all the children we can... */
reap_children(int sig)608 static void reap_children(int sig){
609
610 while(waitpid(-1,NULL,WNOHANG)>0);
611
612 return;
613 }
614
615
616
617 /* install reap_children() signal handler */
install_child_handler(void)618 static void install_child_handler(void){
619 struct sigaction sa;
620
621 sa.sa_handler=reap_children;
622 sa.sa_flags=SA_NOCLDSTOP;
623 sigaction(SIGCHLD,&sa,NULL);
624
625 return;
626 }
627
628
629
630 /* register a file descriptor to be polled for an event set */
register_poll(short events,int fd)631 static void register_poll(short events, int fd){
632 int i;
633
634 /* if it's already in the list, just flag the events */
635 for(i=0;i<npfds;i++){
636 if(pfds[i].fd==fd){
637 pfds[i].events|=events;
638 return;
639 }
640 }
641
642 /* else add it to the list */
643 if(maxpfds==0){
644 maxpfds++;
645 pfds=malloc(sizeof(struct pollfd));
646 }
647 else if(npfds+1 > maxpfds){
648 maxpfds++;
649 pfds=realloc(pfds, sizeof(struct pollfd) * maxpfds);
650 }
651
652 pfds[npfds].fd=fd;
653 pfds[npfds].events=events;
654 pfds[npfds].revents=0;
655 npfds++;
656 }
657
658
659
660 /* register a read handler */
register_read_handler(int fd,void (* fp)(int,void *),void * data)661 static void register_read_handler(int fd, void (*fp)(int, void *), void *data){
662 int i;
663
664 /* register our interest in this descriptor */
665 register_poll(POLLIN,fd);
666
667 /* if it's already in the list, just update the handler */
668 for(i=0;i<nrhand;i++){
669 if(rhand[i].fd==fd){
670 rhand[i].handler=fp;
671 rhand[i].data=data;
672 return;
673 }
674 }
675
676 /* else add it to the list */
677 if(maxrhand==0){
678 maxrhand++;
679 rhand=malloc(sizeof(struct handler_entry));
680 }
681 else if(nrhand+1 > maxrhand){
682 maxrhand++;
683 rhand=realloc(rhand, sizeof(struct handler_entry) * maxrhand);
684 }
685
686 rhand[nrhand].fd=fd;
687 rhand[nrhand].handler=fp;
688 rhand[nrhand].data=data;
689 nrhand++;
690 }
691
692
693
694 /* register a write handler */
register_write_handler(int fd,void (* fp)(int,void *),void * data)695 static void register_write_handler(int fd, void (*fp)(int, void *), void *data){
696 int i;
697
698 /* register our interest in this descriptor */
699 register_poll(POLLOUT,fd);
700
701 /* if it's already in the list, just update the handler */
702 for(i=0;i<nwhand;i++){
703 if(whand[i].fd==fd){
704 whand[i].handler=fp;
705 whand[i].data=data;
706 return;
707 }
708 }
709
710 /* else add it to the list */
711 if(maxwhand==0){
712 maxwhand++;
713 whand=malloc(sizeof(struct handler_entry));
714 }
715 else if(nwhand+1 > maxwhand){
716 maxwhand++;
717 whand=realloc(whand, sizeof(struct handler_entry) * maxwhand);
718 }
719
720 whand[nwhand].fd=fd;
721 whand[nwhand].handler=fp;
722 whand[nwhand].data=data;
723 nwhand++;
724 }
725
726
727
728 /* find read handler */
find_rhand(int fd)729 static int find_rhand(int fd){
730 int i;
731
732 for(i=0;i<nrhand;i++){
733 if(rhand[i].fd==fd)
734 return i;
735 }
736
737 /* we couldn't find the read handler */
738 syslog(LOG_ERR, "Handler stack corrupt - aborting");
739 do_exit(STATE_CRITICAL);
740 }
741
742
743
744 /* find write handler */
find_whand(int fd)745 static int find_whand(int fd){
746 int i;
747
748 for(i=0;i<nwhand;i++){
749 if(whand[i].fd==fd)
750 return i;
751 }
752
753 /* we couldn't find the write handler */
754 syslog(LOG_ERR, "Handler stack corrupt - aborting");
755 do_exit(STATE_CRITICAL);
756 }
757
758
759 /* handle pending events */
handle_events(void)760 static void handle_events(void){
761 void (*handler)(int, void *);
762 void *data;
763 int i, hand;
764
765 /* bail out if necessary */
766 if(sigrestart==TRUE || sigshutdown==TRUE)
767 return;
768
769 poll(pfds,npfds,-1);
770 for(i=0;i<npfds;i++){
771 if((pfds[i].events&POLLIN) && (pfds[i].revents&(POLLIN|POLLERR|POLLHUP|POLLNVAL))){
772 pfds[i].events&=~POLLIN;
773 hand=find_rhand(pfds[i].fd);
774 handler=rhand[hand].handler;
775 data=rhand[hand].data;
776 rhand[hand].handler=NULL;
777 rhand[hand].data=NULL;
778 if((pfds[i].revents&POLLNVAL)==0)
779 handler(pfds[i].fd,data);
780 }
781 if((pfds[i].events&POLLOUT) && (pfds[i].revents&(POLLOUT|POLLERR|POLLHUP|POLLNVAL))){
782 pfds[i].events&=~POLLOUT;
783 hand=find_whand(pfds[i].fd);
784 handler=whand[hand].handler;
785 data=whand[hand].data;
786 whand[hand].handler=NULL;
787 whand[hand].data=NULL;
788 if((pfds[i].revents&POLLNVAL)==0)
789 handler(pfds[i].fd,data);
790 }
791 }
792
793 for(i=0;i<npfds;i++){
794 if(pfds[i].events==0){
795 npfds--;
796 pfds[i].fd=pfds[npfds].fd;
797 pfds[i].events=pfds[npfds].events;
798 }
799 }
800
801 return;
802 }
803
804
805
806 /* wait for incoming connection requests */
wait_for_connections(void)807 static void wait_for_connections(void) {
808 struct sockaddr_in myname;
809 int sock=0;
810 int flag=1;
811
812 /* create a socket for listening */
813 sock=socket(AF_INET,SOCK_STREAM,0);
814
815 /* exit if we couldn't create the socket */
816 if(sock<0){
817 syslog(LOG_ERR,"Network server socket failure (%d: %s)",errno,strerror(errno));
818 do_exit(STATE_CRITICAL);
819 }
820
821 /* set the reuse address flag so we don't get errors when restarting */
822 flag=1;
823 if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag))<0){
824 syslog(LOG_ERR,"Could not set reuse address option on socket!\n");
825 do_exit(STATE_CRITICAL);
826 }
827
828 myname.sin_family=AF_INET;
829 myname.sin_port=htons(server_port);
830 bzero(&myname.sin_zero,8);
831
832 /* what address should we bind to? */
833 if(!strlen(server_address))
834 myname.sin_addr.s_addr=INADDR_ANY;
835 else if(!my_inet_aton(server_address,&myname.sin_addr)){
836 syslog(LOG_ERR,"Server address is not a valid IP address\n");
837 do_exit(STATE_CRITICAL);
838 }
839
840
841 /* bind the address to the Internet socket */
842 if(bind(sock,(struct sockaddr *)&myname,sizeof(myname))<0){
843 syslog(LOG_ERR,"Network server bind failure (%d: %s)\n",errno,strerror(errno));
844 do_exit(STATE_CRITICAL);
845 }
846
847 /* open the socket for listening */
848 if(listen(sock,SOMAXCONN)<0){
849 syslog(LOG_ERR,"Network server listen failure (%d: %s)\n",errno,strerror(errno));
850 do_exit(STATE_CRITICAL);
851 }
852
853 /* log info to syslog facility */
854 syslog(LOG_NOTICE,"Starting up daemon");
855
856 if(debug==TRUE){
857 syslog(LOG_DEBUG,"Listening for connections on port %d\n",htons(myname.sin_port));
858 }
859
860 /* socket should be non-blocking for mult-process daemon */
861 if(mode==MULTI_PROCESS_DAEMON)
862 fcntl(sock,F_SETFL,O_NONBLOCK);
863
864 /* listen for connection requests */
865 if(mode==SINGLE_PROCESS_DAEMON)
866 register_read_handler(sock,accept_connection,NULL);
867 while(1){
868
869 /* bail out if necessary */
870 if(sigrestart==TRUE || sigshutdown==TRUE){
871 /* close the socket we're listening on */
872 close(sock);
873 break;
874 }
875
876 /* accept a new connection */
877 if(mode==MULTI_PROCESS_DAEMON)
878 accept_connection(sock,NULL);
879
880 /* handle the new connection (if any) */
881 else
882 handle_events();
883 }
884
885 return;
886 }
887
888
889
accept_connection(int sock,void * unused)890 static void accept_connection(int sock, void *unused){
891 int new_sd;
892 pid_t pid;
893 struct sockaddr addr;
894 struct sockaddr_in *nptr;
895 socklen_t addrlen;
896 int rc;
897 #ifdef HAVE_LIBWRAP
898 struct request_info req;
899 #endif
900
901 /* DO NOT REMOVE! 01/29/2007 single process daemon will fail if this is removed */
902 if(mode==SINGLE_PROCESS_DAEMON)
903 register_read_handler(sock,accept_connection,NULL);
904
905 /* wait for a connection request */
906 while(1){
907
908 /* we got a live one... */
909 if((new_sd=accept(sock,0,0))>=0)
910 break;
911
912 /* handle the error */
913 else{
914
915 /* bail out if necessary */
916 if(sigrestart==TRUE || sigshutdown==TRUE)
917 return;
918
919 /* try and handle temporary errors */
920 if(errno==EWOULDBLOCK || errno==EINTR || errno==ECHILD || errno==ECONNABORTED){
921 if(mode==MULTI_PROCESS_DAEMON)
922 sleep(1);
923 else
924 return;
925 }
926 else
927 break;
928 }
929 }
930
931 /* hey, there was an error... */
932 if(new_sd<0){
933
934 /* log error to syslog facility */
935 syslog(LOG_ERR,"Network server accept failure (%d: %s)",errno,strerror(errno));
936
937 /* close socket prior to exiting */
938 close(sock);
939 if(mode==MULTI_PROCESS_DAEMON)
940 do_exit(STATE_CRITICAL);
941 return;
942 }
943
944 #ifdef HAVE_LIBWRAP
945
946 /* Check whether or not connections are allowed from this host */
947 request_init(&req,RQ_DAEMON,"nsca",RQ_FILE,new_sd,0);
948 fromhost(&req);
949
950 if(!hosts_access(&req)){
951 /* refuse the connection */
952 syslog(LOG_ERR, "refused connect from %s", eval_client(&req));
953 close(new_sd);
954 return;
955 }
956 #endif
957
958
959 /* fork() if we have to... */
960 if(mode==MULTI_PROCESS_DAEMON){
961
962 pid=fork();
963 if(pid){
964 /* parent doesn't need the new connection */
965 close(new_sd);
966 return;
967 }
968 else{
969 /* child does not need to listen for connections */
970 close(sock);
971 }
972 }
973
974 /* find out who just connected... */
975 addrlen=sizeof(addr);
976 rc=getpeername(new_sd,&addr,&addrlen);
977
978 if(rc<0){
979 /* log error to syslog facility */
980 syslog(LOG_ERR,"Error: Network server getpeername() failure (%d: %s)",errno,strerror(errno));
981
982 /* close socket prior to exiting */
983 close(new_sd);
984 if(mode==MULTI_PROCESS_DAEMON)
985 do_exit(STATE_CRITICAL);
986 return;
987 }
988
989 nptr=(struct sockaddr_in *)&addr;
990
991 /* log info to syslog facility */
992 if(debug==TRUE)
993 syslog(LOG_DEBUG,"Connection from %s port %d",inet_ntoa(nptr->sin_addr),nptr->sin_port);
994
995 /* handle the connection */
996 if(mode==SINGLE_PROCESS_DAEMON)
997 /* mark the connection as ready to be handled */
998 register_write_handler(new_sd, handle_connection, NULL);
999 else
1000 /* handle the client connection */
1001 handle_connection(new_sd, NULL);
1002
1003 return;
1004 }
1005
1006
1007
1008 /* handle a client connection */
handle_connection(int sock,void * data)1009 static void handle_connection(int sock, void *data){
1010 init_packet send_packet;
1011 int bytes_to_send;
1012 int rc;
1013 int flags;
1014 time_t packet_send_time;
1015 struct crypt_instance *CI;
1016
1017
1018 /* log info to syslog facility */
1019 if(debug==TRUE)
1020 syslog(LOG_INFO,"Handling the connection...");
1021
1022 /* socket should be non-blocking */
1023 fcntl(sock,F_GETFL,&flags);
1024 fcntl(sock,F_SETFL,flags|O_NONBLOCK);
1025
1026 /* initialize encryption/decryption routines (server generates the IV to use and send to the client) */
1027 if(encrypt_init(password,decryption_method,NULL,&CI)!=OK){
1028 close(sock);
1029 if(mode==MULTI_PROCESS_DAEMON)
1030 do_exit(STATE_CRITICAL);
1031 return;
1032 }
1033
1034 /* create initial packet to send to client (contains random IV and timestamp) */
1035 memcpy(&send_packet.iv[0],CI->transmitted_iv,TRANSMITTED_IV_SIZE);
1036 time(&packet_send_time);
1037 send_packet.timestamp=(u_int32_t)htonl(packet_send_time);
1038
1039 /* send client the initial packet */
1040 bytes_to_send=sizeof(send_packet);
1041 rc=sendall(sock,(char *)&send_packet,&bytes_to_send);
1042
1043 /* there was an error sending the packet */
1044 if(rc==-1){
1045 syslog(LOG_ERR,"Could not send init packet to client\n");
1046 encrypt_cleanup(decryption_method,CI);
1047 close(sock);
1048 if(mode==MULTI_PROCESS_DAEMON)
1049 do_exit(STATE_CRITICAL);
1050 return;
1051 }
1052
1053 /* for some reason we didn't send all the bytes we were supposed to */
1054 else if(bytes_to_send<sizeof(send_packet)){
1055 syslog(LOG_ERR,"Only able to send %d of %d bytes of init packet to client\n",rc,sizeof(send_packet));
1056 encrypt_cleanup(decryption_method,CI);
1057 close(sock);
1058 if(mode==MULTI_PROCESS_DAEMON)
1059 do_exit(STATE_CRITICAL);
1060 return;
1061 }
1062
1063 /* open the command file if we're aggregating writes */
1064 if(aggregate_writes==TRUE){
1065 if(open_command_file()==ERROR){
1066 close(sock);
1067 if(mode==MULTI_PROCESS_DAEMON)
1068 do_exit(STATE_CRITICAL);
1069 return;
1070 }
1071 }
1072
1073 if(mode==SINGLE_PROCESS_DAEMON)
1074 register_read_handler(sock, handle_connection_read, (void *)CI);
1075 else{
1076 while(1)
1077 handle_connection_read(sock,(void *)CI);
1078 }
1079
1080 return;
1081 }
1082
1083
1084
1085 /* handle reading from a client connection */
handle_connection_read(int sock,void * data)1086 static void handle_connection_read(int sock, void *data){
1087 data_packet receive_packet;
1088 u_int32_t packet_crc32;
1089 u_int32_t calculated_crc32;
1090 struct crypt_instance *CI;
1091 time_t packet_time;
1092 time_t current_time;
1093 int16_t return_code;
1094 unsigned long packet_age=0L;
1095 int bytes_to_recv;
1096 int rc;
1097 char host_name[MAX_HOSTNAME_LENGTH];
1098 char svc_description[MAX_DESCRIPTION_LENGTH];
1099 char plugin_output[MAX_PLUGINOUTPUT_LENGTH];
1100 int packet_length=sizeof(receive_packet);
1101 int plugin_length=MAX_PLUGINOUTPUT_LENGTH;
1102
1103 CI=data;
1104
1105 /* process all data we get from the client... */
1106
1107 /* read the packet from the client */
1108 bytes_to_recv=sizeof(receive_packet);
1109 rc=recvall(sock,(char *)&receive_packet,&bytes_to_recv,socket_timeout);
1110
1111 /* recv() error or client disconnect */
1112 if(rc<=0){
1113 if( OLD_PACKET_LENGTH == bytes_to_recv){
1114 packet_length=OLD_PACKET_LENGTH;
1115 plugin_length=OLD_PLUGINOUTPUT_LENGTH;
1116 }
1117 else {
1118 if(debug==TRUE)
1119 syslog(LOG_ERR,"End of connection...");
1120 encrypt_cleanup(decryption_method, CI);
1121 close(sock);
1122 if(mode==SINGLE_PROCESS_DAEMON)
1123 return;
1124 else
1125 do_exit(STATE_OK);
1126 }
1127 }
1128
1129 /* we couldn't read the correct amount of data, so bail out */
1130 if(bytes_to_recv!=packet_length){
1131 syslog(LOG_ERR,"Data sent from client was too short (%d < %d), aborting...",bytes_to_recv,packet_length);
1132 encrypt_cleanup(decryption_method, CI);
1133 close(sock);
1134 return;
1135 if(mode==SINGLE_PROCESS_DAEMON)
1136 return;
1137 else
1138 do_exit(STATE_CRITICAL);
1139 }
1140
1141 /* if we're single-process, we need to set things up so we handle the next packet after this one... */
1142 if(mode==SINGLE_PROCESS_DAEMON)
1143 register_read_handler(sock, handle_connection_read, (void *)CI);
1144
1145 /* decrypt the packet */
1146 decrypt_buffer((char *)&receive_packet,packet_length,password,decryption_method,CI);
1147
1148 /* make sure this is the right type of packet */
1149 if(ntohs(receive_packet.packet_version)!=NSCA_PACKET_VERSION_3){
1150 syslog(LOG_ERR,"Received invalid packet type/version from client - possibly due to client using wrong password or crypto algorithm?");
1151 /*return;*/
1152 close(sock);
1153 if(mode==SINGLE_PROCESS_DAEMON)
1154 return;
1155 else
1156 do_exit(STATE_OK);
1157 }
1158
1159 /* check the crc 32 value */
1160 packet_crc32=ntohl(receive_packet.crc32_value);
1161 receive_packet.crc32_value=0L;
1162 calculated_crc32=calculate_crc32((char *)&receive_packet,packet_length);
1163 if(packet_crc32!=calculated_crc32){
1164 syslog(LOG_ERR,"Dropping packet with invalid CRC32 - possibly due to client using wrong password or crypto algorithm?");
1165 /*return;*/
1166 close(sock);
1167 if(mode==SINGLE_PROCESS_DAEMON)
1168 return;
1169 else
1170 do_exit(STATE_OK);
1171 }
1172
1173 /* host name */
1174 strncpy(host_name,receive_packet.host_name,sizeof(host_name)-1);
1175 host_name[sizeof(host_name)-1]='\0';
1176
1177 packet_age=(unsigned long)(current_time-packet_time);
1178 if(debug==TRUE)
1179 syslog(LOG_ERR,"Time difference in packet: %lu seconds for host %s", packet_age, host_name);
1180 if((max_packet_age>0 && (packet_age>max_packet_age) && (packet_age>=0)) ||
1181 ((max_packet_age>0) && (packet_age<(0-max_packet_age)) && (packet_age < 0))
1182 ){
1183 syslog(LOG_ERR,"Dropping packet with stale timestamp for %s - packet was %lu seconds old.",host_name,packet_age);
1184 close(sock);
1185 if(mode==SINGLE_PROCESS_DAEMON)
1186 return;
1187 else
1188 do_exit(STATE_OK);
1189 }
1190
1191 /**** GET THE SERVICE CHECK INFORMATION ****/
1192
1193 /* plugin return code */
1194 return_code=ntohs(receive_packet.return_code);
1195
1196 /* service description */
1197 strncpy(svc_description,receive_packet.svc_description,sizeof(svc_description)-1);
1198 svc_description[sizeof(svc_description)-1]='\0';
1199
1200 /* plugin output */
1201 strncpy(plugin_output,receive_packet.plugin_output,plugin_length-1);
1202 plugin_output[plugin_length-1]='\0';
1203
1204 /* log info to syslog facility */
1205 if(debug==TRUE){
1206 if(!strcmp(svc_description,""))
1207 syslog(LOG_NOTICE,"HOST CHECK -> Host Name: '%s', Return Code: '%d', Output: '%s'",host_name,return_code,plugin_output);
1208 else
1209 syslog(LOG_NOTICE,"SERVICE CHECK -> Host Name: '%s', Service Description: '%s', Return Code: '%d', Output: '%s'",host_name,svc_description,return_code,plugin_output);
1210 }
1211
1212 /* write the check result to the external command file.
1213 * Note: it's OK to hang at this point if the write doesn't succeed, as there's
1214 * no way we could handle any other connection properly anyway. so we don't
1215 * use poll() - which fails on a pipe with any data, so it would cause us to
1216 * only ever write one command at a time into the pipe.
1217 */
1218 //syslog(LOG_ERR,"'%s' (%s) []",check_result_path, strlen(check_result_path));
1219 if (check_result_path==NULL){
1220 write_check_result(host_name,svc_description,return_code,plugin_output,time(NULL));
1221 }else{
1222 write_checkresult_file(host_name,svc_description,return_code,plugin_output,time(NULL));
1223 }
1224
1225 return;
1226 }
1227
1228
1229
1230 /* writes service/host check results to the Nagios checkresult directory */
write_checkresult_file(char * host_name,char * svc_description,int return_code,char * plugin_output,time_t check_time)1231 static int write_checkresult_file(char *host_name, char *svc_description, int return_code, char *plugin_output, time_t check_time){
1232 if(debug==TRUE)
1233 syslog(LOG_ERR,"Attempting to write checkresult file");
1234 mode_t new_umask=077;
1235 mode_t old_umask;
1236 time_t current_time;
1237 char *output_file=NULL;
1238 int checkresult_file_fd=-1;
1239 char *checkresult_file=NULL;
1240 char *checkresult_ok_file=NULL;
1241 FILE *checkresult_file_fp=NULL;
1242 FILE *checkresult_ok_file_fp=NULL;
1243 /* change and store umask */
1244 old_umask=umask(new_umask);
1245
1246 /* create safe checkresult file */
1247 asprintf(&checkresult_file,"%s/cXXXXXX",check_result_path);
1248 checkresult_file_fd=mkstemp(checkresult_file);
1249 if(checkresult_file_fd>0){
1250 checkresult_file_fp=fdopen(checkresult_file_fd,"w");
1251 } else {
1252 syslog(LOG_ERR,"Unable to open and write checkresult file '%s', failing back to PIPE",checkresult_file);
1253 return write_check_result(host_name,svc_description,return_code,plugin_output,check_time);
1254 }
1255
1256 if(debug==TRUE)
1257 syslog(LOG_ERR,"checkresult file '%s' open for write.",checkresult_file);
1258
1259 time(¤t_time);
1260 fprintf(checkresult_file_fp,"### NSCA Passive Check Result ###\n");
1261 fprintf(checkresult_file_fp,"# Time: %s",ctime(¤t_time));
1262 fprintf(checkresult_file_fp,"file_time=%d\n\n",current_time);
1263 fprintf(checkresult_file_fp,"### %s Check Result ###\n",(svc_description=="")?"Host":"Service");
1264 fprintf(checkresult_file_fp,"host_name=%s\n",host_name);
1265 if(strcmp(svc_description,""))
1266 fprintf(checkresult_file_fp,"service_description=%s\n",svc_description);
1267 fprintf(checkresult_file_fp,"check_type=1\n");
1268 fprintf(checkresult_file_fp,"scheduled_check=0\n");
1269 fprintf(checkresult_file_fp,"reschedule_check=0\n");
1270 /* We have no latency data at this point. */
1271 fprintf(checkresult_file_fp,"latency=0\n");
1272 fprintf(checkresult_file_fp,"start_time=%lu.%lu\n",check_time,0L);
1273 fprintf(checkresult_file_fp,"finish_time=%lu.%lu\n",check_time,0L);
1274 fprintf(checkresult_file_fp,"return_code=%d\n",return_code);
1275 /* newlines in output are already escaped */
1276 fprintf(checkresult_file_fp,"output=%s\n",(plugin_output==NULL)?"":plugin_output);
1277 fprintf(checkresult_file_fp,"\n");
1278
1279 fclose(checkresult_file_fp);
1280 /* create and close ok file */
1281 asprintf(&checkresult_ok_file,"%s.ok",checkresult_file);
1282 syslog(LOG_DEBUG,"checkresult completion file '%s' open.",checkresult_ok_file);
1283 checkresult_ok_file_fp = fopen(checkresult_ok_file,"w");
1284 fclose(checkresult_ok_file_fp);
1285 /* reset umask */
1286 umask(old_umask);
1287
1288 return OK;
1289 }
1290
1291 /* writes service/host check results to the Nagios command file */
write_check_result(char * host_name,char * svc_description,int return_code,char * plugin_output,time_t check_time)1292 static int write_check_result(char *host_name, char *svc_description, int return_code, char *plugin_output, time_t check_time){
1293 if(debug==TRUE)
1294 syslog(LOG_ERR,"Attempting to write to nagios command pipe");
1295 if(aggregate_writes==FALSE){
1296 if(open_command_file()==ERROR)
1297 return ERROR;
1298 }
1299
1300 if(!strcmp(svc_description,""))
1301 fprintf(command_file_fp,"[%lu] PROCESS_HOST_CHECK_RESULT;%s;%d;%s\n",(unsigned long)check_time,host_name,return_code,plugin_output);
1302 else{
1303 fprintf(command_file_fp,"[%lu] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",(unsigned long)check_time,host_name,svc_description,return_code,plugin_output);
1304 }
1305 if(aggregate_writes==FALSE)
1306 close_command_file();
1307 else
1308 /* if we don't fflush() then we're writing in 4k non-CR-terminated blocks, and
1309 * anything else (eg. pscwatch) which writes to the file will be writing into
1310 * the middle of our commands.
1311 */
1312 fflush(command_file_fp);
1313
1314 return OK;
1315 }
1316
1317
1318
1319 /* opens the command file for writing */
open_command_file(void)1320 static int open_command_file(void)
1321 {
1322 int fd;
1323
1324 /* file is already open */
1325 if(command_file_fp!=NULL && using_alternate_dump_file==FALSE)
1326 return OK;
1327
1328 do
1329 fd = open(command_file,O_WRONLY|((append_to_file==TRUE)?O_APPEND:0));
1330 while(fd < 0 && errno == EINTR);
1331
1332 /* command file doesn't exist - monitoring app probably isn't running... */
1333 if (fd < 0 && errno == ENOENT) {
1334
1335 if (debug == TRUE)
1336 syslog(LOG_ERR, "Command file '%s' does not exist, attempting to use alternate dump file '%s' for output", command_file, alternate_dump_file);
1337
1338 /* try and write checks to alternate dump file */
1339 command_file_fp = fopen(alternate_dump_file, "a");
1340 if (command_file_fp == NULL) {
1341 if(debug == TRUE)
1342 syslog(LOG_ERR, "Could not open alternate dump file '%s' for appending", alternate_dump_file);
1343 return ERROR;
1344 }
1345 using_alternate_dump_file = TRUE;
1346
1347 return OK;
1348 }
1349
1350 if (fd < 0 || (command_file_fp = fdopen(fd, (append_to_file == TRUE) ? "a" : "w")) == NULL) {
1351 if (debug == TRUE)
1352 syslog(LOG_ERR, "Could not open command file '%s' for %s", command_file, (append_to_file == TRUE) ? "appending" : "writing");
1353 return ERROR;
1354 }
1355
1356 using_alternate_dump_file = FALSE;
1357 return OK;
1358 }
1359
1360
1361
1362 /* closes the command file */
close_command_file(void)1363 static void close_command_file(void){
1364
1365 fclose(command_file_fp);
1366 command_file_fp=NULL;
1367
1368 return;
1369 }
1370
1371
1372
1373 /* process command line arguments */
process_arguments(int argc,char ** argv)1374 int process_arguments(int argc, char **argv){
1375 int x;
1376
1377 if(argc<2){
1378 show_help=TRUE;
1379 return OK;
1380 }
1381
1382 /* process arguments */
1383 for(x=2;x<=argc;x++){
1384
1385 /* show usage */
1386 if(!strcmp(argv[x-1],"-h") || !strcmp(argv[x-1],"--help"))
1387 show_help=TRUE;
1388
1389 /* show license */
1390 else if(!strcmp(argv[x-1],"-l") || !strcmp(argv[x-1],"--license"))
1391 show_license=TRUE;
1392
1393 /* show version */
1394 else if(!strcmp(argv[x-1],"-V") || !strcmp(argv[x-1],"--version"))
1395 show_version=TRUE;
1396
1397 else if(!strcmp(argv[x-1],"-d") || !strcmp(argv[x-1],"--daemon"))
1398 mode=MULTI_PROCESS_DAEMON;
1399
1400 else if(!strcmp(argv[x-1],"-s") || !strcmp(argv[x-1],"--single"))
1401 mode=SINGLE_PROCESS_DAEMON;
1402
1403 else if(!strcmp(argv[x-1],"-i") || !strcmp(argv[x-1],"--inetd"))
1404 mode=INETD;
1405
1406 /* config file */
1407 else if(!strcmp(argv[x-1],"-c")){
1408
1409 if(x<argc){
1410 /* grab the config file */
1411 strncpy(config_file,argv[x],sizeof(config_file)-1);
1412 config_file[sizeof(config_file)-1]='\0';
1413 x++;
1414 }
1415 else
1416 return ERROR;
1417 }
1418
1419 else
1420 return ERROR;
1421 }
1422
1423 return OK;
1424 }
1425
1426
1427
1428 /* write an optional pid file */
write_pid_file(uid_t usr,gid_t grp)1429 static int write_pid_file(uid_t usr, gid_t grp){
1430 int fd;
1431 int result=0;
1432 pid_t pid=0;
1433 char pbuf[16];
1434
1435 /* no pid file was specified */
1436 if(pid_file==NULL)
1437 return OK;
1438
1439 /* read existing pid file */
1440 if((fd=open(pid_file,O_RDONLY))>=0){
1441
1442 result=read(fd,pbuf,(sizeof pbuf)-1);
1443
1444 close(fd);
1445
1446 if(result>0){
1447
1448 pbuf[result]='\x0';
1449 pid=(pid_t)atoi(pbuf);
1450
1451 /* if previous process is no longer running running, remove the old pid file */
1452 if(pid && (pid==getpid() || kill(pid,0)<0))
1453 unlink(pid_file);
1454
1455 /* previous process is still running */
1456 else{
1457 syslog(LOG_ERR,"There's already an NSCA server running (PID %lu). Bailing out...",(unsigned long)pid);
1458 return ERROR;
1459 }
1460 }
1461 }
1462
1463 /* write new pid file */
1464 if((fd=open(pid_file,O_WRONLY | O_CREAT,0644))>=0){
1465 sprintf(pbuf,"%d\n",(int)getpid());
1466 write(fd,pbuf,strlen(pbuf));
1467 fchown(fd,usr,grp);
1468 close(fd);
1469 wrote_pid_file=TRUE;
1470 }
1471 else{
1472 syslog(LOG_ERR,"Cannot write to pidfile '%s' - check your privileges.",pid_file);
1473 }
1474
1475 return OK;
1476 }
1477
1478
1479
1480 /* remove pid file */
remove_pid_file(void)1481 static int remove_pid_file(void){
1482
1483 /* no pid file was specified */
1484 if(pid_file==NULL)
1485 return OK;
1486
1487 /* pid file was not written */
1488 if(wrote_pid_file==FALSE)
1489 return OK;
1490
1491 /* remove existing pid file */
1492 if(unlink(pid_file)==-1){
1493 syslog(LOG_ERR,"Cannot remove pidfile '%s' - check your privileges.",pid_file);
1494 return ERROR;
1495 }
1496
1497 return OK;
1498 }
1499
1500
1501
1502 /* get user information */
get_user_info(const char * user,uid_t * uid)1503 static int get_user_info(const char *user, uid_t *uid){
1504 const struct passwd *pw=NULL;
1505
1506 if(user!=NULL){
1507 /* see if this is a user name */
1508 if(strspn(user,"0123456789")<strlen(user)){
1509 pw=(struct passwd *)getpwnam(user);
1510 if(pw!=NULL)
1511 *uid=(uid_t)(pw->pw_uid);
1512 else
1513 syslog(LOG_ERR,"Warning: Could not get passwd entry for '%s'",user);
1514 endpwent();
1515 }
1516
1517 /* else we were passed the UID */
1518 else
1519 *uid=(uid_t)atoi(user);
1520
1521 }
1522 else
1523 *uid=geteuid();
1524
1525 return OK;
1526 }
1527
1528
1529
1530 /* get group information */
get_group_info(const char * group,gid_t * gid)1531 static int get_group_info(const char *group, gid_t *gid){
1532 const struct group *grp=NULL;
1533
1534 /* get group ID */
1535 if(group!=NULL){
1536 /* see if this is a group name */
1537 if(strspn(group,"0123456789")<strlen(group)){
1538 grp=(struct group *)getgrnam(group);
1539 if(grp!=NULL)
1540 *gid=(gid_t)(grp->gr_gid);
1541 else
1542 syslog(LOG_ERR,"Warning: Could not get group entry for '%s'",group);
1543 endgrent();
1544 }
1545
1546 /* else we were passed the GID */
1547 else
1548 *gid=(gid_t)atoi(group);
1549 }
1550 else
1551 *gid=getegid();
1552
1553 return OK;
1554 }
1555
1556
1557
1558 /* drops privileges */
drop_privileges(const char * user,uid_t uid,gid_t gid)1559 static int drop_privileges(const char *user, uid_t uid, gid_t gid){
1560 struct group *grp;
1561 struct passwd *pw;
1562
1563 /* only drop privileges if we're running as root, so we don't interfere with being debugged while running as some random user */
1564 if(getuid()!=0)
1565 return OK;
1566
1567 /* set effective group ID if other than current EGID */
1568 if(gid!=getegid()){
1569 if(setgid(gid)==-1){
1570 syslog(LOG_ERR,"Warning: Could not set effective GID=%d",(int)gid);
1571 return ERROR;
1572 }
1573 }
1574
1575 #ifdef HAVE_INITGROUPS
1576 if(uid!=geteuid()){
1577 /* initialize supplementary groups */
1578 if(initgroups(user,gid)==-1){
1579 if(errno==EPERM)
1580 syslog(LOG_ERR,"Warning: Unable to change supplementary groups using initgroups()");
1581 else{
1582 syslog(LOG_ERR,"Warning: Possibly root user failed dropping privileges with initgroups()");
1583 return ERROR;
1584 }
1585 }
1586 }
1587 #endif
1588
1589 if(setuid(uid)==-1){
1590 syslog(LOG_ERR,"Warning: Could not set effective UID=%d",(int)uid);
1591 return ERROR;
1592 }
1593
1594 return OK;
1595 }
1596
1597
1598
1599 /* perform the chroot() operation if configured to do so */
do_chroot(void)1600 void do_chroot(void){
1601 int retval=0;
1602 const char *err=NULL;
1603
1604 if(nsca_chroot!=NULL){
1605 retval=chdir(nsca_chroot);
1606 if(retval!=0){
1607 err=strerror(errno);
1608 syslog(LOG_ERR, "can not chdir into chroot directory: %s", err);
1609 do_exit(STATE_UNKNOWN);
1610 }
1611 retval=chroot(".");
1612 if(retval!=0){
1613 err=strerror(errno);
1614 syslog(LOG_ERR, "can not chroot: %s", err);
1615 do_exit(STATE_UNKNOWN);
1616 }
1617 }
1618 }
1619
1620
1621
1622 /* handle signals */
sighandler(int sig)1623 void sighandler(int sig){
1624 static char *sigs[]={"EXIT","HUP","INT","QUIT","ILL","TRAP","ABRT","BUS","FPE","KILL","USR1","SEGV","USR2","PIPE","ALRM","TERM","STKFLT","CHLD","CONT","STOP","TSTP","TTIN","TTOU","URG","XCPU","XFSZ","VTALRM","PROF","WINCH","IO","PWR","UNUSED","ZERR","DEBUG",(char *)NULL};
1625 int i;
1626 char temp_buffer[MAX_INPUT_BUFFER];
1627
1628 if(sig<0)
1629 sig=-sig;
1630
1631 for(i=0;sigs[i]!=(char *)NULL;i++);
1632
1633 sig%=i;
1634
1635 /* we received a SIGHUP, so restart... */
1636 if(sig==SIGHUP){
1637
1638 sigrestart=TRUE;
1639
1640 syslog(LOG_NOTICE,"Caught SIGHUP - restarting...\n");
1641 }
1642
1643 /* else begin shutting down... */
1644 if(sig==SIGTERM){
1645
1646 /* if shutdown is already true, we're in a signal trap loop! */
1647 if(sigshutdown==TRUE)
1648 exit(STATE_CRITICAL);
1649
1650 sigshutdown=TRUE;
1651
1652 syslog(LOG_NOTICE,"Caught SIG%s - shutting down...\n",sigs[sig]);
1653 }
1654
1655 return;
1656 }
1657
1658