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