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;
60 static const char *data_dir = NULL;
63 * Map the proxy server configuration parameters to variables.
65 static CONF_PARSER proxy_config[] = {
66 { "retry_delay", PW_TYPE_INTEGER, 0, &mainconfig.proxy_retry_delay, Stringify(RETRY_DELAY) },
67 { "retry_count", PW_TYPE_INTEGER, 0, &mainconfig.proxy_retry_count, Stringify(RETRY_COUNT) },
68 { "synchronous", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_synchronous, "no" },
69 { "default_fallback", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_fallback, "no" },
70 { "dead_time", PW_TYPE_INTEGER, 0, &mainconfig.proxy_dead_time, Stringify(DEAD_TIME) },
71 { "post_proxy_authorize", PW_TYPE_BOOLEAN, 0, &mainconfig.post_proxy_authorize, "yes" },
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 { "datadir", PW_TYPE_STRING_PTR, 0, &data_dir, "${prefix}/share/freeradius"},
102 { "hostname_lookups", PW_TYPE_BOOLEAN, 0, &librad_dodns, "no" },
104 { "snmp", PW_TYPE_BOOLEAN, 0, &mainconfig.do_snmp, "no" },
106 { "max_request_time", PW_TYPE_INTEGER, 0, &mainconfig.max_request_time, Stringify(MAX_REQUEST_TIME) },
107 { "cleanup_delay", PW_TYPE_INTEGER, 0, &mainconfig.cleanup_delay, Stringify(CLEANUP_DELAY) },
108 { "max_requests", PW_TYPE_INTEGER, 0, &mainconfig.max_requests, Stringify(MAX_REQUESTS) },
109 { "delete_blocked_requests", PW_TYPE_INTEGER, 0, &mainconfig.kill_unresponsive_children, Stringify(FALSE) },
110 { "port", PW_TYPE_INTEGER, 0, &auth_port, Stringify(PW_AUTH_UDP_PORT) },
111 { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &mainconfig.allow_core_dumps, "no" },
112 { "log_stripped_names", PW_TYPE_BOOLEAN, 0, &log_stripped_names,"no" },
113 { "log_file", PW_TYPE_STRING_PTR, -1, &mainconfig.log_file, "${logdir}/radius.log" },
114 { "log_auth", PW_TYPE_BOOLEAN, -1, &mainconfig.log_auth, "no" },
115 { "log_auth_badpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_badpass, "no" },
116 { "log_auth_goodpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_goodpass, "no" },
117 { "pidfile", PW_TYPE_STRING_PTR, 0, &mainconfig.pid_file, "${run_dir}/radiusd.pid"},
118 { "bind_address", PW_TYPE_IPADDR, 0, &mainconfig.myip, "*" },
119 { "user", PW_TYPE_STRING_PTR, 0, &mainconfig.uid_name, NULL},
120 { "group", PW_TYPE_STRING_PTR, 0, &mainconfig.gid_name, NULL},
121 { "usercollide", PW_TYPE_BOOLEAN, 0, &mainconfig.do_usercollide, "no" },
122 { "lower_user", PW_TYPE_STRING_PTR, 0, &mainconfig.do_lower_user, "no" },
123 { "lower_pass", PW_TYPE_STRING_PTR, 0, &mainconfig.do_lower_pass, "no" },
124 { "nospace_user", PW_TYPE_STRING_PTR, 0, &mainconfig.do_nospace_user, "no" },
125 { "nospace_pass", PW_TYPE_STRING_PTR, 0, &mainconfig.do_nospace_pass, "no" },
126 { "checkrad", PW_TYPE_STRING_PTR, 0, &mainconfig.checkrad, "${sbindir}/checkrad" },
127 { "proxy_requests", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_requests, "yes" },
128 { "proxy", PW_TYPE_SUBSECTION, 0, proxy_config, NULL },
129 { "security", PW_TYPE_SUBSECTION, 0, security_config, NULL },
130 { "debug_level", PW_TYPE_INTEGER, 0, &mainconfig.debug_level, "0"},
131 { NULL, -1, 0, NULL, NULL }
135 * Xlat for %{config:section.subsection.attribute}
137 static int xlat_config(void *instance, REQUEST *request,
138 char *fmt, char *out, int outlen,
139 RADIUS_ESCAPE_STRING func)
145 const char *start = fmt;
152 * Find the next section.
154 for (p = buffer; (*fmt != 0) && (*fmt != '.'); p++, fmt++) {
160 * The character is a '.', find a section (as the user
161 * has given us a subsection to find)
166 fmt++; /* skip the period */
169 next = cf_section_find(buffer);
171 next = cf_subsection_find_next(cs, NULL, buffer);
174 radlog(L_ERR, "config: No such section %s in format string %s", buffer, start);
179 } else { /* no period, must be a conf-part */
180 cp = cf_pair_find(cs, buffer);
183 radlog(L_ERR, "config: No such section %s in format string %s", buffer, start);
187 } /* until cp is non-NULL */
190 * Ensure that we only copy what's necessary.
192 * If 'outlen' is too small, then the output is chopped to fit.
194 value = cf_pair_value(cp);
196 if (outlen > strlen(value)) {
197 outlen = strlen(value) + 1;
201 return func(out, outlen, value);
206 * Recursively make directories.
208 static int r_mkdir(const char *part) {
209 char *ptr, parentdir[500];
212 if (stat(part, &st) == 0)
215 ptr = strrchr(part, '/');
220 snprintf(parentdir, (ptr - part)+1, "%s", part);
222 if (r_mkdir(parentdir) != 0)
225 if (mkdir(part, 0770) != 0) {
226 fprintf(stderr, "mkdir(%s) error: %s\n", part, strerror(errno));
230 fprintf(stderr, "Created directory %s\n", part);
236 * Checks if the log directory is writeable by a particular user.
238 static int radlogdir_iswritable(const char *effectiveuser) {
239 struct passwd *pwent;
241 if (radlog_dir[0] != '/')
244 if (r_mkdir(radlog_dir) != 0)
247 /* FIXME: do we have this function? */
248 if (strstr(radlog_dir, "radius") == NULL)
251 /* we have a logdir that mentions 'radius', so it's probably
252 * safe to chown the immediate directory to be owned by the normal
253 * process owner. we gotta do it before we give up root. -chad
256 if (!effectiveuser) {
260 pwent = getpwnam(effectiveuser);
262 if (pwent == NULL) /* uh oh! */
265 if (chown(radlog_dir, pwent->pw_uid, -1) != 0)
272 static int switch_users(void) {
275 * Switch UID and GID to what is specified in the config file
279 if (mainconfig.gid_name != NULL) {
282 gr = getgrnam(mainconfig.gid_name);
284 if (errno == ENOMEM) {
285 radlog(L_ERR|L_CONS, "Cannot switch to Group %s: out of memory", mainconfig.gid_name);
287 radlog(L_ERR|L_CONS, "Cannot switch group; %s doesn't exist", mainconfig.gid_name);
291 server_gid = gr->gr_gid;
292 if (setgid(server_gid) < 0) {
293 radlog(L_ERR|L_CONS, "Failed setting Group to %s: %s", mainconfig.gid_name, strerror(errno));
299 if (mainconfig.uid_name != NULL) {
302 pw = getpwnam(mainconfig.uid_name);
304 if (errno == ENOMEM) {
305 radlog(L_ERR|L_CONS, "Cannot switch to User %s: out of memory", mainconfig.uid_name);
307 radlog(L_ERR|L_CONS, "Cannot switch user; %s doesn't exist", mainconfig.uid_name);
311 server_uid = pw->pw_uid;
312 if (setuid(server_uid) < 0) {
313 radlog(L_ERR|L_CONS, "Failed setting User to %s: %s", mainconfig.uid_name, strerror(errno));
322 * Create the linked list of realms from the new configuration type
323 * This way we don't have to change to much in the other source-files
325 static int generate_realms(const char *filename)
328 REALM *my_realms = NULL;
330 char *s, *t, *authhost, *accthost;
334 for (cs = cf_subsection_find_next(mainconfig.config, NULL, "realm"); cs != NULL;
335 cs = cf_subsection_find_next(mainconfig.config, cs, "realm")) {
336 name2 = cf_section_name2(cs);
338 radlog(L_CONS|L_ERR, "%s[%d]: Missing realm name", filename, cf_section_lineno(cs));
342 * We've found a realm, allocate space for it
344 c = rad_malloc(sizeof(REALM));
345 memset(c, 0, sizeof(REALM));
350 * No authhost means LOCAL.
352 if ((authhost = cf_section_value_find(cs, "authhost")) == NULL) {
353 c->ipaddr = htonl(INADDR_NONE);
354 c->auth_port = auth_port;
356 if ((s = strchr(authhost, ':')) != NULL) {
358 c->auth_port = atoi(s);
360 c->auth_port = auth_port;
362 if (strcmp(authhost, "LOCAL") == 0) {
364 * Local realms don't have an IP address,
367 c->ipaddr = htonl(INADDR_NONE);
368 c->auth_port = auth_port;
370 c->ipaddr = ip_getaddr(authhost);
375 * No accthost means LOCAL
377 if ((accthost = cf_section_value_find(cs, "accthost")) == NULL) {
378 c->acct_ipaddr = htonl(INADDR_NONE);
379 c->acct_port = acct_port;
381 if ((s = strchr(accthost, ':')) != NULL) {
383 c->acct_port = atoi(s);
385 c->acct_port = acct_port;
387 if (strcmp(accthost, "LOCAL") == 0) {
389 * Local realms don't have an IP address,
392 c->acct_ipaddr = htonl(INADDR_NONE);
393 c->acct_port = acct_port;
395 c->acct_ipaddr = ip_getaddr(accthost);
400 * Double check length, just to be sure!
402 if (strlen(authhost) >= sizeof(c->server)) {
403 radlog(L_ERR, "%s[%d]: Server name of length %d is greater that allowed: %d",
404 filename, cf_section_lineno(cs),
405 strlen(authhost), sizeof(c->server) - 1);
408 if (strlen(name2) >= sizeof(c->realm)) {
409 radlog(L_ERR, "%s[%d]: Realm name of length %d is greater than allowed %d",
410 filename, cf_section_lineno(cs),
411 strlen(name2), sizeof(c->server) - 1);
415 strcpy(c->realm, name2);
416 strcpy(c->server, authhost);
419 * If one or the other of authentication/accounting
420 * servers is set to LOCALHOST, then don't require
423 if ((c->ipaddr != htonl(INADDR_NONE)) ||
424 (c->acct_ipaddr != htonl(INADDR_NONE))) {
425 if ((s = cf_section_value_find(cs, "secret")) == NULL ) {
426 radlog(L_ERR, "%s[%d]: No shared secret supplied for realm: %s",
427 filename, cf_section_lineno(cs), name2);
431 if (strlen(s) >= sizeof(c->secret)) {
432 radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
433 filename, cf_section_lineno(cs),
434 strlen(s), sizeof(c->secret) - 1);
437 strNcpy((char *)c->secret, s, sizeof(c->secret));
442 if ((cf_section_value_find(cs, "nostrip")) != NULL)
444 if ((cf_section_value_find(cs, "noacct")) != NULL)
446 if ((cf_section_value_find(cs, "trusted")) != NULL)
448 if ((cf_section_value_find(cs, "notrealm")) != NULL)
450 if ((cf_section_value_find(cs, "notsuffix")) != NULL)
452 if ((t = cf_section_value_find(cs,"ldflag")) != NULL) {
453 static const LRAD_NAME_NUMBER ldflags[] = {
455 { "round_robin", 1 },
459 c->ldflag = lrad_str2int(ldflags, t, -1);
460 if (c->ldflag == -1) {
461 radlog(L_ERR, "%s[%d]: Unknown value \"%s\" for ldflag",
462 filename, cf_section_lineno(cs),
468 c->ldflag = 0; /* non, make it fail-over */
471 c->acct_active = TRUE;
479 * And make these realms preferred over the ones
480 * in the 'realms' file.
482 *tail = mainconfig.realms;
483 mainconfig.realms = my_realms;
486 * Ensure that all of the flags agree for the realms.
488 * Yeah, it's O(N^2), but it's only once, and the
489 * maximum number of realms is small.
491 for(c = mainconfig.realms; c != NULL; c = c->next) {
495 * Check that we cannot load balance to LOCAL
496 * realms, as that doesn't make any sense.
498 if ((c->ldflag == 1) &&
499 ((c->ipaddr == htonl(INADDR_NONE)) ||
500 (c->acct_ipaddr == htonl(INADDR_NONE)))) {
501 radlog(L_ERR | L_CONS, "ERROR: Realm %s cannot be load balanced to LOCAL",
507 * Compare this realm to all others, to ensure
508 * that the configuration is consistent.
510 for (this = c->next; this != NULL; this = this->next) {
511 if (strcasecmp(c->realm, this->realm) != 0) {
516 * Same realm: Different load balancing
519 if (c->ldflag != this->ldflag) {
520 radlog(L_ERR | L_CONS, "ERROR: Inconsistent value in realm %s for load balancing 'ldflag' attribute",
532 * Create the linked list of realms from the new configuration
533 * type. This way we don't have to change too much in the other
536 static int generate_clients(const char *filename)
540 char *hostnm, *secret, *shortnm, *netmask;
541 char *nastype, *login, *password;
544 for (cs = cf_subsection_find_next(mainconfig.config, NULL, "client");
546 cs = cf_subsection_find_next(mainconfig.config, cs, "client")) {
548 name2 = cf_section_name2(cs);
550 radlog(L_CONS|L_ERR, "%s[%d]: Missing client name",
551 filename, cf_section_lineno(cs));
555 * Check the lengths, we don't want any core dumps
559 if((secret = cf_section_value_find(cs, "secret")) == NULL) {
560 radlog(L_ERR, "%s[%d]: Missing secret for client: %s",
561 filename, cf_section_lineno(cs), name2);
565 if((shortnm = cf_section_value_find(cs, "shortname")) == NULL) {
566 radlog(L_ERR, "%s[%d]: Missing shortname for client: %s",
567 filename, cf_section_lineno(cs), name2);
571 netmask = strchr(hostnm, '/');
573 if (strlen(secret) >= sizeof(c->secret)) {
574 radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
575 filename, cf_section_lineno(cs),
576 strlen(secret), sizeof(c->secret) - 1);
579 if (strlen(shortnm) > sizeof(c->shortname)) {
580 radlog(L_ERR, "%s[%d]: Client short name of length %d is greater than the allowed maximum of %d.",
581 filename, cf_section_lineno(cs),
582 strlen(shortnm), sizeof(c->shortname) - 1);
586 if((nastype = cf_section_value_find(cs, "nastype")) != NULL) {
587 if(strlen(nastype) >= sizeof(c->nastype)) {
588 radlog(L_ERR, "%s[%d]: nastype of length %d longer than the allowed maximum of %d",
589 filename, cf_section_lineno(cs),
590 strlen(nastype), sizeof(c->nastype) - 1);
595 if((login = cf_section_value_find(cs, "login")) != NULL) {
596 if(strlen(login) >= sizeof(c->login)) {
597 radlog(L_ERR, "%s[%d]: login of length %d longer than the allowed maximum of %d",
598 filename, cf_section_lineno(cs),
599 strlen(login), sizeof(c->login) - 1);
604 if((password = cf_section_value_find(cs, "password")) != NULL) {
605 if(strlen(password) >= sizeof(c->password)) {
606 radlog(L_ERR, "%s[%d]: password of length %d longer than the allowed maximum of %d",
607 filename, cf_section_lineno(cs),
608 strlen(password), sizeof(c->password) - 1);
614 * The size is fine.. Let's create the buffer
616 c = rad_malloc(sizeof(RADCLIENT));
617 memset(c, 0, sizeof(RADCLIENT));
626 mask_length = atoi(netmask + 1);
627 if ((mask_length <= 0) || (mask_length > 32)) {
628 radlog(L_ERR, "%s[%d]: Invalid value '%s' for IP network mask.",
629 filename, cf_section_lineno(cs), netmask + 1);
633 c->netmask = (1 << 31);
634 for (i = 1; i < mask_length; i++) {
635 c->netmask |= (c->netmask >> 1);
639 c->netmask = htonl(c->netmask);
642 c->ipaddr = ip_getaddr(hostnm);
643 if (c->ipaddr == INADDR_NONE) {
644 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
645 filename, cf_section_lineno(cs), hostnm);
650 * Update the client name again...
654 c->ipaddr &= c->netmask;
655 strcpy(c->longname, hostnm);
657 ip_hostname(c->longname, sizeof(c->longname),
661 strcpy((char *)c->secret, secret);
662 strcpy(c->shortname, shortnm);
664 strcpy(c->nastype, nastype);
666 strcpy(c->login, login);
668 strcpy(c->password, password);
670 c->next =mainconfig. clients;
671 mainconfig.clients = c;
677 #ifndef RADIUS_CONFIG
678 #define RADIUS_CONFIG "radiusd.conf"
681 CONF_SECTION *read_radius_conf_file(void)
686 /* Lets go look for the new configuration files */
687 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
688 if ((cs = conf_read(NULL, 0, buffer, NULL)) == NULL) {
693 * This allows us to figure out where, relative to
694 * radiusd.conf, the other configuration files exist.
696 cf_section_parse(cs, NULL, server_config);
698 /* Initialize the dictionary */
699 DEBUG2("read_config_files: reading dictionary");
700 if (dict_init(data_dir, RADIUS_DICTIONARY) != 0) {
701 radlog(L_ERR|L_CONS, "Errors reading dictionary: %s",
703 cf_section_free(&cs);
714 * This function can ONLY be called from the main server process.
716 int read_mainconfig(int reload)
718 struct rlimit core_limits;
719 static int old_debug_level = -1;
721 CONF_SECTION *cs, *oldcs;
724 radlog(L_INFO, "Starting - reading configuration files ...");
726 radlog(L_INFO, "Reloading configuration files.");
729 /* First read radiusd.conf */
730 DEBUG2("reread_config: reading radiusd.conf");
731 if ((cs = read_radius_conf_file()) == NULL) {
733 (radlog_dir == NULL)) {
734 radlog(L_ERR|L_CONS, "Errors reading radiusd.conf");
736 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);
742 * Free the old configuration items, and replace them
745 * Note that where possible, we do atomic switch-overs,
746 * to ensure that the pointers are always valid.
748 oldcs = mainconfig.config;
749 mainconfig.config = cs;
750 cf_section_free(&oldcs);
752 /* old-style naslist file */
753 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_NASLIST);
754 DEBUG2("read_config_files: reading naslist");
755 if (read_naslist_file(buffer) < 0) {
756 radlog(L_ERR|L_CONS, "Errors reading naslist");
759 /* old-style clients file */
760 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_CLIENTS);
761 DEBUG2("read_config_files: reading clients");
762 if (read_clients_file(buffer) < 0) {
763 radlog(L_ERR|L_CONS, "Errors reading clients");
768 * Add to that, the *new* list of clients.
770 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
771 if (generate_clients(buffer) < 0) {
775 /* old-style realms file */
776 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_REALMS);
777 DEBUG2("read_config_files: reading realms");
778 if (read_realms_file(buffer) < 0) {
779 radlog(L_ERR|L_CONS, "Errors reading realms");
784 * If there isn't any realms it isn't fatal..
786 snprintf(buffer, sizeof(buffer), "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
787 if (generate_realms(buffer) < 0) {
792 * Register the %{config:section.subsection} xlat function.
794 xlat_register("config", xlat_config, NULL);
797 * Set the libraries debugging flag to whatever the main
798 * flag is. Note that on a SIGHUP, to turn the debugging
799 * off, we do other magic.
801 * Increase the debug level, if the configuration file
802 * says to, OR, if we're decreasing the debug from what it
803 * was before, allow that, too.
805 if ((mainconfig.debug_level > debug_flag) ||
806 (mainconfig.debug_level <= old_debug_level)) {
807 debug_flag = mainconfig.debug_level;
809 librad_debug = debug_flag;
810 old_debug_level = mainconfig.debug_level;
813 * Go update our behaviour, based on the configuration
817 /* Get the current maximum for core files. */
818 if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
819 radlog(L_ERR|L_CONS, "Failed to get current core limit: %s", strerror(errno));
823 if (mainconfig.allow_core_dumps) {
824 if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
825 radlog(L_ERR|L_CONS, "Cannot update core dump limit: %s",
830 * If we're running as a daemon, and core
831 * dumps are enabled, log that information.
833 } else if ((core_limits.rlim_cur != 0) && !debug_flag)
834 radlog(L_INFO|L_CONS, "Core dumps are enabled.");
836 } else if (!debug_flag) {
838 * Not debugging. Set the core size to zero, to
839 * prevent security breaches. i.e. People
840 * reading passwords from the 'core' file.
842 struct rlimit limits;
845 limits.rlim_max = core_limits.rlim_max;
847 if (setrlimit(RLIMIT_CORE, &limits) < 0) {
848 radlog(L_ERR|L_CONS, "Cannot disable core dumps: %s",
855 * The first time around, ensure that we can write to the
860 * We need root to do mkdir() and chown(), so we
861 * do this before giving up root.
863 radlogdir_iswritable(mainconfig.uid_name);
868 * Sanity check the configuration for internal
871 if (mainconfig.reject_delay > mainconfig.cleanup_delay) {
872 mainconfig.reject_delay = mainconfig.cleanup_delay;
879 * Free the configuration.
881 int free_mainconfig(void)
884 * Clean up the configuration data
887 cf_section_free(&mainconfig.config);
888 realm_free(mainconfig.realms);
889 clients_free(mainconfig.clients);