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(¤t_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