The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
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: 72dcc2016ecb7cffcd913a2d9405a7699cf5a734 $
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: 72dcc2016ecb7cffcd913a2d9405a7699cf5a734 $")
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 rlm_rcode_t 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 = RLM_MODULE_NOT_SET; 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 {
564 tmpl_attr_t *ar = tmpl_attr_list_head(tmpl_attr(map->lhs));
565 if (tmpl_attr_is_list_attr(ar)) ar = tmpl_attr_list_next(tmpl_attr(map->lhs), ar);
566 da = ar->da;
567 if (!da->flags.internal && parent && (parent->type != FR_TYPE_GROUP) &&
568 (da->parent != parent)) {
569 /* FIXME - Broken check, doesn't work for key attributes */
570 cf_log_err(cp, "Invalid location for %s - it is not a child of %s",
571 da->name, parent->name);
572 return -1;
573 }
574 }
575 break;
576
578 case TMPL_TYPE_XLAT:
579 break;
580
581 default:
582 cf_log_err(map->ci, "Left side of map must be an attribute "
583 "or an xlat (that expands to an attribute), not a %s",
584 tmpl_type_to_str(map->lhs->type));
585 return -1;
586 }
587
588 fr_assert(map->rhs);
589
590 switch (map->rhs->type) {
593 case TMPL_TYPE_XLAT:
594 case TMPL_TYPE_DATA:
595 case TMPL_TYPE_ATTR:
596 case TMPL_TYPE_EXEC:
597 break;
598
599 default:
600 cf_log_err(map->ci, "Right side of map must be an attribute, literal, xlat or exec, got type %s",
601 tmpl_type_to_str(map->rhs->type));
602 return -1;
603 }
604
605 return 0;
606}
607
608/** Compile one edit section.
609 */
611{
612 unlang_edit_t *edit;
614 map_t *map;
615 char const *name;
616 fr_token_t op;
617 fr_slen_t slen;
618 fr_dict_attr_t const *parent_da;
619 int num;
620
621 tmpl_rules_t t_rules;
622
624 if (name) {
625 cf_log_err(cs, "Unexpected name2 '%s' for editing list %s ", name, cf_section_name1(cs));
626 return NULL;
627 }
628
629 op = cf_section_name2_quote(cs);
630 if ((op == T_INVALID) || !fr_list_assignment_op[op]) {
631 cf_log_err(cs, "Invalid operator '%s' for editing list %s.", fr_tokens[op], cf_section_name1(cs));
632 return NULL;
633 }
634
635 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
636 cf_log_err(cs, "Invalid operator \"%s\".",
637 fr_table_str_by_value(fr_tokens_table, op, "<INVALID>"));
638 return NULL;
639 }
640
641 /*
642 * We allow unknown attributes here.
643 */
644 t_rules = *(unlang_ctx->rules);
645 t_rules.attr.allow_unknown = true;
646 RULES_VERIFY(&t_rules);
647
648 edit = talloc_zero(parent, unlang_edit_t);
649 if (!edit) return NULL;
650
651 c = out = unlang_edit_to_generic(edit);
653 c->name = cf_section_name1(cs);
654 c->debug_name = c->name;
655 c->ci = CF_TO_ITEM(cs);
656
657 map_list_init(&edit->maps);
658
659 /*
660 * Allocate the map and initialize it.
661 */
662 MEM(map = talloc_zero(edit, map_t));
663 map->op = op;
664 map->ci = cf_section_to_item(cs);
665 map_list_init(&map->child);
666
668
669 slen = tmpl_afrom_attr_str(map, NULL, &map->lhs, name, &t_rules);
670 if (slen <= 0) {
671 cf_log_err(cs, "Failed parsing list reference %s - %s", name, fr_strerror());
672 fail:
673 talloc_free(edit);
674 return NULL;
675 }
676
677 /*
678 * Can't assign to [*] or [#]
679 */
680 num = tmpl_attr_tail_num(map->lhs);
681 if ((num == NUM_ALL) || (num == NUM_COUNT)) {
682 cf_log_err(cs, "Invalid array reference in %s", name);
683 goto fail;
684 }
685
686 /*
687 * If the DA isn't structural, then it can't have children.
688 */
689 parent_da = tmpl_attr_tail_da(map->lhs);
690 if (fr_type_is_structural(parent_da->type)) {
691 map_t *child;
692
693 /*
694 * Reset the namespace to be this attribute. The tmpl tokenizer will take care of
695 * figuring out if this is a group, TLV, dictionary switch, etc.
696 */
697 t_rules.attr.namespace = parent_da;
698
699 if (map_afrom_cs_edit(map, &map->child, cs, &t_rules, &t_rules, unlang_fixup_edit, map, 256) < 0) {
700 goto fail;
701 }
702
703 /*
704 * As a set of fixups... we can't do array references in -=
705 */
706 if (map->op == T_OP_SUB_EQ) {
707 for (child = map_list_head(&map->child); child != NULL; child = map_list_next(&map->child, child)) {
708 if (!tmpl_is_attr(child->lhs)) continue;
709
710 if (tmpl_attr_tail_num(child->lhs) != NUM_UNSPEC) {
711 cf_log_err(child->ci, "Cannot use array references and values when deleting from a list");
712 goto fail;
713 }
714
715 /*
716 * The edit code doesn't do this correctly, so we just forbid it.
717 */
718 if ((tmpl_attr_num_elements(child->lhs) - tmpl_attr_num_elements(map->lhs)) > 1) {
719 cf_log_err(child->ci, "List deletion must operate directly on the final child");
720 goto fail;
721 }
722
723 /*
724 * We don't do list comparisons either.
725 */
726 if (fr_type_is_structural(tmpl_attr_tail_da(child->lhs)->type)) {
727 cf_log_err(child->ci, "List deletion cannot operate on lists");
728 goto fail;
729 }
730 }
731 }
732 } else {
733 /*
734 * foo := { a, b, c }
735 */
736 if (map_list_afrom_cs(map, &map->child, cs, &t_rules, NULL, NULL, 256) < 0) {
737 goto fail;
738 }
739
740 if ((map->op != T_OP_SET) && !map_list_num_elements(&map->child)) {
741 cf_log_err(cs, "Cannot use operator '%s' for assigning empty list to '%s' data type.",
742 fr_tokens[map->op], fr_type_to_str(parent_da->type));
743 goto fail;
744 }
745 }
746 /*
747 * Do basic sanity checks and resolving.
748 */
749 if (!pass2_fixup_map(map, unlang_ctx->rules, NULL)) goto fail;
750
751 /*
752 * Check operators, and ensure that the RHS has been
753 * resolved.
754 */
755// if (unlang_fixup_update(map, NULL) < 0) goto fail;
756
757 map_list_insert_tail(&edit->maps, map);
758
759 return out;
760}
761
762/** Compile one edit pair
763 *
764 */
766{
767 unlang_edit_t *edit;
768 unlang_t *c = NULL, *out = UNLANG_IGNORE;
769 map_t *map;
770 int num;
771
772 tmpl_rules_t t_rules;
773 fr_token_t op;
774
775 /*
776 * We allow unknown attributes here.
777 */
778 t_rules = *(unlang_ctx->rules);
779 t_rules.attr.allow_unknown = true;
780 fr_assert(t_rules.attr.ci == cf_pair_to_item(cp));
781 RULES_VERIFY(&t_rules);
782
783 edit = talloc_zero(parent, unlang_edit_t);
784 if (!edit) return NULL;
785
786 c = out = unlang_edit_to_generic(edit);
788 c->name = cf_pair_attr(cp);
789 c->debug_name = c->name;
790 c->ci = CF_TO_ITEM(cp);
791
792 map_list_init(&edit->maps);
793
794 op = cf_pair_operator(cp);
795 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
796 cf_log_err(cp, "Invalid operator \"%s\".",
797 fr_table_str_by_value(fr_tokens_table, op, "<INVALID>"));
798 fail:
799 talloc_free(edit);
800 return NULL;
801 }
802
803 /*
804 * Convert this particular map.
805 */
806 if (map_afrom_cp(edit, &map, map_list_tail(&edit->maps), cp, &t_rules, NULL, true) < 0) {
807 goto fail;
808 }
809
810 /*
811 * @todo - we still want to do fixups on the RHS?
812 */
813 if (tmpl_is_attr(map->lhs)) {
814 /*
815 * Can't assign to [*] or [#]
816 */
817 num = tmpl_attr_tail_num(map->lhs);
818 if ((num == NUM_ALL) || (num == NUM_COUNT)) {
819 cf_log_err(cp, "Invalid array reference in %s", map->lhs->name);
820 goto fail;
821 }
822
823 if ((map->op == T_OP_SUB_EQ) && fr_type_is_structural(tmpl_attr_tail_da(map->lhs)->type) &&
824 tmpl_is_attr(map->rhs) && tmpl_attr_tail_da(map->rhs)->flags.local) {
825 cf_log_err(cp, "Cannot delete local variable %s", map->rhs->name);
826 goto fail;
827 }
828 }
829
830 /*
831 * Do basic sanity checks and resolving.
832 */
833 if (!pass2_fixup_map(map, unlang_ctx->rules, NULL)) goto fail;
834
835 /*
836 * Check operators, and ensure that the RHS has been
837 * resolved.
838 */
839 if (unlang_fixup_update(map, c) < 0) goto fail;
840
841 map_list_insert_tail(&edit->maps, map);
842
843 return out;
844}
845
846/** Compile a variable definition.
847 *
848 * Definitions which are adjacent to one another are automatically merged
849 * into one larger variable definition.
850 */
852{
855 char const *attr, *value;
856 unlang_group_t *group;
857
859
860 /*
861 * Enforce locations for local variables.
862 */
863 switch (parent->type) {
864 case UNLANG_TYPE_CASE:
865 case UNLANG_TYPE_ELSE:
869 case UNLANG_TYPE_IF:
877 break;
878
879 default:
880 cf_log_err(cp, "Local variables cannot be used here");
881 return -1;
882 }
883
884 /*
885 * The variables exist in the parent block.
886 */
888 if (group->variables) {
889 var = group->variables;
890
891 } else {
892 group->variables = var = talloc_zero(parent, unlang_variable_t);
893 if (!var) return -1;
894
895 var->dict = fr_dict_protocol_alloc(unlang_ctx->rules->attr.dict_def);
896 if (!var->dict) {
897 group->variables = NULL;
898 talloc_free(var);
899 return -1;
900 }
901 var->root = fr_dict_root(var->dict);
902
903 var->max_attr = 1;
904
905 /*
906 * Initialize the new rules, and point them to the parent rules.
907 *
908 * Then replace the parse rules with our rules, and our dictionary.
909 */
910 *t_rules = *unlang_ctx->rules;
911 t_rules->parent = unlang_ctx->rules;
912
913 t_rules->attr.dict_def = var->dict;
914 t_rules->attr.namespace = NULL;
915
916 unlang_ctx->rules = t_rules;
917 }
918
919 attr = cf_pair_attr(cp); /* data type */
920 value = cf_pair_value(cp); /* variable name */
921
923 if (type == FR_TYPE_NULL) {
925 cf_log_err(cp, "Invalid data type '%s'", attr);
926 return -1;
927 }
928
929 /*
930 * Leaf and group are OK. TLV, Vendor, Struct, VSA, etc. are not.
931 */
932 if (!(fr_type_is_leaf(type) || (type == FR_TYPE_GROUP))) goto invalid_type;
933
934 return unlang_define_local_variable(cf_pair_to_item(cp), var, t_rules, type, value, NULL);
935}
936
937/*
938 * Compile action && rcode for later use.
939 */
941{
942 int action;
943 char const *attr, *value;
944
945 attr = cf_pair_attr(cp);
946 value = cf_pair_value(cp);
947 if (!value) return true;
948
949 if (!strcasecmp(value, "return"))
950 action = MOD_ACTION_RETURN;
951
952 else if (!strcasecmp(value, "break"))
953 action = MOD_ACTION_RETURN;
954
955 else if (!strcasecmp(value, "reject"))
956 action = MOD_ACTION_REJECT;
957
958 else if (!strcasecmp(value, "retry"))
959 action = MOD_ACTION_RETRY;
960
961 else if (strspn(value, "0123456789") == strlen(value)) {
962 if (strlen(value) > 2) {
963 invalid_action:
964 cf_log_err(cp, "Priorities MUST be between 1 and 64.");
965 return false;
966 }
967
968 action = (unlang_mod_action_t)MOD_PRIORITY(atoi(value));
969
970 if (!MOD_ACTION_VALID_SET(action)) goto invalid_action;
971
972 } else {
973 cf_log_err(cp, "Unknown action '%s'.\n",
974 value);
975 return false;
976 }
977
978 if (strcasecmp(attr, "default") != 0) {
979 int rcode;
980
981 rcode = fr_table_value_by_str(mod_rcode_table, attr, -1);
982 if (rcode < 0) {
983 cf_log_err(cp,
984 "Unknown module rcode '%s'.",
985 attr);
986 return false;
987 }
988 actions->actions[rcode] = action;
989
990 } else { /* set all unset values to the default */
991 rlm_rcode_t i;
992
993 for (i = RLM_MODULE_NOT_SET; i < RLM_MODULE_NUMCODES; i++) {
994 if (!actions->actions[i]) actions->actions[i] = action;
995 }
996 }
997
998 return true;
999}
1000
1002{
1003 CONF_ITEM *csi;
1004 CONF_SECTION *cs;
1005
1006 cs = cf_item_to_section(ci);
1007 for (csi=cf_item_next(cs, NULL);
1008 csi != NULL;
1009 csi=cf_item_next(cs, csi)) {
1010 CONF_PAIR *cp;
1011 char const *name, *value;
1012
1013 if (cf_item_is_section(csi)) {
1014 cf_log_err(csi, "Invalid subsection in 'retry' configuration.");
1015 return false;
1016 }
1017
1018 if (!cf_item_is_pair(csi)) continue;
1019
1020 cp = cf_item_to_pair(csi);
1021 name = cf_pair_attr(cp);
1022 value = cf_pair_value(cp);
1023
1024 if (!value) {
1025 cf_log_err(csi, "Retry configuration must specify a value");
1026 return false;
1027 }
1028
1029#define CLAMP(_name, _field, _limit) do { \
1030 if (!fr_time_delta_ispos(actions->retry._field)) { \
1031 cf_log_err(csi, "Invalid value for '" STRINGIFY(_name) " = %s' - value must be positive", \
1032 value); \
1033 return false; \
1034 } \
1035 if (fr_time_delta_cmp(actions->retry._field, fr_time_delta_from_sec(_limit)) > 0) { \
1036 cf_log_err(csi, "Invalid value for '" STRINGIFY(_name) " = %s' - value must be less than " STRINGIFY(_limit) "s", \
1037 value); \
1038 return false; \
1039 } \
1040 } while (0)
1041
1042 /*
1043 * We don't use conf_parser_t here for various
1044 * magical reasons.
1045 */
1046 if (strcmp(name, "initial_rtx_time") == 0) {
1047 if (fr_time_delta_from_str(&actions->retry.irt, value, strlen(value), FR_TIME_RES_SEC) < 0) {
1048 error:
1049 cf_log_err(csi, "Failed parsing '%s = %s' - %s",
1050 name, value, fr_strerror());
1051 return false;
1052 }
1053 CLAMP(initial_rtx_time, irt, 2);
1054
1055 } else if (strcmp(name, "max_rtx_time") == 0) {
1056 if (fr_time_delta_from_str(&actions->retry.mrt, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
1057
1058 CLAMP(max_rtx_time, mrt, 10);
1059
1060 } else if (strcmp(name, "max_rtx_count") == 0) {
1061 char *end;
1062 unsigned long v = strtoul(value, &end, 10);
1063
1064 if (*end || (end == value) || (v > 10)) {
1065 cf_log_err(csi, "Invalid value for 'max_rtx_count = %s' - value must be between 0 and 10",
1066 value);
1067 return false;
1068 }
1069
1070 actions->retry.mrc = v;
1071
1072 } else if (strcmp(name, "max_rtx_duration") == 0) {
1073 if (fr_time_delta_from_str(&actions->retry.mrd, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
1074
1075 CLAMP(max_rtx_duration, mrd, 20);
1076
1077 } else {
1078 cf_log_err(csi, "Invalid item '%s' in 'retry' configuration.", name);
1079 return false;
1080 }
1081 }
1082
1083 return true;
1084}
1085
1086bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *cs, bool module_retry)
1087{
1088 rlm_rcode_t i;
1089 bool disallow_retry_action = false;
1090 CONF_ITEM *csi;
1091
1092 /*
1093 * Over-ride the default return codes of the module.
1094 */
1095 for (csi=cf_item_next(cs, NULL);
1096 csi != NULL;
1097 csi=cf_item_next(cs, csi)) {
1098 char const *name;
1099 CONF_PAIR *cp;
1100
1101 if (cf_item_is_section(csi)) {
1102 CONF_SECTION *subcs = cf_item_to_section(csi);
1103
1104 name = cf_section_name1(subcs);
1105
1106 /*
1107 * Look for a "retry" section.
1108 */
1109 if (name && (strcmp(name, "retry") == 0) && !cf_section_name2(subcs)) {
1110 if (!compile_retry_section(actions, csi)) return false;
1111 continue;
1112 }
1113
1114 cf_log_err(csi, "Invalid subsection. Expected 'action = value'");
1115 return false;
1116 }
1117
1118 if (!cf_item_is_pair(csi)) continue;
1119
1120 cp = cf_item_to_pair(csi);
1121
1122 /*
1123 * Allow 'retry = path.to.retry.config'
1124 */
1125 name = cf_pair_attr(cp);
1126 if (strcmp(name, "retry") == 0) {
1127 CONF_ITEM *subci;
1128 char const *value = cf_pair_value(cp);
1129
1130 if (!value) {
1131 cf_log_err(csi, "Missing reference string");
1132 return false;
1133 }
1134
1136 if (!subci) {
1137 cf_log_perr(csi, "Failed finding reference '%s'", value);
1138 return false;
1139 }
1140
1141 if (!compile_retry_section(actions, subci)) return false;
1142 continue;
1143 }
1144
1145 if (!compile_action_pair(actions, cp)) {
1146 return false;
1147 }
1148 }
1149
1150 if (module_retry) {
1151 if (!fr_time_delta_ispos(actions->retry.irt)) {
1152 cf_log_err(cs, "initial_rtx_time MUST be non-zero for modules which support retries.");
1153 return false;
1154 }
1155 } else {
1156 if (fr_time_delta_ispos(actions->retry.irt)) {
1157 cf_log_err(cs, "initial_rtx_time MUST be zero, as only max_rtx_count and max_rtx_duration are used.");
1158 return false;
1159 }
1160
1161 if (!actions->retry.mrc && !fr_time_delta_ispos(actions->retry.mrd)) {
1162 disallow_retry_action = true;
1163 }
1164 }
1165
1166 /*
1167 * Sanity check that "fail = retry", we actually have a
1168 * retry section.
1169 */
1170 for (i = RLM_MODULE_NOT_SET; i < RLM_MODULE_NUMCODES; i++) {
1171 if (actions->actions[i] != MOD_ACTION_RETRY) continue;
1172
1173 if (module_retry) {
1174 cf_log_err(cs, "Cannot use a '%s = retry' action for a module which has its own retries",
1175 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1176 return false;
1177 }
1178
1179 if (disallow_retry_action) {
1180 cf_log_err(cs, "max_rtx_count and max_rtx_duration cannot both be zero when using '%s = retry'",
1181 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1182 return false;
1183 }
1184
1185 if (!fr_time_delta_ispos(actions->retry.irt) &&
1186 !actions->retry.mrc &&
1187 !fr_time_delta_ispos(actions->retry.mrd)) {
1188 cf_log_err(cs, "Cannot use a '%s = retry' action without a 'retry { ... }' section.",
1189 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1190 return false;
1191 }
1192 }
1193
1194 return true;
1195}
1196
1198{
1199 unlang_group_t *g;
1200 unlang_t *c;
1201
1202 /*
1203 * If we're compiling an empty section, then the
1204 * *interpreter* type is GROUP, even if the *debug names*
1205 * are something else.
1206 */
1208 if (!g) return NULL;
1209
1211 if (!cs) {
1212 c->name = unlang_ops[type].name;
1213 c->debug_name = c->name;
1214
1215 } else {
1216 char const *name2;
1217
1218 name2 = cf_section_name2(cs);
1219 if (!name2) {
1220 c->name = cf_section_name1(cs);
1221 c->debug_name = c->name;
1222 } else {
1223 c->name = name2;
1224 c->debug_name = talloc_typed_asprintf(c, "%s %s", cf_section_name1(cs), name2);
1225 }
1226 }
1227
1228 return c;
1229}
1230
1231
1233
1234/*
1235 * compile 'actions { ... }' inside of another group.
1236 */
1238{
1239 CONF_ITEM *ci, *next;
1240
1241 ci = cf_section_to_item(subcs);
1242
1243 next = cf_item_next(cs, ci);
1244 if (next && (cf_item_is_pair(next) || cf_item_is_section(next))) {
1245 cf_log_err(ci, "'actions' MUST be the last block in a section");
1246 return false;
1247 }
1248
1249 if (cf_section_name2(subcs) != NULL) {
1250 cf_log_err(ci, "Invalid name for 'actions' section");
1251 return false;
1252 }
1253
1254 /*
1255 * Over-riding the actions can be done in certain limited
1256 * situations. In other situations (e.g. "redundant",
1257 * "load-balance"), it doesn't make sense.
1258 *
1259 * Note that this limitation also applies to "retry"
1260 * timers. We can do retries of a "group". We cannot do
1261 * retries of "load-balance", as the "load-balance"
1262 * section already takes care of redundancy.
1263 *
1264 * We may need to loosen that limitation in the future.
1265 */
1266 switch (c->type) {
1267 case UNLANG_TYPE_CASE:
1268 case UNLANG_TYPE_CATCH:
1269 case UNLANG_TYPE_IF:
1270 case UNLANG_TYPE_ELSE:
1271 case UNLANG_TYPE_ELSIF:
1273 case UNLANG_TYPE_GROUP:
1274 case UNLANG_TYPE_LIMIT:
1275 case UNLANG_TYPE_SWITCH:
1278 break;
1279
1280 default:
1281 cf_log_err(ci, "'actions' MUST NOT be in a '%s' block", unlang_ops[c->type].name);
1282 return false;
1283 }
1284
1285 return unlang_compile_actions(&c->actions, subcs, false);
1286}
1287
1288
1290{
1291 CONF_ITEM *ci = NULL;
1292 unlang_t *c, *single;
1293 bool was_if = false;
1294 char const *skip_else = NULL;
1296 unlang_compile_ctx_t unlang_ctx2;
1297 tmpl_rules_t t_rules, t2_rules; /* yes, it does */
1298
1300
1301 /*
1302 * Create our own compilation context which can be edited
1303 * by a variable definition.
1304 */
1305 unlang_compile_ctx_copy(&unlang_ctx2, unlang_ctx_in);
1306 t2_rules = *(unlang_ctx_in->rules);
1307
1308 unlang_ctx = &unlang_ctx2;
1309 unlang_ctx2.rules = &t2_rules;
1310
1311 t_rules = *unlang_ctx_in->rules;
1312
1313 /*
1314 * Loop over the children of this group.
1315 */
1316 while ((ci = cf_item_next(g->cs, ci))) {
1317 if (cf_item_is_data(ci)) continue;
1318
1319 t_rules.attr.ci = ci;
1320 t2_rules.attr.ci = ci;
1321
1322 /*
1323 * Sections are keywords, or references to
1324 * modules with updated return codes.
1325 */
1326 if (cf_item_is_section(ci)) {
1327 char const *name = NULL;
1328 CONF_SECTION *subcs = cf_item_to_section(ci);
1329
1330 /*
1331 * Skip precompiled blocks. This is
1332 * mainly for policies.
1333 */
1334 if (cf_data_find(subcs, unlang_group_t, NULL)) continue;
1335
1336 /*
1337 * "actions" apply to the current group.
1338 * It's not a subgroup.
1339 */
1340 name = cf_section_name1(subcs);
1341
1342 /*
1343 * In-line attribute editing. Nothing else in the parse has list assignments, so this must be it.
1344 */
1346 single = compile_edit_section(c, unlang_ctx, subcs);
1347 if (!single) {
1348 fail:
1349 talloc_free(c);
1350 return NULL;
1351 }
1352
1353 goto add_child;
1354 }
1355
1356 if (strcmp(name, "actions") == 0) {
1357 if (!compile_action_subsection(c, g->cs, subcs)) goto fail;
1358 continue;
1359 }
1360
1361 /*
1362 * Special checks for "else" and "elsif".
1363 */
1364 if ((strcmp(name, "else") == 0) || (strcmp(name, "elsif") == 0)) {
1365 /*
1366 * We ran into one without a preceding "if" or "elsif".
1367 * That's not allowed.
1368 */
1369 if (!was_if) {
1370 cf_log_err(ci, "Invalid location for '%s'. There is no preceding "
1371 "'if' or 'elsif' statement", name);
1372 goto fail;
1373 }
1374
1375 /*
1376 * There was a previous "if" or "elsif" which was always taken.
1377 * So we skip this "elsif" or "else".
1378 */
1379 if (skip_else) {
1380 void *ptr;
1381
1382 /*
1383 * And manually free this.
1384 */
1385 ptr = cf_data_remove(subcs, xlat_exp_head_t, NULL);
1386 talloc_free(ptr);
1387
1389
1390 cf_log_debug_prefix(ci, "Skipping contents of '%s' due to previous "
1391 "'%s' always being taken.",
1392 name, skip_else);
1393 continue;
1394 }
1395 }
1396
1397 /*
1398 * Otherwise it's a real keyword.
1399 */
1400 single = compile_item(c, unlang_ctx, ci);
1401 if (!single) {
1402 cf_log_err(ci, "Failed to parse \"%s\" subsection", cf_section_name1(subcs));
1403 goto fail;
1404 }
1405
1406 goto add_child;
1407
1408 } else if (cf_item_is_pair(ci)) {
1409 CONF_PAIR *cp = cf_item_to_pair(ci);
1410
1411 /*
1412 * Variable definition.
1413 */
1414 if (cf_pair_operator(cp) == T_OP_CMP_TRUE) {
1415 if (compile_variable(c, unlang_ctx, cp, &t_rules) < 0) goto fail;
1416
1417 single = UNLANG_IGNORE;
1418 goto add_child;
1419 }
1420
1421 if (!cf_pair_value(cp)) {
1422 single = compile_item(c, unlang_ctx, ci);
1423 if (!single) {
1424 cf_log_err(ci, "Invalid keyword \"%s\".", cf_pair_attr(cp));
1425 goto fail;
1426 }
1427
1428 goto add_child;
1429 }
1430
1431 /*
1432 * What remains MUST be an edit pair. At this point, the state of the compiler
1433 * tells us what it is, and we don't really care if there's a leading '&'.
1434 */
1435 single = compile_edit_pair(c, unlang_ctx, cp);
1436 if (!single) goto fail;
1437
1438 goto add_child;
1439 } else {
1440 cf_log_err(ci, "Asked to compile unknown conf type");
1441 goto fail;
1442 }
1443
1444 add_child:
1445 if (single == UNLANG_IGNORE) continue;
1446
1447 /*
1448 * Do optimizations for "if" and "elsif"
1449 * conditions.
1450 */
1451 switch (single->type) {
1452 case UNLANG_TYPE_ELSIF:
1453 case UNLANG_TYPE_IF:
1454 was_if = true;
1455
1456 {
1457 unlang_group_t *f;
1458 unlang_cond_t *gext;
1459
1460 /*
1461 * Skip else, and/or omit things which will never be run.
1462 */
1463 f = unlang_generic_to_group(single);
1464 gext = unlang_group_to_cond(f);
1465
1466 if (gext->is_truthy) {
1467 if (gext->value) {
1468 skip_else = single->debug_name;
1469 } else {
1470 /*
1471 * If this came from compile_single, then it will already
1472 * have a number and be in the tree.
1473 */
1474 if (single->number) fr_rb_remove(NULL, unlang_instruction_tree, single);
1475
1476 /*
1477 * The condition never
1478 * matches, so we can
1479 * avoid putting it into
1480 * the unlang tree.
1481 */
1482 talloc_free(single);
1483 continue;
1484 }
1485 }
1486 }
1487 break;
1488
1489 default:
1490 was_if = false;
1491 skip_else = NULL;
1492 break;
1493 }
1494
1495 /*
1496 * unlang_group_t is grown by adding a unlang_t to the end
1497 */
1498 fr_assert(g == talloc_parent(single));
1500 unlang_list_insert_tail(&g->children, single);
1501 single->list = &g->children;
1502
1503 /*
1504 * If it's not possible to execute statement
1505 * after the current one, then just stop
1506 * processing the children.
1507 */
1508 if (g->self.closed) {
1509 cf_log_warn(ci, "Skipping remaining instructions due to '%s'",
1510 single->name);
1511 break;
1512 }
1513 }
1514
1515 return c;
1516}
1517
1518
1519/*
1520 * Generic "compile a section with more unlang inside of it".
1521 */
1523{
1524 unlang_group_t *g;
1525 unlang_t *c;
1526 char const *name1, *name2;
1527
1528 fr_assert(unlang_ctx->rules != NULL);
1529 fr_assert(unlang_ctx->rules->attr.list_def);
1530
1531 /*
1532 * We always create a group, even if the section is empty.
1533 */
1535 if (!g) return NULL;
1536
1538
1539 /*
1540 * Remember the name for printing, etc.
1541 */
1542 name1 = cf_section_name1(cs);
1543 name2 = cf_section_name2(cs);
1544 c->name = name1;
1545
1546 /*
1547 * Make sure to tell the user that we're running a
1548 * policy, and not anything else.
1549 */
1550 if (type == UNLANG_TYPE_POLICY) {
1551 MEM(c->debug_name = talloc_typed_asprintf(c, "policy %s", name1));
1552
1553 } else if (!name2) {
1554 c->debug_name = c->name;
1555
1556 } else {
1557 MEM(c->debug_name = talloc_typed_asprintf(c, "%s %s", name1, name2));
1558 }
1559
1561}
1562
1563
1565{
1566 CONF_PAIR *cp = cf_item_to_pair(ci);
1567 unlang_t *c;
1568 unlang_tmpl_t *ut;
1569 fr_slen_t slen;
1570 char const *p = cf_pair_attr(cp);
1571 tmpl_t *vpt;
1572
1573 MEM(ut = talloc_zero(parent, unlang_tmpl_t));
1574 c = unlang_tmpl_to_generic(ut);
1576 c->name = p;
1577 c->debug_name = c->name;
1578 c->ci = CF_TO_ITEM(cp);
1579
1580 RULES_VERIFY(unlang_ctx->rules);
1581 slen = tmpl_afrom_substr(ut, &vpt,
1582 &FR_SBUFF_IN(p, talloc_strlen(p)),
1584 NULL,
1585 unlang_ctx->rules);
1586 if (!vpt) {
1587 cf_canonicalize_error(cp, slen, "Failed parsing expansion", p);
1588 talloc_free(ut);
1589 return NULL;
1590 }
1591 ut->tmpl = vpt; /* const issues */
1592
1593 return c;
1594}
1595
1596/*
1597 * redundant, load-balance and parallel have limits on what can
1598 * go in them.
1599 */
1601{
1602 cf_item_foreach(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 /*
1631 * Allow a module as a child.
1632 */
1633 if (cf_item_is_pair(ci)) {
1634 CONF_PAIR *cp = cf_item_to_pair(ci);
1635
1636 if (cf_pair_operator(cp) == T_OP_CMP_TRUE) continue;
1637
1638 if (cf_pair_value(cp) != NULL) {
1639 cf_log_err(cp, "Unknown keyword '%s', or invalid location", cf_pair_attr(cp));
1640 return false;
1641 }
1642 }
1643 }
1644
1645 return true;
1646}
1647
1648
1650 CONF_SECTION *subcs,
1651 bool policy)
1652{
1653 unlang_compile_ctx_t unlang_ctx2;
1654 unlang_t *c;
1655
1657
1658 /*
1659 * module.c takes care of ensuring that this is:
1660 *
1661 * group foo { ...
1662 * load-balance foo { ...
1663 * redundant foo { ...
1664 * redundant-load-balance foo { ...
1665 *
1666 * We can just recurse to compile the section as
1667 * if it was found here.
1668 */
1669 if (cf_section_name2(subcs)) {
1670 if (policy) {
1671 cf_log_err(subcs, "Unexpected second name in policy");
1672 return NULL;
1673 }
1674
1675 c = compile_item(parent, &unlang_ctx2, cf_section_to_item(subcs));
1676
1677 } else {
1678 /*
1679 * We have:
1680 *
1681 * foo { ...
1682 *
1683 * So we compile it like it was:
1684 *
1685 * group foo { ...
1686 */
1687 c = unlang_compile_section(parent, &unlang_ctx2, subcs,
1689 }
1690 if (!c) return NULL;
1691
1692 /*
1693 * Only a virtual module can get here empty, e.g. "group foo { }".
1694 * An empty policy compiles to an empty group, and runs as a no-op.
1695 *
1696 * Report the error at the call, and point to the definition.
1697 */
1698 if (c == UNLANG_IGNORE) {
1699 fr_assert(!policy);
1700 cf_log_err(ci, "Cannot call virtual module '%s', as it is empty", cf_section_name2(subcs));
1701 cf_log_err(subcs, "Empty section is defined here");
1702 return NULL;
1703 }
1704
1705 /*
1706 * Return the compiled thing if we can.
1707 */
1708 if (!cf_item_is_section(ci)) return c;
1709
1710 /*
1711 * Else we have a reference to a policy, and that reference
1712 * over-rides the return codes for the policy!
1713 */
1714 if (!unlang_compile_actions(&c->actions, cf_item_to_section(ci), false)) {
1715 talloc_free(c);
1716 return NULL;
1717 }
1718
1719 return c;
1720}
1721
1722/** Load a named module from the virtual module list, or from the "policy" subsection.
1723 *
1724 * If it's "foo.method", look for "foo", and return "method" as the method
1725 * we wish to use, instead of the input component.
1726 *
1727 * @param[in] ci Configuration item to check
1728 * @param[in] real_name Complete name string e.g. foo.authorize.
1729 * @param[in] virtual_name Virtual module name e.g. foo.
1730 * @param[in] method_name Method override (may be NULL) or the method
1731 * name e.g. authorize.
1732 * @param[in] unlang_ctx Unlang context this call is being compiled in.
1733 * @param[out] policy whether or not this thing was a policy
1734 * @return the CONF_SECTION specifying the virtual module.
1735 */
1736static CONF_SECTION *virtual_module_find_cs(CONF_ITEM *ci, UNUSED char const *real_name, char const *virtual_name,
1737 char const *method_name, unlang_compile_ctx_t *unlang_ctx, bool *policy)
1738{
1739 CONF_SECTION *cs, *subcs, *conf_root;
1740 CONF_ITEM *loop;
1741 char buffer[256];
1742
1743 *policy = false;
1744 conf_root = cf_root(ci);
1745
1746 /*
1747 * Look for "foo" as a virtual server. If we find it,
1748 * AND there's no method name, we've found the right
1749 * thing.
1750 *
1751 * Found "foo". Load it as "foo", or "foo.method".
1752 *
1753 * Return it to the caller, with the updated method.
1754 */
1755 subcs = module_rlm_virtual_by_name(virtual_name);
1756 if (subcs) goto check_for_loop;
1757
1758 /*
1759 * Look for it in "policy".
1760 *
1761 * If there's no policy section, we can't do anything else.
1762 */
1763 cs = cf_section_find(conf_root, "policy", NULL);
1764 if (!cs) return NULL;
1765
1766 *policy = true;
1767
1768 /*
1769 * "foo.authorize" means "load policy 'foo.authorize' or 'foo'"
1770 * as method "authorize".
1771 *
1772 * And bail out if there's no policy "foo.authorize" or "foo".
1773 */
1774 if (method_name) {
1775 snprintf(buffer, sizeof(buffer), "%s.%s", virtual_name, method_name);
1776 subcs = cf_section_find(cs, buffer, NULL);
1777 if (!subcs) subcs = cf_section_find(cs, virtual_name, NULL);
1778 if (!subcs) return NULL;
1779
1780 goto check_for_loop;
1781 }
1782
1783 /*
1784 * "foo" means "look for foo.name1.name2" first, to allow
1785 * method overrides. If that's not found, look for
1786 * "foo.name1" and if that's not found just look for
1787 * a policy "foo".
1788 */
1789 if (unlang_ctx->section_name2) {
1790 snprintf(buffer, sizeof(buffer), "%s.%s.%s", virtual_name, unlang_ctx->section_name1, unlang_ctx->section_name2);
1791 subcs = cf_section_find(cs, buffer, NULL);
1792 } else {
1793 subcs = NULL;
1794 }
1795
1796 if (!subcs) {
1797 snprintf(buffer, sizeof(buffer), "%s.%s", virtual_name, unlang_ctx->section_name1);
1798 subcs = cf_section_find(cs, buffer, NULL);
1799 }
1800
1801 if (!subcs) subcs = cf_section_find(cs, virtual_name, NULL);
1802 if (!subcs) return NULL;
1803
1804check_for_loop:
1805 /*
1806 * Check that we're not creating a loop. We may
1807 * be compiling an "sql" module reference inside
1808 * of an "sql" policy. If so, we allow the
1809 * second "sql" to refer to the module.
1810 */
1811 for (loop = cf_parent(ci);
1812 loop && subcs;
1813 loop = cf_parent(loop)) {
1814 if (loop == cf_section_to_item(subcs)) {
1815 return NULL;
1816 }
1817 }
1818
1819 return subcs;
1820}
1821
1823{
1824 unlang_t *c;
1825 unlang_module_t *m;
1826 fr_slen_t slen;
1827
1828 MEM(m = talloc_zero(parent, unlang_module_t));
1829 slen = module_rlm_by_name_and_method(m, &m->mmc,
1830 unlang_ctx->vs,
1831 &(section_name_t){ .name1 = unlang_ctx->section_name1, .name2 = unlang_ctx->section_name2 },
1833 unlang_ctx->rules);
1834 if (slen < 0) {
1835 cf_log_perr(ci, "Failed compiling module call");
1836 talloc_free(m);
1837 return NULL;
1838 }
1839
1840 /*
1841 * We parsed a string, but we were told to ignore it. Don't do anything.
1842 */
1843 if (!m->mmc.rlm) return UNLANG_IGNORE;
1844
1845 if (m->mmc.rlm->common.dict &&
1846 !fr_dict_compatible(*m->mmc.rlm->common.dict, unlang_ctx->rules->attr.dict_def)) {
1847 cf_log_err(ci, "The '%s' module can only be used within a '%s' namespace.",
1848 m->mmc.rlm->common.name, fr_dict_root(*m->mmc.rlm->common.dict)->name);
1849 cf_log_err(ci, "Please use the 'subrequest' keyword to change namespaces");
1850 cf_log_err(ci, DOC_KEYWORD_REF(subrequest));
1851 talloc_free(m);
1852 return NULL;
1853 }
1854
1857 c->name = talloc_strdup(c, name);
1858 c->debug_name = c->name;
1859 c->ci = ci;
1860
1861 /*
1862 * Set the default actions for this module.
1863 */
1864 c->actions = m->mmc.mi->actions;
1865
1866 /*
1867 * Parse the method environment for this module / method
1868 */
1869 if (m->mmc.mmb.method_env) {
1871
1872 fr_assert_msg(method_env->inst_size, "Method environment for module %s, method %s %s declared, "
1873 "but no inst_size set",
1874 m->mmc.mi->name, unlang_ctx->section_name1, unlang_ctx->section_name2);
1875
1876 if (!unlang_ctx->rules) {
1877 cf_log_err(ci, "Failed compiling %s - no rules", m->mmc.mi->name);
1878 goto error;
1879 }
1881 unlang_ctx->rules, m->mmc.mi->conf,
1882 &(call_env_ctx_t){
1883 .type = CALL_ENV_CTX_TYPE_MODULE,
1884 .mi = m->mmc.mi,
1885 .asked = &m->mmc.asked
1886 });
1887 if (!m->call_env) {
1888 error:
1889 talloc_free(m);
1890 return NULL;
1891 }
1892 }
1893
1894 /*
1895 * If a module reference is a section, then the section
1896 * should contain action over-rides. We add those here.
1897 */
1898 if (cf_item_is_section(ci) &&
1900 (m->mmc.mi->exported->flags & MODULE_TYPE_RETRY) != 0)) goto error;
1901
1902 return c;
1903}
1904
1905extern int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src);
1906
1907static unlang_op_t *name_to_op(char const *name)
1908{
1909 unlang_op_t *op;
1910
1911 fr_hash_table_find((void **)&op, unlang_op_table, &(unlang_op_t) { .name = name });
1912
1913 return op;
1914}
1915
1917 fr_dict_attr_t const *ref)
1918{
1919 fr_dict_attr_t const *da;
1920 fr_slen_t len;
1921 unlang_op_t const *op;
1922
1923 fr_dict_attr_flags_t flags = {
1924 .internal = true,
1925 .local = true,
1926 };
1927
1928 /*
1929 * No overlap with list names.
1930 */
1932 fail_list:
1933 cf_log_err(ci, "Local variable '%s' cannot be a list reference.", name);
1934 return -1;
1935 }
1936
1937 len = strlen(name);
1938 if (tmpl_attr_list_from_substr(&da, &FR_SBUFF_IN(name, len)) == len) goto fail_list;
1939
1940 /*
1941 * No keyword section names.
1942 */
1943 op = name_to_op(name);
1944 if (op) {
1945 cf_log_err(ci, "Local variable '%s' cannot be an unlang keyword.", name);
1946 return -1;
1947 }
1948
1949 /*
1950 * No protocol names.
1951 */
1952 if (fr_dict_by_protocol_name(name) != NULL) {
1953 cf_log_err(ci, "Local variable '%s' cannot be an existing protocol name.", name);
1954 return -1;
1955 }
1956
1957 /*
1958 * No overlap with attributes in the current dictionary. The lookup in var->root will also check
1959 * the current dictionary, so the check here is really only for better error messages.
1960 */
1961 if (t_rules && t_rules->parent && t_rules->parent->attr.dict_def) {
1962 da = fr_dict_attr_by_name(NULL, fr_dict_root(t_rules->parent->attr.dict_def), name);
1963 if (da) {
1964 cf_log_err(ci, "Local variable '%s' duplicates a dictionary attribute.", name);
1965 return -1;
1966 }
1967 }
1968
1969 /*
1970 * No data types.
1971 */
1973 cf_log_err(ci, "Invalid variable name '%s'.", name);
1974 return -1;
1975 }
1976
1977 /*
1978 * No dups of local variables.
1979 */
1980 da = fr_dict_attr_by_name(NULL, var->root, name);
1981 if (da) {
1982 cf_log_err(ci, "Duplicate variable name '%s'.", name);
1983 return -1;
1984 }
1985
1986 if (fr_dict_attr_add(var->dict, var->root, name, var->max_attr, type, &flags) < 0) {
1987 fail:
1988 cf_log_err(ci, "Failed adding variable '%s' - %s", name, fr_strerror());
1989 return -1;
1990 }
1991 da = fr_dict_attr_by_name(NULL, var->root, name);
1992 fr_assert(da != NULL);
1993
1994 /*
1995 * Copy the children over.
1996 */
1997 var->max_attr++;
1999 fr_fatal_assert(ref != NULL);
2000
2001 if (fr_dict_attr_acopy_local(da, ref) < 0) goto fail;
2002 }
2003
2004
2005 return 0;
2006}
2007
2008/*
2009 * Compile one unlang instruction
2010 */
2012{
2013 char const *name, *p;
2014 CONF_SECTION *cs, *subcs, *modules;
2015 unlang_compile_ctx_t unlang_ctx2;
2016 bool policy;
2017 unlang_t *c;
2018 unlang_op_t const *op;
2019
2020 if (cf_item_is_section(ci)) {
2021 cs = cf_item_to_section(ci);
2022 name = cf_section_name1(cs);
2023 op = name_to_op(name);
2024
2025 if (op) {
2026 /*
2027 * Forbid pair keywords as section names,
2028 * e.g. "break { ... }"
2029 */
2030 if ((op->flag & UNLANG_OP_FLAG_SINGLE_WORD) != 0) {
2031 cf_log_err(ci, "Syntax error after keyword '%s' - unexpected '{'", name);
2032 return NULL;
2033 }
2034
2035 c = op->compile(parent, unlang_ctx, ci);
2036 goto allocate_number;
2037 }
2038
2039 /* else it's something like sql { fail = 1 ...} */
2040 goto check_for_module;
2041
2042 } else if (cf_item_is_pair(ci)) {
2043
2044 /*
2045 * Else it's a module reference such as "sql", OR
2046 * one of the few bare keywords that we allow.
2047 */
2048 CONF_PAIR *cp = cf_item_to_pair(ci);
2049
2050 /*
2051 * We cannot have assignments or actions here.
2052 */
2053 if (cf_pair_value(cp) != NULL) {
2054 cf_log_err(ci, "Invalid assignment");
2055 return NULL;
2056 }
2057
2058 name = cf_pair_attr(cp);
2059 op = name_to_op(name);
2060
2061 if (op) {
2062 /*
2063 * Forbid section keywords as pair names, e.g. "switch = foo"
2064 */
2065 if ((op->flag & UNLANG_OP_FLAG_SINGLE_WORD) == 0) {
2066 cf_log_err(ci, "Syntax error after keyword '%s' - missing '{'", name);
2067 return NULL;
2068 }
2069
2070 c = op->compile(parent, unlang_ctx, ci);
2071 goto allocate_number;
2072 }
2073
2074 /*
2075 * In-place expansions.
2076 *
2077 * @todo - allow only function calls, not %{...}
2078 *
2079 * @todo don't create a tmpl. Instead, create an
2080 * xlat. This functionality is needed for the in-place language functions via
2081 *
2082 * language {{{
2083 * ...
2084 * }}}
2085 */
2086 if (name[0] == '%') {
2088 goto allocate_number;
2089 }
2090
2091 goto check_for_module;
2092
2093 } else {
2094 cf_log_err(ci, "Asked to compile unknown configuration item");
2095 return NULL; /* who knows what it is... */
2096 }
2097
2098check_for_module:
2099 /*
2100 * We now have a name. It can be one of two forms. A
2101 * bare module name, or a section named for the module,
2102 * with over-rides for the return codes.
2103 *
2104 * The name can refer to a real module, in the "modules"
2105 * section. In that case, the name will be either the
2106 * first or second name of the sub-section of "modules".
2107 *
2108 * Or, the name can refer to a policy, in the "policy"
2109 * section. In that case, the name will be first of the
2110 * sub-section of "policy".
2111 *
2112 * Or, the name can refer to a "module.method", in which
2113 * case we're calling a different method than normal for
2114 * this section.
2115 *
2116 * Or, the name can refer to a virtual module, in the
2117 * "modules" section. In that case, the name will be
2118 * name2 of the CONF_SECTION.
2119 *
2120 * We try these in sequence, from the bottom up. This is
2121 * so that virtual modules and things in "policy" can
2122 * over-ride calls to real modules.
2123 */
2124
2125
2126 /*
2127 * Try:
2128 *
2129 * policy { ... name { .. } .. }
2130 * policy { ... name.method { .. } .. }
2131 */
2132 p = strrchr(name, '.');
2133 if (!p) {
2134 subcs = virtual_module_find_cs(ci, name, name, NULL, unlang_ctx, &policy);
2135 } else {
2136 char buffer[256];
2137
2138 if ((size_t) (p - name) >= sizeof(buffer)) {
2139 cf_log_err(ci, "Module name '%s' is too long", name);
2140 return NULL;
2141 }
2142
2143 strlcpy(buffer, name, sizeof(buffer));
2144 buffer[p - name] = '\0';
2145
2146 subcs = virtual_module_find_cs(ci, name,
2147 buffer, buffer + (p - name) + 1, unlang_ctx, &policy);
2148 }
2149
2150 /*
2151 * We've found the thing which defines this "function".
2152 * It MUST be a sub-section.
2153 *
2154 * i.e. it refers to a a subsection in "policy".
2155 */
2156 if (subcs) {
2157 c = compile_function(parent, unlang_ctx, ci, subcs, policy);
2158 goto allocate_number;
2159 }
2160
2161 /*
2162 * Not a function. It must be a real module.
2163 */
2164 modules = cf_section_find(cf_root(ci), "modules", NULL);
2165 if (!modules) {
2166 cf_log_err(ci, "Failed compiling \"%s\" as a module or policy as no modules are enabled", name);
2167 cf_log_err(ci, "Please verify that modules { ... } section is present in the server configuration");
2168 return NULL;
2169 }
2170
2171 /*
2172 * Set the child compilation context BEFORE parsing the
2173 * module name and method. The lookup function will take
2174 * care of returning the appropriate component, name1,
2175 * name2, etc.
2176 */
2178 c = compile_module(parent, &unlang_ctx2, ci, name);
2179
2180allocate_number:
2181 if (!c) return NULL;
2182 if (c == UNLANG_IGNORE) return UNLANG_IGNORE;
2183
2184 /*
2185 * Some compilation paths already go through this path
2186 * and will have assigned a number.
2187 */
2188 if (c->number) return c;
2189
2190 c->number = unlang_number++;
2192
2194 cf_log_err(ci, "Instruction \"%s\" number %u has conflict with previous one.",
2195 c->debug_name, c->number);
2196 talloc_free(c);
2197 return NULL;
2198 }
2199
2200 return c;
2201}
2202
2203/** Compile an unlang section for a virtual server
2204 *
2205 * @param[in] vs Virtual server to compile section for.
2206 * @param[in] cs containing the unlang calls to compile.
2207 * @param[in] actions Actions to use for the unlang section.
2208 * @param[in] rules Rules to use for the unlang section.
2209 * @param[out] instruction Pointer to store the compiled unlang section.
2210 * @return
2211 * - 0 on success.
2212 * - -1 on error.
2213 */
2215 CONF_SECTION *cs, unlang_mod_actions_t const *actions, tmpl_rules_t const *rules, void **instruction)
2216{
2217 unlang_t *c;
2218 char const *name1, *name2;
2219 CONF_DATA const *cd;
2220
2221 /*
2222 * Don't compile it twice, and don't print out debug
2223 * messages twice.
2224 */
2225 cd = cf_data_find(cs, unlang_group_t, NULL);
2226 if (cd) {
2227 if (instruction) *instruction = cf_data_value(cd);
2228 return 1;
2229 }
2230
2231 /*
2232 * Ensure that all compile functions get valid rules.
2233 */
2234 if (!rules) {
2235 cf_log_err(cs, "Failed compiling section - no namespace rules passed");
2236 return -1;
2237 }
2238
2239 name1 = cf_section_name1(cs);
2240 name2 = cf_section_name2(cs);
2241
2242 if (!name2) name2 = "";
2243
2244 cf_log_debug(cs, "Compiling policies in - %s %s {...}", name1, name2);
2245
2246 c = unlang_compile_section(NULL,
2248 .vs = vs,
2249 .section_name1 = cf_section_name1(cs),
2250 .section_name2 = cf_section_name2(cs),
2251 .actions = *actions,
2252 .rules = rules
2253 },
2254 cs, UNLANG_TYPE_GROUP);
2255 if (!c) return -1;
2256
2258
2259 if (DEBUG_ENABLED4) unlang_dump(c, 2);
2260
2261 /*
2262 * Associate the unlang_t with the configuration section.
2263 * It's already parented from "cs", so don't free it.
2264 */
2265 cf_data_add(cs, c, NULL, false);
2267 c->add_filename = true;
2268 if (instruction) *instruction = c;
2269
2270 return 0;
2271}
2272
2273/** Compile an unlang section for a virtual module.
2274 *
2275 * This is just a wrapper around unlang_compile_section(), as the unlang_compile_ctx isn't public.
2276 *
2277 * @param[in] cs containing the unlang calls to compile.
2278 * @param[in] dict dictionary to use
2279 * @return
2280 * - 0 on success.
2281 * - -1 on error.
2282 */
2284{
2285 unlang_t *c;
2286 char const *name;
2287 unlang_op_t const *op;
2288 CONF_DATA const *cd;
2290
2291 /*
2292 * Get the name, and then the opcode type.
2293 */
2294 name = cf_section_name1(cs);
2295 op = name_to_op(name);
2296 if (!op) {
2297 cf_log_err(cs, "Invalid keyword in virtual module");
2298 return -1;
2299 }
2300
2301 /*
2302 * There's no virtual server, just this dictionary.
2303 *
2304 * @todo - find a way to change the list_def. We need to do this based on the caller. But when
2305 * we're compiling the virtual module, we don't know what context the caller will be using.
2306 */
2308 .vs = NULL,
2309 .section_name1 = NULL,
2310 .section_name2 = NULL,
2311 .actions = mod_actions_authorize,
2312 .rules = &(tmpl_rules_t) {
2313 .attr = {
2314 .dict_def = dict,
2315 .list_def = request_attr_request,
2316 },
2317 .literals_safe_for = FR_VALUE_BOX_SAFE_FOR_ANY,
2318 },
2319 };
2320
2321 /*
2322 * Compile it with the appropriate data type.
2323 */
2324 c = unlang_compile_section(NULL, &unlang_ctx, cs, op->type);
2325 if (!c) return -1;
2326
2327 if (c == UNLANG_IGNORE) {
2328 cf_log_err(cs, "Virtual modules cannot be empty");
2329 return -1;
2330 }
2331
2332 /*
2333 * Don't use the talloc type, which might be unlang_load_balance_t.
2334 */
2335 cd = cf_data_add_static(cs, c, unlang_group_t, NULL);
2336 if (!cd) {
2337 cf_log_perr(cs, "Failed caching compiled virtual module");
2338 return -1;
2339 }
2340
2341 fr_assert(cf_data_find(cs, unlang_group_t, NULL) == cd);
2342 fr_assert(c == cf_data_value(cd));
2343
2344 return 0;
2345}
2346
2347/** Check if name is an unlang keyword
2348 *
2349 * @param[in] name to check.
2350 * @return
2351 * - true if it is a keyword.
2352 * - false if it's not a keyword.
2353 */
2355{
2356 if (!name || !*name) return false;
2357
2358 return (name_to_op(name) != NULL);
2359}
2360
2361/*
2362 * These are really unlang_foo_t, but that's fine...
2363 */
2364static fr_cmp_ret_t instruction_cmp(void const *one, void const *two)
2365{
2366 unlang_t const *a = one;
2367 unlang_t const *b = two;
2368
2369 return CMP(a->number, b->number);
2370}
2371
2372
2373void unlang_compile_init(TALLOC_CTX *ctx)
2374{
2376}
static int const char char buffer[256]
Definition acutest.h:641
#define RCSID(id)
Definition build.h:603
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:245
#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:130
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
#define NUM_ELEMENTS(_t)
Definition build.h:437
fr_cmp_ret_t
Result of an ordering comparison.
Definition build.h:113
@ CMP_EQ
a == b
Definition build.h:116
static int invalid_type(fr_type_t type)
Definition calc.c:699
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:792
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:4386
Internal data that is associated with a configuration section.
Definition cf_priv.h:195
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:619
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
Definition cf_util.c:1787
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1405
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1922
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:725
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1391
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:1247
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:671
bool cf_item_is_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
Definition cf_util.c:633
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1772
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:605
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:651
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1450
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1758
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:709
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1742
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
#define cf_data_add(_cf, _data, _name, _free)
Definition cf_util.h:306
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:295
#define cf_log_debug_prefix(_cf, _fmt,...)
Definition cf_util.h:357
#define cf_data_remove(_cf, _type, _name)
Remove an item from a parent by type and name.
Definition cf_util.h:318
#define cf_root(_cf)
Definition cf_util.h:112
#define cf_section_free_children(_x)
Definition cf_util.h:251
#define cf_parent(_cf)
Definition cf_util.h:115
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:418
#define cf_data_add_static(_cf, _data, _type, _name)
Definition cf_util.h:309
#define cf_item_next(_parent, _curr)
Definition cf_util.h:91
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:347
#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_item_foreach(_parent, _iter)
Iterate over every child item of a CONF_SECTION (or any CONF_ITEM that has children).
Definition cf_util.h:106
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:341
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:343
#define cf_item_mark_parsed(_cf)
Definition cf_util.h:188
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:1289
static unlang_t * compile_module(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci, char const *name)
Definition compile.c:1822
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:765
bool unlang_compile_is_keyword(const char *name)
Check if name is an unlang keyword.
Definition compile.c:2354
void unlang_compile_init(TALLOC_CTX *ctx)
Definition compile.c:2373
static bool compile_action_pair(unlang_mod_actions_t *actions, CONF_PAIR *cp)
Definition compile.c:940
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1522
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:610
bool unlang_compile_limit_subsection(CONF_SECTION *cs, char const *name)
Definition compile.c:1600
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:851
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:1086
#define UPDATE_CTX2
Definition compile.c:82
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:1001
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:1736
static unlang_t * compile_item(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci)
Definition compile.c:2011
static unlang_op_t * name_to_op(char const *name)
Definition compile.c:1907
uint64_t unlang_number
Definition interpret.c:55
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:1564
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
static fr_cmp_ret_t instruction_cmp(void const *one, void const *two)
Definition compile.c:2364
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:1197
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:1649
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:1240
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:2214
int unlang_compile_virtual_module(CONF_SECTION *cs, fr_dict_t const *dict)
Compile an unlang section for a virtual module.
Definition compile.c:2283
#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:1916
static bool compile_action_subsection(unlang_t *c, CONF_SECTION *cs, CONF_SECTION *subcs)
Definition compile.c:1237
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:248
#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:205
#define MEM(x)
Definition debug.h:38
#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:1178
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:3600
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:2948
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2717
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:2906
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:2020
fr_dict_t * fr_dict_protocol_alloc(fr_dict_t const *parent)
Allocate a new local dictionary.
Definition dict_util.c:4396
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
int fr_hash_table_find(void **found, fr_hash_table_t *ht, void const *data)
Find data in a hash table.
Definition hash.c:458
talloc_free(hp)
#define DEBUG_ENABLED4
True if global debug level 1-4 messages are enabled.
Definition log.h:265
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:1199
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:1384
ssize_t map_print(fr_sbuff_t *out, map_t const *map)
Print a map to a string.
Definition map.c:2349
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
fr_hash_table_t * unlang_op_table
Definition base.c:45
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.
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_mod_actions_t const mod_actions_authorize
Definition mod_action.c:45
Unlang module actions.
#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
unlang_mod_action_t
Definition mod_action.h:37
@ 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
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:550
CONF_SECTION * module_rlm_virtual_by_name(char const *asked_name)
Definition module_rlm.c:796
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
int fr_rb_remove(void **removed, fr_rb_tree_t *tree, void const *data)
Remove an entry from the tree, without freeing the data.
Definition rb.c:718
int fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:637
#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_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
@ 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
fr_dict_attr_t const * request_attr_request
Definition request.c:43
static const call_env_method_t method_env
Definition rlm_detail.c:486
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:361
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:237
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:355
unlang_mod_actions_t actions
default actions and retries.
Definition module.h:329
fr_dict_t const ** dict
required dictionary for this module.
Definition module.h:208
call_env_method_t const * method_env
Method specific call_env.
Definition module.h:179
module_t * exported
Public module structure.
Definition module.h:302
@ MODULE_TYPE_RETRY
can handle retries
Definition module.h:52
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
Definition tmpl.h:908
#define TMPL_VERIFY(_vpt)
Definition tmpl.h:984
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:661
#define tmpl_is_xlat(vpt)
Definition tmpl.h:217
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:215
#define NUM_ALL
Definition tmpl.h:418
tmpl_rules_t const * parent
for parent / child relationships
Definition tmpl.h:344
static bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar)
Return true if the tmpl_attr is one of the list types.
Definition tmpl.h:706
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:840
#define NUM_COUNT
Definition tmpl.h:419
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:943
@ REQUEST_UNKNOWN
Unknown request.
Definition tmpl.h:104
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:1298
#define NUM_UNSPEC
Definition tmpl.h:417
static size_t tmpl_attr_num_elements(tmpl_t const *vpt)
The number of attribute references contained within a tmpl.
Definition tmpl.h:919
#define tmpl_attr(_tmpl)
Definition tmpl.h:681
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:224
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:346
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition tmpl.h:149
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition tmpl.h:153
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition tmpl.h:157
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition tmpl.h:145
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition tmpl.h:186
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
Definition tmpl.h:200
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:824
fr_slen_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.
struct tmpl_rules_s tmpl_rules_t
Definition tmpl.h:240
#define tmpl_is_regex_xlat_unresolved(vpt)
Definition tmpl.h:228
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:391
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:343
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:310
CONF_ITEM * ci
for migration support and various warnings
Definition tmpl.h:308
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:280
An element in a list of nested attribute references.
Definition tmpl.h:457
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
Definition tmpl.h:461
#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:621
#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:426
#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:234
const bool fr_list_assignment_op[T_TOKEN_LAST]
Definition token.c:251
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:264
const bool fr_binary_op[T_TOKEN_LAST]
Definition token.c:282
@ 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
enum fr_token fr_token_t
#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...
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
unlang_type_t type
enum value for the keyword
#define debug_braces(_type)
bool add_filename
add the filename when printing in debug mode
char const * name
Name of the keyword.
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
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_type_t type
The specialisation of this node.
@ UNLANG_OP_FLAG_SINGLE_WORD
the operation is parsed and compiled as a single word
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:864
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 fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:178