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