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