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