The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
switch.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: df8ab6fc5eab1bad272382342149ab64cbf6c8f4 $
19 *
20 * @file unlang/switch.c
21 * @brief Unlang "switch" keyword evaluation.
22 *
23 * @copyright 2006-2019 The FreeRADIUS server project
24 */
25RCSID("$Id: df8ab6fc5eab1bad272382342149ab64cbf6c8f4 $")
26
27#include <freeradius-devel/server/rcode.h>
28#include "group_priv.h"
29#include "switch_priv.h"
30#include "xlat_priv.h"
31
33{
34 unlang_t *found;
35
36 unlang_group_t *switch_g;
37 unlang_switch_t *switch_gext;
38
39 fr_value_box_t const *box = NULL;
40
42
43 /*
44 * Mock up an unlang_cast_t. Note that these on-stack
45 * buffers are the reason why case_cmp(), case_hash(),
46 * and case_to_key() use direct casts, and not the
47 * "generic to x" functions.
48 */
49 tmpl_t case_vpt = (tmpl_t) {
50 .type = TMPL_TYPE_DATA,
51 };
52 unlang_case_t my_case = (unlang_case_t) {
54 .self = (unlang_t) {
56 },
57 },
58 .vpt = &case_vpt,
59 };
60
61 switch_g = unlang_generic_to_group(frame->instruction);
62 switch_gext = unlang_group_to_switch(switch_g);
63
64 found = NULL;
65
66 /*
67 * The attribute doesn't exist. We can skip
68 * directly to the default 'case' statement.
69 */
70 if (tmpl_is_attr(switch_gext->vpt)) {
71 if (tmpl_find_vp(&vp, request, switch_gext->vpt) < 0) {
72 found = switch_gext->default_case;
73 goto do_null_case;
74 } else {
75 box = &vp->data;
76 }
77
78 /*
79 * Expand the template if necessary, so that it
80 * is evaluated once instead of for each 'case'
81 * statement.
82 */
83 } else if (tmpl_is_xlat(switch_gext->vpt) ||
84 tmpl_is_exec(switch_gext->vpt)) {
85 ssize_t slen;
86
88 request, switch_gext->vpt);
89 if (slen < 0) goto find_null_case;
90 } else if (!fr_cond_assert_msg(0, "Invalid tmpl type %s", tmpl_type_to_str(switch_gext->vpt->type))) {
91 return UNLANG_ACTION_FAIL;
92 }
93
94 /*
95 * case_gext->vpt.data.literal is an in-line box, so we
96 * have to make a shallow copy of its contents.
97 *
98 * Note: We do not pass a ctx here as we don't want to
99 * create a reference.
100 */
101 fr_value_box_copy_shallow(NULL, &case_vpt.data.literal, box);
102 found = fr_htrie_find(switch_gext->ht, &my_case);
103 if (!found) {
104 find_null_case:
105 found = switch_gext->default_case;
106 }
107
108do_null_case:
109 /*
110 * Nothing found. Just continue, and ignore the "switch"
111 * statement.
112 */
113 if (!found) return UNLANG_ACTION_EXECUTE_NEXT;
114
117 }
118
120}
121
122
124{
126
127 if (unlang_list_empty(&g->children)) RETURN_UNLANG_NOOP;
128
129 return unlang_group(p_result, request, frame);
130}
131
132
134{
136 int i;
137 char const *name2;
138 unlang_t *c;
139 unlang_group_t *case_g;
140 unlang_case_t *case_gext;
141 tmpl_t *vpt = NULL;
142 tmpl_rules_t t_rules;
143
144 /*
145 * We allow unknown attributes here.
146 */
147 t_rules = *(unlang_ctx->rules);
148 t_rules.attr.allow_unknown = true;
149 RULES_VERIFY(&t_rules);
150
151 if (!parent || (parent->type != UNLANG_TYPE_SWITCH)) {
152 cf_log_err(cs, "\"case\" statements may only appear within a \"switch\" section");
153 cf_log_err(ci, DOC_KEYWORD_REF(case));
154 return NULL;
155 }
156
157 /*
158 * case THING means "match THING"
159 * case means "match anything"
160 */
161 name2 = cf_section_name2(cs);
162 if (name2) {
163 ssize_t slen;
164 fr_token_t quote;
165 unlang_group_t *switch_g;
166 unlang_switch_t *switch_gext;
167
169 switch_gext = unlang_group_to_switch(switch_g);
170
171 fr_assert(switch_gext->vpt != NULL);
172
173 /*
174 * We need to cast case values to match
175 * what we're switching over, otherwise
176 * integers of different widths won't
177 * match.
178 */
179 t_rules.cast = tmpl_expanded_type(switch_gext->vpt);
180
181 /*
182 * Need to pass the attribute from switch
183 * to tmpl rules so we can convert the
184 * case string to an integer value.
185 */
186 if (tmpl_is_attr(switch_gext->vpt)) {
187 fr_dict_attr_t const *da = tmpl_attr_tail_da(switch_gext->vpt);
188 if (da->flags.has_value) t_rules.enumv = da;
189 }
190
191 quote = cf_section_name2_quote(cs);
192
193 slen = tmpl_afrom_substr(cs, &vpt,
194 &FR_SBUFF_IN_STR(name2),
195 quote,
196 NULL,
197 &t_rules);
198 if (!vpt) {
199 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'case'", name2);
200 return NULL;
201 }
202
203 /*
204 * Bare word strings are attribute references
205 */
207 fail_attr:
208 cf_log_err(cs, "arguments to 'case' statements MUST NOT be attribute references.");
209 goto fail;
210 }
211
213 cf_log_err(cs, "arguments to 'case' statements MUST be static data.");
214 fail:
216 return NULL;
217 }
218
219 /*
220 * References to unresolved attributes are forbidden. They are no longer "bare word
221 * strings".
222 */
223 if ((quote == T_BARE_WORD) && (tmpl_value_type(vpt) == FR_TYPE_STRING)) {
224 goto fail_attr;
225 }
226
227 } /* else it's a default 'case' statement */
228
229 /*
230 * If we were asked to match something, then we MUST
231 * match it, even if the section is empty. Otherwise we
232 * will silently skip the match, and then fall through to
233 * the "default" statement.
234 */
236 if (!c) {
238 return NULL;
239 }
240
241 case_g = unlang_generic_to_group(c);
242 case_gext = unlang_group_to_case(case_g);
243 case_gext->vpt = talloc_steal(case_gext, vpt);
244
245 /*
246 * Set all of it's codes to return, so that
247 * when we pick a 'case' statement, we don't
248 * fall through to processing the next one.
249 */
250 for (i = 0; i < RLM_MODULE_NUMCODES; i++) c->actions.actions[i] = MOD_ACTION_RETURN;
251
252 return c;
253}
254
255static int8_t case_cmp(void const *one, void const *two)
256{
257 unlang_case_t const *a = (unlang_case_t const *) one; /* may not be talloc'd! See switch.c */
258 unlang_case_t const *b = (unlang_case_t const *) two; /* may not be talloc'd! */
259
261}
262
263static uint32_t case_hash(void const *data)
264{
265 unlang_case_t const *a = (unlang_case_t const *) data; /* may not be talloc'd! */
266
267 return fr_value_box_hash(tmpl_value(a->vpt));
268}
269
270static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
271{
272 unlang_case_t const *a = (unlang_case_t const *) data; /* may not be talloc'd! */
273
274 return fr_value_box_to_key(out, outlen, tmpl_value(a->vpt));
275}
276
278{
280 CONF_ITEM *subci;
281 fr_token_t token;
282 char const *name1, *name2;
283 char const *type_name;
284
286 unlang_switch_t *gext;
287
288 unlang_t *c;
289 ssize_t slen;
290
291 tmpl_rules_t t_rules;
292
294 fr_htrie_type_t htype;
295
296 /*
297 * We allow unknown attributes here.
298 */
299 t_rules = *(unlang_ctx->rules);
300 t_rules.attr.allow_unknown = true;
301 RULES_VERIFY(&t_rules);
302
303 name2 = cf_section_name2(cs);
304 if (!name2) {
305 cf_log_err(cs, "You must specify a variable to switch over for 'switch'");
306 print_url:
307 cf_log_err(ci, DOC_KEYWORD_REF(switch));
308 return NULL;
309 }
310
311 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
312
314 if (!g) return NULL;
315
316 gext = unlang_group_to_switch(g);
317
318 /*
319 * Create the template. All attributes and xlats are
320 * defined by now.
321 *
322 * The 'case' statements need g->vpt filled out to ensure
323 * that the data types match.
324 */
325 token = cf_section_name2_quote(cs);
326
327 if ((token == T_BARE_WORD) && (name2[0] != '%')) {
328 slen = tmpl_afrom_attr_substr(gext, NULL, &gext->vpt,
329 &FR_SBUFF_IN_STR(name2),
330 NULL,
331 &t_rules);
332 } else {
333 slen = tmpl_afrom_substr(gext, &gext->vpt,
334 &FR_SBUFF_IN_STR(name2),
335 token,
336 NULL,
337 &t_rules);
338 }
339 if (!gext->vpt) {
340 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'switch'", name2);
341 talloc_free(g);
342 return NULL;
343 }
344
346 c->name = "switch";
347 c->debug_name = talloc_typed_asprintf(c, "switch %s", name2);
348
349 /*
350 * Fixup the template before compiling the children.
351 * This is so that compile_case() can do attribute type
352 * checks / casts against us.
353 */
354 if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
355 talloc_free(g);
356 return NULL;
357 }
358
359 if (tmpl_is_list(gext->vpt)) {
360 cf_log_err(cs, "Cannot use list for 'switch' statement");
361 error:
362 talloc_free(g);
363 goto print_url;
364 }
365
366 if (tmpl_contains_regex(gext->vpt)) {
367 cf_log_err(cs, "Cannot use regular expression for 'switch' statement");
368 goto error;
369 }
370
371 if (tmpl_is_data(gext->vpt)) {
372 cf_log_err(cs, "Cannot use constant data for 'switch' statement");
373 goto error;
374 }
375
376 if (tmpl_is_xlat(gext->vpt)) {
377 xlat_exp_head_t *xlat = tmpl_xlat(gext->vpt);
378
379 if (xlat->flags.constant || xlat->flags.pure) {
380 cf_log_err(cs, "Cannot use constant data for 'switch' statement");
381 goto error;
382 }
383 }
384
385
386 if (tmpl_needs_resolving(gext->vpt)) {
387 cf_log_err(cs, "Cannot resolve key for 'switch' statement");
388 goto error;
389 }
390
391 type_name = cf_section_argv(cs, 0); /* AFTER name1, name2 */
392 if (type_name) {
394
395 /*
396 * Should have been caught in cf_file.c, process_switch()
397 */
400
401 do_cast:
402 if (tmpl_cast_set(gext->vpt, type) < 0) {
403 cf_log_perr(cs, "Failed setting cast type");
404 goto error;
405 }
406
407 } else {
408 /*
409 * Get the return type of the tmpl. If we don't know,
410 * mash it all to string.
411 */
412 type = tmpl_data_type(gext->vpt);
413 if ((type == FR_TYPE_NULL) || (type == FR_TYPE_VOID)) {
415 goto do_cast;
416 }
417 }
418
419 htype = fr_htrie_hint(type);
420 if (htype == FR_HTRIE_INVALID) {
421 cf_log_err(cs, "Invalid data type '%s' used for 'switch' statement",
423 goto error;
424 }
425
426 gext->ht = fr_htrie_alloc(gext, htype,
430 NULL);
431 if (!gext->ht) {
432 cf_log_err(cs, "Failed initializing internal data structures");
433 talloc_free(g);
434 return NULL;
435 }
436
437 /*
438 * Walk through the children of the switch section,
439 * ensuring that they're all 'case' statements, and then compiling them.
440 */
441 for (subci = cf_item_next(cs, NULL);
442 subci != NULL;
443 subci = cf_item_next(cs, subci)) {
444 CONF_SECTION *subcs;
445 unlang_t *single;
446 unlang_case_t *case_gext;
447
448 if (!cf_item_is_section(subci)) {
449 if (!cf_item_is_pair(subci)) continue;
450
451 cf_log_err(subci, "\"switch\" sections can only have \"case\" subsections");
452 goto error;
453 }
454
455 subcs = cf_item_to_section(subci); /* can't return NULL */
456 name1 = cf_section_name1(subcs);
457
458 if (strcmp(name1, "case") != 0) {
459 /*
460 * We finally support "default" sections for "switch".
461 */
462 if (strcmp(name1, "default") == 0) {
463 if (cf_section_name2(subcs) != 0) {
464 cf_log_err(subci, "\"default\" sections cannot have a match argument");
465 goto error;
466 }
467 goto handle_default;
468 }
469
470 cf_log_err(subci, "\"switch\" sections can only have \"case\" subsections");
471 goto error;
472 }
473
474 name2 = cf_section_name2(subcs);
475 if (!name2) {
476 handle_default:
477 if (gext->default_case) {
478 cf_log_err(subci, "Cannot have two 'default' case statements");
479 goto error;
480 }
481 }
482
483 /*
484 * Compile the subsection.
485 */
486 single = unlang_compile_case(c, unlang_ctx, subci);
487 if (!single) goto error;
488
489 fr_assert(single->type == UNLANG_TYPE_CASE);
490
491 /*
492 * Remember the "default" section, and insert the
493 * non-default "case" into the htrie.
494 */
496 if (!case_gext->vpt) {
497 gext->default_case = single;
498
499 } else if (!fr_htrie_insert(gext->ht, single)) {
500 single = fr_htrie_find(gext->ht, single);
501
502 /*
503 * @todo - look up the key and get the previous one?
504 */
505 cf_log_err(subci, "Failed inserting 'case' statement. Is there a duplicate?");
506
507 if (single) cf_log_err(unlang_generic_to_group(single)->cs, "Duplicate may be here.");
508
509 goto error;
510 }
511
512 unlang_list_insert_tail(&g->children, single);
513 }
514
515 return c;
516}
517
519{
521 .name = "switch",
522 .type = UNLANG_TYPE_SWITCH,
524
525 .compile = unlang_compile_switch,
526 .interpret = unlang_switch,
527
528 .unlang_size = sizeof(unlang_switch_t),
529 .unlang_name = "unlang_switch_t",
530
531 .pool_headers = TMPL_POOL_DEF_HEADERS,
532 .pool_len = TMPL_POOL_DEF_LEN
533 });
534
535
537 .name = "case",
538 .type = UNLANG_TYPE_CASE,
540
541 .compile = unlang_compile_case,
542 .interpret = unlang_case,
543
544 .unlang_size = sizeof(unlang_case_t),
545 .unlang_name = "unlang_case_t",
546 });
547}
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_EXECUTE_NEXT
Execute the next unlang_t.
Definition action.h:38
@ UNLANG_ACTION_STOP_PROCESSING
Break out of processing the current request (unwind).
Definition action.h:42
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
#define RCSID(id)
Definition build.h:485
#define UNUSED
Definition build.h:317
#define RULES_VERIFY(_cs, _rules)
Definition cf_file.c:180
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
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:737
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1170
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:683
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:617
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
Return variadic argument at the specified index.
Definition cf_util.c:1212
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1229
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:367
#define cf_item_next(_parent, _curr)
Definition cf_util.h:92
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:296
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1508
bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
Definition compile.c:95
unlang_group_t * unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:447
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:148
unlang_action_t unlang_group(UNUSED unlang_result_t *p_result, request_t *request, UNUSED unlang_stack_frame_t *frame)
Definition group.c:31
Declarations for the "group" keyword.
uint32_t(* fr_hash_t)(void const *)
Definition hash.h:36
fr_htrie_t * fr_htrie_alloc(TALLOC_CTX *ctx, fr_htrie_type_t type, fr_hash_t hash_data, fr_cmp_t cmp_data, fr_trie_key_t get_key, fr_free_t free_data)
An abstraction over our internal hashes, rb trees, and prefix tries.
Definition htrie.c:91
fr_htrie_type_t
Definition htrie.h:49
@ FR_HTRIE_INVALID
Definition htrie.h:50
static fr_htrie_type_t fr_htrie_hint(fr_type_t type)
Definition htrie.h:149
static bool fr_htrie_insert(fr_htrie_t *ht, void const *data)
Insert data into a htrie.
Definition htrie.h:112
static void * fr_htrie_find(fr_htrie_t *ht, void const *data)
Find data in a htrie.
Definition htrie.h:104
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
int unlang_interpret_push(unlang_result_t *p_result, request_t *request, unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
Push a new frame onto the stack.
Definition interpret.c:280
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:152
#define UNLANG_SUB_FRAME
Definition interpret.h:37
static TALLOC_CTX * unlang_ctx
Definition base.c:71
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:56
talloc_free(reap)
fr_type_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VALUE_BOX
A boxed value.
@ FR_TYPE_VOID
User data.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
int8_t(* fr_cmp_t)(void const *a, void const *b)
Definition misc.h:38
@ MOD_ACTION_RETURN
stop processing the section, and return the rcode with unset priority
Definition mod_action.h:40
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:64
#define fr_assert(_expr)
Definition rad_assert.h:38
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:41
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:53
#define RETURN_UNLANG_NOOP
Definition rcode.h:65
#define FR_SBUFF_IN_STR(_start)
int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt))
Returns the first VP matching a tmpl_t.
Definition tmpl_eval.c:772
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:634
#define tmpl_is_xlat(vpt)
Definition tmpl.h:210
#define tmpl_is_attr_unresolved(vpt)
Definition tmpl.h:219
#define tmpl_value(_tmpl)
Definition tmpl.h:937
#define tmpl_contains_regex(vpt)
Definition tmpl.h:226
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
#define tmpl_is_exec(vpt)
Definition tmpl.h:211
fr_dict_attr_t const * enumv
Enumeration attribute used to resolve enum values.
Definition tmpl.h:338
#define tmpl_xlat(_tmpl)
Definition tmpl.h:930
@ 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.
fr_type_t tmpl_data_type(tmpl_t const *vpt)
Definition tmpl_eval.c:1345
static bool tmpl_is_list(tmpl_t const *vpt)
Definition tmpl.h:920
ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, fr_sbuff_t *name, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
#define tmpl_is_data(vpt)
Definition tmpl.h:206
static fr_slen_t vpt
Definition tmpl.h:1269
#define tmpl_aexpand_type(_ctx, _out, _type, _request, _vpt)
Expand a tmpl to a C type, allocing a new buffer to hold the string.
Definition tmpl.h:1071
#define TMPL_POOL_DEF_HEADERS
Define manipulation functions for the attribute reference list.
Definition tmpl.h:486
#define tmpl_value_type(_tmpl)
Definition tmpl.h:939
#define tmpl_is_data_unresolved(vpt)
Definition tmpl.h:217
fr_type_t cast
Whether there was an explicit cast.
Definition tmpl.h:340
#define TMPL_POOL_DEF_LEN
How many additional bytes to allocate in a pool for a tmpl_t.
Definition tmpl.h:491
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:335
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:801
#define tmpl_needs_resolving(vpt)
Definition tmpl.h:223
int tmpl_cast_set(tmpl_t *vpt, fr_type_t type)
Set a cast for a tmpl.
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Definition tmpl_eval.c:203
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
fr_aka_sim_id_type_t type
fr_pair_t * vp
uint8_t allow_unknown
Allow unknown attributes i.e.
Definition tmpl.h:301
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
static unlang_action_t unlang_case(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition switch.c:123
void unlang_switch_init(void)
Definition switch.c:518
static uint32_t case_hash(void const *data)
Definition switch.c:263
static unlang_t * unlang_compile_switch(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition switch.c:277
static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
Definition switch.c:270
static unlang_t * unlang_compile_case(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition switch.c:133
static int8_t case_cmp(void const *one, void const *two)
Definition switch.c:255
static unlang_action_t unlang_switch(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition switch.c:32
fr_htrie_t * ht
Definition switch_priv.h:36
unlang_group_t group
Definition switch_priv.h:56
static unlang_switch_t * unlang_group_to_switch(unlang_group_t *g)
Cast a group structure to the switch keyword extension.
Definition switch_priv.h:42
unlang_t * default_case
Definition switch_priv.h:34
tmpl_t * vpt
Definition switch_priv.h:57
static unlang_case_t * unlang_group_to_case(unlang_group_t *g)
Cast a group structure to the case keyword extension.
Definition switch_priv.h:63
#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
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:514
enum fr_token fr_token_t
@ T_BARE_WORD
Definition token.h:120
int(* fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data)
Definition trie.h:56
uint8_t pure
has no external side effects, true for BOX, LITERAL, and some functions
Definition xlat.h:110
uint8_t constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
Definition xlat.h:114
char const * debug_name
Printed in log messages when the node is executed.
unlang_mod_actions_t actions
Priorities, etc. for the various return codes.
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:99
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
#define UNLANG_IGNORE
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
unlang_list_t children
char const * name
Unknown...
@ UNLANG_TYPE_SWITCH
Switch section.
Definition unlang_priv.h:60
@ UNLANG_TYPE_CASE
Case section (within a UNLANG_TYPE_SWITCH).
Definition unlang_priv.h:61
unlang_t const * instruction
The unlang node we're evaluating.
@ UNLANG_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_BREAK_POINT
Break point.
struct unlang_s unlang_t
unlang_type_t type
The specialisation of this node.
Generic representation of a grouping.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
static fr_slen_t parent
Definition pair.h:841
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
Definition types.c:31
#define fr_type_is_leaf(_x)
Definition types.h:391
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:452
#define DOC_KEYWORD_REF(_x)
Definition version.h:89
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition value.c:6643
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:742
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:4279
int fr_value_box_to_key(uint8_t **out, size_t *outlen, fr_value_box_t const *value)
Get a key from a value box.
Definition value.c:2295
static fr_slen_t data
Definition value.h:1291
static size_t char ** out
Definition value.h:1023
String expansion ("translation").
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:190