int main(int argc, char *argv[]) { TALLOC_CTX *main_ctx=NULL; TR_INSTANCE *tr = NULL; struct cmdline_args opts; struct event_base *ev_base; struct tr_socket_event tids_ev; struct event *cfgwatch_ev; configure_signals(); /* we're going to be multithreaded, so disable null context tracking */ talloc_set_abort_fn(tr_abort); talloc_disable_null_tracking(); #if TALLOC_DEBUG_ENABLE talloc_set_log_fn(tr_talloc_log); #endif /* TALLOC_DEBUG_ENABLE */ main_ctx=talloc_new(NULL); /* Use standalone logging */ tr_log_open(); /***** parse command-line arguments *****/ /* set defaults */ opts.config_dir="."; /* parse the command line*/ argp_parse(&argp, argc, argv, 0, 0, &opts); /* process options */ remove_trailing_slash(opts.config_dir); /***** create a Trust Router instance *****/ if (NULL == (tr = tr_create(main_ctx))) { tr_crit("Unable to create Trust Router instance, exiting."); return 1; } /***** initialize the trust path query server instance *****/ if (NULL == (tr->tids = tids_create (tr))) { tr_crit("Error initializing Trust Path Query Server instance."); return 1; } /***** initialize the trust router protocol server instance *****/ if (NULL == (tr->trps = trps_new(tr))) { tr_crit("Error initializing Trust Router Protocol Server instance."); return 1; } /***** process configuration *****/ tr->cfgwatch=tr_cfgwatch_create(tr); if (tr->cfgwatch == NULL) { tr_crit("Unable to create configuration watcher object, exiting."); return 1; } tr->cfgwatch->config_dir=opts.config_dir; tr->cfgwatch->cfg_mgr=tr->cfg_mgr; tr->cfgwatch->update_cb=tr_config_changed; /* handle configuration changes */ tr->cfgwatch->update_cookie=(void *)tr; if (0 != tr_read_and_apply_config(tr->cfgwatch)) { tr_crit("Error reading configuration, exiting."); return 1; } /***** Set up the event loop *****/ ev_base=tr_event_loop_init(); /* Set up the event loop */ if (ev_base==NULL) { tr_crit("Error initializing event loop."); return 1; } /* already set config_dir, fstat_list and n_files earlier */ if (0 != tr_cfgwatch_event_init(ev_base, tr->cfgwatch, &cfgwatch_ev)) { tr_crit("Error initializing configuration file watcher."); return 1; } /*tr_status_event_init();*/ /* install status reporting events */ /* install TID server events */ if (0 != tr_tids_event_init(ev_base, tr->tids, tr->cfg_mgr, tr->trps, &tids_ev)) { tr_crit("Error initializing Trust Path Query Server instance."); return 1; } /* install TRP handler events */ if (TRP_SUCCESS != tr_trps_event_init(ev_base, tr)) { tr_crit("Error initializing Trust Path Query Server instance."); return 1; } tr_event_loop_run(ev_base); /* does not return until we are done */ tr_destroy(tr); /* thanks to talloc, should destroy everything */ talloc_free(main_ctx); return 0; }
static void test_abort_start(void) { test_abort_count = 0; talloc_set_abort_fn(test_abort_fn); }
static void test_abort_stop(void) { test_abort_count = 0; talloc_set_abort_fn(NULL); }
/* * The main guy. */ int main(int argc, char *argv[]) { int rcode = EXIT_SUCCESS; int argval; const char *input_file = NULL; const char *output_file = NULL; const char *filter_file = NULL; FILE *fp; REQUEST *request; VALUE_PAIR *filter_vps = NULL; if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) progname = argv[0]; else progname++; debug_flag = 0; radius_dir = talloc_strdup(NULL, RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&mainconfig, 0, sizeof(mainconfig)); mainconfig.myip.af = AF_UNSPEC; mainconfig.port = -1; mainconfig.name = "radiusd"; /* * We always log to stdout. */ fr_log_fp = stdout; default_log.dest = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; /* Process the options. */ while ((argval = getopt(argc, argv, "d:D:f:hi:mMn:o:xX")) != EOF) { switch(argval) { case 'd': if (radius_dir) { rad_const_free(radius_dir); } radius_dir = talloc_strdup(NULL, optarg); break; case 'D': mainconfig.dictionary_dir = talloc_strdup(NULL, optarg); break; case 'f': filter_file = optarg; break; case 'h': usage(0); break; case 'i': input_file = optarg; break; case 'm': mainconfig.debug_memory = 1; break; case 'M': memory_report = 1; mainconfig.debug_memory = 1; break; case 'n': mainconfig.name = optarg; break; case 'o': output_file = optarg; break; case 'X': debug_flag += 2; mainconfig.log_auth = true; mainconfig.log_auth_badpass = true; mainconfig.log_auth_goodpass = true; break; case 'x': debug_flag++; break; default: usage(1); break; } } if (memory_report) { talloc_enable_null_tracking(); #ifdef WITH_VERIFY_PTR talloc_set_abort_fn(die_horribly); #endif } talloc_set_log_fn(log_talloc); if (debug_flag) { version(); } fr_debug_flag = debug_flag; /* Read the configuration files, BEFORE doing anything else. */ if (read_mainconfig(0) < 0) { exit(EXIT_FAILURE); } setlinebuf(stdout); /* unbuffered output */ if (!input_file || (strcmp(input_file, "-") == 0)) { fp = stdin; } else { fp = fopen(input_file, "r"); if (!fp) { fprintf(stderr, "Failed reading %s: %s\n", input_file, strerror(errno)); exit(EXIT_FAILURE); } } /* * Grab the VPs from stdin, or from the file. */ request = request_setup(fp); if (!request) { fprintf(stderr, "Failed reading input: %s\n", fr_strerror()); exit(EXIT_FAILURE); } /* * No filter file, OR there's no more input, OR we're * reading from a file, and it's different from the * filter file. */ if (!filter_file || filedone || ((input_file != NULL) && (strcmp(filter_file, input_file) != 0))) { if (output_file) { fclose(fp); fp = NULL; } filedone = 0; } /* * There is a filter file. If necessary, open it. If we * already are reading it via "input_file", then we don't * need to re-open it. */ if (filter_file) { if (!fp) { fp = fopen(filter_file, "r"); if (!fp) { fprintf(stderr, "Failed reading %s: %s\n", filter_file, strerror(errno)); exit(EXIT_FAILURE); } } filter_vps = readvp2(request, fp, &filedone, "radiusd"); if (!filter_vps) { fprintf(stderr, "Failed reading attributes from %s: %s\n", filter_file, fr_strerror()); exit(EXIT_FAILURE); } /* * FIXME: loop over input packets. */ fclose(fp); } rad_virtual_server(request); if (!output_file || (strcmp(output_file, "-") == 0)) { fp = stdout; } else { fp = fopen(output_file, "w"); if (!fp) { fprintf(stderr, "Failed writing %s: %s\n", output_file, strerror(errno)); exit(EXIT_FAILURE); } } print_packet(fp, request->reply); if (output_file) fclose(fp); if (filter_vps && !pairvalidate(filter_vps, request->reply->vps)) { fprintf(stderr, "Output file %s does not match attributes in filter %s\n", output_file, filter_file); exit(EXIT_FAILURE); } talloc_free(request); INFO("Exiting normally."); /* * Detach any modules. */ detach_modules(); xlat_free(); /* modules may have xlat's */ /* * Free the configuration items. */ free_mainconfig(); rad_const_free(radius_dir); if (memory_report) { INFO("Allocated memory at time of report:"); log_talloc_report(NULL); } return rcode; }
/* * The main guy. */ int main(int argc, char *argv[]) { int rcode = EXIT_SUCCESS; int argval; const char *input_file = NULL; const char *output_file = NULL; const char *filter_file = NULL; FILE *fp; REQUEST *request; VALUE_PAIR *vp; VALUE_PAIR *filter_vps = NULL; /* * If the server was built with debugging enabled always install * the basic fatal signal handlers. */ #ifndef NDEBUG if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) { fr_perror("unittest"); exit(EXIT_FAILURE); } #endif if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) progname = argv[0]; else progname++; debug_flag = 0; set_radius_dir(NULL, RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&mainconfig, 0, sizeof(mainconfig)); mainconfig.myip.af = AF_UNSPEC; mainconfig.port = -1; mainconfig.name = "radiusd"; /* * The tests should have only IPs, not host names. */ fr_hostname_lookups = false; /* * We always log to stdout. */ fr_log_fp = stdout; default_log.dst = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; /* Process the options. */ while ((argval = getopt(argc, argv, "d:D:f:hi:mMn:o:xX")) != EOF) { switch(argval) { case 'd': set_radius_dir(NULL, optarg); break; case 'D': mainconfig.dictionary_dir = talloc_typed_strdup(NULL, optarg); break; case 'f': filter_file = optarg; break; case 'h': usage(0); break; case 'i': input_file = optarg; break; case 'm': mainconfig.debug_memory = true; break; case 'M': memory_report = true; mainconfig.debug_memory = true; break; case 'n': mainconfig.name = optarg; break; case 'o': output_file = optarg; break; case 'X': debug_flag += 2; mainconfig.log_auth = true; mainconfig.log_auth_badpass = true; mainconfig.log_auth_goodpass = true; break; case 'x': debug_flag++; break; default: usage(1); break; } } if (memory_report) { talloc_enable_null_tracking(); #ifdef WITH_VERIFY_PTR talloc_set_abort_fn(die_horribly); #endif } talloc_set_log_fn(log_talloc); if (debug_flag) { version(); } fr_debug_flag = debug_flag; /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radiusd"); exit(EXIT_FAILURE); } if (rad_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { exit(EXIT_FAILURE); } /* Read the configuration files, BEFORE doing anything else. */ if (mainconfig_init() < 0) { exit(EXIT_FAILURE); } /* * Load the modules */ if (modules_init(mainconfig.config) < 0) { exit(EXIT_FAILURE); } /* Set the panic action (if required) */ if (mainconfig.panic_action && #ifndef NDEBUG !getenv("PANIC_ACTION") && #endif (fr_fault_setup(mainconfig.panic_action, argv[0]) < 0)) { exit(EXIT_FAILURE); } setlinebuf(stdout); /* unbuffered output */ if (!input_file || (strcmp(input_file, "-") == 0)) { fp = stdin; } else { fp = fopen(input_file, "r"); if (!fp) { fprintf(stderr, "Failed reading %s: %s\n", input_file, strerror(errno)); exit(EXIT_FAILURE); } } /* * Grab the VPs from stdin, or from the file. */ request = request_setup(fp); if (!request) { fprintf(stderr, "Failed reading input: %s\n", fr_strerror()); exit(EXIT_FAILURE); } /* * No filter file, OR there's no more input, OR we're * reading from a file, and it's different from the * filter file. */ if (!filter_file || filedone || ((input_file != NULL) && (strcmp(filter_file, input_file) != 0))) { if (output_file) { fclose(fp); fp = NULL; } filedone = false; } /* * There is a filter file. If necessary, open it. If we * already are reading it via "input_file", then we don't * need to re-open it. */ if (filter_file) { if (!fp) { fp = fopen(filter_file, "r"); if (!fp) { fprintf(stderr, "Failed reading %s: %s\n", filter_file, strerror(errno)); exit(EXIT_FAILURE); } } filter_vps = readvp2(request, fp, &filedone, "radiusd"); if (!filter_vps) { fprintf(stderr, "Failed reading attributes from %s: %s\n", filter_file, fr_strerror()); exit(EXIT_FAILURE); } /* * FIXME: loop over input packets. */ fclose(fp); } rad_virtual_server(request); if (!output_file || (strcmp(output_file, "-") == 0)) { fp = stdout; } else { fp = fopen(output_file, "w"); if (!fp) { fprintf(stderr, "Failed writing %s: %s\n", output_file, strerror(errno)); exit(EXIT_FAILURE); } } print_packet(fp, request->reply); if (output_file) fclose(fp); /* * Update the list with the response type. */ vp = radius_paircreate(request->reply, &request->reply->vps, PW_RESPONSE_PACKET_TYPE, 0); vp->vp_integer = request->reply->code; if (filter_vps && !pairvalidate(filter_vps, request->reply->vps)) { fprintf(stderr, "Output file %s does not match attributes in filter %s\n", output_file ? output_file : input_file, filter_file); exit(EXIT_FAILURE); } talloc_free(request); INFO("Exiting normally."); /* * Detach any modules. */ modules_free(); xlat_free(); /* modules may have xlat's */ /* * Free the configuration items. */ mainconfig_free(); if (memory_report) { INFO("Allocated memory at time of report:"); log_talloc_report(NULL); } return rcode; }
static void popt_samba_callback(poptContext con, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { const char *pname; if (reason == POPT_CALLBACK_REASON_POST) { if (lpcfg_configfile(cmdline_lp_ctx) == NULL) { lpcfg_load_default(cmdline_lp_ctx); } /* Hook any 'every Samba program must do this, after * the smb.conf is setup' functions here */ return; } /* Find out basename of current program */ pname = strrchr_m(poptGetInvocationName(con),'/'); if (!pname) pname = poptGetInvocationName(con); else pname++; if (reason == POPT_CALLBACK_REASON_PRE) { /* Hook for 'almost the first thing to do in a samba program' here */ /* setup for panics */ fault_setup(); /* and logging */ setup_logging(pname, DEBUG_DEFAULT_STDOUT); talloc_set_log_fn(popt_s4_talloc_log_fn); talloc_set_abort_fn(smb_panic); cmdline_lp_ctx = loadparm_init_global(false); return; } switch(opt->val) { case OPT_LEAK_REPORT: talloc_enable_leak_report(); break; case OPT_LEAK_REPORT_FULL: talloc_enable_leak_report_full(); break; case OPT_OPTION: if (!lpcfg_set_option(cmdline_lp_ctx, arg)) { fprintf(stderr, "Error setting option '%s'\n", arg); exit(1); } break; case 'd': lpcfg_set_cmdline(cmdline_lp_ctx, "log level", arg); break; case OPT_DEBUG_STDERR: setup_logging(pname, DEBUG_STDERR); break; case 's': if (arg) { lpcfg_load(cmdline_lp_ctx, arg); } break; case 'l': if (arg) { char *new_logfile = talloc_asprintf(NULL, "%s/log.%s", arg, pname); lpcfg_set_cmdline(cmdline_lp_ctx, "log file", new_logfile); talloc_free(new_logfile); } break; } }
/** Registers signal handlers to execute panic_action on fatal signal * * May be called multiple time to change the panic_action/program. * * @param cmd to execute on fault. If present %p will be substituted * for the parent PID before the command is executed, and %e * will be substituted for the currently running program. * @param program Name of program currently executing (argv[0]). * @return 0 on success -1 on failure. */ int fr_fault_setup(char const *cmd, char const *program) { static bool setup = false; char *out = panic_action; size_t left = sizeof(panic_action); char const *p = cmd; char const *q; if (cmd) { size_t ret; /* Substitute %e for the current program */ while ((q = strstr(p, "%e"))) { out += ret = snprintf(out, left, "%.*s%s", (int) (q - p), p, program ? program : ""); if (left <= ret) { oob: fr_strerror_printf("Panic action too long"); return -1; } left -= ret; p = q + 2; } if (strlen(p) >= left) goto oob; strlcpy(out, p, left); } else { *panic_action = '\0'; } /* * Check for administrator sanity. */ if (fr_fault_check_permissions() < 0) return -1; /* Unsure what the side effects of changing the signal handler mid execution might be */ if (!setup) { char *env; fr_debug_state_t debug_state; /* * Installing signal handlers interferes with some debugging * operations. Give the developer control over whether the * signal handlers are installed or not. */ env = getenv("DEBUG"); if (!env || (strcmp(env, "no") == 0)) { debug_state = DEBUG_STATE_NOT_ATTACHED; } else if (!strcmp(env, "auto") || !strcmp(env, "yes")) { /* * Figure out if we were started under a debugger */ if (fr_debug_state < 0) fr_debug_state = fr_get_debug_state(); debug_state = fr_debug_state; } else { debug_state = DEBUG_STATE_ATTACHED; } talloc_set_log_fn(_fr_talloc_log); /* * These signals can't be properly dealt with in the debugger * if we set our own signal handlers. */ switch (debug_state) { default: #ifndef NDEBUG FR_FAULT_LOG("Debugger check failed: %s", fr_strerror()); FR_FAULT_LOG("Signal processing in debuggers may not work as expected"); #endif /* FALL-THROUGH */ case DEBUG_STATE_NOT_ATTACHED: #ifdef SIGABRT if (fr_set_signal(SIGABRT, fr_fault) < 0) return -1; /* * Use this instead of abort so we get a * full backtrace with broken versions of LLDB */ talloc_set_abort_fn(_fr_talloc_fault); #endif #ifdef SIGILL if (fr_set_signal(SIGILL, fr_fault) < 0) return -1; #endif #ifdef SIGFPE if (fr_set_signal(SIGFPE, fr_fault) < 0) return -1; #endif #ifdef SIGSEGV if (fr_set_signal(SIGSEGV, fr_fault) < 0) return -1; #endif break; case DEBUG_STATE_ATTACHED: break; } /* * Needed for memory reports */ { TALLOC_CTX *tmp; bool *marker; tmp = talloc(NULL, bool); talloc_null_ctx = talloc_parent(tmp); talloc_free(tmp); /* * Disable null tracking on exit, else valgrind complains */ talloc_autofree_ctx = talloc_autofree_context(); marker = talloc(talloc_autofree_ctx, bool); talloc_set_destructor(marker, _fr_disable_null_tracking); } #if defined(HAVE_MALLOPT) && !defined(NDEBUG) /* * If were using glibc malloc > 2.4 this scribbles over * uninitialised and freed memory, to make memory issues easier * to track down. */ if (!getenv("TALLOC_FREE_FILL")) mallopt(M_PERTURB, 0x42); mallopt(M_CHECK_ACTION, 3); #endif #if defined(HAVE_EXECINFO) && defined(__GNUC__) && !defined(NDEBUG) /* * We need to pre-load lgcc_s, else we can get into a deadlock * in fr_fault, as backtrace() attempts to dlopen it. * * Apparently there's a performance impact of loading lgcc_s, * so only do it if this is a debug build. * * See: https://sourceware.org/bugzilla/show_bug.cgi?id=16159 */ { void *stack[10]; backtrace(stack, 10); } #endif }
/** Register talloc fault handlers * * Just register the fault handlers we need to make talloc * produce useful debugging output. */ void fr_talloc_fault_setup(void) { talloc_set_log_fn(_fr_talloc_log); talloc_set_abort_fn(_fr_talloc_fault_simple); }
static void popt_common_callback(poptContext con, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { if (reason == POPT_CALLBACK_REASON_PRE) { set_logfile(con, get_dyn_LOGFILEBASE()); talloc_set_log_fn(popt_s3_talloc_log_fn); talloc_set_abort_fn(smb_panic); return; } if (reason == POPT_CALLBACK_REASON_POST) { if (PrintSambaVersionString) { printf( "Version %s\n", samba_version_string()); exit(0); } if (is_default_dyn_CONFIGFILE()) { if(getenv("SMB_CONF_PATH")) { set_dyn_CONFIGFILE(getenv("SMB_CONF_PATH")); } } /* Further 'every Samba program must do this' hooks here. */ return; } switch(opt->val) { case OPT_OPTION: if (!lp_set_option(arg)) { fprintf(stderr, "Error setting option '%s'\n", arg); exit(1); } break; case 'd': if (arg) { lp_set_cmdline("log level", arg); } break; case 'V': PrintSambaVersionString = True; break; case 'O': if (arg) { lp_do_parameter(-1, "socket options", arg); } break; case 's': if (arg) { set_dyn_CONFIGFILE(arg); } break; case 'n': if (arg) { lp_set_cmdline("netbios name", arg); } break; case 'l': if (arg) { set_logfile(con, arg); override_logfile = True; set_dyn_LOGFILEBASE(arg); } break; case 'i': if (arg) { lp_set_cmdline("netbios scope", arg); } break; case 'W': if (arg) { lp_set_cmdline("workgroup", arg); } break; } }
/* * The main guy. */ int main(int argc, char *argv[]) { int rcode = EXIT_SUCCESS; int status; int argval; int spawn_flag = true; int dont_fork = false; int write_pid = false; int flag = 0; #ifdef HAVE_SIGACTION struct sigaction act; #endif #ifdef OSFC2 set_auth_parameters(argc,argv); #endif if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) progname = argv[0]; else progname++; #ifdef WIN32 { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { fprintf(stderr, "%s: Unable to initialize socket library.\n", progname); return 1; } } #endif debug_flag = 0; spawn_flag = true; radius_dir = talloc_strdup(NULL, RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&mainconfig, 0, sizeof(mainconfig)); mainconfig.myip.af = AF_UNSPEC; mainconfig.port = -1; mainconfig.name = "radiusd"; #ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_flags = 0 ; sigemptyset( &act.sa_mask ) ; #endif /* * Don't put output anywhere until we get told a little * more. */ default_log.dest = L_DST_NULL; default_log.fd = -1; mainconfig.log_file = NULL; /* Process the options. */ while ((argval = getopt(argc, argv, "Cd:D:fhi:l:mMn:p:PstvxX")) != EOF) { switch(argval) { case 'C': check_config = true; spawn_flag = false; dont_fork = true; break; case 'd': if (radius_dir) { rad_const_free(radius_dir); } radius_dir = talloc_strdup(NULL, optarg); break; case 'D': mainconfig.dictionary_dir = talloc_strdup(NULL, optarg); break; case 'f': dont_fork = true; break; case 'h': usage(0); break; case 'l': if (strcmp(optarg, "stdout") == 0) { goto do_stdout; } mainconfig.log_file = strdup(optarg); default_log.dest = L_DST_FILES; default_log.fd = open(mainconfig.log_file, O_WRONLY | O_APPEND | O_CREAT, 0640); if (default_log.fd < 0) { fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, fr_syserror(errno)); exit(EXIT_FAILURE); } fr_log_fp = fdopen(default_log.fd, "a"); break; case 'i': if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) { fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg); exit(EXIT_FAILURE); } flag |= 1; break; case 'n': mainconfig.name = optarg; break; case 'm': mainconfig.debug_memory = 1; break; case 'M': memory_report = 1; mainconfig.debug_memory = 1; break; case 'p': mainconfig.port = atoi(optarg); if ((mainconfig.port <= 0) || (mainconfig.port >= 65536)) { fprintf(stderr, "radiusd: Invalid port number %s\n", optarg); exit(EXIT_FAILURE); } flag |= 2; break; case 'P': /* Force the PID to be written, even in -f mode */ write_pid = true; break; case 's': /* Single process mode */ spawn_flag = false; dont_fork = true; break; case 't': /* no child threads */ spawn_flag = false; break; case 'v': /* Don't print timestamps */ debug_flag += 2; fr_log_fp = stdout; default_log.dest = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; version(); exit(EXIT_SUCCESS); case 'X': spawn_flag = false; dont_fork = true; debug_flag += 2; mainconfig.log_auth = true; mainconfig.log_auth_badpass = true; mainconfig.log_auth_goodpass = true; do_stdout: fr_log_fp = stdout; default_log.dest = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; break; case 'x': debug_flag++; break; default: usage(1); break; } } if (memory_report) { talloc_enable_null_tracking(); #ifdef WITH_VERIFY_PTR talloc_set_abort_fn(die_horribly); #endif } talloc_set_log_fn(log_talloc); /* * Mismatch between build time OpenSSL and linked SSL, * better to die here than segfault later. */ #ifdef HAVE_OPENSSL_CRYPTO_H if (ssl_check_version() < 0) { exit(EXIT_FAILURE); } #endif if (flag && (flag != 0x03)) { fprintf(stderr, "radiusd: The options -i and -p cannot be used individually.\n"); exit(EXIT_FAILURE); } if (debug_flag) { version(); } /* Read the configuration files, BEFORE doing anything else. */ if (read_mainconfig(0) < 0) { exit(EXIT_FAILURE); } #ifndef __MINGW32__ /* * Disconnect from session */ if (dont_fork == false) { pid_t pid = fork(); if (pid < 0) { ERROR("Couldn't fork: %s", fr_syserror(errno)); exit(EXIT_FAILURE); } /* * The parent exits, so the child can run in the background. */ if (pid > 0) { exit(EXIT_SUCCESS); } #ifdef HAVE_SETSID setsid(); #endif } #endif /* * Ensure that we're using the CORRECT pid after forking, * NOT the one we started with. */ radius_pid = getpid(); /* * If we're running as a daemon, close the default file * descriptors, AFTER forking. */ if (!debug_flag) { int devnull; devnull = open("/dev/null", O_RDWR); if (devnull < 0) { ERROR("Failed opening /dev/null: %s\n", fr_syserror(errno)); exit(EXIT_FAILURE); } dup2(devnull, STDIN_FILENO); if (default_log.dest == L_DST_STDOUT) { setlinebuf(stdout); default_log.fd = STDOUT_FILENO; } else { dup2(devnull, STDOUT_FILENO); } if (default_log.dest == L_DST_STDERR) { setlinebuf(stderr); default_log.fd = STDERR_FILENO; } else { dup2(devnull, STDERR_FILENO); } close(devnull); } else { setlinebuf(stdout); /* unbuffered output */ } /* * Now we have logging check that the OpenSSL */ /* * Initialize the event pool, including threads. */ radius_event_init(mainconfig.config, spawn_flag); /* * Now that we've set everything up, we can install the signal * handlers. Before this, if we get any signal, we don't know * what to do, so we might as well do the default, and die. */ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif #ifdef HAVE_SIGACTION act.sa_handler = sig_hup; sigaction(SIGHUP, &act, NULL); act.sa_handler = sig_fatal; sigaction(SIGTERM, &act, NULL); #else #ifdef SIGHUP signal(SIGHUP, sig_hup); #endif signal(SIGTERM, sig_fatal); #endif /* * If we're debugging, then a CTRL-C will cause the * server to die immediately. Use SIGTERM to shut down * the server cleanly in that case. */ if ((mainconfig.debug_memory == 1) || (debug_flag == 0)) { #ifdef HAVE_SIGACTION act.sa_handler = sig_fatal; sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); #else signal(SIGINT, sig_fatal); #ifdef SIGQUIT signal(SIGQUIT, sig_fatal); #endif #endif } /* * Everything seems to have loaded OK, exit gracefully. */ if (check_config) { DEBUG("Configuration appears to be OK"); /* for -C -m|-M */ if (mainconfig.debug_memory) { goto cleanup; } exit(EXIT_SUCCESS); } #ifdef WITH_STATS radius_stats_init(0); #endif /* * Write out the PID anyway if were in foreground mode. */ if (!dont_fork) write_pid = true; /* * Only write the PID file if we're running as a daemon. * * And write it AFTER we've forked, so that we write the * correct PID. */ if (write_pid) { FILE *fp; fp = fopen(mainconfig.pid_file, "w"); if (fp != NULL) { /* * FIXME: What about following symlinks, * and having it over-write a normal file? */ fprintf(fp, "%d\n", (int) radius_pid); fclose(fp); } else { ERROR("Failed creating PID file %s: %s\n", mainconfig.pid_file, fr_syserror(errno)); exit(EXIT_FAILURE); } } exec_trigger(NULL, NULL, "server.start", false); /* * Process requests until HUP or exit. */ while ((status = radius_event_process()) == 0x80) { #ifdef WITH_STATS radius_stats_init(1); #endif hup_mainconfig(); } if (status < 0) { ERROR("Exiting due to internal error: %s", fr_strerror()); rcode = EXIT_FAILURE; } else { INFO("Exiting normally"); } exec_trigger(NULL, NULL, "server.stop", false); /* * Ignore the TERM signal: we're * about to die. */ signal(SIGTERM, SIG_IGN); /* * Send a TERM signal to all * associated processes * (including us, which gets * ignored.) */ #ifndef __MINGW32__ if (spawn_flag) kill(-radius_pid, SIGTERM); #endif /* * We're exiting, so we can delete the PID * file. (If it doesn't exist, we can ignore * the error returned by unlink) */ if (dont_fork == false) { unlink(mainconfig.pid_file); } radius_event_free(); cleanup: /* * Detach any modules. */ detach_modules(); xlat_free(); /* modules may have xlat's */ /* * Free the configuration items. */ free_mainconfig(); rad_const_free(radius_dir); #ifdef WIN32 WSACleanup(); #endif if (memory_report) { INFO("Allocated memory at time of report:"); log_talloc_report(NULL); } return rcode; }