The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
call_env.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: 805a5d1d446cf6dd920000a51a5b455afd5c9ff0 $
19 *
20 * @file unlang/call_env.c
21 * @brief Call environment parsing functions
22 *
23 * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
24 */
25
26RCSID("$Id: 805a5d1d446cf6dd920000a51a5b455afd5c9ff0 $")
27
28#include <freeradius-devel/server/log.h>
29#include <freeradius-devel/server/cf_util.h>
30#include <freeradius-devel/server/tmpl.h>
31#include <freeradius-devel/server/section.h>
32#include <freeradius-devel/unlang/tmpl.h>
33#include <freeradius-devel/unlang/function.h>
34
35#include "call_env.h"
36
38 call_env_parsed_entry_t entry; //!< Entry in list of parsed call_env_parsers.
39
40 union {
41 tmpl_t const *tmpl; //!< Tmpl produced from parsing conf pair.
42 fr_value_box_t const *vb; //!< Value box produced from parsing conf pair.
43 void const *ptr; //!< Data produced from parsing conf pair.
45
46 size_t count; //!< Number of CONF_PAIRs found, matching the #call_env_parser_t.
47 size_t multi_index; //!< Array index for this instance.
48 call_env_parser_t const *rule; //!< Used to produce this.
49};
50FR_DLIST_FUNCS(call_env_parsed, call_env_parsed_t, entry)
51
52#if defined(DEBUG_CALL_ENV)
53# define CALL_ENV_DEBUG(_ci, fmt, ...) cf_log_debug(_ci, fmt, ##__VA_ARGS__)
54#else
55# define CALL_ENV_DEBUG(_ci, ...)
56#endif
57
58/** Parse the result of call_env tmpl expansion
59 */
60static inline CC_HINT(always_inline)
61call_env_result_t call_env_result(TALLOC_CTX *ctx, request_t *request, void *out, call_env_parsed_t const *env,
62 fr_value_box_list_t *tmpl_expanded)
63{
65
66 vb = fr_value_box_list_head(tmpl_expanded);
67 if (!vb) {
68 if (!call_env_nullable(env->rule->flags)) {
69 RPEDEBUG("Failed to evaluate required module option %s = %s", env->rule->name, env->data.tmpl->name);
70 return CALL_ENV_MISSING;
71 }
72 return CALL_ENV_SUCCESS;
73 }
74
75 /*
76 * Concatenate multiple boxes if needed
77 */
78 if ((call_env_concat(env->rule->flags) || call_env_attribute(env->rule->flags)) &&
79 (env->rule->pair.cast_type != FR_TYPE_VOID) &&
80 fr_value_box_list_concat_in_place(vb, vb, tmpl_expanded, env->rule->pair.cast_type,
81 FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0 ) {
82 RPEDEBUG("Failed concatenating values for %s", env->rule->name);
83 return CALL_ENV_INVALID;
84 }
85
86 if (call_env_single(env->rule->flags) && (fr_value_box_list_num_elements(tmpl_expanded) > 1)) {
87 RPEDEBUG("%u values found for %s. Only one is allowed",
88 fr_value_box_list_num_elements(tmpl_expanded), env->rule->name);
89 return CALL_ENV_INVALID;
90 }
91
92 while ((vb = fr_value_box_list_pop_head(tmpl_expanded))) {
93 switch (env->rule->pair.type) {
96 break;
97
99 if (!fr_value_box_list_initialised((fr_value_box_list_t *)out)) fr_value_box_list_init((fr_value_box_list_t *)out);
100 fr_value_box_list_insert_tail((fr_value_box_list_t *)out, vb);
101 break;
102
103 default:
104 fr_assert(0);
105 break;
106 }
107 }
108
109 return CALL_ENV_SUCCESS;
110}
111
112/** Context to keep track of expansion of call environments
113 *
114 */
115typedef struct {
116 call_env_result_t *result; //!< Where to write the return code of callenv expansion.
117 unlang_result_t expansion_result; //!< The result of calling the call env expansions functions.
118 call_env_t const *call_env; //!< Call env being expanded.
119 call_env_parsed_t const *last_expanded; //!< The last expanded tmpl.
120 fr_value_box_list_t tmpl_expanded; //!< List to write value boxes to as tmpls are expanded.
121 void **data; //!< Final destination structure for value boxes.
123
124static unlang_action_t call_env_expand_repeat(UNUSED unlang_result_t *p_result, request_t *request, void *uctx);
125
126/** Start the expansion of a call environment tmpl.
127 *
128 */
130{
131 call_env_rctx_t *call_env_rctx = talloc_get_type_abort(uctx, call_env_rctx_t);
132 TALLOC_CTX *ctx;
133 call_env_parsed_t const *env = NULL;
134 void **out;
135
136again:
137 while ((call_env_rctx->last_expanded = call_env_parsed_next(&call_env_rctx->call_env->parsed, call_env_rctx->last_expanded))) {
138 env = call_env_rctx->last_expanded;
139 fr_assert(env != NULL);
140
141 /*
142 * Subsections are expanded during parsing to produce a list of
143 * call_env_parsed_t. They are not expanded at runtime.
144 */
145 fr_assert_msg(call_env_is_subsection(env->rule->flags) == false, "Subsections cannot be expanded at runtime");
146
147 /*
148 * If there's an offset to copy the output to, do that.
149 * We may also need to expand the tmpl_t and write out the result
150 * to the pair offset.
151 */
152 if (env->rule->pair.parsed.offset >= 0) {
153 /*
154 * If we only need the tmpl or data, just set the pointer and move the next.
155 */
156 out = (void **)((uint8_t *)*call_env_rctx->data + env->rule->pair.parsed.offset);
157
158 /*
159 * For multi pair options, the pointers need to go into a new array.
160 * When processing the first expansion, allocate the array, and for
161 * all expansions adjust the `out` pointer to write to.
162 */
163 if (call_env_multi(env->rule->flags)) {
164 void **array;
165 if (env->multi_index == 0) {
166 /*
167 * Coverity thinks talloc_zero_array being called with the type `void *`
168 * is a size mismatch. This works round the false positive.
169 */
170 MEM(array = _talloc_zero_array((*call_env_rctx->data), sizeof(uint8_t *),
171 env->count, "void *"));
172 *out = array;
173 }
174 array = (void **)(*out);
175 out = (void **)((uint8_t *)array + sizeof(void *) * env->multi_index);
176 }
177
178 switch (env->rule->pair.parsed.type) {
180 *out = UNCONST(tmpl_t *, env->data.tmpl);
181 break;
182
184 *out = UNCONST(fr_value_box_t *, env->data.vb);
185 continue; /* Can't evaluate these */
186
188 *out = UNCONST(void *, env->data.ptr);
189 continue; /* Can't evaluate these */
190 }
191 }
192
193 /*
194 * If this is not parse_only, we need to expand the tmpl.
195 */
196 if ((env->rule->pair.parsed.type == CALL_ENV_PARSE_TYPE_TMPL) && !call_env_parse_only(env->rule->flags)) break;
197 }
198
199 if (!call_env_rctx->last_expanded) { /* No more! */
200 if (call_env_rctx->result) *call_env_rctx->result = CALL_ENV_SUCCESS;
202 }
203
204 ctx = *call_env_rctx->data;
205
206 fr_assert(env != NULL);
207
208 /*
209 * Multi pair options should allocate boxes in the context of the array
210 */
211 if (call_env_multi(env->rule->flags)) {
212 out = (void **)((uint8_t *)(*call_env_rctx->data) + env->rule->pair.offset);
213
214 /*
215 * For multi pair options, allocate the array before expanding the first entry.
216 */
217 if (env->multi_index == 0) {
218 void *array;
219 MEM(array = _talloc_zero_array((*call_env_rctx->data), env->rule->pair.size,
220 env->count, env->rule->pair.type_name));
221 *out = array;
222 }
223 ctx = *out;
224 }
225
226 /*
227 * If the tmpl is already data, we can just copy the data to the right place.
228 */
229 if (tmpl_is_data(call_env_rctx->last_expanded->data.tmpl)) {
230 fr_value_box_t *vb;
231 call_env_result_t result;
232 void *box_out;
233
234 MEM(vb = fr_value_box_acopy(ctx, &call_env_rctx->last_expanded->data.tmpl->data.literal));
235 fr_value_box_list_insert_tail(&call_env_rctx->tmpl_expanded, vb);
236
237 box_out = ((uint8_t*)(*call_env_rctx->data)) + env->rule->pair.offset;
238
239 if (call_env_multi(env->rule->flags)) {
240 void *array = *(void **)box_out;
241 box_out = ((uint8_t *)array) + env->rule->pair.size * env->multi_index;
242 }
243
244 /* coverity[var_deref_model] */
245 result = call_env_result(*call_env_rctx->data, request, box_out, env, &call_env_rctx->tmpl_expanded);
246 if (result != CALL_ENV_SUCCESS) {
247 if (call_env_rctx->result) *call_env_rctx->result = result;
248 return UNLANG_ACTION_FAIL;
249 }
250 goto again;
251 }
252
253 if (unlang_tmpl_push(ctx, &call_env_rctx->expansion_result, &call_env_rctx->tmpl_expanded, request,
254 call_env_rctx->last_expanded->data.tmpl,
255 NULL, UNLANG_SUB_FRAME) < 0) return UNLANG_ACTION_FAIL;
256
258}
259
260/** Extract expanded call environment tmpl and store in env_data
261 *
262 * If there are more call environments to evaluate, push the next one.
263 */
265{
266 void *out = NULL;
267 call_env_rctx_t *call_env_rctx = talloc_get_type_abort(uctx, call_env_rctx_t);
268 call_env_parsed_t const *env;
269 call_env_result_t result;
270
271 /*
272 * Something went wrong expanding the call env
273 * return fail.
274 *
275 * The module should not be executed.
276 */
277 if (call_env_rctx->expansion_result.rcode == RLM_MODULE_FAIL) return UNLANG_ACTION_FAIL;
278
279 env = call_env_rctx->last_expanded;
280 if (!env) return UNLANG_ACTION_CALCULATE_RESULT;
281
282 /*
283 * Find the location of the output
284 */
285 out = ((uint8_t*)(*call_env_rctx->data)) + env->rule->pair.offset;
286
287 /*
288 * If this is a multi pair option, the output is an array.
289 * Find the correct offset in the array
290 */
291 if (call_env_multi(env->rule->flags)) {
292 void *array = *(void **)out;
293 out = ((uint8_t *)array) + env->rule->pair.size * env->multi_index;
294 }
295
296 /* coverity[var_deref_model] */
297 result = call_env_result(*call_env_rctx->data, request, out, env, &call_env_rctx->tmpl_expanded);
298 if (result != CALL_ENV_SUCCESS) {
299 if (call_env_rctx->result) *call_env_rctx->result = result;
300 return UNLANG_ACTION_FAIL;
301 }
302
303 if (!call_env_parsed_next(&call_env_rctx->call_env->parsed, env)) {
304 if (call_env_rctx->result) *call_env_rctx->result = CALL_ENV_SUCCESS;
306 }
307
309 request,
312 NULL,
314 call_env_rctx);
315}
316
317/** Initialise the expansion of a call environment
318 *
319 * @param[in] ctx in which to allocate destination structure for resulting value boxes.
320 * @param[in] request Current request.
321 * @param[out] env_result Where to write the result of the callenv expansion. May be NULL
322 * @param[in,out] env_data Where the destination structure should be created.
323 * @param[in] call_env Call environment being expanded.
324 */
325unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, call_env_result_t *env_result, void **env_data,
326 call_env_t const *call_env)
327{
328 call_env_rctx_t *call_env_rctx;
329
330 MEM(call_env_rctx = talloc_zero(ctx, call_env_rctx_t));
331 MEM(*env_data = talloc_zero_array(ctx, uint8_t, call_env->method->inst_size));
332 talloc_set_name_const(*env_data, call_env->method->inst_type);
333 call_env_rctx->result = env_result;
334 if (env_result) *env_result = CALL_ENV_INVALID; /* Make sure we ran to completion*/
335 call_env_rctx->data = env_data;
336 call_env_rctx->call_env = call_env;
337 fr_value_box_list_init(&call_env_rctx->tmpl_expanded);
338
340 request,
343 NULL,
345 call_env_rctx);
346}
347
348/** Allocates a new call env parsed struct
349 *
350 */
351static inline CC_HINT(always_inline)
353{
354 call_env_parsed_t *call_env_parsed;
355
356 MEM(call_env_parsed = talloc_zero(ctx, call_env_parsed_t));
357 call_env_parsed->rule = rule;
358 call_env_parsed->count = 1;
359 call_env_parsed->multi_index = 0;
360
361 return call_env_parsed;
362}
363
364static inline CC_HINT(always_inline)
365int call_env_parsed_valid(call_env_parsed_t const *parsed, CONF_ITEM const *ci, call_env_parser_t const *rule)
366{
367 tmpl_t const *tmpl;
368
369 if (rule->pair.parsed.type != CALL_ENV_PARSE_TYPE_TMPL) return 0;
370
371 tmpl = parsed->data.tmpl;
372 switch (tmpl->type) {
373 /*
374 * These can't be created from a call_env flag which is marked as an attribute.
375 */
376 case TMPL_TYPE_DATA:
377 case TMPL_TYPE_EXEC:
378 case TMPL_TYPE_XLAT:
379 fr_assert(!call_env_attribute(rule->flags));
380 break;
381
382 /*
383 * This can be created from multiple types of flags, not just an attribute one.
384 */
385 case TMPL_TYPE_ATTR:
386 break;
387
388 default:
389 cf_log_err(ci, "'%s' expands to invalid tmpl type %s", tmpl->name,
390 tmpl_type_to_str(tmpl->type));
391 return -1;
392 }
393
394 return 0;
395}
396
397/** Standard function we use for parsing call env pairs
398 *
399 * @note This is called where no custom pair parsing function is provided, but may be called by custom functions to avoid
400 * duplicating the standard parsing code.
401 *
402 * @param[in] ctx to allocate any data in.
403 * @param[out] out Where to write the result of parsing.
404 * @param[in] t_rules we're parsing attributes with. Contains the default dictionary and nested 'caller' tmpl_rules_t.
405 * @param[in] ci The #CONF_SECTION or #CONF_PAIR to parse.
406 * @param[in] cec information about the call.
407 * @param[in] rule Parse rules - How the #CONF_PAIR or #CONF_SECTION should be converted.
408 * @return
409 * - 0 on success.
410 * - -1 on failure.
411 */
412int call_env_parse_pair(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
413 UNUSED call_env_ctx_t const *cec, call_env_parser_t const *rule)
414{
415 CONF_PAIR const *to_parse = cf_item_to_pair(ci);
416 tmpl_t *parsed_tmpl;
417 fr_token_t quote = cf_pair_value_quote(to_parse);
418
419 /*
420 * If it's marked as containing an attribute reference,
421 * then always parse it as an attribute reference.
422 */
423 if (call_env_attribute(rule->flags) ||
424 ((quote == T_BARE_WORD) && call_env_bare_word_attribute(rule->flags))) {
425 if (tmpl_afrom_attr_str(ctx, NULL, &parsed_tmpl, cf_pair_value(to_parse), t_rules) <= 0) {
426 return -1;
427 }
428 } else {
429 if (tmpl_afrom_substr(ctx, &parsed_tmpl,
432 t_rules) < 0) {
433 return -1;
434 }
435 }
436 *(void **)out = parsed_tmpl;
437
438 /*
439 * All attributes and functions should be resolved at this point
440 */
441 return tmpl_resolve(parsed_tmpl, NULL);
442}
443
444/** Parse per call env
445 *
446 * Used for config options which must be parsed in the context in which
447 * the module is being called.
448 *
449 * @param[in] ctx To allocate parsed environment in.
450 * @param[out] parsed Where to write parsed environment.
451 * @param[in] name Module name for error messages.
452 * @param[in] t_rules controlling how the call env is parsed.
453 * @param[in] cs Module config.
454 * @param[in] cec information about the call.
455 * @param[in] rule to parse.
456 * @return
457 * - 0 on success;
458 * - <0 on failure;
459 */
460int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char const *name, tmpl_rules_t const *t_rules,
461 CONF_SECTION const *cs,
462 call_env_ctx_t const *cec, call_env_parser_t const *rule) {
463 CONF_PAIR const *cp, *next;
464 call_env_parsed_t *call_env_parsed = NULL;
465 ssize_t count, multi_index;
466 call_env_parser_t const *rule_p = rule;
467
468 while (rule_p->name) {
469 CALL_ENV_DEBUG(cs, "%s: Parsing call env data for %s", name, section_name_str(rule_p->name));
470
471 if (call_env_is_subsection(rule_p->flags)) {
472 CONF_SECTION const *subcs;
473 subcs = cf_section_find(cs, rule_p->name, rule_p->section.name2);
474 if (!subcs) {
475 /*
476 * No CONF_SECTION, but it's required. That's an error.
477 */
478 if (call_env_required(rule_p->flags)) {
479 cf_log_err(cs, "Module %s missing required section \"%s\"", name, rule_p->name);
480 return -1;
481 }
482
483 /*
484 * No flag saying "do callback even if subcs is missing", just skip the
485 * callbacks.
486 */
487 if (!call_env_parse_missing(rule_p->flags)) goto next;
488 }
489
490 /*
491 * Hand off to custom parsing function if there is one...
492 */
493 if (rule_p->section.func) {
494 /*
495 * Record our position so we can process any new entries
496 * after the callback returns.
497 */
498 call_env_parsed_t *last = call_env_parsed_tail(parsed);
499
500 CALL_ENV_DEBUG(cs, "%s: Calling subsection callback %p", name, rule_p->section.func);
501
502 if (rule_p->section.func(ctx, parsed, t_rules, cf_section_to_item(subcs), cec, rule_p) < 0) {
503 cf_log_perr(cs, "Failed parsing configuration section %s",
504 rule_p->name == CF_IDENT_ANY ? cf_section_name(cs) : rule_p->name);
505 return -1;
506 }
507
508 CALL_ENV_DEBUG(subcs, "%s: Callback returned %u parsed call envs", name,
509 call_env_parsed_num_elements(parsed));
510
511 /*
512 * We _could_ fix up count and multi_index on behalf of
513 * the callback, but there's no guarantee that all call_env_parsed_t
514 * are related to each other, so we don't.
515 */
516 call_env_parsed = last;
517 while ((call_env_parsed = call_env_parsed_next(parsed, call_env_parsed))) {
518 CALL_ENV_DEBUG(subcs, "%s: Checking parsed env %p", name, rule_p->section.func);
519 if (call_env_parsed_valid(call_env_parsed, cf_section_to_item(subcs), rule_p) < 0) {
520 cf_log_err(cf_section_to_item(subcs), "Invalid data produced by %s",
521 rule_p->name == CF_IDENT_ANY ? cf_section_name(cs) : rule_p->name);
522 return -1;
523 }
524 }
525 goto next;
526 }
527
528 if (call_env_parse(ctx, parsed, name, t_rules, subcs, cec, rule_p->section.subcs) < 0) {
529 CALL_ENV_DEBUG(cs, "%s: Recursive call failed", name);
530 return -1;
531 }
532 goto next;
533 }
534
535 cp = cf_pair_find(cs, rule_p->name);
536
537 if (!cp && !rule_p->pair.dflt) {
538 if (!call_env_required(rule_p->flags)) goto next;
539
540 cf_log_err(cs, "Missing required config item '%s'", rule_p->name);
541 return -1;
542 }
543
544 /*
545 * Check for additional conf pairs and error
546 * if there is one and multi is not allowed.
547 */
548 if (!call_env_multi(rule_p->flags) && ((next = cf_pair_find_next(cs, cp, rule_p->name)))) {
549 cf_log_err(cf_pair_to_item(next), "Invalid duplicate configuration item '%s'", rule_p->name);
550 return -1;
551 }
552
553 count = cf_pair_count(cs, rule_p->name);
554 if (count == 0) count = 1;
555
556 for (multi_index = 0; multi_index < count; multi_index++) {
557 CONF_PAIR *tmp_cp = NULL;
558 CONF_PAIR const *to_parse;
559 tmpl_rules_t our_rules = {};
560 fr_type_t type = rule_p->pair.cast_type;
561 call_env_parse_pair_t func = rule_p->pair.func ? rule_p->pair.func : call_env_parse_pair;
562
563 if (t_rules) {
564 our_rules.parent = t_rules->parent;
565 our_rules.attr.dict_def = t_rules->attr.dict_def;
566 our_rules.escape = rule_p->pair.escape; /* Escape rules will now get embedded in the tmpl_t and used at evaluation */
567 }
568
570 our_rules.cast = ((type == FR_TYPE_VOID) ? FR_TYPE_NULL : type);
571 our_rules.literals_safe_for = rule_p->pair.literals_safe_for;
572
573 call_env_parsed = call_env_parsed_alloc(ctx, rule_p);
574 call_env_parsed->count = count;
575 call_env_parsed->multi_index = multi_index;
576
577 /*
578 * With the conf_parser code we can add default pairs
579 * if they don't exist, but as the same CONF_SECTIONs
580 * are evaluated multiple times for each module call
581 * we can't do that here.
582 */
583 if (cp) {
584 if (call_env_force_quote(rule_p->flags)) {
585 to_parse = tmp_cp = cf_pair_alloc(NULL,
588 call_env_force_quote(rule_p->flags) ? rule_p->pair.dflt_quote : cf_pair_value_quote(cp));
589 } else {
590 to_parse = cp;
591 }
592 } else {
593 to_parse = tmp_cp = cf_pair_alloc(NULL,
594 rule_p->name, rule_p->pair.dflt, T_OP_EQ,
595 T_BARE_WORD, rule_p->pair.dflt_quote);
596 }
597
598 /*
599 * The parsing function can either produce a tmpl_t as tmpl_afrom_substr
600 * would, or produce a custom structure, which will be copied into the
601 * result structure.
602 */
603 if (unlikely(func(ctx, &call_env_parsed->data, &our_rules, cf_pair_to_item(to_parse), cec, rule_p) < 0)) {
604 error:
605 cf_log_perr(to_parse, "Failed to parse configuration item '%s = %s'", rule_p->name, cf_pair_value(to_parse));
606 talloc_free(call_env_parsed);
607 talloc_free(tmp_cp);
608 return -1;
609 }
610 if (!call_env_parsed->data.ptr) {
611 talloc_free(call_env_parsed);
612 goto next_pair;
613 }
614
615 /*
616 * Ensure only valid data is produced.
617 */
618 if (call_env_parsed_valid(call_env_parsed, cf_pair_to_item(to_parse), rule_p) < 0) goto error;
619
620 call_env_parsed_insert_tail(parsed, call_env_parsed);
621 next_pair:
622 talloc_free(tmp_cp);
623 cp = cf_pair_find_next(cs, cp, rule_p->name);
624 }
625 next:
626 rule_p++;
627 }
628
629 CALL_ENV_DEBUG(cs, "Returning after processing %u rules", (unsigned int)(rule_p - rule));
630
631 return 0;
632}
633
634/** Perform a quick assessment of how many parsed call env will be produced.
635 *
636 * @param[in,out] names_len Where to write the sum of bytes required to represent
637 * the strings which will be parsed as tmpls. This is required
638 * to pre-allocate space for the tmpl name buffers.
639 * @param[in] cs Conf section to search for pairs.
640 * @param[in] call_env to parse.
641 * @return Number of parsed_call_env expected to be required.
642 */
643static size_t call_env_count(size_t *names_len, CONF_SECTION const *cs, call_env_parser_t const *call_env)
644{
645 size_t pair_count, tmpl_count = 0;
646 CONF_PAIR const *cp;
647
648 while (call_env->name) {
649 if (call_env_is_subsection(call_env->flags)) {
650 CONF_SECTION const *subcs;
651 subcs = cf_section_find(cs, call_env->name, call_env->section.name2);
652 if (!subcs) goto next;
653
654 /*
655 * May only be a callback...
656 */
657 if (call_env->section.subcs) tmpl_count += call_env_count(names_len, subcs, call_env->section.subcs);
658 goto next;
659 }
660 pair_count = 0;
661 cp = NULL;
662 while ((cp = cf_pair_find_next(cs, cp, call_env->name))) {
663 pair_count++;
664 *names_len += talloc_array_length(cf_pair_value(cp));
665 }
666 if (!pair_count && call_env->pair.dflt) {
667 pair_count = 1;
668 *names_len += strlen(call_env->pair.dflt);
669 }
670 tmpl_count += pair_count;
671 next:
672 call_env++;
673 }
674
675 return tmpl_count;
676}
677
678/** Allocate a new call_env_parsed_t structure and add it to the list of parsed call envs
679 *
680 * @note tmpl_t and void * should be allocated in the context of the call_env_parsed_t
681 *
682 * @param[in] ctx to allocate the new call_env_parsed_t in.
683 * @param[out] head to add the new call_env_parsed_t to.
684 * @param[in] rule to base call_env_parsed_t around. MUST NOT BE THE RULE PASSED TO THE CALLBACK.
685 * The rule passed to the callback describes how to parse a subsection, but the
686 * subsection callback is adding rules describing how to parse its children.
687 * @return The new call_env_parsed_t.
688 */
689call_env_parsed_t *call_env_parsed_add(TALLOC_CTX *ctx, call_env_parsed_head_t *head, call_env_parser_t const *rule)
690{
691 call_env_parsed_t *call_env_parsed;
692 call_env_parser_t *our_rules;
693
694 fr_assert_msg(call_env_is_subsection(rule->flags) == false, "Rules added by subsection callbacks cannot be subsections themselves");
695
696 MEM(call_env_parsed = call_env_parsed_alloc(ctx, rule));
697
698 /*
699 * Copy the rule the callback provided, there's no guarantee
700 * it's not stack allocated, or in some way ephemeral.
701 */
702 MEM(our_rules = talloc(call_env_parsed, call_env_parser_t));
703 memcpy(our_rules, rule, sizeof(*our_rules));
704 call_env_parsed->rule = our_rules;
705 call_env_parsed_insert_tail(head, call_env_parsed);
706
707 return call_env_parsed;
708}
709
710/** Assign a tmpl to a call_env_parsed_t
711 *
712 * @note Intended to be used by subsection callbacks to add a tmpl to be
713 * evaluated during the call.
714 *
715 * @param[in] parsed to assign the tmpl to.
716 * @param[in] tmpl to assign.
717 */
719{
720 fr_assert_msg(parsed->rule->pair.parsed.type == CALL_ENV_PARSE_TYPE_TMPL, "Rule must indicate parsed output is a tmpl_t");
721 parsed->data.tmpl = tmpl;
722}
723
724/** Assign a value box to a call_env_parsed_t
725 *
726 * @note Intended to be used by subsection callbacks to set a static boxed
727 * value to be written out to the result structure.
728 *
729 * @param[in] parsed to assign the tmpl to.
730 * @param[in] vb to assign.
731 */
733{
734 fr_assert_msg(parsed->rule->pair.parsed.type == CALL_ENV_PARSE_TYPE_VALUE_BOX, "Rule must indicate parsed output is a value box");
735 parsed->data.vb = vb;
736}
737
738/** Assign data to a call_env_parsed_t
739 *
740 * @note Intended to be used by subsection callbacks to set arbitrary data
741 * to be written out to the result structure.
742 *
743 * @param[in] parsed to assign the tmpl to.
744 * @param[in] data to assign.
745 */
747{
748 fr_assert_msg(parsed->rule->pair.parsed.type == CALL_ENV_PARSE_TYPE_VOID, "Rule must indicate parsed output is a void *");
749 parsed->data.ptr = data;
750}
751
752/** Assign a count and index to a call_env_parsed_t
753 *
754 * @note Intended to be used by subsection callbacks to indicate related
755 * call_env_parsed_t.
756 *
757 * @param[in] parsed to modify metadata of.
758 * @param[in] count to assign.
759 * @param[in] index to assign.
760 */
761void call_env_parsed_set_multi_index(call_env_parsed_t *parsed, size_t count, size_t index)
762{
763 fr_assert_msg(call_env_multi(parsed->rule->flags), "Rule must indicate parsed output is a multi pair");
764 parsed->multi_index = index;
765 parsed->count = count;
766}
767
768/** Remove a call_env_parsed_t from the list of parsed call envs
769 *
770 * @note Intended to be used by subsection callbacks to remove a call_env_parsed_t
771 * from the list of parsed call envs (typically on error).
772 *
773 * @param[in] parsed to remove parsed data from.
774 * @param[in] ptr to remove.
775 */
776void call_env_parsed_free(call_env_parsed_head_t *parsed, call_env_parsed_t *ptr)
777{
778 call_env_parsed_remove(parsed, ptr);
779 talloc_free(ptr);
780}
781
782/** Given a call_env_method, parse all call_env_pair_t in the context of a specific call to an xlat or module method
783 *
784 * @param[in] ctx to allocate the call_env_t in.
785 * @param[in] name Module name for error messages.
786 * @param[in] call_env_method containing the call_env_pair_t to evaluate against the specified CONF_SECTION.
787 * @param[in] t_rules that control how call_env_pair_t are parsed.
788 * @param[in] cs to parse in the context of the call.
789 * @param[in] cec information about how the call is being made.
790 * @return
791 * - A new call_env_t on success.
792 * - NULL on failure.
793 */
794call_env_t *call_env_alloc(TALLOC_CTX *ctx, char const *name, call_env_method_t const *call_env_method,
795 tmpl_rules_t const *t_rules, CONF_SECTION *cs, call_env_ctx_t const *cec)
796{
797 unsigned int count;
798 size_t names_len = 0;
799 call_env_t *call_env;
800
801 /*
802 * Only used if caller doesn't use a more specific assert
803 */
804 fr_assert_msg(call_env_method->inst_size, "inst_size 0 for %s, method_env (%p)", name, call_env_method);
805
806 /*
807 * Firstly assess how many parsed env there will be and create a talloc pool to hold them.
808 * The pool size is a rough estimate based on each tmpl also allocating at least two children,
809 * for which we allow twice the length of the value to be parsed.
810 */
811 count = call_env_count(&names_len, cs, call_env_method->env);
812
813 /*
814 * Pre-allocated headers:
815 * 1 header for the call_env_pair_parsed_t, 1 header for the tmpl_t, 1 header for the name,
816 * one header for the value.
817 *
818 * Pre-allocated memory:
819 * ((sizeof(call_env_pair_parsed_t) + sizeof(tmpl_t)) * count) + (names of tmpls * 2)... Not sure what
820 * the * 2 is for, maybe for slop?
821 */
822 MEM(call_env = talloc_pooled_object(ctx, call_env_t, count * 4, (sizeof(call_env_parser_t) + sizeof(tmpl_t)) * count + names_len * 2));
823 call_env->method = call_env_method;
824 call_env_parsed_init(&call_env->parsed);
825 if (call_env_parse(call_env, &call_env->parsed, name, t_rules, cs, cec, call_env_method->env) < 0) {
826 talloc_free(call_env);
827 return NULL;
828 }
829
830 return call_env;
831}
832
833/** Bit-pos indexed table of `CALL_ENV_FLAG_*` names. */
849
854
861
863{
864 return fr_table_str_by_value(call_env_parse_type_table, t, "CALL_ENV_PARSE_TYPE_VOID");
865}
866
872
874{
875 return fr_table_str_by_value(call_env_result_type_table, t, "CALL_ENV_RESULT_TYPE_VALUE_BOX");
876}
877
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define RCSID(id)
Definition build.h:512
#define unlikely(_x)
Definition build.h:407
#define UNUSED
Definition build.h:336
#define NUM_ELEMENTS(_t)
Definition build.h:358
static fr_table_num_indexed_bit_pos_t const call_env_flag_table[]
Bit-pos indexed table of CALL_ENV_FLAG_* names.
Definition call_env.c:834
call_env_parser_t const * rule
Used to produce this.
Definition call_env.c:48
size_t count
Number of CONF_PAIRs found, matching the call_env_parser_t.
Definition call_env.c:46
int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char const *name, tmpl_rules_t const *t_rules, CONF_SECTION const *cs, call_env_ctx_t const *cec, call_env_parser_t const *rule)
Parse per call env.
Definition call_env.c:460
call_env_parsed_t const * last_expanded
The last expanded tmpl.
Definition call_env.c:119
void call_env_parsed_free(call_env_parsed_head_t *parsed, call_env_parsed_t *ptr)
Remove a call_env_parsed_t from the list of parsed call envs.
Definition call_env.c:776
static unlang_action_t call_env_expand_start(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
Start the expansion of a call environment tmpl.
Definition call_env.c:129
static unlang_action_t call_env_expand_repeat(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
Extract expanded call environment tmpl and store in env_data.
Definition call_env.c:264
char const * call_env_flag_to_enum_str(call_env_flags_t mask)
Return the source-identifier name for a single CALL_ENV_FLAG_* bit.
Definition call_env.c:850
#define CALL_ENV_DEBUG(_ci,...)
Definition call_env.c:55
static int call_env_parsed_valid(call_env_parsed_t const *parsed, CONF_ITEM const *ci, call_env_parser_t const *rule)
Definition call_env.c:365
static size_t call_env_parse_type_table_len
Definition call_env.c:860
unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, call_env_result_t *env_result, void **env_data, call_env_t const *call_env)
Initialise the expansion of a call environment.
Definition call_env.c:325
static call_env_parsed_t * call_env_parsed_alloc(TALLOC_CTX *ctx, call_env_parser_t const *rule)
Allocates a new call env parsed struct.
Definition call_env.c:352
call_env_parsed_t * call_env_parsed_add(TALLOC_CTX *ctx, call_env_parsed_head_t *head, call_env_parser_t const *rule)
Allocate a new call_env_parsed_t structure and add it to the list of parsed call envs.
Definition call_env.c:689
call_env_t const * call_env
Call env being expanded.
Definition call_env.c:118
static size_t call_env_count(size_t *names_len, CONF_SECTION const *cs, call_env_parser_t const *call_env)
Perform a quick assessment of how many parsed call env will be produced.
Definition call_env.c:643
size_t multi_index
Array index for this instance.
Definition call_env.c:47
void call_env_parsed_set_multi_index(call_env_parsed_t *parsed, size_t count, size_t index)
Assign a count and index to a call_env_parsed_t.
Definition call_env.c:761
char const * call_env_result_type_to_enum_str(call_env_result_type_t t)
Return the source-identifier name for a call_env_result_type_t value.
Definition call_env.c:873
call_env_parsed_entry_t entry
Entry in list of parsed call_env_parsers.
Definition call_env.c:38
char const * call_env_parse_type_to_enum_str(call_env_parse_type_t t)
Return the source-identifier name for a call_env_parse_type_t value.
Definition call_env.c:862
call_env_result_t * result
Where to write the return code of callenv expansion.
Definition call_env.c:116
union call_env_parsed_s::@100 data
void ** data
Final destination structure for value boxes.
Definition call_env.c:121
fr_value_box_list_t tmpl_expanded
List to write value boxes to as tmpls are expanded.
Definition call_env.c:120
void call_env_parsed_set_data(call_env_parsed_t *parsed, void const *data)
Assign data to a call_env_parsed_t.
Definition call_env.c:746
call_env_t * call_env_alloc(TALLOC_CTX *ctx, char const *name, call_env_method_t const *call_env_method, tmpl_rules_t const *t_rules, CONF_SECTION *cs, call_env_ctx_t const *cec)
Given a call_env_method, parse all call_env_pair_t in the context of a specific call to an xlat or mo...
Definition call_env.c:794
void call_env_parsed_set_value(call_env_parsed_t *parsed, fr_value_box_t const *vb)
Assign a value box to a call_env_parsed_t.
Definition call_env.c:732
static size_t call_env_result_type_table_len
Definition call_env.c:871
static size_t call_env_flag_table_len
Definition call_env.c:848
void call_env_parsed_set_tmpl(call_env_parsed_t *parsed, tmpl_t const *tmpl)
Assign a tmpl to a call_env_parsed_t.
Definition call_env.c:718
int call_env_parse_pair(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, UNUSED call_env_ctx_t const *cec, call_env_parser_t const *rule)
Standard function we use for parsing call env pairs.
Definition call_env.c:412
unlang_result_t expansion_result
The result of calling the call env expansions functions.
Definition call_env.c:117
static call_env_result_t call_env_result(TALLOC_CTX *ctx, request_t *request, void *out, call_env_parsed_t const *env, fr_value_box_list_t *tmpl_expanded)
Parse the result of call_env tmpl expansion.
Definition call_env.c:61
static fr_table_num_indexed_t const call_env_result_type_table[]
Definition call_env.c:867
static fr_table_num_indexed_t const call_env_parse_type_table[]
Definition call_env.c:855
Context to keep track of expansion of call environments.
Definition call_env.c:115
Structures and functions for handling call environments.
#define call_env_parse_missing(_flags)
Definition call_env.h:132
call_env_flags_t flags
Flags controlling parser behaviour.
Definition call_env.h:182
#define call_env_is_subsection(_flags)
Definition call_env.h:130
#define call_env_required(_flags)
Definition call_env.h:114
char const * name
Of conf pair to pass to tmpl_tokenizer.
Definition call_env.h:181
#define call_env_nullable(_flags)
Definition call_env.h:122
#define call_env_multi(_flags)
Definition call_env.h:120
#define call_env_single(_flags)
Definition call_env.h:118
#define call_env_concat(_flags)
Definition call_env.h:116
call_env_result_type_t
What type of structure is produced by the evaluation phase.
Definition call_env.h:67
@ CALL_ENV_RESULT_TYPE_VALUE_BOX_LIST
Output of the evaluation phase is a list of value boxes.
Definition call_env.h:69
@ CALL_ENV_RESULT_TYPE_VALUE_BOX
Output of the evaluation phase is a single value box.
Definition call_env.h:68
size_t inst_size
Size of per call env.
Definition call_env.h:245
#define call_env_attribute(_flags)
Definition call_env.h:128
call_env_result_t
Definition call_env.h:51
@ CALL_ENV_INVALID
Definition call_env.h:54
@ CALL_ENV_MISSING
Definition call_env.h:53
@ CALL_ENV_SUCCESS
Definition call_env.h:52
call_env_parser_t const * env
Parsing rules for call method env.
Definition call_env.h:247
char const * inst_type
Type of per call env.
Definition call_env.h:246
#define call_env_parse_only(_flags)
Definition call_env.h:126
call_env_flags_t
Definition call_env.h:73
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
Definition call_env.h:76
@ CALL_ENV_FLAG_SUBSECTION
This is a subsection.
Definition call_env.h:87
@ CALL_ENV_FLAG_SINGLE
If the tmpl produces more than one box this is an error.
Definition call_env.h:77
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl MUST contain an attribute reference.
Definition call_env.h:86
@ CALL_ENV_FLAG_FORCE_QUOTE
Force quote method when parsing tmpl.
Definition call_env.h:81
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
Definition call_env.h:85
@ CALL_ENV_FLAG_SECRET
The value is a secret, and should not be logged.
Definition call_env.h:91
@ CALL_ENV_FLAG_MULTI
Multiple instances of the conf pairs are allowed.
Definition call_env.h:78
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
Definition call_env.h:75
@ CALL_ENV_FLAG_PARSE_MISSING
If this subsection is missing, still parse it.
Definition call_env.h:88
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
Definition call_env.h:92
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
Definition call_env.h:80
#define call_env_force_quote(_flags)
Definition call_env.h:124
call_env_parsed_head_t parsed
The per call parsed call environment.
Definition call_env.h:253
call_env_parse_type_t
What type of structure is produced by the parsing phase.
Definition call_env.h:59
@ CALL_ENV_PARSE_TYPE_VALUE_BOX
Output of the parsing phase is a single value box (static data).
Definition call_env.h:61
@ CALL_ENV_PARSE_TYPE_TMPL
Output of the parsing phase is a tmpl_t.
Definition call_env.h:60
@ CALL_ENV_PARSE_TYPE_VOID
Output of the parsing phase is undefined (a custom structure).
Definition call_env.h:62
#define call_env_bare_word_attribute(_flags)
Definition call_env.h:136
call_env_method_t const * method
The method this call env is for.
Definition call_env.h:254
int(* call_env_parse_pair_t)(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, call_env_parser_t const *rule)
Callback for performing custom parsing of a CONF_PAIR.
Definition call_env.h:151
Per method call config.
Definition call_env.h:180
Structure containing both a talloc pool, a list of parsed call_env_pairs.
Definition call_env.h:252
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
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
Definition cf_util.c:1775
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
Definition cf_util.c:1601
unsigned int cf_pair_count(CONF_SECTION const *cs, char const *attr)
Count the number of times an attribute occurs in a parent section.
Definition cf_util.c:1668
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:746
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition cf_util.c:1434
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:1194
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:1587
char const * cf_section_name(CONF_SECTION const *cs)
Return name2 if set, else name1.
Definition cf_util.c:1364
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1760
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition cf_util.c:1790
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:672
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1746
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:730
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1730
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:345
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:352
#define CF_IDENT_ANY
Definition cf_util.h:80
#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:202
#define MEM(x)
Definition debug.h:36
#define FR_DLIST_FUNCS(_name, _element_type, _element_entry)
Define type specific wrapper functions for dlists.
Definition dlist.h:1134
#define unlang_function_push_with_result(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack that produces a result.
Definition function.h:144
talloc_free(hp)
#define UNLANG_SUB_FRAME
Definition interpret.h:37
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:139
#define RPEDEBUG(fmt,...)
Definition log.h:388
fr_type_t
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VOID
User data.
long int ssize_t
unsigned char uint8_t
#define fr_assert(_expr)
Definition rad_assert.h:37
static uint32_t mask
Definition rbmonkey.c:39
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:48
fr_dict_attr_t const * request_attr_request
Definition request.c:43
static char const * name
#define FR_SBUFF_IN(_start, _len_or_end)
static char const * section_name_str(char const *name)
Return a printable string for the section name.
Definition section.h:97
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:638
tmpl_escape_t escape
How escaping should be handled during evaluation.
Definition tmpl.h:353
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules))
Attempt to resolve functions and attributes in xlats and attribute references.
fr_value_box_safe_for_t literals_safe_for
safe_for value assigned to literal values in xlats, execs, and data.
Definition tmpl.h:351
tmpl_rules_t const * parent
for parent / child relationships
Definition tmpl.h:337
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, char const *name, tmpl_rules_t const *rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition tmpl.h:142
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition tmpl.h:146
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition tmpl.h:150
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition tmpl.h:138
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.
#define tmpl_is_data(vpt)
Definition tmpl.h:206
fr_type_t cast
Whether there was an explicit cast.
Definition tmpl.h:344
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:339
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:336
return count
Definition module.c:155
fr_aka_sim_id_type_t type
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
Definition tmpl.h:295
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:273
#define FR_TABLE_INDEXED_BIT_POS_ENTRY(_v)
Build a single fr_table_num_indexed_bit_pos_t entry from an enum identifier.
Definition table.h:125
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
#define FR_TABLE_INDEXED_ENTRY(_v)
Build a single fr_table_num_indexed_t entry from an enum identifier.
Definition table.h:110
An element in a table indexed by bit position.
Definition table.h:83
An element in a table indexed by numeric value.
Definition table.h:92
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:211
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
int unlang_tmpl_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, tmpl_t const *tmpl, unlang_tmpl_args_t *args, bool top_frame)
Push a tmpl onto the stack for evaluation.
Definition tmpl.c:276
enum fr_token fr_token_t
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
static fr_slen_t head
Definition xlat.h:420
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
Definition value.c:611
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition value.c:4518
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
Definition value.c:6604
@ FR_VALUE_BOX_LIST_FREE
Definition value.h:238
static fr_slen_t data
Definition value.h:1340
static fr_value_box_t * fr_value_box_acopy(TALLOC_CTX *ctx, fr_value_box_t const *src)
Copy an existing box, allocating a new box to hold its contents.
Definition value.h:744
static size_t char ** out
Definition value.h:1030