📄 radiusd.c
字号:
*/ if (debug_flag == 0 && dont_fork == FALSE) { pid = fork(); if(pid < 0) { radlog(L_ERR|L_CONS, "Couldn't fork"); exit(1); } /* * The parent exits, so the child can run in the background. */ if(pid > 0) { exit(0); }#ifdef HAVE_SETSID setsid();#endif } /* * Ensure that we're using the CORRECT pid after forking, * NOT the one we started with. */ radius_pid = getpid(); /* * 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|L_CONS, "Failed creating PID file %s: %s\n", mainconfig.pid_file, strerror(errno)); exit(1); } } /* * If we're running as a daemon, close the default file * descriptors, AFTER forking. */ if (debug_flag == FALSE) { int devnull; devnull = open("/dev/null", O_RDWR); if (devnull < 0) { radlog(L_ERR|L_CONS, "Failed opening /dev/null: %s\n", strerror(errno)); exit(1); } dup2(devnull, STDIN_FILENO); dup2(devnull, STDOUT_FILENO); dup2(devnull, STDERR_FILENO); close(devnull); }#ifdef HAVE_PTHREAD_H /* * If we're spawning children, set up the thread pool. */ if (spawn_flag == TRUE) { thread_pool_init(); }#else /* * Without threads, we ALWAYS run in single-server mode. */ spawn_flag = FALSE;#endif /* * Use linebuffered or unbuffered stdout if * the debug flag is on. */ if (debug_flag == TRUE) setlinebuf(stdout); /* * Print out which ports we're listening on. */ for (listener = mainconfig.listen; listener != NULL; listener = listener->next) { if (listener->ipaddr == INADDR_ANY) { strcpy((char *)buffer, "*"); } else { ip_ntoa((char *)buffer, listener->ipaddr); } switch (listener->type) { case RAD_LISTEN_AUTH: DEBUG("Listening on authentication %s:%d", buffer, listener->port); break; case RAD_LISTEN_ACCT: DEBUG("Listening on accounting %s:%d", buffer, listener->port); break; case RAD_LISTEN_PROXY: DEBUG("Listening on proxy %s:%d", buffer, listener->port); break; default: break; } } /* * 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. */ signal(SIGPIPE, SIG_IGN);#ifdef HAVE_SIGACTION act.sa_handler = sig_hup; sigaction(SIGHUP, &act, NULL); act.sa_handler = sig_fatal; sigaction(SIGTERM, &act, NULL);#else signal(SIGHUP, sig_hup); 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 (debug_flag == 0) {#ifdef HAVE_SIGACTION act.sa_handler = sig_fatal; sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL);#else signal(SIGINT, sig_fatal); signal(SIGQUIT, sig_fatal);#endif } radlog(L_INFO, "Ready to process requests."); start_time = time(NULL); /* * Receive user requests */ for (;;) { /* * If we've been told to exit, then do so, * even if we have data waiting. */ if (do_exit) { DEBUG("Exiting..."); /* * 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.) */ kill(-radius_pid, SIGTERM); /* * FIXME: Kill child threads, and * clean up? */ /* * Detach any modules. */ detach_modules(); /* * FIXME: clean up any active REQUEST * handles. */ /* * 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); } /* * Free the configuration items. */ free_mainconfig(); /* * SIGTERM gets do_exit=0, * and we want to exit cleanly. * * Other signals make us exit * with an error status. */ exit(do_exit - 1); } if (need_reload) {#ifdef HAVE_PTHREAD_H /* * Threads: wait for all threads to stop * processing before re-loading the * config, so we don't pull the rug out * from under them. */ int max_wait = 0; if (!spawn_flag) for(;;) { /* * Block until there are '0' threads * with a REQUEST handle. */ sig_hup_block = TRUE; if( (total_active_threads() == 0) || (max_wait >= 5) ) { sig_hup_block = FALSE; break; } sleep(1); max_wait++; }#endif if (read_mainconfig(TRUE) < 0) { exit(1); } /* Reload the modules. */ DEBUG2("radiusd: entering modules setup"); if (setup_modules() < 0) { radlog(L_ERR|L_CONS, "Errors setting up modules"); exit(1); } need_reload = FALSE; radlog(L_INFO, "Ready to process requests."); } FD_ZERO(&readfds); max_fd = 0; /* * Loop over all the listening FD's. */ for (listener = mainconfig.listen; listener != NULL; listener = listener->next) { FD_SET(listener->fd, &readfds); if (listener->fd > max_fd) max_fd = listener->fd; }#ifdef WITH_SNMP if (mainconfig.do_snmp && (rad_snmp.smux_fd >= 0)) { FD_SET(rad_snmp.smux_fd, &readfds); if (rad_snmp.smux_fd > max_fd) max_fd = rad_snmp.smux_fd; }#endif status = select(max_fd + 1, &readfds, NULL, NULL, tv); if (status == -1) { /* * On interrupts, we clean up the request * list. We then continue with the loop, * so that if we're supposed to exit, * then the code at the start of the loop * catches that, and exits. */ if (errno == EINTR) { tv = rl_clean_list(time(NULL)); continue; } radlog(L_ERR, "Unexpected error in select(): %s", strerror(errno)); exit(1); } time_now = time(NULL);#ifndef HAVE_PTHREAD_H /* * If there are no child threads, then there may * be child processes. In that case, wait for * their exit status, and throw that exit status * away. This helps get rid of zxombie children. */ while (waitpid(-1, &argval, WNOHANG) > 0) { /* do nothing */ }#endif /* * Loop over the open socket FD's, reading any data. */ for (listener = mainconfig.listen; listener != NULL; listener = listener->next) { RAD_REQUEST_FUNP fun; if (!FD_ISSET(listener->fd, &readfds)) continue; /* * Receive the packet. */ if (sig_hup_block != FALSE) { continue; } packet = rad_recv(listener->fd); if (packet == NULL) { radlog(L_ERR, "%s", librad_errstr); continue; } /* * If the destination IP is unknown, check * if the listener has a known IP. If so, * use that. */ if ((packet->dst_ipaddr == htonl(INADDR_ANY)) && (packet->dst_ipaddr != listener->ipaddr)) { packet->dst_ipaddr = listener->ipaddr; } /* * Fill in the destination port. */ packet->dst_port = listener->port; RAD_SNMP_TYPE_INC(listener, total_requests); /* * FIXME: Move this next check into * the packet_ok() function, and add * a 'secret' to the RAIDUS_PACKET * data structure. This involves changing * a bunch of code, but it's probably the * best thing to do. */ /* * Check if we know this client for * authentication and accounting. Check if we know * this proxy for proxying. */ if (listener->type != RAD_LISTEN_PROXY) { RADCLIENT *cl; if ((cl = client_find(packet->src_ipaddr)) == NULL) { RAD_SNMP_TYPE_INC(listener, total_invalid_requests); radlog(L_ERR, "Ignoring request from unknown client %s:%d", ip_ntoa((char *)buffer, packet->src_ipaddr), packet->src_port); rad_free(&packet); continue; } secret = cl->secret; } else { /* It came in on the proxy port */ REALM *rl; if ((rl = realm_findbyaddr(packet->src_ipaddr,packet->src_port)) == NULL) { radlog(L_ERR, "Ignoring request from unknown home server %s:%d", ip_ntoa((char *)buffer, packet->src_ipaddr), packet->src_port); rad_free(&packet); continue; } /* * The secret isn't needed here, * as it's already in the old request */ secret = NULL; } /* * Do some simple checks before we process * the request. */ if ((fun = packet_ok(packet, listener)) == NULL) { rad_free(&packet); continue; } /* * Allocate a new request for packets from * our clients, OR find the old request, * for packets which are replies from a home * server. */ request = request_ok(packet, secret, listener); if (!request) { rad_free(&packet); continue; } /* * Drop the request into the thread pool, * and let the thread pool take care of * doing something with it. */#ifdef HAVE_PTHREAD_H if (spawn_flag) { if (!thread_pool_addrequest(request, fun)) { /* * FIXME: Maybe just drop * the packet on the floor? */ request_reject(request); request->finished = TRUE; } } else#endif rad_respond(request, fun); } /* loop over listening sockets*/#ifdef WITH_SNMP if (mainconfig.do_snmp) { /* * After handling all authentication/accounting * requests, THEN process any pending SMUX/SNMP * queries. * * Note that the handling is done in the main server, * which probably isn't a Good Thing. It really * should be wrapped, and handled in a thread pool. */ if ((rad_snmp.smux_fd >= 0) && FD_ISSET(rad_snmp.smux_fd, &readfds) && (rad_snmp.smux_event == SMUX_READ)) { smux_read(); } /* * If we've got to re-connect, then do so now, * before calling select again. */ if (rad_snmp.smux_event == SMUX_CONNECT) { smux_connect(); } }#endif /* * After processing all new requests, * check if we've got to delete old requests * from the request list. */ tv = rl_clean_list(time_now);#ifdef HAVE_PTHREAD_H /* * Only clean the thread pool if we're spawning * child threads. */ if (spawn_flag) { thread_pool_clean(time_now); }#endif } /* loop forever */}/* * FIXME: The next two functions should all * be in a module. But not until we have * more control over module execution. * -jcarneal *//* * Lowercase the string value of a pair. */static int rad_lowerpair(REQUEST *request UNUSED, VALUE_PAIR *vp) { if (vp == NULL) { return -1; } rad_lowercase((char *)vp->strvalue);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -