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