/***************************************************************************** * * CONFIG.C - Configuration input and verification routines for Nagios * * * License: * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************************************/ #include "../include/config.h" #include "../include/common.h" #include "../include/objects.h" #include "../include/macros.h" #include "../include/nagios.h" #include "../include/broker.h" #include "../include/nebmods.h" #include "../include/nebmodules.h" /*** helpers ****/ /* * find a command with arguments still attached * if we're unsuccessful, the buffer pointed to by 'name' is modified * to have only the real command name (everything up until the first '!') */ static command *find_bang_command(char *name) { char *bang; command *cmd; if (!name) return NULL; bang = strchr(name, '!'); if (!bang) return find_command(name); *bang = 0; cmd = find_command(name); *bang = '!'; return cmd; } /******************************************************************/ /************** CONFIGURATION INPUT FUNCTIONS *********************/ /******************************************************************/ /* read all configuration data */ int read_all_object_data(char *main_config_file) { int result = OK; int options = 0; options = READ_ALL_OBJECT_DATA; /* read in all host configuration data from external sources */ result = read_object_config_data(main_config_file, options); if(result != OK) return ERROR; return OK; } static objectlist *deprecated = NULL; static void obsoleted_warning(const char *key, const char *msg) { char *buf; asprintf(&buf, "Warning: %s is deprecated and will be removed.%s%s\n", key, msg ? " " : "", msg ? msg : ""); if (!buf) return; prepend_object_to_objectlist(&deprecated, buf); } /* process the main configuration file */ int read_main_config_file(char *main_config_file) { char *input = NULL; char *variable = NULL; char *value = NULL; char *error_message = NULL; char *temp_ptr = NULL; mmapfile *thefile = NULL; int current_line = 0; int error = FALSE; char *modptr = NULL; char *argptr = NULL; DIR *tmpdir = NULL; nagios_macros *mac; objectlist *list; mac = get_global_macros(); /* open the config file for reading */ if((thefile = mmap_fopen(main_config_file)) == NULL) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: Cannot open main configuration file '%s' for reading!", main_config_file); exit(ERROR); } /* save the main config file macro */ my_free(mac->x[MACRO_MAINCONFIGFILE]); if((mac->x[MACRO_MAINCONFIGFILE] = (char *)strdup(main_config_file))) strip(mac->x[MACRO_MAINCONFIGFILE]); /* process all lines in the config file */ while(1) { /* free memory */ my_free(input); my_free(variable); my_free(value); /* read the next line */ if((input = mmap_fgets_multiline(thefile)) == NULL) break; current_line = thefile->current_line; strip(input); /* skip blank lines and comments */ if(input[0] == '\x0' || input[0] == '#') continue; /* get the variable name */ if((temp_ptr = my_strtok_with_free(input, "=", FALSE)) == NULL) { asprintf(&error_message, "NULL variable"); error = TRUE; break; } if((variable = (char *)strdup(temp_ptr)) == NULL) { asprintf(&error_message, "malloc() error"); error = TRUE; break; } /* get the value */ if((temp_ptr = my_strtok_with_free(NULL, "\n", FALSE)) == NULL) { asprintf(&error_message, "NULL value"); error = TRUE; break; } if((value = (char *)strdup(temp_ptr)) == NULL) { asprintf(&error_message, "malloc() error"); error = TRUE; break; } temp_ptr = my_strtok_with_free(NULL, "\n", TRUE); strip(variable); strip(value); /* process the variable/value */ if(!strcmp(variable, "resource_file")) { /* save the macro */ my_free(mac->x[MACRO_RESOURCEFILE]); mac->x[MACRO_RESOURCEFILE] = nspath_absolute(value, config_file_dir); /* process the resource file */ if(read_resource_file(mac->x[MACRO_RESOURCEFILE]) == ERROR) { error = TRUE; } } else if(!strcmp(variable, "website_url")) { int lth; my_free(website_url); website_url = strdup(value); lth = strlen(website_url); if (website_url[lth-1] == '/') website_url[lth-1] = '\0'; } else if(!strcmp(variable, "loadctl_options")) error = set_loadctl_options(value, strlen(value)) != OK; else if(!strcmp(variable, "check_workers")) num_check_workers = atoi(value); else if(!strcmp(variable, "query_socket")) { my_free(qh_socket_path); qh_socket_path = nspath_absolute(value, config_file_dir); } else if(!strcmp(variable, "log_file")) { if(strlen(value) > MAX_FILENAME_LENGTH - 1) { asprintf(&error_message, "Log file is too long"); error = TRUE; break; } my_free(log_file); log_file = nspath_absolute(value, config_file_dir); /* make sure the configured logfile takes effect */ close_log_file(); } else if(!strcmp(variable, "debug_level")) debug_level = atoi(value); else if(!strcmp(variable, "debug_verbosity")) debug_verbosity = atoi(value); else if(!strcmp(variable, "debug_file")) { if(strlen(value) > MAX_FILENAME_LENGTH - 1) { asprintf(&error_message, "Debug log file is too long"); error = TRUE; break; } my_free(debug_file); debug_file = nspath_absolute(value, config_file_dir); } else if(!strcmp(variable, "max_debug_file_size")) max_debug_file_size = strtoul(value, NULL, 0); else if(!strcmp(variable, "command_file")) { if(strlen(value) > MAX_FILENAME_LENGTH - 1) { asprintf(&error_message, "Command file is too long"); error = TRUE; break; } my_free(command_file); command_file = nspath_absolute(value, config_file_dir); /* save the macro */ mac->x[MACRO_COMMANDFILE] = command_file; } else if(!strcmp(variable, "temp_file")) { my_free(temp_file); temp_file = strdup(value); } else if(!strcmp(variable, "temp_path")) { my_free(temp_path); temp_path = nspath_absolute(value, config_file_dir); } else if(!strcmp(variable, "check_result_path")) { if(strlen(value) > MAX_FILENAME_LENGTH - 1) { asprintf(&error_message, "Check result path is too long"); error = TRUE; break; } my_free(check_result_path); check_result_path = nspath_absolute(value, config_file_dir); /* make sure we don't have a trailing slash */ if(check_result_path[strlen(check_result_path) - 1] == '/') check_result_path[strlen(check_result_path) - 1] = '\x0'; if((tmpdir = opendir(check_result_path)) == NULL) { asprintf(&error_message, "Check result path '%s' is not a valid directory", check_result_path); error = TRUE; break; } closedir(tmpdir); } else if(!strcmp(variable, "max_check_result_file_age")) max_check_result_file_age = strtoul(value, NULL, 0); else if(!strcmp(variable, "lock_file")) { if(strlen(value) > MAX_FILENAME_LENGTH - 1) { asprintf(&error_message, "Lock file is too long"); error = TRUE; break; } my_free(lock_file); lock_file = nspath_absolute(value, config_file_dir); } else if(!strcmp(variable, "global_host_event_handler")) { my_free(global_host_event_handler); global_host_event_handler = (char *)strdup(value); } else if(!strcmp(variable, "global_service_event_handler")) { my_free(global_service_event_handler); global_service_event_handler = (char *)strdup(value); } else if(!strcmp(variable, "ocsp_command")) { my_free(ocsp_command); ocsp_command = (char *)strdup(value); } else if(!strcmp(variable, "ochp_command")) { my_free(ochp_command); ochp_command = (char *)strdup(value); } else if(!strcmp(variable, "nagios_user")) { my_free(nagios_user); nagios_user = (char *)strdup(value); } else if(!strcmp(variable, "nagios_group")) { my_free(nagios_group); nagios_group = (char *)strdup(value); } else if(!strcmp(variable, "admin_email")) { /* save the macro */ my_free(mac->x[MACRO_ADMINEMAIL]); mac->x[MACRO_ADMINEMAIL] = (char *)strdup(value); } else if(!strcmp(variable, "admin_pager")) { /* save the macro */ my_free(mac->x[MACRO_ADMINPAGER]); mac->x[MACRO_ADMINPAGER] = (char *)strdup(value); } else if(!strcmp(variable, "use_syslog")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for use_syslog"); error = TRUE; break; } use_syslog = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_notifications")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for log_notifications"); error = TRUE; break; } log_notifications = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_service_retries")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for log_service_retries"); error = TRUE; break; } log_service_retries = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_host_retries")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for log_host_retries"); error = TRUE; break; } log_host_retries = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_event_handlers")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for log_event_handlers"); error = TRUE; break; } log_event_handlers = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_external_commands")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for log_external_commands"); error = TRUE; break; } log_external_commands = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_passive_checks")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for log_passive_checks"); error = TRUE; break; } log_passive_checks = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_initial_states")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for log_initial_states"); error = TRUE; break; } log_initial_states = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_current_states")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for log_current_states"); error = TRUE; break; } log_current_states = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "retain_state_information")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for retain_state_information"); error = TRUE; break; } retain_state_information = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "retention_update_interval")) { retention_update_interval = atoi(value); if(retention_update_interval < 0) { asprintf(&error_message, "Illegal value for retention_update_interval"); error = TRUE; break; } } else if(!strcmp(variable, "use_retained_program_state")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for use_retained_program_state"); error = TRUE; break; } use_retained_program_state = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "use_retained_scheduling_info")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for use_retained_scheduling_info"); error = TRUE; break; } use_retained_scheduling_info = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "retention_scheduling_horizon")) { retention_scheduling_horizon = atoi(value); if(retention_scheduling_horizon <= 0) { asprintf(&error_message, "Illegal value for retention_scheduling_horizon"); error = TRUE; break; } } else if(!strcmp(variable, "additional_freshness_latency")) additional_freshness_latency = atoi(value); else if(!strcmp(variable, "retained_host_attribute_mask")) retained_host_attribute_mask = strtoul(value, NULL, 0); else if(!strcmp(variable, "retained_service_attribute_mask")) retained_service_attribute_mask = strtoul(value, NULL, 0); else if(!strcmp(variable, "retained_process_host_attribute_mask")) retained_process_host_attribute_mask = strtoul(value, NULL, 0); else if(!strcmp(variable, "retained_process_service_attribute_mask")) retained_process_service_attribute_mask = strtoul(value, NULL, 0); else if(!strcmp(variable, "retained_contact_host_attribute_mask")) retained_contact_host_attribute_mask = strtoul(value, NULL, 0); else if(!strcmp(variable, "retained_contact_service_attribute_mask")) retained_contact_service_attribute_mask = strtoul(value, NULL, 0); else if(!strcmp(variable, "obsess_over_services")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for obsess_over_services"); error = TRUE; break; } obsess_over_services = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "obsess_over_hosts")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for obsess_over_hosts"); error = TRUE; break; } obsess_over_hosts = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "translate_passive_host_checks")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for translate_passive_host_checks"); error = TRUE; break; } translate_passive_host_checks = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "passive_host_checks_are_soft")) passive_host_checks_are_soft = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "service_check_timeout")) { service_check_timeout = atoi(value); if(service_check_timeout <= 0) { asprintf(&error_message, "Illegal value for service_check_timeout"); error = TRUE; break; } } else if(!strcmp(variable,"service_check_timeout_state")){ if(!strcmp(value,"o")) service_check_timeout_state=STATE_OK; else if(!strcmp(value,"w")) service_check_timeout_state=STATE_WARNING; else if(!strcmp(value,"c")) service_check_timeout_state=STATE_CRITICAL; else if(!strcmp(value,"u")) service_check_timeout_state=STATE_UNKNOWN; else{ asprintf(&error_message,"Illegal value for service_check_timeout_state"); error=TRUE; break; } } else if(!strcmp(variable, "host_check_timeout")) { host_check_timeout = atoi(value); if(host_check_timeout <= 0) { asprintf(&error_message, "Illegal value for host_check_timeout"); error = TRUE; break; } } else if(!strcmp(variable, "event_handler_timeout")) { event_handler_timeout = atoi(value); if(event_handler_timeout <= 0) { asprintf(&error_message, "Illegal value for event_handler_timeout"); error = TRUE; break; } } else if(!strcmp(variable, "notification_timeout")) { notification_timeout = atoi(value); if(notification_timeout <= 0) { asprintf(&error_message, "Illegal value for notification_timeout"); error = TRUE; break; } } else if(!strcmp(variable, "ocsp_timeout")) { ocsp_timeout = atoi(value); if(ocsp_timeout <= 0) { asprintf(&error_message, "Illegal value for ocsp_timeout"); error = TRUE; break; } } else if(!strcmp(variable, "ochp_timeout")) { ochp_timeout = atoi(value); if(ochp_timeout <= 0) { asprintf(&error_message, "Illegal value for ochp_timeout"); error = TRUE; break; } } else if(!strcmp(variable, "use_agressive_host_checking") || !strcmp(variable, "use_aggressive_host_checking")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for use_aggressive_host_checking"); error = TRUE; break; } use_aggressive_host_checking = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "cached_host_check_horizon")) cached_host_check_horizon = strtoul(value, NULL, 0); else if(!strcmp(variable, "enable_predictive_host_dependency_checks")) enable_predictive_host_dependency_checks = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "cached_service_check_horizon")) cached_service_check_horizon = strtoul(value, NULL, 0); else if(!strcmp(variable, "enable_predictive_service_dependency_checks")) enable_predictive_service_dependency_checks = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "soft_state_dependencies")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for soft_state_dependencies"); error = TRUE; break; } soft_state_dependencies = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "log_rotation_method")) { if(!strcmp(value, "n")) log_rotation_method = LOG_ROTATION_NONE; else if(!strcmp(value, "h")) log_rotation_method = LOG_ROTATION_HOURLY; else if(!strcmp(value, "d")) log_rotation_method = LOG_ROTATION_DAILY; else if(!strcmp(value, "w")) log_rotation_method = LOG_ROTATION_WEEKLY; else if(!strcmp(value, "m")) log_rotation_method = LOG_ROTATION_MONTHLY; else { asprintf(&error_message, "Illegal value for log_rotation_method"); error = TRUE; break; } } else if(!strcmp(variable, "log_archive_path")) { if(strlen(value) > MAX_FILENAME_LENGTH - 1) { asprintf(&error_message, "Log archive path too long"); error = TRUE; break; } my_free(log_archive_path); log_archive_path = nspath_absolute(value, config_file_dir); } else if(!strcmp(variable, "enable_event_handlers")) enable_event_handlers = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "enable_notifications")) enable_notifications = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "execute_service_checks")) execute_service_checks = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "accept_passive_service_checks")) accept_passive_service_checks = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "execute_host_checks")) execute_host_checks = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "accept_passive_host_checks")) accept_passive_host_checks = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "service_inter_check_delay_method")) { if(!strcmp(value, "n")) service_inter_check_delay_method = ICD_NONE; else if(!strcmp(value, "d")) service_inter_check_delay_method = ICD_DUMB; else if(!strcmp(value, "s")) service_inter_check_delay_method = ICD_SMART; else { service_inter_check_delay_method = ICD_USER; scheduling_info.service_inter_check_delay = strtod(value, NULL); if(scheduling_info.service_inter_check_delay <= 0.0) { asprintf(&error_message, "Illegal value for service_inter_check_delay_method"); error = TRUE; break; } } } else if(!strcmp(variable, "max_service_check_spread")) { strip(value); max_service_check_spread = atoi(value); if(max_service_check_spread < 1) { asprintf(&error_message, "Illegal value for max_service_check_spread"); error = TRUE; break; } } else if(!strcmp(variable, "host_inter_check_delay_method")) { if(!strcmp(value, "n")) host_inter_check_delay_method = ICD_NONE; else if(!strcmp(value, "d")) host_inter_check_delay_method = ICD_DUMB; else if(!strcmp(value, "s")) host_inter_check_delay_method = ICD_SMART; else { host_inter_check_delay_method = ICD_USER; scheduling_info.host_inter_check_delay = strtod(value, NULL); if(scheduling_info.host_inter_check_delay <= 0.0) { asprintf(&error_message, "Illegal value for host_inter_check_delay_method"); error = TRUE; break; } } } else if(!strcmp(variable, "max_host_check_spread")) { max_host_check_spread = atoi(value); if(max_host_check_spread < 1) { asprintf(&error_message, "Illegal value for max_host_check_spread"); error = TRUE; break; } } else if(!strcmp(variable, "service_interleave_factor")) { if(!strcmp(value, "s")) service_interleave_factor_method = ILF_SMART; else { service_interleave_factor_method = ILF_USER; scheduling_info.service_interleave_factor = atoi(value); if(scheduling_info.service_interleave_factor < 1) scheduling_info.service_interleave_factor = 1; } } else if(!strcmp(variable, "max_concurrent_checks")) { max_parallel_service_checks = atoi(value); if(max_parallel_service_checks < 0) { asprintf(&error_message, "Illegal value for max_concurrent_checks"); error = TRUE; break; } } else if(!strcmp(variable, "check_result_reaper_frequency") || !strcmp(variable, "service_reaper_frequency")) { check_reaper_interval = atoi(value); if(check_reaper_interval < 1) { asprintf(&error_message, "Illegal value for check_result_reaper_frequency"); error = TRUE; break; } } else if(!strcmp(variable, "max_check_result_reaper_time")) { max_check_reaper_time = atoi(value); if(max_check_reaper_time < 1) { asprintf(&error_message, "Illegal value for max_check_result_reaper_time"); error = TRUE; break; } } else if(!strcmp(variable, "sleep_time")) { obsoleted_warning(variable, NULL); } else if(!strcmp(variable, "interval_length")) { interval_length = atoi(value); if(interval_length < 1) { asprintf(&error_message, "Illegal value for interval_length"); error = TRUE; break; } } else if(!strcmp(variable, "check_external_commands")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for check_external_commands"); error = TRUE; break; } check_external_commands = (atoi(value) > 0) ? TRUE : FALSE; } /* @todo Remove before Nagios 4.3 */ else if(!strcmp(variable, "command_check_interval")) { obsoleted_warning(variable, "Commands are always handled on arrival"); } else if(!strcmp(variable, "check_for_orphaned_services")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for check_for_orphaned_services"); error = TRUE; break; } check_orphaned_services = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "check_for_orphaned_hosts")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for check_for_orphaned_hosts"); error = TRUE; break; } check_orphaned_hosts = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "check_service_freshness")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for check_service_freshness"); error = TRUE; break; } check_service_freshness = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "check_host_freshness")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for check_host_freshness"); error = TRUE; break; } check_host_freshness = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "service_freshness_check_interval") || !strcmp(variable, "freshness_check_interval")) { service_freshness_check_interval = atoi(value); if(service_freshness_check_interval <= 0) { asprintf(&error_message, "Illegal value for service_freshness_check_interval"); error = TRUE; break; } } else if(!strcmp(variable, "host_freshness_check_interval")) { host_freshness_check_interval = atoi(value); if(host_freshness_check_interval <= 0) { asprintf(&error_message, "Illegal value for host_freshness_check_interval"); error = TRUE; break; } } else if(!strcmp(variable, "auto_reschedule_checks")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for auto_reschedule_checks"); error = TRUE; break; } auto_reschedule_checks = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "auto_rescheduling_interval")) { auto_rescheduling_interval = atoi(value); if(auto_rescheduling_interval <= 0) { asprintf(&error_message, "Illegal value for auto_rescheduling_interval"); error = TRUE; break; } } else if(!strcmp(variable, "auto_rescheduling_window")) { auto_rescheduling_window = atoi(value); if(auto_rescheduling_window <= 0) { asprintf(&error_message, "Illegal value for auto_rescheduling_window"); error = TRUE; break; } } else if(!strcmp(variable, "status_update_interval")) { status_update_interval = atoi(value); if(status_update_interval < 1) { asprintf(&error_message, "Illegal value for status_update_interval"); error = TRUE; break; } } else if(!strcmp(variable, "time_change_threshold")) { time_change_threshold = atoi(value); if(time_change_threshold <= 5) { asprintf(&error_message, "Illegal value for time_change_threshold"); error = TRUE; break; } } else if(!strcmp(variable, "process_performance_data")) process_performance_data = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "enable_flap_detection")) enable_flap_detection = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "enable_failure_prediction")) obsoleted_warning(variable, NULL); else if(!strcmp(variable, "low_service_flap_threshold")) { low_service_flap_threshold = strtod(value, NULL); if(low_service_flap_threshold <= 0.0 || low_service_flap_threshold >= 100.0) { asprintf(&error_message, "Illegal value for low_service_flap_threshold"); error = TRUE; break; } } else if(!strcmp(variable, "high_service_flap_threshold")) { high_service_flap_threshold = strtod(value, NULL); if(high_service_flap_threshold <= 0.0 || high_service_flap_threshold > 100.0) { asprintf(&error_message, "Illegal value for high_service_flap_threshold"); error = TRUE; break; } } else if(!strcmp(variable, "low_host_flap_threshold")) { low_host_flap_threshold = strtod(value, NULL); if(low_host_flap_threshold <= 0.0 || low_host_flap_threshold >= 100.0) { asprintf(&error_message, "Illegal value for low_host_flap_threshold"); error = TRUE; break; } } else if(!strcmp(variable, "high_host_flap_threshold")) { high_host_flap_threshold = strtod(value, NULL); if(high_host_flap_threshold <= 0.0 || high_host_flap_threshold > 100.0) { asprintf(&error_message, "Illegal value for high_host_flap_threshold"); error = TRUE; break; } } else if(!strcmp(variable, "date_format")) { if(!strcmp(value, "euro")) date_format = DATE_FORMAT_EURO; else if(!strcmp(value, "iso8601")) date_format = DATE_FORMAT_ISO8601; else if(!strcmp(value, "strict-iso8601")) date_format = DATE_FORMAT_STRICT_ISO8601; else date_format = DATE_FORMAT_US; } else if(!strcmp(variable, "use_timezone")) { my_free(use_timezone); use_timezone = (char *)strdup(value); } else if(!strcmp(variable, "event_broker_options")) { if(!strcmp(value, "-1")) event_broker_options = BROKER_EVERYTHING; else event_broker_options = strtoul(value, NULL, 0); } else if(!strcmp(variable, "illegal_object_name_chars")) illegal_object_chars = (char *)strdup(value); else if(!strcmp(variable, "illegal_macro_output_chars")) illegal_output_chars = (char *)strdup(value); else if(!strcmp(variable, "broker_module")) { modptr = strtok(value, " \n"); argptr = strtok(NULL, "\n"); #ifdef USE_EVENT_BROKER modptr = nspath_absolute(modptr, config_file_dir); if (modptr) { neb_add_module(modptr, argptr, TRUE); free(modptr); } else { logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Failed to allocate module path memory for '%s'\n", value); } #endif } else if(!strcmp(variable, "use_regexp_matching")) use_regexp_matches = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "use_true_regexp_matching")) use_true_regexp_matching = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "daemon_dumps_core")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for daemon_dumps_core"); error = TRUE; break; } daemon_dumps_core = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "use_large_installation_tweaks")) { if(strlen(value) != 1 || value[0] < '0' || value[0] > '1') { asprintf(&error_message, "Illegal value for use_large_installation_tweaks "); error = TRUE; break; } use_large_installation_tweaks = (atoi(value) > 0) ? TRUE : FALSE; } else if(!strcmp(variable, "enable_environment_macros")) enable_environment_macros = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "free_child_process_memory")) free_child_process_memory = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "child_processes_fork_twice")) child_processes_fork_twice = (atoi(value) > 0) ? TRUE : FALSE; /*** embedded perl variables are deprecated now ***/ else if(!strcmp(variable, "enable_embedded_perl")) obsoleted_warning(variable, NULL); else if(!strcmp(variable, "use_embedded_perl_implicitly")) obsoleted_warning(variable, NULL); else if(!strcmp(variable, "auth_file")) obsoleted_warning(variable, NULL); else if(!strcmp(variable, "p1_file")) obsoleted_warning(variable, NULL); /*** as is external_command_buffer_slots */ else if(!strcmp(variable, "external_command_buffer_slots")) obsoleted_warning(variable, "All commands are always processed upon arrival"); else if(!strcmp(variable, "check_for_updates")) check_for_updates = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable, "bare_update_check")) bare_update_check = (atoi(value) > 0) ? TRUE : FALSE; /* BEGIN status data variables */ else if(!strcmp(variable, "status_file")) status_file = nspath_absolute(value, config_file_dir); else if(strstr(input, "state_retention_file=") == input) retention_file = nspath_absolute(value, config_file_dir); /* END status data variables */ /*** BEGIN perfdata variables ***/ else if(!strcmp(variable, "perfdata_timeout")) { perfdata_timeout = atoi(value); } else if(!strcmp(variable, "host_perfdata_command")) host_perfdata_command = (char *)strdup(value); else if(!strcmp(variable, "service_perfdata_command")) service_perfdata_command = (char *)strdup(value); else if(!strcmp(variable, "host_perfdata_file_template")) host_perfdata_file_template = (char *)strdup(value); else if(!strcmp(variable, "service_perfdata_file_template")) service_perfdata_file_template = (char *)strdup(value); else if(!strcmp(variable, "host_perfdata_file")) host_perfdata_file = nspath_absolute(value, config_file_dir); else if(!strcmp(variable, "service_perfdata_file")) service_perfdata_file = nspath_absolute(value, config_file_dir); else if(!strcmp(variable, "host_perfdata_file_mode")) { host_perfdata_file_pipe = FALSE; if(strstr(value, "p") != NULL) host_perfdata_file_pipe = TRUE; else if(strstr(value, "w") != NULL) host_perfdata_file_append = FALSE; else host_perfdata_file_append = TRUE; } else if(!strcmp(variable, "service_perfdata_file_mode")) { service_perfdata_file_pipe = FALSE; if(strstr(value, "p") != NULL) service_perfdata_file_pipe = TRUE; else if(strstr(value, "w") != NULL) service_perfdata_file_append = FALSE; else service_perfdata_file_append = TRUE; } else if(!strcmp(variable, "host_perfdata_file_processing_interval")) host_perfdata_file_processing_interval = strtoul(value, NULL, 0); else if(!strcmp(variable, "service_perfdata_file_processing_interval")) service_perfdata_file_processing_interval = strtoul(value, NULL, 0); else if(!strcmp(variable, "host_perfdata_file_processing_command")) host_perfdata_file_processing_command = (char *)strdup(value); else if(!strcmp(variable, "service_perfdata_file_processing_command")) service_perfdata_file_processing_command = (char *)strdup(value); else if(!strcmp(variable,"host_perfdata_process_empty_results")) host_perfdata_process_empty_results = (atoi(value) > 0) ? TRUE : FALSE; else if(!strcmp(variable,"service_perfdata_process_empty_results")) service_perfdata_process_empty_results = (atoi(value) > 0) ? TRUE : FALSE; /*** END perfdata variables */ else if(strstr(input, "cfg_file=") == input || strstr(input, "cfg_dir=") == input) continue; else if(strstr(input, "object_cache_file=") == input) { my_free(object_cache_file); object_cache_file = nspath_absolute(value, config_file_dir); my_free(mac->x[MACRO_OBJECTCACHEFILE]); mac->x[MACRO_OBJECTCACHEFILE] = strdup(object_cache_file); } else if(strstr(input, "precached_object_file=") == input) { my_free(object_precache_file); object_precache_file = nspath_absolute(value, config_file_dir); } else if(!strcmp(variable, "allow_empty_hostgroup_assignment")) { allow_empty_hostgroup_assignment = (atoi(value) > 0) ? TRUE : FALSE; } /* skip external data directives */ else if(strstr(input, "x") == input) continue; else if(!strcmp(variable,"host_down_disable_service_checks")) { host_down_disable_service_checks = strtoul(value, NULL, 0); } else if(!strcmp(variable,"service_skip_check_dependency_status")) { service_skip_check_dependency_status = atoi(value); if(service_skip_check_dependency_status < -1 || service_skip_check_dependency_status > 3) { asprintf(&error_message, "Illegal value for service_skip_check_dependency_status"); error = TRUE; break; } } else if(!strcmp(variable,"service_skip_check_parent_status")) { service_skip_check_parent_status = atoi(value); if(service_skip_check_parent_status < -1 || service_skip_check_parent_status > 3) { asprintf(&error_message, "Illegal value for service_skip_check_parent_status"); error = TRUE; break; } } else if(!strcmp(variable,"service_skip_check_host_down_status")) { service_skip_check_host_down_status = atoi(value); if(service_skip_check_host_down_status < -1 || service_skip_check_host_down_status > 3) { asprintf(&error_message, "Illegal value for service_skip_check_host_down_status"); error = TRUE; break; } } else if(!strcmp(variable,"host_skip_check_dependency_status")) { host_skip_check_dependency_status = atoi(value); if(host_skip_check_dependency_status < -1 || host_skip_check_dependency_status > 3) { asprintf(&error_message, "Illegal value for host_skip_check_dependency_status"); error = TRUE; break; } } /* we don't know what this variable is... */ else { asprintf(&error_message, "UNKNOWN VARIABLE"); error = TRUE; break; } } if (deprecated) { for (list = deprecated; list; list = list->next) { logit(NSLOG_CONFIG_WARNING, TRUE, "%s", (char *)list->object_ptr); free(list->object_ptr); } free_objectlist(&deprecated); deprecated = NULL; } if (!temp_path && !(temp_path = getenv("TMPDIR")) && !(temp_path = getenv("TMP"))) { temp_path = strdup("/tmp"); } else { /* make sure we don't have a trailing slash */ if(temp_path[strlen(temp_path) - 1] == '/') temp_path[strlen(temp_path) - 1] = '\x0'; } if((strlen(temp_path) > MAX_FILENAME_LENGTH - 1)) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: temp_path is too long\n"); return ERROR; } if((tmpdir = opendir(temp_path)) == NULL) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: temp_path '%s' is not a valid directory\n", temp_path); return ERROR; } closedir(tmpdir); /* now that we know we have temp_path, we can set temp_file properly */ if (!temp_file) { temp_file = nspath_absolute("nagios.tmp", temp_path); } else if (*temp_file == '.') { /* temp_file is relative. Make it nagios.cfg-relative */ char *foo = temp_file; temp_file = nspath_absolute(temp_file, config_file_dir); free(foo); } else if (*temp_file != '/') { /* * tempfile is not relative and not absolute, so * put it in temp_path */ char *foo = temp_file; temp_file = nspath_absolute(temp_file, temp_path); free(foo); } if(strlen(temp_file) > MAX_FILENAME_LENGTH - 1) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: Temp file '%s' is too long\n", temp_file); return ERROR; } /* save the macros */ mac->x[MACRO_TEMPPATH] = temp_path; mac->x[MACRO_TEMPFILE] = temp_file; /* adjust timezone values */ if(use_timezone != NULL) set_environment_var("TZ", use_timezone, 1); tzset(); /* adjust tweaks */ if(free_child_process_memory == -1) free_child_process_memory = (use_large_installation_tweaks == TRUE) ? FALSE : TRUE; if(child_processes_fork_twice == -1) child_processes_fork_twice = (use_large_installation_tweaks == TRUE) ? FALSE : TRUE; /* handle errors */ if(error == TRUE) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error in configuration file '%s' - Line %d (%s)", main_config_file, current_line, (error_message == NULL) ? "NULL" : error_message); return ERROR; } /* free leftover memory and close the file */ my_free(input); mmap_fclose(thefile); /* free memory */ my_free(error_message); my_free(input); my_free(variable); my_free(value); /* make sure a log file has been specified */ if(log_file == NULL) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: Log file is not specified anywhere in main config file '%s'!", main_config_file); exit(ERROR); } strip(log_file); return OK; } /* processes macros in resource file */ int read_resource_file(char *resource_file) { char *input = NULL; char *variable = NULL; char *value = NULL; char *temp_ptr = NULL; mmapfile *thefile = NULL; int current_line = 1; int error = FALSE; int user_index = 0; if((thefile = mmap_fopen(resource_file)) == NULL) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: Cannot open resource file '%s' for reading!", resource_file); return ERROR; } /* process all lines in the resource file */ while(1) { /* free memory */ my_free(input); my_free(variable); my_free(value); /* read the next line */ if((input = mmap_fgets_multiline(thefile)) == NULL) break; current_line = thefile->current_line; /* skip blank lines and comments */ if(input[0] == '#' || input[0] == '\x0' || input[0] == '\n' || input[0] == '\r') continue; strip(input); /* get the variable name */ if((temp_ptr = my_strtok_with_free(input, "=", FALSE)) == NULL) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: NULL variable - Line %d of resource file '%s'", current_line, resource_file); error = TRUE; break; } if((variable = (char *)strdup(temp_ptr)) == NULL) { error = TRUE; break; } /* get the value */ if((temp_ptr = my_strtok_with_free(NULL, "\n", FALSE)) == NULL) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: NULL variable value - Line %d of resource file '%s'", current_line, resource_file); error = TRUE; break; } if((value = (char *)strdup(temp_ptr)) == NULL) { error = TRUE; break; } temp_ptr = my_strtok_with_free(NULL, "\n", TRUE); /* what should we do with the variable/value pair? */ /* check for macro declarations */ if(variable[0] == '$' && variable[strlen(variable) - 1] == '$') { /* $USERx$ macro declarations */ if(strstr(variable, "$USER") == variable && strlen(variable) > 5) { user_index = atoi(variable + 5) - 1; if(user_index >= 0 && user_index < MAX_USER_MACROS) { my_free(macro_user[user_index]); macro_user[user_index] = (char *)strdup(value); } } } } /* free leftover memory and close the file */ my_free(input); mmap_fclose(thefile); /* free memory */ my_free(variable); my_free(value); if(error == TRUE) return ERROR; return OK; } /****************************************************************/ /**************** CONFIG VERIFICATION FUNCTIONS *****************/ /****************************************************************/ /* do a pre-flight check to make sure object relationships, etc. make sense */ int pre_flight_check(void) { char *buf = NULL; int warnings = 0; int errors = 0; struct timeval tv[4]; double runtime[4]; int temp_path_fd = -1; if(test_scheduling == TRUE) gettimeofday(&tv[0], NULL); /********************************************/ /* check object relationships */ /********************************************/ pre_flight_object_check(&warnings, &errors); if(test_scheduling == TRUE) gettimeofday(&tv[1], NULL); /********************************************/ /* check for circular paths between hosts */ /********************************************/ pre_flight_circular_check(&warnings, &errors); if(test_scheduling == TRUE) gettimeofday(&tv[2], NULL); /********************************************/ /* check global event handler commands... */ /********************************************/ if(verify_config) printf("Checking global event handlers...\n"); if(global_host_event_handler != NULL) { global_host_event_handler_ptr = find_bang_command(global_host_event_handler); if (global_host_event_handler_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Global host event handler command '%s' is not defined anywhere!", global_host_event_handler); errors++; } } if(global_service_event_handler != NULL) { global_service_event_handler_ptr = find_bang_command(global_service_event_handler); if (global_service_event_handler_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Global service event handler command '%s' is not defined anywhere!", global_service_event_handler); errors++; } } /**************************************************/ /* check obsessive processor commands... */ /**************************************************/ if(verify_config) printf("Checking obsessive compulsive processor commands...\n"); if(ocsp_command != NULL) { ocsp_command_ptr = find_bang_command(ocsp_command); if (!ocsp_command_ptr) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: OCSP command '%s' is not defined anywhere!\n", ocsp_command); errors++; } } if(ochp_command != NULL) { ochp_command_ptr = find_bang_command(ochp_command); if (!ochp_command_ptr) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: OCHP command '%s' is not defined anywhere!\n", ochp_command); errors++; } } /**************************************************/ /* check various settings... */ /**************************************************/ if(verify_config) printf("Checking misc settings...\n"); /* check if we can write to temp_path */ asprintf(&buf, "%s/nagiosXXXXXX", temp_path); if((temp_path_fd = mkstemp(buf)) == -1) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "\tError: Unable to write to temp_path ('%s') - %s\n", temp_path, strerror(errno)); errors++; } else { close(temp_path_fd); remove(buf); } my_free(buf); /* check if we can write to check_result_path */ asprintf(&buf, "%s/nagiosXXXXXX", check_result_path); if((temp_path_fd = mkstemp(buf)) == -1) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "\tError: Unable to write to check_result_path ('%s') - %s\n", check_result_path, strerror(errno)); errors++; } else { close(temp_path_fd); remove(buf); } my_free(buf); /* warn if user didn't specify any illegal macro output chars */ if(illegal_output_chars == NULL) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "%s", "Warning: Nothing specified for illegal_macro_output_chars variable!\n"); warnings++; } else { char *p; for(p = illegal_output_chars; *p; p++) { illegal_output_char_map[(int)*p] = 1; } } if(verify_config) { printf("\n"); printf("Total Warnings: %d\n", warnings); printf("Total Errors: %d\n", errors); } if(test_scheduling == TRUE) gettimeofday(&tv[3], NULL); if(test_scheduling == TRUE) { runtime[0] = tv_delta_f(&tv[0], &tv[1]); runtime[1] = tv_delta_f(&tv[1], &tv[2]); runtime[2] = (double)((double)(tv[3].tv_sec - tv[2].tv_sec) + (double)((tv[3].tv_usec - tv[2].tv_usec) / 1000.0) / 1000.0); runtime[3] = runtime[0] + runtime[1] + runtime[2]; printf("Timing information on configuration verification is listed below.\n\n"); printf("CONFIG VERIFICATION TIMES\n"); printf("----------------------------------\n"); printf("Object Relationships: %.6lf sec\n", runtime[0]); printf("Circular Paths: %.6lf sec\n", runtime[1]); printf("Misc: %.6lf sec\n", runtime[2]); printf(" ============\n"); printf("TOTAL: %.6lf sec\n", runtime[3]); printf("\n\n"); } return (errors > 0) ? ERROR : OK; } /* do a pre-flight check to make sure object relationships make sense */ int pre_flight_object_check(int *w, int *e) { contact *temp_contact = NULL; commandsmember *temp_commandsmember = NULL; contactgroup *temp_contactgroup = NULL; host *temp_host = NULL; host *temp_host2 = NULL; hostsmember *temp_hostsmember = NULL; servicesmember *sm = NULL; hostgroup *temp_hostgroup = NULL; servicegroup *temp_servicegroup = NULL; service *temp_service = NULL; command *temp_command = NULL; timeperiod *temp_timeperiod = NULL; timeperiod *temp_timeperiod2 = NULL; timeperiodexclusion *temp_timeperiodexclusion = NULL; int total_objects = 0; int warnings = 0; int errors = 0; #ifdef TEST void *ptr = NULL; char *buf1 = ""; char *buf2 = ""; buf1 = "temptraxe1"; buf2 = "Probe 2"; for(temp_se = get_first_serviceescalation_by_service(buf1, buf2, &ptr); temp_se != NULL; temp_se = get_next_serviceescalation_by_service(buf1, buf2, &ptr)) { printf("FOUND ESCALATION FOR SVC '%s'/'%s': %d-%d/%.3f, PTR=%p\n", buf1, buf2, temp_se->first_notification, temp_se->last_notification, temp_se->notification_interval, ptr); } for(temp_he = get_first_hostescalation_by_host(buf1, &ptr); temp_he != NULL; temp_he = get_next_hostescalation_by_host(buf1, &ptr)) { printf("FOUND ESCALATION FOR HOST '%s': %d-%d/%d, PTR=%p\n", buf1, temp_he->first_notification, temp_he->last_notification, temp_he->notification_interval, ptr); } #endif if(verify_config) printf("Checking objects...\n"); /*****************************************/ /* check each service... */ /*****************************************/ if(get_service_count() == 0) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: There are no services defined!"); errors++; } total_objects = 0; for(temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) { total_objects++; /* check the event handler command */ if(temp_service->event_handler != NULL) { temp_service->event_handler_ptr = find_bang_command(temp_service->event_handler); if(temp_service->event_handler_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Event handler command '%s' specified in service '%s' for host '%s' not defined anywhere", temp_service->event_handler, temp_service->description, temp_service->host_name); errors++; } } /* check the service check_command */ temp_service->check_command_ptr = find_bang_command(temp_service->check_command); if(temp_service->check_command_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Service check command '%s' specified in service '%s' for host '%s' not defined anywhere!", temp_service->check_command, temp_service->description, temp_service->host_name); errors++; } /* check for sane recovery options */ if(temp_service->notification_options == OPT_RECOVERY) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Recovery notification option in service '%s' for host '%s' doesn't make any sense - specify warning and/or critical options as well", temp_service->description, temp_service->host_name); warnings++; } /* check to see if there is at least one contact/group */ if(temp_service->contacts == NULL && temp_service->contact_groups == NULL) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Service '%s' on host '%s' has no default contacts or contactgroups defined!", temp_service->description, temp_service->host_name); warnings++; } /* verify service check timeperiod */ if(temp_service->check_period == NULL) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Service '%s' on host '%s' has no check time period defined!", temp_service->description, temp_service->host_name); warnings++; } /* check service notification timeperiod */ if(temp_service->notification_period == NULL) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Service '%s' on host '%s' has no notification time period defined!", temp_service->description, temp_service->host_name); warnings++; } /* check parent services */ for(sm = temp_service->parents; sm; sm = sm->next) { sm->service_ptr = find_service(sm->host_name, sm->service_description); if(sm->service_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Service '%s' on host '%s' is not a valid parent for service '%s' on host '%s'\n", sm->host_name, sm->service_description, temp_service->host_name, temp_service->description); errors++; } /* add a reverse (child) link to make searches faster later on */ add_child_link_to_service(sm->service_ptr, temp_service); } /* see if the notification interval is less than the check interval */ if(temp_service->notification_interval < temp_service->check_interval && temp_service->notification_interval != 0) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Service '%s' on host '%s' has a notification interval less than its check interval! Notifications are only re-sent after checks are made, so the effective notification interval will be that of the check interval.", temp_service->description, temp_service->host_name); warnings++; } /* check for illegal characters in service description */ if(use_precached_objects == FALSE) { if(contains_illegal_object_chars(temp_service->description) == TRUE) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The description string for service '%s' on host '%s' contains one or more illegal characters.", temp_service->description, temp_service->host_name); errors++; } } } if(verify_config) printf("\tChecked %d services.\n", total_objects); /*****************************************/ /* check all hosts... */ /*****************************************/ if(get_host_count() == 0) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: There are no hosts defined!"); errors++; } total_objects = 0; for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) { total_objects++; /* make sure each host has at least one service associated with it */ if(temp_host->total_services == 0 && verify_config >= 2) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Host '%s' has no services associated with it!", temp_host->name); warnings++; } /* check the event handler command */ if(temp_host->event_handler != NULL) { temp_host->event_handler_ptr = find_bang_command(temp_host->event_handler); if(temp_host->event_handler_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Event handler command '%s' specified for host '%s' not defined anywhere", temp_host->event_handler, temp_host->name); errors++; } } /* hosts that don't have check commands defined shouldn't ever be checked... */ if(temp_host->check_command != NULL) { temp_host->check_command_ptr = find_bang_command(temp_host->check_command); if(temp_host->check_command_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Host check command '%s' specified for host '%s' is not defined anywhere!", temp_host->check_command, temp_host->name); errors++; } } /* check host check timeperiod */ if(temp_host->check_period != NULL) { temp_timeperiod = find_timeperiod(temp_host->check_period); if(temp_timeperiod == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Check period '%s' specified for host '%s' is not defined anywhere!", temp_host->check_period, temp_host->name); errors++; } /* save the pointer to the check timeperiod for later */ temp_host->check_period_ptr = temp_timeperiod; } /* check to see if there is at least one contact/group */ if(temp_host->contacts == NULL && temp_host->contact_groups == NULL) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Host '%s' has no default contacts or contactgroups defined!", temp_host->name); warnings++; } /* check notification timeperiod */ if(temp_host->notification_period != NULL) { temp_timeperiod = find_timeperiod(temp_host->notification_period); if(temp_timeperiod == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Notification period '%s' specified for host '%s' is not defined anywhere!", temp_host->notification_period, temp_host->name); errors++; } /* save the pointer to the notification timeperiod for later */ temp_host->notification_period_ptr = temp_timeperiod; } /* check all parent parent host */ for(temp_hostsmember = temp_host->parent_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { if((temp_host2 = find_host(temp_hostsmember->host_name)) == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: '%s' is not a valid parent for host '%s'!", temp_hostsmember->host_name, temp_host->name); errors++; } /* save the parent host pointer for later */ temp_hostsmember->host_ptr = temp_host2; /* add a reverse (child) link to make searches faster later on */ add_child_link_to_host(temp_host2, temp_host); } /* check for sane recovery options */ if(temp_host->notification_options == OPT_RECOVERY) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Recovery notification option in host '%s' definition doesn't make any sense - specify down and/or unreachable options as well", temp_host->name); warnings++; } /* check for illegal characters in host name */ if(use_precached_objects == FALSE) { if(contains_illegal_object_chars(temp_host->name) == TRUE) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The name of host '%s' contains one or more illegal characters.", temp_host->name); errors++; } } } if(verify_config) printf("\tChecked %d hosts.\n", total_objects); /*****************************************/ /* check each host group... */ /*****************************************/ for(temp_hostgroup = hostgroup_list, total_objects = 0; temp_hostgroup != NULL; temp_hostgroup = temp_hostgroup->next, total_objects++) { /* check for illegal characters in hostgroup name */ if(use_precached_objects == FALSE) { if(contains_illegal_object_chars(temp_hostgroup->group_name) == TRUE) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The name of hostgroup '%s' contains one or more illegal characters.", temp_hostgroup->group_name); errors++; } } } if(verify_config) printf("\tChecked %d host groups.\n", total_objects); /*****************************************/ /* check each service group... */ /*****************************************/ for(temp_servicegroup = servicegroup_list, total_objects = 0; temp_servicegroup != NULL; temp_servicegroup = temp_servicegroup->next, total_objects++) { /* check for illegal characters in servicegroup name */ if(use_precached_objects == FALSE) { if(contains_illegal_object_chars(temp_servicegroup->group_name) == TRUE) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The name of servicegroup '%s' contains one or more illegal characters.", temp_servicegroup->group_name); errors++; } } } if(verify_config) printf("\tChecked %d service groups.\n", total_objects); /*****************************************/ /* check all contacts... */ /*****************************************/ if(contact_list == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: There are no contacts defined!"); errors++; } for(temp_contact = contact_list, total_objects = 0; temp_contact != NULL; temp_contact = temp_contact->next, total_objects++) { /* check service notification commands */ if(temp_contact->service_notification_commands == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Contact '%s' has no service notification commands defined!", temp_contact->name); errors++; } else for(temp_commandsmember = temp_contact->service_notification_commands; temp_commandsmember != NULL; temp_commandsmember = temp_commandsmember->next) { temp_commandsmember->command_ptr = find_bang_command(temp_commandsmember->command); if(temp_commandsmember->command_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Service notification command '%s' specified for contact '%s' is not defined anywhere!", temp_commandsmember->command, temp_contact->name); errors++; } } /* check host notification commands */ if(temp_contact->host_notification_commands == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Contact '%s' has no host notification commands defined!", temp_contact->name); errors++; } else for(temp_commandsmember = temp_contact->host_notification_commands; temp_commandsmember != NULL; temp_commandsmember = temp_commandsmember->next) { temp_commandsmember->command_ptr = find_bang_command(temp_commandsmember->command); if(temp_commandsmember->command_ptr == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Host notification command '%s' specified for contact '%s' is not defined anywhere!", temp_commandsmember->command, temp_contact->name); errors++; } } /* check service notification timeperiod */ if(temp_contact->service_notification_period == NULL) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Contact '%s' has no service notification time period defined!", temp_contact->name); warnings++; } else { temp_timeperiod = find_timeperiod(temp_contact->service_notification_period); if(temp_timeperiod == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Service notification period '%s' specified for contact '%s' is not defined anywhere!", temp_contact->service_notification_period, temp_contact->name); errors++; } /* save the pointer to the service notification timeperiod for later */ temp_contact->service_notification_period_ptr = temp_timeperiod; } /* check host notification timeperiod */ if(temp_contact->host_notification_period == NULL) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Contact '%s' has no host notification time period defined!", temp_contact->name); warnings++; } else { temp_timeperiod = find_timeperiod(temp_contact->host_notification_period); if(temp_timeperiod == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Host notification period '%s' specified for contact '%s' is not defined anywhere!", temp_contact->host_notification_period, temp_contact->name); errors++; } /* save the pointer to the host notification timeperiod for later */ temp_contact->host_notification_period_ptr = temp_timeperiod; } /* check for sane host recovery options */ if(temp_contact->host_notification_options == OPT_RECOVERY) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Host recovery notification option for contact '%s' doesn't make any sense - specify down and/or unreachable options as well", temp_contact->name); warnings++; } /* check for sane service recovery options */ if(temp_contact->service_notification_options == OPT_RECOVERY) { logit(NSLOG_VERIFICATION_WARNING, TRUE, "Warning: Service recovery notification option for contact '%s' doesn't make any sense - specify critical and/or warning options as well", temp_contact->name); warnings++; } /* check for illegal characters in contact name */ if(use_precached_objects == FALSE) { if(contains_illegal_object_chars(temp_contact->name) == TRUE) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The name of contact '%s' contains one or more illegal characters.", temp_contact->name); errors++; } } } if(verify_config) printf("\tChecked %d contacts.\n", total_objects); /*****************************************/ /* check each contact group... */ /*****************************************/ for(temp_contactgroup = contactgroup_list, total_objects = 0; temp_contactgroup != NULL; temp_contactgroup = temp_contactgroup->next, total_objects++) { /* check for illegal characters in contactgroup name */ if(use_precached_objects == FALSE) { if(contains_illegal_object_chars(temp_contactgroup->group_name) == TRUE) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The name of contact group '%s' contains one or more illegal characters.", temp_contactgroup->group_name); errors++; } } } if(verify_config) printf("\tChecked %d contact groups.\n", total_objects); /*****************************************/ /* check all commands... */ /*****************************************/ for(temp_command = command_list, total_objects = 0; temp_command != NULL; temp_command = temp_command->next, total_objects++) { /* check for illegal characters in command name */ if(use_precached_objects == FALSE) { if(contains_illegal_object_chars(temp_command->name) == TRUE) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The name of command '%s' contains one or more illegal characters.", temp_command->name); errors++; } } } if(verify_config) printf("\tChecked %d commands.\n", total_objects); /*****************************************/ /* check all timeperiods... */ /*****************************************/ for(temp_timeperiod = timeperiod_list, total_objects = 0; temp_timeperiod != NULL; temp_timeperiod = temp_timeperiod->next, total_objects++) { /* check for illegal characters in timeperiod name */ if(use_precached_objects == FALSE) { if(contains_illegal_object_chars(temp_timeperiod->name) == TRUE) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The name of time period '%s' contains one or more illegal characters.", temp_timeperiod->name); errors++; } } /* check for valid timeperiod names in exclusion list */ for(temp_timeperiodexclusion = temp_timeperiod->exclusions; temp_timeperiodexclusion != NULL; temp_timeperiodexclusion = temp_timeperiodexclusion->next) { temp_timeperiod2 = find_timeperiod(temp_timeperiodexclusion->timeperiod_name); if(temp_timeperiod2 == NULL) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Excluded time period '%s' specified in timeperiod '%s' is not defined anywhere!", temp_timeperiodexclusion->timeperiod_name, temp_timeperiod->name); errors++; } /* save the timeperiod pointer for later */ temp_timeperiodexclusion->timeperiod_ptr = temp_timeperiod2; } } if(verify_config) printf("\tChecked %d time periods.\n", total_objects); /* help people use scripts to verify that objects are loaded */ if(verify_config) { printf("\tChecked %u host escalations.\n", num_objects.hostescalations); printf("\tChecked %u service escalations.\n", num_objects.serviceescalations); } /* update warning and error count */ *w += warnings; *e += errors; return (errors > 0) ? ERROR : OK; } /* dfs status values */ #define DFS_UNCHECKED 0 /* default value */ #define DFS_TEMP_CHECKED 1 /* check just one time */ #define DFS_OK 2 /* no problem */ #define DFS_NEAR_LOOP 3 /* has trouble sons */ #define DFS_LOOPY 4 /* is a part of a loop */ #define dfs_get_status(obj) (obj ? ary[obj->id] : DFS_OK) #define dfs_set_status(obj, value) ary[obj->id] = (value) /** * Modified version of Depth-first Search * http://en.wikipedia.org/wiki/Depth-first_search * * In a dependency tree like this (parent->child, dep->dep or whatever): * A - B C * \ / * D * / \ * E - F - G * / \\ * H H * * ... we look at the nodes in the following order: * A B D C G (marking all of them as OK) * E F D G H F (D,G are already OK, E is marked near-loopy F and H are loopy) * H (which is already marked as loopy, so we don't follow it) * * We look at each node at most once per parent, so the algorithm has * O(nx) worst-case complexity,, where x is the average number of * parents. */ /* * same as dfs_host_path, but we flip the the tree and traverse it * backwards, since core Nagios doesn't need the child pointer at * later stages. */ static int dfs_servicedep_path(char *ary, service *root, int dep_type, int *errors) { objectlist *olist; int status; status = dfs_get_status(root); if(status != DFS_UNCHECKED) return status; dfs_set_status(root, DFS_TEMP_CHECKED); if (dep_type == NOTIFICATION_DEPENDENCY) { olist = root->notify_deps; } else { olist = root->exec_deps; } if (!olist) { /* no children, so we can't be loopy */ dfs_set_status(root, DFS_OK); return DFS_OK; } for (; olist; olist = olist->next) { int child_status; service *child; servicedependency *child_dep = (servicedependency *)olist->object_ptr; /* tree is upside down, so look to master */ child = child_dep->master_service_ptr; child_status = dfs_servicedep_path(ary, child, dep_type, errors); if (child_status == DFS_OK) continue; if(child_status == DFS_TEMP_CHECKED) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Circular %s dependency detected for services '%s;%s' and '%s;%s'\n", dep_type == NOTIFICATION_DEPENDENCY ? "notification" : "execution", root->host_name, root->description, child->host_name, child->description); (*errors)++; dfs_set_status(child, DFS_LOOPY); dfs_set_status(root, DFS_LOOPY); continue; } } /* * if we've hit ourself, we'll have marked us as loopy * above, so if we're TEMP_CHECKED still we're ok */ if (dfs_get_status(root) == DFS_TEMP_CHECKED) dfs_set_status(root, DFS_OK); return dfs_get_status(root); } static int dfs_hostdep_path(char *ary, host *root, int dep_type, int *errors) { objectlist *olist; int status; status = dfs_get_status(root); if(status != DFS_UNCHECKED) return status; dfs_set_status(root, DFS_TEMP_CHECKED); if (dep_type == NOTIFICATION_DEPENDENCY) { olist = root->notify_deps; } else { olist = root->exec_deps; } for (; olist; olist = olist->next) { int child_status; host *child; hostdependency *child_dep = (hostdependency *)olist->object_ptr; child = child_dep->master_host_ptr; child_status = dfs_hostdep_path(ary, child, dep_type, errors); if (child_status == DFS_OK) continue; if(child_status == DFS_TEMP_CHECKED) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: Circular %s dependency detected for hosts '%s' and '%s'\n", dep_type == NOTIFICATION_DEPENDENCY ? "notification" : "execution", root->name, child->name); dfs_set_status(child, DFS_LOOPY); dfs_set_status(root, DFS_LOOPY); (*errors)++; continue; } } /* * if we've hit ourself, we'll have marked us as loopy * above, so if we're still TEMP_CHECKED we're ok */ if (dfs_get_status(root) == DFS_TEMP_CHECKED) dfs_set_status(root, DFS_OK); return dfs_get_status(root); } static int dfs_host_path(char *ary, host *root, int *errors) { hostsmember *child = NULL; if(dfs_get_status(root) != DFS_UNCHECKED) return dfs_get_status(root); /* Mark the root temporary checked */ dfs_set_status(root, DFS_TEMP_CHECKED); /* We are scanning the children */ for(child = root->child_hosts; child != NULL; child = child->next) { int child_status = dfs_host_path(ary, child->host_ptr, errors); /* we can move on quickly if child is ok */ if(child_status == DFS_OK) continue; /* If a child already temporary checked, its a problem, * loop inside, and its a acked status */ if(child_status == DFS_TEMP_CHECKED) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The hosts '%s' and '%s' form or lead into a circular parent/child chain!", root->name, child->host_ptr->name); (*errors)++; dfs_set_status(child->host_ptr, DFS_LOOPY); dfs_set_status(root, DFS_LOOPY); continue; } } /* * If root have been modified, do not set it OK * A node is OK if and only if all of his children are OK * If it does not have child, goes ok */ if(dfs_get_status(root) == DFS_TEMP_CHECKED) dfs_set_status(root, DFS_OK); return dfs_get_status(root); } static int dfs_timeperiod_path(char *ary, timeperiod *root, int *errors) { timeperiodexclusion *exc; if(dfs_get_status(root) != DFS_UNCHECKED) return dfs_get_status(root); /* Mark the root temporary checked */ dfs_set_status(root, DFS_TEMP_CHECKED); for (exc = root->exclusions; exc; exc = exc->next) { int child_status = dfs_timeperiod_path(ary, exc->timeperiod_ptr, errors); if(child_status == DFS_TEMP_CHECKED) { logit(NSLOG_VERIFICATION_ERROR, TRUE, "Error: The timeperiods '%s' and '%s' form or lead into a circular exclusion chain!", root->name, exc->timeperiod_ptr->name); (*errors)++; dfs_set_status(exc->timeperiod_ptr, DFS_LOOPY); dfs_set_status(root, DFS_LOOPY); continue; } } if(dfs_get_status(root) == DFS_TEMP_CHECKED) dfs_set_status(root, DFS_OK); return dfs_get_status(root); } /* check for circular paths and dependencies */ int pre_flight_circular_check(int *w, int *e) { host *temp_host = NULL; servicedependency *temp_sd = NULL; hostdependency *temp_hd = NULL; timeperiod *tp; unsigned int i; int errors = 0; unsigned int alloc, dep_type; char *ary[2]; if(num_objects.hosts > num_objects.services) alloc = num_objects.hosts; else alloc = num_objects.services; if(num_objects.timeperiods > alloc) alloc = num_objects.timeperiods; for (i = 0; i < ARRAY_SIZE(ary); i++) { if (!(ary[i] = calloc(1, alloc))) { while (i) { my_free(ary[--i]); } logit(NSLOG_CONFIG_ERROR, TRUE, "Error: Unable to allocate memory for circular path checks.\n"); errors++; return ERROR; } } /********************************************/ /* check for circular paths between hosts */ /********************************************/ if(verify_config) printf("Checking for circular paths...\n"); for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) { dfs_host_path(ary[0], temp_host, &errors); } if (verify_config) printf("\tChecked %u hosts\n", num_objects.hosts); /********************************************/ /* check for circular dependencies */ /********************************************/ /* check service dependencies */ /* We must clean the dfs status from previous check */ for (i = 0; i < ARRAY_SIZE(ary); i++) memset(ary[i], 0, alloc); for(i = 0; i < num_objects.servicedependencies; i++) { temp_sd = servicedependency_ary[i]; dep_type = temp_sd->dependency_type; /* * this shouldn't happen, but it can in case dependencies are * added to services on hosts in empty hostgroups (ie, nonexistent) */ if(dep_type < 1 || dep_type > ARRAY_SIZE(ary)) continue; dfs_servicedep_path(ary[dep_type - 1], temp_sd->dependent_service_ptr, dep_type, &errors); } if(verify_config) printf("\tChecked %u service dependencies\n", num_objects.servicedependencies); /* check host dependencies */ for (i = 0; i < ARRAY_SIZE(ary); i++) memset(ary[i], 0, alloc); for(i = 0; i < num_objects.hostdependencies; i++) { temp_hd = hostdependency_ary[i]; dep_type = temp_hd->dependency_type; /* see above */ if(dep_type < 1 || dep_type > ARRAY_SIZE(ary)) continue; dfs_hostdep_path(ary[dep_type - 1], temp_hd->dependent_host_ptr, dep_type, &errors); } if(verify_config) printf("\tChecked %u host dependencies\n", num_objects.hostdependencies); /* check timeperiod exclusion chains */ for (i = 0; i < ARRAY_SIZE(ary); i++) memset(ary[i], 0, alloc); for (tp = timeperiod_list; tp; tp = tp->next) { dfs_timeperiod_path(ary[0], tp, &errors); } if (verify_config) printf("\tChecked %u timeperiods\n", num_objects.timeperiods); /* update warning and error count */ *e += errors; for (i = 0; i < ARRAY_SIZE(ary); i++) free(ary[i]); return (errors > 0) ? ERROR : OK; }