Include proto in API, no matter what build options
[freeradius.git] / src / main / realms.c
1 /*
2  * realms.c     Realm handling code
3  *
4  * Version:     $Id$
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 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.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 #ifdef HAVE_REGEX_H
36 #include <regex.h>
37
38 /*
39  *  For POSIX Regular expressions.
40  *  (0) Means no extended regular expressions.
41  *  REG_EXTENDED means use extended regular expressions.
42  */
43 #ifndef REG_EXTENDED
44 #define REG_EXTENDED (0)
45 #endif
46
47 #ifndef REG_NOSUB
48 #define REG_NOSUB (0)
49 #endif
50
51 #ifndef REG_ICASE
52 #define REG_ICASE (0)
53 #endif
54 #endif
55
56 static rbtree_t *realms_byname = NULL;
57
58 #ifdef HAVE_REGEX_H
59 typedef struct realm_regex_t {
60         REALM   *realm;
61         struct realm_regex_t *next;
62 } realm_regex_t;
63
64 static realm_regex_t *realms_regex = NULL;
65
66 #endif /* HAVE_REGEX_H */
67
68 typedef struct realm_config_t {
69         CONF_SECTION    *cs;
70         int             dead_time;
71         int             retry_count;
72         int             retry_delay;
73         int             fallback;
74         int             wake_all_if_all_dead;
75 } realm_config_t;
76
77 static realm_config_t *realm_config = NULL;
78
79 #ifdef WITH_PROXY
80 static rbtree_t *home_servers_byaddr = NULL;
81 static rbtree_t *home_servers_byname = NULL;
82 #ifdef WITH_STATS
83 static int home_server_max_number = 0;
84 static rbtree_t *home_servers_bynumber = NULL;
85 #endif
86
87 static rbtree_t *home_pools_byname = NULL;
88
89 /*
90  *  Map the proxy server configuration parameters to variables.
91  */
92 static const CONF_PARSER proxy_config[] = {
93         { "retry_delay",  PW_TYPE_INTEGER,
94           offsetof(realm_config_t, retry_delay),
95           NULL, Stringify(RETRY_DELAY) },
96
97         { "retry_count",  PW_TYPE_INTEGER,
98           offsetof(realm_config_t, retry_count),
99           NULL, Stringify(RETRY_COUNT) },
100
101         { "default_fallback", PW_TYPE_BOOLEAN,
102           offsetof(realm_config_t, fallback),
103           NULL, "no" },
104
105         { "dead_time",    PW_TYPE_INTEGER, 
106           offsetof(realm_config_t, dead_time),
107           NULL, Stringify(DEAD_TIME) },
108
109         { "wake_all_if_all_dead", PW_TYPE_BOOLEAN,
110           offsetof(realm_config_t, wake_all_if_all_dead),
111           NULL, "no" },
112
113         { NULL, -1, 0, NULL, NULL }
114 };
115 #endif
116
117 static int realm_name_cmp(const void *one, const void *two)
118 {
119         const REALM *a = one;
120         const REALM *b = two;
121
122         return strcasecmp(a->name, b->name);
123 }
124
125
126 #ifdef WITH_PROXY
127 static int home_server_name_cmp(const void *one, const void *two)
128 {
129         const home_server *a = one;
130         const home_server *b = two;
131
132         if (a->type < b->type) return -1;
133         if (a->type > b->type) return +1;
134
135         return strcasecmp(a->name, b->name);
136 }
137
138 static int home_server_addr_cmp(const void *one, const void *two)
139 {
140         const home_server *a = one;
141         const home_server *b = two;
142
143         if (a->server && !b->server) return -1;
144         if (!a->server && b->server) return +1;
145         if (a->server && b->server) {
146                 int rcode = a->type - b->type;
147                 if (rcode != 0) return rcode;
148                 return strcmp(a->server, b->server);
149         }
150
151 #ifdef WITH_TCP
152         if (a->proto < b->proto) return -1;
153         if (a->proto > b->proto) return +1;
154 #endif
155
156         if (a->port < b->port) return -1;
157         if (a->port > b->port) return +1;
158
159         return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
160 }
161
162 #ifdef WITH_STATS
163 static int home_server_number_cmp(const void *one, const void *two)
164 {
165         const home_server *a = one;
166         const home_server *b = two;
167
168         return (a->number - b->number);
169 }
170 #endif
171
172 static int home_pool_name_cmp(const void *one, const void *two)
173 {
174         const home_pool_t *a = one;
175         const home_pool_t *b = two;
176
177         if (a->server_type < b->server_type) return -1;
178         if (a->server_type > b->server_type) return +1;
179
180         return strcasecmp(a->name, b->name);
181 }
182
183
184 /*
185  *      Xlat for %{home_server:foo}
186  */
187 static size_t xlat_home_server(UNUSED void *instance, REQUEST *request,
188                                char *fmt, char *out, size_t outlen,
189                                UNUSED RADIUS_ESCAPE_STRING func)
190 {
191         const char *value = NULL;
192         CONF_PAIR *cp;
193
194         if (!fmt || !out || (outlen < 1)) return 0;
195
196         if (!request || !request->home_server) {
197                 *out = '\0';
198                 return 0;
199         }
200
201         cp = cf_pair_find(request->home_server->cs, fmt);
202         if (!cp || !(value = cf_pair_value(cp))) {
203                 *out = '\0';
204                 return 0;
205         }
206         
207         strlcpy(out, value, outlen);
208
209         return strlen(out);
210 }
211
212
213 /*
214  *      Xlat for %{home_server_pool:foo}
215  */
216 static size_t xlat_server_pool(UNUSED void *instance, REQUEST *request,
217                                char *fmt, char *out, size_t outlen,
218                                UNUSED RADIUS_ESCAPE_STRING func)
219 {
220         const char *value = NULL;
221         CONF_PAIR *cp;
222
223         if (!fmt || !out || (outlen < 1)) return 0;
224
225         if (!request || !request->home_pool) {
226                 *out = '\0';
227                 return 0;
228         }
229
230         cp = cf_pair_find(request->home_pool->cs, fmt);
231         if (!cp || !(value = cf_pair_value(cp))) {
232                 *out = '\0';
233                 return 0;
234         }
235         
236         strlcpy(out, value, outlen);
237
238         return strlen(out);
239 }
240 #endif
241
242 void realms_free(void)
243 {
244 #ifdef WITH_PROXY
245 #ifdef WITH_STATS
246         rbtree_free(home_servers_bynumber);
247         home_servers_bynumber = NULL;
248 #endif
249
250         rbtree_free(home_servers_byname);
251         home_servers_byname = NULL;
252
253         rbtree_free(home_servers_byaddr);
254         home_servers_byaddr = NULL;
255
256         rbtree_free(home_pools_byname);
257         home_pools_byname = NULL;
258 #endif
259
260         rbtree_free(realms_byname);
261         realms_byname = NULL;
262
263 #ifdef HAVE_REGEX_H
264         if (realms_regex) {
265                 realm_regex_t *this, *next;
266
267                 for (this = realms_regex; this != NULL; this = next) {
268                         next = this->next;
269                         free(this->realm);
270                         free(this);
271                 }
272                 realms_regex = NULL;
273         }
274 #endif
275
276         free(realm_config);
277         realm_config = NULL;
278 }
279
280
281 #ifdef WITH_PROXY
282 static CONF_PARSER limit_config[] = {
283         { "max_connections", PW_TYPE_INTEGER,
284           offsetof(home_server, max_connections), NULL,   "16" },
285
286         { "max_requests", PW_TYPE_INTEGER,
287           offsetof(home_server,max_requests), NULL,   "0" },
288
289         { "lifetime", PW_TYPE_INTEGER,
290           offsetof(home_server,lifetime), NULL,   "0" },
291
292         { "idle_timeout", PW_TYPE_INTEGER,
293           offsetof(home_server,idle_timeout), NULL,   "0" },
294
295         { NULL, -1, 0, NULL, NULL }             /* end the list */
296 };
297
298 static struct in_addr hs_ip4addr;
299 static struct in6_addr hs_ip6addr;
300 static char *hs_srcipaddr = NULL;
301 static char *hs_type = NULL;
302 static char *hs_check = NULL;
303 static char *hs_virtual_server = NULL;
304 #ifdef WITH_TCP
305 static char *hs_proto = NULL;
306 #endif
307
308 static CONF_PARSER home_server_config[] = {
309         { "ipaddr",  PW_TYPE_IPADDR,
310           0, &hs_ip4addr,  NULL },
311         { "ipv6addr",  PW_TYPE_IPV6ADDR,
312           0, &hs_ip6addr, NULL },
313         { "virtual_server",  PW_TYPE_STRING_PTR,
314           0, &hs_virtual_server, NULL },
315
316         { "port", PW_TYPE_INTEGER,
317           offsetof(home_server,port), NULL,   "0" },
318
319         { "type",  PW_TYPE_STRING_PTR,
320           0, &hs_type, NULL },
321
322 #ifdef WITH_TCP
323         { "proto",  PW_TYPE_STRING_PTR,
324           0, &hs_proto, NULL },
325 #endif
326
327         { "secret",  PW_TYPE_STRING_PTR,
328           offsetof(home_server,secret), NULL,  NULL},
329
330         { "src_ipaddr",  PW_TYPE_STRING_PTR,
331           0, &hs_srcipaddr,  NULL },
332
333         { "response_window", PW_TYPE_INTEGER,
334           offsetof(home_server,response_window), NULL,   "30" },
335         { "no_response_fail", PW_TYPE_BOOLEAN,
336           offsetof(home_server,no_response_fail), NULL,   NULL },
337         { "max_outstanding", PW_TYPE_INTEGER,
338           offsetof(home_server,max_outstanding), NULL,   "65536" },
339         { "require_message_authenticator",  PW_TYPE_BOOLEAN,
340           offsetof(home_server, message_authenticator), 0, NULL },
341
342         { "zombie_period", PW_TYPE_INTEGER,
343           offsetof(home_server,zombie_period), NULL,   "40" },
344         { "status_check", PW_TYPE_STRING_PTR,
345           0, &hs_check,   "none" },
346         { "ping_check", PW_TYPE_STRING_PTR,
347           0, &hs_check,   NULL },
348
349         { "ping_interval", PW_TYPE_INTEGER,
350           offsetof(home_server,ping_interval), NULL,   "30" },
351         { "check_interval", PW_TYPE_INTEGER,
352           offsetof(home_server,ping_interval), NULL,   "30" },
353         { "num_answers_to_alive", PW_TYPE_INTEGER,
354           offsetof(home_server,num_pings_to_alive), NULL,   "3" },
355         { "num_pings_to_alive", PW_TYPE_INTEGER,
356           offsetof(home_server,num_pings_to_alive), NULL,   "3" },
357         { "revive_interval", PW_TYPE_INTEGER,
358           offsetof(home_server,revive_interval), NULL,   "300" },
359         { "status_check_timeout", PW_TYPE_INTEGER,
360           offsetof(home_server,ping_timeout), NULL,   "4" },
361
362         { "username",  PW_TYPE_STRING_PTR,
363           offsetof(home_server,ping_user_name), NULL,  NULL},
364         { "password",  PW_TYPE_STRING_PTR,
365           offsetof(home_server,ping_user_password), NULL,  NULL},
366
367 #ifdef WITH_STATS
368         { "historic_average_window", PW_TYPE_INTEGER,
369           offsetof(home_server,ema.window), NULL,  NULL },
370 #endif
371
372 #ifdef WITH_COA
373         { "irt",  PW_TYPE_INTEGER,
374           offsetof(home_server, coa_irt), 0, Stringify(2) },
375         { "mrt",  PW_TYPE_INTEGER,
376           offsetof(home_server, coa_mrt), 0, Stringify(16) },
377         { "mrc",  PW_TYPE_INTEGER,
378           offsetof(home_server, coa_mrc), 0, Stringify(5) },
379         { "mrd",  PW_TYPE_INTEGER,
380           offsetof(home_server, coa_mrd), 0, Stringify(30) },
381 #endif
382
383         { "limit", PW_TYPE_SUBSECTION, 0, NULL, (const void *) limit_config },
384
385         { NULL, -1, 0, NULL, NULL }             /* end the list */
386 };
387
388
389 static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
390 {
391         const char *name2;
392         home_server *home;
393         int dual = FALSE;
394         CONF_PAIR *cp;
395
396         free(hs_virtual_server); /* used only for printing during parsing */
397         hs_virtual_server = NULL;
398
399         name2 = cf_section_name1(cs);
400         if (!name2 || (strcasecmp(name2, "home_server") != 0)) {
401                 cf_log_err(cf_sectiontoitem(cs),
402                            "Section is not a home_server.");
403                 return 0;
404         }
405
406         name2 = cf_section_name2(cs);
407         if (!name2) {
408                 cf_log_err(cf_sectiontoitem(cs),
409                            "Home server section is missing a name.");
410                 return 0;
411         }
412
413         home = rad_malloc(sizeof(*home));
414         memset(home, 0, sizeof(*home));
415
416         home->name = name2;
417         home->cs = cs;
418
419         memset(&hs_ip4addr, 0, sizeof(hs_ip4addr));
420         memset(&hs_ip6addr, 0, sizeof(hs_ip6addr));
421         if (cf_section_parse(cs, home, home_server_config) < 0) {
422                 goto error;
423         }
424
425         /*
426          *      Figure out which one to use.
427          */
428         if (cf_pair_find(cs, "ipaddr")) {
429                 home->ipaddr.af = AF_INET;
430                 home->ipaddr.ipaddr.ip4addr = hs_ip4addr;
431
432         } else if (cf_pair_find(cs, "ipv6addr")) {
433                 home->ipaddr.af = AF_INET6;
434                 home->ipaddr.ipaddr.ip6addr = hs_ip6addr;
435
436         } else if ((cp = cf_pair_find(cs, "virtual_server")) != NULL) {
437                 home->ipaddr.af = AF_UNSPEC;
438                 home->server = cf_pair_value(cp);
439                 if (!home->server) {
440                         cf_log_err(cf_sectiontoitem(cs),
441                                    "Invalid value for virtual_server");
442                         goto error;
443                 }
444
445                 if (!cf_section_sub_find_name2(rc->cs, "server", home->server)) {
446                   
447                         cf_log_err(cf_sectiontoitem(cs),
448                                    "No such server %s", home->server);
449                         goto error;
450                 }
451
452                 /*
453                  *      When CoA is used, the user has to specify the type
454                  *      of the home server, even when they point to
455                  *      virtual servers.
456                  */
457                 home->secret = strdup("");
458                 goto skip_port;
459
460         } else {
461                 cf_log_err(cf_sectiontoitem(cs),
462                            "No ipaddr, ipv6addr, or virtual_server defined for home server \"%s\".",
463                            name2);
464         error:
465                 free(home);
466                 free(hs_type);
467                 hs_type = NULL;
468                 free(hs_check);
469                 hs_check = NULL;
470                 free(hs_srcipaddr);
471                 hs_srcipaddr = NULL;
472 #ifdef WITH_TCP
473                 free(hs_proto);
474                 hs_proto = NULL;
475 #endif
476                 return 0;
477         }
478
479         if (!home->port || (home->port > 65535)) {
480                 cf_log_err(cf_sectiontoitem(cs),
481                            "No port, or invalid port defined for home server %s.",
482                            name2);
483                 goto error;
484         }
485
486         if (0) {
487                 cf_log_err(cf_sectiontoitem(cs),
488                            "Fatal error!  Home server %s is ourselves!",
489                            name2);
490                 goto error;
491         }
492
493         if (!home->secret) {
494                 cf_log_err(cf_sectiontoitem(cs),
495                            "No shared secret defined for home server %s.",
496                            name2);
497                 goto error;
498         }
499
500         /*
501          *      Use a reasonable default.
502          */
503  skip_port:
504         if (!hs_type) hs_type = strdup("auth+acct");
505
506         if (strcasecmp(hs_type, "auth") == 0) {
507                 home->type = HOME_TYPE_AUTH;
508                 if (pool_type != home->type) {
509                 mismatch:
510                         cf_log_err(cf_sectiontoitem(cs),
511                                    "Server pool cannot include home server %s of type \"%s\"",
512                                    name2, hs_type);
513                         goto error;
514                 }
515
516         } else if (strcasecmp(hs_type, "acct") == 0) {
517                 home->type = HOME_TYPE_ACCT;
518                 if (pool_type != home->type) goto mismatch;
519
520         } else if (strcasecmp(hs_type, "auth+acct") == 0) {
521                 home->type = HOME_TYPE_AUTH;
522                 dual = TRUE;
523
524 #ifdef WITH_COA
525         } else if (strcasecmp(hs_type, "coa") == 0) {
526                 home->type = HOME_TYPE_COA;
527                 dual = FALSE;
528
529                 if (pool_type != home->type) goto mismatch;
530
531                 if (home->server != NULL) {
532                         cf_log_err(cf_sectiontoitem(cs),
533                                    "Home servers of type \"coa\" cannot point to a virtual server");
534                         goto error;
535                 }
536 #endif
537
538         } else {
539                 cf_log_err(cf_sectiontoitem(cs),
540                            "Invalid type \"%s\" for home server %s.",
541                            hs_type, name2);
542                 goto error;
543         }
544         free(hs_type);
545         hs_type = NULL;
546
547         if (!hs_check || (strcasecmp(hs_check, "none") == 0)) {
548                 home->ping_check = HOME_PING_CHECK_NONE;
549
550         } else if (strcasecmp(hs_check, "status-server") == 0) {
551                 home->ping_check = HOME_PING_CHECK_STATUS_SERVER;
552
553         } else if (strcasecmp(hs_check, "request") == 0) {
554                 home->ping_check = HOME_PING_CHECK_REQUEST;
555
556         } else {
557                 cf_log_err(cf_sectiontoitem(cs),
558                            "Invalid ping_check \"%s\" for home server %s.",
559                            hs_check, name2);
560                 goto error;
561         }
562         free(hs_check);
563         hs_check = NULL;
564
565         if ((home->ping_check != HOME_PING_CHECK_NONE) &&
566             (home->ping_check != HOME_PING_CHECK_STATUS_SERVER)) {
567                 if (!home->ping_user_name) {
568                         cf_log_err(cf_sectiontoitem(cs), "You must supply a user name to enable ping checks");
569                         goto error;
570                 }
571
572                 if ((home->type == HOME_TYPE_AUTH) &&
573                     !home->ping_user_password) {
574                         cf_log_err(cf_sectiontoitem(cs), "You must supply a password to enable ping checks");
575                         goto error;
576                 }
577         }
578
579         home->proto = IPPROTO_UDP;
580 #ifdef WITH_TCP
581         if (hs_proto) {
582                 if (strcmp(hs_proto, "udp") == 0) {
583                         free(hs_proto);
584                         hs_proto = NULL;
585                         
586                 } else if (strcmp(hs_proto, "tcp") == 0) {
587                         free(hs_proto);
588                         hs_proto = NULL;
589                         home->proto = IPPROTO_TCP;
590                         
591                 } else {
592                         cf_log_err(cf_sectiontoitem(cs),
593                                    "Unknown proto \"%s\".", hs_proto);
594                         goto error;
595                 }
596         }
597 #endif
598
599         if (!home->server &&
600             rbtree_finddata(home_servers_byaddr, home)) {
601                 cf_log_err(cf_sectiontoitem(cs), "Duplicate home server");
602                 goto error;
603         }
604
605         /*
606          *      If the home is a virtual server, don't look up source IP.
607          */
608         if (!home->server) {
609                 rad_assert(home->ipaddr.af != AF_UNSPEC);
610
611                 /*
612                  *      Otherwise look up the source IP using the same
613                  *      address family as the destination IP.
614                  */
615                 if (hs_srcipaddr) {
616                         if (ip_hton(hs_srcipaddr, home->ipaddr.af, &home->src_ipaddr) < 0) {
617                                 cf_log_err(cf_sectiontoitem(cs), "Failed parsing src_ipaddr");
618                                 goto error;
619                         }
620                         
621                 } else {
622                         /*
623                          *      Source isn't specified: Source is
624                          *      the correct address family, but all zeros.
625                          */
626                         home->src_ipaddr.af = home->ipaddr.af;
627                 }
628         }
629
630         free(hs_srcipaddr);
631         hs_srcipaddr = NULL;
632
633         if (!rbtree_insert(home_servers_byname, home)) {
634                 cf_log_err(cf_sectiontoitem(cs),
635                            "Internal error %d adding home server %s.",
636                            __LINE__, name2);
637                 goto error;
638         }
639
640         if (!home->server &&
641             !rbtree_insert(home_servers_byaddr, home)) {
642                 rbtree_deletebydata(home_servers_byname, home);
643                 cf_log_err(cf_sectiontoitem(cs),
644                            "Internal error %d adding home server %s.",
645                            __LINE__, name2);
646                 goto error;
647         }
648
649 #ifdef WITH_STATS
650         home->number = home_server_max_number++;
651         if (!rbtree_insert(home_servers_bynumber, home)) {
652                 rbtree_deletebydata(home_servers_byname, home);
653                 if (home->ipaddr.af != AF_UNSPEC) {
654                         rbtree_deletebydata(home_servers_byname, home);
655                 }
656                 cf_log_err(cf_sectiontoitem(cs),
657                            "Internal error %d adding home server %s.",
658                            __LINE__, name2);
659                 goto error;
660         }
661 #endif
662
663         if (home->max_outstanding < 8) home->max_outstanding = 8;
664         if (home->max_outstanding > 65536*16) home->max_outstanding = 65536*16;
665
666         if (home->ping_interval < 6) home->ping_interval = 6;
667         if (home->ping_interval > 120) home->ping_interval = 120;
668
669         if (home->response_window < 1) home->response_window = 1;
670         if (home->response_window > 60) home->response_window = 60;
671
672         if (home->zombie_period < 1) home->zombie_period = 1;
673         if (home->zombie_period > 120) home->zombie_period = 120;
674
675         if (home->zombie_period < home->response_window) {
676                 home->zombie_period = home->response_window;
677         }
678
679         if (home->num_pings_to_alive < 3) home->num_pings_to_alive = 3;
680         if (home->num_pings_to_alive > 10) home->num_pings_to_alive = 10;
681
682         if (home->ping_timeout < 3) home->ping_timeout = 3;
683         if (home->ping_timeout > 10) home->ping_timeout = 10;
684
685         if (home->revive_interval < 60) home->revive_interval = 60;
686         if (home->revive_interval > 3600) home->revive_interval = 3600;
687
688 #ifdef WITH_COA
689         if (home->coa_irt < 1) home->coa_irt = 1;
690         if (home->coa_irt > 5) home->coa_irt = 5;
691
692         if (home->coa_mrc < 0) home->coa_mrc = 0;
693         if (home->coa_mrc > 20 ) home->coa_mrc = 20;
694
695         if (home->coa_mrt < 0) home->coa_mrt = 0;
696         if (home->coa_mrt > 30 ) home->coa_mrt = 30;
697
698         if (home->coa_mrd < 5) home->coa_mrd = 5;
699         if (home->coa_mrd > 60 ) home->coa_mrd = 60;
700 #endif
701
702         if (home->max_connections > 1024) home->max_connections = 1024;
703
704 #ifdef WITH_TCP
705         /*
706          *      UDP sockets can't be connection limited.
707          */
708         if (home->proto != IPPROTO_TCP) home->max_connections = 0;
709 #endif
710
711         if ((home->idle_timeout > 0) && (home->idle_timeout < 5))
712                 home->idle_timeout = 5;
713         if ((home->lifetime > 0) && (home->lifetime < 5))
714                 home->lifetime = 5;
715         if ((home->lifetime > 0) && (home->idle_timeout > home->lifetime))
716                 home->idle_timeout = 0;
717
718         if (dual) {
719                 home_server *home2 = rad_malloc(sizeof(*home2));
720
721                 memcpy(home2, home, sizeof(*home2));
722
723                 home2->type = HOME_TYPE_ACCT;
724                 home2->port++;
725                 home2->ping_user_password = NULL;
726                 home2->cs = cs;
727
728                 if (!rbtree_insert(home_servers_byname, home2)) {
729                         cf_log_err(cf_sectiontoitem(cs),
730                                    "Internal error %d adding home server %s.",
731                                    __LINE__, name2);
732                         free(home2);
733                         return 0;
734                 }
735                 
736                 if (!home->server &&
737                     !rbtree_insert(home_servers_byaddr, home2)) {
738                         rbtree_deletebydata(home_servers_byname, home2);
739                         cf_log_err(cf_sectiontoitem(cs),
740                                    "Internal error %d adding home server %s.",
741                                    __LINE__, name2);
742                         free(home2);
743                         return 0;
744                 }
745
746 #ifdef WITH_STATS
747                 home2->number = home_server_max_number++;
748                 if (!rbtree_insert(home_servers_bynumber, home2)) {
749                         rbtree_deletebydata(home_servers_byname, home2);
750                         if (!home2->server) {
751                                 rbtree_deletebydata(home_servers_byname, home2);
752                         }
753                         cf_log_err(cf_sectiontoitem(cs),
754                                    "Internal error %d adding home server %s.",
755                                    __LINE__, name2);
756                         free(home2);
757                         return 0;
758                 }
759 #endif
760         }
761
762         return 1;
763 }
764
765
766 static home_pool_t *server_pool_alloc(const char *name, home_pool_type_t type,
767                                       int server_type, int num_home_servers)
768 {
769         home_pool_t *pool;
770
771         pool = rad_malloc(sizeof(*pool) + (sizeof(pool->servers[0]) *
772                                            num_home_servers));
773         if (!pool) return NULL; /* just for pairanoia */
774         
775         memset(pool, 0, sizeof(*pool) + (sizeof(pool->servers[0]) *
776                                          num_home_servers));
777
778         pool->name = name;
779         pool->type = type;
780         pool->server_type = server_type;
781         pool->num_home_servers = num_home_servers;
782
783         return pool;
784 }
785
786 static int pool_check_home_server(realm_config_t *rc, CONF_PAIR *cp,
787                                   const char *name, int server_type,
788                                   home_server **phome)
789 {
790         home_server myhome, *home;
791         CONF_SECTION *server_cs;
792
793         if (!name) {
794                 cf_log_err(cf_pairtoitem(cp),
795                            "No value given for home_server.");
796                 return 0;
797         }
798
799         myhome.name = name;
800         myhome.type = server_type;
801         home = rbtree_finddata(home_servers_byname, &myhome);
802         if (home) {
803                 *phome = home;
804                 return 1;
805         }
806         
807         server_cs = cf_section_sub_find_name2(rc->cs, "home_server", name);
808         if (!server_cs) {
809                 cf_log_err(cf_pairtoitem(cp),
810                            "Unknown home_server \"%s\".", name);
811                 return 0;
812         }
813         
814         if (!home_server_add(rc, server_cs, server_type)) {
815                 return 0;
816         }
817         
818         home = rbtree_finddata(home_servers_byname, &myhome);
819         if (!home) {
820                 cf_log_err(cf_pairtoitem(cp),
821                            "Internal error %d adding home server \"%s\".",
822                            __LINE__, name);
823                 return 0;
824         }
825
826         *phome = home;
827         return 1;
828 }
829
830
831 static int server_pool_add(realm_config_t *rc,
832                            CONF_SECTION *cs, int server_type, int do_print)
833 {
834         const char *name2;
835         home_pool_t *pool = NULL;
836         const char *value;
837         CONF_PAIR *cp;
838         int num_home_servers;
839         home_server *home;
840
841         name2 = cf_section_name1(cs);
842         if (!name2 || ((strcasecmp(name2, "server_pool") != 0) &&
843                        (strcasecmp(name2, "home_server_pool") != 0))) {
844                 cf_log_err(cf_sectiontoitem(cs),
845                            "Section is not a home_server_pool.");
846                 return 0;
847         }
848
849         name2 = cf_section_name2(cs);
850         if (!name2) {
851                 cf_log_err(cf_sectiontoitem(cs),
852                            "Server pool section is missing a name.");
853                 return 0;
854         }
855
856         /*
857          *      Count the home servers and initalize them.
858          */
859         num_home_servers = 0;
860         for (cp = cf_pair_find(cs, "home_server");
861              cp != NULL;
862              cp = cf_pair_find_next(cs, cp, "home_server")) {
863                 num_home_servers++;
864
865                 if (!pool_check_home_server(rc, cp, cf_pair_value(cp),
866                                             server_type, &home)) {
867                         return 0;
868                 }
869         }
870
871         if (num_home_servers == 0) {
872                 cf_log_err(cf_sectiontoitem(cs),
873                            "No home servers defined in pool %s",
874                            name2);
875                 goto error;
876         }
877
878         pool = server_pool_alloc(name2, HOME_POOL_FAIL_OVER, server_type,
879                                  num_home_servers);
880         pool->cs = cs;
881
882
883         /*
884          *      Fallback servers must be defined, and must be
885          *      virtual servers.
886          */
887         cp = cf_pair_find(cs, "fallback");
888         if (cp) {
889 #ifdef WITH_COA
890                 if (server_type == HOME_TYPE_COA) {
891                         cf_log_err(cf_sectiontoitem(cs), "Home server pools of type \"coa\" cannot have a fallback virtual server.");
892                         goto error;
893                 }
894 #endif
895
896                 if (!pool_check_home_server(rc, cp, cf_pair_value(cp),
897                                             server_type, &pool->fallback)) {
898                         
899                         goto error;
900                 }
901
902                 if (!pool->fallback->server) {
903                         cf_log_err(cf_sectiontoitem(cs), "Fallback home_server %s does NOT contain a virtual_server directive.", pool->fallback->name);
904                         goto error;
905                 }
906         }
907
908         if (do_print) cf_log_info(cs, " home_server_pool %s {", name2);
909
910         cp = cf_pair_find(cs, "type");
911         if (cp) {
912                 static FR_NAME_NUMBER pool_types[] = {
913                         { "load-balance", HOME_POOL_LOAD_BALANCE },
914                         { "fail-over", HOME_POOL_FAIL_OVER },
915                         { "round_robin", HOME_POOL_LOAD_BALANCE },
916                         { "fail_over", HOME_POOL_FAIL_OVER },
917                         { "client-balance", HOME_POOL_CLIENT_BALANCE },
918                         { "client-port-balance", HOME_POOL_CLIENT_PORT_BALANCE },
919                         { "keyed-balance", HOME_POOL_KEYED_BALANCE },
920                         { NULL, 0 }
921                 };
922
923                 value = cf_pair_value(cp);
924                 if (!value) {
925                         cf_log_err(cf_pairtoitem(cp),
926                                    "No value given for type.");
927                         goto error;
928                 }
929
930                 pool->type = fr_str2int(pool_types, value, 0);
931                 if (!pool->type) {
932                         cf_log_err(cf_pairtoitem(cp),
933                                    "Unknown type \"%s\".",
934                                    value);
935                         goto error;
936                 }
937
938                 if (do_print) cf_log_info(cs, "\ttype = %s", value);
939         }
940
941         cp = cf_pair_find(cs, "virtual_server");
942         if (cp) {
943                 pool->virtual_server = cf_pair_value(cp);               
944                 if (!pool->virtual_server) {
945                         cf_log_err(cf_pairtoitem(cp), "No value given for virtual_server");
946                         goto error;
947                 }
948
949                 if (do_print) {
950                         cf_log_info(cs, "\tvirtual_server = %s", pool->virtual_server);
951                 }
952
953                 if (!cf_section_sub_find_name2(rc->cs, "server",
954                                                pool->virtual_server)) {
955                         cf_log_err(cf_pairtoitem(cp), "No such server %s",
956                                    pool->virtual_server);
957                         goto error;
958                 }
959
960         }
961
962         num_home_servers = 0;
963         for (cp = cf_pair_find(cs, "home_server");
964              cp != NULL;
965              cp = cf_pair_find_next(cs, cp, "home_server")) {
966                 home_server myhome;
967
968                 value = cf_pair_value(cp);
969
970                 memset(&myhome, 0, sizeof(&myhome));
971                 myhome.name = value;
972                 myhome.type = server_type;
973
974                 home = rbtree_finddata(home_servers_byname, &myhome);
975                 if (!home) {
976                         DEBUG2("Internal sanity check failed");
977                         goto error;
978                 }
979
980                 if (0) {
981                         DEBUG2("Warning: Duplicate home server %s in server pool %s", home->name, pool->name);
982                         continue;
983                 }
984
985                 if (do_print) cf_log_info(cs, "\thome_server = %s", home->name);
986                 pool->servers[num_home_servers++] = home;
987         } /* loop over home_server's */
988
989         if (pool->fallback && do_print) {
990                 cf_log_info(cs, "\tfallback = %s", pool->fallback->name);
991         }
992
993         if (!rbtree_insert(home_pools_byname, pool)) {
994                 rad_assert("Internal sanity check failed");
995                 goto error;
996         }
997
998         if (do_print) cf_log_info(cs, " }");
999
1000         cf_data_add(cs, "home_server_pool", pool, free);
1001
1002         rad_assert(pool->server_type != 0);
1003
1004         return 1;
1005
1006  error:
1007         if (do_print) cf_log_info(cs, " }");
1008         free(pool);
1009         return 0;
1010 }
1011 #endif
1012
1013 static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
1014                           const char *realm,
1015                           const char *name, const char *secret,
1016                           home_pool_type_t ldflag, home_pool_t **pool_p,
1017                           int type, const char *server)
1018 {
1019 #ifdef WITH_PROXY
1020         int i, insert_point, num_home_servers;
1021         home_server myhome, *home;
1022         home_pool_t mypool, *pool;
1023         CONF_SECTION *subcs;
1024 #else
1025         rc = rc;                /* -Wunused */
1026         realm = realm;
1027         secret = secret;
1028         ldflag = ldflag;
1029         type = type;
1030         server = server;
1031 #endif
1032
1033         /*
1034          *      LOCAL realms get sanity checked, and nothing else happens.
1035          */
1036         if (strcmp(name, "LOCAL") == 0) {
1037                 if (*pool_p) {
1038                         cf_log_err(cf_sectiontoitem(cs), "Realm \"%s\" cannot be both LOCAL and remote", name);
1039                         return 0;
1040                 }
1041                 return 1;
1042         }
1043
1044 #ifndef WITH_PROXY
1045         return 0;               /* Not proxying.  Can't do non-LOCAL realms */
1046
1047 #else
1048         mypool.name = realm;
1049         mypool.server_type = type;
1050         pool = rbtree_finddata(home_pools_byname, &mypool);
1051         if (pool) {
1052                 if (pool->type != ldflag) {
1053                         cf_log_err(cf_sectiontoitem(cs), "Inconsistent ldflag for server pool \"%s\"", name);
1054                         return 0;
1055                 }
1056
1057                 if (pool->server_type != type) {
1058                         cf_log_err(cf_sectiontoitem(cs), "Inconsistent home server type for server pool \"%s\"", name);
1059                         return 0;
1060                 }
1061         }
1062
1063         myhome.name = name;
1064         myhome.type = type;
1065         home = rbtree_finddata(home_servers_byname, &myhome);
1066         if (home) {
1067                 if (secret && (strcmp(home->secret, secret) != 0)) {
1068                         cf_log_err(cf_sectiontoitem(cs), "Inconsistent shared secret for home server \"%s\"", name);
1069                         return 0;
1070                 }
1071
1072                 if (home->type != type) {
1073                         cf_log_err(cf_sectiontoitem(cs), "Inconsistent type for home server \"%s\"", name);
1074                         return 0;
1075                 }
1076
1077                 /*
1078                  *      See if the home server is already listed
1079                  *      in the pool.  If so, do nothing else.
1080                  */
1081                 if (pool) for (i = 0; i < pool->num_home_servers; i++) {
1082                         if (pool->servers[i] == home) {
1083                                 return 1;
1084                         }
1085                 }
1086         }
1087
1088         /*
1089          *      If we do have a pool, check that there is room to
1090          *      insert the home server we've found, or the one that we
1091          *      create here.
1092          *
1093          *      Note that we insert it into the LAST available
1094          *      position, in order to maintain the same order as in
1095          *      the configuration files.
1096          */
1097         insert_point = -1;
1098         if (pool) {
1099                 for (i = pool->num_home_servers - 1; i >= 0; i--) {
1100                         if (pool->servers[i]) break;
1101
1102                         if (!pool->servers[i]) {
1103                                 insert_point = i;
1104                         }
1105                 }
1106
1107                 if (insert_point < 0) {
1108                         cf_log_err(cf_sectiontoitem(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);
1109                         return 0;
1110                 }
1111         }
1112
1113         /*
1114          *      No home server, allocate one.
1115          */
1116         if (!home) {
1117                 const char *p;
1118                 char *q;
1119
1120                 home = rad_malloc(sizeof(*home));
1121                 memset(home, 0, sizeof(*home));
1122
1123                 home->name = name;
1124                 home->hostname = name;
1125                 home->type = type;
1126                 home->secret = secret;
1127                 home->cs = cs;
1128
1129                 p = strchr(name, ':');
1130                 if (!p) {
1131                         if (type == HOME_TYPE_AUTH) {
1132                                 home->port = PW_AUTH_UDP_PORT;
1133                         } else {
1134                                 home->port = PW_ACCT_UDP_PORT;
1135                         }
1136
1137                         p = name;
1138                         q = NULL;
1139
1140                 } else if (p == name) {
1141                                 cf_log_err(cf_sectiontoitem(cs),
1142                                            "Invalid hostname %s.",
1143                                            name);
1144                                 free(home);
1145                                 return 0;
1146
1147                 } else {
1148                         home->port = atoi(p + 1);
1149                         if ((home->port == 0) || (home->port > 65535)) {
1150                                 cf_log_err(cf_sectiontoitem(cs),
1151                                            "Invalid port %s.",
1152                                            p + 1);
1153                                 free(home);
1154                                 return 0;
1155                         }
1156
1157                         q = rad_malloc((p - name) + 1);
1158                         memcpy(q, name, (p - name));
1159                         q[p - name] = '\0';
1160                         p = q;
1161                 }
1162
1163                 if (!server) {
1164                         if (ip_hton(p, AF_UNSPEC, &home->ipaddr) < 0) {
1165                                 cf_log_err(cf_sectiontoitem(cs),
1166                                            "Failed looking up hostname %s.",
1167                                            p);
1168                                 free(home);
1169                                 free(q);
1170                                 return 0;
1171                         }
1172                         home->src_ipaddr.af = home->ipaddr.af;
1173                 } else {
1174                         home->ipaddr.af = AF_UNSPEC;
1175                         home->server = server;
1176                 }
1177                 free(q);
1178
1179                 /*
1180                  *      Use the old-style configuration.
1181                  */
1182                 home->max_outstanding = 65535*16;
1183                 home->zombie_period = rc->retry_delay * rc->retry_count;
1184                 if (home->zombie_period == 0) home->zombie_period =30;
1185                 home->response_window = home->zombie_period - 1;
1186
1187                 home->ping_check = HOME_PING_CHECK_NONE;
1188
1189                 home->revive_interval = rc->dead_time;
1190
1191                 if (rbtree_finddata(home_servers_byaddr, home)) {
1192                         cf_log_err(cf_sectiontoitem(cs), "Home server %s has the same IP address and/or port as another home server.", name);
1193                         free(home);
1194                         return 0;
1195                 }
1196
1197                 if (!rbtree_insert(home_servers_byname, home)) {
1198                         cf_log_err(cf_sectiontoitem(cs), "Internal error %d adding home server %s.", __LINE__, name);
1199                         free(home);
1200                         return 0;
1201                 }
1202
1203                 if (!rbtree_insert(home_servers_byaddr, home)) {
1204                         rbtree_deletebydata(home_servers_byname, home);
1205                         cf_log_err(cf_sectiontoitem(cs), "Internal error %d adding home server %s.", __LINE__, name);
1206                         free(home);
1207                         return 0;
1208                 }
1209
1210 #ifdef WITH_STATS
1211                 home->number = home_server_max_number++;
1212                 if (!rbtree_insert(home_servers_bynumber, home)) {
1213                         rbtree_deletebydata(home_servers_byname, home);
1214                         if (home->ipaddr.af != AF_UNSPEC) {
1215                                 rbtree_deletebydata(home_servers_byname, home);
1216                         }
1217                         cf_log_err(cf_sectiontoitem(cs),
1218                                    "Internal error %d adding home server %s.",
1219                                    __LINE__, name);
1220                         free(home);
1221                         return 0;
1222                 }
1223 #endif
1224         }
1225
1226         /*
1227          *      We now have a home server, see if we can insert it
1228          *      into pre-existing pool.
1229          */
1230         if (insert_point >= 0) {
1231                 rad_assert(pool != NULL);
1232                 pool->servers[insert_point] = home;
1233                 return 1;
1234         }
1235
1236         rad_assert(pool == NULL);
1237         rad_assert(home != NULL);
1238
1239         /*
1240          *      Count the old-style realms of this name.
1241          */
1242         num_home_servers = 0;
1243         for (subcs = cf_section_find_next(cs, NULL, "realm");
1244              subcs != NULL;
1245              subcs = cf_section_find_next(cs, subcs, "realm")) {
1246                 const char *this = cf_section_name2(subcs);
1247
1248                 if (!this || (strcmp(this, realm) != 0)) continue;
1249                 num_home_servers++;
1250         }
1251
1252         if (num_home_servers == 0) {
1253                 cf_log_err(cf_sectiontoitem(cs), "Internal error counting pools for home server %s.", name);
1254                 free(home);
1255                 return 0;
1256         }
1257
1258         pool = server_pool_alloc(realm, ldflag, type, num_home_servers);
1259         pool->cs = cs;
1260
1261         pool->servers[0] = home;
1262
1263         if (!rbtree_insert(home_pools_byname, pool)) {
1264                 rad_assert("Internal sanity check failed");
1265                 return 0;
1266         }
1267
1268         *pool_p = pool;
1269
1270         return 1;
1271 #endif
1272 }
1273
1274 static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
1275 {
1276         const char *host;
1277         const char *secret = NULL;
1278         home_pool_type_t ldflag;
1279         CONF_PAIR *cp;
1280
1281         cp = cf_pair_find(cs, "ldflag");
1282         ldflag = HOME_POOL_FAIL_OVER;
1283         if (cp) {
1284                 host = cf_pair_value(cp);
1285                 if (!host) {
1286                         cf_log_err(cf_pairtoitem(cp), "No value specified for ldflag");
1287                         return 0;
1288                 }
1289
1290                 if (strcasecmp(host, "fail_over") == 0) {
1291                         cf_log_info(cs, "\tldflag = fail_over");
1292                         
1293                 } else if (strcasecmp(host, "round_robin") == 0) {
1294                         ldflag = HOME_POOL_LOAD_BALANCE;
1295                         cf_log_info(cs, "\tldflag = round_robin");
1296                         
1297                 } else {
1298                         cf_log_err(cf_sectiontoitem(cs), "Unknown value \"%s\" for ldflag", host);
1299                         return 0;
1300                 }
1301         } /* else don't print it. */
1302
1303         /*
1304          *      Allow old-style if it doesn't exist, or if it exists and
1305          *      it's LOCAL.
1306          */
1307         cp = cf_pair_find(cs, "authhost");
1308         if (cp) {
1309                 host = cf_pair_value(cp);
1310                 if (!host) {
1311                         cf_log_err(cf_pairtoitem(cp), "No value specified for authhost");
1312                         return 0;
1313                 }
1314
1315                 if (strcmp(host, "LOCAL") != 0) {
1316                         cp = cf_pair_find(cs, "secret");
1317                         if (!cp) {
1318                                 cf_log_err(cf_sectiontoitem(cs), "No shared secret supplied for realm: %s", r->name);
1319                                 return 0;
1320                         }
1321
1322                         secret = cf_pair_value(cp);
1323                         if (!secret) {
1324                                 cf_log_err(cf_pairtoitem(cp), "No value specified for secret");
1325                                 return 0;
1326                         }
1327                 }
1328                         
1329                 cf_log_info(cs, "\tauthhost = %s",  host);
1330
1331                 if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
1332                                     &r->auth_pool, HOME_TYPE_AUTH, NULL)) {
1333                         return 0;
1334                 }
1335         }
1336
1337         cp = cf_pair_find(cs, "accthost");
1338         if (cp) {
1339                 host = cf_pair_value(cp);
1340                 if (!host) {
1341                         cf_log_err(cf_pairtoitem(cp), "No value specified for accthost");
1342                         return 0;
1343                 }
1344
1345                 /*
1346                  *      Don't look for a secret again if it was found
1347                  *      above.
1348                  */
1349                 if ((strcmp(host, "LOCAL") != 0) && !secret) {
1350                         cp = cf_pair_find(cs, "secret");
1351                         if (!cp) {
1352                                 cf_log_err(cf_sectiontoitem(cs), "No shared secret supplied for realm: %s", r->name);
1353                                 return 0;
1354                         }
1355                         
1356                         secret = cf_pair_value(cp);
1357                         if (!secret) {
1358                                 cf_log_err(cf_pairtoitem(cp), "No value specified for secret");
1359                                 return 0;
1360                         }
1361                 }
1362                 
1363                 cf_log_info(cs, "\taccthost = %s", host);
1364
1365                 if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
1366                                     &r->acct_pool, HOME_TYPE_ACCT, NULL)) {
1367                         return 0;
1368                 }
1369         }
1370
1371         cp = cf_pair_find(cs, "virtual_server");
1372         if (cp) {
1373                 host = cf_pair_value(cp);
1374                 if (!host) {
1375                         cf_log_err(cf_pairtoitem(cp), "No value specified for virtual_server");
1376                         return 0;
1377                 }
1378
1379                 cf_log_info(cs, "\tvirtual_server = %s", host);
1380
1381                 if (!old_server_add(rc, cs, r->name, host, "", ldflag,
1382                                     &r->auth_pool, HOME_TYPE_AUTH, host)) {
1383                         return 0;
1384                 }
1385                 if (!old_server_add(rc, cs, r->name, host, "", ldflag,
1386                                     &r->acct_pool, HOME_TYPE_ACCT, host)) {
1387                         return 0;
1388                 }
1389         }
1390
1391         if (secret) cf_log_info(cs, "\tsecret = %s", secret);
1392
1393         return 1;
1394
1395 }
1396
1397
1398 #ifdef WITH_PROXY
1399 static int add_pool_to_realm(realm_config_t *rc, CONF_SECTION *cs,
1400                              const char *name, home_pool_t **dest,
1401                              int server_type, int do_print)
1402 {
1403         home_pool_t mypool, *pool;
1404
1405         mypool.name = name;
1406         mypool.server_type = server_type;
1407
1408         pool = rbtree_finddata(home_pools_byname, &mypool);
1409         if (!pool) {
1410                 CONF_SECTION *pool_cs;
1411
1412                 pool_cs = cf_section_sub_find_name2(rc->cs,
1413                                                     "home_server_pool",
1414                                                     name);
1415                 if (!pool_cs) {
1416                         pool_cs = cf_section_sub_find_name2(rc->cs,
1417                                                             "server_pool",
1418                                                             name);
1419                 }
1420                 if (!pool_cs) {
1421                         cf_log_err(cf_sectiontoitem(cs), "Failed to find home_server_pool \"%s\"", name);
1422                         return 0;
1423                 }
1424
1425                 if (!server_pool_add(rc, pool_cs, server_type, do_print)) {
1426                         return 0;
1427                 }
1428
1429                 pool = rbtree_finddata(home_pools_byname, &mypool);
1430                 if (!pool) {
1431                         radlog(L_ERR, "Internal sanity check failed in add_pool_to_realm");
1432                         return 0;
1433                 }
1434         }
1435
1436         if (pool->server_type != server_type) {
1437                 cf_log_err(cf_sectiontoitem(cs), "Incompatible home_server_pool \"%s\" (mixed auth_pool / acct_pool)", name);
1438                 return 0;
1439         }
1440
1441         *dest = pool;
1442
1443         return 1;
1444 }
1445 #endif
1446
1447
1448 static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
1449 {
1450         const char *name2;
1451         REALM *r = NULL;
1452         CONF_PAIR *cp;
1453 #ifdef WITH_PROXY
1454         home_pool_t *auth_pool, *acct_pool;
1455         const char *auth_pool_name, *acct_pool_name;
1456 #endif
1457
1458         name2 = cf_section_name1(cs);
1459         if (!name2 || (strcasecmp(name2, "realm") != 0)) {
1460                 cf_log_err(cf_sectiontoitem(cs), "Section is not a realm.");
1461                 return 0;
1462         }
1463
1464         name2 = cf_section_name2(cs);
1465         if (!name2) {
1466                 cf_log_err(cf_sectiontoitem(cs), "Realm section is missing the realm name.");
1467                 return 0;
1468         }
1469
1470 #ifdef WITH_PROXY
1471         auth_pool = acct_pool = NULL;
1472         auth_pool_name = acct_pool_name = NULL;
1473
1474         /*
1475          *      Prefer new configuration to old one.
1476          */
1477         cp = cf_pair_find(cs, "pool");
1478         if (!cp) cp = cf_pair_find(cs, "home_server_pool");
1479         if (cp) auth_pool_name = cf_pair_value(cp);
1480         if (cp && auth_pool_name) {
1481                 acct_pool_name = auth_pool_name;
1482                 if (!add_pool_to_realm(rc, cs,
1483                                        auth_pool_name, &auth_pool,
1484                                        HOME_TYPE_AUTH, 1)) {
1485                         return 0;
1486                 }
1487                 if (!add_pool_to_realm(rc, cs,
1488                                        auth_pool_name, &acct_pool,
1489                                        HOME_TYPE_ACCT, 0)) {
1490                         return 0;
1491                 }
1492         }
1493
1494         cp = cf_pair_find(cs, "auth_pool");
1495         if (cp) auth_pool_name = cf_pair_value(cp);
1496         if (cp && auth_pool_name) {
1497                 if (auth_pool) {
1498                         cf_log_err(cf_sectiontoitem(cs), "Cannot use \"pool\" and \"auth_pool\" at the same time.");
1499                         return 0;
1500                 }
1501                 if (!add_pool_to_realm(rc, cs,
1502                                        auth_pool_name, &auth_pool,
1503                                        HOME_TYPE_AUTH, 1)) {
1504                         return 0;
1505                 }
1506         }
1507
1508         cp = cf_pair_find(cs, "acct_pool");
1509         if (cp) acct_pool_name = cf_pair_value(cp);
1510         if (cp && acct_pool_name) {
1511                 int do_print = TRUE;
1512
1513                 if (acct_pool) {
1514                         cf_log_err(cf_sectiontoitem(cs), "Cannot use \"pool\" and \"acct_pool\" at the same time.");
1515                         return 0;
1516                 }
1517
1518                 if (!auth_pool ||
1519                     (strcmp(auth_pool_name, acct_pool_name) != 0)) {
1520                         do_print = TRUE;
1521                 }
1522
1523                 if (!add_pool_to_realm(rc, cs,
1524                                        acct_pool_name, &acct_pool,
1525                                        HOME_TYPE_ACCT, do_print)) {
1526                         return 0;
1527                 }
1528         }
1529 #endif
1530
1531         cf_log_info(cs, " realm %s {", name2);
1532
1533 #ifdef WITH_PROXY
1534         /*
1535          *      The realm MAY already exist if it's an old-style realm.
1536          *      In that case, merge the old-style realm with this one.
1537          */
1538         r = realm_find2(name2);
1539         if (r && (strcmp(r->name, name2) == 0)) {
1540                 if (cf_pair_find(cs, "auth_pool") ||
1541                     cf_pair_find(cs, "acct_pool")) {
1542                         cf_log_err(cf_sectiontoitem(cs), "Duplicate realm \"%s\"", name2);
1543                         goto error;
1544                 }
1545
1546                 if (!old_realm_config(rc, cs, r)) {
1547                         goto error;
1548                 }
1549
1550                 cf_log_info(cs, " } # realm %s", name2);
1551                 return 1;
1552         }
1553 #endif
1554
1555 #ifdef HAVE_REGEX_H
1556         if (name2[0] == '~') {
1557                 regex_t reg;
1558                 
1559                 /*
1560                  *      Include substring matches.
1561                  */
1562                 if (regcomp(&reg, name2 + 1,
1563                             REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) {
1564                         cf_log_err(cf_sectiontoitem(cs),
1565                                    "Invalid regex in realm \"%s\"", name2);
1566                         goto error;
1567                 }
1568                 regfree(&reg);
1569         }
1570 #endif
1571
1572         r = rad_malloc(sizeof(*r));
1573         memset(r, 0, sizeof(*r));
1574
1575         r->name = name2;
1576         r->striprealm = 1;
1577 #ifdef WITH_PROXY
1578         r->auth_pool = auth_pool;
1579         r->acct_pool = acct_pool;
1580         
1581         if (auth_pool_name &&
1582             (auth_pool_name == acct_pool_name)) { /* yes, ptr comparison */
1583                 cf_log_info(cs, "\tpool = %s", auth_pool_name);
1584         } else {
1585                 if (auth_pool_name) cf_log_info(cs, "\tauth_pool = %s", auth_pool_name);
1586                 if (acct_pool_name) cf_log_info(cs, "\tacct_pool = %s", acct_pool_name);
1587         }
1588 #endif
1589
1590         cp = cf_pair_find(cs, "nostrip");
1591         if (cp && (cf_pair_value(cp) == NULL)) {
1592                 r->striprealm = 0;
1593                 cf_log_info(cs, "\tnostrip");
1594         }
1595
1596         /*
1597          *      We're a new-style realm.  Complain if we see the old
1598          *      directives.
1599          */
1600         if (r->auth_pool || r->acct_pool) {
1601                 if (((cp = cf_pair_find(cs, "authhost")) != NULL) ||
1602                     ((cp = cf_pair_find(cs, "accthost")) != NULL) ||
1603                     ((cp = cf_pair_find(cs, "secret")) != NULL) ||
1604                     ((cp = cf_pair_find(cs, "ldflag")) != NULL)) {
1605                         DEBUG2("WARNING: Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
1606                 }
1607
1608
1609                 /*
1610                  *      The realm MAY be an old-style realm, as there
1611                  *      was no auth_pool or acct_pool.  Double-check
1612                  *      it, just to be safe.
1613                  */
1614         } else if (!old_realm_config(rc, cs, r)) {
1615                 goto error;
1616         }
1617
1618 #ifdef HAVE_REGEX_H
1619         /*
1620          *      It's a regex.  Add it to a separate list.
1621          */
1622         if (name2[0] == '~') {
1623                 realm_regex_t *rr, **last;
1624
1625                 rr = rad_malloc(sizeof(*rr));
1626                 
1627                 last = &realms_regex;
1628                 while (*last) last = &((*last)->next);  /* O(N^2)... sue me. */
1629
1630                 r->name = name2;
1631                 rr->realm = r;
1632                 rr->next = NULL;
1633
1634                 *last = rr;
1635
1636                 cf_log_info(cs, " }");
1637                 return 1;
1638         }
1639 #endif
1640
1641         if (!rbtree_insert(realms_byname, r)) {
1642                 rad_assert("Internal sanity check failed");
1643                 goto error;
1644         }
1645
1646         cf_log_info(cs, " }");
1647
1648         return 1;
1649
1650  error:
1651         cf_log_info(cs, " } # realm %s", name2);
1652         free(r);
1653         return 0;
1654 }
1655
1656 #ifdef WITH_COA
1657 static const FR_NAME_NUMBER home_server_types[] = {
1658         { "auth", HOME_TYPE_AUTH },
1659         { "auth+acct", HOME_TYPE_AUTH },
1660         { "acct", HOME_TYPE_ACCT },
1661         { "coa", HOME_TYPE_COA },
1662         { NULL, 0 }
1663 };
1664
1665 static int pool_peek_type(CONF_SECTION *config, CONF_SECTION *cs)
1666 {
1667         int home;
1668         const char *name, *type;
1669         CONF_PAIR *cp;
1670         CONF_SECTION *server_cs;
1671
1672         cp = cf_pair_find(cs, "home_server");
1673         if (!cp) {
1674                 cf_log_err(cf_sectiontoitem(cs), "Pool does not contain a \"home_server\" entry");
1675                 return HOME_TYPE_INVALID;
1676         }
1677
1678         name = cf_pair_value(cp);
1679         if (!name) {
1680                 cf_log_err(cf_pairtoitem(cp), "home_server entry does not reference a home server");
1681                 return HOME_TYPE_INVALID;
1682         }
1683
1684         server_cs = cf_section_sub_find_name2(config, "home_server", name);
1685         if (!server_cs) {
1686                 cf_log_err(cf_pairtoitem(cp), "home_server \"%s\" does not exist", name);
1687                 return HOME_TYPE_INVALID;
1688         }
1689
1690         cp = cf_pair_find(server_cs, "type");
1691         if (!cp) {
1692                 cf_log_err(cf_sectiontoitem(server_cs), "home_server %s does not contain a \"type\" entry", name);
1693                 return HOME_TYPE_INVALID;
1694         }
1695
1696         type = cf_pair_value(cp);
1697         if (!type) {
1698                 cf_log_err(cf_sectiontoitem(server_cs), "home_server %s contains an empty \"type\" entry", name);
1699                 return HOME_TYPE_INVALID;
1700         }
1701
1702         home = fr_str2int(home_server_types, type, HOME_TYPE_INVALID);
1703         if (home == HOME_TYPE_INVALID) {
1704                 cf_log_err(cf_sectiontoitem(server_cs), "home_server %s contains an invalid \"type\" entry of value \"%s\"", name, type);
1705                 return HOME_TYPE_INVALID;
1706         }
1707
1708         return home;            /* 'cause we miss it so much */
1709 }
1710 #endif
1711
1712 int realms_init(CONF_SECTION *config)
1713 {
1714         CONF_SECTION *cs;
1715         realm_config_t *rc, *old_rc;
1716
1717         if (realms_byname) return 1;
1718
1719         realms_byname = rbtree_create(realm_name_cmp, free, 0);
1720         if (!realms_byname) {
1721                 realms_free();
1722                 return 0;
1723         }
1724
1725 #ifdef WITH_PROXY
1726         home_servers_byaddr = rbtree_create(home_server_addr_cmp, free, 0);
1727         if (!home_servers_byaddr) {
1728                 realms_free();
1729                 return 0;
1730         }
1731
1732         home_servers_byname = rbtree_create(home_server_name_cmp, NULL, 0);
1733         if (!home_servers_byname) {
1734                 realms_free();
1735                 return 0;
1736         }
1737
1738 #ifdef WITH_STATS
1739         home_servers_bynumber = rbtree_create(home_server_number_cmp, NULL, 0);
1740         if (!home_servers_bynumber) {
1741                 realms_free();
1742                 return 0;
1743         }
1744 #endif
1745
1746         home_pools_byname = rbtree_create(home_pool_name_cmp, NULL, 0);
1747         if (!home_pools_byname) {
1748                 realms_free();
1749                 return 0;
1750         }
1751 #endif
1752
1753         rc = rad_malloc(sizeof(*rc));
1754         memset(rc, 0, sizeof(*rc));
1755         rc->cs = config;
1756
1757 #ifdef WITH_PROXY
1758         cs = cf_subsection_find_next(config, NULL, "proxy");
1759         if (cs) {
1760                 cf_section_parse(cs, rc, proxy_config);
1761         } else {
1762                 rc->dead_time = DEAD_TIME;
1763                 rc->retry_count = RETRY_COUNT;
1764                 rc->retry_delay = RETRY_DELAY;
1765                 rc->fallback = 0;
1766                 rc->wake_all_if_all_dead= 0;
1767         }
1768 #endif
1769
1770         for (cs = cf_subsection_find_next(config, NULL, "realm");
1771              cs != NULL;
1772              cs = cf_subsection_find_next(config, cs, "realm")) {
1773                 if (!realm_add(rc, cs)) {
1774                         free(rc);
1775                         realms_free();
1776                         return 0;
1777                 }
1778         }
1779
1780 #ifdef WITH_COA
1781         /*
1782          *      CoA pools aren't tied to realms.
1783          */
1784         for (cs = cf_subsection_find_next(config, NULL, "home_server_pool");
1785              cs != NULL;
1786              cs = cf_subsection_find_next(config, cs, "home_server_pool")) {
1787                 int type;
1788
1789                 /*
1790                  *      Pool was already loaded.
1791                  */
1792                 if (cf_data_find(cs, "home_server_pool")) continue;
1793
1794                 type = pool_peek_type(config, cs);
1795                 if (type == HOME_TYPE_INVALID) return 0;
1796
1797                 if (!server_pool_add(rc, cs, type, TRUE)) {
1798                         return 0;
1799                 }
1800         }
1801 #endif
1802
1803
1804 #ifdef WITH_PROXY
1805         xlat_register("home_server", xlat_home_server, NULL);
1806         xlat_register("home_server_pool", xlat_server_pool, NULL);
1807 #endif
1808
1809         /*
1810          *      Swap pointers atomically.
1811          */
1812         old_rc = realm_config;
1813         realm_config = rc;
1814         free(old_rc);
1815
1816         return 1;
1817 }
1818
1819 /*
1820  *      Find a realm where "name" might be the regex.
1821  */
1822 REALM *realm_find2(const char *name)
1823 {
1824         REALM myrealm;
1825         REALM *realm;
1826         
1827         if (!name) name = "NULL";
1828
1829         myrealm.name = name;
1830         realm = rbtree_finddata(realms_byname, &myrealm);
1831         if (realm) return realm;
1832
1833 #ifdef HAVE_REGEX_H
1834         if (realms_regex) {
1835                 realm_regex_t *this;
1836
1837                 for (this = realms_regex; this != NULL; this = this->next) {
1838                         if (strcmp(this->realm->name, name) == 0) {
1839                                 return this->realm;
1840                         }
1841                 }
1842         }
1843 #endif
1844
1845         /*
1846          *      Couldn't find a realm.  Look for DEFAULT.
1847          */
1848         myrealm.name = "DEFAULT";
1849         return rbtree_finddata(realms_byname, &myrealm);
1850 }
1851
1852
1853 /*
1854  *      Find a realm in the REALM list.
1855  */
1856 REALM *realm_find(const char *name)
1857 {
1858         REALM myrealm;
1859         REALM *realm;
1860         
1861         if (!name) name = "NULL";
1862
1863         myrealm.name = name;
1864         realm = rbtree_finddata(realms_byname, &myrealm);
1865         if (realm) return realm;
1866
1867 #ifdef HAVE_REGEX_H
1868         if (realms_regex) {
1869                 realm_regex_t *this;
1870
1871                 for (this = realms_regex; this != NULL; this = this->next) {
1872                         int compare;
1873                         regex_t reg;
1874
1875                         /*
1876                          *      Include substring matches.
1877                          */
1878                         if (regcomp(&reg, this->realm->name + 1,
1879                                     REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) {
1880                                 continue;
1881                         }
1882
1883                         compare = regexec(&reg, name, 0, NULL, 0);
1884                         regfree(&reg);
1885
1886                         if (compare == 0) return this->realm;
1887                 }
1888         }
1889 #endif
1890
1891         /*
1892          *      Couldn't find a realm.  Look for DEFAULT.
1893          */
1894         myrealm.name = "DEFAULT";
1895         return rbtree_finddata(realms_byname, &myrealm);
1896 }
1897
1898
1899 #ifdef WITH_PROXY
1900 home_server *home_server_ldb(const char *realmname,
1901                              home_pool_t *pool, REQUEST *request)
1902 {
1903         int             start;
1904         int             count;
1905         home_server     *found = NULL;
1906         home_server     *zombie = NULL;
1907         VALUE_PAIR      *vp;
1908
1909         /*
1910          *      Determine how to pick choose the home server.
1911          */
1912         switch (pool->type) {
1913                 uint32_t hash;
1914
1915                 /*
1916                  *      For load-balancing by client IP address, we
1917                  *      pick a home server by hashing the client IP.
1918                  *
1919                  *      This isn't as even a load distribution as
1920                  *      tracking the State attribute, but it's better
1921                  *      than nothing.
1922                  */
1923         case HOME_POOL_CLIENT_BALANCE:
1924                 switch (request->packet->src_ipaddr.af) {
1925                 case AF_INET:
1926                         hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
1927                                          sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
1928                         break;
1929                 case AF_INET6:
1930                         hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
1931                                          sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
1932                         break;
1933                 default:
1934                         hash = 0;
1935                         break;
1936                 }
1937                 start = hash % pool->num_home_servers;
1938                 break;
1939
1940         case HOME_POOL_CLIENT_PORT_BALANCE:
1941                 switch (request->packet->src_ipaddr.af) {
1942                 case AF_INET:
1943                         hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
1944                                          sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
1945                         break;
1946                 case AF_INET6:
1947                         hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
1948                                          sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
1949                         break;
1950                 default:
1951                         hash = 0;
1952                         break;
1953                 }
1954                 fr_hash_update(&request->packet->src_port,
1955                                  sizeof(request->packet->src_port), hash);
1956                 start = hash % pool->num_home_servers;
1957                 break;
1958
1959         case HOME_POOL_KEYED_BALANCE:
1960                 if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY)) != NULL) {
1961                         hash = fr_hash(vp->vp_strvalue, vp->length);
1962                         start = hash % pool->num_home_servers;
1963                         break;
1964                 }
1965                 /* FALL-THROUGH */
1966                                 
1967         case HOME_POOL_LOAD_BALANCE:
1968         case HOME_POOL_FAIL_OVER:
1969                 start = 0;
1970                 break;
1971
1972         default:                /* this shouldn't happen... */
1973                 start = 0;
1974                 break;
1975
1976         }
1977
1978         /*
1979          *      Starting with the home server we chose, loop through
1980          *      all home servers.  If the current one is dead, skip
1981          *      it.  If it is too busy, skip it.
1982          *
1983          *      Otherwise, use it.
1984          */
1985         for (count = 0; count < pool->num_home_servers; count++) {
1986                 home_server *home = pool->servers[(start + count) % pool->num_home_servers];
1987
1988                 if (!home) continue;
1989
1990                 /*
1991                  *      Skip dead home servers.
1992                  */
1993                 if (home->state == HOME_STATE_IS_DEAD) {
1994                         continue;
1995                 }
1996
1997                 /*
1998                  *      This home server is too busy.  Choose another one.
1999                  */
2000                 if (home->currently_outstanding >= home->max_outstanding) {
2001                         continue;
2002                 }
2003
2004 #ifdef WITH_DETAIL
2005                 /*
2006                  *      We read the packet from a detail file, AND it
2007                  *      came from this server.  Don't re-proxy it
2008                  *      there.
2009                  */
2010                 if ((request->listener->type == RAD_LISTEN_DETAIL) &&
2011                     (request->packet->code == PW_ACCOUNTING_REQUEST) &&
2012                     (fr_ipaddr_cmp(&home->ipaddr, &request->packet->src_ipaddr) == 0)) {
2013                         continue;
2014                 }
2015 #endif
2016
2017                 /*
2018                  *      It's zombie, so we remember the first zombie
2019                  *      we find, but we don't mark it as a "live"
2020                  *      server.
2021                  */
2022                 if (home->state == HOME_STATE_ZOMBIE) {
2023                         if (!zombie) zombie = home;
2024                         continue;
2025                 }
2026
2027                 /*
2028                  *      We've found the first "live" one.  Use that.
2029                  */
2030                 if (pool->type == HOME_POOL_FAIL_OVER) {
2031                         found = home;
2032                         break;
2033                 }
2034
2035                 /*
2036                  *      Otherwise we're doing some kind of load balancing.
2037                  *      If we haven't found one yet, pick this one.
2038                  */
2039                 if (!found) {
2040                         found = home;
2041                         continue;
2042                 }
2043
2044                 RDEBUG3("PROXY %s %d\t%s %d",
2045                        found->name, found->currently_outstanding,
2046                        home->name, home->currently_outstanding);
2047
2048                 /*
2049                  *      Prefer this server if it's less busy than the
2050                  *      one we had previously found.
2051                  */
2052                 if (home->currently_outstanding < found->currently_outstanding) {
2053                         RDEBUG3("PROXY Choosing %s: It's less busy than %s",
2054                                home->name, found->name);
2055                         found = home;
2056                         continue;
2057                 }
2058
2059                 /*
2060                  *      Ignore servers which are busier than the one
2061                  *      we found.
2062                  */
2063                 if (home->currently_outstanding > found->currently_outstanding) {
2064                         RDEBUG3("PROXY Skipping %s: It's busier than %s",
2065                                home->name, found->name);
2066                         continue;
2067                 }
2068
2069                 /*
2070                  *      From the list of servers which have the same
2071                  *      load, choose one at random.
2072                  */
2073                 if (((count + 1) * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
2074                         found = home;
2075                 }
2076         } /* loop over the home servers */
2077
2078         /*
2079          *      We have no live servers, BUT we have a zombie.  Use
2080          *      the zombie as a last resort.
2081          */
2082         if (!found && zombie) {
2083                 found = zombie;
2084                 zombie = NULL;
2085         }
2086
2087         /*
2088          *      There's a fallback if they're all dead.
2089          */
2090         if (!found && pool->fallback) {
2091                 found = pool->fallback;
2092         }
2093
2094         if (found) {
2095         update_and_return:
2096                 /*
2097                  *      Allocate the proxy packet, only if it wasn't
2098                  *      already allocated by a module.  This check is
2099                  *      mainly to support the proxying of EAP-TTLS and
2100                  *      EAP-PEAP tunneled requests.
2101                  *
2102                  *      In those cases, the EAP module creates a
2103                  *      "fake" request, and recursively passes it
2104                  *      through the authentication stage of the
2105                  *      server.  The module then checks if the request
2106                  *      was supposed to be proxied, and if so, creates
2107                  *      a proxy packet from the TUNNELED request, and
2108                  *      not from the EAP request outside of the
2109                  *      tunnel.
2110                  *
2111                  *      The proxy then works like normal, except that
2112                  *      the response packet is "eaten" by the EAP
2113                  *      module, and encapsulated into an EAP packet.
2114                  */
2115                 if (!request->proxy) {
2116                         if ((request->proxy = rad_alloc(TRUE)) == NULL) {
2117                                 radlog(L_ERR|L_CONS, "no memory");
2118                                 exit(1);
2119                         }
2120                         
2121                         /*
2122                          *      Copy the request, then look up name
2123                          *      and plain-text password in the copy.
2124                          *
2125                          *      Note that the User-Name attribute is
2126                          *      the *original* as sent over by the
2127                          *      client.  The Stripped-User-Name
2128                          *      attribute is the one hacked through
2129                          *      the 'hints' file.
2130                          */
2131                         request->proxy->vps =  paircopy(request->packet->vps);
2132
2133                         /*
2134                          *      Set the source IP address for proxying.
2135                          */
2136                         request->proxy->src_ipaddr = found->src_ipaddr;
2137                 }
2138
2139                 /*
2140                  *      Update the various fields as appropriate.
2141                  */
2142                 request->proxy->src_ipaddr = found->src_ipaddr;
2143                 request->proxy->src_port = 0;
2144                 request->proxy->dst_ipaddr = found->ipaddr;
2145                 request->proxy->dst_port = found->port;
2146                 request->home_server = found;
2147
2148                 /*
2149                  *      We're supposed to add a Message-Authenticator
2150                  *      if it doesn't exist, and it doesn't exist.
2151                  */
2152                 if (found->message_authenticator &&
2153                     (request->packet->code == PW_AUTHENTICATION_REQUEST) &&
2154                     !pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR)) {
2155                         radius_pairmake(request, &request->proxy->vps,
2156                                         "Message-Authenticator", "0x00",
2157                                         T_OP_SET);
2158                 }
2159
2160                 return found;
2161         }
2162
2163         /*
2164          *      No live match found, and no fallback to the "DEFAULT"
2165          *      realm.  We fix this by blindly marking all servers as
2166          *      "live".  But only do it for ones that don't support
2167          *      "pings", as they will be marked live when they
2168          *      actually are live.
2169          */
2170         if (!realm_config->fallback &&
2171             realm_config->wake_all_if_all_dead) {
2172                 for (count = 0; count < pool->num_home_servers; count++) {
2173                         home_server *home = pool->servers[count];
2174
2175                         if (!home) continue;
2176
2177                         if ((home->state == HOME_STATE_IS_DEAD) &&
2178                             (home->ping_check == HOME_PING_CHECK_NONE)) {
2179                                 home->state = HOME_STATE_ALIVE;
2180                                 if (!found) found = home;
2181                         }
2182                 }
2183
2184                 if (found) goto update_and_return;
2185         }
2186
2187         /*
2188          *      Still nothing.  Look up the DEFAULT realm, but only
2189          *      if we weren't looking up the NULL or DEFAULT realms.
2190          */
2191         if (realm_config->fallback &&
2192             realmname &&
2193             (strcmp(realmname, "NULL") != 0) &&
2194             (strcmp(realmname, "DEFAULT") != 0)) {
2195                 REALM *rd = realm_find("DEFAULT");
2196
2197                 if (!rd) return NULL;
2198
2199                 pool = NULL;
2200                 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
2201                         pool = rd->auth_pool;
2202
2203                 } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
2204                         pool = rd->acct_pool;
2205                 }
2206                 if (!pool) return NULL;
2207
2208                 RDEBUG2("PROXY - realm %s has no live home servers.  Falling back to the DEFAULT realm.", realmname);
2209                 return home_server_ldb(rd->name, pool, request);
2210         }
2211
2212         /*
2213          *      Still haven't found anything.  Oh well.
2214          */
2215         return NULL;
2216 }
2217
2218
2219 home_server *home_server_find(fr_ipaddr_t *ipaddr, int port)
2220 {
2221         home_server myhome;
2222
2223         memset(&myhome, 0, sizeof(myhome));
2224         myhome.ipaddr = *ipaddr;
2225         myhome.port = port;
2226         myhome.server = NULL;   /* we're not called for internal proxying */
2227
2228         return rbtree_finddata(home_servers_byaddr, &myhome);
2229 }
2230
2231 #ifdef WITH_COA
2232 home_server *home_server_byname(const char *name, int type)
2233 {
2234         home_server myhome;
2235
2236         memset(&myhome, 0, sizeof(myhome));
2237         myhome.type = type;
2238         myhome.name = name;
2239
2240         return rbtree_finddata(home_servers_byname, &myhome);
2241 }
2242 #endif
2243
2244 #ifdef WITH_STATS
2245 home_server *home_server_bynumber(int number)
2246 {
2247         home_server myhome;
2248
2249         memset(&myhome, 0, sizeof(myhome));
2250         myhome.number = number;
2251         myhome.server = NULL;   /* we're not called for internal proxying */
2252
2253         return rbtree_finddata(home_servers_bynumber, &myhome);
2254 }
2255 #endif
2256
2257 home_pool_t *home_pool_byname(const char *name, int type)
2258 {
2259         home_pool_t mypool;
2260         
2261         memset(&mypool, 0, sizeof(mypool));
2262         mypool.name = name;
2263         mypool.server_type = type;
2264         return rbtree_finddata(home_pools_byname, &mypool);
2265 }
2266
2267 #endif