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