/* * Read config files. * * This function can ONLY be called from the main server process. */ int main_config_init(void) { char const *p = NULL; CONF_SECTION *cs; struct stat statbuf; cached_config_t *cc; char buffer[1024]; if (stat(radius_dir, &statbuf) < 0) { ERROR("Errors reading %s: %s", radius_dir, fr_syserror(errno)); return -1; } #ifdef S_IWOTH if ((statbuf.st_mode & S_IWOTH) != 0) { ERROR("Configuration directory %s is globally writable. Refusing to start due to insecure configuration.", radius_dir); return -1; } #endif #ifdef S_IROTH if (0 && (statbuf.st_mode & S_IROTH) != 0) { ERROR("Configuration directory %s is globally readable. Refusing to start due to insecure configuration.", radius_dir); return -1; } #endif INFO("Starting - reading configuration files ..."); /* * We need to load the dictionaries before reading the * configuration files. This is because of the * pre-compilation in conffile.c. That should probably * be fixed to be done as a second stage. */ if (!main_config.dictionary_dir) { main_config.dictionary_dir = talloc_typed_strdup(NULL, DICTDIR); } /* * Read the distribution dictionaries first, then * the ones in raddb. */ DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY); if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) { ERROR("Errors reading dictionary: %s", fr_strerror()); return -1; } #define DICT_READ_OPTIONAL(_d, _n) \ do {\ switch (dict_read(_d, _n)) {\ case -1:\ ERROR("Errors reading %s/%s: %s", _d, _n, fr_strerror());\ return -1;\ case 0:\ DEBUG2("including dictionary file %s/%s", _d,_n);\ break;\ default:\ break;\ }\ } while (0) /* * Try to load protocol-specific dictionaries. It's OK * if they don't exist. */ #ifdef WITH_DHCP DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.dhcp"); #endif #ifdef WITH_VMPS DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.vqp"); #endif /* * It's OK if this one doesn't exist. */ DICT_READ_OPTIONAL(radius_dir, RADIUS_DICTIONARY); /* Read the configuration file */ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, main_config.name); if ((cs = cf_file_read(buffer)) == NULL) { ERROR("Errors reading or parsing %s", buffer); return -1; } /* * If there was no log destination set on the command line, * set it now. */ if (default_log.dst == L_DST_NULL) { if (cf_section_parse(cs, NULL, serverdest_config) < 0) { fprintf(stderr, "radiusd: Error: Failed to parse log{} section.\n"); cf_file_free(cs); return -1; } if (!radlog_dest) { fprintf(stderr, "radiusd: Error: No log destination specified.\n"); cf_file_free(cs); return -1; } default_log.dst = fr_str2int(log_str2dst, radlog_dest, L_DST_NUM_DEST); if (default_log.dst == L_DST_NUM_DEST) { fprintf(stderr, "radiusd: Error: Unknown log_destination %s\n", radlog_dest); cf_file_free(cs); return -1; } if (default_log.dst == L_DST_SYSLOG) { /* * Make sure syslog_facility isn't NULL * before using it */ if (!syslog_facility) { fprintf(stderr, "radiusd: Error: Syslog chosen but no facility was specified\n"); cf_file_free(cs); return -1; } main_config.syslog_facility = fr_str2int(syslog_str2fac, syslog_facility, -1); if (main_config.syslog_facility < 0) { fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n", syslog_facility); cf_file_free(cs); return -1; } #ifdef HAVE_SYSLOG_H /* * Call openlog only once, when the * program starts. */ openlog(progname, LOG_PID, main_config.syslog_facility); #endif } else if (default_log.dst == L_DST_FILES) { if (!main_config.log_file) { fprintf(stderr, "radiusd: Error: Specified \"files\" as a log destination, but no log filename was given!\n"); cf_file_free(cs); return -1; } } } #ifdef HAVE_SETUID /* * Switch users as early as possible. */ if (!switch_users(cs)) fr_exit(1); #endif /* * Open the log file AFTER switching uid / gid. If we * did switch uid/gid, then the code in switch_users() * took care of setting the file permissions correctly. */ if ((default_log.dst == L_DST_FILES) && (default_log.fd < 0)) { default_log.fd = open(main_config.log_file, O_WRONLY | O_APPEND | O_CREAT, 0640); if (default_log.fd < 0) { fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno)); cf_file_free(cs); return -1; } } /* * This allows us to figure out where, relative to * radiusd.conf, the other configuration files exist. */ if (cf_section_parse(cs, NULL, server_config) < 0) { return -1; } /* * We ignore colourization of output until after the * configuration files have been parsed. */ p = getenv("TERM"); if (do_colourise && p && isatty(default_log.fd) && strstr(p, "xterm")) { default_log.colourise = true; } else { default_log.colourise = false; } /* * Starting the server, WITHOUT "-x" on the * command-line: use whatever is in the config * file. */ if (debug_flag == 0) { debug_flag = main_config.debug_level; } fr_debug_flag = debug_flag; FR_INTEGER_COND_CHECK("max_request_time", main_config.max_request_time, (main_config.max_request_time != 0), 100); FR_INTEGER_BOUND_CHECK("reject_delay", main_config.reject_delay, <=, 10); FR_INTEGER_BOUND_CHECK("cleanup_delay", main_config.cleanup_delay, <=, 10); /* * Set default initial request processing delay to 1/3 of a second. * Will be updated by the lowest response window across all home servers, * if it is less than this. */ main_config.init_delay.tv_sec = 0; main_config.init_delay.tv_usec = 1000000 / 3; /* * Free the old configuration items, and replace them * with the new ones. * * Note that where possible, we do atomic switch-overs, * to ensure that the pointers are always valid. */ rad_assert(main_config.config == NULL); root_config = main_config.config = cs; DEBUG2("%s: #### Loading Realms and Home Servers ####", main_config.name); if (!realms_init(cs)) { return -1; } DEBUG2("%s: #### Loading Clients ####", main_config.name); if (!clients_parse_section(cs, false)) { return -1; } /* * Register the %{config:section.subsection} xlat function. */ xlat_register("config", xlat_config, NULL, NULL); xlat_register("client", xlat_client, NULL, NULL); xlat_register("getclient", xlat_getclient, NULL, NULL); /* * Go update our behaviour, based on the configuration * changes. */ /* * Sanity check the configuration for internal * consistency. */ FR_INTEGER_BOUND_CHECK("reject_delay", main_config.reject_delay, <=, main_config.cleanup_delay); if (chroot_dir) { if (chdir(radlog_dir) < 0) { ERROR("Failed to 'chdir %s' after chroot: %s", radlog_dir, fr_syserror(errno)); return -1; } } cc = talloc_zero(NULL, cached_config_t); if (!cc) return -1; cc->cs = talloc_steal(cc ,cs); rad_assert(cs_cache == NULL); cs_cache = cc; /* Clear any unprocessed configuration errors */ (void) fr_strerror(); return 0; }
/* * Read config files. * * This function can ONLY be called from the main server process. */ int main_config_init(void) { char const *p = NULL; CONF_SECTION *cs, *subcs; struct stat statbuf; cached_config_t *cc; char buffer[1024]; if (stat(radius_dir, &statbuf) < 0) { ERROR("Errors reading %s: %s", radius_dir, fr_syserror(errno)); return -1; } #ifdef S_IWOTH if ((statbuf.st_mode & S_IWOTH) != 0) { ERROR("Configuration directory %s is globally writable. Refusing to start due to insecure configuration.", radius_dir); return -1; } #endif #if 0 && defined(S_IROTH) if (statbuf.st_mode & S_IROTH != 0) { ERROR("Configuration directory %s is globally readable. Refusing to start due to insecure configuration.", radius_dir); return -1; } #endif INFO("Starting - reading configuration files ..."); /* * We need to load the dictionaries before reading the * configuration files. This is because of the * pre-compilation in conffile.c. That should probably * be fixed to be done as a second stage. */ if (!main_config.dictionary_dir) { main_config.dictionary_dir = DICTDIR; } /* * About sizeof(REQUEST) + sizeof(RADIUS_PACKET) * 2 + sizeof(VALUE_PAIR) * 400 * * Which should be enough for many configurations. */ main_config.talloc_pool_size = 8 * 1024; /* default */ /* * Read the distribution dictionaries first, then * the ones in raddb. */ DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY); if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) { ERROR("Errors reading dictionary: %s", fr_strerror()); return -1; } #define DICT_READ_OPTIONAL(_d, _n) \ do {\ switch (dict_read(_d, _n)) {\ case -1:\ ERROR("Errors reading %s/%s: %s", _d, _n, fr_strerror());\ return -1;\ case 0:\ DEBUG2("including dictionary file %s/%s", _d,_n);\ break;\ default:\ break;\ }\ } while (0) /* * Try to load protocol-specific dictionaries. It's OK * if they don't exist. */ #ifdef WITH_DHCP DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.dhcp"); #endif #ifdef WITH_VMPS DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.vqp"); #endif /* * It's OK if this one doesn't exist. */ DICT_READ_OPTIONAL(radius_dir, RADIUS_DICTIONARY); cs = cf_section_alloc(NULL, "main", NULL); if (!cs) return -1; /* * Add a 'feature' subsection off the main config * We check if it's defined first, as the user may * have defined their own feature flags, or want * to manually override the ones set by modules * or the server. */ subcs = cf_section_sub_find(cs, "feature"); if (!subcs) { subcs = cf_section_alloc(cs, "feature", NULL); if (!subcs) return -1; cf_section_add(cs, subcs); } version_init_features(subcs); /* * Add a 'version' subsection off the main config * We check if it's defined first, this is for * backwards compatibility. */ subcs = cf_section_sub_find(cs, "version"); if (!subcs) { subcs = cf_section_alloc(cs, "version", NULL); if (!subcs) return -1; cf_section_add(cs, subcs); } version_init_numbers(subcs); /* Read the configuration file */ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, main_config.name); if (cf_file_read(cs, buffer) < 0) { ERROR("Errors reading or parsing %s", buffer); talloc_free(cs); return -1; } /* * If there was no log destination set on the command line, * set it now. */ if (default_log.dst == L_DST_NULL) { default_log.dst = L_DST_STDERR; default_log.fd = STDERR_FILENO; if (cf_section_parse(cs, NULL, startup_server_config) == -1) { fprintf(stderr, "%s: Error: Failed to parse log{} section.\n", main_config.name); cf_file_free(cs); return -1; } if (!radlog_dest) { fprintf(stderr, "%s: Error: No log destination specified.\n", main_config.name); cf_file_free(cs); return -1; } default_log.fd = -1; default_log.dst = fr_str2int(log_str2dst, radlog_dest, L_DST_NUM_DEST); if (default_log.dst == L_DST_NUM_DEST) { fprintf(stderr, "%s: Error: Unknown log_destination %s\n", main_config.name, radlog_dest); cf_file_free(cs); return -1; } if (default_log.dst == L_DST_SYSLOG) { /* * Make sure syslog_facility isn't NULL * before using it */ if (!syslog_facility) { fprintf(stderr, "%s: Error: Syslog chosen but no facility was specified\n", main_config.name); cf_file_free(cs); return -1; } main_config.syslog_facility = fr_str2int(syslog_facility_table, syslog_facility, -1); if (main_config.syslog_facility < 0) { fprintf(stderr, "%s: Error: Unknown syslog_facility %s\n", main_config.name, syslog_facility); cf_file_free(cs); return -1; } #ifdef HAVE_SYSLOG_H /* * Call openlog only once, when the * program starts. */ openlog(main_config.name, LOG_PID, main_config.syslog_facility); #endif } else if (default_log.dst == L_DST_FILES) { if (!main_config.log_file) { fprintf(stderr, "%s: Error: Specified \"files\" as a log destination, but no log filename was given!\n", main_config.name); cf_file_free(cs); return -1; } } } #ifdef HAVE_SETUID /* * Switch users as early as possible. */ if (!switch_users(cs)) fr_exit(1); #endif /* * This allows us to figure out where, relative to * radiusd.conf, the other configuration files exist. */ if (cf_section_parse(cs, NULL, server_config) < 0) return -1; /* * Fix up log_auth, and log_accept and log_reject */ if (main_config.log_auth) { main_config.log_accept = main_config.log_reject = true; } /* * We ignore colourization of output until after the * configuration files have been parsed. */ p = getenv("TERM"); if (do_colourise && p && isatty(default_log.fd) && strstr(p, "xterm")) { default_log.colourise = true; } else { default_log.colourise = false; } /* * Starting the server, WITHOUT "-x" on the * command-line: use whatever is in the config * file. */ if (rad_debug_lvl == 0) { rad_debug_lvl = main_config.debug_level; } fr_debug_lvl = rad_debug_lvl; FR_INTEGER_COND_CHECK("max_request_time", main_config.max_request_time, (main_config.max_request_time != 0), 100); /* * reject_delay can be zero. OR 1 though 10. */ if ((main_config.reject_delay.tv_sec != 0) || (main_config.reject_delay.tv_usec != 0)) { FR_TIMEVAL_BOUND_CHECK("reject_delay", &main_config.reject_delay, >=, 1, 0); }