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: dd4aeea73bca5de26b8ced9a2de606e247f38b5e $
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: dd4aeea73bca5de26b8ced9a2de606e247f38b5e $")
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 unlang_result_t last_result; //!< 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 (XLAT_RESULT_SUCCESS(&rctx->last_result)) {
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 fr_strerror_printf("Failed all choices for redundant expansion %s", xctx->ex->fmt);
109 error:
110 xa = XLAT_ACTION_FAIL;
111 goto done;
112 }
113
114 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
115
116 /*
117 * Push the next child...
118 */
119 if (unlang_xlat_push(ctx, &rctx->last_result, (fr_value_box_list_t *)out->dlist,
120 request, *rctx->current, UNLANG_SUB_FRAME) < 0) goto error;
121
123}
124
125/** Pass back the result from a single redundant child call
126 *
127 */
129 xlat_ctx_t const *xctx,
130 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
131{
132 xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
134
135 talloc_free(rctx);
136
137 return xa;
138}
139
140/** xlat "redundant", "load-balance" and "redundant-load-balance" processing
141 *
142 * @ingroup xlat_functions
143 */
145 xlat_ctx_t const *xctx,
146 request_t *request, UNUSED fr_value_box_list_t *in)
147{
150
151 MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_redundant_rctx_t));
152
153 switch (xri->xr->type) {
154 /*
155 * Run through each of the redundant functions sequentially
156 * starting at the first.
157 */
158 case XLAT_REDUNDANT:
159 rctx->current = rctx->first = xri->ex; /* First element first */
160 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) {
161 error:
162 talloc_free(rctx);
163 return XLAT_ACTION_FAIL;
164 }
165 break;
166
167 /*
168 * Run a single random redundant function.
169 */
171 rctx->first = &xri->ex[(size_t)fr_rand() & (talloc_array_length(xri->ex) - 1)]; /* Random start */
172 if (unlang_xlat_yield(request, xlat_load_balance_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
173 break;
174
175 /*
176 * Run through each of the redundant functions sequentially
177 * starting at a random element.
178 */
180 rctx->first = &xri->ex[(size_t)fr_rand() & (talloc_array_length(xri->ex) - 1)]; /* Random start */
181 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
182 break;
183
184 default:
185 fr_assert(0);
186 }
187
188 if (unlang_xlat_push(ctx, &rctx->last_result, (fr_value_box_list_t *)out->dlist,
189 request, *rctx->current, UNLANG_SUB_FRAME) < 0) return XLAT_ACTION_FAIL;
190
192}
193
195{
196 xlat_exp_foreach(head, node) {
197 if (node->type == XLAT_BOX) {
198 fr_value_box_mark_safe_for(&node->data, safe_for);
199 continue;
200 }
201
202 if (node->type == XLAT_GROUP) {
203 xlat_mark_safe_for(node->group, safe_for);
204 }
205 }
206}
207
208/** Allocate an xlat node to call an xlat function
209 *
210 * @param[in] ctx to allocate the new node in.
211 * @param[in] func to call.
212 * @param[in] args Arguments to the function. Will be copied,
213 * and freed when the new xlat node is freed.
214 * @param[in] dict the dictionary
215 */
216static 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)
217{
218 xlat_exp_t *node;
219
220 MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, func->name, strlen(func->name)));
221 xlat_exp_set_func(node, func, dict);
222
223 node->flags = func->flags;
224 node->flags.impure_func = !func->flags.pure;
225
226 if (args) {
227 xlat_flags_merge(&node->flags, &args->flags);
228
229 /*
230 * If the function is pure, AND it's arguments are pure,
231 * then remember that we need to call a pure function.
232 */
233 node->flags.can_purify = (func->flags.pure && args->flags.pure) | args->flags.can_purify;
234
235 MEM(node->call.args = xlat_exp_head_alloc(node));
236 node->call.args->is_argv = true;
237
238 if (unlikely(xlat_copy(node, node->call.args, args) < 0)) {
239 talloc_free(node);
240 return NULL;
241 }
242 }
243
244 /*
245 * The original tokenizing is done using the redundant xlat argument parser so the boxes need to
246 * have their "safe_for" value changed to the new one.
247 */
248 if (func->args) {
249 xlat_arg_parser_t const *arg_p;
250 xlat_exp_t *arg;
251
253
254 arg = xlat_exp_head(node->call.args);
255
256 for (arg_p = node->call.func->args; arg_p->type != FR_TYPE_NULL; arg_p++) {
257 if (!arg) break;
258
259 xlat_mark_safe_for(arg->group, arg_p->safe_for);
260
261 arg = xlat_exp_next(node->call.args, arg);
262 }
263 }
264
265 return node;
266}
267
268
269/** Allocate additional nodes for evaluation
270 *
271 */
273{
274 xlat_redundant_t *xr = talloc_get_type_abort(xctx->uctx, xlat_redundant_t);
275 xlat_redundant_inst_t *xri = talloc_get_type_abort(xctx->inst, xlat_redundant_inst_t);
276 unsigned int num = 0;
277 xlat_redundant_func_t const *first;
278 fr_dict_t const *dict = NULL;
279
280 MEM(xri->ex = talloc_array(xri, xlat_exp_head_t *, fr_dlist_num_elements(&xr->funcs)));
281 xri->xr = xr;
282
283 first = talloc_get_type_abort(fr_dlist_head(&xr->funcs), xlat_redundant_func_t);
284
285 /*
286 * For each function, create the appropriate xlat
287 * node, and duplicate the child arguments.
288 */
290 xlat_exp_t *node;
292
293 /*
294 * We have to do this here as it only
295 * becomes an error when the user tries
296 * to use the redundant xlat.
297 */
298 if ((!first->func->args && xrf->func->args) ||
299 (first->func->args && !xrf->func->args)) {
300 cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different argument styles "
301 "cannot be used in the same redundant section", first->func->name, xrf->func->name);
302 error:
303 talloc_free(xri->ex);
304 return -1;
305 }
306
307 if (!dict) {
308 dict = xctx->ex->call.dict;
309 fr_assert(dict != NULL);
310
311 } else if (dict != xctx->ex->call.dict) {
312 cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different dictionaries"
313 "cannot be used in the same redundant section", first->func->name, xrf->func->name);
314 goto error;
315 }
316
317 /*
318 * We pass the current arguments in
319 * so that the instantiation functions
320 * for the new node can operate
321 * correctly.
322 */
324 MEM(node = xlat_exp_func_alloc(head, xrf->func, xctx->ex->call.args, dict));
326
327 if (xlat_validate_function_args(node) < 0) {
328 PERROR("Invalid arguments for redundant expansion function \"%s\"",
329 xrf->func->name);
330 goto error;
331 }
332
333 /*
334 * Add the xlat function (and any children)
335 * to the end of the instantiation list so
336 * they'll get called at some point after
337 * we return.
338 */
339 head->flags = node->flags;
340 if (xlat_finalize(head, NULL) < 0) {
341 PERROR("Failed bootstrapping function \"%s\"",
342 xrf->func->name);
343 goto error;
344 }
345 xri->ex[num++] = head;
346 }
347
348 /*
349 * Free the original argument nodes so they're
350 * not evaluated when the redundant xlat is called.
351 *
352 * We need to re-evaluate the arguments for each
353 * redundant function call we perform.
354 *
355 * The xlat_exp_func_alloc call above associates
356 * a copy of the original arguments with each
357 * function that's called.
358 */
359 fr_dlist_talloc_free(&xctx->ex->call.args->dlist);
360
361 return 0;
362}
363
368
369static inline CC_HINT(always_inline)
371{
373
374 MEM(xrf = talloc_zero(xr, xlat_redundant_func_t));
375 xrf->func = x;
376 fr_dlist_insert_tail(&xr->funcs, xrf);
377}
378
379/** Compare two module_rlm_xlat_t based on whether they have the same name
380 *
381 * @note If the two xlats both have the same name as the module that registered them,
382 * then they are considered equal.
383 */
384static int8_t module_xlat_cmp(void const *a, void const *b)
385{
388 char const *a_p, *b_p;
389
390 /*
391 * A null result means a self-named module xlat,
392 * which is always equal to another self-named
393 * module xlat.
394 */
395 a_p = strchr(mrx_a->xlat->name, '.');
396 b_p = strchr(mrx_b->xlat->name, '.');
397 if (!a_p && !b_p) return 0;
398
399 /*
400 * Compare the bit after the module name
401 */
402 if (!a_p || !b_p) return CMP(a_p, b_p);
403
404 return CMP(strcmp(a_p, b_p), 0);
405}
406
407static int8_t module_qualified_xlat_cmp(void const *a, void const *b)
408{
409 int8_t ret;
410
413
414 ret = module_xlat_cmp(a, b);
415 if (ret != 0) return ret;
416
417 return CMP(mrx_a->mi, mrx_b->mi);
418}
419
420/** Registers a redundant xlat
421 *
422 * These xlats wrap the xlat methods of the modules in a redundant section,
423 * emulating the behaviour of a redundant section, but over xlats.
424 *
425 * @return
426 * - 0 on success.
427 * - -1 on error.
428 * - 1 if the modules in the section do not have an xlat method.
429 */
431{
432 static fr_table_num_sorted_t const xlat_redundant_type_table[] = {
433 { L("load-balance"), XLAT_LOAD_BALANCE },
434 { L("redundant"), XLAT_REDUNDANT },
435 { L("redundant-load-balance"), XLAT_REDUNDANT_LOAD_BALANCE },
436 };
437 static size_t xlat_redundant_type_table_len = NUM_ELEMENTS(xlat_redundant_type_table);
438
439 char const *name1;
440 xlat_redundant_type_t xr_type;
441 xlat_func_flags_t default_flags = 0; /* Prevent warnings about default flags if xr_rype is corrupt */
442
443 fr_type_t return_type = FR_TYPE_NULL;
444
445 CONF_ITEM *ci = NULL;
446 int children = 0, i;
447 fr_rb_tree_t *mrx_tree; /* Temporary tree for ordering xlats */
448
449 name1 = cf_section_name1(cs);
450 xr_type = fr_table_value_by_str(xlat_redundant_type_table, name1, XLAT_REDUNDANT_INVALID);
451 switch (xr_type) {
453 cf_log_err(cs, "Invalid redundant section verb \"%s\"", name1);
454 return -1;
455
456 case XLAT_REDUNDANT:
457 default_flags = XLAT_FUNC_FLAG_PURE; /* Can be pure */
458 break;
459
461 default_flags = XLAT_FUNC_FLAG_NONE; /* Can never be pure because of random selection */
462 break;
463
465 default_flags = XLAT_FUNC_FLAG_NONE; /* Can never be pure because of random selection */
466 break;
467 }
468
469 /*
470 * Count the children
471 */
472 while ((ci = cf_item_next(cs, ci))) {
473 if (!cf_item_is_pair(ci)) continue;
474
475 children++;
476 }
477
478 /*
479 * There must be at least one child.
480 *
481 * It's useful to allow a redundant section with only one
482 * child, for debugging.
483 */
484 if (children == 0) {
485 cf_log_err(cs, "%s %s { ... } section must contain at least one module",
487 return -1;
488 }
489
490 /*
491 * Resolve all the modules in the redundant section,
492 * and insert all the mrx into a temporary tree to
493 * order them.
494 *
495 * Next we'll iterate over all the mrx, creating
496 * redundant xlats from contiguous runs of mrxs
497 * pointing to the same xlat.
498 */
500 for (ci = cf_item_next(cs, NULL), i = 0;
501 ci;
502 ci = cf_item_next(cs, ci), i++) {
505 char const *name;
506
507 if (!cf_item_is_pair(ci)) continue;
508
510
512 if (!mi) {
513 cf_log_err(ci, "Module '%s' not found. Referenced in %s %s { ... } section",
515 error:
516 talloc_free(mrx_tree);
517 return -1;
518 }
519
520 mri = talloc_get_type_abort(mi->uctx, module_rlm_instance_t);
521 fr_dlist_foreach(&mri->xlats, module_rlm_xlat_t const, mrx) {
522 if (!fr_rb_insert(mrx_tree, mrx)) {
523 cf_log_err(cs, "Module '%s' referenced multiple times in %s %s { ... } section",
524 mrx->mi->name, cf_section_name1(cs), cf_section_name2(cs));
525 goto error;
526 }
527 }
528 }
529
530 if (fr_rb_num_elements(mrx_tree) == 0) {
531 cf_log_debug(cs, "No expansions exported by modules in %s %s { ... } section, "
532 "not registering redundant/load-balance expansion",
534 talloc_free(mrx_tree);
535 return 0;
536 }
537
538 /*
539 * Iterate over the xlats registered for the first module,
540 * verifying that the other module instances have all registered
541 * the similarly named xlat functions.
542 *
543 * We ignore any xlat functions that aren't available in all the
544 * modules.
545 */
546 {
549 fr_sbuff_marker_t name_start;
551 module_rlm_xlat_t *mrx, *prev_mrx;
553
554 FR_SBUFF_TALLOC_THREAD_LOCAL(&name, 128, SIZE_MAX);
555
556 /*
557 * Prepopulate the name buffer with <section_name2>.
558 * as every function wil be registered with this
559 * prefix.
560 */
562 (fr_sbuff_in_char(name, '.') <= 0)) {
563 cf_log_perr(cs, "Name too long");
564 return -1;
565 }
566
567 fr_sbuff_marker(&name_start, name);
568
569 mrx = fr_rb_iter_init_inorder(&iter, mrx_tree);
570
571 /*
572 * Iterate over the all the xlats, registered by
573 * all the modules in the section.
574 */
575 while (mrx) {
576 xlat_t *xlat;
577 xlat_func_flags_t flags = default_flags;
578 char const *name_p;
579
580 mi = mrx->mi;
581
582 /*
583 * Where the xlat name is in the format <mod>.<name2>
584 * then the redundant xlat will be <section_name2>.<xlat_name>.
585 *
586 * Where the xlat has no '.', it's likely just the module
587 * name, in which case we just use <section_name2>.
588 */
589 name_p = strchr(mrx->xlat->name, '.');
590 if (name_p) {
591 name_p++;
592 fr_sbuff_set(name, &name_start); /* Reset the aggregation buffer to the '.' */
593 if (fr_sbuff_in_bstrncpy(name, name_p, strlen(name_p)) < 0) {
594 cf_log_perr(cs, "Name too long");
595 goto error;
596 }
597 name_p = fr_sbuff_start(name);
598 } else {
599 name_p = cf_section_name2(cs);
600 }
601
602 MEM(xr = talloc_zero(NULL, xlat_redundant_t));
603 xr->type = xr_type;
604 xr->cs = cs;
606
607 /*
608 * Iterate over all the xlats registered by all the modules
609 * in the section, when we reach the end of a run of common
610 * xlats, we register the redundant xlat.
611 *
612 * Note: Just because a xlat function has the same name,
613 * it does not mean the function signature is compatible.
614 *
615 * These issues are caught when we instantiate a redundant
616 * xlat, as the arguments passed to the redunant xlat are
617 * validated against the argument definitions for each
618 * individual xlat the redunant xlat would call.
619 */
620 do {
621 if (!mrx->xlat->flags.pure) flags &= ~XLAT_FUNC_FLAG_PURE;
623 prev_mrx = mrx;
624 } while ((mrx = fr_rb_iter_next_inorder(&iter)) && (module_xlat_cmp(prev_mrx, mrx) == 0));
625
626 /*
627 * Warn, but allow, redundant/failover expansions that are
628 * neither redundant, nor failover.
629 *
630 * Sometimes useful to comment out modules during testing.
631 */
632 if (fr_dlist_num_elements(&xr->funcs) == 1) {
633 cf_log_warn(cs, "%s expansion has no alternates, only %s",
634 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"),
635 ((xlat_redundant_func_t *)fr_dlist_head(&xr->funcs))->func->name);
636
637 }
638
639 /*
640 * Register the new redundant xlat, and hang it off of
641 * the first module instance in the section.
642 *
643 * This isn't great, but at least the xlat should
644 * get unregistered at about the right time.
645 */
646 xlat = xlat_func_register(mi, name_p, xlat_redundant, return_type);
647 if (unlikely(xlat == NULL)) {
648 cf_log_err(cs, "Registering expansion for %s section failed",
649 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"));
650 talloc_free(xr);
651 return -1;
652 }
653 talloc_steal(xlat, xr); /* redundant xlat should own its own config */
654
655 cf_log_debug(cs, "Registered %s expansion \"%s\" with %u alternates",
656 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"),
657 xlat->name, fr_dlist_num_elements(&xr->funcs));
658
659 xlat_func_flags_set(xlat, flags);
662 }
663 }
664 talloc_free(mrx_tree);
665
666 return 0;
667}
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:841
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:1657
#define UNLANG_SUB_FRAME
Definition interpret.h:37
#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:359
Module instance data.
Definition module.h:285
#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:287
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:548
int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, 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:270
fr_type_t type
Type to cast argument to.
Definition xlat.h:155
int xlat_validate_function_args(xlat_exp_t *node)
xlat_escape_func_t func
Function to handle tainted values.
Definition xlat.h:156
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition xlat.h:137
static fr_slen_t head
Definition xlat.h:420
#define XLAT_RESULT_SUCCESS(_p_result)
Definition xlat.h:503
fr_value_box_safe_for_t safe_for
Escaped value to set for boxes processed by this escape function.
Definition xlat.h:157
#define xlat_copy(_ctx, _out, _in)
Definition xlat.h:458
uint8_t can_purify
if the xlat has a pure function with pure arguments.
Definition xlat.h:112
uint8_t pure
has no external side effects, true for BOX, LITERAL, and some functions
Definition xlat.h:110
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
uint8_t impure_func
xlat contains an impure function
Definition xlat.h:111
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:145
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1073
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition value.h:161
static size_t char ** out
Definition value.h:1022
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 const * ex
Tokenized expression.
Definition xlat_ctx.h:55
xlat_exp_t * ex
Tokenized expression to use in expansion.
Definition xlat_ctx.h:64
void const * inst
xlat instance data.
Definition xlat_ctx.h:50
void * uctx
Passed to the registration function.
Definition xlat_ctx.h:66
void * inst
xlat instance data to populate.
Definition xlat_ctx.h:63
An xlat calling ctx.
Definition xlat_ctx.h:49
An xlat instantiation ctx.
Definition xlat_ctx.h:62
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:399
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363
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:273
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:246
@ 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:229
char const *_CONST fmt
The original format string (a talloced buffer).
Definition xlat_priv.h:151
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
Definition xlat_priv.h:282
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:222
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
Definition xlat_priv.h:238
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition xlat_priv.h:209
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)
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)
unlang_result_t last_result
Did the last call succeed?
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.