The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
xlat_redundant.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: 391fd89ac01d712c6fbaae42cf0f285c67ec5cdc $
19 *
20 * @file xlat_redundant.c
21 * @brief Register xlat functions for calling redundant xlats
22 *
23 * @copyright 2023 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 */
25RCSID("$Id: 391fd89ac01d712c6fbaae42cf0f285c67ec5cdc $")
26
27#include <freeradius-devel/unlang/interpret.h>
28#include <freeradius-devel/unlang/xlat_redundant.h>
29#include <freeradius-devel/unlang/xlat_func.h>
30#include <freeradius-devel/unlang/xlat_priv.h>
31
32#include <freeradius-devel/server/module.h>
33#include <freeradius-devel/server/module_rlm.h>
34
35#include <freeradius-devel/util/rand.h>
36
37
38/*
39 * Internal redundant handler for xlats
40 */
41typedef enum {
42 XLAT_REDUNDANT_INVALID = 0, //!< Not a valid redundant type.
43 XLAT_REDUNDANT, //!< Use the first xlat function first, then
44 ///< go through in sequence, using the next
45 ///< function after each failure.
46
47 XLAT_LOAD_BALANCE, //!< Pick a random xlat, and if that fails
48 ///< then the call as a whole fails.
49
50 XLAT_REDUNDANT_LOAD_BALANCE, //!< Pick a random xlat to start, then fail
51 ///< between the other xlats in the redundant
52 ///< group.
54
55typedef struct {
56 fr_dlist_t entry; //!< Entry in the redundant function list.
57 xlat_t const *func; //!< Resolved xlat function.
59
60typedef struct {
61 xlat_redundant_type_t type; //!< Type of redundant xlat expression.
62 fr_dlist_head_t funcs; //!< List of redundant xlat functions.
63 CONF_SECTION *cs; //!< That this redundant xlat list was created from.
65
66typedef struct {
67 xlat_redundant_t *xr; //!< Information about the redundant xlat.
68 xlat_exp_head_t **ex; //!< Array of xlat expressions created by
69 ///< tokenizing the arguments to the redundant
70 ///< xlat, then duplicating them multiple times,
71 ///< one for each xlat function that may be called.
73
74typedef struct {
75 bool last_success; //!< Did the last call succeed?
76
77 xlat_exp_head_t **first; //!< First function called.
78 ///< Used for redundant-load-balance.
79 xlat_exp_head_t **current; //!< Last function called, used for redundant xlats.
81
82/** Pass back the result from a single redundant child call
83 *
84 */
86 xlat_ctx_t const *xctx,
87 request_t *request, UNUSED fr_value_box_list_t *in)
88{
90 xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
92
93 if (rctx->last_success) {
94 done:
95 talloc_free(rctx);
96 return xa;
97 }
98
99 /*
100 * We're at the end, loop back to the start
101 */
102 if (++rctx->current >= (xri->ex + talloc_array_length(xri->ex))) rctx->current = xri->ex;
103
104 /*
105 * We're back to the first one we tried, fail...
106 */
107 if (rctx->current == rctx->first) {
108 error:
109 xa = XLAT_ACTION_FAIL;
110 goto done;
111 }
112
113 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
114
115 /*
116 * Push the next child...
117 */
118 if (unlang_xlat_push(ctx, &rctx->last_success, (fr_value_box_list_t *)out->dlist,
119 request, *rctx->current, UNLANG_SUB_FRAME) < 0) goto error;
120
122}
123
124/** Pass back the result from a single redundant child call
125 *
126 */
128 xlat_ctx_t const *xctx,
129 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
130{
131 xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
133
134 talloc_free(rctx);
135
136 return xa;
137}
138
139/** xlat "redundant", "load-balance" and "redundant-load-balance" processing
140 *
141 * @ingroup xlat_functions
142 */
144 xlat_ctx_t const *xctx,
145 request_t *request, UNUSED fr_value_box_list_t *in)
146{
149
150 MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_redundant_rctx_t));
151
152 switch (xri->xr->type) {
153 /*
154 * Run through each of the redundant functions sequentially
155 * starting at the first.
156 */
157 case XLAT_REDUNDANT:
158 rctx->current = rctx->first = xri->ex; /* First element first */
159 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) {
160 error:
161 talloc_free(rctx);
162 return XLAT_ACTION_FAIL;
163 }
164 break;
165
166 /*
167 * Run a single random redundant function.
168 */
170 rctx->first = &xri->ex[(size_t)fr_rand() & (talloc_array_length(xri->ex) - 1)]; /* Random start */
171 if (unlang_xlat_yield(request, xlat_load_balance_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
172 break;
173
174 /*
175 * Run through each of the redundant functions sequentially
176 * starting at a random element.
177 */
179 rctx->first = &xri->ex[(size_t)fr_rand() & (talloc_array_length(xri->ex) - 1)]; /* Random start */
180 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
181 break;
182
183 default:
184 fr_assert(0);
185 }
186
187 if (unlang_xlat_push(ctx, &rctx->last_success, (fr_value_box_list_t *)out->dlist,
188 request, *rctx->current, UNLANG_SUB_FRAME) < 0) return XLAT_ACTION_FAIL;
189
191}
192
194{
195 xlat_exp_foreach(head, node) {
196 if (node->type == XLAT_BOX) {
197 fr_value_box_mark_safe_for(&node->data, safe_for);
198 continue;
199 }
200
201 if (node->type == XLAT_GROUP) {
202 xlat_mark_safe_for(node->group, safe_for);
203 }
204 }
205}
206
207/** Allocate an xlat node to call an xlat function
208 *
209 * @param[in] ctx to allocate the new node in.
210 * @param[in] func to call.
211 * @param[in] args Arguments to the function. Will be copied,
212 * and freed when the new xlat node is freed.
213 * @param[in] dict the dictionary
214 */
215static xlat_exp_t *xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t const *func, xlat_exp_head_t const *args, fr_dict_t const *dict)
216{
217 xlat_exp_t *node;
218
219 MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, func->name, strlen(func->name)));
220 xlat_exp_set_func(node, func, dict);
221
222 node->flags = func->flags;
223 node->flags.impure_func = !func->flags.pure;
224
225 if (args) {
226 xlat_flags_merge(&node->flags, &args->flags);
227
228 /*
229 * If the function is pure, AND it's arguments are pure,
230 * then remember that we need to call a pure function.
231 */
232 node->flags.can_purify = (func->flags.pure && args->flags.pure) | args->flags.can_purify;
233
234 MEM(node->call.args = xlat_exp_head_alloc(node));
235 node->call.args->is_argv = true;
236
237 if (unlikely(xlat_copy(node, node->call.args, args) < 0)) {
238 talloc_free(node);
239 return NULL;
240 }
241 }
242
243 /*
244 * The original tokenizing is done using the redundant xlat argument parser so the boxes need to
245 * have their "safe_for" value changed to the new one.
246 */
247 if (func->args) {
248 xlat_arg_parser_t const *arg_p;
249 xlat_exp_t *arg;
250
252
253 arg = xlat_exp_head(node->call.args);
254
255 for (arg_p = node->call.func->args; arg_p->type != FR_TYPE_NULL; arg_p++) {
256 if (!arg) break;
257
258 xlat_mark_safe_for(arg->group, arg_p->safe_for);
259
260 arg = xlat_exp_next(node->call.args, arg);
261 }
262 }
263
264 return node;
265}
266
267
268/** Allocate additional nodes for evaluation
269 *
270 */
272{
273 xlat_redundant_t *xr = talloc_get_type_abort(xctx->uctx, xlat_redundant_t);
274 xlat_redundant_inst_t *xri = talloc_get_type_abort(xctx->inst, xlat_redundant_inst_t);
275 unsigned int num = 0;
276 xlat_redundant_func_t const *first;
277 fr_dict_t const *dict = NULL;
278
279 MEM(xri->ex = talloc_array(xri, xlat_exp_head_t *, fr_dlist_num_elements(&xr->funcs)));
280 xri->xr = xr;
281
282 first = talloc_get_type_abort(fr_dlist_head(&xr->funcs), xlat_redundant_func_t);
283
284 /*
285 * For each function, create the appropriate xlat
286 * node, and duplicate the child arguments.
287 */
289 xlat_exp_t *node;
291
292 /*
293 * We have to do this here as it only
294 * becomes an error when the user tries
295 * to use the redundant xlat.
296 */
297 if ((!first->func->args && xrf->func->args) ||
298 (first->func->args && !xrf->func->args)) {
299 cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different argument styles "
300 "cannot be used in the same redundant section", first->func->name, xrf->func->name);
301 error:
302 talloc_free(xri->ex);
303 return -1;
304 }
305
306 if (!dict) {
307 dict = xctx->ex->call.dict;
308 fr_assert(dict != NULL);
309
310 } else if (dict != xctx->ex->call.dict) {
311 cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different dictionaries"
312 "cannot be used in the same redundant section", first->func->name, xrf->func->name);
313 goto error;
314 }
315
316 /*
317 * We pass the current arguments in
318 * so that the instantiation functions
319 * for the new node can operate
320 * correctly.
321 */
323 MEM(node = xlat_exp_func_alloc(head, xrf->func, xctx->ex->call.args, dict));
325
326 if (xlat_validate_function_args(node) < 0) {
327 PERROR("Invalid arguments for redundant expansion function \"%s\"",
328 xrf->func->name);
329 goto error;
330 }
331
332 /*
333 * Add the xlat function (and any children)
334 * to the end of the instantiation list so
335 * they'll get called at some point after
336 * we return.
337 */
338 head->flags = node->flags;
339 if (xlat_finalize(head, NULL) < 0) {
340 PERROR("Failed bootstrapping function \"%s\"",
341 xrf->func->name);
342 goto error;
343 }
344 xri->ex[num++] = head;
345 }
346
347 /*
348 * Free the original argument nodes so they're
349 * not evaluated when the redundant xlat is called.
350 *
351 * We need to re-evaluate the arguments for each
352 * redundant function call we perform.
353 *
354 * The xlat_exp_func_alloc call above associates
355 * a copy of the original arguments with each
356 * function that's called.
357 */
358 fr_dlist_talloc_free(&xctx->ex->call.args->dlist);
359
360 return 0;
361}
362
367
368static inline CC_HINT(always_inline)
370{
372
373 MEM(xrf = talloc_zero(xr, xlat_redundant_func_t));
374 xrf->func = x;
375 fr_dlist_insert_tail(&xr->funcs, xrf);
376}
377
378/** Compare two module_rlm_xlat_t based on whether they have the same name
379 *
380 * @note If the two xlats both have the same name as the module that registered them,
381 * then they are considered equal.
382 */
383static int8_t module_xlat_cmp(void const *a, void const *b)
384{
387 char const *a_p, *b_p;
388
389 /*
390 * A null result means a self-named module xlat,
391 * which is always equal to another self-named
392 * module xlat.
393 */
394 a_p = strchr(mrx_a->xlat->name, '.');
395 b_p = strchr(mrx_b->xlat->name, '.');
396 if (!a_p && !b_p) return 0;
397
398 /*
399 * Compare the bit after the module name
400 */
401 if (!a_p || !b_p) return CMP(a_p, b_p);
402
403 return CMP(strcmp(a_p, b_p), 0);
404}
405
406static int8_t module_qualified_xlat_cmp(void const *a, void const *b)
407{
408 int8_t ret;
409
412
413 ret = module_xlat_cmp(a, b);
414 if (ret != 0) return ret;
415
416 return CMP(mrx_a->mi, mrx_b->mi);
417}
418
419/** Registers a redundant xlat
420 *
421 * These xlats wrap the xlat methods of the modules in a redundant section,
422 * emulating the behaviour of a redundant section, but over xlats.
423 *
424 * @return
425 * - 0 on success.
426 * - -1 on error.
427 * - 1 if the modules in the section do not have an xlat method.
428 */
430{
431 static fr_table_num_sorted_t const xlat_redundant_type_table[] = {
432 { L("load-balance"), XLAT_LOAD_BALANCE },
433 { L("redundant"), XLAT_REDUNDANT },
434 { L("redundant-load-balance"), XLAT_REDUNDANT_LOAD_BALANCE },
435 };
436 static size_t xlat_redundant_type_table_len = NUM_ELEMENTS(xlat_redundant_type_table);
437
438 char const *name1;
439 xlat_redundant_type_t xr_type;
440 xlat_func_flags_t default_flags = 0; /* Prevent warnings about default flags if xr_rype is corrupt */
441
442 fr_type_t return_type = FR_TYPE_NULL;
443
444 CONF_ITEM *ci = NULL;
445 int children = 0, i;
446 fr_rb_tree_t *mrx_tree; /* Temporary tree for ordering xlats */
447
448 name1 = cf_section_name1(cs);
449 xr_type = fr_table_value_by_str(xlat_redundant_type_table, name1, XLAT_REDUNDANT_INVALID);
450 switch (xr_type) {
452 cf_log_err(cs, "Invalid redundant section verb \"%s\"", name1);
453 return -1;
454
455 case XLAT_REDUNDANT:
456 default_flags = XLAT_FUNC_FLAG_PURE; /* Can be pure */
457 break;
458
460 default_flags = XLAT_FUNC_FLAG_NONE; /* Can never be pure because of random selection */
461 break;
462
464 default_flags = XLAT_FUNC_FLAG_NONE; /* Can never be pure because of random selection */
465 break;
466 }
467
468 /*
469 * Count the children
470 */
471 while ((ci = cf_item_next(cs, ci))) {
472 if (!cf_item_is_pair(ci)) continue;
473
474 children++;
475 }
476
477 /*
478 * There must be at least one child.
479 *
480 * It's useful to allow a redundant section with only one
481 * child, for debugging.
482 */
483 if (children == 0) {
484 cf_log_err(cs, "%s %s { ... } section must contain at least one module",
486 return -1;
487 }
488
489 /*
490 * Resolve all the modules in the redundant section,
491 * and insert all the mrx into a temporary tree to
492 * order them.
493 *
494 * Next we'll iterate over all the mrx, creating
495 * redundant xlats from contiguous runs of mrxs
496 * pointing to the same xlat.
497 */
499 for (ci = cf_item_next(cs, NULL), i = 0;
500 ci;
501 ci = cf_item_next(cs, ci), i++) {
504 char const *name;
505
506 if (!cf_item_is_pair(ci)) continue;
507
509
511 if (!mi) {
512 cf_log_err(ci, "Module '%s' not found. Referenced in %s %s { ... } section",
514 error:
515 talloc_free(mrx_tree);
516 return -1;
517 }
518
519 mri = talloc_get_type_abort(mi->uctx, module_rlm_instance_t);
520 fr_dlist_foreach(&mri->xlats, module_rlm_xlat_t const, mrx) {
521 if (!fr_rb_insert(mrx_tree, mrx)) {
522 cf_log_err(cs, "Module '%s' referenced multiple times in %s %s { ... } section",
523 mrx->mi->name, cf_section_name1(cs), cf_section_name2(cs));
524 goto error;
525 }
526 }
527 }
528
529 if (fr_rb_num_elements(mrx_tree) == 0) {
530 cf_log_debug(cs, "No expansions exported by modules in %s %s { ... } section, "
531 "not registering redundant/load-balance expansion",
533 talloc_free(mrx_tree);
534 return 0;
535 }
536
537 /*
538 * Iterate over the xlats registered for the first module,
539 * verifying that the other module instances have all registered
540 * the similarly named xlat functions.
541 *
542 * We ignore any xlat functions that aren't available in all the
543 * modules.
544 */
545 {
548 fr_sbuff_marker_t name_start;
550 module_rlm_xlat_t *mrx, *prev_mrx;
552
553 FR_SBUFF_TALLOC_THREAD_LOCAL(&name, 128, SIZE_MAX);
554
555 /*
556 * Prepopulate the name buffer with <section_name2>.
557 * as every function wil be registered with this
558 * prefix.
559 */
561 (fr_sbuff_in_char(name, '.') <= 0)) {
562 cf_log_perr(cs, "Name too long");
563 return -1;
564 }
565
566 fr_sbuff_marker(&name_start, name);
567
568 mrx = fr_rb_iter_init_inorder(&iter, mrx_tree);
569
570 /*
571 * Iterate over the all the xlats, registered by
572 * all the modules in the section.
573 */
574 while (mrx) {
575 xlat_t *xlat;
576 xlat_func_flags_t flags = default_flags;
577 char const *name_p;
578
579 mi = mrx->mi;
580
581 /*
582 * Where the xlat name is in the format <mod>.<name2>
583 * then the redundant xlat will be <section_name2>.<xlat_name>.
584 *
585 * Where the xlat has no '.', it's likely just the module
586 * name, in which case we just use <section_name2>.
587 */
588 name_p = strchr(mrx->xlat->name, '.');
589 if (name_p) {
590 name_p++;
591 fr_sbuff_set(name, &name_start); /* Reset the aggregation buffer to the '.' */
592 if (fr_sbuff_in_bstrncpy(name, name_p, strlen(name_p)) < 0) {
593 cf_log_perr(cs, "Name too long");
594 goto error;
595 }
596 name_p = fr_sbuff_start(name);
597 } else {
598 name_p = cf_section_name2(cs);
599 }
600
601 MEM(xr = talloc_zero(NULL, xlat_redundant_t));
602 xr->type = xr_type;
603 xr->cs = cs;
605
606 /*
607 * Iterate over all the xlats registered by all the modules
608 * in the section, when we reach the end of a run of common
609 * xlats, we register the redundant xlat.
610 *
611 * Note: Just because a xlat function has the same name,
612 * it does not mean the function signature is compatible.
613 *
614 * These issues are caught when we instantiate a redundant
615 * xlat, as the arguments passed to the redunant xlat are
616 * validated against the argument definitions for each
617 * individual xlat the redunant xlat would call.
618 */
619 do {
620 if (!mrx->xlat->flags.pure) flags &= ~XLAT_FUNC_FLAG_PURE;
622 prev_mrx = mrx;
623 } while ((mrx = fr_rb_iter_next_inorder(&iter)) && (module_xlat_cmp(prev_mrx, mrx) == 0));
624
625 /*
626 * Warn, but allow, redundant/failover expansions that are
627 * neither redundant, nor failover.
628 *
629 * Sometimes useful to comment out modules during testing.
630 */
631 if (fr_dlist_num_elements(&xr->funcs) == 1) {
632 cf_log_warn(cs, "%s expansion has no alternates, only %s",
633 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"),
634 ((xlat_redundant_func_t *)fr_dlist_head(&xr->funcs))->func->name);
635
636 }
637
638 /*
639 * Register the new redundant xlat, and hang it off of
640 * the first module instance in the section.
641 *
642 * This isn't great, but at least the xlat should
643 * get unregistered at about the right time.
644 */
645 xlat = xlat_func_register(mi, name_p, xlat_redundant, return_type);
646 if (unlikely(xlat == NULL)) {
647 cf_log_err(cs, "Registering expansion for %s section failed",
648 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"));
649 talloc_free(xr);
650 return -1;
651 }
652 talloc_steal(xlat, xr); /* redundant xlat should own its own config */
653
654 cf_log_debug(cs, "Registered %s expansion \"%s\" with %u alternates",
655 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"),
656 xlat->name, fr_dlist_num_elements(&xr->funcs));
657
658 xlat_func_flags_set(xlat, flags);
661 }
662 }
663 talloc_free(mrx_tree);
664
665 return 0;
666}
va_list args
Definition acutest.h:770
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#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:112
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
Common header for all CONF_* types.
Definition cf_priv.h:49
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:631
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1184
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1170
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:663
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1577
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_item_next(_parent, _curr)
Definition cf_util.h:92
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:296
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:290
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:292
#define MEM(x)
Definition debug.h:36
static fr_slen_t in
Definition dict.h:833
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:486
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
Definition dlist.h:94
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
Definition dlist.h:908
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:939
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:378
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:275
Head of a doubly linked list.
Definition dlist.h:51
Entry in a doubly linked list.
Definition dlist.h:41
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_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1462
#define UNLANG_SUB_FRAME
Definition interpret.h:36
#define PERROR(_fmt,...)
Definition log.h:228
talloc_free(reap)
fr_type_t
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VOID
User data.
unsigned long int size_t
module_instance_t * module_rlm_static_by_name(module_instance_t const *parent, char const *asked_name)
Definition module_rlm.c:814
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
xlat_t const * xlat
The xlat function.
Definition module_rlm.h:53
An xlat function registered to a module.
Definition module_rlm.h:52
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition rb.c:824
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
#define fr_rb_talloc_alloc(_ctx, _type, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:205
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:321
The main red black tree structure.
Definition rb.h:73
static char const * name
ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1482
ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1504
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_set(_dst, _src)
#define fr_sbuff_in_char(_sbuff,...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
void * uctx
Extra data passed to module_instance_alloc.
Definition module.h:340
Module instance data.
Definition module.h:266
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define talloc_get_type_abort_const
Definition talloc.h:282
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition xlat.c:569
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:282
fr_type_t type
Type to cast argument to.
Definition xlat.h:153
int xlat_validate_function_args(xlat_exp_t *node)
xlat_escape_func_t func
Function to handle tainted values.
Definition xlat.h:154
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition xlat.h:136
static fr_slen_t head
Definition xlat.h:416
fr_value_box_safe_for_t safe_for
Escaped value to set for boxes processed by this escape function.
Definition xlat.h:155
#define xlat_copy(_ctx, _out, _in)
Definition xlat.h:454
uint8_t can_purify
if the xlat has a pure function with pure arguments.
Definition xlat.h:111
uint8_t pure
has no external side effects, true for BOX, LITERAL, and some functions
Definition xlat.h:109
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:166
uint8_t impure_func
xlat contains an impure function
Definition xlat.h:110
int xlat_finalize(xlat_exp_head_t *head, fr_event_list_t *runtime_el)
Bootstrap static xlats, or instantiate ephemeral ones.
Definition xlat_inst.c:693
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
Definition xlat.h:42
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
Definition xlat.h:39
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:144
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1063
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition value.h:155
static size_t char ** out
Definition value.h:1012
void xlat_exp_set_func(xlat_exp_t *node, xlat_t const *func, fr_dict_t const *dict)
Set the function for a node.
Definition xlat_alloc.c:274
void * rctx
Resume context.
Definition xlat_ctx.h:54
xlat_exp_t * ex
Tokenized expression to use in expansion.
Definition xlat_ctx.h:63
void const * inst
xlat instance data.
Definition xlat_ctx.h:50
void * uctx
Passed to the registration function.
Definition xlat_ctx.h:65
void * inst
xlat instance data to populate.
Definition xlat_ctx.h:62
An xlat calling ctx.
Definition xlat_ctx.h:49
An xlat instantiation ctx.
Definition xlat_ctx.h:61
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
Definition xlat_func.c:398
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:362
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:216
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
Definition xlat_func.h:93
xlat_func_flags_t
Definition xlat_func.h:36
@ XLAT_FUNC_FLAG_NONE
Definition xlat_func.h:37
@ XLAT_FUNC_FLAG_PURE
Definition xlat_func.h:38
char const * name
Name of xlat function.
Definition xlat_priv.h:64
#define xlat_exp_head_alloc(_ctx)
Definition xlat_priv.h:272
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:154
static xlat_exp_t * xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
Definition xlat_priv.h:245
@ XLAT_BOX
fr_value_box_t
Definition xlat_priv.h:108
@ XLAT_FUNC
xlat module
Definition xlat_priv.h:110
@ XLAT_GROUP
encapsulated string of xlats
Definition xlat_priv.h:116
xlat_arg_parser_t const * args
Definition of args consumed.
Definition xlat_priv.h:94
static void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
Merge flags from child to parent.
Definition xlat_priv.h:228
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
Definition xlat_priv.h:281
xlat_flags_t flags
various flags
Definition xlat_priv.h:92
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
Definition xlat_priv.h:221
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
Definition xlat_priv.h:237
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition xlat_priv.h:208
An xlat expansion node.
Definition xlat_priv.h:148
static xlat_action_t xlat_load_balance_resume(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Pass back the result from a single redundant child call.
xlat_redundant_t * xr
Information about the redundant xlat.
static xlat_arg_parser_t const xlat_redundant_args[]
static int8_t module_qualified_xlat_cmp(void const *a, void const *b)
bool last_success
Did the last call succeed?
fr_dlist_head_t funcs
List of redundant xlat functions.
fr_dlist_t entry
Entry in the redundant function list.
static int8_t module_xlat_cmp(void const *a, void const *b)
Compare two module_rlm_xlat_t based on whether they have the same name.
xlat_exp_head_t ** first
First function called.
xlat_redundant_type_t type
Type of redundant xlat expression.
xlat_exp_head_t ** current
Last function called, used for redundant xlats.
xlat_exp_head_t ** ex
Array of xlat expressions created by tokenizing the arguments to the redundant xlat,...
static void xlat_mark_safe_for(xlat_exp_head_t *head, fr_value_box_safe_for_t safe_for)
static void xlat_redundant_add_xlat(xlat_redundant_t *xr, xlat_t const *x)
static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx)
Allocate additional nodes for evaluation.
int xlat_register_redundant(CONF_SECTION *cs)
Registers a redundant xlat.
xlat_t const * func
Resolved xlat function.
CONF_SECTION * cs
That this redundant xlat list was created from.
static xlat_exp_t * xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t const *func, xlat_exp_head_t const *args, fr_dict_t const *dict)
Allocate an xlat node to call an xlat function.
xlat_redundant_type_t
@ XLAT_REDUNDANT_INVALID
Not a valid redundant type.
@ XLAT_REDUNDANT
Use the first xlat function first, then go through in sequence, using the next function after each fa...
@ XLAT_LOAD_BALANCE
Pick a random xlat, and if that fails then the call as a whole fails.
@ XLAT_REDUNDANT_LOAD_BALANCE
Pick a random xlat to start, then fail between the other xlats in the redundant group.
static xlat_action_t xlat_redundant_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Pass back the result from a single redundant child call.