The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
radiusd.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: 544f1427c69f786825fc41529dc713e9d8a78542 $
19 *
20 * @file radiusd.c
21 * @brief Main loop of the radius server.
22 *
23 * @copyright 2000-2018 The FreeRADIUS server project
24 * @copyright 1999,2000 Miquel van Smoorenburg (miquels@cistron.nl)
25 * @copyright 2000 Alan DeKok (aland@freeradius.org)
26 * @copyright 2000 Alan Curry (pacman-radius@cqc.com)
27 * @copyright 2000 Jeff Carneal (jeff@apex.net)
28 * @copyright 2000 Chad Miller (cmiller@surfsouth.com)
29 */
30RCSID("$Id: 544f1427c69f786825fc41529dc713e9d8a78542 $")
31
32#include <freeradius-devel/server/base.h>
33#include <freeradius-devel/server/radmin.h>
34#include <freeradius-devel/server/snmp.h>
35#include <freeradius-devel/util/size.h>
36
37#include <freeradius-devel/io/thread.h>
38
39#include <freeradius-devel/tls/base.h>
40#include <freeradius-devel/tls/log.h>
41
42#include <freeradius-devel/unlang/base.h>
43
44#include <freeradius-devel/util/misc.h>
45#include <freeradius-devel/util/syserror.h>
46
47#ifdef HAVE_CAPABILITY_H
48#include <freeradius-devel/util/cap.h>
49#endif
50
51#include <fcntl.h>
52#include <sys/file.h>
53#include <sys/mman.h>
54
55#ifdef HAVE_GETOPT_H
56# include <getopt.h>
57#endif
58
59#ifdef HAVE_SYS_WAIT_H
60# include <sys/wait.h>
61#endif
62#ifndef WEXITSTATUS
63# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
64#endif
65#ifndef WIFEXITED
66# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
67#endif
68
69#ifdef HAVE_SYSTEMD
70# include <systemd/sd-daemon.h>
71#endif
72
73#ifdef WITH_TLS
74# include <freeradius-devel/tls/version.h>
75#endif
76
77char const *radiusd_version = RADIUSD_VERSION_BUILD("FreeRADIUS");
78static pid_t radius_pid;
79static char const *program = NULL;
80
81/*
82 * Configuration items.
83 */
84
85/*
86 * Static functions.
87 */
88static void usage(int status);
89
90static void sig_fatal (int);
91#ifdef SIGHUP
92static void sig_hup (int);
93#endif
94
95/** Configure talloc debugging features
96 *
97 * @param[in] config The main config.
98 * @return
99 * - 1 on config conflict.
100 * - 0 on success.
101 * - -1 on error.
102 */
104{
105 if (config->spawn_workers) {
106 if (config->talloc_memory_report) {
107 fr_strerror_printf("talloc_memory_report requires single threaded mode (-s | -X)");
108 return 1;
109 }
110 return 0;
111 }
112
113 if (!config->talloc_memory_report) {
114 talloc_disable_null_tracking();
115 return 0;
116 }
117
118 talloc_enable_null_tracking();
119
120 return 0;
121}
122
123
124/** Create module and xlat per-thread instances
125 *
126 */
127static int thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el, UNUSED void *uctx)
128{
129 if (fr_thread_instantiate(ctx, el) < 0) return -1;
130
131 if (modules_rlm_coord_attach(el) < 0) return -1;
132
133 return 0;
134}
135
136/** Explicitly cleanup module/xlat resources
137 *
138 */
139static void thread_detach(UNUSED void *uctx)
140{
142}
143
144#define EXIT_WITH_FAILURE \
145do { \
146 ret = EXIT_FAILURE; \
147 goto cleanup; \
148} while (0)
149
150#define EXIT_WITH_SUCCESS \
151do { \
152 ret = EXIT_SUCCESS; \
153 goto cleanup; \
154} while (0)
155
156#define EXIT_WITH_PERROR \
157do { \
158 fr_perror("%s", program); \
159 EXIT_WITH_FAILURE; \
160} while (0)
161
163
165{
167
168 (void) fr_timer_in(tl, tl, &fr_time_sync_ev, when, false, fr_time_sync_event, NULL);
169 (void) fr_time_sync();
170}
171
172#ifndef NDEBUG
173/** Encourage the server to exit after a period of time
174 *
175 * @param[in] tl The main loop.
176 * @param[in] now Current time. Should be 0, when adding the event.
177 * @param[in] uctx Pointer to a fr_time_delta_t indicating how long
178 * the server should run before exit.
179 */
180static void fr_exit_after(fr_timer_list_t *tl, fr_time_t now, void *uctx)
181{
182 static fr_timer_t *ev;
183
184 fr_time_delta_t exit_after = *(fr_time_delta_t *)uctx;
185
186 if (fr_time_eq(now, fr_time_wrap(0))) {
187 if (fr_timer_in(tl, tl, &ev, exit_after, false, fr_exit_after, uctx) < 0) {
188 PERROR("%s: Failed inserting exit event", program);
189 }
190 return;
191 }
192
194}
195#endif
196
197#ifdef HAVE_CAPABILITY_H
198#define DUMP_CAPABILITIES(_phase) \
199{ \
200 char *cap_str; \
201 if (fr_cap_set_to_str(talloc_autofree_context(), &cap_str) < 0) { \
202 PWARN("Failed retrieving %s capabilities", _phase); \
203 } else { \
204 INFO("%s capabilities: %s", _phase, cap_str); \
205 talloc_free(cap_str); \
206 } \
207}
208#else
209#define DUMP_CAPABILITIES(_phase)
210#endif
211
212/** Entry point for the daemon
213 *
214 * @hidecallgraph
215 */
216int main(int argc, char *argv[])
217{
218 int status;
219 int c;
220 bool display_version = false;
221 bool radmin = false;
222 int from_child[2] = {-1, -1};
223 fr_schedule_t *sc = NULL;
224 int ret = EXIT_SUCCESS;
225
226 TALLOC_CTX *global_ctx = NULL;
227 main_config_t *config = NULL;
228 bool talloc_memory_report = false;
229
230 bool confdir_set = false;
231
232 size_t pool_size = 0;
233 void *pool_page_start = NULL;
234 size_t pool_page_len = 0;
235 bool do_mprotect;
236 int std_fd[3];
237
238#ifndef NDEBUG
239 fr_time_delta_t exit_after = fr_time_delta_wrap(0);
240#endif
241 /*
242 * Must be called first, so the handler is called last
243 */
245
246 /*
247 * Setup talloc callbacks so we get useful errors
248 */
249 (void) fr_talloc_fault_setup();
250
251 /*
252 * Set some default values
253 */
254 program = strrchr(argv[0], FR_DIR_SEP);
255 if (!program) {
256 program = argv[0];
257 } else {
258 program++;
259 }
260
261 /*
262 * We probably don't want to free the talloc global_ctx context
263 * directly, so we'll allocate a new context beneath it, and
264 * free that before any leak reports.
265 */
266 {
267 char *env;
268
269 /*
270 * If a FR_GLOBAL_POOL value is provided and
271 * is of a valid size, we pre-allocate a global
272 * memory pool, and mprotect() it once we're done
273 * parsing the global config.
274 *
275 * This lets us catch stray writes into global
276 * memory.
277 */
278 env = getenv("FR_GLOBAL_POOL");
279 if (env) {
280 if (fr_size_from_str(&pool_size, &FR_SBUFF_IN_STR(env)) < 0) {
281 fr_perror("%s: Invalid pool size string \"%s\"", program, env);
283 }
284
285 /*
286 * Pre-allocate a global memory pool for the static
287 * config to exist in. We mprotect() this later to
288 * catch any stray writes.
289 */
291 &pool_page_start, &pool_page_len, 0, pool_size);
292 do_mprotect = true;
293 } else {
294 global_ctx = talloc_new(talloc_autofree_context());
295 do_mprotect = false;
296 }
297
298 if (!global_ctx) {
299 fprintf(stderr, "Failed allocating global context\n");
301 }
302 }
303
304 /*
305 * Allocate the main config structure.
306 * It's allocated so we can hang talloced buffers off it.
307 */
309 if (!config) {
310 fprintf(stderr, "Failed allocating main config");
312 }
313
315
316 config->daemonize = true;
317 config->spawn_workers = true;
318
319 fr_debug_lvl = 0;
321
322 /*
323 * Don't put output anywhere until we get told a little
324 * more.
325 */
327 default_log.fd = -1;
330
331 /*
332 * Set the panic action and enable other debugging facilities
333 */
334 if (fr_fault_setup(global_ctx, getenv("PANIC_ACTION"), argv[0], PANIC_ACTION_SIGNALS) < 0) {
335 fr_perror("%s: Failed installing fault handlers... continuing", program);
336 }
337
338 /* Process the options. */
339 while ((c = getopt(argc, argv, "Cd:D:e:fhl:Mmn:PrsS:tTvxX")) != -1) switch (c) {
340 case 'C':
341 check_config = true;
342 config->spawn_workers = false;
343 config->daemonize = false;
344 break;
345
346 case 'd':
348 confdir_set = true;
349 break;
350
351 case 'D':
353 break;
354
355 case 'e':
356 /*
357 * For non-debug builds, accept '-e', but ignore it.
358 */
359#ifndef NDEBUG
360 exit_after = fr_time_delta_from_sec(atoi(optarg));
361#endif
362 break;
363
364 case 'f':
365 config->daemonize = false;
366 break;
367
368 case 'h':
369 usage(EXIT_SUCCESS);
370 break;
371
372 case 'l':
373 if (strcmp(optarg, "stdout") == 0) goto do_stdout;
374
375 config->log_file = talloc_strdup(global_ctx, optarg);
378 default_log.fd = open(config->log_file, O_WRONLY | O_APPEND | O_CREAT, 0640);
379 if (default_log.fd < 0) {
380 fprintf(stderr, "%s: Failed to open log file %s: %s\n",
381 program, config->log_file, fr_syserror(errno));
383 }
384 break;
385
386 case 'm':
387 config->allow_multiple_procs = true;
388 break;
389
390 case 'M':
391 config->talloc_memory_report = true;
392 break;
393
394 case 'n':
396 break;
397
398 case 'P': /* Force the PID to be written, even in -f mode */
399 config->write_pid = true;
400 break;
401
402 case 'r': /* internal radmin-style control interface */
403 config->spawn_workers = false;
404 config->daemonize = false;
405 radmin = true;
406 break;
407
408 case 's': /* Single process mode */
409 config->spawn_workers = false;
410 config->daemonize = false;
411 break;
412
413 case 'S': /* Migration support */
414 if (main_config_save_override(optarg) < 0) {
415 fprintf(stderr, "%s: Failed saving configuration option '%s' - %s\n",
416 program, optarg, fr_strerror());
418 }
419 break;
420
421 case 't': /* no child threads */
422 config->spawn_workers = false;
423 break;
424
425 case 'T': /* enable timestamps */
427 break;
428
429 case 'v':
430 display_version = true;
431 break;
432
433 case 'X':
434 config->spawn_workers = false;
435 config->daemonize = false;
436 fr_debug_lvl += 2;
437
438 do_stdout:
440 default_log.fd = STDOUT_FILENO;
441 break;
442
443 case 'x':
444 fr_debug_lvl++;
445 break;
446
447 default:
448 usage(EXIT_FAILURE);
449 break;
450 }
451
453
454 /*
455 * Allow the configuration directory to be set from an
456 * environment variable. This allows tests to change the
457 * configuration directory without changing the scripts
458 * being executed.
459 */
460 if (!confdir_set) {
461 char const *confdir = getenv("FREERADIUS_CONFIG_DIR");
462
463 if (confdir) main_config_confdir_set(config, confdir);
464 }
465
466 /*
467 * We've now got enough information to check to see
468 * if another process is running with the same config.
469 */
470 config->debug_level = fr_debug_lvl;
471
472 /*
473 * Mismatch between the binary and the libraries it depends on.
474 */
477 }
478
480
481#ifdef WITH_TLS
482 /*
483 * Mismatch between build time OpenSSL and linked SSL, better to die
484 * here than segfault later.
485 */
487
488 /*
489 * Initialising OpenSSL once, here, is safer than having individual modules do it.
490 * Must be called before display_version to ensure relevant engines are loaded.
491 *
492 * fr_openssl_init() must be called before *ANY* OpenSSL functions are used, which is why
493 * it's called so early.
494 */
495 if (fr_openssl_init() < 0) EXIT_WITH_FAILURE;
496#endif
497
498 /*
499 * According to the talloc peeps, no two threads may modify any part of
500 * a ctx tree with a common root without synchronisation.
501 *
502 * So we can't run with a null context and threads.
503 */
504 if (talloc_config_set(config) != 0) {
506 }
507
508 /*
509 * Better here, so it doesn't matter whether we get passed -xv or -vx.
510 */
511 if (display_version) {
512 if (fr_debug_lvl == 0) fr_debug_lvl = 1;
514 default_log.fd = STDOUT_FILENO;
515
516 INFO("%s - %s", program, radiusd_version);
519 }
520
522
523#ifdef WITH_VERIFY_PTR
524 WARN(" ");
525 WARN("#######################################################################");
526 WARN("# ");
527 WARN("# The server was built with the 'WITH_VERIFY_PTR' flag set. This is a");
528 WARN("# developer-only build option that DRASTICALLY slows down the server.");
529 WARN("# If you are using the server in a production environment, you will see");
530 WARN("# significantly improved performance (3x-4x) by re-running 'configure'");
531 WARN("# with the flag '--disable-developer', and then re-building and");
532 WARN("# re-installing the server.");
533 WARN("# ");
534 WARN("#######################################################################");
535 WARN(" ");
536#endif
537
538 /*
539 * Under linux CAP_SYS_PTRACE is usually only available before setuid/setguid,
540 * so we need to check whether we can attach before calling those functions
541 * (in main_config_init()).
542 */
544
545 /*
546 * Write the PID always if we're running as a daemon.
547 */
548 if (config->daemonize) config->write_pid = true;
549
550 /*
551 * Initialize the DL infrastructure, which is used by the
552 * config file parser. Note that we pass an empty path
553 * here, as we haven't yet read the configuration file.
554 */
555 modules_init(NULL);
556
557 /*
558 * Initialise the top level dictionary hashes which hold
559 * the protocols.
560 */
561 if (!fr_dict_global_ctx_init(NULL, true, config->dict_dir)) {
563 }
564
565#ifdef WITH_TLS
566 if (fr_tls_dict_init() < 0) {
568 }
569#endif
570
571 /*
572 * Setup the global structures for module lists
573 */
574 if (modules_rlm_init() < 0) {
576 }
577
578 if (virtual_servers_init() < 0) {
580 }
581
582 /*
583 * Load dictionary attributes used
584 * for requests.
585 */
586 if (request_global_init() < 0) {
588 }
589
590 /*
591 * The radmin functions need to write somewhere.
592 *
593 * The log functions redirect stdin and stdout to /dev/null, so that exec'd programs can't mangle
594 * them. But radmin needs to be able to use them.
595 */
596#define RDUP(_x) \
597do { \
598 if ((std_fd[_x] = dup(_x)) < 0) EXIT_WITH_PERROR; \
599 if (fr_cloexec(std_fd[_x]) < 0) EXIT_WITH_PERROR; \
600} while (0)
601
602 if (radmin) {
603 RDUP(STDIN_FILENO);
604 RDUP(STDOUT_FILENO);
605 RDUP(STDERR_FILENO);
606 }
607
608 /*
609 * Read the configuration files, BEFORE doing anything else.
610 */
612
613 /*
614 * Suppress secrets if asked, and if at a low debug level.
615 */
616 default_log.suppress_secrets = config->suppress_secrets && (fr_debug_lvl <= 2);
617
618 /*
619 * Check we're the only process using this config.
620 */
621 if (!config->allow_multiple_procs && !check_config) {
623 case 0: /* No other processes running */
624 break;
625
626 case -1: /* Permissions error - fail open */
627 PWARN("%s: Process concurrency checks disabled", program);
628 break;
629
630 case 1:
631 default: /* All other errors */
633 }
634 }
635
636 /*
637 * Set panic_action from the main config if one wasn't specified in the
638 * environment.
639 */
640 if (config->panic_action && !getenv("PANIC_ACTION") &&
641 (fr_fault_setup(global_ctx, config->panic_action, argv[0], PANIC_ACTION_SIGNALS) < 0)) {
642 fr_perror("%s: Failed configuring panic action", program);
644 }
645
646 /*
647 * This is very useful in figuring out why the panic_action didn't fire.
648 */
650
651 /*
652 * Track configuration versions. This lets us know if the configuration changed.
653 */
654 if (fr_debug_lvl) {
655 uint8_t digest[16];
656
657 cf_md5_final(digest);
658
659 digest[6] &= 0x0f; /* ver is 0b0100 at bits 48:51 */
660 digest[6] |= 0x40;
661 digest[8] &= ~0xc0; /* var is 0b10 at bits 64:65 */
662 digest[8] |= 0x80;
663
664 /*
665 * UUIDv4 format: 4-2-2-2-6
666 */
667 INFO("Configuration version: %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
668 digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
669 digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]);
670 }
671
672 /*
673 * Call this again now we've loaded the configuration. Yes I know...
674 */
675 if (talloc_config_set(config) != 0) {
677 }
678
679 /*
680 * Check for vulnerabilities in the version of libssl were linked against.
681 */
682#ifdef WITH_TLS
683# ifdef ENABLE_OPENSSL_VERSION_CHECK
684 if (fr_openssl_version_check(config->allow_vulnerable_openssl) < 0) EXIT_WITH_FAILURE;
685# endif
686
687 /*
688 * Toggle FIPS mode
689 */
690 if (config->openssl_fips_mode_is_set &&
691 (fr_openssl_fips_mode(config->openssl_fips_mode) < 0)) EXIT_WITH_FAILURE;
692#endif
693
694 /*
695 * The systemd watchdog enablement must be checked before we
696 * daemonize, but the watchdog notifications can come from any
697 * process.
698 */
699#ifdef HAVE_SYSTEMD_WATCHDOG
700 if (!check_config) main_loop_set_sd_watchdog_interval();
701#else
702 /*
703 * If the default systemd unit file is used, but the server wasn't
704 * built with support for systemd, the status returned by systemctl
705 * will stay permanently as "activating".
706 *
707 * We detect this condition and warn about it here, using the
708 * presence of the NOTIFY_SOCKET environmental variable to determine
709 * whether we're running under systemd.
710 */
711 if (getenv("NOTIFY_SOCKET")) INFO("Built without support for systemd watchdog, but running under systemd");
712#endif
713
714 /*
715 * Don't allow radmin when checking the config.
716 */
717 if (check_config) radmin = false;
718
719 if (fr_radmin_start(config, radmin, std_fd) < 0) EXIT_WITH_FAILURE;
720
721 /*
722 * Disconnect from session
723 */
724 if (config->daemonize) {
725 pid_t pid;
726 int devnull;
727
728 DUMP_CAPABILITIES("pre-fork");
729
730 /*
731 * Really weird things happen if we leave stdin open and call things like
732 * system() later.
733 *
734 * main_config_init() already calls fr_log_init_legacy(), which closes stdout/stderr.
735 */
736 devnull = open("/dev/null", O_RDWR);
737 if (devnull < 0) {
738 ERROR("Failed opening /dev/null: %s", fr_syserror(errno));
740 }
741 dup2(devnull, STDIN_FILENO);
742
743 close(devnull);
744
745 if (pipe(from_child) != 0) {
746 ERROR("Couldn't open pipe for child status: %s", fr_syserror(errno));
748 }
749
750 pid = fork();
751 if (pid < 0) {
752 ERROR("Couldn't fork: %s", fr_syserror(errno));
754 }
755
756 /*
757 * The parent exits, so the child can run in the background.
758 *
759 * As the child can still encounter an error during initialisation
760 * we do a blocking read on a pipe between it and the parent.
761 *
762 * Just before entering the event loop the child will send a success
763 * or failure message to the parent, via the pipe.
764 */
765 if (pid > 0) {
766 uint8_t child_ret;
767 int stat_loc;
768
769 /* So the pipe is correctly widowed if the child exits */
770 close(from_child[1]);
771
772 /*
773 * The child writes a 0x01 byte on success, and closes
774 * the pipe on error.
775 */
776 if ((read(from_child[0], &child_ret, 1) <= 0)) child_ret = 0;
777
778 /* For cleanliness... */
779 close(from_child[0]);
780
781 /* Don't turn children into zombies */
782 if (child_ret == 0) {
783 waitpid(pid, &stat_loc, WNOHANG);
785 }
786
787#ifdef HAVE_SYSTEMD
788 /*
789 * Update the systemd MAINPID to be our child,
790 * as the parent is about to exit.
791 */
792 sd_notifyf(0, "MAINPID=%lu", (unsigned long)pid);
793#endif
794
795 goto cleanup;
796 /*
797 * The child needs to increment the semaphore as the parent
798 * is going to exit, and it will decrement the semaphore.
799 */
800 } else if (pid == 0) {
802 PWARN("%s: Failed incrementing exclusive proc semaphore in child", program);
803 }
804 }
805
806 /* so the pipe is correctly widowed if the parent exits?! */
807 close(from_child[0]);
808#ifdef HAVE_SETSID
809 setsid();
810#endif
811
812 DUMP_CAPABILITIES("post-fork");
813 } else {
814 DUMP_CAPABILITIES("pre-suid-down");
815 }
816
817 /*
818 * Ensure that we're using the CORRECT pid after forking, NOT the one
819 * we started with.
820 */
821 radius_pid = getpid();
822
823 /*
824 * Initialise the interpreter, registering operations.
825 */
827
828 /*
829 * Initialize the global event loop which handles things like
830 * systemd.
831 *
832 * This has to be done post-fork in case we're using kqueue, where the
833 * queue isn't inherited by the child process.
834 *
835 * Done before `server_init` so that module instantiate callbacks can
836 * register fds / timers against `main_loop_event_list()` directly.
837 * `main_loop_init` has no dependencies on module or virtual server
838 * state, so this reordering is safe.
839 */
840 if (main_loop_init() < 0) {
841 PERROR("Failed initialising main event loop");
843 }
844
846
847 /*
848 * Everything seems to have loaded OK, exit gracefully.
849 */
850 if (check_config) {
851 DEBUG("Configuration appears to be OK");
852 goto cleanup;
853 }
854
855 /*
856 * Initialise the SNMP stats structures
857 */
858 if (fr_snmp_init() < 0) {
859 PERROR("Failed initialising SNMP");
861 }
862
863 /*
864 * Start the network / worker threads.
865 */
866 {
867 fr_schedule_config_t *schedule;
868
869 MEM(schedule = talloc_zero(global_ctx, fr_schedule_config_t));
870 schedule->max_workers = config->max_workers;
871 schedule->max_networks = config->max_networks;
872 schedule->stats_interval = config->stats_interval;
873
874 schedule->network.max_outstanding = config->worker.max_requests;
875 schedule->worker = config->worker;
876 schedule->cs = cf_section_find(config->root_cs, "thread", CF_IDENT_ANY);
877
878 /*
879 * Fix spurious messages
880 */
882 sc = fr_schedule_create(NULL, !config->spawn_workers, main_loop_event_list(),
885 if (!sc) {
886 PERROR("Failed starting the scheduler");
888 }
889
890 /*
891 * Tell the virtual servers to open their sockets.
892 */
894 }
895
896 /*
897 * At this point, no one has any business *ever* going
898 * back to root uid.
899 */
901
902 /*
903 * Move the current working directory to a place where it
904 * can't hurt anything.
905 */
907 if (chdir(main_config->chdir) < 0) {
908 ERROR("Failed changing working to %s: %s", main_config->chdir, fr_syserror(errno));
910 }
911 }
912
913 DUMP_CAPABILITIES("post-suid-down");
914
915 /*
916 * Dropping down may change the RLIMIT_CORE value, so
917 * reset it back to what to should be here.
918 */
920
921 /*
922 * If we're debugging, then a CTRL-C will cause the server to die
923 * immediately. Use SIGTERM to shut down the server cleanly in
924 * that case.
925 */
926 if (fr_set_signal(SIGINT, sig_fatal) < 0) {
927 set_signal_error:
928 PERROR("Failed installing signal handler");
930 }
931
932#ifdef SIGQUIT
933 if (fr_set_signal(SIGQUIT, sig_fatal) < 0) goto set_signal_error;
934#endif
935
936 /*
937 * Now that we've set everything up, we can install the signal
938 * handlers. Before this, if we get any signal, we don't know
939 * what to do, so we might as well do the default, and die.
940 */
941#ifdef SIGPIPE
942 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
943 ERROR("Failed ignoring SIGPIPE: %s", fr_syserror(errno));
944 goto cleanup;
945 }
946#endif
947
948 if (fr_set_signal(SIGHUP, sig_hup) < 0) goto set_signal_error;
949 if (fr_set_signal(SIGTERM, sig_fatal) < 0) goto set_signal_error;
950
951 /*
952 * Write the PID after we've forked, so that we write the correct one.
953 */
954 if (config->write_pid) {
955 FILE *fp;
956
957 fp = fopen(config->pid_file, "w");
958 if (fp != NULL) {
959 /*
960 * @fixme What about following symlinks,
961 * and having it over-write a normal file?
962 */
963 fprintf(fp, "%d\n", (int) radius_pid);
964 fclose(fp);
965 } else {
966 ERROR("Failed creating PID file %s: %s", config->pid_file, fr_syserror(errno));
968 }
969 }
970
971 trigger(NULL, NULL, NULL, "server.start", false, NULL, NULL);
972
973 /*
974 * Inform the parent (who should still be waiting) that the rest of
975 * initialisation went OK, and that it should exit with a 0 status.
976 * If we don't get this far, then we just close the pipe on exit, and the
977 * parent gets a read failure.
978 */
979 if (config->daemonize) {
980 if (write(from_child[1], "\001", 1) < 0) {
981 WARN("Failed informing parent of successful start: %s",
982 fr_syserror(errno));
983 }
984 close(from_child[1]);
985 }
986
987 /*
988 * Clear the libfreeradius error buffer.
989 */
991
992 /*
993 * Prevent anything from modifying the dictionaries
994 * they're now immutable.
995 */
997
998 /*
999 * Protect global memory - If something attempts
1000 * to write to this memory we get a SIGBUS.
1001 */
1002 if (do_mprotect) {
1003 if (mprotect(pool_page_start, pool_page_len, PROT_READ) < 0) {
1004 ERROR("Protecting global memory failed: %s", fr_syserror(errno));
1006 }
1007 DEBUG("Global memory protected");
1008 }
1009
1011#ifndef NDEBUG
1012 if (fr_time_delta_ispos(exit_after)) fr_exit_after(main_loop_event_list()->tl, fr_time_wrap(0), &exit_after);
1013#endif
1014 /*
1015 * Process requests until HUP or exit.
1016 */
1017 INFO("Ready to process requests"); /* we were actually ready a while ago, but oh well */
1018 while ((status = main_loop_start()) == 0x80) {
1020 }
1021
1022 /*
1023 * Ignore the TERM signal: we're about to die.
1024 */
1025 if (unlikely(signal(SIGTERM, SIG_IGN) == SIG_ERR)) {
1026 ERROR("Failed blocking SIGTERM, we may receive spurious signals: %s",
1027 fr_syserror(errno));
1028 }
1029
1030 /*
1031 * Unprotect global memory
1032 */
1033 if (do_mprotect) {
1034 if (mprotect(pool_page_start, pool_page_len,
1035 PROT_READ | PROT_WRITE) < 0) {
1036 ERROR("Unprotecting global memory failed: %s", fr_syserror(errno));
1038 }
1039 DEBUG("Global memory unprotected");
1040 }
1041
1042 if (status < 0) {
1043 PERROR("Exiting due to internal error");
1044 ret = EXIT_FAILURE;
1045 } else {
1046 INFO("Exiting normally");
1047 ret = EXIT_SUCCESS;
1048 }
1049
1051
1052 /*
1053 * Fire signal and stop triggers after ignoring SIGTERM, so handlers are
1054 * not killed with the rest of the process group, below.
1055 */
1056 if (status == 2) trigger(NULL, NULL, NULL, "server.signal.term", true, NULL, NULL);
1057 trigger(NULL, NULL, NULL, "server.stop", false, NULL, NULL);
1058
1059 /*
1060 * Stop the scheduler, this signals the network and worker threads
1061 * to exit gracefully. fr_schedule_destroy only returns once all
1062 * threads have been joined.
1063 */
1064 if (unlikely(fr_schedule_destroy(&sc) < 0)) {
1066 }
1067
1068 /*
1069 * We're exiting, so we can delete the PID file.
1070 * (If it doesn't exist, we can ignore the error returned by unlink)
1071 */
1072 if (config->daemonize) {
1073 DEBUG3("Unlinking PID file %s", config->pid_file);
1074 unlink(config->pid_file);
1075 }
1076
1077 /*
1078 * Free memory in an explicit and consistent order
1079 *
1080 * We could let everything be freed by the global_ctx
1081 * context, but in some cases there are odd interactions
1082 * with destructors that may cause double frees and
1083 * SEGVs.
1084 */
1085 if (!config->spawn_workers) {
1087
1090 }
1091
1093
1094 /*
1095 * Send a TERM signal to all associated processes
1096 * (including us, which gets ignored.)
1097 *
1098 * This _shouldn't_ be needed, but may help with
1099 * processes created by the exec code or triggers.
1100 *
1101 * Only do this when we lead the process group, i.e. when
1102 * we daemonized (setsid), or a supervisor such as systemd
1103 * or a container runtime gave us our own group. When run
1104 * in the foreground from a shell the group belongs to the
1105 * shell, and signalling it would take out the shell and
1106 * its terminal along with our children.
1107 */
1108 if (config->spawn_workers && (getpgid(0) == radius_pid)) {
1109 INFO("All threads have exited, sending SIGTERM to remaining children");
1110
1111 /*
1112 * If pid is negative, but not -1, sig
1113 * shall be sent to all processes
1114 * (excluding an unspecified set of system processes)
1115 * whose process group ID is equal to the absolute value
1116 * of pid, and for which the process has permission
1117 * to send a signal.
1118 */
1119 kill(-getpgid(radius_pid), SIGTERM);
1120 }
1121
1122 /*
1123 * Remove the semaphore, allowing other processes
1124 * to start. We do this before the cleanup label
1125 * as the parent process MUST NOT call this
1126 * function as it exits, otherwise the semaphore
1127 * is removed and there's no exclusivity.
1128 */
1130
1131cleanup:
1132 /*
1133 * If we're told to just exit without cleaning up memory,
1134 * then do so.
1135 */
1136 if (config && config->talloc_skip_cleanup) {
1138 exit(ret);
1139 }
1140
1141 /*
1142 * This may not have been done earlier if we're
1143 * exiting due to a startup error.
1144 */
1145 (void) fr_schedule_destroy(&sc);
1146
1147 /*
1148 * Threads not managed by the schedule (e.g. librdkafka's
1149 * bg threads) hold a `_Thread_local fr_log_pool` we can't
1150 * clear from this thread. `fr_atexit_thread_trigger_all`
1151 * below frees the underlying chunks, leaving those slots
1152 * dangling. Flip the logger into pool-less mode first so
1153 * any log line that races the trigger - or fires after it -
1154 * goes through `talloc_new(NULL)` instead of dereferencing
1155 * a freed pool.
1156 */
1158
1159 /*
1160 * Ensure all thread local memory is cleaned up
1161 * before we start cleaning up global resources.
1162 * This is necessary for single threaded mode
1163 * to ensure that thread local resources that
1164 * depend on global resources are freed at the
1165 * appropriate time.
1166 */
1168
1169 server_free();
1170
1171#ifdef WITH_TLS
1172 fr_openssl_free(); /* Cleanup any memory alloced by OpenSSL and placed into globals */
1173#endif
1174
1175 if (config) talloc_memory_report = config->talloc_memory_report; /* Grab this before we free the config */
1176
1177 /*
1178 * Virtual servers need to be freed before modules
1179 * as state entries containing data with module-specific
1180 * destructors may exist.
1181 */
1183
1184 /*
1185 * Free modules, this needs to be done explicitly
1186 * because some libraries used by modules use atexit
1187 * handlers registered after ours, and they may deinit
1188 * themselves before we free the modules and cause
1189 * crashes on exit.
1190 */
1192
1193#ifdef WITH_TLS
1194 fr_tls_dict_free();
1195#endif
1196
1197 /*
1198 * And now nothing should be left anywhere except the
1199 * parsed configuration items.
1200 */
1202
1203 /*
1204 * Cleanup everything else
1205 */
1206 if (talloc_free(global_ctx) < 0) {
1207#ifndef NDEBUG
1208 fr_perror("program");
1209 ret = EXIT_FAILURE;
1210#endif
1211 }
1212
1213 /*
1214 * Anything not cleaned up by the above is allocated in
1215 * the NULL top level context, and is likely leaked memory.
1216 */
1217 if (talloc_memory_report) fr_log_talloc_report(NULL);
1218
1219 /*
1220 * If we're running under LSAN, try and SUID back up so
1221 * we don't inteferere with the onexit() handler.
1222 */
1224 fr_strerror_clear(); /* clear error buffer */
1225
1226 /*
1227 * Ensure our atexit handlers run before any other
1228 * atexit handlers registered by third party libraries.
1229 */
1231
1232 return ret;
1233}
1234
1235/*
1236 * Display the syntax for starting this program.
1237 */
1238static NEVER_RETURNS void usage(int status)
1239{
1240 FILE *output = status ? stderr : stdout;
1241
1242 fprintf(output, "Usage: %s [options]\n", program);
1243 fprintf(output, "Options:\n");
1244 fprintf(output, " -C Check configuration and exit.\n");
1245 fprintf(output, " -d <confdir> Configuration file directory (defaults to " CONFDIR ").\n");
1246 fprintf(output, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
1247#ifndef NDEBUG
1248 fprintf(output, " -e <seconds> Exit after the specified number of seconds. Useful for diagnosing \"crash-on-exit\" issues.\n");
1249#endif
1250 fprintf(output, " -f Run as a foreground process, not a daemon.\n");
1251 fprintf(output, " -h Print this help message.\n");
1252 fprintf(output, " -l <log_file> Logging output will be written to this file.\n");
1253#ifndef NDEBUG
1254 fprintf(output, " -L <size> When running in memory debug mode, set a hard limit on talloced memory\n");
1255#endif
1256 fprintf(output, " -n <name> Read ${confdir}/name.conf instead of ${confdir}/%s.conf.\n", program);
1257 fprintf(output, " -m Allow multiple processes reading the same %s.conf to exist simultaneously.\n", program);
1258#ifndef NDEBUG
1259 fprintf(output, " -M Enable talloc memory debugging, and issue a memory report when the server terminates\n");
1260#endif
1261 fprintf(output, " -P Always write out PID, even with -f.\n");
1262 fprintf(output, " -s Do not spawn child processes to handle requests (same as -ft).\n");
1263
1264 /*
1265 * Place-holder in case we need it. Should be removed before the release.
1266 */
1267// fprintf(output, " -S <flag> Set migration flags to assist with upgrades from version 3.\n");
1268 fprintf(output, " -t Disable threads.\n");
1269 fprintf(output, " -T Prepend timestamps to log messages.\n");
1270 fprintf(output, " -v Print server version information.\n");
1271 fprintf(output, " -X Turn on full debugging (similar to -tfxxl stdout).\n");
1272 fprintf(output, " -x Turn on additional debugging (-xx gives more debugging).\n");
1273 fr_exit(status);
1274}
1275
1276
1277/*
1278 * We got a fatal signal.
1279 */
1280static void sig_fatal(int sig)
1281{
1282 static volatile sig_atomic_t last_sig;
1283
1284 if (getpid() != radius_pid) _exit(sig);
1285
1286 /*
1287 * Suppress duplicate signals.
1288 *
1289 * For some reason on macOS we get multiple signals
1290 * for the same event (SIGINT).
1291 *
1292 * ...this also fixes the problem of the user hammering
1293 * Ctrl-C and causing ungraceful exits as we try and
1294 * write out signals to a pipe that's already closed.
1295 */
1296 if (sig == last_sig) return;
1297 last_sig = sig;
1298
1299 switch (sig) {
1300 case SIGTERM:
1302 break;
1303
1304 case SIGINT:
1305#ifdef SIGQUIT
1306 case SIGQUIT:
1307#endif
1309 break;
1310
1311 default:
1312 fr_exit(sig);
1313 }
1314}
1315
1316#ifdef SIGHUP
1317/*
1318 * We got the hangup signal.
1319 * Re-read the configuration files.
1320 */
1321static void sig_hup(UNUSED int sig)
1322{
1323 reset_signal(SIGHUP, sig_hup);
1324
1326}
1327#endif
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:179
void fr_atexit_global_disarm_all(void)
Remove all global destructors (without executing them)
Definition atexit.c:283
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:310
#define fr_atexit_thread_trigger_all(...)
Definition atexit.h:236
void fr_radmin_stop(void)
Definition radmin.c:1150
int fr_radmin_start(main_config_t *config, bool cli, int std_fd[static 3])
Definition radmin.c:1082
#define RCSID(id)
Definition build.h:560
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:382
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
bool check_config
Definition cf_file.c:61
void cf_md5_final(uint8_t *digest)
Definition cf_file.c:3618
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
#define CF_IDENT_ANY
Definition cf_util.h:80
char const * fr_debug_state_to_msg(fr_debug_state_t state)
Return current value of debug_state.
Definition debug.c:525
int fr_log_talloc_report(TALLOC_CTX const *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
Definition debug.c:975
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
Definition debug.c:756
int fr_get_lsan_state(void)
Definition debug.c:245
void fr_debug_state_store(void)
Should be run before using setuid or setgid to get useful results.
Definition debug.c:505
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition debug.c:1050
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program, unsigned long fault_signals)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1074
fr_debug_state_t fr_debug_state
Whether we're attached to by a debugger.
Definition debug.c:74
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition debug.h:266
#define PANIC_ACTION_SIGNALS
Definition debug.h:133
#define MEM(x)
Definition debug.h:38
void dependency_version_print(void)
Definition dependency.c:364
int rad_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition dependency.c:69
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static NEVER_RETURNS void usage(void)
Definition dhcpclient.c:113
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:5040
void fr_dict_global_ctx_read_only(void)
Mark all dictionaries and the global dictionary ctx as read only.
Definition dict_util.c:4956
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:5065
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir))
Initialise the global protocol hashes.
Definition dict_util.c:4850
talloc_free(hp)
uint32_t max_outstanding
Definition network.h:46
int server_init(CONF_SECTION *cs, char const *conf_dir, fr_dict_t *dict)
Initialize src/lib/server/.
Definition base.c:42
void server_free(void)
Free src/lib/server/.
Definition base.c:137
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG3(_fmt,...)
Definition log.h:271
#define PWARN(_fmt,...)
Definition log.h:232
void rad_suid_up(void)
Definition util.c:767
bool rad_suid_is_down_permanent(void)
Return whether we've permanently dropped root privileges.
Definition util.c:788
void(*)(int) reset_signal(int signo, void(*func)(int))
Definition util.c:49
void rad_suid_down_permanent(void)
Definition util.c:776
int unlang_global_init(void)
Definition base.c:158
#define fr_time()
Definition event.c:60
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition event.c:2383
Stores all information relating to an event list.
Definition event.c:377
int fr_debug_lvl
Definition log.c:41
void fr_log_disable_pools(void)
Disable per-thread log pools for the rest of the process lifetime.
Definition log.c:334
static FILE * devnull
File handle for /dev/null.
Definition log.c:74
fr_log_t default_log
Definition log.c:308
@ 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_STDOUT
Log to stdout.
Definition log.h:75
@ L_TIMESTAMP_ON
Always log timestamps.
Definition log.h:87
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)
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)
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
int main_config_init(main_config_t *config)
void main_config_confdir_set(main_config_t *config, char const *name)
Set the global radius config directory.
main_config_t const * main_config
Main server configuration.
Definition main_config.c:56
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.
void main_config_dict_dir_set(main_config_t *config, char const *name)
Set the global dictionary directory.
char const * chdir
where to chdir() to when we start.
Main server configuration.
Definition main_config.h:59
int main_loop_start(void)
Definition main_loop.c:203
fr_event_list_t * main_loop_event_list(void)
Return the main loop event list.
Definition main_loop.c:173
void main_loop_signal_raise(int flag)
Definition main_loop.c:78
int main_loop_init(void)
Initialise the main event loop, setting up signal handlers.
Definition main_loop.c:262
void main_loop_free(void)
Definition main_loop.c:198
@ RADIUS_SIGNAL_SELF_HUP
Definition main_loop.h:36
@ RADIUS_SIGNAL_SELF_TERM
Definition main_loop.h:37
unsigned char uint8_t
int fr_set_signal(int sig, sig_t func)
Sets a signal handler using sigaction if available, else signal.
Definition misc.c:47
int modules_rlm_coord_attach(fr_event_list_t *el)
Runs the coord_attach method of all registered backend modules.
Definition module_rlm.c:992
int modules_rlm_free(void)
Cleanup all global structures.
int modules_rlm_init(void)
Initialise the module list structure.
static const conf_parser_t config[]
Definition base.c:162
#define WARN(fmt,...)
#define INFO(fmt,...)
Definition radict.c:63
int main(int argc, char *argv[])
Entry point for the daemon.
Definition radiusd.c:216
static void thread_detach(UNUSED void *uctx)
Explicitly cleanup module/xlat resources.
Definition radiusd.c:139
#define EXIT_WITH_PERROR
Definition radiusd.c:156
static void fr_exit_after(fr_timer_list_t *tl, fr_time_t now, void *uctx)
Encourage the server to exit after a period of time.
Definition radiusd.c:180
static void fr_time_sync_event(fr_timer_list_t *tl, UNUSED fr_time_t now, UNUSED void *uctx)
Definition radiusd.c:164
#define DUMP_CAPABILITIES(_phase)
Definition radiusd.c:209
#define RDUP(_x)
#define EXIT_WITH_SUCCESS
Definition radiusd.c:150
char const * radiusd_version
Definition radiusd.c:77
static int thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el, UNUSED void *uctx)
Create module and xlat per-thread instances.
Definition radiusd.c:127
static int talloc_config_set(main_config_t *config)
Configure talloc debugging features.
Definition radiusd.c:103
static void sig_fatal(int)
Definition radiusd.c:1280
static pid_t radius_pid
Definition radiusd.c:78
#define EXIT_WITH_FAILURE
Definition radiusd.c:144
static fr_timer_t * fr_time_sync_ev
Definition radiusd.c:162
static char const * program
Definition radiusd.c:79
static bool cleanup
Definition radsniff.c:59
int request_global_init(void)
Definition request.c:598
#define FR_SBUFF_IN_STR(_start)
fr_schedule_t * fr_schedule_create(TALLOC_CTX *ctx, bool single_threaded, fr_event_list_t *el, fr_log_t *logger, fr_log_lvl_t lvl, fr_schedule_thread_instantiate_t worker_thread_instantiate, fr_schedule_thread_detach_t worker_thread_detach, fr_schedule_config_t *config)
Create a scheduler and spawn the child threads.
Definition schedule.c:292
int fr_schedule_destroy(fr_schedule_t **sc_to_free)
Destroy a scheduler, and tell its child threads to exit.
Definition schedule.c:597
The scheduler.
Definition schedule.c:77
fr_network_config_t network
configuration for each network;
Definition schedule.h:69
uint32_t max_workers
number of worker threads
Definition schedule.h:66
CONF_SECTION * cs
root config section
Definition schedule.h:73
fr_worker_config_t worker
configuration for each worker
Definition schedule.h:68
fr_time_delta_t stats_interval
print channel statistics
Definition schedule.h:71
uint32_t max_networks
number of network threads
Definition schedule.h:65
fr_slen_t fr_size_from_str(size_t *out, fr_sbuff_t *in)
Parse a size string with optional unit.
Definition size.c:40
static const uchar sc[16]
Definition smbdes.c:115
int fr_snmp_init(void)
Initialise the tree of SNMP map structures used to attach callbacks to OIDs.
Definition snmp.c:1141
void modules_init(char const *lib_dir)
Perform global initialisation for modules.
Definition module.c:1981
fr_log_dst_t dst
Log destination.
Definition log.h:94
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
bool suppress_secrets
suppress secrets when printing to this destination
Definition log.h:105
char const * file
Path to log file.
Definition log.h:110
bool print_level
sometimes we don't want log levels printed
Definition log.h:103
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
static TALLOC_CTX * global_ctx
Definition talloc.c:33
TALLOC_CTX * talloc_page_aligned_pool(TALLOC_CTX *ctx, void **start, size_t *end_len, unsigned int headers, size_t size)
Return a page aligned talloc memory pool.
Definition talloc.c:309
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
int fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Instantiate thread-specific data for modules, virtual servers, xlats, unlang, and TLS.
Definition thread.c:165
void fr_thread_detach(void)
Detach thread-specific data for modules, virtual servers, xlats.
Definition thread.c:190
int fr_time_sync(void)
Get a new fr_time_monotonic_to_realtime value.
Definition time.c:109
int fr_time_start(void)
Initialize the local time.
Definition time.c:157
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_eq(_a, _b)
Definition time.h:241
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:49
A timer event.
Definition timer.c:83
#define fr_timer_in(...)
Definition timer.h:87
int fr_openssl_version_consistent(void)
Definition version.c:246
int trigger(unlang_interpret_t *intp, CONF_SECTION const *cs, CONF_PAIR **trigger_cp, char const *name, bool rate_limit, fr_pair_list_t *args, void const *uctx)
Execute a trigger - call an executable to process an event.
Definition trigger.c:160
static fr_event_list_t * el
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
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition version.c:40
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
Definition version.h:58
#define RADIUSD_MAGIC_NUMBER
Definition version.h:81
int virtual_servers_open(fr_schedule_t *sc)
Open all the listen sockets.
int virtual_servers_init(void)
Performs global initialisation for the virtual server code.
int virtual_servers_free(void)