Merge branch 'tr-integ' into kevin-chbind
[freeradius.git] / src / main / realms.c
index c2a1af6..0dd0164 100644 (file)
@@ -230,8 +230,7 @@ static size_t xlat_cs(CONF_SECTION *cs, const char *fmt, char *out, size_t outle
  *     Xlat for %{home_server:foo}
  */
 static size_t xlat_home_server(UNUSED void *instance, REQUEST *request,
-                              const char *fmt, char *out, size_t outlen,
-                              UNUSED RADIUS_ESCAPE_STRING func)
+                              const char *fmt, char *out, size_t outlen)
 {
        if (!fmt || !out || (outlen < 1)) return 0;
 
@@ -248,8 +247,7 @@ static size_t xlat_home_server(UNUSED void *instance, REQUEST *request,
  *     Xlat for %{home_server_pool:foo}
  */
 static size_t xlat_server_pool(UNUSED void *instance, REQUEST *request,
-                              const char *fmt, char *out, size_t outlen,
-                              UNUSED RADIUS_ESCAPE_STRING func)
+                              const char *fmt, char *out, size_t outlen)
 {
        if (!fmt || !out || (outlen < 1)) return 0;
 
@@ -370,12 +368,8 @@ static CONF_PARSER home_server_config[] = {
 
        { "response_window", PW_TYPE_INTEGER,
          offsetof(home_server,response_window), NULL,   "30" },
-       { "no_response_fail", PW_TYPE_BOOLEAN,
-         offsetof(home_server,no_response_fail), NULL,   NULL },
        { "max_outstanding", PW_TYPE_INTEGER,
          offsetof(home_server,max_outstanding), NULL,   "65536" },
-       { "require_message_authenticator",  PW_TYPE_BOOLEAN,
-         offsetof(home_server, message_authenticator), 0, NULL },
 
        { "zombie_period", PW_TYPE_INTEGER,
          offsetof(home_server,zombie_period), NULL,   "40" },
@@ -390,8 +384,6 @@ static CONF_PARSER home_server_config[] = {
          offsetof(home_server,ping_interval), NULL,   "30" },
        { "num_answers_to_alive", PW_TYPE_INTEGER,
          offsetof(home_server,num_pings_to_alive), NULL,   "3" },
-       { "num_pings_to_alive", PW_TYPE_INTEGER,
-         offsetof(home_server,num_pings_to_alive), NULL,   "3" },
        { "revive_interval", PW_TYPE_INTEGER,
          offsetof(home_server,revive_interval), NULL,   "300" },
        { "status_check_timeout", PW_TYPE_INTEGER,
@@ -421,6 +413,179 @@ static void null_free(UNUSED void *data)
 {
 }
 
+
+int realms_home_server_add(home_server *home, CONF_SECTION *cs, int dual)
+{
+        CONF_SECTION *parent = NULL;
+       const char * name2 = home->name;
+       
+       /*
+        *      Make sure that this is set.
+        */
+       if (home->src_ipaddr.af == AF_UNSPEC) {
+               home->src_ipaddr.af = home->ipaddr.af;
+       }
+
+       hs_srcipaddr = NULL;
+
+       if (rbtree_finddata(home_servers_byname, home) != NULL) {
+               cf_log_err(cf_sectiontoitem(cs),
+                          "Duplicate home server name %s.", name2);
+               goto error;
+       }
+
+       if (!home->server &&
+           (rbtree_finddata(home_servers_byaddr, home) != NULL)) {
+               cf_log_err(cf_sectiontoitem(cs),
+                          "Duplicate home server IP %s.", name2);
+               goto error;
+       }
+
+       if (!rbtree_insert(home_servers_byname, home)) {
+               cf_log_err(cf_sectiontoitem(cs),
+                          "Internal error %d adding home server %s.",
+                          __LINE__, name2);
+               goto error;
+       }
+
+       if (!home->server &&
+           !rbtree_insert(home_servers_byaddr, home)) {
+               rbtree_deletebydata(home_servers_byname, home);
+               cf_log_err(cf_sectiontoitem(cs),
+                          "Internal error %d adding home server %s.",
+                          __LINE__, name2);
+               goto error;
+       }
+
+#ifdef WITH_STATS
+       home->number = home_server_max_number++;
+       if (!rbtree_insert(home_servers_bynumber, home)) {
+               rbtree_deletebydata(home_servers_byname, home);
+               if (home->ipaddr.af != AF_UNSPEC) {
+                       rbtree_deletebydata(home_servers_byname, home);
+               }
+               cf_log_err(cf_sectiontoitem(cs),
+                          "Internal error %d adding home server %s.",
+                          __LINE__, name2);
+               goto error;
+       }
+#endif
+
+       if (home->max_outstanding < 8) home->max_outstanding = 8;
+       if (home->max_outstanding > 65536*16) home->max_outstanding = 65536*16;
+
+       if (home->ping_interval < 6) home->ping_interval = 6;
+       if (home->ping_interval > 120) home->ping_interval = 120;
+
+       if (home->response_window < 1) home->response_window = 1;
+       if (home->response_window > 60) home->response_window = 60;
+       if (home->response_window > mainconfig.max_request_time) home->response_window = mainconfig.max_request_time;
+
+       if (home->zombie_period < 1) home->zombie_period = 1;
+       if (home->zombie_period > 120) home->zombie_period = 120;
+
+       if (home->zombie_period < home->response_window) {
+               home->zombie_period = home->response_window;
+       }
+
+       if (home->num_pings_to_alive < 3) home->num_pings_to_alive = 3;
+       if (home->num_pings_to_alive > 10) home->num_pings_to_alive = 10;
+
+       if (home->ping_timeout < 3) home->ping_timeout = 3;
+       if (home->ping_timeout > 10) home->ping_timeout = 10;
+
+       if (home->revive_interval < 60) home->revive_interval = 60;
+       if (home->revive_interval > 3600) home->revive_interval = 3600;
+
+#ifdef WITH_COA
+       if (home->coa_irt < 1) home->coa_irt = 1;
+       if (home->coa_irt > 5) home->coa_irt = 5;
+
+       if (home->coa_mrc < 0) home->coa_mrc = 0;
+       if (home->coa_mrc > 20 ) home->coa_mrc = 20;
+
+       if (home->coa_mrt < 0) home->coa_mrt = 0;
+       if (home->coa_mrt > 30 ) home->coa_mrt = 30;
+
+       if (home->coa_mrd < 5) home->coa_mrd = 5;
+       if (home->coa_mrd > 60 ) home->coa_mrd = 60;
+#endif
+
+       if (home->limit.max_connections > 1024) home->limit.max_connections = 1024;
+
+#ifdef WITH_TCP
+       /*
+        *      UDP sockets can't be connection limited.
+        */
+       if (home->proto != IPPROTO_TCP) home->limit.max_connections = 0;
+#endif
+
+       if ((home->limit.idle_timeout > 0) && (home->limit.idle_timeout < 5))
+               home->limit.idle_timeout = 5;
+       if ((home->limit.lifetime > 0) && (home->limit.lifetime < 5))
+               home->limit.lifetime = 5;
+       if ((home->limit.lifetime > 0) && (home->limit.idle_timeout > home->limit.lifetime))
+               home->limit.idle_timeout = 0;
+
+       
+       if (cs) {
+               parent = cf_item_parent(cf_sectiontoitem(cs));
+               if (strcmp(cf_section_name1(parent), "server") == 0) {
+                       home->parent_server = cf_section_name2(parent);
+               }
+       }
+       
+       if (dual) {
+               home_server *home2 = rad_malloc(sizeof(*home2));
+
+               memcpy(home2, home, sizeof(*home2));
+
+               home2->type = HOME_TYPE_ACCT;
+               home2->port++;
+               home2->ping_user_password = NULL;
+               home2->cs = cs;
+               home2->parent_server = home->parent_server;
+
+               if (!rbtree_insert(home_servers_byname, home2)) {
+                       cf_log_err(cf_sectiontoitem(cs),
+                                  "Internal error %d adding home server %s.",
+                                  __LINE__, name2);
+                       free(home2);
+                       return 0;
+               }
+               
+               if (!home->server &&
+                   !rbtree_insert(home_servers_byaddr, home2)) {
+                       rbtree_deletebydata(home_servers_byname, home2);
+                       cf_log_err(cf_sectiontoitem(cs),
+                                  "Internal error %d adding home server %s.",
+                                  __LINE__, name2);
+                       free(home2);
+                       return 0;
+               }
+
+#ifdef WITH_STATS
+               home2->number = home_server_max_number++;
+               if (!rbtree_insert(home_servers_bynumber, home2)) {
+                       rbtree_deletebydata(home_servers_byname, home2);
+                       if (!home2->server) {
+                               rbtree_deletebydata(home_servers_byname, home2);
+                       }
+                       cf_log_err(cf_sectiontoitem(cs),
+                                  "Internal error %d adding home server %s.",
+                                  __LINE__, name2);
+                       free(home2);
+                       return 0;
+               }
+#endif
+       }
+
+       return 1;
+ error:
+       return 0;
+}
+
+
 static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
 {
        const char *name2;
@@ -429,7 +594,6 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
        CONF_PAIR *cp;
        CONF_SECTION *tls;
 
-       free(hs_virtual_server); /* used only for printing during parsing */
        hs_virtual_server = NULL;
 
        name2 = cf_section_name2(cs);
@@ -444,24 +608,11 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
 
        home->name = name2;
        home->cs = cs;
-
-        /*
-        *      For zombie period calculations.  We want to count
-        *      zombies from the time when the server starts, instead
-        *      of from 1970.
-        */
-       home->last_packet = time(NULL);
+       home->state = HOME_STATE_UNKNOWN;
 
        /*
-        *      Authentication servers have a default "no_response_fail = 0".
-        *      Accounting servers have a default "no_response_fail = 1".
-        *
-        *      This is because authentication packets are retried, so
-        *      they can fail over to another home server.  Accounting
-        *      packets are not retried, so they cannot fail over, and
-        *      instead should be rejected immediately.
+        *      Last packet sent / received are zero.
         */
-       home->no_response_fail = 2;
 
        memset(&hs_ip4addr, 0, sizeof(hs_ip4addr));
        memset(&hs_ip6addr, 0, sizeof(hs_ip6addr));
@@ -509,15 +660,11 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
                           "No ipaddr, ipv6addr, or virtual_server defined for home server \"%s\".",
                           name2);
        error:
-               free(home);
-               free(hs_type);
+               talloc_free(hs_type);
                hs_type = NULL;
-               free(hs_check);
                hs_check = NULL;
-               free(hs_srcipaddr);
                hs_srcipaddr = NULL;
 #ifdef WITH_TCP
-               free(hs_proto);
                hs_proto = NULL;
 #endif
                return 0;
@@ -548,15 +695,13 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
         *      Use a reasonable default.
         */
  skip_port:
-       if (!hs_type) hs_type = strdup("auth+acct");
+       if (!hs_type) hs_type = talloc_strdup(cs, "auth+acct");
 
        if (strcasecmp(hs_type, "auth") == 0) {
                home->type = HOME_TYPE_AUTH;
-               if (home->no_response_fail == 2) home->no_response_fail = 0;
 
        } else if (strcasecmp(hs_type, "acct") == 0) {
                home->type = HOME_TYPE_ACCT;
-               if (home->no_response_fail == 2) home->no_response_fail = 1;
 
        } else if (strcasecmp(hs_type, "auth+acct") == 0) {
                home->type = HOME_TYPE_AUTH;
@@ -580,7 +725,7 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
                           hs_type, name2);
                goto error;
        }
-       free(hs_type);
+       if (hs_type) talloc_free(hs_type);
        hs_type = NULL;
 
        if (!hs_check || (strcasecmp(hs_check, "none") == 0)) {
@@ -611,7 +756,6 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
                           hs_check, name2);
                goto error;
        }
-       free(hs_check);
        hs_check = NULL;
 
        if ((home->ping_check != HOME_PING_CHECK_NONE) &&
@@ -632,11 +776,9 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
 #ifdef WITH_TCP
        if (hs_proto) {
                if (strcmp(hs_proto, "udp") == 0) {
-                       free(hs_proto);
                        hs_proto = NULL;
                        
                } else if (strcmp(hs_proto, "tcp") == 0) {
-                       free(hs_proto);
                        hs_proto = NULL;
                        home->proto = IPPROTO_TCP;
                        
@@ -718,167 +860,8 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
                goto error;
        }
 
-       /*
-        *      Make sure that this is set.
-        */
-       if (home->src_ipaddr.af == AF_UNSPEC) {
-               home->src_ipaddr.af = home->ipaddr.af;
-       }
-
-       free(hs_srcipaddr);
-       hs_srcipaddr = NULL;
-
-       if (rbtree_finddata(home_servers_byname, home) != NULL) {
-               cf_log_err(cf_sectiontoitem(cs),
-                          "Duplicate home server name %s.", name2);
-               goto error;
-       }
-
-       if (!home->server &&
-           (rbtree_finddata(home_servers_byaddr, home) != NULL)) {
-               cf_log_err(cf_sectiontoitem(cs),
-                          "Duplicate home server IP %s.", name2);
+       if ( !realms_home_server_add( home, cs, dual))
                goto error;
-       }
-
-       if (!rbtree_insert(home_servers_byname, home)) {
-               cf_log_err(cf_sectiontoitem(cs),
-                          "Internal error %d adding home server %s.",
-                          __LINE__, name2);
-               goto error;
-       }
-
-       if (!home->server &&
-           !rbtree_insert(home_servers_byaddr, home)) {
-               rbtree_deletebydata(home_servers_byname, home);
-               cf_log_err(cf_sectiontoitem(cs),
-                          "Internal error %d adding home server %s.",
-                          __LINE__, name2);
-               goto error;
-       }
-
-#ifdef WITH_STATS
-       home->number = home_server_max_number++;
-       if (!rbtree_insert(home_servers_bynumber, home)) {
-               rbtree_deletebydata(home_servers_byname, home);
-               if (home->ipaddr.af != AF_UNSPEC) {
-                       rbtree_deletebydata(home_servers_byname, home);
-               }
-               cf_log_err(cf_sectiontoitem(cs),
-                          "Internal error %d adding home server %s.",
-                          __LINE__, name2);
-               goto error;
-       }
-#endif
-
-       if (home->max_outstanding < 8) home->max_outstanding = 8;
-       if (home->max_outstanding > 65536*16) home->max_outstanding = 65536*16;
-
-       if (home->ping_interval < 6) home->ping_interval = 6;
-       if (home->ping_interval > 120) home->ping_interval = 120;
-
-       if (home->response_window < 1) home->response_window = 1;
-       if (home->response_window > 60) home->response_window = 60;
-       if (home->response_window > mainconfig.max_request_time) home->response_window = mainconfig.max_request_time;
-
-       if (home->zombie_period < 1) home->zombie_period = 1;
-       if (home->zombie_period > 120) home->zombie_period = 120;
-
-       if (home->zombie_period < home->response_window) {
-               home->zombie_period = home->response_window;
-       }
-
-       if (home->num_pings_to_alive < 3) home->num_pings_to_alive = 3;
-       if (home->num_pings_to_alive > 10) home->num_pings_to_alive = 10;
-
-       if (home->ping_timeout < 3) home->ping_timeout = 3;
-       if (home->ping_timeout > 10) home->ping_timeout = 10;
-
-       if (home->revive_interval < 60) home->revive_interval = 60;
-       if (home->revive_interval > 3600) home->revive_interval = 3600;
-
-#ifdef WITH_COA
-       if (home->coa_irt < 1) home->coa_irt = 1;
-       if (home->coa_irt > 5) home->coa_irt = 5;
-
-       if (home->coa_mrc < 0) home->coa_mrc = 0;
-       if (home->coa_mrc > 20 ) home->coa_mrc = 20;
-
-       if (home->coa_mrt < 0) home->coa_mrt = 0;
-       if (home->coa_mrt > 30 ) home->coa_mrt = 30;
-
-       if (home->coa_mrd < 5) home->coa_mrd = 5;
-       if (home->coa_mrd > 60 ) home->coa_mrd = 60;
-#endif
-
-       if (home->limit.max_connections > 1024) home->limit.max_connections = 1024;
-
-#ifdef WITH_TCP
-       /*
-        *      UDP sockets can't be connection limited.
-        */
-       if (home->proto != IPPROTO_TCP) home->limit.max_connections = 0;
-#endif
-
-       if ((home->limit.idle_timeout > 0) && (home->limit.idle_timeout < 5))
-               home->limit.idle_timeout = 5;
-       if ((home->limit.lifetime > 0) && (home->limit.lifetime < 5))
-               home->limit.lifetime = 5;
-       if ((home->limit.lifetime > 0) && (home->limit.idle_timeout > home->limit.lifetime))
-               home->limit.idle_timeout = 0;
-
-       tls = cf_item_parent(cf_sectiontoitem(cs));
-       if (strcmp(cf_section_name1(tls), "server") == 0) {
-               home->parent_server = cf_section_name2(tls);
-       }
-
-       if (dual) {
-               home_server *home2 = rad_malloc(sizeof(*home2));
-
-               memcpy(home2, home, sizeof(*home2));
-
-               home2->type = HOME_TYPE_ACCT;
-               home2->port++;
-               home2->ping_user_password = NULL;
-               home2->cs = cs;
-               home2->parent_server = home->parent_server;
-
-               if (home->no_response_fail == 2) home->no_response_fail = 0;
-               if (home2->no_response_fail == 2) home2->no_response_fail = 1;
-
-               if (!rbtree_insert(home_servers_byname, home2)) {
-                       cf_log_err(cf_sectiontoitem(cs),
-                                  "Internal error %d adding home server %s.",
-                                  __LINE__, name2);
-                       free(home2);
-                       return 0;
-               }
-               
-               if (!home->server &&
-                   !rbtree_insert(home_servers_byaddr, home2)) {
-                       rbtree_deletebydata(home_servers_byname, home2);
-                       cf_log_err(cf_sectiontoitem(cs),
-                                  "Internal error %d adding home server %s.",
-                                  __LINE__, name2);
-                       free(home2);
-                       return 0;
-               }
-
-#ifdef WITH_STATS
-               home2->number = home_server_max_number++;
-               if (!rbtree_insert(home_servers_bynumber, home2)) {
-                       rbtree_deletebydata(home_servers_byname, home2);
-                       if (!home2->server) {
-                               rbtree_deletebydata(home_servers_byname, home2);
-                       }
-                       cf_log_err(cf_sectiontoitem(cs),
-                                  "Internal error %d adding home server %s.",
-                                  __LINE__, name2);
-                       free(home2);
-                       return 0;
-               }
-#endif
-       }
 
        /*
         *      Mark it as already processed
@@ -950,6 +933,16 @@ static int pool_check_home_server(realm_config_t *rc, CONF_PAIR *cp,
 }
 
 
+int realms_pool_add( home_pool_t *pool, UNUSED CONF_SECTION *cs)
+{
+               if (!rbtree_insert(home_pools_byname, pool)) {
+               rad_assert("Internal sanity check failed");
+               return 0;
+       }
+               return 1;
+}
+
+
 static int server_pool_add(realm_config_t *rc,
                           CONF_SECTION *cs, int server_type, int do_print)
 {
@@ -1112,8 +1105,7 @@ static int server_pool_add(realm_config_t *rc,
                cf_log_info(cs, "\tfallback = %s", pool->fallback->name);
        }
 
-       if (!rbtree_insert(home_pools_byname, pool)) {
-               rad_assert("Internal sanity check failed");
+       if (! realms_pool_add(pool, cs)) {
                goto error;
        }
 
@@ -1568,6 +1560,38 @@ static int add_pool_to_realm(realm_config_t *rc, CONF_SECTION *cs,
 #endif
 
 
+int realms_realm_add (REALM *r, CONF_SECTION *cs)
+{
+       #ifdef HAVE_REGEX_H
+       /*
+        *      It's a regex.  Add it to a separate list.
+        */
+       if (r->name[0] == '~') {
+               realm_regex_t *rr, **last;
+
+               rr = rad_malloc(sizeof(*rr));
+               
+               last = &realms_regex;
+               while (*last) last = &((*last)->next);  /* O(N^2)... sue me. */
+
+               rr->realm = r;
+               rr->next = NULL;
+
+               *last = rr;
+
+               return 1;
+       }
+#endif
+
+       if (!rbtree_insert(realms_byname, r)) {
+               rad_assert("Internal sanity check failed");
+               return 0;
+       }
+
+       return 1;
+}
+
+
 static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
 {
        const char *name2;
@@ -1761,7 +1785,7 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
                    ((cp = cf_pair_find(cs, "accthost")) != NULL) ||
                    ((cp = cf_pair_find(cs, "secret")) != NULL) ||
                    ((cp = cf_pair_find(cs, "ldflag")) != NULL)) {
-                       DEBUG2("WARNING: Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
+                       DEBUG2W("Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
                }
 
 
@@ -1774,38 +1798,12 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
                goto error;
        }
 
-#ifdef HAVE_REGEX_H
-       /*
-        *      It's a regex.  Add it to a separate list.
-        */
-       if (name2[0] == '~') {
-               realm_regex_t *rr, **last;
-
-               rr = rad_malloc(sizeof(*rr));
-               
-               last = &realms_regex;
-               while (*last) last = &((*last)->next);  /* O(N^2)... sue me. */
-
-               r->name = name2;
-               rr->realm = r;
-               rr->next = NULL;
-
-               *last = rr;
+       if ( !realms_realm_add(r, cs))
+               goto error;
 
                cf_log_info(cs, " }");
                return 1;
-       }
-#endif
-
-       if (!rbtree_insert(realms_byname, r)) {
-               rad_assert("Internal sanity check failed");
-               goto error;
-       }
-
-       cf_log_info(cs, " }");
-
-       return 1;
-
+               
  error:
        cf_log_info(cs, " } # realm %s", name2);
        free(r);
@@ -1919,7 +1917,13 @@ int realms_init(CONF_SECTION *config)
 #ifdef WITH_PROXY
        cs = cf_subsection_find_next(config, NULL, "proxy");
        if (cs) {
-               cf_section_parse(cs, rc, proxy_config);
+               if (cf_section_parse(cs, rc, proxy_config) < 0) {
+                       radlog(L_ERR, "Failed parsing proxy section");
+                       
+                       free(rc);
+                       realms_free();
+                       return 0;
+               }
        } else {
                rc->dead_time = DEAD_TIME;
                rc->retry_count = RETRY_COUNT;
@@ -2093,6 +2097,80 @@ REALM *realm_find(const char *name)
 
 
 #ifdef WITH_PROXY
+
+/*
+ *     Allocate the proxy list if it doesn't already exist, and copy request
+ *     VPs into it. Setup src/dst IP addresses based on home server, and
+ *     calculate and add the message-authenticator.
+ *
+ *     This is a distinct function from home_server_ldb, as not all home_server
+ *     lookups result in the *CURRENT* request being proxied,
+ *     as in rlm_replicate, and this may trigger asserts elsewhere in the
+ *     server.
+ */
+void home_server_update_request(home_server *home, REQUEST *request)
+{
+
+       /*
+        *      Allocate the proxy packet, only if it wasn't
+        *      already allocated by a module.  This check is
+        *      mainly to support the proxying of EAP-TTLS and
+        *      EAP-PEAP tunneled requests.
+        *
+        *      In those cases, the EAP module creates a
+        *      "fake" request, and recursively passes it
+        *      through the authentication stage of the
+        *      server.  The module then checks if the request
+        *      was supposed to be proxied, and if so, creates
+        *      a proxy packet from the TUNNELED request, and
+        *      not from the EAP request outside of the
+        *      tunnel.
+        *
+        *      The proxy then works like normal, except that
+        *      the response packet is "eaten" by the EAP
+        *      module, and encapsulated into an EAP packet.
+        */
+       if (!request->proxy) {
+               request->proxy = rad_alloc(request, TRUE);
+               if (!request->proxy) {
+                       radlog(L_ERR, "no memory");
+                       exit(1);
+               }
+               
+               /*
+                *      Copy the request, then look up name
+                *      and plain-text password in the copy.
+                *
+                *      Note that the User-Name attribute is
+                *      the *original* as sent over by the
+                *      client.  The Stripped-User-Name
+                *      attribute is the one hacked through
+                *      the 'hints' file.
+                */
+               request->proxy->vps =  paircopy(request->packet->vps);
+       }
+
+       /*
+        *      Update the various fields as appropriate.
+        */
+       request->proxy->src_ipaddr = home->src_ipaddr;
+       request->proxy->src_port = 0;
+       request->proxy->dst_ipaddr = home->ipaddr;
+       request->proxy->dst_port = home->port;
+       request->home_server = home;
+
+       /*
+        *      Access-Requests have a Message-Authenticator added,
+        *      unless one already exists.
+        */
+       if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
+           !pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY)) {
+               radius_pairmake(request, &request->proxy->vps,
+                               "Message-Authenticator", "0x00",
+                               T_OP_SET);
+       }
+}
+
 home_server *home_server_ldb(const char *realmname,
                             home_pool_t *pool, REQUEST *request)
 {
@@ -2153,7 +2231,7 @@ home_server *home_server_ldb(const char *realmname,
                break;
 
        case HOME_POOL_KEYED_BALANCE:
-               if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY, 0)) != NULL) {
+               if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY, 0, TAG_ANY)) != NULL) {
                        hash = fr_hash(vp->vp_strvalue, vp->length);
                        start = hash % pool->num_home_servers;
                        break;
@@ -2185,6 +2263,9 @@ home_server *home_server_ldb(const char *realmname,
 
                /*
                 *      Skip dead home servers.
+                *
+                *      Home servers that are unknown, alive, or zombie
+                *      are used for proxying.
                 */
                if (home->state == HOME_STATE_IS_DEAD) {
                        continue;
@@ -2310,7 +2391,7 @@ home_server *home_server_ldb(const char *realmname,
        if (!found && pool->fallback) {
                found = pool->fallback;
 
-               DEBUG("WARNING: Home server pool %s failing over to fallback %s",
+               DEBUGW("Home server pool %s failing over to fallback %s",
                      pool->name, found->server);
                if (pool->in_fallback) goto update_and_return;
 
@@ -2333,65 +2414,6 @@ home_server *home_server_ldb(const char *realmname,
                        exec_trigger(request, pool->cs, "home_server_pool.normal", FALSE);
                }
 
-               /*
-                *      Allocate the proxy packet, only if it wasn't
-                *      already allocated by a module.  This check is
-                *      mainly to support the proxying of EAP-TTLS and
-                *      EAP-PEAP tunneled requests.
-                *
-                *      In those cases, the EAP module creates a
-                *      "fake" request, and recursively passes it
-                *      through the authentication stage of the
-                *      server.  The module then checks if the request
-                *      was supposed to be proxied, and if so, creates
-                *      a proxy packet from the TUNNELED request, and
-                *      not from the EAP request outside of the
-                *      tunnel.
-                *
-                *      The proxy then works like normal, except that
-                *      the response packet is "eaten" by the EAP
-                *      module, and encapsulated into an EAP packet.
-                */
-               if (!request->proxy) {
-                       if ((request->proxy = rad_alloc(TRUE)) == NULL) {
-                               radlog(L_ERR|L_CONS, "no memory");
-                               exit(1);
-                       }
-                       
-                       /*
-                        *      Copy the request, then look up name
-                        *      and plain-text password in the copy.
-                        *
-                        *      Note that the User-Name attribute is
-                        *      the *original* as sent over by the
-                        *      client.  The Stripped-User-Name
-                        *      attribute is the one hacked through
-                        *      the 'hints' file.
-                        */
-                       request->proxy->vps =  paircopy(request->packet->vps);
-               }
-
-               /*
-                *      Update the various fields as appropriate.
-                */
-               request->proxy->src_ipaddr = found->src_ipaddr;
-               request->proxy->src_port = 0;
-               request->proxy->dst_ipaddr = found->ipaddr;
-               request->proxy->dst_port = found->port;
-               request->home_server = found;
-
-               /*
-                *      We're supposed to add a Message-Authenticator
-                *      if it doesn't exist, and it doesn't exist.
-                */
-               if (found->message_authenticator &&
-                   (request->packet->code == PW_AUTHENTICATION_REQUEST) &&
-                   !pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0)) {
-                       radius_pairmake(request, &request->proxy->vps,
-                                       "Message-Authenticator", "0x00",
-                                       T_OP_SET);
-               }
-
                return found;
        }