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: 62df4b1d6ac53bf70d97d8f04c30fd55ab89f825 $
19 *
20 * @file unlang/switch.c
21 * @brief Unlang "switch" keyword evaluation.
22 *
23 * @copyright 2006-2019 The FreeRADIUS server project
24 */
25RCSID("$Id: 62df4b1d6ac53bf70d97d8f04c30fd55ab89f825 $")
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) {
90 RDEBUG("Switch failed expanding %s - %s", switch_gext->vpt->name, fr_strerror());
91 goto find_null_case;
92 }
93 } else if (!fr_cond_assert_msg(0, "Invalid tmpl type %s", tmpl_type_to_str(switch_gext->vpt->type))) {
94 return UNLANG_ACTION_FAIL;
95 }
96
97 /*
98 * case_gext->vpt.data.literal is an in-line box, so we
99 * have to make a shallow copy of its contents.
100 *
101 * Note: We do not pass a ctx here as we don't want to
102 * create a reference.
103 */
104 fr_value_box_copy_shallow(NULL, &case_vpt.data.literal, box);
105 found = fr_htrie_find(switch_gext->ht, &my_case);
106 if (!found) {
107 find_null_case:
108 found = switch_gext->default_case;
109 }
110
111do_null_case:
112 /*
113 * Nothing found. Just continue, and ignore the "switch"
114 * statement.
115 */
116 if (!found) {
117 if (box) {
118 RWDEBUG("Failed to find 'case' target for value %pV", box);
119 } else {
120 RWDEBUG("Failed to find 'default' target when expansion of %s returning no value",
121 switch_gext->vpt->name);
122 }
124 }
125
128 }
129
131}
132
133
135{
137
138 if (unlang_list_empty(&g->children)) RETURN_UNLANG_NOOP;
139
140 return unlang_group(p_result, request, frame);
141}
142
143
145{
147 int i;
148 char const *name2;
149 unlang_t *c;
150 unlang_group_t *case_g;
151 unlang_case_t *case_gext;
152 tmpl_t *vpt = NULL;
153 tmpl_rules_t t_rules;
154
155 /*
156 * We allow unknown attributes here.
157 */
158 t_rules = *(unlang_ctx->rules);
159 t_rules.attr.allow_unknown = true;
160 RULES_VERIFY(&t_rules);
161
162 if (!parent || (parent->type != UNLANG_TYPE_SWITCH)) {
163 cf_log_err(cs, "\"case\" statements may only appear within a \"switch\" section");
164 cf_log_err(ci, DOC_KEYWORD_REF(case));
165 return NULL;
166 }
167
168 /*
169 * case THING means "match THING"
170 * case means "match anything"
171 */
172 name2 = cf_section_name2(cs);
173 if (name2) {
174 ssize_t slen;
175 fr_token_t quote;
176 unlang_group_t *switch_g;
177 unlang_switch_t *switch_gext;
178
180 switch_gext = unlang_group_to_switch(switch_g);
181
182 fr_assert(switch_gext->vpt != NULL);
183
184 /*
185 * We need to cast case values to match
186 * what we're switching over, otherwise
187 * integers of different widths won't
188 * match.
189 */
190 t_rules.cast = tmpl_expanded_type(switch_gext->vpt);
191
192 /*
193 * Need to pass the attribute from switch
194 * to tmpl rules so we can convert the
195 * case string to an integer value.
196 */
197 if (tmpl_is_attr(switch_gext->vpt)) {
198 fr_dict_attr_t const *da = tmpl_attr_tail_da(switch_gext->vpt);
199 if (da->flags.has_value) t_rules.enumv = da;
200 }
201
202 quote = cf_section_name2_quote(cs);
203
204 slen = tmpl_afrom_substr(cs, &vpt,
205 &FR_SBUFF_IN_STR(name2),
206 quote,
207 NULL,
208 &t_rules);
209 if (!vpt) {
210 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'case'", name2);
211 return NULL;
212 }
213
214 /*
215 * Bare word strings are attribute references
216 */
218 fail_attr:
219 cf_log_err(cs, "arguments to 'case' statements MUST NOT be attribute references.");
220 goto fail;
221 }
222
224 cf_log_err(cs, "arguments to 'case' statements MUST be static data.");
225 fail:
227 return NULL;
228 }
229
230 /*
231 * References to unresolved attributes are forbidden. They are no longer "bare word
232 * strings".
233 */
234 if ((quote == T_BARE_WORD) && (tmpl_value_type(vpt) == FR_TYPE_STRING)) {
235 goto fail_attr;
236 }
237
238 } /* else it's a default 'case' statement */
239
240 /*
241 * If we were asked to match something, then we MUST
242 * match it, even if the section is empty. Otherwise we
243 * will silently skip the match, and then fall through to
244 * the "default" statement.
245 */
247 if (!c) {
249 return NULL;
250 }
251
252 case_g = unlang_generic_to_group(c);
253 case_gext = unlang_group_to_case(case_g);
254 case_gext->vpt = talloc_steal(case_gext, vpt);
255
256 /*
257 * Set all of it's codes to return, so that
258 * when we pick a 'case' statement, we don't
259 * fall through to processing the next one.
260 */
261 for (i = 0; i < RLM_MODULE_NUMCODES; i++) c->actions.actions[i] = MOD_ACTION_RETURN;
262
263 return c;
264}
265
266static int8_t case_cmp(void const *one, void const *two)
267{
268 unlang_case_t const *a = (unlang_case_t const *) one; /* may not be talloc'd! See switch.c */
269 unlang_case_t const *b = (unlang_case_t const *) two; /* may not be talloc'd! */
270
272}
273
274static uint32_t case_hash(void const *data)
275{
276 unlang_case_t const *a = (unlang_case_t const *) data; /* may not be talloc'd! */
277
278 return fr_value_box_hash(tmpl_value(a->vpt));
279}
280
281static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
282{
283 unlang_case_t const *a = (unlang_case_t const *) data; /* may not be talloc'd! */
284
285 return fr_value_box_to_key(out, outlen, tmpl_value(a->vpt));
286}
287
289{
291 CONF_ITEM *subci;
292 fr_token_t token;
293 char const *name1, *name2;
294 char const *type_name;
295
297 unlang_switch_t *gext;
298
299 unlang_t *c;
300 ssize_t slen;
301
302 tmpl_rules_t t_rules;
303
305 fr_htrie_type_t htype;
306
307 /*
308 * We allow unknown attributes here.
309 */
310 t_rules = *(unlang_ctx->rules);
311 t_rules.attr.allow_unknown = true;
312 RULES_VERIFY(&t_rules);
313
314 name2 = cf_section_name2(cs);
315 if (!name2) {
316 cf_log_err(cs, "You must specify a variable to switch over for 'switch'");
317 print_url:
318 cf_log_err(ci, DOC_KEYWORD_REF(switch));
319 return NULL;
320 }
321
322 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
323
325 if (!g) return NULL;
326
327 gext = unlang_group_to_switch(g);
328
329 /*
330 * Create the template. All attributes and xlats are
331 * defined by now.
332 *
333 * The 'case' statements need g->vpt filled out to ensure
334 * that the data types match.
335 */
336 token = cf_section_name2_quote(cs);
337
338 if ((token == T_BARE_WORD) && (name2[0] != '%')) {
339 slen = tmpl_afrom_attr_substr(gext, NULL, &gext->vpt,
340 &FR_SBUFF_IN_STR(name2),
341 NULL,
342 &t_rules);
343 } else {
344 slen = tmpl_afrom_substr(gext, &gext->vpt,
345 &FR_SBUFF_IN_STR(name2),
346 token,
347 NULL,
348 &t_rules);
349 }
350 if (!gext->vpt) {
351 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'switch'", name2);
352 talloc_free(g);
353 return NULL;
354 }
355
357 c->name = "switch";
358 c->debug_name = talloc_typed_asprintf(c, "switch %s", name2);
359
360 /*
361 * Fixup the template before compiling the children.
362 * This is so that compile_case() can do attribute type
363 * checks / casts against us.
364 */
365 if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
366 talloc_free(g);
367 return NULL;
368 }
369
370 if (tmpl_is_list(gext->vpt)) {
371 cf_log_err(cs, "Cannot use list for 'switch' statement");
372 error:
373 talloc_free(g);
374 goto print_url;
375 }
376
377 if (tmpl_contains_regex(gext->vpt)) {
378 cf_log_err(cs, "Cannot use regular expression for 'switch' statement");
379 goto error;
380 }
381
382 if (tmpl_is_data(gext->vpt)) {
383 cf_log_err(cs, "Cannot use constant data for 'switch' statement");
384 goto error;
385 }
386
387 if (tmpl_is_xlat(gext->vpt)) {
388 xlat_exp_head_t *xlat = tmpl_xlat(gext->vpt);
389
390 if (xlat->flags.constant || xlat->flags.pure) {
391 cf_log_err(cs, "Cannot use constant data for 'switch' statement");
392 goto error;
393 }
394 }
395
396
397 if (tmpl_needs_resolving(gext->vpt)) {
398 cf_log_err(cs, "Cannot resolve key for 'switch' statement");
399 goto error;
400 }
401
402 type_name = cf_section_argv(cs, 0); /* AFTER name1, name2 */
403 if (type_name) {
405
406 /*
407 * Should have been caught in cf_file.c, process_switch()
408 */
411
412 do_cast:
413 if (tmpl_cast_set(gext->vpt, type) < 0) {
414 cf_log_perr(cs, "Failed setting cast type");
415 goto error;
416 }
417
418 } else {
419 /*
420 * Get the return type of the tmpl. If we don't know,
421 * mash it all to string.
422 */
423 type = tmpl_data_type(gext->vpt);
424 if ((type == FR_TYPE_NULL) || (type == FR_TYPE_VOID)) {
426 goto do_cast;
427 }
428 }
429
430 htype = fr_htrie_hint(type);
431 if (htype == FR_HTRIE_INVALID) {
432 cf_log_err(cs, "Invalid data type '%s' used for 'switch' statement",
434 goto error;
435 }
436
437 gext->ht = fr_htrie_alloc(gext, htype,
441 NULL);
442 if (!gext->ht) {
443 cf_log_err(cs, "Failed initializing internal data structures");
444 talloc_free(g);
445 return NULL;
446 }
447
448 /*
449 * Walk through the children of the switch section,
450 * ensuring that they're all 'case' statements, and then compiling them.
451 */
452 for (subci = cf_item_next(cs, NULL);
453 subci != NULL;
454 subci = cf_item_next(cs, subci)) {
455 CONF_SECTION *subcs;
456 unlang_t *single;
457 unlang_case_t *case_gext;
458
459 if (!cf_item_is_section(subci)) {
460 if (!cf_item_is_pair(subci)) continue;
461
462 cf_log_err(subci, "\"switch\" sections can only have \"case\" subsections");
463 goto error;
464 }
465
466 subcs = cf_item_to_section(subci); /* can't return NULL */
467 name1 = cf_section_name1(subcs);
468
469 if (strcmp(name1, "case") != 0) {
470 /*
471 * We finally support "default" sections for "switch".
472 */
473 if (strcmp(name1, "default") == 0) {
474 if (cf_section_name2(subcs) != 0) {
475 cf_log_err(subci, "\"default\" sections cannot have a match argument");
476 goto error;
477 }
478 goto handle_default;
479 }
480
481 cf_log_err(subci, "\"switch\" sections can only have \"case\" subsections");
482 goto error;
483 }
484
485 name2 = cf_section_name2(subcs);
486 if (!name2) {
487 handle_default:
488 if (gext->default_case) {
489 cf_log_err(subci, "Cannot have two 'default' case statements");
490 goto error;
491 }
492 }
493
494 /*
495 * Compile the subsection.
496 */
497 single = unlang_compile_case(c, unlang_ctx, subci);
498 if (!single) goto error;
499
500 fr_assert(single->type == UNLANG_TYPE_CASE);
501
502 /*
503 * Remember the "default" section, and insert the
504 * non-default "case" into the htrie.
505 */
507 if (!case_gext->vpt) {
508 gext->default_case = single;
509
510 } else if (!fr_htrie_insert(gext->ht, single)) {
511 single = fr_htrie_find(gext->ht, single);
512
513 /*
514 * @todo - look up the key and get the previous one?
515 */
516 cf_log_err(subci, "Failed inserting 'case' statement. Is there a duplicate?");
517
518 if (single) cf_log_err(unlang_generic_to_group(single)->cs, "Duplicate may be here.");
519
520 goto error;
521 }
522
523 unlang_list_insert_tail(&g->children, single);
524 }
525
526 return c;
527}
528
530{
532 .name = "switch",
533 .type = UNLANG_TYPE_SWITCH,
535
536 .compile = unlang_compile_switch,
537 .interpret = unlang_switch,
538
539 .unlang_size = sizeof(unlang_switch_t),
540 .unlang_name = "unlang_switch_t",
541
542 .pool_headers = TMPL_POOL_DEF_HEADERS,
543 .pool_len = TMPL_POOL_DEF_LEN
544 });
545
546
548 .name = "case",
549 .type = UNLANG_TYPE_CASE,
551
552 .compile = unlang_compile_case,
553 .interpret = unlang_case,
554
555 .unlang_size = sizeof(unlang_case_t),
556 .unlang_name = "unlang_case_t",
557 });
558}
#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:487
#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:288
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:366
#define cf_item_next(_parent, _curr)
Definition cf_util.h:92
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:295
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1520
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:457
#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:1673
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
#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:38
#define RDEBUG(fmt,...)
Definition radclient.h:53
@ 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:1338
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
#define tmpl_is_data_unresolved(vpt)
Definition tmpl.h:217
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:134
void unlang_switch_init(void)
Definition switch.c:529
static uint32_t case_hash(void const *data)
Definition switch.c:274
static unlang_t * unlang_compile_switch(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition switch.c:288
static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
Definition switch.c:281
static unlang_t * unlang_compile_case(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition switch.c:144
static int8_t case_cmp(void const *one, void const *two)
Definition switch.c:266
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:515
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:57
unsigned int pure
has no external side effects, true for BOX, LITERAL, and some functions
Definition xlat.h:110
unsigned int 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: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.
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:858
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
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:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
#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:6982
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:749
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:4533
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:2514
static fr_slen_t data
Definition value.h:1334
static size_t char ** out
Definition value.h:1024
String expansion ("translation").
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:190