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