The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
compile.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: cce0ec2443cc2018bb5690ca761259f60782d9e5 $
19 *
20 * @file unlang/compile.c
21 * @brief Functions to convert configuration sections into unlang structures.
22 *
23 * @copyright 2006-2016 The FreeRADIUS server project
24 */
25RCSID("$Id: cce0ec2443cc2018bb5690ca761259f60782d9e5 $")
26
27#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
28
29#include <freeradius-devel/server/virtual_servers.h>
30
31#include <freeradius-devel/server/cf_file.h>
32#include <freeradius-devel/server/map_proc.h>
33#include <freeradius-devel/server/modpriv.h>
34
35
36#include <freeradius-devel/unlang/xlat_priv.h>
37
38#include "call_priv.h"
39#include "caller_priv.h"
40#include "condition_priv.h"
41#include "foreach_priv.h"
42#include "load_balance_priv.h"
43#include "map_priv.h"
44#include "module_priv.h"
45#include "parallel_priv.h"
46#include "subrequest_priv.h"
47#include "switch_priv.h"
48#include "edit_priv.h"
49#include "timeout_priv.h"
50#include "limit_priv.h"
51#include "transaction_priv.h"
52#include "try_priv.h"
53#include "mod_action.h"
54
55extern uint64_t unlang_number;
56
57/*
58 * Until we know how many instructions there are, we can't
59 * allocate an array. So we have to put the instructions into an
60 * RB tree.
61 */
64
65/* Here's where we recognize all of our keywords: first the rcodes, then the
66 * actions */
68 { L("..."), RLM_MODULE_NOT_SET },
69 { L("disallow"), RLM_MODULE_DISALLOW },
70 { L("fail"), RLM_MODULE_FAIL },
71 { L("handled"), RLM_MODULE_HANDLED },
72 { L("invalid"), RLM_MODULE_INVALID },
73 { L("noop"), RLM_MODULE_NOOP },
74 { L("notfound"), RLM_MODULE_NOTFOUND },
75 { L("ok"), RLM_MODULE_OK },
76 { L("reject"), RLM_MODULE_REJECT },
77 { L("timeout"), RLM_MODULE_TIMEOUT },
78 { L("updated"), RLM_MODULE_UPDATED }
79};
81
82#define UPDATE_CTX2 unlang_compile_ctx_copy(&unlang_ctx2, unlang_ctx)
83
84
85static char const unlang_spaces[] = " ";
86
87bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
88{
89 tmpl_t *vpt = *vpt_p;
90
92
93 /*
94 * We may now know the correct dictionary
95 * where we didn't before...
96 */
97 if (!vpt->rules.attr.dict_def) tmpl_set_dict_def(vpt, dict);
98
99 /*
100 * Fixup any other tmpl types
101 */
102 if (tmpl_resolve(vpt, &(tmpl_res_rules_t){ .dict_def = dict, .force_dict_def = (dict != NULL)}) < 0) {
103 cf_log_perr(ci, NULL);
104 return false;
105 }
106
107 return true;
108}
109
110/** Fixup ONE map (recursively)
111 *
112 * This function resolves most things. Most notable it CAN leave the
113 * RHS unresolved, for use in `map` sections.
114 */
116{
117 RULES_VERIFY(rules);
118
119 if (tmpl_is_data_unresolved(map->lhs)) {
120 if (!pass2_fixup_tmpl(map, &map->lhs, map->ci, rules->attr.dict_def)) {
121 return false;
122 }
123 }
124
125 /*
126 * Enforce parent-child relationships in nested maps.
127 */
128 if (parent) {
129 if ((map->op != T_OP_EQ) && (!map->parent || (map->parent->op != T_OP_SUB_EQ))) {
130 cf_log_err(map->ci, "Invalid operator \"%s\" in nested map section. "
131 "Only '=' is allowed",
132 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
133 return false;
134 }
135 }
136
137 if (map->rhs) {
138 if (tmpl_is_data_unresolved(map->rhs)) {
140
141 if (!pass2_fixup_tmpl(map, &map->rhs, map->ci, rules->attr.dict_def)) {
142 return false;
143 }
144 }
145 }
146
147 /*
148 * Sanity check sublists.
149 */
150 if (!map_list_empty(&map->child)) {
151 fr_dict_attr_t const *da;
152 map_t *child;
153
154 if (!tmpl_is_attr(map->lhs)) {
155 cf_log_err(map->ci, "Sublists can only be assigned to a known attribute");
156 return false;
157 }
158
159 da = tmpl_attr_tail_da(map->lhs);
160
161 /*
162 * Resolve all children.
163 */
164 for (child = map_list_next(&map->child, NULL);
165 child != NULL;
166 child = map_list_next(&map->child, child)) {
167 if (!pass2_fixup_map(child, rules, da)) {
168 return false;
169 }
170 }
171 }
172
173 return true;
174}
175
176/*
177 * Do all kinds of fixups and checks for update sections.
178 */
180{
182 map_t *map = NULL;
183
184 RULES_VERIFY(rules);
185
186 while ((map = map_list_next(&gext->map, map))) {
187 /*
188 * Mostly fixup the map, but maybe leave the RHS
189 * unresolved.
190 */
191 if (!pass2_fixup_map(map, rules, NULL)) return false;
192
193 /*
194 * Check allowed operators, and ensure that the
195 * RHS is resolved.
196 */
197 if (cf_item_is_pair(map->ci) && (unlang_fixup_update(map, NULL) < 0)) return false;
198 }
199
200 return true;
201}
202
203/*
204 * Compile the RHS of map sections to xlat_exp_t
205 */
207{
209 map_t *map = NULL;
210
211 RULES_VERIFY(rules);
212
213 /*
214 * Do most fixups on the maps. Leaving the RHS as
215 * unresolved, so that the `map` function can interpret
216 * the RHS as a reference to a json string, SQL column
217 * name, etc.
218 */
219 while ((map = map_list_next(&gext->map, map))) {
220 if (!pass2_fixup_map(map, rules, NULL)) return false;
221 }
222
223 /*
224 * Map sections don't need a VPT.
225 */
226 if (!gext->vpt) return true;
227
228 if (map_list_num_elements(&gext->map) == 0) return true;
229
230 return pass2_fixup_tmpl(map_list_head(&gext->map)->ci, &gext->vpt,
231 cf_section_to_item(g->cs), rules->attr.dict_def);
232}
233
234static void unlang_dump(unlang_t *c, int depth)
235{
237 map_t *map;
238 char buffer[1024];
239
240 switch (c->type) {
241 case UNLANG_TYPE_NULL:
243 case UNLANG_TYPE_MAX:
244 fr_assert(0);
245 break;
246
248 DEBUG("%.*s%s", depth, unlang_spaces, c->debug_name);
249 break;
250
252 {
254
255 DEBUG("%.*s%s", depth, unlang_spaces, m->mmc.mi->name);
256 }
257 break;
258
259 case UNLANG_TYPE_MAP:
260 {
261 unlang_map_t *gext;
262
263 DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name);
264
266 gext = unlang_group_to_map(g);
267 map = NULL;
268 while ((map = map_list_next(&gext->map, map))) {
269 map_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map);
270 DEBUG("%.*s%s", depth + 1, unlang_spaces, buffer);
271 }
272
273 DEBUG("%.*s}", depth, unlang_spaces);
274 }
275 break;
276
277 case UNLANG_TYPE_EDIT:
278 {
279 unlang_edit_t *edit;
280
281 DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name);
282
283 edit = unlang_generic_to_edit(c);
284 map = NULL;
285 while ((map = map_list_next(&edit->maps, map))) {
286 if (!map->rhs) continue; /* @todo - fixme */
287
288 map_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map);
289 DEBUG("%.*s%s", depth + 1, unlang_spaces, buffer);
290 }
291
292 DEBUG("%.*s}", depth, unlang_spaces);
293 }
294 break;
295
296 case UNLANG_TYPE_CALL:
298 case UNLANG_TYPE_CASE:
301 case UNLANG_TYPE_ELSE:
304 case UNLANG_TYPE_IF:
315 case UNLANG_TYPE_TRY:
316 case UNLANG_TYPE_CATCH: /* @todo - print out things we catch, too */
318
319 DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name);
320 unlang_list_foreach(&g->children, child) {
321 unlang_dump(child, depth + 1);
322 }
323 DEBUG("%.*s}", depth, unlang_spaces);
324 break;
325
330 case UNLANG_TYPE_TMPL:
331 case UNLANG_TYPE_XLAT:
332 DEBUG("%.*s%s", depth, unlang_spaces, c->debug_name);
333 break;
334 }
335}
336
337
338/** Validate and fixup a map that's part of an update section.
339 *
340 * @param map to validate.
341 * @param ctx data to pass to fixup function (currently unused).
342 * @return
343 * - 0 if valid.
344 * - -1 not valid.
345 */
346int unlang_fixup_update(map_t *map, void *ctx)
347{
348 CONF_PAIR *cp = cf_item_to_pair(map->ci);
349
350 if (!ctx) {
351 /*
352 * Fixup RHS attribute references to change NUM_UNSPEC to NUM_ALL.
353 *
354 * RHS may be NULL for T_OP_CMP_FALSE.
355 */
356 if (map->rhs) {
357 switch (map->rhs->type) {
358 case TMPL_TYPE_ATTR:
360 break;
361
362 default:
363 break;
364 }
365 }
366 }
367
368 /*
369 * Lots of sanity checks for insane people...
370 */
371
372 /*
373 * Depending on the attribute type, some operators are disallowed.
374 */
375 if (tmpl_is_attr(map->lhs)) {
376 /*
377 * What exactly were you expecting to happen here?
378 */
379 if (tmpl_attr_tail_da_is_leaf(map->lhs) &&
380 map->rhs && tmpl_is_list(map->rhs)) {
381 cf_log_err(map->ci, "Can't copy list into an attribute");
382 return -1;
383 }
384
385 if (!fr_assignment_op[map->op] && !fr_comparison_op[map->op] && !fr_binary_op[map->op]) {
386 cf_log_err(map->ci, "Invalid operator \"%s\" in update section. "
387 "Only assignment or filter operators are allowed",
388 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
389 return -1;
390 }
391
392 if (fr_comparison_op[map->op] && (map->op != T_OP_CMP_FALSE)) {
393 cf_log_warn(cp, "Please use the 'filter' keyword for attribute filtering");
394 }
395 }
396
397 /*
398 * If the map has a unary operator there's no further
399 * processing we need to, as RHS is unused.
400 */
401 if (map->op == T_OP_CMP_FALSE) return 0;
402
403 if (unlikely(!map->rhs)) {
404 cf_log_err(map->ci, "Missing rhs");
405 return -1;
406 }
407
408 if (!tmpl_is_data_unresolved(map->rhs)) return 0;
409
410 /*
411 * If LHS is an attribute, and RHS is a literal, we can
412 * preparse the information into a TMPL_TYPE_DATA.
413 *
414 * Unless it's a unary operator in which case we
415 * ignore map->rhs.
416 */
417 if (tmpl_is_attr(map->lhs) && tmpl_is_data_unresolved(map->rhs)) {
418 fr_type_t type = tmpl_attr_tail_da(map->lhs)->type;
419
420 /*
421 * @todo - allow passing octets to
422 * FR_TYPE_STRUCT, which can then decode them as
423 * data? That would be rather powerful.
424 */
426
427 /*
428 * It's a literal string, just copy it.
429 * Don't escape anything.
430 */
431 if (tmpl_cast_in_place(map->rhs, type, tmpl_attr_tail_da(map->lhs)) < 0) {
432 cf_log_perr(map->ci, "Cannot convert RHS value (%s) to LHS attribute type (%s)",
435 return -1;
436 }
437
438 return 0;
439 } /* else we can't precompile the data */
440
441 if (!tmpl_is_xlat(map->lhs)) {
442 fr_assert(0);
443 cf_log_err(map->ci, "Cannot determine what update action to perform");
444 return -1;
445 }
446
447 return 0;
448}
449
450
452{
454 unlang_t *c;
455 TALLOC_CTX *ctx;
456 unlang_op_t const *op = &unlang_ops[type];
457
458 ctx = parent;
459 if (!ctx) ctx = cs;
460
461 fr_assert(op->unlang_size > 0);
462
463 /*
464 * All the groups have a common header
465 */
466 g = (unlang_group_t *)_talloc_zero_pooled_object(ctx, op->unlang_size, op->unlang_name,
467 op->pool_headers, op->pool_len);
468 if (!g) return NULL;
469
470 g->cs = cs;
471
473 c->ci = CF_TO_ITEM(cs);
474
476
477 return g;
478}
479
480/** Update a compiled unlang_t with the default actions.
481 *
482 * Don't over-ride any actions which have been set.
483 */
485{
486 int i;
487
488 /*
489 * Note that we do NOT copy over the default retries, as
490 * that would result in every subsection doing it's own
491 * retries. That is not what we want. Instead, we want
492 * the retries to apply only to the _current_ section.
493 */
494
495 /*
496 * Set the default actions if they haven't already been
497 * set.
498 */
499 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
500 if (!c->actions.actions[i]) {
501 c->actions.actions[i] = unlang_ctx->actions.actions[i];
502 }
503 }
504}
505
506#define T(_x) [T_OP_ ## _x] = true
507
508static const bool edit_list_sub_op[T_TOKEN_LAST] = {
509 T(NE),
510 T(GE),
511 T(GT),
512 T(LE),
513 T(LT),
514 T(CMP_EQ),
515};
516
517/** Validate and fixup a map that's part of an edit section.
518 *
519 * @param map to validate.
520 * @param ctx data to pass to fixup function (currently unused).
521 * @return 0 if valid else -1.
522 *
523 * @todo - this is only called for CONF_PAIR maps, not for
524 * CONF_SECTION. So when we parse nested maps, there's no validation
525 * done of the CONF_SECTION. In order to fix this, we need to have
526 * map_afrom_cs() call the validation function for the CONF_SECTION
527 * *before* recursing.
528 */
529static int unlang_fixup_edit(map_t *map, void *ctx)
530{
531 CONF_PAIR *cp = cf_item_to_pair(map->ci);
532 fr_dict_attr_t const *da;
533 fr_dict_attr_t const *parent = NULL;
534 map_t *parent_map = ctx;
535
536 fr_assert(parent_map);
537#ifdef STATIC_ANALYZER
538 if (!parent_map) return -1;
539#endif
540
541 fr_assert(tmpl_is_attr(parent_map->lhs));
542
543 if (parent_map->op == T_OP_SUB_EQ) {
544 if (!edit_list_sub_op[map->op]) {
545 cf_log_err(cp, "Invalid operator '%s' for right-hand side list. It must be a comparison operator", fr_tokens[map->op]);
546 return -1;
547 }
548
549 } else if (map->op != T_OP_EQ) {
550 cf_log_err(cp, "Invalid operator '%s' for right-hand side list. It must be '='", fr_tokens[map->op]);
551 return -1;
552 }
553
554 /*
555 * map_afrom_cs() will build its tree recursively, and call us for each child map.
556 */
557 if (map->parent && (map->parent != parent_map)) parent_map = map->parent;
558
559 parent = tmpl_attr_tail_da(parent_map->lhs);
560
561 switch (map->lhs->type) {
562 case TMPL_TYPE_ATTR:
563 da = tmpl_attr_tail_da(map->lhs);
564 if (!da->flags.internal && parent && (parent->type != FR_TYPE_GROUP) &&
565 (da->parent != parent)) {
566 /* FIXME - Broken check, doesn't work for key attributes */
567 cf_log_err(cp, "Invalid location for %s - it is not a child of %s",
568 da->name, parent->name);
569 return -1;
570 }
571 break;
572
574 case TMPL_TYPE_XLAT:
575 break;
576
577 default:
578 cf_log_err(map->ci, "Left side of map must be an attribute "
579 "or an xlat (that expands to an attribute), not a %s",
580 tmpl_type_to_str(map->lhs->type));
581 return -1;
582 }
583
584 fr_assert(map->rhs);
585
586 switch (map->rhs->type) {
589 case TMPL_TYPE_XLAT:
590 case TMPL_TYPE_DATA:
591 case TMPL_TYPE_ATTR:
592 case TMPL_TYPE_EXEC:
593 break;
594
595 default:
596 cf_log_err(map->ci, "Right side of map must be an attribute, literal, xlat or exec, got type %s",
597 tmpl_type_to_str(map->rhs->type));
598 return -1;
599 }
600
601 return 0;
602}
603
604/** Compile one edit section.
605 */
607{
608 unlang_edit_t *edit;
610 map_t *map;
611 char const *name;
612 fr_token_t op;
613 ssize_t slen;
614 fr_dict_attr_t const *parent_da;
615 int num;
616
617 tmpl_rules_t t_rules;
618
620 if (name) {
621 cf_log_err(cs, "Unexpected name2 '%s' for editing list %s ", name, cf_section_name1(cs));
622 return NULL;
623 }
624
625 op = cf_section_name2_quote(cs);
626 if ((op == T_INVALID) || !fr_list_assignment_op[op]) {
627 cf_log_err(cs, "Invalid operator '%s' for editing list %s.", fr_tokens[op], cf_section_name1(cs));
628 return NULL;
629 }
630
631 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
632 cf_log_err(cs, "Invalid operator \"%s\".",
633 fr_table_str_by_value(fr_tokens_table, op, "<INVALID>"));
634 return NULL;
635 }
636
637 /*
638 * We allow unknown attributes here.
639 */
640 t_rules = *(unlang_ctx->rules);
641 t_rules.attr.allow_unknown = true;
642 RULES_VERIFY(&t_rules);
643
644 edit = talloc_zero(parent, unlang_edit_t);
645 if (!edit) return NULL;
646
647 c = out = unlang_edit_to_generic(edit);
649 c->name = cf_section_name1(cs);
650 c->debug_name = c->name;
651 c->ci = CF_TO_ITEM(cs);
652
653 map_list_init(&edit->maps);
654
655 /*
656 * Allocate the map and initialize it.
657 */
658 MEM(map = talloc_zero(edit, map_t));
659 map->op = op;
660 map->ci = cf_section_to_item(cs);
661 map_list_init(&map->child);
662
664
665 slen = tmpl_afrom_attr_str(map, NULL, &map->lhs, name, &t_rules);
666 if (slen <= 0) {
667 cf_log_err(cs, "Failed parsing list reference %s - %s", name, fr_strerror());
668 fail:
669 talloc_free(edit);
670 return NULL;
671 }
672
673 /*
674 * Can't assign to [*] or [#]
675 */
676 num = tmpl_attr_tail_num(map->lhs);
677 if ((num == NUM_ALL) || (num == NUM_COUNT)) {
678 cf_log_err(cs, "Invalid array reference in %s", name);
679 goto fail;
680 }
681
682 /*
683 * If the DA isn't structural, then it can't have children.
684 */
685 parent_da = tmpl_attr_tail_da(map->lhs);
686 if (fr_type_is_structural(parent_da->type)) {
687 map_t *child;
688
689 /*
690 * Reset the namespace to be this attribute. The tmpl tokenizer will take care of
691 * figuring out if this is a group, TLV, dictionary switch, etc.
692 */
693 t_rules.attr.namespace = parent_da;
694
695 if (map_afrom_cs_edit(map, &map->child, cs, &t_rules, &t_rules, unlang_fixup_edit, map, 256) < 0) {
696 goto fail;
697 }
698
699 /*
700 * As a set of fixups... we can't do array references in -=
701 */
702 if (map->op == T_OP_SUB_EQ) {
703 for (child = map_list_head(&map->child); child != NULL; child = map_list_next(&map->child, child)) {
704 if (!tmpl_is_attr(child->lhs)) continue;
705
706 if (tmpl_attr_tail_num(child->lhs) != NUM_UNSPEC) {
707 cf_log_err(child->ci, "Cannot use array references and values when deleting from a list");
708 goto fail;
709 }
710
711 /*
712 * The edit code doesn't do this correctly, so we just forbid it.
713 */
714 if ((tmpl_attr_num_elements(child->lhs) - tmpl_attr_num_elements(map->lhs)) > 1) {
715 cf_log_err(child->ci, "List deletion must operate directly on the final child");
716 goto fail;
717 }
718
719 /*
720 * We don't do list comparisons either.
721 */
722 if (fr_type_is_structural(tmpl_attr_tail_da(child->lhs)->type)) {
723 cf_log_err(child->ci, "List deletion cannot operate on lists");
724 goto fail;
725 }
726 }
727 }
728 } else {
729 /*
730 * foo := { a, b, c }
731 */
732 if (map_list_afrom_cs(map, &map->child, cs, &t_rules, NULL, NULL, 256) < 0) {
733 goto fail;
734 }
735
736 if ((map->op != T_OP_SET) && !map_list_num_elements(&map->child)) {
737 cf_log_err(cs, "Cannot use operator '%s' for assigning empty list to '%s' data type.",
738 fr_tokens[map->op], fr_type_to_str(parent_da->type));
739 goto fail;
740 }
741 }
742 /*
743 * Do basic sanity checks and resolving.
744 */
745 if (!pass2_fixup_map(map, unlang_ctx->rules, NULL)) goto fail;
746
747 /*
748 * Check operators, and ensure that the RHS has been
749 * resolved.
750 */
751// if (unlang_fixup_update(map, NULL) < 0) goto fail;
752
753 map_list_insert_tail(&edit->maps, map);
754
755 return out;
756}
757
758/** Compile one edit pair
759 *
760 */
762{
763 unlang_edit_t *edit;
764 unlang_t *c = NULL, *out = UNLANG_IGNORE;
765 map_t *map;
766 int num;
767
768 tmpl_rules_t t_rules;
769 fr_token_t op;
770
771 /*
772 * We allow unknown attributes here.
773 */
774 t_rules = *(unlang_ctx->rules);
775 t_rules.attr.allow_unknown = true;
776 fr_assert(t_rules.attr.ci == cf_pair_to_item(cp));
777 RULES_VERIFY(&t_rules);
778
779 edit = talloc_zero(parent, unlang_edit_t);
780 if (!edit) return NULL;
781
782 c = out = unlang_edit_to_generic(edit);
784 c->name = cf_pair_attr(cp);
785 c->debug_name = c->name;
786 c->ci = CF_TO_ITEM(cp);
787
788 map_list_init(&edit->maps);
789
790 op = cf_pair_operator(cp);
791 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
792 cf_log_err(cp, "Invalid operator \"%s\".",
793 fr_table_str_by_value(fr_tokens_table, op, "<INVALID>"));
794 fail:
795 talloc_free(edit);
796 return NULL;
797 }
798
799 /*
800 * Convert this particular map.
801 */
802 if (map_afrom_cp(edit, &map, map_list_tail(&edit->maps), cp, &t_rules, NULL, true) < 0) {
803 goto fail;
804 }
805
806 /*
807 * @todo - we still want to do fixups on the RHS?
808 */
809 if (tmpl_is_attr(map->lhs)) {
810 /*
811 * Can't assign to [*] or [#]
812 */
813 num = tmpl_attr_tail_num(map->lhs);
814 if ((num == NUM_ALL) || (num == NUM_COUNT)) {
815 cf_log_err(cp, "Invalid array reference in %s", map->lhs->name);
816 goto fail;
817 }
818
819 if ((map->op == T_OP_SUB_EQ) && fr_type_is_structural(tmpl_attr_tail_da(map->lhs)->type) &&
820 tmpl_is_attr(map->rhs) && tmpl_attr_tail_da(map->rhs)->flags.local) {
821 cf_log_err(cp, "Cannot delete local variable %s", map->rhs->name);
822 goto fail;
823 }
824 }
825
826 /*
827 * Do basic sanity checks and resolving.
828 */
829 if (!pass2_fixup_map(map, unlang_ctx->rules, NULL)) goto fail;
830
831 /*
832 * Check operators, and ensure that the RHS has been
833 * resolved.
834 */
835 if (unlang_fixup_update(map, c) < 0) goto fail;
836
837 map_list_insert_tail(&edit->maps, map);
838
839 return out;
840}
841
842/** Compile a variable definition.
843 *
844 * Definitions which are adjacent to one another are automatically merged
845 * into one larger variable definition.
846 */
848{
851 char const *attr, *value;
852 unlang_group_t *group;
853
855
856 /*
857 * Enforce locations for local variables.
858 */
859 switch (parent->type) {
860 case UNLANG_TYPE_CASE:
861 case UNLANG_TYPE_ELSE:
865 case UNLANG_TYPE_IF:
873 break;
874
875 default:
876 cf_log_err(cp, "Local variables cannot be used here");
877 return -1;
878 }
879
880 /*
881 * The variables exist in the parent block.
882 */
884 if (group->variables) {
885 var = group->variables;
886
887 } else {
888 group->variables = var = talloc_zero(parent, unlang_variable_t);
889 if (!var) return -1;
890
891 var->dict = fr_dict_protocol_alloc(unlang_ctx->rules->attr.dict_def);
892 if (!var->dict) {
893 group->variables = NULL;
894 talloc_free(var);
895 return -1;
896 }
897 var->root = fr_dict_root(var->dict);
898
899 var->max_attr = 1;
900
901 /*
902 * Initialize the new rules, and point them to the parent rules.
903 *
904 * Then replace the parse rules with our rules, and our dictionary.
905 */
906 *t_rules = *unlang_ctx->rules;
907 t_rules->parent = unlang_ctx->rules;
908
909 t_rules->attr.dict_def = var->dict;
910 t_rules->attr.namespace = NULL;
911
912 unlang_ctx->rules = t_rules;
913 }
914
915 attr = cf_pair_attr(cp); /* data type */
916 value = cf_pair_value(cp); /* variable name */
917
919 if (type == FR_TYPE_NULL) {
921 cf_log_err(cp, "Invalid data type '%s'", attr);
922 return -1;
923 }
924
925 /*
926 * Leaf and group are OK. TLV, Vendor, Struct, VSA, etc. are not.
927 */
928 if (!(fr_type_is_leaf(type) || (type == FR_TYPE_GROUP))) goto invalid_type;
929
930 return unlang_define_local_variable(cf_pair_to_item(cp), var, t_rules, type, value, NULL);
931}
932
933/*
934 * Compile action && rcode for later use.
935 */
937{
938 int action;
939 char const *attr, *value;
940
941 attr = cf_pair_attr(cp);
942 value = cf_pair_value(cp);
943 if (!value) return true;
944
945 if (!strcasecmp(value, "return"))
946 action = MOD_ACTION_RETURN;
947
948 else if (!strcasecmp(value, "break"))
949 action = MOD_ACTION_RETURN;
950
951 else if (!strcasecmp(value, "reject"))
952 action = MOD_ACTION_REJECT;
953
954 else if (!strcasecmp(value, "retry"))
955 action = MOD_ACTION_RETRY;
956
957 else if (strspn(value, "0123456789") == strlen(value)) {
958 if (strlen(value) > 2) {
959 invalid_action:
960 cf_log_err(cp, "Priorities MUST be between 1 and 64.");
961 return false;
962 }
963
964 action = MOD_PRIORITY(atoi(value));
965
966 if (!MOD_ACTION_VALID_SET(action)) goto invalid_action;
967
968 } else {
969 cf_log_err(cp, "Unknown action '%s'.\n",
970 value);
971 return false;
972 }
973
974 if (strcasecmp(attr, "default") != 0) {
975 int rcode;
976
977 rcode = fr_table_value_by_str(mod_rcode_table, attr, -1);
978 if (rcode < 0) {
979 cf_log_err(cp,
980 "Unknown module rcode '%s'.",
981 attr);
982 return false;
983 }
984 actions->actions[rcode] = action;
985
986 } else { /* set all unset values to the default */
987 int i;
988
989 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
990 if (!actions->actions[i]) actions->actions[i] = action;
991 }
992 }
993
994 return true;
995}
996
998{
999 CONF_ITEM *csi;
1000 CONF_SECTION *cs;
1001
1002 cs = cf_item_to_section(ci);
1003 for (csi=cf_item_next(cs, NULL);
1004 csi != NULL;
1005 csi=cf_item_next(cs, csi)) {
1006 CONF_PAIR *cp;
1007 char const *name, *value;
1008
1009 if (cf_item_is_section(csi)) {
1010 cf_log_err(csi, "Invalid subsection in 'retry' configuration.");
1011 return false;
1012 }
1013
1014 if (!cf_item_is_pair(csi)) continue;
1015
1016 cp = cf_item_to_pair(csi);
1017 name = cf_pair_attr(cp);
1018 value = cf_pair_value(cp);
1019
1020 if (!value) {
1021 cf_log_err(csi, "Retry configuration must specify a value");
1022 return false;
1023 }
1024
1025#define CLAMP(_name, _field, _limit) do { \
1026 if (!fr_time_delta_ispos(actions->retry._field)) { \
1027 cf_log_err(csi, "Invalid value for '" STRINGIFY(_name) " = %s' - value must be positive", \
1028 value); \
1029 return false; \
1030 } \
1031 if (fr_time_delta_cmp(actions->retry._field, fr_time_delta_from_sec(_limit)) > 0) { \
1032 cf_log_err(csi, "Invalid value for '" STRINGIFY(_name) " = %s' - value must be less than " STRINGIFY(_limit) "s", \
1033 value); \
1034 return false; \
1035 } \
1036 } while (0)
1037
1038 /*
1039 * We don't use conf_parser_t here for various
1040 * magical reasons.
1041 */
1042 if (strcmp(name, "initial_rtx_time") == 0) {
1043 if (fr_time_delta_from_str(&actions->retry.irt, value, strlen(value), FR_TIME_RES_SEC) < 0) {
1044 error:
1045 cf_log_err(csi, "Failed parsing '%s = %s' - %s",
1046 name, value, fr_strerror());
1047 return false;
1048 }
1049 CLAMP(initial_rtx_time, irt, 2);
1050
1051 } else if (strcmp(name, "max_rtx_time") == 0) {
1052 if (fr_time_delta_from_str(&actions->retry.mrt, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
1053
1054 CLAMP(max_rtx_time, mrt, 10);
1055
1056 } else if (strcmp(name, "max_rtx_count") == 0) {
1057 char *end;
1058 unsigned long v = strtoul(value, &end, 10);
1059
1060 if (*end || (end == value) || (v > 10)) {
1061 cf_log_err(csi, "Invalid value for 'max_rtx_count = %s' - value must be between 0 and 10",
1062 value);
1063 return false;
1064 }
1065
1066 actions->retry.mrc = v;
1067
1068 } else if (strcmp(name, "max_rtx_duration") == 0) {
1069 if (fr_time_delta_from_str(&actions->retry.mrd, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
1070
1071 CLAMP(max_rtx_duration, mrd, 20);
1072
1073 } else {
1074 cf_log_err(csi, "Invalid item '%s' in 'retry' configuration.", name);
1075 return false;
1076 }
1077 }
1078
1079 return true;
1080}
1081
1082bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *cs, bool module_retry)
1083{
1084 int i;
1085 bool disallow_retry_action = false;
1086 CONF_ITEM *csi;
1087
1088 /*
1089 * Over-ride the default return codes of the module.
1090 */
1091 for (csi=cf_item_next(cs, NULL);
1092 csi != NULL;
1093 csi=cf_item_next(cs, csi)) {
1094 char const *name;
1095 CONF_PAIR *cp;
1096
1097 if (cf_item_is_section(csi)) {
1098 CONF_SECTION *subcs = cf_item_to_section(csi);
1099
1100 name = cf_section_name1(subcs);
1101
1102 /*
1103 * Look for a "retry" section.
1104 */
1105 if (name && (strcmp(name, "retry") == 0) && !cf_section_name2(subcs)) {
1106 if (!compile_retry_section(actions, csi)) return false;
1107 continue;
1108 }
1109
1110 cf_log_err(csi, "Invalid subsection. Expected 'action = value'");
1111 return false;
1112 }
1113
1114 if (!cf_item_is_pair(csi)) continue;
1115
1116 cp = cf_item_to_pair(csi);
1117
1118 /*
1119 * Allow 'retry = path.to.retry.config'
1120 */
1121 name = cf_pair_attr(cp);
1122 if (strcmp(name, "retry") == 0) {
1123 CONF_ITEM *subci;
1124 char const *value = cf_pair_value(cp);
1125
1126 if (!value) {
1127 cf_log_err(csi, "Missing reference string");
1128 return false;
1129 }
1130
1132 if (!subci) {
1133 cf_log_perr(csi, "Failed finding reference '%s'", value);
1134 return false;
1135 }
1136
1137 if (!compile_retry_section(actions, subci)) return false;
1138 continue;
1139 }
1140
1141 if (!compile_action_pair(actions, cp)) {
1142 return false;
1143 }
1144 }
1145
1146 if (module_retry) {
1147 if (!fr_time_delta_ispos(actions->retry.irt)) {
1148 cf_log_err(cs, "initial_rtx_time MUST be non-zero for modules which support retries.");
1149 return false;
1150 }
1151 } else {
1152 if (fr_time_delta_ispos(actions->retry.irt)) {
1153 cf_log_err(cs, "initial_rtx_time MUST be zero, as only max_rtx_count and max_rtx_duration are used.");
1154 return false;
1155 }
1156
1157 if (!actions->retry.mrc && !fr_time_delta_ispos(actions->retry.mrd)) {
1158 disallow_retry_action = true;
1159 }
1160 }
1161
1162 /*
1163 * Sanity check that "fail = retry", we actually have a
1164 * retry section.
1165 */
1166 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1167 if (actions->actions[i] != MOD_ACTION_RETRY) continue;
1168
1169 if (module_retry) {
1170 cf_log_err(cs, "Cannot use a '%s = retry' action for a module which has its own retries",
1171 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1172 return false;
1173 }
1174
1175 if (disallow_retry_action) {
1176 cf_log_err(cs, "max_rtx_count and max_rtx_duration cannot both be zero when using '%s = retry'",
1177 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1178 return false;
1179 }
1180
1181 if (!fr_time_delta_ispos(actions->retry.irt) &&
1182 !actions->retry.mrc &&
1183 !fr_time_delta_ispos(actions->retry.mrd)) {
1184 cf_log_err(cs, "Cannot use a '%s = retry' action without a 'retry { ... }' section.",
1185 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1186 return false;
1187 }
1188 }
1189
1190 return true;
1191}
1192
1194{
1195 unlang_group_t *g;
1196 unlang_t *c;
1197
1198 /*
1199 * If we're compiling an empty section, then the
1200 * *interpreter* type is GROUP, even if the *debug names*
1201 * are something else.
1202 */
1204 if (!g) return NULL;
1205
1207 if (!cs) {
1208 c->name = unlang_ops[type].name;
1209 c->debug_name = c->name;
1210
1211 } else {
1212 char const *name2;
1213
1214 name2 = cf_section_name2(cs);
1215 if (!name2) {
1216 c->name = cf_section_name1(cs);
1217 c->debug_name = c->name;
1218 } else {
1219 c->name = name2;
1220 c->debug_name = talloc_typed_asprintf(c, "%s %s", cf_section_name1(cs), name2);
1221 }
1222 }
1223
1224 return c;
1225}
1226
1227
1229
1230/*
1231 * compile 'actions { ... }' inside of another group.
1232 */
1234{
1235 CONF_ITEM *ci, *next;
1236
1237 ci = cf_section_to_item(subcs);
1238
1239 next = cf_item_next(cs, ci);
1240 if (next && (cf_item_is_pair(next) || cf_item_is_section(next))) {
1241 cf_log_err(ci, "'actions' MUST be the last block in a section");
1242 return false;
1243 }
1244
1245 if (cf_section_name2(subcs) != NULL) {
1246 cf_log_err(ci, "Invalid name for 'actions' section");
1247 return false;
1248 }
1249
1250 /*
1251 * Over-riding the actions can be done in certain limited
1252 * situations. In other situations (e.g. "redundant",
1253 * "load-balance"), it doesn't make sense.
1254 *
1255 * Note that this limitation also applies to "retry"
1256 * timers. We can do retries of a "group". We cannot do
1257 * retries of "load-balance", as the "load-balance"
1258 * section already takes care of redundancy.
1259 *
1260 * We may need to loosen that limitation in the future.
1261 */
1262 switch (c->type) {
1263 case UNLANG_TYPE_CASE:
1264 case UNLANG_TYPE_CATCH:
1265 case UNLANG_TYPE_IF:
1266 case UNLANG_TYPE_ELSE:
1267 case UNLANG_TYPE_ELSIF:
1269 case UNLANG_TYPE_GROUP:
1270 case UNLANG_TYPE_LIMIT:
1271 case UNLANG_TYPE_SWITCH:
1274 break;
1275
1276 default:
1277 cf_log_err(ci, "'actions' MUST NOT be in a '%s' block", unlang_ops[c->type].name);
1278 return false;
1279 }
1280
1281 return unlang_compile_actions(&c->actions, subcs, false);
1282}
1283
1284
1286{
1287 CONF_ITEM *ci = NULL;
1288 unlang_t *c, *single;
1289 bool was_if = false;
1290 char const *skip_else = NULL;
1292 unlang_compile_ctx_t unlang_ctx2;
1293 tmpl_rules_t t_rules, t2_rules; /* yes, it does */
1294
1296
1297 /*
1298 * Create our own compilation context which can be edited
1299 * by a variable definition.
1300 */
1301 unlang_compile_ctx_copy(&unlang_ctx2, unlang_ctx_in);
1302 t2_rules = *(unlang_ctx_in->rules);
1303
1304 unlang_ctx = &unlang_ctx2;
1305 unlang_ctx2.rules = &t2_rules;
1306
1307 t_rules = *unlang_ctx_in->rules;
1308
1309 /*
1310 * Loop over the children of this group.
1311 */
1312 while ((ci = cf_item_next(g->cs, ci))) {
1313 if (cf_item_is_data(ci)) continue;
1314
1315 t_rules.attr.ci = ci;
1316 t2_rules.attr.ci = ci;
1317
1318 /*
1319 * Sections are keywords, or references to
1320 * modules with updated return codes.
1321 */
1322 if (cf_item_is_section(ci)) {
1323 char const *name = NULL;
1324 CONF_SECTION *subcs = cf_item_to_section(ci);
1325
1326 /*
1327 * Skip precompiled blocks. This is
1328 * mainly for policies.
1329 */
1330 if (cf_data_find(subcs, unlang_group_t, NULL)) continue;
1331
1332 /*
1333 * "actions" apply to the current group.
1334 * It's not a subgroup.
1335 */
1336 name = cf_section_name1(subcs);
1337
1338 /*
1339 * In-line attribute editing. Nothing else in the parse has list assignments, so this must be it.
1340 */
1342 single = compile_edit_section(c, unlang_ctx, subcs);
1343 if (!single) {
1344 fail:
1345 talloc_free(c);
1346 return NULL;
1347 }
1348
1349 goto add_child;
1350 }
1351
1352 if (strcmp(name, "actions") == 0) {
1353 if (!compile_action_subsection(c, g->cs, subcs)) goto fail;
1354 continue;
1355 }
1356
1357 /*
1358 * Special checks for "else" and "elsif".
1359 */
1360 if ((strcmp(name, "else") == 0) || (strcmp(name, "elsif") == 0)) {
1361 /*
1362 * We ran into one without a preceding "if" or "elsif".
1363 * That's not allowed.
1364 */
1365 if (!was_if) {
1366 cf_log_err(ci, "Invalid location for '%s'. There is no preceding "
1367 "'if' or 'elsif' statement", name);
1368 goto fail;
1369 }
1370
1371 /*
1372 * There was a previous "if" or "elsif" which was always taken.
1373 * So we skip this "elsif" or "else".
1374 */
1375 if (skip_else) {
1376 void *ptr;
1377
1378 /*
1379 * And manually free this.
1380 */
1381 ptr = cf_data_remove(subcs, xlat_exp_head_t, NULL);
1382 talloc_free(ptr);
1383
1385
1386 cf_log_debug_prefix(ci, "Skipping contents of '%s' due to previous "
1387 "'%s' always being taken.",
1388 name, skip_else);
1389 continue;
1390 }
1391 }
1392
1393 /*
1394 * Otherwise it's a real keyword.
1395 */
1396 single = compile_item(c, unlang_ctx, ci);
1397 if (!single) {
1398 cf_log_err(ci, "Failed to parse \"%s\" subsection", cf_section_name1(subcs));
1399 goto fail;
1400 }
1401
1402 goto add_child;
1403
1404 } else if (cf_item_is_pair(ci)) {
1405 CONF_PAIR *cp = cf_item_to_pair(ci);
1406
1407 /*
1408 * Variable definition.
1409 */
1410 if (cf_pair_operator(cp) == T_OP_CMP_TRUE) {
1411 if (compile_variable(c, unlang_ctx, cp, &t_rules) < 0) goto fail;
1412
1413 single = UNLANG_IGNORE;
1414 goto add_child;
1415 }
1416
1417 if (!cf_pair_value(cp)) {
1418 single = compile_item(c, unlang_ctx, ci);
1419 if (!single) {
1420 cf_log_err(ci, "Invalid keyword \"%s\".", cf_pair_attr(cp));
1421 goto fail;
1422 }
1423
1424 goto add_child;
1425 }
1426
1427 /*
1428 * What remains MUST be an edit pair. At this point, the state of the compiler
1429 * tells us what it is, and we don't really care if there's a leading '&'.
1430 */
1431 single = compile_edit_pair(c, unlang_ctx, cp);
1432 if (!single) goto fail;
1433
1434 goto add_child;
1435 } else {
1436 cf_log_err(ci, "Asked to compile unknown conf type");
1437 goto fail;
1438 }
1439
1440 add_child:
1441 if (single == UNLANG_IGNORE) continue;
1442
1443 /*
1444 * Do optimizations for "if" and "elsif"
1445 * conditions.
1446 */
1447 switch (single->type) {
1448 case UNLANG_TYPE_ELSIF:
1449 case UNLANG_TYPE_IF:
1450 was_if = true;
1451
1452 {
1453 unlang_group_t *f;
1454 unlang_cond_t *gext;
1455
1456 /*
1457 * Skip else, and/or omit things which will never be run.
1458 */
1459 f = unlang_generic_to_group(single);
1460 gext = unlang_group_to_cond(f);
1461
1462 if (gext->is_truthy) {
1463 if (gext->value) {
1464 skip_else = single->debug_name;
1465 } else {
1466 /*
1467 * If this came from compile_single, then it will already
1468 * have a number and be in the tree.
1469 */
1470 if (single->number) fr_rb_remove(unlang_instruction_tree, single);
1471
1472 /*
1473 * The condition never
1474 * matches, so we can
1475 * avoid putting it into
1476 * the unlang tree.
1477 */
1478 talloc_free(single);
1479 continue;
1480 }
1481 }
1482 }
1483 break;
1484
1485 default:
1486 was_if = false;
1487 skip_else = NULL;
1488 break;
1489 }
1490
1491 /*
1492 * unlang_group_t is grown by adding a unlang_t to the end
1493 */
1494 fr_assert(g == talloc_parent(single));
1496 unlang_list_insert_tail(&g->children, single);
1497 single->list = &g->children;
1498
1499 /*
1500 * If it's not possible to execute statement
1501 * after the current one, then just stop
1502 * processing the children.
1503 */
1504 if (g->self.closed) {
1505 cf_log_warn(ci, "Skipping remaining instructions due to '%s'",
1506 single->name);
1507 break;
1508 }
1509 }
1510
1511 return c;
1512}
1513
1514
1515/*
1516 * Generic "compile a section with more unlang inside of it".
1517 */
1519{
1520 unlang_group_t *g;
1521 unlang_t *c;
1522 char const *name1, *name2;
1523
1524 fr_assert(unlang_ctx->rules != NULL);
1525 fr_assert(unlang_ctx->rules->attr.list_def);
1526
1527 /*
1528 * We always create a group, even if the section is empty.
1529 */
1531 if (!g) return NULL;
1532
1534
1535 /*
1536 * Remember the name for printing, etc.
1537 */
1538 name1 = cf_section_name1(cs);
1539 name2 = cf_section_name2(cs);
1540 c->name = name1;
1541
1542 /*
1543 * Make sure to tell the user that we're running a
1544 * policy, and not anything else.
1545 */
1546 if (type == UNLANG_TYPE_POLICY) {
1547 MEM(c->debug_name = talloc_typed_asprintf(c, "policy %s", name1));
1548
1549 } else if (!name2) {
1550 c->debug_name = c->name;
1551
1552 } else {
1553 MEM(c->debug_name = talloc_typed_asprintf(c, "%s %s", name1, name2));
1554 }
1555
1557}
1558
1559
1561{
1562 CONF_PAIR *cp = cf_item_to_pair(ci);
1563 unlang_t *c;
1564 unlang_tmpl_t *ut;
1565 ssize_t slen;
1566 char const *p = cf_pair_attr(cp);
1567 tmpl_t *vpt;
1568
1569 MEM(ut = talloc_zero(parent, unlang_tmpl_t));
1570 c = unlang_tmpl_to_generic(ut);
1572 c->name = p;
1573 c->debug_name = c->name;
1574 c->ci = CF_TO_ITEM(cp);
1575
1576 RULES_VERIFY(unlang_ctx->rules);
1577 slen = tmpl_afrom_substr(ut, &vpt,
1578 &FR_SBUFF_IN(p, talloc_strlen(p)),
1580 NULL,
1581 unlang_ctx->rules);
1582 if (!vpt) {
1583 cf_canonicalize_error(cp, slen, "Failed parsing expansion", p);
1584 talloc_free(ut);
1585 return NULL;
1586 }
1587 ut->tmpl = vpt; /* const issues */
1588
1589 return c;
1590}
1591
1592/*
1593 * redundant, load-balance and parallel have limits on what can
1594 * go in them.
1595 */
1597{
1598 CONF_ITEM *ci;
1599
1600 for (ci=cf_item_next(cs, NULL);
1601 ci != NULL;
1602 ci=cf_item_next(cs, ci)) {
1603 /*
1604 * If we're a redundant, etc. group, then the
1605 * intention is to call modules, rather than
1606 * processing logic. These checks aren't
1607 * *strictly* necessary, but they keep the users
1608 * from doing crazy things.
1609 */
1610 if (cf_item_is_section(ci)) {
1611 CONF_SECTION *subcs = cf_item_to_section(ci);
1612 char const *name1 = cf_section_name1(subcs);
1613
1614 /*
1615 * Allow almost anything except "else"
1616 * statements. The normal processing
1617 * falls through from "if" to "else", and
1618 * we can't do that for redundant and
1619 * load-balance sections.
1620 */
1621 if ((strcmp(name1, "else") == 0) ||
1622 (strcmp(name1, "elsif") == 0)) {
1623 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1624 name, name1);
1625 return false;
1626 }
1627 continue;
1628 }
1629
1630 if (cf_item_is_pair(ci)) {
1631 CONF_PAIR *cp = cf_item_to_pair(ci);
1632
1633 if (cf_pair_operator(cp) == T_OP_CMP_TRUE) continue;
1634
1635 if (cf_pair_value(cp) != NULL) {
1636 cf_log_err(cp, "Unknown keyword '%s', or invalid location", cf_pair_attr(cp));
1637 return false;
1638 }
1639 }
1640 }
1641
1642 return true;
1643}
1644
1645
1647 CONF_SECTION *subcs,
1648 bool policy)
1649{
1650 unlang_compile_ctx_t unlang_ctx2;
1651 unlang_t *c;
1652
1654
1655 /*
1656 * module.c takes care of ensuring that this is:
1657 *
1658 * group foo { ...
1659 * load-balance foo { ...
1660 * redundant foo { ...
1661 * redundant-load-balance foo { ...
1662 *
1663 * We can just recurse to compile the section as
1664 * if it was found here.
1665 */
1666 if (cf_section_name2(subcs)) {
1667 if (policy) {
1668 cf_log_err(subcs, "Unexpected second name in policy");
1669 return NULL;
1670 }
1671
1672 c = compile_item(parent, &unlang_ctx2, cf_section_to_item(subcs));
1673
1674 } else {
1675 /*
1676 * We have:
1677 *
1678 * foo { ...
1679 *
1680 * So we compile it like it was:
1681 *
1682 * group foo { ...
1683 */
1684 c = unlang_compile_section(parent, &unlang_ctx2, subcs,
1686 }
1687 if (!c) return NULL;
1689
1690 /*
1691 * Return the compiled thing if we can.
1692 */
1693 if (!cf_item_is_section(ci)) return c;
1694
1695 /*
1696 * Else we have a reference to a policy, and that reference
1697 * over-rides the return codes for the policy!
1698 */
1699 if (!unlang_compile_actions(&c->actions, cf_item_to_section(ci), false)) {
1700 talloc_free(c);
1701 return NULL;
1702 }
1703
1704 return c;
1705}
1706
1707/** Load a named module from the virtual module list, or from the "policy" subsection.
1708 *
1709 * If it's "foo.method", look for "foo", and return "method" as the method
1710 * we wish to use, instead of the input component.
1711 *
1712 * @param[in] ci Configuration item to check
1713 * @param[in] real_name Complete name string e.g. foo.authorize.
1714 * @param[in] virtual_name Virtual module name e.g. foo.
1715 * @param[in] method_name Method override (may be NULL) or the method
1716 * name e.g. authorize.
1717 * @param[in] unlang_ctx Unlang context this call is being compiled in.
1718 * @param[out] policy whether or not this thing was a policy
1719 * @return the CONF_SECTION specifying the virtual module.
1720 */
1721static CONF_SECTION *virtual_module_find_cs(CONF_ITEM *ci, UNUSED char const *real_name, char const *virtual_name,
1722 char const *method_name, unlang_compile_ctx_t *unlang_ctx, bool *policy)
1723{
1724 CONF_SECTION *cs, *subcs, *conf_root;
1725 CONF_ITEM *loop;
1726 char buffer[256];
1727
1728 *policy = false;
1729 conf_root = cf_root(ci);
1730
1731 /*
1732 * Look for "foo" as a virtual server. If we find it,
1733 * AND there's no method name, we've found the right
1734 * thing.
1735 *
1736 * Found "foo". Load it as "foo", or "foo.method".
1737 *
1738 * Return it to the caller, with the updated method.
1739 */
1740 subcs = module_rlm_virtual_by_name(virtual_name);
1741 if (subcs) goto check_for_loop;
1742
1743 /*
1744 * Look for it in "policy".
1745 *
1746 * If there's no policy section, we can't do anything else.
1747 */
1748 cs = cf_section_find(conf_root, "policy", NULL);
1749 if (!cs) return NULL;
1750
1751 *policy = true;
1752
1753 /*
1754 * "foo.authorize" means "load policy 'foo.authorize' or 'foo'"
1755 * as method "authorize".
1756 *
1757 * And bail out if there's no policy "foo.authorize" or "foo".
1758 */
1759 if (method_name) {
1760 snprintf(buffer, sizeof(buffer), "%s.%s", virtual_name, method_name);
1761 subcs = cf_section_find(cs, buffer, NULL);
1762 if (!subcs) subcs = cf_section_find(cs, virtual_name, NULL);
1763 if (!subcs) return NULL;
1764
1765 goto check_for_loop;
1766 }
1767
1768 /*
1769 * "foo" means "look for foo.name1.name2" first, to allow
1770 * method overrides. If that's not found, look for
1771 * "foo.name1" and if that's not found just look for
1772 * a policy "foo".
1773 */
1774 if (unlang_ctx->section_name2) {
1775 snprintf(buffer, sizeof(buffer), "%s.%s.%s", virtual_name, unlang_ctx->section_name1, unlang_ctx->section_name2);
1776 subcs = cf_section_find(cs, buffer, NULL);
1777 } else {
1778 subcs = NULL;
1779 }
1780
1781 if (!subcs) {
1782 snprintf(buffer, sizeof(buffer), "%s.%s", virtual_name, unlang_ctx->section_name1);
1783 subcs = cf_section_find(cs, buffer, NULL);
1784 }
1785
1786 if (!subcs) subcs = cf_section_find(cs, virtual_name, NULL);
1787 if (!subcs) return NULL;
1788
1789check_for_loop:
1790 /*
1791 * Check that we're not creating a loop. We may
1792 * be compiling an "sql" module reference inside
1793 * of an "sql" policy. If so, we allow the
1794 * second "sql" to refer to the module.
1795 */
1796 for (loop = cf_parent(ci);
1797 loop && subcs;
1798 loop = cf_parent(loop)) {
1799 if (loop == cf_section_to_item(subcs)) {
1800 return NULL;
1801 }
1802 }
1803
1804 return subcs;
1805}
1806
1808{
1809 unlang_t *c;
1810 unlang_module_t *m;
1811 fr_slen_t slen;
1812
1813 MEM(m = talloc_zero(parent, unlang_module_t));
1814 slen = module_rlm_by_name_and_method(m, &m->mmc,
1815 unlang_ctx->vs,
1816 &(section_name_t){ .name1 = unlang_ctx->section_name1, .name2 = unlang_ctx->section_name2 },
1818 unlang_ctx->rules);
1819 if (slen < 0) {
1820 cf_log_perr(ci, "Failed compiling module call");
1821 talloc_free(m);
1822 return NULL;
1823 }
1824
1825 /*
1826 * We parsed a string, but we were told to ignore it. Don't do anything.
1827 */
1828 if (!m->mmc.rlm) return UNLANG_IGNORE;
1829
1830 if (m->mmc.rlm->common.dict &&
1831 !fr_dict_compatible(*m->mmc.rlm->common.dict, unlang_ctx->rules->attr.dict_def)) {
1832 cf_log_err(ci, "The '%s' module can only be used within a '%s' namespace.",
1833 m->mmc.rlm->common.name, fr_dict_root(*m->mmc.rlm->common.dict)->name);
1834 cf_log_err(ci, "Please use the 'subrequest' keyword to change namespaces");
1835 cf_log_err(ci, DOC_KEYWORD_REF(subrequest));
1836 talloc_free(m);
1837 return NULL;
1838 }
1839
1842 c->name = talloc_strdup(c, name);
1843 c->debug_name = c->name;
1844 c->ci = ci;
1845
1846 /*
1847 * Set the default actions for this module.
1848 */
1849 c->actions = m->mmc.mi->actions;
1850
1851 /*
1852 * Parse the method environment for this module / method
1853 */
1854 if (m->mmc.mmb.method_env) {
1856
1857 fr_assert_msg(method_env->inst_size, "Method environment for module %s, method %s %s declared, "
1858 "but no inst_size set",
1859 m->mmc.mi->name, unlang_ctx->section_name1, unlang_ctx->section_name2);
1860
1861 if (!unlang_ctx->rules) {
1862 cf_log_err(ci, "Failed compiling %s - no rules", m->mmc.mi->name);
1863 goto error;
1864 }
1866 unlang_ctx->rules, m->mmc.mi->conf,
1867 &(call_env_ctx_t){
1868 .type = CALL_ENV_CTX_TYPE_MODULE,
1869 .mi = m->mmc.mi,
1870 .asked = &m->mmc.asked
1871 });
1872 if (!m->call_env) {
1873 error:
1874 talloc_free(m);
1875 return NULL;
1876 }
1877 }
1878
1879 /*
1880 * If a module reference is a section, then the section
1881 * should contain action over-rides. We add those here.
1882 */
1883 if (cf_item_is_section(ci) &&
1885 (m->mmc.mi->exported->flags & MODULE_TYPE_RETRY) != 0)) goto error;
1886
1887 return c;
1888}
1889
1890extern int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src);
1891
1892#define name_to_op(name) fr_hash_table_find(unlang_op_table, &(unlang_op_t) { .name = name })
1893
1895 fr_dict_attr_t const *ref)
1896{
1897 fr_dict_attr_t const *da;
1898 fr_slen_t len;
1899 unlang_op_t const *op;
1900
1901 fr_dict_attr_flags_t flags = {
1902 .internal = true,
1903 .local = true,
1904 };
1905
1906 /*
1907 * No overlap with list names.
1908 */
1910 fail_list:
1911 cf_log_err(ci, "Local variable '%s' cannot be a list reference.", name);
1912 return -1;
1913 }
1914
1915 len = strlen(name);
1916 if (tmpl_attr_list_from_substr(&da, &FR_SBUFF_IN(name, len)) == len) goto fail_list;
1917
1918 /*
1919 * No keyword section names.
1920 */
1921 op = name_to_op(name);
1922 if (op) {
1923 cf_log_err(ci, "Local variable '%s' cannot be an unlang keyword.", name);
1924 return -1;
1925 }
1926
1927 /*
1928 * No protocol names.
1929 */
1930 if (fr_dict_by_protocol_name(name) != NULL) {
1931 cf_log_err(ci, "Local variable '%s' cannot be an existing protocol name.", name);
1932 return -1;
1933 }
1934
1935 /*
1936 * No overlap with attributes in the current dictionary. The lookup in var->root will also check
1937 * the current dictionary, so the check here is really only for better error messages.
1938 */
1939 if (t_rules && t_rules->parent && t_rules->parent->attr.dict_def) {
1940 da = fr_dict_attr_by_name(NULL, fr_dict_root(t_rules->parent->attr.dict_def), name);
1941 if (da) {
1942 cf_log_err(ci, "Local variable '%s' duplicates a dictionary attribute.", name);
1943 return -1;
1944 }
1945 }
1946
1947 /*
1948 * No data types.
1949 */
1951 cf_log_err(ci, "Invalid variable name '%s'.", name);
1952 return -1;
1953 }
1954
1955 /*
1956 * No dups of local variables.
1957 */
1958 da = fr_dict_attr_by_name(NULL, var->root, name);
1959 if (da) {
1960 cf_log_err(ci, "Duplicate variable name '%s'.", name);
1961 return -1;
1962 }
1963
1964 if (fr_dict_attr_add(var->dict, var->root, name, var->max_attr, type, &flags) < 0) {
1965 fail:
1966 cf_log_err(ci, "Failed adding variable '%s' - %s", name, fr_strerror());
1967 return -1;
1968 }
1969 da = fr_dict_attr_by_name(NULL, var->root, name);
1970 fr_assert(da != NULL);
1971
1972 /*
1973 * Copy the children over.
1974 */
1975 var->max_attr++;
1977 fr_fatal_assert(ref != NULL);
1978
1979 if (fr_dict_attr_acopy_local(da, ref) < 0) goto fail;
1980 }
1981
1982
1983 return 0;
1984}
1985
1986/*
1987 * Compile one unlang instruction
1988 */
1990{
1991 char const *name, *p;
1992 CONF_SECTION *cs, *subcs, *modules;
1993 unlang_compile_ctx_t unlang_ctx2;
1994 bool policy;
1995 unlang_t *c;
1996 unlang_op_t const *op;
1997
1998 if (cf_item_is_section(ci)) {
1999 cs = cf_item_to_section(ci);
2000 name = cf_section_name1(cs);
2001 op = name_to_op(name);
2002
2003 if (op) {
2004 /*
2005 * Forbid pair keywords as section names,
2006 * e.g. "break { ... }"
2007 */
2008 if ((op->flag & UNLANG_OP_FLAG_SINGLE_WORD) != 0) {
2009 cf_log_err(ci, "Syntax error after keyword '%s' - unexpected '{'", name);
2010 return NULL;
2011 }
2012
2013 c = op->compile(parent, unlang_ctx, ci);
2014 goto allocate_number;
2015 }
2016
2017 /* else it's something like sql { fail = 1 ...} */
2018 goto check_for_module;
2019
2020 } else if (cf_item_is_pair(ci)) {
2021
2022 /*
2023 * Else it's a module reference such as "sql", OR
2024 * one of the few bare keywords that we allow.
2025 */
2026 CONF_PAIR *cp = cf_item_to_pair(ci);
2027
2028 /*
2029 * We cannot have assignments or actions here.
2030 */
2031 if (cf_pair_value(cp) != NULL) {
2032 cf_log_err(ci, "Invalid assignment");
2033 return NULL;
2034 }
2035
2036 name = cf_pair_attr(cp);
2037 op = name_to_op(name);
2038
2039 if (op) {
2040 /*
2041 * Forbid section keywords as pair names, e.g. "switch = foo"
2042 */
2043 if ((op->flag & UNLANG_OP_FLAG_SINGLE_WORD) == 0) {
2044 cf_log_err(ci, "Syntax error after keyword '%s' - missing '{'", name);
2045 return NULL;
2046 }
2047
2048 c = op->compile(parent, unlang_ctx, ci);
2049 goto allocate_number;
2050 }
2051
2052 /*
2053 * In-place expansions.
2054 *
2055 * @todo - allow only function calls, not %{...}
2056 *
2057 * @todo don't create a tmpl. Instead, create an
2058 * xlat. This functionality is needed for the in-place language functions via
2059 *
2060 * language {{{
2061 * ...
2062 * }}}
2063 */
2064 if (name[0] == '%') {
2066 goto allocate_number;
2067 }
2068
2069 goto check_for_module;
2070
2071 } else {
2072 cf_log_err(ci, "Asked to compile unknown configuration item");
2073 return NULL; /* who knows what it is... */
2074 }
2075
2076check_for_module:
2077 /*
2078 * We now have a name. It can be one of two forms. A
2079 * bare module name, or a section named for the module,
2080 * with over-rides for the return codes.
2081 *
2082 * The name can refer to a real module, in the "modules"
2083 * section. In that case, the name will be either the
2084 * first or second name of the sub-section of "modules".
2085 *
2086 * Or, the name can refer to a policy, in the "policy"
2087 * section. In that case, the name will be first of the
2088 * sub-section of "policy".
2089 *
2090 * Or, the name can refer to a "module.method", in which
2091 * case we're calling a different method than normal for
2092 * this section.
2093 *
2094 * Or, the name can refer to a virtual module, in the
2095 * "modules" section. In that case, the name will be
2096 * name2 of the CONF_SECTION.
2097 *
2098 * We try these in sequence, from the bottom up. This is
2099 * so that virtual modules and things in "policy" can
2100 * over-ride calls to real modules.
2101 */
2102
2103
2104 /*
2105 * Try:
2106 *
2107 * policy { ... name { .. } .. }
2108 * policy { ... name.method { .. } .. }
2109 */
2110 p = strrchr(name, '.');
2111 if (!p) {
2112 subcs = virtual_module_find_cs(ci, name, name, NULL, unlang_ctx, &policy);
2113 } else {
2114 char buffer[256];
2115
2116 strlcpy(buffer, name, sizeof(buffer));
2117 buffer[p - name] = '\0';
2118
2119 subcs = virtual_module_find_cs(ci, name,
2120 buffer, buffer + (p - name) + 1, unlang_ctx, &policy);
2121 }
2122
2123 /*
2124 * We've found the thing which defines this "function".
2125 * It MUST be a sub-section.
2126 *
2127 * i.e. it refers to a a subsection in "policy".
2128 */
2129 if (subcs) {
2130 c = compile_function(parent, unlang_ctx, ci, subcs, policy);
2131 goto allocate_number;
2132 }
2133
2134 /*
2135 * Not a function. It must be a real module.
2136 */
2137 modules = cf_section_find(cf_root(ci), "modules", NULL);
2138 if (!modules) {
2139 cf_log_err(ci, "Failed compiling \"%s\" as a module or policy as no modules are enabled", name);
2140 cf_log_err(ci, "Please verify that modules { ... } section is present in the server configuration");
2141 return NULL;
2142 }
2143
2144 /*
2145 * Set the child compilation context BEFORE parsing the
2146 * module name and method. The lookup function will take
2147 * care of returning the appropriate component, name1,
2148 * name2, etc.
2149 */
2151 c = compile_module(parent, &unlang_ctx2, ci, name);
2152
2153allocate_number:
2154 if (!c) return NULL;
2155 if (c == UNLANG_IGNORE) return UNLANG_IGNORE;
2156
2157 /*
2158 * Some compilation paths already go through this path
2159 * and will have assigned a number.
2160 */
2161 if (c->number) return c;
2162
2163 c->number = unlang_number++;
2165
2167 cf_log_err(ci, "Instruction \"%s\" number %u has conflict with previous one.",
2168 c->debug_name, c->number);
2169 talloc_free(c);
2170 return NULL;
2171 }
2172
2173 return c;
2174}
2175
2176/** Compile an unlang section for a virtual server
2177 *
2178 * @param[in] vs Virtual server to compile section for.
2179 * @param[in] cs containing the unlang calls to compile.
2180 * @param[in] actions Actions to use for the unlang section.
2181 * @param[in] rules Rules to use for the unlang section.
2182 * @param[out] instruction Pointer to store the compiled unlang section.
2183 * @return
2184 * - 0 on success.
2185 * - -1 on error.
2186 */
2188 CONF_SECTION *cs, unlang_mod_actions_t const *actions, tmpl_rules_t const *rules, void **instruction)
2189{
2190 unlang_t *c;
2191 char const *name1, *name2;
2192 CONF_DATA const *cd;
2193
2194 /*
2195 * Don't compile it twice, and don't print out debug
2196 * messages twice.
2197 */
2198 cd = cf_data_find(cs, unlang_group_t, NULL);
2199 if (cd) {
2200 if (instruction) *instruction = cf_data_value(cd);
2201 return 1;
2202 }
2203
2204 /*
2205 * Ensure that all compile functions get valid rules.
2206 */
2207 if (!rules) {
2208 cf_log_err(cs, "Failed compiling section - no namespace rules passed");
2209 return -1;
2210 }
2211
2212 name1 = cf_section_name1(cs);
2213 name2 = cf_section_name2(cs);
2214
2215 if (!name2) name2 = "";
2216
2217 cf_log_debug(cs, "Compiling policies in - %s %s {...}", name1, name2);
2218
2219 c = unlang_compile_section(NULL,
2221 .vs = vs,
2222 .section_name1 = cf_section_name1(cs),
2223 .section_name2 = cf_section_name2(cs),
2224 .actions = *actions,
2225 .rules = rules
2226 },
2227 cs, UNLANG_TYPE_GROUP);
2228 if (!c) return -1;
2229
2231
2232 if (DEBUG_ENABLED4) unlang_dump(c, 2);
2233
2234 /*
2235 * Associate the unlang_t with the configuration section.
2236 * It's already parented from "cs", so don't free it.
2237 */
2238 cf_data_add(cs, c, NULL, false);
2240 if (instruction) *instruction = c;
2241
2242 return 0;
2243}
2244
2245
2246/** Check if name is an unlang keyword
2247 *
2248 * @param[in] name to check.
2249 * @return
2250 * - true if it is a keyword.
2251 * - false if it's not a keyword.
2252 */
2254{
2255 if (!name || !*name) return false;
2256
2257 return (name_to_op(name) != NULL);
2258}
2259
2260/*
2261 * These are really unlang_foo_t, but that's fine...
2262 */
2263static int8_t instruction_cmp(void const *one, void const *two)
2264{
2265 unlang_t const *a = one;
2266 unlang_t const *b = two;
2267
2268 return CMP(a->number, b->number);
2269}
2270
2271
2272void unlang_compile_init(TALLOC_CTX *ctx)
2273{
2275}
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:512
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:113
#define unlikely(_x)
Definition build.h:407
#define UNUSED
Definition build.h:336
#define NUM_ELEMENTS(_t)
Definition build.h:358
static int invalid_type(fr_type_t type)
Definition calc.c:698
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
size_t inst_size
Size of per call env.
Definition call_env.h:245
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Definition cf_file.c:4211
Internal data that is associated with a configuration section.
Definition cf_priv.h:155
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
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:640
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
Definition cf_util.c:1775
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1352
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1906
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_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_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_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
Definition cf_util.c:654
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1760
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:626
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:672
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1397
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_data_add(_cf, _data, _name, _free)
Definition cf_util.h:311
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:300
#define cf_log_debug_prefix(_cf, _fmt,...)
Definition cf_util.h:362
#define cf_data_remove(_cf, _type, _name)
Remove an item from a parent by type and name.
Definition cf_util.h:323
#define cf_root(_cf)
Definition cf_util.h:115
#define cf_section_free_children(_x)
Definition cf_util.h:254
#define cf_parent(_cf)
Definition cf_util.h:118
#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
#define CF_TO_ITEM(_cf)
Auto cast from the input type to CONF_ITEM (which is the base type)
Definition cf_util.h:65
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:346
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:348
#define cf_item_mark_parsed(_cf)
Definition cf_util.h:191
fr_dict_t * dict
Definition common.c:31
unlang_t * unlang_compile_children(unlang_group_t *g, unlang_compile_ctx_t *unlang_ctx_in)
Definition compile.c:1285
static unlang_t * compile_module(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci, char const *name)
Definition compile.c:1807
static unlang_t * compile_edit_pair(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_PAIR *cp)
Compile one edit pair.
Definition compile.c:761
bool unlang_compile_is_keyword(const char *name)
Check if name is an unlang keyword.
Definition compile.c:2253
void unlang_compile_init(TALLOC_CTX *ctx)
Definition compile.c:2272
static bool compile_action_pair(unlang_mod_actions_t *actions, CONF_PAIR *cp)
Definition compile.c:936
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_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules)
Definition compile.c:206
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
static unlang_t * compile_edit_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs)
Compile one edit section.
Definition compile.c:606
bool unlang_compile_limit_subsection(CONF_SECTION *cs, char const *name)
Definition compile.c:1596
static void unlang_dump(unlang_t *c, int depth)
Definition compile.c:234
static int compile_variable(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_PAIR *cp, tmpl_rules_t *t_rules)
Compile a variable definition.
Definition compile.c:847
static char const unlang_spaces[]
Definition compile.c:85
bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *cs, bool module_retry)
Definition compile.c:1082
#define UPDATE_CTX2
Definition compile.c:82
#define name_to_op(name)
Definition compile.c:1892
static int8_t instruction_cmp(void const *one, void const *two)
Definition compile.c:2263
int unlang_fixup_update(map_t *map, void *ctx)
Validate and fixup a map that's part of an update section.
Definition compile.c:346
static bool compile_retry_section(unlang_mod_actions_t *actions, CONF_ITEM *ci)
Definition compile.c:997
static CONF_SECTION * virtual_module_find_cs(CONF_ITEM *ci, UNUSED char const *real_name, char const *virtual_name, char const *method_name, unlang_compile_ctx_t *unlang_ctx, bool *policy)
Load a named module from the virtual module list, or from the "policy" subsection.
Definition compile.c:1721
static unlang_t * compile_item(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci)
Definition compile.c:1989
uint64_t unlang_number
Definition interpret.c:54
static const bool edit_list_sub_op[T_TOKEN_LAST]
Definition compile.c:508
size_t mod_rcode_table_len
Definition compile.c:80
static unlang_t * compile_tmpl(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci)
Definition compile.c:1560
static void compile_set_default_actions(unlang_t *c, unlang_compile_ctx_t *unlang_ctx)
Update a compiled unlang_t with the default actions.
Definition compile.c:484
unlang_t * unlang_compile_empty(unlang_t *parent, UNUSED unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1193
unlang_group_t * unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:451
fr_rb_tree_t * unlang_instruction_tree
Definition compile.c:63
bool pass2_fixup_map(map_t *map, tmpl_rules_t const *rules, fr_dict_attr_t const *parent)
Fixup ONE map (recursively)
Definition compile.c:115
bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules)
Definition compile.c:179
static unlang_t * compile_function(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci, CONF_SECTION *subcs, bool policy)
Definition compile.c:1646
int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src)
Copy the children of an existing attribute.
Definition dict_util.c:1166
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:67
static int unlang_fixup_edit(map_t *map, void *ctx)
Validate and fixup a map that's part of an edit section.
Definition compile.c:529
int unlang_compile(virtual_server_t const *vs, CONF_SECTION *cs, unlang_mod_actions_t const *actions, tmpl_rules_t const *rules, void **instruction)
Compile an unlang section for a virtual server.
Definition compile.c:2187
#define CLAMP(_name, _field, _limit)
#define T(_x)
Definition compile.c:506
int unlang_define_local_variable(CONF_ITEM *ci, unlang_variable_t *var, tmpl_rules_t *t_rules, fr_type_t type, char const *name, fr_dict_attr_t const *ref)
Definition compile.c:1894
static bool compile_action_subsection(unlang_t *c, CONF_SECTION *cs, CONF_SECTION *subcs)
Definition compile.c:1233
static unlang_cond_t * unlang_group_to_cond(unlang_group_t *g)
Cast a group structure to the cond keyword extension.
#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 fr_fatal_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:159
#define MEM(x)
Definition debug.h:36
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
int fr_dict_attr_acopy_local(fr_dict_attr_t const *dst, fr_dict_attr_t const *src)
Definition dict_util.c:1104
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3505
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
Definition dict_util.c:2861
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2639
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:88
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition dict_util.c:2819
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, unsigned int attr, fr_type_t type, fr_dict_attr_flags_t const *flags))
Add an attribute to the dictionary.
Definition dict_util.c:1942
fr_dict_t * fr_dict_protocol_alloc(fr_dict_t const *parent)
Allocate a new local dictionary.
Definition dict_util.c:4243
Values of the encryption flags.
Test enumeration values.
Definition dict_test.h:92
map_list_t maps
Head of the map list.
Definition edit_priv.h:33
static unlang_t * unlang_edit_to_generic(unlang_edit_t const *p)
Definition edit_priv.h:45
static unlang_edit_t * unlang_generic_to_edit(unlang_t const *p)
Cast a generic structure to the edit extension.
Definition edit_priv.h:39
talloc_free(hp)
#define DEBUG_ENABLED4
True if global debug level 1-4 messages are enabled.
Definition log.h:260
int map_afrom_cs_edit(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into an attribute map for editing.
Definition map.c:1167
int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *input_rhs_rules, bool edit)
Convert CONFIG_PAIR (which may contain refs) to map_t.
Definition map.c:110
int map_list_afrom_cs(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *t_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into a list of { a, b, c, d, ... }.
Definition map.c:1352
ssize_t map_print(fr_sbuff_t *out, map_t const *map)
Print a map to a string.
Definition map.c:2387
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
Definition base.c:31
static TALLOC_CTX * unlang_ctx
Definition base.c:71
static unlang_map_t * unlang_group_to_map(unlang_group_t *g)
Cast a group structure to the map keyword extension.
Definition map_priv.h:41
map_list_t map
Head of the map list.
Definition map_priv.h:34
tmpl_t * vpt
Definition map_priv.h:33
fr_type_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
ssize_t fr_slen_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
int strcasecmp(char *s1, char *s2)
Definition missing.c:65
Unlang module actions.
@ MOD_ACTION_RETURN
stop processing the section, and return the rcode with unset priority
Definition mod_action.h:41
@ MOD_ACTION_REJECT
change the rcode to REJECT, with unset priority
Definition mod_action.h:40
@ MOD_ACTION_RETRY
retry the instruction, MUST also set a retry config
Definition mod_action.h:39
#define MOD_ACTION_VALID_SET(_x)
Definition mod_action.h:66
fr_retry_config_t retry
Definition mod_action.h:70
#define MOD_PRIORITY(_x)
Definition mod_action.h:34
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:69
Declarations for the unlang module interface.
static unlang_t * unlang_module_to_generic(unlang_module_t *p)
Definition module_priv.h:92
static unlang_module_t * unlang_generic_to_module(unlang_t const *p)
Definition module_priv.h:86
module_method_call_t mmc
Everything needed to call a module method.
Definition module_priv.h:38
unlang_t self
Common fields in all unlang_t tree nodes.
Definition module_priv.h:36
call_env_t const * call_env
The per call parsed call environment.
Definition module_priv.h:37
A call to a module method.
Definition module_priv.h:35
fr_slen_t module_rlm_by_name_and_method(TALLOC_CTX *ctx, module_method_call_t *mmc_out, virtual_server_t const *vs, section_name_t const *section, fr_sbuff_t *name, tmpl_rules_t const *t_rules)
Find an existing module instance and verify it implements the specified method.
Definition module_rlm.c:548
CONF_SECTION * module_rlm_virtual_by_name(char const *asked_name)
Definition module_rlm.c:792
module_instance_t * mi
The process modules also push module calls onto the stack for execution.
Definition module_rlm.h:63
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
module_method_binding_t mmb
Method we're calling.
Definition module_rlm.h:70
module_rlm_t const * rlm
Cached module_rlm_t.
Definition module_rlm.h:66
Declarations for the unlang "parallel" keyword.
#define fr_assert(_expr)
Definition rad_assert.h:37
void * fr_rb_remove(fr_rb_tree_t *tree, void const *data)
Remove an entry from the tree, without freeing the data.
Definition rb.c:695
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
#define fr_rb_alloc(_ctx, _data_cmp, _data_free)
Allocs a red black tree.
Definition rb.h:221
The main red black tree structure.
Definition rb.h:71
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:51
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:49
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:48
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:52
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:47
@ RLM_MODULE_TIMEOUT
Module (or section) timed out.
Definition rcode.h:56
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:53
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:55
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:45
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:54
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:57
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:50
static const call_env_method_t method_env
Definition rlm_detail.c:474
static char const * name
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_IN_STR(_start)
#define FR_SBUFF_OUT(_start, _len_or_end)
Section name identifier.
Definition section.h:43
char const * name
Instance name e.g. user_database.
Definition module.h:357
@ MODULE_TYPE_RETRY
can handle retries
Definition module.h:51
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:236
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:351
unlang_mod_actions_t actions
default actions and retries.
Definition module.h:325
fr_dict_t const ** dict
required dictionary for this module.
Definition module.h:207
call_env_method_t const * method_env
Method specific call_env.
Definition module.h:178
module_t * exported
Public module structure.
Definition module.h:298
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
Definition tmpl.h:885
#define TMPL_VERIFY(_vpt)
Definition tmpl.h:961
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
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_table_num_sorted_t const tmpl_request_ref_table[]
Map keywords to tmpl_request_ref_t values.
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
#define NUM_ALL
Definition tmpl.h:395
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
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition tmpl.h:179
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
Definition tmpl.h:193
static bool tmpl_attr_tail_da_is_leaf(tmpl_t const *vpt)
Return true if the last attribute reference is a leaf attribute.
Definition tmpl.h:817
#define NUM_COUNT
Definition tmpl.h:396
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.
static bool tmpl_is_list(tmpl_t const *vpt)
Definition tmpl.h:920
int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv))
Convert tmpl_t of type TMPL_TYPE_DATA_UNRESOLVED or TMPL_TYPE_DATA to TMPL_TYPE_DATA of type specifie...
static fr_slen_t vpt
Definition tmpl.h:1269
#define NUM_UNSPEC
Definition tmpl.h:394
static size_t tmpl_attr_num_elements(tmpl_t const *vpt)
The number of attribute references contained within a tmpl.
Definition tmpl.h:896
void tmpl_attr_rewrite_leaf_num(tmpl_t *vpt, int16_t num)
Rewrite the leaf's instance number.
#define tmpl_is_data_unresolved(vpt)
Definition tmpl.h:217
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
@ REQUEST_UNKNOWN
Unknown request.
Definition tmpl.h:97
#define tmpl_is_regex_xlat_unresolved(vpt)
Definition tmpl.h:221
void tmpl_set_dict_def(tmpl_t *vpt, fr_dict_t const *dict)
Change the default dictionary in the tmpl's resolution rules.
fr_slen_t tmpl_attr_list_from_substr(fr_dict_attr_t const **da_p, fr_sbuff_t *in)
Parse one a single list reference.
Similar to tmpl_rules_t, but used to specify parameters that may change during subsequent resolution ...
Definition tmpl.h:368
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:336
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
fr_aka_sim_id_type_t type
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
Value pair map.
Definition map.h:77
fr_token_t op
The operator that controls insertion of the dst attribute.
Definition map.h:82
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition map.h:78
map_list_t child
parent map, for nested ones
Definition map.h:89
map_t * parent
Definition map.h:88
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition map.h:79
CONF_ITEM * ci
Config item that the map was created from.
Definition map.h:85
unsigned int allow_unknown
Allow unknown attributes i.e.
Definition tmpl.h:303
CONF_ITEM * ci
for migration support and various warnings
Definition tmpl.h:301
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:273
#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
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
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
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
fr_slen_t fr_time_delta_from_str(fr_time_delta_t *out, char const *in, size_t inlen, fr_time_res_t hint)
Create fr_time_delta_t from a string.
Definition time.c:412
#define fr_time_delta_ispos(_a)
Definition time.h:290
@ FR_TIME_RES_SEC
Definition time.h:50
const bool fr_assignment_op[T_TOKEN_LAST]
Definition token.c:236
const bool fr_list_assignment_op[T_TOKEN_LAST]
Definition token.c:253
fr_table_num_ordered_t const fr_tokens_table[]
Definition token.c:33
char const * fr_tokens[T_TOKEN_LAST]
Definition token.c:146
const bool fr_comparison_op[T_TOKEN_LAST]
Definition token.c:266
const bool fr_binary_op[T_TOKEN_LAST]
Definition token.c:284
enum fr_token fr_token_t
@ T_OP_SUB_EQ
Definition token.h:68
@ T_INVALID
Definition token.h:37
@ T_OP_CMP_TRUE
Definition token.h:102
@ T_OP_EQ
Definition token.h:81
@ T_OP_SET
Definition token.h:82
@ T_OP_CMP_FALSE
Definition token.h:103
#define T_TOKEN_LAST
Definition token.h:127
Declarations for unlang transactions.
Declaration for unlang try.
#define RULES_VERIFY(_rules)
CONF_SECTION * cs
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.
tmpl_rules_t const * rules
unlang_t * parent
Previous node.
static void unlang_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
fr_dict_attr_t const * root
the root of our dictionary
size_t pool_len
How much additional space to allocate for chunks.
static void unlang_compile_ctx_copy(unlang_compile_ctx_t *dst, unlang_compile_ctx_t const *src)
bool closed
whether or not this section is closed to new statements
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
#define unlang_list_foreach(_list_head, _iter)
char const * unlang_name
Talloc type name for the unlang_t.
#define UNLANG_IGNORE
static unlang_t * unlang_tmpl_to_generic(unlang_tmpl_t const *p)
CONF_ITEM * ci
used to generate this item
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
unsigned int number
unique node number
size_t unlang_size
Total length of the unlang_t + specialisation struct.
unlang_list_t children
char const * name
Unknown...
unlang_type_t
Types of unlang_t nodes.
Definition unlang_priv.h:47
@ UNLANG_TYPE_SWITCH
Switch section.
Definition unlang_priv.h:59
@ UNLANG_TYPE_TRANSACTION
transactions for editing lists
Definition unlang_priv.h:75
@ UNLANG_TYPE_FINALLY
run at the end of a virtual server.
Definition unlang_priv.h:78
@ UNLANG_TYPE_SUBREQUEST
create a child subrequest
Definition unlang_priv.h:67
@ UNLANG_TYPE_CONTINUE
Break statement (within a UNLANG_TYPE_FOREACH).
Definition unlang_priv.h:63
@ UNLANG_TYPE_ELSIF
!Condition && Condition.
Definition unlang_priv.h:58
@ UNLANG_TYPE_ELSE
!Condition.
Definition unlang_priv.h:57
@ UNLANG_TYPE_LOAD_BALANCE
Load balance section.
Definition unlang_priv.h:53
@ UNLANG_TYPE_DETACH
detach a child
Definition unlang_priv.h:70
@ UNLANG_TYPE_GROUP
Grouping section.
Definition unlang_priv.h:51
@ UNLANG_TYPE_POLICY
Policy section.
Definition unlang_priv.h:79
@ UNLANG_TYPE_TMPL
asynchronously expand a tmpl_t
Definition unlang_priv.h:81
@ UNLANG_TYPE_CASE
Case section (within a UNLANG_TYPE_SWITCH).
Definition unlang_priv.h:60
@ UNLANG_TYPE_LIMIT
limit number of requests in a section
Definition unlang_priv.h:74
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH or UNLANG_TYPE_CASE).
Definition unlang_priv.h:62
@ UNLANG_TYPE_TRY
try / catch blocks
Definition unlang_priv.h:76
@ UNLANG_TYPE_CALL
call another virtual server
Definition unlang_priv.h:71
@ UNLANG_TYPE_RETURN
Return statement.
Definition unlang_priv.h:64
@ UNLANG_TYPE_REDUNDANT
exactly like group, but with different default return codes
Definition unlang_priv.h:52
@ UNLANG_TYPE_MAX
Definition unlang_priv.h:83
@ UNLANG_TYPE_IF
Condition.
Definition unlang_priv.h:56
@ UNLANG_TYPE_XLAT
Represents one level of an xlat expansion.
Definition unlang_priv.h:80
@ UNLANG_TYPE_NULL
unlang type not set.
Definition unlang_priv.h:48
@ UNLANG_TYPE_MAP
Mapping section (like #UNLANG_TYPE_UPDATE, but uses values from a map_proc_t call).
Definition unlang_priv.h:65
@ UNLANG_TYPE_CALLER
conditionally check parent dictionary type
Definition unlang_priv.h:72
@ UNLANG_TYPE_TIMEOUT
time-based timeouts.
Definition unlang_priv.h:73
@ UNLANG_TYPE_MODULE
Module method.
Definition unlang_priv.h:49
@ UNLANG_TYPE_REDUNDANT_LOAD_BALANCE
Redundant load balance section.
Definition unlang_priv.h:54
@ UNLANG_TYPE_CHILD_REQUEST
a frame at the top of a child's request stack used to signal the parent when the child is complete.
Definition unlang_priv.h:68
@ UNLANG_TYPE_CATCH
catch a previous try
Definition unlang_priv.h:77
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
Definition unlang_priv.h:50
@ UNLANG_TYPE_EDIT
edit VPs in place. After 20 years!
Definition unlang_priv.h:82
@ UNLANG_TYPE_FOREACH
Foreach section.
Definition unlang_priv.h:61
@ UNLANG_TYPE_PARALLEL
execute statements in parallel
Definition unlang_priv.h:55
unsigned pool_headers
How much additional space to allocate for chunk headers.
unlang_compile_t compile
compile the keyword
unlang_variable_t * variables
rarely used, so we don't usually need it
#define debug_braces(_type)
char const * name
Name of the keyword.
int max_attr
1..N local attributes have been defined
fr_dict_t * dict
our dictionary
static void unlang_group_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
tmpl_t const * tmpl
@ UNLANG_OP_FLAG_SINGLE_WORD
the operation is parsed and compiled as a single word
unlang_type_t type
The specialisation of this node.
unlang_op_flag_t flag
Interpreter flags for this operation.
unlang_list_t * list
so we have fewer run-time dereferences
Generic representation of a grouping.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
A naked xlat.
static fr_slen_t parent
Definition pair.h:858
fr_time_delta_t irt
Initial transmission time.
Definition retry.h:33
fr_time_delta_t mrt
Maximum retransmission time.
Definition retry.h:34
uint32_t mrc
Maximum retransmission count.
Definition retry.h:36
fr_time_delta_t mrd
Maximum retransmission duration.
Definition retry.h:35
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_structural(_x)
Definition types.h:392
#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
static size_t char ** out
Definition value.h:1030