The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: a23e456a1469822293682f090008e31765935e13 $
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: a23e456a1469822293682f090008e31765935e13 $")
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/main_config.h>
33#include <freeradius-devel/server/map_proc.h>
34#include <freeradius-devel/server/modpriv.h>
35#include <freeradius-devel/server/module_rlm.h>
36
37
38#include <freeradius-devel/unlang/xlat_priv.h>
39
40#include "call_priv.h"
41#include "caller_priv.h"
42#include "condition_priv.h"
43#include "foreach_priv.h"
44#include "load_balance_priv.h"
45#include "map_priv.h"
46#include "module_priv.h"
47#include "parallel_priv.h"
48#include "subrequest_priv.h"
49#include "switch_priv.h"
50#include "edit_priv.h"
51#include "timeout_priv.h"
52#include "limit_priv.h"
53#include "transaction_priv.h"
54#include "try_priv.h"
55#include "mod_action.h"
56
57static unsigned int unlang_number = 1;
58
59/*
60 * For simplicity, this is just array[unlang_number]. Once we
61 * call unlang_thread_instantiate(), the "unlang_number" above MUST
62 * NOT change.
63 */
65
66/*
67 * Until we know how many instructions there are, we can't
68 * allocate an array. So we have to put the instructions into an
69 * RB tree.
70 */
72
73/* Here's where we recognize all of our keywords: first the rcodes, then the
74 * actions */
76 { L("..."), RLM_MODULE_NOT_SET },
77 { L("disallow"), RLM_MODULE_DISALLOW },
78 { L("fail"), RLM_MODULE_FAIL },
79 { L("handled"), RLM_MODULE_HANDLED },
80 { L("invalid"), RLM_MODULE_INVALID },
81 { L("noop"), RLM_MODULE_NOOP },
82 { L("notfound"), RLM_MODULE_NOTFOUND },
83 { L("ok"), RLM_MODULE_OK },
84 { L("reject"), RLM_MODULE_REJECT },
85 { L("timeout"), RLM_MODULE_TIMEOUT },
86 { L("updated"), RLM_MODULE_UPDATED }
87};
89
90#define UPDATE_CTX2 unlang_compile_ctx_copy(&unlang_ctx2, unlang_ctx)
91
92
93static char const unlang_spaces[] = " ";
94
95bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
96{
97 tmpl_t *vpt = *vpt_p;
98
100
101 /*
102 * We may now know the correct dictionary
103 * where we didn't before...
104 */
105 if (!vpt->rules.attr.dict_def) tmpl_set_dict_def(vpt, dict);
106
107 /*
108 * Fixup any other tmpl types
109 */
110 if (tmpl_resolve(vpt, &(tmpl_res_rules_t){ .dict_def = dict, .force_dict_def = (dict != NULL)}) < 0) {
111 cf_log_perr(ci, NULL);
112 return false;
113 }
114
115 return true;
116}
117
118/** Fixup ONE map (recursively)
119 *
120 * This function resolves most things. Most notable it CAN leave the
121 * RHS unresolved, for use in `map` sections.
122 */
124{
125 RULES_VERIFY(rules);
126
127 if (tmpl_is_data_unresolved(map->lhs)) {
128 if (!pass2_fixup_tmpl(map, &map->lhs, map->ci, rules->attr.dict_def)) {
129 return false;
130 }
131 }
132
133 /*
134 * Enforce parent-child relationships in nested maps.
135 */
136 if (parent) {
137 if ((map->op != T_OP_EQ) && (!map->parent || (map->parent->op != T_OP_SUB_EQ))) {
138 cf_log_err(map->ci, "Invalid operator \"%s\" in nested map section. "
139 "Only '=' is allowed",
140 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
141 return false;
142 }
143 }
144
145 if (map->rhs) {
146 if (tmpl_is_data_unresolved(map->rhs)) {
148
149 if (!pass2_fixup_tmpl(map, &map->rhs, map->ci, rules->attr.dict_def)) {
150 return false;
151 }
152 }
153 }
154
155 /*
156 * Sanity check sublists.
157 */
158 if (!map_list_empty(&map->child)) {
159 fr_dict_attr_t const *da;
160 map_t *child;
161
162 if (!tmpl_is_attr(map->lhs)) {
163 cf_log_err(map->ci, "Sublists can only be assigned to a known attribute");
164 return false;
165 }
166
167 da = tmpl_attr_tail_da(map->lhs);
168
169 /*
170 * Resolve all children.
171 */
172 for (child = map_list_next(&map->child, NULL);
173 child != NULL;
174 child = map_list_next(&map->child, child)) {
175 if (!pass2_fixup_map(child, rules, da)) {
176 return false;
177 }
178 }
179 }
180
181 return true;
182}
183
184/*
185 * Do all kinds of fixups and checks for update sections.
186 */
188{
190 map_t *map = NULL;
191
192 RULES_VERIFY(rules);
193
194 while ((map = map_list_next(&gext->map, map))) {
195 /*
196 * Mostly fixup the map, but maybe leave the RHS
197 * unresolved.
198 */
199 if (!pass2_fixup_map(map, rules, NULL)) return false;
200
201 /*
202 * Check allowed operators, and ensure that the
203 * RHS is resolved.
204 */
205 if (cf_item_is_pair(map->ci) && (unlang_fixup_update(map, NULL) < 0)) return false;
206 }
207
208 return true;
209}
210
211/*
212 * Compile the RHS of map sections to xlat_exp_t
213 */
215{
217 map_t *map = NULL;
218
219 RULES_VERIFY(rules);
220
221 /*
222 * Do most fixups on the maps. Leaving the RHS as
223 * unresolved, so that the `map` function can interpret
224 * the RHS as a reference to a json string, SQL column
225 * name, etc.
226 */
227 while ((map = map_list_next(&gext->map, map))) {
228 if (!pass2_fixup_map(map, rules, NULL)) return false;
229 }
230
231 /*
232 * Map sections don't need a VPT.
233 */
234 if (!gext->vpt) return true;
235
236 return pass2_fixup_tmpl(map_list_head(&gext->map)->ci, &gext->vpt,
237 cf_section_to_item(g->cs), rules->attr.dict_def);
238}
239
240static void unlang_dump(unlang_t *c, int depth)
241{
243 map_t *map;
244 char buffer[1024];
245
246 switch (c->type) {
247 case UNLANG_TYPE_NULL:
249 case UNLANG_TYPE_MAX:
250 fr_assert(0);
251 break;
252
254 DEBUG("%.*s%s", depth, unlang_spaces, c->debug_name);
255 break;
256
258 {
260
261 DEBUG("%.*s%s", depth, unlang_spaces, m->mmc.mi->name);
262 }
263 break;
264
265 case UNLANG_TYPE_MAP:
266 {
267 unlang_map_t *gext;
268
269 DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name);
270
272 gext = unlang_group_to_map(g);
273 map = NULL;
274 while ((map = map_list_next(&gext->map, map))) {
275 map_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map);
276 DEBUG("%.*s%s", depth + 1, unlang_spaces, buffer);
277 }
278
279 DEBUG("%.*s}", depth, unlang_spaces);
280 }
281 break;
282
283 case UNLANG_TYPE_EDIT:
284 {
285 unlang_edit_t *edit;
286
287 edit = unlang_generic_to_edit(c);
288 map = NULL;
289 while ((map = map_list_next(&edit->maps, map))) {
290 if (!map->rhs) continue; /* @todo - fixme */
291
292 map_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map);
293 DEBUG("%.*s%s", depth + 1, unlang_spaces, buffer);
294 }
295
296 DEBUG("%.*s}", depth, unlang_spaces);
297 }
298 break;
299
300 case UNLANG_TYPE_CALL:
302 case UNLANG_TYPE_CASE:
305 case UNLANG_TYPE_ELSE:
308 case UNLANG_TYPE_IF:
319 case UNLANG_TYPE_TRY:
320 case UNLANG_TYPE_CATCH: /* @todo - print out things we catch, too */
322
323 DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name);
324 unlang_list_foreach(&g->children, child) {
325 unlang_dump(child, depth + 1);
326 }
327 DEBUG("%.*s}", depth, unlang_spaces);
328 break;
329
334 case UNLANG_TYPE_TMPL:
335 case UNLANG_TYPE_XLAT:
336 DEBUG("%.*s%s", depth, unlang_spaces, c->debug_name);
337 break;
338 }
339}
340
341
342/** Validate and fixup a map that's part of an update section.
343 *
344 * @param map to validate.
345 * @param ctx data to pass to fixup function (currently unused).
346 * @return
347 * - 0 if valid.
348 * - -1 not valid.
349 */
350int unlang_fixup_update(map_t *map, void *ctx)
351{
352 CONF_PAIR *cp = cf_item_to_pair(map->ci);
353
354 if (!ctx) {
355 /*
356 * Fixup RHS attribute references to change NUM_UNSPEC to NUM_ALL.
357 */
358 switch (map->rhs->type) {
359 case TMPL_TYPE_ATTR:
361 break;
362
363 default:
364 break;
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 where you expecting to happen here?
378 */
379 if (tmpl_attr_tail_da_is_leaf(map->lhs) &&
380 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 (!tmpl_is_data_unresolved(map->rhs)) return 0;
404
405 /*
406 * If LHS is an attribute, and RHS is a literal, we can
407 * preparse the information into a TMPL_TYPE_DATA.
408 *
409 * Unless it's a unary operator in which case we
410 * ignore map->rhs.
411 */
412 if (tmpl_is_attr(map->lhs) && tmpl_is_data_unresolved(map->rhs)) {
413 fr_type_t type = tmpl_attr_tail_da(map->lhs)->type;
414
415 /*
416 * @todo - allow passing octets to
417 * FR_TYPE_STRUCT, which can then decode them as
418 * data? That would be rather powerful.
419 */
421
422 /*
423 * It's a literal string, just copy it.
424 * Don't escape anything.
425 */
426 if (tmpl_cast_in_place(map->rhs, type, tmpl_attr_tail_da(map->lhs)) < 0) {
427 cf_log_perr(map->ci, "Cannot convert RHS value (%s) to LHS attribute type (%s)",
430 return -1;
431 }
432
433 return 0;
434 } /* else we can't precompile the data */
435
436 if (!tmpl_is_xlat(map->lhs)) {
437 fr_assert(0);
438 cf_log_err(map->ci, "Cannot determine what update action to perform");
439 return -1;
440 }
441
442 return 0;
443}
444
445
447{
449 unlang_t *c;
450 TALLOC_CTX *ctx;
451 unlang_op_t const *op = &unlang_ops[type];
452
453 ctx = parent;
454 if (!ctx) ctx = cs;
455
456 fr_assert(op->unlang_size > 0);
457
458 /*
459 * All the groups have a common header
460 */
461 g = (unlang_group_t *)_talloc_zero_pooled_object(ctx, op->unlang_size, op->unlang_name,
462 op->pool_headers, op->pool_len);
463 if (!g) return NULL;
464
465 g->cs = cs;
466
468 c->ci = CF_TO_ITEM(cs);
469
471
472 return g;
473}
474
475/** Update a compiled unlang_t with the default actions.
476 *
477 * Don't over-ride any actions which have been set.
478 */
480{
481 int i;
482
483 /*
484 * Note that we do NOT copy over the default retries, as
485 * that would result in every subsection doing it's own
486 * retries. That is not what we want. Instead, we want
487 * the retries to apply only to the _current_ section.
488 */
489
490 /*
491 * Set the default actions if they haven't already been
492 * set.
493 */
494 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
495 if (!c->actions.actions[i]) {
496 c->actions.actions[i] = unlang_ctx->actions.actions[i];
497 }
498 }
499}
500
501#define T(_x) [T_OP_ ## _x] = true
502
503static const bool edit_list_sub_op[T_TOKEN_LAST] = {
504 T(NE),
505 T(GE),
506 T(GT),
507 T(LE),
508 T(LT),
509 T(CMP_EQ),
510};
511
512/** Validate and fixup a map that's part of an edit section.
513 *
514 * @param map to validate.
515 * @param ctx data to pass to fixup function (currently unused).
516 * @return 0 if valid else -1.
517 *
518 * @todo - this is only called for CONF_PAIR maps, not for
519 * CONF_SECTION. So when we parse nested maps, there's no validation
520 * done of the CONF_SECTION. In order to fix this, we need to have
521 * map_afrom_cs() call the validation function for the CONF_SECTION
522 * *before* recursing.
523 */
524static int unlang_fixup_edit(map_t *map, void *ctx)
525{
526 CONF_PAIR *cp = cf_item_to_pair(map->ci);
527 fr_dict_attr_t const *da;
528 fr_dict_attr_t const *parent = NULL;
529 map_t *parent_map = ctx;
530
531 fr_assert(parent_map);
532#ifdef STATIC_ANALYZER
533 if (!parent_map) return -1;
534#endif
535
536 fr_assert(tmpl_is_attr(parent_map->lhs));
537
538 if (parent_map && (parent_map->op == T_OP_SUB_EQ)) {
539 if (!edit_list_sub_op[map->op]) {
540 cf_log_err(cp, "Invalid operator '%s' for right-hand side list. It must be a comparison operator", fr_tokens[map->op]);
541 return -1;
542 }
543
544 } else if (map->op != T_OP_EQ) {
545 cf_log_err(cp, "Invalid operator '%s' for right-hand side list. It must be '='", fr_tokens[map->op]);
546 return -1;
547 }
548
549 /*
550 * map_afrom_cs() will build its tree recursively, and call us for each child map.
551 */
552 if (map->parent && (map->parent != parent_map)) parent_map = map->parent;
553
554 parent = tmpl_attr_tail_da(parent_map->lhs);
555
556 switch (map->lhs->type) {
557 case TMPL_TYPE_ATTR:
558 da = tmpl_attr_tail_da(map->lhs);
559 if (!da->flags.internal && parent && (parent->type != FR_TYPE_GROUP) &&
560 (da->parent != parent)) {
561 /* FIXME - Broken check, doesn't work for key attributes */
562 cf_log_err(cp, "Invalid location for %s - it is not a child of %s",
563 da->name, parent->name);
564 return 0;
565 }
566 break;
567
569 case TMPL_TYPE_XLAT:
570 break;
571
572 default:
573 cf_log_err(map->ci, "Left side of map must be an attribute "
574 "or an xlat (that expands to an attribute), not a %s",
575 tmpl_type_to_str(map->lhs->type));
576 return -1;
577 }
578
579 fr_assert(map->rhs);
580
581 switch (map->rhs->type) {
584 case TMPL_TYPE_XLAT:
585 case TMPL_TYPE_DATA:
586 case TMPL_TYPE_ATTR:
587 case TMPL_TYPE_EXEC:
588 break;
589
590 default:
591 cf_log_err(map->ci, "Right side of map must be an attribute, literal, xlat or exec, got type %s",
592 tmpl_type_to_str(map->rhs->type));
593 return -1;
594 }
595
596 return 0;
597}
598
599/** Compile one edit section.
600 */
602{
603 unlang_edit_t *edit;
605 map_t *map;
606 char const *name;
607 fr_token_t op;
608 ssize_t slen;
609 fr_dict_attr_t const *parent_da;
610 int num;
611
612 tmpl_rules_t t_rules;
613
615 if (name) {
616 cf_log_err(cs, "Unexpected name2 '%s' for editing list %s ", name, cf_section_name1(cs));
617 return NULL;
618 }
619
620 op = cf_section_name2_quote(cs);
621 if ((op == T_INVALID) || !fr_list_assignment_op[op]) {
622 cf_log_err(cs, "Invalid operator '%s' for editing list %s.", fr_tokens[op], cf_section_name1(cs));
623 return NULL;
624 }
625
626 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
627 cf_log_err(cs, "Invalid operator \"%s\".",
628 fr_table_str_by_value(fr_tokens_table, op, "<INVALID>"));
629 return NULL;
630 }
631
632 /*
633 * We allow unknown attributes here.
634 */
635 t_rules = *(unlang_ctx->rules);
636 t_rules.attr.allow_unknown = true;
637 RULES_VERIFY(&t_rules);
638
639 edit = talloc_zero(parent, unlang_edit_t);
640 if (!edit) return NULL;
641
642 c = out = unlang_edit_to_generic(edit);
644 c->name = cf_section_name1(cs);
645 c->debug_name = c->name;
646 c->ci = CF_TO_ITEM(cs);
647
648 map_list_init(&edit->maps);
649
650 /*
651 * Allocate the map and initialize it.
652 */
653 MEM(map = talloc_zero(parent, map_t));
654 map->op = op;
655 map->ci = cf_section_to_item(cs);
656 map_list_init(&map->child);
657
659
660 slen = tmpl_afrom_attr_str(map, NULL, &map->lhs, name, &t_rules);
661 if (slen <= 0) {
662 cf_log_err(cs, "Failed parsing list reference %s - %s", name, fr_strerror());
663 fail:
664 talloc_free(edit);
665 return NULL;
666 }
667
668 /*
669 * Can't assign to [*] or [#]
670 */
671 num = tmpl_attr_tail_num(map->lhs);
672 if ((num == NUM_ALL) || (num == NUM_COUNT)) {
673 cf_log_err(cs, "Invalid array reference in %s", name);
674 goto fail;
675 }
676
677 /*
678 * If the DA isn't structural, then it can't have children.
679 */
680 parent_da = tmpl_attr_tail_da(map->lhs);
681 if (fr_type_is_structural(parent_da->type)) {
682 map_t *child;
683
684 /*
685 * Don't update namespace for reply += { ... }
686 *
687 * Do update namespace for reply.foo += { ... }
688 *
689 * Don't update if the LHS is an internal group.
690 */
691 if ((tmpl_attr_num_elements(map->lhs) > 1) && (t_rules.attr.list_def != parent_da) &&
692 !((parent_da->type == FR_TYPE_GROUP) && parent_da->flags.internal)) {
693 t_rules.attr.namespace = parent_da;
694 }
695
696 if (map_afrom_cs_edit(map, &map->child, cs, &t_rules, &t_rules, unlang_fixup_edit, map, 256) < 0) {
697 goto fail;
698 }
699
700 /*
701 * As a set of fixups... we can't do array references in -=
702 */
703 if (map->op == T_OP_SUB_EQ) {
704 for (child = map_list_head(&map->child); child != NULL; child = map_list_next(&map->child, child)) {
705 if (!tmpl_is_attr(child->lhs)) continue;
706
707 if (tmpl_attr_tail_num(child->lhs) != NUM_UNSPEC) {
708 cf_log_err(child->ci, "Cannot use array references and values when deleting from a list");
709 goto fail;
710 }
711
712 /*
713 * The edit code doesn't do this correctly, so we just forbid it.
714 */
715 if ((tmpl_attr_num_elements(child->lhs) - tmpl_attr_num_elements(map->lhs)) > 1) {
716 cf_log_err(child->ci, "List deletion must operate directly on the final child");
717 goto fail;
718 }
719
720 /*
721 * We don't do list comparisons either.
722 */
723 if (fr_type_is_structural(tmpl_attr_tail_da(child->lhs)->type)) {
724 cf_log_err(child->ci, "List deletion cannot operate on lists");
725 goto fail;
726 }
727 }
728 }
729 } else {
730 /*
731 * foo := { a, b, c }
732 */
733 if (map_list_afrom_cs(map, &map->child, cs, &t_rules, NULL, NULL, 256) < 0) {
734 goto fail;
735 }
736
737 if ((map->op != T_OP_SET) && !map_list_num_elements(&map->child)) {
738 cf_log_err(cs, "Cannot use operator '%s' for assigning empty list to '%s' data type.",
739 fr_tokens[map->op], fr_type_to_str(parent_da->type));
740 goto fail;
741 }
742 }
743 /*
744 * Do basic sanity checks and resolving.
745 */
746 if (!pass2_fixup_map(map, unlang_ctx->rules, NULL)) goto fail;
747
748 /*
749 * Check operators, and ensure that the RHS has been
750 * resolved.
751 */
752// if (unlang_fixup_update(map, NULL) < 0) goto fail;
753
754 map_list_insert_tail(&edit->maps, map);
755
756 return out;
757}
758
759/** Compile one edit pair
760 *
761 */
763{
764 unlang_edit_t *edit;
765 unlang_t *c = NULL, *out = UNLANG_IGNORE;
766 map_t *map;
767 int num;
768
769 tmpl_rules_t t_rules;
770 fr_token_t op;
771
772 /*
773 * We allow unknown attributes here.
774 */
775 t_rules = *(unlang_ctx->rules);
776 t_rules.attr.allow_unknown = true;
777 fr_assert(t_rules.attr.ci == cf_pair_to_item(cp));
778 RULES_VERIFY(&t_rules);
779
780 edit = talloc_zero(parent, unlang_edit_t);
781 if (!edit) return NULL;
782
783 c = out = unlang_edit_to_generic(edit);
785 c->name = cf_pair_attr(cp);
786 c->debug_name = c->name;
787 c->ci = CF_TO_ITEM(cp);
788
789 map_list_init(&edit->maps);
790
791 op = cf_pair_operator(cp);
792 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
793 cf_log_err(cp, "Invalid operator \"%s\".",
794 fr_table_str_by_value(fr_tokens_table, op, "<INVALID>"));
795 return NULL;
796 }
797
798 /*
799 * Convert this particular map.
800 */
801 if (map_afrom_cp(edit, &map, map_list_tail(&edit->maps), cp, &t_rules, NULL, true) < 0) {
802 fail:
803 talloc_free(edit);
804 return NULL;
805 }
806
807 /*
808 * @todo - we still want to do fixups on the RHS?
809 */
810 if (tmpl_is_attr(map->lhs)) {
811 /*
812 * Can't assign to [*] or [#]
813 */
814 num = tmpl_attr_tail_num(map->lhs);
815 if ((num == NUM_ALL) || (num == NUM_COUNT)) {
816 cf_log_err(cp, "Invalid array reference in %s", map->lhs->name);
817 goto fail;
818 }
819
820 if ((map->op == T_OP_SUB_EQ) && fr_type_is_structural(tmpl_attr_tail_da(map->lhs)->type) &&
821 tmpl_is_attr(map->rhs) && tmpl_attr_tail_da(map->rhs)->flags.local) {
822 cf_log_err(cp, "Cannot delete local variable %s", map->rhs->name);
823 goto fail;
824 }
825 }
826
827 /*
828 * Do basic sanity checks and resolving.
829 */
830 if (!pass2_fixup_map(map, unlang_ctx->rules, NULL)) goto fail;
831
832 /*
833 * Check operators, and ensure that the RHS has been
834 * resolved.
835 */
836 if (unlang_fixup_update(map, c) < 0) goto fail;
837
838 map_list_insert_tail(&edit->maps, map);
839
840 return out;
841}
842
843#define debug_braces(_type) (unlang_ops[_type].flag & UNLANG_OP_FLAG_DEBUG_BRACES)
844
845/** Compile a variable definition.
846 *
847 * Definitions which are adjacent to one another are automatically merged
848 * into one larger variable definition.
849 */
851{
854 char const *attr, *value;
855 unlang_group_t *group;
856
858
859 /*
860 * Enforce locations for local variables.
861 */
862 switch (parent->type) {
863 case UNLANG_TYPE_CASE:
864 case UNLANG_TYPE_ELSE:
868 case UNLANG_TYPE_IF:
876 break;
877
878 default:
879 cf_log_err(cp, "Local variables cannot be used here");
880 return -1;
881 }
882
883 /*
884 * The variables exist in the parent block.
885 */
887 if (group->variables) {
888 var = group->variables;
889
890 } else {
891 group->variables = var = talloc_zero(parent, unlang_variable_t);
892 if (!var) return -1;
893
894 var->dict = fr_dict_protocol_alloc(unlang_ctx->rules->attr.dict_def);
895 if (!var->dict) {
896 talloc_free(var);
897 return -1;
898 }
899 var->root = fr_dict_root(var->dict);
900
901 var->max_attr = 1;
902
903 /*
904 * Initialize the new rules, and point them to the parent rules.
905 *
906 * Then replace the parse rules with our rules, and our dictionary.
907 */
908 *t_rules = *unlang_ctx->rules;
909 t_rules->parent = unlang_ctx->rules;
910
911 t_rules->attr.dict_def = var->dict;
912 t_rules->attr.namespace = NULL;
913
914 unlang_ctx->rules = t_rules;
915 }
916
917 attr = cf_pair_attr(cp); /* data type */
918 value = cf_pair_value(cp); /* variable name */
919
921 if (type == FR_TYPE_NULL) {
923 cf_log_err(cp, "Invalid data type '%s'", attr);
924 return -1;
925 }
926
927 /*
928 * Leaf and group are OK. TLV, Vendor, Struct, VSA, etc. are not.
929 */
930 if (!(fr_type_is_leaf(type) || (type == FR_TYPE_GROUP))) goto invalid_type;
931
932 return unlang_define_local_variable(cf_pair_to_item(cp), var, t_rules, type, value, NULL);
933}
934
935/*
936 * Compile action && rcode for later use.
937 */
939{
940 int action;
941 char const *attr, *value;
942
943 attr = cf_pair_attr(cp);
944 value = cf_pair_value(cp);
945 if (!value) return 0;
946
947 if (!strcasecmp(value, "return"))
948 action = MOD_ACTION_RETURN;
949
950 else if (!strcasecmp(value, "break"))
951 action = MOD_ACTION_RETURN;
952
953 else if (!strcasecmp(value, "reject"))
954 action = MOD_ACTION_REJECT;
955
956 else if (!strcasecmp(value, "retry"))
957 action = MOD_ACTION_RETRY;
958
959 else if (strspn(value, "0123456789") == strlen(value)) {
960 if (strlen(value) > 2) {
961 invalid_action:
962 cf_log_err(cp, "Priorities MUST be between 1 and 64.");
963 return 0;
964 }
965
966 action = MOD_PRIORITY(atoi(value));
967
968 if (!MOD_ACTION_VALID_SET(action)) goto invalid_action;
969
970 } else {
971 cf_log_err(cp, "Unknown action '%s'.\n",
972 value);
973 return 0;
974 }
975
976 if (strcasecmp(attr, "default") != 0) {
977 int rcode;
978
979 rcode = fr_table_value_by_str(mod_rcode_table, attr, -1);
980 if (rcode < 0) {
981 cf_log_err(cp,
982 "Unknown module rcode '%s'.",
983 attr);
984 return 0;
985 }
986 actions->actions[rcode] = action;
987
988 } else { /* set all unset values to the default */
989 int i;
990
991 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
992 if (!actions->actions[i]) actions->actions[i] = action;
993 }
994 }
995
996 return 1;
997}
998
1000{
1001 CONF_ITEM *csi;
1002 CONF_SECTION *cs;
1003
1004 cs = cf_item_to_section(ci);
1005 for (csi=cf_item_next(cs, NULL);
1006 csi != NULL;
1007 csi=cf_item_next(cs, csi)) {
1008 CONF_PAIR *cp;
1009 char const *name, *value;
1010
1011 if (cf_item_is_section(csi)) {
1012 cf_log_err(csi, "Invalid subsection in 'retry' configuration.");
1013 return false;
1014 }
1015
1016 if (!cf_item_is_pair(csi)) continue;
1017
1018 cp = cf_item_to_pair(csi);
1019 name = cf_pair_attr(cp);
1020 value = cf_pair_value(cp);
1021
1022 if (!value) {
1023 cf_log_err(csi, "Retry configuration must specify a value");
1024 return false;
1025 }
1026
1027#define CLAMP(_name, _field, _limit) do { \
1028 if (!fr_time_delta_ispos(actions->retry._field)) { \
1029 cf_log_err(csi, "Invalid value for '" STRINGIFY(_name) " = %s' - value must be positive", \
1030 value); \
1031 return false; \
1032 } \
1033 if (fr_time_delta_cmp(actions->retry._field, fr_time_delta_from_sec(_limit)) > 0) { \
1034 cf_log_err(csi, "Invalid value for '" STRINGIFY(_name) " = %s' - value must be less than " STRINGIFY(_limit) "s", \
1035 value); \
1036 return false; \
1037 } \
1038 } while (0)
1039
1040 /*
1041 * We don't use conf_parser_t here for various
1042 * magical reasons.
1043 */
1044 if (strcmp(name, "initial_rtx_time") == 0) {
1045 if (fr_time_delta_from_str(&actions->retry.irt, value, strlen(value), FR_TIME_RES_SEC) < 0) {
1046 error:
1047 cf_log_err(csi, "Failed parsing '%s = %s' - %s",
1048 name, value, fr_strerror());
1049 return false;
1050 }
1051 CLAMP(initial_rtx_time, irt, 2);
1052
1053 } else if (strcmp(name, "max_rtx_time") == 0) {
1054 if (fr_time_delta_from_str(&actions->retry.mrt, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
1055
1056 CLAMP(max_rtx_time, mrt, 10);
1057
1058 } else if (strcmp(name, "max_rtx_count") == 0) {
1059 unsigned long v = strtoul(value, 0, 0);
1060
1061 if (v > 10) {
1062 cf_log_err(csi, "Invalid value for 'max_rtx_count = %s' - value must be between 0 and 10",
1063 value);
1064 return false;
1065 }
1066
1067 actions->retry.mrc = v;
1068
1069 } else if (strcmp(name, "max_rtx_duration") == 0) {
1070 if (fr_time_delta_from_str(&actions->retry.mrd, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
1071
1072 CLAMP(max_rtx_duration, mrd, 20);
1073
1074 } else {
1075 cf_log_err(csi, "Invalid item '%s' in 'retry' configuration.", name);
1076 return false;
1077 }
1078 }
1079
1080 return true;
1081}
1082
1083bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *action_cs, bool module_retry)
1084{
1085 int i;
1086 bool disallow_retry_action = false;
1087 CONF_ITEM *csi;
1088 CONF_SECTION *cs;
1089
1090 /*
1091 * Over-ride the default return codes of the module.
1092 */
1093 cs = cf_item_to_section(cf_section_to_item(action_cs));
1094 for (csi=cf_item_next(cs, NULL);
1095 csi != NULL;
1096 csi=cf_item_next(cs, csi)) {
1097 char const *name;
1098 CONF_PAIR *cp;
1099
1100 if (cf_item_is_section(csi)) {
1101 CONF_SECTION *subcs = cf_item_to_section(csi);
1102
1103 name = cf_section_name1(subcs);
1104
1105 /*
1106 * Look for a "retry" section.
1107 */
1108 if (name && (strcmp(name, "retry") == 0) && !cf_section_name2(subcs)) {
1109 if (!compile_retry_section(actions, csi)) return false;
1110 continue;
1111 }
1112
1113 cf_log_err(csi, "Invalid subsection. Expected 'action = value'");
1114 return false;
1115 }
1116
1117 if (!cf_item_is_pair(csi)) continue;
1118
1119 cp = cf_item_to_pair(csi);
1120
1121 /*
1122 * Allow 'retry = path.to.retry.config'
1123 */
1124 name = cf_pair_attr(cp);
1125 if (strcmp(name, "retry") == 0) {
1126 CONF_ITEM *subci;
1127 char const *value = cf_pair_value(cp);
1128
1129 if (!value) {
1130 cf_log_err(csi, "Missing reference string");
1131 return false;
1132 }
1133
1134 subci = cf_reference_item(cs, cf_root(cf_section_to_item(action_cs)), value);
1135 if (!subci) {
1136 cf_log_perr(csi, "Failed finding reference '%s'", value);
1137 return false;
1138 }
1139
1140 if (!compile_retry_section(actions, subci)) return false;
1141 continue;
1142 }
1143
1144 if (!compile_action_pair(actions, cp)) {
1145 return false;
1146 }
1147 }
1148
1149 if (module_retry) {
1150 if (!fr_time_delta_ispos(actions->retry.irt)) {
1151 cf_log_err(csi, "initial_rtx_time MUST be non-zero for modules which support retries.");
1152 return false;
1153 }
1154 } else {
1155 if (fr_time_delta_ispos(actions->retry.irt)) {
1156 cf_log_err(csi, "initial_rtx_time MUST be zero, as only max_rtx_count and max_rtx_duration are used.");
1157 return false;
1158 }
1159
1160 if (!actions->retry.mrc && !fr_time_delta_ispos(actions->retry.mrd)) {
1161 disallow_retry_action = true;
1162 }
1163 }
1164
1165 /*
1166 * Sanity check that "fail = retry", we actually have a
1167 * retry section.
1168 */
1169 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1170 if (actions->actions[i] != MOD_ACTION_RETRY) continue;
1171
1172 if (module_retry) {
1173 cf_log_err(csi, "Cannot use a '%s = retry' action for a module which has its own retries",
1174 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1175 return false;
1176 }
1177
1178 if (disallow_retry_action) {
1179 cf_log_err(csi, "max_rtx_count and max_rtx_duration cannot both be zero when using '%s = retry'",
1180 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1181 return false;
1182 }
1183
1184 if (!fr_time_delta_ispos(actions->retry.irt) &&
1185 !actions->retry.mrc &&
1186 !fr_time_delta_ispos(actions->retry.mrd)) {
1187 cf_log_err(csi, "Cannot use a '%s = retry' action without a 'retry { ... }' section.",
1188 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1189 return false;
1190 }
1191 }
1192
1193 return true;
1194}
1195
1197{
1198 unlang_group_t *g;
1199 unlang_t *c;
1200
1201 /*
1202 * If we're compiling an empty section, then the
1203 * *interpreter* type is GROUP, even if the *debug names*
1204 * are something else.
1205 */
1207 if (!g) return NULL;
1208
1210 if (!cs) {
1211 c->name = unlang_ops[type].name;
1212 c->debug_name = c->name;
1213
1214 } else {
1215 char const *name2;
1216
1217 name2 = cf_section_name2(cs);
1218 if (!name2) {
1219 c->name = cf_section_name1(cs);
1220 c->debug_name = c->name;
1221 } else {
1222 c->name = name2;
1223 c->debug_name = talloc_typed_asprintf(c, "%s %s", cf_section_name1(cs), name2);
1224 }
1225 }
1226
1227 return c;
1228}
1229
1230
1232
1233/*
1234 * compile 'actions { ... }' inside of another group.
1235 */
1237{
1238 CONF_ITEM *ci, *next;
1239
1240 ci = cf_section_to_item(subcs);
1241
1242 next = cf_item_next(cs, ci);
1243 if (next && (cf_item_is_pair(next) || cf_item_is_section(next))) {
1244 cf_log_err(ci, "'actions' MUST be the last block in a section");
1245 return false;
1246 }
1247
1248 if (cf_section_name2(subcs) != NULL) {
1249 cf_log_err(ci, "Invalid name for 'actions' section");
1250 return false;
1251 }
1252
1253 /*
1254 * Over-riding the actions can be done in certain limited
1255 * situations. In other situations (e.g. "redundant",
1256 * "load-balance"), it doesn't make sense.
1257 *
1258 * Note that this limitation also applies to "retry"
1259 * timers. We can do retries of a "group". We cannot do
1260 * retries of "load-balance", as the "load-balance"
1261 * section already takes care of redundancy.
1262 *
1263 * We may need to loosen that limitation in the future.
1264 */
1265 switch (c->type) {
1266 case UNLANG_TYPE_CASE:
1267 case UNLANG_TYPE_CATCH:
1268 case UNLANG_TYPE_IF:
1269 case UNLANG_TYPE_ELSE:
1270 case UNLANG_TYPE_ELSIF:
1272 case UNLANG_TYPE_GROUP:
1273 case UNLANG_TYPE_LIMIT:
1274 case UNLANG_TYPE_SWITCH:
1277 break;
1278
1279 default:
1280 cf_log_err(ci, "'actions' MUST NOT be in a '%s' block", unlang_ops[c->type].name);
1281 return false;
1282 }
1283
1284 return unlang_compile_actions(&c->actions, subcs, false);
1285}
1286
1287
1289{
1290 CONF_ITEM *ci = NULL;
1291 unlang_t *c, *single;
1292 bool was_if = false;
1293 char const *skip_else = NULL;
1295 unlang_compile_ctx_t unlang_ctx2;
1296 tmpl_rules_t t_rules, t2_rules; /* yes, it does */
1297
1299
1300 /*
1301 * Create our own compilation context which can be edited
1302 * by a variable definition.
1303 */
1304 unlang_compile_ctx_copy(&unlang_ctx2, unlang_ctx_in);
1305 t2_rules = *(unlang_ctx_in->rules);
1306
1307 unlang_ctx = &unlang_ctx2;
1308 unlang_ctx2.rules = &t2_rules;
1309
1310 t_rules = *unlang_ctx_in->rules;
1311
1312 /*
1313 * Loop over the children of this group.
1314 */
1315 while ((ci = cf_item_next(g->cs, ci))) {
1316 if (cf_item_is_data(ci)) continue;
1317
1318 t_rules.attr.ci = ci;
1319 t2_rules.attr.ci = ci;
1320
1321 /*
1322 * Sections are keywords, or references to
1323 * modules with updated return codes.
1324 */
1325 if (cf_item_is_section(ci)) {
1326 char const *name = NULL;
1327 CONF_SECTION *subcs = cf_item_to_section(ci);
1328
1329 /*
1330 * Skip precompiled blocks. This is
1331 * mainly for policies.
1332 */
1333 if (cf_data_find(subcs, unlang_group_t, NULL)) continue;
1334
1335 /*
1336 * "actions" apply to the current group.
1337 * It's not a subgroup.
1338 */
1339 name = cf_section_name1(subcs);
1340
1341 /*
1342 * In-line attribute editing. Nothing else in the parse has list assignments, so this must be it.
1343 */
1345 single = compile_edit_section(c, unlang_ctx, subcs);
1346 if (!single) {
1347 fail:
1348 talloc_free(c);
1349 return NULL;
1350 }
1351
1352 goto add_child;
1353 }
1354
1355 if (strcmp(name, "actions") == 0) {
1356 if (!compile_action_subsection(c, g->cs, subcs)) goto fail;
1357 continue;
1358 }
1359
1360 /*
1361 * Special checks for "else" and "elsif".
1362 */
1363 if ((strcmp(name, "else") == 0) || (strcmp(name, "elsif") == 0)) {
1364 /*
1365 * We ran into one without a preceding "if" or "elsif".
1366 * That's not allowed.
1367 */
1368 if (!was_if) {
1369 cf_log_err(ci, "Invalid location for '%s'. There is no preceding "
1370 "'if' or 'elsif' statement", name);
1371 goto fail;
1372 }
1373
1374 /*
1375 * There was a previous "if" or "elsif" which was always taken.
1376 * So we skip this "elsif" or "else".
1377 */
1378 if (skip_else) {
1379 void *ptr;
1380
1381 /*
1382 * And manually free this.
1383 */
1384 ptr = cf_data_remove(subcs, xlat_exp_head_t, NULL);
1385 talloc_free(ptr);
1386
1388
1389 cf_log_debug_prefix(ci, "Skipping contents of '%s' due to previous "
1390 "'%s' being always being taken.",
1391 name, skip_else);
1392 continue;
1393 }
1394 }
1395
1396 /*
1397 * Otherwise it's a real keyword.
1398 */
1399 single = compile_item(c, unlang_ctx, ci);
1400 if (!single) {
1401 cf_log_err(ci, "Failed to parse \"%s\" subsection", cf_section_name1(subcs));
1402 goto fail;
1403 }
1404
1405 goto add_child;
1406
1407 } else if (cf_item_is_pair(ci)) {
1408 CONF_PAIR *cp = cf_item_to_pair(ci);
1409
1410 /*
1411 * Variable definition.
1412 */
1413 if (cf_pair_operator(cp) == T_OP_CMP_TRUE) {
1414 if (compile_variable(c, unlang_ctx, cp, &t_rules) < 0) goto fail;
1415
1416 single = UNLANG_IGNORE;
1417 goto add_child;
1418 }
1419
1420 if (!cf_pair_value(cp)) {
1421 single = compile_item(c, unlang_ctx, ci);
1422 if (!single) {
1423 cf_log_err(ci, "Invalid keyword \"%s\".", cf_pair_attr(cp));
1424 goto fail;
1425 }
1426
1427 goto add_child;
1428 }
1429
1430 /*
1431 * What remains MUST be an edit pair. At this point, the state of the compiler
1432 * tells us what it is, and we don't really care if there's a leading '&'.
1433 */
1434 single = compile_edit_pair(c, unlang_ctx, cp);
1435 if (!single) goto fail;
1436
1437 goto add_child;
1438 } else {
1439 cf_log_err(ci, "Asked to compile unknown conf type");
1440 goto fail;
1441 }
1442
1443 add_child:
1444 if (single == UNLANG_IGNORE) continue;
1445
1446 /*
1447 * Do optimizations for "if" and "elsif"
1448 * conditions.
1449 */
1450 switch (single->type) {
1451 case UNLANG_TYPE_ELSIF:
1452 case UNLANG_TYPE_IF:
1453 was_if = true;
1454
1455 {
1456 unlang_group_t *f;
1457 unlang_cond_t *gext;
1458
1459 /*
1460 * Skip else, and/or omit things which will never be run.
1461 */
1462 f = unlang_generic_to_group(single);
1463 gext = unlang_group_to_cond(f);
1464
1465 if (gext->is_truthy) {
1466 if (gext->value) {
1467 skip_else = single->debug_name;
1468 } else {
1469 /*
1470 * The condition never
1471 * matches, so we can
1472 * avoid putting it into
1473 * the unlang tree.
1474 */
1475 talloc_free(single);
1476 continue;
1477 }
1478 }
1479 }
1480 break;
1481
1482 default:
1483 was_if = false;
1484 skip_else = NULL;
1485 break;
1486 }
1487
1488 /*
1489 * unlang_group_t is grown by adding a unlang_t to the end
1490 */
1491 fr_assert(g == talloc_parent(single));
1493 unlang_list_insert_tail(&g->children, single);
1494 single->list = &g->children;
1495
1496 /*
1497 * If it's not possible to execute statement
1498 * after the current one, then just stop
1499 * processing the children.
1500 */
1501 if (g->self.closed) {
1502 cf_log_warn(ci, "Skipping remaining instructions due to '%s'",
1503 single->name);
1504 break;
1505 }
1506 }
1507
1508 return c;
1509}
1510
1511
1512/*
1513 * Generic "compile a section with more unlang inside of it".
1514 */
1516{
1517 unlang_group_t *g;
1518 unlang_t *c;
1519 char const *name1, *name2;
1520
1521 fr_assert(unlang_ctx->rules != NULL);
1522 fr_assert(unlang_ctx->rules->attr.list_def);
1523
1524 /*
1525 * We always create a group, even if the section is empty.
1526 */
1528 if (!g) return NULL;
1529
1531
1532 /*
1533 * Remember the name for printing, etc.
1534 */
1535 name1 = cf_section_name1(cs);
1536 name2 = cf_section_name2(cs);
1537 c->name = name1;
1538
1539 /*
1540 * Make sure to tell the user that we're running a
1541 * policy, and not anything else.
1542 */
1543 if (type == UNLANG_TYPE_POLICY) {
1544 MEM(c->debug_name = talloc_typed_asprintf(c, "policy %s", name1));
1545
1546 } else if (!name2) {
1547 c->debug_name = c->name;
1548
1549 } else {
1550 MEM(c->debug_name = talloc_typed_asprintf(c, "%s %s", name1, name2));
1551 }
1552
1554}
1555
1556
1558{
1559 CONF_PAIR *cp = cf_item_to_pair(ci);
1560 unlang_t *c;
1561 unlang_tmpl_t *ut;
1562 ssize_t slen;
1563 char const *p = cf_pair_attr(cp);
1564 tmpl_t *vpt;
1565
1566 MEM(ut = talloc_zero(parent, unlang_tmpl_t));
1567 c = unlang_tmpl_to_generic(ut);
1569 c->name = p;
1570 c->debug_name = c->name;
1571 c->ci = CF_TO_ITEM(cp);
1572
1573 RULES_VERIFY(unlang_ctx->rules);
1574 slen = tmpl_afrom_substr(ut, &vpt,
1575 &FR_SBUFF_IN(p, talloc_array_length(p) - 1),
1577 NULL,
1578 unlang_ctx->rules);
1579 if (!vpt) {
1580 cf_canonicalize_error(cp, slen, "Failed parsing expansion", p);
1581 talloc_free(ut);
1582 return NULL;
1583 }
1584 ut->tmpl = vpt; /* const issues */
1585
1586 return c;
1587}
1588
1589/*
1590 * redundant, load-balance and parallel have limits on what can
1591 * go in them.
1592 */
1594{
1595 CONF_ITEM *ci;
1596
1597 for (ci=cf_item_next(cs, NULL);
1598 ci != NULL;
1599 ci=cf_item_next(cs, ci)) {
1600 /*
1601 * If we're a redundant, etc. group, then the
1602 * intention is to call modules, rather than
1603 * processing logic. These checks aren't
1604 * *strictly* necessary, but they keep the users
1605 * from doing crazy things.
1606 */
1607 if (cf_item_is_section(ci)) {
1608 CONF_SECTION *subcs = cf_item_to_section(ci);
1609 char const *name1 = cf_section_name1(subcs);
1610
1611 /*
1612 * Allow almost anything except "else"
1613 * statements. The normal processing
1614 * falls through from "if" to "else", and
1615 * we can't do that for redundant and
1616 * load-balance sections.
1617 */
1618 if ((strcmp(name1, "else") == 0) ||
1619 (strcmp(name1, "elsif") == 0)) {
1620 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1621 name, name1);
1622 return false;
1623 }
1624 continue;
1625 }
1626
1627 if (cf_item_is_pair(ci)) {
1628 CONF_PAIR *cp = cf_item_to_pair(ci);
1629
1630 if (cf_pair_operator(cp) == T_OP_CMP_TRUE) return true;
1631
1632 if (cf_pair_value(cp) != NULL) {
1633 cf_log_err(cp, "Unknown keyword '%s', or invalid location", cf_pair_attr(cp));
1634 return false;
1635 }
1636 }
1637 }
1638
1639 return true;
1640}
1641
1642
1644 CONF_SECTION *subcs,
1645 bool policy)
1646{
1647 unlang_compile_ctx_t unlang_ctx2;
1648 unlang_t *c;
1649
1651
1652 /*
1653 * module.c takes care of ensuring that this is:
1654 *
1655 * group foo { ...
1656 * load-balance foo { ...
1657 * redundant foo { ...
1658 * redundant-load-balance foo { ...
1659 *
1660 * We can just recurse to compile the section as
1661 * if it was found here.
1662 */
1663 if (cf_section_name2(subcs)) {
1664 if (policy) {
1665 cf_log_err(subcs, "Unexpected second name in policy");
1666 return NULL;
1667 }
1668
1669 c = compile_item(parent, &unlang_ctx2, cf_section_to_item(subcs));
1670
1671 } else {
1672 /*
1673 * We have:
1674 *
1675 * foo { ...
1676 *
1677 * So we compile it like it was:
1678 *
1679 * group foo { ...
1680 */
1681 c = unlang_compile_section(parent, &unlang_ctx2, subcs,
1683 }
1684 if (!c) return NULL;
1686
1687 /*
1688 * Return the compiled thing if we can.
1689 */
1690 if (!cf_item_is_section(ci)) return c;
1691
1692 /*
1693 * Else we have a reference to a policy, and that reference
1694 * over-rides the return codes for the policy!
1695 */
1696 if (!unlang_compile_actions(&c->actions, cf_item_to_section(ci), false)) {
1697 talloc_free(c);
1698 return NULL;
1699 }
1700
1701 return c;
1702}
1703
1704/** Load a named module from the virtual module list, or from the "policy" subsection.
1705 *
1706 * If it's "foo.method", look for "foo", and return "method" as the method
1707 * we wish to use, instead of the input component.
1708 *
1709 * @param[in] ci Configuration item to check
1710 * @param[in] real_name Complete name string e.g. foo.authorize.
1711 * @param[in] virtual_name Virtual module name e.g. foo.
1712 * @param[in] method_name Method override (may be NULL) or the method
1713 * name e.g. authorize.
1714 * @param[in] unlang_ctx Unlang context this call is being compiled in.
1715 * @param[out] policy whether or not this thing was a policy
1716 * @return the CONF_SECTION specifying the virtual module.
1717 */
1718static CONF_SECTION *virtual_module_find_cs(CONF_ITEM *ci, UNUSED char const *real_name, char const *virtual_name,
1719 char const *method_name, unlang_compile_ctx_t *unlang_ctx, bool *policy)
1720{
1721 CONF_SECTION *cs, *subcs, *conf_root;
1722 CONF_ITEM *loop;
1723 char buffer[256];
1724
1725 *policy = false;
1726 conf_root = cf_root(ci);
1727
1728 /*
1729 * Look for "foo" as a virtual server. If we find it,
1730 * AND there's no method name, we've found the right
1731 * thing.
1732 *
1733 * Found "foo". Load it as "foo", or "foo.method".
1734 *
1735 * Return it to the caller, with the updated method.
1736 */
1737 subcs = module_rlm_virtual_by_name(virtual_name);
1738 if (subcs) goto check_for_loop;
1739
1740 /*
1741 * Look for it in "policy".
1742 *
1743 * If there's no policy section, we can't do anything else.
1744 */
1745 cs = cf_section_find(conf_root, "policy", NULL);
1746 if (!cs) return NULL;
1747
1748 *policy = true;
1749
1750 /*
1751 * "foo.authorize" means "load policy 'foo.authorize' or 'foo'"
1752 * as method "authorize".
1753 *
1754 * And bail out if there's no policy "foo.authorize" or "foo".
1755 */
1756 if (method_name) {
1757 snprintf(buffer, sizeof(buffer), "%s.%s", virtual_name, method_name);
1758 subcs = cf_section_find(cs, buffer, NULL);
1759 if (!subcs) subcs = cf_section_find(cs, virtual_name, NULL);
1760 if (!subcs) return NULL;
1761
1762 goto check_for_loop;
1763 }
1764
1765 /*
1766 * "foo" means "look for foo.name1.name2" first, to allow
1767 * method overrides. If that's not found, look for
1768 * "foo.name1" and if that's not found just look for
1769 * a policy "foo".
1770 */
1771 snprintf(buffer, sizeof(buffer), "%s.%s.%s", virtual_name, unlang_ctx->section_name1, unlang_ctx->section_name2);
1772 subcs = cf_section_find(cs, buffer, NULL);
1773
1774 if (!subcs) {
1775 snprintf(buffer, sizeof(buffer), "%s.%s", virtual_name, unlang_ctx->section_name1);
1776 subcs = cf_section_find(cs, buffer, NULL);
1777 }
1778
1779 if (!subcs) subcs = cf_section_find(cs, virtual_name, NULL);
1780 if (!subcs) return NULL;
1781
1782check_for_loop:
1783 /*
1784 * Check that we're not creating a loop. We may
1785 * be compiling an "sql" module reference inside
1786 * of an "sql" policy. If so, we allow the
1787 * second "sql" to refer to the module.
1788 */
1789 for (loop = cf_parent(ci);
1790 loop && subcs;
1791 loop = cf_parent(loop)) {
1792 if (loop == cf_section_to_item(subcs)) {
1793 return NULL;
1794 }
1795 }
1796
1797 return subcs;
1798}
1799
1801{
1802 unlang_t *c;
1803 unlang_module_t *m;
1804 fr_slen_t slen;
1805
1806 MEM(m = talloc_zero(parent, unlang_module_t));
1807 slen = module_rlm_by_name_and_method(m, &m->mmc,
1808 unlang_ctx->vs,
1809 &(section_name_t){ .name1 = unlang_ctx->section_name1, .name2 = unlang_ctx->section_name2 },
1811 unlang_ctx->rules);
1812 if (slen < 0) {
1813 cf_log_perr(ci, "Failed compiling module call");
1814 talloc_free(m);
1815 return NULL;
1816 }
1817
1818 if (m->mmc.rlm->common.dict &&
1819 !fr_dict_compatible(*m->mmc.rlm->common.dict, unlang_ctx->rules->attr.dict_def)) {
1820 cf_log_err(ci, "The '%s' module can only be used within a '%s' namespace.",
1821 m->mmc.rlm->common.name, fr_dict_root(*m->mmc.rlm->common.dict)->name);
1822 cf_log_err(ci, "Please use the 'subrequest' keyword to change namespaces");
1823 cf_log_err(ci, DOC_KEYWORD_REF(subrequest));
1824 talloc_free(m);
1825 return NULL;
1826 }
1827
1830 c->name = talloc_typed_strdup(c, name);
1831 c->debug_name = c->name;
1832 c->ci = ci;
1833
1834 /*
1835 * Set the default actions for this module.
1836 */
1837 c->actions = m->mmc.mi->actions;
1838
1839 /*
1840 * Parse the method environment for this module / method
1841 */
1842 if (m->mmc.mmb.method_env) {
1844
1845 fr_assert_msg(method_env->inst_size, "Method environment for module %s, method %s %s declared, "
1846 "but no inst_size set",
1847 m->mmc.mi->name, unlang_ctx->section_name1, unlang_ctx->section_name2);
1848
1849 if (!unlang_ctx->rules) {
1850 cf_log_err(ci, "Failed compiling %s - no rules", m->mmc.mi->name);
1851 goto error;
1852 }
1854 unlang_ctx->rules, m->mmc.mi->conf,
1855 &(call_env_ctx_t){
1856 .type = CALL_ENV_CTX_TYPE_MODULE,
1857 .mi = m->mmc.mi,
1858 .asked = &m->mmc.asked
1859 });
1860 if (!m->call_env) {
1861 error:
1862 talloc_free(m);
1863 return NULL;
1864 }
1865 }
1866
1867 /*
1868 * If a module reference is a section, then the section
1869 * should contain action over-rides. We add those here.
1870 */
1871 if (cf_item_is_section(ci) &&
1873 (m->mmc.mi->exported->flags & MODULE_TYPE_RETRY) != 0)) goto error;
1874
1875 return c;
1876}
1877
1878extern int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src);
1879
1880static inline CC_HINT(always_inline) unlang_op_t const *name_to_op(char const *name)
1881{
1882 unlang_op_t const *op;
1883
1884 op = fr_hash_table_find(unlang_op_table, &(unlang_op_t) { .name = name });
1885 if (op) return op;
1886
1887 return NULL;
1888}
1889
1891 fr_dict_attr_t const *ref)
1892{
1893 fr_dict_attr_t const *da;
1894 fr_slen_t len;
1895 unlang_op_t const *op;
1896
1897 fr_dict_attr_flags_t flags = {
1898 .internal = true,
1899 .local = true,
1900 };
1901
1902 /*
1903 * No overlap with list names.
1904 */
1906 fail_list:
1907 cf_log_err(ci, "Local variable '%s' cannot be a list reference.", name);
1908 return -1;
1909 }
1910
1911 len = strlen(name);
1912 if (tmpl_attr_list_from_substr(&da, &FR_SBUFF_IN(name, len)) == len) goto fail_list;
1913
1914 /*
1915 * No keyword section names.
1916 */
1917 op = name_to_op(name);
1918 if (op) {
1919 cf_log_err(ci, "Local variable '%s' cannot be an unlang keyword.", name);
1920 return -1;
1921 }
1922
1923 /*
1924 * No protocol names.
1925 */
1926 if (fr_dict_by_protocol_name(name) != NULL) {
1927 cf_log_err(ci, "Local variable '%s' cannot be an existing protocol name.", name);
1928 return -1;
1929 }
1930
1931 /*
1932 * No overlap with attributes in the current dictionary. The lookup in var->root will also check
1933 * the current dictionary, so the check here is really only for better error messages.
1934 */
1935 if (t_rules && t_rules->parent && t_rules->parent->attr.dict_def) {
1936 da = fr_dict_attr_by_name(NULL, fr_dict_root(t_rules->parent->attr.dict_def), name);
1937 if (da) {
1938 cf_log_err(ci, "Local variable '%s' duplicates a dictionary attribute.", name);
1939 return -1;
1940 }
1941 }
1942
1943 /*
1944 * No data types.
1945 */
1947 cf_log_err(ci, "Invalid variable name '%s'.", name);
1948 return -1;
1949 }
1950
1951 /*
1952 * No dups of local variables.
1953 */
1954 da = fr_dict_attr_by_name(NULL, var->root, name);
1955 if (da) {
1956 cf_log_err(ci, "Duplicate variable name '%s'.", name);
1957 return -1;
1958 }
1959
1960 if (fr_dict_attr_add(var->dict, var->root, name, var->max_attr, type, &flags) < 0) {
1961 fail:
1962 cf_log_err(ci, "Failed adding variable '%s' - %s", name, fr_strerror());
1963 return -1;
1964 }
1965 da = fr_dict_attr_by_name(NULL, var->root, name);
1966 fr_assert(da != NULL);
1967
1968 /*
1969 * Copy the children over.
1970 */
1972 fr_fatal_assert(ref != NULL);
1973
1974 if (fr_dict_attr_acopy_local(da, ref) < 0) goto fail;
1975 }
1976
1977 var->max_attr++;
1978
1979 return 0;
1980}
1981
1982/*
1983 * Compile one unlang instruction
1984 */
1986{
1987 char const *name, *p;
1988 CONF_SECTION *cs, *subcs, *modules;
1989 char const *realname;
1990 unlang_compile_ctx_t unlang_ctx2;
1991 bool policy;
1992 unlang_t *c;
1993 bool ignore_notfound = false;
1994 unlang_op_t const *op;
1995
1996 if (cf_item_is_section(ci)) {
1997 cs = cf_item_to_section(ci);
1998 name = cf_section_name1(cs);
1999 op = name_to_op(name);
2000
2001 if (op) {
2002 /*
2003 * Forbid pair keywords as section names,
2004 * e.g. "break { ... }"
2005 */
2006 if ((op->flag & UNLANG_OP_FLAG_SINGLE_WORD) != 0) {
2007 cf_log_err(ci, "Syntax error after keyword '%s' - unexpected '{'", name);
2008 return NULL;
2009 }
2010
2011 c = op->compile(parent, unlang_ctx, ci);
2012 goto allocate_number;
2013 }
2014
2015 /* else it's something like sql { fail = 1 ...} */
2016 goto check_for_module;
2017
2018 } else if (cf_item_is_pair(ci)) {
2019
2020 /*
2021 * Else it's a module reference such as "sql", OR
2022 * one of the few bare keywords that we allow.
2023 */
2024 CONF_PAIR *cp = cf_item_to_pair(ci);
2025
2026 /*
2027 * We cannot have assignments or actions here.
2028 */
2029 if (cf_pair_value(cp) != NULL) {
2030 cf_log_err(ci, "Invalid assignment");
2031 return NULL;
2032 }
2033
2034 name = cf_pair_attr(cp);
2035 op = name_to_op(name);
2036
2037 if (op) {
2038 /*
2039 * Forbid section keywords as pair names, e.g. "switch = foo"
2040 */
2041 if ((op->flag & UNLANG_OP_FLAG_SINGLE_WORD) == 0) {
2042 cf_log_err(ci, "Syntax error after keyword '%s' - missing '{'", name);
2043 return NULL;
2044 }
2045
2046 c = op->compile(parent, unlang_ctx, ci);
2047 goto allocate_number;
2048 }
2049
2050 /*
2051 * In-place expansions.
2052 *
2053 * @todo - allow only function calls, not %{...}
2054 *
2055 * @todo don't create a tmpl. Instead, create an
2056 * xlat. This functionality is needed for the in-place language functions via
2057 *
2058 * language {{{
2059 * ...
2060 * }}}
2061 */
2062 if (name[0] == '%') {
2064 goto allocate_number;
2065 }
2066
2067 goto check_for_module;
2068
2069 } else {
2070 cf_log_err(ci, "Asked to compile unknown configuration item");
2071 return NULL; /* who knows what it is... */
2072 }
2073
2074check_for_module:
2075 /*
2076 * We now have a name. It can be one of two forms. A
2077 * bare module name, or a section named for the module,
2078 * with over-rides for the return codes.
2079 *
2080 * The name can refer to a real module, in the "modules"
2081 * section. In that case, the name will be either the
2082 * first or second name of the sub-section of "modules".
2083 *
2084 * Or, the name can refer to a policy, in the "policy"
2085 * section. In that case, the name will be first of the
2086 * sub-section of "policy".
2087 *
2088 * Or, the name can refer to a "module.method", in which
2089 * case we're calling a different method than normal for
2090 * this section.
2091 *
2092 * Or, the name can refer to a virtual module, in the
2093 * "modules" section. In that case, the name will be
2094 * name2 of the CONF_SECTION.
2095 *
2096 * We try these in sequence, from the bottom up. This is
2097 * so that virtual modules and things in "policy" can
2098 * over-ride calls to real modules.
2099 */
2100
2101
2102 /*
2103 * Try:
2104 *
2105 * policy { ... name { .. } .. }
2106 * policy { ... name.method { .. } .. }
2107 */
2108 p = strrchr(name, '.');
2109 if (!p) {
2110 subcs = virtual_module_find_cs(ci, name, name, NULL, unlang_ctx, &policy);
2111 } else {
2112 char buffer[256];
2113
2114 strlcpy(buffer, name, sizeof(buffer));
2115 buffer[p - name] = '\0';
2116
2117 subcs = virtual_module_find_cs(ci, name,
2118 buffer, buffer + (p - name) + 1, unlang_ctx, &policy);
2119 }
2120
2121 /*
2122 * We've found the thing which defines this "function".
2123 * It MUST be a sub-section.
2124 *
2125 * i.e. it refers to a a subsection in "policy".
2126 */
2127 if (subcs) {
2128 c = compile_function(parent, unlang_ctx, ci, subcs, policy);
2129 goto allocate_number;
2130 }
2131
2132 /*
2133 * Not a function. It must be a real module.
2134 */
2135 modules = cf_section_find(cf_root(ci), "modules", NULL);
2136 if (!modules) {
2137 cf_log_err(ci, "Failed compiling \"%s\" as a module or policy as no modules are enabled", name);
2138 cf_log_err(ci, "Please verify that modules { ... } section is present in the server configuration");
2139 return NULL;
2140 }
2141
2142 realname = name;
2143
2144 /*
2145 * Try to load the optional module.
2146 */
2147 if (*realname == '-') {
2148 ignore_notfound = true;
2149 realname++;
2150 }
2151
2152 /*
2153 * Set the child compilation context BEFORE parsing the
2154 * module name and method. The lookup function will take
2155 * care of returning the appropriate component, name1,
2156 * name2, etc.
2157 */
2159 c = compile_module(parent, &unlang_ctx2, ci, realname);
2160 if (!c) {
2161 if (ignore_notfound) {
2162 cf_log_warn(ci, "Ignoring \"%s\" as the \"%s\" module is not enabled, "
2163 "or the method does not exist", name, realname);
2164 return UNLANG_IGNORE;
2165 }
2166
2167 return NULL;
2168 }
2169
2170allocate_number:
2171 if (!c) return NULL;
2172 if (c == UNLANG_IGNORE) return UNLANG_IGNORE;
2173
2174 c->number = unlang_number++;
2176
2177 /*
2178 * Only insert the per-thread allocation && instantiation if it's used.
2179 */
2180 op = &unlang_ops[c->type];
2181 if (!op->thread_inst_size) return c;
2182
2184 cf_log_err(ci, "Instruction \"%s\" number %u has conflict with previous one.",
2185 c->debug_name, c->number);
2186 talloc_free(c);
2187 return NULL;
2188 }
2189
2190 return c;
2191}
2192
2193/** Compile an unlang section for a virtual server
2194 *
2195 * @param[in] vs Virtual server to compile section for.
2196 * @param[in] cs containing the unlang calls to compile.
2197 * @param[in] actions Actions to use for the unlang section.
2198 * @param[in] rules Rules to use for the unlang section.
2199 * @param[out] instruction Pointer to store the compiled unlang section.
2200 * @return
2201 * - 0 on success.
2202 * - -1 on error.
2203 */
2205 CONF_SECTION *cs, unlang_mod_actions_t const *actions, tmpl_rules_t const *rules, void **instruction)
2206{
2207 unlang_t *c;
2208 tmpl_rules_t my_rules;
2209 char const *name1, *name2;
2210 CONF_DATA const *cd;
2211
2212 /*
2213 * Don't compile it twice, and don't print out debug
2214 * messages twice.
2215 */
2216 cd = cf_data_find(cs, unlang_group_t, NULL);
2217 if (cd) {
2218 if (instruction) *instruction = cf_data_value(cd);
2219 return 1;
2220 }
2221
2222 name1 = cf_section_name1(cs);
2223 name2 = cf_section_name2(cs);
2224
2225 if (!name2) name2 = "";
2226
2227 cf_log_debug(cs, "Compiling policies in - %s %s {...}", name1, name2);
2228
2229 /*
2230 * Ensure that all compile functions get valid rules.
2231 */
2232 if (!rules) {
2233 memset(&my_rules, 0, sizeof(my_rules));
2234 rules = &my_rules;
2235 }
2236
2237 c = unlang_compile_section(NULL,
2239 .vs = vs,
2240 .section_name1 = cf_section_name1(cs),
2241 .section_name2 = cf_section_name2(cs),
2242 .actions = *actions,
2243 .rules = rules
2244 },
2245 cs, UNLANG_TYPE_GROUP);
2246 if (!c) return -1;
2247
2249
2250 if (DEBUG_ENABLED4) unlang_dump(c, 2);
2251
2252 /*
2253 * Associate the unlang with the configuration section,
2254 * and free the unlang code when the configuration
2255 * section is freed.
2256 */
2257 cf_data_add(cs, c, NULL, true);
2258 if (instruction) *instruction = c;
2259
2260 return 0;
2261}
2262
2263
2264/** Check if name is an unlang keyword
2265 *
2266 * @param[in] name to check.
2267 * @return
2268 * - true if it is a keyword.
2269 * - false if it's not a keyword.
2270 */
2272{
2273 if (!name || !*name) return false;
2274
2275 return (name_to_op(name) != 0);
2276}
2277
2278/*
2279 * These are really unlang_foo_t, but that's fine...
2280 */
2281static int8_t instruction_cmp(void const *one, void const *two)
2282{
2283 unlang_t const *a = one;
2284 unlang_t const *b = two;
2285
2286 return CMP(a->number, b->number);
2287}
2288
2289
2290void unlang_compile_init(TALLOC_CTX *ctx)
2291{
2293}
2294
2295
2296/** Create thread-specific data structures for unlang
2297 *
2298 */
2299int unlang_thread_instantiate(TALLOC_CTX *ctx)
2300{
2302 unlang_t *instruction;
2303
2304 if (unlang_thread_array) {
2305 fr_strerror_const("already initialized");
2306 return -1;
2307 }
2308
2309 MEM(unlang_thread_array = talloc_zero_array(ctx, unlang_thread_t, unlang_number + 1));
2310// talloc_set_destructor(unlang_thread_array, _unlang_thread_array_free);
2311
2312 /*
2313 * Instantiate each instruction with thread-specific data.
2314 */
2315 for (instruction = fr_rb_iter_init_inorder(&iter, unlang_instruction_tree);
2316 instruction;
2317 instruction = fr_rb_iter_next_inorder(&iter)) {
2318 unlang_op_t *op;
2319
2320 unlang_thread_array[instruction->number].instruction = instruction;
2321
2322 op = &unlang_ops[instruction->type];
2323
2325
2326 /*
2327 * Allocate any thread-specific instance data.
2328 */
2329 MEM(unlang_thread_array[instruction->number].thread_inst = talloc_zero_array(unlang_thread_array, uint8_t, op->thread_inst_size));
2330 talloc_set_name_const(unlang_thread_array[instruction->number].thread_inst, op->thread_inst_type);
2331
2332 if (op->thread_instantiate && (op->thread_instantiate(instruction, unlang_thread_array[instruction->number].thread_inst) < 0)) {
2333 return -1;
2334 }
2335 }
2336
2337 return 0;
2338}
2339
2340/** Get the thread-instance data for an instruction.
2341 *
2342 * @param[in] instruction the instruction to use
2343 * @return a pointer to thread-local data
2344 */
2345void *unlang_thread_instance(unlang_t const *instruction)
2346{
2347 if (!instruction->number || !unlang_thread_array) return NULL;
2348
2349 fr_assert(instruction->number <= unlang_number);
2350
2351 return unlang_thread_array[instruction->number].thread_inst;
2352}
2353
2354#ifdef WITH_PERF
2356{
2357 unlang_thread_t *t;
2358 fr_time_t now;
2359 unlang_t const *instruction = frame->instruction;
2360
2361 if (!instruction->number || !unlang_thread_array) return;
2362
2363 fr_assert(instruction->number <= unlang_number);
2364
2365 t = &unlang_thread_array[instruction->number];
2366
2367 t->use_count++;
2368 t->yielded++; // everything starts off as yielded
2369 now = fr_time();
2370
2371 fr_time_tracking_start(NULL, &frame->tracking, now);
2372 fr_time_tracking_yield(&frame->tracking, fr_time());
2373}
2374
2376{
2377 unlang_t const *instruction = frame->instruction;
2378 unlang_thread_t *t;
2379
2380 if (!instruction->number || !unlang_thread_array) return;
2381
2382 t = &unlang_thread_array[instruction->number];
2383 t->yielded++;
2384 t->running--;
2385
2386 fr_time_tracking_yield(&frame->tracking, fr_time());
2387}
2388
2390{
2391 unlang_t const *instruction = frame->instruction;
2392 unlang_thread_t *t;
2393
2394 if (!instruction->number || !unlang_thread_array) return;
2395
2396 if (frame->tracking.state != FR_TIME_TRACKING_YIELDED) return;
2397
2398 t = &unlang_thread_array[instruction->number];
2399 t->running++;
2400 t->yielded--;
2401
2402 fr_time_tracking_resume(&frame->tracking, fr_time());
2403}
2404
2406{
2407 unlang_t const *instruction = frame->instruction;
2408 unlang_thread_t *t;
2409
2410 if (!instruction || !instruction->number || !unlang_thread_array) return;
2411
2412 fr_assert(instruction->number <= unlang_number);
2413
2414 t = &unlang_thread_array[instruction->number];
2415
2416 if (frame->tracking.state == FR_TIME_TRACKING_YIELDED) {
2417 t->yielded--;
2418 fr_time_tracking_resume(&frame->tracking, fr_time());
2419 } else {
2420 t->running--;
2421 }
2422
2423 fr_time_tracking_end(NULL, &frame->tracking, fr_time());
2424 t->tracking.running_total = fr_time_delta_add(t->tracking.running_total, frame->tracking.running_total);
2425 t->tracking.waiting_total = fr_time_delta_add(t->tracking.waiting_total, frame->tracking.waiting_total);
2426}
2427
2428
2429static void unlang_perf_dump(fr_log_t *log, unlang_t const *instruction, int depth)
2430{
2431 unlang_group_t const *g;
2432 unlang_thread_t *t;
2433 char const *file;
2434 int line;
2435
2436 if (!instruction || !instruction->number) return;
2437
2438 /*
2439 * These are generally pushed onto the stack, and therefore ignored.
2440 */
2441 if (instruction->type == UNLANG_TYPE_TMPL) return;
2442
2443 /*
2444 * Everything else is an unlang_group_t;
2445 */
2446 g = unlang_generic_to_group(instruction);
2447
2448 if (!g->cs) return;
2449
2450 file = cf_filename(g->cs);
2451 line = cf_lineno(g->cs);
2452
2453 if (depth) {
2454 fr_log(log, L_DBG, file, line, "%.*s", depth, unlang_spaces);
2455 }
2456
2457 if (debug_braces(instruction->type)) {
2458 fr_log(log, L_DBG, file, line, "%s { #", instruction->debug_name);
2459 } else {
2460 fr_log(log, L_DBG, file, line, "%s #", instruction->debug_name);
2461 }
2462
2463 t = &unlang_thread_array[instruction->number];
2464
2465 fr_log(log, L_DBG, file, line, "count=%" PRIu64 " cpu_time=%" PRId64 " yielded_time=%" PRId64 ,
2466 t->use_count, fr_time_delta_unwrap(t->tracking.running_total), fr_time_delta_unwrap(t->tracking.waiting_total));
2467
2468 if (!unlang_list_empty(&g->children)) {
2469 unlang_list_foreach(&g->children, child) {
2470 unlang_perf_dump(log, child, depth + 1);
2471 }
2472 }
2473
2474 if (debug_braces(instruction->type)) {
2475 if (depth) {
2476 fr_log(log, L_DBG, file, line, "%.*s", depth, unlang_spaces);
2477 }
2478
2479 fr_log(log, L_DBG, file, line, "}");
2480 }
2481}
2482
2483void unlang_perf_virtual_server(fr_log_t *log, char const *name)
2484{
2485
2487 CONF_SECTION *cs;
2488 CONF_ITEM *ci;
2489 char const *file;
2490 int line;
2491
2492 if (!vs) return;
2493
2494 cs = virtual_server_cs(vs);
2495
2496 file = cf_filename(cs);
2497 line = cf_lineno(cs);
2498
2499 fr_log(log, L_DBG, file, line, " server %s {\n", name);
2500
2501 /*
2502 * Loop over the children of the virtual server, checking for unlang_t;
2503 */
2504 for (ci = cf_item_next(cs, NULL);
2505 ci != NULL;
2506 ci = cf_item_next(cs, ci)) {
2507 char const *name1, *name2;
2508 unlang_t *instruction;
2509 CONF_SECTION *subcs;
2510
2511 if (!cf_item_is_section(ci)) continue;
2512
2513 instruction = (unlang_t *)cf_data_value(cf_data_find(ci, unlang_group_t, NULL));
2514 if (!instruction) continue;
2515
2516 subcs = cf_item_to_section(ci);
2517 name1 = cf_section_name1(subcs);
2518 name2 = cf_section_name2(subcs);
2519 file = cf_filename(ci);
2520 line = cf_lineno(ci);
2521
2522 if (!name2) {
2523 fr_log(log, L_DBG, file, line, " %s {\n", name1);
2524 } else {
2525 fr_log(log, L_DBG, file, line, " %s %s {\n", name1, name2);
2526 }
2527
2528 unlang_perf_dump(log, instruction, 2);
2529
2530 fr_log(log, L_DBG, file, line, " }\n");
2531 }
2532
2533 fr_log(log, L_DBG, file, line, "}\n");
2534}
2535#endif
static int const char char buffer[256]
Definition acutest.h:578
int const char * file
Definition acutest.h:704
int const char int line
Definition acutest.h:704
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#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:112
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
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:793
size_t inst_size
Size of per call env.
Definition call_env.h:245
#define RULES_VERIFY(_cs, _rules)
Definition cf_file.c:180
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Definition cf_file.c:3745
Internal data that is associated with a configuration section.
Definition cf_priv.h:125
Common header for all CONF_* types.
Definition cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:631
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
Definition cf_util.c:1610
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1184
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1750
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:737
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1170
CONF_SECTION * cf_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:1027
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:683
bool cf_item_is_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
Definition cf_util.c:645
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1595
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:617
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:663
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1229
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1581
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:721
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1565
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:286
#define cf_lineno(_cf)
Definition cf_util.h:104
#define cf_data_add(_cf, _data, _name, _free)
Definition cf_util.h:252
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:241
#define cf_log_debug_prefix(_cf, _fmt,...)
Definition cf_util.h:303
#define cf_data_remove(_cf, _type, _name)
Remove an item from a parent by type and name.
Definition cf_util.h:264
#define cf_root(_cf)
Definition cf_util.h:98
#define cf_section_free_children(_x)
Definition cf_util.h:193
#define cf_parent(_cf)
Definition cf_util.h:101
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:364
#define cf_item_next(_parent, _curr)
Definition cf_util.h:92
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:293
#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_filename(_cf)
Definition cf_util.h:107
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:287
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:289
static int compile_action_pair(unlang_mod_actions_t *actions, CONF_PAIR *cp)
Definition compile.c:938
unlang_t * unlang_compile_children(unlang_group_t *g, unlang_compile_ctx_t *unlang_ctx_in)
Definition compile.c:1288
static unlang_t * compile_module(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci, char const *name)
Definition compile.c:1800
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:762
bool unlang_compile_is_keyword(const char *name)
Check if name is an unlang keyword.
Definition compile.c:2271
void unlang_compile_init(TALLOC_CTX *ctx)
Definition compile.c:2290
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1515
bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *action_cs, bool module_retry)
Definition compile.c:1083
bool pass2_fixup_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules)
Definition compile.c:214
bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
Definition compile.c:95
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:601
bool unlang_compile_limit_subsection(CONF_SECTION *cs, char const *name)
Definition compile.c:1593
int unlang_thread_instantiate(TALLOC_CTX *ctx)
Create thread-specific data structures for unlang.
Definition compile.c:2299
static void unlang_dump(unlang_t *c, int depth)
Definition compile.c:240
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:850
static char const unlang_spaces[]
Definition compile.c:93
#define UPDATE_CTX2
Definition compile.c:90
static int8_t instruction_cmp(void const *one, void const *two)
Definition compile.c:2281
int unlang_fixup_update(map_t *map, void *ctx)
Validate and fixup a map that's part of an update section.
Definition compile.c:350
static bool compile_retry_section(unlang_mod_actions_t *actions, CONF_ITEM *ci)
Definition compile.c:999
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:1718
static unlang_t * compile_item(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci)
Definition compile.c:1985
static const bool edit_list_sub_op[T_TOKEN_LAST]
Definition compile.c:503
size_t mod_rcode_table_len
Definition compile.c:88
static unlang_t * compile_tmpl(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM *ci)
Definition compile.c:1557
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:479
static unsigned int unlang_number
Definition compile.c:57
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:1196
unlang_group_t * unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:446
#define debug_braces(_type)
Definition compile.c:843
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:123
static fr_rb_tree_t * unlang_instruction_tree
Definition compile.c:71
bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules)
Definition compile.c:187
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:1643
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:1187
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:75
void * unlang_thread_instance(unlang_t const *instruction)
Get the thread-instance data for an instruction.
Definition compile.c:2345
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:524
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:2204
static _Thread_local unlang_thread_t * unlang_thread_array
Definition compile.c:64
static unlang_op_t const * name_to_op(char const *name)
Definition compile.c:1880
#define CLAMP(_name, _field, _limit)
#define T(_x)
Definition compile.c:501
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:1890
static bool compile_action_subsection(unlang_t *c, CONF_SECTION *cs, CONF_SECTION *subcs)
Definition compile.c:1236
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:39
int fr_dict_attr_acopy_local(fr_dict_attr_t const *dst, fr_dict_attr_t const *src)
Definition dict_util.c:1125
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:3525
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:2881
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2662
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:90
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition dict_util.c:2839
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:1960
fr_dict_t * fr_dict_protocol_alloc(fr_dict_t const *parent)
Allocate a new local dictionary.
Definition dict_util.c:4264
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
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
Find data in a hash table.
Definition hash.c:428
#define DEBUG_ENABLED4
True if global debug level 1-3 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:1161
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:105
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:1346
ssize_t map_print(fr_sbuff_t *out, map_t const *map)
Print a map to a string.
Definition map.c:2389
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
talloc_free(reap)
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:577
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
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
unsigned char uint8_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:66
Unlang module actions.
@ MOD_ACTION_RETURN
stop processing the section, and return the rcode with unset priority
Definition mod_action.h:40
@ MOD_ACTION_REJECT
change the rcode to REJECT, with unset priority
Definition mod_action.h:39
@ MOD_ACTION_RETRY
retry the instruction, MUST also set a retry config
Definition mod_action.h:38
#define MOD_ACTION_VALID_SET(_x)
Definition mod_action.h:61
fr_retry_config_t retry
Definition mod_action.h:65
#define MOD_PRIORITY(_x)
Definition mod_action.h:34
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:64
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:562
CONF_SECTION * module_rlm_virtual_by_name(char const *asked_name)
Definition module_rlm.c:803
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:38
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition rb.c:824
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
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:223
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:321
The main red black tree structure.
Definition rb.h:73
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:47
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:45
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:44
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:48
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:43
@ RLM_MODULE_TIMEOUT
Module (or section) timed out.
Definition rcode.h:52
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:49
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:51
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:41
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:50
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:53
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:46
static const call_env_method_t method_env
Definition rlm_detail.c:480
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:44
char const * name
Instance name e.g. user_database.
Definition module.h:355
@ 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:349
unlang_mod_actions_t actions
default actions and retries.
Definition module.h:323
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:296
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
Definition tmpl.h:887
#define TMPL_VERIFY(_vpt)
Definition tmpl.h:963
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:636
#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:393
tmpl_rules_t const * parent
for parent / child relationships
Definition tmpl.h:335
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 the last attribute reference is a leaf attribute.
Definition tmpl.h:819
#define NUM_COUNT
Definition tmpl.h:394
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:922
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:1271
#define NUM_UNSPEC
Definition tmpl.h:392
static size_t tmpl_attr_num_elements(tmpl_t const *vpt)
The number of attribute references contained within a tmpl.
Definition tmpl.h:898
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:337
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:803
@ 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:366
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:334
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
fr_aka_sim_id_type_t type
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
Definition log.h:96
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
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
Definition tmpl.h:295
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
uint8_t allow_unknown
Allow unknown attributes i.e.
Definition tmpl.h:303
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
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:514
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:467
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
static fr_time_delta_t fr_time_delta_add(fr_time_delta_t a, fr_time_delta_t b)
Definition time.h:255
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
#define fr_time_delta_ispos(_a)
Definition time.h:290
@ FR_TIME_RES_SEC
Definition time.h:50
"server local" time.
Definition time.h:69
@ FR_TIME_TRACKING_YIELDED
We're currently tracking time in the yielded state.
static void fr_time_tracking_yield(fr_time_tracking_t *tt, fr_time_t now)
Transition to the yielded state, recording the time we just spent running.
static void fr_time_tracking_end(fr_time_delta_t *predicted, fr_time_tracking_t *tt, fr_time_t now)
End time tracking for this entity.
static void fr_time_tracking_start(fr_time_tracking_t *parent, fr_time_tracking_t *tt, fr_time_t now)
Start time tracking for a tracked entity.
static void fr_time_tracking_resume(fr_time_tracking_t *tt, fr_time_t now)
Track that a request resumed.
const bool fr_assignment_op[T_TOKEN_LAST]
Definition token.c:169
const bool fr_list_assignment_op[T_TOKEN_LAST]
Definition token.c:186
fr_table_num_ordered_t const fr_tokens_table[]
Definition token.c:34
char const * fr_tokens[T_TOKEN_LAST]
Definition token.c:79
const bool fr_comparison_op[T_TOKEN_LAST]
Definition token.c:199
const bool fr_binary_op[T_TOKEN_LAST]
Definition token.c:217
enum fr_token fr_token_t
@ T_OP_SUB_EQ
Definition token.h:70
@ T_INVALID
Definition token.h:39
@ T_OP_CMP_TRUE
Definition token.h:104
@ T_OP_EQ
Definition token.h:83
@ T_OP_SET
Definition token.h:84
@ T_OP_CMP_FALSE
Definition token.h:105
#define T_TOKEN_LAST
Definition token.h:129
Declarations for unlang transactions.
Declaration for unlang try.
#define unlang_frame_perf_resume(_x)
CONF_SECTION * cs
char const * debug_name
Printed in log messages when the node is executed.
void * state
Stack frame specialisations.
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)
char const * thread_inst_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)
#define unlang_frame_perf_init(_x)
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
unlang_t const * instruction
The unlang node we're evaluating.
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_t const * instruction
instruction which we're executing
char const * name
Name of the keyword.
#define unlang_frame_perf_yield(_x)
#define unlang_frame_perf_cleanup(_x)
int max_attr
1..N local attributes have been defined
unlang_thread_instantiate_t thread_instantiate
per-thread instantiation function
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.
size_t thread_inst_size
unlang_op_flag_t flag
Interpreter flags for this operation.
unlang_list_t * list
so we have fewer run-time dereferences
void * thread_inst
thread-specific instance data
Generic representation of a grouping.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
A naked xlat.
static fr_slen_t parent
Definition pair.h:854
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:553
#define fr_strerror_const(_msg)
Definition strerror.h:223
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:393
#define fr_type_is_leaf(_x)
Definition types.h:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
#define DOC_KEYWORD_REF(_x)
Definition version.h:89
static size_t char ** out
Definition value.h:1023
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.