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