The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
main_config.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 38da5cfd09609643cca77e0af0ad09b4256b03ee $
19 *
20 * @brief Handle the main server's (radiusd) configuration.
21 * @file src/lib/server/main_config.c
22 *
23 * @copyright 2002,2006-2007 The FreeRADIUS server project
24 * @copyright 2002 Alan DeKok (aland@freeradius.org)
25 */
26
27RCSID("$Id: 38da5cfd09609643cca77e0af0ad09b4256b03ee $")
28
29#include <freeradius-devel/server/cf_file.h>
30#include <freeradius-devel/server/client.h>
31#include <freeradius-devel/server/dependency.h>
32#include <freeradius-devel/server/main_config.h>
33#include <freeradius-devel/server/map_proc.h>
34#include <freeradius-devel/server/modpriv.h>
35#include <freeradius-devel/server/util.h>
36#include <freeradius-devel/server/virtual_servers.h>
37
38
39#include <freeradius-devel/util/conf.h>
40#include <freeradius-devel/util/file.h>
41#include <freeradius-devel/util/hw.h>
42#include <freeradius-devel/util/perm.h>
43#include <freeradius-devel/util/sem.h>
44#include <freeradius-devel/util/pair_legacy.h>
45
46#include <freeradius-devel/unlang/xlat_func.h>
47
48#ifdef HAVE_SYSLOG_H
49# include <syslog.h>
50#endif
51
52#ifdef HAVE_FCNTL_H
53# include <fcntl.h>
54#endif
55
56main_config_t const *main_config; //!< Main server configuration.
57
58extern fr_log_t debug_log;
59
60fr_log_t debug_log = { .fd = -1, .dst = L_DST_NULL };
61
62/*
63 * Configuration file overrides
64 */
65FR_DLIST_TYPES(fr_override_list)
66typedef FR_DLIST_HEAD(fr_override_list) fr_override_list_t;
67FR_DLIST_TYPEDEFS(fr_override_list, fr_override_list_t, fr_override_entry_t)
68
69static fr_override_list_t override;
70
71typedef struct {
72 char *name; //!< must not be 'const'
73 char *value;
74 FR_DLIST_ENTRY(fr_override_list) entry;
76
77FR_DLIST_FUNCS(fr_override_list, fr_override_t, entry)
78
79#define fr_override_list_foreach(_list_head, _iter) \
80 for (fr_override_t *JOIN(_next,_iter), *_iter = fr_override_list_head(_list_head); JOIN(_next,_iter) = fr_override_list_next(_list_head, _iter), _iter != NULL; _iter = JOIN(_next,_iter))
81
82
83/**********************************************************************
84 *
85 * We need to figure out where the logs go, before doing anything
86 * else. This is so that the log messages go to the correct
87 * place.
88 *
89 * BUT, we want the settings from the command line to over-ride
90 * the ones in the configuration file. So, these items are
91 * parsed ONLY if there is no "-l foo" on the command line.
92 *
93 **********************************************************************/
94
95static int reverse_lookups_parse(TALLOC_CTX *ctx, void *out, void *parent,CONF_ITEM *ci, conf_parser_t const *rule);
96static int hostname_lookups_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
97
98static int num_networks_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
99static int num_workers_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
100static int num_workers_dflt(CONF_PAIR **out, void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule);
101
102static int lib_dir_on_read(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
103
104static int talloc_pool_size_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
105
106static int max_request_time_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
107
108static int name_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
109
110/*
111 * Log destinations
112 */
114 { FR_CONF_OFFSET("destination", main_config_t, log_dest), .dflt = "file" },
115 { FR_CONF_OFFSET("syslog_facility", main_config_t, syslog_facility), .dflt = "daemon",
117 .uctx = &(cf_table_parse_ctx_t){
118 .table = syslog_facility_table,
120 }
121 },
122 { FR_CONF_OFFSET("local_state_dir", main_config_t, local_state_dir), .dflt = "${prefix}/var"},
123 { FR_CONF_OFFSET("logdir", main_config_t, log_dir), .dflt = "${local_state_dir}/log"},
124 { FR_CONF_OFFSET("file", main_config_t, log_file), .dflt = "${logdir}/radius.log" },
125 { FR_CONF_OFFSET("suppress_secrets", main_config_t, suppress_secrets), .dflt = "yes" },
129};
130
131/*
132 * Basic configuration for the server.
133 */
135 { FR_CONF_POINTER("log", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) initial_log_config },
136
138};
139
140/*
141 * Basic configuration for the server.
142 */
144 { FR_CONF_OFFSET("prefix", main_config_t, prefix), .dflt = "/usr/local" },
145
148
149 { FR_CONF_OFFSET("libdir", main_config_t, lib_dir), .dflt = "${prefix}/lib",
151
153};
154
155/**********************************************************************
156 *
157 * Now that we've parsed the log destination, AND the security
158 * items, we can parse the rest of the configuration items.
159 *
160 **********************************************************************/
161static const conf_parser_t log_config[] = {
162 { FR_CONF_OFFSET("colourise", main_config_t, do_colourise) },
163 { FR_CONF_OFFSET("line_number", main_config_t, log_line_number) },
167};
168
169
170static const conf_parser_t resources[] = {
171 /*
172 * Don't set defaults here. They're set in the command line. This means
173 * that the config item will *not* get printed out in debug mode, so that no one knows it exists.
174 */
175 { FR_CONF_OFFSET_FLAGS("talloc_memory_report", CONF_FLAG_HIDDEN, main_config_t, talloc_memory_report) }, /* DO NOT SET DEFAULT */
176 { FR_CONF_OFFSET_FLAGS("talloc_skip_cleanup", CONF_FLAG_HIDDEN, main_config_t, talloc_skip_cleanup) }, /* DO NOT SET DEFAULT */
178};
179
180static const conf_parser_t thread_config[] = {
181 { FR_CONF_OFFSET("num_networks", main_config_t, max_networks), .dflt = STRINGIFY(1),
183 { FR_CONF_OFFSET("num_workers", main_config_t, max_workers), .dflt = STRINGIFY(0),
184 .func = num_workers_parse, .dflt_func = num_workers_dflt },
185
186 { FR_CONF_OFFSET_TYPE_FLAGS("stats_interval", FR_TYPE_TIME_DELTA, CONF_FLAG_HIDDEN, main_config_t, stats_interval) },
187
188#ifdef WITH_TLS
189 { FR_CONF_OFFSET_TYPE_FLAGS("openssl_async_pool_init", FR_TYPE_SIZE, 0, main_config_t, openssl_async_pool_init), .dflt = "64" },
190 { FR_CONF_OFFSET_TYPE_FLAGS("openssl_async_pool_max", FR_TYPE_SIZE, 0, main_config_t, openssl_async_pool_max), .dflt = "1024" },
191#endif
192
194};
195
196/*
197 * Migration configuration.
198 */
202
203#ifndef NDEBUG
204/*
205 * Migration configuration.
206 */
208 { FR_CONF_OFFSET_FLAGS("countup_instructions", CONF_FLAG_HIDDEN, main_config_t, ins_countup) },
209 { FR_CONF_OFFSET_FLAGS("max_instructions", CONF_FLAG_HIDDEN, main_config_t, ins_max) },
211};
212#endif
213
218
220 { FR_CONF_OFFSET("max", main_config_t, worker.max_requests), .dflt = "0" },
221 { FR_CONF_OFFSET("timeout", main_config_t, worker.max_request_time), .dflt = STRINGIFY(MAX_REQUEST_TIME), .func = max_request_time_parse },
222 { FR_CONF_OFFSET_TYPE_FLAGS("talloc_pool_size", FR_TYPE_SIZE, CONF_FLAG_HIDDEN, main_config_t, worker.reuse.child_pool_size), .func = talloc_pool_size_parse }, /* DO NOT SET DEFAULT */
223 { FR_CONF_OFFSET_SUBSECTION("reuse", 0, main_config_t, worker.reuse, request_reuse_config) },
225};
226
227static const conf_parser_t server_config[] = {
228 /*
229 * FIXME: 'prefix' is the ONLY one which should be
230 * configured at compile time. Hard-coding it here is
231 * bad. It will be cleaned up once we clean up the
232 * hard-coded defines for the locations of the various
233 * files.
234 */
235 { FR_CONF_OFFSET("prefix", main_config_t, prefix), .dflt = "/usr/local" },
236 { FR_CONF_OFFSET("local_state_dir", main_config_t, local_state_dir), .dflt = "${prefix}/var"},
237 { FR_CONF_OFFSET("sbin_dir", main_config_t, sbin_dir), .dflt = "${prefix}/sbin"},
238 { FR_CONF_OFFSET("logdir", main_config_t, log_dir), .dflt = "${local_state_dir}/log"},
239 { FR_CONF_OFFSET("run_dir", main_config_t, run_dir), .dflt = "${local_state_dir}/run/${name}"},
240 { FR_CONF_OFFSET("radacctdir", main_config_t, radacct_dir), .dflt = "${logdir}/radacct" },
241 { FR_CONF_OFFSET("panic_action", main_config_t, panic_action) },
242 { FR_CONF_OFFSET("reverse_lookups", main_config_t, reverse_lookups), .dflt = "no", .func = reverse_lookups_parse },
243 { FR_CONF_OFFSET("hostname_lookups", main_config_t, hostname_lookups), .dflt = "yes", .func = hostname_lookups_parse },
244 { FR_CONF_OFFSET("pidfile", main_config_t, pid_file), .dflt = "${run_dir}/radiusd.pid"},
245
246 { FR_CONF_OFFSET_FLAGS("debug_level", CONF_FLAG_HIDDEN, main_config_t, debug_level), .dflt = "0" },
247
248 { FR_CONF_POINTER("request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) request_config },
249
250 { FR_CONF_POINTER("log", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) log_config },
251
252 { FR_CONF_POINTER("resources", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) resources },
253
254 { FR_CONF_POINTER("thread", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) thread_config, .name2 = CF_IDENT_ANY },
255
256 { FR_CONF_POINTER("migrate", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) migrate_config, .name2 = CF_IDENT_ANY },
257
258#ifndef NDEBUG
259 { FR_CONF_POINTER("interpret", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) interpret_config, .name2 = CF_IDENT_ANY },
260#endif
261
262 { FR_CONF_V3_DEPRECATED("max_requests", main_config_t, worker.max_requests) },
263 { FR_CONF_V3_DEPRECATED("max_request_time", main_config_t, worker.max_request_time) },
264
266};
267
268
270 { FR_CONF_OFFSET_FLAGS("allow", CONF_FLAG_MULTI, main_config_limit_t, allowed_files) },
271 { FR_CONF_OFFSET_FLAGS("read", CONF_FLAG_MULTI, main_config_limit_t, readonly_files) },
272
274};
275
281
282static const conf_parser_t limit_config[] = {
283 { /* there's no macro for FR_CONF_OFFSET_SUBSECTION_IS_SET(_name, _flags, _struct, _field, _is_set_field, _subcs) */
284 .name1 = "files",
286 .offset = offsetof(main_config_t, limit),
287 .is_set_offset = offsetof(main_config_t, limit.files_is_set),
288 .subcs = (void const *) limit_files_config
289 },
290
291 { /* there's no macro for FR_CONF_OFFSET_SUBSECTION_IS_SET(_name, _flags, _struct, _field, _is_set_field, _subcs) */
292 .name1 = "exec",
294 .offset = offsetof(main_config_t, limit),
295 .is_set_offset = offsetof(main_config_t, limit.exec_is_set),
296 .subcs = (void const *) limit_exec_config
297 },
298
300};
301
302
303/**********************************************************************
304 *
305 * The next few items are here to allow for switching of users
306 * while still opening the various output files with the correct
307 * permission.
308 *
309 * It's rare (or impossible) to have parse errors for these
310 * configuration items, so we don't worry too much about that.
311 * In contrast, when we parse the rest of the configuration, we
312 * CAN get parse errors. We want THOSE parse errors to go to the
313 * log file, and we want the log file to have the correct
314 * permissions.
315 *
316 **********************************************************************/
318#ifdef HAVE_SETUID
320 { FR_CONF_OFFSET_IS_SET("group", FR_TYPE_VOID, 0, main_config_t, gid), .func = cf_parse_gid },
321#endif
322 { FR_CONF_OFFSET("allow_core_dumps", main_config_t, allow_core_dumps), .dflt = "no" },
323
324#ifdef ENABLE_OPENSSL_VERSION_CHECK
325 { FR_CONF_OFFSET("allow_vulnerable_openssl", main_config_t, allow_vulnerable_openssl), .dflt = "no" },
326#endif
327
328#ifdef WITH_TLS
329 { FR_CONF_OFFSET_IS_SET("openssl_fips_mode", FR_TYPE_BOOL, 0, main_config_t, openssl_fips_mode), .dflt = "no" },
330#endif
331
332 { FR_CONF_OFFSET_IS_SET("chdir", FR_TYPE_STRING, 0, main_config_t, chdir), },
333
334 { FR_CONF_POINTER("limit", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) limit_config },
335
337};
338
340 { FR_CONF_POINTER("security", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) security_config },
341
342 { FR_CONF_OFFSET("name", main_config_t, name), .func = name_parse }, /* DO NOT SET DEFAULT */
343
344 { FR_CONF_OFFSET("prefix", main_config_t, prefix), .dflt = "/usr/local" },
345 { FR_CONF_OFFSET("local_state_dir", main_config_t, local_state_dir), .dflt = "${prefix}/var"},
346
347 { FR_CONF_OFFSET("run_dir", main_config_t, run_dir), .dflt = "${local_state_dir}/run/${name}"},
348
349 /*
350 * For backwards compatibility.
351 */
352#ifdef HAVE_SETUID
353 { FR_CONF_V3_DEPRECATED("user", main_config_t, uid) },
354 { FR_CONF_V3_DEPRECATED("group", main_config_t, gid) },
355#endif
356 { FR_CONF_V3_DEPRECATED("chroot", main_config_t, NULL) },
357 { FR_CONF_V3_DEPRECATED("allow_core_dumps", main_config_t, NULL) },
359};
360
361static int reverse_lookups_parse(TALLOC_CTX *ctx, void *out, void *parent,
362 CONF_ITEM *ci, conf_parser_t const *rule)
363{
364 int ret;
365
366 if ((ret = cf_pair_parse_value(ctx, out, parent, ci, rule)) < 0) return ret;
367
368 memcpy(&fr_reverse_lookups, out, sizeof(fr_reverse_lookups));
369
370 return 0;
371}
372
373static int hostname_lookups_parse(TALLOC_CTX *ctx, void *out, void *parent,
374 CONF_ITEM *ci, conf_parser_t const *rule)
375{
376 int ret;
377
378 if ((ret = cf_pair_parse_value(ctx, out, parent, ci, rule)) < 0) return ret;
379
381
382 return 0;
383}
384
385static int talloc_pool_size_parse(TALLOC_CTX *ctx, void *out, void *parent,
386 CONF_ITEM *ci, conf_parser_t const *rule)
387{
388 int ret;
389 size_t value;
390
391 if ((ret = cf_pair_parse_value(ctx, out, parent, ci, rule)) < 0) return ret;
392
393 memcpy(&value, out, sizeof(value));
394
395 FR_SIZE_BOUND_CHECK("request.talloc_pool_size", value, >=, (size_t)(2 * 1024));
396 FR_SIZE_BOUND_CHECK("request.talloc_pool_size", value, <=, (size_t)(1024 * 1024));
397
398 memcpy(out, &value, sizeof(value));
399
400 return 0;
401}
402
403static int max_request_time_parse(TALLOC_CTX *ctx, void *out, void *parent,
404 CONF_ITEM *ci, conf_parser_t const *rule)
405{
406 int ret;
408
409 if ((ret = cf_pair_parse_value(ctx, out, parent, ci, rule)) < 0) return ret;
410
411 memcpy(&value, out, sizeof(value));
412
413 FR_TIME_DELTA_BOUND_CHECK("request.timeout", value, >=, fr_time_delta_from_sec(5));
414 FR_TIME_DELTA_BOUND_CHECK("request.timeout", value, <=, fr_time_delta_from_sec(120));
415
416 memcpy(out, &value, sizeof(value));
417
418 return 0;
419}
420
421static int lib_dir_on_read(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *parent,
422 CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
423{
424 CONF_PAIR *cp = cf_item_to_pair(ci);
425 char const *value;
426
427 fr_assert(main_config != NULL);
428 value = cf_pair_value(cp);
429 if (value) {
431
432 memcpy(&config, &main_config, sizeof(config)); /* const issues */
433
434 config->lib_dir = value;
435 }
436
437 /*
438 * Initialize the DL infrastructure, which is used by the
439 * config file parser. And also add in the search path.
440 */
442 cf_log_perr(ci, "Failed initializing 'lib_dir'");
443 return -1;
444 }
445
446 return 0;
447}
448
449/** Configured server name takes precedence over default values
450 *
451 */
452static int name_parse(TALLOC_CTX *ctx, void *out, void *parent,
453 CONF_ITEM *ci, conf_parser_t const *rule)
454{
456
457 if (*((char **)out)) {
458 if (config->overwrite_config_name) return 0; /* Don't change */
459
460 talloc_free(*((char **)out)); /* Free existing buffer */
461 }
462
463 return cf_pair_parse_value(ctx, out, parent, ci, rule); /* Set new value */
464}
465
466static int num_networks_parse(TALLOC_CTX *ctx, void *out, void *parent,
467 CONF_ITEM *ci, conf_parser_t const *rule)
468{
469 int ret;
471
472 if ((ret = cf_pair_parse_value(ctx, out, parent, ci, rule)) < 0) return ret;
473
474 memcpy(&value, out, sizeof(value));
475
476 FR_INTEGER_BOUND_CHECK("thread.num_networks", value, ==, 1);
477
478 memcpy(out, &value, sizeof(value));
479
480 return 0;
481}
482
483static inline CC_HINT(always_inline)
485{
487
489 if (value == 0) {
490 cf_log_pwarn(parent, "Failed retrieving core count, defaulting to 1 worker");
491 value = 1;
492 }
493
494 /*
495 * If we've got more than four times
496 * the number of cores as we have
497 * networks, then set the number of
498 * workers to the number of cores
499 * minus networks.
500 *
501 * This ensures at a least a 4:1
502 * ratio of workers to networks,
503 * which seems like a sensible ratio.
504 */
505 else if (value > (conf->max_networks * 4)) {
506 value -= conf->max_networks;
507 }
508
509 return value;
510}
511
512static int num_workers_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
513{
514 int ret;
517
518 if ((ret = cf_pair_parse_value(ctx, out, parent, ci, rule)) < 0) return ret;
519
520 memcpy(&value, out, sizeof(value));
521
522 if (value == 0) value = num_workers_auto(conf, ci);
523
524 /*
525 * If no value is specified, try and
526 * discover it automatically.
527 */
528 FR_INTEGER_BOUND_CHECK("thread.num_workers", value, >=, 1);
529 FR_INTEGER_BOUND_CHECK("thread.num_workers", value, <=, 128);
530
531 memcpy(out, &value, sizeof(value));
532
533 return 0;
534}
535
536static int num_workers_dflt(CONF_PAIR **out, void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule)
537{
538 char *strvalue;
541
543 strvalue = talloc_asprintf(NULL, "%u", value);
544 *out = cf_pair_alloc(cs, rule->name1, strvalue, T_OP_EQ, T_BARE_WORD, quote);
545 talloc_free(strvalue);
546
547 /*
548 * Otherwise just create as many
549 * workers as we have cores.
550 */
551 cf_log_info(cs, "Dynamically determined thread.workers = %u", value);
552
553 return 0;
554}
555
556static int xlat_config_escape(fr_value_box_t *vb, UNUSED void *uctx)
557{
558 static char const disallowed[] = "%{}\\'\"`";
559 size_t outmax = vb->vb_length * 3;
560 char *escaped;
561 char const *in, *end;
562 char *out;
563
564 if (!vb->vb_length) return 0;
565
566 fr_assert(vb->type == FR_TYPE_STRING);
567
568 escaped = out = talloc_array(vb, char, outmax + 1);
569 if (!escaped) return -1;
570
571 end = escaped + outmax + 1;
572
573 for (in = vb->vb_strvalue; in < (vb->vb_strvalue + vb->vb_length); in++) {
574 /*
575 * Non-printable characters get replaced with their
576 * mime-encoded equivalents.
577 */
578 if (in[0] < 32) {
579 snprintf(out, (size_t) (end - out), "=%02X", (unsigned char) in[0]);
580 out += 3;
581 continue;
582 }
583
584 if (strchr(disallowed, *in) != NULL) {
585 out[0] = '\\';
586 out[1] = *in;
587 out += 2;
588 continue;
589 }
590
591 /*
592 * Allowed character.
593 */
594 *out = *in;
595 out++;
596 }
597 *out = '\0';
598
599 /*
600 * No change - do nothing.
601 */
602 if ((size_t) (out - escaped) == vb->vb_length) {
603 talloc_free(escaped);
604 return 0;
605 }
606
607 /*
608 * Replace the original string.
609 */
610 (void) fr_value_box_bstrndup(vb, vb, vb->enumv, escaped, (size_t) (out - escaped), vb->tainted);
611 talloc_free(escaped);
612
613 return 0;
614
615}
616
618 { .required = true, .concat = true, .type = FR_TYPE_STRING, .always_escape = true, .func = xlat_config_escape },
620};
621
622/** xlat to get config values
623 *
624@verbatim
625%config(section.subsection.attribute)
626@endverbatim
627 *
628 * @ingroup xlat_functions
629 */
630static xlat_action_t xlat_config(TALLOC_CTX *ctx, fr_dcursor_t *out,
631 UNUSED xlat_ctx_t const *xctx,
632 request_t *request, fr_value_box_list_t *in)
633{
634 char const *value;
635 CONF_PAIR *cp;
636 CONF_ITEM *ci;
637 fr_value_box_t *in_head = fr_value_box_list_head(in);
638 fr_value_box_t *vb;
639
640 ci = cf_reference_item(main_config->root_cs, main_config->root_cs, in_head->vb_strvalue);
641 if (!ci || !cf_item_is_pair(ci)) {
642 RPEDEBUG("Failed finding configuration item '%s'", in_head->vb_strvalue);
643 return XLAT_ACTION_FAIL;
644 }
645
646 cp = cf_item_to_pair(ci);
647
648 value = cf_pair_value(cp);
649 if (!value) return XLAT_ACTION_DONE;
650
651 MEM(vb = fr_value_box_alloc_null(ctx));
652 fr_value_box_bstrndup(vb, vb, NULL, value, strlen(value), false);
654
655 return XLAT_ACTION_DONE;
656}
657
658#ifdef HAVE_SETUID
659static int mkdir_chown(int fd, char const *path, void *uctx)
660{
661 main_config_t *config = uctx;
662 int ret = 0;
663
664 if ((config->server_uid != (uid_t)-1) || (config->server_gid != (gid_t)-1)) {
665 rad_suid_up();
666 ret = fchown(fd, config->server_uid, config->server_gid);
667 if (ret < 0) fr_strerror_printf("Failed changing ownership on directory \"%s\": %s",
668 path, fr_syserror(errno));
670 }
671
672 return ret;
673}
674/*
675 * Switch UID and GID to what is specified in the config file
676 */
677static int switch_users(main_config_t *config, CONF_SECTION *cs)
678{
679 bool do_suid = false;
680 bool do_sgid = false;
681
682 /*
683 * Get the current maximum for core files. Do this
684 * before anything else so as to ensure it's properly
685 * initialized.
686 */
687 if (fr_set_dumpable_init() < 0) {
688 fr_perror("%s", config->name);
689 return -1;
690 }
691
693 fprintf(stderr, "%s: Error: Failed pushing parse rules for user/group information.\n",
694 config->name);
695 return -1;
696 }
697
698 DEBUG("Parsing security rules to bootstrap UID / GID / etc.");
699 if (cf_section_parse(config, config, cs) < 0) {
700 fprintf(stderr, "%s: Error: Failed to parse user/group information.\n",
701 config->name);
702 return -1;
703 }
704
705 /*
706 * Don't do setuid/setgid if we're in debugging
707 * as non-root.
708 */
709 if (DEBUG_ENABLED && (getuid() != 0)) {
710 WARN("Ignoring configured UID / GID as we're running in debug mode");
711 return 0;
712 }
713#ifdef HAVE_GRP_H
714 /*
715 * Get the correct GID for the server.
716 */
717 config->server_gid = getgid();
718 if (config->gid_is_set && (config->server_gid != config->gid)) {
719 config->server_gid = config->gid;
720 do_sgid = true;
721 }
722#endif
723
724 /*
725 * Get the correct UID for the server.
726 */
727 config->server_uid = getuid();
728 if (config->uid_is_set && (config->server_uid != config->uid)) {
729 /*
730 * We're not the correct user. Go set that.
731 */
732 config->server_uid = config->uid;
733 do_suid = true;
734
735#ifdef HAVE_INITGROUPS
736 {
737 struct passwd *user;
738
739 if (fr_perm_getpwuid(config, &user, config->uid) < 0) {
740 fprintf(stderr, "%s: Failed resolving UID %i: %s\n",
741 config->name, (int)config->uid, fr_syserror(errno));
742 return -1;
743 }
744
745 if (initgroups(user->pw_name, config->server_gid) < 0) {
746 fprintf(stderr, "%s: Cannot initialize supplementary group list "
747 "for user %s: %s\n",
748 config->name, user->pw_name, fr_syserror(errno));
749 talloc_free(user);
750 return -1;
751 }
752
753 talloc_free(user);
754 }
755#endif
756 }
757
758 /*
759 * Set the user/group we're going to use
760 * to check read permissions on configuration files.
761 */
762 cf_file_check_set_uid_gid(config->server_uid ? config->server_uid : (uid_t)-1,
763 config->server_gid ? config->server_gid : (gid_t)-1);
764
765#ifdef HAVE_GRP_H
766 /*
767 * Set the GID. Don't bother checking it.
768 */
769 if (do_sgid) {
770 if (setgid(config->server_gid) < 0) {
771 struct group *group;
772
773 if (fr_perm_getgrgid(config, &group, config->gid) < 0) {
774 fprintf(stderr, "%s: Failed resolving GID %i: %s\n",
775 config->name, (int)config->gid, fr_syserror(errno));
776 return -1;
777 }
778
779 fprintf(stderr, "%s: Failed setting group to %s: %s",
780 config->name, group->gr_name, fr_syserror(errno));
781 talloc_free(group);
782 return -1;
783 }
784 }
785#endif
786
787 /*
788 * The directories for PID files and logs must exist. We
789 * need to create them if we're told to write files to
790 * those directories.
791 *
792 * Because this creation is new in 3.0.9, it's a soft
793 * fail.
794 *
795 */
796 if (config->write_pid) {
797 /*
798 * Control sockets may be accessible by users
799 * other than the freeradius user, so we need
800 * to allow 'other' to traverse the run
801 * directory.
802 *
803 * The freeradius user should be the only one
804 * allowed to write to this directory however.
805 */
806 if (fr_mkdir(NULL, config->run_dir, -1, 0755, mkdir_chown, config) < 0) {
807 WARN("Failed creating run_dir %s: %s", config->run_dir, fr_syserror(errno));
808 }
809 }
810
811 if ((default_log.dst == L_DST_FILES) && config->log_dir) {
812 /*
813 * Every other Linux daemon allows 'other'
814 * to traverse the log directory. That doesn't
815 * mean the actual files should be world
816 * readable.
817 */
818 if (fr_mkdir(NULL, config->log_dir, -1, 0755, mkdir_chown, config) < 0) {
819 WARN("Failed creating log_dir %s: %s", config->log_dir, fr_syserror(errno));
820 }
821 }
822
823 /*
824 * If we don't already have a log file open, open one
825 * now. We may not have been logging anything yet. The
826 * server normally starts up fairly quietly.
827 */
828 if ((default_log.dst == L_DST_FILES) &&
829 (default_log.fd < 0)) {
830 default_log.fd = open(config->log_file,
831 O_WRONLY | O_APPEND | O_CREAT, 0640);
832 if (default_log.fd < 0) {
833 fprintf(stderr, "%s: Failed to open log file %s: %s\n",
834 config->name, config->log_file, fr_syserror(errno));
835 return -1;
836 }
837 }
838
839 /*
840 * If we need to change UID, ensure that the log files
841 * have the correct owner && group.
842 *
843 * We have to do this because some log files MAY already
844 * have been written as root. We need to change them to
845 * have the correct ownership before proceeding.
846 */
847 if ((do_suid || do_sgid) &&
849 if (fchown(default_log.fd, config->server_uid, config->server_gid) < 0) {
850 fprintf(stderr, "%s: Cannot change ownership of log file %s: %s\n",
851 config->name, config->log_file, fr_syserror(errno));
852 return -1;
853 }
854 }
855
856 /*
857 * Once we're done with all of the privileged work,
858 * permanently change the UID.
859 */
860 if (do_suid) {
861 rad_suid_set_down_uid(config->server_uid);
863 }
864
865 return 0;
866}
867#endif /* HAVE_SETUID */
868
869
870/** Set the server name
871 *
872 * @note Will only add pair if one does not already exist
873 *
874 * @param[in] config to alter.
875 * @param[in] name to set e.g. "radiusd".
876 * @param[in] overwrite_config replace any CONF_PAIRs with this value.
877 */
878void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
879{
880 if (config->name) {
881 char *p;
882
883 memcpy(&p, &config->name, sizeof(p));
884 talloc_free(p);
885 config->name = NULL;
886 }
887 if (name) config->name = talloc_strdup(config, name);
888
889 config->overwrite_config_name = overwrite_config;
890}
891
892/** Set the global radius config directory.
893 *
894 * @param[in] config to alter.
895 * @param[in] name to set as main configuration directory.
896 */
898{
899 if (config->confdir) {
900 talloc_const_free(config->confdir);
901 config->confdir = NULL;
902 }
903 if (name) config->confdir = talloc_strdup(config, name);
904}
905
906/** Clean up the semaphore when the main config is freed
907 *
908 * This helps with permissions issues if the user is switching between
909 * running the process under something like systemd and running it under
910 * debug mode.
911 */
913#ifndef HAVE_SEMAPHORES
914 UNUSED
915#endif
916 main_config_t const *config)
917{
918#ifdef HAVE_SEMAPHORES
919 if (config->multi_proc_sem_id >= 0) fr_sem_close(config->multi_proc_sem_id, NULL);
920#endif
921}
922
923/** Increment the semaphore in the child process so that it's not released when the parent exits
924 *
925 * @param[in] config specifying the path to the main config file.
926 * @return
927 * - 0 on success.
928 * - -1 on failure.
929 */
931#ifndef HAVE_SEMAPHORES
932 UNUSED
933#endif
934 main_config_t const *config)
935{
936#ifdef HAVE_SEMAPHORES
937 return fr_sem_take(config->multi_proc_sem_id, config->multi_proc_sem_path, true);
938#else
939 return 0;
940#endif
941}
942
943/** Check to see if we're the only process using this configuration file (or PID file if specified)
944 *
945 * @param[in] config specifying the path to the main config file.
946 * @return
947 * - 1 if another process is running with this config file
948 * - 0 if no other process is running with this config file.
949 * - -1 on error.
950 */
952{
953 char *path;
954
955#ifdef HAVE_SEMAPHORES
956 int sem_id;
957#endif
958
959 int ret = 0;
960 FILE *fp = NULL;
961 static bool sem_initd;
962
963 if (unlikely(sem_initd)) return 0;
964
965 if (config->write_pid) {
966 fr_assert(config->pid_file);
967 fp = fopen(config->pid_file, "w");
968 if (!fp) {
969 fr_strerror_printf("Refusing to start - Failed creating PID file at \"%s\" - %s",
970 config->pid_file, fr_syserror(errno));
971 return -1;
972 }
973 MEM(path = talloc_strdup(config, config->pid_file));
974 } else {
975 MEM(path = talloc_asprintf(config, "%s/%s.conf", config->confdir, config->name));
976 }
977
978#ifdef HAVE_SEMAPHORES
979 sem_id = fr_sem_get(path, 0,
980 main_config->uid_is_set ? main_config->uid : geteuid(),
981 main_config->gid_is_set ? main_config->gid : getegid(),
982 true, false);
983 if (sem_id < 0) {
984 talloc_free(path);
985 ret = -1;
986 goto done;
987 }
988
989 config->multi_proc_sem_id = -1;
990
991 ret = fr_sem_wait(sem_id, path, true, true);
992 switch (ret) {
993 case 0: /* we have the semaphore */
994 talloc_free(config->multi_proc_sem_path); /* Allow this to be called multiple times */
995 config->multi_proc_sem_id = sem_id;
996 config->multi_proc_sem_path = path;
997 sem_initd = true;
998 break;
999
1000 case 1: /* another process has the semaphore */
1001 {
1002 pid_t pid;
1003
1004 fr_sem_pid(&pid, sem_id);
1005 fr_strerror_printf("Refusing to start - PID %u already running with \"%s\"", pid, path);
1006 talloc_free(path);
1007 }
1008 break;
1009
1010 default:
1011 talloc_free(path);
1012 break;
1013 }
1014done:
1015#endif
1016 if (fp != NULL) fclose(fp);
1017
1018 return ret;
1019}
1020
1021/** Set the global dictionary directory.
1022 *
1023 * @param[in] config to alter.
1024 * @param[in] name to set as dict dir root e.g. /usr/local/share/freeradius.
1025 */
1027{
1028 if (config->dict_dir) {
1029 talloc_const_free(config->dict_dir);
1030 config->dict_dir = NULL;
1031 }
1032 if (name) config->dict_dir = talloc_strdup(config, name);
1033}
1034
1035/** Allocate a main_config_t struct, setting defaults
1036 *
1037 */
1039{
1041
1042 config = talloc_zero(ctx, main_config_t);
1043 if (!config) {
1044 fr_strerror_const("Failed allocating main config");
1045 return NULL;
1046 }
1047
1048 /*
1049 * Set the defaults from compile time arguments
1050 * these can be overridden later on the command line.
1051 */
1054
1056
1057 fr_override_list_init(&override);
1058
1059 return config;
1060}
1061
1062static int _dlhandle_free(void **dl_handle)
1063{
1064 dlclose(*dl_handle);
1065 return 0;
1066}
1067
1068/*
1069 * Read config files.
1070 *
1071 * This function can ONLY be called from the main server process.
1072 */
1074{
1075 char const *p = NULL;
1076 CONF_SECTION *cs = NULL, *subcs;
1077 struct stat statbuf;
1078 bool can_colourise = false;
1079 char buffer[1024];
1080 xlat_t *xlat;
1081
1082 /*
1083 * Initialize the xlats before we load the configuration files,
1084 * so that we can later call xlat_func_register().
1085 */
1087
1088 if (stat(config->confdir, &statbuf) < 0) {
1089 ERROR("Error checking confdir \"%s\": %s", config->confdir, fr_syserror(errno));
1090 return -1;
1091 }
1092
1093#ifdef S_IWOTH
1094 if ((statbuf.st_mode & S_IWOTH) != 0) {
1095 ERROR("Configuration directory %s is globally writable. "
1096 "Refusing to start due to insecure configuration", config->confdir);
1097 return -1;
1098 }
1099#endif
1100
1101#if 0 && defined(S_IROTH)
1102 if (statbuf.st_mode & S_IROTH != 0) {
1103 ERROR("Configuration directory %s is globally readable. "
1104 "Refusing to start due to insecure configuration", config->confdir);
1105 return -1;
1106 }
1107#endif
1108 INFO("Starting - reading configuration files ...");
1109
1110 cs = cf_section_alloc(NULL, NULL, "main", NULL);
1111 if (!cs) return -1;
1112
1113 /*
1114 * Add a 'feature' subsection off the main config
1115 * We check if it's defined first, as the user may
1116 * have defined their own feature flags, or want
1117 * to manually override the ones set by modules
1118 * or the server.
1119 */
1120 subcs = cf_section_find(cs, "feature", NULL);
1121 if (!subcs) {
1122 subcs = cf_section_alloc(cs, cs, "feature", NULL);
1123 if (!subcs) {
1124 failure:
1125 fr_dict_free(&config->dict, __FILE__);
1126 talloc_free(cs);
1127 return -1;
1128 }
1129 }
1131
1133 PERROR("Failed reading internal dictionaries");
1134 goto failure;
1135 }
1136
1137 /*
1138 * Special-case things. If the output is a TTY, AND
1139 * we're debugging, colourise things. This flag also
1140 * removes the "Debug : " prefix from the log messages.
1141 */
1142 p = getenv("TERM");
1143 if (p && isatty(default_log.fd) && strstr(p, "xterm") && fr_debug_lvl) {
1144 can_colourise = default_log.colourise = true;
1145 } else {
1146 can_colourise = default_log.colourise = false;
1147 }
1148 default_log.line_number = config->log_line_number;
1149
1150 /*
1151 * Add a 'version' subsection off the main config
1152 * We check if it's defined first, this is for
1153 * backwards compatibility.
1154 */
1155 subcs = cf_section_find(cs, "version", NULL);
1156 if (!subcs) {
1157 subcs = cf_section_alloc(cs, cs, "version", NULL);
1158 if (!subcs) goto failure;
1159 }
1161
1162 /*
1163 * @todo - not quite done yet... these dictionaries have
1164 * to be loaded from confdir. But the
1165 * fr_dict_autoload_t has a base_dir pointer
1166 * there... it's probably best to pass confdir into
1167 * fr_dict_autoload() and have it use that instead.
1168 *
1169 * Once that's done, the proto_foo dictionaries SHOULD be
1170 * autoloaded, AND loaded before the configuration files
1171 * are read.
1172 *
1173 * And then all of the modules have to be updated to use
1174 * their local dict pointer, instead of NULL.
1175 */
1176 if (cf_section_rules_push(cs, lib_dir_on_read_config) < 0) goto failure;
1177 if (cf_section_rules_push(cs, virtual_servers_on_read_config) < 0) goto failure;
1178
1179 /*
1180 * Track the status of the configuration.
1181 */
1183
1184 /* Read the configuration file */
1185 snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", config->confdir, config->name);
1186 if (cf_file_read(cs, buffer, true) < 0) {
1187 ERROR("Error reading or parsing %s", buffer);
1188 goto failure;
1189 }
1190
1191 /*
1192 * Do any fixups here that might be used in references
1193 */
1194 if (config->name) {
1195 CONF_PAIR *cp;
1196
1197 cp = cf_pair_find(cs, "name");
1198 if (cp){
1199 if (config->overwrite_config_name && (cf_pair_replace(cs, cp, config->name) < 0)) {
1200 ERROR("Failed adding/replacing \"name\" config item");
1201 goto failure;
1202 }
1203 } else {
1205 }
1206 }
1207
1208 if (cf_section_pass2(cs) < 0) goto failure;
1209
1210 /*
1211 * Parse environment variables first.
1212 */
1213 subcs = cf_section_find(cs, "ENV", NULL);
1214 if (subcs) {
1215 char const *attr, *value;
1216 CONF_PAIR *cp;
1217 CONF_ITEM *ci;
1218
1219 for (ci = cf_item_next(subcs, NULL);
1220 ci != NULL;
1221 ci = cf_item_next(subcs, ci)) {
1222 if (cf_item_is_data(ci)) continue;
1223
1224 if (!cf_item_is_pair(ci)) {
1225 cf_log_err(ci, "Unexpected item in ENV section");
1226 goto failure;
1227 }
1228
1229 cp = cf_item_to_pair(ci);
1230 if (cf_pair_operator(cp) != T_OP_EQ) {
1231 cf_log_err(ci, "Invalid operator for item in ENV section");
1232 goto failure;
1233 }
1234
1235 attr = cf_pair_attr(cp);
1236 value = cf_pair_value(cp);
1237 if (!value) {
1238 if (unsetenv(attr) < 0) {
1239 cf_log_err(ci, "Failed deleting environment variable %s: %s",
1240 attr, fr_syserror(errno));
1241 goto failure;
1242 }
1243 } else {
1244 void *handle;
1245 void **handle_p;
1246
1247 if (setenv(attr, value, 1) < 0) {
1248 cf_log_err(ci, "Failed setting environment variable %s: %s",
1249 attr, fr_syserror(errno));
1250 goto failure;
1251 }
1252
1253 /*
1254 * Hacks for LD_PRELOAD.
1255 */
1256 if (strcmp(attr, "LD_PRELOAD") != 0) continue;
1257
1258 handle = dlopen(value, RTLD_NOW | RTLD_GLOBAL);
1259 if (!handle) {
1260 cf_log_err(ci, "Failed loading library %s: %s", value, dlerror());
1261 goto failure;
1262 }
1263
1264 /*
1265 * Wrap the pointer, so we can set a destructor.
1266 */
1267 MEM(handle_p = talloc(NULL, void *));
1268 *handle_p = handle;
1269 talloc_set_destructor(handle_p, _dlhandle_free);
1270 (void) cf_data_add(subcs, handle_p, value, true);
1271 }
1272 } /* loop over pairs in ENV */
1273 } /* there's an ENV subsection */
1274
1275 /*
1276 * Now that we've read the configuration files, override the values.
1277 */
1278 fr_override_list_foreach(&override, ov) {
1279 if (cf_pair_replace_or_add(cs, ov->name, ov->value) < 0) {
1280 fprintf(stderr, "%s: Error: Cannot update configuration item '%s' - %s.\n",
1281 config->name, ov->name, fr_strerror());
1282 goto failure;
1283 }
1284 }
1285
1286 /*
1287 * Parse log section of main config.
1288 */
1290 fprintf(stderr, "%s: Error: Failed pushing rules for log {} section.\n",
1291 config->name);
1292 goto failure;
1293 }
1294
1295 DEBUG("Parsing initial logging configuration.");
1296 if (cf_section_parse(config, config, cs) < 0) {
1297 fprintf(stderr, "%s: Error: Failed to parse log{} section.\n",
1298 config->name);
1299 goto failure;
1300 }
1301
1302 /*
1303 * If there was no log destination set on the command line,
1304 * set it now.
1305 */
1306 if (default_log.dst == L_DST_NULL) {
1307 if (!config->log_dest) {
1308 fprintf(stderr, "%s: Error: No log destination specified.\n",
1309 config->name);
1310 goto failure;
1311 }
1312
1314
1315 switch (default_log.dst) {
1316 case L_DST_NUM_DEST:
1317 fprintf(stderr, "%s: Error: Unknown log_destination %s\n",
1318 config->name, config->log_dest);
1319 goto failure;
1320
1321#ifdef HAVE_SYSLOG_H
1322 case L_DST_SYSLOG:
1323 /*
1324 * Call openlog only once, when the
1325 * program starts.
1326 */
1327 openlog(config->name, LOG_PID, config->syslog_facility);
1328 break;
1329#endif
1330
1331 case L_DST_FILES:
1332 if (!config->log_file) {
1333 fprintf(stderr, "%s: Error: Specified \"files\" as a log destination, but no log filename was given!\n",
1334 config->name);
1335 goto failure;
1336 }
1337 default_log.file = config->log_file;
1338 break;
1339
1340 default:
1341 break;
1342 }
1343 }
1344
1345 /*
1346 * Only set timestamp logging from the config file if no value was
1347 * specified on the command line.
1348 */
1349 if (config->log_timestamp_is_set && (default_log.timestamp == L_TIMESTAMP_AUTO)) {
1351 }
1352
1353 default_log.dates_utc = config->log_dates_utc;
1354
1355#ifdef HAVE_SETUID
1356 /*
1357 * Switch users as early as possible.
1358 */
1359 if (switch_users(config, cs) < 0) goto failure;
1360#endif
1361
1362 /*
1363 * This also clears the dumpable flag if core dumps
1364 * aren't allowed.
1365 */
1366 if (fr_set_dumpable(config->allow_core_dumps) < 0) PERROR("Failed enabling core dumps");
1367 if (config->allow_core_dumps) INFO("Core dumps are enabled");
1368
1369 /*
1370 * This allows us to figure out where, relative to
1371 * radiusd.conf, the other configuration files exist.
1372 */
1373 if (cf_section_rules_push(cs, server_config) < 0) goto failure;
1374 if (cf_section_rules_push(cs, virtual_servers_config) < 0) goto failure;
1375
1376 DEBUG("Parsing main configuration");
1377 if (cf_section_parse(config, config, cs) < 0) goto failure;
1378
1379 /*
1380 * Reset the colourisation state. The configuration
1381 * files can disable colourisation if the terminal
1382 * supports it. The configuration files *cannot* enable
1383 * colourisation if the terminal window doesn't support
1384 * it.
1385 */
1386 if (can_colourise && !config->do_colourise) {
1387 default_log.colourise = false;
1388 }
1389
1390 /*
1391 * Starting the server, WITHOUT "-x" on the
1392 * command-line: use whatever is in the config
1393 * file.
1394 */
1395 if (fr_debug_lvl == 0) fr_debug_lvl = config->debug_level;
1396
1397 INFO("Switching to configured log settings");
1398
1399 /*
1400 * Free the old configuration items, and replace them
1401 * with the new ones.
1402 *
1403 * Note that where possible, we do atomic switch-overs,
1404 * to ensure that the pointers are always valid.
1405 */
1406 fr_assert(config->root_cs == NULL);
1407
1408 /*
1409 * Redirect stderr/stdout as appropriate.
1410 */
1411 if (log_global_init(&default_log, config->daemonize) < 0) {
1412 cf_log_err(cs, "Failed initializing logging");
1413 goto failure;
1414 }
1415
1416 /*
1417 * Load different logging destinations.
1418 */
1419 for (subcs = cf_section_find_next(cs, NULL, "log", CF_IDENT_ANY);
1420 subcs != NULL;
1421 subcs = cf_section_find_next(cs, subcs, "log", CF_IDENT_ANY)) {
1422 if (!cf_section_name2(subcs)) continue;
1423
1424 if (log_parse_section(subcs) < 0) {
1425 cf_log_err(subcs, "Failed parsing log section: %s", fr_strerror());
1426 goto failure;
1427 }
1428 }
1429
1430 DEBUG2("%s: #### Loading Clients ####", config->name);
1431 if (!client_list_parse_section(cs, 0, false)) goto failure;
1432
1433 /*
1434 * Register the %config(section.subsection) xlat function.
1435 */
1436 if (unlikely((xlat = xlat_func_register(NULL, "config", xlat_config, FR_TYPE_STRING)) == NULL)) goto failure;
1439
1440 config->root_cs = cs; /* Do this last to avoid dangling pointers on error */
1441
1442 /* Clear any unprocessed configuration errors */
1444
1445 return 0;
1446}
1447
1448/*
1449 * Free the configuration. Called only when the server is exiting.
1450 */
1452{
1453 /*
1454 * Frees request specific logging resources which is OK
1455 * because all the requests will have been stopped.
1456 */
1458
1459 /*
1460 * Clean up the configuration data
1461 * structures.
1462 */
1464
1465 /*
1466 * Frees current config and any previous configs.
1467 */
1468 TALLOC_FREE((*config)->root_cs);
1469 fr_dict_free(&(*config)->dict, __FILE__);
1470 TALLOC_FREE(*config);
1471
1472 return 0;
1473}
1474
1476{
1477 int fd, old_fd;
1478
1479 if (default_log.dst != L_DST_FILES) return;
1480
1481 fd = open(config->log_file, O_WRONLY | O_APPEND | O_CREAT, 0640);
1482 if (fd >= 0) {
1483 /*
1484 * Atomic swap. We'd like to keep the old
1485 * FD around so that callers don't
1486 * suddenly find the FD closed, and the
1487 * writes go nowhere. But that's hard to
1488 * do. So... we have the case where a
1489 * log message *might* be lost on HUP.
1490 */
1491 old_fd = default_log.fd;
1492 default_log.fd = fd;
1493 close(old_fd);
1494 }
1495}
1496
1498{
1499 fr_time_t when;
1500
1501 static fr_time_t last_hup = fr_time_wrap(0);
1502
1503 /*
1504 * Re-open the log file. If we can't, then keep logging
1505 * to the old log file.
1506 *
1507 * The "open log file" code is here rather than in log.c,
1508 * because it makes that function MUCH simpler.
1509 */
1511
1512 /*
1513 * Only check the config files every few seconds.
1514 */
1515 when = fr_time();
1516 if (fr_time_gteq(fr_time_add(last_hup, fr_time_delta_from_sec(2)), when)) {
1517 INFO("HUP - Last HUP was too recent. Ignoring");
1518 return;
1519 }
1520 last_hup = when;
1521
1522 INFO("HUP - NYI in version 4"); /* Not yet implemented in v4 */
1523}
1524
1525/*
1526 * Migration function that allows for command-line over-ride of
1527 * data structures which need to be initialized before the
1528 * configuration files are loaded.
1529 *
1530 * This should really only be temporary, until we get rid of flat vs nested.
1531 */
1532int main_config_save_override(char const *str)
1533{
1534 char *p;
1535 fr_override_t *ov;
1536
1537 MEM(ov = talloc_zero(main_config, fr_override_t));
1538
1539 MEM(ov->name = talloc_strdup(ov, str));
1540
1541 p = strchr(ov->name, '=');
1542 if (!p) {
1543 talloc_free(ov);
1544 fr_strerror_const("Missing '='");
1545 return -1;
1546 }
1547
1548 *p++ = '\0';
1549 if (!*p) {
1550 talloc_free(ov);
1551 fr_strerror_const("Missing value after '='");
1552 return -1;
1553 }
1554 ov->value = p;
1555
1556 fr_override_list_insert_tail(&override, ov);
1557 return 0;
1558}
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:560
#define STRINGIFY(x)
Definition build.h:216
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
void cf_md5_init(void)
Definition cf_file.c:3605
int cf_file_read(CONF_SECTION *cs, char const *filename, bool root)
Definition cf_file.c:3987
int cf_section_pass2(CONF_SECTION *cs)
Definition cf_file.c:1130
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Definition cf_file.c:4332
void cf_file_check_set_uid_gid(uid_t uid, gid_t gid)
Set the euid/egid used when performing file checks.
Definition cf_file.c:824
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition cf_parse.c:1288
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition cf_parse.c:1723
int cf_pair_parse_value(TALLOC_CTX *ctx, void *out, UNUSED void *base, CONF_ITEM *ci, conf_parser_t const *rule)
Parses a CONF_PAIR into a C data type.
Definition cf_parse.c:212
int cf_parse_gid(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Generic function for resolving GID strings to uid_t values.
Definition cf_parse.c:1790
int cf_parse_uid(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Generic function for resolving UID strings to uid_t values.
Definition cf_parse.c:1775
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:673
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:627
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:533
#define FR_CONF_V3_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a deprecated v3 item is found
Definition cf_parse.h:413
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
#define FR_SIZE_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:523
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:705
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition cf_parse.h:334
char const * name1
Name of the CONF_ITEM to parse.
Definition cf_parse.h:611
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
Definition cf_parse.h:294
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
cf_parse_t on_read
Function to call as the item is being read, just after it has been allocated and initialized.
Definition cf_parse.h:630
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition cf_parse.h:309
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:544
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:433
@ CONF_FLAG_MULTI
CONF_PAIR can have multiple copies.
Definition cf_parse.h:450
@ CONF_FLAG_IS_SET
Write whether this config item was left as the default to is_set_offset or is_set_ptr.
Definition cf_parse.h:455
@ CONF_FLAG_OK_MISSING
OK if it's missing.
Definition cf_parse.h:458
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition cf_parse.h:427
@ CONF_FLAG_HIDDEN
Used by scripts to omit items from the generated documentation.
Definition cf_parse.h:459
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:238
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:610
Common header for all CONF_* types.
Definition cf_priv.h:54
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:644
int cf_pair_replace_or_add(CONF_SECTION *cs, char const *ref, char const *value)
Definition cf_util.c:2566
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1363
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:750
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition cf_util.c:1445
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1205
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1598
bool cf_item_is_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
Definition cf_util.c:658
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1730
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:676
CONF_SECTION * cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev, char const *name1, char const *name2)
Return the next matching section.
Definition cf_util.c:1226
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1716
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
Replace pair value in a given section with the given value.
Definition cf_util.c:1519
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1700
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:343
#define cf_data_add(_cf, _data, _name, _free)
Definition cf_util.h:309
#define cf_log_info(_cf, _fmt,...)
Definition cf_util.h:345
#define cf_item_next(_parent, _curr)
Definition cf_util.h:94
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:350
#define cf_log_pwarn(_cf, _fmt,...)
Definition cf_util.h:351
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:201
#define CF_IDENT_ANY
Definition cf_util.h:80
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
static char panic_action[512]
The command to execute when panicking.
Definition debug.c:66
int fr_set_dumpable(bool allow_core_dumps)
Enable or disable core dumps.
Definition debug.c:688
int fr_set_dumpable_init(void)
Get the current maximum for core files.
Definition debug.c:673
#define MEM(x)
Definition debug.h:38
void dependency_features_init(CONF_SECTION *cs)
Initialise core feature flags.
Definition dependency.c:182
void dependency_version_numbers_init(CONF_SECTION *cs)
Initialise core version flags.
Definition dependency.c:332
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent))
(Re-)Initialize the special internal dictionary
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4466
static fr_slen_t in
Definition dict.h:904
Test enumeration values.
Definition dict_test.h:92
#define RTLD_NOW
Definition dl.c:44
dl_module_loader_t * dl_module_loader_init(char const *lib_dir)
Initialise structures needed by the dynamic linker.
Definition dl_module.c:524
#define FR_DLIST_TYPES(_name)
Define type specific wrapper structs for dlists.
Definition dlist.h:1146
#define FR_DLIST_ENTRY(_name)
Expands to the type name used for the entry wrapper structure.
Definition dlist.h:1132
#define FR_DLIST_FUNCS(_name, _element_type, _element_entry)
Define type specific wrapper functions for dlists.
Definition dlist.h:1169
#define FR_DLIST_HEAD(_name)
Expands to the type name used for the head wrapper structure.
Definition dlist.h:1139
#define FR_DLIST_TYPEDEFS(_name, _head, _entry)
Define friendly names for type specific dlist head and entry structures.
Definition dlist.h:1156
talloc_free(hp)
uint32_t fr_hw_num_cores_active(void)
Definition hw.c:121
bool fr_hostname_lookups
hostname -> IP lookups?
Definition inet.c:52
bool fr_reverse_lookups
IP -> hostname lookups?
Definition inet.c:51
static bool log_timestamp
Definition log.c:1148
fr_table_num_sorted_t const log_destination_table[]
Definition log.c:186
int log_global_init(fr_log_t *log, bool daemonize)
Initialises the server logging functionality, and the underlying libfreeradius log.
Definition log.c:1322
int log_parse_section(CONF_SECTION *cs)
Parse a named logging section.
Definition log.c:1187
size_t syslog_facility_table_len
Definition log.c:143
fr_table_num_sorted_t const syslog_facility_table[]
Syslog facility table.
Definition log.c:66
void log_global_free(void)
Definition log.c:1358
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG_ENABLED
True if global debug level 1 messages are enabled.
Definition log.h:262
#define RPEDEBUG(fmt,...)
Definition log.h:393
void rad_suid_up(void)
Definition util.c:767
void rad_suid_down(void)
Definition util.c:771
void rad_suid_set_down_uid(uid_t uid)
Definition util.c:763
#define fr_time()
Definition event.c:60
ssize_t fr_mkdir(int *fd_out, char const *path, ssize_t len, mode_t mode, fr_mkdir_func_t func, void *uctx)
Create directories that are missing in the specified path.
Definition file.c:218
int fr_debug_lvl
Definition log.c:41
fr_log_t default_log
Definition log.c:308
bool log_dates_utc
Definition log.c:306
@ L_DST_NULL
Discard log messages.
Definition log.h:80
@ L_DST_FILES
Log to a file on disk.
Definition log.h:76
@ L_DST_NUM_DEST
Definition log.h:81
@ L_DST_SYSLOG
Log to syslog.
Definition log.h:77
@ L_TIMESTAMP_ON
Always log timestamps.
Definition log.h:87
@ L_TIMESTAMP_OFF
Never log timestamps.
Definition log.h:88
@ L_TIMESTAMP_AUTO
Timestamp logging preference not specified.
Definition log.h:85
static const conf_parser_t log_config[]
static const conf_parser_t resources[]
fr_log_t debug_log
Definition main_config.c:60
int main_config_save_override(char const *str)
int main_config_free(main_config_t **config)
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
void main_config_exclusive_proc_done(UNUSED main_config_t const *config)
Clean up the semaphore when the main config is freed.
void main_config_hup(main_config_t *config)
static const conf_parser_t thread_config[]
int main_config_exclusive_proc(main_config_t *config)
Check to see if we're the only process using this configuration file (or PID file if specified)
static int lib_dir_on_read(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static int num_workers_dflt(CONF_PAIR **out, void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule)
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
static const conf_parser_t limit_exec_config[]
static int reverse_lookups_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static const conf_parser_t switch_users_config[]
static const conf_parser_t server_config[]
static int _dlhandle_free(void **dl_handle)
void hup_logfile(main_config_t *config)
static int xlat_config_escape(fr_value_box_t *vb, UNUSED void *uctx)
static xlat_arg_parser_t const xlat_config_args[]
static const conf_parser_t security_config[]
static uint32_t num_workers_auto(main_config_t *conf, CONF_ITEM *parent)
static const conf_parser_t initial_log_config[]
static const conf_parser_t request_config[]
static int max_request_time_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static int num_networks_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static const conf_parser_t migrate_config[]
int main_config_init(main_config_t *config)
static const conf_parser_t initial_server_config[]
static int hostname_lookups_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
void main_config_confdir_set(main_config_t *config, char const *name)
Set the global radius config directory.
static int name_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Configured server name takes precedence over default values.
main_config_t const * main_config
Main server configuration.
Definition main_config.c:56
static const conf_parser_t lib_dir_on_read_config[]
#define fr_override_list_foreach(_list_head, _iter)
Definition main_config.c:79
static const conf_parser_t request_reuse_config[]
fr_override_t
Definition main_config.c:75
static const conf_parser_t limit_config[]
static const conf_parser_t limit_files_config[]
int main_config_exclusive_proc_child(UNUSED main_config_t const *config)
Increment the semaphore in the child process so that it's not released when the parent exits.
static const conf_parser_t interpret_config[]
static int talloc_pool_size_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static int num_workers_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
void main_config_dict_dir_set(main_config_t *config, char const *name)
Set the global dictionary directory.
#define MAX_REQUEST_TIME
Default maximum request time.
Definition main_config.h:35
char const * lib_dir
Definition main_config.h:80
CONF_SECTION * root_cs
Root of the server config.
Definition main_config.h:63
Main server configuration.
Definition main_config.h:59
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
unsigned int uint32_t
int fr_perm_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
Resolve a gid to a group database entry.
Definition perm.c:331
int fr_perm_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
Resolve a uid to a passwd entry.
Definition perm.c:205
static const conf_parser_t config[]
Definition base.c:162
#define fr_assert(_expr)
Definition rad_assert.h:37
#define DEBUG2(fmt,...)
#define WARN(fmt,...)
static bool done
Definition radclient.c:80
#define INFO(fmt,...)
Definition radict.c:63
static rs_t * conf
Definition radsniff.c:52
static char const * name
static const conf_parser_t xlat_config[]
Definition rlm_rest.c:160
int fr_sem_wait(int sem_id, char const *file, bool undo_on_exit, bool nonblock)
Wait for a semaphore to reach 0, then increment it by 1.
Definition sem.c:251
int fr_sem_close(int sem_id, char const *file)
Remove the semaphore, this helps with permissions issues.
Definition sem.c:328
int fr_sem_pid(pid_t *pid, int sem_id)
Return the PID of the process that last operated on the semaphore.
Definition sem.c:52
int fr_sem_get(char const *file, int proj_id, uid_t uid, gid_t gid, bool check_perm, bool must_exist)
Returns a semid for the semaphore associated with the file.
Definition sem.c:420
int fr_sem_take(int sem_id, char const *file, bool undo_on_exit)
Increment the semaphore by 1.
Definition sem.c:220
#define HAVE_SEMAPHORES
Definition sem.h:32
#define FR_SLAB_CONFIG_CONF_PARSER
conf_parser_t entries to populate user configurable slab values
Definition slab.h:35
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
void client_list_free(void)
Definition client.c:84
fr_client_list_t * client_list_parse_section(CONF_SECTION *section, int proto, TLS_UNUSED bool tls_required)
Definition client.c:475
Definition log.h:93
bool dates_utc
Whether timestamps should be UTC or local timezone.
Definition log.h:101
bool colourise
Prefix log messages with VT100 escape codes to change text colour.
Definition log.h:98
fr_log_dst_t dst
Log destination.
Definition log.h:94
bool line_number
Log src file and line number.
Definition log.h:96
int fd
File descriptor to write messages to.
Definition log.h:109
fr_log_timestamp_t timestamp
Prefix log messages with timestamps.
Definition log.h:107
char const * file
Path to log file.
Definition log.h:110
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:685
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:288
#define talloc_asprintf
Definition talloc.h:151
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
#define fr_time_gteq(_a, _b)
Definition time.h:238
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
enum fr_token fr_token_t
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:136
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:160
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumed by an xlat function.
Definition xlat.h:135
#define FR_DICTIONARY_INTERNAL_DIR
Definition conf.h:7
static fr_slen_t parent
Definition pair.h:860
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:737
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:581
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition value.c:4899
static fr_sbuff_err_t char ** out
Definition value.h:1062
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:680
const conf_parser_t virtual_servers_on_read_config[]
const conf_parser_t virtual_servers_config[]
An xlat calling ctx.
Definition xlat_ctx.h:49
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
Definition xlat_func.c:401
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:374
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition xlat_func.c:225
int xlat_func_init(void)
Definition xlat_func.c:551
@ XLAT_FUNC_FLAG_PURE
Definition xlat_func.h:38