📄 mainconfig.c
字号:
/* * mainconf.c Handle the server's configuration. * * Version: $Id: mainconfig.c,v 1.36.2.3 2004/09/30 14:49:55 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 2002 The FreeRADIUS server project * Copyright 2002 Alan DeKok <aland@ox.org> */#include "autoconf.h"#include "libradius.h"#include <stdlib.h>#include <string.h>#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#ifdef HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#include "radiusd.h"#include "rad_assert.h"#include "conffile.h"#include "token.h"#include <sys/resource.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <sys/stat.h>#include <grp.h>#include <pwd.h>#ifdef WITH_UDPFROMTO#include "udpfromto.h"#endifstruct main_config_t mainconfig;/* * Local variables for stuff. */static uid_t server_uid;static gid_t server_gid;/* * These are not used anywhere else.. */static const char *localstatedir = NULL;static const char *prefix = NULL;static int auth_port = 0;/* * Map the proxy server configuration parameters to variables. */static CONF_PARSER proxy_config[] = { { "retry_delay", PW_TYPE_INTEGER, 0, &mainconfig.proxy_retry_delay, Stringify(RETRY_DELAY) }, { "retry_count", PW_TYPE_INTEGER, 0, &mainconfig.proxy_retry_count, Stringify(RETRY_COUNT) }, { "synchronous", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_synchronous, "no" }, { "default_fallback", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_fallback, "no" }, { "dead_time", PW_TYPE_INTEGER, 0, &mainconfig.proxy_dead_time, Stringify(DEAD_TIME) }, { "post_proxy_authorize", PW_TYPE_BOOLEAN, 0, &mainconfig.post_proxy_authorize, "yes" }, { "wake_all_if_all_dead", PW_TYPE_BOOLEAN, 0, &mainconfig.wake_all_if_all_dead, "no" }, { NULL, -1, 0, NULL, NULL }};/* * Security configuration for the server. */static CONF_PARSER security_config[] = { { "max_attributes", PW_TYPE_INTEGER, 0, &librad_max_attributes, Stringify(0) }, { "reject_delay", PW_TYPE_INTEGER, 0, &mainconfig.reject_delay, Stringify(0) }, { "status_server", PW_TYPE_BOOLEAN, 0, &mainconfig.status_server, "no"}, { NULL, -1, 0, NULL, NULL }};/* * A mapping of configuration file names to internal variables */static CONF_PARSER server_config[] = { /* * FIXME: 'prefix' is the ONLY one which should be * configured at compile time. Hard-coding it here is * bad. It will be cleaned up once we clean up the * hard-coded defines for the locations of the various * files. */ { "prefix", PW_TYPE_STRING_PTR, 0, &prefix, "/usr/local"}, { "localstatedir", PW_TYPE_STRING_PTR, 0, &localstatedir, "${prefix}/var"}, { "logdir", PW_TYPE_STRING_PTR, 0, &radlog_dir, "${localstatedir}/log"}, { "libdir", PW_TYPE_STRING_PTR, 0, &radlib_dir, "${prefix}/lib"}, { "radacctdir", PW_TYPE_STRING_PTR, 0, &radacct_dir, "${logdir}/radacct" }, { "hostname_lookups", PW_TYPE_BOOLEAN, 0, &librad_dodns, "no" },#ifdef WITH_SNMP { "snmp", PW_TYPE_BOOLEAN, 0, &mainconfig.do_snmp, "no" },#endif { "max_request_time", PW_TYPE_INTEGER, 0, &mainconfig.max_request_time, Stringify(MAX_REQUEST_TIME) }, { "cleanup_delay", PW_TYPE_INTEGER, 0, &mainconfig.cleanup_delay, Stringify(CLEANUP_DELAY) }, { "max_requests", PW_TYPE_INTEGER, 0, &mainconfig.max_requests, Stringify(MAX_REQUESTS) }, { "delete_blocked_requests", PW_TYPE_INTEGER, 0, &mainconfig.kill_unresponsive_children, Stringify(FALSE) }, { "port", PW_TYPE_INTEGER, 0, &auth_port, Stringify(PW_AUTH_UDP_PORT) }, { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &mainconfig.allow_core_dumps, "no" }, { "log_stripped_names", PW_TYPE_BOOLEAN, 0, &log_stripped_names,"no" }, { "log_file", PW_TYPE_STRING_PTR, -1, &mainconfig.log_file, "${logdir}/radius.log" }, { "log_auth", PW_TYPE_BOOLEAN, -1, &mainconfig.log_auth, "no" }, { "log_auth_badpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_badpass, "no" }, { "log_auth_goodpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_goodpass, "no" }, { "pidfile", PW_TYPE_STRING_PTR, 0, &mainconfig.pid_file, "${run_dir}/radiusd.pid"}, { "bind_address", PW_TYPE_IPADDR, 0, &mainconfig.myip, "*" }, { "user", PW_TYPE_STRING_PTR, 0, &mainconfig.uid_name, NULL}, { "group", PW_TYPE_STRING_PTR, 0, &mainconfig.gid_name, NULL}, { "usercollide", PW_TYPE_BOOLEAN, 0, &mainconfig.do_usercollide, "no" }, { "lower_user", PW_TYPE_STRING_PTR, 0, &mainconfig.do_lower_user, "no" }, { "lower_pass", PW_TYPE_STRING_PTR, 0, &mainconfig.do_lower_pass, "no" }, { "nospace_user", PW_TYPE_STRING_PTR, 0, &mainconfig.do_nospace_user, "no" }, { "nospace_pass", PW_TYPE_STRING_PTR, 0, &mainconfig.do_nospace_pass, "no" }, { "checkrad", PW_TYPE_STRING_PTR, 0, &mainconfig.checkrad, "${sbindir}/checkrad" }, { "proxy_requests", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_requests, "yes" }, { "proxy", PW_TYPE_SUBSECTION, 0, proxy_config, NULL }, { "security", PW_TYPE_SUBSECTION, 0, security_config, NULL }, { "debug_level", PW_TYPE_INTEGER, 0, &mainconfig.debug_level, "0"}, { NULL, -1, 0, NULL, NULL }};/* * Xlat for %{config:section.subsection.attribute} */static int xlat_config(void *instance, REQUEST *request, char *fmt, char *out, size_t outlen, RADIUS_ESCAPE_STRING func){ CONF_SECTION *cs; CONF_PAIR *cp; char buffer[1024]; char *p, *value; const char *start = fmt; request = request; /* -Wunused */ instance = instance; /* -Wunused */ cp = NULL; cs = NULL; while (cp == NULL) { /* * Find the next section. */ for (p = buffer; (*fmt != 0) && (*fmt != '.'); p++, fmt++) { *p = *fmt; } *p = '\0'; /* * The character is a '.', find a section (as the user * has given us a subsection to find) */ if (*fmt == '.') { CONF_SECTION *next; fmt++; /* skip the period */ if (cs == NULL) { next = cf_section_find(buffer); } else { next = cf_subsection_find_next(cs, NULL, buffer); } if (next == NULL) { radlog(L_ERR, "config: No such section %s in format string %s", buffer, start); return 0; } cs = next; } else { /* no period, must be a conf-part */ cp = cf_pair_find(cs, buffer); if (cp == NULL) { radlog(L_ERR, "config: No such section %s in format string %s", buffer, start); return 0; } } } /* until cp is non-NULL */ /* * Ensure that we only copy what's necessary. * * If 'outlen' is too small, then the output is chopped to fit. */ value = cf_pair_value(cp); if (value) { if (outlen > strlen(value)) { outlen = strlen(value) + 1; } } return func(out, outlen, value);}/* * Recursively make directories. */static int r_mkdir(const char *part){ char *ptr, parentdir[500]; struct stat st; if (stat(part, &st) == 0) return(0); ptr = strrchr(part, '/'); if (ptr == part) return(0); snprintf(parentdir, (ptr - part)+1, "%s", part); if (r_mkdir(parentdir) != 0) return(1); if (mkdir(part, 0770) != 0) { fprintf(stderr, "mkdir(%s) error: %s\n", part, strerror(errno)); return(1); } return(0);}/* * Checks if the log directory is writeable by a particular user. */static int radlogdir_iswritable(const char *effectiveuser){ struct passwd *pwent; if (radlog_dir[0] != '/') return(0); if (r_mkdir(radlog_dir) != 0) return(1); /* FIXME: do we have this function? */ if (strstr(radlog_dir, "radius") == NULL) return(0); /* we have a logdir that mentions 'radius', so it's probably * safe to chown the immediate directory to be owned by the normal * process owner. we gotta do it before we give up root. -chad */ if (!effectiveuser) { return 1; } pwent = getpwnam(effectiveuser); if (pwent == NULL) /* uh oh! */ return(1); if (chown(radlog_dir, pwent->pw_uid, -1) != 0) return(1); return(0);}/* * Switch UID and GID to what is specified in the config file */static int switch_users(void){ /* Set GID. */ if (mainconfig.gid_name != NULL) { struct group *gr; gr = getgrnam(mainconfig.gid_name); if (gr == NULL) { if (errno == ENOMEM) { radlog(L_ERR|L_CONS, "Cannot switch to Group %s: out of memory", mainconfig.gid_name); } else { radlog(L_ERR|L_CONS, "Cannot switch group; %s doesn't exist", mainconfig.gid_name); } exit(1); } server_gid = gr->gr_gid; if (setgid(server_gid) < 0) { radlog(L_ERR|L_CONS, "Failed setting Group to %s: %s", mainconfig.gid_name, strerror(errno)); exit(1); } } else { server_gid = getgid(); } /* Set UID. */ if (mainconfig.uid_name != NULL) { struct passwd *pw; pw = getpwnam(mainconfig.uid_name); if (pw == NULL) { if (errno == ENOMEM) { radlog(L_ERR|L_CONS, "Cannot switch to User %s: out of memory", mainconfig.uid_name); } else { radlog(L_ERR|L_CONS, "Cannot switch user; %s doesn't exist", mainconfig.uid_name); } exit(1); } server_uid = pw->pw_uid;#ifdef HAVE_INITGROUPS if (initgroups(mainconfig.uid_name, server_gid) < 0) { if (errno != EPERM) { radlog(L_ERR|L_CONS, "Failed setting supplementary groups for User %s: %s", mainconfig.uid_name, strerror(errno)); exit(1); } }#endif if (setuid(server_uid) < 0) { radlog(L_ERR|L_CONS, "Failed setting User to %s: %s", mainconfig.uid_name, strerror(errno)); exit(1); } } return(0);}/* * Create the linked list of realms from the new configuration type * This way we don't have to change to much in the other source-files */static int generate_realms(const char *filename){ CONF_SECTION *cs; REALM *my_realms = NULL; REALM *c, **tail; char *s, *t, *authhost, *accthost; char *name2; tail = &my_realms; for (cs = cf_subsection_find_next(mainconfig.config, NULL, "realm"); cs != NULL; cs = cf_subsection_find_next(mainconfig.config, cs, "realm")) { name2 = cf_section_name2(cs); if (!name2) { radlog(L_CONS|L_ERR, "%s[%d]: Missing realm name", filename, cf_section_lineno(cs)); return -1; } /* * We've found a realm, allocate space for it */ c = rad_malloc(sizeof(REALM)); memset(c, 0, sizeof(REALM)); c->secret[0] = '\0'; /* * No authhost means LOCAL. */ if ((authhost = cf_section_value_find(cs, "authhost")) == NULL) { c->ipaddr = htonl(INADDR_NONE); c->auth_port = auth_port; } else { if ((s = strchr(authhost, ':')) != NULL) { *s++ = 0; c->auth_port = atoi(s); } else { c->auth_port = auth_port; } if (strcmp(authhost, "LOCAL") == 0) { /* * Local realms don't have an IP address, * secret, or port. */ c->ipaddr = htonl(INADDR_NONE); c->auth_port = auth_port; } else { c->ipaddr = ip_getaddr(authhost); if (c->ipaddr == htonl(INADDR_NONE)) { radlog(L_ERR, "%s[%d]: Host %s not found", filename, cf_section_lineno(cs), authhost); return -1; } } /* * Double check length, just to be sure! */ if (strlen(authhost) >= sizeof(c->server)) { radlog(L_ERR, "%s[%d]: Server name of length %d is greater than allowed: %d", filename, cf_section_lineno(cs), (int) strlen(authhost), (int) sizeof(c->server) - 1); return -1; } } /* * No accthost means LOCAL */ if ((accthost = cf_section_value_find(cs, "accthost")) == NULL) { c->acct_ipaddr = htonl(INADDR_NONE); c->acct_port = 0; } else { if ((s = strchr(accthost, ':')) != NULL) { *s++ = 0; c->acct_port = atoi(s); } else { c->acct_port = auth_port + 1; } if (strcmp(accthost, "LOCAL") == 0) { /* * Local realms don't have an IP address, * secret, or port. */ c->acct_ipaddr = htonl(INADDR_NONE); c->acct_port = 0; } else { c->acct_ipaddr = ip_getaddr(accthost); if (c->acct_ipaddr == htonl(INADDR_NONE)) { radlog(L_ERR, "%s[%d]: Host %s not found", filename, cf_section_lineno(cs), accthost); return -1; } } if (strlen(accthost) >= sizeof(c->acct_server)) { radlog(L_ERR, "%s[%d]: Server name of length %d is greater than allowed: %d", filename, cf_section_lineno(cs), (int) strlen(accthost), (int) sizeof(c->acct_server) - 1); return -1; } } if (strlen(name2) >= sizeof(c->realm)) { radlog(L_ERR, "%s[%d]: Realm name of length %d is greater than allowed %d", filename, cf_section_lineno(cs), (int) strlen(name2), (int) sizeof(c->server) - 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -