The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
module_rlm.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 763f3f006a1b6f4994243b58e625e687f5c1a029 $
19 *
20 * @file src/lib/server/module_rlm.c
21 * @brief Defines functions for rlm module (re-)initialisation.
22 *
23 * @copyright 2003,2006,2016 The FreeRADIUS server project
24 * @copyright 2016,2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 * @copyright 2000 Alan DeKok (aland@freeradius.org)
26 * @copyright 2000 Alan Curry (pacman@world.std.com)
27 */
28
29RCSID("$Id: 763f3f006a1b6f4994243b58e625e687f5c1a029 $")
30
31#include <freeradius-devel/server/cf_file.h>
32
33#include <freeradius-devel/server/global_lib.h>
34#include <freeradius-devel/server/modpriv.h>
35#include <freeradius-devel/server/module_rlm.h>
36#include <freeradius-devel/server/pair.h>
37
38#include <freeradius-devel/util/atexit.h>
39
40#include <freeradius-devel/unlang/compile.h>
41
42#include <freeradius-devel/unlang/xlat_func.h>
43#include <freeradius-devel/unlang/xlat_redundant.h>
44
45
46/** Lookup virtual module by name
47 */
49
50typedef struct {
51 fr_rb_node_t name_node; //!< Entry in the name tree.
52 char const *name; //!< module name
53 CONF_SECTION *cs; //!< CONF_SECTION where it is defined
54 module_instance_t *mi; //!< module instance
55 fr_dict_t const *dict; //!< dict / namespace we expect to use.
56 bool xlat_redundant; //!< whether we might need it
58
59/** Compare virtual modules by name
60 */
61static fr_cmp_ret_t module_rlm_virtual_name_cmp(void const *one, void const *two)
62{
63 module_rlm_virtual_t const *a = one;
64 module_rlm_virtual_t const *b = two;
65 int ret;
66
67 ret = strcmp(a->name, b->name);
68 return CMP(ret, 0);
69}
70
71/** Global module list for all backend modules
72 *
73 */
75
76/** Runtime instantiated list
77 *
78 */
80
81/** Print information on all loaded modules
82 *
83 */
88
89/** Initialise a module specific exfile handle
90 *
91 * @see exfile_init
92 *
93 * @param[in] ctx to bind the lifetime of the exfile handle to.
94 * @param[in] module section.
95 * @param[in] max_entries Max file descriptors to cache, and manage locks for.
96 * @param[in] max_idle Maximum time a file descriptor can be idle before it's closed.
97 * @param[in] locking Whether or not to lock the files.
98 * @param[in] triggers Should triggers be enabled.
99 * @param[in] trigger_prefix if NULL will be set automatically from the module CONF_SECTION.
100 * @param[in] trigger_args to make available in any triggers executed by the connection pool.
101 * @return
102 * - New connection pool.
103 * - NULL on error.
104 */
106 CONF_SECTION *module,
107 uint32_t max_entries,
108 fr_time_delta_t max_idle,
109 bool locking,
110 bool triggers,
111 char const *trigger_prefix,
112 fr_pair_list_t *trigger_args)
113{
114 char trigger_prefix_buff[128];
115 bool prefix_set = trigger_prefix ? true : false;
116 exfile_t *handle;
117
118 if (!trigger_prefix) {
119 snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.file", cf_section_name1(module));
120 trigger_prefix = trigger_prefix_buff;
121 }
122
123 handle = exfile_init(ctx, max_entries, max_idle, locking);
124 if (!handle) return NULL;
125
126 if (triggers) exfile_enable_triggers(handle, prefix_set ? module : cf_section_find(module, "file", NULL),
127 trigger_prefix, trigger_args);
128
129 return handle;
130}
131
132/** Resolve polymorphic item's from a module's #CONF_SECTION to a subsection in another module
133 *
134 * This allows certain module sections to reference module sections in other instances
135 * of the same module and share #CONF_DATA associated with them.
136 *
137 * @verbatim
138 example {
139 data {
140 ...
141 }
142 }
143
144 example inst {
145 data = example
146 }
147 * @endverbatim
148 *
149 * @param[out] out where to write the pointer to a module's config section. May be NULL on success,
150 * indicating the config item was not found within the module #CONF_SECTION
151 * or the chain of module references was followed and the module at the end of the chain
152 * did not a subsection.
153 * @param[in] module #CONF_SECTION.
154 * @param[in] name of the polymorphic sub-section.
155 * @return
156 * - 0 on success with referenced section.
157 * - 1 on success with local section.
158 * - -1 on failure.
159 */
161{
162 CONF_PAIR *cp;
163 CONF_SECTION *cs;
164 CONF_DATA const *cd;
165
166
168 char const *inst_name;
169
170#define FIND_SIBLING_CF_KEY "find_sibling"
171
172 *out = NULL;
173
174 /*
175 * Is a real section (not referencing sibling module).
176 */
177 cs = cf_section_find(module, name, NULL);
178 if (cs) {
179 *out = cs;
180 return 0;
181 }
182
183 /*
184 * Item omitted completely from module config.
185 */
186 cp = cf_pair_find(module, name);
187 if (!cp) return 0;
188
190 cf_log_err(cp, "Module reference loop found");
191 return -1;
192 }
193 cd = cf_data_add(module, module, FIND_SIBLING_CF_KEY, false);
194
195 /*
196 * Item found, resolve it to a module instance.
197 * This triggers module loading, so we don't have
198 * instantiation order issues.
199 */
200 inst_name = cf_pair_value(cp);
201 mi = module_instance_by_name(rlm_modules_static, NULL, inst_name);
202 if (!mi) {
203 cf_log_err(cp, "Unknown module instance \"%s\"", inst_name);
204 error:
205 cf_data_remove_by_data(module, cd);
206 return -1;
207 }
208
209 if ((mi->state != MODULE_INSTANCE_INSTANTIATED) &&
211 goto error;
212 }
213
214 /*
215 * Remove the config data we added for loop
216 * detection.
217 */
218 cf_data_remove_by_data(module, cd);
219
220 /*
221 * Check the module instances are of the same type.
222 */
223 if (strcmp(cf_section_name1(mi->conf), cf_section_name1(module)) != 0) {
224 cf_log_err(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
226 return -1;
227 }
228
229 *out = cf_section_find(mi->conf, name, NULL);
230
231 return 1;
232}
233
235 char const *name, xlat_func_t func, fr_type_t return_type)
236{
237 module_instance_t *mi = mctx->mi;
238 module_rlm_instance_t *mri = talloc_get_type_abort(mi->uctx, module_rlm_instance_t);
240 xlat_t *x;
241 char inst_name[256];
242
243 fr_assert_msg(name != mctx->mi->name, "`name` must not be the same as the module "
244 "instance name. Pass a NULL `name` arg if this is required");
245
246 if (!name) {
247 name = mctx->mi->name;
248 } else {
249 if ((size_t)snprintf(inst_name, sizeof(inst_name), "%s.%s", mctx->mi->name, name) >= sizeof(inst_name)) {
250 ERROR("%s: Instance name too long", __FUNCTION__);
251 return NULL;
252 }
253 name = inst_name;
254 }
255
256 x = xlat_func_register(ctx, name, func, return_type);
257 if (unlikely(x == NULL)) return NULL;
258
259 xlat_mctx_set(x, mctx);
260
261 MEM(mrx = talloc(mi, module_rlm_xlat_t));
262 mrx->xlat = x;
263 mrx->mi = mi;
264
265 fr_dlist_insert_tail(&mri->xlats, mrx);
266
267 return x;
268}
269
270/** Initialise a module specific connection pool
271 *
272 * @see fr_pool_init
273 *
274 * @param[in] module section.
275 * @param[in] opaque data pointer to pass to callbacks.
276 * @param[in] c Callback to create new connections.
277 * @param[in] a Callback to check the status of connections.
278 * @param[in] log_prefix override, if NULL will be set automatically from the module CONF_SECTION.
279 * @param[in] trigger_prefix if NULL will be set automatically from the module CONF_SECTION.
280 * @param[in] trigger_args to make available in any triggers executed by the connection pool.
281 * @return
282 * - New connection pool.
283 * - NULL on error.
284 */
286 void *opaque,
289 char const *log_prefix,
290 char const *trigger_prefix,
291 fr_pair_list_t *trigger_args)
292{
293 CONF_SECTION *cs, *mycs;
294 char log_prefix_buff[128];
295 char trigger_prefix_buff[128];
296
297 fr_pool_t *pool;
298 char const *mod_name1, *mod_name2;
299
300 int ret;
301
302#define parent_name(_x) cf_section_name(cf_item_to_section(cf_parent(_x)))
303
304 mod_name1 = cf_section_name1(module);
305 mod_name2 = cf_section_name2(module);
306 if (!mod_name2) mod_name2 = mod_name1;
307
308 if (!trigger_prefix) {
309 snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.pool", mod_name1);
310 trigger_prefix = trigger_prefix_buff;
311 }
312
313 if (!log_prefix) {
314 snprintf(log_prefix_buff, sizeof(log_prefix_buff), "rlm_%s (%s)", mod_name1, mod_name2);
315 log_prefix = log_prefix_buff;
316 }
317
318 /*
319 * Get sibling's pool config section
320 */
321 ret = module_rlm_sibling_section_find(&cs, module, "pool");
322 switch (ret) {
323 case -1:
324 return NULL;
325
326 case 1:
327 DEBUG4("%s: Using pool section from \"%s\"", log_prefix, parent_name(cs));
328 break;
329
330 case 0:
331 DEBUG4("%s: Using local pool section", log_prefix);
332 break;
333 }
334
335 /*
336 * Get our pool config section
337 */
338 mycs = cf_section_find(module, "pool", NULL);
339 if (!mycs) {
340 DEBUG4("%s: Adding pool section to module configuration \"%s\" to store pool references", log_prefix,
341 mod_name2);
342
343 mycs = cf_section_alloc(module, module, "pool", NULL);
344 if (!mycs) return NULL;
345 }
346
347 /*
348 * Sibling didn't have a pool config section
349 * Use our own local pool.
350 */
351 if (!cs) {
352 DEBUG4("%s: \"%s.pool\" section not found, using \"%s.pool\"", log_prefix,
353 mod_name1, parent_name(mycs));
354 cs = mycs;
355 }
356
357 /*
358 * If fr_pool_init has already been called
359 * for this config section, reuse the previous instance.
360 *
361 * This allows modules to pass in the config sections
362 * they would like to use the connection pool from.
363 */
364 pool = cf_data_value(cf_data_find(cs, fr_pool_t, NULL));
365 if (!pool) {
366 DEBUG4("%s: No pool reference found for config item \"%s.pool\"", log_prefix, parent_name(cs));
367 pool = fr_pool_init(cs, cs, opaque, c, a, log_prefix);
368 if (!pool) return NULL;
369
370 fr_pool_enable_triggers(pool, trigger_prefix, trigger_args);
371
372 if (fr_pool_start(pool) < 0) {
373 ERROR("%s: Starting initial connections failed", log_prefix);
374 return NULL;
375 }
376
377 DEBUG4("%s: Adding pool reference %p to config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
378 cf_data_add(cs, pool, NULL, false);
379 return pool;
380 }
381 fr_pool_ref(pool);
382
383 DEBUG4("%s: Found pool reference %p in config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
384
385 /*
386 * We're reusing pool data add it to our local config
387 * section. This allows other modules to transitively
388 * reuse a pool through this module.
389 */
390 if (mycs != cs) {
391 DEBUG4("%s: Copying pool reference %p from config item \"%s.pool\" to config item \"%s.pool\"",
392 log_prefix, pool, parent_name(cs), parent_name(mycs));
393 cf_data_add(mycs, pool, NULL, false);
394 }
395
396 return pool;
397}
398
399/** Set the next section type if it's not already set
400 *
401 * @param[in] request The current request.
402 * @param[in] type_da to use. Usually attr_auth_type.
403 * @param[in] enumv Enumeration value of the specified type_da.
404 */
406{
407 fr_pair_t *vp;
408
409 switch (pair_update_control(&vp, type_da)) {
410 case 0:
411 if (unlikely(fr_value_box_copy(vp, &vp->data, enumv->value) < 0)) {
412 fr_strerror_printf("Failed to set control.%pP to %s", vp, enumv->name);
413 return false;
414 }
415 vp->data.enumv = vp->da; /* So we get the correct string alias */
416 RDEBUG2("Setting control.%pP", vp);
417 return true;
418
419 case 1:
420 RDEBUG2("control.%s already set. Not setting to %s", vp->da->name, enumv->name);
421 return false;
422
423 default:
424 return false;
425 }
426}
427
428/** Iterate over an array of named module methods, looking for matches
429 *
430 * @param[in] mmg A structure containing a terminated array of
431 * module method bindings. pre-sorted using #section_name_cmp
432 * with name2 sublists populated.
433 * @param[in] section name1 of the method being called can be one of the following:
434 * - An itenfier.
435 * - CF_IDENT_ANY if the method is a wildcard.
436 * name2 of the method being called can be one of the following:
437 * - An itenfier.
438 * - NULL to match section names with only a name1.
439 * - CF_IDENT_ANY if the method is a wildcard.
440 * @return
441 * - The module_method_name_t on success.
442 * - NULL on not found.
443 */
444static CC_HINT(nonnull)
446{
447 module_method_group_t const *mmg_p = mmg;
449
450 while (mmg_p) {
451 /*
452 * This could potentially be improved by using a binary search
453 * but given the small number of items, reduced branches and
454 * sequential access just scanning the list, it's probably not
455 * worth it.
456 */
457 for (p = mmg_p->bindings; p->section; p++) {
458 switch (section_name_match(p->section, section)) {
459 case 1: /* match */
460 return p;
461
462 case -1: /* name1 didn't match, skip to the end of the sub-list */
463 p = fr_dlist_tail(&p->same_name1);
464 break;
465
466 case 0: /* name1 did match - see if we can find a matching name2 */
467 {
468 fr_dlist_head_t const *same_name1 = &p->same_name1;
469
470 while ((p = fr_dlist_next(same_name1, p))) {
471 if (section_name2_match(p->section, section)) return p;
472 }
473 p = fr_dlist_tail(same_name1);
474 }
475 break;
476 }
477#ifdef __clang_analyzer__
478 /* Will never be NULL, worse case, p doesn't change*/
479 if (!p) break;
480#endif
481 }
482
483 /*
484 * Failed to match, search the next deepest group in the chain.
485 */
486 mmg_p = mmg_p->next;
487 }
488
489 return NULL;
490}
491
492/** Dump the available bindings for the module into the strerror stack
493 *
494 * @note Methods from _all_ linked module method groups will be pushed onto the error stack.
495 *
496 * @param[in] mmg module method group to evaluate.
497 */
499{
500 module_method_group_t const *mmg_p = mmg;
501 module_method_binding_t const *mmb_p;
502 bool first = true;
503
504 while (mmg_p) {
505 mmb_p = mmg_p->bindings;
506
507 if (!mmb_p || !mmb_p[0].section) goto next;
508
509 if (first) {
510 fr_strerror_const_push("Available methods are:");
511 first = false;
512 }
513
514 for (; mmb_p->section; mmb_p++) {
515 char const *name1 = section_name_str(mmb_p->section->name1);
516 char const *name2 = section_name_str(mmb_p->section->name2);
517
518 fr_strerror_printf_push(" %s%s%s",
519 name1, name2 ? "." : "", name2 ? name2 : "");
520 }
521 next:
522 mmg_p = mmg_p->next;
523 }
524
525 if (first) {
526 fr_strerror_const_push("No methods available");
527 }
528}
529
530/** Find an existing module instance and verify it implements the specified method
531 *
532 * Extracts the method from the module name where the format is @verbatim <module>[.<method1>[.<method2>]] @endverbatim
533 * and ensures the module implements the specified method.
534 *
535 * @param[in] ctx to allocate the dynamic module key tmpl from.
536 * @param[out] mmc_out the result from resolving the module method,
537 * plus the key tmpl for dynamic modules.
538 * This is not allocated from the ctx to save the runtime
539 * dereference.
540 * @param[in] vs Virtual server to search for alternative module names in.
541 * @param[in] section Section name containing the module call.
542 * @param[in] name The module method call i.e. module[<key>][.<method>]
543 * @param[in] t_rules for resolving the dynamic module key.
544 * @return
545 * - The module instance on success.
546 * - NULL on not found
547 *
548 * If the module exists but the method doesn't exist, then `method` is set to NULL.
549 */
551 virtual_server_t const *vs, section_name_t const *section, fr_sbuff_t *name,
552 tmpl_rules_t const *t_rules)
553{
554 fr_sbuff_term_t const *dyn_tt = &FR_SBUFF_TERMS(
555 L(""),
556 L("\t"),
557 L("\n"),
558 L(" "),
559 L("[")
560 );
561
562 fr_sbuff_term_t const *elem_tt = &FR_SBUFF_TERMS(
563 L(""),
564 L("\t"),
565 L("\n"),
566 L(" "),
567 L(".")
568 );
569
570 fr_sbuff_t *elem1;
572 module_method_call_t mmc_tmp;
573 module_method_binding_t const *mmb;
574
575 fr_sbuff_marker_t meth_start;
576 bool softfail;
577
578 fr_slen_t slen;
579 size_t len;
580 fr_sbuff_t our_name = FR_SBUFF(name);
581
582 mmc = mmc_out ? mmc_out : &mmc_tmp;
583 if (mmc_out) *mmc_out = (module_method_call_t) {};
584
585 softfail = fr_sbuff_next_if_char(&our_name, '-');
586
587 /*
588 * Advance until the start of the dynamic selector
589 * (if it exists).
590 */
591 if (fr_sbuff_adv_until(&our_name, SIZE_MAX, dyn_tt, '\0') == 0) {
592 fr_strerror_printf("Invalid module method name");
593 return fr_sbuff_error(&our_name);
594 }
595
597
598 /*
599 * If the method string contains a '['
600 *
601 * Search for a dynamic module method, e.g. `elem1[<key>]`.
602 */
603 if (fr_sbuff_is_char(&our_name, '[')) {
604 fr_sbuff_marker_t end, s_end;
605 fr_sbuff_marker(&end, &our_name);
606
607 slen = tmpl_afrom_substr(ctx, &mmc->key, &our_name, T_BARE_WORD, NULL, t_rules);
608 if (slen < 0) {
609 fr_strerror_const_push("Invalid dynamic module selector expression");
610 return slen;
611 }
612
613 if (!fr_sbuff_is_char(&our_name, ']')) {
614 fr_strerror_const_push("Missing terminating ']' for dynamic module selector");
615 error:
616 return fr_sbuff_error(&our_name);
617 }
618 fr_sbuff_marker(&s_end, &our_name);
619
620 fr_sbuff_set_to_start(&our_name);
621 len = fr_sbuff_ahead(&end);
622 if (fr_sbuff_out_bstrncpy(elem1, &our_name, len) < len) {
623 fr_strerror_const("Module method string too long");
624 goto error;
625 }
626 mmc->mi = module_instance_by_name(rlm_modules_dynamic, NULL, elem1->start);
627 if (!mmc->mi) {
628 fr_strerror_printf("No such dynamic module '%s'", elem1->start);
629 goto error;
630 }
632
633 fr_sbuff_set(&our_name, &s_end);
634 fr_sbuff_advance(&our_name, 1); /* Skip the ']' */
635 /*
636 * With elem1.elem2.elem3
637 *
638 * Search for a static module matching one of the following:
639 *
640 * - elem1.elem2.elem3
641 * - elem1.elem2
642 * - elem1
643 */
644 } else {
645 char *p;
646
647 fr_sbuff_set_to_start(&our_name);
648
649 len = fr_sbuff_out_bstrncpy_until(elem1, &our_name, SIZE_MAX, dyn_tt, NULL);
650 if (len == 0) {
651 fr_strerror_const("Invalid module name");
652 goto error;
653 }
654
655 /*
656 * The copy stopped before a terminal, so elem1 filled.
657 */
658 if (fr_sbuff_extend(&our_name) && !fr_sbuff_is_terminal(&our_name, dyn_tt)) {
659 fr_strerror_const("Module method string too long");
660 goto error;
661 }
662
663 /*
664 * Now we have a mutable buffer, we can start chopping
665 * it up to find the module.
666 */
667 for (;;) {
668 mmc->mi = (module_instance_t *)module_rlm_static_by_name(NULL, elem1->start);
669 if (mmc->mi) {
671 break; /* Done */
672 }
673
674 p = strrchr(elem1->start, '.');
675 if (!p) break; /* No more '.' */
676 *p = '\0'; /* Chop off the last '.' */
677 }
678
679 if (!mmc->mi) {
680 if (softfail) return fr_sbuff_set(name, &our_name);
681
682 fr_strerror_printf("No such module '%pV'", fr_box_strvalue_len(our_name.start, len));
683 return -1;
684 }
685
686 fr_sbuff_set_to_start(&our_name);
687 fr_sbuff_advance(&our_name, strlen(elem1->start)); /* Advance past the module name */
688 if (fr_sbuff_is_char(&our_name, '.')) {
689 fr_sbuff_advance(&our_name, 1); /* Static module method, search directly */
690 } else {
691 fr_sbuff_marker(&meth_start, &our_name); /* for the errors... */
692 goto by_section; /* Get the method dynamically from the section*/
693 }
694 }
695
696 /*
697 * For both cases, the buffer should be pointing
698 * at the start of the method string.
699 */
700 fr_sbuff_marker(&meth_start, &our_name);
701
702 /*
703 * If a module method was provided, search for it in the named
704 * methods provided by the module.
705 *
706 * The method name should be either:
707 *
708 * - name1
709 * - name1.name2
710 */
711 {
712 section_name_t method;
713 fr_sbuff_t *elem2;
714
715 fr_sbuff_set_to_start(elem1); /* May have used this already for module lookups */
716
717 len = fr_sbuff_out_bstrncpy_until(elem1, &our_name, SIZE_MAX, elem_tt, NULL);
718 if (fr_sbuff_extend(&our_name) && !fr_sbuff_is_terminal(&our_name, elem_tt)) {
719 fr_strerror_const("Module method string too long");
720 return fr_sbuff_error(&our_name);
721 }
722 if (len == 0) goto by_section; /* This works for both dynamic and static modules */
723
725
726 if (fr_sbuff_is_char(&our_name, '.')) {
727 fr_sbuff_advance(&our_name, 1);
728 if (fr_sbuff_out_bstrncpy_until(elem2, &our_name, SIZE_MAX,
729 elem_tt, NULL) == MODULE_INSTANCE_LEN_MAX) {
730 fr_strerror_const("Module method string too long");
731 goto error;
732 }
733 }
734
735 method = (section_name_t) {
736 .name1 = elem1->start,
737 .name2 = fr_sbuff_used(elem2) ? elem2->start : NULL
738 };
739
740 mmb = module_binding_find(&mmc->rlm->method_group, &method);
741 if (!mmb) {
742 fr_strerror_printf("Module \"%s\" does not have method %s%s%s",
743 mmc->mi->name,
744 method.name1,
745 method.name2 ? "." : "",
746 method.name2 ? method.name2 : ""
747 );
748
750 return fr_sbuff_error(&meth_start);
751 }
752 mmc->mmb = *mmb; /* For locality of reference and fewer derefs */
753 if (mmc_out) section_name_dup(ctx, &mmc->asked, &method);
754
755 return fr_sbuff_set(name, &our_name);
756 }
757
758by_section:
759 /*
760 * First look for the section name in the module's
761 * bindings. If that fails, look for the alt
762 * section names from the virtual server section.
763 *
764 * If that fails, we're done.
765 */
766 mmb = module_binding_find(&mmc->rlm->method_group, section);
767 if (!mmb) {
768 section_name_t const **alt_p;
769
770 if (!vs) goto section_error;
771
772 alt_p = virtual_server_section_methods(vs, section);
773 if (alt_p) {
774 for (; *alt_p; alt_p++) {
775 mmb = module_binding_find(&mmc->rlm->method_group, *alt_p);
776 if (mmb) {
777 if (mmc_out) section_name_dup(ctx, &mmc->asked, *alt_p);
778 break;
779 }
780 }
781 }
782 } else {
783 if (mmc_out) section_name_dup(ctx, &mmc->asked, section);
784 }
785 if (!mmb) {
786 section_error:
787 fr_strerror_printf("Module \"%s\" has no method for section %s %s { ... }, i.e. %s%s%s",
788 mmc->mi->name,
789 section->name1,
790 section->name2 ? section->name2 : "",
791 section->name1,
792 section->name2 ? "." : "",
793 section->name2 ? section->name2 : ""
794 );
796
797 return fr_sbuff_error(&meth_start);
798 }
799 mmc->mmb = *mmb; /* For locality of reference and fewer derefs */
800
801 return fr_sbuff_set(name, &our_name);
802}
803
805{
807
810 .name = asked_name,
811 });
812 if (!inst) return NULL;
813
814 return inst->cs;
815}
816
821
826
827/** Create a virtual module.
828 *
829 * @param[in] cs that defines the virtual module.
830 * @return
831 * - 0 on success.
832 * - -1 on failure.
833 */
835{
836 char const *name;
837 bool xlat_redundant;
838 CONF_ITEM *sub_ci = NULL;
839 CONF_PAIR *cp;
842
844
845 /*
846 * Groups, etc. must have a name.
847 */
848 if ((strcmp(name, "group") == 0) ||
849 (strcmp(name, "redundant") == 0) ||
850 (strcmp(name, "redundant-load-balance") == 0) ||
851 (strcmp(name, "load-balance") == 0)) {
853 if (!name) {
854 cf_log_err(cs, "Keyword module must have a second name");
855 return -1;
856 }
857
858 /*
859 * name2 was already checked in modules_rlm_bootstrap()
860 */
862 } else {
863 cf_log_err(cs, "Module names cannot be unlang keywords '%s'", name);
864 return -1;
865 }
866
867 /*
868 * Ensure that the module doesn't exist.
869 */
871 if (mi) {
872 ERROR("Duplicate module \"%s\" in file %s[%d] and file %s[%d]",
873 name,
874 cf_filename(cs),
875 cf_lineno(cs),
876 cf_filename(mi->conf),
877 cf_lineno(mi->conf));
878 return -1;
879 }
880
881 /*
882 * Don't bother registering redundant xlats for a simple "group".
883 */
884 xlat_redundant = (strcmp(cf_section_name1(cs), "group") != 0);
885
886 /*
887 * Do a quick check to see if we _might_ need to load a virtual module.
888 */
889 while ((sub_ci = cf_item_next(cs, sub_ci))) {
890 char const *attr;
891
892 if (!cf_item_is_pair(sub_ci)) {
893 xlat_redundant = false;
894 continue;
895 }
896
897 cp = cf_item_to_pair(sub_ci);
898 if (cf_pair_value(cp)) {
899 cf_log_err(sub_ci, "Cannot edit attributes or set return codes in a %s block - use 'group' to separate individual items",
900 cf_section_name1(cs));
901 return -1;
902 }
903
904 attr = cf_pair_attr(cp);
905
906 /*
907 * A conditionally loaded module (e.g. "-foo") means that we silently omit it if
908 * it doesn't exist, which changes all of the load-balance and redundant
909 * behavior.
910 *
911 * Plus, a conditionally loaded module is almost always going to be of a
912 * different type than the other modules. Which means that any redundant xlats
913 * won't work.
914 */
915 if (*attr == '-') {
916 cf_log_err(sub_ci, "Cannot use conditionally loaded modules in a %s block",
917 cf_section_name1(cs));
918 return -1;
919 }
920
921 /*
922 * %foo() is not a module.
923 */
924 if (!isalpha((uint8_t) *attr)) {
925 xlat_redundant = false;
926 continue;
927 }
928 } /* loop over things in a virtual module section */
929
930 inst = talloc_zero(cs, module_rlm_virtual_t);
931 if (!inst) return -1;
932
933 inst->cs = cs;
934 inst->mi = mi;
935 MEM(inst->name = talloc_strdup(inst, name));
936 inst->xlat_redundant = xlat_redundant;
937
939 if (old) {
940 ERROR("Duplicate module \"%s\" in file %s[%d] and file %s[%d]",
941 name,
942 cf_filename(cs),
943 cf_lineno(cs),
944 cf_filename(old->cs),
945 cf_lineno(old->cs));
947 return -1;
948 }
949
951 cf_log_perr(cs, "Failed inserting module into internal tracking table");
953 return -1;
954 }
955
956 return 0;
957}
958
959/** Generic conf_parser_t func for loading drivers
960 *
961 */
962int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent,
963 CONF_ITEM *ci, conf_parser_t const *rule)
964{
965 conf_parser_t our_rule = *rule;
966
967 our_rule.uctx = &rlm_modules_static;
968
969 return module_submodule_parse(ctx, out, parent, ci, &our_rule);
970}
971
972/** Frees thread-specific data for all registered backend modules
973 *
974 */
979
980/** Allocates thread-specific data for all registered backend modules
981 *
982 * @param[in] ctx To allocate any thread-specific data in.
983 * @param[in] el to register events.
984 * @return
985 * - 0 if all modules were instantiated successfully.
986 * - -1 if a module failed instantiation.
987 */
992
993/** Runs the coord_attach method of all registered backend modules
994 *
995 * @param[in] el to register events.
996 * @return
997 * - 0 if all calls succeeded.
998 * - -1 if a call failed.
999 */
1004
1005/** Runs the coord_detach method of all registered backend modules
1006 */
1011
1012/** Performs the instantiation phase for all backend modules
1013 *
1014 * @return
1015 * - 0 if all modules were instantiated successfully.
1016 * - -1 if a module failed instantiation.
1017 */
1022
1023/** Compare the section names of two module_method_binding_t structures
1024 */
1025static fr_cmp_ret_t binding_name_cmp(void const *one, void const *two)
1026{
1027 module_method_binding_t const *a = one;
1028 module_method_binding_t const *b = two;
1029
1030 return section_name_cmp(a->section, b->section);
1031}
1032
1034{
1035 module_method_binding_t *p, *srt_p;
1036 fr_dlist_head_t bindings;
1037 bool in_order = true;
1038
1039 /*
1040 * Not all modules export module method bindings
1041 */
1042 if (!group || !group->bindings || group->validated) return 0;
1043
1044 fr_dlist_init(&bindings, module_method_binding_t, entry);
1045
1046 for (p = group->bindings; p->section; p++) {
1048 "First section identifier can't be NULL")) return -1;
1049
1050 /*
1051 * All the bindings go in a list so we can sort them
1052 * and produce the list in the correct order.
1053 */
1054 fr_dlist_insert_tail(&bindings, p);
1055 }
1056
1057 fr_dlist_sort(&bindings, binding_name_cmp);
1058
1059 /*
1060 * Iterate over the sorted list of bindings,
1061 * and the original list, to ensure they're
1062 * in the correct order.
1063 */
1064 for (srt_p = fr_dlist_head(&bindings), p = group->bindings;
1065 srt_p;
1066 srt_p = fr_dlist_next(&bindings, srt_p), p++) {
1067 if (p != srt_p) {
1068 in_order = false;
1069 break;
1070 }
1071 }
1072
1073 /*
1074 * Rebuild the binding list in the correct order.
1075 */
1076 if (!in_order) {
1077 module_method_binding_t *ordered;
1078
1079 MEM(ordered = talloc_array(NULL, module_method_binding_t, fr_dlist_num_elements(&bindings)));
1080 for (srt_p = fr_dlist_head(&bindings), p = ordered;
1081 srt_p;
1082 srt_p = fr_dlist_next(&bindings, srt_p), p++) {
1083 *p = *srt_p;
1084 }
1085 memcpy(group->bindings, ordered, fr_dlist_num_elements(&bindings) * sizeof(*ordered));
1086 talloc_free(ordered);
1087 }
1088
1089 /*
1090 * Build the "skip" list of name1 entries
1091 */
1092 {
1093 module_method_binding_t *last_binding = NULL;
1094
1095 for (p = group->bindings; p->section; p++) {
1096 if (!last_binding ||
1097 (
1098 (last_binding->section->name1 != p->section->name1) &&
1099 (
1100 (last_binding->section->name1 == CF_IDENT_ANY) ||
1101 (p->section->name1 == CF_IDENT_ANY) ||
1102 (strcmp(last_binding->section->name1, p->section->name1) != 0)
1103 )
1104 )
1105 ) {
1107 last_binding = p;
1108 }
1109 fr_dlist_insert_tail(&last_binding->same_name1, p);
1110 }
1111 }
1112 group->validated = true;
1113
1114 return module_method_group_validate(group->next);
1115}
1116
1123
1124/** Allocate a rlm module instance
1125 *
1126 * These have extra space allocated to hold the dlist of associated xlats.
1127 *
1128 * @param[in] ml Module list to allocate from.
1129 * @param[in] parent Parent module instance.
1130 * @param[in] type Type of module instance.
1131 * @param[in] mod_name Name of the module.
1132 * @param[in] inst_name Name of the instance.
1133 * @param[in] init_state Initial state of the module instance.
1134 * @return
1135 * - The allocated module instance on success.
1136 * - NULL on failure.
1137 */
1138static inline CC_HINT(always_inline)
1141 dl_module_type_t type, char const *mod_name, char const *inst_name,
1142 module_instance_state_t init_state)
1143{
1146
1147 mi = module_instance_alloc(ml, parent, type, mod_name, inst_name, init_state);
1148 if (unlikely(mi == NULL)) return NULL;
1149
1150 MEM(mri = talloc(mi, module_rlm_instance_t));
1151 module_instance_uctx_set(mi, mri);
1152
1154
1155 return mi;
1156}
1157
1159{
1160 char const *name;
1161 char const *inst_name;
1162 module_instance_t *mi = NULL;
1163 CONF_SECTION *actions;
1164
1165 /*
1166 * name2 can't be a keyword
1167 */
1168 name = cf_section_name2(mod_conf);
1170 invalid_name:
1171 cf_log_err(mod_conf, "Module names cannot be unlang keywords '%s'", name);
1172 return -1;
1173 }
1174
1175 name = cf_section_name1(mod_conf);
1176
1177 /*
1178 * For now, ignore name1 which is a keyword.
1179 */
1181 if (!cf_section_name2(mod_conf)) {
1182 cf_log_err(mod_conf, "Missing second name at '%s'", name);
1183 return -1;
1184 }
1185 if (module_rlm_bootstrap_virtual(mod_conf) < 0) return -1;
1186 return 0;
1187 }
1188
1189 /*
1190 * Skip inline templates, and disallow "template { ... }"
1191 */
1192 if (strcmp(name, "template") == 0) {
1193 if (!cf_section_name2(mod_conf)) goto invalid_name;
1194 return 0;
1195 }
1196
1197 if (module_instance_name_from_conf(&inst_name, mod_conf) < 0) goto invalid_name;
1198
1199 mi = module_rlm_instance_alloc(ml, NULL, DL_MODULE_TYPE_MODULE, name, inst_name, 0);
1200 if (unlikely(mi == NULL)) {
1201 cf_log_perr(mod_conf, "Failed loading module");
1202 return -1;
1203 }
1204
1205 /*
1206 * First time we've loaded the dl module, so we need to
1207 * check the module methods to make sure they're ordered
1208 * correctly, and to add the "skip list" style name2
1209 * entries.
1210 */
1211 if ((mi->module->refs == 1) && (module_method_validate(mi) < 0)) {
1212 talloc_free(mi);
1213 return -1;
1214 }
1215
1216 if (module_instance_conf_parse(mi, mod_conf) < 0) {
1217 cf_log_perr(mod_conf, "Failed parsing module config");
1218 talloc_free(mi);
1219 return -1;
1220 }
1221
1222 /*
1223 * Compile the default "actions" subsection, which includes retries.
1224 */
1225 actions = cf_section_find(mod_conf, "actions", NULL);
1226 if (actions && !unlang_compile_actions(&mi->actions, actions, (mi->exported->flags & MODULE_TYPE_RETRY))) {
1227 talloc_free(mi);
1228 return -1;
1229 }
1230
1231 return 0;
1232}
1233
1234/** Figure out the dictionary so that we can compile a virtual module.
1235 *
1236 * Virtual modules replace the v3 home_server_pool and "fallback" configuration. However, using the v4
1237 * syntax means putting sections inside of each other. So we have to walk the entire hierarchy to determine
1238 * what to do. e.g.:
1239 *
1240 * redundant pool1 {
1241 * load-balance "%{Calling-Station-Id}" {
1242 * radius1
1243 * radius2
1244 * ...
1245 * }
1246 * group {
1247 * fallback policy
1248 * }
1249 * }
1250 *
1251 * @todo - if there is no dictionary, then compile it once for each possible dictionary?
1252 *
1253 * @todo - look at the attributes, to determine which dictionary that they belong to?
1254 */
1256{
1257 cf_item_foreach(cs, ci) {
1258 CONF_PAIR *cp;
1259 char const *name;
1260 fr_dict_t const *dict;
1262
1263 if (cf_item_is_data(ci)) continue;
1264
1265 if (cf_item_is_section(ci)) {
1266 CONF_SECTION *subcs;
1267
1268 subcs = cf_item_to_section(ci);
1269 name = cf_section_name1(subcs);
1270
1271 /*
1272 * Ignore edit sections.
1273 */
1274 if (fr_list_assignment_op[cf_section_name2_quote(subcs)]) continue;
1275
1276 /*
1277 * Recurse into keywords
1278 */
1280 if (virtual_module_determine_dict(vm, subcs) < 0) return -1;
1281 continue;
1282 }
1283
1284 if ((strcmp(name, "actions") == 0) ||
1285 (strcmp(name, "retry") == 0)) {
1286 return 0;
1287 }
1288
1289 goto check_for_module;
1290 }
1291
1292 /*
1293 * Ignore edit assignments
1294 */
1295 cp = cf_item_to_pair(ci);
1296 if (cf_pair_value(cp)) continue;
1297
1298 name = cf_pair_attr(cp);
1299
1300 /*
1301 * %debug(4)
1302 */
1303 if ((*name == '%') || (*name == '&')) continue;
1304
1305 /*
1306 * Ignore 'break', 'return', etc.
1307 */
1308 if (unlang_compile_is_keyword(name)) continue;
1309
1310 if (*name == '-') name++;
1311
1312 check_for_module:
1313 /*
1314 * Be forgiving about module names.
1315 */
1316 mi = module_rlm_static_by_name(NULL, name);
1317 if (!mi) continue;
1318
1319 if (!mi->exported->dict) continue;
1320
1321 /*
1322 * Check that the namespaces are compatible.
1323 */
1324 dict = *mi->exported->dict;
1325
1326 if (!vm->dict) {
1327 vm->dict = dict;
1328
1329 } else if (vm->dict != dict) {
1330 cf_log_err(ci, "Module %s has namespace %s, while the previous modules in this section have namespace %s",
1331 mi->name, fr_dict_root(dict)->name,
1332 fr_dict_root(vm->dict)->name);
1333 cf_log_err(ci, "Cannot have modules for different namespaces in %s %s { ... } section",
1334 cf_section_name1(vm->cs), vm->name);
1335 return -1;
1336 }
1337 }
1338
1339 return 0;
1340}
1341
1342/** Bootstrap modules and virtual modules
1343 *
1344 * Parse the module config sections, and load and call each module's init() function.
1345 *
1346 * @param[in] root of the server configuration.
1347 * @return
1348 * - 0 if all modules were bootstrapped successfully.
1349 * - -1 if a module/virtual module failed to bootstrap.
1350 */
1352{
1353 CONF_SECTION *cs, *modules, *static_cs, *dynamic_cs;
1356
1357 /*
1358 * Ensure any libraries the modules depend on are instantiated
1359 */
1360 if (global_lib_instantiate() < 0) return -1;
1361
1362 /*
1363 * Remember where the modules were stored.
1364 */
1365 modules = cf_section_find(root, "modules", NULL);
1366 if (!modules) {
1367 WARN("Cannot find a \"modules\" section in the configuration file!");
1368 return 0;
1369 }
1370
1371 static_cs = cf_section_find(modules, "static", NULL);
1372 if (!static_cs) {
1373 static_cs = cf_section_alloc(modules, NULL, "static", NULL);
1374 cf_section_foreach(modules, mod_cs) {
1375 CONF_ITEM *prev;
1376 char const *name1 = cf_section_name1(mod_cs);
1377
1378 /*
1379 * Skip over the dynamic section
1380 */
1381 if ((strcmp(name1, "dynamic") == 0) && !cf_section_name2(mod_cs)) continue;
1382
1383 /*
1384 * Ignore this section if it is commented out with a magic name.
1385 */
1386 if (*name1 == '-') continue;
1387
1388 /*
1389 * Move all modules which are not in
1390 * the dynamic section into the static
1391 * section for backwards compatibility.
1392 */
1393 prev = cf_item_remove(modules, mod_cs);
1394 cf_item_add(static_cs, mod_cs);
1395
1396 /*
1397 * Find the previous item that's a section
1398 */
1399 while (prev && !cf_item_is_section(prev)) prev = cf_item_prev(modules, prev);
1400
1401 /*
1402 * Resume iterating from that item
1403 */
1404 mod_cs = cf_item_to_section(prev);
1405 }
1406 cf_item_add(modules, static_cs);
1407 }
1408 DEBUG2("#### Bootstrapping static modules ####");
1409 cf_log_debug(modules, " modules {");
1410 cf_log_debug(modules, " static {");
1411 cf_section_foreach(static_cs, mod_conf) {
1412 if (module_conf_parse(rlm_modules_static, mod_conf) < 0) return -1;
1413 }
1414 cf_log_debug(modules, " } # static");
1415
1416 /*
1417 * Now we have a module tree, run bootstrap on all the modules.
1418 * This will bootstrap modules and then submodules.
1419 */
1420 if (unlikely(modules_bootstrap(rlm_modules_static) < 0)) return -1;
1421
1422 if (fr_command_register_hook(NULL, NULL, static_cs, module_cmd_list_table) < 0) {
1423 PERROR("Failed registering radmin commands for modules");
1424 return -1;
1425 }
1426
1427 /*
1428 * Build the configuration and parse dynamic modules
1429 */
1430 dynamic_cs = cf_section_find(modules, "dynamic", NULL);
1431 if (dynamic_cs) {
1432 DEBUG2("#### Bootstrapping dynamic modules ####");
1433 /*
1434 * Parse and then instantiate any dynamic modules configure
1435 */
1436 cf_log_debug(modules, " dynamic {");
1437 cf_section_foreach(dynamic_cs, mod_conf) {
1438 if (unlikely(module_conf_parse(rlm_modules_dynamic, mod_conf) < 0)) return -1;
1439 }
1440 cf_log_debug(modules, " } # dynamic");
1441 if (unlikely(modules_bootstrap(rlm_modules_dynamic) < 0)) return -1;
1442 cf_log_debug(modules, " } # modules");
1443 }
1444
1445 /*
1446 * Check for duplicate policies. They're treated as
1447 * modules, so we might as well check them here.
1448 */
1449 cs = cf_section_find(root, "policy", NULL);
1450 if (cs) {
1451 cf_section_foreach(cs, policy_cs) {
1452 CONF_SECTION *problemcs;
1453 char const *name1 = cf_section_name1(policy_cs);
1454
1455 if (unlang_compile_is_keyword(name1)) {
1456 cf_log_err(policy_cs, "Policy name '%s' cannot be an unlang keyword", name1);
1457 return -1;
1458 }
1459
1460 if (cf_section_name2(policy_cs)) {
1461 cf_log_err(policy_cs, "Policies cannot have two names");
1462 return -1;
1463 }
1464
1465 problemcs = cf_section_find_next(cs, policy_cs, name1, CF_IDENT_ANY);
1466 if (!problemcs) continue;
1467
1468 cf_log_err(problemcs, "Duplicate policy '%s' is forbidden.",
1469 cf_section_name1(policy_cs));
1470 return -1;
1471 }
1472 }
1473
1474 /*
1475 * Now that all of the xlat things have been registered, register our redundant xlats.
1476 *
1477 * Since the checks above in module_rlm_bootstrap_virtual() only checked for CONF_PAIRs, we have
1478 * to double-check the module instances. We couldn't do that previously, due to the fact that
1479 * modules are loaded in alphabetical order. A virtual module "aaa" may therefore reference a
1480 * real module "zzz", which would not have yet been loaded.
1481 */
1483 vm;
1485 CONF_ITEM *sub_ci = NULL;
1486 module_t const *last = NULL;
1487 bool all_same = true;
1488
1489 if (!vm->xlat_redundant) continue;
1490
1491 while ((sub_ci = cf_item_next(vm->cs, sub_ci))) {
1493 CONF_PAIR *cp;
1494
1495 if (!cf_item_is_pair(sub_ci)) continue;
1496
1497 cp = cf_item_to_pair(sub_ci);
1499 if (!mi) {
1500 cf_log_perr(sub_ci, "Failed resolving module reference '%s' in %s block",
1502 return -1;
1503 }
1504
1505 if (!all_same) continue;
1506
1507 if (!last) {
1508 last = mi->exported;
1509 } else if (last != mi->exported) {
1510 last = NULL;
1511 all_same = false;
1512 }
1513 }
1514
1515 /*
1516 * See if we can automatically determine the
1517 * dictionary by walking the unlang tree.
1518 */
1519 if (virtual_module_determine_dict(vm, vm->cs) < 0) return -1;
1520
1521 /*
1522 * Associate the dictionary with the CONF_SECTION, so that later compilation code can
1523 * find it.
1524 */
1525 if (vm->dict) cf_data_add(vm->cs, vm->dict, "dict", false);
1526
1527 if (!all_same) continue;
1528
1529 if (xlat_register_redundant(vm->cs) < 0) return -1;
1530 }
1531
1532 return 0;
1533}
1534
1535/** Iterate over the virtual modules.
1536 *
1537 */
1539{
1541
1543 if (!vm) return NULL;
1544
1545 return vm->cs;
1546}
1547
1549{
1551
1553 if (!vm) return NULL;
1554
1555 return vm->cs;
1556}
1557
1558
1559/** Cleanup all global structures
1560 *
1561 * Automatically called on exit.
1562 */
1564{
1565 if (talloc_free(rlm_modules_static) < 0) return -1;
1566 rlm_modules_static = NULL;
1567
1568 if (talloc_free(rlm_modules_dynamic) < 0) return -1;
1569 rlm_modules_dynamic = NULL;
1570
1571 if (talloc_free(module_rlm_virtual_name_tree) < 0) return -1;
1573
1574 return 0;
1575}
1576
1577static int _modules_rlm_free_atexit(UNUSED void *uctx)
1578{
1579 return modules_rlm_free();
1580}
1581
1582/** Initialise the module list structure
1583 *
1584 */
1586{
1589 module_list_mask_set(rlm_modules_dynamic, MODULE_INSTANCE_INSTANTIATED); /* Ensure we never instantiate dynamic modules */
1590
1594
1595 return 0;
1596}
#define fr_atexit_global(_func, _uctx)
Add a free function to the global free list.
Definition atexit.h:58
#define RCSID(id)
Definition build.h:560
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:113
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
void const * uctx
User data accessible by the cf_parse_t func.
Definition cf_parse.h:629
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:606
Internal data that is associated with a configuration section.
Definition cf_priv.h:156
Common header for all CONF_* types.
Definition cf_priv.h:54
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:644
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1363
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1876
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1349
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1205
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:696
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1598
bool cf_item_is_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
Definition cf_util.c:658
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:630
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:676
CONF_SECTION * cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev, char const *name1, char const *name2)
Return the next matching section.
Definition cf_util.c:1226
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1408
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1716
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1700
#define cf_item_add(_parent, _child)
Definition cf_util.h:85
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:343
#define cf_lineno(_cf)
Definition cf_util.h:121
#define cf_section_foreach(_parent, _iter)
Definition cf_util.h:213
#define cf_data_add(_cf, _data, _name, _free)
Definition cf_util.h:309
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:298
#define cf_data_remove_by_data(_cf, _cd)
Remove an item from a parent.
Definition cf_util.h:328
#define cf_item_prev(_parent, _curr)
Definition cf_util.h:112
#define cf_item_remove(_parent, _child)
Definition cf_util.h:91
#define cf_item_next(_parent, _curr)
Definition cf_util.h:94
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:350
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:201
#define cf_item_foreach(_parent, _iter)
Iterate over every child item of a CONF_SECTION (or any CONF_ITEM that has children).
Definition cf_util.h:109
#define cf_filename(_cf)
Definition cf_util.h:124
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:346
#define CF_IDENT_ANY
Definition cf_util.h:80
fr_command_register_hook_t fr_command_register_hook
Definition command.c:41
fr_dict_t * dict
Definition common.c:31
bool unlang_compile_is_keyword(const char *name)
Check if name is an unlang keyword.
Definition compile.c:2338
bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *cs, bool module_retry)
Definition compile.c:1082
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:248
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:194
#define MEM(x)
Definition debug.h:38
#define ERROR(fmt,...)
Definition dhcpclient.c:40
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2720
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:281
char const * name
Enum name.
Definition dict.h:278
Value of an enumerated attribute.
Definition dict.h:277
dl_module_type_t
Definition dl_module.h:65
@ DL_MODULE_TYPE_MODULE
Standard loadable module.
Definition dl_module.h:66
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:242
static int fr_dlist_sort(fr_dlist_head_t *list, fr_cmp_t cmp)
Sort a dlist using merge sort.
Definition dlist.h:1078
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:468
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:921
static void * fr_dlist_tail(fr_dlist_head_t const *list_head)
Return the TAIL item of a list or NULL if the list is empty.
Definition dlist.h:513
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:360
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:257
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:537
Head of a doubly linked list.
Definition dlist.h:51
Definition dwarf.c:424
exfile_t * exfile_init(TALLOC_CTX *ctx, uint32_t max_entries, fr_time_delta_t max_idle, bool locking)
Initialize a way for multiple threads to log to one or more files.
Definition exfile.c:170
void exfile_enable_triggers(exfile_t *ef, CONF_SECTION *conf, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Enable triggers for an exfiles handle.
Definition exfile.c:218
int global_lib_instantiate(void)
Walk the tree of libraries and instantiate any which are pending.
Definition global_lib.c:218
static xlat_action_t xlat_redundant(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
xlat "redundant", "load-balance" and "redundant-load-balance" processing
talloc_free(hp)
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG4(_fmt,...)
Definition log.h:272
Stores all information relating to an event list.
Definition event.c:377
static char const * mod_name(fr_listen_t *li)
Definition master.c:3186
fr_type_t
unsigned int uint32_t
size_t fr_sbuff_out_bstrncpy_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
unsigned char uint8_t
ssize_t fr_slen_t
fr_cmp_ret_t
Result of an ordering comparison.
Definition misc.h:50
fr_cmd_table_t module_cmd_list_table[]
Definition module.c:91
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
static module_list_t * rlm_modules_dynamic
Runtime instantiated list.
Definition module_rlm.c:79
static int _modules_rlm_free_atexit(UNUSED void *uctx)
void modules_rlm_thread_detach(void)
Frees thread-specific data for all registered backend modules.
Definition module_rlm.c:975
CONF_SECTION * module_rlm_virtual_iter_init(fr_rb_iter_inorder_t *iter)
Iterate over the virtual modules.
int modules_rlm_bootstrap(CONF_SECTION *root)
Bootstrap modules and virtual modules.
static int module_rlm_bootstrap_virtual(CONF_SECTION *cs)
Create a virtual module.
Definition module_rlm.c:834
static module_method_binding_t const * module_binding_find(module_method_group_t const *mmg, section_name_t const *section)
Iterate over an array of named module methods, looking for matches.
Definition module_rlm.c:445
fr_slen_t module_rlm_by_name_and_method(TALLOC_CTX *ctx, module_method_call_t *mmc_out, virtual_server_t const *vs, section_name_t const *section, fr_sbuff_t *name, tmpl_rules_t const *t_rules)
Find an existing module instance and verify it implements the specified method.
Definition module_rlm.c:550
exfile_t * module_rlm_exfile_init(TALLOC_CTX *ctx, CONF_SECTION *module, uint32_t max_entries, fr_time_delta_t max_idle, bool locking, bool triggers, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Initialise a module specific exfile handle.
Definition module_rlm.c:105
static int virtual_module_determine_dict(module_rlm_virtual_t *vm, CONF_SECTION *cs)
Figure out the dictionary so that we can compile a virtual module.
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition module_rlm.c:234
module_instance_t * module_rlm_dynamic_by_name(module_instance_t const *parent, char const *asked_name)
Definition module_rlm.c:817
bool xlat_redundant
whether we might need it
Definition module_rlm.c:56
char const * name
module name
Definition module_rlm.c:52
fr_dict_t const * dict
dict / namespace we expect to use.
Definition module_rlm.c:55
fr_rb_node_t name_node
Entry in the name tree.
Definition module_rlm.c:51
int module_rlm_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char const *name)
Resolve polymorphic item's from a module's CONF_SECTION to a subsection in another module.
Definition module_rlm.c:160
void module_rlm_list_debug(void)
Print information on all loaded modules.
Definition module_rlm.c:84
static int module_method_validate(module_instance_t *mi)
CONF_SECTION * module_rlm_virtual_iter_next(fr_rb_iter_inorder_t *iter)
static fr_rb_tree_t * module_rlm_virtual_name_tree
Lookup virtual module by name.
Definition module_rlm.c:48
static fr_cmp_ret_t binding_name_cmp(void const *one, void const *two)
Compare the section names of two module_method_binding_t structures.
int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic conf_parser_t func for loading drivers.
Definition module_rlm.c:962
module_instance_t * module_rlm_static_by_name(module_instance_t const *parent, char const *asked_name)
Definition module_rlm.c:822
int modules_rlm_coord_attach(fr_event_list_t *el)
Runs the coord_attach method of all registered backend modules.
bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
Set the next section type if it's not already set.
Definition module_rlm.c:405
fr_pool_t * module_rlm_connection_pool_init(CONF_SECTION *module, void *opaque, fr_pool_connection_create_t c, fr_pool_connection_alive_t a, char const *log_prefix, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Initialise a module specific connection pool.
Definition module_rlm.c:285
static int module_conf_parse(module_list_t *ml, CONF_SECTION *mod_conf)
static fr_cmp_ret_t module_rlm_virtual_name_cmp(void const *one, void const *two)
Compare virtual modules by name.
Definition module_rlm.c:61
static void module_rlm_methods_to_strerror(module_method_group_t const *mmg)
Dump the available bindings for the module into the strerror stack.
Definition module_rlm.c:498
int modules_rlm_free(void)
Cleanup all global structures.
#define FIND_SIBLING_CF_KEY
int modules_rlm_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Allocates thread-specific data for all registered backend modules.
Definition module_rlm.c:988
static module_instance_t * module_rlm_instance_alloc(module_list_t *ml, module_instance_t const *parent, dl_module_type_t type, char const *mod_name, char const *inst_name, module_instance_state_t init_state)
Allocate a rlm module instance.
int modules_rlm_coord_detach(void)
Runs the coord_detach method of all registered backend modules.
module_instance_t * mi
module instance
Definition module_rlm.c:54
#define parent_name(_x)
CONF_SECTION * module_rlm_virtual_by_name(char const *asked_name)
Definition module_rlm.c:804
static module_list_t * rlm_modules_static
Global module list for all backend modules.
Definition module_rlm.c:74
int modules_rlm_instantiate(void)
Performs the instantiation phase for all backend modules.
int modules_rlm_init(void)
Initialise the module list structure.
static int module_method_group_validate(module_method_group_t *group)
CONF_SECTION * cs
CONF_SECTION where it is defined.
Definition module_rlm.c:53
module_method_group_t method_group
named methods
Definition module_rlm.h:40
module_instance_t * mi
The module instance that registered the xlat.
Definition module_rlm.h:54
fr_dlist_head_t xlats
xlats registered to this module instance.
Definition module_rlm.h:44
module_instance_t * mi
The process modules also push module calls onto the stack for execution.
Definition module_rlm.h:63
xlat_t const * xlat
The xlat function.
Definition module_rlm.h:53
tmpl_t * key
Dynamic key, only set for dynamic modules.
Definition module_rlm.h:71
section_name_t asked
The actual <name1>.
Definition module_rlm.h:67
module_method_binding_t mmb
Method we're calling.
Definition module_rlm.h:70
module_rlm_t const * rlm
Cached module_rlm_t.
Definition module_rlm.h:66
static module_rlm_t * module_rlm_from_module(module_t *module)
Definition module_rlm.h:74
The output of module_rlm_by_name_and_method.
Definition module_rlm.h:62
An xlat function registered to a module.
Definition module_rlm.h:52
int fr_pool_start(fr_pool_t *pool)
Definition pool.c:1119
void fr_pool_ref(fr_pool_t *pool)
Increment pool reference by one.
Definition pool.c:1215
fr_pool_t * fr_pool_init(TALLOC_CTX *ctx, CONF_SECTION const *cs, void *opaque, fr_pool_connection_create_t c, fr_pool_connection_alive_t a, char const *log_prefix)
Create a new connection pool.
Definition pool.c:970
void fr_pool_enable_triggers(fr_pool_t *pool, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Enable triggers for a connection pool.
Definition pool.c:936
A connection pool.
Definition pool.c:85
void *(* fr_pool_connection_create_t)(TALLOC_CTX *ctx, void *opaque, fr_time_delta_t timeout)
Create a new connection handle.
Definition pool.h:111
int(* fr_pool_connection_alive_t)(void *opaque, void *connection)
Check a connection handle is still viable.
Definition pool.h:126
#define fr_assert(_expr)
Definition rad_assert.h:37
#define RDEBUG2(fmt,...)
#define DEBUG2(fmt,...)
#define WARN(fmt,...)
int fr_rb_find(void **found, fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:586
void * fr_rb_iter_init_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Initialise an in-order iterator.
Definition rb.c:850
int fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:637
void * fr_rb_iter_next_inorder(UNUSED fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:876
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition rb.h:269
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:319
The main red black tree structure.
Definition rb.h:71
static char const * name
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition sbuff.c:2258
size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr)
Wind position until we hit a character in the terminal set.
Definition sbuff.c:1958
size_t fr_sbuff_out_bstrncpy(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
Copy as many bytes as possible from a sbuff to a sbuff.
Definition sbuff.c:735
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition sbuff.c:2194
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:190
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define fr_sbuff_error(_sbuff_or_marker)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_used(_sbuff_or_marker)
#define fr_sbuff_ahead(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Set of terminal elements.
int8_t section_name_cmp(void const *one, void const *two)
Compare two sections.
Definition section.c:47
static int section_name2_match(section_name_t const *a, section_name_t const *b)
Definition section.h:59
static char const * section_name_str(char const *name)
Return a printable string for the section name.
Definition section.h:97
static int section_name_match(section_name_t const *a, section_name_t const *b)
Definition section.h:83
static void section_name_dup(TALLOC_CTX *ctx, section_name_t *dst, section_name_t const *src)
Definition section.h:104
char const * name2
Second section name. Usually a packet type like 'access-request', 'access-accept',...
Definition section.h:45
char const * name1
First section name. Usually a verb like 'recv', 'send', etc...
Definition section.h:44
Section name identifier.
Definition section.h:43
char const * name
Instance name e.g. user_database.
Definition module.h:359
@ MODULE_TYPE_RETRY
can handle retries
Definition module.h:51
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:236
module_method_group_t * next
Next group in the list.
Definition module.h:168
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:353
module_instance_state_t state
What's been done with this module so far.
Definition module.h:352
unlang_mod_actions_t actions
default actions and retries.
Definition module.h:327
fr_dict_t const ** dict
required dictionary for this module.
Definition module.h:207
bool validated
Set to true by module_method_group_validate.
Definition module.h:167
#define MODULE_INSTANCE_LEN_MAX
The maximum size of a module instance.
Definition module.h:148
fr_dlist_head_t same_name1
List of bindings with the same name1.
Definition module.h:187
module_instance_state_t
What state the module instance is currently in.
Definition module.h:267
@ MODULE_INSTANCE_INSTANTIATED
Module instance has been bootstrapped and instantiated.
Definition module.h:270
void * uctx
Extra data passed to module_instance_alloc.
Definition module.h:363
module_method_binding_t * bindings
named methods
Definition module.h:165
section_name_t const * section
Identifier for a section.
Definition module.h:175
module_t * exported
Public module structure.
Definition module.h:300
Module instance data.
Definition module.h:289
A list of modules.
Definition module.h:419
Named methods exported by a module.
Definition module.h:174
A group of methods exported by a module or added as an overlay.
Definition module.h:164
Struct exported by a rlm_* module.
Definition module.h:203
#define pair_update_control(_attr, _da)
Return or allocate a fr_pair_t in the control list.
Definition pair.h:140
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:336
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
void module_list_debug(module_list_t const *ml)
Print the contents of a module list.
Definition module.c:620
module_list_type_t const module_list_type_thread_local
Callbacks for a thread local list.
Definition module.c:587
module_instance_t * module_instance_by_name(module_list_t const *ml, module_instance_t const *parent, char const *asked_name)
Find an existing module instance by its name and parent.
Definition module.c:902
void module_list_mask_set(module_list_t *ml, module_instance_state_t mask)
Set a new bootstrap/instantiate state for a list.
Definition module.c:1904
module_instance_t * module_instance_alloc(module_list_t *ml, module_instance_t const *parent, dl_module_type_t type, char const *mod_name, char const *inst_name, module_instance_state_t init_state)
Allocate a new module and add it to a module list for later bootstrap/instantiation.
Definition module.c:1720
fr_slen_t module_instance_name_from_conf(char const **name, CONF_SECTION *conf)
Avoid boilerplate when setting the module instance name.
Definition module.c:734
void modules_thread_detach(module_list_t *ml)
Remove thread-specific data for a given module list.
Definition module.c:1008
int modules_thread_instantiate(TALLOC_CTX *ctx, module_list_t const *ml, fr_event_list_t *el)
Creates per-thread instance data for modules which need it.
Definition module.c:1159
int modules_instantiate(module_list_t const *ml)
Completes instantiation of modules.
Definition module.c:1338
module_list_t * module_list_alloc(TALLOC_CTX *ctx, module_list_type_t const *type, char const *name, bool write_protect)
Allocate a new module list.
Definition module.c:1926
void module_instance_uctx_set(module_instance_t *mi, void *uctx)
Set the uctx pointer for a module instance.
Definition module.c:1688
int modules_coord_attach(module_list_t const *ml, fr_event_list_t *el)
Call the coordinator attach callback for any modules using a coordinator.
Definition module.c:1195
int modules_coord_detach(module_list_t const *ml)
Call the coordinator detach callback for any modules using a coordinator.
Definition module.c:1221
module_list_type_t const module_list_type_global
Callbacks for a global module list.
Definition module.c:533
int modules_bootstrap(module_list_t const *ml)
Bootstrap any modules which have not been bootstrapped already.
Definition module.c:1429
int module_instantiate(module_instance_t *instance)
Manually complete module setup by calling its instantiate function.
Definition module.c:1252
int module_submodule_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic callback for conf_parser_t to load a submodule.
Definition module.c:846
int module_instance_conf_parse(module_instance_t *mi, CONF_SECTION *conf)
Covert a CONF_SECTION into parsed module instance data.
Definition module.c:763
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
const bool fr_list_assignment_op[T_TOKEN_LAST]
Definition token.c:253
@ T_BARE_WORD
Definition token.h:118
static fr_event_list_t * el
xlat_action_t(* xlat_func_t)(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
xlat callback function
Definition xlat.h:222
static fr_slen_t parent
Definition pair.h:860
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const_push(_msg)
Definition strerror.h:227
#define fr_strerror_const(_msg)
Definition strerror.h:223
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:4422
#define fr_box_strvalue_len(_val, _len)
Definition value.h:334
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1062
section_name_t const ** virtual_server_section_methods(virtual_server_t const *vs, section_name_t const *section)
Find the component for a section.
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition xlat_func.c:225
void xlat_mctx_set(xlat_t *x, module_inst_ctx_t const *mctx)
Associate a module calling ctx with the xlat.
Definition xlat_func.c:307
int xlat_register_redundant(CONF_SECTION *cs)
Registers a redundant xlat.