Fall back to using DEFAULT realm. Based on patch from
[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 static rbtree_t *realms_byname = NULL;
36
37 static rbtree_t *home_servers_byaddr = NULL;
38 static rbtree_t *home_servers_byname = NULL;
39
40 static rbtree_t *home_pools_byname = NULL;
41
42 typedef struct realm_config_t {
43         CONF_SECTION    *cs;
44         int             dead_time;
45         int             retry_count;
46         int             retry_delay;
47         int             fallback;
48         int             wake_all_if_all_dead;
49 } realm_config_t;
50
51 static realm_config_t *realm_config = NULL;
52
53 /*
54  *  Map the proxy server configuration parameters to variables.
55  */
56 static const CONF_PARSER proxy_config[] = {
57         { "retry_delay",  PW_TYPE_INTEGER,
58           offsetof(realm_config_t, retry_delay),
59           NULL, Stringify(RETRY_DELAY) },
60
61         { "retry_count",  PW_TYPE_INTEGER,
62           offsetof(realm_config_t, retry_count),
63           NULL, Stringify(RETRY_COUNT) },
64
65         { "default_fallback", PW_TYPE_BOOLEAN,
66           offsetof(realm_config_t, fallback),
67           NULL, "no" },
68
69         { "dead_time",    PW_TYPE_INTEGER, 
70           offsetof(realm_config_t, dead_time),
71           NULL, Stringify(DEAD_TIME) },
72
73         { "wake_all_if_all_dead", PW_TYPE_BOOLEAN,
74           offsetof(realm_config_t, wake_all_if_all_dead),
75           NULL, "no" },
76
77         { NULL, -1, 0, NULL, NULL }
78 };
79
80 static int realm_name_cmp(const void *one, const void *two)
81 {
82         const REALM *a = one;
83         const REALM *b = two;
84
85         return strcasecmp(a->name, b->name);
86 }
87
88
89 static int home_server_name_cmp(const void *one, const void *two)
90 {
91         const home_server *a = one;
92         const home_server *b = two;
93
94         if (a->type < b->type) return -1;
95         if (a->type > b->type) return +1;
96
97         return strcasecmp(a->name, b->name);
98 }
99
100 static int home_server_addr_cmp(const void *one, const void *two)
101 {
102         const home_server *a = one;
103         const home_server *b = two;
104
105         if (a->port < b->port) return -1;
106         if (a->port > b->port) return +1;
107
108         return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
109 }
110
111
112 static int home_pool_name_cmp(const void *one, const void *two)
113 {
114         const home_pool_t *a = one;
115         const home_pool_t *b = two;
116
117         if (a->server_type < b->server_type) return -1;
118         if (a->server_type > b->server_type) return +1;
119
120         return strcasecmp(a->name, b->name);
121 }
122
123
124 /*
125  *      Xlat for %{home_server:foo}
126  */
127 static size_t xlat_home_server(UNUSED void *instance, REQUEST *request,
128                                char *fmt, char *out, size_t outlen,
129                                UNUSED RADIUS_ESCAPE_STRING func)
130 {
131         const char *value = NULL;
132         CONF_PAIR *cp;
133
134         if (!fmt || !out || (outlen < 1)) return 0;
135
136         if (!request || !request->home_server) {
137                 *out = '\0';
138                 return 0;
139         }
140
141         cp = cf_pair_find(request->home_server->cs, fmt);
142         if (!cp || !(value = cf_pair_value(cp))) {
143                 *out = '\0';
144                 return 0;
145         }
146         
147         strlcpy(out, value, outlen);
148
149         return strlen(out);
150 }
151
152
153 /*
154  *      Xlat for %{home_server_pool:foo}
155  */
156 static size_t xlat_server_pool(UNUSED void *instance, REQUEST *request,
157                                char *fmt, char *out, size_t outlen,
158                                UNUSED RADIUS_ESCAPE_STRING func)
159 {
160         const char *value = NULL;
161         CONF_PAIR *cp;
162
163         if (!fmt || !out || (outlen < 1)) return 0;
164
165         if (!request || !request->home_pool) {
166                 *out = '\0';
167                 return 0;
168         }
169
170         cp = cf_pair_find(request->home_pool->cs, fmt);
171         if (!cp || !(value = cf_pair_value(cp))) {
172                 *out = '\0';
173                 return 0;
174         }
175         
176         strlcpy(out, value, outlen);
177
178         return strlen(out);
179 }
180
181
182 void realms_free(void)
183 {
184         rbtree_free(home_servers_byname);
185         home_servers_byname = NULL;
186
187         rbtree_free(home_servers_byaddr);
188         home_servers_byaddr = NULL;
189
190         rbtree_free(home_pools_byname);
191         home_pools_byname = NULL;
192
193         rbtree_free(realms_byname);
194         realms_byname = NULL;
195
196         free(realm_config);
197 }
198
199
200 static struct in_addr hs_ip4addr;
201 static struct in6_addr hs_ip6addr;
202 static char *hs_type = NULL;
203 static char *hs_check = NULL;
204
205 static CONF_PARSER home_server_config[] = {
206         { "ipaddr",  PW_TYPE_IPADDR,
207           0, &hs_ip4addr,  NULL },
208         { "ipv6addr",  PW_TYPE_IPV6ADDR,
209           0, &hs_ip6addr, NULL },
210
211         { "port", PW_TYPE_INTEGER,
212           offsetof(home_server,port), NULL,   "0" },
213
214         { "type",  PW_TYPE_STRING_PTR,
215           0, &hs_type, NULL },
216
217         { "secret",  PW_TYPE_STRING_PTR,
218           offsetof(home_server,secret), NULL,  NULL},
219
220         { "response_window", PW_TYPE_INTEGER,
221           offsetof(home_server,response_window), NULL,   "30" },
222         { "max_outstanding", PW_TYPE_INTEGER,
223           offsetof(home_server,max_outstanding), NULL,   "65536" },
224
225         { "zombie_period", PW_TYPE_INTEGER,
226           offsetof(home_server,zombie_period), NULL,   "40" },
227         { "status_check", PW_TYPE_STRING_PTR,
228           0, &hs_check,   "none" },
229         { "ping_check", PW_TYPE_STRING_PTR,
230           0, &hs_check,   "none" },
231
232         { "ping_interval", PW_TYPE_INTEGER,
233           offsetof(home_server,ping_interval), NULL,   "30" },
234         { "check_interval", PW_TYPE_INTEGER,
235           offsetof(home_server,ping_interval), NULL,   "30" },
236         { "num_answers_to_alive", PW_TYPE_INTEGER,
237           offsetof(home_server,num_pings_to_alive), NULL,   "3" },
238         { "num_pings_to_alive", PW_TYPE_INTEGER,
239           offsetof(home_server,num_pings_to_alive), NULL,   "3" },
240         { "revive_interval", PW_TYPE_INTEGER,
241           offsetof(home_server,revive_interval), NULL,   "300" },
242         { "status_check_timeout", PW_TYPE_INTEGER,
243           offsetof(home_server,ping_timeout), NULL,   "4" },
244
245         { "username",  PW_TYPE_STRING_PTR,
246           offsetof(home_server,ping_user_name), NULL,  NULL},
247         { "password",  PW_TYPE_STRING_PTR,
248           offsetof(home_server,ping_user_password), NULL,  NULL},
249
250         { NULL, -1, 0, NULL, NULL }             /* end the list */
251
252 };
253
254
255 static int home_server_add(CONF_SECTION *cs, int type)
256 {
257         const char *name2;
258         home_server *home;
259         int dual = FALSE;
260
261         name2 = cf_section_name1(cs);
262         if (!name2 || (strcasecmp(name2, "home_server") != 0)) {
263                 cf_log_err(cf_sectiontoitem(cs),
264                            "Section is not a home_server.");
265                 return 0;
266         }
267
268         name2 = cf_section_name2(cs);
269         if (!name2) {
270                 cf_log_err(cf_sectiontoitem(cs),
271                            "Home server section is missing a name.");
272                 return 0;
273         }
274
275         home = rad_malloc(sizeof(*home));
276         memset(home, 0, sizeof(*home));
277
278         home->name = name2;
279         home->cs = cs;
280
281         memset(&hs_ip4addr, 0, sizeof(hs_ip4addr));
282         memset(&hs_ip6addr, 0, sizeof(hs_ip6addr));
283         cf_section_parse(cs, home, home_server_config);
284
285         if (!cf_pair_find(cs, "ipaddr") &&
286             !cf_pair_find(cs, "ipv6addr")) {
287                 cf_log_err(cf_sectiontoitem(cs),
288                            "No IPv4 or IPv6 address defined for home server %s.",
289                            name2);
290                 free(home);
291                 free(hs_type);
292                 hs_type = NULL;
293                 free(hs_check);
294                 hs_check = NULL;
295                 return 0;
296         }
297
298         /*
299          *      Figure out which one to use.
300          */
301         if (cf_pair_find(cs, "ipaddr")) {
302                 home->ipaddr.af = AF_INET;
303                 home->ipaddr.ipaddr.ip4addr = hs_ip4addr;
304
305         } else if (cf_pair_find(cs, "ipv6addr")) {
306                 home->ipaddr.af = AF_INET6;
307                 home->ipaddr.ipaddr.ip6addr = hs_ip6addr;
308
309         } else {
310                 cf_log_err(cf_sectiontoitem(cs),
311                            "Internal sanity check failed for home server %s.",
312                            name2);
313                 free(home);
314                 free(hs_type);
315                 hs_type = NULL;
316                 free(hs_check);
317                 hs_check = NULL;
318                 return 0;
319         }
320
321         if (!home->port || (home->port > 65535)) {
322                 cf_log_err(cf_sectiontoitem(cs),
323                            "No port, or invalid port defined for home server %s.",
324                            name2);
325                 free(home);
326                 free(hs_type);
327                 hs_type = NULL;
328                 free(hs_check);
329                 hs_check = NULL;
330                 return 0;
331         }
332
333         if (0) {
334                 cf_log_err(cf_sectiontoitem(cs),
335                            "Fatal error!  Home server %s is ourselves!",
336                            name2);
337                 free(home);
338                 free(hs_type);
339                 hs_type = NULL;
340                 free(hs_check);
341                 hs_check = NULL;
342                 return 0;
343         }
344
345         /*
346          *      Use a reasonable default.
347          */
348         if (!hs_type) hs_type = strdup("auth+acct");
349
350         if (strcasecmp(hs_type, "auth") == 0) {
351                 home->type = HOME_TYPE_AUTH;
352                 if (type != home->type) {
353                         cf_log_err(cf_sectiontoitem(cs),
354                                    "Server pool of \"acct\" servers cannot include home server %s of type \"auth\"",
355                                    name2);
356                         free(home);
357                         return 0;
358                 }
359
360         } else if (strcasecmp(hs_type, "acct") == 0) {
361                 home->type = HOME_TYPE_ACCT;
362                 if (type != home->type) {
363                         cf_log_err(cf_sectiontoitem(cs),
364                                    "Server pool of \"auth\" servers cannot include home server %s of type \"acct\"",
365                                    name2);
366                         free(home);
367                         return 0;
368                 }
369
370         } else if (strcasecmp(hs_type, "auth+acct") == 0) {
371                 home->type = HOME_TYPE_AUTH;
372                 dual = TRUE;
373
374         } else {
375                 cf_log_err(cf_sectiontoitem(cs),
376                            "Invalid type \"%s\" for home server %s.",
377                            hs_type, name2);
378                 free(home);
379                 free(hs_type);
380                 hs_type = NULL;
381                 free(hs_check);
382                 hs_check = NULL;
383                 return 0;
384         }
385         free(hs_type);
386         hs_type = NULL;
387
388         if (!home->secret) {
389                 cf_log_err(cf_sectiontoitem(cs),
390                            "No shared secret defined for home server %s.",
391                            name2);
392                 free(home);
393                 return 0;
394         }
395
396         if (!hs_check || (strcasecmp(hs_check, "none") == 0)) {
397                 home->ping_check = HOME_PING_CHECK_NONE;
398
399         } else if (strcasecmp(hs_check, "status-server") == 0) {
400                 home->ping_check = HOME_PING_CHECK_STATUS_SERVER;
401
402         } else if (strcasecmp(hs_check, "request") == 0) {
403                 home->ping_check = HOME_PING_CHECK_REQUEST;
404
405         } else {
406                 cf_log_err(cf_sectiontoitem(cs),
407                            "Invalid ping_check \"%s\" for home server %s.",
408                            hs_check, name2);
409                 free(home);
410                 free(hs_check);
411                 hs_check = NULL;
412                 return 0;
413         }
414         free(hs_check);
415         hs_check = NULL;
416
417         if ((home->ping_check != HOME_PING_CHECK_NONE) &&
418             (home->ping_check != HOME_PING_CHECK_STATUS_SERVER)) {
419                 if (!home->ping_user_name) {
420                         cf_log_err(cf_sectiontoitem(cs), "You must supply a user name to enable ping checks");
421                         free(home);
422                         return 0;
423                 }
424
425                 if ((home->type == HOME_TYPE_AUTH) &&
426                     !home->ping_user_password) {
427                         cf_log_err(cf_sectiontoitem(cs), "You must supply a password to enable ping checks");
428                         free(home);
429                         return 0;
430                 }
431         }
432
433         if (rbtree_finddata(home_servers_byaddr, home)) {
434                 DEBUG2("Ignoring duplicate home server %s.", name2);
435                 return 1;
436         }
437
438         if (!rbtree_insert(home_servers_byname, home)) {
439                 cf_log_err(cf_sectiontoitem(cs),
440                            "Internal error adding home server %s.",
441                            name2);
442                 free(home);
443                 return 0;
444         }
445
446         if (!rbtree_insert(home_servers_byaddr, home)) {
447                 rbtree_deletebydata(home_servers_byname, home);
448                 cf_log_err(cf_sectiontoitem(cs),
449                            "Internal error adding home server %s.",
450                            name2);
451                 free(home);
452                 return 0;
453         }
454
455         if (home->response_window < 5) home->response_window = 5;
456         if (home->response_window > 60) home->response_window = 60;
457
458         if (home->max_outstanding < 8) home->max_outstanding = 8;
459         if (home->max_outstanding > 65536*16) home->max_outstanding = 65536*16;
460
461         if (home->ping_interval < 6) home->ping_interval = 6;
462         if (home->ping_interval > 120) home->ping_interval = 120;
463
464         if (home->zombie_period < 20) home->zombie_period = 20;
465         if (home->zombie_period > 120) home->zombie_period = 120;
466
467         if (home->zombie_period < home->response_window) {
468                 home->zombie_period = home->response_window;
469         }
470
471         if (home->num_pings_to_alive < 3) home->num_pings_to_alive = 3;
472         if (home->num_pings_to_alive > 10) home->num_pings_to_alive = 10;
473
474         if (home->ping_timeout < 3) home->ping_timeout = 3;
475         if (home->ping_timeout > 10) home->ping_timeout = 10;
476
477         if (home->revive_interval < 60) home->revive_interval = 60;
478         if (home->revive_interval > 3600) home->revive_interval = 3600;
479
480         if (dual) {
481                 home_server *home2 = rad_malloc(sizeof(*home2));
482
483                 memcpy(home2, home, sizeof(*home2));
484
485                 home2->type = HOME_TYPE_ACCT;
486                 home2->port++;
487                 home2->ping_user_password = NULL;
488                 home2->cs = cs;
489
490                 if (!rbtree_insert(home_servers_byname, home2)) {
491                         cf_log_err(cf_sectiontoitem(cs),
492                                    "Internal error adding home server %s.",
493                                    name2);
494                         free(home2);
495                         return 0;
496                 }
497                 
498                 if (!rbtree_insert(home_servers_byaddr, home2)) {
499                         rbtree_deletebydata(home_servers_byname, home2);
500                         cf_log_err(cf_sectiontoitem(cs),
501                                    "Internal error adding home server %s.",
502                                    name2);
503                         free(home2);
504                         return 0;
505                 }
506         }
507
508         return 1;
509 }
510
511
512 static home_pool_t *server_pool_alloc(const char *name, home_pool_type_t type,
513                                       int server_type, int num_home_servers)
514 {
515         home_pool_t *pool;
516
517         pool = rad_malloc(sizeof(*pool) + (sizeof(pool->servers[0]) *
518                                            num_home_servers));
519         if (!pool) return NULL; /* just for pairanoia */
520         
521         memset(pool, 0, sizeof(*pool) + (sizeof(pool->servers[0]) *
522                                          num_home_servers));
523
524         pool->name = name;
525         pool->type = type;
526         pool->server_type = server_type;
527         pool->num_home_servers = num_home_servers;
528
529         return pool;
530 }
531
532
533 static int server_pool_add(realm_config_t *rc,
534                            CONF_SECTION *cs, int server_type, int do_print)
535 {
536         const char *name2;
537         home_pool_t *pool = NULL;
538         const char *value;
539         CONF_PAIR *cp;
540         int num_home_servers;
541
542         name2 = cf_section_name1(cs);
543         if (!name2 || ((strcasecmp(name2, "server_pool") != 0) &&
544                        (strcasecmp(name2, "home_server_pool") != 0))) {
545                 cf_log_err(cf_sectiontoitem(cs),
546                            "Section is not a home_server_pool.");
547                 return 0;
548         }
549
550         name2 = cf_section_name2(cs);
551         if (!name2) {
552                 cf_log_err(cf_sectiontoitem(cs),
553                            "Server pool section is missing a name.");
554                 return 0;
555         }
556
557         /*
558          *      Count the home servers and initalize them.
559          */
560         num_home_servers = 0;
561         for (cp = cf_pair_find(cs, "home_server");
562              cp != NULL;
563              cp = cf_pair_find_next(cs, cp, "home_server")) {
564                 home_server myhome, *home;
565                 CONF_SECTION *server_cs;
566
567                 num_home_servers++;
568
569                 value = cf_pair_value(cp);
570                 if (!value) {
571                         cf_log_err(cf_pairtoitem(cp),
572                                    "No value given for home_server.");
573                         return 0;;
574                 }
575
576                 myhome.name = value;
577                 myhome.type = server_type;
578                 home = rbtree_finddata(home_servers_byname, &myhome);
579                 if (home) continue;
580
581                 server_cs = cf_section_sub_find_name2(rc->cs,
582                                                       "home_server",
583                                                       value);
584                 if (!server_cs) {
585                         cf_log_err(cf_pairtoitem(cp),
586                                    "Unknown home_server \"%s\".",
587                                    value);
588                         return 0;
589                 }
590
591                 if (!home_server_add(server_cs, server_type)) {
592                         return 0;
593                 }
594
595                 home = rbtree_finddata(home_servers_byname, &myhome);
596                 if (!home) {
597                         radlog(L_ERR, "Internal sanity check failed %d",
598                                __LINE__);
599                         return 0;
600                 }
601         }
602
603         if (num_home_servers == 0) {
604                 cf_log_err(cf_sectiontoitem(cs),
605                            "No home servers defined in pool %s",
606                            name2);
607                 goto error;
608         }
609
610         pool = server_pool_alloc(name2, HOME_POOL_FAIL_OVER, server_type,
611                                  num_home_servers);
612         pool->cs = cs;
613
614         if (do_print) cf_log_info(cs, " home_server_pool %s {", name2);
615
616         cp = cf_pair_find(cs, "type");
617         if (cp) {
618                 static FR_NAME_NUMBER pool_types[] = {
619                         { "load-balance", HOME_POOL_LOAD_BALANCE },
620                         { "fail-over", HOME_POOL_FAIL_OVER },
621                         { "round_robin", HOME_POOL_LOAD_BALANCE },
622                         { "fail_over", HOME_POOL_FAIL_OVER },
623                         { "client-balance", HOME_POOL_CLIENT_BALANCE },
624                         { "client-port-balance", HOME_POOL_CLIENT_PORT_BALANCE },
625                         { "keyed-balance", HOME_POOL_KEYED_BALANCE },
626                         { NULL, 0 }
627                 };
628
629                 value = cf_pair_value(cp);
630                 if (!value) {
631                         cf_log_err(cf_pairtoitem(cp),
632                                    "No value given for type.");
633                         goto error;
634                 }
635
636                 pool->type = fr_str2int(pool_types, value, 0);
637                 if (!pool->type) {
638                         cf_log_err(cf_pairtoitem(cp),
639                                    "Unknown type \"%s\".",
640                                    value);
641                         goto error;
642                 }
643
644                 if (do_print) cf_log_info(cs, "\ttype = %s", value);
645         }
646
647         cp = cf_pair_find(cs, "virtual_server");
648         if (cp) {
649                 pool->virtual_server = cf_pair_value(cp);
650                 if (do_print && pool->virtual_server) {
651                         cf_log_info(cs, "\tvirtual_server = %s", pool->virtual_server);
652                 }
653
654                 if (!cf_section_sub_find_name2(rc->cs, "server",
655                                                pool->virtual_server)) {
656                         cf_log_err(cf_pairtoitem(cp), "No such server %s",
657                                    pool->virtual_server);
658                         goto error;
659                 }
660
661         }
662
663         num_home_servers = 0;
664         for (cp = cf_pair_find(cs, "home_server");
665              cp != NULL;
666              cp = cf_pair_find_next(cs, cp, "home_server")) {
667                 home_server myhome, *home;
668
669                 value = cf_pair_value(cp);
670                 if (!value) {
671                         cf_log_err(cf_pairtoitem(cp),
672                                    "No value given for home_server.");
673                         goto error;
674                 }
675
676                 myhome.name = value;
677                 myhome.type = server_type;
678
679                 home = rbtree_finddata(home_servers_byname, &myhome);
680                 if (!home) {
681                         DEBUG2("Internal sanity check failed");
682                         goto error;
683                 }
684
685                 if (0) {
686                         DEBUG2("Warning: Duplicate home server %s in server pool %s", home->name, pool->name);
687                         continue;
688                 }
689
690                 if (do_print) cf_log_info(cs, "\thome_server = %s", home->name);
691                 pool->servers[num_home_servers++] = home;
692         } /* loop over home_server's */
693
694         if (!rbtree_insert(home_pools_byname, pool)) {
695                 rad_assert("Internal sanity check failed");
696                 goto error;
697         }
698
699         if (do_print) cf_log_info(cs, " }");
700
701         rad_assert(pool->server_type != 0);
702
703         return 1;
704
705  error:
706         if (do_print) cf_log_info(cs, " }");
707         free(pool);
708         return 0;
709 }
710
711
712 static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
713                           const char *realm,
714                           const char *name, const char *secret,
715                           home_pool_type_t ldflag, home_pool_t **pool_p,
716                           int type)
717 {
718         int i, insert_point, num_home_servers;
719         home_server myhome, *home;
720         home_pool_t mypool, *pool;
721         CONF_SECTION *subcs;
722
723         /*
724          *      LOCAL realms get sanity checked, and nothing else happens.
725          */
726         if (strcmp(name, "LOCAL") == 0) {
727                 if (*pool_p) {
728                         cf_log_err(cf_sectiontoitem(cs), "Realm \"%s\" cannot be both LOCAL and remote", name);
729                         return 0;
730                 }
731                 return 1;
732         }
733
734         mypool.name = realm;
735         mypool.server_type = type;
736         pool = rbtree_finddata(home_pools_byname, &mypool);
737         if (pool) {
738                 if (pool->type != ldflag) {
739                         cf_log_err(cf_sectiontoitem(cs), "Inconsistent ldflag for server pool \"%s\"", name);
740                         return 0;
741                 }
742
743                 if (pool->server_type != type) {
744                         cf_log_err(cf_sectiontoitem(cs), "Inconsistent home server type for server pool \"%s\"", name);
745                         return 0;
746                 }
747         }
748
749         myhome.name = name;
750         myhome.type = type;
751         home = rbtree_finddata(home_servers_byname, &myhome);
752         if (home) {
753                 if (strcmp(home->secret, secret) != 0) {
754                         cf_log_err(cf_sectiontoitem(cs), "Inconsistent shared secret for home server \"%s\"", name);
755                         return 0;
756                 }
757
758                 if (home->type != type) {
759                         cf_log_err(cf_sectiontoitem(cs), "Inconsistent type for home server \"%s\"", name);
760                         return 0;
761                 }
762
763                 /*
764                  *      See if the home server is already listed
765                  *      in the pool.  If so, do nothing else.
766                  */
767                 if (pool) for (i = 0; i < pool->num_home_servers; i++) {
768                         if (pool->servers[i] == home) {
769                                 return 1;
770                         }
771                 }
772         }
773
774         /*
775          *      If we do have a pool, check that there is room to
776          *      insert the home server we've found, or the one that we
777          *      create here.
778          *
779          *      Note that we insert it into the LAST available
780          *      position, in order to maintain the same order as in
781          *      the configuration files.
782          */
783         insert_point = -1;
784         if (pool) {
785                 for (i = pool->num_home_servers - 1; i >= 0; i--) {
786                         if (pool->servers[i]) break;
787
788                         if (!pool->servers[i]) {
789                                 insert_point = i;
790                         }
791                 }
792
793                 if (insert_point < 0) {
794                         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);
795                         return 0;
796                 }
797         }
798
799         /*
800          *      No home server, allocate one.
801          */
802         if (!home) {
803                 const char *p;
804                 char *q;
805
806                 home = rad_malloc(sizeof(*home));
807                 memset(home, 0, sizeof(*home));
808
809                 home->name = name;
810                 home->hostname = name;
811                 home->type = type;
812                 home->secret = secret;
813                 home->cs = cs;
814
815                 p = strchr(name, ':');
816                 if (!p) {
817                         if (type == HOME_TYPE_AUTH) {
818                                 home->port = PW_AUTH_UDP_PORT;
819                         } else {
820                                 home->port = PW_ACCT_UDP_PORT;
821                         }
822
823                         p = name;
824                         q = NULL;
825
826                 } else if (p == name) {
827                                 cf_log_err(cf_sectiontoitem(cs),
828                                            "Invalid hostname %s.",
829                                            name);
830                                 free(home);
831                                 return 0;
832
833                 } else {
834                         home->port = atoi(p + 1);
835                         if ((home->port == 0) || (home->port > 65535)) {
836                                 cf_log_err(cf_sectiontoitem(cs),
837                                            "Invalid port %s.",
838                                            p + 1);
839                                 free(home);
840                                 return 0;
841                         }
842
843                         q = rad_malloc((p - name) + 1);
844                         memcpy(q, name, (p - name));
845                         q[p - name] = '\0';
846                         p = q;
847                 }
848
849                 if (ip_hton(p, AF_UNSPEC, &home->ipaddr) < 0) {
850                         cf_log_err(cf_sectiontoitem(cs),
851                                    "Failed looking up hostname %s.",
852                                    p);
853                         free(home);
854                         free(q);
855                         return 0;
856                 }
857                 free(q);
858
859                 /*
860                  *      Use the old-style configuration.
861                  */
862                 home->max_outstanding = 65535*16;
863                 home->zombie_period = rc->retry_delay * rc->retry_count;
864                 if (home->zombie_period == 0) home->zombie_period =30;
865                 home->response_window = home->zombie_period - 1;
866
867                 home->ping_check = HOME_PING_CHECK_NONE;
868
869                 home->revive_interval = rc->dead_time;
870
871                 if (rbtree_finddata(home_servers_byaddr, home)) {
872                         cf_log_err(cf_sectiontoitem(cs), "Home server %s has the same IP address and/or port as another home server.", name);
873                         free(home);
874                         return 0;
875                 }
876
877                 if (!rbtree_insert(home_servers_byname, home)) {
878                         cf_log_err(cf_sectiontoitem(cs), "Internal error adding home server %s.", name);
879                         free(home);
880                         return 0;
881                 }
882
883                 if (!rbtree_insert(home_servers_byaddr, home)) {
884                         rbtree_deletebydata(home_servers_byname, home);
885                         cf_log_err(cf_sectiontoitem(cs), "Internal error adding home server %s.", name);
886                         free(home);
887                         return 0;
888                 }
889         }
890
891         /*
892          *      We now have a home server, see if we can insert it
893          *      into pre-existing pool.
894          */
895         if (insert_point >= 0) {
896                 rad_assert(pool != NULL);
897                 pool->servers[insert_point] = home;
898                 return 1;
899         }
900
901         rad_assert(pool == NULL);
902         rad_assert(home != NULL);
903
904         /*
905          *      Count the old-style realms of this name.
906          */
907         num_home_servers = 0;
908         for (subcs = cf_section_find_next(cs, NULL, "realm");
909              subcs != NULL;
910              subcs = cf_section_find_next(cs, subcs, "realm")) {
911                 const char *this = cf_section_name2(subcs);
912
913                 if (!this || (strcmp(this, realm) != 0)) continue;
914                 num_home_servers++;
915         }
916
917         if (num_home_servers == 0) {
918                 cf_log_err(cf_sectiontoitem(cs), "Internal error counting pools for home server %s.", name);
919                 free(home);
920                 return 0;
921         }
922
923         pool = server_pool_alloc(realm, ldflag, type, num_home_servers);
924         pool->cs = cs;
925
926         pool->servers[0] = home;
927
928         if (!rbtree_insert(home_pools_byname, pool)) {
929                 rad_assert("Internal sanity check failed");
930                 return 0;
931         }
932
933         *pool_p = pool;
934
935         return 1;
936 }
937
938 static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
939 {
940         const char *host;
941         const char *secret = NULL;
942         home_pool_type_t ldflag;
943         CONF_PAIR *cp;
944
945         cp = cf_pair_find(cs, "ldflag");
946         ldflag = HOME_POOL_FAIL_OVER;
947         if (cp) {
948                 host = cf_pair_value(cp);
949                 if (!host) {
950                         cf_log_err(cf_pairtoitem(cp), "No value specified for ldflag");
951                         return 0;
952                 }
953
954                 if (strcasecmp(host, "fail_over") == 0) {
955                         cf_log_info(cs, "\tldflag = fail_over");
956                         
957                 } else if (strcasecmp(host, "round_robin") == 0) {
958                         ldflag = HOME_POOL_LOAD_BALANCE;
959                         cf_log_info(cs, "\tldflag = round_robin");
960                         
961                 } else {
962                         cf_log_err(cf_sectiontoitem(cs), "Unknown value \"%s\" for ldflag", host);
963                         return 0;
964                 }
965         } /* else don't print it. */
966
967         /*
968          *      Allow old-style if it doesn't exist, or if it exists and
969          *      it's LOCAL.
970          */
971         cp = cf_pair_find(cs, "authhost");
972         if (cp) {
973                 host = cf_pair_value(cp);
974                 if (!host) {
975                         cf_log_err(cf_pairtoitem(cp), "No value specified for authhost");
976                         return 0;
977                 }
978
979                 if (strcmp(host, "LOCAL") != 0) {
980                         cp = cf_pair_find(cs, "secret");
981                         if (!cp) {
982                                 cf_log_err(cf_sectiontoitem(cs), "No shared secret supplied for realm: %s", r->name);
983                                 return 0;
984                         }
985
986                         secret = cf_pair_value(cp);
987                         if (!secret) {
988                                 cf_log_err(cf_pairtoitem(cp), "No value specified for secret");
989                                 return 0;
990                         }
991                 }
992                         
993                 cf_log_info(cs, "\tauthhost = %s",  host);
994
995                 if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
996                                     &r->auth_pool, HOME_TYPE_AUTH)) {
997                         return 0;
998                 }
999         }
1000
1001         cp = cf_pair_find(cs, "accthost");
1002         if (cp) {
1003                 host = cf_pair_value(cp);
1004                 if (!host) {
1005                         cf_log_err(cf_pairtoitem(cp), "No value specified for accthost");
1006                         return 0;
1007                 }
1008
1009                 /*
1010                  *      Don't look for a secret again if it was found
1011                  *      above.
1012                  */
1013                 if ((strcmp(host, "LOCAL") != 0) && !secret) {
1014                         cp = cf_pair_find(cs, "secret");
1015                         if (!cp) {
1016                                 cf_log_err(cf_sectiontoitem(cs), "No shared secret supplied for realm: %s", r->name);
1017                                 return 0;
1018                         }
1019                         
1020                         secret = cf_pair_value(cp);
1021                         if (!secret) {
1022                                 cf_log_err(cf_pairtoitem(cp), "No value specified for secret");
1023                                 return 0;
1024                         }
1025                 }
1026                 
1027                 cf_log_info(cs, "\taccthost = %s", host);
1028
1029                 if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
1030                                     &r->acct_pool, HOME_TYPE_ACCT)) {
1031                         return 0;
1032                 }
1033         }
1034
1035         if (secret) cf_log_info(cs, "\tsecret = %s", secret);
1036
1037         return 1;
1038
1039 }
1040
1041
1042 static int add_pool_to_realm(realm_config_t *rc, CONF_SECTION *cs,
1043                              const char *name, home_pool_t **dest,
1044                              int server_type, int do_print)
1045 {
1046         home_pool_t mypool, *pool;
1047
1048         mypool.name = name;
1049         mypool.server_type = server_type;
1050
1051         pool = rbtree_finddata(home_pools_byname, &mypool);
1052         if (!pool) {
1053                 CONF_SECTION *pool_cs;
1054
1055                 pool_cs = cf_section_sub_find_name2(rc->cs,
1056                                                     "home_server_pool",
1057                                                     name);
1058                 if (!pool_cs) {
1059                         pool_cs = cf_section_sub_find_name2(rc->cs,
1060                                                             "server_pool",
1061                                                             name);
1062                 }
1063                 if (!pool_cs) {
1064                         cf_log_err(cf_sectiontoitem(cs), "Failed to find home_server_pool \"%s\"", name);
1065                         return 0;
1066                 }
1067
1068                 if (!server_pool_add(rc, pool_cs, server_type, do_print)) {
1069                         return 0;
1070                 }
1071
1072                 pool = rbtree_finddata(home_pools_byname, &mypool);
1073                 if (!pool) {
1074                         radlog(L_ERR, "Internal sanity check failed in add_pool_to_realm");
1075                         return 0;
1076                 }
1077         }
1078
1079         if (pool->server_type != server_type) {
1080                 cf_log_err(cf_sectiontoitem(cs), "Incompatible home_server_pool \"%s\" (mixed auth_pool / acct_pool)", name);
1081                 return 0;
1082         }
1083
1084         *dest = pool;
1085
1086         return 1;
1087 }
1088
1089 static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
1090 {
1091         const char *name2;
1092         REALM *r = NULL;
1093         CONF_PAIR *cp;
1094         home_pool_t *auth_pool, *acct_pool;
1095         const char *auth_pool_name, *acct_pool_name;
1096
1097         name2 = cf_section_name1(cs);
1098         if (!name2 || (strcasecmp(name2, "realm") != 0)) {
1099                 cf_log_err(cf_sectiontoitem(cs), "Section is not a realm.");
1100                 return 0;
1101         }
1102
1103         name2 = cf_section_name2(cs);
1104         if (!name2) {
1105                 cf_log_err(cf_sectiontoitem(cs), "Realm section is missing the realm name.");
1106                 return 0;
1107         }
1108
1109         auth_pool = acct_pool = NULL;
1110         auth_pool_name = acct_pool_name = NULL;
1111
1112         /*
1113          *      Prefer new configuration to old one.
1114          */
1115         cp = cf_pair_find(cs, "pool");
1116         if (!cp) cp = cf_pair_find(cs, "home_server_pool");
1117         if (cp) auth_pool_name = cf_pair_value(cp);
1118         if (cp && auth_pool_name) {
1119                 acct_pool_name = auth_pool_name;
1120                 if (!add_pool_to_realm(rc, cs,
1121                                        auth_pool_name, &auth_pool,
1122                                        HOME_TYPE_AUTH, 1)) {
1123                         return 0;
1124                 }
1125                 if (!add_pool_to_realm(rc, cs,
1126                                        auth_pool_name, &acct_pool,
1127                                        HOME_TYPE_ACCT, 0)) {
1128                         return 0;
1129                 }
1130         }
1131
1132         cp = cf_pair_find(cs, "auth_pool");
1133         if (cp) auth_pool_name = cf_pair_value(cp);
1134         if (cp && auth_pool_name) {
1135                 if (auth_pool) {
1136                         cf_log_err(cf_sectiontoitem(cs), "Cannot use \"pool\" and \"auth_pool\" at the same time.");
1137                         return 0;
1138                 }
1139                 if (!add_pool_to_realm(rc, cs,
1140                                        auth_pool_name, &auth_pool,
1141                                        HOME_TYPE_AUTH, 1)) {
1142                         return 0;
1143                 }
1144         }
1145
1146         cp = cf_pair_find(cs, "acct_pool");
1147         if (cp) acct_pool_name = cf_pair_value(cp);
1148         if (cp && acct_pool_name) {
1149                 int do_print = TRUE;
1150
1151                 if (acct_pool) {
1152                         cf_log_err(cf_sectiontoitem(cs), "Cannot use \"pool\" and \"acct_pool\" at the same time.");
1153                         return 0;
1154                 }
1155
1156                 if (!auth_pool ||
1157                     (strcmp(auth_pool_name, acct_pool_name) != 0)) {
1158                         do_print = TRUE;
1159                 }
1160
1161                 if (!add_pool_to_realm(rc, cs,
1162                                        acct_pool_name, &acct_pool,
1163                                        HOME_TYPE_ACCT, do_print)) {
1164                         return 0;
1165                 }
1166         }
1167
1168         cf_log_info(cs, " realm %s {", name2);
1169
1170         /*
1171          *      The realm MAY already exist if it's an old-style realm.
1172          *      In that case, merge the old-style realm with this one.
1173          */
1174         r = realm_find(name2);
1175         if (r) {
1176                 if (cf_pair_find(cs, "auth_pool") ||
1177                     cf_pair_find(cs, "acct_pool")) {
1178                         cf_log_err(cf_sectiontoitem(cs), "Duplicate realm \"%s\"", name2);
1179                         goto error;
1180                 }
1181
1182                 if (!old_realm_config(rc, cs, r)) {
1183                         goto error;
1184                 }
1185
1186                 cf_log_info(cs, " } # realm %s", name2);
1187                 return 1;
1188         }
1189
1190         r = rad_malloc(sizeof(*r));
1191         memset(r, 0, sizeof(*r));
1192
1193         r->name = name2;
1194         r->auth_pool = auth_pool;
1195         r->acct_pool = acct_pool;
1196         r->striprealm = 1;
1197
1198         if (auth_pool_name &&
1199             (auth_pool_name == acct_pool_name)) { /* yes, ptr comparison */
1200                 cf_log_info(cs, "\tpool = %s", auth_pool_name);
1201         } else {
1202                 if (auth_pool_name) cf_log_info(cs, "\tauth_pool = %s", auth_pool_name);
1203                 if (acct_pool_name) cf_log_info(cs, "\tacct_pool = %s", acct_pool_name);
1204         }
1205
1206         cp = cf_pair_find(cs, "nostrip");
1207         if (cp && (cf_pair_value(cp) == NULL)) {
1208                 r->striprealm = 0;
1209                 cf_log_info(cs, "\tnostrip");
1210         }
1211
1212         /*
1213          *      We're a new-style realm.  Complain if we see the old
1214          *      directives.
1215          */
1216         if (r->auth_pool || r->acct_pool) {
1217                 if (((cp = cf_pair_find(cs, "authhost")) != NULL) ||
1218                     ((cp = cf_pair_find(cs, "accthost")) != NULL) ||
1219                     ((cp = cf_pair_find(cs, "secret")) != NULL) ||
1220                     ((cp = cf_pair_find(cs, "ldflag")) != NULL)) {
1221                         DEBUG2("WARNING: Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
1222                 }
1223
1224
1225                 /*
1226                  *      The realm MAY be an old-style realm, as there
1227                  *      was no auth_pool or acct_pool.  Double-check
1228                  *      it, just to be safe.
1229                  */
1230         } else if (!old_realm_config(rc, cs, r)) {
1231                 goto error;
1232         }
1233
1234         if (!rbtree_insert(realms_byname, r)) {
1235                 rad_assert("Internal sanity check failed");
1236                 goto error;
1237         }
1238
1239         cf_log_info(cs, " }");
1240
1241         return 1;
1242
1243  error:
1244         cf_log_info(cs, " } # realm %s", name2);
1245         free(r);
1246         return 0;
1247 }
1248
1249
1250 int realms_init(CONF_SECTION *config)
1251 {
1252         CONF_SECTION *cs;
1253         realm_config_t *rc, *old_rc;
1254
1255         if (realms_byname) return 1;
1256
1257         realms_byname = rbtree_create(realm_name_cmp, free, 0);
1258         if (!realms_byname) {
1259                 realms_free();
1260                 return 0;
1261         }
1262
1263         home_servers_byaddr = rbtree_create(home_server_addr_cmp, free, 0);
1264         if (!home_servers_byaddr) {
1265                 realms_free();
1266                 return 0;
1267         }
1268
1269         home_servers_byname = rbtree_create(home_server_name_cmp, NULL, 0);
1270         if (!home_servers_byname) {
1271                 realms_free();
1272                 return 0;
1273         }
1274
1275         home_pools_byname = rbtree_create(home_pool_name_cmp, free, 0);
1276         if (!home_pools_byname) {
1277                 realms_free();
1278                 return 0;
1279         }
1280
1281         rc = rad_malloc(sizeof(*rc));
1282         memset(rc, 0, sizeof(*rc));
1283         rc->cs = config;
1284
1285         cs = cf_subsection_find_next(config, NULL, "proxy");
1286         if (cs) {
1287                 cf_section_parse(cs, rc, proxy_config);
1288         } else {
1289                 rc->dead_time = DEAD_TIME;
1290                 rc->retry_count = RETRY_COUNT;
1291                 rc->retry_delay = RETRY_DELAY;
1292                 rc->fallback = 0;
1293                 rc->wake_all_if_all_dead= 0;
1294         }
1295
1296         for (cs = cf_subsection_find_next(config, NULL, "realm");
1297              cs != NULL;
1298              cs = cf_subsection_find_next(config, cs, "realm")) {
1299                 if (!realm_add(rc, cs)) {
1300                         free(rc);
1301                         realms_free();
1302                         return 0;
1303                 }
1304         }
1305
1306         xlat_register("home_server", xlat_home_server, NULL);
1307         xlat_register("home_server_pool", xlat_server_pool, NULL);
1308
1309         /*
1310          *      Swap pointers atomically.
1311          */
1312         old_rc = realm_config;
1313         realm_config = rc;
1314         free(old_rc);
1315
1316         return 1;
1317 }
1318
1319
1320 /*
1321  *      Find a realm in the REALM list.
1322  */
1323 REALM *realm_find(const char *name)
1324 {
1325         REALM myrealm;
1326         REALM *realm;
1327         
1328         if (!name) name = "NULL";
1329
1330         myrealm.name = name;
1331         realm = rbtree_finddata(realms_byname, &myrealm);
1332         if (realm) return realm;
1333
1334         /*
1335          *      Couldn't find a realm.  Look for DEFAULT.
1336          */
1337         myrealm.name = "DEFAULT";
1338         return rbtree_finddata(realms_byname, &myrealm);
1339 }
1340
1341
1342 home_server *home_server_ldb(const char *realmname,
1343                              home_pool_t *pool, REQUEST *request)
1344 {
1345         int             start;
1346         int             count;
1347         home_server     *found = NULL;
1348         VALUE_PAIR      *vp;
1349
1350         start = 0;
1351
1352         /*
1353          *      Determine how to pick choose the home server.
1354          */
1355         switch (pool->type) {
1356                 uint32_t hash;
1357
1358                 /*
1359                  *      For load-balancing by client IP address, we
1360                  *      pick a home server by hashing the client IP.
1361                  *
1362                  *      This isn't as even a load distribution as
1363                  *      tracking the State attribute, but it's better
1364                  *      than nothing.
1365                  */
1366         case HOME_POOL_CLIENT_BALANCE:
1367                 switch (request->packet->src_ipaddr.af) {
1368                 case AF_INET:
1369                         hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
1370                                          sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
1371                         break;
1372                 case AF_INET6:
1373                         hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
1374                                          sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
1375                         break;
1376                 default:
1377                         hash = 0;
1378                         break;
1379                 }
1380                 start = hash % pool->num_home_servers;
1381                 break;
1382
1383         case HOME_POOL_CLIENT_PORT_BALANCE:
1384                 switch (request->packet->src_ipaddr.af) {
1385                 case AF_INET:
1386                         hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
1387                                          sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
1388                         break;
1389                 case AF_INET6:
1390                         hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
1391                                          sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
1392                         break;
1393                 default:
1394                         hash = 0;
1395                         break;
1396                 }
1397                 fr_hash_update(&request->packet->src_port,
1398                                  sizeof(request->packet->src_port), hash);
1399                 start = hash % pool->num_home_servers;
1400                 break;
1401
1402         case HOME_POOL_KEYED_BALANCE:
1403                 if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY)) != NULL) {
1404                         hash = fr_hash(vp->vp_strvalue, vp->length);
1405                         start = hash % pool->num_home_servers;
1406                         break;
1407                 }
1408                 /* FALL-THROUGH */
1409                                 
1410         case HOME_POOL_LOAD_BALANCE:
1411                 found = pool->servers[0];
1412
1413         default:
1414                 start = 0;
1415                 break;
1416         }
1417
1418         /*
1419          *      Starting with the home server we chose, loop through
1420          *      all home servers.  If the current one is dead, skip
1421          *      it.  If it is too busy, skip it.
1422          *
1423          *      Otherwise, use it.
1424          */
1425         for (count = 0; count < pool->num_home_servers; count++) {
1426                 home_server *home = pool->servers[(start + count) % pool->num_home_servers];
1427
1428                 if (home->state == HOME_STATE_IS_DEAD) {
1429                         continue;
1430                 }
1431
1432                 /*
1433                  *      This home server is too busy.  Choose another one.
1434                  */
1435                 if (home->currently_outstanding >= home->max_outstanding) {
1436                         continue;
1437                 }
1438
1439                 if (pool->type != HOME_POOL_LOAD_BALANCE) {
1440                         return home;
1441                 }
1442
1443                 DEBUG3("PROXY %s %d\t%s %d",
1444                        found->name, found->currently_outstanding,
1445                        home->name, home->currently_outstanding);
1446
1447                 /*
1448                  *      Prefer this server if it's less busy than the
1449                  *      one we previously found.
1450                  */
1451                 if (home->currently_outstanding < found->currently_outstanding) {
1452                         DEBUG3("Choosing %s: It's less busy than %s",
1453                                home->name, found->name);
1454                         found = home;
1455                         continue;
1456                 }
1457
1458                 /*
1459                  *      Ignore servers which are busier than the one
1460                  *      we found.
1461                  */
1462                 if (home->currently_outstanding > found->currently_outstanding) {
1463                         DEBUG3("Skipping %s: It's busier than %s",
1464                                home->name, found->name);
1465                         continue;
1466                 }
1467
1468                 if (home->total_requests_sent < found->total_requests_sent) {
1469                         DEBUG3("Choosing %s: It's been less busy than %s",
1470                                home->name, found->name);
1471                         found = home;
1472                         continue;
1473                 }
1474
1475                 if (home->total_requests_sent > found->total_requests_sent) {
1476                         DEBUG3("Skipping %s: It's been busier than %s",
1477                                home->name, found->name);
1478                         continue;
1479                 }
1480
1481                 /*
1482                  *      From the list of servers which have the same
1483                  *      load, choose one at random.
1484                  */
1485                 if (((count + 1) * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
1486                         found = home;
1487                 }
1488
1489         } /* loop over the home servers */
1490
1491         if (found) return found;
1492
1493         /*
1494          *      No live match found, and no fallback to the "DEFAULT"
1495          *      realm.  We fix this by blindly marking all servers as
1496          *      "live".  But only do it for ones that don't support
1497          *      "pings", as they will be marked live when they
1498          *      actually are live.
1499          */
1500         if (!realm_config->fallback &&
1501             realm_config->wake_all_if_all_dead) {
1502                 home_server *lb = NULL;
1503
1504                 for (count = 0; count < pool->num_home_servers; count++) {
1505                         home_server *home = pool->servers[count];
1506
1507                         if ((home->state == HOME_STATE_IS_DEAD) &&
1508                             (home->ping_check == HOME_PING_CHECK_NONE)) {
1509                                 home->state = HOME_STATE_ALIVE;
1510                                 if (!lb) lb = home;
1511                         }
1512                 }
1513
1514                 if (lb) return lb;
1515         }
1516
1517         /*
1518          *      Still nothing.  Look up the DEFAULT realm, but only
1519          *      if we weren't looking up the NULL or DEFAULT realms.
1520          */
1521         if (realm_config->fallback &&
1522             realmname &&
1523             (strcmp(realmname, "NULL") != 0) &&
1524             (strcmp(realmname, "DEFAULT") != 0)) {
1525                 REALM *rd = realm_find("DEFAULT");
1526
1527                 if (!rd) return NULL;
1528
1529                 pool = NULL;
1530                 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1531                         pool = rd->auth_pool;
1532
1533                 } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1534                         pool = rd->acct_pool;
1535                 }
1536                 if (!pool) return NULL;
1537
1538                 DEBUG2("  Realm %s has no live home servers.  Falling back to the DEFAULT realm.", realmname);
1539                 return home_server_ldb(rd->name, pool, request);
1540         }
1541
1542         /*
1543          *      Still haven't found anything.  Oh well.
1544          */
1545         return NULL;
1546 }
1547
1548
1549 home_server *home_server_find(fr_ipaddr_t *ipaddr, int port)
1550 {
1551         home_server myhome;
1552
1553         myhome.ipaddr = *ipaddr;
1554         myhome.port = port;
1555
1556         return rbtree_finddata(home_servers_byaddr, &myhome);
1557 }