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(&current_time);
1260         fprintf(checkresult_file_fp,"### NSCA Passive Check Result ###\n");
1261         fprintf(checkresult_file_fp,"# Time: %s",ctime(&current_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