1 /**
2  * @file ndo2db.c Nagios Data Output to Database Daemon
3  */
4 /*
5  * Copyright 2009-2014 Nagios Core Development Team and Community Contributors
6  * Copyright 2005-2009 Ethan Galstad
7  *
8  * First Written: 05-19-2005
9  * Last Modified: 2017-04-13
10  *
11  * This file is part of NDOUtils.
12  *
13  * NDOUtils is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2 as
15  * published by the Free Software Foundation.
16  *
17  * NDOUtils is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with NDOUtils. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 /*#define DEBUG_MEMORY 1*/
27 
28 #ifdef DEBUG_MEMORY
29 #include <mcheck.h>
30 #endif
31 
32 /* include our project's header files */
33 #include "../include/config.h"
34 #include "../include/common.h"
35 #include "../include/io.h"
36 #include "../include/utils.h"
37 #include "../include/protoapi.h"
38 #include "../include/ndo2db.h"
39 #include "../include/db.h"
40 #include "../include/dbhandlers.h"
41 #include "../include/queue.h"
42 
43 #ifdef HAVE_SYSTEMD
44 #include <systemd/sd-daemon.h>
45 #endif
46 
47 #ifdef HAVE_SSL
48 #include "../include/dh.h"
49 #endif
50 
51 #include <pthread.h>
52 
53 #define NDO2DB_VERSION "2.1.3"
54 #define NDO2DB_NAME "NDO2DB"
55 #define NDO2DB_DATE "2017-04-13"
56 
57 #ifdef HAVE_SSL
58 # if (defined(__sun) && defined(SOLARIS_10)) || defined(_AIX) || defined(__hpux)
59 SSL_METHOD *meth;
60 # else
61 const SSL_METHOD *meth;
62 # endif
63 SSL_CTX *ctx;
64 int allow_weak_random_seed = NDO_FALSE;
65 #endif
66 extern int use_ssl;
67 
68 extern int errno;
69 
70 char *ndo2db_config_file=NULL;
71 char *lock_file=NULL;
72 char *ndo2db_user=NULL;
73 char *ndo2db_group=NULL;
74 int ndo2db_sd=0;
75 int ndo2db_socket_type=NDO_SINK_UNIXSOCKET;
76 char *ndo2db_socket_name=NULL;
77 int ndo2db_tcp_port=NDO_DEFAULT_TCP_PORT;
78 int ndo2db_use_inetd=NDO_FALSE;
79 int ndo2db_no_fork=NDO_FALSE;
80 int ndo2db_show_version=NDO_FALSE;
81 int ndo2db_show_license=NDO_FALSE;
82 int ndo2db_show_help=NDO_FALSE;
83 
84 ndo2db_dbconfig ndo2db_db_settings;
85 time_t ndo2db_db_last_checkin_time=0L;
86 
87 char *ndo2db_debug_file=NULL;
88 int ndo2db_debug_level=NDO2DB_DEBUGL_NONE;
89 int ndo2db_debug_verbosity=NDO2DB_DEBUGV_BASIC;
90 FILE *ndo2db_debug_file_fp=NULL;
91 unsigned long ndo2db_max_debug_file_size=0L;
92 unsigned long ndo2db_max_output_buffer_size=65536;
93 
94 extern char *ndo2db_db_tablenames[NDO2DB_MAX_DBTABLES];
95 
96 
97 
98 /*#define DEBUG_NDO2DB 1*/                        /* don't daemonize */
99 /*#define DEBUG_NDO2DB_EXIT_AFTER_CONNECTION 1*/    /* exit after first client disconnects */
100 /*#define DEBUG_NDO2DB2 1*/
101 /*#define NDO2DB_DEBUG_MBUF 1*/
102 /*
103 #ifdef NDO2DB_DEBUG_MBUF
104 unsigned long mbuf_bytes_allocated=0L;
105 unsigned long mbuf_data_allocated=0L;
106 #endif
107 */
108 
109 
main(int argc,char ** argv)110 int main(int argc, char **argv){
111 	int db_supported=NDO_FALSE;
112 	int result=NDO_OK;
113 
114 #ifdef DEBUG_MEMORY
115 	mtrace();
116 #endif
117 
118 #ifdef HAVE_SSL
119 	DH *dh;
120 	char seedfile[FILENAME_MAX];
121 	int i,c;
122 #endif
123 
124 	result=ndo2db_process_arguments(argc,argv);
125 
126         if(result!=NDO_OK || ndo2db_show_help==NDO_TRUE || ndo2db_show_license==NDO_TRUE || ndo2db_show_version==NDO_TRUE){
127 
128 		if(result!=NDO_OK)
129 			printf("Incorrect command line arguments supplied\n");
130 
131 		printf("\n");
132 		printf("%s %s\n",NDO2DB_NAME,NDO2DB_VERSION);
133 		printf("Copyright (c) 2009 Nagios Core Development Team and Community Contributors\n");
134 		printf("Copyright (c) 2005-2008 Ethan Galstad\n");
135 		printf("Last Modified: %s\n",NDO2DB_DATE);
136 		printf("License: GPL v2\n");
137 #ifdef HAVE_SSL
138 		printf("SSL/TLS Available: Anonymous DH Mode, OpenSSL 0.9.6 or higher required\n");
139 #endif
140 		printf("\n");
141 		printf("Stores Nagios event and configuration data to a database for later retrieval\n");
142 		printf("and processing.  Clients that are capable of sending data to the NDO2DB daemon\n");
143 		printf("include the LOG2NDO utility and NDOMOD event broker module.\n");
144 		printf("\n");
145 		printf("Usage: %s -c <config_file> [-i] [-f]\n",argv[0]);
146 		printf("\n");
147 		printf("-i  = Run under INETD/XINETD.\n");
148 		printf("-f  = Do not fork daemon.\n");
149 		printf("\n");
150 		exit(1);
151 	        }
152 
153 	/* initialize variables */
154 	ndo2db_initialize_variables();
155 
156 	/* process config file */
157 	if(ndo2db_process_config_file(ndo2db_config_file)!=NDO_OK){
158 		printf("Error processing config file '%s'.\n",ndo2db_config_file);
159 		exit(1);
160 	        }
161 
162 #ifdef HAVE_SSL
163         /* initialize SSL */
164         if(use_ssl==NDO_TRUE){
165         	SSL_library_init();
166         	SSLeay_add_ssl_algorithms();
167         	meth=SSLv23_server_method();
168         	SSL_load_error_strings();
169 
170         	/* use week random seed if necessary */
171         	if(allow_weak_random_seed && (RAND_status()==0)){
172 
173         		if(RAND_file_name(seedfile,sizeof(seedfile)-1))
174         			if(RAND_load_file(seedfile,-1))
175         				RAND_write_file(seedfile);
176 
177         		if(RAND_status()==0){
178         			syslog(LOG_ERR,"Warning: SSL/TLS uses a weak random seed which is highly discouraged");
179         			srand(time(NULL));
180         			for(i=0;i<500 && RAND_status()==0;i++){
181         				for(c=0;c<sizeof(seedfile);c+=sizeof(int)){
182         					*((int *)(seedfile+c))=rand();
183         					}
184         				RAND_seed(seedfile,sizeof(seedfile));
185         				}
186         			}
187         		}
188         	if((ctx=SSL_CTX_new(meth))==NULL){
189         		syslog(LOG_ERR,"Error: could not create SSL context.\n");
190         		exit(1);
191         		}
192 
193         	/* ADDED 01/19/2004 */
194         	/* use only TLSv1 protocol */
195         	SSL_CTX_set_options(ctx,SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
196 
197         	/* use anonymous DH ciphers */
198         	SSL_CTX_set_cipher_list(ctx,"ADH");
199 			dh=get_dh2048();
200         	SSL_CTX_set_tmp_dh(ctx,dh);
201         	DH_free(dh);
202         	syslog(LOG_INFO,"INFO: SSL/TLS initialized. All network traffic will be encrypted.");
203         	}
204         else{
205         	syslog(LOG_INFO,"INFO: SSL/TLS NOT initialized. Network encryption DISABLED.");
206         	}
207         /*Fin Hack SSL*/
208 #endif
209 
210 	/* make sure we're good to go */
211 	if(ndo2db_check_init_reqs()!=NDO_OK){
212 		printf("One or more required parameters is missing or incorrect.\n");
213 		exit(1);
214 	        }
215 
216 	/* make sure we support the db option chosen... */
217 #ifdef USE_MYSQL
218 	if(ndo2db_db_settings.server_type==NDO2DB_DBSERVER_MYSQL)
219 		db_supported=NDO_TRUE;
220 #endif
221 
222 	if (!db_supported) {
223 		printf("Support for the specified database server is either not yet supported, or was not found on your system.\n");
224 
225 #ifdef HAVE_SSL
226 		if(use_ssl==NDO_TRUE)
227 			SSL_CTX_free(ctx);
228 #endif
229 
230 		exit(1);
231 		}
232 
233 	/* initialize signal handling */
234 	signal(SIGQUIT,ndo2db_parent_sighandler);
235 	signal(SIGTERM,ndo2db_parent_sighandler);
236 	signal(SIGINT,ndo2db_parent_sighandler);
237 	signal(SIGSEGV,ndo2db_parent_sighandler);
238 	signal(SIGFPE,ndo2db_parent_sighandler);
239 	signal(SIGCHLD,ndo2db_parent_sighandler);
240 
241 	/* drop privileges */
242 	ndo2db_drop_privileges(ndo2db_user,ndo2db_group);
243 
244 	/* open debug log */
245 	ndo2db_open_debug_log();
246 
247 	/* if we're running under inetd... */
248 	if(ndo2db_use_inetd==NDO_TRUE){
249 
250 		/* redirect STDERR to /dev/null */
251 		close(2);
252 		open("/dev/null",O_WRONLY);
253 
254 		/* handle the connection */
255 		ndo2db_handle_client_connection(0);
256 	        }
257 
258 	/* standalone daemon... */
259 	else{
260 
261 		/* create socket and wait for clients to connect */
262 		if(ndo2db_wait_for_connections()==NDO_ERROR)
263 			return 1;
264 	        }
265 
266 	/* close debug log */
267 	ndo2db_close_debug_log();
268 
269 	/* free memory */
270 	ndo2db_free_program_memory();
271 
272 #ifdef HAVE_SSL
273 	if(use_ssl==NDO_TRUE)
274 		SSL_CTX_free(ctx);
275 #endif
276 
277 	return 0;
278 }
279 
280 
281 /* process command line arguments */
ndo2db_process_arguments(int argc,char ** argv)282 int ndo2db_process_arguments(int argc, char **argv){
283 	char optchars[32];
284 	int c=1;
285 
286 #ifdef HAVE_GETOPT_H
287 	int option_index=0;
288 	static struct option long_options[]={
289 		{"configfile", required_argument, 0, 'c'},
290 		{"inetd", no_argument, 0, 'i'},
291 		{"no-forking", no_argument, 0, 'f'},
292 		{"help", no_argument, 0, 'h'},
293 		{"license", no_argument, 0, 'l'},
294 		{"version", no_argument, 0, 'V'},
295 		{0, 0, 0, 0}
296                 };
297 #endif
298 
299 	/* no options were supplied */
300 	if(argc<2){
301 		ndo2db_show_help=NDO_TRUE;
302 		return NDO_OK;
303 	        }
304 
305 	snprintf(optchars,sizeof(optchars),"c:ifhlV");
306 
307 	while(1){
308 #ifdef HAVE_GETOPT_H
309 		c=getopt_long(argc,argv,optchars,long_options,&option_index);
310 #else
311 		c=getopt(argc,argv,optchars);
312 #endif
313 		if(c==-1 || c==EOF)
314 			break;
315 
316 		/* process all arguments */
317 		switch(c){
318 
319 		case '?':
320 		case 'h':
321 			ndo2db_show_help=NDO_TRUE;
322 			break;
323 		case 'V':
324 			ndo2db_show_version=NDO_TRUE;
325 			break;
326 		case 'l':
327 			ndo2db_show_license=NDO_TRUE;
328 			break;
329 		case 'c':
330 			ndo2db_config_file=strdup(optarg);
331 			break;
332 		case 'i':
333 			ndo2db_use_inetd=NDO_TRUE;
334 			break;
335 		case 'f':
336 			ndo2db_use_inetd=NDO_FALSE;
337 			ndo2db_no_fork=NDO_TRUE;
338 			break;
339 		default:
340 			return NDO_ERROR;
341 			break;
342 		        }
343 	        }
344 
345 	/* make sure required args were supplied */
346 	if((ndo2db_config_file==NULL) && ndo2db_show_help==NDO_FALSE && ndo2db_show_version==NDO_FALSE  && ndo2db_show_license==NDO_FALSE)
347 		return NDO_ERROR;
348 
349 	return NDO_OK;
350         }
351 
352 
353 
354 /****************************************************************************/
355 /* CONFIG FUNCTIONS                                                         */
356 /****************************************************************************/
357 
358 /* process all config vars in a file */
ndo2db_process_config_file(char * filename)359 int ndo2db_process_config_file(char *filename){
360 	ndo_mmapfile *thefile=NULL;
361 	char *buf=NULL;
362 	int result=NDO_OK;
363 
364 	/* open the file */
365 	if((thefile=ndo_mmap_fopen(filename))==NULL)
366 		return NDO_ERROR;
367 
368 	/* process each line of the file */
369 	while((buf=ndo_mmap_fgets(thefile))){
370 
371 		/* skip comments */
372 		if(buf[0]=='#'){
373 			free(buf);
374 			continue;
375 		        }
376 
377 		/* skip blank lines */
378 		if(!strcmp(buf,"")){
379 			free(buf);
380 			continue;
381 		        }
382 
383 		/* process the variable */
384 		result=ndo2db_process_config_var(buf);
385 
386 		/* free memory */
387 		free(buf);
388 
389 		if(result!=NDO_OK)
390 			break;
391 	        }
392 
393 	/* close the file */
394 	ndo_mmap_fclose(thefile);
395 
396 	return result;
397         }
398 
399 
400 /* process a single module config variable */
ndo2db_process_config_var(char * arg)401 int ndo2db_process_config_var(char *arg){
402 	char *var=NULL;
403 	char *val=NULL;
404 
405 	/* split var/val */
406 	var=strtok(arg,"=");
407 	val=strtok(NULL,"\n");
408 
409 	/* skip incomplete var/val pairs */
410 	if(var==NULL || val==NULL)
411 		return NDO_OK;
412 
413 	/* process the variable... */
414 
415 	if(!strcmp(var,"lock_file")){
416 		if((lock_file=strdup(val))==NULL)
417 			return NDO_ERROR;
418 	        }
419 	else if(!strcmp(var,"socket_type")){
420 		if(!strcmp(val,"tcp"))
421 			ndo2db_socket_type=NDO_SINK_TCPSOCKET;
422 		else
423 			ndo2db_socket_type=NDO_SINK_UNIXSOCKET;
424 	        }
425 	else if(!strcmp(var,"socket_name")){
426 		if((ndo2db_socket_name=strdup(val))==NULL)
427 			return NDO_ERROR;
428 	        }
429 	else if(!strcmp(var,"tcp_port")){
430 		ndo2db_tcp_port=atoi(val);
431 	        }
432 	else if(!strcmp(var,"db_servertype")){
433 		if(!strcmp(val,"mysql"))
434 			ndo2db_db_settings.server_type=NDO2DB_DBSERVER_MYSQL;
435 		else
436 			return NDO_ERROR;
437 	        }
438 	else if(!strcmp(var,"db_host")){
439 		if((ndo2db_db_settings.host=strdup(val))==NULL)
440 			return NDO_ERROR;
441 	        }
442 	else if(!strcmp(var,"db_port")){
443 		ndo2db_db_settings.port=atoi(val);
444 	        }
445 	else if (!strcmp(var, "db_socket")) {
446 		if(!(ndo2db_db_settings.socket = strdup(val)))
447 			return NDO_ERROR;
448 	        }
449 	else if(!strcmp(var,"db_user")){
450 		if((ndo2db_db_settings.username=strdup(val))==NULL)
451 			return NDO_ERROR;
452 	        }
453 	else if(!strcmp(var,"db_pass")){
454 		if((ndo2db_db_settings.password=strdup(val))==NULL)
455 			return NDO_ERROR;
456 	        }
457 	else if(!strcmp(var,"db_name")){
458 		if((ndo2db_db_settings.dbname=strdup(val))==NULL)
459 			return NDO_ERROR;
460 	        }
461 	else if(!strcmp(var,"db_prefix")){
462 		if((ndo2db_db_settings.dbprefix=strdup(val))==NULL)
463 			return NDO_ERROR;
464 	        }
465 
466 	else if(!strcmp(var,"max_timedevents_age"))
467 		ndo2db_db_settings.max_timedevents_age=strtoul(val,NULL,0)*60;
468 
469 	else if(!strcmp(var,"max_systemcommands_age"))
470 		ndo2db_db_settings.max_systemcommands_age=strtoul(val,NULL,0)*60;
471 
472 	else if(!strcmp(var,"max_servicechecks_age"))
473 		ndo2db_db_settings.max_servicechecks_age=strtoul(val,NULL,0)*60;
474 
475 	else if(!strcmp(var,"max_hostchecks_age"))
476 		ndo2db_db_settings.max_hostchecks_age=strtoul(val,NULL,0)*60;
477 
478 	else if(!strcmp(var,"max_eventhandlers_age"))
479 		ndo2db_db_settings.max_eventhandlers_age=strtoul(val,NULL,0)*60;
480 
481 	else if(!strcmp(var,"max_externalcommands_age"))
482 		ndo2db_db_settings.max_externalcommands_age=strtoul(val,NULL,0)*60;
483 
484 	else if(!strcmp(var,"max_logentries_age"))
485 		ndo2db_db_settings.max_logentries_age=strtoul(val,NULL,0)*60;
486 
487 	else if(!strcmp(var,"max_notifications_age"))
488 		ndo2db_db_settings.max_notifications_age=strtoul(val,NULL,0)*60;
489 
490 	else if(!strcmp(var,"max_contactnotifications") || !strcmp(var,"max_contactnotifications_age"))
491 		/* Accept max_contactnotifications too (a typo in old configs). */
492 		ndo2db_db_settings.max_contactnotifications_age=strtoul(val,NULL,0)*60;
493 
494 	else if(!strcmp(var,"max_contactnotificationmethods") || !strcmp(var,"max_contactnotificationmethods_age"))
495 		/* Accept max_contactnotificationmethods too (a typo in old configs). */
496 		ndo2db_db_settings.max_contactnotificationmethods_age=strtoul(val,NULL,0)*60;
497 
498 	else if(!strcmp(var,"max_acknowledgements_age"))
499 		ndo2db_db_settings.max_acknowledgements_age=strtoul(val,NULL,0)*60;
500 
501 	else if(!strcmp(var,"ndo2db_user"))
502 		ndo2db_user=strdup(val);
503 	else if(!strcmp(var,"ndo2db_group"))
504 		ndo2db_group=strdup(val);
505 
506 	else if(!strcmp(var,"debug_file")){
507 		if((ndo2db_debug_file=strdup(val))==NULL)
508 			return NDO_ERROR;
509 	        }
510 	else if(!strcmp(var,"debug_level"))
511 		ndo2db_debug_level=atoi(val);
512 	else if(!strcmp(var,"debug_verbosity"))
513 		ndo2db_debug_verbosity=atoi(val);
514 	else if(!strcmp(var,"max_debug_file_size"))
515 		ndo2db_max_debug_file_size=strtoul(val,NULL,0);
516 	else if(!strcmp(var, "max_output_buffer_size"))
517 		ndo2db_max_output_buffer_size=strtoul(val,NULL,0);
518 	else if(!strcmp(var,"use_ssl")){
519 		if (strlen(val) == 1) {
520 			if (isdigit((int)val[strlen(val)-1]) != NDO_FALSE)
521 				use_ssl = atoi(val);
522 			else
523 				use_ssl = 0;
524 		}
525 	}
526 
527 	return NDO_OK;
528         }
529 
530 
531 /* initialize variables */
ndo2db_initialize_variables(void)532 int ndo2db_initialize_variables(void){
533 
534 	ndo2db_db_settings.server_type=NDO2DB_DBSERVER_NONE;
535 	ndo2db_db_settings.host=NULL;
536 	ndo2db_db_settings.port=0;
537 	ndo2db_db_settings.socket = NULL;
538 	ndo2db_db_settings.username=NULL;
539 	ndo2db_db_settings.password=NULL;
540 	ndo2db_db_settings.dbname=NULL;
541 	ndo2db_db_settings.dbprefix=NULL;
542 	ndo2db_db_settings.max_timedevents_age=0L;
543 	ndo2db_db_settings.max_systemcommands_age=0L;
544 	ndo2db_db_settings.max_servicechecks_age=0L;
545 	ndo2db_db_settings.max_hostchecks_age=0L;
546 	ndo2db_db_settings.max_eventhandlers_age=0L;
547 	ndo2db_db_settings.max_externalcommands_age=0L;
548 	ndo2db_db_settings.max_notifications_age=0L;
549 	ndo2db_db_settings.max_contactnotifications_age=0L;
550 	ndo2db_db_settings.max_contactnotificationmethods_age=0L;
551 	ndo2db_db_settings.max_logentries_age=0L;
552 	ndo2db_db_settings.max_acknowledgements_age=0L;
553 
554 	return NDO_OK;
555         }
556 
557 
558 
559 /****************************************************************************/
560 /* CLEANUP FUNCTIONS                                                       */
561 /****************************************************************************/
562 
563 /* free program memory */
ndo2db_free_program_memory(void)564 int ndo2db_free_program_memory(void){
565 
566 	if(ndo2db_config_file){
567 		free(ndo2db_config_file);
568 		ndo2db_config_file=NULL;
569 		}
570 	if(ndo2db_user){
571 		free(ndo2db_user);
572 		ndo2db_user=NULL;
573 		}
574 	if(ndo2db_group){
575 		free(ndo2db_group);
576 		ndo2db_group=NULL;
577 		}
578 	if(ndo2db_socket_name){
579 		free(ndo2db_socket_name);
580 		ndo2db_socket_name=NULL;
581 		}
582 	if(ndo2db_db_settings.host){
583 		free(ndo2db_db_settings.host);
584 		ndo2db_db_settings.host=NULL;
585 		}
586 	if(ndo2db_db_settings.socket){
587 		free(ndo2db_db_settings.socket);
588 		ndo2db_db_settings.socket=NULL;
589 		}
590 	if(ndo2db_db_settings.username){
591 		free(ndo2db_db_settings.username);
592 		ndo2db_db_settings.username=NULL;
593 		}
594 	if(ndo2db_db_settings.password){
595 		free(ndo2db_db_settings.password);
596 		ndo2db_db_settings.password=NULL;
597 		}
598 	if(ndo2db_db_settings.dbname){
599 		free(ndo2db_db_settings.dbname);
600 		ndo2db_db_settings.dbname=NULL;
601 		}
602 	if(ndo2db_db_settings.dbprefix){
603 		free(ndo2db_db_settings.dbprefix);
604 		ndo2db_db_settings.dbprefix=NULL;
605 		}
606 	if(ndo2db_debug_file){
607 		free(ndo2db_debug_file);
608 		ndo2db_debug_file=NULL;
609 		}
610 
611 	return NDO_OK;
612 	}
613 
614 
615 
616 /****************************************************************************/
617 /* UTILITY FUNCTIONS                                                        */
618 /****************************************************************************/
619 
ndo2db_check_init_reqs(void)620 int ndo2db_check_init_reqs(void){
621 
622 	if(ndo2db_socket_type==NDO_SINK_UNIXSOCKET){
623 		if(ndo2db_socket_name==NULL){
624 			printf("No socket name specified.\n");
625 			return NDO_ERROR;
626 		        }
627 	        }
628 
629 	return NDO_OK;
630         }
631 
632 
633 
634 /* drops privileges */
ndo2db_drop_privileges(char * user,char * group)635 int ndo2db_drop_privileges(char *user, char *group){
636 	uid_t uid=-1;
637 	gid_t gid=-1;
638 	struct group *grp;
639 	struct passwd *pw;
640 
641 	/* set effective group ID */
642 	if(group!=NULL){
643 
644 		/* see if this is a group name */
645 		if(strspn(group,"0123456789")<strlen(group)){
646 			grp=(struct group *)getgrnam(group);
647 			if(grp!=NULL)
648 				gid=(gid_t)(grp->gr_gid);
649 			else
650 				syslog(LOG_ERR,"Warning: Could not get group entry for '%s'",group);
651 			endgrent();
652 		        }
653 
654 		/* else we were passed the GID */
655 		else
656 			gid=(gid_t)atoi(group);
657 
658 		/* set effective group ID if other than current EGID */
659 		if(gid!=getegid()){
660 
661 			if(setgid(gid)==-1)
662 				syslog(LOG_ERR,"Warning: Could not set effective GID=%d",(int)gid);
663 		        }
664 	        }
665 
666 
667 	/* set effective user ID */
668 	if(user!=NULL){
669 
670 		/* see if this is a user name */
671 		if(strspn(user,"0123456789")<strlen(user)){
672 			pw=(struct passwd *)getpwnam(user);
673 			if(pw!=NULL)
674 				uid=(uid_t)(pw->pw_uid);
675 			else
676 				syslog(LOG_ERR,"Warning: Could not get passwd entry for '%s'",user);
677 			endpwent();
678 		        }
679 
680 		/* else we were passed the UID */
681 		else
682 			uid=(uid_t)atoi(user);
683 
684 		/* set effective user ID if other than current EUID */
685 		if(uid!=geteuid()){
686 
687 #ifdef HAVE_INITGROUPS
688 			/* initialize supplementary groups */
689 			if(initgroups(user,gid)==-1){
690 				if(errno==EPERM)
691 					syslog(LOG_ERR,"Warning: Unable to change supplementary groups using initgroups()");
692 				else{
693 					syslog(LOG_ERR,"Warning: Possibly root user failed dropping privileges with initgroups()");
694 					return NDO_ERROR;
695 			                }
696 	                        }
697 #endif
698 
699 			if(setuid(uid)==-1)
700 				syslog(LOG_ERR,"Warning: Could not set effective UID=%d",(int)uid);
701 		        }
702 	        }
703 
704 	return NDO_OK;
705         }
706 
707 
ndo2db_daemonize(void)708 int ndo2db_daemonize(void){
709 	pid_t pid=-1;
710 	int lockfile=0;
711 	struct flock lock;
712 	int val=0;
713 	char buf[256];
714 	char *msg=NULL;
715 
716 	umask(S_IWGRP|S_IWOTH);
717 
718 	/* get a lock on the lockfile */
719 	if(lock_file){
720 		lockfile=open(lock_file,O_RDWR | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
721 		if(lockfile<0){
722 			asprintf(&msg,"Failed to obtain lock on file %s: %s\n", lock_file, strerror(errno));
723 			perror(msg);
724 			ndo2db_cleanup_socket();
725 			return NDO_ERROR;
726 			}
727 
728 		/* see if we can read the contents of the lockfile */
729 		if((val=read(lockfile,buf,(size_t)10))<0){
730 			asprintf(&msg,"Lockfile exists but cannot be read");
731 			perror(msg);
732 			ndo2db_cleanup_socket();
733 			return NDO_ERROR;
734 			}
735 
736 		/* place a file lock on the lock file */
737 		lock.l_type=F_WRLCK;
738 		lock.l_start=0;
739 		lock.l_whence=SEEK_SET;
740 		lock.l_len=0;
741 		if(fcntl(lockfile,F_SETLK,&lock)<0){
742 			if(errno==EACCES || errno==EAGAIN){
743 				fcntl(lockfile,F_GETLK,&lock);
744 				asprintf(&msg,"Lockfile '%s' looks like its already held by another instance (%d).  Bailing out...",lock_file,(int)lock.l_pid);
745 				}
746 			else
747 				asprintf(&msg,"Cannot lock lockfile '%s': %s. Bailing out...",lock_file,strerror(errno));
748 
749 			perror(msg);
750 			ndo2db_cleanup_socket();
751 			return NDO_ERROR;
752 			}
753 		}
754 
755 	/* fork (maybe) */
756 	if(ndo2db_no_fork != NDO_TRUE) {
757 
758 		if((pid=fork())<0){
759 			perror("Fork error");
760 			ndo2db_cleanup_socket();
761 			return NDO_ERROR;
762 				}
763 
764 		/* parent process goes away... */
765 		else if((int)pid!=0){
766 			ndo2db_free_program_memory();
767 			waitpid(pid, NULL, 0);		/* Wait for the updated lock file. */
768 			exit(0);
769 			}
770 
771 		/* child forks again... */
772 		else{
773 
774 			if((pid=fork())<0){
775 				perror("Fork error");
776 				ndo2db_cleanup_socket();
777 				return NDO_ERROR;
778 						}
779 
780 			/* first child process goes away.. */
781 			else if((int)pid!=0){
782 				ndo2db_free_program_memory();
783 				exit(0);
784 			}
785 		}
786 
787 
788 
789 
790 	}
791 
792 	/* Write the PID to the lock file... */
793 
794 	if (lock_file) {
795 		int n;
796 		lseek(lockfile, 0, SEEK_SET);
797 		if (ftruncate(lockfile, 0)) {
798 			syslog(LOG_ERR, "Warning: Unable to truncate lockfile (errno %d): %s",
799 					errno, strerror(errno));
800 		}
801 		sprintf(buf, "%d\n", (int)getpid());
802 		n = (int)strlen(buf);
803 		if (write(lockfile, buf, n) < n) {
804 			syslog(LOG_ERR, "Warning: Unable to write pid to lockfile (errno %d): %s",
805 					errno, strerror(errno));
806 		}
807 	}
808 
809 	/* become session leader... */
810 	setsid();
811 
812 	if(lock_file) {
813 		/* make sure lock file stays open while program is executing... */
814 		val=fcntl(lockfile,F_GETFD,0);
815 		val|=FD_CLOEXEC;
816 		fcntl(lockfile,F_SETFD,val);
817 	}
818 
819         /* close existing stdin, stdout, stderr */
820 	close(0);
821 #ifndef DEBUG_NDO2DB
822 	close(1);
823 #endif
824 	close(2);
825 
826 	/* re-open stdin, stdout, stderr with known values */
827 	open("/dev/null",O_RDONLY);
828 #ifndef DEBUG_NDO2DB
829 	open("/dev/null",O_WRONLY);
830 #endif
831 	open("/dev/null",O_WRONLY);
832 
833 	return NDO_OK;
834         }
835 
836 
ndo2db_cleanup_socket(void)837 int ndo2db_cleanup_socket(void){
838 
839 	/* we're running under INETD */
840 	if(ndo2db_use_inetd==NDO_TRUE)
841 		return NDO_OK;
842 
843 	/* close the socket */
844 	shutdown(ndo2db_sd,2);
845 	close(ndo2db_sd);
846 
847 	/* unlink the file */
848 	if(ndo2db_socket_type==NDO_SINK_UNIXSOCKET)
849 		unlink(ndo2db_socket_name);
850 
851 	if(lock_file)
852 		unlink(lock_file);
853 
854 	return NDO_OK;
855         }
856 
857 
ndo2db_parent_sighandler(int sig)858 void ndo2db_parent_sighandler(int sig){
859 
860 	switch (sig){
861 	case SIGTERM:
862 	case SIGINT:
863 		/* forward signal to all members of this group of processes */
864 		kill(0, sig);
865 		break;
866 	case SIGCHLD:
867 		/* cleanup children that exit, so we don't have zombies */
868 		while(waitpid(-1,NULL,WNOHANG)>0);
869 		return;
870 	default:
871 		printf("Caught the Signal '%d' but don't care about this.\n", sig);
872 	}
873 
874 	/* cleanup the socket */
875 	ndo2db_cleanup_socket();
876 
877 	/* free memory */
878 	ndo2db_free_program_memory();
879 
880 	exit(0);
881 
882 	return;
883         }
884 
885 
ndo2db_child_sighandler(int sig)886 void ndo2db_child_sighandler(int sig){
887 
888 	_exit(0);
889 
890 	return;
891         }
892 
893 
894 /****************************************************************************/
895 /* UTILITY FUNCTIONS                                                        */
896 /****************************************************************************/
897 
898 
ndo2db_wait_for_connections(void)899 int ndo2db_wait_for_connections(void){
900 	int sd_flag=1;
901 	int new_sd=0;
902 	pid_t new_pid=-1;
903 	struct sockaddr_un server_address_u;
904 	struct sockaddr_in server_address_i;
905 	struct sockaddr_un client_address_u;
906 	struct sockaddr_in client_address_i;
907 	socklen_t client_address_length;
908 	static int listen_backlog = INT_MAX;
909 
910 
911 #ifdef HAVE_SYSTEMD
912 	/* Socket inherited from systemd */
913 	if (sd_listen_fds(0) == 1) {
914 		ndo2db_sd = SD_LISTEN_FDS_START + 0;
915 		if (sd_is_socket_inet(ndo2db_sd, 0, 0, -1, 0))
916 			client_address_length = (socklen_t)sizeof(client_address_i);
917 		else
918 			client_address_length = (socklen_t)sizeof(client_address_u);
919 	}
920 	else
921 #endif
922 
923 	/* TCP socket */
924 	if(ndo2db_socket_type==NDO_SINK_TCPSOCKET){
925 
926 		/* create a socket */
927 		if(!(ndo2db_sd=socket(PF_INET,SOCK_STREAM,0))){
928 			perror("Cannot create socket");
929 			return NDO_ERROR;
930 		        }
931 
932 		/* set the reuse address flag so we don't get errors when restarting */
933 		sd_flag=1;
934 		if(setsockopt(ndo2db_sd,SOL_SOCKET,SO_REUSEADDR,(char *)&sd_flag,sizeof(sd_flag))<0){
935 			printf("Could not set reuse address option on socket!\n");
936 			return NDO_ERROR;
937 	                }
938 
939 		/* clear the address */
940 		bzero((char *)&server_address_i,sizeof(server_address_i));
941 		server_address_i.sin_family=AF_INET;
942 		server_address_i.sin_addr.s_addr=INADDR_ANY;
943 		server_address_i.sin_port=htons(ndo2db_tcp_port);
944 
945 		/* bind the socket */
946 		if((bind(ndo2db_sd,(struct sockaddr *)&server_address_i,sizeof(server_address_i)))){
947 			close(ndo2db_sd);
948 			perror("Could not bind socket");
949 			return NDO_ERROR;
950 	                }
951 
952 		client_address_length=(socklen_t)sizeof(client_address_i);
953 	        }
954 
955 	/* UNIX domain socket */
956 	else{
957 
958 		/* create a socket */
959 		if(!(ndo2db_sd=socket(AF_UNIX,SOCK_STREAM,0))){
960 			perror("Cannot create socket");
961 			return NDO_ERROR;
962 	                }
963 
964 		/* copy the socket path */
965 		strncpy(server_address_u.sun_path,ndo2db_socket_name,sizeof(server_address_u.sun_path));
966 		server_address_u.sun_family=AF_UNIX;
967 
968 		/* bind the socket */
969 		if((bind(ndo2db_sd,(struct sockaddr *)&server_address_u,SUN_LEN(&server_address_u)))){
970 			close(ndo2db_sd);
971 			perror("Could not bind socket");
972 			return NDO_ERROR;
973 	                }
974 
975 		client_address_length=(socklen_t)sizeof(client_address_u);
976 	        }
977 
978     /* Default the backlog number on listen() to INT_MAX. If INT_MAX fails,
979      * try using SOMAXCONN (usually 127) and if that fails, return an error */
980     for (;;) {
981         if (listen(ndo2db_sd, listen_backlog)) {
982             if (listen_backlog == SOMAXCONN) {
983 				perror("Cannot listen on socket");
984 				ndo2db_cleanup_socket();
985 				return NDO_ERROR;
986             } else
987                 listen_backlog = SOMAXCONN;
988         }
989         break;
990     }
991 
992 
993 	/* daemonize */
994 #ifndef DEBUG_NDO2DB
995 	if(ndo2db_daemonize()!=NDO_OK)
996 		return NDO_ERROR;
997 #endif
998 
999 	/* accept connections... */
1000 	while(1){
1001 
1002 		/*
1003 		Solaris 10 gets an EINTR error when file2sock invoked on the 2nd call
1004 		An alternative fix is not to fork below, but this has wider implications
1005 		*/
1006 		while(1) {
1007 			new_sd=accept(ndo2db_sd,(ndo2db_socket_type==NDO_SINK_TCPSOCKET)?(struct sockaddr *)&client_address_i:(struct sockaddr *)&client_address_u,(socklen_t *)&client_address_length);
1008 
1009 			/* ToDo:  Hendrik 08/12/2009
1010 			 * If both ends think differently about SSL encryption, data from a ndomod will
1011 			 * be lost forever (likewise on database errors/misconfiguration)
1012 			 * This seems a good place to output some information from which client
1013 			 * a possible misconfiguration comes from.
1014 			 * Logging the ip address together with the ndomod instance name might be
1015 			 * a great hint for further error hunting
1016 			 */
1017 			if(new_sd>=0)
1018 				/* data available */
1019 				break;
1020 			if(errno == EINTR) {
1021 				/* continue */
1022 				}
1023 			else {
1024 				perror("Accept error");
1025 				ndo2db_cleanup_socket();
1026 				return NDO_ERROR;
1027 				}
1028 			}
1029 
1030 
1031 #ifndef DEBUG_NDO2DB
1032 		/* fork... */
1033 		new_pid=fork();
1034 
1035 		switch(new_pid){
1036 		case -1:
1037 			/* parent simply prints an error message and keeps on going... */
1038 			perror("Fork error");
1039 			close(new_sd);
1040 			break;
1041 
1042 		case 0:
1043 #endif
1044 			/* child processes data... */
1045 			ndo2db_handle_client_connection(new_sd);
1046 
1047 			/* close socket when we're done */
1048 			close(new_sd);
1049 #ifndef DEBUG_NDO2DB
1050 			return NDO_OK;
1051 			break;
1052 
1053 		default:
1054 			/* parent keeps on going... */
1055 			close(new_sd);
1056 			break;
1057 		        }
1058 #endif
1059 
1060 #ifdef DEBUG_NDO2DB_EXIT_AFTER_CONNECTION
1061 		break;
1062 #endif
1063 	        }
1064 
1065 	/* cleanup after ourselves */
1066 	ndo2db_cleanup_socket();
1067 
1068 	return NDO_OK;
1069         }
1070 
1071 
ndo2db_handle_client_connection(int sd)1072 int ndo2db_handle_client_connection(int sd){
1073 	ndo_dbuf dbuf;
1074 	int dbuf_chunk=2048;
1075 	ndo2db_idi idi;
1076 	char buf[512];
1077 	int result=0;
1078 	int error=NDO_FALSE;
1079 
1080 #ifdef HAVE_SSL
1081 	SSL *ssl=NULL;
1082 #endif
1083 
1084 	/* open syslog facility */
1085 	/*openlog("ndo2db",0,LOG_DAEMON);*/
1086 
1087 	/* re-open debug log */
1088 	ndo2db_close_debug_log();
1089 	ndo2db_open_debug_log();
1090 
1091 	/* reset signal handling */
1092 	signal(SIGQUIT,ndo2db_child_sighandler);
1093 	signal(SIGTERM,ndo2db_child_sighandler);
1094 	signal(SIGINT,ndo2db_child_sighandler);
1095 	signal(SIGSEGV,ndo2db_child_sighandler);
1096 	signal(SIGFPE,ndo2db_child_sighandler);
1097 
1098 	pid_t chpid;
1099 	if ((chpid = fork()) == 0) {
1100 		ndo2db_async_client_handle();
1101 	}
1102 
1103 	/* initialize input data information */
1104 	ndo2db_idi_init(&idi);
1105 
1106 	/* initialize dynamic buffer (2KB chunk size) */
1107 	ndo_dbuf_init(&dbuf,dbuf_chunk);
1108 
1109 	/* initialize database connection */
1110 	ndo2db_db_init(&idi);
1111 	ndo2db_db_connect(&idi);
1112 
1113 #ifdef HAVE_SSL
1114 	if(use_ssl==NDO_TRUE){
1115 		if((ssl=SSL_new(ctx))!=NULL){
1116 
1117 			SSL_set_fd(ssl,sd);
1118 
1119 			/* keep attempting the request if needed */
1120 			while(((result=SSL_accept(ssl))!=1) && (SSL_get_error(ssl,result)==SSL_ERROR_WANT_READ));
1121 
1122 			if(result!=1){
1123 				syslog(LOG_ERR,"Error: Could not complete SSL handshake. %d\n",SSL_get_error(ssl,result));
1124 
1125 				return NDO_ERROR;
1126 			}
1127 		}
1128 	}
1129 #endif
1130 
1131 	/* read all data from client */
1132 	while(1){
1133 #ifdef HAVE_SSL
1134 		if(use_ssl==NDO_FALSE)
1135 			result=read(sd,buf,sizeof(buf)-1);
1136 		else{
1137 			result=SSL_read(ssl,buf,sizeof(buf)-1);
1138 			if(result==-1 && (SSL_get_error(ssl,result)==SSL_ERROR_WANT_READ)){
1139 				syslog(LOG_ERR,"SSL read error\n");
1140 			}
1141 		}
1142 #else
1143 
1144 		result=read(sd,buf,sizeof(buf)-1);
1145 #endif
1146 		/* bail out on hard errors */
1147 		if(result==-1) {
1148 			/* EAGAIN and EINTR are soft errors, so try another read() */
1149 			if (errno==EAGAIN || errno==EINTR)
1150 				continue;
1151 			else {
1152 				error=NDO_TRUE;
1153 
1154 #ifdef HAVE_SSL
1155 				if(ssl){
1156 					SSL_shutdown(ssl);
1157 					SSL_free(ssl);
1158 					syslog(LOG_INFO,"INFO: SSL Socket Shutdown.\n");
1159 				}
1160 #endif
1161 				break;
1162 				}
1163 		        }
1164 
1165 		/* zero bytes read means we lost the connection with the client */
1166 		if(result==0){
1167 
1168 #ifdef HAVE_SSL
1169 				if(ssl){
1170 					SSL_shutdown(ssl);
1171 					SSL_free(ssl);
1172 					syslog(LOG_INFO,"INFO: SSL Socket Shutdown.\n");
1173 				}
1174 #endif
1175 
1176 			/* gracefully back out of current operation... */
1177 			ndo2db_db_goodbye(&idi);
1178 			kill (chpid, SIGTERM);
1179 
1180 			break;
1181 		        }
1182 
1183 #ifdef DEBUG_NDO2DB2
1184 		printf("BYTESREAD: %d\n",result);
1185 #endif
1186 
1187 		/* append data we just read to dynamic buffer */
1188 		buf[result]='\x0';
1189 		ndo_dbuf_strcat(&dbuf,buf);
1190 
1191 		/* check for completed lines of input */
1192 		ndo2db_check_for_client_input(&idi,&dbuf);
1193 		/* reinitialize buffer */
1194 		ndo_dbuf_free(&dbuf);
1195 		ndo_dbuf_init(&dbuf,dbuf_chunk);
1196 
1197 		/* should we disconnect the client? */
1198 		if(idi.disconnect_client==NDO_TRUE){
1199 
1200 			/* gracefully back out of current operation... */
1201 			ndo2db_db_goodbye(&idi);
1202 			kill (chpid, SIGTERM);
1203 
1204 			break;
1205 		        }
1206 	        }
1207 
1208 #ifdef DEBUG_NDO2DB2
1209 	printf("BYTES: %lu, LINES: %lu\n",idi.bytes_processed,idi.lines_processed);
1210 #endif
1211 
1212 	/* free memory allocated to dynamic buffer */
1213 	ndo_dbuf_free(&dbuf);
1214 
1215 	/* disconnect from database */
1216 	ndo2db_db_disconnect(&idi);
1217 	ndo2db_db_deinit(&idi);
1218 
1219 	/* free memory */
1220 	ndo2db_free_input_memory(&idi);
1221 	ndo2db_free_connection_memory(&idi);
1222 
1223 	/* clean queue */
1224 	del_queue();
1225 
1226 	/* wait for child to end work */
1227 	waitpid(chpid, NULL, 0);
1228 
1229 	/* close syslog facility */
1230 	/*closelog();*/
1231 
1232 	if(error==NDO_TRUE)
1233 		return NDO_ERROR;
1234 
1235 	return NDO_OK;
1236         }
1237 
1238 
1239 /* initializes structure for tracking data */
ndo2db_idi_init(ndo2db_idi * idi)1240 int ndo2db_idi_init(ndo2db_idi *idi){
1241 	int x=0;
1242 
1243 	if(idi==NULL)
1244 		return NDO_ERROR;
1245 
1246 	idi->disconnect_client=NDO_FALSE;
1247 	idi->ignore_client_data=NDO_FALSE;
1248 	idi->protocol_version=0;
1249 	idi->instance_name=NULL;
1250 	idi->buffered_input=NULL;
1251 	idi->agent_name=NULL;
1252 	idi->agent_version=NULL;
1253 	idi->disposition=NULL;
1254 	idi->connect_source=NULL;
1255 	idi->connect_type=NULL;
1256 	idi->current_input_section=NDO2DB_INPUT_SECTION_NONE;
1257 	idi->current_input_data=NDO2DB_INPUT_DATA_NONE;
1258 	idi->bytes_processed=0L;
1259 	idi->lines_processed=0L;
1260 	idi->entries_processed=0L;
1261 	idi->current_object_config_type=NDO2DB_CONFIGTYPE_ORIGINAL;
1262 	idi->data_start_time=0L;
1263 	idi->data_end_time=0L;
1264 
1265 	/* initialize mbuf */
1266 	for(x=0;x<NDO2DB_MAX_MBUF_ITEMS;x++){
1267 		idi->mbuf[x].used_lines=0;
1268 		idi->mbuf[x].allocated_lines=0;
1269 		idi->mbuf[x].buffer=NULL;
1270 	        }
1271 
1272 	return NDO_OK;
1273         }
1274 
1275 
1276 /* checks for single lines of input from a client connection */
ndo2db_check_for_client_input(ndo2db_idi * idi,ndo_dbuf * dbuf)1277 int ndo2db_check_for_client_input(ndo2db_idi *idi,ndo_dbuf *dbuf){
1278 	char *buf=NULL;
1279 	register int x;
1280 
1281 
1282 	if(dbuf==NULL)
1283 		return NDO_OK;
1284 	if(dbuf->buf==NULL)
1285 		return NDO_OK;
1286 
1287 #ifdef DEBUG_NDO2DB2
1288 	printf("RAWBUF: %s\n",dbuf->buf);
1289 	printf("  USED1: %lu, BYTES: %lu, LINES: %lu\n",dbuf->used_size,idi->bytes_processed,idi->lines_processed);
1290 #endif
1291 
1292 	get_queue_id(getpid());
1293 	push_into_queue(dbuf->buf);
1294 
1295 	return NDO_OK;
1296         }
1297 
1298 /* asynchronous handle clients events */
ndo2db_async_client_handle()1299 void ndo2db_async_client_handle() {
1300 	ndo2db_idi idi;
1301 
1302 	size_t len = 0, curlen, insz, maxbuf = ndo2db_max_output_buffer_size, bufsz = ndo2db_max_output_buffer_size + (1024 * 2);
1303     int i;
1304 	char *buf = (char*)calloc(bufsz, sizeof(char));
1305 	char *temp_buf;
1306 
1307 	/* double check max output buffer size sanity */
1308 	if (bufsz < maxbuf) {
1309 		bufsz = maxbuf;
1310 		maxbuf -= 1024 * 2;
1311 	}
1312 
1313 	/* initialize input data information */
1314 	ndo2db_idi_init(&idi);
1315 
1316 	/* initialize database connection */
1317 	ndo2db_db_init(&idi);
1318 	ndo2db_db_connect(&idi);
1319 
1320 	get_queue_id(getppid());
1321 
1322 	for (;;) {
1323 		char * qbuf = pop_from_queue();
1324 
1325 		ndo2db_log_debug_info(NDO2DB_DEBUGL_PROCESSINFO, 2,"Queue Message: %s\n", qbuf);
1326 
1327 		insz = strlen(qbuf);
1328 		curlen = len + insz;
1329 		strcat(buf, qbuf);
1330 		free(qbuf);
1331 
1332         i = 0;
1333 		for ( ; i < curlen; i++) {
1334 			if (buf[i] == '\n') {
1335 				temp_buf = (char*)malloc((curlen + 4) * sizeof(char));
1336 				strncpy(temp_buf, buf, i);
1337 				temp_buf[i] = '\x0';
1338 
1339 				ndo2db_log_debug_info(NDO2DB_DEBUGL_PROCESSINFO, 2,"Handling: %s\n", temp_buf);
1340 				ndo2db_handle_client_input(&idi,temp_buf);
1341 /*				ndo2db_log_debug_info(NDO2DB_DEBUGL_PROCESSINFO, 2,"Full Buffer: %s\n", buf); */
1342 
1343 				memmove(buf, &buf[i+1], bufsz - i);
1344 				len = 0;
1345 				curlen = strlen(buf);
1346 				free(temp_buf);
1347 
1348 				idi.lines_processed++;
1349 				idi.bytes_processed += i+1;
1350                 i = -1;
1351 			}
1352 		}
1353 
1354 		len = curlen;
1355 		if (len  > maxbuf) {
1356 			buf[maxbuf+1] = 0;
1357 			len = curlen = maxbuf;
1358 			ndo2db_log_debug_info(NDO2DB_DEBUGL_PROCESSINFO, 2,"Truncating text at position %d - %s\n", maxbuf+1, &buf[maxbuf+2]);
1359 		} else if (len == 0)
1360 			memset(buf, 0, bufsz * sizeof(char));
1361 	}
1362 
1363 	free(buf);
1364 
1365 	/* disconnect from database */
1366 	ndo2db_db_disconnect(&idi);
1367 	ndo2db_db_deinit(&idi);
1368 
1369 	/* free memory */
1370 	ndo2db_free_input_memory(&idi);
1371 	ndo2db_free_connection_memory(&idi);
1372 }
1373 
1374 /* handles a single line of input from a client connection */
ndo2db_handle_client_input(ndo2db_idi * idi,char * buf)1375 int ndo2db_handle_client_input(ndo2db_idi *idi, char *buf){
1376 	char *var=NULL;
1377 	char *val=NULL;
1378 	unsigned long data_type_long=0L;
1379 	int data_type=NDO_DATA_NONE;
1380 	int input_type=NDO2DB_INPUT_DATA_NONE;
1381 
1382 #ifdef DEBUG_NDO2DB2
1383 	printf("HANDLING: '%s'\n",buf);
1384 #endif
1385 
1386 	if(buf==NULL || idi==NULL)
1387 		return NDO_ERROR;
1388 
1389 	/* we're ignoring client data because of wrong protocol version, etc...  */
1390 	if(idi->ignore_client_data==NDO_TRUE)
1391 		return NDO_ERROR;
1392 
1393 	/* skip empty lines */
1394 	if(buf[0]=='\x0')
1395 		return NDO_OK;
1396 
1397 	switch(idi->current_input_section){
1398 
1399 	case NDO2DB_INPUT_SECTION_NONE:
1400 
1401 		var=strtok(buf,":");
1402 		val=strtok(NULL,"\n");
1403 
1404 		if(!strcmp(var,NDO_API_HELLO)){
1405 
1406 			idi->current_input_section=NDO2DB_INPUT_SECTION_HEADER;
1407 			idi->current_input_data=NDO2DB_INPUT_DATA_NONE;
1408 
1409 			/* free old connection memory (necessary in some cases) */
1410 			ndo2db_free_connection_memory(idi);
1411 		        }
1412 
1413 		break;
1414 
1415 	case NDO2DB_INPUT_SECTION_HEADER:
1416 
1417 		var=strtok(buf,":");
1418 		val=strtok(NULL,"\n");
1419 
1420 		if(!strcmp(var,NDO_API_STARTDATADUMP)){
1421 
1422 			/* client is using wrong protocol version, bail out here... */
1423 			if(idi->protocol_version!=NDO_API_PROTOVERSION){
1424 				syslog(LOG_USER|LOG_INFO,"Error: Client protocol version %d is incompatible with server version %d.  Disconnecting client...",idi->protocol_version,NDO_API_PROTOVERSION);
1425 				idi->disconnect_client=NDO_TRUE;
1426 				idi->ignore_client_data=NDO_TRUE;
1427 				return NDO_ERROR;
1428 			        }
1429 
1430 			idi->current_input_section=NDO2DB_INPUT_SECTION_DATA;
1431 
1432 			/* save connection info to DB */
1433 			ndo2db_db_hello(idi);
1434 		        }
1435 
1436 		else if(!strcmp(var,NDO_API_PROTOCOL))
1437 			ndo2db_convert_string_to_int((val+1),&idi->protocol_version);
1438 
1439 		else if(!strcmp(var,NDO_API_INSTANCENAME))
1440 			idi->instance_name=strdup(val+1);
1441 
1442 		else if(!strcmp(var,NDO_API_AGENT))
1443 			idi->agent_name=strdup(val+1);
1444 
1445 		else if(!strcmp(var,NDO_API_AGENTVERSION))
1446 			idi->agent_version=strdup(val+1);
1447 
1448 		else if(!strcmp(var,NDO_API_DISPOSITION))
1449 			idi->disposition=strdup(val+1);
1450 
1451 		else if(!strcmp(var,NDO_API_CONNECTION))
1452 			idi->connect_source=strdup(val+1);
1453 
1454 		else if(!strcmp(var,NDO_API_CONNECTTYPE))
1455 			idi->connect_type=strdup(val+1);
1456 
1457 		else if(!strcmp(var,NDO_API_STARTTIME))
1458 			ndo2db_convert_string_to_unsignedlong((val+1),&idi->data_start_time);
1459 
1460 		break;
1461 
1462 	case NDO2DB_INPUT_SECTION_FOOTER:
1463 
1464 		var=strtok(buf,":");
1465 		val=strtok(NULL,"\n");
1466 
1467 		/* client is saying goodbye... */
1468 		if(!strcmp(var,NDO_API_GOODBYE))
1469 			idi->current_input_section=NDO2DB_INPUT_SECTION_NONE;
1470 
1471 		else if(!strcmp(var,NDO_API_ENDTIME))
1472 			ndo2db_convert_string_to_unsignedlong((val+1),&idi->data_end_time);
1473 
1474 		break;
1475 
1476 	case NDO2DB_INPUT_SECTION_DATA:
1477 
1478 		if(idi->current_input_data==NDO2DB_INPUT_DATA_NONE){
1479 
1480 			var=strtok(buf,":");
1481 			val=strtok(NULL,"\n");
1482 
1483 			input_type=atoi(var);
1484 
1485 			switch(input_type){
1486 
1487 			/* we're reached the end of all of the data... */
1488 			case NDO_API_ENDDATADUMP:
1489 				idi->current_input_section=NDO2DB_INPUT_SECTION_FOOTER;
1490 				idi->current_input_data=NDO2DB_INPUT_DATA_NONE;
1491 				break;
1492 
1493 			/* config dumps */
1494 			case NDO_API_STARTCONFIGDUMP:
1495 				idi->current_input_data=NDO2DB_INPUT_DATA_CONFIGDUMPSTART;
1496 				break;
1497 			case NDO_API_ENDCONFIGDUMP:
1498 				idi->current_input_data=NDO2DB_INPUT_DATA_CONFIGDUMPEND;
1499 				break;
1500 
1501 			/* archived data */
1502 			case NDO_API_LOGENTRY:
1503 				idi->current_input_data=NDO2DB_INPUT_DATA_LOGENTRY;
1504 				break;
1505 
1506 			/* realtime data */
1507 			case NDO_API_PROCESSDATA:
1508 				idi->current_input_data=NDO2DB_INPUT_DATA_PROCESSDATA;
1509 				break;
1510 			case NDO_API_TIMEDEVENTDATA:
1511 				idi->current_input_data=NDO2DB_INPUT_DATA_TIMEDEVENTDATA;
1512 				break;
1513 			case NDO_API_LOGDATA:
1514 				idi->current_input_data=NDO2DB_INPUT_DATA_LOGDATA;
1515 				break;
1516 			case NDO_API_SYSTEMCOMMANDDATA:
1517 				idi->current_input_data=NDO2DB_INPUT_DATA_SYSTEMCOMMANDDATA;
1518 				break;
1519 			case NDO_API_EVENTHANDLERDATA:
1520 				idi->current_input_data=NDO2DB_INPUT_DATA_EVENTHANDLERDATA;
1521 				break;
1522 			case NDO_API_NOTIFICATIONDATA:
1523 				idi->current_input_data=NDO2DB_INPUT_DATA_NOTIFICATIONDATA;
1524 				break;
1525 			case NDO_API_SERVICECHECKDATA:
1526 				idi->current_input_data=NDO2DB_INPUT_DATA_SERVICECHECKDATA;
1527 				break;
1528 			case NDO_API_HOSTCHECKDATA:
1529 				idi->current_input_data=NDO2DB_INPUT_DATA_HOSTCHECKDATA;
1530 				break;
1531 			case NDO_API_COMMENTDATA:
1532 				idi->current_input_data=NDO2DB_INPUT_DATA_COMMENTDATA;
1533 				break;
1534 			case NDO_API_DOWNTIMEDATA:
1535 				idi->current_input_data=NDO2DB_INPUT_DATA_DOWNTIMEDATA;
1536 				break;
1537 			case NDO_API_FLAPPINGDATA:
1538 				idi->current_input_data=NDO2DB_INPUT_DATA_FLAPPINGDATA;
1539 				break;
1540 			case NDO_API_PROGRAMSTATUSDATA:
1541 				idi->current_input_data=NDO2DB_INPUT_DATA_PROGRAMSTATUSDATA;
1542 				break;
1543 			case NDO_API_HOSTSTATUSDATA:
1544 				idi->current_input_data=NDO2DB_INPUT_DATA_HOSTSTATUSDATA;
1545 				break;
1546 			case NDO_API_SERVICESTATUSDATA:
1547 				idi->current_input_data=NDO2DB_INPUT_DATA_SERVICESTATUSDATA;
1548 				break;
1549 			case NDO_API_CONTACTSTATUSDATA:
1550 				idi->current_input_data=NDO2DB_INPUT_DATA_CONTACTSTATUSDATA;
1551 				break;
1552 			case NDO_API_ADAPTIVEPROGRAMDATA:
1553 				idi->current_input_data=NDO2DB_INPUT_DATA_ADAPTIVEPROGRAMDATA;
1554 				break;
1555 			case NDO_API_ADAPTIVEHOSTDATA:
1556 				idi->current_input_data=NDO2DB_INPUT_DATA_ADAPTIVEHOSTDATA;
1557 				break;
1558 			case NDO_API_ADAPTIVESERVICEDATA:
1559 				idi->current_input_data=NDO2DB_INPUT_DATA_ADAPTIVESERVICEDATA;
1560 				break;
1561 			case NDO_API_ADAPTIVECONTACTDATA:
1562 				idi->current_input_data=NDO2DB_INPUT_DATA_ADAPTIVECONTACTDATA;
1563 				break;
1564 			case NDO_API_EXTERNALCOMMANDDATA:
1565 				idi->current_input_data=NDO2DB_INPUT_DATA_EXTERNALCOMMANDDATA;
1566 				break;
1567 			case NDO_API_AGGREGATEDSTATUSDATA:
1568 				idi->current_input_data=NDO2DB_INPUT_DATA_AGGREGATEDSTATUSDATA;
1569 				break;
1570 			case NDO_API_RETENTIONDATA:
1571 				idi->current_input_data=NDO2DB_INPUT_DATA_RETENTIONDATA;
1572 				break;
1573 			case NDO_API_CONTACTNOTIFICATIONDATA:
1574 				idi->current_input_data=NDO2DB_INPUT_DATA_CONTACTNOTIFICATIONDATA;
1575 				break;
1576 			case NDO_API_CONTACTNOTIFICATIONMETHODDATA:
1577 				idi->current_input_data=NDO2DB_INPUT_DATA_CONTACTNOTIFICATIONMETHODDATA;
1578 				break;
1579 			case NDO_API_ACKNOWLEDGEMENTDATA:
1580 				idi->current_input_data=NDO2DB_INPUT_DATA_ACKNOWLEDGEMENTDATA;
1581 				break;
1582 			case NDO_API_STATECHANGEDATA:
1583 				idi->current_input_data=NDO2DB_INPUT_DATA_STATECHANGEDATA;
1584 				break;
1585 
1586 			/* config variables */
1587 			case NDO_API_MAINCONFIGFILEVARIABLES:
1588 				idi->current_input_data=NDO2DB_INPUT_DATA_MAINCONFIGFILEVARIABLES;
1589 				break;
1590 			case NDO_API_RESOURCECONFIGFILEVARIABLES:
1591 				idi->current_input_data=NDO2DB_INPUT_DATA_RESOURCECONFIGFILEVARIABLES;
1592 				break;
1593 			case NDO_API_CONFIGVARIABLES:
1594 				idi->current_input_data=NDO2DB_INPUT_DATA_CONFIGVARIABLES;
1595 				break;
1596 			case NDO_API_RUNTIMEVARIABLES:
1597 				idi->current_input_data=NDO2DB_INPUT_DATA_RUNTIMEVARIABLES;
1598 				break;
1599 
1600 			/* object configuration */
1601 			case NDO_API_HOSTDEFINITION:
1602 				idi->current_input_data=NDO2DB_INPUT_DATA_HOSTDEFINITION;
1603 				break;
1604 			case NDO_API_HOSTGROUPDEFINITION:
1605 				idi->current_input_data=NDO2DB_INPUT_DATA_HOSTGROUPDEFINITION;
1606 				break;
1607 			case NDO_API_SERVICEDEFINITION:
1608 				idi->current_input_data=NDO2DB_INPUT_DATA_SERVICEDEFINITION;
1609 				break;
1610 			case NDO_API_SERVICEGROUPDEFINITION:
1611 				idi->current_input_data=NDO2DB_INPUT_DATA_SERVICEGROUPDEFINITION;
1612 				break;
1613 			case NDO_API_HOSTDEPENDENCYDEFINITION:
1614 				idi->current_input_data=NDO2DB_INPUT_DATA_HOSTDEPENDENCYDEFINITION;
1615 				break;
1616 			case NDO_API_SERVICEDEPENDENCYDEFINITION:
1617 				idi->current_input_data=NDO2DB_INPUT_DATA_SERVICEDEPENDENCYDEFINITION;
1618 				break;
1619 			case NDO_API_HOSTESCALATIONDEFINITION:
1620 				idi->current_input_data=NDO2DB_INPUT_DATA_HOSTESCALATIONDEFINITION;
1621 				break;
1622 			case NDO_API_SERVICEESCALATIONDEFINITION:
1623 				idi->current_input_data=NDO2DB_INPUT_DATA_SERVICEESCALATIONDEFINITION;
1624 				break;
1625 			case NDO_API_COMMANDDEFINITION:
1626 				idi->current_input_data=NDO2DB_INPUT_DATA_COMMANDDEFINITION;
1627 				break;
1628 			case NDO_API_TIMEPERIODDEFINITION:
1629 				idi->current_input_data=NDO2DB_INPUT_DATA_TIMEPERIODDEFINITION;
1630 				break;
1631 			case NDO_API_CONTACTDEFINITION:
1632 				idi->current_input_data=NDO2DB_INPUT_DATA_CONTACTDEFINITION;
1633 				break;
1634 			case NDO_API_CONTACTGROUPDEFINITION:
1635 				idi->current_input_data=NDO2DB_INPUT_DATA_CONTACTGROUPDEFINITION;
1636 				break;
1637 			case NDO_API_HOSTEXTINFODEFINITION:
1638 				/* deprecated - merged with host definitions */
1639 			case NDO_API_SERVICEEXTINFODEFINITION:
1640 				/* deprecated - merged with service definitions */
1641 
1642 			case NDO_API_ACTIVEOBJECTSLIST:
1643 				idi->current_input_data=NDO2DB_INPUT_DATA_ACTIVEOBJECTSLIST;
1644 				break;
1645 
1646 			default:
1647 				break;
1648 			        }
1649 
1650 			/* initialize input data */
1651 			ndo2db_start_input_data(idi);
1652 		        }
1653 
1654 		/* we are processing some type of data already... */
1655 		else{
1656 
1657 			var=strtok(buf,"=");
1658 			val=strtok(NULL,"\n");
1659 
1660 			/* get the data type */
1661 			data_type_long=strtoul(var,NULL,0);
1662 
1663 			/* there was an error with the data type - throw it out */
1664 			if(data_type_long==ULONG_MAX && errno==ERANGE)
1665 				break;
1666 
1667 			data_type=(int)data_type_long;
1668 
1669 			/* the current data section is ending... */
1670 			if(data_type==NDO_API_ENDDATA){
1671 
1672 				/* finish current data processing */
1673 				ndo2db_end_input_data(idi);
1674 
1675 				idi->current_input_data=NDO2DB_INPUT_DATA_NONE;
1676 		                }
1677 
1678 			/* add data for already existing data type... */
1679 			else{
1680 
1681 				/* the data type is out of range - throw it out */
1682 				if (data_type > NDO_MAX_DATA_TYPES) {
1683 #ifdef DEBUG_NDO2DB2
1684 						printf("## DISCARD! LINE: %lu, TYPE: %d, VAL: %s\n",idi->lines_processed,data_type,val);
1685 #endif
1686 						break;
1687 				}
1688 
1689 #ifdef DEBUG_NDO2DB2
1690 				printf("LINE: %lu, TYPE: %d, VAL:%s\n",idi->lines_processed,data_type,val);
1691 #endif
1692 				ndo2db_add_input_data_item(idi,data_type,val);
1693 			}
1694 		}
1695 
1696 		break;
1697 
1698 	default:
1699 		break;
1700 	}
1701 
1702 	return NDO_OK;
1703 }
1704 
1705 
ndo2db_start_input_data(ndo2db_idi * idi)1706 int ndo2db_start_input_data(ndo2db_idi *idi){
1707 	int x;
1708 
1709 	if(idi==NULL)
1710 		return NDO_ERROR;
1711 
1712 	/* sometimes ndo2db_end_input_data() isn't called, so free memory if we find it */
1713 	ndo2db_free_input_memory(idi);
1714 
1715 	/* allocate memory for holding buffered input */
1716 	if((idi->buffered_input=(char **)malloc(sizeof(char *)*NDO_MAX_DATA_TYPES))==NULL)
1717 		return NDO_ERROR;
1718 
1719 	/* initialize buffered input slots */
1720 	for(x=0;x<NDO_MAX_DATA_TYPES;x++)
1721 		idi->buffered_input[x]=NULL;
1722 
1723 	return NDO_OK;
1724         }
1725 
1726 
ndo2db_add_input_data_item(ndo2db_idi * idi,int type,char * buf)1727 int ndo2db_add_input_data_item(ndo2db_idi *idi, int type, char *buf){
1728 	char *newbuf=NULL;
1729 	int mbuf_used=NDO_TRUE;
1730 
1731 	if(idi==NULL)
1732 		return NDO_ERROR;
1733 
1734 	if (idi->current_input_data == NDO2DB_INPUT_DATA_ACTIVEOBJECTSLIST) {
1735 		if(buf==NULL)
1736 			newbuf=strdup("");
1737 		else
1738 			newbuf=strdup(buf);
1739 		if (type != NDO_DATA_ACTIVEOBJECTSTYPE)
1740 			ndo_unescape_buffer(newbuf);
1741 		if(idi->buffered_input[type]!=NULL){
1742 			free(idi->buffered_input[type]);
1743 			idi->buffered_input[type]=NULL;
1744 		}
1745 		/* save buffered item */
1746 		idi->buffered_input[type]=newbuf;
1747 
1748 		return NDO_OK;
1749 	}
1750 
1751 	/* escape data if necessary */
1752 	switch(type){
1753 
1754 	case NDO_DATA_ACKAUTHOR:
1755 	case NDO_DATA_ACKDATA:
1756 	case NDO_DATA_AUTHORNAME:
1757 	case NDO_DATA_CHECKCOMMAND:
1758 	case NDO_DATA_COMMANDARGS:
1759 	case NDO_DATA_COMMANDLINE:
1760 	case NDO_DATA_COMMANDSTRING:
1761 	case NDO_DATA_COMMENT:
1762 	case NDO_DATA_EVENTHANDLER:
1763 	case NDO_DATA_GLOBALHOSTEVENTHANDLER:
1764 	case NDO_DATA_GLOBALSERVICEEVENTHANDLER:
1765 	case NDO_DATA_HOST:
1766 	case NDO_DATA_LOGENTRY:
1767 	case NDO_DATA_OUTPUT:
1768 	case NDO_DATA_LONGOUTPUT:
1769 	case NDO_DATA_PERFDATA:
1770 	case NDO_DATA_SERVICE:
1771 	case NDO_DATA_PROGRAMNAME:
1772 	case NDO_DATA_PROGRAMVERSION:
1773 	case NDO_DATA_PROGRAMDATE:
1774 
1775 	case NDO_DATA_COMMANDNAME:
1776 	case NDO_DATA_CONTACTADDRESS:
1777 	case NDO_DATA_CONTACTALIAS:
1778 	case NDO_DATA_CONTACTGROUP:
1779 	case NDO_DATA_CONTACTGROUPALIAS:
1780 	case NDO_DATA_CONTACTGROUPMEMBER:
1781 	case NDO_DATA_CONTACTGROUPNAME:
1782 	case NDO_DATA_CONTACTNAME:
1783 	case NDO_DATA_DEPENDENTHOSTNAME:
1784 	case NDO_DATA_DEPENDENTSERVICEDESCRIPTION:
1785 	case NDO_DATA_EMAILADDRESS:
1786 	case NDO_DATA_HOSTADDRESS:
1787 	case NDO_DATA_HOSTALIAS:
1788 	case NDO_DATA_HOSTCHECKCOMMAND:
1789 	case NDO_DATA_HOSTCHECKPERIOD:
1790 	case NDO_DATA_HOSTEVENTHANDLER:
1791 	case NDO_DATA_HOSTFAILUREPREDICTIONOPTIONS:
1792 	case NDO_DATA_HOSTGROUPALIAS:
1793 	case NDO_DATA_HOSTGROUPMEMBER:
1794 	case NDO_DATA_HOSTGROUPNAME:
1795 	case NDO_DATA_HOSTNAME:
1796 	case NDO_DATA_HOSTNOTIFICATIONCOMMAND:
1797 	case NDO_DATA_HOSTNOTIFICATIONPERIOD:
1798 	case NDO_DATA_PAGERADDRESS:
1799 	case NDO_DATA_PARENTHOST:
1800 	case NDO_DATA_SERVICECHECKCOMMAND:
1801 	case NDO_DATA_SERVICECHECKPERIOD:
1802 	case NDO_DATA_SERVICEDESCRIPTION:
1803 	case NDO_DATA_SERVICEEVENTHANDLER:
1804 	case NDO_DATA_SERVICEFAILUREPREDICTIONOPTIONS:
1805 	case NDO_DATA_SERVICEGROUPALIAS:
1806 	case NDO_DATA_SERVICEGROUPMEMBER:
1807 	case NDO_DATA_SERVICEGROUPNAME:
1808 	case NDO_DATA_SERVICENOTIFICATIONCOMMAND:
1809 	case NDO_DATA_SERVICENOTIFICATIONPERIOD:
1810 	case NDO_DATA_TIMEPERIODALIAS:
1811 	case NDO_DATA_TIMEPERIODNAME:
1812 	case NDO_DATA_TIMERANGE:
1813 
1814 	case NDO_DATA_ACTIONURL:
1815 	case NDO_DATA_ICONIMAGE:
1816 	case NDO_DATA_ICONIMAGEALT:
1817 	case NDO_DATA_NOTES:
1818 	case NDO_DATA_NOTESURL:
1819 	case NDO_DATA_CUSTOMVARIABLE:
1820 	case NDO_DATA_CONTACT:
1821 	case NDO_DATA_PARENTSERVICE:
1822 
1823 		/* strings are escaped when they arrive */
1824 		if(buf==NULL)
1825 			newbuf=strdup("");
1826 		else
1827 			newbuf=strdup(buf);
1828 		ndo_unescape_buffer(newbuf);
1829 		break;
1830 
1831 	default:
1832 
1833 		/* data hasn't been escaped */
1834 		if(buf==NULL)
1835 			newbuf=strdup("");
1836 		else
1837 			newbuf=strdup(buf);
1838 		break;
1839 	}
1840 
1841 	/* check for errors */
1842 	if(newbuf==NULL){
1843 #ifdef DEBUG_NDO2DB
1844 		printf("ALLOCATION ERROR\n");
1845 #endif
1846 		return NDO_ERROR;
1847 	        }
1848 
1849 	/* store the buffered data */
1850 	switch(type){
1851 
1852 	/* special case for data items that may appear multiple times */
1853 	case NDO_DATA_CONTACTGROUP:
1854 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_CONTACTGROUP,newbuf);
1855 		break;
1856 	case NDO_DATA_CONTACTGROUPMEMBER:
1857 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_CONTACTGROUPMEMBER,newbuf);
1858 		break;
1859 	case NDO_DATA_SERVICEGROUPMEMBER:
1860 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_SERVICEGROUPMEMBER,newbuf);
1861 		break;
1862 	case NDO_DATA_HOSTGROUPMEMBER:
1863 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_HOSTGROUPMEMBER,newbuf);
1864 		break;
1865 	case NDO_DATA_SERVICENOTIFICATIONCOMMAND:
1866 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_SERVICENOTIFICATIONCOMMAND,newbuf);
1867 		break;
1868 	case NDO_DATA_HOSTNOTIFICATIONCOMMAND:
1869 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_HOSTNOTIFICATIONCOMMAND,newbuf);
1870 		break;
1871 	case NDO_DATA_CONTACTADDRESS:
1872 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_CONTACTADDRESS,newbuf);
1873 		break;
1874 	case NDO_DATA_TIMERANGE:
1875 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_TIMERANGE,newbuf);
1876 		break;
1877 	case NDO_DATA_PARENTHOST:
1878 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_PARENTHOST,newbuf);
1879 		break;
1880 	case NDO_DATA_CONFIGFILEVARIABLE:
1881 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_CONFIGFILEVARIABLE,newbuf);
1882 		break;
1883 	case NDO_DATA_CONFIGVARIABLE:
1884 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_CONFIGVARIABLE,newbuf);
1885 		break;
1886 	case NDO_DATA_RUNTIMEVARIABLE:
1887 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_RUNTIMEVARIABLE,newbuf);
1888 		break;
1889 	case NDO_DATA_CUSTOMVARIABLE:
1890 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_CUSTOMVARIABLE,newbuf);
1891 		break;
1892 	case NDO_DATA_CONTACT:
1893 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_CONTACT,newbuf);
1894 		break;
1895 	case NDO_DATA_PARENTSERVICE:
1896 		ndo2db_add_input_data_mbuf(idi,type,NDO2DB_MBUF_PARENTSERVICE,newbuf);
1897 		break;
1898 
1899 	/* NORMAL DATA */
1900 	/* normal data items appear only once per data type */
1901 	default:
1902 
1903 		mbuf_used=NDO_FALSE;
1904 
1905 		/* if there was already a matching item, discard the old one */
1906 		if(idi->buffered_input[type]!=NULL){
1907 			free(idi->buffered_input[type]);
1908 			idi->buffered_input[type]=NULL;
1909 		        }
1910 
1911 		/* save buffered item */
1912 		idi->buffered_input[type]=newbuf;
1913 	        }
1914 
1915 	return NDO_OK;
1916         }
1917 
1918 
1919 
ndo2db_add_input_data_mbuf(ndo2db_idi * idi,int type,int mbuf_slot,char * buf)1920 int ndo2db_add_input_data_mbuf(ndo2db_idi *idi, int type, int mbuf_slot, char *buf){
1921 	int allocation_chunk=80;
1922 	char **newbuffer=NULL;
1923 
1924 	if(idi==NULL || buf==NULL)
1925 		return NDO_ERROR;
1926 
1927 	if(mbuf_slot>=NDO2DB_MAX_MBUF_ITEMS)
1928 		return NDO_ERROR;
1929 
1930 	/* create buffer */
1931 	if(idi->mbuf[mbuf_slot].buffer==NULL){
1932 #ifdef NDO2DB_DEBUG_MBUF
1933 		mbuf_bytes_allocated+=sizeof(char *)*allocation_chunk;
1934 		printf("MBUF INITIAL ALLOCATION (MBUF = %lu bytes)\n",mbuf_bytes_allocated);
1935 #endif
1936 		idi->mbuf[mbuf_slot].buffer=(char **)malloc(sizeof(char *)*allocation_chunk);
1937 		idi->mbuf[mbuf_slot].allocated_lines+=allocation_chunk;
1938 	        }
1939 
1940 	/* expand buffer */
1941 	if(idi->mbuf[mbuf_slot].used_lines==idi->mbuf[mbuf_slot].allocated_lines){
1942 		newbuffer=(char **)realloc(idi->mbuf[mbuf_slot].buffer,sizeof(char *)*(idi->mbuf[mbuf_slot].allocated_lines+allocation_chunk));
1943 		if(newbuffer==NULL)
1944 			return NDO_ERROR;
1945 #ifdef NDO2DB_DEBUG_MBUF
1946 		mbuf_bytes_allocated+=sizeof(char *)*allocation_chunk;
1947 		printf("MBUF RESIZED (MBUF = %lu bytes)\n",mbuf_bytes_allocated);
1948 #endif
1949 		idi->mbuf[mbuf_slot].buffer=newbuffer;
1950 		idi->mbuf[mbuf_slot].allocated_lines+=allocation_chunk;
1951 	        }
1952 
1953 	/* store the data */
1954 	if(idi->mbuf[mbuf_slot].buffer){
1955 		idi->mbuf[mbuf_slot].buffer[idi->mbuf[mbuf_slot].used_lines]=buf;
1956 		idi->mbuf[mbuf_slot].used_lines++;
1957 	        }
1958 	else
1959 		return NDO_ERROR;
1960 
1961 	return NDO_OK;
1962         }
1963 
1964 
1965 
ndo2db_end_input_data(ndo2db_idi * idi)1966 int ndo2db_end_input_data(ndo2db_idi *idi){
1967 	int result=NDO_OK;
1968 
1969 	if(idi==NULL)
1970 		return NDO_ERROR;
1971 
1972 	/* update db stats occasionally */
1973 	if(ndo2db_db_last_checkin_time<(time(NULL)-60))
1974 		ndo2db_db_checkin(idi);
1975 
1976 #ifdef DEBUG_NDO2DB2
1977 	printf("HANDLING TYPE: %d\n",idi->current_input_data);
1978 #endif
1979 
1980 	switch(idi->current_input_data){
1981 
1982 	/* archived log entries */
1983 	case NDO2DB_INPUT_DATA_LOGENTRY:
1984 		result=ndo2db_handle_logentry(idi);
1985 		break;
1986 
1987 	/* realtime Nagios data */
1988 	case NDO2DB_INPUT_DATA_PROCESSDATA:
1989 		result=ndo2db_handle_processdata(idi);
1990 		break;
1991 	case NDO2DB_INPUT_DATA_TIMEDEVENTDATA:
1992 		result=ndo2db_handle_timedeventdata(idi);
1993 		break;
1994 	case NDO2DB_INPUT_DATA_LOGDATA:
1995 		result=ndo2db_handle_logdata(idi);
1996 		break;
1997 	case NDO2DB_INPUT_DATA_SYSTEMCOMMANDDATA:
1998 		result=ndo2db_handle_systemcommanddata(idi);
1999 		break;
2000 	case NDO2DB_INPUT_DATA_EVENTHANDLERDATA:
2001 		result=ndo2db_handle_eventhandlerdata(idi);
2002 		break;
2003 	case NDO2DB_INPUT_DATA_NOTIFICATIONDATA:
2004 		result=ndo2db_handle_notificationdata(idi);
2005 		break;
2006 	case NDO2DB_INPUT_DATA_SERVICECHECKDATA:
2007 		result=ndo2db_handle_servicecheckdata(idi);
2008 		break;
2009 	case NDO2DB_INPUT_DATA_HOSTCHECKDATA:
2010 		result=ndo2db_handle_hostcheckdata(idi);
2011 		break;
2012 	case NDO2DB_INPUT_DATA_COMMENTDATA:
2013 		result=ndo2db_handle_commentdata(idi);
2014 		break;
2015 	case NDO2DB_INPUT_DATA_DOWNTIMEDATA:
2016 		result=ndo2db_handle_downtimedata(idi);
2017 		break;
2018 	case NDO2DB_INPUT_DATA_FLAPPINGDATA:
2019 		result=ndo2db_handle_flappingdata(idi);
2020 		break;
2021 	case NDO2DB_INPUT_DATA_PROGRAMSTATUSDATA:
2022 		result=ndo2db_handle_programstatusdata(idi);
2023 		break;
2024 	case NDO2DB_INPUT_DATA_HOSTSTATUSDATA:
2025 		result=ndo2db_handle_hoststatusdata(idi);
2026 		break;
2027 	case NDO2DB_INPUT_DATA_SERVICESTATUSDATA:
2028 		result=ndo2db_handle_servicestatusdata(idi);
2029 		break;
2030 	case NDO2DB_INPUT_DATA_CONTACTSTATUSDATA:
2031 		result=ndo2db_handle_contactstatusdata(idi);
2032 		break;
2033 	case NDO2DB_INPUT_DATA_ADAPTIVEPROGRAMDATA:
2034 		result=ndo2db_handle_adaptiveprogramdata(idi);
2035 		break;
2036 	case NDO2DB_INPUT_DATA_ADAPTIVEHOSTDATA:
2037 		result=ndo2db_handle_adaptivehostdata(idi);
2038 		break;
2039 	case NDO2DB_INPUT_DATA_ADAPTIVESERVICEDATA:
2040 		result=ndo2db_handle_adaptiveservicedata(idi);
2041 		break;
2042 	case NDO2DB_INPUT_DATA_ADAPTIVECONTACTDATA:
2043 		result=ndo2db_handle_adaptivecontactdata(idi);
2044 		break;
2045 	case NDO2DB_INPUT_DATA_EXTERNALCOMMANDDATA:
2046 		result=ndo2db_handle_externalcommanddata(idi);
2047 		break;
2048 	case NDO2DB_INPUT_DATA_AGGREGATEDSTATUSDATA:
2049 		result=ndo2db_handle_aggregatedstatusdata(idi);
2050 		break;
2051 	case NDO2DB_INPUT_DATA_RETENTIONDATA:
2052 		result=ndo2db_handle_retentiondata(idi);
2053 		break;
2054 	case NDO2DB_INPUT_DATA_CONTACTNOTIFICATIONDATA:
2055 		result=ndo2db_handle_contactnotificationdata(idi);
2056 		break;
2057 	case NDO2DB_INPUT_DATA_CONTACTNOTIFICATIONMETHODDATA:
2058 		result=ndo2db_handle_contactnotificationmethoddata(idi);
2059 		break;
2060 	case NDO2DB_INPUT_DATA_ACKNOWLEDGEMENTDATA:
2061 		result=ndo2db_handle_acknowledgementdata(idi);
2062 		break;
2063 	case NDO2DB_INPUT_DATA_STATECHANGEDATA:
2064 		result=ndo2db_handle_statechangedata(idi);
2065 		break;
2066 
2067 	/* config file and variable dumps */
2068 	case NDO2DB_INPUT_DATA_MAINCONFIGFILEVARIABLES:
2069 		result=ndo2db_handle_configfilevariables(idi,0);
2070 		break;
2071 	case NDO2DB_INPUT_DATA_RESOURCECONFIGFILEVARIABLES:
2072 		result=ndo2db_handle_configfilevariables(idi,1);
2073 		break;
2074 	case NDO2DB_INPUT_DATA_CONFIGVARIABLES:
2075 		result=ndo2db_handle_configvariables(idi);
2076 		break;
2077 	case NDO2DB_INPUT_DATA_RUNTIMEVARIABLES:
2078 		result=ndo2db_handle_runtimevariables(idi);
2079 		break;
2080 	case NDO2DB_INPUT_DATA_CONFIGDUMPSTART:
2081 		result=ndo2db_handle_configdumpstart(idi);
2082 		break;
2083 	case NDO2DB_INPUT_DATA_CONFIGDUMPEND:
2084 		result=ndo2db_handle_configdumpend(idi);
2085 		break;
2086 
2087 	/* config definitions */
2088 	case NDO2DB_INPUT_DATA_HOSTDEFINITION:
2089 		result=ndo2db_handle_hostdefinition(idi);
2090 		break;
2091 	case NDO2DB_INPUT_DATA_HOSTGROUPDEFINITION:
2092 		result=ndo2db_handle_hostgroupdefinition(idi);
2093 		break;
2094 	case NDO2DB_INPUT_DATA_SERVICEDEFINITION:
2095 		result=ndo2db_handle_servicedefinition(idi);
2096 		break;
2097 	case NDO2DB_INPUT_DATA_SERVICEGROUPDEFINITION:
2098 		result=ndo2db_handle_servicegroupdefinition(idi);
2099 		break;
2100 	case NDO2DB_INPUT_DATA_HOSTDEPENDENCYDEFINITION:
2101 		result=ndo2db_handle_hostdependencydefinition(idi);
2102 		break;
2103 	case NDO2DB_INPUT_DATA_SERVICEDEPENDENCYDEFINITION:
2104 		result=ndo2db_handle_servicedependencydefinition(idi);
2105 		break;
2106 	case NDO2DB_INPUT_DATA_HOSTESCALATIONDEFINITION:
2107 		result=ndo2db_handle_hostescalationdefinition(idi);
2108 		break;
2109 	case NDO2DB_INPUT_DATA_SERVICEESCALATIONDEFINITION:
2110 		result=ndo2db_handle_serviceescalationdefinition(idi);
2111 		break;
2112 	case NDO2DB_INPUT_DATA_COMMANDDEFINITION:
2113 		result=ndo2db_handle_commanddefinition(idi);
2114 		break;
2115 	case NDO2DB_INPUT_DATA_TIMEPERIODDEFINITION:
2116 		result=ndo2db_handle_timeperiodefinition(idi);
2117 		break;
2118 	case NDO2DB_INPUT_DATA_CONTACTDEFINITION:
2119 		result=ndo2db_handle_contactdefinition(idi);
2120 		break;
2121 	case NDO2DB_INPUT_DATA_CONTACTGROUPDEFINITION:
2122 		result=ndo2db_handle_contactgroupdefinition(idi);
2123 		break;
2124 	case NDO2DB_INPUT_DATA_HOSTEXTINFODEFINITION:
2125 		/* deprecated - merged with host definitions */
2126 		break;
2127 	case NDO2DB_INPUT_DATA_SERVICEEXTINFODEFINITION:
2128 		/* deprecated - merged with service definitions */
2129 		break;
2130 	case NDO2DB_INPUT_DATA_ACTIVEOBJECTSLIST:
2131 		result = ndo2db_handle_activeobjectlist(idi);
2132 		break;
2133 
2134 	default:
2135 		break;
2136 	        }
2137 
2138 	/* free input memory */
2139 	ndo2db_free_input_memory(idi);
2140 
2141 	/* adjust items processed */
2142 	idi->entries_processed++;
2143 
2144 	/* perform periodic maintenance... */
2145 	ndo2db_db_perform_maintenance(idi);
2146 
2147 	return result;
2148         }
2149 
2150 
2151 /* free memory allocated to data input */
ndo2db_free_input_memory(ndo2db_idi * idi)2152 int ndo2db_free_input_memory(ndo2db_idi *idi){
2153 	register int x=0;
2154 	register int y=0;
2155 
2156 	if(idi==NULL)
2157 		return NDO_ERROR;
2158 
2159 	/* free memory allocated to single-instance data buffers */
2160 	if(idi->buffered_input){
2161 
2162 		for(x=0;x<NDO_MAX_DATA_TYPES;x++){
2163 			if(idi->buffered_input[x])
2164 				free(idi->buffered_input[x]);
2165 			idi->buffered_input[x]=NULL;
2166 	                }
2167 
2168 		free(idi->buffered_input);
2169 		idi->buffered_input=NULL;
2170 	        }
2171 
2172 	/* free memory allocated to multi-instance data buffers */
2173 	if(idi->mbuf){
2174 		for(x=0;x<NDO2DB_MAX_MBUF_ITEMS;x++){
2175 			if(idi->mbuf[x].buffer){
2176 				for(y=0;y<idi->mbuf[x].used_lines;y++){
2177 					if(idi->mbuf[x].buffer[y]){
2178 						free(idi->mbuf[x].buffer[y]);
2179 						idi->mbuf[x].buffer[y]=NULL;
2180 						}
2181 					}
2182 				free(idi->mbuf[x].buffer);
2183 				idi->mbuf[x].buffer=NULL;
2184 				}
2185 			idi->mbuf[x].used_lines=0;
2186 			idi->mbuf[x].allocated_lines=0;
2187 			}
2188 		}
2189 
2190 	return NDO_OK;
2191 	}
2192 
2193 
2194 /* free memory allocated to connection */
ndo2db_free_connection_memory(ndo2db_idi * idi)2195 int ndo2db_free_connection_memory(ndo2db_idi *idi){
2196 
2197 	if(idi->instance_name){
2198 		free(idi->instance_name);
2199 		idi->instance_name=NULL;
2200 		}
2201 	if(idi->agent_name){
2202 		free(idi->agent_name);
2203 		idi->agent_name=NULL;
2204 		}
2205 	if(idi->agent_version){
2206 		free(idi->agent_version);
2207 		idi->agent_version=NULL;
2208 		}
2209 	if(idi->disposition){
2210 		free(idi->disposition);
2211 		idi->disposition=NULL;
2212 		}
2213 	if(idi->connect_source){
2214 		free(idi->connect_source);
2215 		idi->connect_source=NULL;
2216 		}
2217 	if(idi->connect_type){
2218 		free(idi->connect_type);
2219 		idi->connect_type=NULL;
2220 		}
2221 
2222 	return NDO_OK;
2223 	}
2224 
2225 
2226 
2227 /****************************************************************************/
2228 /* DATA TYPE CONVERSION ROUTINES                                            */
2229 /****************************************************************************/
2230 
ndo2db_convert_standard_data_elements(ndo2db_idi * idi,int * type,int * flags,int * attr,struct timeval * tstamp)2231 int ndo2db_convert_standard_data_elements(ndo2db_idi *idi, int *type, int *flags, int *attr, struct timeval *tstamp){
2232 	int result1=NDO_OK;
2233 	int result2=NDO_OK;
2234 	int result3=NDO_OK;
2235 	int result4=NDO_OK;
2236 
2237 	result1=ndo2db_convert_string_to_int(idi->buffered_input[NDO_DATA_TYPE],type);
2238 	result2=ndo2db_convert_string_to_int(idi->buffered_input[NDO_DATA_FLAGS],flags);
2239 	result3=ndo2db_convert_string_to_int(idi->buffered_input[NDO_DATA_ATTRIBUTES],attr);
2240 	result4=ndo2db_convert_string_to_timeval(idi->buffered_input[NDO_DATA_TIMESTAMP],tstamp);
2241 
2242 	if(result1==NDO_ERROR || result2==NDO_ERROR || result3==NDO_ERROR || result4==NDO_ERROR)
2243 		return NDO_ERROR;
2244 
2245 	return NDO_OK;
2246         }
2247 
2248 
ndo2db_convert_string_to_int(char * buf,int * i)2249 int ndo2db_convert_string_to_int(char *buf, int *i){
2250 
2251 	if(buf==NULL)
2252 		return NDO_ERROR;
2253 
2254 	*i=atoi(buf);
2255 
2256 	return NDO_OK;
2257         }
2258 
2259 
ndo2db_convert_string_to_float(char * buf,float * f)2260 int ndo2db_convert_string_to_float(char *buf, float *f){
2261 	char *endptr=NULL;
2262 
2263 	if(buf==NULL)
2264 		return NDO_ERROR;
2265 
2266 #ifdef HAVE_STRTOF
2267 	*f=strtof(buf,&endptr);
2268 #else
2269 	/* Solaris 8 doesn't have strtof() */
2270 	*f=(float)strtod(buf,&endptr);
2271 #endif
2272 
2273 	if(*f==0 && (endptr==buf || errno==ERANGE))
2274 		return NDO_ERROR;
2275 	if(errno==ERANGE)
2276 		return NDO_ERROR;
2277 
2278 	return NDO_OK;
2279         }
2280 
2281 
ndo2db_convert_string_to_double(char * buf,double * d)2282 int ndo2db_convert_string_to_double(char *buf, double *d){
2283 	char *endptr=NULL;
2284 
2285 	if(buf==NULL)
2286 		return NDO_ERROR;
2287 
2288 	*d=strtod(buf,&endptr);
2289 
2290 	if(*d==0 && (endptr==buf || errno==ERANGE))
2291 		return NDO_ERROR;
2292 	if(errno==ERANGE)
2293 		return NDO_ERROR;
2294 
2295 	return NDO_OK;
2296         }
2297 
2298 
ndo2db_convert_string_to_long(char * buf,long * l)2299 int ndo2db_convert_string_to_long(char *buf, long *l){
2300 	char *endptr=NULL;
2301 
2302 	if(buf==NULL)
2303 		return NDO_ERROR;
2304 
2305 	*l=strtol(buf,&endptr,0);
2306 
2307 	if(*l==LONG_MAX && errno==ERANGE)
2308 		return NDO_ERROR;
2309 	if(*l==0L && endptr==buf)
2310 		return NDO_ERROR;
2311 
2312 	return NDO_OK;
2313         }
2314 
2315 
ndo2db_convert_string_to_unsignedlong(char * buf,unsigned long * ul)2316 int ndo2db_convert_string_to_unsignedlong(char *buf, unsigned long *ul){
2317 	char *endptr=NULL;
2318 
2319 	if(buf==NULL)
2320 		return NDO_ERROR;
2321 
2322 	*ul=strtoul(buf,&endptr,0);
2323 
2324 	if(*ul==ULONG_MAX && errno==ERANGE)
2325 		return NDO_ERROR;
2326 	if(*ul==0L && endptr==buf)
2327 		return NDO_ERROR;
2328 
2329 	return NDO_OK;
2330         }
2331 
2332 
ndo2db_convert_string_to_timeval(char * buf,struct timeval * tv)2333 int ndo2db_convert_string_to_timeval(char *buf, struct timeval *tv){
2334 	char *newbuf=NULL;
2335 	char *ptr=NULL;
2336 	int result=NDO_OK;
2337 
2338 	if(buf==NULL)
2339 		return NDO_ERROR;
2340 
2341 	tv->tv_sec=(time_t)0L;
2342 	tv->tv_usec=0;
2343 
2344 	if((newbuf=strdup(buf))==NULL)
2345 		return NDO_ERROR;
2346 
2347 	ptr=strtok(newbuf,".");
2348 	if((result=ndo2db_convert_string_to_unsignedlong(ptr,(unsigned long *)&tv->tv_sec))==NDO_OK){
2349 		ptr=strtok(NULL,"\n");
2350 		result=ndo2db_convert_string_to_unsignedlong(ptr,(unsigned long *)&tv->tv_usec);
2351 	        }
2352 
2353 	free(newbuf);
2354 
2355 	if(result==NDO_ERROR)
2356 		return NDO_ERROR;
2357 
2358 	return NDO_OK;
2359         }
2360 
2361 
2362 
2363 /****************************************************************************/
2364 /* LOGGING ROUTINES                                                         */
2365 /****************************************************************************/
2366 
2367 /* opens the debug log for writing */
ndo2db_open_debug_log(void)2368 int ndo2db_open_debug_log(void){
2369 
2370 	/* don't do anything if we're not debugging */
2371 	if(ndo2db_debug_level==NDO2DB_DEBUGL_NONE)
2372 		return NDO_OK;
2373 
2374 	if((ndo2db_debug_file_fp=fopen(ndo2db_debug_file,"a+"))==NULL) {
2375 		syslog(LOG_ERR, "Warning: Could not open debug file '%s' - '%s'", ndo2db_debug_file, strerror(errno));
2376 		return NDO_ERROR;
2377 	}
2378 
2379 	return NDO_OK;
2380 	}
2381 
2382 
2383 /* closes the debug log */
ndo2db_close_debug_log(void)2384 int ndo2db_close_debug_log(void){
2385 
2386 	if(ndo2db_debug_file_fp!=NULL)
2387 		fclose(ndo2db_debug_file_fp);
2388 
2389 	ndo2db_debug_file_fp=NULL;
2390 
2391 	return NDO_OK;
2392 	}
2393 
2394 
2395 /* write to the debug log */
ndo2db_log_debug_info(int level,int verbosity,const char * fmt,...)2396 int ndo2db_log_debug_info(int level, int verbosity, const char *fmt, ...){
2397 	va_list ap;
2398 	char *temp_path=NULL;
2399 	struct timeval current_time;
2400 
2401 	if(!(ndo2db_debug_level==NDO2DB_DEBUGL_ALL || (level & ndo2db_debug_level)))
2402 		return NDO_OK;
2403 
2404 	if(verbosity>ndo2db_debug_verbosity)
2405 		return NDO_OK;
2406 
2407 	if(ndo2db_debug_file_fp==NULL)
2408 		return NDO_ERROR;
2409 
2410 	/* write the timestamp */
2411 	gettimeofday(&current_time,NULL);
2412 	fprintf(ndo2db_debug_file_fp,"[%lu.%06lu] [%03d.%d] [pid=%lu] ",current_time.tv_sec,current_time.tv_usec,level,verbosity,(unsigned long)getpid());
2413 
2414 	/* write the data */
2415 	va_start(ap,fmt);
2416 	vfprintf(ndo2db_debug_file_fp,fmt,ap);
2417 	va_end(ap);
2418 
2419 	/* flush, so we don't have problems tailing or when fork()ing */
2420 	fflush(ndo2db_debug_file_fp);
2421 
2422 	/* if file has grown beyond max, rotate it */
2423 	if((unsigned long)ftell(ndo2db_debug_file_fp)>ndo2db_max_debug_file_size && ndo2db_max_debug_file_size>0L){
2424 
2425 		/* close the file */
2426 		ndo2db_close_debug_log();
2427 
2428 		/* rotate the log file */
2429 		asprintf(&temp_path,"%s.old",ndo2db_debug_file);
2430 		if(temp_path){
2431 
2432 			/* unlink the old debug file */
2433 			unlink(temp_path);
2434 
2435 			/* rotate the debug file */
2436 			my_rename(ndo2db_debug_file,temp_path);
2437 
2438 			/* free memory */
2439 			my_free(temp_path);
2440 			}
2441 
2442 		/* open a new file */
2443 		ndo2db_open_debug_log();
2444 		}
2445 
2446 	return NDO_OK;
2447 	}
2448 
2449