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