"Fossies" - the Fresh Open Source Software Archive

Member "freeradius-server-3.0.23/src/main/realms.c" (10 Jun 2021, 73466 Bytes) of package /linux/misc/freeradius-server-3.0.23.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "realms.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.22_vs_3.0.23.

    1 /*
    2  * realms.c Realm handling code
    3  *
    4  * Version:     $Id: 4a6dafb7419a230e4410ed621bfb2116c63f5279 $
    5  *
    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.
   10  *
   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.
   15  *
   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
   19  *
   20  * Copyright 2007  The FreeRADIUS server project
   21  * Copyright 2007  Alan DeKok <aland@deployingradius.com>
   22  */
   23 
   24 RCSID("$Id: 4a6dafb7419a230e4410ed621bfb2116c63f5279 $")
   25 
   26 #include <freeradius-devel/radiusd.h>
   27 #include <freeradius-devel/realms.h>
   28 #include <freeradius-devel/rad_assert.h>
   29 
   30 #include <sys/stat.h>
   31 
   32 #include <ctype.h>
   33 #include <fcntl.h>
   34 
   35 static rbtree_t *realms_byname = NULL;
   36 #ifdef WITH_TCP
   37 bool home_servers_udp = false;
   38 #endif
   39 
   40 #ifdef HAVE_DIRENT_H
   41 #include <dirent.h>
   42 #endif
   43 
   44 #ifdef HAVE_REGEX
   45 typedef struct realm_regex realm_regex_t;
   46 
   47 /** Regular expression associated with a realm
   48  *
   49  */
   50 struct realm_regex {
   51     REALM       *realm;     //!< The realm this regex matches.
   52     regex_t     *preg;      //!< The pre-compiled regular expression.
   53     realm_regex_t   *next;      //!< The next realm in the list of regular expressions.
   54 };
   55 static realm_regex_t *realms_regex = NULL;
   56 #endif /* HAVE_REGEX */
   57 
   58 struct realm_config {
   59     CONF_SECTION        *cs;
   60 #ifdef HAVE_DIRENT_H
   61     char const      *directory;
   62 #endif
   63     uint32_t        dead_time;
   64     uint32_t        retry_count;
   65     uint32_t        retry_delay;
   66     bool            dynamic;
   67     bool            fallback;
   68     bool            wake_all_if_all_dead;
   69 };
   70 
   71 static const FR_NAME_NUMBER home_server_types[] = {
   72     { "auth",       HOME_TYPE_AUTH },
   73     { "acct",       HOME_TYPE_ACCT },
   74     { "auth+acct",      HOME_TYPE_AUTH_ACCT },
   75     { "coa",        HOME_TYPE_COA },
   76     { NULL, 0 }
   77 };
   78 
   79 static const FR_NAME_NUMBER home_ping_check[] = {
   80     { "none",       HOME_PING_CHECK_NONE },
   81     { "status-server",  HOME_PING_CHECK_STATUS_SERVER },
   82     { "request",        HOME_PING_CHECK_REQUEST },
   83     { NULL, 0 }
   84 };
   85 
   86 static const FR_NAME_NUMBER home_proto[] = {
   87     { "UDP",        IPPROTO_UDP },
   88     { "TCP",        IPPROTO_TCP },
   89     { NULL, 0 }
   90 };
   91 
   92 
   93 static realm_config_t *realm_config = NULL;
   94 
   95 #ifdef WITH_PROXY
   96 static rbtree_t *home_servers_byaddr = NULL;
   97 static rbtree_t *home_servers_byname = NULL;
   98 #ifdef WITH_STATS
   99 static int home_server_max_number = 0;
  100 static rbtree_t *home_servers_bynumber = NULL;
  101 #endif
  102 
  103 static rbtree_t *home_pools_byname = NULL;
  104 
  105 /*
  106  *  Map the proxy server configuration parameters to variables.
  107  */
  108 static const CONF_PARSER proxy_config[] = {
  109     { "retry_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, retry_delay), STRINGIFY(RETRY_DELAY)  },
  110 
  111     { "retry_count", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, retry_count), STRINGIFY(RETRY_COUNT)  },
  112 
  113     { "default_fallback", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, fallback), "no" },
  114 
  115     { "dynamic", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, dynamic), NULL },
  116 
  117 #ifdef HAVE_DIRENT_H
  118     { "directory", FR_CONF_OFFSET(PW_TYPE_STRING, realm_config_t, directory), NULL },
  119 #endif
  120 
  121     { "dead_time", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, dead_time), STRINGIFY(DEAD_TIME)  },
  122 
  123     { "wake_all_if_all_dead", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, wake_all_if_all_dead), "no" },
  124     CONF_PARSER_TERMINATOR
  125 };
  126 #endif
  127 
  128 static int realm_name_cmp(void const *one, void const *two)
  129 {
  130     REALM const *a = one;
  131     REALM const *b = two;
  132 
  133     return strcasecmp(a->name, b->name);
  134 }
  135 
  136 
  137 #ifdef WITH_PROXY
  138 static void home_server_free(void *data)
  139 {
  140     home_server_t *home = talloc_get_type_abort(data, home_server_t);
  141 
  142     talloc_free(home);
  143 }
  144 
  145 static int home_server_name_cmp(void const *one, void const *two)
  146 {
  147     home_server_t const *a = one;
  148     home_server_t const *b = two;
  149 
  150     if (a->type < b->type) return -1;
  151     if (a->type > b->type) return +1;
  152 
  153     return strcasecmp(a->name, b->name);
  154 }
  155 
  156 static int home_server_addr_cmp(void const *one, void const *two)
  157 {
  158     int rcode;
  159     home_server_t const *a = one;
  160     home_server_t const *b = two;
  161 
  162     if (a->server && !b->server) return -1;
  163     if (!a->server && b->server) return +1;
  164     if (a->server && b->server) {
  165         rcode = a->type - b->type;
  166         if (rcode != 0) return rcode;
  167         return strcmp(a->server, b->server);
  168     }
  169 
  170     if (a->port < b->port) return -1;
  171     if (a->port > b->port) return +1;
  172 
  173 #ifdef WITH_TCP
  174     if (a->proto < b->proto) return -1;
  175     if (a->proto > b->proto) return +1;
  176 #endif
  177 
  178     rcode = fr_ipaddr_cmp(&a->src_ipaddr, &b->src_ipaddr);
  179     if (rcode != 0) return rcode;
  180 
  181     return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
  182 }
  183 
  184 #ifdef WITH_STATS
  185 static int home_server_number_cmp(void const *one, void const *two)
  186 {
  187     home_server_t const *a = one;
  188     home_server_t const *b = two;
  189 
  190     return (a->number - b->number);
  191 }
  192 #endif
  193 
  194 static int home_pool_name_cmp(void const *one, void const *two)
  195 {
  196     home_pool_t const *a = one;
  197     home_pool_t const *b = two;
  198 
  199     if (a->server_type < b->server_type) return -1;
  200     if (a->server_type > b->server_type) return +1;
  201 
  202     return strcasecmp(a->name, b->name);
  203 }
  204 
  205 
  206 static size_t xlat_cs(CONF_SECTION *cs, char const *fmt, char *out, size_t outlen)
  207 {
  208     char const *value = NULL;
  209 
  210     if (!fmt) {
  211         DEBUG("No configuration item requested.  Ignoring.");
  212 
  213         *out = '\0';
  214         return 0;
  215     }
  216 
  217     /*
  218      *  Instance name
  219      */
  220     if (strcmp(fmt, "instance") == 0) {
  221         value = cf_section_name2(cs);
  222         if (!value) {
  223             *out = '\0';
  224             return 0;
  225         }
  226     } else {
  227         CONF_PAIR *cp;
  228 
  229         cp = cf_pair_find(cs, fmt);
  230         if (!cp || !(value = cf_pair_value(cp))) {
  231             *out = '\0';
  232             return 0;
  233         }
  234     }
  235 
  236     strlcpy(out, value, outlen);
  237 
  238     return strlen(out);
  239 }
  240 
  241 
  242 /*
  243  *  Xlat for %{home_server:foo}
  244  */
  245 static ssize_t xlat_home_server(UNUSED void *instance, REQUEST *request,
  246                 char const *fmt, char *out, size_t outlen)
  247 {
  248     if (!request->home_server) {
  249         RWDEBUG("No home_server associated with this request");
  250 
  251         *out = '\0';
  252         return 0;
  253     }
  254 
  255     if (!fmt) {
  256         RWDEBUG("No configuration item requested.  Ignoring.");
  257 
  258         *out = '\0';
  259         return 0;
  260     }
  261 
  262     if (strcmp(fmt, "state") == 0) {
  263         char const *state;
  264 
  265         switch (request->home_server->state) {
  266         case HOME_STATE_ALIVE:
  267             state = "alive";
  268             break;
  269 
  270         case HOME_STATE_ZOMBIE:
  271             state = "zombie";
  272             break;
  273 
  274         case HOME_STATE_IS_DEAD:
  275             state = "dead";
  276             break;
  277 
  278         case HOME_STATE_CONNECTION_FAIL:
  279             state = "fail";
  280             break;
  281 
  282         case HOME_STATE_ADMIN_DOWN:
  283             state = "down";
  284             break;
  285 
  286         default:
  287             state = "unknown";
  288             break;
  289         }
  290 
  291         strlcpy(out, state, outlen);
  292         return strlen(out);
  293     }
  294 
  295     return xlat_cs(request->home_server->cs, fmt, out, outlen);
  296 }
  297 
  298 
  299 /*
  300  *  Xlat for %{home_server_pool:foo}
  301  */
  302 static ssize_t xlat_server_pool(UNUSED void *instance, REQUEST *request,
  303                 char const *fmt, char *out, size_t outlen)
  304 {
  305     if (!request->home_pool) {
  306         RWDEBUG("No home_pool associated with this request");
  307 
  308         *out = '\0';
  309         return 0;
  310     }
  311 
  312     if (!fmt) {
  313         RWDEBUG("No configuration item requested.  Ignoring.");
  314 
  315         *out = '\0';
  316         return 0;
  317     }
  318 
  319     if (strcmp(fmt, "state") == 0) {
  320         char const *state;
  321 
  322         if (request->home_pool->in_fallback) {
  323             state = "fallback";
  324 
  325         } else {
  326             state = "alive";
  327         }
  328 
  329         strlcpy(out, state, outlen);
  330         return strlen(out);
  331     }
  332 
  333     return xlat_cs(request->home_pool->cs, fmt, out, outlen);
  334 }
  335 
  336 
  337 /*
  338  *  Xlat for %{home_server_dynamic:foo}
  339  */
  340 static ssize_t xlat_home_server_dynamic(UNUSED void *instance, REQUEST *request,
  341                     char const *fmt, char *out, size_t outlen)
  342 {
  343     int type;
  344     char const *p;
  345     home_server_t *home;
  346 
  347     if (outlen < 2) return 0;
  348 
  349     switch (request->packet->code) {
  350     case PW_CODE_ACCESS_REQUEST:
  351         type = HOME_TYPE_AUTH;
  352         break;
  353 
  354 #ifdef WITH_ACCOUNTING
  355     case PW_CODE_ACCOUNTING_REQUEST:
  356         type = HOME_TYPE_ACCT;
  357         break;
  358 #endif
  359 
  360 #ifdef WITH_COA
  361     case PW_CODE_COA_REQUEST:
  362     case PW_CODE_DISCONNECT_REQUEST:
  363         type = HOME_TYPE_COA;
  364         break;
  365 #endif
  366 
  367     default:
  368         *out = '\0';
  369         return 0;
  370     }
  371 
  372     p = fmt;
  373     while (isspace((int) *p)) p++;
  374 
  375     home = home_server_byname(p, type);
  376     if (!home) {
  377         *out = '\0';
  378         return 0;
  379     }
  380 
  381     /*
  382      *  1 for dynamic, 0 for static
  383      */
  384     out[0] = '0' + home->dynamic;
  385     out[1] = '\0';
  386 
  387     return 1;
  388 }
  389 #endif
  390 
  391 void realms_free(void)
  392 {
  393 #ifdef WITH_PROXY
  394 #  ifdef WITH_STATS
  395     rbtree_free(home_servers_bynumber);
  396     home_servers_bynumber = NULL;
  397 #  endif
  398 
  399     rbtree_free(home_servers_byname);
  400     home_servers_byname = NULL;
  401 
  402     rbtree_free(home_servers_byaddr);
  403     home_servers_byaddr = NULL;
  404 
  405     rbtree_free(home_pools_byname);
  406     home_pools_byname = NULL;
  407 #endif
  408 
  409     rbtree_free(realms_byname);
  410     realms_byname = NULL;
  411 
  412     realm_pool_free(NULL);
  413 
  414     talloc_free(realm_config);
  415     realm_config = NULL;
  416 }
  417 
  418 
  419 #ifdef WITH_PROXY
  420 static CONF_PARSER limit_config[] = {
  421     { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.max_connections), "16" },
  422     { "max_requests", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.max_requests), "0" },
  423     { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.lifetime), "0" },
  424     { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.idle_timeout), "0" },
  425     CONF_PARSER_TERMINATOR
  426 };
  427 
  428 #ifdef WITH_COA
  429 static CONF_PARSER home_server_coa[] = {
  430     { "irt",  FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_irt), STRINGIFY(2) },
  431     { "mrt",  FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrt), STRINGIFY(16) },
  432     { "mrc",  FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrc), STRINGIFY(5) },
  433     { "mrd",  FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrd), STRINGIFY(30) },
  434     CONF_PARSER_TERMINATOR
  435 };
  436 #endif
  437 
  438 static CONF_PARSER home_server_config[] = {
  439     { "ipaddr", FR_CONF_OFFSET(PW_TYPE_COMBO_IP_ADDR, home_server_t, ipaddr), NULL },
  440     { "ipv4addr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, home_server_t, ipaddr), NULL },
  441     { "ipv6addr", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, home_server_t, ipaddr), NULL },
  442     { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, server), NULL },
  443 
  444     { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, home_server_t, port), "0" },
  445 
  446     { "type", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, type_str), NULL },
  447 
  448 #ifdef WITH_TCP
  449     { "proto", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, proto_str), NULL },
  450 #endif
  451 
  452     { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, home_server_t, secret), NULL },
  453 
  454     { "src_ipaddr", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, src_ipaddr_str), NULL },
  455 
  456     { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, home_server_t, response_window), "30" },
  457     { "response_timeouts", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, max_response_timeouts), "1" },
  458     { "max_outstanding", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, max_outstanding), "65536" },
  459 
  460     { "zombie_period", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, zombie_period), "40" },
  461 
  462     { "status_check",  FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, ping_check_str), "none" },
  463     { "ping_check", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, ping_check_str), NULL },
  464 
  465     { "ping_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_interval), "30" },
  466     { "check_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_interval), NULL },
  467 
  468     { "check_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_timeout), "4" },
  469     { "status_check_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_timeout), NULL },
  470 
  471     { "num_answers_to_alive", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, num_pings_to_alive), "3" },
  472     { "revive_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, revive_interval), "300" },
  473 
  474     { "username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, ping_user_name), NULL },
  475     { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, ping_user_password), NULL },
  476 
  477 #ifdef WITH_STATS
  478     { "historic_average_window", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ema.window), NULL },
  479 #endif
  480 
  481     { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
  482 
  483 #ifdef WITH_COA
  484     { "coa", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) home_server_coa },
  485 #endif
  486 
  487     CONF_PARSER_TERMINATOR
  488 };
  489 
  490 
  491 static void null_free(UNUSED void *data)
  492 {
  493 }
  494 
  495 /*
  496  *  Ensure that all of the parameters in the home server are OK.
  497  */
  498 void realm_home_server_sanitize(home_server_t *home, CONF_SECTION *cs)
  499 {
  500     CONF_SECTION *parent = NULL;
  501 
  502     FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, >=, 8);
  503     FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, <=, 65536*16);
  504 
  505     FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, >=, 6);
  506     FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, <=, 120);
  507 
  508     FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, >=, 0, 1000);
  509     FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=,
  510                    main_config.max_request_time, 0);
  511     FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=, 60, 0);
  512 
  513     FR_INTEGER_BOUND_CHECK("response_timeouts", home->max_response_timeouts, >=, 1);
  514     FR_INTEGER_BOUND_CHECK("response_timeouts", home->max_response_timeouts, <=, 1000);
  515 
  516     /*
  517      *  Track the minimum response window, so that we can
  518      *  correctly set the timers in process.c
  519      */
  520     if (timercmp(&main_config.init_delay, &home->response_window, >)) {
  521         main_config.init_delay = home->response_window;
  522     }
  523 
  524     FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, 1);
  525     FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, <=, 120);
  526     FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, (uint32_t) home->response_window.tv_sec);
  527 
  528     FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, >=, 3);
  529     FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, <=, 10);
  530 
  531     FR_INTEGER_BOUND_CHECK("check_timeout", home->ping_timeout, >=, 1);
  532     FR_INTEGER_BOUND_CHECK("check_timeout", home->ping_timeout, <=, 10);
  533 
  534     FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, >=, 10);
  535     FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, <=, 3600);
  536 
  537 #ifdef WITH_COA
  538     FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, >=, 1);
  539     FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, <=, 5);
  540 
  541     FR_INTEGER_BOUND_CHECK("coa_mrc", home->coa_mrc, <=, 20);
  542 
  543     FR_INTEGER_BOUND_CHECK("coa_mrt", home->coa_mrt, <=, 30);
  544 
  545     FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, >=, 5);
  546     FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, <=, 60);
  547 #endif
  548 
  549     FR_INTEGER_BOUND_CHECK("max_connections", home->limit.max_connections, <=, 1024);
  550 
  551 #ifdef WITH_TCP
  552     /*
  553      *  UDP sockets can't be connection limited.
  554      */
  555     if (home->proto != IPPROTO_TCP) home->limit.max_connections = 0;
  556 #endif
  557 
  558     if ((home->limit.idle_timeout > 0) && (home->limit.idle_timeout < 5))
  559         home->limit.idle_timeout = 5;
  560     if ((home->limit.lifetime > 0) && (home->limit.lifetime < 5))
  561         home->limit.lifetime = 5;
  562     if ((home->limit.lifetime > 0) && (home->limit.idle_timeout > home->limit.lifetime))
  563         home->limit.idle_timeout = 0;
  564 
  565     /*
  566      *  Make sure that this is set.
  567      */
  568     if (home->src_ipaddr.af == AF_UNSPEC) {
  569         home->src_ipaddr.af = home->ipaddr.af;
  570     }
  571 
  572     parent = cf_item_parent(cf_section_to_item(cs));
  573     if (parent && strcmp(cf_section_name1(parent), "server") == 0) {
  574         home->parent_server = cf_section_name2(parent);
  575     }
  576 }
  577 
  578 /** Insert a new home server into the various internal lookup trees
  579  *
  580  * @param home server to add.
  581  * @param cs That defined the home server.
  582  * @return true on success else false.
  583  */
  584 static bool home_server_insert(home_server_t *home, CONF_SECTION *cs)
  585 {
  586     if (home->name && !rbtree_insert(home_servers_byname, home)) {
  587         cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
  588         return false;
  589     }
  590 
  591     if (!home->server && !rbtree_insert(home_servers_byaddr, home)) {
  592         rbtree_deletebydata(home_servers_byname, home);
  593         cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
  594         return false;
  595     }
  596 
  597 #ifdef WITH_STATS
  598     home->number = home_server_max_number++;
  599     if (!rbtree_insert(home_servers_bynumber, home)) {
  600         rbtree_deletebydata(home_servers_byname, home);
  601         if (home->ipaddr.af != AF_UNSPEC) {
  602             rbtree_deletebydata(home_servers_byname, home);
  603         }
  604         cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
  605         return false;
  606     }
  607 #endif
  608 
  609     return true;
  610 }
  611 
  612 /** Add an already allocate home_server_t to the various trees
  613  *
  614  * @param home server to add.
  615  * @return true on success, else false on error.
  616  */
  617 bool realm_home_server_add(home_server_t *home)
  618 {
  619     /*
  620      *  The structs aren't mutex protected.  Refuse to destroy
  621      *  the server.
  622      */
  623     if (event_loop_started && !realm_config->dynamic) {
  624         ERROR("Failed to add dynamic home server, \"dynamic = yes\" must be set in proxy.conf");
  625         return false;
  626     }
  627 
  628     if (home->name && (rbtree_finddata(home_servers_byname, home) != NULL)) {
  629         cf_log_err_cs(home->cs, "Duplicate home server name %s", home->name);
  630         return false;
  631     }
  632 
  633     if (!home->server && (rbtree_finddata(home_servers_byaddr, home) != NULL)) {
  634         char buffer[INET6_ADDRSTRLEN + 3];
  635 
  636         inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr, buffer, sizeof(buffer));
  637 
  638         cf_log_err_cs(home->cs, "Duplicate home server address%s%s%s: %s:%s%s/%i",
  639                   home->name ? " (already in use by " : "",
  640                   home->name ? home->name : "",
  641                   home->name ? ")" : "",
  642                   buffer,
  643                   fr_int2str(home_proto, home->proto, "<INVALID>"),
  644 #ifdef WITH_TLS
  645                   home->tls ? "+tls" : "",
  646 #else
  647                   "",
  648 #endif
  649                   home->port);
  650 
  651         return false;
  652     }
  653 
  654     if (!home_server_insert(home, home->cs)) return false;
  655 
  656     /*
  657      *  Dual home servers cause us to auto-create an
  658      *  accounting server for UDP sockets, and leave
  659      *  everything alone for TLS sockets.
  660      */
  661     if (home->dual
  662 #ifdef WITH_TLS
  663         && !home->tls
  664 #endif
  665 ) {
  666         home_server_t *home2 = talloc(talloc_parent(home), home_server_t);
  667 
  668         memcpy(home2, home, sizeof(*home2));
  669 
  670         home2->type = HOME_TYPE_ACCT;
  671         home2->dual = true;
  672         home2->port++;
  673 
  674         home2->ping_user_password = NULL;
  675         home2->cs = home->cs;
  676         home2->parent_server = home->parent_server;
  677 
  678         if (!home_server_insert(home2, home->cs)) {
  679             talloc_free(home2);
  680             return false;
  681         }
  682     }
  683 
  684     /*
  685      *  Mark it as already processed
  686      */
  687     cf_data_add(home->cs, "home_server", (void *)null_free, null_free);
  688 
  689     return true;
  690 }
  691 
  692 /** Alloc a new home server defined by a CONF_SECTION
  693  *
  694  * @param ctx to allocate home_server_t in.
  695  * @param rc Realm config, may be NULL in which case the global realm_config will be used.
  696  * @param cs Configuration section containing home server parameters.
  697  * @return a new home_server_t alloced in the context of the realm_config, or NULL on error.
  698  */
  699 home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SECTION *cs)
  700 {
  701     home_server_t   *home;
  702     CONF_SECTION    *tls;
  703 
  704     if (!rc) rc = realm_config; /* Use the global config */
  705 
  706     home = talloc_zero(ctx, home_server_t);
  707     home->name = cf_section_name2(cs);
  708     home->log_name = talloc_typed_strdup(home, home->name);
  709     home->cs = cs;
  710     home->state = HOME_STATE_UNKNOWN;
  711     home->proto = IPPROTO_UDP;
  712 
  713     /*
  714      *  Parse the configuration into the home server
  715      *  struct.
  716      */
  717     if (cf_section_parse(cs, home, home_server_config) < 0) goto error;
  718 
  719     /*
  720      *  It has an IP address, it must be a remote server.
  721      */
  722     if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
  723         if (fr_inaddr_any(&home->ipaddr) == 1) {
  724             cf_log_err_cs(cs, "Wildcard '*' addresses are not permitted for home servers");
  725             goto error;
  726         }
  727 
  728         if (!home->log_name) {
  729             char buffer[INET6_ADDRSTRLEN + 3];
  730 
  731             fr_ntop(buffer, sizeof(buffer), &home->ipaddr);
  732 
  733             home->log_name = talloc_asprintf(home, "%s:%i", buffer, home->port);
  734         }
  735     /*
  736      *  If it has a 'virtual_Server' config item, it's
  737      *  a loopback into a virtual server.
  738      */
  739     } else if (cf_pair_find(cs, "virtual_server") != NULL) {
  740         home->ipaddr.af = AF_UNSPEC;    /* mark ipaddr as unused */
  741 
  742         if (!home->server) {
  743             cf_log_err_cs(cs, "Invalid value for virtual_server");
  744             goto error;
  745         }
  746 
  747         /*
  748          *  Try and find a 'server' section off the root of
  749          *  the config with a name that matches the
  750          *  virtual_server.
  751          */
  752         if (!rc) goto error;
  753 
  754         if (!cf_section_sub_find_name2(rc->cs, "server", home->server)) {
  755             cf_log_err_cs(cs, "No such server %s", home->server);
  756             goto error;
  757         }
  758 
  759         home->secret = "";
  760         home->log_name = talloc_typed_strdup(home, home->server);
  761     /*
  762      *  Otherwise it's an invalid config section and we
  763      *  raise an error.
  764      */
  765     } else {
  766         cf_log_err_cs(cs, "No ipaddr, ipv4addr, ipv6addr, or virtual_server defined "
  767                   "for home server");
  768     error:
  769         talloc_free(home);
  770         return false;
  771     }
  772 
  773     {
  774         home_type_t type = HOME_TYPE_AUTH_ACCT;
  775 
  776         if (home->type_str) type = fr_str2int(home_server_types, home->type_str, HOME_TYPE_INVALID);
  777 
  778         home->type = type;
  779 
  780         switch (type) {
  781         case HOME_TYPE_AUTH_ACCT:
  782             home->dual = true;
  783             break;
  784 
  785         case HOME_TYPE_AUTH:
  786         case HOME_TYPE_ACCT:
  787             break;
  788 
  789 #ifdef WITH_COA
  790         case HOME_TYPE_COA:
  791             if (home->server != NULL) {
  792                 cf_log_err_cs(cs, "Home servers of type \"coa\" cannot point to a virtual server");
  793                 goto error;
  794             }
  795             break;
  796 #endif
  797 
  798         case HOME_TYPE_INVALID:
  799             cf_log_err_cs(cs, "Invalid type \"%s\" for home server %s", home->type_str, home->log_name);
  800             goto error;
  801         }
  802     }
  803 
  804     {
  805         home_ping_check_t type = HOME_PING_CHECK_NONE;
  806 
  807         if (home->ping_check_str) type = fr_str2int(home_ping_check, home->ping_check_str,
  808                                 HOME_PING_CHECK_INVALID);
  809 
  810         switch (type) {
  811         case HOME_PING_CHECK_STATUS_SERVER:
  812         case HOME_PING_CHECK_NONE:
  813             break;
  814 
  815         case HOME_PING_CHECK_REQUEST:
  816             if (!home->ping_user_name) {
  817                 cf_log_err_cs(cs, "You must supply a 'username' to enable status_check=request");
  818                 goto error;
  819             }
  820 
  821             if (((home->type == HOME_TYPE_AUTH) ||
  822                  (home->type == HOME_TYPE_AUTH_ACCT)) && !home->ping_user_password) {
  823                 cf_log_err_cs(cs, "You must supply a 'password' to enable status_check=request");
  824                 goto error;
  825             }
  826 
  827             break;
  828 
  829         case HOME_PING_CHECK_INVALID:
  830             cf_log_err_cs(cs, "Invalid status_check \"%s\" for home server %s",
  831                       home->ping_check_str, home->log_name);
  832             goto error;
  833         }
  834 
  835         home->ping_check = type;
  836     }
  837 
  838     {
  839         int proto = IPPROTO_UDP;
  840 
  841         if (home->proto_str) proto = fr_str2int(home_proto, home->proto_str, -1);
  842 
  843         switch (proto) {
  844         case IPPROTO_UDP:
  845 #ifdef WITH_TCP
  846             home_servers_udp = true;
  847 #endif
  848             break;
  849 
  850         case IPPROTO_TCP:
  851 #ifndef WITH_TCP
  852             cf_log_err_cs(cs, "Server not built with support for RADIUS over TCP");
  853             goto error;
  854 #endif
  855             if (home->ping_check != HOME_PING_CHECK_NONE) {
  856                 cf_log_err_cs(cs, "Only 'status_check = none' is allowed for home "
  857                           "servers with 'proto = tcp'");
  858                 goto error;
  859             }
  860             break;
  861 
  862         default:
  863             cf_log_err_cs(cs, "Unknown proto \"%s\"", home->proto_str);
  864             goto error;
  865         }
  866 
  867         home->proto = proto;
  868     }
  869 
  870     if (!home->server && rbtree_finddata(home_servers_byaddr, home)) {
  871         cf_log_err_cs(cs, "Duplicate home server");
  872         goto error;
  873     }
  874 
  875     /*
  876      *  Check the TLS configuration.
  877      */
  878     tls = cf_section_sub_find(cs, "tls");
  879 #ifndef WITH_TLS
  880     if (tls) {
  881         cf_log_err_cs(cs, "TLS transport is not available in this executable");
  882         goto error;
  883     }
  884 #endif
  885 
  886     /*
  887      *  If were doing RADSEC (tls+tcp) the secret should default
  888      *  to radsec, else a secret must be set.
  889      */
  890     if (!home->secret) {
  891 #ifdef WITH_TLS
  892         if (tls && (home->proto == IPPROTO_TCP)) {
  893             home->secret = "radsec";
  894         } else
  895 #endif
  896         {
  897             cf_log_err_cs(cs, "No shared secret defined for home server %s", home->log_name);
  898             goto error;
  899         }
  900     }
  901 
  902     /*
  903      *  Virtual servers have some TLS restrictions.
  904      */
  905     if (home->server) {
  906         if (tls) {
  907             cf_log_err_cs(cs, "Virtual home_servers cannot have a \"tls\" subsection");
  908             goto error;
  909         }
  910     } else {
  911         /*
  912          *  If the home is not a virtual server, guess the port
  913          *  and look up the source ip address.
  914          */
  915         rad_assert(home->ipaddr.af != AF_UNSPEC);
  916 
  917 #ifdef WITH_TLS
  918         if (tls && (home->proto != IPPROTO_TCP)) {
  919             cf_log_err_cs(cs, "TLS transport is not available for UDP sockets");
  920             goto error;
  921         }
  922 #endif
  923 
  924         /*
  925          *  Set the default port if necessary.
  926          */
  927         if (home->port == 0) {
  928             char buffer[INET6_ADDRSTRLEN + 3];
  929 
  930             /*
  931              *  For RADSEC we use the special RADIUS over TCP/TLS port
  932              *  for both accounting and authentication, but for some
  933              *  bizarre reason for RADIUS over plain TCP we use separate
  934              *  ports 1812 and 1813.
  935              */
  936 #ifdef WITH_TLS
  937             if (tls) {
  938                 home->port = PW_RADIUS_TLS_PORT;
  939             } else
  940 #endif
  941             switch (home->type) {
  942             default:
  943                 rad_assert(0);
  944                 /* FALL-THROUGH */
  945 
  946             /*
  947              *  One is added to get the accounting port
  948              *  for home->dual.
  949              */
  950             case HOME_TYPE_AUTH_ACCT:
  951             case HOME_TYPE_AUTH:
  952                 home->port = PW_AUTH_UDP_PORT;
  953                 break;
  954 
  955             case HOME_TYPE_ACCT:
  956                 home->port = PW_ACCT_UDP_PORT;
  957                 break;
  958 
  959             case HOME_TYPE_COA:
  960                 home->port = PW_COA_UDP_PORT;
  961                 break;
  962             }
  963 
  964             /*
  965              *  Now that we have a real port, use that.
  966              */
  967             rad_const_free(home->log_name);
  968 
  969             fr_ntop(buffer, sizeof(buffer), &home->ipaddr);
  970 
  971             home->log_name = talloc_asprintf(home, "%s:%i", buffer, home->port);
  972         }
  973 
  974         /*
  975          *  If we have a src_ipaddr_str resolve it to
  976          *  the same address family as the destination
  977          *  IP.
  978          */
  979         if (home->src_ipaddr_str) {
  980             if (ip_hton(&home->src_ipaddr, home->ipaddr.af, home->src_ipaddr_str, false) < 0) {
  981                 cf_log_err_cs(cs, "Failed parsing src_ipaddr");
  982                 goto error;
  983             }
  984         /*
  985          *  Source isn't specified, set it to the
  986          *  correct address family, but leave it as
  987          *  zeroes.
  988          */
  989         } else {
  990             home->src_ipaddr.af = home->ipaddr.af;
  991         }
  992 
  993 #ifdef WITH_TLS
  994         /*
  995          *  Parse the SSL client configuration.
  996          */
  997         if (tls) {
  998             home->tls = tls_client_conf_parse(tls);
  999             if (!home->tls) {
 1000                 goto error;
 1001             }
 1002         }
 1003 #endif
 1004     } /* end of parse home server */
 1005 
 1006     realm_home_server_sanitize(home, cs);
 1007 
 1008     return home;
 1009 }
 1010 
 1011 /** Fixup a client configuration section to specify a home server
 1012  *
 1013  * This is used to create the equivalent CoA home server entry for a client,
 1014  * so that the server can originate CoA messages.
 1015  *
 1016  * The server section automatically inherits the following fields from the client:
 1017  *  - ipaddr/ipv4addr/ipv6addr
 1018  *  - secret
 1019  *  - src_ipaddr
 1020  *
 1021  * @note new CONF_SECTION will be allocated in the context of the client, but the client
 1022  *  CONF_SECTION will not be modified.
 1023  *
 1024  * @param client CONF_SECTION to inherit values from.
 1025  * @return a new server CONF_SCTION, or a pointer to the existing CONF_SECTION in the client.
 1026  */
 1027 CONF_SECTION *home_server_cs_afrom_client(CONF_SECTION *client)
 1028 {
 1029     CONF_SECTION *server, *cs;
 1030     CONF_PAIR *cp;
 1031 
 1032     /*
 1033      *  Alloc a plain home server for both cases
 1034      *
 1035      *  There's no way these can be referenced by a pool,
 1036      *  and they may conflict with home servers in proxy.conf
 1037      *  so it's easier to not set a name.
 1038      */
 1039 
 1040     /*
 1041      *
 1042      *  Duplicate the server section, so we don't mangle
 1043      *  the client CONF_SECTION we were passed.
 1044      */
 1045     cs = cf_section_sub_find(client, "coa_server");
 1046     if (cs) {
 1047         server = cf_section_dup(client, cs, "home_server", NULL, true);
 1048     } else {
 1049         server = cf_section_alloc(client, "home_server", cf_section_name2(client));
 1050     }
 1051 
 1052     if (!cs || (!cf_pair_find(cs, "ipaddr") && !cf_pair_find(cs, "ipv4addr") && !cf_pair_find(cs, "ipv6addr"))) {
 1053         cp = cf_pair_find(client, "ipaddr");
 1054         if (!cp) cp = cf_pair_find(client, "ipv4addr");
 1055         if (!cp) cp = cf_pair_find(client, "ipv6addr");
 1056 
 1057         cf_pair_add(server, cf_pair_dup(server, cp));
 1058     }
 1059 
 1060     if (!cs || !cf_pair_find(cs, "secret")) {
 1061         cp = cf_pair_find(client, "secret");
 1062         if (cp) cf_pair_add(server, cp);
 1063     }
 1064 
 1065     if (!cs || !cf_pair_find(cs, "src_ipaddr")) {
 1066         cp = cf_pair_find(client, "src_ipaddr");
 1067         if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
 1068     }
 1069 
 1070     if (!cs || !(cp = cf_pair_find(cs, "type"))) {
 1071         cp = cf_pair_alloc(server, "type", "coa", T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
 1072         if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
 1073     } else if (strcmp(cf_pair_value(cp), "coa") != 0) {
 1074         talloc_free(server);
 1075         cf_log_err_cs(server, "server.type must be \"coa\"");
 1076         return NULL;
 1077     }
 1078 
 1079     return server;
 1080 }
 1081 
 1082 static home_pool_t *server_pool_alloc(char const *name, home_pool_type_t type,
 1083                       home_type_t server_type, int num_home_servers)
 1084 {
 1085     home_pool_t *pool;
 1086 
 1087     pool = rad_malloc(sizeof(*pool) + (sizeof(pool->servers[0]) * num_home_servers));
 1088     if (!pool) return NULL; /* just for pairanoia */
 1089 
 1090     memset(pool, 0, sizeof(*pool) + (sizeof(pool->servers[0]) * num_home_servers));
 1091 
 1092     pool->name = name;
 1093     pool->type = type;
 1094     pool->server_type = server_type;
 1095     pool->num_home_servers = num_home_servers;
 1096 
 1097     return pool;
 1098 }
 1099 
 1100 /*
 1101  * Ensure any home_server clauses in a home_server_pool section reference
 1102  * defined home servers, which should already have been created, regardless
 1103  * of where they appear in the configuration.
 1104  */
 1105 static int pool_check_home_server(UNUSED realm_config_t *rc, CONF_PAIR *cp,
 1106                   char const *name, home_type_t server_type,
 1107                   home_server_t **phome)
 1108 {
 1109     home_server_t myhome, *home;
 1110 
 1111     if (!name) {
 1112         cf_log_err_cp(cp,
 1113                "No value given for home_server");
 1114         return 0;
 1115     }
 1116 
 1117     myhome.name = name;
 1118     myhome.type = server_type;
 1119     home = rbtree_finddata(home_servers_byname, &myhome);
 1120     if (home) {
 1121         *phome = home;
 1122         return 1;
 1123     }
 1124 
 1125     switch (server_type) {
 1126     case HOME_TYPE_AUTH:
 1127     case HOME_TYPE_ACCT:
 1128         myhome.type = HOME_TYPE_AUTH_ACCT;
 1129         home = rbtree_finddata(home_servers_byname, &myhome);
 1130         if (home) {
 1131             *phome = home;
 1132             return 1;
 1133         }
 1134         break;
 1135 
 1136     default:
 1137         break;
 1138     }
 1139 
 1140     cf_log_err_cp(cp, "Unknown home_server \"%s\".", name);
 1141     return 0;
 1142 }
 1143 
 1144 
 1145 #ifndef HAVE_PTHREAD_H
 1146 void realm_pool_free(home_pool_t *pool)
 1147 {
 1148     if (!event_loop_started) return;
 1149     if (!realm_config->dynamic) return;
 1150 
 1151     talloc_free(pool);
 1152 }
 1153 #else  /* HAVE_PTHREAD_H */
 1154 typedef struct pool_list_t pool_list_t;
 1155 
 1156 struct pool_list_t {
 1157     pool_list_t *next;
 1158     home_pool_t *pool;
 1159     time_t      when;
 1160 };
 1161 
 1162 static bool     pool_free_init = false;
 1163 static pthread_mutex_t  pool_free_mutex;
 1164 static pool_list_t  *pool_list = NULL;
 1165 
 1166 void realm_pool_free(home_pool_t *pool)
 1167 {
 1168     int i;
 1169     time_t now;
 1170     pool_list_t *this, **last;
 1171 
 1172     if (!event_loop_started) return;
 1173     if (!realm_config->dynamic) return;
 1174 
 1175     if (pool) {
 1176         /*
 1177          *  Double-check that the realm wasn't loaded from the
 1178          *  configuration files.
 1179          */
 1180         for (i = 0; i < pool->num_home_servers; i++) {
 1181             if (pool->servers[i]->cs) {
 1182                 rad_assert(0 == 1);
 1183                 return;
 1184             }
 1185         }
 1186     }
 1187 
 1188     if (!pool_free_init) {
 1189         pthread_mutex_init(&pool_free_mutex, NULL);
 1190         pool_free_init = true;
 1191     }
 1192 
 1193     /*
 1194      *  Ensure only one caller at a time is freeing a pool.
 1195      */
 1196     pthread_mutex_lock(&pool_free_mutex);
 1197 
 1198     /*
 1199      *  Free all of the pools.
 1200      */
 1201     if (!pool) {
 1202         while ((this = pool_list) != NULL) {
 1203             pool_list = this->next;
 1204             talloc_free(this->pool);
 1205             talloc_free(this);
 1206         }
 1207         pthread_mutex_unlock(&pool_free_mutex);
 1208         return;
 1209     }
 1210 
 1211     now = time(NULL);
 1212 
 1213     /*
 1214      *  Free the oldest pool(s)
 1215      */
 1216     while ((this = pool_list) != NULL) {
 1217         if (this->when > now) break;
 1218 
 1219         pool_list = this->next;
 1220         talloc_free(this->pool);
 1221         talloc_free(this);
 1222     }
 1223 
 1224     /*
 1225      *  Add this pool to the end of the list.
 1226      */
 1227     for (last = &pool_list;
 1228          *last != NULL;
 1229          last = &((*last))->next) {
 1230         /* do nothing */
 1231     }
 1232 
 1233     *last = this = talloc(NULL, pool_list_t);
 1234     if (!this) {
 1235         talloc_free(pool); /* hope for the best */
 1236         pthread_mutex_unlock(&pool_free_mutex);
 1237         return;
 1238     }
 1239 
 1240     this->next = NULL;
 1241     this->when = now + 300;
 1242     this->pool = pool;
 1243     pthread_mutex_unlock(&pool_free_mutex);
 1244 }
 1245 #endif  /* HAVE_PTHREAD_H */
 1246 
 1247 int realm_pool_add(home_pool_t *pool, UNUSED CONF_SECTION *cs)
 1248 {
 1249     /*
 1250      *  The structs aren't mutex protected.  Refuse to destroy
 1251      *  the server.
 1252      */
 1253     if (event_loop_started && !realm_config->dynamic) {
 1254         DEBUG("Must set \"dynamic = true\" in proxy.conf");
 1255         return 0;
 1256     }
 1257 
 1258     if (!rbtree_insert(home_pools_byname, pool)) {
 1259         rad_assert("Internal sanity check failed" == NULL);
 1260         return 0;
 1261     }
 1262 
 1263     return 1;
 1264 }
 1265 
 1266 static int server_pool_add(realm_config_t *rc,
 1267                CONF_SECTION *cs, home_type_t server_type, bool do_print)
 1268 {
 1269     char const *name2;
 1270     home_pool_t *pool = NULL;
 1271     char const *value;
 1272     CONF_PAIR *cp;
 1273     int num_home_servers;
 1274     home_server_t *home;
 1275 
 1276     name2 = cf_section_name1(cs);
 1277     if (!name2 || ((strcasecmp(name2, "server_pool") != 0) &&
 1278                (strcasecmp(name2, "home_server_pool") != 0))) {
 1279         cf_log_err_cs(cs,
 1280                "Section is not a home_server_pool");
 1281         return 0;
 1282     }
 1283 
 1284     name2 = cf_section_name2(cs);
 1285     if (!name2) {
 1286         cf_log_err_cs(cs,
 1287                "Server pool section is missing a name");
 1288         return 0;
 1289     }
 1290 
 1291     /*
 1292      *  Count the home servers and initalize them.
 1293      */
 1294     num_home_servers = 0;
 1295     for (cp = cf_pair_find(cs, "home_server");
 1296          cp != NULL;
 1297          cp = cf_pair_find_next(cs, cp, "home_server")) {
 1298         num_home_servers++;
 1299 
 1300         if (!pool_check_home_server(rc, cp, cf_pair_value(cp),
 1301                         server_type, &home)) {
 1302             return 0;
 1303         }
 1304     }
 1305 
 1306     if (num_home_servers == 0) {
 1307         cf_log_err_cs(cs,
 1308                "No home servers defined in pool %s",
 1309                name2);
 1310         goto error;
 1311     }
 1312 
 1313     pool = server_pool_alloc(name2, HOME_POOL_FAIL_OVER, server_type,
 1314                  num_home_servers);
 1315     if (!pool) {
 1316         cf_log_err_cs(cs, "Failed allocating memory for pool");
 1317         goto error;
 1318     }
 1319     pool->cs = cs;
 1320 
 1321 
 1322     /*
 1323      *  Fallback servers must be defined, and must be
 1324      *  virtual servers.
 1325      */
 1326     cp = cf_pair_find(cs, "fallback");
 1327     if (cp) {
 1328 #ifdef WITH_COA
 1329         if (server_type == HOME_TYPE_COA) {
 1330             cf_log_err_cs(cs, "Home server pools of type \"coa\" cannot have a fallback virtual server");
 1331             goto error;
 1332         }
 1333 #endif
 1334 
 1335         if (!pool_check_home_server(rc, cp, cf_pair_value(cp), server_type, &pool->fallback)) {
 1336             goto error;
 1337         }
 1338 
 1339         if (!pool->fallback->server) {
 1340             cf_log_err_cs(cs, "Fallback home_server %s does NOT contain a virtual_server directive",
 1341                       pool->fallback->log_name);
 1342             goto error;
 1343         }
 1344     }
 1345 
 1346     if (do_print) cf_log_info(cs, " home_server_pool %s {", name2);
 1347 
 1348     cp = cf_pair_find(cs, "type");
 1349     if (cp) {
 1350         static FR_NAME_NUMBER pool_types[] = {
 1351             { "load-balance", HOME_POOL_LOAD_BALANCE },
 1352 
 1353             { "fail-over", HOME_POOL_FAIL_OVER },
 1354             { "fail_over", HOME_POOL_FAIL_OVER },
 1355 
 1356             { "round-robin", HOME_POOL_LOAD_BALANCE },
 1357             { "round_robin", HOME_POOL_LOAD_BALANCE },
 1358 
 1359             { "client-balance", HOME_POOL_CLIENT_BALANCE },
 1360             { "client-port-balance", HOME_POOL_CLIENT_PORT_BALANCE },
 1361             { "keyed-balance", HOME_POOL_KEYED_BALANCE },
 1362             { NULL, 0 }
 1363         };
 1364 
 1365         value = cf_pair_value(cp);
 1366         if (!value) {
 1367             cf_log_err_cp(cp,
 1368                    "No value given for type");
 1369             goto error;
 1370         }
 1371 
 1372         pool->type = fr_str2int(pool_types, value, 0);
 1373         if (!pool->type) {
 1374             cf_log_err_cp(cp,
 1375                    "Unknown type \"%s\".",
 1376                    value);
 1377             goto error;
 1378         }
 1379 
 1380         if (do_print) cf_log_info(cs, "\ttype = %s", value);
 1381     }
 1382 
 1383     cp = cf_pair_find(cs, "virtual_server");
 1384     if (cp) {
 1385         pool->virtual_server = cf_pair_value(cp);
 1386         if (!pool->virtual_server) {
 1387             cf_log_err_cp(cp, "No value given for virtual_server");
 1388             goto error;
 1389         }
 1390 
 1391         if (do_print) {
 1392             cf_log_info(cs, "\tvirtual_server = %s", pool->virtual_server);
 1393         }
 1394 
 1395         if (!cf_section_sub_find_name2(rc->cs, "server", pool->virtual_server)) {
 1396             cf_log_err_cp(cp, "No such server %s", pool->virtual_server);
 1397             goto error;
 1398         }
 1399 
 1400     }
 1401 
 1402     num_home_servers = 0;
 1403     for (cp = cf_pair_find(cs, "home_server");
 1404          cp != NULL;
 1405          cp = cf_pair_find_next(cs, cp, "home_server")) {
 1406         home_server_t myhome;
 1407 
 1408         value = cf_pair_value(cp);
 1409 
 1410         memset(&myhome, 0, sizeof(myhome));
 1411         myhome.name = value;
 1412         myhome.type = server_type;
 1413 
 1414         home = rbtree_finddata(home_servers_byname, &myhome);
 1415         if (!home) {
 1416             switch (server_type) {
 1417             case HOME_TYPE_AUTH:
 1418             case HOME_TYPE_ACCT:
 1419                 myhome.type = HOME_TYPE_AUTH_ACCT;
 1420                 home = rbtree_finddata(home_servers_byname, &myhome);
 1421                 break;
 1422 
 1423             default:
 1424                 break;
 1425             }
 1426         }
 1427 
 1428         if (!home) {
 1429             ERROR("Failed to find home server %s", value);
 1430             goto error;
 1431         }
 1432 
 1433         if (do_print) cf_log_info(cs, "\thome_server = %s", home->name);
 1434         pool->servers[num_home_servers++] = home;
 1435     } /* loop over home_server's */
 1436 
 1437     if (pool->fallback && do_print) {
 1438         cf_log_info(cs, "\tfallback = %s", pool->fallback->name);
 1439     }
 1440 
 1441     if (!realm_pool_add(pool, cs)) goto error;
 1442 
 1443     if (do_print) cf_log_info(cs, " }");
 1444 
 1445     cf_data_add(cs, "home_server_pool", pool, free);
 1446 
 1447     rad_assert(pool->server_type != 0);
 1448 
 1449     return 1;
 1450 
 1451  error:
 1452     if (do_print) cf_log_info(cs, " }");
 1453     free(pool);
 1454     return 0;
 1455 }
 1456 #endif
 1457 
 1458 static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
 1459               char const *realm,
 1460               char const *name, char const *secret,
 1461               home_pool_type_t ldflag, home_pool_t **pool_p,
 1462               home_type_t type, char const *server)
 1463 {
 1464 #ifdef WITH_PROXY
 1465     int i, insert_point, num_home_servers;
 1466     home_server_t myhome, *home;
 1467     home_pool_t mypool, *pool;
 1468     CONF_SECTION *subcs;
 1469 #else
 1470     (void) rc;      /* -Wunused */
 1471     (void) realm;
 1472     (void) secret;
 1473     (void) ldflag;
 1474     (void) type;
 1475     (void) server;
 1476 #endif
 1477 
 1478     /*
 1479      *  LOCAL realms get sanity checked, and nothing else happens.
 1480      */
 1481     if (strcmp(name, "LOCAL") == 0) {
 1482         if (*pool_p) {
 1483             cf_log_err_cs(cs, "Realm \"%s\" cannot be both LOCAL and remote", name);
 1484             return 0;
 1485         }
 1486         return 1;
 1487     }
 1488 
 1489 #ifndef WITH_PROXY
 1490     return 0;       /* Not proxying.  Can't do non-LOCAL realms */
 1491 
 1492 #else
 1493     mypool.name = realm;
 1494     mypool.server_type = type;
 1495     pool = rbtree_finddata(home_pools_byname, &mypool);
 1496     if (pool) {
 1497         if (pool->type != ldflag) {
 1498             cf_log_err_cs(cs, "Inconsistent ldflag for server pool \"%s\"", name);
 1499             return 0;
 1500         }
 1501 
 1502         if (pool->server_type != type) {
 1503             cf_log_err_cs(cs, "Inconsistent home server type for server pool \"%s\"", name);
 1504             return 0;
 1505         }
 1506     }
 1507 
 1508     myhome.name = name;
 1509     myhome.type = type;
 1510     home = rbtree_finddata(home_servers_byname, &myhome);
 1511     if (home) {
 1512         WARN("Please use pools instead of authhost and accthost");
 1513 
 1514         if (secret && (strcmp(home->secret, secret) != 0)) {
 1515             cf_log_err_cs(cs, "Inconsistent shared secret for home server \"%s\"", name);
 1516             return 0;
 1517         }
 1518 
 1519         if (home->type != type) {
 1520             cf_log_err_cs(cs, "Inconsistent type for home server \"%s\"", name);
 1521             return 0;
 1522         }
 1523 
 1524         /*
 1525          *  Don't check for duplicate home servers.  If
 1526          *  the user specifies that, well, they can do it.
 1527          *
 1528          *  Allowing duplicates means that all of the
 1529          *  realm->server[] entries are filled, which is
 1530          *  what the rest of the code assumes.
 1531          */
 1532     }
 1533 
 1534     /*
 1535      *  If we do have a pool, check that there is room to
 1536      *  insert the home server we've found, or the one that we
 1537      *  create here.
 1538      *
 1539      *  Note that we insert it into the LAST available
 1540      *  position, in order to maintain the same order as in
 1541      *  the configuration files.
 1542      */
 1543     insert_point = -1;
 1544     if (pool) {
 1545         for (i = pool->num_home_servers - 1; i >= 0; i--) {
 1546             if (pool->servers[i]) break;
 1547 
 1548             if (!pool->servers[i]) {
 1549                 insert_point = i;
 1550             }
 1551         }
 1552 
 1553         if (insert_point < 0) {
 1554             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);
 1555             return 0;
 1556         }
 1557     }
 1558 
 1559     /*
 1560      *  No home server, allocate one.
 1561      */
 1562     if (!home) {
 1563         char const *p;
 1564         char *q;
 1565 
 1566         home = talloc_zero(rc, home_server_t);
 1567         home->name = name;
 1568         home->type = type;
 1569         home->secret = secret;
 1570         home->cs = cs;
 1571         home->proto = IPPROTO_UDP;
 1572 
 1573         p = strchr(name, ':');
 1574         if (!p) {
 1575             if (type == HOME_TYPE_AUTH) {
 1576                 home->port = PW_AUTH_UDP_PORT;
 1577             } else {
 1578                 home->port = PW_ACCT_UDP_PORT;
 1579             }
 1580 
 1581             p = name;
 1582             q = NULL;
 1583 
 1584         } else if (p == name) {
 1585             cf_log_err_cs(cs, "Invalid hostname %s", name);
 1586             talloc_free(home);
 1587             return 0;
 1588         } else {
 1589             unsigned long port = strtoul(p + 1, NULL, 0);
 1590             if ((port == 0) || (port > 65535)) {
 1591                 cf_log_err_cs(cs, "Invalid port %s", p + 1);
 1592                 talloc_free(home);
 1593                 return 0;
 1594             }
 1595 
 1596             home->port = (uint16_t)port;
 1597             q = talloc_array(home, char, (p - name) + 1);
 1598             memcpy(q, name, (p - name));
 1599             q[p - name] = '\0';
 1600             p = q;
 1601         }
 1602 
 1603         if (!server) {
 1604             if (ip_hton(&home->ipaddr, AF_UNSPEC, p, false) < 0) {
 1605                 cf_log_err_cs(cs,
 1606                        "Failed looking up hostname %s.",
 1607                        p);
 1608                 talloc_free(home);
 1609                 talloc_free(q);
 1610                 return 0;
 1611             }
 1612             home->src_ipaddr.af = home->ipaddr.af;
 1613         } else {
 1614             home->ipaddr.af = AF_UNSPEC;
 1615             home->server = server;
 1616         }
 1617         talloc_free(q);
 1618 
 1619         /*
 1620          *  Use the old-style configuration.
 1621          */
 1622         home->max_outstanding = 65535*16;
 1623         home->zombie_period = rc->retry_delay * rc->retry_count;
 1624         if (home->zombie_period < 2) home->zombie_period = 30;
 1625         home->response_window.tv_sec = home->zombie_period - 1;
 1626         home->response_window.tv_usec = 0;
 1627 
 1628         home->ping_check = HOME_PING_CHECK_NONE;
 1629 
 1630         home->revive_interval = rc->dead_time;
 1631 
 1632         if (rbtree_finddata(home_servers_byaddr, home)) {
 1633             cf_log_err_cs(cs, "Home server %s has the same IP address and/or port as another home server.", name);
 1634             talloc_free(home);
 1635             return 0;
 1636         }
 1637 
 1638         if (!rbtree_insert(home_servers_byname, home)) {
 1639             cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
 1640             talloc_free(home);
 1641             return 0;
 1642         }
 1643 
 1644         if (!rbtree_insert(home_servers_byaddr, home)) {
 1645             rbtree_deletebydata(home_servers_byname, home);
 1646             cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
 1647             talloc_free(home);
 1648             return 0;
 1649         }
 1650 
 1651 #ifdef WITH_STATS
 1652         home->number = home_server_max_number++;
 1653         if (!rbtree_insert(home_servers_bynumber, home)) {
 1654             rbtree_deletebydata(home_servers_byname, home);
 1655             if (home->ipaddr.af != AF_UNSPEC) {
 1656                 rbtree_deletebydata(home_servers_byname, home);
 1657             }
 1658             cf_log_err_cs(cs,
 1659                    "Internal error %d adding home server %s.",
 1660                    __LINE__, name);
 1661             talloc_free(home);
 1662             return 0;
 1663         }
 1664 #endif
 1665     }
 1666 
 1667     /*
 1668      *  We now have a home server, see if we can insert it
 1669      *  into pre-existing pool.
 1670      */
 1671     if (insert_point >= 0) {
 1672         rad_assert(pool != NULL);
 1673         pool->servers[insert_point] = home;
 1674         return 1;
 1675     }
 1676 
 1677     rad_assert(pool == NULL);
 1678     rad_assert(home != NULL);
 1679 
 1680     /*
 1681      *  Count the old-style realms of this name.
 1682      */
 1683     num_home_servers = 0;
 1684     for (subcs = cf_section_find_next(cs, NULL, "realm");
 1685          subcs != NULL;
 1686          subcs = cf_section_find_next(cs, subcs, "realm")) {
 1687         char const *this = cf_section_name2(subcs);
 1688 
 1689         if (!this || (strcmp(this, realm) != 0)) continue;
 1690         num_home_servers++;
 1691     }
 1692 
 1693     if (num_home_servers == 0) {
 1694         cf_log_err_cs(cs, "Internal error counting pools for home server %s.", name);
 1695         talloc_free(home);
 1696         return 0;
 1697     }
 1698 
 1699     pool = server_pool_alloc(realm, ldflag, type, num_home_servers);
 1700     if (!pool) {
 1701         cf_log_err_cs(cs, "Out of memory");
 1702         return 0;
 1703     }
 1704 
 1705     pool->cs = cs;
 1706 
 1707     pool->servers[0] = home;
 1708 
 1709     if (!rbtree_insert(home_pools_byname, pool)) {
 1710         rad_assert("Internal sanity check failed" == NULL);
 1711         return 0;
 1712     }
 1713 
 1714     *pool_p = pool;
 1715 
 1716     return 1;
 1717 #endif
 1718 }
 1719 
 1720 static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
 1721 {
 1722     char const *host;
 1723     char const *secret = NULL;
 1724     home_pool_type_t ldflag;
 1725     CONF_PAIR *cp;
 1726 
 1727     cp = cf_pair_find(cs, "ldflag");
 1728     ldflag = HOME_POOL_FAIL_OVER;
 1729     if (cp) {
 1730         host = cf_pair_value(cp);
 1731         if (!host) {
 1732             cf_log_err_cp(cp, "No value specified for ldflag");
 1733             return 0;
 1734         }
 1735 
 1736         if (strcasecmp(host, "fail_over") == 0) {
 1737             cf_log_info(cs, "\tldflag = fail_over");
 1738 
 1739         } else if (strcasecmp(host, "round_robin") == 0) {
 1740             ldflag = HOME_POOL_LOAD_BALANCE;
 1741             cf_log_info(cs, "\tldflag = round_robin");
 1742 
 1743         } else {
 1744             cf_log_err_cs(cs, "Unknown value \"%s\" for ldflag", host);
 1745             return 0;
 1746         }
 1747     } /* else don't print it. */
 1748 
 1749     /*
 1750      *  Allow old-style if it doesn't exist, or if it exists and
 1751      *  it's LOCAL.
 1752      */
 1753     cp = cf_pair_find(cs, "authhost");
 1754     if (cp) {
 1755         host = cf_pair_value(cp);
 1756         if (!host) {
 1757             cf_log_err_cp(cp, "No value specified for authhost");
 1758             return 0;
 1759         }
 1760 
 1761         if (strcmp(host, "LOCAL") != 0) {
 1762             cp = cf_pair_find(cs, "secret");
 1763             if (!cp) {
 1764                 cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
 1765                 return 0;
 1766             }
 1767 
 1768             secret = cf_pair_value(cp);
 1769             if (!secret) {
 1770                 cf_log_err_cp(cp, "No value specified for secret");
 1771                 return 0;
 1772             }
 1773         }
 1774 
 1775         cf_log_info(cs, "\tauthhost = %s",  host);
 1776 
 1777         if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
 1778                     &r->auth_pool, HOME_TYPE_AUTH, NULL)) {
 1779             return 0;
 1780         }
 1781     }
 1782 
 1783     cp = cf_pair_find(cs, "accthost");
 1784     if (cp) {
 1785         host = cf_pair_value(cp);
 1786         if (!host) {
 1787             cf_log_err_cp(cp, "No value specified for accthost");
 1788             return 0;
 1789         }
 1790 
 1791         /*
 1792          *  Don't look for a secret again if it was found
 1793          *  above.
 1794          */
 1795         if ((strcmp(host, "LOCAL") != 0) && !secret) {
 1796             cp = cf_pair_find(cs, "secret");
 1797             if (!cp) {
 1798                 cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
 1799                 return 0;
 1800             }
 1801 
 1802             secret = cf_pair_value(cp);
 1803             if (!secret) {
 1804                 cf_log_err_cp(cp, "No value specified for secret");
 1805                 return 0;
 1806             }
 1807         }
 1808 
 1809         cf_log_info(cs, "\taccthost = %s", host);
 1810 
 1811         if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
 1812                     &r->acct_pool, HOME_TYPE_ACCT, NULL)) {
 1813             return 0;
 1814         }
 1815     }
 1816 
 1817     cp = cf_pair_find(cs, "virtual_server");
 1818     if (cp) {
 1819         host = cf_pair_value(cp);
 1820         if (!host) {
 1821             cf_log_err_cp(cp, "No value specified for virtual_server");
 1822             return 0;
 1823         }
 1824 
 1825         cf_log_info(cs, "\tvirtual_server = %s", host);
 1826 
 1827         if (!old_server_add(rc, cs, r->name, host, "", ldflag,
 1828                     &r->auth_pool, HOME_TYPE_AUTH, host)) {
 1829             return 0;
 1830         }
 1831         if (!old_server_add(rc, cs, r->name, host, "", ldflag,
 1832                     &r->acct_pool, HOME_TYPE_ACCT, host)) {
 1833             return 0;
 1834         }
 1835     }
 1836 
 1837     if (secret) {
 1838         if (rad_debug_lvl <= 2) {
 1839             cf_log_info(cs, "\tsecret = <<< secret >>>");
 1840         } else {
 1841             cf_log_info(cs, "\tsecret = %s", secret);
 1842         }
 1843     }
 1844 
 1845     return 1;
 1846 
 1847 }
 1848 
 1849 
 1850 #ifdef WITH_PROXY
 1851 static int add_pool_to_realm(realm_config_t *rc, CONF_SECTION *cs,
 1852                  char const *name, home_pool_t **dest,
 1853                  home_type_t server_type, bool do_print)
 1854 {
 1855     home_pool_t mypool, *pool;
 1856 
 1857     mypool.name = name;
 1858     mypool.server_type = server_type;
 1859 
 1860     pool = rbtree_finddata(home_pools_byname, &mypool);
 1861     if (!pool) {
 1862         CONF_SECTION *pool_cs;
 1863 
 1864         pool_cs = cf_section_sub_find_name2(rc->cs,
 1865                             "home_server_pool",
 1866                             name);
 1867         if (!pool_cs) {
 1868             pool_cs = cf_section_sub_find_name2(rc->cs,
 1869                                 "server_pool",
 1870                                 name);
 1871         }
 1872         if (!pool_cs) {
 1873             cf_log_err_cs(cs, "Failed to find home_server_pool \"%s\"", name);
 1874             return 0;
 1875         }
 1876 
 1877         if (!server_pool_add(rc, pool_cs, server_type, do_print)) {
 1878             return 0;
 1879         }
 1880 
 1881         pool = rbtree_finddata(home_pools_byname, &mypool);
 1882         if (!pool) {
 1883             ERROR("Internal sanity check failed in add_pool_to_realm");
 1884             return 0;
 1885         }
 1886     }
 1887 
 1888     if (pool->server_type != server_type) {
 1889         cf_log_err_cs(cs, "Incompatible home_server_pool \"%s\" (mixed auth_pool / acct_pool)", name);
 1890         return 0;
 1891     }
 1892 
 1893     *dest = pool;
 1894 
 1895     return 1;
 1896 }
 1897 #endif
 1898 
 1899 
 1900 static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
 1901 {
 1902     char const *name2;
 1903     REALM *r = NULL;
 1904     CONF_PAIR *cp;
 1905 #ifdef WITH_PROXY
 1906     home_pool_t *auth_pool, *acct_pool;
 1907     char const *auth_pool_name, *acct_pool_name;
 1908 #ifdef WITH_COA
 1909     char const *coa_pool_name;
 1910     home_pool_t *coa_pool;
 1911 #endif
 1912 #endif
 1913 
 1914     name2 = cf_section_name1(cs);
 1915     if (!name2 || (strcasecmp(name2, "realm") != 0)) {
 1916         cf_log_err_cs(cs, "Section is not a realm");
 1917         return 0;
 1918     }
 1919 
 1920     name2 = cf_section_name2(cs);
 1921     if (!name2) {
 1922         cf_log_err_cs(cs, "Realm section is missing the realm name");
 1923         return 0;
 1924     }
 1925 
 1926 #ifdef WITH_PROXY
 1927     auth_pool = acct_pool = NULL;
 1928     auth_pool_name = acct_pool_name = NULL;
 1929 #ifdef WITH_COA
 1930     coa_pool = NULL;
 1931     coa_pool_name = NULL;
 1932 #endif
 1933 
 1934     /*
 1935      *  Prefer new configuration to old one.
 1936      */
 1937     cp = cf_pair_find(cs, "pool");
 1938     if (!cp) cp = cf_pair_find(cs, "home_server_pool");
 1939     if (cp) auth_pool_name = cf_pair_value(cp);
 1940     if (cp && auth_pool_name) {
 1941         acct_pool_name = auth_pool_name;
 1942         if (!add_pool_to_realm(rc, cs,
 1943                        auth_pool_name, &auth_pool,
 1944                        HOME_TYPE_AUTH, 1)) {
 1945             return 0;
 1946         }
 1947         if (!add_pool_to_realm(rc, cs,
 1948                        auth_pool_name, &acct_pool,
 1949                        HOME_TYPE_ACCT, 0)) {
 1950             return 0;
 1951         }
 1952     }
 1953 
 1954     cp = cf_pair_find(cs, "auth_pool");
 1955     if (cp) auth_pool_name = cf_pair_value(cp);
 1956     if (cp && auth_pool_name) {
 1957         if (auth_pool) {
 1958             cf_log_err_cs(cs, "Cannot use \"pool\" and \"auth_pool\" at the same time");
 1959             return 0;
 1960         }
 1961         if (!add_pool_to_realm(rc, cs,
 1962                        auth_pool_name, &auth_pool,
 1963                        HOME_TYPE_AUTH, 1)) {
 1964             return 0;
 1965         }
 1966     }
 1967 
 1968     cp = cf_pair_find(cs, "acct_pool");
 1969     if (cp) acct_pool_name = cf_pair_value(cp);
 1970     if (cp && acct_pool_name) {
 1971         bool do_print = true;
 1972 
 1973         if (acct_pool) {
 1974             cf_log_err_cs(cs, "Cannot use \"pool\" and \"acct_pool\" at the same time");
 1975             return 0;
 1976         }
 1977 
 1978         if (!auth_pool ||
 1979             (auth_pool_name &&
 1980              (strcmp(auth_pool_name, acct_pool_name) != 0))) {
 1981             do_print = true;
 1982         }
 1983 
 1984         if (!add_pool_to_realm(rc, cs,
 1985                        acct_pool_name, &acct_pool,
 1986                        HOME_TYPE_ACCT, do_print)) {
 1987             return 0;
 1988         }
 1989     }
 1990 
 1991 #ifdef WITH_COA
 1992     cp = cf_pair_find(cs, "coa_pool");
 1993     if (cp) coa_pool_name = cf_pair_value(cp);
 1994     if (cp && coa_pool_name) {
 1995         bool do_print = true;
 1996 
 1997         if (!add_pool_to_realm(rc, cs,
 1998                        coa_pool_name, &coa_pool,
 1999                        HOME_TYPE_COA, do_print)) {
 2000             return 0;
 2001         }
 2002     }
 2003 #endif
 2004 #endif
 2005 
 2006     cf_log_info(cs, " realm %s {", name2);
 2007 
 2008 #ifdef WITH_PROXY
 2009     /*
 2010      *  The realm MAY already exist if it's an old-style realm.
 2011      *  In that case, merge the old-style realm with this one.
 2012      */
 2013     r = realm_find2(name2);
 2014     if (r && (strcmp(r->name, name2) == 0)) {
 2015         if (cf_pair_find(cs, "auth_pool") ||
 2016             cf_pair_find(cs, "acct_pool")) {
 2017             cf_log_err_cs(cs, "Duplicate realm \"%s\"", name2);
 2018             goto error;
 2019         }
 2020 
 2021         if (!old_realm_config(rc, cs, r)) {
 2022             goto error;
 2023         }
 2024 
 2025         cf_log_info(cs, " } # realm %s", name2);
 2026         return 1;
 2027     }
 2028 #endif
 2029 
 2030     r = talloc_zero(rc, REALM);
 2031     r->name = name2;
 2032     r->strip_realm = true;
 2033 #ifdef WITH_PROXY
 2034     r->auth_pool = auth_pool;
 2035     r->acct_pool = acct_pool;
 2036 #ifdef WITH_COA
 2037     r->coa_pool = coa_pool;
 2038 #endif
 2039 
 2040     if (auth_pool_name &&
 2041         (auth_pool_name == acct_pool_name)) { /* yes, ptr comparison */
 2042         cf_log_info(cs, "\tpool = %s", auth_pool_name);
 2043     } else {
 2044         if (auth_pool_name) cf_log_info(cs, "\tauth_pool = %s", auth_pool_name);
 2045         if (acct_pool_name) cf_log_info(cs, "\tacct_pool = %s", acct_pool_name);
 2046 #ifdef WITH_COA
 2047         if (coa_pool_name) cf_log_info(cs, "\tcoa_pool = %s", coa_pool_name);
 2048 #endif
 2049     }
 2050 #endif
 2051 
 2052     cp = cf_pair_find(cs, "nostrip");
 2053     if (cp && (cf_pair_value(cp) == NULL)) {
 2054         r->strip_realm = false;
 2055         cf_log_info(cs, "\tnostrip");
 2056     }
 2057 
 2058     /*
 2059      *  We're a new-style realm.  Complain if we see the old
 2060      *  directives.
 2061      */
 2062     if (r->auth_pool || r->acct_pool) {
 2063         if (((cp = cf_pair_find(cs, "authhost")) != NULL) ||
 2064             ((cp = cf_pair_find(cs, "accthost")) != NULL) ||
 2065             ((cp = cf_pair_find(cs, "secret")) != NULL) ||
 2066             ((cp = cf_pair_find(cs, "ldflag")) != NULL)) {
 2067             WARN("Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
 2068         }
 2069 
 2070 
 2071         /*
 2072          *  The realm MAY be an old-style realm, as there
 2073          *  was no auth_pool or acct_pool.  Double-check
 2074          *  it, just to be safe.
 2075          */
 2076     } else if (!old_realm_config(rc, cs, r)) {
 2077         goto error;
 2078     }
 2079 
 2080     if (!realm_realm_add(r, cs)) {
 2081         goto error;
 2082     }
 2083 
 2084     cf_log_info(cs, " }");
 2085 
 2086     return 1;
 2087 
 2088  error:
 2089     cf_log_info(cs, " } # realm %s", name2);
 2090     return 0;
 2091 }
 2092 
 2093 #ifdef HAVE_REGEX
 2094 int realm_realm_add(REALM *r, CONF_SECTION *cs)
 2095 #else
 2096 int realm_realm_add(REALM *r, UNUSED CONF_SECTION *cs)
 2097 #endif
 2098 {
 2099     /*
 2100      *  The structs aren't mutex protected.  Refuse to destroy
 2101      *  the server.
 2102      */
 2103     if (event_loop_started && !realm_config->dynamic) {
 2104         DEBUG("Must set \"dynamic = true\" in proxy.conf");
 2105         return 0;
 2106     }
 2107 
 2108 #ifdef HAVE_REGEX
 2109     /*
 2110      *  It's a regex.  Sanity check it, and add it to a
 2111      *  separate list.
 2112      */
 2113     if (r->name[0] == '~') {
 2114         ssize_t slen;
 2115         realm_regex_t *rr, **last;
 2116 
 2117         rr = talloc(r, realm_regex_t);
 2118 
 2119         /*
 2120          *  Include substring matches.
 2121          */
 2122         slen = regex_compile(rr, &rr->preg, r->name + 1, strlen(r->name) - 1, true, false, false, false);
 2123         if (slen <= 0) {
 2124             char *spaces, *text;
 2125 
 2126             fr_canonicalize_error(r, &spaces, &text, slen, r->name + 1);
 2127 
 2128             cf_log_err_cs(cs, "Invalid regular expression:");
 2129             cf_log_err_cs(cs, "%s", text);
 2130             cf_log_err_cs(cs, "%s^ %s", spaces, fr_strerror());
 2131 
 2132             talloc_free(spaces);
 2133             talloc_free(text);
 2134             talloc_free(rr);
 2135 
 2136             return 0;
 2137         }
 2138 
 2139         last = &realms_regex;
 2140         while (*last) last = &((*last)->next);  /* O(N^2)... sue me. */
 2141 
 2142         rr->realm = r;
 2143         rr->next = NULL;
 2144 
 2145         *last = rr;
 2146         return 1;
 2147     }
 2148 #endif
 2149 
 2150     if (!rbtree_insert(realms_byname, r)) {
 2151         rad_assert("Internal sanity check failed" == NULL);
 2152         return 0;
 2153     }
 2154 
 2155     return 1;
 2156 }
 2157 
 2158 #ifdef WITH_COA
 2159 
 2160 static int pool_peek_type(CONF_SECTION *config, CONF_SECTION *cs)
 2161 {
 2162     int home;
 2163     char const *name, *type;
 2164     CONF_PAIR *cp;
 2165     CONF_SECTION *server_cs;
 2166 
 2167     cp = cf_pair_find(cs, "home_server");
 2168     if (!cp) {
 2169         cf_log_err_cs(cs, "Pool does not contain a \"home_server\" entry");
 2170         return HOME_TYPE_INVALID;
 2171     }
 2172 
 2173     name = cf_pair_value(cp);
 2174     if (!name) {
 2175         cf_log_err_cp(cp, "home_server entry does not reference a home server");
 2176         return HOME_TYPE_INVALID;
 2177     }
 2178 
 2179     server_cs = cf_section_sub_find_name2(config, "home_server", name);
 2180     if (!server_cs) {
 2181         cf_log_err_cp(cp, "home_server \"%s\" does not exist", name);
 2182         return HOME_TYPE_INVALID;
 2183     }
 2184 
 2185     cp = cf_pair_find(server_cs, "type");
 2186     if (!cp) {
 2187         cf_log_err_cs(server_cs, "home_server %s does not contain a \"type\" entry", name);
 2188         return HOME_TYPE_INVALID;
 2189     }
 2190 
 2191     type = cf_pair_value(cp);
 2192     if (!type) {
 2193         cf_log_err_cs(server_cs, "home_server %s contains an empty \"type\" entry", name);
 2194         return HOME_TYPE_INVALID;
 2195     }
 2196 
 2197     home = fr_str2int(home_server_types, type, HOME_TYPE_INVALID);
 2198     if (home == HOME_TYPE_INVALID) {
 2199         cf_log_err_cs(server_cs, "home_server %s contains an invalid \"type\" entry of value \"%s\"", name, type);
 2200         return HOME_TYPE_INVALID;
 2201     }
 2202 
 2203     return home;        /* 'cause we miss it so much */
 2204 }
 2205 #endif
 2206 
 2207 int realms_init(CONF_SECTION *config)
 2208 {
 2209     CONF_SECTION *cs;
 2210     int flags = 0;
 2211 #ifdef WITH_PROXY
 2212     CONF_SECTION *server_cs;
 2213 #endif
 2214     realm_config_t *rc;
 2215 
 2216     if (event_loop_started) return 1;
 2217 
 2218     rc = talloc_zero(NULL, realm_config_t);
 2219     rc->cs = config;
 2220 
 2221 #ifdef WITH_PROXY
 2222     cs = cf_subsection_find_next(config, NULL, "proxy");
 2223     if (cs) {
 2224         if (cf_section_parse(cs, rc, proxy_config) < 0) {
 2225             ERROR("Failed parsing proxy section");
 2226             goto error;
 2227         }
 2228     } else {
 2229         rc->dead_time = DEAD_TIME;
 2230         rc->retry_count = RETRY_COUNT;
 2231         rc->retry_delay = RETRY_DELAY;
 2232         rc->fallback = false;
 2233         rc->dynamic = false;
 2234         rc->wake_all_if_all_dead= 0;
 2235     }
 2236 
 2237     if (rc->dynamic) {
 2238         flags = RBTREE_FLAG_LOCK;
 2239     }
 2240 
 2241     home_servers_byaddr = rbtree_create(NULL, home_server_addr_cmp, home_server_free, flags);
 2242     if (!home_servers_byaddr) goto error;
 2243 
 2244     home_servers_byname = rbtree_create(NULL, home_server_name_cmp, NULL, flags);
 2245     if (!home_servers_byname) goto error;
 2246 
 2247 #ifdef WITH_STATS
 2248     home_servers_bynumber = rbtree_create(NULL, home_server_number_cmp, NULL, flags);
 2249     if (!home_servers_bynumber) goto error;
 2250 #endif
 2251 
 2252     home_pools_byname = rbtree_create(NULL, home_pool_name_cmp, NULL, flags);
 2253     if (!home_pools_byname) goto error;
 2254 
 2255     for (cs = cf_subsection_find_next(config, NULL, "home_server");
 2256          cs != NULL;
 2257          cs = cf_subsection_find_next(config, cs, "home_server")) {
 2258             home_server_t *home;
 2259 
 2260             home = home_server_afrom_cs(rc, rc, cs);
 2261             if (!home) goto error;
 2262         if (!realm_home_server_add(home)) goto error;
 2263     }
 2264 
 2265     /*
 2266      *  Loop over virtual servers to find home servers which
 2267      *  are defined in them.
 2268      */
 2269     for (server_cs = cf_subsection_find_next(config, NULL, "server");
 2270          server_cs != NULL;
 2271          server_cs = cf_subsection_find_next(config, server_cs, "server")) {
 2272         for (cs = cf_subsection_find_next(server_cs, NULL, "home_server");
 2273              cs != NULL;
 2274              cs = cf_subsection_find_next(server_cs, cs, "home_server")) {
 2275             home_server_t *home;
 2276 
 2277             home = home_server_afrom_cs(rc, rc, cs);
 2278             if (!home) goto error;
 2279             if (!realm_home_server_add(home)) goto error;
 2280         }
 2281     }
 2282 #endif
 2283 
 2284     /*
 2285      *  Now create the realms, which point to the home servers
 2286      *  and home server pools.
 2287      */
 2288     realms_byname = rbtree_create(NULL, realm_name_cmp, NULL, flags);
 2289     if (!realms_byname) goto error;
 2290 
 2291     for (cs = cf_subsection_find_next(config, NULL, "realm");
 2292          cs != NULL;
 2293          cs = cf_subsection_find_next(config, cs, "realm")) {
 2294         if (!realm_add(rc, cs)) {
 2295         error:
 2296             realms_free();
 2297             /*
 2298              *  Must be called after realms_free as home_servers
 2299              *  parented by rc are in trees freed by realms_free()
 2300              */
 2301             talloc_free(rc);
 2302             return 0;
 2303         }
 2304     }
 2305 
 2306 #ifdef WITH_COA
 2307     /*
 2308      *  CoA pools aren't necessarily tied to realms.
 2309      */
 2310     for (cs = cf_subsection_find_next(config, NULL, "home_server_pool");
 2311          cs != NULL;
 2312          cs = cf_subsection_find_next(config, cs, "home_server_pool")) {
 2313         int type;
 2314 
 2315         /*
 2316          *  Pool was already loaded.
 2317          */
 2318         if (cf_data_find(cs, "home_server_pool")) continue;
 2319 
 2320         type = pool_peek_type(config, cs);
 2321         if (type == HOME_TYPE_INVALID) goto error;
 2322         if (!server_pool_add(rc, cs, type, true)) goto error;
 2323     }
 2324 #endif
 2325 
 2326 #ifdef WITH_PROXY
 2327     xlat_register("home_server", xlat_home_server, NULL, NULL);
 2328     xlat_register("home_server_pool", xlat_server_pool, NULL, NULL);
 2329     xlat_register("home_server_dynamic", xlat_home_server_dynamic, NULL, NULL);
 2330 #endif
 2331 
 2332     realm_config = rc;
 2333 
 2334 #ifdef HAVE_DIRENT_H
 2335     if (!rc->dynamic) {
 2336         if (rc->directory) {
 2337             WARN("Ignoring 'directory' as dynamic home servers were not configured.");
 2338         }
 2339     } else {
 2340         DIR     *dir;
 2341         struct dirent   *dp;
 2342 
 2343         if (!rc->directory) {
 2344             WARN("Ignoring \"dynamic = true\" due to not set \"directory\" in proxy.conf");
 2345             return 1;
 2346         }
 2347 
 2348         DEBUG2("including files in directory %s", rc->directory);
 2349 
 2350         dir = opendir(rc->directory);
 2351         if (!dir) {
 2352             cf_log_err_cs(config, "Error reading directory %s: %s",
 2353                       rc->directory, fr_syserror(errno));                     
 2354             goto error;
 2355         }
 2356 
 2357         /*
 2358          *  Read the directory, ignoring "." files.
 2359          */
 2360         while ((dp = readdir(dir)) != NULL) {
 2361             char const *p;
 2362             char conf_file[PATH_MAX];
 2363 
 2364             if (dp->d_name[0] == '.') continue;
 2365 
 2366             /*
 2367              *  Check for valid characters
 2368              */
 2369             for (p = dp->d_name; *p != '\0'; p++) {
 2370                 if (isalpha((int)*p) ||
 2371                     isdigit((int)*p) ||
 2372                     (*p == '-') ||
 2373                     (*p == '_') ||
 2374                     (*p == '.')) continue;
 2375                 break;
 2376             }
 2377             if (*p != '\0') continue;
 2378         
 2379             snprintf(conf_file, sizeof(conf_file), "%s/%s", rc->directory, dp->d_name);
 2380             if (home_server_afrom_file(conf_file) < 0) {
 2381                 ERROR("Failed reading home_server from %s - %s",
 2382                       conf_file, fr_strerror());
 2383                 closedir(dir);
 2384                 goto error;
 2385             }
 2386         }
 2387         closedir(dir);
 2388     }
 2389 #endif
 2390 
 2391     return 1;
 2392 }
 2393 
 2394 /*
 2395  *  Find a realm where "name" might be the regex.
 2396  */
 2397 REALM *realm_find2(char const *name)
 2398 {
 2399     REALM myrealm;
 2400     REALM *realm;
 2401 
 2402     if (!name) name = "NULL";
 2403 
 2404     myrealm.name = name;
 2405     realm = rbtree_finddata(realms_byname, &myrealm);
 2406     if (realm) return realm;
 2407 
 2408 #ifdef HAVE_REGEX
 2409     if (realms_regex) {
 2410         realm_regex_t *this;
 2411 
 2412         for (this = realms_regex; this != NULL; this = this->next) {
 2413             if (strcmp(this->realm->name, name) == 0) {
 2414                 return this->realm;
 2415             }
 2416         }
 2417     }
 2418 #endif
 2419 
 2420     /*
 2421      *  Couldn't find a realm.  Look for DEFAULT.
 2422      */
 2423     myrealm.name = "DEFAULT";
 2424     return rbtree_finddata(realms_byname, &myrealm);
 2425 }
 2426 
 2427 
 2428 /*
 2429  *  Find a realm in the REALM list.
 2430  */
 2431 REALM *realm_find(char const *name)
 2432 {
 2433     REALM myrealm;
 2434     REALM *realm;
 2435 
 2436     if (!name) name = "NULL";
 2437 
 2438     myrealm.name = name;
 2439     realm = rbtree_finddata(realms_byname, &myrealm);
 2440     if (realm) return realm;
 2441 
 2442 #ifdef HAVE_REGEX
 2443     if (realms_regex) {
 2444         realm_regex_t *this;
 2445 
 2446         for (this = realms_regex;
 2447              this != NULL;
 2448              this = this->next) {
 2449             int compare;
 2450 
 2451             compare = regex_exec(this->preg, name, strlen(name), NULL, NULL);
 2452             if (compare < 0) {
 2453                 ERROR("Failed performing realm comparison: %s", fr_strerror());
 2454                 return NULL;
 2455             }
 2456             if (compare == 1) return this->realm;
 2457         }
 2458     }
 2459 #endif
 2460 
 2461     /*
 2462      *  Couldn't find a realm.  Look for DEFAULT.
 2463      */
 2464     myrealm.name = "DEFAULT";
 2465     return rbtree_finddata(realms_byname, &myrealm);
 2466 }
 2467 
 2468 
 2469 #ifdef WITH_PROXY
 2470 
 2471 /*
 2472  *  Allocate the proxy list if it doesn't already exist, and copy request
 2473  *  VPs into it. Setup src/dst IP addresses based on home server, and
 2474  *  calculate and add the message-authenticator.
 2475  *
 2476  *  This is a distinct function from home_server_ldb, as not all home_server_t
 2477  *  lookups result in the *CURRENT* request being proxied,
 2478  *  as in rlm_replicate, and this may trigger asserts elsewhere in the
 2479  *  server.
 2480  */
 2481 void home_server_update_request(home_server_t *home, REQUEST *request)
 2482 {
 2483 
 2484     /*
 2485      *  Allocate the proxy packet, only if it wasn't
 2486      *  already allocated by a module.  This check is
 2487      *  mainly to support the proxying of EAP-TTLS and
 2488      *  EAP-PEAP tunneled requests.
 2489      *
 2490      *  In those cases, the EAP module creates a
 2491      *  "fake" request, and recursively passes it
 2492      *  through the authentication stage of the
 2493      *  server.  The module then checks if the request
 2494      *  was supposed to be proxied, and if so, creates
 2495      *  a proxy packet from the TUNNELED request, and
 2496      *  not from the EAP request outside of the
 2497      *  tunnel.
 2498      *
 2499      *  The proxy then works like normal, except that
 2500      *  the response packet is "eaten" by the EAP
 2501      *  module, and encapsulated into an EAP packet.
 2502      */
 2503     if (!request->proxy) {
 2504         request->proxy = rad_alloc(request, true);
 2505         if (!request->proxy) {
 2506             ERROR("no memory");
 2507             fr_exit(1);
 2508         }
 2509 
 2510         /*
 2511          *  Copy the request, then look up name
 2512          *  and plain-text password in the copy.
 2513          *
 2514          *  Note that the User-Name attribute is
 2515          *  the *original* as sent over by the
 2516          *  client.  The Stripped-User-Name
 2517          *  attribute is the one hacked through
 2518          *  the 'hints' file.
 2519          */
 2520         request->proxy->vps = fr_pair_list_copy(request->proxy,
 2521                            request->packet->vps);
 2522     }
 2523 
 2524     /*
 2525      *  Update the various fields as appropriate.
 2526      */
 2527     request->proxy->src_ipaddr = home->src_ipaddr;
 2528     request->proxy->src_port = 0;
 2529     request->proxy->dst_ipaddr = home->ipaddr;
 2530     request->proxy->dst_port = home->port;
 2531 #ifdef WITH_TCP
 2532     request->proxy->proto = home->proto;
 2533 #endif
 2534     request->home_server = home;
 2535 
 2536     /*
 2537      *  Access-Requests have a Message-Authenticator added,
 2538      *  unless one already exists.
 2539      */
 2540     if ((request->packet->code == PW_CODE_ACCESS_REQUEST) &&
 2541         !fr_pair_find_by_num(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY)) {
 2542         fr_pair_make(request->proxy, &request->proxy->vps,
 2543              "Message-Authenticator", "0x00",
 2544              T_OP_SET);
 2545     }
 2546 }
 2547 
 2548 home_server_t *home_server_ldb(char const *realmname,
 2549                  home_pool_t *pool, REQUEST *request)
 2550 {
 2551     int     start;
 2552     int     count;
 2553     home_server_t   *found = NULL;
 2554     home_server_t   *zombie = NULL;
 2555     VALUE_PAIR  *vp;
 2556     uint32_t    hash;
 2557 
 2558     /*
 2559      *  Determine how to pick choose the home server.
 2560      */
 2561     switch (pool->type) {
 2562 
 2563 
 2564         /*
 2565          *  For load-balancing by client IP address, we
 2566          *  pick a home server by hashing the client IP.
 2567          *
 2568          *  This isn't as even a load distribution as
 2569          *  tracking the State attribute, but it's better
 2570          *  than nothing.
 2571          */
 2572     case HOME_POOL_CLIENT_BALANCE:
 2573         switch (request->packet->src_ipaddr.af) {
 2574         case AF_INET:
 2575             hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
 2576                      sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
 2577             break;
 2578 
 2579         case AF_INET6:
 2580             hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
 2581                      sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
 2582             break;
 2583 
 2584         default:
 2585             hash = 0;
 2586             break;
 2587         }
 2588         start = hash % pool->num_home_servers;
 2589         break;
 2590 
 2591     case HOME_POOL_CLIENT_PORT_BALANCE:
 2592         switch (request->packet->src_ipaddr.af) {
 2593         case AF_INET:
 2594             hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
 2595                      sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
 2596             break;
 2597 
 2598         case AF_INET6:
 2599             hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
 2600                      sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
 2601             break;
 2602 
 2603         default:
 2604             hash = 0;
 2605             break;
 2606         }
 2607         hash = fr_hash_update(&request->packet->src_port,
 2608                       sizeof(request->packet->src_port), hash);
 2609         start = hash % pool->num_home_servers;
 2610         break;
 2611 
 2612     case HOME_POOL_KEYED_BALANCE:
 2613         if ((vp = fr_pair_find_by_num(request->config, PW_LOAD_BALANCE_KEY, 0, TAG_ANY)) != NULL) {
 2614             hash = fr_hash(vp->vp_strvalue, vp->vp_length);
 2615             start = hash % pool->num_home_servers;
 2616             break;
 2617         }
 2618         /* FALL-THROUGH */
 2619 
 2620     case HOME_POOL_LOAD_BALANCE:
 2621     case HOME_POOL_FAIL_OVER:
 2622         start = 0;
 2623         break;
 2624 
 2625     default:        /* this shouldn't happen... */
 2626         start = 0;
 2627         break;
 2628 
 2629     }
 2630 
 2631     /*
 2632      *  Starting with the home server we chose, loop through
 2633      *  all home servers.  If the current one is dead, skip
 2634      *  it.  If it is too busy, skip it.
 2635      *
 2636      *  Otherwise, use it.
 2637      */
 2638     for (count = 0; count < pool->num_home_servers; count++) {
 2639         home_server_t *home = pool->servers[(start + count) % pool->num_home_servers];
 2640 
 2641         if (!home) continue;
 2642 
 2643         /*
 2644          *  Skip dead home servers.
 2645          *
 2646          *  Home servers that are unknown, alive, or zombie
 2647          *  are used for proxying.
 2648          */
 2649         if (home->state >= HOME_STATE_IS_DEAD) {
 2650             continue;
 2651         }
 2652 
 2653         /*
 2654          *  This home server is too busy.  Choose another one.
 2655          */
 2656         if (home->currently_outstanding >= home->max_outstanding) {
 2657             continue;
 2658         }
 2659 
 2660 #ifdef WITH_DETAIL
 2661         /*
 2662          *  We read the packet from a detail file, AND it
 2663          *  came from this server.  Don't re-proxy it
 2664          *  there.
 2665          */
 2666         if (request->listener &&
 2667             (request->listener->type == RAD_LISTEN_DETAIL) &&
 2668             (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
 2669             (fr_ipaddr_cmp(&home->ipaddr, &request->packet->src_ipaddr) == 0)) {
 2670             continue;
 2671         }
 2672 #endif
 2673 
 2674         /*
 2675          *  Default virtual: ignore homes tied to a
 2676          *  virtual.
 2677          */
 2678         if (!request->server && home->parent_server) {
 2679             continue;
 2680         }
 2681 
 2682         /*
 2683          *  A virtual AND home is tied to virtual,
 2684          *  ignore ones which don't match.
 2685          */
 2686         if (request->server && home->parent_server &&
 2687             strcmp(request->server, home->parent_server) != 0) {
 2688             continue;
 2689         }
 2690 
 2691         /*
 2692          *  Allow request->server && !home->parent_server
 2693          *
 2694          *  i.e. virtuals can proxy to globally defined
 2695          *  homes.
 2696          */
 2697 
 2698         /*
 2699          *  It's zombie, so we remember the first zombie
 2700          *  we find, but we don't mark it as a "live"
 2701          *  server.
 2702          */
 2703         if (home->state == HOME_STATE_ZOMBIE) {
 2704             if (!zombie) zombie = home;
 2705             continue;
 2706         }
 2707 
 2708         /*
 2709          *  We've found the first "live" one.  Use that.
 2710          */
 2711         if (pool->type != HOME_POOL_LOAD_BALANCE) {
 2712             found = home;
 2713             break;
 2714         }
 2715 
 2716         /*
 2717          *  Otherwise we're doing some kind of load balancing.
 2718          *  If we haven't found one yet, pick this one.
 2719          */
 2720         if (!found) {
 2721             found = home;
 2722             continue;
 2723         }
 2724 
 2725         RDEBUG3("PROXY %s %d\t%s %d",
 2726                found->log_name, found->currently_outstanding,
 2727                home->log_name, home->currently_outstanding);
 2728 
 2729         /*
 2730          *  Prefer this server if it's less busy than the
 2731          *  one we had previously found.
 2732          */
 2733         if (home->currently_outstanding < found->currently_outstanding) {
 2734             RDEBUG3("PROXY Choosing %s: It's less busy than %s",
 2735                    home->log_name, found->log_name);
 2736             found = home;
 2737             continue;
 2738         }
 2739 
 2740         /*
 2741          *  Ignore servers which are busier than the one
 2742          *  we found.
 2743          */
 2744         if (home->currently_outstanding > found->currently_outstanding) {
 2745             RDEBUG3("PROXY Skipping %s: It's busier than %s",
 2746                    home->log_name, found->log_name);
 2747             continue;
 2748         }
 2749 
 2750         /*
 2751          *  From the list of servers which have the same
 2752          *  load, choose one at random.
 2753          */
 2754         if (((count + 1) * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
 2755             found = home;
 2756         }
 2757     } /* loop over the home servers */
 2758 
 2759     /*
 2760      *  We have no live servers, BUT we have a zombie.  Use
 2761      *  the zombie as a last resort.
 2762      */
 2763     if (!found && zombie) {
 2764         found = zombie;
 2765         zombie = NULL;
 2766     }
 2767 
 2768     /*
 2769      *  There's a fallback if they're all dead.
 2770      */
 2771     if (!found && pool->fallback) {
 2772         found = pool->fallback;
 2773 
 2774         WARN("Home server pool %s failing over to fallback %s",
 2775               pool->name, found->server);
 2776         if (pool->in_fallback) goto update_and_return;
 2777 
 2778         pool->in_fallback = true;
 2779 
 2780         /*
 2781          *      Run the trigger once an hour saying that
 2782          *      they're all dead.
 2783          */
 2784         if ((pool->time_all_dead + 3600) < request->timestamp) {
 2785             pool->time_all_dead = request->timestamp;
 2786             exec_trigger(request, pool->cs, "home_server_pool.fallback", false);
 2787         }
 2788     }
 2789 
 2790     if (found) {
 2791     update_and_return:
 2792         if ((found != pool->fallback) && pool->in_fallback) {
 2793             pool->in_fallback = false;
 2794             exec_trigger(request, pool->cs, "home_server_pool.normal", false);
 2795         }
 2796 
 2797         return found;
 2798     }
 2799 
 2800     /*
 2801      *  No live match found, and no fallback to the "DEFAULT"
 2802      *  realm.  We fix this by blindly marking all servers as
 2803      *  "live".  But only do it for ones that don't support
 2804      *  "pings", as they will be marked live when they
 2805      *  actually are live.
 2806      */
 2807     if (!realm_config->fallback &&
 2808         realm_config->wake_all_if_all_dead) {
 2809         for (count = 0; count < pool->num_home_servers; count++) {
 2810             home_server_t *home = pool->servers[count];
 2811 
 2812             if (!home) continue;
 2813 
 2814             if ((home->state >= HOME_STATE_IS_DEAD) &&
 2815                 (home->ping_check == HOME_PING_CHECK_NONE)) {
 2816                 home->state = HOME_STATE_ALIVE;
 2817                 home->response_timeouts = 0;
 2818                 if (!found) found = home;
 2819             }
 2820         }
 2821 
 2822         if (found) goto update_and_return;
 2823     }
 2824 
 2825     /*
 2826      *  Still nothing.  Look up the DEFAULT realm, but only
 2827      *  if we weren't looking up the NULL or DEFAULT realms.
 2828      */
 2829     if (realm_config->fallback &&
 2830         realmname &&
 2831         (strcmp(realmname, "NULL") != 0) &&
 2832         (strcmp(realmname, "DEFAULT") != 0)) {
 2833         REALM *rd = realm_find("DEFAULT");
 2834 
 2835         if (!rd) return NULL;
 2836 
 2837         pool = NULL;
 2838         if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
 2839             pool = rd->auth_pool;
 2840 
 2841         } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
 2842             pool = rd->acct_pool;
 2843         }
 2844         if (!pool) return NULL;
 2845 
 2846         RDEBUG2("PROXY - realm %s has no live home servers.  Falling back to the DEFAULT realm.", realmname);
 2847         return home_server_ldb(rd->name, pool, request);
 2848     }
 2849 
 2850     /*
 2851      *  Still haven't found anything.  Oh well.
 2852      */
 2853     return NULL;
 2854 }
 2855 
 2856 
 2857 home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port,
 2858 #ifndef WITH_TCP
 2859                 UNUSED
 2860 #endif
 2861                 int proto)
 2862 {
 2863     home_server_t myhome;
 2864 
 2865     memset(&myhome, 0, sizeof(myhome));
 2866     myhome.ipaddr = *ipaddr;
 2867     myhome.src_ipaddr.af = ipaddr->af;
 2868     myhome.port = port;
 2869 #ifdef WITH_TCP
 2870     myhome.proto = proto;
 2871 #else
 2872     myhome.proto = IPPROTO_UDP;
 2873 #endif
 2874     myhome.server = NULL;   /* we're not called for internal proxying */
 2875 
 2876     return rbtree_finddata(home_servers_byaddr, &myhome);
 2877 }
 2878 
 2879 home_server_t *home_server_find_bysrc(fr_ipaddr_t *ipaddr, uint16_t port,
 2880                 int proto,
 2881                 fr_ipaddr_t *src_ipaddr)
 2882 {
 2883     home_server_t myhome;
 2884 
 2885     if (!src_ipaddr) return home_server_find(ipaddr, port, proto);
 2886 
 2887     if (src_ipaddr->af != ipaddr->af) return NULL;
 2888 
 2889     memset(&myhome, 0, sizeof(myhome));
 2890     myhome.ipaddr = *ipaddr;
 2891     myhome.src_ipaddr = *src_ipaddr;
 2892     myhome.port = port;
 2893 #ifdef WITH_TCP
 2894     myhome.proto = proto;
 2895 #else
 2896     myhome.proto = IPPROTO_UDP;
 2897 #endif
 2898     myhome.server = NULL;   /* we're not called for internal proxying */
 2899 
 2900     return rbtree_finddata(home_servers_byaddr, &myhome);
 2901 }
 2902 
 2903 #ifdef WITH_COA
 2904 home_server_t *home_server_byname(char const *name, int type)
 2905 {
 2906     home_server_t myhome;
 2907 
 2908     memset(&myhome, 0, sizeof(myhome));
 2909     myhome.type = type;
 2910     myhome.name = name;
 2911 
 2912     return rbtree_finddata(home_servers_byname, &myhome);
 2913 }
 2914 #endif
 2915 
 2916 #ifdef WITH_STATS
 2917 home_server_t *home_server_bynumber(int number)
 2918 {
 2919     home_server_t myhome;
 2920 
 2921     memset(&myhome, 0, sizeof(myhome));
 2922     myhome.number = number;
 2923     myhome.server = NULL;   /* we're not called for internal proxying */
 2924 
 2925     return rbtree_finddata(home_servers_bynumber, &myhome);
 2926 }
 2927 #endif
 2928 
 2929 home_pool_t *home_pool_byname(char const *name, int type)
 2930 {
 2931     home_pool_t mypool;
 2932 
 2933     memset(&mypool, 0, sizeof(mypool));
 2934     mypool.name = name;
 2935     mypool.server_type = type;
 2936     return rbtree_finddata(home_pools_byname, &mypool);
 2937 }
 2938 
 2939 int home_server_afrom_file(char const *filename)
 2940 {
 2941     CONF_SECTION *cs, *subcs;
 2942     char const *p;
 2943     home_server_t *home;
 2944 
 2945     if (!realm_config->dynamic) {
 2946         fr_strerror_printf("Must set \"dynamic = true\" in proxy.conf for dynamic home servers to work");
 2947         return -1;
 2948     }
 2949 
 2950     cs = cf_section_alloc(NULL, "home", filename);
 2951     if (!cs) {
 2952         fr_strerror_printf("Failed allocating memory");
 2953         return -1;
 2954     }
 2955 
 2956     if (cf_file_read(cs, filename) < 0) {
 2957         fr_strerror_printf("Failed reading file %s", filename);
 2958     error:
 2959         talloc_free(cs);
 2960         return -1;
 2961     }
 2962 
 2963     p = strrchr(filename, '/');
 2964     if (p) {
 2965         p++;
 2966     } else {
 2967         p = filename;
 2968     }
 2969 
 2970     subcs = cf_section_sub_find_name2(cs, "home_server", p);
 2971     if (!subcs) {
 2972         fr_strerror_printf("No 'home_server %s' definition in the file.", p);
 2973         goto error;
 2974     }
 2975 
 2976     home = home_server_afrom_cs(realm_config, realm_config, subcs);
 2977     if (!home) {
 2978         fr_strerror_printf("Failed parsing configuration to a home_server structure");
 2979         goto error;
 2980     }
 2981 
 2982     home->dynamic = true;
 2983 
 2984     if (home->server || home->dual) {
 2985         fr_strerror_printf("Dynamic home_server '%s' cannot have 'server' or 'auth+acct'", p);
 2986         talloc_free(home);
 2987         goto error;
 2988     }
 2989 
 2990     if (!realm_home_server_add(home)) {
 2991         fr_strerror_printf("Failed adding home_server to the internal data structures");
 2992         talloc_free(home);
 2993         goto error;
 2994     }
 2995 
 2996     return 0;
 2997 }
 2998 
 2999 int home_server_delete(char const *name, char const *type_name)
 3000 {
 3001     home_server_t *home;
 3002     int type;
 3003     char const *p;
 3004 
 3005     if (!realm_config->dynamic) {
 3006         fr_strerror_printf("Must set 'dynamic' in proxy.conf for dynamic home servers to work");
 3007         return -1;
 3008     }
 3009 
 3010     type = fr_str2int(home_server_types, type_name, HOME_TYPE_INVALID);
 3011     if (type == HOME_TYPE_INVALID) {
 3012         fr_strerror_printf("Unknown home_server type '%s'", type_name);
 3013         return -1;
 3014     }
 3015 
 3016     p = strrchr(name, '/');
 3017     if (p) {
 3018         p++;
 3019     } else {
 3020         p = name;
 3021     }
 3022 
 3023     home = home_server_byname(p, type);
 3024     if (!home) {
 3025         fr_strerror_printf("Failed to find home_server %s", p);
 3026         return -1;
 3027     }
 3028 
 3029     if (!home->dynamic) {
 3030         fr_strerror_printf("Cannot delete static home_server %s", p);
 3031         return -1;
 3032     }
 3033 
 3034     (void) rbtree_deletebydata(home_servers_byname, home);
 3035     (void) rbtree_deletebydata(home_servers_byaddr, home);
 3036 #ifdef WITH_STATS
 3037     (void) rbtree_deletebydata(home_servers_bynumber, home);
 3038 #endif
 3039 
 3040     /*
 3041      *  Leak home, and home->cs.  Oh well.
 3042      */
 3043     return 0;
 3044 }
 3045 #endif