The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: a6941dca5e0f74cd77be0d29099c1a696b4d7d86 $
19 *
20 * @file unlang/switch.c
21 * @brief Unlang "switch" keyword evaluation.
22 *
23 * @copyright 2006-2019 The FreeRADIUS server project
24 */
25RCSID("$Id: a6941dca5e0f74cd77be0d29099c1a696b4d7d86 $")
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, *to_free = 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) {
90 RDEBUG("Switch failed expanding %s - %s", switch_gext->vpt->name, fr_strerror());
91 goto find_null_case;
92 }
93 to_free = box;
94
95 } else if (!fr_cond_assert_msg(0, "Invalid tmpl type %s", tmpl_type_to_str(switch_gext->vpt->type))) {
96 return UNLANG_ACTION_FAIL;
97 }
98
99 /*
100 * case_gext->vpt.data.literal is an in-line box, so we
101 * have to make a shallow copy of its contents.
102 *
103 * Note: We do not pass a ctx here as we don't want to
104 * create a reference.
105 */
106 fr_value_box_copy_shallow(NULL, &case_vpt.data.literal, box);
107 found = fr_htrie_find(switch_gext->ht, &my_case);
108 if (!found) {
109 find_null_case:
110 found = switch_gext->default_case;
111 }
112
113do_null_case:
114 /*
115 * Nothing found. Just continue, and ignore the "switch"
116 * statement.
117 */
118 if (!found) {
119 if (box) {
120 RWDEBUG("Failed to find 'case' target for value %pV", box);
121 } else {
122 RWDEBUG("Failed to find 'default' target when expansion of %s returning no value",
123 switch_gext->vpt->name);
124 }
125 talloc_const_free(to_free);
127 }
128 talloc_const_free(to_free);
129
132 }
133
135}
136
137
139{
141
142 if (unlang_list_empty(&g->children)) RETURN_UNLANG_NOOP;
143
144 return unlang_group(p_result, request, frame);
145}
146
147
149{
151 int i;
152 char const *name2;
153 unlang_t *c;
154 unlang_group_t *case_g;
155 unlang_case_t *case_gext;
156 tmpl_t *vpt = NULL;
157 tmpl_rules_t t_rules;
158
159 /*
160 * We allow unknown attributes here.
161 */
162 t_rules = *(unlang_ctx->rules);
163 t_rules.attr.allow_unknown = true;
164 RULES_VERIFY(&t_rules);
165
166 if (!parent || (parent->type != UNLANG_TYPE_SWITCH)) {
167 cf_log_err(cs, "\"case\" statements may only appear within a \"switch\" section");
168 cf_log_err(ci, DOC_KEYWORD_REF(case));
169 return NULL;
170 }
171
172 /*
173 * case THING means "match THING"
174 * case means "match anything"
175 */
176 name2 = cf_section_name2(cs);
177 if (name2) {
178 ssize_t slen;
179 fr_token_t quote;
180 unlang_group_t *switch_g;
181 unlang_switch_t *switch_gext;
182
184 switch_gext = unlang_group_to_switch(switch_g);
185
186 fr_assert(switch_gext->vpt != NULL);
187
188 /*
189 * We need to cast case values to match
190 * what we're switching over, otherwise
191 * integers of different widths won't
192 * match.
193 */
194 t_rules.cast = tmpl_expanded_type(switch_gext->vpt);
195
196 /*
197 * Need to pass the attribute from switch
198 * to tmpl rules so we can convert the
199 * case string to an integer value.
200 */
201 if (tmpl_is_attr(switch_gext->vpt)) {
202 fr_dict_attr_t const *da = tmpl_attr_tail_da(switch_gext->vpt);
203 if (da->flags.has_value) t_rules.enumv = da;
204 }
205
206 quote = cf_section_name2_quote(cs);
207
208 slen = tmpl_afrom_substr(cs, &vpt,
209 &FR_SBUFF_IN_STR(name2),
210 quote,
211 NULL,
212 &t_rules);
213 if (!vpt) {
214 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'case'", name2);
215 return NULL;
216 }
217
218 /*
219 * Bare word strings are attribute references
220 */
222 cf_log_err(cs, "arguments to 'case' statements MUST NOT be attribute references.");
223 goto fail;
224 }
225
226 if (!tmpl_is_data(vpt)) {
227 cf_log_err(cs, "arguments to 'case' statements MUST be static data.");
228 fail:
230 return NULL;
231 }
232
233 /*
234 * References to unresolved attributes are forbidden. They are no longer "bare word
235 * strings".
236 */
237 if ((quote == T_BARE_WORD) && (tmpl_value_type(vpt) == FR_TYPE_STRING)) {
238 cf_log_err(cs, "String arguments to 'case' statements MUST be quoted.");
239 goto fail;
240 }
241
242 } /* else it's a default 'case' statement */
243
244 /*
245 * If we were asked to match something, then we MUST
246 * match it, even if the section is empty. Otherwise we
247 * will silently skip the match, and then fall through to
248 * the "default" statement.
249 */
251 if (!c) {
253 return NULL;
254 }
255
256 case_g = unlang_generic_to_group(c);
257 case_gext = unlang_group_to_case(case_g);
258 case_gext->vpt = talloc_steal(case_gext, vpt);
259
260 /*
261 * Set all of its codes to return, so that
262 * when we pick a 'case' statement, we don't
263 * fall through to processing the next one.
264 */
265 for (i = 0; i < RLM_MODULE_NUMCODES; i++) c->actions.actions[i] = MOD_ACTION_RETURN;
266
267 return c;
268}
269
270static int8_t case_cmp(void const *one, void const *two)
271{
272 unlang_case_t const *a = (unlang_case_t const *) one; /* may not be talloc'd! See switch.c */
273 unlang_case_t const *b = (unlang_case_t const *) two; /* may not be talloc'd! */
274
276}
277
278static uint32_t case_hash(void const *data)
279{
280 unlang_case_t const *a = (unlang_case_t const *) data; /* may not be talloc'd! */
281
282 return fr_value_box_hash(tmpl_value(a->vpt));
283}
284
285static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
286{
287 unlang_case_t const *a = (unlang_case_t const *) data; /* may not be talloc'd! */
288
289 return fr_value_box_to_key(out, outlen, tmpl_value(a->vpt));
290}
291
293{
295 CONF_ITEM *subci;
296 fr_token_t token;
297 char const *name1, *name2;
298 char const *type_name;
299
301 unlang_switch_t *gext;
302
303 unlang_t *c;
304 ssize_t slen;
305
306 tmpl_rules_t t_rules;
307
309 fr_htrie_type_t htype;
310
311 /*
312 * We allow unknown attributes here.
313 */
314 t_rules = *(unlang_ctx->rules);
315 t_rules.attr.allow_unknown = true;
316 RULES_VERIFY(&t_rules);
317
318 name2 = cf_section_name2(cs);
319 if (!name2) {
320 cf_log_err(cs, "You must specify a variable to switch over for 'switch'");
321 print_url:
322 cf_log_err(ci, DOC_KEYWORD_REF(switch));
323 return NULL;
324 }
325
326 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
327
329 if (!g) return NULL;
330
331 gext = unlang_group_to_switch(g);
332
333 /*
334 * Create the template. All attributes and xlats are
335 * defined by now.
336 *
337 * The 'case' statements need g->vpt filled out to ensure
338 * that the data types match.
339 */
340 token = cf_section_name2_quote(cs);
341
342 if ((token == T_BARE_WORD) && (name2[0] != '%')) {
343 slen = tmpl_afrom_attr_substr(gext, NULL, &gext->vpt,
344 &FR_SBUFF_IN_STR(name2),
345 NULL,
346 &t_rules);
347 } else {
348 slen = tmpl_afrom_substr(gext, &gext->vpt,
349 &FR_SBUFF_IN_STR(name2),
350 token,
351 NULL,
352 &t_rules);
353 }
354 if (!gext->vpt) {
355 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'switch'", name2);
356 talloc_free(g);
357 return NULL;
358 }
359
361 c->name = "switch";
362 c->debug_name = talloc_typed_asprintf(c, "switch %s", name2);
363
364 /*
365 * Fixup the template before compiling the children.
366 * This is so that compile_case() can do attribute type
367 * checks / casts against us.
368 */
369 if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
370 talloc_free(g);
371 return NULL;
372 }
373
374 if (tmpl_is_list(gext->vpt)) {
375 cf_log_err(cs, "Cannot use list for 'switch' statement");
376 error:
377 talloc_free(g);
378 goto print_url;
379 }
380
381 if (tmpl_contains_regex(gext->vpt)) {
382 cf_log_err(cs, "Cannot use regular expression for 'switch' statement");
383 goto error;
384 }
385
386 if (tmpl_is_data(gext->vpt)) {
387 cf_log_err(cs, "Cannot use constant data for 'switch' statement");
388 goto error;
389 }
390
391 if (tmpl_is_xlat(gext->vpt)) {
392 xlat_exp_head_t *xlat = tmpl_xlat(gext->vpt);
393
394 fr_assert(xlat != NULL);
395
396 /*
397 * Pure xlats are allowed, e.g. for %tolower(User-Name).
398 */
399 if (xlat->flags.constant) {
400 cf_log_err(cs, "Cannot use constant data for 'switch' statement");
401 goto error;
402 }
403 }
404
405 if (tmpl_needs_resolving(gext->vpt)) {
406 cf_log_err(cs, "Cannot resolve key for 'switch' statement");
407 goto error;
408 }
409
410 type_name = cf_section_argv(cs, 0); /* AFTER name1, name2 */
411 if (type_name) {
413
414 /*
415 * Should have been caught in cf_file.c, process_switch()
416 */
419
420 goto do_cast;
421
422 } else {
423 /*
424 * Get the return type of the tmpl. If we don't know,
425 * mash it all to string.
426 */
427 type = tmpl_data_type(gext->vpt);
428 if ((type == FR_TYPE_NULL) || (type == FR_TYPE_VOID)) {
430 }
431
432 do_cast:
433 if (tmpl_cast_set(gext->vpt, type) < 0) {
434 cf_log_perr(cs, "Failed setting cast type");
435 goto error;
436 }
437 }
438
439 htype = fr_htrie_hint(type);
440 if (htype == FR_HTRIE_INVALID) {
441 cf_log_err(cs, "Invalid data type '%s' used for 'switch' statement",
443 goto error;
444 }
445
446 gext->ht = fr_htrie_alloc(gext, htype,
450 NULL);
451 if (!gext->ht) {
452 cf_log_err(cs, "Failed initializing internal data structures");
453 talloc_free(g);
454 return NULL;
455 }
456
457 /*
458 * Walk through the children of the switch section,
459 * ensuring that they're all 'case' statements, and then compiling them.
460 */
461 for (subci = cf_item_next(cs, NULL);
462 subci != NULL;
463 subci = cf_item_next(cs, subci)) {
464 CONF_SECTION *subcs;
465 unlang_t *single;
466 unlang_case_t *case_gext;
467
468 if (!cf_item_is_section(subci)) {
469 if (!cf_item_is_pair(subci)) continue;
470
471 cf_log_err(subci, "\"switch\" sections can only have \"case\" subsections");
472 goto error;
473 }
474
475 subcs = cf_item_to_section(subci); /* can't return NULL */
476 name1 = cf_section_name1(subcs);
477
478 if (strcmp(name1, "case") != 0) {
479 /*
480 * We finally support "default" sections for "switch".
481 */
482 if (strcmp(name1, "default") == 0) {
483 if (cf_section_name2(subcs) != NULL) {
484 cf_log_err(subci, "\"default\" sections cannot have a match argument");
485 goto error;
486 }
487 goto handle_default;
488 }
489
490 cf_log_err(subci, "\"switch\" sections can only have \"case\" subsections");
491 goto error;
492 }
493
494 name2 = cf_section_name2(subcs);
495 if (!name2) {
496 handle_default:
497 if (gext->default_case) {
498 cf_log_err(subci, "Cannot have two 'default' case statements");
499 goto error;
500 }
501 }
502
503 /*
504 * Compile the subsection.
505 */
506 single = unlang_compile_case(c, unlang_ctx, subci);
507 if (!single) goto error;
508
509 fr_assert(single->type == UNLANG_TYPE_CASE);
510
511 /*
512 * Remember the "default" section, and insert the
513 * non-default "case" into the htrie.
514 */
516 if (!case_gext->vpt) {
517 gext->default_case = single;
518
519 } else if (!fr_htrie_insert(gext->ht, single)) {
520 single = fr_htrie_find(gext->ht, single);
521
522 /*
523 * @todo - look up the key and get the previous one?
524 */
525 cf_log_err(subci, "Failed inserting 'case' statement. Is there a duplicate?");
526
527 if (single) cf_log_err(unlang_generic_to_group(single)->cs, "Duplicate may be here.");
528
529 goto error;
530 }
531
532 unlang_list_insert_tail(&g->children, single);
533 }
534
535 return c;
536}
537
539{
541 .name = "switch",
542 .type = UNLANG_TYPE_SWITCH,
544
545 .compile = unlang_compile_switch,
546 .interpret = unlang_switch,
547
548 .unlang_size = sizeof(unlang_switch_t),
549 .unlang_name = "unlang_switch_t",
550
551 .pool_headers = TMPL_POOL_DEF_HEADERS,
552 .pool_len = TMPL_POOL_DEF_LEN
553 });
554
555
557 .name = "case",
558 .type = UNLANG_TYPE_CASE,
560
561 .compile = unlang_compile_case,
562 .interpret = unlang_case,
563
564 .unlang_size = sizeof(unlang_case_t),
565 .unlang_name = "unlang_case_t",
566 });
567}
#define RETURN_UNLANG_ACTION_FATAL
Definition action.h:44
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_FAIL
Encountered an unexpected error.
Definition action.h:36
#define RCSID(id)
Definition build.h:512
#define UNUSED
Definition build.h:336
Common header for all CONF_* types.
Definition cf_priv.h:54
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:640
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1352
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:746
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1338
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:692
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:626
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
Return variadic argument at the specified index.
Definition cf_util.c:1380
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1397
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:345
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:423
#define cf_item_next(_parent, _curr)
Definition cf_util.h:94
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:352
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1518
bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
Definition compile.c:87
unlang_group_t * unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:451
#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
talloc_free(hp)
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:95
fr_htrie_type_t
Definition htrie.h:58
@ FR_HTRIE_INVALID
Definition htrie.h:59
static fr_htrie_type_t fr_htrie_hint(fr_type_t type)
Definition htrie.h:180
static bool fr_htrie_insert(fr_htrie_t *ht, void const *data)
Insert data into a htrie.
Definition htrie.h:123
static void * fr_htrie_find(fr_htrie_t *ht, void const *data)
Find data in a htrie.
Definition htrie.h:115
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:2035
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:616
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:157
#define UNLANG_SUB_FRAME
Definition interpret.h:37
struct unlang_s unlang_t
Definition interpret.h:166
#define RWDEBUG(fmt,...)
Definition log.h:373
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
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:41
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:69
#define fr_assert(_expr)
Definition rad_assert.h:37
#define RDEBUG(fmt,...)
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:45
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:57
#define RETURN_UNLANG_NOOP
Definition rcode.h:69
#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:776
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:638
#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:342
#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:1342
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:1073
#define TMPL_POOL_DEF_HEADERS
Define manipulation functions for the attribute reference list.
Definition tmpl.h:490
#define tmpl_value_type(_tmpl)
Definition tmpl.h:939
fr_type_t cast
Whether there was an explicit cast.
Definition tmpl.h:344
#define TMPL_POOL_DEF_LEN
How many additional bytes to allocate in a pool for a tmpl_t.
Definition tmpl.h:495
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:339
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:336
fr_aka_sim_id_type_t type
fr_pair_t * vp
unsigned int allow_unknown
Allow unknown attributes i.e.
Definition tmpl.h:303
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:138
void unlang_switch_init(void)
Definition switch.c:538
static uint32_t case_hash(void const *data)
Definition switch.c:278
static unlang_t * unlang_compile_switch(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition switch.c:292
static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
Definition switch.c:285
static unlang_t * unlang_compile_case(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition switch.c:148
static int8_t case_cmp(void const *one, void const *two)
Definition switch.c:270
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:685
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:546
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:254
enum fr_token fr_token_t
@ T_BARE_WORD
Definition token.h:118
int(* fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data)
Definition trie.h:55
unsigned int constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
Definition xlat.h:114
#define RULES_VERIFY(_rules)
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:98
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:59
@ UNLANG_TYPE_CASE
Case section (within a UNLANG_TYPE_SWITCH).
Definition unlang_priv.h:60
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.
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:858
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
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:393
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
#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:7088
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:748
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_to_key(uint8_t **out, size_t *outlen, fr_value_box_t const *value)
Get a key from a value box.
Definition value.c:2484
static fr_slen_t data
Definition value.h:1340
static size_t char ** out
Definition value.h:1030
String expansion ("translation").
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:190