📄 radiusd.c
字号:
/* * radiusd.c Main loop of the radius server. * * Version: $Id: radiusd.c,v 1.321.2.2 2005/04/11 23:45:21 aland Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2000,2001,2002,2003,2004 The FreeRADIUS server project * Copyright 1999,2000 Miquel van Smoorenburg <miquels@cistron.nl> * Copyright 2000 Alan DeKok <aland@ox.org> * Copyright 2000 Alan Curry <pacman-radius@cqc.com> * Copyright 2000 Jeff Carneal <jeff@apex.net> * Copyright 2000 Chad Miller <cmiller@surfsouth.com> *//* don't look here for the version, run radiusd -v or look in version.c */static const char rcsid[] ="$Id: radiusd.c,v 1.321.2.2 2005/04/11 23:45:21 aland Exp $";#include "autoconf.h"#include "libradius.h"#include <sys/file.h>#ifdef HAVE_NETINET_IN_H# include <netinet/in.h>#endif#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <ctype.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <signal.h>#ifdef HAVE_GETOPT_H# include <getopt.h>#endif#ifdef HAVE_SYS_SELECT_H# include <sys/select.h>#endif#ifdef HAVE_SYSLOG_H# include <syslog.h>#endif#ifdef HAVE_SYS_WAIT_H# include <sys/wait.h>#endif#ifndef WEXITSTATUS# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)#endif#ifndef WIFEXITED# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)#endif#include "radiusd.h"#include "rad_assert.h"#include "conffile.h"#include "modules.h"#include "request_list.h"#include "radius_snmp.h"/* * Global variables. */const char *progname = NULL;const char *radius_dir = NULL;const char *radacct_dir = NULL;const char *radlog_dir = NULL;radlog_dest_t radlog_dest = RADLOG_FILES;const char *radlib_dir = NULL;int syslog_facility;int log_stripped_names;int debug_flag = 0;int log_auth_detail = FALSE;int need_reload = FALSE;int sig_hup_block = FALSE;const char *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION ", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;static time_t time_now;static pid_t radius_pid;/* * Configuration items. */static int dont_fork = FALSE;static time_t start_time = 0;static int spawn_flag = TRUE;static int do_exit = 0;/* * Static functions. */static void usage(int);static void sig_fatal (int);static void sig_hup (int);static int rad_status_server(REQUEST *request);/* * Parse a string into a syslog facility level. */static int str2fac(const char *s){#ifdef LOG_KERN if(!strcmp(s, "kern")) return LOG_KERN; else#endif#ifdef LOG_USER if(!strcmp(s, "user")) return LOG_USER; else#endif#ifdef LOG_MAIL if(!strcmp(s, "mail")) return LOG_MAIL; else#endif#ifdef LOG_DAEMON if(!strcmp(s, "daemon")) return LOG_DAEMON; else#endif#ifdef LOG_AUTH if(!strcmp(s, "auth")) return LOG_AUTH; else#endif#ifdef LOG_SYSLOG if(!strcmp(s, "auth")) return LOG_AUTH; else#endif#ifdef LOG_LPR if(!strcmp(s, "lpr")) return LOG_LPR; else#endif#ifdef LOG_NEWS if(!strcmp(s, "news")) return LOG_NEWS; else#endif#ifdef LOG_UUCP if(!strcmp(s, "uucp")) return LOG_UUCP; else#endif#ifdef LOG_CRON if(!strcmp(s, "cron")) return LOG_CRON; else#endif#ifdef LOG_AUTHPRIV if(!strcmp(s, "authpriv")) return LOG_AUTHPRIV; else#endif#ifdef LOG_FTP if(!strcmp(s, "ftp")) return LOG_FTP; else#endif#ifdef LOG_LOCAL0 if(!strcmp(s, "local0")) return LOG_LOCAL0; else#endif#ifdef LOG_LOCAL1 if(!strcmp(s, "local1")) return LOG_LOCAL1; else#endif#ifdef LOG_LOCAL2 if(!strcmp(s, "local2")) return LOG_LOCAL2; else#endif#ifdef LOG_LOCAL3 if(!strcmp(s, "local3")) return LOG_LOCAL3; else#endif#ifdef LOG_LOCAL4 if(!strcmp(s, "local4")) return LOG_LOCAL4; else#endif#ifdef LOG_LOCAL5 if(!strcmp(s, "local5")) return LOG_LOCAL5; else#endif#ifdef LOG_LOCAL6 if(!strcmp(s, "local6")) return LOG_LOCAL6; else#endif#ifdef LOG_LOCAL7 if(!strcmp(s, "local7")) return LOG_LOCAL7; else#endif { fprintf(stderr, "%s: Error: Unknown syslog facility: %s\n", progname, s); exit(1); } /* this should never be reached */ return LOG_DAEMON;}/* * Check if an incoming request is "ok" * * It takes packets, not requests. It sees if the packet looks * OK. If so, it does a number of sanity checks on it. */static RAD_REQUEST_FUNP packet_ok(RADIUS_PACKET *packet, rad_listen_t *listener){ REQUEST *curreq; RAD_REQUEST_FUNP fun = NULL; /* * Some sanity checks, based on the packet code. */ switch(packet->code) { case PW_AUTHENTICATION_REQUEST: /* * Check for requests sent to the wrong * port, and ignore them, if so. */ if (listener->type != RAD_LISTEN_AUTH) { RAD_SNMP_INC(rad_snmp.auth.total_packets_dropped); radlog(L_ERR, "Authentication-Request sent to a non-authentication port from " "client %s:%d - ID %d : IGNORED", client_name(packet->src_ipaddr), packet->src_port, packet->id); return NULL; } fun = rad_authenticate; break; case PW_ACCOUNTING_REQUEST: /* * Check for requests sent to the wrong * port, and ignore them, if so. */ if (listener->type != RAD_LISTEN_ACCT) { RAD_SNMP_INC(rad_snmp.acct.total_packets_dropped); radlog(L_ERR, "Accounting-Request packet sent to a non-accounting port from " "client %s:%d - ID %d : IGNORED", client_name(packet->src_ipaddr), packet->src_port, packet->id); return NULL; } fun = rad_accounting; break; case PW_AUTHENTICATION_ACK: case PW_ACCESS_CHALLENGE: case PW_AUTHENTICATION_REJECT: /* * Replies NOT sent to the proxy port get * an error message logged, and the * packet is dropped. */ if (listener->type != RAD_LISTEN_PROXY) { RAD_SNMP_INC(rad_snmp.auth.total_packets_dropped); radlog(L_ERR, "Authentication reply packet code %d sent to a non-proxy reply port from " "client %s:%d - ID %d : IGNORED", packet->code, client_name(packet->src_ipaddr), packet->src_port, packet->id); return NULL; } fun = rad_authenticate; break; case PW_ACCOUNTING_RESPONSE: /* * Replies NOT sent to the proxy port get * an error message logged, and the * packet is dropped. */ if (listener->type != RAD_LISTEN_PROXY) { RAD_SNMP_INC(rad_snmp.acct.total_packets_dropped); radlog(L_ERR, "Accounting reply packet code %d sent to a non-proxy reply port from " "client %s:%d - ID %d : IGNORED", packet->code, client_name(packet->src_ipaddr), packet->src_port, packet->id); return 0; } fun = rad_accounting; break; case PW_STATUS_SERVER: if (!mainconfig.status_server) { DEBUG("WARNING: Ignoring Status-Server request due to security configuration"); return NULL; } fun = rad_status_server; break; case PW_PASSWORD_REQUEST: RAD_SNMP_INC(rad_snmp.auth.total_unknown_types); /* * We don't support this anymore. */ radlog(L_ERR, "Deprecated password change request from client %s:%d - ID %d : IGNORED", client_name(packet->src_ipaddr), packet->src_port, packet->id); return NULL; break; default: RAD_SNMP_INC(rad_snmp.auth.total_unknown_types); radlog(L_ERR, "Unknown packet code %d from client %s:%d " "- ID %d : IGNORED", packet->code, client_name(packet->src_ipaddr), packet->src_port, packet->id); return NULL; break; } /* switch over packet types */ /* * Don't handle proxy replies here. They need to * return the *old* request, so we can re-process it. */ if (listener->type == RAD_LISTEN_PROXY) { return fun; } /* * If there is no existing request of id, code, etc., * then we can return, and let it be processed. */ if ((curreq = rl_find(packet)) == NULL) { /* * Count the total number of requests, to see if * there are too many. If so, return with an * error. */ if (mainconfig.max_requests) { int request_count = rl_num_requests(); /* * This is a new request. Let's see if * it makes us go over our configured * bounds. */ if (request_count > mainconfig.max_requests) { radlog(L_ERR, "Dropping request (%d is too many): " "from client %s:%d - ID: %d", request_count, client_name(packet->src_ipaddr), packet->src_port, packet->id); radlog(L_INFO, "WARNING: Please check the radiusd.conf file.\n" "\tThe value for 'max_requests' is probably set too low.\n"); return NULL; } /* else there were a small number of requests */ } /* else there was no configured limit for requests */ /* * FIXME: Add checks for system load. If the * system is busy, start dropping requests... * * We can probably keep some statistics * ourselves... if there are more requests * coming in than we can handle, start dropping * some. */ return fun; } /* * "fake" requests MUST NEVER be in the request list. * * They're used internally in the server. Any reply * is a reply to the local server, and any proxied packet * gets sent outside of the tunnel. */ rad_assert((curreq->options & RAD_REQUEST_OPTION_FAKE_REQUEST) == 0); /* * The current request isn't finished, which * means that the NAS sent us a new packet, while * we are still processing the old request. */ if (!curreq->finished) { /* * If the authentication vectors are identical, * then the NAS is re-transmitting it, trying to * kick us into responding to the request. */ if (memcmp(curreq->packet->vector, packet->vector, sizeof(packet->vector)) == 0) { RAD_SNMP_INC(rad_snmp.auth.total_dup_requests); /* * It's not finished because the request * was proxied, but there was no reply * from the home server. */ if (curreq->proxy && !curreq->proxy_reply) { /* * We're taking care of sending * duplicate proxied packets, so * we ignore any duplicate * requests from the NAS. * * FIXME: Make it ALWAYS synchronous! */ if (!mainconfig.proxy_synchronous) { RAD_SNMP_TYPE_INC(listener, total_packets_dropped); DEBUG2("Ignoring duplicate packet from client " "%s:%d - ID: %d, due to outstanding proxied request %d.", client_name(packet->src_ipaddr), packet->src_port, packet->id, curreq->number); return NULL; /* * We ARE proxying the request, * and we have NOT received a * proxy reply yet, and we ARE * doing synchronous proxying. * * In that case, go kick * the home RADIUS server * again. */ } else { char buffer[64]; DEBUG2("Sending duplicate proxied request to home server %s:%d - ID: %d", ip_ntoa(buffer, curreq->proxy->dst_ipaddr), curreq->proxy->dst_port, curreq->proxy->id); } curreq->proxy_next_try = time_now + mainconfig.proxy_retry_delay; rad_send(curreq->proxy, curreq->packet, curreq->proxysecret); return NULL; } /* else the packet was not proxied */ /* * Someone's still working on it, so we * ignore the duplicate request. */ radlog(L_ERR, "Discarding duplicate request from " "client %s:%d - ID: %d due to unfinished request %d", client_name(packet->src_ipaddr), packet->src_port, packet->id, curreq->number); return NULL; } /* else the authentication vectors were different */ /* * The authentication vectors are different, so * the NAS has given up on us, as we've taken too * long to process the request. This is a * SERIOUS problem! */ RAD_SNMP_TYPE_INC(listener, total_packets_dropped); radlog(L_ERR, "Dropping conflicting packet from " "client %s:%d - ID: %d due to unfinished request %d", client_name(packet->src_ipaddr),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -