2 * mainconf.c Handle the server's configuration.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2002 The FreeRADIUS server project
21 * Copyright 2002 Alan DeKok <aland@ox.org>
25 #include "libradius.h"
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
35 #include "rad_assert.h"
39 #include <sys/resource.h>
41 #include <sys/types.h>
47 struct main_config_t mainconfig;
50 * Local variables for stuff.
52 static uid_t server_uid;
53 static gid_t server_gid;
56 * These are not used anywhere else..
58 static const char *localstatedir = NULL;
59 static const char *prefix = NULL;
62 * Map the proxy server configuration parameters to variables.
64 static CONF_PARSER proxy_config[] = {
65 { "retry_delay", PW_TYPE_INTEGER, 0, &mainconfig.proxy_retry_delay, Stringify(RETRY_DELAY) },
66 { "retry_count", PW_TYPE_INTEGER, 0, &mainconfig.proxy_retry_count, Stringify(RETRY_COUNT) },
67 { "synchronous", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_synchronous, "no" },
68 { "default_fallback", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_fallback, "no" },
69 { "dead_time", PW_TYPE_INTEGER, 0, &mainconfig.proxy_dead_time, Stringify(DEAD_TIME) },
70 { "post_proxy_authorize", PW_TYPE_BOOLEAN, 0, &mainconfig.post_proxy_authorize, "yes" },
71 { "wake_all_if_all_dead", PW_TYPE_BOOLEAN, 0, &mainconfig.wake_all_if_all_dead, "no" },
72 { NULL, -1, 0, NULL, NULL }
76 * Security configuration for the server.
78 static CONF_PARSER security_config[] = {
79 { "max_attributes", PW_TYPE_INTEGER, 0, &librad_max_attributes, Stringify(0) },
80 { "reject_delay", PW_TYPE_INTEGER, 0, &mainconfig.reject_delay, Stringify(0) },
81 { "status_server", PW_TYPE_BOOLEAN, 0, &mainconfig.status_server, "no"},
82 { NULL, -1, 0, NULL, NULL }
86 * A mapping of configuration file names to internal variables
88 static CONF_PARSER server_config[] = {
90 * FIXME: 'prefix' is the ONLY one which should be
91 * configured at compile time. Hard-coding it here is
92 * bad. It will be cleaned up once we clean up the
93 * hard-coded defines for the locations of the various
96 { "prefix", PW_TYPE_STRING_PTR, 0, &prefix, "/usr/local"},
97 { "localstatedir", PW_TYPE_STRING_PTR, 0, &localstatedir, "${prefix}/var"},
98 { "logdir", PW_TYPE_STRING_PTR, 0, &radlog_dir, "${localstatedir}/log"},
99 { "libdir", PW_TYPE_STRING_PTR, 0, &radlib_dir, "${prefix}/lib"},
100 { "radacctdir", PW_TYPE_STRING_PTR, 0, &radacct_dir, "${logdir}/radacct" },
101 { "hostname_lookups", PW_TYPE_BOOLEAN, 0, &librad_dodns, "no" },
103 { "snmp", PW_TYPE_BOOLEAN, 0, &mainconfig.do_snmp, "no" },
105 { "max_request_time", PW_TYPE_INTEGER, 0, &mainconfig.max_request_time, Stringify(MAX_REQUEST_TIME) },
106 { "cleanup_delay", PW_TYPE_INTEGER, 0, &mainconfig.cleanup_delay, Stringify(CLEANUP_DELAY) },
107 { "max_requests", PW_TYPE_INTEGER, 0, &mainconfig.max_requests, Stringify(MAX_REQUESTS) },
108 { "delete_blocked_requests", PW_TYPE_INTEGER, 0, &mainconfig.kill_unresponsive_children, Stringify(FALSE) },
109 { "port", PW_TYPE_INTEGER, 0, &auth_port, Stringify(PW_AUTH_UDP_PORT) },
110 { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &mainconfig.allow_core_dumps, "no" },
111 { "log_stripped_names", PW_TYPE_BOOLEAN, 0, &log_stripped_names,"no" },
112 { "log_file", PW_TYPE_STRING_PTR, -1, &mainconfig.log_file, "${logdir}/radius.log" },
113 { "log_auth", PW_TYPE_BOOLEAN, -1, &mainconfig.log_auth, "no" },
114 { "log_auth_badpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_badpass, "no" },
115 { "log_auth_goodpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_goodpass, "no" },
116 { "pidfile", PW_TYPE_STRING_PTR, 0, &mainconfig.pid_file, "${run_dir}/radiusd.pid"},
117 { "bind_address", PW_TYPE_IPADDR, 0, &mainconfig.myip, "*" },
118 { "user", PW_TYPE_STRING_PTR, 0, &mainconfig.uid_name, NULL},
119 { "group", PW_TYPE_STRING_PTR, 0, &mainconfig.gid_name, NULL},
120 { "usercollide", PW_TYPE_BOOLEAN, 0, &mainconfig.do_usercollide, "no" },
121 { "lower_user", PW_TYPE_STRING_PTR, 0, &mainconfig.do_lower_user, "no" },
122 { "lower_pass", PW_TYPE_STRING_PTR, 0, &mainconfig.do_lower_pass, "no" },
123 { "nospace_user", PW_TYPE_STRING_PTR, 0, &mainconfig.do_nospace_user, "no" },
124 { "nospace_pass", PW_TYPE_STRING_PTR, 0, &mainconfig.do_nospace_pass, "no" },
125 { "checkrad", PW_TYPE_STRING_PTR, 0, &mainconfig.checkrad, "${sbindir}/checkrad" },
126 { "proxy_requests", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_requests, "yes" },
127 { "proxy", PW_TYPE_SUBSECTION, 0, proxy_config, NULL },
128 { "security", PW_TYPE_SUBSECTION, 0, security_config, NULL },
129 { "debug_level", PW_TYPE_INTEGER, 0, &mainconfig.debug_level, "0"},
130 { NULL, -1, 0, NULL, NULL }
134 * Xlat for %{config:section.subsection.attribute}
136 static int xlat_config(void *instance, REQUEST *request,
137 char *fmt, char *out,
139 RADIUS_ESCAPE_STRING func)
145 const char *start = fmt;
147 request = request; /* -Wunused */
148 instance = instance; /* -Wunused */
155 * Find the next section.
157 for (p = buffer; (*fmt != 0) && (*fmt != '.'); p++, fmt++) {
163 * The character is a '.', find a section (as the user
164 * has given us a subsection to find)
169 fmt++; /* skip the period */
172 next = cf_section_find(buffer);
174 next = cf_subsection_find_next(cs, NULL, buffer);
177 radlog(L_ERR, "config: No such section %s in format string %s", buffer, start);
182 } else { /* no period, must be a conf-part */
183 cp = cf_pair_find(cs, buffer);
186 radlog(L_ERR, "config: No such section %s in format string %s", buffer, start);
190 } /* until cp is non-NULL */
193 * Ensure that we only copy what's necessary.
195 * If 'outlen' is too small, then the output is chopped to fit.
197 value = cf_pair_value(cp);
199 if (outlen > strlen(value)) {
200 outlen = strlen(value) + 1;
204 return func(out, outlen, value);
209 * Recursively make directories.
211 static int r_mkdir(const char *part) {
212 char *ptr, parentdir[500];
215 if (stat(part, &st) == 0)
218 ptr = strrchr(part, '/');
223 snprintf(parentdir, (ptr - part)+1, "%s", part);
225 if (r_mkdir(parentdir) != 0)
228 if (mkdir(part, 0770) != 0) {
229 fprintf(stderr, "mkdir(%s) error: %s\n", part, strerror(errno));
233 fprintf(stderr, "Created directory %s\n", part);
239 * Checks if the log directory is writeable by a particular user.
241 static int radlogdir_iswritable(const char *effectiveuser) {
242 struct passwd *pwent;
244 if (radlog_dir[0] != '/')
247 if (r_mkdir(radlog_dir) != 0)
250 /* FIXME: do we have this function? */
251 if (strstr(radlog_dir, "radius") == NULL)
254 /* we have a logdir that mentions 'radius', so it's probably
255 * safe to chown the immediate directory to be owned by the normal
256 * process owner. we gotta do it before we give up root. -chad
259 if (!effectiveuser) {
263 pwent = getpwnam(effectiveuser);
265 if (pwent == NULL) /* uh oh! */
268 if (chown(radlog_dir, pwent->pw_uid, -1) != 0)
275 static int switch_users(void) {
278 * Switch UID and GID to what is specified in the config file
282 if (mainconfig.gid_name != NULL) {
285 gr = getgrnam(mainconfig.gid_name);
287 if (errno == ENOMEM) {
288 radlog(L_ERR|L_CONS, "Cannot switch to Group %s: out of memory", mainconfig.gid_name);
290 radlog(L_ERR|L_CONS, "Cannot switch group; %s doesn't exist", mainconfig.gid_name);
294 server_gid = gr->gr_gid;
295 if (setgid(server_gid) < 0) {
296 radlog(L_ERR|L_CONS, "Failed setting Group to %s: %s",
297 mainconfig.gid_name, strerror(errno));
303 if (mainconfig.uid_name != NULL) {
306 pw = getpwnam(mainconfig.uid_name);
308 if (errno == ENOMEM) {
309 radlog(L_ERR|L_CONS, "Cannot switch to User %s: out of memory", mainconfig.uid_name);
311 radlog(L_ERR|L_CONS, "Cannot switch user; %s doesn't exist", mainconfig.uid_name);
315 server_uid = pw->pw_uid;
316 if (setuid(server_uid) < 0) {
317 radlog(L_ERR|L_CONS, "Failed setting User to %s: %s", mainconfig.uid_name, strerror(errno));
326 * Create the linked list of realms from the new configuration type
327 * This way we don't have to change to much in the other source-files
329 static int generate_realms(const char *filename)
332 REALM *my_realms = NULL;
334 char *s, *t, *authhost, *accthost;
338 for (cs = cf_subsection_find_next(mainconfig.config, NULL, "realm");
340 cs = cf_subsection_find_next(mainconfig.config, cs, "realm")) {
341 name2 = cf_section_name2(cs);
343 radlog(L_CONS|L_ERR, "%s[%d]: Missing realm name",
344 filename, cf_section_lineno(cs));
348 * We've found a realm, allocate space for it
350 c = rad_malloc(sizeof(REALM));
351 memset(c, 0, sizeof(REALM));
356 * No authhost means LOCAL.
358 if ((authhost = cf_section_value_find(cs, "authhost")) == NULL) {
359 c->ipaddr = htonl(INADDR_NONE);
360 c->auth_port = auth_port;
362 if ((s = strchr(authhost, ':')) != NULL) {
364 c->auth_port = atoi(s);
366 c->auth_port = auth_port;
368 if (strcmp(authhost, "LOCAL") == 0) {
370 * Local realms don't have an IP address,
373 c->ipaddr = htonl(INADDR_NONE);
374 c->auth_port = auth_port;
376 c->ipaddr = ip_getaddr(authhost);
377 if (c->ipaddr == htonl(INADDR_NONE)) {
378 radlog(L_ERR, "%s[%d]: Host %s not found",
379 filename, cf_section_lineno(cs),
386 * Double check length, just to be sure!
388 if (strlen(authhost) >= sizeof(c->server)) {
389 radlog(L_ERR, "%s[%d]: Server name of length %d is greater than allowed: %d",
390 filename, cf_section_lineno(cs),
391 (int) strlen(authhost),
392 (int) sizeof(c->server) - 1);
398 * No accthost means LOCAL
400 if ((accthost = cf_section_value_find(cs, "accthost")) == NULL) {
401 c->acct_ipaddr = htonl(INADDR_NONE);
402 c->acct_port = acct_port;
404 if ((s = strchr(accthost, ':')) != NULL) {
406 c->acct_port = atoi(s);
408 c->acct_port = acct_port;
410 if (strcmp(accthost, "LOCAL") == 0) {
412 * Local realms don't have an IP address,
415 c->acct_ipaddr = htonl(INADDR_NONE);
416 c->acct_port = acct_port;
418 c->acct_ipaddr = ip_getaddr(accthost);
419 if (c->acct_ipaddr == htonl(INADDR_NONE)) {
420 radlog(L_ERR, "%s[%d]: Host %s not found",
421 filename, cf_section_lineno(cs),
427 if (strlen(accthost) >= sizeof(c->acct_server)) {
428 radlog(L_ERR, "%s[%d]: Server name of length %d is greater than allowed: %d",
429 filename, cf_section_lineno(cs),
430 (int) strlen(accthost),
431 (int) sizeof(c->acct_server) - 1);
436 if (strlen(name2) >= sizeof(c->realm)) {
437 radlog(L_ERR, "%s[%d]: Realm name of length %d is greater than allowed %d",
438 filename, cf_section_lineno(cs),
440 (int) sizeof(c->server) - 1);
444 strcpy(c->realm, name2);
445 if (authhost) strcpy(c->server, authhost);
446 if (accthost) strcpy(c->acct_server, accthost);
449 * If one or the other of authentication/accounting
450 * servers is set to LOCALHOST, then don't require
453 if ((c->ipaddr != htonl(INADDR_NONE)) ||
454 (c->acct_ipaddr != htonl(INADDR_NONE))) {
455 if ((s = cf_section_value_find(cs, "secret")) == NULL ) {
456 radlog(L_ERR, "%s[%d]: No shared secret supplied for realm: %s",
457 filename, cf_section_lineno(cs), name2);
461 if (strlen(s) >= sizeof(c->secret)) {
462 radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
463 filename, cf_section_lineno(cs),
464 strlen(s), sizeof(c->secret) - 1);
467 strNcpy((char *)c->secret, s, sizeof(c->secret));
472 if ((cf_section_value_find(cs, "nostrip")) != NULL)
474 if ((cf_section_value_find(cs, "noacct")) != NULL)
476 if ((cf_section_value_find(cs, "trusted")) != NULL)
478 if ((cf_section_value_find(cs, "notrealm")) != NULL)
480 if ((cf_section_value_find(cs, "notsuffix")) != NULL)
482 if ((t = cf_section_value_find(cs,"ldflag")) != NULL) {
483 static const LRAD_NAME_NUMBER ldflags[] = {
485 { "round_robin", 1 },
489 c->ldflag = lrad_str2int(ldflags, t, -1);
490 if (c->ldflag == -1) {
491 radlog(L_ERR, "%s[%d]: Unknown value \"%s\" for ldflag",
492 filename, cf_section_lineno(cs),
498 c->ldflag = 0; /* non, make it fail-over */
501 c->acct_active = TRUE;
509 * And make these realms preferred over the ones
510 * in the 'realms' file.
512 *tail = mainconfig.realms;
513 mainconfig.realms = my_realms;
516 * Ensure that all of the flags agree for the realms.
518 * Yeah, it's O(N^2), but it's only once, and the
519 * maximum number of realms is small.
521 for(c = mainconfig.realms; c != NULL; c = c->next) {
525 * Check that we cannot load balance to LOCAL
526 * realms, as that doesn't make any sense.
528 if ((c->ldflag == 1) &&
529 ((c->ipaddr == htonl(INADDR_NONE)) ||
530 (c->acct_ipaddr == htonl(INADDR_NONE)))) {
531 radlog(L_ERR | L_CONS, "ERROR: Realm %s cannot be load balanced to LOCAL",
537 * Compare this realm to all others, to ensure
538 * that the configuration is consistent.
540 for (this = c->next; this != NULL; this = this->next) {
541 if (strcasecmp(c->realm, this->realm) != 0) {
546 * Same realm: Different load balancing
549 if (c->ldflag != this->ldflag) {
550 radlog(L_ERR | L_CONS, "ERROR: Inconsistent value in realm %s for load balancing 'ldflag' attribute",
562 * Create the linked list of realms from the new configuration
563 * type. This way we don't have to change too much in the other
566 static int generate_clients(const char *filename)
570 char *hostnm, *secret, *shortnm, *netmask;
571 char *nastype, *login, *password;
574 for (cs = cf_subsection_find_next(mainconfig.config, NULL, "client");
576 cs = cf_subsection_find_next(mainconfig.config, cs, "client")) {
578 name2 = cf_section_name2(cs);
580 radlog(L_CONS|L_ERR, "%s[%d]: Missing client name",
581 filename, cf_section_lineno(cs));
585 * Check the lengths, we don't want any core dumps
589 if((secret = cf_section_value_find(cs, "secret")) == NULL) {
590 radlog(L_ERR, "%s[%d]: Missing secret for client: %s",
591 filename, cf_section_lineno(cs), name2);
595 if((shortnm = cf_section_value_find(cs, "shortname")) == NULL) {
596 radlog(L_ERR, "%s[%d]: Missing shortname for client: %s",
597 filename, cf_section_lineno(cs), name2);
601 netmask = strchr(hostnm, '/');
603 if (strlen(secret) >= sizeof(c->secret)) {
604 radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
605 filename, cf_section_lineno(cs),
606 strlen(secret), sizeof(c->secret) - 1);
609 if (strlen(shortnm) > sizeof(c->shortname)) {
610 radlog(L_ERR, "%s[%d]: Client short name of length %d is greater than the allowed maximum of %d.",
611 filename, cf_section_lineno(cs),
612 strlen(shortnm), sizeof(c->shortname) - 1);
616 if((nastype = cf_section_value_find(cs, "nastype")) != NULL) {
617 if(strlen(nastype) >= sizeof(c->nastype)) {
618 radlog(L_ERR, "%s[%d]: nastype of length %d longer than the allowed maximum of %d",
619 filename, cf_section_lineno(cs),
620 strlen(nastype), sizeof(c->nastype) - 1);
625 if((login = cf_section_value_find(cs, "login")) != NULL) {
626 if(strlen(login) >= sizeof(c->login)) {
627 radlog(L_ERR, "%s[%d]: login of length %d longer than the allowed maximum of %d",
628 filename, cf_section_lineno(cs),
629 strlen(login), sizeof(c->login) - 1);
634 if((password = cf_section_value_find(cs, "password")) != NULL) {
635 if(strlen(password) >= sizeof(c->password)) {
636 radlog(L_ERR, "%s[%d]: password of length %d longer than the allowed maximum of %d",
637 filename, cf_section_lineno(cs),
638 strlen(password), sizeof(c->password) - 1);
644 * The size is fine.. Let's create the buffer
646 c = rad_malloc(sizeof(RADCLIENT));
647 memset(c, 0, sizeof(RADCLIENT));
656 mask_length = atoi(netmask + 1);
657 if ((mask_length < 0) || (mask_length > 32)) {
658 radlog(L_ERR, "%s[%d]: Invalid value '%s' for IP network mask.",
659 filename, cf_section_lineno(cs), netmask + 1);
663 c->netmask = (1 << 31);
664 for (i = 1; i < mask_length; i++) {
665 c->netmask |= (c->netmask >> 1);
669 c->netmask = htonl(c->netmask);
672 c->ipaddr = ip_getaddr(hostnm);
673 if (c->ipaddr == INADDR_NONE) {
674 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
675 filename, cf_section_lineno(cs), hostnm);
680 * Update the client name again...
684 c->ipaddr &= c->netmask;
685 strcpy(c->longname, hostnm);
687 ip_hostname(c->longname, sizeof(c->longname),
691 strcpy((char *)c->secret, secret);
692 strcpy(c->shortname, shortnm);
694 strcpy(c->nastype, nastype);
696 strcpy(c->login, login);
698 strcpy(c->password, password);
700 c->next =mainconfig. clients;
701 mainconfig.clients = c;
707 #ifndef RADIUS_CONFIG
708 #define RADIUS_CONFIG "radiusd.conf"
711 CONF_SECTION *read_radius_conf_file(void)
716 /* Lets go look for the new configuration files */
717 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
718 if ((cs = conf_read(NULL, 0, buffer, NULL)) == NULL) {
723 * This allows us to figure out where, relative to
724 * radiusd.conf, the other configuration files exist.
726 cf_section_parse(cs, NULL, server_config);
728 /* Initialize the dictionary */
729 DEBUG2("read_config_files: reading dictionary");
730 if (dict_init(radius_dir, RADIUS_DICTIONARY) != 0) {
731 radlog(L_ERR|L_CONS, "Errors reading dictionary: %s",
733 cf_section_free(&cs);
744 * This function can ONLY be called from the main server process.
746 int read_mainconfig(int reload)
748 struct rlimit core_limits;
749 static int old_debug_level = -1;
751 CONF_SECTION *cs, *oldcs;
754 radlog(L_INFO, "Starting - reading configuration files ...");
756 radlog(L_INFO, "Reloading configuration files.");
759 /* First read radiusd.conf */
760 DEBUG2("reread_config: reading radiusd.conf");
761 if ((cs = read_radius_conf_file()) == NULL) {
763 (radlog_dir == NULL)) {
764 radlog(L_ERR|L_CONS, "Errors reading radiusd.conf");
766 radlog(L_ERR|L_CONS, "Errors reading %s/radiusd.conf: For more information, please read the tail end of %s", radlog_dir, mainconfig.log_file);
772 * Free the old configuration items, and replace them
775 * Note that where possible, we do atomic switch-overs,
776 * to ensure that the pointers are always valid.
778 oldcs = mainconfig.config;
779 mainconfig.config = cs;
780 cf_section_free(&oldcs);
782 /* old-style naslist file */
783 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_NASLIST);
784 DEBUG2("read_config_files: reading naslist");
785 if (read_naslist_file(buffer) < 0) {
786 radlog(L_ERR|L_CONS, "Errors reading naslist");
789 /* old-style clients file */
790 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_CLIENTS);
791 DEBUG2("read_config_files: reading clients");
792 if (read_clients_file(buffer) < 0) {
793 radlog(L_ERR|L_CONS, "Errors reading clients");
798 * Add to that, the *new* list of clients.
800 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
801 if (generate_clients(buffer) < 0) {
805 /* old-style realms file */
806 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_REALMS);
807 DEBUG2("read_config_files: reading realms");
808 if (read_realms_file(buffer) < 0) {
809 radlog(L_ERR|L_CONS, "Errors reading realms");
814 * If there isn't any realms it isn't fatal..
816 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
817 if (generate_realms(buffer) < 0) {
822 * Register the %{config:section.subsection} xlat function.
824 xlat_register("config", xlat_config, NULL);
827 * Set the libraries debugging flag to whatever the main
828 * flag is. Note that on a SIGHUP, to turn the debugging
829 * off, we do other magic.
831 * Increase the debug level, if the configuration file
832 * says to, OR, if we're decreasing the debug from what it
833 * was before, allow that, too.
835 if ((mainconfig.debug_level > debug_flag) ||
836 (mainconfig.debug_level <= old_debug_level)) {
837 debug_flag = mainconfig.debug_level;
839 librad_debug = debug_flag;
840 old_debug_level = mainconfig.debug_level;
843 * Go update our behaviour, based on the configuration
847 /* Get the current maximum for core files. */
848 if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
849 radlog(L_ERR|L_CONS, "Failed to get current core limit: %s", strerror(errno));
853 if (mainconfig.allow_core_dumps) {
854 if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
855 radlog(L_ERR|L_CONS, "Cannot update core dump limit: %s",
860 * If we're running as a daemon, and core
861 * dumps are enabled, log that information.
863 } else if ((core_limits.rlim_cur != 0) && !debug_flag)
864 radlog(L_INFO|L_CONS, "Core dumps are enabled.");
866 } else if (!debug_flag) {
868 * Not debugging. Set the core size to zero, to
869 * prevent security breaches. i.e. People
870 * reading passwords from the 'core' file.
872 struct rlimit limits;
875 limits.rlim_max = core_limits.rlim_max;
877 if (setrlimit(RLIMIT_CORE, &limits) < 0) {
878 radlog(L_ERR|L_CONS, "Cannot disable core dumps: %s",
885 * The first time around, ensure that we can write to the
890 * We need root to do mkdir() and chown(), so we
891 * do this before giving up root.
893 radlogdir_iswritable(mainconfig.uid_name);
898 * Sanity check the configuration for internal
901 if (mainconfig.reject_delay > mainconfig.cleanup_delay) {
902 mainconfig.reject_delay = mainconfig.cleanup_delay;
909 * Free the configuration.
911 int free_mainconfig(void)
914 * Clean up the configuration data
917 cf_section_free(&mainconfig.config);
918 realm_free(mainconfig.realms);
919 clients_free(mainconfig.clients);