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