1 /*
2 * modules.c Radius module support.
3 *
4 * Version: $Id: 9919482c8605d89c907ab37f6479f7c651b0f1a6 $
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 2003,2006 The FreeRADIUS server project
21 * Copyright 2000 Alan DeKok <aland@ox.org>
22 * Copyright 2000 Alan Curry <pacman@world.std.com>
23 */
24
25 RCSID("$Id: 9919482c8605d89c907ab37f6479f7c651b0f1a6 $")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modpriv.h>
29 #include <freeradius-devel/modcall.h>
30 #include <freeradius-devel/parser.h>
31 #include <freeradius-devel/rad_assert.h>
32
33 /** Path to search for modules in
34 *
35 */
36 char const *radlib_dir = NULL;
37
38 typedef struct indexed_modcallable {
39 rlm_components_t comp;
40 int idx;
41 modcallable *modulelist;
42 } indexed_modcallable;
43
44 typedef struct virtual_server_t {
45 char const *name;
46 time_t created;
47 int can_free;
48 CONF_SECTION *cs;
49 rbtree_t *components;
50 modcallable *mc[MOD_COUNT];
51 CONF_SECTION *subcs[MOD_COUNT];
52 struct virtual_server_t *next;
53 } virtual_server_t;
54
55 /*
56 * Keep a hash of virtual servers, so that we can reload them.
57 */
58 #define VIRTUAL_SERVER_HASH_SIZE (256)
59 static virtual_server_t *virtual_servers[VIRTUAL_SERVER_HASH_SIZE];
60
61 static rbtree_t *module_tree = NULL;
62
63 static rbtree_t *instance_tree = NULL;
64
65 struct fr_module_hup_t {
66 module_instance_t *mi;
67 time_t when;
68 void *insthandle;
69 fr_module_hup_t *next;
70 };
71
72 /*
73 * Ordered by component
74 */
75 const section_type_value_t section_type_value[MOD_COUNT] = {
76 { "authenticate", "Auth-Type", PW_AUTH_TYPE },
77 { "authorize", "Autz-Type", PW_AUTZ_TYPE },
78 { "preacct", "Pre-Acct-Type", PW_PRE_ACCT_TYPE },
79 { "accounting", "Acct-Type", PW_ACCT_TYPE },
80 { "session", "Session-Type", PW_SESSION_TYPE },
81 { "pre-proxy", "Pre-Proxy-Type", PW_PRE_PROXY_TYPE },
82 { "post-proxy", "Post-Proxy-Type", PW_POST_PROXY_TYPE },
83 { "post-auth", "Post-Auth-Type", PW_POST_AUTH_TYPE }
84 #ifdef WITH_COA
85 ,
86 { "recv-coa", "Recv-CoA-Type", PW_RECV_COA_TYPE },
87 { "send-coa", "Send-CoA-Type", PW_SEND_COA_TYPE }
88 #endif
89 };
90
91 #ifndef RTLD_NOW
92 #define RTLD_NOW (0)
93 #endif
94 #ifndef RTLD_LOCAL
95 #define RTLD_LOCAL (0)
96 #endif
97
98 /** Check if the magic number in the module matches the one in the library
99 *
100 * This is used to detect potential ABI issues caused by running with modules which
101 * were built for a different version of the server.
102 *
103 * @param cs being parsed.
104 * @param module being loaded.
105 * @returns 0 on success, -1 if prefix mismatch, -2 if version mismatch, -3 if commit mismatch.
106 */
check_module_magic(CONF_SECTION * cs,module_t const * module)107 static int check_module_magic(CONF_SECTION *cs, module_t const *module)
108 {
109 #ifdef HAVE_DLADDR
110 Dl_info dl_info;
111 dladdr(module, &dl_info);
112 #endif
113
114 if (MAGIC_PREFIX(module->magic) != MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER)) {
115 #ifdef HAVE_DLADDR
116 cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
117 #endif
118 cf_log_err_cs(cs, "Application and rlm_%s magic number (prefix) mismatch."
119 " application: %x module: %x", module->name,
120 MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER),
121 MAGIC_PREFIX(module->magic));
122 return -1;
123 }
124
125 if (MAGIC_VERSION(module->magic) != MAGIC_VERSION(RADIUSD_MAGIC_NUMBER)) {
126 #ifdef HAVE_DLADDR
127 cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
128 #endif
129 cf_log_err_cs(cs, "Application and rlm_%s magic number (version) mismatch."
130 " application: %lx module: %lx", module->name,
131 (unsigned long) MAGIC_VERSION(RADIUSD_MAGIC_NUMBER),
132 (unsigned long) MAGIC_VERSION(module->magic));
133 return -2;
134 }
135
136 if (MAGIC_COMMIT(module->magic) != MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER)) {
137 #ifdef HAVE_DLADDR
138 cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
139 #endif
140 cf_log_err_cs(cs, "Application and rlm_%s magic number (commit) mismatch."
141 " application: %lx module: %lx", module->name,
142 (unsigned long) MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER),
143 (unsigned long) MAGIC_COMMIT(module->magic));
144 return -3;
145 }
146
147 return 0;
148 }
149
fr_dlopenext(char const * name)150 fr_dlhandle fr_dlopenext(char const *name)
151 {
152 int flags = RTLD_NOW;
153 void *handle;
154 char buffer[2048];
155 char *env;
156 char const *search_path;
157 #ifdef RTLD_GLOBAL
158 if (strcmp(name, "rlm_perl") == 0) {
159 flags |= RTLD_GLOBAL;
160 } else
161 #endif
162 flags |= RTLD_LOCAL;
163 #if defined(RTLD_DEEPBIND) && !defined(__SANITIZE_ADDRESS__)
164 flags |= RTLD_DEEPBIND;
165 #endif
166
167 #ifndef NDEBUG
168 /*
169 * Bind all the symbols *NOW* so we don't hit errors later
170 */
171 flags |= RTLD_NOW;
172 #endif
173
174 /*
175 * Apple removed support for DYLD_LIBRARY_PATH in rootless mode.
176 */
177 env = getenv("FR_LIBRARY_PATH");
178 if (env) {
179 DEBUG3("Ignoring libdir as FR_LIBRARY_PATH set. Module search path will be: %s", env);
180 search_path = env;
181 } else {
182 search_path = radlib_dir;
183 }
184
185 /*
186 * Prefer loading our libraries by absolute path.
187 */
188 if (search_path) {
189 char *error;
190 char *ctx, *paths, *path;
191 char *p;
192
193 fr_strerror();
194
195 ctx = paths = talloc_strdup(NULL, search_path);
196 while ((path = strsep(&paths, ":")) != NULL) {
197 /*
198 * Trim the trailing slash
199 */
200 p = strrchr(path, '/');
201 if (p && ((p[1] == '\0') || (p[1] == ':'))) *p = '\0';
202
203 path = talloc_asprintf(ctx, "%s/%s%s", path, name, LT_SHREXT);
204
205 DEBUG4("Loading %s with path: %s", name, path);
206
207 handle = dlopen(path, flags);
208 if (handle) {
209 talloc_free(ctx);
210 return handle;
211 }
212 error = dlerror();
213
214 fr_strerror_printf("%s%s\n", fr_strerror(), error);
215 DEBUG4("Loading %s failed: %s - %s", name, error,
216 (access(path, R_OK) < 0) ? fr_syserror(errno) : "No access errors");
217 talloc_free(path);
218 }
219 talloc_free(ctx);
220 }
221
222 DEBUG4("Loading library using linker search path(s)");
223 if (DEBUG_ENABLED4) {
224 #ifdef __APPLE__
225 env = getenv("LD_LIBRARY_PATH");
226 if (env) {
227 DEBUG4("LD_LIBRARY_PATH : %s", env);
228 }
229 env = getenv("DYLD_LIBRARY_PATH");
230 if (env) {
231 DEBUG4("DYLB_LIBRARY_PATH : %s", env);
232 }
233 env = getenv("DYLD_FALLBACK_LIBRARY_PATH");
234 if (env) {
235 DEBUG4("DYLD_FALLBACK_LIBRARY_PATH : %s", env);
236 }
237 env = getcwd(buffer, sizeof(buffer));
238 if (env) {
239 DEBUG4("Current directory : %s", env);
240 }
241 #else
242 env = getenv("LD_LIBRARY_PATH");
243 if (env) {
244 DEBUG4("LD_LIBRARY_PATH : %s", env);
245 }
246 DEBUG4("Defaults : /lib:/usr/lib");
247 #endif
248 }
249
250 strlcpy(buffer, name, sizeof(buffer));
251 /*
252 * FIXME: Make this configurable...
253 */
254 strlcat(buffer, LT_SHREXT, sizeof(buffer));
255
256 handle = dlopen(buffer, flags);
257 if (!handle) {
258 char *error = dlerror();
259
260 DEBUG4("Failed with error: %s", error);
261 /*
262 * Don't overwrite the previous message
263 * It's likely to contain a better error.
264 */
265 if (!radlib_dir) fr_strerror_printf("%s", dlerror());
266 return NULL;
267 }
268 return handle;
269 }
270
fr_dlsym(fr_dlhandle handle,char const * symbol)271 void *fr_dlsym(fr_dlhandle handle, char const *symbol)
272 {
273 return dlsym(handle, symbol);
274 }
275
fr_dlclose(fr_dlhandle handle)276 int fr_dlclose(fr_dlhandle handle)
277 {
278 if (!handle) return 0;
279
280 return dlclose(handle);
281 }
282
fr_dlerror(void)283 char const *fr_dlerror(void)
284 {
285 return dlerror();
286 }
287
virtual_server_idx(char const * name)288 static int virtual_server_idx(char const *name)
289 {
290 uint32_t hash;
291
292 if (!name) return 0;
293
294 hash = fr_hash_string(name);
295
296 return hash & (VIRTUAL_SERVER_HASH_SIZE - 1);
297 }
298
virtual_server_find(char const * name)299 static virtual_server_t *virtual_server_find(char const *name)
300 {
301 rlm_rcode_t rcode;
302 virtual_server_t *server;
303
304 rcode = virtual_server_idx(name);
305 for (server = virtual_servers[rcode];
306 server != NULL;
307 server = server->next) {
308 if (!name && !server->name) break;
309
310 if ((name && server->name) &&
311 (strcmp(name, server->name) == 0)) break;
312 }
313
314 return server;
315 }
316
_virtual_server_free(virtual_server_t * server)317 static int _virtual_server_free(virtual_server_t *server)
318 {
319 if (server->components) rbtree_free(server->components);
320 return 0;
321 }
322
virtual_servers_free(time_t when)323 void virtual_servers_free(time_t when)
324 {
325 int i;
326 virtual_server_t **last;
327
328 for (i = 0; i < VIRTUAL_SERVER_HASH_SIZE; i++) {
329 virtual_server_t *server, *next;
330
331 last = &virtual_servers[i];
332 for (server = virtual_servers[i];
333 server != NULL;
334 server = next) {
335 next = server->next;
336
337 /*
338 * If we delete it, fix the links so that
339 * we don't orphan anything. Also,
340 * delete it if it's old, AND a newer one
341 * was defined.
342 *
343 * Otherwise, the last pointer gets set to
344 * the one we didn't delete.
345 */
346 if ((when == 0) ||
347 ((server->created < when) && server->can_free)) {
348 *last = server->next;
349 talloc_free(server);
350 } else {
351 last = &(server->next);
352 }
353 }
354 }
355 }
356
indexed_modcallable_cmp(void const * one,void const * two)357 static int indexed_modcallable_cmp(void const *one, void const *two)
358 {
359 indexed_modcallable const *a = one;
360 indexed_modcallable const *b = two;
361
362 if (a->comp < b->comp) return -1;
363 if (a->comp > b->comp) return +1;
364
365 return a->idx - b->idx;
366 }
367
368
369 /*
370 * Compare two module entries
371 */
module_instance_cmp(void const * one,void const * two)372 static int module_instance_cmp(void const *one, void const *two)
373 {
374 module_instance_t const *a = one;
375 module_instance_t const *b = two;
376
377 return strcmp(a->name, b->name);
378 }
379
380
module_instance_free_old(UNUSED CONF_SECTION * cs,module_instance_t * node,time_t when)381 static void module_instance_free_old(UNUSED CONF_SECTION *cs, module_instance_t *node, time_t when)
382 {
383 fr_module_hup_t *mh, **last;
384
385 /*
386 * Walk the list, freeing up old instances.
387 */
388 last = &(node->mh);
389 while (*last) {
390 mh = *last;
391
392 /*
393 * Free only every 60 seconds.
394 */
395 if ((when - mh->when) < 60) {
396 last = &(mh->next);
397 continue;
398 }
399
400 talloc_free(mh->insthandle);
401
402 *last = mh->next;
403 talloc_free(mh);
404 }
405 }
406
407
408 /*
409 * Free a module instance.
410 */
module_instance_free(void * data)411 static void module_instance_free(void *data)
412 {
413 module_instance_t *module = talloc_get_type_abort(data, module_instance_t);
414
415 module_instance_free_old(module->cs, module, time(NULL) + 100);
416
417 #ifdef HAVE_PTHREAD_H
418 if (module->mutex) {
419 /*
420 * FIXME
421 * The mutex MIGHT be locked...
422 * we'll check for that later, I guess.
423 */
424 pthread_mutex_destroy(module->mutex);
425 talloc_free(module->mutex);
426 }
427 #endif
428
429 xlat_unregister(module->name, NULL, module->insthandle);
430
431 /*
432 * Remove all xlat's registered to module instance.
433 */
434 if (module->insthandle) {
435 /*
436 * Remove any registered paircompares.
437 */
438 paircompare_unregister_instance(module->insthandle);
439
440 xlat_unregister_module(module->insthandle);
441 }
442 talloc_free(module);
443 }
444
445
446 /*
447 * Compare two module entries
448 */
module_entry_cmp(void const * one,void const * two)449 static int module_entry_cmp(void const *one, void const *two)
450 {
451 module_entry_t const *a = one;
452 module_entry_t const *b = two;
453
454 return strcmp(a->name, b->name);
455 }
456
457 /*
458 * Free a module entry.
459 */
_module_entry_free(module_entry_t * this)460 static int _module_entry_free(module_entry_t *this)
461 {
462 #ifndef NDEBUG
463 /*
464 * Don't dlclose() modules if we're doing memory
465 * debugging. This removes the symbols needed by
466 * valgrind.
467 */
468 if (!main_config.debug_memory)
469 #endif
470 dlclose(this->handle); /* ignore any errors */
471 return 0;
472 }
473
474
475 /*
476 * Remove the module lists.
477 */
modules_free(void)478 int modules_free(void)
479 {
480 rbtree_free(instance_tree);
481 rbtree_free(module_tree);
482
483 return 0;
484 }
485
486
487 /*
488 * dlopen() a module.
489 */
module_dlopen(CONF_SECTION * cs,char const * module_name)490 static module_entry_t *module_dlopen(CONF_SECTION *cs, char const *module_name)
491 {
492 module_entry_t myentry;
493 module_entry_t *node;
494 void *handle = NULL;
495 module_t const *module;
496
497 strlcpy(myentry.name, module_name, sizeof(myentry.name));
498 node = rbtree_finddata(module_tree, &myentry);
499 if (node) return node;
500
501 /*
502 * Link to the module's rlm_FOO{} structure, the same as
503 * the module name.
504 */
505
506 #if !defined(WITH_LIBLTDL) && defined(HAVE_DLFCN_H) && defined(RTLD_SELF)
507 module = dlsym(RTLD_SELF, module_name);
508 if (module) goto open_self;
509 #endif
510
511 /*
512 * Keep the handle around so we can dlclose() it.
513 */
514 handle = fr_dlopenext(module_name);
515 if (!handle) {
516 cf_log_err_cs(cs, "Failed to link to module '%s': %s", module_name, fr_strerror());
517 return NULL;
518 }
519
520 DEBUG3("Loaded %s, checking if it's valid", module_name);
521
522 module = dlsym(handle, module_name);
523 if (!module) {
524 cf_log_err_cs(cs, "Failed linking to %s structure: %s", module_name, dlerror());
525 dlclose(handle);
526 return NULL;
527 }
528
529 #if !defined(WITH_LIBLTDL) && defined (HAVE_DLFCN_H) && defined(RTLD_SELF)
530 open_self:
531 #endif
532 /*
533 * Before doing anything else, check if it's sane.
534 */
535 if (check_module_magic(cs, module) < 0) {
536 dlclose(handle);
537 return NULL;
538 }
539
540 /* make room for the module type */
541 node = talloc_zero(cs, module_entry_t);
542 talloc_set_destructor(node, _module_entry_free);
543 strlcpy(node->name, module_name, sizeof(node->name));
544 node->module = module;
545 node->handle = handle;
546
547 cf_log_module(cs, "Loaded module %s", module_name);
548
549 /*
550 * Add the module as "rlm_foo-version" to the configuration
551 * section.
552 */
553 if (!rbtree_insert(module_tree, node)) {
554 ERROR("Failed to cache module %s", module_name);
555 dlclose(handle);
556 talloc_free(node);
557 return NULL;
558 }
559
560 return node;
561 }
562
563 /** Parse module's configuration section and setup destructors
564 *
565 */
module_conf_parse(module_instance_t * node,void ** handle)566 static int module_conf_parse(module_instance_t *node, void **handle)
567 {
568 *handle = NULL;
569
570 /*
571 * If there is supposed to be instance data, allocate it now.
572 * Also parse the configuration data, if required.
573 */
574 if (node->entry->module->inst_size) {
575 *handle = talloc_zero_array(node, uint8_t, node->entry->module->inst_size);
576 rad_assert(*handle);
577
578 talloc_set_name(*handle, "rlm_%s_t",
579 node->entry->module->name ? node->entry->module->name : "config");
580
581 if (node->entry->module->config &&
582 (cf_section_parse(node->cs, *handle, node->entry->module->config) < 0)) {
583 cf_log_err_cs(node->cs,"Invalid configuration for module \"%s\"", node->name);
584 talloc_free(*handle);
585
586 return -1;
587 }
588
589 /*
590 * Set the destructor.
591 */
592 if (node->entry->module->detach) {
593 talloc_set_destructor(*handle, node->entry->module->detach);
594 }
595 }
596
597 return 0;
598 }
599
600 /** Bootstrap a module.
601 *
602 * Load the module shared library, allocate instance memory for it,
603 * parse the module configuration, and call the modules "bootstrap" method.
604 */
module_bootstrap(CONF_SECTION * cs)605 static module_instance_t *module_bootstrap(CONF_SECTION *cs)
606 {
607 char const *name1, *name2, *askedname;
608 module_instance_t *node, myNode;
609 char module_name[256];
610
611 /*
612 * Figure out which module we want to load.
613 */
614 name1 = cf_section_name1(cs);
615 askedname = name2 = cf_section_name2(cs);
616 if (!askedname) {
617 askedname = name1;
618 name2 = "";
619 }
620
621 strlcpy(myNode.name, askedname, sizeof(myNode.name));
622
623 /*
624 * See if the module already exists.
625 */
626 node = rbtree_finddata(instance_tree, &myNode);
627 if (node) {
628 ERROR("Duplicate module \"%s %s { ... }\", in file %s:%d and file %s:%d",
629 name1, name2,
630 cf_section_filename(cs),
631 cf_section_lineno(cs),
632 cf_section_filename(node->cs),
633 cf_section_lineno(node->cs));
634 return NULL;
635 }
636
637 /*
638 * Hang the node struct off of the configuration
639 * section. If the CS is free'd the instance will be
640 * free'd, too.
641 */
642 node = talloc_zero(instance_tree, module_instance_t);
643 node->cs = cs;
644 strlcpy(node->name, askedname, sizeof(node->name));
645
646 /*
647 * Names in the "modules" section aren't prefixed
648 * with "rlm_", so we add it here.
649 */
650 snprintf(module_name, sizeof(module_name), "rlm_%s", name1);
651
652 /*
653 * Load the module shared library.
654 */
655 node->entry = module_dlopen(cs, module_name);
656 if (!node->entry) {
657 talloc_free(node);
658 return NULL;
659 }
660
661 cf_log_module(cs, "Loading module \"%s\" from file %s", node->name,
662 cf_section_filename(cs));
663
664 /*
665 * Parse the modules configuration.
666 */
667 if (module_conf_parse(node, &node->insthandle) < 0) {
668 talloc_free(node);
669 return NULL;
670 }
671
672 /*
673 * Bootstrap the module.
674 */
675 if (node->entry->module->bootstrap &&
676 ((node->entry->module->bootstrap)(cs, node->insthandle) < 0)) {
677 cf_log_err_cs(cs, "Instantiation failed for module \"%s\"", node->name);
678 talloc_free(node);
679 return NULL;
680 }
681
682 /*
683 * Remember the module for later.
684 */
685 rbtree_insert(instance_tree, node);
686
687 return node;
688 }
689
690
691 /** Find an existing module instance.
692 *
693 */
module_find(CONF_SECTION * modules,char const * askedname)694 module_instance_t *module_find(CONF_SECTION *modules, char const *askedname)
695 {
696 char const *instname;
697 module_instance_t myNode;
698
699 if (!modules) return NULL;
700
701 /*
702 * Look for the real name. Ignore the first character,
703 * which tells the server "it's OK for this module to not
704 * exist."
705 */
706 instname = askedname;
707 if (instname[0] == '-') instname++;
708
709 strlcpy(myNode.name, instname, sizeof(myNode.name));
710
711 return rbtree_finddata(instance_tree, &myNode);
712 }
713
714
715 /** Load a module, and instantiate it.
716 *
717 */
module_instantiate(CONF_SECTION * modules,char const * askedname)718 module_instance_t *module_instantiate(CONF_SECTION *modules, char const *askedname)
719 {
720 module_instance_t *node;
721
722 /*
723 * Find the module. If it's not there, do nothing.
724 */
725 node = module_find(modules, askedname);
726 if (!node) {
727 ERROR("Cannot find module \"%s\"", askedname);
728 return NULL;
729 }
730
731 /*
732 * The module is already instantiated. Return it.
733 */
734 if (node->instantiated) return node;
735
736 /*
737 * Now that ALL modules are instantiated, and ALL xlats
738 * are defined, go compile the config items marked as XLAT.
739 */
740 if (node->entry->module->config &&
741 (cf_section_parse_pass2(node->cs, node->insthandle,
742 node->entry->module->config) < 0)) {
743 return NULL;
744 }
745
746 /*
747 * Call the instantiate method, if any.
748 */
749 if (node->entry->module->instantiate) {
750 cf_log_module(node->cs, "Instantiating module \"%s\" from file %s", node->name,
751 cf_section_filename(node->cs));
752
753 /*
754 * Call the module's instantiation routine.
755 */
756 if ((node->entry->module->instantiate)(node->cs, node->insthandle) < 0) {
757 cf_log_err_cs(node->cs, "Instantiation failed for module \"%s\"", node->name);
758
759 return NULL;
760 }
761 }
762
763 #ifdef HAVE_PTHREAD_H
764 /*
765 * If we're threaded, check if the module is thread-safe.
766 *
767 * If it isn't, we create a mutex.
768 */
769 if ((node->entry->module->type & RLM_TYPE_THREAD_UNSAFE) != 0) {
770 node->mutex = talloc_zero(node, pthread_mutex_t);
771
772 /*
773 * Initialize the mutex.
774 */
775 pthread_mutex_init(node->mutex, NULL);
776 }
777 #endif
778
779 node->instantiated = true;
780 node->last_hup = time(NULL); /* don't let us load it, then immediately hup it */
781
782 return node;
783 }
784
785
module_instantiate_method(CONF_SECTION * modules,char const * name,rlm_components_t * method)786 module_instance_t *module_instantiate_method(CONF_SECTION *modules, char const *name, rlm_components_t *method)
787 {
788 char *p;
789 rlm_components_t i;
790 module_instance_t *mi;
791
792 /*
793 * If the module exists, ensure it's instantiated.
794 *
795 * Doing it this way avoids complaints from
796 * module_instantiate()
797 */
798 mi = module_find(modules, name);
799 if (mi) return module_instantiate(modules, name);
800
801 /*
802 * Find out which method is being used.
803 */
804 p = strrchr(name, '.');
805 if (!p) return NULL;
806
807 p++;
808
809 /*
810 * Find the component.
811 */
812 for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
813 if (strcmp(p, section_type_value[i].section) == 0) {
814 char buffer[256];
815
816 strlcpy(buffer, name, sizeof(buffer));
817 buffer[p - name - 1] = '\0';
818
819 mi = module_find(modules, buffer);
820 if (mi) {
821 if (method) *method = i;
822 return module_instantiate(modules, buffer);
823 }
824 }
825 }
826
827 /*
828 * Not found.
829 */
830 return NULL;
831 }
832
833
834 /** Resolve polymorphic item's from a module's CONF_SECTION to a subsection in another module
835 *
836 * This allows certain module sections to reference module sections in other instances
837 * of the same module and share CONF_DATA associated with them.
838 *
839 * @verbatim
840 example {
841 data {
842 ...
843 }
844 }
845
846 example inst {
847 data = example
848 }
849 * @endverbatim
850 *
851 * @param out where to write the pointer to a module's config section. May be NULL on success, indicating the config
852 * item was not found within the module CONF_SECTION, or the chain of module references was followed and the
853 * module at the end of the chain did not a subsection.
854 * @param module CONF_SECTION.
855 * @param name of the polymorphic sub-section.
856 * @return 0 on success with referenced section, 1 on success with local section, or -1 on failure.
857 */
find_module_sibling_section(CONF_SECTION ** out,CONF_SECTION * module,char const * name)858 int find_module_sibling_section(CONF_SECTION **out, CONF_SECTION *module, char const *name)
859 {
860 static bool loop = true; /* not used, we just need a valid pointer to quiet static analysis */
861
862 CONF_PAIR *cp;
863 CONF_SECTION *cs;
864
865 module_instance_t *inst;
866 char const *inst_name;
867
868 #define FIND_SIBLING_CF_KEY "find_sibling"
869
870 *out = NULL;
871
872 /*
873 * Is a real section (not referencing sibling module).
874 */
875 cs = cf_section_sub_find(module, name);
876 if (cs) {
877 *out = cs;
878
879 return 0;
880 }
881
882 /*
883 * Item omitted completely from module config.
884 */
885 cp = cf_pair_find(module, name);
886 if (!cp) return 0;
887
888 if (cf_data_find(module, FIND_SIBLING_CF_KEY)) {
889 cf_log_err_cp(cp, "Module reference loop found");
890
891 return -1;
892 }
893 cf_data_add(module, FIND_SIBLING_CF_KEY, &loop, NULL);
894
895 /*
896 * Item found, resolve it to a module instance.
897 * This triggers module loading, so we don't have
898 * instantiation order issues.
899 */
900 inst_name = cf_pair_value(cp);
901 inst = module_instantiate(cf_item_parent(cf_section_to_item(module)), inst_name);
902
903 /*
904 * Remove the config data we added for loop
905 * detection.
906 */
907 cf_data_remove(module, FIND_SIBLING_CF_KEY);
908 if (!inst) {
909 cf_log_err_cp(cp, "Unknown module instance \"%s\"", inst_name);
910
911 return -1;
912 }
913
914 /*
915 * Check the module instances are of the same type.
916 */
917 if (strcmp(cf_section_name1(inst->cs), cf_section_name1(module)) != 0) {
918 cf_log_err_cp(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
919 cf_section_name1(inst->cs), cf_section_name1(module));
920
921 return -1;
922 }
923
924 *out = cf_section_sub_find(inst->cs, name);
925
926 return 1;
927 }
928
lookup_by_index(rbtree_t * components,rlm_components_t comp,int idx)929 static indexed_modcallable *lookup_by_index(rbtree_t *components,
930 rlm_components_t comp, int idx)
931 {
932 indexed_modcallable myc;
933
934 myc.comp = comp;
935 myc.idx = idx;
936
937 return rbtree_finddata(components, &myc);
938 }
939
940 /*
941 * Create a new sublist.
942 */
new_sublist(CONF_SECTION * cs,rbtree_t * components,rlm_components_t comp,int idx)943 static indexed_modcallable *new_sublist(CONF_SECTION *cs,
944 rbtree_t *components, rlm_components_t comp, int idx)
945 {
946 indexed_modcallable *c;
947
948 c = lookup_by_index(components, comp, idx);
949
950 /* It is an error to try to create a sublist that already
951 * exists. It would almost certainly be caused by accidental
952 * duplication in the config file.
953 *
954 * index 0 is the exception, because it is used when we want
955 * to collect _all_ listed modules under a single index by
956 * default, which is currently the case in all components
957 * except authenticate. */
958 if (c) {
959 if (idx == 0) {
960 return c;
961 }
962 return NULL;
963 }
964
965 c = talloc_zero(cs, indexed_modcallable);
966 c->modulelist = NULL;
967 c->comp = comp;
968 c->idx = idx;
969
970 if (!rbtree_insert(components, c)) {
971 talloc_free(c);
972 return NULL;
973 }
974
975 return c;
976 }
977
indexed_modcall(rlm_components_t comp,int idx,REQUEST * request)978 rlm_rcode_t indexed_modcall(rlm_components_t comp, int idx, REQUEST *request)
979 {
980 rlm_rcode_t rcode;
981 modcallable *list = NULL;
982 virtual_server_t *server;
983
984 /*
985 * Hack to find the correct virtual server.
986 */
987 server = virtual_server_find(request->server);
988 if (!server) {
989 RDEBUG("No such virtual server \"%s\"", request->server);
990 return RLM_MODULE_FAIL;
991 }
992
993 if (idx == 0) {
994 list = server->mc[comp];
995 if (!list) {
996 if (server->name) {
997 RDEBUG3("Empty %s section in virtual server \"%s\". Using default return values.",
998 section_type_value[comp].section, server->name);
999 } else {
1000 RDEBUG3("Empty %s section. Using default return values.", section_type_value[comp].section);
1001 }
1002 }
1003 } else {
1004 indexed_modcallable *this;
1005
1006 this = lookup_by_index(server->components, comp, idx);
1007 if (this) {
1008 list = this->modulelist;
1009 } else {
1010 RDEBUG2("%s sub-section not found. Ignoring.", section_type_value[comp].typename);
1011 }
1012 }
1013
1014 if (server->subcs[comp]) {
1015 if (idx == 0) {
1016 RDEBUG("# Executing section %s from file %s",
1017 section_type_value[comp].section,
1018 cf_section_filename(server->subcs[comp]));
1019 } else {
1020 RDEBUG("# Executing group from file %s",
1021 cf_section_filename(server->subcs[comp]));
1022 }
1023 }
1024 request->component = section_type_value[comp].section;
1025 rcode = modcall(comp, list, request);
1026 request->component = "<core>";
1027
1028 return rcode;
1029 }
1030
1031 /*
1032 * Load a sub-module list, as found inside an Auth-Type foo {}
1033 * block
1034 */
load_subcomponent_section(CONF_SECTION * cs,rbtree_t * components,DICT_ATTR const * da,rlm_components_t comp)1035 static int load_subcomponent_section(CONF_SECTION *cs,
1036 rbtree_t *components,
1037 DICT_ATTR const *da, rlm_components_t comp)
1038 {
1039 indexed_modcallable *subcomp;
1040 modcallable *ml;
1041 DICT_VALUE *dval;
1042 char const *name2 = cf_section_name2(cs);
1043
1044 /*
1045 * Sanity check.
1046 */
1047 if (!name2) {
1048 return 1;
1049 }
1050
1051 DEBUG("Compiling %s %s for attr %s", cf_section_name1(cs), name2, da->name);
1052
1053 /*
1054 * Compile the group.
1055 */
1056 ml = compile_modgroup(NULL, comp, cs);
1057 if (!ml) {
1058 return 0;
1059 }
1060
1061 /*
1062 * We must assign a numeric index to this subcomponent.
1063 * It is generated and placed in the dictionary
1064 * automatically. If it isn't found, it's a serious
1065 * error.
1066 */
1067 dval = dict_valbyname(da->attr, da->vendor, name2);
1068 if (!dval) {
1069 talloc_free(ml);
1070 cf_log_err_cs(cs,
1071 "The %s attribute has no VALUE defined for %s",
1072 section_type_value[comp].typename, name2);
1073 return 0;
1074 }
1075
1076 subcomp = new_sublist(cs, components, comp, dval->value);
1077 if (!subcomp) {
1078 talloc_free(ml);
1079 return 1;
1080 }
1081
1082 /*
1083 * Link it into the talloc hierarchy.
1084 */
1085 subcomp->modulelist = talloc_steal(subcomp, ml);
1086 return 1; /* OK */
1087 }
1088
1089 /*
1090 * Don't complain too often.
1091 */
1092 #define MAX_IGNORED (32)
1093 static int last_ignored = -1;
1094 static char const *ignored[MAX_IGNORED];
1095
load_component_section(CONF_SECTION * cs,rbtree_t * components,rlm_components_t comp)1096 static int load_component_section(CONF_SECTION *cs,
1097 rbtree_t *components, rlm_components_t comp)
1098 {
1099 modcallable *this;
1100 CONF_ITEM *modref;
1101 int idx;
1102 indexed_modcallable *subcomp;
1103 char const *modname;
1104 DICT_ATTR const *da;
1105
1106 /*
1107 * Find the attribute used to store VALUEs for this section.
1108 */
1109 da = dict_attrbyvalue(section_type_value[comp].attr, 0);
1110 if (!da) {
1111 cf_log_err_cs(cs,
1112 "No such attribute %s",
1113 section_type_value[comp].typename);
1114 return -1;
1115 }
1116
1117 /*
1118 * Loop over the entries in the named section, loading
1119 * the sections this time.
1120 */
1121 for (modref = cf_item_find_next(cs, NULL);
1122 modref != NULL;
1123 modref = cf_item_find_next(cs, modref)) {
1124 char const *name1;
1125 CONF_PAIR *cp = NULL;
1126 CONF_SECTION *scs = NULL;
1127
1128 if (cf_item_is_section(modref)) {
1129 scs = cf_item_to_section(modref);
1130
1131 name1 = cf_section_name1(scs);
1132
1133 if (strcmp(name1,
1134 section_type_value[comp].typename) == 0) {
1135 if (!load_subcomponent_section(scs,
1136 components,
1137 da,
1138 comp)) {
1139
1140 return -1; /* FIXME: memleak? */
1141 }
1142 continue;
1143 }
1144
1145 cp = NULL;
1146
1147 } else if (cf_item_is_pair(modref)) {
1148 cp = cf_item_to_pair(modref);
1149
1150 } else {
1151 continue; /* ignore it */
1152 }
1153
1154 /*
1155 * Look for Auth-Type foo {}, which are special
1156 * cases of named sections, and allowable ONLY
1157 * at the top-level.
1158 *
1159 * i.e. They're not allowed in a "group" or "redundant"
1160 * subsection.
1161 */
1162 if (comp == MOD_AUTHENTICATE) {
1163 DICT_VALUE *dval;
1164 char const *modrefname = NULL;
1165
1166 if (cp) {
1167 modrefname = cf_pair_attr(cp);
1168 } else {
1169 modrefname = cf_section_name2(scs);
1170 if (!modrefname) {
1171 cf_log_err_cs(cs,
1172 "Errors parsing %s sub-section.\n",
1173 cf_section_name1(scs));
1174 return -1;
1175 }
1176 }
1177 if (*modrefname == '-') modrefname++;
1178
1179 dval = dict_valbyname(PW_AUTH_TYPE, 0, modrefname);
1180 if (!dval) {
1181 /*
1182 * It's a section, but nothing we
1183 * recognize. Die!
1184 */
1185 cf_log_err_cs(cs,
1186 "Unknown Auth-Type \"%s\" in %s sub-section.",
1187 modrefname, section_type_value[comp].section);
1188 return -1;
1189 }
1190 idx = dval->value;
1191 } else {
1192 /* See the comment in new_sublist() for explanation
1193 * of the special index 0 */
1194 idx = 0;
1195 }
1196
1197 subcomp = new_sublist(cs, components, comp, idx);
1198 if (!subcomp) continue;
1199
1200 /*
1201 * Try to compile one entry.
1202 */
1203 this = compile_modsingle(subcomp, &subcomp->modulelist, comp, modref, &modname);
1204
1205 /*
1206 * It's OK for the module to not exist.
1207 */
1208 if (!this && modname && (modname[0] == '-')) {
1209 int i;
1210
1211 if (last_ignored < 0) {
1212 save_complain:
1213 last_ignored++;
1214 ignored[last_ignored] = modname;
1215
1216 complain:
1217 WARN("Ignoring \"%s\" (see raddb/mods-available/README.rst)", modname + 1);
1218 continue;
1219 }
1220
1221 if (last_ignored >= MAX_IGNORED) goto complain;
1222
1223 for (i = 0; i <= last_ignored; i++) {
1224 if (strcmp(ignored[i], modname) == 0) {
1225 break;
1226 }
1227 }
1228
1229 if (i > last_ignored) goto save_complain;
1230 continue;
1231 }
1232
1233 if (!this) {
1234 cf_log_err_cs(cs,
1235 "Errors parsing %s section.\n",
1236 cf_section_name1(cs));
1237 return -1;
1238 }
1239
1240 if (rad_debug_lvl > 2) modcall_debug(this, 2);
1241
1242 add_to_modcallable(subcomp->modulelist, this);
1243 }
1244
1245
1246 return 0;
1247 }
1248
load_byserver(CONF_SECTION * cs)1249 static int load_byserver(CONF_SECTION *cs)
1250 {
1251 rlm_components_t comp;
1252 bool found;
1253 char const *name = cf_section_name2(cs);
1254 rbtree_t *components;
1255 virtual_server_t *server = NULL;
1256 indexed_modcallable *c;
1257 bool is_bare;
1258
1259 if (name) {
1260 cf_log_info(cs, "server %s { # from file %s",
1261 name, cf_section_filename(cs));
1262 } else {
1263 cf_log_info(cs, "server { # from file %s",
1264 cf_section_filename(cs));
1265 }
1266
1267 is_bare = (cf_item_parent(cf_section_to_item(cs)) == NULL);
1268
1269 server = talloc_zero(cs, virtual_server_t);
1270 server->name = name;
1271 server->created = time(NULL);
1272 server->cs = cs;
1273 server->components = components = rbtree_create(server, indexed_modcallable_cmp, NULL, 0);
1274 if (!components) {
1275 ERROR("Failed to initialize components");
1276
1277 error:
1278 if (rad_debug_lvl == 0) {
1279 ERROR("Failed to load virtual server %s",
1280 (name != NULL) ? name : "<default>");
1281 }
1282 return -1;
1283 }
1284 talloc_set_destructor(server, _virtual_server_free);
1285
1286 /*
1287 * Loop over all of the known components, finding their
1288 * configuration section, and loading it.
1289 */
1290 found = false;
1291 for (comp = 0; comp < MOD_COUNT; ++comp) {
1292 CONF_SECTION *subcs;
1293
1294 subcs = cf_section_sub_find(cs,
1295 section_type_value[comp].section);
1296 if (!subcs) continue;
1297
1298 if (is_bare) {
1299 cf_log_err_cs(subcs, "The %s section should be inside of a 'server { ... }' block!",
1300 section_type_value[comp].section);
1301 }
1302
1303 if (cf_item_find_next(subcs, NULL) == NULL) continue;
1304
1305 /*
1306 * Skip pre/post-proxy sections if we're not
1307 * proxying.
1308 */
1309 if (
1310 #ifdef WITH_PROXY
1311 !main_config.proxy_requests &&
1312 #endif
1313 ((comp == MOD_PRE_PROXY) ||
1314 (comp == MOD_POST_PROXY))) {
1315 continue;
1316 }
1317
1318 #ifndef WITH_ACCOUNTING
1319 if (comp == MOD_ACCOUNTING) continue;
1320 #endif
1321
1322 #ifndef WITH_SESSION_MGMT
1323 if (comp == MOD_SESSION) continue;
1324 #endif
1325
1326 if (rad_debug_lvl <= 3) {
1327 cf_log_module(cs, "Loading %s {...}",
1328 section_type_value[comp].section);
1329 } else {
1330 DEBUG(" %s {", section_type_value[comp].section);
1331 }
1332
1333 if (load_component_section(subcs, components, comp) < 0) {
1334 goto error;
1335 }
1336
1337 if (rad_debug_lvl > 3) {
1338 DEBUG(" } # %s", section_type_value[comp].section);
1339 }
1340
1341 /*
1342 * Cache a default, if it exists. Some people
1343 * put empty sections for some reason...
1344 */
1345 c = lookup_by_index(components, comp, 0);
1346 if (c) server->mc[comp] = c->modulelist;
1347
1348 server->subcs[comp] = subcs;
1349
1350 found = true;
1351 } /* loop over components */
1352
1353 /*
1354 * We haven't loaded any of the normal sections. Maybe we're
1355 * supposed to load the vmps section.
1356 *
1357 * This is a bit of a hack...
1358 */
1359 if (!found) do {
1360 #if defined(WITH_VMPS) || defined(WITH_DHCP)
1361 CONF_SECTION *subcs;
1362 #endif
1363 #if defined(WITH_DHCP) || defined(WITH_TLS)
1364 DICT_ATTR const *da;
1365 #endif
1366
1367 #ifdef WITH_VMPS
1368 subcs = cf_section_sub_find(cs, "vmps");
1369 if (subcs) {
1370 cf_log_module(cs, "Loading vmps {...}");
1371 if (load_component_section(subcs, components,
1372 MOD_POST_AUTH) < 0) {
1373 goto error;
1374 }
1375 c = lookup_by_index(components,
1376 MOD_POST_AUTH, 0);
1377 if (c) server->mc[MOD_POST_AUTH] = c->modulelist;
1378 break;
1379 }
1380 #endif
1381
1382 #ifdef WITH_TLS
1383 /*
1384 * It's OK to not have TLS cache sections.
1385 */
1386 da = dict_attrbyname("TLS-Cache-Method");
1387 subcs = cf_section_sub_find_name2(cs, "cache", "load");
1388 if (subcs && !load_subcomponent_section(subcs,
1389 components,
1390 da,
1391 MOD_POST_AUTH)) {
1392 goto error; /* FIXME: memleak? */
1393 }
1394
1395 subcs = cf_section_sub_find_name2(cs, "cache", "save");
1396 if (subcs && !load_subcomponent_section(subcs,
1397 components,
1398 da,
1399 MOD_POST_AUTH)) {
1400 goto error; /* FIXME: memleak? */
1401 }
1402
1403 subcs = cf_section_sub_find_name2(cs, "cache", "clear");
1404 if (subcs && !load_subcomponent_section(subcs,
1405 components,
1406 da,
1407 MOD_POST_AUTH)) {
1408 goto error; /* FIXME: memleak? */
1409 }
1410
1411 subcs = cf_section_sub_find_name2(cs, "cache", "refresh");
1412 if (subcs && !load_subcomponent_section(subcs,
1413 components,
1414 da,
1415 MOD_POST_AUTH)) {
1416 goto error; /* FIXME: memleak? */
1417 }
1418 #endif
1419
1420 #ifdef WITH_DHCP
1421 /*
1422 * It's OK to not have DHCP.
1423 */
1424 subcs = cf_subsection_find_next(cs, NULL, "dhcp");
1425 if (!subcs) break;
1426
1427 da = dict_attrbyname("DHCP-Message-Type");
1428
1429 /*
1430 * Handle each DHCP Message type separately.
1431 */
1432 while (subcs) {
1433 char const *name2 = cf_section_name2(subcs);
1434
1435 if (name2) {
1436 cf_log_module(cs, "Loading dhcp %s {...}", name2);
1437 } else {
1438 cf_log_module(cs, "Loading dhcp {...}");
1439 }
1440 if (!load_subcomponent_section(subcs,
1441 components,
1442 da,
1443 MOD_POST_AUTH)) {
1444 goto error; /* FIXME: memleak? */
1445 }
1446 c = lookup_by_index(components,
1447 MOD_POST_AUTH, 0);
1448 if (c) server->mc[MOD_POST_AUTH] = c->modulelist;
1449
1450 subcs = cf_subsection_find_next(cs, subcs, "dhcp");
1451 }
1452 #endif
1453
1454
1455 } while (0);
1456
1457 if (name) {
1458 cf_log_info(cs, "} # server %s", name);
1459 } else {
1460 cf_log_info(cs, "} # server");
1461 }
1462
1463 if (rad_debug_lvl == 0) {
1464 INFO("Loaded virtual server %s",
1465 (name != NULL) ? name : "<default>");
1466 }
1467
1468 /*
1469 * Now that it is OK, insert it into the list.
1470 *
1471 * This is thread-safe...
1472 */
1473 comp = virtual_server_idx(name);
1474 server->next = virtual_servers[comp];
1475 virtual_servers[comp] = server;
1476
1477 /*
1478 * Mark OLDER ones of the same name as being unused.
1479 */
1480 server = server->next;
1481 while (server) {
1482 if ((!name && !server->name) ||
1483 (name && server->name &&
1484 (strcmp(server->name, name) == 0))) {
1485 server->can_free = true;
1486 break;
1487 }
1488 server = server->next;
1489 }
1490
1491 return 0;
1492 }
1493
1494
pass2_cb(UNUSED void * ctx,void * data)1495 static int pass2_cb(UNUSED void *ctx, void *data)
1496 {
1497 indexed_modcallable *this = data;
1498
1499 if (!modcall_pass2(this->modulelist)) return -1;
1500
1501 return 0;
1502 }
1503
1504
1505 /*
1506 * Load all of the virtual servers.
1507 */
virtual_servers_load(CONF_SECTION * config)1508 int virtual_servers_load(CONF_SECTION *config)
1509 {
1510 CONF_SECTION *cs;
1511 virtual_server_t *server;
1512 static bool first_time = true;
1513
1514 DEBUG2("%s: #### Loading Virtual Servers ####", main_config.name);
1515
1516 /*
1517 * If we have "server { ...}", then there SHOULD NOT be
1518 * bare "authorize", etc. sections. if there is no such
1519 * server, then try to load the old-style sections first.
1520 *
1521 * In either case, load the "default" virtual server first.
1522 * this matches better with users expectations.
1523 */
1524 cs = cf_section_find_name2(cf_subsection_find_next(config, NULL,
1525 "server"),
1526 "server", NULL);
1527 if (cs) {
1528 if (load_byserver(cs) < 0) {
1529 return -1;
1530 }
1531 } else {
1532 if (load_byserver(config) < 0) {
1533 return -1;
1534 }
1535 }
1536
1537 /*
1538 * Load all of the virtual servers.
1539 */
1540 for (cs = cf_subsection_find_next(config, NULL, "server");
1541 cs != NULL;
1542 cs = cf_subsection_find_next(config, cs, "server")) {
1543 char const *name2;
1544
1545 name2 = cf_section_name2(cs);
1546 if (!name2) continue; /* handled above */
1547
1548 server = virtual_server_find(name2);
1549 if (server &&
1550 (cf_top_section(server->cs) == config)) {
1551 ERROR("Duplicate virtual server \"%s\" in file %s:%d and file %s:%d",
1552 server->name,
1553 cf_section_filename(server->cs),
1554 cf_section_lineno(server->cs),
1555 cf_section_filename(cs),
1556 cf_section_lineno(cs));
1557 return -1;
1558 }
1559
1560 if (load_byserver(cs) < 0) {
1561 /*
1562 * Once we successfully started once,
1563 * continue loading the OTHER servers,
1564 * even if one fails.
1565 */
1566 if (!first_time) continue;
1567 return -1;
1568 }
1569 }
1570
1571 /*
1572 * Try to compile the "authorize", etc. sections which
1573 * aren't in a virtual server.
1574 */
1575 server = virtual_server_find(NULL);
1576 if (server) {
1577 int i;
1578
1579 for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
1580 if (!modcall_pass2(server->mc[i])) return -1;
1581 }
1582
1583 if (server->components &&
1584 (rbtree_walk(server->components, RBTREE_IN_ORDER,
1585 pass2_cb, NULL) != 0)) {
1586 return -1;
1587 }
1588 }
1589
1590 /*
1591 * Now that we've loaded everything, run pass 2 over the
1592 * conditions and xlats.
1593 */
1594 for (cs = cf_subsection_find_next(config, NULL, "server");
1595 cs != NULL;
1596 cs = cf_subsection_find_next(config, cs, "server")) {
1597 int i;
1598 char const *name2;
1599
1600 name2 = cf_section_name2(cs);
1601
1602 server = virtual_server_find(name2);
1603 if (!server) continue;
1604
1605 for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
1606 if (!modcall_pass2(server->mc[i])) return -1;
1607 }
1608
1609 if (server->components &&
1610 (rbtree_walk(server->components, RBTREE_IN_ORDER,
1611 pass2_cb, NULL) != 0)) {
1612 return -1;
1613 }
1614 }
1615
1616 /*
1617 * If we succeed the first time around, remember that.
1618 */
1619 first_time = false;
1620
1621 return 0;
1622 }
1623
module_hup_module(CONF_SECTION * cs,module_instance_t * node,time_t when)1624 int module_hup_module(CONF_SECTION *cs, module_instance_t *node, time_t when)
1625 {
1626 void *insthandle;
1627 fr_module_hup_t *mh;
1628
1629 if (!node ||
1630 node->entry->module->bootstrap ||
1631 !node->entry->module->instantiate ||
1632 ((node->entry->module->type & RLM_TYPE_HUP_SAFE) == 0)) {
1633 return 1;
1634 }
1635
1636 /*
1637 * Silently ignore multiple HUPs within a short time period.
1638 */
1639 if ((node->last_hup + 2) >= when) return 1;
1640 node->last_hup = when;
1641
1642 cf_log_module(cs, "Trying to reload module \"%s\"", node->name);
1643
1644 /*
1645 * Parse the module configuration, and setup destructors so the
1646 * module's detach method is called when it's instance data is
1647 * about to be freed.
1648 */
1649 if (module_conf_parse(node, &insthandle) < 0) {
1650 cf_log_err_cs(cs, "HUP failed for module \"%s\" (parsing config failed). "
1651 "Using old configuration", node->name);
1652
1653 return 0;
1654 }
1655
1656 if ((node->entry->module->instantiate)(cs, insthandle) < 0) {
1657 cf_log_err_cs(cs, "HUP failed for module \"%s\". Using old configuration.", node->name);
1658 talloc_free(insthandle);
1659
1660 return 0;
1661 }
1662
1663 INFO(" Module: Reloaded module \"%s\"", node->name);
1664
1665 module_instance_free_old(cs, node, when);
1666
1667 /*
1668 * Save the old instance handle for later deletion.
1669 */
1670 mh = talloc_zero(cs, fr_module_hup_t);
1671 mh->mi = node;
1672 mh->when = when;
1673 mh->insthandle = node->insthandle;
1674 mh->next = node->mh;
1675 node->mh = mh;
1676
1677 /*
1678 * Replace the instance handle while the module is running.
1679 */
1680 node->insthandle = insthandle;
1681
1682 /*
1683 * FIXME: Set a timeout to come back in 60s, so that
1684 * we can pro-actively clean up the old instances.
1685 */
1686
1687 return 1;
1688 }
1689
1690
modules_hup(CONF_SECTION * modules)1691 int modules_hup(CONF_SECTION *modules)
1692 {
1693 time_t when;
1694 CONF_ITEM *ci;
1695 CONF_SECTION *cs;
1696 module_instance_t *node;
1697
1698 if (!modules) return 0;
1699
1700 when = time(NULL);
1701
1702 /*
1703 * Loop over the modules
1704 */
1705 for (ci=cf_item_find_next(modules, NULL);
1706 ci != NULL;
1707 ci=cf_item_find_next(modules, ci)) {
1708 char const *instname;
1709 module_instance_t myNode;
1710
1711 /*
1712 * If it's not a section, ignore it.
1713 */
1714 if (!cf_item_is_section(ci)) continue;
1715
1716 cs = cf_item_to_section(ci);
1717 instname = cf_section_name2(cs);
1718 if (!instname) instname = cf_section_name1(cs);
1719
1720 strlcpy(myNode.name, instname, sizeof(myNode.name));
1721 node = rbtree_finddata(instance_tree, &myNode);
1722
1723 module_hup_module(cs, node, when);
1724 }
1725
1726 return 1;
1727 }
1728
1729
define_type(CONF_SECTION * cs,DICT_ATTR const * da,char const * name)1730 static int define_type(CONF_SECTION *cs, DICT_ATTR const *da, char const *name)
1731 {
1732 uint32_t value;
1733 DICT_VALUE *dval;
1734
1735 /*
1736 * Allow for conditionally loaded types
1737 */
1738 if (*name == '-') name++;
1739
1740 /*
1741 * If the value already exists, don't
1742 * create it again.
1743 */
1744 dval = dict_valbyname(da->attr, da->vendor, name);
1745 if (dval) {
1746 if (dval->value == 0) {
1747 ERROR("The dictionaries must not define VALUE %s %s 0",
1748 da->name, name);
1749 return 0;
1750 }
1751 return 1;
1752 }
1753
1754 /*
1755 * Create a new unique value with a
1756 * meaningless number. You can't look at
1757 * it from outside of this code, so it
1758 * doesn't matter. The only requirement
1759 * is that it's unique.
1760 */
1761 do {
1762 value = (fr_rand() & 0x00ffffff) + 1;
1763 } while (dict_valbyattr(da->attr, da->vendor, value));
1764
1765 cf_log_module(cs, "Creating %s = %s", da->name, name);
1766 if (dict_addvalue(name, da->name, value) < 0) {
1767 ERROR("%s", fr_strerror());
1768 return 0;
1769 }
1770
1771 return 1;
1772 }
1773
1774 /*
1775 * Define Auth-Type, etc. in a server.
1776 */
server_define_types(CONF_SECTION * cs)1777 static bool server_define_types(CONF_SECTION *cs)
1778 {
1779 rlm_components_t comp;
1780
1781 /*
1782 * Loop over all of the components
1783 */
1784 for (comp = 0; comp < MOD_COUNT; ++comp) {
1785 CONF_SECTION *subcs, *type_cs;
1786 DICT_ATTR const *da;
1787
1788 subcs = cf_section_sub_find(cs,
1789 section_type_value[comp].section);
1790 if (!subcs) continue;
1791
1792 if (cf_item_find_next(subcs, NULL) == NULL) continue;
1793
1794 /*
1795 * Find the attribute used to store VALUEs for this section.
1796 */
1797 da = dict_attrbyvalue(section_type_value[comp].attr, 0);
1798 if (!da) {
1799 cf_log_err_cs(subcs,
1800 "No such attribute %s",
1801 section_type_value[comp].typename);
1802 return false;
1803 }
1804
1805 /*
1806 * Define dynamic types, so that others can reference
1807 * them.
1808 *
1809 * First, bare modules for 'authenticate'.
1810 * Second, Auth-Type, etc.
1811 */
1812 if (section_type_value[comp].attr == PW_AUTH_TYPE) {
1813 CONF_ITEM *modref;
1814
1815 for (modref = cf_item_find_next(subcs, NULL);
1816 modref != NULL;
1817 modref = cf_item_find_next(subcs, modref)) {
1818 CONF_PAIR *cp;
1819
1820 if (!cf_item_is_pair(modref)) continue;
1821
1822 cp = cf_item_to_pair(modref);
1823 if (!define_type(cs, da, cf_pair_attr(cp))) {
1824 return false;
1825 }
1826
1827 /*
1828 * Check for duplicates
1829 */
1830 if (rad_debug_lvl) {
1831 CONF_PAIR *cp2;
1832 CONF_SECTION *cs2;
1833
1834 cp2 = cf_pair_find(subcs, cf_pair_attr(cp));
1835 rad_assert(cp2 != NULL);
1836 if (cp2 != cp) {
1837 WARN("%s[%d]: Duplicate module '%s'",
1838 cf_pair_filename(cp2),
1839 cf_pair_lineno(cp2),
1840 cf_pair_attr(cp));
1841 }
1842
1843 cs2 = cf_section_sub_find_name2(subcs, section_type_value[comp].typename, cf_pair_attr(cp));
1844 if (cs2) {
1845 WARN("%s[%d]: Duplicate Auth-Type '%s'",
1846 cf_section_filename(cs2),
1847 cf_section_lineno(cs2),
1848 cf_pair_attr(cp));
1849 }
1850 }
1851
1852 }
1853 }
1854
1855 /*
1856 * And loop over the type names
1857 */
1858 for (type_cs = cf_subsection_find_next(subcs, NULL, section_type_value[comp].typename);
1859 type_cs != NULL;
1860 type_cs = cf_subsection_find_next(subcs, type_cs, section_type_value[comp].typename)) {
1861 if (!define_type(cs, da, cf_section_name2(type_cs))) {
1862 return false;
1863 }
1864
1865 if (rad_debug_lvl) {
1866 CONF_SECTION *cs2;
1867
1868 cs2 = cf_section_sub_find_name2(subcs, section_type_value[comp].typename, cf_section_name2(type_cs));
1869 rad_assert(cs2 != NULL);
1870 if (cs2 != type_cs) {
1871 WARN("%s[%d]: Duplicate Auth-Type '%s'",
1872 cf_section_filename(cs2),
1873 cf_section_lineno(cs2),
1874 cf_section_name2(cs2));
1875 }
1876 }
1877 }
1878 } /* loop over components */
1879
1880 return true;
1881 }
1882
1883 extern char const *unlang_keyword[];
1884
is_reserved_word(const char * name)1885 static bool is_reserved_word(const char *name)
1886 {
1887 int i;
1888
1889 if (!name || !*name) return false;
1890
1891 for (i = 1; unlang_keyword[i] != NULL; i++) {
1892 if (strcmp(name, unlang_keyword[i]) == 0) return true;
1893 }
1894
1895 return false;
1896 }
1897
1898
1899 /*
1900 * Parse the module config sections, and load
1901 * and call each module's init() function.
1902 */
modules_init(CONF_SECTION * config)1903 int modules_init(CONF_SECTION *config)
1904 {
1905 CONF_ITEM *ci, *next;
1906 CONF_SECTION *cs, *modules;
1907
1908 /*
1909 * Set up the internal module struct.
1910 */
1911 module_tree = rbtree_create(NULL, module_entry_cmp, NULL, 0);
1912 if (!module_tree) {
1913 ERROR("Failed to initialize modules\n");
1914 return -1;
1915 }
1916
1917 instance_tree = rbtree_create(NULL, module_instance_cmp,
1918 module_instance_free, 0);
1919 if (!instance_tree) {
1920 ERROR("Failed to initialize modules\n");
1921 return -1;
1922 }
1923
1924 memset(virtual_servers, 0, sizeof(virtual_servers));
1925
1926 /*
1927 * Remember where the modules were stored.
1928 */
1929 modules = cf_section_sub_find(config, "modules");
1930 if (!modules) {
1931 WARN("Cannot find a \"modules\" section in the configuration file!");
1932 }
1933
1934 /*
1935 * Load dictionaries.
1936 */
1937 for (cs = cf_subsection_find_next(config, NULL, "server");
1938 cs != NULL;
1939 cs = cf_subsection_find_next(config, cs, "server")) {
1940 #if defined(WITH_DHCP) || defined(WITH_VMPS)
1941 CONF_SECTION *subcs;
1942 DICT_ATTR const *da;
1943 #endif
1944
1945 #ifdef WITH_VMPS
1946 /*
1947 * Auto-load the VMPS/VQP dictionary.
1948 */
1949 subcs = cf_section_sub_find(cs, "vmps");
1950 if (subcs) {
1951 da = dict_attrbyname("VQP-Packet-Type");
1952 if (!da) {
1953 if (dict_read(main_config.dictionary_dir, "dictionary.vqp") < 0) {
1954 ERROR("Failed reading dictionary.vqp: %s",
1955 fr_strerror());
1956 return -1;
1957 }
1958 cf_log_module(cs, "Loading dictionary.vqp");
1959
1960 da = dict_attrbyname("VQP-Packet-Type");
1961 if (!da) {
1962 ERROR("No VQP-Packet-Type in dictionary.vqp");
1963 return -1;
1964 }
1965 }
1966 }
1967 #endif
1968
1969 #ifdef WITH_DHCP
1970 /*
1971 * Auto-load the DHCP dictionary.
1972 */
1973 subcs = cf_subsection_find_next(cs, NULL, "dhcp");
1974 if (subcs) {
1975 da = dict_attrbyname("DHCP-Message-Type");
1976 if (!da) {
1977 cf_log_module(cs, "Loading dictionary.dhcp");
1978 if (dict_read(main_config.dictionary_dir, "dictionary.dhcp") < 0) {
1979 ERROR("Failed reading dictionary.dhcp: %s",
1980 fr_strerror());
1981 return -1;
1982 }
1983
1984 da = dict_attrbyname("DHCP-Message-Type");
1985 if (!da) {
1986 ERROR("No DHCP-Message-Type in dictionary.dhcp");
1987 return -1;
1988 }
1989 }
1990 }
1991 #endif
1992 /*
1993 * Else it's a RADIUS virtual server, and the
1994 * dictionaries are already loaded.
1995 */
1996
1997 /*
1998 * Root through each virtual server, defining
1999 * Autz-Type and Auth-Type. This is so that the
2000 * modules can reference a particular type.
2001 */
2002 if (!server_define_types(cs)) return -1;
2003 }
2004
2005 DEBUG2("%s: #### Instantiating modules ####", main_config.name);
2006
2007 cf_log_info(config, " modules {");
2008
2009 /*
2010 * Loop over module definitions, looking for duplicates.
2011 *
2012 * This is O(N^2) in the number of modules, but most
2013 * systems should have less than 100 modules.
2014 */
2015 for (ci = cf_item_find_next(modules, NULL);
2016 ci != NULL;
2017 ci = next) {
2018 char const *name1;
2019 CONF_SECTION *subcs;
2020 module_instance_t *node;
2021
2022 next = cf_item_find_next(modules, ci);
2023
2024 if (!cf_item_is_section(ci)) continue;
2025
2026 subcs = cf_item_to_section(ci);
2027
2028 node = module_bootstrap(subcs);
2029 if (!node) return -1;
2030
2031 if (!next || !cf_item_is_section(next)) continue;
2032
2033 name1 = cf_section_name1(subcs);
2034
2035 if (is_reserved_word(name1)) {
2036 cf_log_err_cs(subcs, "Module cannot be named for an 'unlang' keyword");
2037 return -1;
2038 }
2039 }
2040
2041 /*
2042 * Look for the 'instantiate' section, which tells us
2043 * the instantiation order of the modules, and also allows
2044 * us to load modules with no authorize/authenticate/etc.
2045 * sections.
2046 */
2047 cs = cf_section_sub_find(config, "instantiate");
2048 if (cs) {
2049 CONF_PAIR *cp;
2050 module_instance_t *module;
2051 char const *name;
2052
2053 cf_log_info(cs, " instantiate {");
2054
2055 /*
2056 * Loop over the items in the 'instantiate' section.
2057 */
2058 for (ci=cf_item_find_next(cs, NULL);
2059 ci != NULL;
2060 ci=cf_item_find_next(cs, ci)) {
2061 /*
2062 * Skip sections and "other" stuff.
2063 * Sections will be handled later, if
2064 * they're referenced at all...
2065 */
2066 if (cf_item_is_pair(ci)) {
2067 cp = cf_item_to_pair(ci);
2068 name = cf_pair_attr(cp);
2069
2070 module = module_instantiate(modules, name);
2071 if (!module && (name[0] != '-')) {
2072 return -1;
2073 }
2074 }
2075
2076 /*
2077 * Can only be "redundant" or
2078 * "load-balance" or
2079 * "redundant-load-balance"
2080 */
2081 if (cf_item_is_section(ci)) {
2082 bool all_same = true;
2083 module_t const *last = NULL;
2084 CONF_SECTION *subcs;
2085 CONF_ITEM *subci;
2086
2087 subcs = cf_item_to_section(ci);
2088 name = cf_section_name1(subcs);
2089
2090 /*
2091 * Groups, etc. must have a name.
2092 */
2093 if (((strcmp(name, "group") == 0) ||
2094 (strcmp(name, "redundant") == 0) ||
2095 (strcmp(name, "redundant-load-balance") == 0) ||
2096 strcmp(name, "load-balance") == 0)) {
2097 name = cf_section_name2(subcs);
2098 if (!name) {
2099 cf_log_err_cs(subcs, "Subsection must have a name");
2100 return -1;
2101 }
2102
2103 if (is_reserved_word(name)) {
2104 cf_log_err_cs(subcs, "Instantiate sections cannot be named for an 'unlang' keyword");
2105 return -1;
2106 }
2107 } else {
2108 if (is_reserved_word(name)) {
2109 cf_log_err_cs(subcs, "Instantiate sections cannot be named for an 'unlang' keyword");
2110 return -1;
2111 }
2112 }
2113
2114 /*
2115 * Ensure that the modules we reference here exist.
2116 */
2117 for (subci=cf_item_find_next(subcs, NULL);
2118 subci != NULL;
2119 subci=cf_item_find_next(subcs, subci)) {
2120 if (cf_item_is_pair(subci)) {
2121 cp = cf_item_to_pair(subci);
2122 if (cf_pair_value(cp)) {
2123 cf_log_err(subci, "Cannot set return codes in a %s block",
2124 cf_section_name1(subcs));
2125 return -1;
2126 }
2127
2128 /*
2129 * Allow "foo.authorize" in subsections.
2130 */
2131 module = module_instantiate_method(modules, cf_pair_attr(cp), NULL);
2132 if (!module) {
2133 return -1;
2134 }
2135
2136 if (all_same) {
2137 if (!last) {
2138 last = module->entry->module;
2139 } else if (last != module->entry->module) {
2140 last = NULL;
2141 all_same = false;
2142 }
2143 }
2144 } else {
2145 all_same = false;
2146 }
2147
2148 /*
2149 * Don't check subsections for now.
2150 */
2151 } /* loop over modules in a "redundant foo" section */
2152
2153 /*
2154 * Register a redundant xlat
2155 */
2156 if (all_same) {
2157 if (!xlat_register_redundant(cf_item_to_section(ci))) {
2158 WARN("%s[%d] Not registering expansions for %s",
2159 cf_section_filename(subcs), cf_section_lineno(subcs),
2160 cf_section_name2(subcs));
2161 }
2162 }
2163 } /* handle subsections */
2164 } /* loop over the "instantiate" section */
2165
2166 cf_log_info(cs, " }");
2167 } /* if there's an 'instantiate' section. */
2168
2169 /*
2170 * Now that we've loaded the explicitly ordered modules,
2171 * load everything in the "modules" section. This is
2172 * because we've now split up the modules into
2173 * mods-enabled.
2174 */
2175 for (ci=cf_item_find_next(modules, NULL);
2176 ci != NULL;
2177 ci=next) {
2178 char const *name;
2179 module_instance_t *module;
2180 CONF_SECTION *subcs;
2181
2182 next = cf_item_find_next(modules, ci);
2183
2184 if (!cf_item_is_section(ci)) continue;
2185
2186 subcs = cf_item_to_section(ci);
2187 name = cf_section_name2(subcs);
2188 if (!name) name = cf_section_name1(subcs);
2189
2190 module = module_instantiate(modules, name);
2191 if (!module) return -1;
2192 }
2193 cf_log_info(config, " } # modules");
2194
2195 if (virtual_servers_load(config) < 0) return -1;
2196
2197 return 0;
2198 }
2199
2200 /*
2201 * Call all authorization modules until one returns
2202 * somethings else than RLM_MODULE_OK
2203 */
process_authorize(int autz_type,REQUEST * request)2204 rlm_rcode_t process_authorize(int autz_type, REQUEST *request)
2205 {
2206 return indexed_modcall(MOD_AUTHORIZE, autz_type, request);
2207 }
2208
2209 /*
2210 * Authenticate a user/password with various methods.
2211 */
process_authenticate(int auth_type,REQUEST * request)2212 rlm_rcode_t process_authenticate(int auth_type, REQUEST *request)
2213 {
2214 return indexed_modcall(MOD_AUTHENTICATE, auth_type, request);
2215 }
2216
2217 #ifdef WITH_ACCOUNTING
2218 /*
2219 * Do pre-accounting for ALL configured sessions
2220 */
module_preacct(REQUEST * request)2221 rlm_rcode_t module_preacct(REQUEST *request)
2222 {
2223 return indexed_modcall(MOD_PREACCT, 0, request);
2224 }
2225
2226 /*
2227 * Do accounting for ALL configured sessions
2228 */
process_accounting(int acct_type,REQUEST * request)2229 rlm_rcode_t process_accounting(int acct_type, REQUEST *request)
2230 {
2231 return indexed_modcall(MOD_ACCOUNTING, acct_type, request);
2232 }
2233 #endif
2234
2235 #ifdef WITH_SESSION_MGMT
2236 /*
2237 * See if a user is already logged in.
2238 *
2239 * Returns: 0 == OK, 1 == double logins, 2 == multilink attempt
2240 */
process_checksimul(int sess_type,REQUEST * request,int maxsimul)2241 int process_checksimul(int sess_type, REQUEST *request, int maxsimul)
2242 {
2243 rlm_rcode_t rcode;
2244
2245 if(!request->username)
2246 return 0;
2247
2248 request->simul_count = 0;
2249 request->simul_max = maxsimul;
2250 request->simul_mpp = 1;
2251
2252 rcode = indexed_modcall(MOD_SESSION, sess_type, request);
2253
2254 if (rcode != RLM_MODULE_OK) {
2255 /* FIXME: Good spot for a *rate-limited* warning to the log */
2256 return 0;
2257 }
2258
2259 return (request->simul_count < maxsimul) ? 0 : request->simul_mpp;
2260 }
2261 #endif
2262
2263 #ifdef WITH_PROXY
2264 /*
2265 * Do pre-proxying for ALL configured sessions
2266 */
process_pre_proxy(int type,REQUEST * request)2267 rlm_rcode_t process_pre_proxy(int type, REQUEST *request)
2268 {
2269 return indexed_modcall(MOD_PRE_PROXY, type, request);
2270 }
2271
2272 /*
2273 * Do post-proxying for ALL configured sessions
2274 */
process_post_proxy(int type,REQUEST * request)2275 rlm_rcode_t process_post_proxy(int type, REQUEST *request)
2276 {
2277 return indexed_modcall(MOD_POST_PROXY, type, request);
2278 }
2279 #endif
2280
2281 /*
2282 * Do post-authentication for ALL configured sessions
2283 */
process_post_auth(int postauth_type,REQUEST * request)2284 rlm_rcode_t process_post_auth(int postauth_type, REQUEST *request)
2285 {
2286 return indexed_modcall(MOD_POST_AUTH, postauth_type, request);
2287 }
2288
2289 #ifdef WITH_COA
process_recv_coa(int recv_coa_type,REQUEST * request)2290 rlm_rcode_t process_recv_coa(int recv_coa_type, REQUEST *request)
2291 {
2292 return indexed_modcall(MOD_RECV_COA, recv_coa_type, request);
2293 }
2294
process_send_coa(int send_coa_type,REQUEST * request)2295 rlm_rcode_t process_send_coa(int send_coa_type, REQUEST *request)
2296 {
2297 return indexed_modcall(MOD_SEND_COA, send_coa_type, request);
2298 }
2299 #endif
2300