Don't make old log_foo over-ride new one. This closes bug #525
[freeradius.git] / src / main / mainconfig.c
1 /*
2  * mainconf.c   Handle the server's configuration.
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2002,2006-2007  The FreeRADIUS server project
21  * Copyright 2002  Alan DeKok <aland@ox.org>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 #include <freeradius-devel/rad_assert.h>
30
31 #include <sys/stat.h>
32
33 #ifdef HAVE_SYS_RESOURCE_H
34 #include <sys/resource.h>
35 #endif
36
37 #ifdef HAVE_PWD_H
38 #include <pwd.h>
39 #endif
40
41 #ifdef HAVE_GRP_H
42 #include <grp.h>
43 #endif
44
45 #ifdef HAVE_SYS_PRCTL_H
46 #include <sys/prctl.h>
47 #endif
48
49 #ifdef HAVE_SYSLOG_H
50 #       include <syslog.h>
51 #endif
52
53 struct main_config_t mainconfig;
54
55 /*
56  *      Temporary local variables for parsing the configuration
57  *      file.
58  */
59 static uid_t server_uid;
60 static gid_t server_gid;
61 static const char *uid_name = NULL;
62 static const char *gid_name = NULL;
63 static int allow_core_dumps = 0;
64 static const char *radlog_dest = NULL;
65
66 /*
67  *      These are not used anywhere else..
68  */
69 static const char *localstatedir = NULL;
70 static const char *prefix = NULL;
71 static char *syslog_facility = NULL;
72 static const FR_NAME_NUMBER str2fac[] = {
73 #ifdef LOG_KERN
74         { "kern", LOG_KERN },
75 #endif
76 #ifdef LOG_USER
77         { "user", LOG_USER },
78 #endif
79 #ifdef LOG_MAIL
80         { "mail", LOG_MAIL },
81 #endif
82 #ifdef LOG_DAEMON
83         { "daemon", LOG_DAEMON },
84 #endif
85 #ifdef LOG_AUTH
86         { "auth", LOG_AUTH },
87 #endif
88 #ifdef LOG_LPR
89         { "lpr", LOG_LPR },
90 #endif
91 #ifdef LOG_NEWS
92         { "news", LOG_NEWS },
93 #endif
94 #ifdef LOG_UUCP
95         { "uucp", LOG_UUCP },
96 #endif
97 #ifdef LOG_CRON
98         { "cron", LOG_CRON },
99 #endif
100 #ifdef LOG_AUTHPRIV
101         { "authpriv", LOG_AUTHPRIV },
102 #endif
103 #ifdef LOG_FTP
104         { "ftp", LOG_FTP },
105 #endif
106 #ifdef LOG_LOCAL0
107         { "local0", LOG_LOCAL0 },
108 #endif
109 #ifdef LOG_LOCAL1
110         { "local1", LOG_LOCAL1 },
111 #endif
112 #ifdef LOG_LOCAL2
113         { "local2", LOG_LOCAL2 },
114 #endif
115 #ifdef LOG_LOCAL3
116         { "local3", LOG_LOCAL3 },
117 #endif
118 #ifdef LOG_LOCAL4
119         { "local4", LOG_LOCAL4 },
120 #endif
121 #ifdef LOG_LOCAL5
122         { "local5", LOG_LOCAL5 },
123 #endif
124 #ifdef LOG_LOCAL6
125         { "local6", LOG_LOCAL6 },
126 #endif
127 #ifdef LOG_LOCAL7
128         { "local7", LOG_LOCAL7 },
129 #endif
130         { NULL, -1 }
131 };
132
133 /*
134  *  Security configuration for the server.
135  */
136 static const CONF_PARSER security_config[] = {
137         { "max_attributes",  PW_TYPE_INTEGER, 0, &librad_max_attributes, Stringify(0) },
138         { "reject_delay",  PW_TYPE_INTEGER, 0, &mainconfig.reject_delay, Stringify(0) },
139         { "status_server", PW_TYPE_BOOLEAN, 0, &mainconfig.status_server, "no"},
140         { NULL, -1, 0, NULL, NULL }
141 };
142
143
144 /*
145  *      Logging configuration for the server.
146  */
147 static const CONF_PARSER log_config[] = {
148         { "destination",  PW_TYPE_STRING_PTR, 0, &radlog_dest, "files" },
149         { "syslog_facility",  PW_TYPE_STRING_PTR, 0, &syslog_facility, Stringify(0) },
150         { "stripped_names", PW_TYPE_BOOLEAN, 0, &log_stripped_names,"no" },
151
152         { "file", PW_TYPE_STRING_PTR, -1, &mainconfig.log_file, "${logdir}/radius.log" },
153         { "auth", PW_TYPE_BOOLEAN, -1, &mainconfig.log_auth, "no" },
154         { "auth_badpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_badpass, "no" },
155         { "auth_goodpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_goodpass, "no" },
156         { NULL, -1, 0, NULL, NULL }
157 };
158
159
160 /*
161  *  A mapping of configuration file names to internal variables
162  */
163 static const CONF_PARSER server_config[] = {
164         /*
165          *      FIXME: 'prefix' is the ONLY one which should be
166          *      configured at compile time.  Hard-coding it here is
167          *      bad.  It will be cleaned up once we clean up the
168          *      hard-coded defines for the locations of the various
169          *      files.
170          */
171         { "prefix",             PW_TYPE_STRING_PTR, 0, &prefix,            "/usr/local"},
172         { "localstatedir",      PW_TYPE_STRING_PTR, 0, &localstatedir,     "${prefix}/var"},
173         { "logdir",             PW_TYPE_STRING_PTR, 0, &radlog_dir,        "${localstatedir}/log"},
174         { "libdir",             PW_TYPE_STRING_PTR, 0, &radlib_dir,        "${prefix}/lib"},
175         { "radacctdir",         PW_TYPE_STRING_PTR, 0, &radacct_dir,       "${logdir}/radacct" },
176         { "hostname_lookups",   PW_TYPE_BOOLEAN,    0, &librad_dodns,      "no" },
177         { "max_request_time", PW_TYPE_INTEGER, 0, &mainconfig.max_request_time, Stringify(MAX_REQUEST_TIME) },
178         { "cleanup_delay", PW_TYPE_INTEGER, 0, &mainconfig.cleanup_delay, Stringify(CLEANUP_DELAY) },
179         { "max_requests", PW_TYPE_INTEGER, 0, &mainconfig.max_requests, Stringify(MAX_REQUESTS) },
180 #ifdef DELETE_BLOCKED_REQUESTS
181         { "delete_blocked_requests", PW_TYPE_INTEGER, 0, &mainconfig.kill_unresponsive_children, Stringify(FALSE) },
182 #endif
183         { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &allow_core_dumps, "no" },
184
185         { "pidfile", PW_TYPE_STRING_PTR, 0, &mainconfig.pid_file, "${run_dir}/radiusd.pid"},
186         { "user", PW_TYPE_STRING_PTR, 0, &uid_name, NULL},
187         { "group", PW_TYPE_STRING_PTR, 0, &gid_name, NULL},
188         { "checkrad", PW_TYPE_STRING_PTR, 0, &mainconfig.checkrad, "${sbindir}/checkrad" },
189
190         { "debug_level", PW_TYPE_INTEGER, 0, &mainconfig.debug_level, "0"},
191
192         { "proxy_requests", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_requests, "yes" },
193         { "security", PW_TYPE_SUBSECTION, 0, NULL, (const void *) security_config },
194         { NULL, -1, 0, NULL, NULL }
195 };
196
197 static const CONF_PARSER serverlog_config[] = {
198         { "log", PW_TYPE_SUBSECTION, 0, NULL,  (const void *) log_config},
199
200         /*
201          *      People with old configs will have these.  They are listed
202          *      AFTER the "log" section, so if they exist in radiusd.conf,
203          *      it will prefer "log_foo = bar" to "log { foo = bar }".
204          *      They're listed with default values of NULL, so that if they
205          *      DON'T exist in radiusd.conf, then the previously parsed
206          *      values for "log { foo = bar}" will be used.
207          */
208         { "log_auth", PW_TYPE_BOOLEAN, -1, &mainconfig.log_auth, NULL },
209         { "log_auth_badpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_badpass, NULL },
210         { "log_auth_goodpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_goodpass, NULL },
211         { "log_stripped_names", PW_TYPE_BOOLEAN, 0, &log_stripped_names, NULL },
212         { "log_file", PW_TYPE_STRING_PTR, -1, &mainconfig.log_file, NULL },
213         { "log_destination", PW_TYPE_STRING_PTR, -1, &radlog_dest, NULL },
214         { NULL, -1, 0, NULL, NULL }
215 };
216
217
218 #define MAX_ARGV (256)
219
220
221 static size_t config_escape_func(char *out, size_t outlen, const char *in)
222 {
223         size_t len = 0;
224         static const char *disallowed = "%{}\\'\"`";
225
226         while (in[0]) {
227                 /*
228                  *      Non-printable characters get replaced with their
229                  *      mime-encoded equivalents.
230                  */
231                 if ((in[0] < 32)) {
232                         if (outlen <= 3) break;
233
234                         snprintf(out, outlen, "=%02X", (unsigned char) in[0]);
235                         in++;
236                         out += 3;
237                         outlen -= 3;
238                         len += 3;
239                         continue;
240
241                 } else if (strchr(disallowed, *in) != NULL) {
242                         if (outlen <= 2) break;
243
244                         out[0] = '\\';
245                         out[1] = *in;
246                         in++;
247                         out += 2;
248                         outlen -= 2;
249                         len += 2;
250                         continue;
251                 }
252
253                 /*
254                  *      Only one byte left.
255                  */
256                 if (outlen <= 1) {
257                         break;
258                 }
259
260                 /*
261                  *      Allowed character.
262                  */
263                 *out = *in;
264                 out++;
265                 in++;
266                 outlen--;
267                 len++;
268         }
269         *out = '\0';
270         return len;
271 }
272
273 /*
274  *      Xlat for %{config:section.subsection.attribute}
275  */
276 static size_t xlat_config(void *instance, REQUEST *request,
277                           char *fmt, char *out,
278                           size_t outlen,
279                           RADIUS_ESCAPE_STRING func)
280 {
281         const char *value;
282         CONF_PAIR *cp;
283         CONF_ITEM *ci;
284         char buffer[1024];
285
286         request = request;      /* -Wunused */
287         instance = instance;    /* -Wunused */
288
289         /*
290          *      Expand it safely.
291          */
292         if (!radius_xlat(buffer, sizeof(buffer), fmt, request, config_escape_func)) {
293                 return 0;
294         }
295
296         ci = cf_reference_item(request->root->config,
297                                request->root->config, buffer);
298         if (!ci || !cf_item_is_pair(ci)) {
299                 *out = '\0';
300                 return 0;
301         }
302
303         cp = cf_itemtopair(ci);
304
305         /*
306          *  Ensure that we only copy what's necessary.
307          *
308          *  If 'outlen' is too small, then the output is chopped to fit.
309          */
310         value = cf_pair_value(cp);
311         if (value) {
312                 if (outlen > strlen(value)) {
313                         outlen = strlen(value) + 1;
314                 }
315         }
316
317         return func(out, outlen, value);
318 }
319
320
321 /*
322  *      Xlat for %{client:foo}
323  */
324 static size_t xlat_client(UNUSED void *instance, REQUEST *request,
325                        char *fmt, char *out,
326                        size_t outlen,
327                        UNUSED RADIUS_ESCAPE_STRING func)
328 {
329         const char *value = NULL;
330         CONF_PAIR *cp;
331
332         if (!fmt || !out || (outlen < 1)) return 0;
333
334         if (!request || !request->client) {
335                 *out = '\0';
336                 return 0;
337         }
338
339         cp = cf_pair_find(request->client->cs, fmt);
340         if (!cp || !(value = cf_pair_value(cp))) {
341                 *out = '\0';
342                 return 0;
343         }
344         
345         strlcpy(out, value, outlen);
346
347         return strlen(out);
348 }
349
350 /*
351  *      Recursively make directories.
352  */
353 static int r_mkdir(const char *part)
354 {
355         char *ptr, parentdir[500];
356         struct stat st;
357
358         if (stat(part, &st) == 0)
359                 return(0);
360
361         ptr = strrchr(part, FR_DIR_SEP);
362
363         if (ptr == part)
364                 return(0);
365
366         snprintf(parentdir, (ptr - part)+1, "%s", part);
367
368         if (r_mkdir(parentdir) != 0)
369                 return(1);
370
371         if (mkdir(part, 0770) != 0) {
372                 radlog(L_ERR, "mkdir(%s) error: %s\n", part, strerror(errno));
373                 return(1);
374         }
375
376         return(0);
377 }
378
379 /*
380  *      Checks if the log directory is writeable by a particular user.
381  */
382 static int radlogdir_iswritable(const char *effectiveuser)
383 {
384 #ifdef HAVE_GETPWNAM
385         struct passwd *pwent;
386 #endif
387
388         if (!radlog_dir || FR_DIR_IS_RELATIVE(radlog_dir))
389                 return(0);
390
391         if (r_mkdir(radlog_dir) != 0)
392                 return(1);
393
394         /* FIXME: do we have this function? */
395         if (strstr(radlog_dir, "radius") == NULL)
396                 return(0);
397
398         /* we have a logdir that mentions 'radius', so it's probably
399          * safe to chown the immediate directory to be owned by the normal
400          * process owner. we gotta do it before we give up root.  -chad
401          */
402
403         if (!effectiveuser) {
404                 return 1;
405         }
406
407 #ifdef HAVE_GETPWNAM
408         pwent = getpwnam(effectiveuser);
409
410         if (pwent == NULL) /* uh oh! */
411                 return(1);
412
413         if (chown(radlog_dir, pwent->pw_uid, -1) != 0)
414                 return(1);
415 #endif
416
417         return(0);
418 }
419
420
421 /*
422  *  Switch UID and GID to what is specified in the config file
423  */
424 static int switch_users(void)
425 {
426         int did_setuid = FALSE;
427
428 #ifdef HAVE_SYS_RESOURCE_H
429         struct rlimit core_limits;
430 #endif
431
432 #ifdef HAVE_GRP_H
433         /*  Set GID.  */
434         if (gid_name != NULL) {
435                 struct group *gr;
436
437                 gr = getgrnam(gid_name);
438                 if (gr == NULL) {
439                         if (errno == ENOMEM) {
440                                 radlog(L_ERR, "Cannot switch to Group %s: out of memory", gid_name);
441                         } else {
442                                 radlog(L_ERR, "Cannot switch group; %s doesn't exist", gid_name);
443                         }
444                         return 0;
445                 }
446                 server_gid = gr->gr_gid;
447                 if (setgid(server_gid) < 0) {
448                         radlog(L_ERR, "Failed setting Group to %s: %s",
449                                gid_name, strerror(errno));
450                         return 0;
451                 }
452         } else {
453                 server_gid = getgid();
454         }
455 #endif
456
457 #ifdef HAVE_PWD_H
458         /*  Set UID.  */
459         if (uid_name != NULL) {
460                 struct passwd *pw;
461
462                 pw = getpwnam(uid_name);
463                 if (pw == NULL) {
464                         if (errno == ENOMEM) {
465                                 radlog(L_ERR, "Cannot switch to User %s: out of memory", uid_name);
466                         } else {
467                                 radlog(L_ERR, "Cannot switch user; %s doesn't exist", uid_name);
468                         }
469                         return 0;
470                 }
471                 server_uid = pw->pw_uid;
472 #ifdef HAVE_INITGROUPS
473                 if (initgroups(uid_name, server_gid) < 0) {
474                         if (errno != EPERM) {
475                                 radlog(L_ERR, "Failed setting supplementary groups for User %s: %s", uid_name, strerror(errno));
476                                 return 0;
477                         }
478                 }
479 #endif
480                 if (setuid(server_uid) < 0) {
481                         radlog(L_ERR, "Failed setting User to %s: %s", uid_name, strerror(errno));
482                         return 0;
483                 }
484
485                 /*
486                  *      Now core dumps are disabled on most secure systems.
487                  */
488                 did_setuid = TRUE;
489         }
490 #endif
491
492 #ifdef HAVE_SYS_RESOURCE_H
493         /*  Get the current maximum for core files.  */
494         if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
495                 radlog(L_ERR, "Failed to get current core limit:  %s", strerror(errno));
496                 return 0;
497         }
498 #endif
499
500         /*
501          *      Core dumps are allowed if we're in debug mode, OR
502          *      we've allowed them, OR we did a setuid (which turns
503          *      core dumps off).
504          *
505          *      Otherwise, disable core dumps for security.
506          *      
507          */
508         if (!(debug_flag || allow_core_dumps || did_setuid)) {
509 #ifdef HAVE_SYS_RESOURCE_H
510                 struct rlimit no_core;
511
512                 no_core.rlim_cur = 0;
513                 no_core.rlim_max = 0;
514
515                 if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
516                         radlog(L_ERR, "Failed disabling core dumps: %s",
517                                strerror(errno));
518                         return 0;
519                 }
520 #endif
521
522                 /*
523                  *      Otherwise, re-enable core dumps if we're
524                  *      running as a daemon, AND core dumps are
525                  *      allowed, AND we changed UID's.
526                  */
527         } else if ((debug_flag == 0) && allow_core_dumps && did_setuid) {
528                 /*
529                  *      Set the dumpable flag.
530                  */
531 #ifdef HAVE_SYS_PRCTL_H
532 #ifdef PR_SET_DUMPABLE
533                 if (prctl(PR_SET_DUMPABLE, 1) < 0) {
534                         radlog(L_ERR,"Cannot enable core dumps: prctl(PR_SET_DUMPABLE) failed: '%s'",
535                                strerror(errno));
536                 }
537 #endif
538 #endif
539
540                 /*
541                  *      Reset the core dump limits again, just to
542                  *      double check that they haven't changed.
543                  */
544 #ifdef HAVE_SYS_RESOURCE_H
545                 if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
546                         radlog(L_ERR, "Cannot update core dump limit: %s",
547                                         strerror(errno));
548                         return 0;
549                 }
550 #endif
551
552                 radlog(L_INFO, "Core dumps are enabled.");
553         }
554         /*
555          *      Else we're debugging (so core dumps are enabled)
556          *      OR we're not debugging, AND "allow_core_dumps == FALSE",
557          *      OR we're not debugging, AND core dumps are allowed,
558          *         BUT we didn't call setuid, so we haven't changed the
559          *         core dump capabilities inherited from the parent shell.
560          */
561
562 #if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
563         /*
564          *      We've probably written to the log file already as
565          *      root.root, so if we have switched users, we've got to
566          *      update the ownership of the file.
567          */
568         if ((debug_flag == 0) &&
569             (mainconfig.radlog_dest == RADLOG_FILES) &&
570             (mainconfig.log_file != NULL)) {
571                 chown(mainconfig.log_file, server_uid, server_gid);
572         }
573 #endif
574         return 1;
575 }
576
577
578 static const FR_NAME_NUMBER str2dest[] = {
579         { "null", RADLOG_NULL },
580         { "files", RADLOG_FILES },
581         { "syslog", RADLOG_SYSLOG },
582         { "stdout", RADLOG_STDOUT },
583         { "stderr", RADLOG_STDERR },
584         { NULL, RADLOG_NUM_DEST }
585 };
586
587
588 /*
589  *      Read config files.
590  *
591  *      This function can ONLY be called from the main server process.
592  */
593 int read_mainconfig(int reload)
594 {
595         const char *p = NULL;
596         static int old_debug_level = -1;
597         CONF_PAIR *cp;
598         CONF_SECTION *cs;
599         struct stat statbuf;
600         char buffer[1024];
601
602         if (stat(radius_dir, &statbuf) < 0) {
603                 radlog(L_ERR, "Errors reading %s: %s",
604                        radius_dir, strerror(errno));
605                 return -1;
606         }
607
608 #ifdef S_IWOTH
609         if ((statbuf.st_mode & S_IWOTH) != 0) {
610                 radlog(L_ERR, "Configuration directory %s is globally writable.  Refusing to start due to insecure configuration.",
611                        radius_dir);
612           return -1;
613         }
614 #endif
615
616 #ifdef S_IROTH
617         if (0 && (statbuf.st_mode & S_IROTH) != 0) {
618                 radlog(L_ERR, "Configuration directory %s is globally readable.  Refusing to start due to insecure configuration.",
619                        radius_dir);
620                 return -1;
621         }
622 #endif
623
624         if (!reload) {
625                 radlog(L_INFO, "Starting - reading configuration files ...");
626         } else {
627                 radlog(L_INFO, "Reloading - reading configuration files...");
628         }
629
630         /* Read the configuration file */
631         snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
632                  radius_dir, mainconfig.name);
633         if ((cs = cf_file_read(buffer)) == NULL) {
634                 radlog(L_ERR, "Errors reading %s", buffer);
635                 return -1;
636         }
637
638         /*
639          *      Debug flag 1 MAY go to files.
640          *      Debug flag 2 ALWAYS goes to stdout
641          *
642          *      Parse the log{} section before printing anything else.
643          *      All messages before this MUST be errors, which log.c
644          *      will print to stderr.
645          */
646         if (debug_flag < 2) {
647                 if (cf_section_parse(cs, NULL, serverlog_config) < 0) {
648                         fprintf(stderr, "radiusd: Error: Failed to parse log{} section.\n");
649                         cf_section_free(&cs);
650                         return -1;
651                 }
652
653                 if (!radlog_dest) {
654                         fprintf(stderr, "radiusd: Error: No log destination specified.\n");
655                         cf_section_free(&cs);
656                         return -1;
657                 }
658
659                 mainconfig.radlog_dest = fr_str2int(str2dest, radlog_dest,
660                                                     RADLOG_NUM_DEST);
661                 if (mainconfig.radlog_dest == RADLOG_NUM_DEST) {
662                         fprintf(stderr, "radiusd: Error: Unknown log_destination %s\n",
663                                 radlog_dest);
664                         cf_section_free(&cs);
665                         return -1;
666                 }
667
668                 if (mainconfig.radlog_dest == RADLOG_SYSLOG) {
669                         /*
670                          *      Make sure syslog_facility isn't NULL
671                          *      before using it
672                          */
673                         if (!syslog_facility) {
674                                 fprintf(stderr, "radiusd: Error: Syslog chosen but no facility was specified\n");
675                                 cf_section_free(&cs);
676                                 return -1;
677                         }
678                         mainconfig.syslog_facility = fr_str2int(str2fac, syslog_facility, -1);
679                         if (mainconfig.syslog_facility < 0) {
680                                 fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n",
681                                         syslog_facility);
682                                 cf_section_free(&cs);
683                                 return -1;
684                         }
685                 }
686         } else {
687                 mainconfig.radlog_dest = RADLOG_STDOUT;
688                 mainconfig.radlog_fd = STDOUT_FILENO;
689         }
690
691         /* Initialize the dictionary */
692         cp = cf_pair_find(cs, "dictionary");
693         if (cp) p = cf_pair_value(cp);
694         if (!p) p = radius_dir;
695         DEBUG2("including dictionary file %s/%s", p, RADIUS_DICTIONARY);
696         if (dict_init(p, RADIUS_DICTIONARY) != 0) {
697                 radlog(L_ERR, "Errors reading dictionary: %s",
698                                 librad_errstr);
699                 return -1;
700         }
701
702         /*
703          *      This allows us to figure out where, relative to
704          *      radiusd.conf, the other configuration files exist.
705          */
706         cf_section_parse(cs, NULL, server_config);
707
708         /*
709          *      Free the old configuration items, and replace them
710          *      with the new ones.
711          *
712          *      Note that where possible, we do atomic switch-overs,
713          *      to ensure that the pointers are always valid.
714          */
715         cf_section_free(&mainconfig.config);
716         mainconfig.config = cs;
717
718         clients_parse_section(cs);
719
720         DEBUG2("%s: #### Loading Realms and Home Servers ####", mainconfig.name);
721
722         if (!realms_init(cs)) {
723                 return -1;
724         }
725
726         /*
727          *  Register the %{config:section.subsection} xlat function.
728          */
729         xlat_register("config", xlat_config, NULL);
730         xlat_register("client", xlat_client, NULL);
731
732         /*
733          *      Reload: change debug flag if it's changed in the
734          *      configuration file.
735          */
736         if (reload) {
737                 if (mainconfig.debug_level != old_debug_level) {
738                         debug_flag = mainconfig.debug_level;
739                 }
740
741         } else if (debug_flag == 0) {
742
743                 /*
744                  *      Starting the server, WITHOUT "-x" on the
745                  *      command-line: use whatever's in the config
746                  *      file.
747                  */
748                 debug_flag = mainconfig.debug_level;
749         }
750         librad_debug = debug_flag;
751         old_debug_level = mainconfig.debug_level;
752
753         /*
754          *  Go update our behaviour, based on the configuration
755          *  changes.
756          */
757
758         /*
759          *      The first time around, ensure that we can write to the
760          *      log directory.
761          */
762         if (!reload && !debug_flag) {
763                 /*
764                  *      We need root to do mkdir() and chown(), so we
765                  *      do this before giving up root.
766                  */
767                 radlogdir_iswritable(uid_name);
768         }
769
770         /*
771          *      We should really switch users earlier in the process.
772          */
773         if (!switch_users()) exit(1);
774
775         /*
776          *      Sanity check the configuration for internal
777          *      consistency.
778          */
779         if (mainconfig.reject_delay > mainconfig.cleanup_delay) {
780                 mainconfig.reject_delay = mainconfig.cleanup_delay;
781         }
782         if (mainconfig.reject_delay < 0) mainconfig.reject_delay = 0;
783
784         /*  Reload the modules.  */
785         if (setup_modules(reload, mainconfig.config) < 0) {
786                 radlog(L_ERR, "Errors initializing modules");
787                 return -1;
788         }
789
790         return 0;
791 }
792
793 /*
794  *      Free the configuration.  Called only when the server is exiting.
795  */
796 int free_mainconfig(void)
797 {
798         /*
799          *      Clean up the configuration data
800          *      structures.
801          */
802         cf_section_free(&mainconfig.config);
803         realms_free();
804         listen_free(&mainconfig.listen);
805         dict_free();
806
807         return 0;
808 }