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