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