Add config item to toggle openssl vulnerability check
[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 RCSID("$Id$")
25
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/rad_assert.h>
29
30 #include <sys/stat.h>
31
32 #ifdef HAVE_PWD_H
33 #include <pwd.h>
34 #endif
35
36 #ifdef HAVE_GRP_H
37 #include <grp.h>
38 #endif
39
40 #ifdef HAVE_SYSLOG_H
41 #       include <syslog.h>
42 #endif
43
44 #ifdef HAVE_SYS_STAT_H
45 #include <sys/stat.h>
46 #endif
47
48 #ifdef HAVE_FCNTL_H
49 #include <fcntl.h>
50 #endif
51
52 struct main_config_t mainconfig;
53 char *debug_condition = NULL;
54 extern int log_dates_utc;
55
56 typedef struct cached_config_t {
57         struct cached_config_t *next;
58         time_t          created;
59         CONF_SECTION    *cs;
60 } cached_config_t;
61
62 static cached_config_t  *cs_cache = NULL;
63
64 /*
65  *      Temporary local variables for parsing the configuration
66  *      file.
67  */
68 #ifdef HAVE_SETUID
69 /*
70  *      Systems that have set/getresuid also have setuid.
71  */
72 static uid_t server_uid = 0;
73 static gid_t server_gid = 0;
74 static char const *uid_name = NULL;
75 static char const *gid_name = NULL;
76 #endif
77 static char const *chroot_dir = NULL;
78 static bool allow_core_dumps = false;
79 static char const *radlog_dest = NULL;
80
81 /*
82  *      These are not used anywhere else..
83  */
84 static char const       *localstatedir = NULL;
85 static char const       *prefix = NULL;
86 static char             my_name;
87 static char const       *sbindir = NULL;
88 static char const       *run_dir = NULL;
89 static char             *syslog_facility = NULL;
90 static bool             do_colourise = false;
91
92 static char const       *radius_dir = NULL;     //!< Path to raddb directory
93
94
95 /*
96  *  Security configuration for the server.
97  */
98 static const CONF_PARSER security_config[] = {
99         { "max_attributes",  PW_TYPE_INTEGER, 0, &fr_max_attributes, STRINGIFY(0) },
100         { "reject_delay",  PW_TYPE_INTEGER, 0, &mainconfig.reject_delay, STRINGIFY(0) },
101         { "status_server", PW_TYPE_BOOLEAN, 0, &mainconfig.status_server, "no"},
102         { "allow_vulnerable_openssl", PW_TYPE_BOOLEAN, 0, &mainconfig.allow_vulnerable_openssl, "no"},
103         { NULL, -1, 0, NULL, NULL }
104 };
105
106
107 /*
108  *      Logging configuration for the server.
109  */
110 static const CONF_PARSER logdest_config[] = {
111         { "destination",  PW_TYPE_STRING_PTR, 0, &radlog_dest, "files" },
112         { "syslog_facility",  PW_TYPE_STRING_PTR, 0, &syslog_facility, STRINGIFY(0) },
113
114         { "file", PW_TYPE_STRING_PTR, 0, &mainconfig.log_file, "${logdir}/radius.log" },
115         { "requests", PW_TYPE_STRING_PTR, 0, &default_log.file, NULL },
116         { NULL, -1, 0, NULL, NULL }
117 };
118
119
120 static const CONF_PARSER serverdest_config[] = {
121         { "log", PW_TYPE_SUBSECTION, 0, NULL, (void const *) logdest_config },
122         { "log_file", PW_TYPE_STRING_PTR, 0, &mainconfig.log_file, NULL },
123         { "log_destination", PW_TYPE_STRING_PTR, 0, &radlog_dest, NULL },
124         { "use_utc", PW_TYPE_BOOLEAN, 0, &log_dates_utc, NULL },
125         { NULL, -1, 0, NULL, NULL }
126 };
127
128
129 static const CONF_PARSER log_config_nodest[] = {
130         { "stripped_names", PW_TYPE_BOOLEAN, 0, &log_stripped_names,"no" },
131         { "auth", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth, "no" },
132         { "auth_badpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_badpass, "no" },
133         { "auth_goodpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_goodpass, "no" },
134         { "msg_badpass", PW_TYPE_STRING_PTR, 0, &mainconfig.auth_badpass_msg, NULL},
135         { "msg_goodpass", PW_TYPE_STRING_PTR, 0, &mainconfig.auth_goodpass_msg, NULL},
136         { "colourise", PW_TYPE_BOOLEAN, 0, &do_colourise, NULL },
137         { "use_utc", PW_TYPE_BOOLEAN, 0, &log_dates_utc, NULL },
138         { "msg_denied", PW_TYPE_STRING_PTR, 0, &mainconfig.denied_msg,
139           "You are already logged in - access denied" },
140
141         { NULL, -1, 0, NULL, NULL }
142 };
143
144
145 /*
146  *  A mapping of configuration file names to internal variables
147  */
148 static const CONF_PARSER server_config[] = {
149         /*
150          *      FIXME: 'prefix' is the ONLY one which should be
151          *      configured at compile time.  Hard-coding it here is
152          *      bad.  It will be cleaned up once we clean up the
153          *      hard-coded defines for the locations of the various
154          *      files.
155          */
156         { "name",              PW_TYPE_STRING_PTR, 0, &my_name,   "radiusd"},
157         { "prefix",          PW_TYPE_STRING_PTR, 0, &prefix,        "/usr/local"},
158         { "localstatedir",      PW_TYPE_STRING_PTR, 0, &localstatedir,     "${prefix}/var"},
159         { "sbindir",        PW_TYPE_STRING_PTR, 0, &sbindir,        "${prefix}/sbin"},
160         { "logdir",          PW_TYPE_STRING_PTR, 0, &radlog_dir,        "${localstatedir}/log"},
161         { "run_dir",        PW_TYPE_STRING_PTR, 0, &run_dir,       "${localstatedir}/run/${name}"},
162         { "libdir",          PW_TYPE_STRING_PTR, 0, &radlib_dir,        "${prefix}/lib"},
163         { "radacctdir",  PW_TYPE_STRING_PTR, 0, &radacct_dir,       "${logdir}/radacct" },
164         { "panic_action", PW_TYPE_STRING_PTR, 0, &mainconfig.panic_action, NULL},
165         { "hostname_lookups",   PW_TYPE_BOOLEAN,    0, &fr_dns_lookups,      "no" },
166         { "max_request_time", PW_TYPE_INTEGER, 0, &mainconfig.max_request_time, STRINGIFY(MAX_REQUEST_TIME) },
167         { "cleanup_delay", PW_TYPE_INTEGER, 0, &mainconfig.cleanup_delay, STRINGIFY(CLEANUP_DELAY) },
168         { "max_requests", PW_TYPE_INTEGER, 0, &mainconfig.max_requests, STRINGIFY(MAX_REQUESTS) },
169 #ifdef DELETE_BLOCKED_REQUESTS
170         { "delete_blocked_requests", PW_TYPE_INTEGER, 0, &mainconfig.kill_unresponsive_children, STRINGIFY(false) },
171 #endif
172         { "pidfile", PW_TYPE_STRING_PTR, 0, &mainconfig.pid_file, "${run_dir}/radiusd.pid"},
173         { "checkrad", PW_TYPE_STRING_PTR, 0, &mainconfig.checkrad, "${sbindir}/checkrad" },
174
175         { "debug_level", PW_TYPE_INTEGER, 0, &mainconfig.debug_level, "0"},
176
177 #ifdef WITH_PROXY
178         { "proxy_requests", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_requests, "yes" },
179 #endif
180         { "log", PW_TYPE_SUBSECTION, 0, NULL, (void const *) log_config_nodest },
181
182         /*
183          *      People with old configs will have these.  They are listed
184          *      AFTER the "log" section, so if they exist in radiusd.conf,
185          *      it will prefer "log_foo = bar" to "log { foo = bar }".
186          *      They're listed with default values of NULL, so that if they
187          *      DON'T exist in radiusd.conf, then the previously parsed
188          *      values for "log { foo = bar}" will be used.
189          */
190         { "log_auth", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &mainconfig.log_auth, NULL },
191         { "log_auth_badpass", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &mainconfig.log_auth_badpass, NULL },
192         { "log_auth_goodpass", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &mainconfig.log_auth_goodpass, NULL },
193         { "log_stripped_names", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &log_stripped_names, NULL },
194
195         {  "security", PW_TYPE_SUBSECTION, 0, NULL, (void const *) security_config },
196
197         { NULL, -1, 0, NULL, NULL }
198 };
199
200 static const CONF_PARSER bootstrap_security_config[] = {
201 #ifdef HAVE_SETUID
202         { "user",  PW_TYPE_STRING_PTR, 0, &uid_name, NULL },
203         { "group",  PW_TYPE_STRING_PTR, 0, &gid_name, NULL },
204 #endif
205         { "chroot",  PW_TYPE_STRING_PTR, 0, &chroot_dir, NULL },
206         { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &allow_core_dumps, "no" },
207
208         { NULL, -1, 0, NULL, NULL }
209 };
210
211 static const CONF_PARSER bootstrap_config[] = {
212         {  "security", PW_TYPE_SUBSECTION, 0, NULL, (void const *) bootstrap_security_config },
213
214         /*
215          *      For backwards compatibility.
216          */
217 #ifdef HAVE_SETUID
218         { "user",  PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, 0, &uid_name, NULL },
219         { "group",  PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, 0, &gid_name, NULL },
220 #endif
221         { "chroot",  PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, 0, &chroot_dir, NULL },
222         { "allow_core_dumps", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &allow_core_dumps, NULL },
223
224         { NULL, -1, 0, NULL, NULL }
225 };
226
227
228
229 #define MAX_ARGV (256)
230
231
232 static size_t config_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
233 {
234         size_t len = 0;
235         static char const *disallowed = "%{}\\'\"`";
236
237         while (in[0]) {
238                 /*
239                  *      Non-printable characters get replaced with their
240                  *      mime-encoded equivalents.
241                  */
242                 if ((in[0] < 32)) {
243                         if (outlen <= 3) break;
244
245                         snprintf(out, outlen, "=%02X", (unsigned char) in[0]);
246                         in++;
247                         out += 3;
248                         outlen -= 3;
249                         len += 3;
250                         continue;
251
252                 } else if (strchr(disallowed, *in) != NULL) {
253                         if (outlen <= 2) break;
254
255                         out[0] = '\\';
256                         out[1] = *in;
257                         in++;
258                         out += 2;
259                         outlen -= 2;
260                         len += 2;
261                         continue;
262                 }
263
264                 /*
265                  *      Only one byte left.
266                  */
267                 if (outlen <= 1) {
268                         break;
269                 }
270
271                 /*
272                  *      Allowed character.
273                  */
274                 *out = *in;
275                 out++;
276                 in++;
277                 outlen--;
278                 len++;
279         }
280         *out = '\0';
281         return len;
282 }
283
284 /*
285  *      Xlat for %{config:section.subsection.attribute}
286  */
287 static ssize_t xlat_config(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
288 {
289         char const *value;
290         CONF_PAIR *cp;
291         CONF_ITEM *ci;
292         char buffer[1024];
293
294         /*
295          *      Expand it safely.
296          */
297         if (radius_xlat(buffer, sizeof(buffer), request, fmt, config_escape_func, NULL) < 0) {
298                 return 0;
299         }
300
301         ci = cf_reference_item(request->root->config,
302                                request->root->config, buffer);
303         if (!ci || !cf_item_is_pair(ci)) {
304                 REDEBUG("Config item \"%s\" does not exist", fmt);
305                 *out = '\0';
306                 return -1;
307         }
308
309         cp = cf_itemtopair(ci);
310
311         /*
312          *  Ensure that we only copy what's necessary.
313          *
314          *  If 'outlen' is too small, then the output is chopped to fit.
315          */
316         value = cf_pair_value(cp);
317         if (!value) {
318                 out[0] = '\0';
319                 return 0;
320         }
321
322         if (outlen > strlen(value)) {
323                 outlen = strlen(value) + 1;
324         }
325
326         strlcpy(out, value, outlen);
327
328         return strlen(out);
329 }
330
331
332 /*
333  *      Xlat for %{client:foo}
334  */
335 static ssize_t xlat_client(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
336 {
337         char const *value = NULL;
338         CONF_PAIR *cp;
339
340         if (!fmt || !out || (outlen < 1)) return 0;
341
342         if (!request || !request->client) {
343                 RWDEBUG("No client associated with this request");
344                 *out = '\0';
345                 return 0;
346         }
347
348         cp = cf_pair_find(request->client->cs, fmt);
349         if (!cp || !(value = cf_pair_value(cp))) {
350                 if (strcmp(fmt, "shortname") == 0) {
351                         strlcpy(out, request->client->shortname, outlen);
352                         return strlen(out);
353                 }
354                 RDEBUG("Client does not contain config item \"%s\"", fmt);
355                 *out = '\0';
356                 return 0;
357         }
358
359         strlcpy(out, value, outlen);
360
361         return strlen(out);
362 }
363
364 /*
365  *      Xlat for %{getclient:<ipaddr>.foo}
366  */
367 static ssize_t xlat_getclient(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
368 {
369         char const *value = NULL;
370         char buffer[INET6_ADDRSTRLEN], *q;
371         char const *p = fmt;
372         fr_ipaddr_t ip;
373         CONF_PAIR *cp;
374         RADCLIENT *client = NULL;
375
376         if (!fmt || !out || (outlen < 1)) return 0;
377
378         q = strrchr(p, '.');
379         if (!q || (q == p) || (((size_t)(q - p)) > sizeof(buffer))) {
380                 REDEBUG("Invalid client string");
381                 goto error;
382         }
383
384         strlcpy(buffer, p, (q + 1) - p);
385         if (ip_ptonx(buffer, &ip) <= 0) {
386                 REDEBUG("\"%s\" is not a valid IPv4 or IPv6 address", buffer);
387                 goto error;
388         }
389
390         fmt = q + 1;
391
392         client = client_find(NULL, &ip, IPPROTO_IP);
393         if (!client) {
394                 RDEBUG("No client found with IP \"%s\"", buffer);
395                 *out = '\0';
396                 return 0;
397         }
398
399         cp = cf_pair_find(client->cs, fmt);
400         if (!cp || !(value = cf_pair_value(cp))) {
401                 if (strcmp(fmt, "shortname") == 0) {
402                         strlcpy(out, request->client->shortname, outlen);
403                         return strlen(out);
404                 }
405                 RDEBUG("Client does not contain config item \"%s\"", fmt);
406                 *out = '\0';
407                 return 0;
408         }
409
410         strlcpy(out, value, outlen);
411         return strlen(out);
412
413         error:
414         *out = '\0';
415         return -1;
416 }
417
418 #ifdef HAVE_SETUID
419 static bool doing_setuid = false;
420
421 #  if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
422 void fr_suid_up(void)
423 {
424         uid_t ruid, euid, suid;
425
426         if (getresuid(&ruid, &euid, &suid) < 0) {
427                 ERROR("Failed getting saved UID's");
428                 fr_exit_now(1);
429         }
430
431         if (setresuid(-1, suid, -1) < 0) {
432                 ERROR("Failed switching to privileged user");
433                 fr_exit_now(1);
434         }
435
436         if (geteuid() != suid) {
437                 ERROR("Switched to unknown UID");
438                 fr_exit_now(1);
439         }
440 }
441
442 void fr_suid_down(void)
443 {
444         if (!doing_setuid) return;
445
446         if (setresuid(-1, server_uid, geteuid()) < 0) {
447                 fprintf(stderr, "%s: Failed switching to uid %s: %s\n",
448                         progname, uid_name, fr_syserror(errno));
449                 fr_exit_now(1);
450         }
451
452         if (geteuid() != server_uid) {
453                 fprintf(stderr, "%s: Failed switching uid: UID is incorrect\n",
454                         progname);
455                 fr_exit_now(1);
456         }
457
458         fr_set_dumpable(allow_core_dumps);
459 }
460
461 void fr_suid_down_permanent(void)
462 {
463         if (!doing_setuid) return;
464
465         if (setresuid(server_uid, server_uid, server_uid) < 0) {
466                 ERROR("Failed in permanent switch to uid %s: %s",
467                        uid_name, fr_syserror(errno));
468                 fr_exit_now(1);
469         }
470
471         if (geteuid() != server_uid) {
472                 ERROR("Switched to unknown uid");
473                 fr_exit_now(1);
474         }
475
476         fr_set_dumpable(allow_core_dumps);
477 }
478 #  else
479 /*
480  *      Much less secure...
481  */
482 void fr_suid_up(void)
483 {
484 }
485
486 void fr_suid_down(void)
487 {
488         if (!uid_name) return;
489
490         if (setuid(server_uid) < 0) {
491                 fprintf(stderr, "%s: Failed switching to uid %s: %s\n",
492                         progname, uid_name, fr_syserror(errno));
493                 fr_exit(1);
494         }
495
496         fr_set_dumpable(allow_core_dumps);
497 }
498
499 void fr_suid_down_permanent(void)
500 {
501         fr_set_dumpable(allow_core_dumps);
502 }
503 #  endif /* HAVE_SETRESUID && HAVE_GETRESUID */
504 #else  /* HAVE_SETUID */
505 void fr_suid_up(void)
506 {
507 }
508 void fr_suid_down(void)
509 {
510         fr_set_dumpable(allow_core_dumps);
511 }
512 void fr_suid_down_permanent(void)
513 {
514         fr_set_dumpable(allow_core_dumps);
515 }
516 #endif /* HAVE_SETUID */
517
518 #ifdef HAVE_SETUID
519
520 /*
521  *  Do chroot, if requested.
522  *
523  *  Switch UID and GID to what is specified in the config file
524  */
525 static int switch_users(CONF_SECTION *cs)
526 {
527         /*
528          *      Get the current maximum for core files.  Do this
529          *      before anything else so as to ensure it's properly
530          *      initialized.
531          */
532         if (fr_set_dumpable_init() < 0) {
533                 fr_perror("radiusd");
534                 return 0;
535         }
536
537         /*
538          *      Don't do chroot/setuid/setgid if we're in debugging
539          *      as non-root.
540          */
541         if (debug_flag && (getuid() != 0)) return 1;
542
543         if (cf_section_parse(cs, NULL, bootstrap_config) < 0) {
544                 fprintf(stderr, "radiusd: Error: Failed to parse user/group information.\n");
545                 return 0;
546         }
547
548
549 #ifdef HAVE_GRP_H
550         /*  Set GID.  */
551         if (gid_name) {
552                 struct group *gr;
553
554                 gr = getgrnam(gid_name);
555                 if (gr == NULL) {
556                         fprintf(stderr, "%s: Cannot get ID for group %s: %s\n",
557                                 progname, gid_name, fr_syserror(errno));
558                         return 0;
559                 }
560                 server_gid = gr->gr_gid;
561         } else {
562                 server_gid = getgid();
563         }
564 #endif
565
566 #ifdef HAVE_PWD_H
567         /*  Set UID.  */
568         if (uid_name) {
569                 struct passwd *pw;
570
571                 pw = getpwnam(uid_name);
572                 if (pw == NULL) {
573                         fprintf(stderr, "%s: Cannot get passwd entry for user %s: %s\n",
574                                 progname, uid_name, fr_syserror(errno));
575                         return 0;
576                 }
577
578                 if (getuid() == pw->pw_uid) {
579                         uid_name = NULL;
580                 } else {
581
582                         server_uid = pw->pw_uid;
583 #ifdef HAVE_INITGROUPS
584                         if (initgroups(uid_name, server_gid) < 0) {
585                                 fprintf(stderr, "%s: Cannot initialize supplementary group list for user %s: %s\n",
586                                         progname, uid_name, fr_syserror(errno));
587                                 return 0;
588                         }
589 #endif
590                 }
591         } else {
592                 server_uid = getuid();
593         }
594 #endif
595
596         if (chroot_dir) {
597                 if (chroot(chroot_dir) < 0) {
598                         fprintf(stderr, "%s: Failed to perform chroot %s: %s",
599                                 progname, chroot_dir, fr_syserror(errno));
600                         return 0;
601                 }
602
603                 /*
604                  *      Note that we leave chdir alone.  It may be
605                  *      OUTSIDE of the root.  This allows us to read
606                  *      the configuration from "-d ./etc/raddb", with
607                  *      the chroot as "./chroot/" for example.  After
608                  *      the server has been loaded, it does a "cd
609                  *      ${logdir}" below, so that core files (if any)
610                  *      go to a logging directory.
611                  *
612                  *      This also allows the configuration of the
613                  *      server to be outside of the chroot.  If the
614                  *      server is statically linked, then the only
615                  *      things needed inside of the chroot are the
616                  *      logging directories.
617                  */
618         }
619
620 #ifdef HAVE_GRP_H
621         /*  Set GID.  */
622         if (gid_name && (setgid(server_gid) < 0)) {
623                 fprintf(stderr, "%s: Failed setting group to %s: %s",
624                         progname, gid_name, fr_syserror(errno));
625                 return 0;
626         }
627 #endif
628
629 #ifdef HAVE_SETUID
630         /*
631          *      Just before losing root permissions, ensure that the
632          *      log files have the correct owner && group.
633          *
634          *      We have to do this because the log file MAY have been
635          *      specified on the command-line.
636          */
637         if (uid_name || gid_name) {
638                 if ((default_log.dst == L_DST_FILES) &&
639                     (default_log.fd < 0)) {
640                         default_log.fd = open(mainconfig.log_file,
641                                               O_WRONLY | O_APPEND | O_CREAT, 0640);
642                         if (default_log.fd < 0) {
643                                 fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, fr_syserror(errno));
644                                 return 0;
645                         }
646
647                         if (chown(mainconfig.log_file, server_uid, server_gid) < 0) {
648                                 fprintf(stderr, "%s: Cannot change ownership of log file %s: %s\n",
649                                         progname, mainconfig.log_file, fr_syserror(errno));
650                                 return 0;
651                         }
652                 }
653         }
654
655         if (uid_name) {
656                 doing_setuid = true;
657
658                 fr_suid_down();
659         }
660 #endif
661
662         /*
663          *      This also clears the dumpable flag if core dumps
664          *      aren't allowed.
665          */
666         if (fr_set_dumpable(allow_core_dumps) < 0) {
667                 ERROR("%s", fr_strerror());
668         }
669
670         if (allow_core_dumps) {
671                 INFO("Core dumps are enabled.");
672         }
673
674         return 1;
675 }
676 #endif  /* HAVE_SETUID */
677
678 /** Set the global radius config directory.
679  *
680  * @param ctx Where to allocate the memory for the path string.
681  * @param path to config dir root e.g. /usr/local/etc/raddb
682  */
683 void set_radius_dir(TALLOC_CTX *ctx, char const *path)
684 {
685         if (radius_dir) {
686                 char *p;
687
688                 memcpy(&p, &radius_dir, sizeof(p));
689                 talloc_free(p);
690                 radius_dir = NULL;
691         }
692         if (path) radius_dir = talloc_strdup(ctx, path);
693 }
694
695 /** Get the global radius config directory.
696  *
697  * @return the global radius config directory.
698  */
699 char const *get_radius_dir(void)
700 {
701         return radius_dir;
702 }
703
704 /*
705  *      Read config files.
706  *
707  *      This function can ONLY be called from the main server process.
708  */
709 int read_mainconfig(int reload)
710 {
711         int rcode;
712         char const *p = NULL;
713         CONF_SECTION *cs;
714         struct stat statbuf;
715         cached_config_t *cc;
716         char buffer[1024];
717
718         if (reload != 0) {
719                 ERROR("Reload is not implemented");
720                 return -1;
721         }
722
723         if (stat(radius_dir, &statbuf) < 0) {
724                 ERROR("Errors reading %s: %s",
725                        radius_dir, fr_syserror(errno));
726                 return -1;
727         }
728
729 #ifdef S_IWOTH
730         if ((statbuf.st_mode & S_IWOTH) != 0) {
731                 ERROR("Configuration directory %s is globally writable.  Refusing to start due to insecure configuration.",
732                        radius_dir);
733           return -1;
734         }
735 #endif
736
737 #ifdef S_IROTH
738         if (0 && (statbuf.st_mode & S_IROTH) != 0) {
739                 ERROR("Configuration directory %s is globally readable.  Refusing to start due to insecure configuration.",
740                        radius_dir);
741                 return -1;
742         }
743 #endif
744         INFO("Starting - reading configuration files ...");
745
746         /*
747          *      We need to load the dictionaries before reading the
748          *      configuration files.  This is because of the
749          *      pre-compilation in conffile.c.  That should probably
750          *      be fixed to be done as a second stage.
751          */
752         if (!mainconfig.dictionary_dir) {
753                 mainconfig.dictionary_dir = DICTDIR;
754         }
755
756         /*
757          *      Read the distribution dictionaries first, then
758          *      the ones in raddb.
759          */
760         DEBUG2("including dictionary file %s/%s", mainconfig.dictionary_dir, RADIUS_DICTIONARY);
761         if (dict_init(mainconfig.dictionary_dir, RADIUS_DICTIONARY) != 0) {
762                 ERROR("Errors reading dictionary: %s",
763                       fr_strerror());
764                 return -1;
765         }
766
767         /*
768          *      Try to load protocol-specific dictionaries.  It's OK
769          *      if they don't exist.
770          */
771 #ifdef WITH_DHCP
772         dict_read(mainconfig.dictionary_dir, "dictionary.dhcp");
773 #endif
774
775 #ifdef WITH_VMPS
776         dict_read(mainconfig.dictionary_dir, "dictionary.vqp");
777 #endif
778
779         /*
780          *      It's OK if this one doesn't exist.
781          */
782         rcode = dict_read(radius_dir, RADIUS_DICTIONARY);
783         if (rcode == -1) {
784                 ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY,
785                       fr_strerror());
786                 return -1;
787         }
788
789         /*
790          *      We print this after reading it.  That way if
791          *      it doesn't exist, it's OK, and we don't print
792          *      anything.
793          */
794         if (rcode == 0) {
795                 DEBUG2("including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY);
796         }
797
798         /* Read the configuration file */
799         snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
800                  radius_dir, mainconfig.name);
801         if ((cs = cf_file_read(buffer)) == NULL) {
802                 ERROR("Errors reading or parsing %s", buffer);
803                 return -1;
804         }
805
806         /*
807          *      If there was no log destination set on the command line,
808          *      set it now.
809          */
810         if (default_log.dst == L_DST_NULL) {
811                 if (cf_section_parse(cs, NULL, serverdest_config) < 0) {
812                         fprintf(stderr, "radiusd: Error: Failed to parse log{} section.\n");
813                         cf_file_free(cs);
814                         return -1;
815                 }
816
817                 if (!radlog_dest) {
818                         fprintf(stderr, "radiusd: Error: No log destination specified.\n");
819                         cf_file_free(cs);
820                         return -1;
821                 }
822
823                 default_log.dst = fr_str2int(log_str2dst, radlog_dest,
824                                               L_DST_NUM_DEST);
825                 if (default_log.dst == L_DST_NUM_DEST) {
826                         fprintf(stderr, "radiusd: Error: Unknown log_destination %s\n",
827                                 radlog_dest);
828                         cf_file_free(cs);
829                         return -1;
830                 }
831
832                 if (default_log.dst == L_DST_SYSLOG) {
833                         /*
834                          *      Make sure syslog_facility isn't NULL
835                          *      before using it
836                          */
837                         if (!syslog_facility) {
838                                 fprintf(stderr, "radiusd: Error: Syslog chosen but no facility was specified\n");
839                                 cf_file_free(cs);
840                                 return -1;
841                         }
842                         mainconfig.syslog_facility = fr_str2int(syslog_str2fac, syslog_facility, -1);
843                         if (mainconfig.syslog_facility < 0) {
844                                 fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n",
845                                         syslog_facility);
846                                 cf_file_free(cs);
847                                 return -1;
848                         }
849
850 #ifdef HAVE_SYSLOG_H
851                         /*
852                          *      Call openlog only once, when the
853                          *      program starts.
854                          */
855                         openlog(progname, LOG_PID, mainconfig.syslog_facility);
856 #endif
857
858                 } else if (default_log.dst == L_DST_FILES) {
859                         if (!mainconfig.log_file) {
860                                 fprintf(stderr, "radiusd: Error: Specified \"files\" as a log destination, but no log filename was given!\n");
861                                 cf_file_free(cs);
862                                 return -1;
863                         }
864                 }
865         }
866
867 #ifdef HAVE_SETUID
868         /*
869          *      Switch users as early as possible.
870          */
871         if (!switch_users(cs)) fr_exit(1);
872 #endif
873
874         /*
875          *      Open the log file AFTER switching uid / gid.  If we
876          *      did switch uid/gid, then the code in switch_users()
877          *      took care of setting the file permissions correctly.
878          */
879         if ((default_log.dst == L_DST_FILES) &&
880             (default_log.fd < 0)) {
881                 default_log.fd = open(mainconfig.log_file,
882                                             O_WRONLY | O_APPEND | O_CREAT, 0640);
883                 if (default_log.fd < 0) {
884                         fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, fr_syserror(errno));
885                         cf_file_free(cs);
886                         return -1;
887                 }
888         }
889
890         /*
891          *      This allows us to figure out where, relative to
892          *      radiusd.conf, the other configuration files exist.
893          */
894         if (cf_section_parse(cs, NULL, server_config) < 0) {
895                 return -1;
896         }
897
898         /*
899          *      We ignore colourization of output until after the
900          *      configuration files have been parsed.
901          */
902         p = getenv("TERM");
903         if (do_colourise && p && isatty(default_log.fd) && strstr(p, "xterm")) {
904                 default_log.colourise = true;
905         } else {
906                 default_log.colourise = false;
907         }
908
909         if (mainconfig.max_request_time == 0) mainconfig.max_request_time = 100;
910         if (mainconfig.reject_delay > 5) mainconfig.reject_delay = 5;
911         if (mainconfig.cleanup_delay > 5) mainconfig.cleanup_delay =5;
912
913         /*
914          *      Free the old configuration items, and replace them
915          *      with the new ones.
916          *
917          *      Note that where possible, we do atomic switch-overs,
918          *      to ensure that the pointers are always valid.
919          */
920         rad_assert(mainconfig.config == NULL);
921         root_config = mainconfig.config = cs;
922
923         DEBUG2("%s: #### Loading Realms and Home Servers ####", mainconfig.name);
924         if (!realms_init(cs)) {
925                 return -1;
926         }
927
928         DEBUG2("%s: #### Loading Clients ####", mainconfig.name);
929         if (!clients_parse_section(cs, false)) {
930                 return -1;
931         }
932
933         /*
934          *  Register the %{config:section.subsection} xlat function.
935          */
936         xlat_register("config", xlat_config, NULL, NULL);
937         xlat_register("client", xlat_client, NULL, NULL);
938         xlat_register("getclient", xlat_getclient, NULL, NULL);
939
940         /*
941          *      Starting the server, WITHOUT "-x" on the
942          *      command-line: use whatever is in the config
943          *      file.
944          */
945         if (debug_flag == 0) {
946                 debug_flag = mainconfig.debug_level;
947         }
948         fr_debug_flag = debug_flag;
949
950         /*
951          *  Go update our behaviour, based on the configuration
952          *  changes.
953          */
954
955         /*
956          *      Sanity check the configuration for internal
957          *      consistency.
958          */
959         if (mainconfig.reject_delay > mainconfig.cleanup_delay) {
960                 mainconfig.reject_delay = mainconfig.cleanup_delay;
961         }
962         if (mainconfig.reject_delay < 0) mainconfig.reject_delay = 0;
963
964         /*  Reload the modules.  */
965         if (setup_modules(reload, mainconfig.config) < 0) {
966                 return -1;
967         }
968
969         if (chroot_dir) {
970                 if (chdir(radlog_dir) < 0) {
971                         ERROR("Failed to 'chdir %s' after chroot: %s",
972                                radlog_dir, fr_syserror(errno));
973                         return -1;
974                 }
975         }
976
977         cc = talloc_zero(NULL, cached_config_t);
978         if (!cc) return -1;
979
980         cc->cs = talloc_steal(cc ,cs);
981         rad_assert(cs_cache == NULL);
982         cs_cache = cc;
983
984         /* Clear any unprocessed configuration errors */
985         (void) fr_strerror();
986
987         return 0;
988 }
989
990 /*
991  *      Free the configuration.  Called only when the server is exiting.
992  */
993 int free_mainconfig(void)
994 {
995         virtual_servers_free(0);
996
997         /*
998          *      Clean up the configuration data
999          *      structures.
1000          */
1001         clients_free(NULL);
1002         realms_free();
1003         listen_free(&mainconfig.listen);
1004
1005         /*
1006          *      Frees current config and any previous configs.
1007          */
1008         TALLOC_FREE(cs_cache);
1009         dict_free();
1010
1011         return 0;
1012 }
1013
1014 void hup_logfile(void)
1015 {
1016                 int fd, old_fd;
1017
1018                 if (default_log.dst != L_DST_FILES) return;
1019
1020                 fd = open(mainconfig.log_file,
1021                           O_WRONLY | O_APPEND | O_CREAT, 0640);
1022                 if (fd >= 0) {
1023                         /*
1024                          *      Atomic swap. We'd like to keep the old
1025                          *      FD around so that callers don't
1026                          *      suddenly find the FD closed, and the
1027                          *      writes go nowhere.  But that's hard to
1028                          *      do.  So... we have the case where a
1029                          *      log message *might* be lost on HUP.
1030                          */
1031                         old_fd = default_log.fd;
1032                         default_log.fd = fd;
1033                         close(old_fd);
1034                 }
1035 }
1036
1037 void hup_mainconfig(void)
1038 {
1039         cached_config_t *cc;
1040         CONF_SECTION *cs;
1041         char buffer[1024];
1042
1043         INFO("HUP - Re-reading configuration files");
1044
1045         /* Read the configuration file */
1046         snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
1047                  radius_dir, mainconfig.name);
1048         if ((cs = cf_file_read(buffer)) == NULL) {
1049                 ERROR("Failed to re-read or parse %s", buffer);
1050                 return;
1051         }
1052
1053         cc = talloc_zero(cs_cache, cached_config_t);
1054         if (!cc) {
1055                 ERROR("Out of memory");
1056                 return;
1057         }
1058
1059         /*
1060          *      Save the current configuration.  Note that we do NOT
1061          *      free older ones.  We should probably do so at some
1062          *      point.  Doing so will require us to mark which modules
1063          *      are still in use, and which aren't.  Modules that
1064          *      can't be HUPed always use the original configuration.
1065          *      Modules that can be HUPed use one of the newer
1066          *      configurations.
1067          */
1068         cc->created = time(NULL);
1069         cc->cs = talloc_steal(cc, cs);
1070         cc->next = cs_cache;
1071         cs_cache = cc;
1072
1073         /*
1074          *      Re-open the log file.  If we can't, then keep logging
1075          *      to the old log file.
1076          *
1077          *      The "open log file" code is here rather than in log.c,
1078          *      because it makes that function MUCH simpler.
1079          */
1080         hup_logfile();
1081
1082         INFO("HUP - loading modules");
1083
1084         /*
1085          *      Prefer the new module configuration.
1086          */
1087         module_hup(cf_section_sub_find(cs, "modules"));
1088
1089         /*
1090          *      Load new servers BEFORE freeing old ones.
1091          */
1092         virtual_servers_load(cs);
1093
1094         virtual_servers_free(cc->created - mainconfig.max_request_time * 4);
1095 }