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