cf27d54145bc47ece31eeb82149780b72edd7774
[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_PRTCL_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
62 /*
63  *      These are not used anywhere else..
64  */
65 static const char *localstatedir = NULL;
66 static const char *prefix = NULL;
67 static char *syslog_facility = NULL;
68 static const LRAD_NAME_NUMBER str2fac[] = {
69 #ifdef LOG_KERN
70         { "kern", LOG_KERN },
71 #endif  
72 #ifdef LOG_USER
73         { "user", LOG_USER },
74 #endif
75 #ifdef LOG_MAIL
76         { "mail", LOG_MAIL },
77 #endif
78 #ifdef LOG_DAEMON
79         { "daemon", LOG_DAEMON },
80 #endif
81 #ifdef LOG_AUTH
82         { "auth", LOG_AUTH },
83 #endif
84 #ifdef LOG_LPR
85         { "lpr", LOG_LPR },
86 #endif
87 #ifdef LOG_NEWS
88         { "news", LOG_NEWS },
89 #endif
90 #ifdef LOG_UUCP
91         { "uucp", LOG_UUCP },
92 #endif
93 #ifdef LOG_CRON
94         { "cron", LOG_CRON },
95 #endif
96 #ifdef LOG_AUTHPRIV
97         { "authpriv", LOG_AUTHPRIV },
98 #endif
99 #ifdef LOG_FTP
100         { "ftp", LOG_FTP },
101 #endif
102 #ifdef LOG_LOCAL0
103         { "local0", LOG_LOCAL0 },
104 #endif
105 #ifdef LOG_LOCAL1
106         { "local1", LOG_LOCAL1 },
107 #endif
108 #ifdef LOG_LOCAL2
109         { "local2", LOG_LOCAL2 },
110 #endif
111 #ifdef LOG_LOCAL3
112         { "local3", LOG_LOCAL3 },
113 #endif
114 #ifdef LOG_LOCAL4
115         { "local4", LOG_LOCAL4 },
116 #endif
117 #ifdef LOG_LOCAL5
118         { "local5", LOG_LOCAL5 },
119 #endif
120 #ifdef LOG_LOCAL6
121         { "local6", LOG_LOCAL6 },
122 #endif
123 #ifdef LOG_LOCAL7
124         { "local7", LOG_LOCAL7 },
125 #endif
126         { NULL, -1 }
127 };
128
129 /*
130  *  Map the proxy server configuration parameters to variables.
131  */
132 static const CONF_PARSER proxy_config[] = {
133         { "retry_delay",  PW_TYPE_INTEGER, 0, &mainconfig.proxy_retry_delay, Stringify(RETRY_DELAY) },
134         { "retry_count",  PW_TYPE_INTEGER, 0, &mainconfig.proxy_retry_count, Stringify(RETRY_COUNT) },
135         { "default_fallback", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_fallback, "no" },
136         { "dead_time",    PW_TYPE_INTEGER, 0, &mainconfig.proxy_dead_time, Stringify(DEAD_TIME) },
137         { "wake_all_if_all_dead", PW_TYPE_BOOLEAN, 0, &mainconfig.wake_all_if_all_dead, "no" },
138         { "proxy_fail_type", PW_TYPE_STRING_PTR, 0, &mainconfig.proxy_fail_type, NULL},
139         { NULL, -1, 0, NULL, NULL }
140 };
141
142
143 /*
144  *  Security configuration for the server.
145  */
146 static const CONF_PARSER security_config[] = {
147         { "max_attributes",  PW_TYPE_INTEGER, 0, &librad_max_attributes, Stringify(0) },
148         { "reject_delay",  PW_TYPE_INTEGER, 0, &mainconfig.reject_delay, Stringify(0) },
149         { "status_server", PW_TYPE_BOOLEAN, 0, &mainconfig.status_server, "no"},
150         { NULL, -1, 0, NULL, NULL }
151 };
152
153
154 /*
155  *  syslog configuration for the server.
156  */
157 static const CONF_PARSER log_config[] = {
158         { "syslog_facility",  PW_TYPE_STRING_PTR, 0, &syslog_facility, Stringify(0) },
159         { NULL, -1, 0, NULL, NULL }
160 };
161
162
163 /*
164  *  A mapping of configuration file names to internal variables
165  */
166 static const CONF_PARSER server_config[] = {
167         /*
168          *      FIXME: 'prefix' is the ONLY one which should be
169          *      configured at compile time.  Hard-coding it here is
170          *      bad.  It will be cleaned up once we clean up the
171          *      hard-coded defines for the locations of the various
172          *      files.
173          */
174         { "prefix",             PW_TYPE_STRING_PTR, 0, &prefix,            "/usr/local"},
175         { "localstatedir",      PW_TYPE_STRING_PTR, 0, &localstatedir,     "${prefix}/var"},
176         { "logdir",             PW_TYPE_STRING_PTR, 0, &radlog_dir,        "${localstatedir}/log"},
177         { "libdir",             PW_TYPE_STRING_PTR, 0, &radlib_dir,        "${prefix}/lib"},
178         { "radacctdir",         PW_TYPE_STRING_PTR, 0, &radacct_dir,       "${logdir}/radacct" },
179         { "hostname_lookups",   PW_TYPE_BOOLEAN,    0, &librad_dodns,      "no" },
180 #ifdef WITH_SNMP
181         { "snmp",               PW_TYPE_BOOLEAN,    0, &mainconfig.do_snmp,      "no" },
182 #endif
183         { "max_request_time", PW_TYPE_INTEGER, 0, &mainconfig.max_request_time, Stringify(MAX_REQUEST_TIME) },
184         { "cleanup_delay", PW_TYPE_INTEGER, 0, &mainconfig.cleanup_delay, Stringify(CLEANUP_DELAY) },
185         { "max_requests", PW_TYPE_INTEGER, 0, &mainconfig.max_requests, Stringify(MAX_REQUESTS) },
186 #ifdef DELETE_BLOCKED_REQUESTS
187         { "delete_blocked_requests", PW_TYPE_INTEGER, 0, &mainconfig.kill_unresponsive_children, Stringify(FALSE) },
188 #endif
189         { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &mainconfig.allow_core_dumps, "no" },
190         { "log_stripped_names", PW_TYPE_BOOLEAN, 0, &log_stripped_names,"no" },
191
192         { "log_file", PW_TYPE_STRING_PTR, -1, &mainconfig.log_file, "${logdir}/radius.log" },
193         { "log_auth", PW_TYPE_BOOLEAN, -1, &mainconfig.log_auth, "no" },
194         { "log_auth_badpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_badpass, "no" },
195         { "log_auth_goodpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_goodpass, "no" },
196         { "pidfile", PW_TYPE_STRING_PTR, 0, &mainconfig.pid_file, "${run_dir}/radiusd.pid"},
197         { "user", PW_TYPE_STRING_PTR, 0, &mainconfig.uid_name, NULL},
198         { "group", PW_TYPE_STRING_PTR, 0, &mainconfig.gid_name, NULL},
199         { "checkrad", PW_TYPE_STRING_PTR, 0, &mainconfig.checkrad, "${sbindir}/checkrad" },
200
201         { "debug_level", PW_TYPE_INTEGER, 0, &mainconfig.debug_level, "0"},
202
203         { "proxy_requests", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_requests, "yes" },
204         { "log", PW_TYPE_SUBSECTION, 0, NULL,  (const void *) log_config},
205         { "proxy", PW_TYPE_SUBSECTION, 0, NULL, (const void *) proxy_config },
206         { "security", PW_TYPE_SUBSECTION, 0, NULL, (const void *) security_config },
207         { NULL, -1, 0, NULL, NULL }
208 };
209
210
211 #define MAX_ARGV (256)
212 /*
213  *      Xlat for %{config:section.subsection.attribute}
214  */
215 static int xlat_config(void *instance, REQUEST *request,
216                        char *fmt, char *out,
217                        size_t outlen,
218                        RADIUS_ESCAPE_STRING func)
219 {
220         CONF_SECTION *cs;
221         CONF_PAIR *cp;
222         int i, argc, left;
223         const char *from, *value;
224         char *to;
225         char myfmt[1024];
226         char argv_buf[1024];
227         char *argv[MAX_ARGV];
228
229         request = request;      /* -Wunused */
230         instance = instance;    /* -Wunused */
231
232         cp = NULL;
233         cs = NULL;
234
235         /*
236          *      Split the string into argv's BEFORE doing radius_xlat...
237          *      Copied from exec.c
238          */
239         from = fmt;
240         to = myfmt; 
241         argc = 0;
242         while (*from) {
243                 int flag, length;
244                 
245                 flag = 0;
246                 argv[argc] = to;
247                 argc++;
248                 
249                 if (argc >= (MAX_ARGV - 1)) break;
250                 
251                 /*
252                  *      Copy the argv over to our buffer.
253                  */
254                 while (*from) {
255                         if (to >= myfmt + sizeof(myfmt) - 1) {
256                                 return 0; /* no error msg */
257                         }
258
259                         switch (*from) {
260                         case '%':
261                                 if (from[1] == '{') {
262                                         *(to++) = *(from++);
263                                         
264                                         length = rad_copy_variable(to, from);
265                                         if (length < 0) {
266                                                 return -1;
267                                         }
268                                         from += length;
269                                         to += length;
270                                 } else { /* FIXME: catch %%{ ? */
271                                         *(to++) = *(from++);
272                                 }
273                                 break;
274
275                         case '[':
276                                 if (flag != 0) {
277                                         radlog(L_ERR, "config: Unexpected nested '[' in \"%s\"", fmt);
278                                         return 0;
279                                 }
280                                 flag++;
281                                 *(to++) = *(from++);
282                                 break;
283
284                         case ']':
285                                 if (flag == 0) {
286                                         radlog(L_ERR, "config: Unbalanced ']' in \"%s\"", fmt);
287                                         return 0;
288                                 }
289                                 if (from[1] != '.') {
290                                         radlog(L_ERR, "config: Unexpected text after ']' in \"%s\"", fmt);
291                                         return 0;
292                                 }
293
294                                 flag--;
295                                 *(to++) = *(from++);
296                                 break;
297
298                         case '.':
299                                 if (flag == 0) break;
300                                 /* FALL-THROUGH */
301
302                         default:
303                                 *(to++) = *(from++);
304                                 break;
305                         }
306
307                         if ((*from == '.') && (flag == 0)) {
308                                 from++;
309                                 break;
310                         }
311                 } /* end of string, or found a period */
312
313                 if (flag != 0) {
314                         radlog(L_ERR, "config: Unbalanced '[' in \"%s\"", fmt);
315                         return 0;
316                 }
317
318                 *(to++) = '\0'; /* terminate the string. */
319         }
320
321         /*
322          *      Expand each string, as appropriate
323          */
324         to = argv_buf;
325         left = sizeof(argv_buf);
326         for (i = 0; i < argc; i++) {
327                 int sublen;
328
329                 /*
330                  *      Don't touch argv's which won't be translated.
331                  */
332                 if (strchr(argv[i], '%') == NULL) continue;
333
334                 sublen = radius_xlat(to, left - 1, argv[i], request, NULL);
335                 if (sublen <= 0) {
336                         /*
337                          *      Fail to be backwards compatible.
338                          *
339                          *      It's yucky, but it won't break anything,
340                          *      and it won't cause security problems.
341                          */
342                         sublen = 0;
343                 }
344                 
345                 argv[i] = to;
346                 to += sublen;
347                 *(to++) = '\0';
348                 left -= sublen;
349                 left--;
350
351                 if (left <= 0) {
352                         return 0;
353                 }
354         }
355         argv[argc] = NULL;
356
357         cs = cf_section_find(NULL); /* get top-level section */
358
359         /*
360          *      Root through section & subsection references.
361          *      The last entry of argv MUST be the CONF_PAIR.
362          */
363         for (i = 0; i < argc - 1; i++) {
364                 char *name2 = NULL;
365                 CONF_SECTION *subcs;
366
367                 /*
368                  *      FIXME: What about RADIUS attributes containing '['?
369                  */
370                 name2 = strchr(argv[i], '[');
371                 if (name2) {
372                         char *p = strchr(name2, ']');
373                         rad_assert(p != NULL);
374                         rad_assert(p[1] =='\0');
375                         *p = '\0';
376                         *name2 = '\0';
377                         name2++;
378                 }
379
380                 if (name2) {
381                         subcs = cf_section_sub_find_name2(cs, argv[i],
382                                                           name2);
383                         if (!subcs) {
384                           radlog(L_ERR, "config: section \"%s %s {}\" not found while dereferencing \"%s\"", argv[i], name2, fmt);
385                           return 0;
386                         }
387                 } else {
388                         subcs = cf_section_sub_find(cs, argv[i]);
389                         if (!subcs) {
390                           radlog(L_ERR, "config: section \"%s {}\" not found while dereferencing \"%s\"", argv[i], fmt);
391                           return 0;
392                         }
393                 }
394                 cs = subcs;
395         } /* until argc - 1 */
396
397         /*
398          *      This can now have embedded periods in it.
399          */
400         cp = cf_pair_find(cs, argv[argc - 1]);
401         if (!cp) {
402                 radlog(L_ERR, "config: item \"%s\" not found while dereferencing \"%s\"", argv[argc], fmt);
403                 return 0;
404         }
405
406         /*
407          *  Ensure that we only copy what's necessary.
408          *
409          *  If 'outlen' is too small, then the output is chopped to fit.
410          */
411         value = cf_pair_value(cp);
412         if (value) {
413                 if (outlen > strlen(value)) {
414                         outlen = strlen(value) + 1;
415                 }
416         }
417
418         return func(out, outlen, value);
419 }
420
421
422 /*
423  *      Recursively make directories.
424  */
425 static int r_mkdir(const char *part)
426 {
427         char *ptr, parentdir[500];
428         struct stat st;
429
430         if (stat(part, &st) == 0)
431                 return(0);
432
433         ptr = strrchr(part, '/');
434
435         if (ptr == part)
436                 return(0);
437
438         snprintf(parentdir, (ptr - part)+1, "%s", part);
439
440         if (r_mkdir(parentdir) != 0)
441                 return(1);
442
443         if (mkdir(part, 0770) != 0) {
444                 radlog(L_ERR, "mkdir(%s) error: %s\n", part, strerror(errno));
445                 return(1);
446         }
447
448         return(0);
449 }
450
451 /*
452  *      Checks if the log directory is writeable by a particular user.
453  */
454 static int radlogdir_iswritable(const char *effectiveuser)
455 {
456 #ifdef HAVE_GETPWNAM
457         struct passwd *pwent;
458 #endif
459
460         if (!radlog_dir || radlog_dir[0] != '/')
461                 return(0);
462
463         if (r_mkdir(radlog_dir) != 0)
464                 return(1);
465
466         /* FIXME: do we have this function? */
467         if (strstr(radlog_dir, "radius") == NULL)
468                 return(0);
469
470         /* we have a logdir that mentions 'radius', so it's probably
471          * safe to chown the immediate directory to be owned by the normal
472          * process owner. we gotta do it before we give up root.  -chad
473          */
474
475         if (!effectiveuser) {
476                 return 1;
477         }
478
479 #ifdef HAVE_GETPWNAM
480         pwent = getpwnam(effectiveuser);
481
482         if (pwent == NULL) /* uh oh! */
483                 return(1);
484
485         if (chown(radlog_dir, pwent->pw_uid, -1) != 0)
486                 return(1);
487 #endif
488
489         return(0);
490 }
491
492
493 /*
494  *  Switch UID and GID to what is specified in the config file
495  */
496 static int switch_users(void)
497 {
498 #ifdef HAVE_SYS_RESOURCE_H
499         struct rlimit core_limits;
500 #endif
501
502 #ifdef HAVE_GRP_H
503         /*  Set GID.  */
504         if (mainconfig.gid_name != NULL) {
505                 struct group *gr;
506
507                 gr = getgrnam(mainconfig.gid_name);
508                 if (gr == NULL) {
509                         if (errno == ENOMEM) {
510                                 radlog(L_ERR|L_CONS, "Cannot switch to Group %s: out of memory", mainconfig.gid_name);
511                         } else {
512                                 radlog(L_ERR|L_CONS, "Cannot switch group; %s doesn't exist", mainconfig.gid_name);
513                         }
514                         exit(1);
515                 }
516                 server_gid = gr->gr_gid;
517                 if (setgid(server_gid) < 0) {
518                         radlog(L_ERR|L_CONS, "Failed setting Group to %s: %s",
519                                mainconfig.gid_name, strerror(errno));
520                         exit(1);
521                 }
522         } else {
523                 server_gid = getgid();
524         }
525 #endif
526
527 #ifdef HAVE_PWD_H
528         /*  Set UID.  */
529         if (mainconfig.uid_name != NULL) {
530                 struct passwd *pw;
531
532                 pw = getpwnam(mainconfig.uid_name);
533                 if (pw == NULL) {
534                         if (errno == ENOMEM) {
535                                 radlog(L_ERR|L_CONS, "Cannot switch to User %s: out of memory", mainconfig.uid_name);
536                         } else {
537                                 radlog(L_ERR|L_CONS, "Cannot switch user; %s doesn't exist", mainconfig.uid_name);
538                         }
539                         exit(1);
540                 }
541                 server_uid = pw->pw_uid;
542 #ifdef HAVE_INITGROUPS
543                 if (initgroups(mainconfig.uid_name, server_gid) < 0) {
544                         if (errno != EPERM) {
545                                 radlog(L_ERR|L_CONS, "Failed setting supplementary groups for User %s: %s", mainconfig.uid_name, strerror(errno));
546                                 exit(1);
547                         }
548                 }
549 #endif
550                 if (setuid(server_uid) < 0) {
551                         radlog(L_ERR|L_CONS, "Failed setting User to %s: %s", mainconfig.uid_name, strerror(errno));
552                         exit(1);
553                 }
554         }
555 #endif
556
557 #ifdef HAVE_SYS_RESOURCE_H
558         /*  Get the current maximum for core files.  */
559         if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
560                 radlog(L_ERR|L_CONS, "Failed to get current core limit:  %s", strerror(errno));
561                 exit(1);
562         }
563 #endif
564
565         if (mainconfig.allow_core_dumps) {
566 #ifdef HAVE_SYS_PRTCL_H
567 #ifdef PR_SET_DUMPABLE
568                 if (prctl(PR_SET_DUMPABLE, 1) < 0) {
569                         radlog(L_ERR|L_CONS,"Cannot enable core dumps: prctl(PR_SET_DUMPABLE) failed: '%s'",
570                                strerror(errno));
571                 }
572 #endif
573 #endif
574
575 #ifdef HAVE_SYS_RESOURCE_H
576                 if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
577                         radlog(L_ERR|L_CONS, "Cannot update core dump limit: %s",
578                                         strerror(errno));
579                         exit(1);
580
581                         /*
582                          *  If we're running as a daemon, and core
583                          *  dumps are enabled, log that information.
584                          */
585                 } else if ((core_limits.rlim_cur != 0) && !debug_flag)
586                         radlog(L_INFO|L_CONS, "Core dumps are enabled.");
587 #endif
588
589         } else if (!debug_flag) {
590 #ifdef HAVE_SYS_RESOURCE_H
591                 /*
592                  *  Not debugging.  Set the core size to zero, to
593                  *  prevent security breaches.  i.e. People
594                  *  reading passwords from the 'core' file.
595                  */
596                 struct rlimit limits;
597
598                 limits.rlim_cur = 0;
599                 limits.rlim_max = core_limits.rlim_max;
600
601                 if (setrlimit(RLIMIT_CORE, &limits) < 0) {
602                         radlog(L_ERR|L_CONS, "Cannot disable core dumps: %s",
603                                         strerror(errno));
604                         exit(1);
605                 }
606 #endif
607         }
608
609 #if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
610         /*
611          *      We've probably written to the log file already as
612          *      root.root, so if we have switched users, we've got to
613          *      update the ownership of the file.
614          */
615         if ((debug_flag == 0) &&
616             (mainconfig.radlog_dest == RADLOG_FILES) &&
617             (mainconfig.log_file != NULL)) {
618                 chown(mainconfig.log_file, server_uid, server_gid);
619         }
620 #endif
621         return(0);
622 }
623
624
625 static const LRAD_NAME_NUMBER str2dest[] = {
626         { "null", RADLOG_NULL },
627         { "files", RADLOG_FILES },
628         { "syslog", RADLOG_SYSLOG },
629         { "stdout", RADLOG_STDOUT },
630         { "stderr", RADLOG_STDERR },
631         { NULL, RADLOG_NUM_DEST }
632 };
633
634
635 /*
636  *      Read config files.
637  *
638  *      This function can ONLY be called from the main server process.
639  */
640 int read_mainconfig(int reload)
641 {
642         static int old_debug_level = -1;
643         char buffer[1024];
644         CONF_SECTION *cs, *templates;
645         rad_listen_t *listener;
646         struct stat statbuf;
647
648         if (stat(radius_dir, &statbuf) < 0) {
649                 radlog(L_ERR|L_CONS, "Errors reading %s: %s",
650                        radius_dir, strerror(errno));
651                 return -1;
652         }
653
654 #ifdef S_IWOTH
655         if ((statbuf.st_mode & S_IWOTH) != 0) {
656                 radlog(L_ERR|L_CONS, "Configuration directory %s is globally writable.  Refusing to start due to insecure configuration.",
657                        radius_dir);
658           return -1;
659         }
660 #endif
661
662 #ifdef S_IROTH
663         if (0 && (statbuf.st_mode & S_IROTH) != 0) {
664                 radlog(L_ERR|L_CONS, "Configuration directory %s is globally readable.  Refusing to start due to insecure configuration.",
665                        radius_dir);
666                 return -1;
667         }
668 #endif
669
670         /* Read the configuration file */
671         snprintf(buffer, sizeof(buffer), "%.200s/%.50s",
672                  radius_dir, mainconfig.radiusd_conf);
673         if ((cs = cf_file_read(buffer)) == NULL) {
674                 radlog(L_ERR|L_CONS, "Errors reading %s", buffer);
675                 return -1;
676         }
677
678         /*
679          *      Add templates to each kind of subsection.
680          */
681         templates = cf_section_sub_find(cs, "templates");
682         if (templates) {
683                 CONF_SECTION *ts, *mycs;
684
685                 /*
686                  *      Loop over the templates, adding them to the
687                  *      sections in the main configuration file.
688                  */
689                 for (ts = cf_subsection_find_next(templates, NULL, NULL);
690                      ts != NULL;
691                      ts = cf_subsection_find_next(templates, ts, NULL)) {
692                         const char *name1 = cf_section_name1(ts);
693
694                         /*
695                          *      Loop over sections in the main config
696                          *      file, adding templats.
697                          */
698                         for (mycs = cf_subsection_find_next(cs, NULL, name1);
699                              mycs != NULL;
700                              mycs = cf_subsection_find_next(cs, mycs, name1)) {
701                                 const char *value;
702
703                                 value = cf_section_value_find(mycs, "template");
704                                 if (value) {
705                                         CONF_SECTION *tts;
706
707                                         tts = cf_section_sub_find_name2(templates,
708                                                                         name1,
709                                                                         value);
710                                         if (!tts) {
711                                                 radlog(L_ERR|L_CONS, "%s[%d]: Section refers to non-existent template \"%s\"", buffer, cf_section_lineno(mycs), value);
712                                                 return -1;
713                                         }
714                                         cf_section_template(mycs, tts);
715                                 } else {
716                                         cf_section_template(mycs, ts);
717                                 }
718                         }
719                 }
720         }
721
722         /*
723          *      Debug flag 1 MAY go to files.
724          *      Debug flag 2 ALWAYS goes to stdout
725          *
726          *      Parse the log_destination before printing anything else.
727          *      All messages before this MUST be errors, which log.c
728          *      will print to stderr, since log_file is NULL, too.
729          */
730         if (debug_flag < 2) {
731                 int rcode;
732                 char *radlog_dest = NULL;
733
734                 rcode = cf_item_parse(cs, "log_destination",
735                                       PW_TYPE_STRING_PTR, &radlog_dest,
736                                       "files");
737                 if (rcode < 0) return -1;
738         
739                 mainconfig.radlog_dest = lrad_str2int(str2dest, radlog_dest, RADLOG_NUM_DEST);
740                 if (mainconfig.radlog_dest == RADLOG_NUM_DEST) {
741                         fprintf(stderr, "radiusd: Error: Unknown log_destination %s\n",
742                                 radlog_dest);
743                         free(radlog_dest);
744                         cf_section_free(&cs);
745                         return -1;
746                 }
747                 
748                 if (mainconfig.radlog_dest == RADLOG_SYSLOG) {
749                         static const CONF_PARSER syslog_config[] = {
750                                 { "log", PW_TYPE_SUBSECTION, 0, NULL,  (const void *) log_config},
751                                 { NULL, -1, 0, NULL, NULL }
752                         };
753                         cf_section_parse(cs, NULL, syslog_config);
754
755                         /*
756                          *      Make sure syslog_facility isn't NULL before using it
757                          */
758                         if (!syslog_facility) {
759                                 fprintf(stderr, "radiusd: Error: Unknown syslog chosen but no facility spedified\n");
760                                 free(radlog_dest);
761                                 cf_section_free(&cs);
762                                 return -1;
763                         }
764                         mainconfig.syslog_facility = lrad_str2int(str2fac, syslog_facility, -1);
765                         if (mainconfig.syslog_facility < 0) {
766                                 fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n",
767                                         syslog_facility);
768                                 free(radlog_dest);
769                                 free(syslog_facility);
770                                 cf_section_free(&cs);
771                                 return -1;
772                         }
773                 }
774
775                 if (mainconfig.radlog_dest == RADLOG_FILES) {
776                         static const CONF_PARSER file_config[] = {
777                                 { "log_file", PW_TYPE_STRING_PTR, -1, &mainconfig.log_file, "${logdir}/radius.log" },
778                                 { NULL, -1, 0, NULL, NULL }
779                         };
780
781                         cf_section_parse(cs, NULL, file_config);
782                 }
783
784                 free(radlog_dest);
785         } else {
786                 mainconfig.radlog_dest = RADLOG_STDOUT;
787                 mainconfig.radlog_fd = STDOUT_FILENO;
788         }
789
790         radlog(L_INFO, "%s", radiusd_version);
791         if (!reload) {
792                 radlog(L_INFO, "Starting - reading configuration files ...");
793         } else {
794                 radlog(L_INFO, "Reloading - reading configuration files...");
795         }
796
797         /* Initialize the dictionary */
798         DEBUG2("read_config_files:  reading dictionary");
799         if (dict_init(radius_dir, RADIUS_DICTIONARY) != 0) {
800                 radlog(L_ERR|L_CONS, "Errors reading dictionary: %s",
801                                 librad_errstr);
802                 return -1;
803         }
804
805         /*
806          *      This allows us to figure out where, relative to
807          *      radiusd.conf, the other configuration files exist.
808          */
809         cf_section_parse(cs, NULL, server_config);
810
811 #if 0
812         /*
813          *      Merge the old with the new.
814          */
815         if (reload) {
816                 CONF_SECTION *newcs;
817
818                 newcs = cf_section_sub_find(cs, "modules");
819                 oldcs = cf_section_sub_find(mainconfig.config, "modules");
820                 if (newcs && oldcs) {
821                         if (!cf_section_migrate(newcs, oldcs)) {
822                                 radlog(L_ERR|L_CONS, "Fatal error migrating configuration data");
823                                 return -1;
824                         }
825                 }
826         }
827 #endif
828
829         /*
830          *      Free the old configuration items, and replace them
831          *      with the new ones.
832          *
833          *      Note that where possible, we do atomic switch-overs,
834          *      to ensure that the pointers are always valid.
835          */
836         cf_section_free(&mainconfig.config);
837         mainconfig.config = cs;
838
839         snprintf(buffer, sizeof(buffer), "%.200s/%.50s",
840                  radius_dir, mainconfig.radiusd_conf);
841         if (!realms_init(buffer)) {
842                 return -1;
843         }
844
845         /*
846          *  Register the %{config:section.subsection} xlat function.
847          */
848         xlat_register("config", xlat_config, NULL);
849
850         /*
851          *      Reload: change debug flag if it's changed in the
852          *      configuration file.
853          */
854         if (reload) {
855                 if (mainconfig.debug_level != old_debug_level) {
856                         debug_flag = mainconfig.debug_level;
857                 }
858
859         } else if (debug_flag == 0) {
860                 
861                 /*
862                  *      Starting the server, WITHOUT "-x" on the
863                  *      command-line: use whatever's in the config
864                  *      file.
865                  */
866                 debug_flag = mainconfig.debug_level;
867         }
868         librad_debug = debug_flag;
869         old_debug_level = mainconfig.debug_level;
870
871         /*
872          *  Go update our behaviour, based on the configuration
873          *  changes.
874          */
875
876         /*
877          *      The first time around, ensure that we can write to the
878          *      log directory.
879          */
880         if (!reload) {
881                 /*
882                  *      We need root to do mkdir() and chown(), so we
883                  *      do this before giving up root.
884                  */
885                 radlogdir_iswritable(mainconfig.uid_name);
886         }
887
888         /*
889          *      We should really switch users earlier in the process.
890          */
891         switch_users();
892
893         /*
894          *      Sanity check the configuration for internal
895          *      consistency.
896          */
897         if (mainconfig.reject_delay > mainconfig.cleanup_delay) {
898                 mainconfig.reject_delay = mainconfig.cleanup_delay;
899         }
900         if (mainconfig.reject_delay < 0) mainconfig.reject_delay = 0;
901
902         /*
903          *      Initialize the old "bind_address" and "port", first.
904          */
905         listener = NULL;
906
907         /*
908          *      Read the list of listeners.
909          */
910         snprintf(buffer, sizeof(buffer), "%.200s/%.50s",
911                  radius_dir, mainconfig.radiusd_conf);
912         if (listen_init(buffer, &listener) < 0) {
913                 exit(1);
914         }
915
916         if (!listener) {
917                 radlog(L_ERR|L_CONS, "Server is not configured to listen on any ports.  Exiting.");
918                 exit(1);
919         }
920
921         listen_free(&mainconfig.listen);
922         mainconfig.listen = listener;
923
924         /*
925          *      Walk through the listeners.  If we're listening on acct
926          *      or auth, read in the clients files, else ignore them.
927          */
928         for (listener = mainconfig.listen;
929              listener != NULL;
930              listener = listener->next) {
931                 if ((listener->type == RAD_LISTEN_AUTH) ||
932                     (listener->type == RAD_LISTEN_ACCT)) {
933                         break;
934                 }
935         }
936
937         if (listener != NULL) {
938                 RADCLIENT_LIST *clients;
939
940                 /*
941                  *      Create the new clients first, and add them
942                  *      to the CONF_SECTION, where they're automagically
943                  *      freed if anything goes wrong.
944                  */
945                 snprintf(buffer, sizeof(buffer), "%.200s/%.50s",
946                          radius_dir, mainconfig.radiusd_conf);
947                 clients = clients_parse_section(buffer, mainconfig.config);
948                 if (!clients) {
949                         return -1;
950                 }
951
952                 /*
953                  *      The old clients are already NULL, because they
954                  *      are in a configuration section, and the client
955                  *      "free" function was added by clients parse
956                  *      section, above.
957                  *
958                  *      Note that because we require at least one
959                  *      client in the main configuration file, any
960                  *      clients added by SQL will be inserted into
961                  *      that, and automatically freed.
962                  */
963                 mainconfig.clients = clients;
964         }
965
966         /*  Reload the modules.  */
967         DEBUG2("radiusd:  entering modules setup");
968         if (setup_modules(reload) < 0) {
969                 radlog(L_ERR|L_CONS, "Errors setting up modules");
970                 return -1;
971         }
972         return 0;
973 }
974
975 /*
976  *      Free the configuration.  Called only when the server is exiting.
977  */
978 int free_mainconfig(void)
979 {
980         /*
981          *      Clean up the configuration data
982          *      structures.
983          */
984         cf_section_free(&mainconfig.config);
985         free(mainconfig.radiusd_conf);
986         realms_free();
987         listen_free(&mainconfig.listen);
988         xlat_free();
989         dict_free();
990         lt_dlexit();
991
992         return 0;
993 }