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