static void print_packet(FILE *fp, RADIUS_PACKET *packet) { VALUE_PAIR *vp; vp_cursor_t cursor; if (!packet) { fprintf(fp, "\n"); return; } fprintf(fp, "%s\n", fr_packet_codes[packet->code]); for (vp = fr_cursor_init(&cursor, &packet->vps); vp; vp = fr_cursor_next(&cursor)) { /* * Take this opportunity to verify all the VALUE_PAIRs are still valid. */ if (!talloc_get_type(vp, VALUE_PAIR)) { ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp)); log_talloc_report(vp); rad_assert(0); } vp_print(fp, vp); } fflush(fp); }
/** Print a list of valuepairs to stderr or error log. * * @param[in] vp to print. */ void debug_pair_list(VALUE_PAIR *vp) { vp_cursor_t cursor; if (!vp || !debug_flag || !fr_log_fp) return; for (vp = paircursor(&cursor, &vp); vp; vp = pairnext(&cursor)) { /* * Take this opportunity to verify all the VALUE_PAIRs are still valid. */ if (!talloc_get_type(vp, VALUE_PAIR)) { ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp)); log_talloc_report(vp); rad_assert(0); } vp_print(fr_log_fp, vp); } fflush(fr_log_fp); }
/** Print a list of valuepairs to the request list. * * @param[in] level Debug level (1-4). * @param[in] request to read logging params from. * @param[in] vp to print. */ void rdebug_pair_list(int level, REQUEST *request, VALUE_PAIR *vp) { vp_cursor_t cursor; char buffer[256]; if (!vp || !request || !request->radlog) return; for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { /* * Take this opportunity to verify all the VALUE_PAIRs are still valid. */ if (!talloc_get_type(vp, VALUE_PAIR)) { REDEBUG("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp)); log_talloc_report(vp); rad_assert(0); } vp_prints(buffer, sizeof(buffer), vp); RDEBUGX(level, "\t%s", buffer); } }
/* * 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 REQUEST *request_setup(FILE *fp) { VALUE_PAIR *vp; REQUEST *request; vp_cursor_t cursor; /* * Create and initialize the new request. */ request = request_alloc(NULL); request->packet = rad_alloc(request, 0); if (!request->packet) { ERROR("No memory"); request_free(&request); return NULL; } request->reply = rad_alloc(request, 0); if (!request->reply) { ERROR("No memory"); request_free(&request); return NULL; } request->listener = listen_alloc(request); request->client = client_alloc(request); request->number = 0; request->master_state = REQUEST_ACTIVE; request->child_state = REQUEST_RUNNING; request->handle = NULL; request->server = talloc_typed_strdup(request, "default"); request->root = &mainconfig; /* * Read packet from fp */ request->packet->vps = readvp2(request->packet, fp, &filedone, "radiusd:"); if (!request->packet->vps) { talloc_free(request); return NULL; } /* * Set the defaults for IPs, etc. */ request->packet->code = PW_CODE_AUTHENTICATION_REQUEST; request->packet->src_ipaddr.af = AF_INET; request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK); request->packet->src_port = 18120; request->packet->dst_ipaddr.af = AF_INET; request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK); request->packet->dst_port = 1812; /* * Copied from radclient */ #if 1 /* * Fix up Digest-Attributes issues */ for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) { /* * Double quoted strings get marked up as xlat expansions, * but we don't support that here. */ if (vp->type == VT_XLAT) { vp->vp_strvalue = vp->value.xlat; vp->value.xlat = NULL; vp->type = VT_DATA; } if (!vp->da->vendor) switch (vp->da->attr) { default: break; /* * Allow it to set the packet type in * the attributes read from the file. */ case PW_PACKET_TYPE: request->packet->code = vp->vp_integer; break; case PW_PACKET_DST_PORT: request->packet->dst_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_DST_IP_ADDRESS: request->packet->dst_ipaddr.af = AF_INET; request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; break; case PW_PACKET_DST_IPV6_ADDRESS: request->packet->dst_ipaddr.af = AF_INET6; request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; break; case PW_PACKET_SRC_PORT: request->packet->src_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_SRC_IP_ADDRESS: request->packet->src_ipaddr.af = AF_INET; request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; break; case PW_PACKET_SRC_IPV6_ADDRESS: request->packet->src_ipaddr.af = AF_INET6; request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; break; case PW_CHAP_PASSWORD: { int i, already_hex = 0; /* * If it's 17 octets, it *might* be already encoded. * Or, it might just be a 17-character password (maybe UTF-8) * Check it for non-printable characters. The odds of ALL * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17, * or 1/(2^51), which is pretty much zero. */ if (vp->length == 17) { for (i = 0; i < 17; i++) { if (vp->vp_octets[i] < 32) { already_hex = 1; break; } } } /* * Allow the user to specify ASCII or hex CHAP-Password */ if (!already_hex) { uint8_t *p; size_t len, len2; len = len2 = vp->length; if (len2 < 17) len2 = 17; p = talloc_zero_array(vp, uint8_t, len2); memcpy(p, vp->vp_strvalue, len); rad_chap_encode(request->packet, p, fr_rand() & 0xff, vp); vp->vp_octets = p; vp->length = 17; } } break; case PW_DIGEST_REALM: case PW_DIGEST_NONCE: case PW_DIGEST_METHOD: case PW_DIGEST_URI: case PW_DIGEST_QOP: case PW_DIGEST_ALGORITHM: case PW_DIGEST_BODY_DIGEST: case PW_DIGEST_CNONCE: case PW_DIGEST_NONCE_COUNT: case PW_DIGEST_USER_NAME: /* overlapping! */ { DICT_ATTR const *da; uint8_t *p, *q; p = talloc_array(vp, uint8_t, vp->length + 2); memcpy(p + 2, vp->vp_octets, vp->length); p[0] = vp->da->attr - PW_DIGEST_REALM + 1; vp->length += 2; p[1] = vp->length; da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0); rad_assert(da != NULL); vp->da = da; /* * Re-do pairmemsteal ourselves, * because we play games with * vp->da, and pairmemsteal goes * to GREAT lengths to sanitize * and fix and change and * double-check the various * fields. */ memcpy(&q, &vp->vp_octets, sizeof(q)); talloc_free(q); vp->vp_octets = talloc_steal(vp, p); vp->type = VT_DATA; VERIFY_VP(vp); } break; } } /* loop over the VP's we read in */ #endif if (debug_flag) { for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) { /* * Take this opportunity to verify all the VALUE_PAIRs are still valid. */ if (!talloc_get_type(vp, VALUE_PAIR)) { ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp)); log_talloc_report(vp); rad_assert(0); } vp_print(fr_log_fp, vp); } fflush(fr_log_fp); } /* * FIXME: set IPs, etc. */ request->packet->code = PW_CODE_AUTHENTICATION_REQUEST; request->packet->src_ipaddr.af = AF_INET; request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK); request->packet->src_port = 18120; request->packet->dst_ipaddr.af = AF_INET; request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK); request->packet->dst_port = 1812; /* * Build the reply template from the request. */ request->reply->sockfd = request->packet->sockfd; request->reply->dst_ipaddr = request->packet->src_ipaddr; request->reply->src_ipaddr = request->packet->dst_ipaddr; request->reply->dst_port = request->packet->src_port; request->reply->src_port = request->packet->dst_port; request->reply->id = request->packet->id; request->reply->code = 0; /* UNKNOWN code */ memcpy(request->reply->vector, request->packet->vector, sizeof(request->reply->vector)); request->reply->vps = NULL; request->reply->data = NULL; request->reply->data_len = 0; /* * Debugging */ request->options = debug_flag; request->radlog = vradlog_request; request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY); request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY); return request; }
/* * 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; int argval; int spawn_flag = TRUE; int dont_fork = 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 = strdup(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. */ mainconfig.radlog_dest = RADLOG_NULL; mainconfig.radlog_fd = -1; mainconfig.log_file = NULL; /* Process the options. */ while ((argval = getopt(argc, argv, "Cd:fhi:l:mMn:p:stvxX")) != EOF) { switch(argval) { case 'C': check_config = TRUE; spawn_flag = FALSE; dont_fork = TRUE; break; case 'd': if (radius_dir) free(radius_dir); radius_dir = strdup(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); mainconfig.radlog_dest = RADLOG_FILES; mainconfig.radlog_fd = open(mainconfig.log_file, O_WRONLY | O_APPEND | O_CREAT, 0640); if (mainconfig.radlog_fd < 0) { fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno)); exit(1); } fr_log_fp = fdopen(mainconfig.radlog_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(1); } 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(1); } flag |= 2; 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; mainconfig.radlog_dest = RADLOG_STDOUT; mainconfig.radlog_fd = STDOUT_FILENO; version(); exit(0); 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; mainconfig.radlog_dest = RADLOG_STDOUT; mainconfig.radlog_fd = STDOUT_FILENO; break; case 'x': debug_flag++; break; default: usage(1); break; } } if (memory_report) { talloc_enable_null_tracking(); 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(1); } #endif if (flag && (flag != 0x03)) { fprintf(stderr, "radiusd: The options -i and -p cannot be used individually.\n"); exit(1); } if (debug_flag) version(); /* Read the configuration files, BEFORE doing anything else. */ if (read_mainconfig(0) < 0) { exit(1); } #ifndef __MINGW32__ /* * Disconnect from session */ if (dont_fork == FALSE) { pid_t pid = fork(); if (pid < 0) { radlog(L_ERR, "Couldn't fork: %s", strerror(errno)); exit(1); } /* * The parent exits, so the child can run in the background. */ if (pid > 0) { exit(0); } #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) { radlog(L_ERR, "Failed opening /dev/null: %s\n", strerror(errno)); exit(1); } dup2(devnull, STDIN_FILENO); if (mainconfig.radlog_dest == RADLOG_STDOUT) { setlinebuf(stdout); mainconfig.radlog_fd = STDOUT_FILENO; } else { dup2(devnull, STDOUT_FILENO); } if (mainconfig.radlog_dest == RADLOG_STDERR) { setlinebuf(stderr); mainconfig.radlog_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."); exit(0); } #ifdef WITH_STATS radius_stats_init(0); #endif /* * 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 (dont_fork == FALSE) { 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 { radlog(L_ERR, "Failed creating PID file %s: %s\n", mainconfig.pid_file, strerror(errno)); exit(1); } } exec_trigger(NULL, NULL, "server.start", FALSE); /* * Process requests until HUP or exit. */ while ((rcode = radius_event_process()) == 0x80) { #ifdef WITH_STATS radius_stats_init(1); #endif hup_mainconfig(); } if (rcode < 0) { radlog(L_ERR, "Exiting due to internal error: %s", fr_strerror()); rcode = 2; } else { radlog(L_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(); /* * Detach any modules. */ detach_modules(); xlat_free(); /* modules may have xlat's */ /* * Free the configuration items. */ free_mainconfig(); free(radius_dir); #ifdef WIN32 WSACleanup(); #endif if (memory_report) { log_talloc_report(NULL); } return (rcode - 1); }