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