2 * realms.c Realm handling code
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2007 The FreeRADIUS server project
21 * Copyright 2007 Alan DeKok <aland@deployingradius.com>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/realms.h>
28 #include <freeradius-devel/rad_assert.h>
35 static rbtree_t *realms_byname = NULL;
37 bool home_servers_udp = false;
41 typedef struct realm_regex realm_regex_t;
43 /** Regular expression associated with a realm
47 REALM *realm; //!< The realm this regex matches.
48 regex_t *preg; //!< The pre-compiled regular expression.
49 realm_regex_t *next; //!< The next realm in the list of regular expressions.
51 static realm_regex_t *realms_regex = NULL;
52 #endif /* HAVE_REGEX */
61 bool wake_all_if_all_dead;
64 static const FR_NAME_NUMBER home_server_types[] = {
65 { "auth", HOME_TYPE_AUTH },
66 { "acct", HOME_TYPE_ACCT },
67 { "auth+acct", HOME_TYPE_AUTH_ACCT },
68 { "coa", HOME_TYPE_COA },
72 static const FR_NAME_NUMBER home_ping_check[] = {
73 { "none", HOME_PING_CHECK_NONE },
74 { "status-server", HOME_PING_CHECK_STATUS_SERVER },
75 { "request", HOME_PING_CHECK_REQUEST },
79 static const FR_NAME_NUMBER home_proto[] = {
80 { "UDP", IPPROTO_UDP },
81 { "TCP", IPPROTO_TCP },
86 static realm_config_t *realm_config = NULL;
89 static rbtree_t *home_servers_byaddr = NULL;
90 static rbtree_t *home_servers_byname = NULL;
92 static int home_server_max_number = 0;
93 static rbtree_t *home_servers_bynumber = NULL;
96 static rbtree_t *home_pools_byname = NULL;
99 * Map the proxy server configuration parameters to variables.
101 static const CONF_PARSER proxy_config[] = {
102 { "retry_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, retry_delay), STRINGIFY(RETRY_DELAY) },
104 { "retry_count", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, retry_count), STRINGIFY(RETRY_COUNT) },
106 { "default_fallback", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, fallback), "no" },
108 { "dynamic", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, dynamic), NULL },
110 { "dead_time", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, dead_time), STRINGIFY(DEAD_TIME) },
112 { "wake_all_if_all_dead", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, wake_all_if_all_dead), "no" },
113 CONF_PARSER_TERMINATOR
117 static int realm_name_cmp(void const *one, void const *two)
119 REALM const *a = one;
120 REALM const *b = two;
122 return strcasecmp(a->name, b->name);
127 static void home_server_free(void *data)
129 home_server_t *home = talloc_get_type_abort(data, home_server_t);
134 static int home_server_name_cmp(void const *one, void const *two)
136 home_server_t const *a = one;
137 home_server_t const *b = two;
139 if (a->type < b->type) return -1;
140 if (a->type > b->type) return +1;
142 return strcasecmp(a->name, b->name);
145 static int home_server_addr_cmp(void const *one, void const *two)
148 home_server_t const *a = one;
149 home_server_t const *b = two;
151 if (a->server && !b->server) return -1;
152 if (!a->server && b->server) return +1;
153 if (a->server && b->server) {
154 rcode = a->type - b->type;
155 if (rcode != 0) return rcode;
156 return strcmp(a->server, b->server);
159 if (a->port < b->port) return -1;
160 if (a->port > b->port) return +1;
163 if (a->proto < b->proto) return -1;
164 if (a->proto > b->proto) return +1;
167 rcode = fr_ipaddr_cmp(&a->src_ipaddr, &b->src_ipaddr);
168 if (rcode != 0) return rcode;
170 return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
174 static int home_server_number_cmp(void const *one, void const *two)
176 home_server_t const *a = one;
177 home_server_t const *b = two;
179 return (a->number - b->number);
183 static int home_pool_name_cmp(void const *one, void const *two)
185 home_pool_t const *a = one;
186 home_pool_t const *b = two;
188 if (a->server_type < b->server_type) return -1;
189 if (a->server_type > b->server_type) return +1;
191 return strcasecmp(a->name, b->name);
195 static size_t CC_HINT(nonnull) xlat_cs(CONF_SECTION *cs, char const *fmt, char *out, size_t outlen)
197 char const *value = NULL;
202 if (strcmp(fmt, "instance") == 0) {
203 value = cf_section_name2(cs);
211 cp = cf_pair_find(cs, fmt);
212 if (!cp || !(value = cf_pair_value(cp))) {
218 strlcpy(out, value, outlen);
225 * Xlat for %{home_server:foo}
227 static ssize_t CC_HINT(nonnull) xlat_home_server(UNUSED void *instance, REQUEST *request,
228 char const *fmt, char *out, size_t outlen)
230 if (!request->home_server) {
231 RWDEBUG("No home_server associated with this request");
237 return xlat_cs(request->home_server->cs, fmt, out, outlen);
242 * Xlat for %{home_server_pool:foo}
244 static ssize_t CC_HINT(nonnull) xlat_server_pool(UNUSED void *instance, REQUEST *request,
245 char const *fmt, char *out, size_t outlen)
247 if (!request->home_pool) {
248 RWDEBUG("No home_pool associated with this request");
254 return xlat_cs(request->home_pool->cs, fmt, out, outlen);
258 void realms_free(void)
262 rbtree_free(home_servers_bynumber);
263 home_servers_bynumber = NULL;
266 rbtree_free(home_servers_byname);
267 home_servers_byname = NULL;
269 rbtree_free(home_servers_byaddr);
270 home_servers_byaddr = NULL;
272 rbtree_free(home_pools_byname);
273 home_pools_byname = NULL;
276 rbtree_free(realms_byname);
277 realms_byname = NULL;
279 realm_pool_free(NULL);
281 talloc_free(realm_config);
287 static CONF_PARSER limit_config[] = {
288 { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.max_connections), "16" },
289 { "max_requests", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.max_requests), "0" },
290 { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.lifetime), "0" },
291 { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.idle_timeout), "0" },
292 CONF_PARSER_TERMINATOR
296 static CONF_PARSER home_server_coa[] = {
297 { "irt", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_irt), STRINGIFY(2) },
298 { "mrt", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrt), STRINGIFY(16) },
299 { "mrc", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrc), STRINGIFY(5) },
300 { "mrd", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrd), STRINGIFY(30) },
301 CONF_PARSER_TERMINATOR
305 static CONF_PARSER home_server_config[] = {
306 { "ipaddr", FR_CONF_OFFSET(PW_TYPE_COMBO_IP_ADDR, home_server_t, ipaddr), NULL },
307 { "ipv4addr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, home_server_t, ipaddr), NULL },
308 { "ipv6addr", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, home_server_t, ipaddr), NULL },
309 { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, server), NULL },
311 { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, home_server_t, port), "0" },
313 { "type", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, type_str), NULL },
316 { "proto", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, proto_str), NULL },
319 { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, home_server_t, secret), NULL },
321 { "src_ipaddr", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, src_ipaddr_str), NULL },
323 { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, home_server_t, response_window), "30" },
324 { "response_timeouts", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, max_response_timeouts), "1" },
325 { "max_outstanding", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, max_outstanding), "65536" },
327 { "zombie_period", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, zombie_period), "40" },
329 { "status_check", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, ping_check_str), "none" },
330 { "ping_check", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, ping_check_str), NULL },
332 { "ping_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_interval), "30" },
333 { "check_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_interval), NULL },
335 { "check_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_timeout), "4" },
336 { "status_check_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_timeout), NULL },
338 { "num_answers_to_alive", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, num_pings_to_alive), "3" },
339 { "revive_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, revive_interval), "300" },
341 { "username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, ping_user_name), NULL },
342 { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, ping_user_password), NULL },
345 { "historic_average_window", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ema.window), NULL },
348 { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
351 { "coa", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) home_server_coa },
354 CONF_PARSER_TERMINATOR
358 static void null_free(UNUSED void *data)
363 * Ensure that all of the parameters in the home server are OK.
365 void realm_home_server_sanitize(home_server_t *home, CONF_SECTION *cs)
367 CONF_SECTION *parent = NULL;
369 FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, >=, 8);
370 FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, <=, 65536*16);
372 FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, >=, 6);
373 FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, <=, 120);
375 FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, >=, 0, 1000);
376 FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=, 60, 0);
377 FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=,
378 main_config.max_request_time, 0);
380 FR_INTEGER_BOUND_CHECK("response_timeouts", home->max_response_timeouts, >=, 1);
381 FR_INTEGER_BOUND_CHECK("response_timeouts", home->max_response_timeouts, <=, 1000);
384 * Track the minimum response window, so that we can
385 * correctly set the timers in process.c
387 if (timercmp(&main_config.init_delay, &home->response_window, >)) {
388 main_config.init_delay = home->response_window;
391 FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, 1);
392 FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, <=, 120);
393 FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, (uint32_t) home->response_window.tv_sec);
395 FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, >=, 3);
396 FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, <=, 10);
398 FR_INTEGER_BOUND_CHECK("check_timeout", home->ping_timeout, >=, 1);
399 FR_INTEGER_BOUND_CHECK("check_timeout", home->ping_timeout, <=, 10);
401 FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, >=, 60);
402 FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, <=, 3600);
405 FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, >=, 1);
406 FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, <=, 5);
408 FR_INTEGER_BOUND_CHECK("coa_mrc", home->coa_mrc, <=, 20);
410 FR_INTEGER_BOUND_CHECK("coa_mrt", home->coa_mrt, <=, 30);
412 FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, >=, 5);
413 FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, <=, 60);
416 FR_INTEGER_BOUND_CHECK("max_connections", home->limit.max_connections, <=, 1024);
420 * UDP sockets can't be connection limited.
422 if (home->proto != IPPROTO_TCP) home->limit.max_connections = 0;
425 if ((home->limit.idle_timeout > 0) && (home->limit.idle_timeout < 5))
426 home->limit.idle_timeout = 5;
427 if ((home->limit.lifetime > 0) && (home->limit.lifetime < 5))
428 home->limit.lifetime = 5;
429 if ((home->limit.lifetime > 0) && (home->limit.idle_timeout > home->limit.lifetime))
430 home->limit.idle_timeout = 0;
433 * Make sure that this is set.
435 if (home->src_ipaddr.af == AF_UNSPEC) {
436 home->src_ipaddr.af = home->ipaddr.af;
439 parent = cf_item_parent(cf_section_to_item(cs));
440 if (parent && strcmp(cf_section_name1(parent), "server") == 0) {
441 home->parent_server = cf_section_name2(parent);
445 /** Insert a new home server into the various internal lookup trees
447 * @param home server to add.
448 * @param cs That defined the home server.
449 * @return true on success else false.
451 static bool home_server_insert(home_server_t *home, CONF_SECTION *cs)
453 if (home->name && !rbtree_insert(home_servers_byname, home)) {
454 cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
458 if (!home->server && !rbtree_insert(home_servers_byaddr, home)) {
459 rbtree_deletebydata(home_servers_byname, home);
460 cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
465 home->number = home_server_max_number++;
466 if (!rbtree_insert(home_servers_bynumber, home)) {
467 rbtree_deletebydata(home_servers_byname, home);
468 if (home->ipaddr.af != AF_UNSPEC) {
469 rbtree_deletebydata(home_servers_byname, home);
471 cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
479 /** Add an already allocate home_server_t to the various trees
481 * @param home server to add.
482 * @return true on success, else false on error.
484 bool realm_home_server_add(home_server_t *home)
487 * The structs aren't mutex protected. Refuse to destroy
490 if (event_loop_started && !realm_config->dynamic) {
491 ERROR("Failed to add dynamic home server, \"dynamic = yes\" must be set in proxy.conf");
495 if (home->name && (rbtree_finddata(home_servers_byname, home) != NULL)) {
496 cf_log_err_cs(home->cs, "Duplicate home server name %s", home->name);
500 if (!home->server && (rbtree_finddata(home_servers_byaddr, home) != NULL)) {
501 char buffer[INET6_ADDRSTRLEN + 3];
503 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr, buffer, sizeof(buffer));
505 cf_log_err_cs(home->cs, "Duplicate home server address%s%s%s: %s:%s%s/%i",
506 home->name ? " (already in use by" : "",
507 home->name ? home->name : "",
508 home->name ? ")" : "",
510 fr_int2str(home_proto, home->proto, "<INVALID>"),
512 home->tls ? "+tls" : "",
521 if (!home_server_insert(home, home->cs)) return false;
524 * Dual home servers cause us to auto-create an
525 * accounting server for UDP sockets, and leave
526 * everything alone for TLS sockets.
533 home_server_t *home2 = talloc(talloc_parent(home), home_server_t);
535 memcpy(home2, home, sizeof(*home2));
537 home2->type = HOME_TYPE_ACCT;
541 home2->ping_user_password = NULL;
542 home2->cs = home->cs;
543 home2->parent_server = home->parent_server;
545 if (!home_server_insert(home2, home->cs)) {
552 * Mark it as already processed
554 cf_data_add(home->cs, "home_server", (void *)null_free, null_free);
559 /** Alloc a new home server defined by a CONF_SECTION
561 * @param ctx to allocate home_server_t in.
562 * @param rc Realm config, may be NULL in which case the global realm_config will be used.
563 * @param cs Configuration section containing home server parameters.
564 * @return a new home_server_t alloced in the context of the realm_config, or NULL on error.
566 home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SECTION *cs)
571 if (!rc) rc = realm_config; /* Use the global config */
573 home = talloc_zero(ctx, home_server_t);
574 home->name = cf_section_name2(cs);
575 home->log_name = talloc_typed_strdup(home, home->name);
577 home->state = HOME_STATE_UNKNOWN;
578 home->proto = IPPROTO_UDP;
581 * Parse the configuration into the home server
584 if (cf_section_parse(cs, home, home_server_config) < 0) goto error;
587 * It has an IP address, it must be a remote server.
589 if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
590 if (fr_inaddr_any(&home->ipaddr) == 1) {
591 cf_log_err_cs(cs, "Wildcard '*' addresses are not permitted for home servers");
595 if (!home->log_name) {
596 char buffer[INET6_ADDRSTRLEN + 3];
598 fr_ntop(buffer, sizeof(buffer), &home->ipaddr);
600 home->log_name = talloc_asprintf(home, "%s:%i", buffer, home->port);
603 * If it has a 'virtual_Server' config item, it's
604 * a loopback into a virtual server.
606 } else if (cf_pair_find(cs, "virtual_server") != NULL) {
607 home->ipaddr.af = AF_UNSPEC; /* mark ipaddr as unused */
610 cf_log_err_cs(cs, "Invalid value for virtual_server");
615 * Try and find a 'server' section off the root of
616 * the config with a name that matches the
619 if (!cf_section_sub_find_name2(rc->cs, "server", home->server)) {
620 cf_log_err_cs(cs, "No such server %s", home->server);
625 home->log_name = talloc_typed_strdup(home, home->server);
627 * Otherwise it's an invalid config section and we
631 cf_log_err_cs(cs, "No ipaddr, ipv4addr, ipv6addr, or virtual_server defined "
639 home_type_t type = HOME_TYPE_AUTH_ACCT;
641 if (home->type_str) type = fr_str2int(home_server_types, home->type_str, HOME_TYPE_INVALID);
646 case HOME_TYPE_AUTH_ACCT:
656 if (home->server != NULL) {
657 cf_log_err_cs(cs, "Home servers of type \"coa\" cannot point to a virtual server");
663 case HOME_TYPE_INVALID:
664 cf_log_err_cs(cs, "Invalid type \"%s\" for home server %s", home->type_str, home->log_name);
670 home_ping_check_t type = HOME_PING_CHECK_NONE;
672 if (home->ping_check_str) type = fr_str2int(home_ping_check, home->ping_check_str,
673 HOME_PING_CHECK_INVALID);
676 case HOME_PING_CHECK_STATUS_SERVER:
677 case HOME_PING_CHECK_NONE:
680 case HOME_PING_CHECK_REQUEST:
681 if (!home->ping_user_name) {
682 cf_log_err_cs(cs, "You must supply a 'username' to enable status_check=request");
686 if ((home->type == HOME_TYPE_AUTH) && !home->ping_user_password) {
687 cf_log_err_cs(cs, "You must supply a 'password' to enable status_check=request");
693 case HOME_PING_CHECK_INVALID:
694 cf_log_err_cs(cs, "Invalid status_check \"%s\" for home server %s",
695 home->ping_check_str, home->log_name);
699 home->ping_check = type;
703 int proto = IPPROTO_UDP;
705 if (home->proto_str) proto = fr_str2int(home_proto, home->proto_str, -1);
709 home_servers_udp = true;
714 cf_log_err_cs(cs, "Server not built with support for RADIUS over TCP");
717 if (home->ping_check != HOME_PING_CHECK_NONE) {
718 cf_log_err_cs(cs, "Only 'status_check = none' is allowed for home "
719 "servers with 'proto = tcp'");
725 cf_log_err_cs(cs, "Unknown proto \"%s\"", home->proto_str);
732 if (!home->server && rbtree_finddata(home_servers_byaddr, home)) {
733 cf_log_err_cs(cs, "Duplicate home server");
738 * Check the TLS configuration.
740 tls = cf_section_sub_find(cs, "tls");
743 cf_log_err_cs(cs, "TLS transport is not available in this executable");
749 * If were doing RADSEC (tls+tcp) the secret should default
750 * to radsec, else a secret must be set.
754 if (tls && (home->proto == IPPROTO_TCP)) {
755 home->secret = "radsec";
759 cf_log_err_cs(cs, "No shared secret defined for home server %s", home->log_name);
765 * Virtual servers have some TLS restrictions.
769 cf_log_err_cs(cs, "Virtual home_servers cannot have a \"tls\" subsection");
774 * If the home is not a virtual server, guess the port
775 * and look up the source ip address.
777 rad_assert(home->ipaddr.af != AF_UNSPEC);
780 if (tls && (home->proto != IPPROTO_TCP)) {
781 cf_log_err_cs(cs, "TLS transport is not available for UDP sockets");
787 * Set the default port if necessary.
789 if (home->port == 0) {
790 char buffer[INET6_ADDRSTRLEN + 3];
793 * For RADSEC we use the special RADIUS over TCP/TLS port
794 * for both accounting and authentication, but for some
795 * bizarre reason for RADIUS over plain TCP we use separate
796 * ports 1812 and 1813.
800 home->port = PW_RADIUS_TLS_PORT;
803 switch (home->type) {
809 home->port = PW_AUTH_UDP_PORT;
813 home->port = PW_ACCT_UDP_PORT;
817 home->port = PW_COA_UDP_PORT;
822 * Now that we have a real port, use that.
824 rad_const_free(home->log_name);
826 fr_ntop(buffer, sizeof(buffer), &home->ipaddr);
828 home->log_name = talloc_asprintf(home, "%s:%i", buffer, home->port);
832 * If we have a src_ipaddr_str resolve it to
833 * the same address family as the destination
836 if (home->src_ipaddr_str) {
837 if (ip_hton(&home->src_ipaddr, home->ipaddr.af, home->src_ipaddr_str, false) < 0) {
838 cf_log_err_cs(cs, "Failed parsing src_ipaddr");
842 * Source isn't specified, set it to the
843 * correct address family, but leave it as
847 home->src_ipaddr.af = home->ipaddr.af;
852 * Parse the SSL client configuration.
855 home->tls = tls_client_conf_parse(tls);
861 } /* end of parse home server */
863 realm_home_server_sanitize(home, cs);
868 /** Fixup a client configuration section to specify a home server
870 * This is used to create the equivalent CoA home server entry for a client,
871 * so that the server can originate CoA messages.
873 * The server section automatically inherits the following fields from the client:
874 * - ipaddr/ipv4addr/ipv6addr
878 * @note new CONF_SECTION will be allocated in the context of the client, but the client
879 * CONF_SECTION will not be modified.
881 * @param client CONF_SECTION to inherit values from.
882 * @return a new server CONF_SCTION, or a pointer to the existing CONF_SECTION in the client.
884 CONF_SECTION *home_server_cs_afrom_client(CONF_SECTION *client)
886 CONF_SECTION *server, *cs;
890 * Alloc a plain home server for both cases
892 * There's no way these can be referenced by a pool,
893 * and they may conflict with home servers in proxy.conf
894 * so it's easier to not set a name.
899 * Duplicate the server section, so we don't mangle
900 * the client CONF_SECTION we were passed.
902 cs = cf_section_sub_find(client, "coa_server");
904 server = cf_section_dup(client, cs, "home_server", NULL, true);
906 server = cf_section_alloc(client, "home_server", NULL);
909 if (!cs || (!cf_pair_find(cs, "ipaddr") && !cf_pair_find(cs, "ipv4addr") && !cf_pair_find(cs, "ipv6addr"))) {
910 cp = cf_pair_find(client, "ipaddr");
911 if (!cp) cp = cf_pair_find(client, "ipv4addr");
912 if (!cp) cp = cf_pair_find(client, "ipv6addr");
914 cf_pair_add(server, cf_pair_dup(server, cp));
917 if (!cs || !cf_pair_find(cs, "secret")) {
918 cp = cf_pair_find(client, "secret");
919 if (cp) cf_pair_add(server, cp);
922 if (!cs || !cf_pair_find(cs, "src_ipaddr")) {
923 cp = cf_pair_find(client, "src_ipaddr");
924 if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
927 if (!cs || !(cp = cf_pair_find(cs, "type"))) {
928 cp = cf_pair_alloc(server, "type", "coa", T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
929 if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
930 } else if (strcmp(cf_pair_value(cp), "coa") != 0) {
932 cf_log_err_cs(server, "server.type must be \"coa\"");
939 static home_pool_t *server_pool_alloc(char const *name, home_pool_type_t type,
940 home_type_t server_type, int num_home_servers)
944 pool = rad_malloc(sizeof(*pool) + (sizeof(pool->servers[0]) * num_home_servers));
945 if (!pool) return NULL; /* just for pairanoia */
947 memset(pool, 0, sizeof(*pool) + (sizeof(pool->servers[0]) * num_home_servers));
951 pool->server_type = server_type;
952 pool->num_home_servers = num_home_servers;
958 * Ensure any home_server clauses in a home_server_pool section reference
959 * defined home servers, which should already have been created, regardless
960 * of where they appear in the configuration.
962 static int pool_check_home_server(UNUSED realm_config_t *rc, CONF_PAIR *cp,
963 char const *name, home_type_t server_type,
964 home_server_t **phome)
966 home_server_t myhome, *home;
970 "No value given for home_server");
975 myhome.type = server_type;
976 home = rbtree_finddata(home_servers_byname, &myhome);
982 switch (server_type) {
985 myhome.type = HOME_TYPE_AUTH_ACCT;
986 home = rbtree_finddata(home_servers_byname, &myhome);
997 cf_log_err_cp(cp, "Unknown home_server \"%s\".", name);
1002 #ifndef HAVE_PTHREAD_H
1003 void realm_pool_free(home_pool_t *pool)
1005 if (!event_loop_started) return;
1006 if (!realm_config->dynamic) return;
1010 #else /* HAVE_PTHREAD_H */
1011 typedef struct pool_list_t pool_list_t;
1013 struct pool_list_t {
1019 static bool pool_free_init = false;
1020 static pthread_mutex_t pool_free_mutex;
1021 static pool_list_t *pool_list = NULL;
1023 void realm_pool_free(home_pool_t *pool)
1027 pool_list_t *this, **last;
1029 if (!event_loop_started) return;
1030 if (!realm_config->dynamic) return;
1034 * Double-check that the realm wasn't loaded from the
1035 * configuration files.
1037 for (i = 0; i < pool->num_home_servers; i++) {
1038 if (pool->servers[i]->cs) {
1045 if (!pool_free_init) {
1046 pthread_mutex_init(&pool_free_mutex, NULL);
1047 pool_free_init = true;
1051 * Ensure only one caller at a time is freeing a pool.
1053 pthread_mutex_lock(&pool_free_mutex);
1056 * Free all of the pools.
1059 while ((this = pool_list) != NULL) {
1060 pool_list = this->next;
1061 talloc_free(this->pool);
1064 pthread_mutex_unlock(&pool_free_mutex);
1071 * Free the oldest pool(s)
1073 while ((this = pool_list) != NULL) {
1074 if (this->when > now) break;
1076 pool_list = this->next;
1077 talloc_free(this->pool);
1082 * Add this pool to the end of the list.
1084 for (last = &pool_list;
1086 last = &((*last))->next) {
1090 *last = this = talloc(NULL, pool_list_t);
1092 talloc_free(pool); /* hope for the best */
1093 pthread_mutex_unlock(&pool_free_mutex);
1098 this->when = now + 60;
1100 pthread_mutex_unlock(&pool_free_mutex);
1102 #endif /* HAVE_PTHREAD_H */
1104 int realm_pool_add(home_pool_t *pool, UNUSED CONF_SECTION *cs)
1107 * The structs aren't mutex protected. Refuse to destroy
1110 if (event_loop_started && !realm_config->dynamic) {
1111 DEBUG("Must set \"dynamic = true\" in proxy.conf");
1115 if (!rbtree_insert(home_pools_byname, pool)) {
1116 rad_assert("Internal sanity check failed" == NULL);
1123 static int server_pool_add(realm_config_t *rc,
1124 CONF_SECTION *cs, home_type_t server_type, bool do_print)
1127 home_pool_t *pool = NULL;
1130 int num_home_servers;
1131 home_server_t *home;
1133 name2 = cf_section_name1(cs);
1134 if (!name2 || ((strcasecmp(name2, "server_pool") != 0) &&
1135 (strcasecmp(name2, "home_server_pool") != 0))) {
1137 "Section is not a home_server_pool");
1141 name2 = cf_section_name2(cs);
1144 "Server pool section is missing a name");
1149 * Count the home servers and initalize them.
1151 num_home_servers = 0;
1152 for (cp = cf_pair_find(cs, "home_server");
1154 cp = cf_pair_find_next(cs, cp, "home_server")) {
1157 if (!pool_check_home_server(rc, cp, cf_pair_value(cp),
1158 server_type, &home)) {
1163 if (num_home_servers == 0) {
1165 "No home servers defined in pool %s",
1170 pool = server_pool_alloc(name2, HOME_POOL_FAIL_OVER, server_type,
1173 cf_log_err_cs(cs, "Failed allocating memory for pool");
1180 * Fallback servers must be defined, and must be
1183 cp = cf_pair_find(cs, "fallback");
1186 if (server_type == HOME_TYPE_COA) {
1187 cf_log_err_cs(cs, "Home server pools of type \"coa\" cannot have a fallback virtual server");
1192 if (!pool_check_home_server(rc, cp, cf_pair_value(cp), server_type, &pool->fallback)) {
1196 if (!pool->fallback->server) {
1197 cf_log_err_cs(cs, "Fallback home_server %s does NOT contain a virtual_server directive",
1198 pool->fallback->log_name);
1203 if (do_print) cf_log_info(cs, " home_server_pool %s {", name2);
1205 cp = cf_pair_find(cs, "type");
1207 static FR_NAME_NUMBER pool_types[] = {
1208 { "load-balance", HOME_POOL_LOAD_BALANCE },
1210 { "fail-over", HOME_POOL_FAIL_OVER },
1211 { "fail_over", HOME_POOL_FAIL_OVER },
1213 { "round-robin", HOME_POOL_LOAD_BALANCE },
1214 { "round_robin", HOME_POOL_LOAD_BALANCE },
1216 { "client-balance", HOME_POOL_CLIENT_BALANCE },
1217 { "client-port-balance", HOME_POOL_CLIENT_PORT_BALANCE },
1218 { "keyed-balance", HOME_POOL_KEYED_BALANCE },
1222 value = cf_pair_value(cp);
1225 "No value given for type");
1229 pool->type = fr_str2int(pool_types, value, 0);
1232 "Unknown type \"%s\".",
1237 if (do_print) cf_log_info(cs, "\ttype = %s", value);
1240 cp = cf_pair_find(cs, "virtual_server");
1242 pool->virtual_server = cf_pair_value(cp);
1243 if (!pool->virtual_server) {
1244 cf_log_err_cp(cp, "No value given for virtual_server");
1249 cf_log_info(cs, "\tvirtual_server = %s", pool->virtual_server);
1252 if (!cf_section_sub_find_name2(rc->cs, "server", pool->virtual_server)) {
1253 cf_log_err_cp(cp, "No such server %s", pool->virtual_server);
1259 num_home_servers = 0;
1260 for (cp = cf_pair_find(cs, "home_server");
1262 cp = cf_pair_find_next(cs, cp, "home_server")) {
1263 home_server_t myhome;
1265 value = cf_pair_value(cp);
1267 memset(&myhome, 0, sizeof(myhome));
1268 myhome.name = value;
1269 myhome.type = server_type;
1271 home = rbtree_finddata(home_servers_byname, &myhome);
1273 switch (server_type) {
1274 case HOME_TYPE_AUTH:
1275 case HOME_TYPE_ACCT:
1276 myhome.type = HOME_TYPE_AUTH_ACCT;
1277 home = rbtree_finddata(home_servers_byname, &myhome);
1286 ERROR("Failed to find home server %s", value);
1290 if (do_print) cf_log_info(cs, "\thome_server = %s", home->name);
1291 pool->servers[num_home_servers++] = home;
1292 } /* loop over home_server's */
1294 if (pool->fallback && do_print) {
1295 cf_log_info(cs, "\tfallback = %s", pool->fallback->name);
1298 if (!realm_pool_add(pool, cs)) goto error;
1300 if (do_print) cf_log_info(cs, " }");
1302 cf_data_add(cs, "home_server_pool", pool, free);
1304 rad_assert(pool->server_type != 0);
1309 if (do_print) cf_log_info(cs, " }");
1315 static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
1317 char const *name, char const *secret,
1318 home_pool_type_t ldflag, home_pool_t **pool_p,
1319 home_type_t type, char const *server)
1322 int i, insert_point, num_home_servers;
1323 home_server_t myhome, *home;
1324 home_pool_t mypool, *pool;
1325 CONF_SECTION *subcs;
1327 (void) rc; /* -Wunused */
1336 * LOCAL realms get sanity checked, and nothing else happens.
1338 if (strcmp(name, "LOCAL") == 0) {
1340 cf_log_err_cs(cs, "Realm \"%s\" cannot be both LOCAL and remote", name);
1347 return 0; /* Not proxying. Can't do non-LOCAL realms */
1350 mypool.name = realm;
1351 mypool.server_type = type;
1352 pool = rbtree_finddata(home_pools_byname, &mypool);
1354 if (pool->type != ldflag) {
1355 cf_log_err_cs(cs, "Inconsistent ldflag for server pool \"%s\"", name);
1359 if (pool->server_type != type) {
1360 cf_log_err_cs(cs, "Inconsistent home server type for server pool \"%s\"", name);
1367 home = rbtree_finddata(home_servers_byname, &myhome);
1369 WARN("Please use pools instead of authhost and accthost");
1371 if (secret && (strcmp(home->secret, secret) != 0)) {
1372 cf_log_err_cs(cs, "Inconsistent shared secret for home server \"%s\"", name);
1376 if (home->type != type) {
1377 cf_log_err_cs(cs, "Inconsistent type for home server \"%s\"", name);
1382 * See if the home server is already listed
1383 * in the pool. If so, do nothing else.
1385 if (pool) for (i = 0; i < pool->num_home_servers; i++) {
1386 if (pool->servers[i] == home) {
1393 * If we do have a pool, check that there is room to
1394 * insert the home server we've found, or the one that we
1397 * Note that we insert it into the LAST available
1398 * position, in order to maintain the same order as in
1399 * the configuration files.
1403 for (i = pool->num_home_servers - 1; i >= 0; i--) {
1404 if (pool->servers[i]) break;
1406 if (!pool->servers[i]) {
1411 if (insert_point < 0) {
1412 cf_log_err_cs(cs, "No room in pool to add home server \"%s\". Please update the realm configuration to use the new-style home servers and server pools.", name);
1418 * No home server, allocate one.
1424 home = talloc_zero(rc, home_server_t);
1427 home->secret = secret;
1429 home->proto = IPPROTO_UDP;
1431 p = strchr(name, ':');
1433 if (type == HOME_TYPE_AUTH) {
1434 home->port = PW_AUTH_UDP_PORT;
1436 home->port = PW_ACCT_UDP_PORT;
1442 } else if (p == name) {
1443 cf_log_err_cs(cs, "Invalid hostname %s", name);
1447 unsigned long port = strtoul(p + 1, NULL, 0);
1448 if ((port == 0) || (port > 65535)) {
1449 cf_log_err_cs(cs, "Invalid port %s", p + 1);
1454 home->port = (uint16_t)port;
1455 q = talloc_array(home, char, (p - name) + 1);
1456 memcpy(q, name, (p - name));
1462 if (ip_hton(&home->ipaddr, AF_UNSPEC, p, false) < 0) {
1464 "Failed looking up hostname %s.",
1470 home->src_ipaddr.af = home->ipaddr.af;
1472 home->ipaddr.af = AF_UNSPEC;
1473 home->server = server;
1478 * Use the old-style configuration.
1480 home->max_outstanding = 65535*16;
1481 home->zombie_period = rc->retry_delay * rc->retry_count;
1482 if (home->zombie_period < 2) home->zombie_period = 30;
1483 home->response_window.tv_sec = home->zombie_period - 1;
1484 home->response_window.tv_usec = 0;
1486 home->ping_check = HOME_PING_CHECK_NONE;
1488 home->revive_interval = rc->dead_time;
1490 if (rbtree_finddata(home_servers_byaddr, home)) {
1491 cf_log_err_cs(cs, "Home server %s has the same IP address and/or port as another home server.", name);
1496 if (!rbtree_insert(home_servers_byname, home)) {
1497 cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
1502 if (!rbtree_insert(home_servers_byaddr, home)) {
1503 rbtree_deletebydata(home_servers_byname, home);
1504 cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
1510 home->number = home_server_max_number++;
1511 if (!rbtree_insert(home_servers_bynumber, home)) {
1512 rbtree_deletebydata(home_servers_byname, home);
1513 if (home->ipaddr.af != AF_UNSPEC) {
1514 rbtree_deletebydata(home_servers_byname, home);
1517 "Internal error %d adding home server %s.",
1526 * We now have a home server, see if we can insert it
1527 * into pre-existing pool.
1529 if (insert_point >= 0) {
1530 rad_assert(pool != NULL);
1531 pool->servers[insert_point] = home;
1535 rad_assert(pool == NULL);
1536 rad_assert(home != NULL);
1539 * Count the old-style realms of this name.
1541 num_home_servers = 0;
1542 for (subcs = cf_section_find_next(cs, NULL, "realm");
1544 subcs = cf_section_find_next(cs, subcs, "realm")) {
1545 char const *this = cf_section_name2(subcs);
1547 if (!this || (strcmp(this, realm) != 0)) continue;
1551 if (num_home_servers == 0) {
1552 cf_log_err_cs(cs, "Internal error counting pools for home server %s.", name);
1557 pool = server_pool_alloc(realm, ldflag, type, num_home_servers);
1559 cf_log_err_cs(cs, "Out of memory");
1565 pool->servers[0] = home;
1567 if (!rbtree_insert(home_pools_byname, pool)) {
1568 rad_assert("Internal sanity check failed" == NULL);
1578 static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
1581 char const *secret = NULL;
1582 home_pool_type_t ldflag;
1585 cp = cf_pair_find(cs, "ldflag");
1586 ldflag = HOME_POOL_FAIL_OVER;
1588 host = cf_pair_value(cp);
1590 cf_log_err_cp(cp, "No value specified for ldflag");
1594 if (strcasecmp(host, "fail_over") == 0) {
1595 cf_log_info(cs, "\tldflag = fail_over");
1597 } else if (strcasecmp(host, "round_robin") == 0) {
1598 ldflag = HOME_POOL_LOAD_BALANCE;
1599 cf_log_info(cs, "\tldflag = round_robin");
1602 cf_log_err_cs(cs, "Unknown value \"%s\" for ldflag", host);
1605 } /* else don't print it. */
1608 * Allow old-style if it doesn't exist, or if it exists and
1611 cp = cf_pair_find(cs, "authhost");
1613 host = cf_pair_value(cp);
1615 cf_log_err_cp(cp, "No value specified for authhost");
1619 if (strcmp(host, "LOCAL") != 0) {
1620 cp = cf_pair_find(cs, "secret");
1622 cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
1626 secret = cf_pair_value(cp);
1628 cf_log_err_cp(cp, "No value specified for secret");
1633 cf_log_info(cs, "\tauthhost = %s", host);
1635 if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
1636 &r->auth_pool, HOME_TYPE_AUTH, NULL)) {
1641 cp = cf_pair_find(cs, "accthost");
1643 host = cf_pair_value(cp);
1645 cf_log_err_cp(cp, "No value specified for accthost");
1650 * Don't look for a secret again if it was found
1653 if ((strcmp(host, "LOCAL") != 0) && !secret) {
1654 cp = cf_pair_find(cs, "secret");
1656 cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
1660 secret = cf_pair_value(cp);
1662 cf_log_err_cp(cp, "No value specified for secret");
1667 cf_log_info(cs, "\taccthost = %s", host);
1669 if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
1670 &r->acct_pool, HOME_TYPE_ACCT, NULL)) {
1675 cp = cf_pair_find(cs, "virtual_server");
1677 host = cf_pair_value(cp);
1679 cf_log_err_cp(cp, "No value specified for virtual_server");
1683 cf_log_info(cs, "\tvirtual_server = %s", host);
1685 if (!old_server_add(rc, cs, r->name, host, "", ldflag,
1686 &r->auth_pool, HOME_TYPE_AUTH, host)) {
1689 if (!old_server_add(rc, cs, r->name, host, "", ldflag,
1690 &r->acct_pool, HOME_TYPE_ACCT, host)) {
1695 if (secret) cf_log_info(cs, "\tsecret = %s", secret);
1703 static int add_pool_to_realm(realm_config_t *rc, CONF_SECTION *cs,
1704 char const *name, home_pool_t **dest,
1705 home_type_t server_type, bool do_print)
1707 home_pool_t mypool, *pool;
1710 mypool.server_type = server_type;
1712 pool = rbtree_finddata(home_pools_byname, &mypool);
1714 CONF_SECTION *pool_cs;
1716 pool_cs = cf_section_sub_find_name2(rc->cs,
1720 pool_cs = cf_section_sub_find_name2(rc->cs,
1725 cf_log_err_cs(cs, "Failed to find home_server_pool \"%s\"", name);
1729 if (!server_pool_add(rc, pool_cs, server_type, do_print)) {
1733 pool = rbtree_finddata(home_pools_byname, &mypool);
1735 ERROR("Internal sanity check failed in add_pool_to_realm");
1740 if (pool->server_type != server_type) {
1741 cf_log_err_cs(cs, "Incompatible home_server_pool \"%s\" (mixed auth_pool / acct_pool)", name);
1752 static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
1758 home_pool_t *auth_pool, *acct_pool;
1759 char const *auth_pool_name, *acct_pool_name;
1761 char const *coa_pool_name;
1762 home_pool_t *coa_pool;
1766 name2 = cf_section_name1(cs);
1767 if (!name2 || (strcasecmp(name2, "realm") != 0)) {
1768 cf_log_err_cs(cs, "Section is not a realm");
1772 name2 = cf_section_name2(cs);
1774 cf_log_err_cs(cs, "Realm section is missing the realm name");
1779 auth_pool = acct_pool = NULL;
1780 auth_pool_name = acct_pool_name = NULL;
1783 coa_pool_name = NULL;
1787 * Prefer new configuration to old one.
1789 cp = cf_pair_find(cs, "pool");
1790 if (!cp) cp = cf_pair_find(cs, "home_server_pool");
1791 if (cp) auth_pool_name = cf_pair_value(cp);
1792 if (cp && auth_pool_name) {
1793 acct_pool_name = auth_pool_name;
1794 if (!add_pool_to_realm(rc, cs,
1795 auth_pool_name, &auth_pool,
1796 HOME_TYPE_AUTH, 1)) {
1799 if (!add_pool_to_realm(rc, cs,
1800 auth_pool_name, &acct_pool,
1801 HOME_TYPE_ACCT, 0)) {
1806 cp = cf_pair_find(cs, "auth_pool");
1807 if (cp) auth_pool_name = cf_pair_value(cp);
1808 if (cp && auth_pool_name) {
1810 cf_log_err_cs(cs, "Cannot use \"pool\" and \"auth_pool\" at the same time");
1813 if (!add_pool_to_realm(rc, cs,
1814 auth_pool_name, &auth_pool,
1815 HOME_TYPE_AUTH, 1)) {
1820 cp = cf_pair_find(cs, "acct_pool");
1821 if (cp) acct_pool_name = cf_pair_value(cp);
1822 if (cp && acct_pool_name) {
1823 bool do_print = true;
1826 cf_log_err_cs(cs, "Cannot use \"pool\" and \"acct_pool\" at the same time");
1832 (strcmp(auth_pool_name, acct_pool_name) != 0))) {
1836 if (!add_pool_to_realm(rc, cs,
1837 acct_pool_name, &acct_pool,
1838 HOME_TYPE_ACCT, do_print)) {
1844 cp = cf_pair_find(cs, "coa_pool");
1845 if (cp) coa_pool_name = cf_pair_value(cp);
1846 if (cp && coa_pool_name) {
1847 bool do_print = true;
1849 if (!add_pool_to_realm(rc, cs,
1850 coa_pool_name, &coa_pool,
1851 HOME_TYPE_COA, do_print)) {
1858 cf_log_info(cs, " realm %s {", name2);
1862 * The realm MAY already exist if it's an old-style realm.
1863 * In that case, merge the old-style realm with this one.
1865 r = realm_find2(name2);
1866 if (r && (strcmp(r->name, name2) == 0)) {
1867 if (cf_pair_find(cs, "auth_pool") ||
1868 cf_pair_find(cs, "acct_pool")) {
1869 cf_log_err_cs(cs, "Duplicate realm \"%s\"", name2);
1873 if (!old_realm_config(rc, cs, r)) {
1877 cf_log_info(cs, " } # realm %s", name2);
1882 r = talloc_zero(rc, REALM);
1884 r->strip_realm = true;
1886 r->auth_pool = auth_pool;
1887 r->acct_pool = acct_pool;
1889 r->coa_pool = coa_pool;
1892 if (auth_pool_name &&
1893 (auth_pool_name == acct_pool_name)) { /* yes, ptr comparison */
1894 cf_log_info(cs, "\tpool = %s", auth_pool_name);
1896 if (auth_pool_name) cf_log_info(cs, "\tauth_pool = %s", auth_pool_name);
1897 if (acct_pool_name) cf_log_info(cs, "\tacct_pool = %s", acct_pool_name);
1899 if (coa_pool_name) cf_log_info(cs, "\tcoa_pool = %s", coa_pool_name);
1904 cp = cf_pair_find(cs, "nostrip");
1905 if (cp && (cf_pair_value(cp) == NULL)) {
1906 r->strip_realm = false;
1907 cf_log_info(cs, "\tnostrip");
1911 * We're a new-style realm. Complain if we see the old
1914 if (r->auth_pool || r->acct_pool) {
1915 if (((cp = cf_pair_find(cs, "authhost")) != NULL) ||
1916 ((cp = cf_pair_find(cs, "accthost")) != NULL) ||
1917 ((cp = cf_pair_find(cs, "secret")) != NULL) ||
1918 ((cp = cf_pair_find(cs, "ldflag")) != NULL)) {
1919 WARN("Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
1924 * The realm MAY be an old-style realm, as there
1925 * was no auth_pool or acct_pool. Double-check
1926 * it, just to be safe.
1928 } else if (!old_realm_config(rc, cs, r)) {
1932 if (!realm_realm_add(r, cs)) {
1936 cf_log_info(cs, " }");
1941 cf_log_info(cs, " } # realm %s", name2);
1946 int realm_realm_add(REALM *r, CONF_SECTION *cs)
1948 int realm_realm_add(REALM *r, UNUSED CONF_SECTION *cs)
1952 * The structs aren't mutex protected. Refuse to destroy
1955 if (event_loop_started && !realm_config->dynamic) {
1956 DEBUG("Must set \"dynamic = true\" in proxy.conf");
1962 * It's a regex. Sanity check it, and add it to a
1965 if (r->name[0] == '~') {
1967 realm_regex_t *rr, **last;
1969 rr = talloc(r, realm_regex_t);
1972 * Include substring matches.
1974 slen = regex_compile(rr, &rr->preg, r->name + 1, strlen(r->name) - 1, true, false, false, false);
1976 char *spaces, *text;
1978 fr_canonicalize_error(r, &spaces, &text, slen, r->name + 1);
1980 cf_log_err_cs(cs, "Invalid regular expression:");
1981 cf_log_err_cs(cs, "%s", text);
1982 cf_log_err_cs(cs, "%s^ %s", spaces, fr_strerror());
1984 talloc_free(spaces);
1991 last = &realms_regex;
1992 while (*last) last = &((*last)->next); /* O(N^2)... sue me. */
2002 if (!rbtree_insert(realms_byname, r)) {
2003 rad_assert("Internal sanity check failed" == NULL);
2012 static int pool_peek_type(CONF_SECTION *config, CONF_SECTION *cs)
2015 char const *name, *type;
2017 CONF_SECTION *server_cs;
2019 cp = cf_pair_find(cs, "home_server");
2021 cf_log_err_cs(cs, "Pool does not contain a \"home_server\" entry");
2022 return HOME_TYPE_INVALID;
2025 name = cf_pair_value(cp);
2027 cf_log_err_cp(cp, "home_server entry does not reference a home server");
2028 return HOME_TYPE_INVALID;
2031 server_cs = cf_section_sub_find_name2(config, "home_server", name);
2033 cf_log_err_cp(cp, "home_server \"%s\" does not exist", name);
2034 return HOME_TYPE_INVALID;
2037 cp = cf_pair_find(server_cs, "type");
2039 cf_log_err_cs(server_cs, "home_server %s does not contain a \"type\" entry", name);
2040 return HOME_TYPE_INVALID;
2043 type = cf_pair_value(cp);
2045 cf_log_err_cs(server_cs, "home_server %s contains an empty \"type\" entry", name);
2046 return HOME_TYPE_INVALID;
2049 home = fr_str2int(home_server_types, type, HOME_TYPE_INVALID);
2050 if (home == HOME_TYPE_INVALID) {
2051 cf_log_err_cs(server_cs, "home_server %s contains an invalid \"type\" entry of value \"%s\"", name, type);
2052 return HOME_TYPE_INVALID;
2055 return home; /* 'cause we miss it so much */
2059 int realms_init(CONF_SECTION *config)
2064 CONF_SECTION *server_cs;
2068 if (event_loop_started) return 1;
2070 rc = talloc_zero(NULL, realm_config_t);
2074 cs = cf_subsection_find_next(config, NULL, "proxy");
2076 if (cf_section_parse(cs, rc, proxy_config) < 0) {
2077 ERROR("Failed parsing proxy section");
2081 rc->dead_time = DEAD_TIME;
2082 rc->retry_count = RETRY_COUNT;
2083 rc->retry_delay = RETRY_DELAY;
2084 rc->fallback = false;
2085 rc->dynamic = false;
2086 rc->wake_all_if_all_dead= 0;
2090 flags = RBTREE_FLAG_LOCK;
2093 home_servers_byaddr = rbtree_create(NULL, home_server_addr_cmp, home_server_free, flags);
2094 if (!home_servers_byaddr) goto error;
2096 home_servers_byname = rbtree_create(NULL, home_server_name_cmp, NULL, flags);
2097 if (!home_servers_byname) goto error;
2100 home_servers_bynumber = rbtree_create(NULL, home_server_number_cmp, NULL, flags);
2101 if (!home_servers_bynumber) goto error;
2104 home_pools_byname = rbtree_create(NULL, home_pool_name_cmp, NULL, flags);
2105 if (!home_pools_byname) goto error;
2107 for (cs = cf_subsection_find_next(config, NULL, "home_server");
2109 cs = cf_subsection_find_next(config, cs, "home_server")) {
2110 home_server_t *home;
2112 home = home_server_afrom_cs(rc, rc, cs);
2113 if (!home) goto error;
2114 if (!realm_home_server_add(home)) goto error;
2118 * Loop over virtual servers to find home servers which
2119 * are defined in them.
2121 for (server_cs = cf_subsection_find_next(config, NULL, "server");
2123 server_cs = cf_subsection_find_next(config, server_cs, "server")) {
2124 for (cs = cf_subsection_find_next(server_cs, NULL, "home_server");
2126 cs = cf_subsection_find_next(server_cs, cs, "home_server")) {
2127 home_server_t *home;
2129 home = home_server_afrom_cs(rc, rc, cs);
2130 if (!home) goto error;
2131 if (!realm_home_server_add(home)) goto error;
2137 * Now create the realms, which point to the home servers
2138 * and home server pools.
2140 realms_byname = rbtree_create(NULL, realm_name_cmp, NULL, flags);
2141 if (!realms_byname) goto error;
2143 for (cs = cf_subsection_find_next(config, NULL, "realm");
2145 cs = cf_subsection_find_next(config, cs, "realm")) {
2146 if (!realm_add(rc, cs)) {
2150 * Must be called after realms_free as home_servers
2151 * parented by rc are in trees freed by realms_free()
2160 * CoA pools aren't necessarily tied to realms.
2162 for (cs = cf_subsection_find_next(config, NULL, "home_server_pool");
2164 cs = cf_subsection_find_next(config, cs, "home_server_pool")) {
2168 * Pool was already loaded.
2170 if (cf_data_find(cs, "home_server_pool")) continue;
2172 type = pool_peek_type(config, cs);
2173 if (type == HOME_TYPE_INVALID) goto error;
2174 if (!server_pool_add(rc, cs, type, true)) goto error;
2179 xlat_register("home_server", xlat_home_server, NULL, NULL);
2180 xlat_register("home_server_pool", xlat_server_pool, NULL, NULL);
2188 * Find a realm where "name" might be the regex.
2190 REALM *realm_find2(char const *name)
2195 if (!name) name = "NULL";
2197 myrealm.name = name;
2198 realm = rbtree_finddata(realms_byname, &myrealm);
2199 if (realm) return realm;
2203 realm_regex_t *this;
2205 for (this = realms_regex; this != NULL; this = this->next) {
2206 if (strcmp(this->realm->name, name) == 0) {
2214 * Couldn't find a realm. Look for DEFAULT.
2216 myrealm.name = "DEFAULT";
2217 return rbtree_finddata(realms_byname, &myrealm);
2222 * Find a realm in the REALM list.
2224 REALM *realm_find(char const *name)
2229 if (!name) name = "NULL";
2231 myrealm.name = name;
2232 realm = rbtree_finddata(realms_byname, &myrealm);
2233 if (realm) return realm;
2237 realm_regex_t *this;
2239 for (this = realms_regex;
2241 this = this->next) {
2244 compare = regex_exec(this->preg, name, strlen(name), NULL, NULL);
2246 ERROR("Failed performing realm comparison: %s", fr_strerror());
2249 if (compare == 1) return this->realm;
2255 * Couldn't find a realm. Look for DEFAULT.
2257 myrealm.name = "DEFAULT";
2258 return rbtree_finddata(realms_byname, &myrealm);
2265 * Allocate the proxy list if it doesn't already exist, and copy request
2266 * VPs into it. Setup src/dst IP addresses based on home server, and
2267 * calculate and add the message-authenticator.
2269 * This is a distinct function from home_server_ldb, as not all home_server_t
2270 * lookups result in the *CURRENT* request being proxied,
2271 * as in rlm_replicate, and this may trigger asserts elsewhere in the
2274 void home_server_update_request(home_server_t *home, REQUEST *request)
2278 * Allocate the proxy packet, only if it wasn't
2279 * already allocated by a module. This check is
2280 * mainly to support the proxying of EAP-TTLS and
2281 * EAP-PEAP tunneled requests.
2283 * In those cases, the EAP module creates a
2284 * "fake" request, and recursively passes it
2285 * through the authentication stage of the
2286 * server. The module then checks if the request
2287 * was supposed to be proxied, and if so, creates
2288 * a proxy packet from the TUNNELED request, and
2289 * not from the EAP request outside of the
2292 * The proxy then works like normal, except that
2293 * the response packet is "eaten" by the EAP
2294 * module, and encapsulated into an EAP packet.
2296 if (!request->proxy) {
2297 request->proxy = rad_alloc(request, true);
2298 if (!request->proxy) {
2304 * Copy the request, then look up name
2305 * and plain-text password in the copy.
2307 * Note that the User-Name attribute is
2308 * the *original* as sent over by the
2309 * client. The Stripped-User-Name
2310 * attribute is the one hacked through
2313 request->proxy->vps = fr_pair_list_copy(request->proxy,
2314 request->packet->vps);
2318 * Update the various fields as appropriate.
2320 request->proxy->src_ipaddr = home->src_ipaddr;
2321 request->proxy->src_port = 0;
2322 request->proxy->dst_ipaddr = home->ipaddr;
2323 request->proxy->dst_port = home->port;
2325 request->proxy->proto = home->proto;
2327 request->home_server = home;
2330 * Access-Requests have a Message-Authenticator added,
2331 * unless one already exists.
2333 if ((request->packet->code == PW_CODE_ACCESS_REQUEST) &&
2334 !fr_pair_find_by_num(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY)) {
2335 fr_pair_make(request->proxy, &request->proxy->vps,
2336 "Message-Authenticator", "0x00",
2341 home_server_t *home_server_ldb(char const *realmname,
2342 home_pool_t *pool, REQUEST *request)
2346 home_server_t *found = NULL;
2347 home_server_t *zombie = NULL;
2352 * Determine how to pick choose the home server.
2354 switch (pool->type) {
2358 * For load-balancing by client IP address, we
2359 * pick a home server by hashing the client IP.
2361 * This isn't as even a load distribution as
2362 * tracking the State attribute, but it's better
2365 case HOME_POOL_CLIENT_BALANCE:
2366 switch (request->packet->src_ipaddr.af) {
2368 hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
2369 sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
2373 hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
2374 sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
2381 start = hash % pool->num_home_servers;
2384 case HOME_POOL_CLIENT_PORT_BALANCE:
2385 switch (request->packet->src_ipaddr.af) {
2387 hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
2388 sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
2392 hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
2393 sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
2400 fr_hash_update(&request->packet->src_port,
2401 sizeof(request->packet->src_port), hash);
2402 start = hash % pool->num_home_servers;
2405 case HOME_POOL_KEYED_BALANCE:
2406 if ((vp = fr_pair_find_by_num(request->config, PW_LOAD_BALANCE_KEY, 0, TAG_ANY)) != NULL) {
2407 hash = fr_hash(vp->vp_strvalue, vp->vp_length);
2408 start = hash % pool->num_home_servers;
2413 case HOME_POOL_LOAD_BALANCE:
2414 case HOME_POOL_FAIL_OVER:
2418 default: /* this shouldn't happen... */
2425 * Starting with the home server we chose, loop through
2426 * all home servers. If the current one is dead, skip
2427 * it. If it is too busy, skip it.
2429 * Otherwise, use it.
2431 for (count = 0; count < pool->num_home_servers; count++) {
2432 home_server_t *home = pool->servers[(start + count) % pool->num_home_servers];
2434 if (!home) continue;
2437 * Skip dead home servers.
2439 * Home servers that are unknown, alive, or zombie
2440 * are used for proxying.
2442 if (home->state == HOME_STATE_IS_DEAD) {
2447 * This home server is too busy. Choose another one.
2449 if (home->currently_outstanding >= home->max_outstanding) {
2455 * We read the packet from a detail file, AND it
2456 * came from this server. Don't re-proxy it
2459 if ((request->listener->type == RAD_LISTEN_DETAIL) &&
2460 (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
2461 (fr_ipaddr_cmp(&home->ipaddr, &request->packet->src_ipaddr) == 0)) {
2467 * Default virtual: ignore homes tied to a
2470 if (!request->server && home->parent_server) {
2475 * A virtual AND home is tied to virtual,
2476 * ignore ones which don't match.
2478 if (request->server && home->parent_server &&
2479 strcmp(request->server, home->parent_server) != 0) {
2484 * Allow request->server && !home->parent_server
2486 * i.e. virtuals can proxy to globally defined
2491 * It's zombie, so we remember the first zombie
2492 * we find, but we don't mark it as a "live"
2495 if (home->state == HOME_STATE_ZOMBIE) {
2496 if (!zombie) zombie = home;
2501 * We've found the first "live" one. Use that.
2503 if (pool->type != HOME_POOL_LOAD_BALANCE) {
2509 * Otherwise we're doing some kind of load balancing.
2510 * If we haven't found one yet, pick this one.
2517 RDEBUG3("PROXY %s %d\t%s %d",
2518 found->log_name, found->currently_outstanding,
2519 home->log_name, home->currently_outstanding);
2522 * Prefer this server if it's less busy than the
2523 * one we had previously found.
2525 if (home->currently_outstanding < found->currently_outstanding) {
2526 RDEBUG3("PROXY Choosing %s: It's less busy than %s",
2527 home->log_name, found->log_name);
2533 * Ignore servers which are busier than the one
2536 if (home->currently_outstanding > found->currently_outstanding) {
2537 RDEBUG3("PROXY Skipping %s: It's busier than %s",
2538 home->log_name, found->log_name);
2543 * From the list of servers which have the same
2544 * load, choose one at random.
2546 if (((count + 1) * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
2549 } /* loop over the home servers */
2552 * We have no live servers, BUT we have a zombie. Use
2553 * the zombie as a last resort.
2555 if (!found && zombie) {
2561 * There's a fallback if they're all dead.
2563 if (!found && pool->fallback) {
2564 found = pool->fallback;
2566 WARN("Home server pool %s failing over to fallback %s",
2567 pool->name, found->server);
2568 if (pool->in_fallback) goto update_and_return;
2570 pool->in_fallback = true;
2573 * Run the trigger once an hour saying that
2576 if ((pool->time_all_dead + 3600) < request->timestamp) {
2577 pool->time_all_dead = request->timestamp;
2578 exec_trigger(request, pool->cs, "home_server_pool.fallback", false);
2584 if ((found != pool->fallback) && pool->in_fallback) {
2585 pool->in_fallback = false;
2586 exec_trigger(request, pool->cs, "home_server_pool.normal", false);
2593 * No live match found, and no fallback to the "DEFAULT"
2594 * realm. We fix this by blindly marking all servers as
2595 * "live". But only do it for ones that don't support
2596 * "pings", as they will be marked live when they
2597 * actually are live.
2599 if (!realm_config->fallback &&
2600 realm_config->wake_all_if_all_dead) {
2601 for (count = 0; count < pool->num_home_servers; count++) {
2602 home_server_t *home = pool->servers[count];
2604 if (!home) continue;
2606 if ((home->state == HOME_STATE_IS_DEAD) &&
2607 (home->ping_check == HOME_PING_CHECK_NONE)) {
2608 home->state = HOME_STATE_ALIVE;
2609 home->response_timeouts = 0;
2610 if (!found) found = home;
2614 if (found) goto update_and_return;
2618 * Still nothing. Look up the DEFAULT realm, but only
2619 * if we weren't looking up the NULL or DEFAULT realms.
2621 if (realm_config->fallback &&
2623 (strcmp(realmname, "NULL") != 0) &&
2624 (strcmp(realmname, "DEFAULT") != 0)) {
2625 REALM *rd = realm_find("DEFAULT");
2627 if (!rd) return NULL;
2630 if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
2631 pool = rd->auth_pool;
2633 } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
2634 pool = rd->acct_pool;
2636 if (!pool) return NULL;
2638 RDEBUG2("PROXY - realm %s has no live home servers. Falling back to the DEFAULT realm.", realmname);
2639 return home_server_ldb(rd->name, pool, request);
2643 * Still haven't found anything. Oh well.
2649 home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port, int proto)
2651 home_server_t myhome;
2653 memset(&myhome, 0, sizeof(myhome));
2654 myhome.ipaddr = *ipaddr;
2655 myhome.src_ipaddr.af = ipaddr->af;
2658 myhome.proto = proto;
2660 myhome.proto = IPPROTO_UDP;
2662 myhome.server = NULL; /* we're not called for internal proxying */
2664 return rbtree_finddata(home_servers_byaddr, &myhome);
2668 home_server_t *home_server_byname(char const *name, int type)
2670 home_server_t myhome;
2672 memset(&myhome, 0, sizeof(myhome));
2676 return rbtree_finddata(home_servers_byname, &myhome);
2681 home_server_t *home_server_bynumber(int number)
2683 home_server_t myhome;
2685 memset(&myhome, 0, sizeof(myhome));
2686 myhome.number = number;
2687 myhome.server = NULL; /* we're not called for internal proxying */
2689 return rbtree_finddata(home_servers_bynumber, &myhome);
2693 home_pool_t *home_pool_byname(char const *name, int type)
2697 memset(&mypool, 0, sizeof(mypool));
2699 mypool.server_type = type;
2700 return rbtree_finddata(home_pools_byname, &mypool);