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