📄 realms.c
字号:
/* * realms.c Realm handling code * * Version: $Id: realms.c,v 1.52 2008/04/18 09:29:49 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2007 The FreeRADIUS server project * Copyright 2007 Alan DeKok <aland@deployingradius.com> */#include <freeradius-devel/ident.h>RCSID("$Id: realms.c,v 1.52 2008/04/18 09:29:49 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/rad_assert.h>#include <sys/stat.h>#include <ctype.h>#include <fcntl.h>#ifdef HAVE_REGEX_H#include <regex.h>/* * For POSIX Regular expressions. * (0) Means no extended regular expressions. * REG_EXTENDED means use extended regular expressions. */#ifndef REG_EXTENDED#define REG_EXTENDED (0)#endif#ifndef REG_NOSUB#define REG_NOSUB (0)#endif#ifndef REG_ICASE#define REG_ICASE (0)#endif#endifstatic rbtree_t *realms_byname = NULL;#ifdef HAVE_REGEX_Htypedef struct realm_regex_t { REALM *realm; struct realm_regex_t *next;} realm_regex_t;static realm_regex_t *realms_regex = NULL;#endif /* HAVE_REGEX_H */static rbtree_t *home_servers_byaddr = NULL;static rbtree_t *home_servers_byname = NULL;static rbtree_t *home_pools_byname = NULL;typedef struct realm_config_t { CONF_SECTION *cs; int dead_time; int retry_count; int retry_delay; int fallback; int wake_all_if_all_dead;} realm_config_t;static realm_config_t *realm_config = NULL;/* * Map the proxy server configuration parameters to variables. */static const CONF_PARSER proxy_config[] = { { "retry_delay", PW_TYPE_INTEGER, offsetof(realm_config_t, retry_delay), NULL, Stringify(RETRY_DELAY) }, { "retry_count", PW_TYPE_INTEGER, offsetof(realm_config_t, retry_count), NULL, Stringify(RETRY_COUNT) }, { "default_fallback", PW_TYPE_BOOLEAN, offsetof(realm_config_t, fallback), NULL, "no" }, { "dead_time", PW_TYPE_INTEGER, offsetof(realm_config_t, dead_time), NULL, Stringify(DEAD_TIME) }, { "wake_all_if_all_dead", PW_TYPE_BOOLEAN, offsetof(realm_config_t, wake_all_if_all_dead), NULL, "no" }, { NULL, -1, 0, NULL, NULL }};static int realm_name_cmp(const void *one, const void *two){ const REALM *a = one; const REALM *b = two; return strcasecmp(a->name, b->name);}static int home_server_name_cmp(const void *one, const void *two){ const home_server *a = one; const home_server *b = two; if (a->type < b->type) return -1; if (a->type > b->type) return +1; return strcasecmp(a->name, b->name);}static int home_server_addr_cmp(const void *one, const void *two){ const home_server *a = one; const home_server *b = two; if (a->server && !b->server) return -1; if (!a->server && b->server) return +1; if (a->server && b->server) { int rcode = a->type - b->type; if (rcode != 0) return rcode; return strcmp(a->server, b->server); } if (a->port < b->port) return -1; if (a->port > b->port) return +1; return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);}static int home_pool_name_cmp(const void *one, const void *two){ const home_pool_t *a = one; const home_pool_t *b = two; if (a->server_type < b->server_type) return -1; if (a->server_type > b->server_type) return +1; return strcasecmp(a->name, b->name);}/* * Xlat for %{home_server:foo} */static size_t xlat_home_server(UNUSED void *instance, REQUEST *request, char *fmt, char *out, size_t outlen, UNUSED RADIUS_ESCAPE_STRING func){ const char *value = NULL; CONF_PAIR *cp; if (!fmt || !out || (outlen < 1)) return 0; if (!request || !request->home_server) { *out = '\0'; return 0; } cp = cf_pair_find(request->home_server->cs, fmt); if (!cp || !(value = cf_pair_value(cp))) { *out = '\0'; return 0; } strlcpy(out, value, outlen); return strlen(out);}/* * Xlat for %{home_server_pool:foo} */static size_t xlat_server_pool(UNUSED void *instance, REQUEST *request, char *fmt, char *out, size_t outlen, UNUSED RADIUS_ESCAPE_STRING func){ const char *value = NULL; CONF_PAIR *cp; if (!fmt || !out || (outlen < 1)) return 0; if (!request || !request->home_pool) { *out = '\0'; return 0; } cp = cf_pair_find(request->home_pool->cs, fmt); if (!cp || !(value = cf_pair_value(cp))) { *out = '\0'; return 0; } strlcpy(out, value, outlen); return strlen(out);}void realms_free(void){ rbtree_free(home_servers_byname); home_servers_byname = NULL; rbtree_free(home_servers_byaddr); home_servers_byaddr = NULL; rbtree_free(home_pools_byname); home_pools_byname = NULL; rbtree_free(realms_byname); realms_byname = NULL;#ifdef HAVE_REGEX_H if (realms_regex) { realm_regex_t *this, *next; for (this = realms_regex; this != NULL; this = next) { next = this->next; free(this->realm); free(this); } }#endif free(realm_config);}static struct in_addr hs_ip4addr;static struct in6_addr hs_ip6addr;static char *hs_type = NULL;static char *hs_check = NULL;static char *hs_virtual_server = NULL;static CONF_PARSER home_server_config[] = { { "ipaddr", PW_TYPE_IPADDR, 0, &hs_ip4addr, NULL }, { "ipv6addr", PW_TYPE_IPV6ADDR, 0, &hs_ip6addr, NULL }, { "virtual_server", PW_TYPE_STRING_PTR, 0, &hs_virtual_server, NULL }, { "port", PW_TYPE_INTEGER, offsetof(home_server,port), NULL, "0" }, { "type", PW_TYPE_STRING_PTR, 0, &hs_type, NULL }, { "secret", PW_TYPE_STRING_PTR, offsetof(home_server,secret), NULL, NULL}, { "response_window", PW_TYPE_INTEGER, offsetof(home_server,response_window), NULL, "30" }, { "max_outstanding", PW_TYPE_INTEGER, offsetof(home_server,max_outstanding), NULL, "65536" }, { "zombie_period", PW_TYPE_INTEGER, offsetof(home_server,zombie_period), NULL, "40" }, { "status_check", PW_TYPE_STRING_PTR, 0, &hs_check, "none" }, { "ping_check", PW_TYPE_STRING_PTR, 0, &hs_check, "none" }, { "ping_interval", PW_TYPE_INTEGER, offsetof(home_server,ping_interval), NULL, "30" }, { "check_interval", PW_TYPE_INTEGER, offsetof(home_server,ping_interval), NULL, "30" }, { "num_answers_to_alive", PW_TYPE_INTEGER, offsetof(home_server,num_pings_to_alive), NULL, "3" }, { "num_pings_to_alive", PW_TYPE_INTEGER, offsetof(home_server,num_pings_to_alive), NULL, "3" }, { "revive_interval", PW_TYPE_INTEGER, offsetof(home_server,revive_interval), NULL, "300" }, { "status_check_timeout", PW_TYPE_INTEGER, offsetof(home_server,ping_timeout), NULL, "4" }, { "username", PW_TYPE_STRING_PTR, offsetof(home_server,ping_user_name), NULL, NULL}, { "password", PW_TYPE_STRING_PTR, offsetof(home_server,ping_user_password), NULL, NULL}, { NULL, -1, 0, NULL, NULL } /* end the list */};static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int type){ const char *name2; home_server *home; int dual = FALSE; CONF_PAIR *cp; free(hs_virtual_server); /* used only for printing during parsing */ hs_virtual_server = NULL; name2 = cf_section_name1(cs); if (!name2 || (strcasecmp(name2, "home_server") != 0)) { cf_log_err(cf_sectiontoitem(cs), "Section is not a home_server."); return 0; } name2 = cf_section_name2(cs); if (!name2) { cf_log_err(cf_sectiontoitem(cs), "Home server section is missing a name."); return 0; } home = rad_malloc(sizeof(*home)); memset(home, 0, sizeof(*home)); home->name = name2; home->cs = cs; memset(&hs_ip4addr, 0, sizeof(hs_ip4addr)); memset(&hs_ip6addr, 0, sizeof(hs_ip6addr)); cf_section_parse(cs, home, home_server_config); /* * Figure out which one to use. */ if (cf_pair_find(cs, "ipaddr")) { home->ipaddr.af = AF_INET; home->ipaddr.ipaddr.ip4addr = hs_ip4addr; } else if (cf_pair_find(cs, "ipv6addr")) { home->ipaddr.af = AF_INET6; home->ipaddr.ipaddr.ip6addr = hs_ip6addr; } else if ((cp = cf_pair_find(cs, "virtual_server")) != NULL) { home->ipaddr.af = AF_UNSPEC; home->server = cf_pair_value(cp); if (!home->server) { cf_log_err(cf_sectiontoitem(cs), "Invalid value for virtual_server"); goto error; } if (!cf_section_sub_find_name2(rc->cs, "server", home->server)) { cf_log_err(cf_sectiontoitem(cs), "No such server %s", home->server); goto error; } free(hs_type); hs_type = NULL; home->secret = strdup(""); goto skip_port; } else { cf_log_err(cf_sectiontoitem(cs), "No ipaddr, ipv6addr, or virtual_server defined for home server \"%s\".", name2); error: free(home); free(hs_type); hs_type = NULL; free(hs_check); hs_check = NULL; return 0; } if (!home->port || (home->port > 65535)) { cf_log_err(cf_sectiontoitem(cs), "No port, or invalid port defined for home server %s.", name2); goto error; } if (0) { cf_log_err(cf_sectiontoitem(cs), "Fatal error! Home server %s is ourselves!", name2); goto error; } if (!home->secret) { cf_log_err(cf_sectiontoitem(cs), "No shared secret defined for home server %s.", name2); free(home); return 0; } /* * Use a reasonable default. */ skip_port: if (!hs_type) hs_type = strdup("auth+acct"); if (strcasecmp(hs_type, "auth") == 0) { home->type = HOME_TYPE_AUTH; if (type != home->type) { cf_log_err(cf_sectiontoitem(cs), "Server pool of \"acct\" servers cannot include home server %s of type \"auth\"", name2); free(home); return 0; } } else if (strcasecmp(hs_type, "acct") == 0) { home->type = HOME_TYPE_ACCT; if (type != home->type) { cf_log_err(cf_sectiontoitem(cs), "Server pool of \"auth\" servers cannot include home server %s of type \"acct\"", name2); free(home); return 0; } } else if (strcasecmp(hs_type, "auth+acct") == 0) { home->type = HOME_TYPE_AUTH; dual = TRUE; } else { cf_log_err(cf_sectiontoitem(cs), "Invalid type \"%s\" for home server %s.", hs_type, name2); free(home); free(hs_type); hs_type = NULL; free(hs_check); hs_check = NULL; return 0; } free(hs_type); hs_type = NULL; if (!hs_check || (strcasecmp(hs_check, "none") == 0)) { home->ping_check = HOME_PING_CHECK_NONE; } else if (strcasecmp(hs_check, "status-server") == 0) { home->ping_check = HOME_PING_CHECK_STATUS_SERVER; } else if (strcasecmp(hs_check, "request") == 0) { home->ping_check = HOME_PING_CHECK_REQUEST; } else { cf_log_err(cf_sectiontoitem(cs), "Invalid ping_check \"%s\" for home server %s.", hs_check, name2); free(home); free(hs_check); hs_check = NULL; return 0; } free(hs_check); hs_check = NULL; if ((home->ping_check != HOME_PING_CHECK_NONE) && (home->ping_check != HOME_PING_CHECK_STATUS_SERVER)) { if (!home->ping_user_name) { cf_log_err(cf_sectiontoitem(cs), "You must supply a user name to enable ping checks"); free(home); return 0; } if ((home->type == HOME_TYPE_AUTH) && !home->ping_user_password) { cf_log_err(cf_sectiontoitem(cs), "You must supply a password to enable ping checks"); free(home); return 0; } } if (rbtree_finddata(home_servers_byaddr, home)) { DEBUG2("Ignoring duplicate home server %s.", name2); return 1; } if (!rbtree_insert(home_servers_byname, home)) { cf_log_err(cf_sectiontoitem(cs), "Internal error adding home server %s.", name2); free(home); return 0; } if (!rbtree_insert(home_servers_byaddr, home)) { rbtree_deletebydata(home_servers_byname, home); cf_log_err(cf_sectiontoitem(cs), "Internal error adding home server %s.", name2); free(home); return 0; } if (home->response_window < 5) home->response_window = 5; if (home->response_window > 60) home->response_window = 60; if (home->max_outstanding < 8) home->max_outstanding = 8; if (home->max_outstanding > 65536*16) home->max_outstanding = 65536*16; if (home->ping_interval < 6) home->ping_interval = 6; if (home->ping_interval > 120) home->ping_interval = 120; if (home->zombie_period < 20) home->zombie_period = 20; if (home->zombie_period > 120) home->zombie_period = 120; if (home->zombie_period < home->response_window) { home->zombie_period = home->response_window; } if (home->num_pings_to_alive < 3) home->num_pings_to_alive = 3; if (home->num_pings_to_alive > 10) home->num_pings_to_alive = 10; if (home->ping_timeout < 3) home->ping_timeout = 3; if (home->ping_timeout > 10) home->ping_timeout = 10; if (home->revive_interval < 60) home->revive_interval = 60; if (home->revive_interval > 3600) home->revive_interval = 3600; if (dual) { home_server *home2 = rad_malloc(sizeof(*home2)); memcpy(home2, home, sizeof(*home2)); home2->type = HOME_TYPE_ACCT; home2->port++; home2->ping_user_password = NULL; home2->cs = cs; if (!rbtree_insert(home_servers_byname, home2)) { cf_log_err(cf_sectiontoitem(cs), "Internal error adding home server %s.", name2); free(home2); return 0; } if (!rbtree_insert(home_servers_byaddr, home2)) { rbtree_deletebydata(home_servers_byname, home2); cf_log_err(cf_sectiontoitem(cs), "Internal error adding home server %s.", name2); free(home2); return 0; } } return 1;}static home_pool_t *server_pool_alloc(const char *name, home_pool_type_t type, int server_type, int num_home_servers){ home_pool_t *pool; pool = rad_malloc(sizeof(*pool) + (sizeof(pool->servers[0]) * num_home_servers)); if (!pool) return NULL; /* just for pairanoia */ memset(pool, 0, sizeof(*pool) + (sizeof(pool->servers[0]) * num_home_servers)); pool->name = name; pool->type = type; pool->server_type = server_type; pool->num_home_servers = num_home_servers; return pool;}static int pool_check_home_server(realm_config_t *rc, CONF_PAIR *cp, const char *name, int server_type,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -