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