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: d65889d5a62669af28fdabaa9d1b7b2ca2b29b8b $
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: d65889d5a62669af28fdabaa9d1b7b2ca2b29b8b $")
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#include <freeradius-devel/server/tmpl.h>
38#include <freeradius-devel/server/cf_util.h>
39#include <freeradius-devel/util/time.h>
40#include <freeradius-devel/util/dict.h>
41
42#include "catch_priv.h"
43#include "call_priv.h"
44#include "caller_priv.h"
45#include "condition_priv.h"
46#include "foreach_priv.h"
47#include "load_balance_priv.h"
48#include "map_priv.h"
49#include "module_priv.h"
50#include "parallel_priv.h"
51#include "subrequest_priv.h"
52#include "switch_priv.h"
53#include "edit_priv.h"
54#include "timeout_priv.h"
55#include "limit_priv.h"
56#include "transaction_priv.h"
57#include "try_priv.h"
58#include "mod_action.h"
59
60#define UNLANG_IGNORE ((unlang_t *) -1)
61
62extern bool tmpl_require_enum_prefix;
63
64static unsigned int unlang_number = 1;
65
66/*
67 * For simplicity, this is just array[unlang_number]. Once we
68 * call unlang_thread_instantiate(), the "unlang_number" above MUST
69 * NOT change.
70 */
72
73/*
74 * Until we know how many instructions there are, we can't
75 * allocate an array. So we have to put the instructions into an
76 * RB tree.
77 */
79
80/* Here's where we recognize all of our keywords: first the rcodes, then the
81 * actions */
83 { L("..."), RLM_MODULE_NOT_SET },
84 { L("disallow"), RLM_MODULE_DISALLOW },
85 { L("fail"), RLM_MODULE_FAIL },
86 { L("handled"), RLM_MODULE_HANDLED },
87 { L("invalid"), RLM_MODULE_INVALID },
88 { L("noop"), RLM_MODULE_NOOP },
89 { L("notfound"), RLM_MODULE_NOTFOUND },
90 { L("ok"), RLM_MODULE_OK },
91 { L("reject"), RLM_MODULE_REJECT },
92 { L("updated"), RLM_MODULE_UPDATED }
93};
95
96typedef struct {
97 virtual_server_t const *vs; //!< Virtual server we're compiling in the context of.
98 ///< This shouldn't change during the compilation of
99 ///< a single unlang section.
100 char const *section_name1;
101 char const *section_name2;
105
106/*
107 * When we switch to a new unlang ctx, we use the new component
108 * name and number, but we use the CURRENT actions.
109 */
110static inline CC_HINT(always_inline)
112{
113 int i;
114
115 *dst = *src;
116
117 /*
118 * Ensure that none of the actions are RETRY.
119 */
120 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
121 if (dst->actions.actions[i] == MOD_ACTION_RETRY) dst->actions.actions[i] = MOD_PRIORITY_MIN;
122 }
123 memset(&dst->actions.retry, 0, sizeof(dst->actions.retry)); \
124}
125
126#define UPDATE_CTX2 compile_copy_context(&unlang_ctx2, unlang_ctx)
127
128
130
131static char const unlang_spaces[] = " ";
132
133static inline CC_HINT(always_inline) int unlang_attr_rules_verify(tmpl_attr_rules_t const *rules)
134{
135 if (!fr_cond_assert_msg(rules->dict_def, "No protocol dictionary set")) return -1;
136 if (!fr_cond_assert_msg(rules->dict_def != fr_dict_internal(), "rules->attr.dict_def must not be the internal dictionary")) return -1;
137 if (!fr_cond_assert_msg(!rules->allow_foreign, "rules->attr.allow_foreign must be false")) return -1;
138
139 return 0;
140}
141
142static inline CC_HINT(always_inline) int unlang_rules_verify(tmpl_rules_t const *rules)
143{
144 if (!fr_cond_assert_msg(!rules->at_runtime, "rules->at_runtime must be false")) return -1;
145 return unlang_attr_rules_verify(&rules->attr);
146}
147
148#if 0
149#define ATTR_RULES_VERIFY(_rules) if (unlang_attr_rules_verify(_rules) < 0) return NULL;
150#endif
151#define RULES_VERIFY(_rules) do { if (unlang_rules_verify(_rules) < 0) return NULL; } while (0)
152
153static bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
154{
155 tmpl_t *vpt = *vpt_p;
156
158
159 /*
160 * We may now know the correct dictionary
161 * where we didn't before...
162 */
163 if (!vpt->rules.attr.dict_def) tmpl_set_dict_def(vpt, dict);
164
165 /*
166 * Fixup any other tmpl types
167 */
168 if (tmpl_resolve(vpt, &(tmpl_res_rules_t){ .dict_def = dict, .force_dict_def = (dict != NULL)}) < 0) {
169 cf_log_perr(ci, NULL);
170 return false;
171 }
172
173 return true;
174}
175
176/** Fixup ONE map (recursively)
177 *
178 * This function resolves most things. Most notable it CAN leave the
179 * RHS unresolved, for use in `map` sections.
180 */
181static bool pass2_fixup_map(map_t *map, tmpl_rules_t const *rules, fr_dict_attr_t const *parent)
182{
183 RULES_VERIFY(rules);
184
185 if (tmpl_is_data_unresolved(map->lhs)) {
186 if (!pass2_fixup_tmpl(map, &map->lhs, map->ci, rules->attr.dict_def)) {
187 return false;
188 }
189 }
190
191 /*
192 * Enforce parent-child relationships in nested maps.
193 */
194 if (parent) {
195 if ((map->op != T_OP_EQ) && (!map->parent || (map->parent->op != T_OP_SUB_EQ))) {
196 cf_log_err(map->ci, "Invalid operator \"%s\" in nested map section. "
197 "Only '=' is allowed",
198 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
199 return false;
200 }
201 }
202
203 if (map->rhs) {
204 if (tmpl_is_data_unresolved(map->rhs)) {
206
207 if (!pass2_fixup_tmpl(map, &map->rhs, map->ci, rules->attr.dict_def)) {
208 return false;
209 }
210 }
211 }
212
213 /*
214 * Sanity check sublists.
215 */
216 if (!map_list_empty(&map->child)) {
217 fr_dict_attr_t const *da;
218 map_t *child;
219
220 if (!tmpl_is_attr(map->lhs)) {
221 cf_log_err(map->ci, "Sublists can only be assigned to a known attribute");
222 return false;
223 }
224
225 da = tmpl_attr_tail_da(map->lhs);
226
227 /*
228 * Resolve all children.
229 */
230 for (child = map_list_next(&map->child, NULL);
231 child != NULL;
232 child = map_list_next(&map->child, child)) {
233 if (!pass2_fixup_map(child, rules, da)) {
234 return false;
235 }
236 }
237 }
238
239 return true;
240}
241
242/*
243 * Do all kinds of fixups and checks for update sections.
244 */
245static bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules)
246{
248 map_t *map = NULL;
249
250 RULES_VERIFY(rules);
251
252 while ((map = map_list_next(&gext->map, map))) {
253 /*
254 * Mostly fixup the map, but maybe leave the RHS
255 * unresolved.
256 */
257 if (!pass2_fixup_map(map, rules, NULL)) return false;
258
259 /*
260 * Check allowed operators, and ensure that the
261 * RHS is resolved.
262 */
263 if (cf_item_is_pair(map->ci) && (unlang_fixup_update(map, NULL) < 0)) return false;
264 }
265
266 return true;
267}
268
269/*
270 * Compile the RHS of map sections to xlat_exp_t
271 */
273{
275 map_t *map = NULL;
276
277 RULES_VERIFY(rules);
278
279 /*
280 * Do most fixups on the maps. Leaving the RHS as
281 * unresolved, so that the `map` function can interpret
282 * the RHS as a reference to a json string, SQL column
283 * name, etc.
284 */
285 while ((map = map_list_next(&gext->map, map))) {
286 if (!pass2_fixup_map(map, rules, NULL)) return false;
287 }
288
289 /*
290 * Map sections don't need a VPT.
291 */
292 if (!gext->vpt) return true;
293
294 return pass2_fixup_tmpl(map_list_head(&gext->map)->ci, &gext->vpt,
295 cf_section_to_item(g->cs), rules->attr.dict_def);
296}
297
298static void unlang_dump(unlang_t *instruction, int depth)
299{
300 unlang_t *c;
302 map_t *map;
303 char buffer[1024];
304
305 for (c = instruction; c != NULL; c = c->next) {
306 switch (c->type) {
307 case UNLANG_TYPE_NULL:
308 case UNLANG_TYPE_MAX:
309 fr_assert(0);
310 break;
311
313 DEBUG("%.*s%s", depth, unlang_spaces, c->debug_name);
314 break;
315
317 {
319
320 DEBUG("%.*s%s", depth, unlang_spaces, m->mmc.mi->name);
321 }
322 break;
323
324 case UNLANG_TYPE_MAP:
326 {
327 unlang_map_t *gext;
328
329 DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name);
330
332 gext = unlang_group_to_map(g);
333 map = NULL;
334 while ((map = map_list_next(&gext->map, map))) {
335 map_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map);
336 DEBUG("%.*s%s", depth + 1, unlang_spaces, buffer);
337 }
338
339 DEBUG("%.*s}", depth, unlang_spaces);
340 }
341 break;
342
343 case UNLANG_TYPE_EDIT:
344 {
345 unlang_edit_t *edit;
346
347 edit = unlang_generic_to_edit(c);
348 map = NULL;
349 while ((map = map_list_next(&edit->maps, map))) {
350 if (!map->rhs) continue; /* @todo - fixme */
351
352 map_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map);
353 DEBUG("%.*s%s", depth + 1, unlang_spaces, buffer);
354 }
355
356 DEBUG("%.*s}", depth, unlang_spaces);
357 }
358 break;
359
360
361 case UNLANG_TYPE_CALL:
363 case UNLANG_TYPE_CASE:
365 case UNLANG_TYPE_ELSE:
368 case UNLANG_TYPE_IF:
379 case UNLANG_TYPE_TRY:
380 case UNLANG_TYPE_CATCH: /* @todo - print out things we catch, too */
382 DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name);
383 unlang_dump(g->children, depth + 1);
384 DEBUG("%.*s}", depth, unlang_spaces);
385 break;
386
390 case UNLANG_TYPE_TMPL:
391 case UNLANG_TYPE_XLAT:
392 DEBUG("%.*s%s", depth, unlang_spaces, c->debug_name);
393 break;
394 }
395 }
396}
397
398/** Validate and fixup a map that's part of an map section.
399 *
400 * @param map to validate.
401 * @param ctx data to pass to fixup function (currently unused).
402 * @return 0 if valid else -1.
403 */
404static int unlang_fixup_map(map_t *map, UNUSED void *ctx)
405{
406 CONF_PAIR *cp = cf_item_to_pair(map->ci);
407
408 /*
409 * Anal-retentive checks.
410 */
411 if (DEBUG_ENABLED3) {
412 if (tmpl_is_attr(map->lhs) && (map->lhs->name[0] != '&')) {
413 cf_log_warn(cp, "Please change attribute reference to '&%s %s ...'",
414 map->lhs->name, fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
415 }
416
417 if (tmpl_is_attr(map->rhs) && (map->rhs->name[0] != '&')) {
418 cf_log_warn(cp, "Please change attribute reference to '... %s &%s'",
419 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"), map->rhs->name);
420 }
421 }
422
423 switch (map->lhs->type) {
424 case TMPL_TYPE_ATTR:
426 case TMPL_TYPE_XLAT:
427 break;
428
429 default:
430 cf_log_err(map->ci, "Left side of map must be an attribute "
431 "or an xlat (that expands to an attribute), not a %s",
432 tmpl_type_to_str(map->lhs->type));
433 return -1;
434 }
435
436 switch (map->rhs->type) {
439 case TMPL_TYPE_DATA:
440 case TMPL_TYPE_XLAT:
441 case TMPL_TYPE_ATTR:
442 case TMPL_TYPE_EXEC:
443 break;
444
445 default:
446 cf_log_err(map->ci, "Right side of map must be an attribute, literal, xlat or exec, got type %s",
447 tmpl_type_to_str(map->rhs->type));
448 return -1;
449 }
450
451 if (!fr_assignment_op[map->op] && !fr_comparison_op[map->op]) {
452 cf_log_err(map->ci, "Invalid operator \"%s\" in map section. "
453 "Only assignment or filter operators are allowed",
454 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
455 return -1;
456 }
457
458 return 0;
459}
460
461
462/** Validate and fixup a map that's part of an update section.
463 *
464 * @param map to validate.
465 * @param ctx data to pass to fixup function (currently unused).
466 * @return
467 * - 0 if valid.
468 * - -1 not valid.
469 */
470int unlang_fixup_update(map_t *map, void *ctx)
471{
472 CONF_PAIR *cp = cf_item_to_pair(map->ci);
473
474 /*
475 * Anal-retentive checks.
476 */
477 if (DEBUG_ENABLED3) {
478 if (tmpl_is_attr(map->lhs) && (map->lhs->name[0] != '&')) {
479 cf_log_warn(cp, "Please change attribute reference to '&%s %s ...'",
480 map->lhs->name, fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
481 }
482
483 if (tmpl_is_attr(map->rhs) && (map->rhs->name[0] != '&')) {
484 cf_log_warn(cp, "Please change attribute reference to '... %s &%s'",
485 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"), map->rhs->name);
486 }
487 }
488
489 if (!ctx) {
490 /*
491 * Fixup RHS attribute references to change NUM_UNSPEC to NUM_ALL.
492 */
493 switch (map->rhs->type) {
494 case TMPL_TYPE_ATTR:
496 break;
497
498 default:
499 break;
500 }
501 }
502
503 /*
504 * Values used by unary operators should be literal ANY
505 *
506 * We then free the template and alloc a NULL one instead.
507 */
508 if ((map->op == T_OP_CMP_FALSE) && !tmpl_is_null(map->rhs)) {
509 if (!tmpl_is_data_unresolved(map->rhs) || (strcmp(map->rhs->name, "ANY") != 0)) {
510 WARN("%s[%d] Wildcard deletion MUST use '!* ANY'",
511 cf_filename(cp), cf_lineno(cp));
512 }
513
514 TALLOC_FREE(map->rhs);
515
516 map->rhs = tmpl_alloc(map, TMPL_TYPE_NULL, T_INVALID, NULL, 0);
517 }
518
519 /*
520 * Lots of sanity checks for insane people...
521 */
522
523 /*
524 * Depending on the attribute type, some operators are disallowed.
525 */
526 if (tmpl_is_attr(map->lhs)) {
527 /*
528 * What exactly where you expecting to happen here?
529 */
530 if (tmpl_attr_tail_da_is_leaf(map->lhs) &&
531 tmpl_is_list(map->rhs)) {
532 cf_log_err(map->ci, "Can't copy list into an attribute");
533 return -1;
534 }
535
536 if (!fr_assignment_op[map->op] && !fr_comparison_op[map->op] && !fr_binary_op[map->op]) {
537 cf_log_err(map->ci, "Invalid operator \"%s\" in update section. "
538 "Only assignment or filter operators are allowed",
539 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
540 return -1;
541 }
542
543 if (fr_comparison_op[map->op] && (map->op != T_OP_CMP_FALSE)) {
544 cf_log_warn(cp, "Please use the 'filter' keyword for attribute filtering");
545 }
546 }
547
548 /*
549 * If the map has a unary operator there's no further
550 * processing we need to, as RHS is unused.
551 */
552 if (map->op == T_OP_CMP_FALSE) return 0;
553
554 if (!tmpl_is_data_unresolved(map->rhs)) return 0;
555
556 /*
557 * If LHS is an attribute, and RHS is a literal, we can
558 * preparse the information into a TMPL_TYPE_DATA.
559 *
560 * Unless it's a unary operator in which case we
561 * ignore map->rhs.
562 */
563 if (tmpl_is_attr(map->lhs) && tmpl_is_data_unresolved(map->rhs)) {
564 fr_type_t type = tmpl_attr_tail_da(map->lhs)->type;
565
566 /*
567 * @todo - allow passing octets to
568 * FR_TYPE_STRUCT, which can then decode them as
569 * data? That would be rather powerful.
570 */
572
573 /*
574 * It's a literal string, just copy it.
575 * Don't escape anything.
576 */
577 if (tmpl_cast_in_place(map->rhs, type, tmpl_attr_tail_da(map->lhs)) < 0) {
578 cf_log_perr(map->ci, "Cannot convert RHS value (%s) to LHS attribute type (%s)",
581 return -1;
582 }
583
584 return 0;
585 } /* else we can't precompile the data */
586
587 if (!tmpl_is_xlat(map->lhs)) {
588 fr_assert(0);
589 cf_log_err(map->ci, "Cannot determine what update action to perform");
590 return -1;
591 }
592
593 return 0;
594}
595
596
598{
600 unlang_t *c;
601 TALLOC_CTX *ctx;
602
603 ctx = parent;
604 if (!ctx) ctx = cs;
605
606 /*
607 * All the groups have a common header
608 */
609 g = (unlang_group_t *)_talloc_zero_pooled_object(ctx, ext->len, ext->type_name,
610 ext->pool_headers, ext->pool_len);
611 if (!g) return NULL;
612
613 g->children = NULL;
614 g->tail = &g->children;
615 g->cs = cs;
616
618 c->parent = parent;
619 c->type = ext->type;
620 c->ci = CF_TO_ITEM(cs);
621
622 return g;
623}
624
626{
627 int i;
628
629 /*
630 * Note that we do NOT copy over the default retries, as
631 * that would result in every subsection doing it's own
632 * retries. That is not what we want. Instead, we want
633 * the retries to apply only to the _current_ section.
634 */
635
636 /*
637 * Children of "redundant" and "redundant-load-balance"
638 * have RETURN for all actions except fail. But THEIR children are normal.
639 */
640 if (c->parent &&
642 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
643 if (i == RLM_MODULE_FAIL) {
644 if (!c->actions.actions[i]) {
645 c->actions.actions[i] = 1;
646 }
647
648 continue;
649 }
650
651 if (!c->actions.actions[i]) {
653 }
654 }
655
656 return;
657 }
658
659 /*
660 * Set the default actions, if they haven't already been
661 * set.
662 */
663 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
664 if (!c->actions.actions[i]) {
665 c->actions.actions[i] = unlang_ctx->actions.actions[i];
666 }
667 }
668}
669
671{
673
674 /*
675 * map <module-name> <arg>
676 */
677 if (gext->vpt) {
678 char quote;
679 size_t quoted_len;
680 char *quoted_str;
681
682 switch (cf_section_argv_quote(g->cs, 0)) {
684 quote = '"';
685 break;
686
688 quote = '\'';
689 break;
690
692 quote = '`';
693 break;
694
695 default:
696 quote = '\0';
697 break;
698 }
699
700 quoted_len = fr_snprint_len(gext->vpt->name, gext->vpt->len, quote);
701 quoted_str = talloc_array(g, char, quoted_len);
702 fr_snprint(quoted_str, quoted_len, gext->vpt->name, gext->vpt->len, quote);
703
704 g->self.name = talloc_typed_asprintf(g, "map %s %s", cf_section_name2(g->cs), quoted_str);
705 g->self.debug_name = g->self.name;
706 talloc_free(quoted_str);
707
708 return 0;
709 }
710
711 g->self.name = talloc_typed_asprintf(g, "map %s", cf_section_name2(g->cs));
712 g->self.debug_name = g->self.name;
713
714 return 0;
715}
716
718{
720 int rcode;
721
723 unlang_map_t *gext;
724
725 unlang_t *c;
726 CONF_SECTION *modules;
727 char const *tmpl_str;
728
729 tmpl_t *vpt = NULL;
730
731 map_proc_t *proc;
732 map_proc_inst_t *proc_inst;
733
734 char const *name2 = cf_section_name2(cs);
735
736 tmpl_rules_t t_rules;
737
738 static unlang_ext_t const map_ext = {
740 .len = sizeof(unlang_map_t),
741 .type_name = "unlang_map_t"
742 };
743
744 /*
745 * We allow unknown attributes here.
746 */
747 t_rules = *(unlang_ctx->rules);
748 t_rules.attr.allow_unknown = true;
749 RULES_VERIFY(&t_rules);
750
751 modules = cf_section_find(cf_root(cs), "modules", NULL);
752 if (!modules) {
753 cf_log_err(cs, "'map' sections require a 'modules' section");
754 return NULL;
755 }
756
757 proc = map_proc_find(name2);
758 if (!proc) {
759 cf_log_err(cs, "Failed to find map processor '%s'", name2);
760 return NULL;
761 }
763
764 g = group_allocate(parent, cs, &map_ext);
765 if (!g) return NULL;
766
767 gext = unlang_group_to_map(g);
768
769 /*
770 * If there's a third string, it's the map src.
771 *
772 * Convert it into a template.
773 */
774 tmpl_str = cf_section_argv(cs, 0); /* AFTER name1, name2 */
775 if (tmpl_str) {
777
779
780 /*
781 * Try to parse the template.
782 */
783 (void) tmpl_afrom_substr(gext, &vpt,
784 &FR_SBUFF_IN(tmpl_str, talloc_array_length(tmpl_str) - 1),
785 type,
786 NULL,
787 &t_rules);
788 if (!vpt) {
789 cf_log_perr(cs, "Failed parsing map");
790 error:
791 talloc_free(g);
792 return NULL;
793 }
794
795 /*
796 * Limit the allowed template types.
797 */
798 switch (vpt->type) {
800 case TMPL_TYPE_ATTR:
802 case TMPL_TYPE_XLAT:
804 case TMPL_TYPE_EXEC:
806 case TMPL_TYPE_DATA:
807 break;
808
809 default:
811 cf_log_err(cs, "Invalid third argument for map");
812 return NULL;
813 }
814 }
815
816 /*
817 * This looks at cs->name2 to determine which list to update
818 */
819 map_list_init(&gext->map);
820 rcode = map_afrom_cs(gext, &gext->map, cs, &t_rules, &t_rules, unlang_fixup_map, NULL, 256);
821 if (rcode < 0) return NULL; /* message already printed */
822 if (map_list_empty(&gext->map)) {
823 cf_log_err(cs, "'map' sections cannot be empty");
824 goto error;
825 }
826
827
828 /*
829 * Call the map's instantiation function to validate
830 * the map and perform any caching required.
831 */
832 proc_inst = map_proc_instantiate(gext, proc, cs, vpt, &gext->map);
833 if (!proc_inst) {
834 cf_log_err(cs, "Failed instantiating map function '%s'", name2);
835 goto error;
836 }
838
839 gext->vpt = vpt;
840 gext->proc_inst = proc_inst;
841
843
844 /*
845 * Cache the module in the unlang_group_t struct.
846 *
847 * Ensure that the module has a "map" entry in its module
848 * header? Or ensure that the map is registered in the
849 * "bootstrap" phase, so that it's always available here.
850 */
851 if (!pass2_fixup_map_rhs(g, unlang_ctx->rules)) goto error;
852
854
855 return c;
856}
857
858static int edit_section_alloc(CONF_SECTION *parent, CONF_SECTION **child, char const *name1, fr_token_t op)
859{
860 CONF_SECTION *cs;
861
862 cs = cf_section_alloc(parent, parent, name1, NULL);
863 if (!cs) return -1;
864
866
867 if (child) *child = cs;
868
869 return 0;
870}
871
872static int edit_pair_alloc(CONF_SECTION *cs, CONF_PAIR *original, char const *attr, fr_token_t op, char const *value, fr_token_t list_op)
873{
874 CONF_PAIR *cp;
875 fr_token_t rhs_quote;
876
877 if (original) {
878 rhs_quote = cf_pair_value_quote(original);
879 } else {
880 rhs_quote = T_BARE_WORD;
881 }
882
883 cp = cf_pair_alloc(cs, attr, value, op, T_BARE_WORD, rhs_quote);
884 if (!cp) return -1;
885
886 if (!original) return 0;
887
888 cf_filename_set(cp, cf_filename(original));
889 cf_lineno_set(cp, cf_lineno(original));
890
891 if (fr_debug_lvl >= 3) {
892 if (list_op == T_INVALID) {
893 cf_log_err(original, "%s %s %s --> %s %s %s",
894 cf_pair_attr(original), fr_tokens[cf_pair_operator(original)], cf_pair_value(original),
895 attr, fr_tokens[op], value);
896 } else {
897 if (*attr == '&') attr++;
898 cf_log_err(original, "%s %s %s --> %s %s { %s %s %s }",
899 cf_pair_attr(original), fr_tokens[cf_pair_operator(original)], cf_pair_value(original),
900 cf_section_name1(cs), fr_tokens[list_op], attr, fr_tokens[op], value);
901 }
902 } else if (fr_debug_lvl >= 2) {
903 if (list_op == T_INVALID) {
904 cf_log_err(original, "--> %s %s %s",
905 attr, fr_tokens[op], value);
906 } else {
907 cf_log_err(original, "--> %s %s { %s %s %s }",
908 cf_section_name1(cs), fr_tokens[list_op], attr, fr_tokens[op], value);
909 }
910 }
911
912 return 0;
913}
914
915/*
916 * Convert "update" to "edit" using evil spells and sorcery.
917 */
919{
920 char const *name2 = cf_section_name2(cs);
921 CONF_ITEM *ci;
922 CONF_SECTION *group;
924 char list_buffer[32];
925 char value_buffer[256];
926 char attr_buffer[256];
927 char const *list;
928
930
931 /*
932 * Wrap it all in a group, no matter what. Because of
933 * limitations in the cf_pair_alloc() API.
934 */
935 group = cf_section_alloc(g->cs, g->cs, "group", NULL);
936 if (!group) return NULL;
937
938 (void) cf_item_remove(g->cs, group); /* was added at the end */
939 cf_item_insert_after(g->cs, cs, group);
940
941 /*
942 * Hoist this out of the loop, and make sure it always has a '&' prefix.
943 */
944 if (name2) {
945 if (*name2 == '&') name2++;
946 snprintf(list_buffer, sizeof(list_buffer), "&%s", name2);
947 } else {
948 snprintf(list_buffer, sizeof(list_buffer), "&%s", tmpl_list_name(unlang_ctx->rules->attr.list_def, "<INVALID>"));
949
950 }
951
952 /*
953 * Loop over the entries, rewriting them.
954 */
955 for (ci = cf_item_next(cs, NULL);
956 ci != NULL;
957 ci = cf_item_next(cs, ci)) {
958 CONF_PAIR *cp;
959 CONF_SECTION *child;
960 int rcode;
961 fr_token_t op;
962 char const *attr, *value, *end;
963
964 if (cf_item_is_section(ci)) {
965 cf_log_err(ci, "Cannot specify subsections for 'update'");
966 return NULL;
967 }
968
969 if (!cf_item_is_pair(ci)) continue;
970
971 cp = cf_item_to_pair(ci);
972
973 attr = cf_pair_attr(cp);
974 value = cf_pair_value(cp);
975 op = cf_pair_operator(cp);
976
977 fr_assert(attr);
979
980 list = list_buffer;
981
982 if (*attr == '&') attr++;
983
984 end = strchr(attr, '.');
985 if (!end) end = attr + strlen(attr);
986
987 /*
988 * Separate out the various possibilities for the "name", which could be a list, an
989 * attribute name, or a list followed by an attribute name.
990 *
991 * Note that even if we have "update request { ....}", the v3 parser allowed the contents
992 * of the "update" section to still specify parent / lists. Which makes parsing it all
993 * annoying.
994 *
995 * The good news is that all we care about is whether or not there's a parent / list ref.
996 * We don't care what that ref is.
997 */
998 {
1000
1001 /*
1002 * Allow for a "parent" or "outer" reference. There may be multiple
1003 * "parent.parent", so we keep processing them until we get a list reference.
1004 */
1006
1007 /*
1008 * Catch one more case where the behavior is different.
1009 *
1010 * &request += &config[*]
1011 */
1012 if ((cf_pair_value_quote(cp) == T_BARE_WORD) && (*value == '&') &&
1013 (strchr(value, '.') == NULL) && (strchr(value, '[') != NULL)) {
1014 char const *p = strchr(value, '[');
1015
1016 cf_log_err(cp, "Cannot do array assignments for lists. Just use '%s %s %.*s'",
1017 list, fr_tokens[op], (int) (p - value), value);
1018 return NULL;
1019 }
1020
1021 goto attr_is_list;
1022
1023 /*
1024 * Doesn't have a parent ref, maybe it's a list ref?
1025 */
1026 } else if (tmpl_attr_list_from_substr(&tmpl_list, &FR_SBUFF_IN(attr, (end - attr))) > 0) {
1027 char *p;
1028
1029 attr_is_list:
1030 snprintf(attr_buffer, sizeof(attr_buffer), "&%s", attr);
1031 list = attr_buffer;
1032 attr = NULL;
1033
1034 p = strchr(attr_buffer, '.');
1035 if (p) {
1036 *(p++) = '\0';
1037 attr = p;
1038 }
1039 }
1040 }
1041
1042 switch (op) {
1043 /*
1044 * FOO !* ANY
1045 *
1046 * The RHS doesn't matter, so we ignore it.
1047 */
1048 case T_OP_CMP_FALSE:
1049 if (!attr) {
1050 /*
1051 * Set list to empty value.
1052 */
1053 rcode = edit_section_alloc(group, NULL, list, T_OP_SET);
1054
1055 } else {
1056 if (strchr(attr, '[') == NULL) {
1057 snprintf(value_buffer, sizeof(value_buffer), "&%s[*]", attr);
1058 } else {
1059 snprintf(value_buffer, sizeof(value_buffer), "&%s", attr);
1060 }
1061
1062 rcode = edit_pair_alloc(group, cp, list, T_OP_SUB_EQ, value_buffer, T_INVALID);
1063 }
1064 break;
1065
1066 case T_OP_SET:
1067 /*
1068 * Must be a list-to-list operation
1069 */
1070 if (!attr) {
1071 list_op:
1072 rcode = edit_pair_alloc(group, cp, list, op, value, T_INVALID);
1073 break;
1074 }
1075 goto pair_op;
1076
1077 case T_OP_EQ:
1078 /*
1079 * Allow &list = "foo"
1080 */
1081 if (!attr) {
1082 if (!value) {
1083 cf_log_err(cp, "Missing value");
1084 return NULL;
1085 }
1086
1087 rcode = edit_pair_alloc(group, cp, list, op, value, T_INVALID);
1088 break;
1089 }
1090
1091 pair_op:
1092 fr_assert(*attr != '&');
1093 if (snprintf(value_buffer, sizeof(value_buffer), "%s.%s", list, attr) < 0) {
1094 cf_log_err(cp, "RHS of update too long to convert to edit automatically");
1095 return NULL;
1096 }
1097
1098 rcode = edit_pair_alloc(group, cp, value_buffer, op, value, T_INVALID);
1099 break;
1100
1101 case T_OP_ADD_EQ:
1102 case T_OP_PREPEND:
1103 if (!attr) goto list_op;
1104
1105 rcode = edit_section_alloc(group, &child, list, op);
1106 if (rcode < 0) break;
1107
1108 snprintf(attr_buffer, sizeof(attr_buffer), "&%s", attr);
1109 rcode = edit_pair_alloc(child, cp, attr_buffer, T_OP_EQ, value, op);
1110 break;
1111
1112 /*
1113 * Remove matching attributes
1114 */
1115 case T_OP_SUB_EQ:
1116 op = T_OP_CMP_EQ;
1117
1118 filter:
1119 if (!attr) {
1120 cf_log_err(cp, "Invalid operator for list assignment");
1121 return NULL;
1122 }
1123
1124 rcode = edit_section_alloc(group, &child, list, T_OP_SUB_EQ);
1125 if (rcode < 0) break;
1126
1127 if (strchr(attr, '[') != 0) {
1128 cf_log_err(cp, "Cannot do filtering with array indexes");
1129 return NULL;
1130 }
1131
1132 snprintf(attr_buffer, sizeof(attr_buffer), "&%s", attr);
1133 rcode = edit_pair_alloc(child, cp, attr_buffer, op, value, T_OP_SUB_EQ);
1134 break;
1135
1136 /*
1137 * Keep matching attributes, i.e. remove non-matching ones.
1138 */
1139 case T_OP_CMP_EQ:
1140 op = T_OP_NE;
1141 goto filter;
1142
1143 case T_OP_NE:
1144 op = T_OP_CMP_EQ;
1145 goto filter;
1146
1147 case T_OP_LT:
1148 op = T_OP_GE;
1149 goto filter;
1150
1151 case T_OP_LE:
1152 op = T_OP_GT;
1153 goto filter;
1154
1155 case T_OP_GT:
1156 op = T_OP_LE;
1157 goto filter;
1158
1159 case T_OP_GE:
1160 op = T_OP_LT;
1161 goto filter;
1162
1163 default:
1164 cf_log_err(cp, "Unsupported operator - cannot auto-convert to edit section");
1165 return NULL;
1166 }
1167
1168 if (rcode < 0) {
1169 cf_log_err(cp, "Failed converting entry");
1170 return NULL;
1171 }
1172 }
1173
1174 return UNLANG_IGNORE;
1175}
1176
1178{
1180 int rcode;
1181
1182 unlang_group_t *g;
1183 unlang_map_t *gext;
1184
1185 unlang_t *c;
1186 char const *name2 = cf_section_name2(cs);
1187
1188 tmpl_rules_t t_rules;
1189
1190 static unlang_ext_t const update_ext = {
1192 .len = sizeof(unlang_map_t),
1193 .type_name = "unlang_map_t"
1194 };
1195
1196 if (main_config_migrate_option_get("forbid_update")) {
1197 cf_log_err(cs, "The use of 'update' sections is forbidden by the server configuration");
1198 return NULL;
1199 }
1200
1201 /*
1202 * If we're migrating "update" sections to edit, then go
1203 * do that now.
1204 */
1205 if (main_config_migrate_option_get("rewrite_update")) {
1207 }
1208
1209 /*
1210 * We allow unknown attributes here.
1211 */
1212 t_rules = *(unlang_ctx->rules);
1213 t_rules.attr.allow_unknown = true;
1214 t_rules.attr.allow_wildcard = true;
1215 RULES_VERIFY(&t_rules);
1216
1217 g = group_allocate(parent, cs, &update_ext);
1218 if (!g) return NULL;
1219
1220 gext = unlang_group_to_map(g);
1221
1222 /*
1223 * This looks at cs->name2 to determine which list to update
1224 */
1225 map_list_init(&gext->map);
1226 rcode = map_afrom_cs(gext, &gext->map, cs, &t_rules, &t_rules, unlang_fixup_update, NULL, 128);
1227 if (rcode < 0) return NULL; /* message already printed */
1228 if (map_list_empty(&gext->map)) {
1229 cf_log_err(cs, "'update' sections cannot be empty");
1230 error:
1231 talloc_free(g);
1232 return NULL;
1233 }
1234
1236 if (name2) {
1237 c->name = name2;
1238 c->debug_name = talloc_typed_asprintf(c, "update %s", name2);
1239 } else {
1240 c->name = "update";
1241 c->debug_name = c->name;
1242 }
1243
1244 if (!pass2_fixup_update(g, unlang_ctx->rules)) goto error;
1245
1247
1248 return c;
1249}
1250
1251#define T(_x) [T_OP_ ## _x] = true
1252
1253static const bool edit_list_sub_op[T_TOKEN_LAST] = {
1254 T(NE),
1255 T(GE),
1256 T(GT),
1257 T(LE),
1258 T(LT),
1259 T(CMP_EQ),
1260};
1261
1262/** Validate and fixup a map that's part of an edit section.
1263 *
1264 * @param map to validate.
1265 * @param ctx data to pass to fixup function (currently unused).
1266 * @return 0 if valid else -1.
1267 *
1268 * @todo - this is only called for CONF_PAIR maps, not for
1269 * CONF_SECTION. So when we parse nested maps, there's no validation
1270 * done of the CONF_SECTION. In order to fix this, we need to have
1271 * map_afrom_cs() call the validation function for the CONF_SECTION
1272 * *before* recursing.
1273 */
1274static int unlang_fixup_edit(map_t *map, void *ctx)
1275{
1276 CONF_PAIR *cp = cf_item_to_pair(map->ci);
1277 fr_dict_attr_t const *da;
1278 fr_dict_attr_t const *parent = NULL;
1279 map_t *parent_map = ctx;
1280
1281 fr_assert(parent_map);
1282#ifdef STATIC_ANALYZER
1283 if (!parent_map) return -1;
1284#endif
1285
1286 fr_assert(tmpl_is_attr(parent_map->lhs));
1287
1288 if (parent_map && (parent_map->op == T_OP_SUB_EQ)) {
1289 if (!edit_list_sub_op[map->op]) {
1290 cf_log_err(cp, "Invalid operator '%s' for right-hand side list. It must be a comparison operator", fr_tokens[map->op]);
1291 return -1;
1292 }
1293
1294 } else if (map->op != T_OP_EQ) {
1295 cf_log_err(cp, "Invalid operator '%s' for right-hand side list. It must be '='", fr_tokens[map->op]);
1296 return -1;
1297 }
1298
1299 /*
1300 * map_afrom_cs() will build its tree recursively, and call us for each child map.
1301 */
1302 if (map->parent && (map->parent != parent_map)) parent_map = map->parent;
1303
1304 parent = tmpl_attr_tail_da(parent_map->lhs);
1305
1306 /*
1307 * Anal-retentive checks.
1308 */
1309 if (DEBUG_ENABLED3) {
1310 if (tmpl_is_attr(map->lhs) && (map->lhs->name[0] != '&')) {
1311 cf_log_warn(cp, "Please change attribute reference to '&%s %s ...'",
1312 map->lhs->name, fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
1313 }
1314
1315 if (tmpl_is_attr(map->rhs) && (map->rhs->name[0] != '&')) {
1316 cf_log_warn(cp, "Please change attribute reference to '... %s &%s'",
1317 fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"), map->rhs->name);
1318 }
1319 }
1320
1321 switch (map->lhs->type) {
1322 case TMPL_TYPE_ATTR:
1323 da = tmpl_attr_tail_da(map->lhs);
1324 if (!da->flags.internal && parent && (parent->type != FR_TYPE_GROUP) &&
1325 (da->parent != parent)) {
1326 /* FIXME - Broken check, doesn't work for key attributes */
1327 cf_log_err(cp, "Invalid location for %s - it is not a child of %s",
1328 da->name, parent->name);
1329 return 0;
1330 }
1331 break;
1332
1334 case TMPL_TYPE_XLAT:
1335 break;
1336
1337 default:
1338 cf_log_err(map->ci, "Left side of map must be an attribute "
1339 "or an xlat (that expands to an attribute), not a %s",
1340 tmpl_type_to_str(map->lhs->type));
1341 return -1;
1342 }
1343
1344 fr_assert(map->rhs);
1345
1346 switch (map->rhs->type) {
1349 case TMPL_TYPE_XLAT:
1350 case TMPL_TYPE_DATA:
1351 case TMPL_TYPE_ATTR:
1352 case TMPL_TYPE_EXEC:
1353 break;
1354
1355 default:
1356 cf_log_err(map->ci, "Right side of map must be an attribute, literal, xlat or exec, got type %s",
1357 tmpl_type_to_str(map->rhs->type));
1358 return -1;
1359 }
1360
1361 return 0;
1362}
1363
1364/** Compile one edit section.
1365 */
1367{
1368 unlang_edit_t *edit;
1369 unlang_t *c, *out = UNLANG_IGNORE;
1370 map_t *map;
1371 char const *name;
1372 fr_token_t op;
1373 ssize_t slen;
1374 fr_dict_attr_t const *parent_da;
1375 int num;
1376
1377 tmpl_rules_t t_rules;
1378
1379 name = cf_section_name2(cs);
1380 if (name) {
1381 cf_log_err(cs, "Unexpected name2 '%s' for editing list %s ", name, cf_section_name1(cs));
1382 return NULL;
1383 }
1384
1385 op = cf_section_name2_quote(cs);
1386 if ((op == T_INVALID) || !fr_list_assignment_op[op]) {
1387 cf_log_err(cs, "Invalid operator '%s' for editing list %s.", fr_tokens[op], cf_section_name1(cs));
1388 return NULL;
1389 }
1390
1391 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
1392 cf_log_err(cs, "Invalid operator \"%s\".",
1393 fr_table_str_by_value(fr_tokens_table, op, "<INVALID>"));
1394 return NULL;
1395 }
1396
1397 /*
1398 * We allow unknown attributes here.
1399 */
1400 t_rules = *(unlang_ctx->rules);
1401 t_rules.attr.allow_unknown = true;
1402 RULES_VERIFY(&t_rules);
1403
1404 edit = talloc_zero(parent, unlang_edit_t);
1405 if (!edit) return NULL;
1406
1407 c = out = unlang_edit_to_generic(edit);
1408 c->parent = parent;
1409 c->next = NULL;
1410 c->name = cf_section_name1(cs);
1411 c->debug_name = c->name;
1413 c->ci = CF_TO_ITEM(cs);
1414
1415 map_list_init(&edit->maps);
1416
1418
1419 /*
1420 * Allocate the map and initialize it.
1421 */
1422 MEM(map = talloc_zero(parent, map_t));
1423 map->op = op;
1424 map->ci = cf_section_to_item(cs);
1425 map_list_init(&map->child);
1426
1427 name = cf_section_name1(cs);
1428
1429 slen = tmpl_afrom_attr_str(map, NULL, &map->lhs, name, &t_rules);
1430 if (slen <= 0) {
1431 cf_log_err(cs, "Failed parsing list reference %s - %s", name, fr_strerror());
1432 fail:
1433 talloc_free(edit);
1434 return NULL;
1435 }
1436
1437 /*
1438 * Can't assign to [*] or [#]
1439 */
1440 num = tmpl_attr_tail_num(map->lhs);
1441 if ((num == NUM_ALL) || (num == NUM_COUNT)) {
1442 cf_log_err(cs, "Invalid array reference in %s", name);
1443 goto fail;
1444 }
1445
1446 /*
1447 * If the DA isn't structural, then it can't have children.
1448 */
1449 parent_da = tmpl_attr_tail_da(map->lhs);
1450 if (fr_type_is_structural(parent_da->type)) {
1451 map_t *child;
1452
1453 /*
1454 * Don't update namespace for &reply += { ... }
1455 *
1456 * Do update namespace for &reply.foo += { ... }
1457 *
1458 * Don't update if the LHS is an internal group.
1459 */
1460 if ((tmpl_attr_num_elements(map->lhs) > 1) && (t_rules.attr.list_def != parent_da) &&
1461 !((parent_da->type == FR_TYPE_GROUP) && parent_da->flags.internal)) {
1462 t_rules.attr.namespace = parent_da;
1463 }
1464
1465 if (map_afrom_cs_edit(map, &map->child, cs, &t_rules, &t_rules, unlang_fixup_edit, map, 256) < 0) {
1466 goto fail;
1467 }
1468
1469 /*
1470 * As a set of fixups... we can't do array references in -=
1471 */
1472 if (map->op == T_OP_SUB_EQ) {
1473 for (child = map_list_head(&map->child); child != NULL; child = map_list_next(&map->child, child)) {
1474 if (!tmpl_is_attr(child->lhs)) continue;
1475
1476 if (tmpl_attr_tail_num(child->lhs) != NUM_UNSPEC) {
1477 cf_log_err(child->ci, "Cannot use array references and values when deleting from a list");
1478 goto fail;
1479 }
1480
1481 /*
1482 * The edit code doesn't do this correctly, so we just forbid it.
1483 */
1484 if ((tmpl_attr_num_elements(child->lhs) - tmpl_attr_num_elements(map->lhs)) > 1) {
1485 cf_log_err(child->ci, "List deletion must operate directly on the final child");
1486 goto fail;
1487 }
1488
1489 /*
1490 * We don't do list comparisons either.
1491 */
1492 if (fr_type_is_structural(tmpl_attr_tail_da(child->lhs)->type)) {
1493 cf_log_err(child->ci, "List deletion cannot operate on lists");
1494 goto fail;
1495 }
1496 }
1497 }
1498 } else {
1499 /*
1500 * &foo := { a, b, c }
1501 */
1502 if (map_list_afrom_cs(map, &map->child, cs, &t_rules, NULL, NULL, 256) < 0) {
1503 goto fail;
1504 }
1505
1506 if ((map->op != T_OP_SET) && !map_list_num_elements(&map->child)) {
1507 cf_log_err(cs, "Cannot use operator '%s' for assigning empty list to '%s' data type.",
1508 fr_tokens[map->op], fr_type_to_str(parent_da->type));
1509 goto fail;
1510 }
1511 }
1512 /*
1513 * Do basic sanity checks and resolving.
1514 */
1515 if (!pass2_fixup_map(map, unlang_ctx->rules, NULL)) goto fail;
1516
1517 /*
1518 * Check operators, and ensure that the RHS has been
1519 * resolved.
1520 */
1521// if (unlang_fixup_update(map, NULL) < 0) goto fail;
1522
1523 map_list_insert_tail(&edit->maps, map);
1524
1525 return out;
1526}
1527
1528/** Compile one edit pair
1529 *
1530 */
1532{
1533 unlang_edit_t *edit;
1534 unlang_t *c = NULL, *out = UNLANG_IGNORE;
1535 map_t *map;
1536 int num;
1537
1538 tmpl_rules_t t_rules;
1539 fr_token_t op;
1540
1541 /*
1542 * We allow unknown attributes here.
1543 */
1544 t_rules = *(unlang_ctx->rules);
1545 t_rules.attr.allow_unknown = true;
1546 RULES_VERIFY(&t_rules);
1547
1548 edit = talloc_zero(parent, unlang_edit_t);
1549 if (!edit) return NULL;
1550
1551 c = out = unlang_edit_to_generic(edit);
1552 c->parent = parent;
1553 c->next = NULL;
1554 c->name = cf_pair_attr(cp);
1555 c->debug_name = c->name;
1557 c->ci = CF_TO_ITEM(cp);
1558
1559 map_list_init(&edit->maps);
1560
1562
1563 op = cf_pair_operator(cp);
1564 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
1565 cf_log_err(cp, "Invalid operator \"%s\".",
1566 fr_table_str_by_value(fr_tokens_table, op, "<INVALID>"));
1567 return NULL;
1568 }
1569
1570 /*
1571 * Convert this particular map.
1572 */
1573 if (map_afrom_cp(edit, &map, map_list_tail(&edit->maps), cp, &t_rules, NULL, true) < 0) {
1574 fail:
1575 talloc_free(edit);
1576 return NULL;
1577 }
1578
1579 /*
1580 * @todo - we still want to do fixups on the RHS?
1581 */
1582 if (tmpl_is_attr(map->lhs)) {
1583 /*
1584 * Can't assign to [*] or [#]
1585 */
1586 num = tmpl_attr_tail_num(map->lhs);
1587 if ((num == NUM_ALL) || (num == NUM_COUNT)) {
1588 cf_log_err(cp, "Invalid array reference in %s", map->lhs->name);
1589 goto fail;
1590 }
1591
1592 if ((map->op == T_OP_SUB_EQ) && fr_type_is_structural(tmpl_attr_tail_da(map->lhs)->type) &&
1593 tmpl_is_attr(map->rhs) && tmpl_attr_tail_da(map->rhs)->flags.local) {
1594 cf_log_err(cp, "Cannot delete local variable %s", map->rhs->name);
1595 goto fail;
1596 }
1597 }
1598
1599 /*
1600 * Do basic sanity checks and resolving.
1601 */
1602 if (!pass2_fixup_map(map, unlang_ctx->rules, NULL)) goto fail;
1603
1604 /*
1605 * Check operators, and ensure that the RHS has been
1606 * resolved.
1607 */
1608 if (unlang_fixup_update(map, c) < 0) goto fail;
1609
1610 map_list_insert_tail(&edit->maps, map);
1611
1612 return out;
1613}
1614
1615static int define_local_variable(CONF_ITEM *ci, unlang_variable_t *var, tmpl_rules_t *t_rules, fr_type_t type, char const *name,
1616 fr_dict_attr_t const *ref);
1617
1618
1619/** Compile a variable definition.
1620 *
1621 * Definitions which are adjacent to one another are automatically merged
1622 * into one larger variable definition.
1623 */
1625{
1626 unlang_variable_t *var;
1628 char const *attr, *value;
1629 unlang_group_t *group;
1630
1632
1633 /*
1634 * Enforce locations for local variables.
1635 */
1636 switch (parent->type) {
1637 case UNLANG_TYPE_CASE:
1638 case UNLANG_TYPE_ELSE:
1639 case UNLANG_TYPE_ELSIF:
1641 case UNLANG_TYPE_GROUP:
1642 case UNLANG_TYPE_IF:
1644 case UNLANG_TYPE_LIMIT:
1645 case UNLANG_TYPE_POLICY:
1649 break;
1650
1651 default:
1652 cf_log_err(cp, "Local variables cannot be used here");
1653 return -1;
1654 }
1655
1656 /*
1657 * The variables exist in the parent block.
1658 */
1660 if (group->variables) {
1661 var = group->variables;
1662
1663 } else {
1664 group->variables = var = talloc_zero(parent, unlang_variable_t);
1665 if (!var) return -1;
1666
1667 var->dict = fr_dict_protocol_alloc(unlang_ctx->rules->attr.dict_def);
1668 if (!var->dict) {
1669 talloc_free(var);
1670 return -1;
1671 }
1672 var->root = fr_dict_root(var->dict);
1673
1674 var->max_attr = 1;
1675
1676 /*
1677 * Initialize the new rules, and point them to the parent rules.
1678 *
1679 * Then replace the parse rules with our rules, and our dictionary.
1680 */
1681 *t_rules = *unlang_ctx->rules;
1682 t_rules->parent = unlang_ctx->rules;
1683
1684 t_rules->attr.dict_def = var->dict;
1685 t_rules->attr.namespace = NULL;
1686
1687 unlang_ctx->rules = t_rules;
1688 }
1689
1690 attr = cf_pair_attr(cp); /* data type */
1691 value = cf_pair_value(cp); /* variable name */
1692
1694 if (type == FR_TYPE_NULL) {
1696 cf_log_err(cp, "Invalid data type '%s'", attr);
1697 return -1;
1698 }
1699
1700 /*
1701 * Leaf and group are OK. TLV, Vendor, Struct, VSA, etc. are not.
1702 */
1703 if (!(fr_type_is_leaf(type) || (type == FR_TYPE_GROUP))) goto invalid_type;
1704
1705 return define_local_variable(cf_pair_to_item(cp), var, t_rules, type, value, NULL);
1706}
1707
1708/*
1709 * Compile action && rcode for later use.
1710 */
1712{
1713 int action;
1714 char const *attr, *value;
1715
1716 attr = cf_pair_attr(cp);
1717 value = cf_pair_value(cp);
1718 if (!value) return 0;
1719
1720 if (!strcasecmp(value, "return"))
1721 action = MOD_ACTION_RETURN;
1722
1723 else if (!strcasecmp(value, "break"))
1724 action = MOD_ACTION_RETURN;
1725
1726 else if (!strcasecmp(value, "reject"))
1727 action = MOD_ACTION_REJECT;
1728
1729 else if (!strcasecmp(value, "retry"))
1730 action = MOD_ACTION_RETRY;
1731
1732 else if (strspn(value, "0123456789")==strlen(value)) {
1733 action = atoi(value);
1734
1735 if (!action || (action > MOD_PRIORITY_MAX)) {
1736 cf_log_err(cp, "Priorities MUST be between 1 and 64.");
1737 return 0;
1738 }
1739
1740 } else {
1741 cf_log_err(cp, "Unknown action '%s'.\n",
1742 value);
1743 return 0;
1744 }
1745
1746 if (strcasecmp(attr, "default") != 0) {
1747 int rcode;
1748
1749 rcode = fr_table_value_by_str(mod_rcode_table, attr, -1);
1750 if (rcode < 0) {
1751 cf_log_err(cp,
1752 "Unknown module rcode '%s'.",
1753 attr);
1754 return 0;
1755 }
1756 actions->actions[rcode] = action;
1757
1758 } else { /* set all unset values to the default */
1759 int i;
1760
1761 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1762 if (!actions->actions[i]) actions->actions[i] = action;
1763 }
1764 }
1765
1766 return 1;
1767}
1768
1770{
1771 CONF_ITEM *csi;
1772 CONF_SECTION *cs;
1773
1774 cs = cf_item_to_section(ci);
1775 for (csi=cf_item_next(cs, NULL);
1776 csi != NULL;
1777 csi=cf_item_next(cs, csi)) {
1778 CONF_PAIR *cp;
1779 char const *name, *value;
1780
1781 if (cf_item_is_section(csi)) {
1782 cf_log_err(csi, "Invalid subsection in 'retry' configuration.");
1783 return false;
1784 }
1785
1786 if (!cf_item_is_pair(csi)) continue;
1787
1788 cp = cf_item_to_pair(csi);
1789 name = cf_pair_attr(cp);
1790 value = cf_pair_value(cp);
1791
1792 if (!value) {
1793 cf_log_err(csi, "Retry configuration must specify a value");
1794 return false;
1795 }
1796
1797 /*
1798 * We don't use conf_parser_t here for various
1799 * magical reasons.
1800 */
1801 if (strcmp(name, "initial_rtx_time") == 0) {
1802 if (fr_time_delta_from_str(&actions->retry.irt, value, strlen(value), FR_TIME_RES_SEC) < 0) {
1803 error:
1804 cf_log_err(csi, "Failed parsing '%s = %s' - %s",
1805 name, value, fr_strerror());
1806 return false;
1807 }
1808
1809 } else if (strcmp(name, "max_rtx_time") == 0) {
1810 if (fr_time_delta_from_str(&actions->retry.mrt, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
1811
1812 if (!fr_time_delta_ispos(actions->retry.mrt)) {
1813 cf_log_err(csi, "Invalid value for 'max_rtx_time = %s' - value must be positive",
1814 value);
1815 return false;
1816 }
1817
1818 } else if (strcmp(name, "max_rtx_count") == 0) {
1819 unsigned long v = strtoul(value, 0, 0);
1820
1821 if (v > 65536) {
1822 cf_log_err(csi, "Invalid value for 'max_rtx_count = %s' - value must be between 0 and 65536",
1823 value);
1824 return false;
1825 }
1826
1827 actions->retry.mrc = v;
1828
1829 } else if (strcmp(name, "max_rtx_duration") == 0) {
1830 if (fr_time_delta_from_str(&actions->retry.mrd, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
1831
1832 if (!fr_time_delta_ispos(actions->retry.mrd)) {
1833 cf_log_err(csi, "Invalid value for 'max_rtx_duration = %s' - value must be positive",
1834 value);
1835 return false;
1836 }
1837
1838 } else {
1839 cf_log_err(csi, "Invalid item '%s' in 'retry' configuration.", name);
1840 return false;
1841 }
1842 }
1843
1844 return true;
1845}
1846
1847bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *action_cs, bool module_retry)
1848{
1849 int i;
1850 bool disallow_retry_action = false;
1851 CONF_ITEM *csi;
1852 CONF_SECTION *cs;
1853
1854 /*
1855 * Over-ride the default return codes of the module.
1856 */
1857 cs = cf_item_to_section(cf_section_to_item(action_cs));
1858 for (csi=cf_item_next(cs, NULL);
1859 csi != NULL;
1860 csi=cf_item_next(cs, csi)) {
1861 char const *name;
1862 CONF_PAIR *cp;
1863
1864 if (cf_item_is_section(csi)) {
1865 CONF_SECTION *subcs = cf_item_to_section(csi);
1866
1867 name = cf_section_name1(subcs);
1868
1869 /*
1870 * Look for a "retry" section.
1871 */
1872 if (name && (strcmp(name, "retry") == 0) && !cf_section_name2(subcs)) {
1873 if (!compile_retry_section(actions, csi)) return false;
1874 continue;
1875 }
1876
1877 cf_log_err(csi, "Invalid subsection. Expected 'action = value'");
1878 return false;
1879 }
1880
1881 if (!cf_item_is_pair(csi)) continue;
1882
1883 cp = cf_item_to_pair(csi);
1884
1885 /*
1886 * Allow 'retry = path.to.retry.config'
1887 */
1888 name = cf_pair_attr(cp);
1889 if (strcmp(name, "retry") == 0) {
1890 CONF_ITEM *subci;
1891 char const *value = cf_pair_value(cp);
1892
1893 subci = cf_reference_item(cs, cf_root(cf_section_to_item(action_cs)), value);
1894 if (!subci) {
1895 cf_log_err(csi, "Unknown reference '%s'", value ? value : "<INVALID>");
1896 return false;
1897 }
1898
1899 if (!compile_retry_section(actions, subci)) return false;
1900 continue;
1901 }
1902
1903 if (!compile_action_pair(actions, cp)) {
1904 return false;
1905 }
1906 }
1907
1908 if (module_retry) {
1909 if (!fr_time_delta_ispos(actions->retry.irt)) {
1910 cf_log_err(csi, "initial_rtx_time MUST be non-zero for modules which support retries.");
1911 return false;
1912 }
1913 } else {
1914 if (fr_time_delta_ispos(actions->retry.irt)) {
1915 cf_log_err(csi, "initial_rtx_time MUST be zero, as only max_rtx_count and max_rtx_duration are used.");
1916 return false;
1917 }
1918
1919 if (!actions->retry.mrc && !fr_time_delta_ispos(actions->retry.mrd)) {
1920 disallow_retry_action = true;
1921 }
1922 }
1923
1924 /*
1925 * Sanity check that "fail = retry", we actually have a
1926 * retry section.
1927 */
1928 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1929 if (actions->actions[i] != MOD_ACTION_RETRY) continue;
1930
1931 if (module_retry) {
1932 cf_log_err(csi, "Cannot use a '%s = retry' action for a module which has its own retries",
1933 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1934 return false;
1935 }
1936
1937 if (disallow_retry_action) {
1938 cf_log_err(csi, "max_rtx_count and max_rtx_duration cannot both be zero when using '%s = retry'",
1939 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1940 return false;
1941 }
1942
1943 if (!fr_time_delta_ispos(actions->retry.irt) &&
1944 !actions->retry.mrc &&
1945 !fr_time_delta_ispos(actions->retry.mrd)) {
1946 cf_log_err(csi, "Cannot use a '%s = retry' action without a 'retry { ... }' section.",
1947 fr_table_str_by_value(mod_rcode_table, i, "<INVALID>"));
1948 return false;
1949 }
1950 }
1951
1952 return true;
1953}
1954
1956{
1957 unlang_group_t *g;
1958 unlang_t *c;
1959
1960 /*
1961 * If we're compiling an empty section, then the
1962 * *interpreter* type is GROUP, even if the *debug names*
1963 * are something else.
1964 */
1965 g = group_allocate(parent, cs, ext);
1966 if (!g) return NULL;
1967
1969 if (!cs) {
1970 c->name = unlang_ops[ext->type].name;
1971 c->debug_name = c->name;
1972
1973 } else {
1974 char const *name2;
1975
1976 name2 = cf_section_name2(cs);
1977 if (!name2) {
1978 c->name = cf_section_name1(cs);
1979 c->debug_name = c->name;
1980 } else {
1981 c->name = name2;
1982 c->debug_name = talloc_typed_asprintf(c, "%s %s", cf_section_name1(cs), name2);
1983 }
1984 }
1985
1987 return c;
1988}
1989
1990
1992
1993/*
1994 * compile 'actions { ... }' inside of another group.
1995 */
1997{
1998 CONF_ITEM *ci, *next;
1999
2000 ci = cf_section_to_item(subcs);
2001
2002 next = cf_item_next(cs, ci);
2003 if (next && (cf_item_is_pair(next) || cf_item_is_section(next))) {
2004 cf_log_err(ci, "'actions' MUST be the last block in a section");
2005 return false;
2006 }
2007
2008 if (cf_section_name2(subcs) != NULL) {
2009 cf_log_err(ci, "Invalid name for 'actions' section");
2010 return false;
2011 }
2012
2013 /*
2014 * Over-riding the actions can be done in certain limited
2015 * situations. In other situations (e.g. "redundant",
2016 * "load-balance"), it doesn't make sense.
2017 *
2018 * Note that this limitation also applies to "retry"
2019 * timers. We can do retries of a "group". We cannot do
2020 * retries of "load-balance", as the "load-balance"
2021 * section already takes care of redundancy.
2022 *
2023 * We may need to loosen that limitation in the future.
2024 */
2025 switch (c->type) {
2026 case UNLANG_TYPE_CASE:
2027 case UNLANG_TYPE_IF:
2028 case UNLANG_TYPE_ELSE:
2029 case UNLANG_TYPE_ELSIF:
2031 case UNLANG_TYPE_GROUP:
2032 case UNLANG_TYPE_LIMIT:
2033 case UNLANG_TYPE_SWITCH:
2036 break;
2037
2038 default:
2039 cf_log_err(ci, "'actions' MUST NOT be in a '%s' block", unlang_ops[c->type].name);
2040 return false;
2041 }
2042
2043 return unlang_compile_actions(&c->actions, subcs, false);
2044}
2045
2046
2047static unlang_t *compile_children(unlang_group_t *g, unlang_compile_t *unlang_ctx_in, bool set_action_defaults)
2048{
2049 CONF_ITEM *ci = NULL;
2050 unlang_t *c, *single;
2051 bool was_if = false;
2052 char const *skip_else = NULL;
2054 unlang_compile_t unlang_ctx2;
2055 tmpl_rules_t t_rules;
2056
2058
2059 /*
2060 * Create our own compilation context which can be edited
2061 * by a variable definition.
2062 */
2063 compile_copy_context(&unlang_ctx2, unlang_ctx_in);
2064 unlang_ctx = &unlang_ctx2;
2065 t_rules = *unlang_ctx_in->rules;
2066
2067 /*
2068 * Loop over the children of this group.
2069 */
2070 while ((ci = cf_item_next(g->cs, ci))) {
2071 if (cf_item_is_data(ci)) continue;
2072
2073 /*
2074 * Sections are keywords, or references to
2075 * modules with updated return codes.
2076 */
2077 if (cf_item_is_section(ci)) {
2078 char const *name = NULL;
2079 CONF_SECTION *subcs = cf_item_to_section(ci);
2080
2081 /*
2082 * Skip precompiled blocks. This is
2083 * mainly for policies.
2084 */
2085 if (cf_data_find(subcs, unlang_group_t, NULL)) continue;
2086
2087 /*
2088 * "actions" apply to the current group.
2089 * It's not a subgroup.
2090 */
2091 name = cf_section_name1(subcs);
2092
2093 /*
2094 * In-line attribute editing. Nothing else in the parse has list assignments, so this must be it.
2095 */
2097 single = compile_edit_section(c, unlang_ctx, subcs);
2098 if (!single) {
2099 talloc_free(c);
2100 return NULL;
2101 }
2102
2103 goto add_child;
2104 }
2105
2106 if (strcmp(name, "actions") == 0) {
2107 if (!compile_action_subsection(c, g->cs, subcs)) {
2108 talloc_free(c);
2109 return NULL;
2110 }
2111
2112 continue;
2113 }
2114
2115 /*
2116 * Special checks for "else" and "elsif".
2117 */
2118 if ((strcmp(name, "else") == 0) || (strcmp(name, "elsif") == 0)) {
2119 /*
2120 * We ran into one without a preceding "if" or "elsif".
2121 * That's not allowed.
2122 */
2123 if (!was_if) {
2124 cf_log_err(ci, "Invalid location for '%s'. There is no preceding "
2125 "'if' or 'elsif' statement", name);
2126 talloc_free(c);
2127 return NULL;
2128 }
2129
2130 /*
2131 * There was a previous "if" or "elsif" which was always taken.
2132 * So we skip this "elsif" or "else".
2133 */
2134 if (skip_else) {
2135 void *ptr;
2136
2137 /*
2138 * And manually free this.
2139 */
2140 ptr = cf_data_remove(subcs, xlat_exp_head_t, NULL);
2141 talloc_free(ptr);
2142
2144
2145 cf_log_debug_prefix(ci, "Skipping contents of '%s' due to previous "
2146 "'%s' being always being taken.",
2147 name, skip_else);
2148 continue;
2149 }
2150 }
2151
2152 /*
2153 * Otherwise it's a real keyword.
2154 */
2155 single = compile_item(c, unlang_ctx, ci);
2156 if (!single) {
2157 cf_log_err(ci, "Failed to parse \"%s\" subsection", cf_section_name1(subcs));
2158 talloc_free(c);
2159 return NULL;
2160 }
2161
2162 goto add_child;
2163
2164 } else if (cf_item_is_pair(ci)) {
2165 CONF_PAIR *cp = cf_item_to_pair(ci);
2166
2167 /*
2168 * Variable definition.
2169 */
2170 if (cf_pair_operator(cp) == T_OP_CMP_TRUE) {
2171 if (compile_variable(c, unlang_ctx, cp, &t_rules) < 0) {
2172 talloc_free(c);
2173 return NULL;
2174 }
2175
2176 single = UNLANG_IGNORE;
2177 goto add_child;
2178 }
2179
2180 if (!cf_pair_value(cp)) {
2181 single = compile_item(c, unlang_ctx, ci);
2182 if (!single) {
2183 cf_log_err(ci, "Invalid keyword \"%s\".", cf_pair_attr(cp));
2184 talloc_free(c);
2185 return NULL;
2186 }
2187
2188 goto add_child;
2189 }
2190
2191 /*
2192 * What remains MUST be an edit pair. At this point, the state of the compiler
2193 * tells us what it is, and we don't really care if there's a leading '&'.
2194 */
2195 single = compile_edit_pair(c, unlang_ctx, cp);
2196 if (!single) {
2197 talloc_free(c);
2198 return NULL;
2199 }
2200
2201 goto add_child;
2202 } else {
2203 cf_log_err(ci, "Asked to compile unknown conf type");
2204 talloc_free(c);
2205 return NULL;
2206 }
2207
2208 add_child:
2209 if (single == UNLANG_IGNORE) continue;
2210
2211 /*
2212 * Do optimizations for "if" and "elsif"
2213 * conditions.
2214 */
2215 switch (single->type) {
2216 case UNLANG_TYPE_ELSIF:
2217 case UNLANG_TYPE_IF:
2218 was_if = true;
2219
2220 {
2221 unlang_group_t *f;
2222 unlang_cond_t *gext;
2223
2224 /*
2225 * Skip else, and/or omit things which will never be run.
2226 */
2227 f = unlang_generic_to_group(single);
2228 gext = unlang_group_to_cond(f);
2229
2230 if (gext->is_truthy) {
2231 if (gext->value) {
2232 skip_else = single->debug_name;
2233 } else {
2234 /*
2235 * The condition never
2236 * matches, so we can
2237 * avoid putting it into
2238 * the unlang tree.
2239 */
2240 talloc_free(single);
2241 continue;
2242 }
2243 }
2244 }
2245 break;
2246
2247 default:
2248 was_if = false;
2249 skip_else = NULL;
2250 break;
2251 }
2252
2253 /*
2254 * unlang_group_t is grown by adding a unlang_t to the end
2255 */
2256 fr_assert(g == talloc_parent(single));
2258 fr_assert(!single->next);
2259
2260 *g->tail = single;
2261 g->tail = &single->next;
2262 g->num_children++;
2263
2264 /*
2265 * If it's not possible to execute statement
2266 * after the current one, then just stop
2267 * processing the children.
2268 */
2269 if (g->self.closed) {
2270 cf_log_warn(ci, "Skipping remaining instructions due to '%s'",
2271 single->name);
2272 break;
2273 }
2274 }
2275
2276 /*
2277 * Set the default actions, if they haven't already been
2278 * set by an "actions" section above.
2279 */
2280 if (set_action_defaults) compile_action_defaults(c, unlang_ctx);
2281
2282 return c;
2283}
2284
2285
2286/*
2287 * Generic "compile a section with more unlang inside of it".
2288 */
2290 unlang_ext_t const *ext)
2291{
2292 unlang_group_t *g;
2293 unlang_t *c;
2294 char const *name1, *name2;
2295
2296 fr_assert(unlang_ctx->rules != NULL);
2297 fr_assert(unlang_ctx->rules->attr.list_def);
2298
2299 /*
2300 * We always create a group, even if the section is empty.
2301 */
2302 g = group_allocate(parent, cs, ext);
2303 if (!g) return NULL;
2304
2306
2307 /*
2308 * Remember the name for printing, etc.
2309 */
2310 name1 = cf_section_name1(cs);
2311 name2 = cf_section_name2(cs);
2312 c->name = name1;
2313
2314 /*
2315 * Make sure to tell the user that we're running a
2316 * policy, and not anything else.
2317 */
2318 if (ext->type == UNLANG_TYPE_POLICY) {
2319 MEM(c->debug_name = talloc_typed_asprintf(c, "policy %s", name1));
2320
2321 } else if (!name2) {
2322 c->debug_name = c->name;
2323
2324 } else {
2325 MEM(c->debug_name = talloc_typed_asprintf(c, "%s %s", name1, name2));
2326 }
2327
2328 return compile_children(g, unlang_ctx, true);
2329}
2330
2331
2333{
2334 static unlang_ext_t const group = {
2336 .len = sizeof(unlang_group_t),
2337 .type_name = "unlang_group_t",
2338 };
2339
2340 if (!cf_item_next(ci, NULL)) return UNLANG_IGNORE;
2341
2343}
2344
2346 { L("case"), 1 },
2347 { L("else"), 1 },
2348 { L("elsif"), 1 },
2349 { L("foreach"), 1 },
2350 { L("group"), 1 },
2351 { L("if"), 1 },
2352 { L("limit"), 1 },
2353 { L("load-balance"), 1 },
2354 { L("redundant"), 1 },
2355 { L("redundant-load-balance"), 1 },
2356 { L("switch"), 1 },
2357 { L("timeout"), 1 },
2358 { L("transaction"), 1 },
2359};
2361
2362/** Limit the operations which can appear in a transaction.
2363 */
2365{
2366 CONF_ITEM *ci = NULL;
2367
2368 while ((ci = cf_item_next(cs, ci)) != NULL) {
2369 char const *name;
2370
2371 if (cf_item_is_section(ci)) {
2372 CONF_SECTION *subcs;
2373
2374 subcs = cf_item_to_section(ci);
2375 name = cf_section_name1(subcs);
2376
2377 if (strcmp(name, "actions") == 0) continue;
2378
2379 /*
2380 * Definitely an attribute editing thing.
2381 */
2382 if (*name == '&') continue;
2383
2385
2387 cf_log_err(ci, "Invalid keyword in 'transaction'");
2388 return false;
2389 }
2390
2391 if (!transaction_ok(subcs)) return false;
2392
2393 continue;
2394
2395 } else if (cf_item_is_pair(ci)) {
2396 CONF_PAIR *cp;
2397
2398 cp = cf_item_to_pair(ci);
2399 name = cf_pair_attr(cp);
2400
2401 /*
2402 * If there's a value then it's not a module call.
2403 */
2404 if (cf_pair_value(cp)) continue;
2405
2406 if (*name == '&') continue;
2407
2408 /*
2409 * Allow rcodes via the "always" module.
2410 */
2412 continue;
2413 }
2414
2415 cf_log_err(ci, "Invalid module reference in 'transaction'");
2416 return false;
2417
2418 } else {
2419 continue;
2420 }
2421 }
2422
2423 return true;
2424}
2425
2427{
2429 unlang_group_t *g;
2430 unlang_t *c;
2431 unlang_compile_t unlang_ctx2;
2432
2433 static unlang_ext_t const transaction = {
2435 .len = sizeof(unlang_transaction_t),
2436 .type_name = "unlang_transaction_t",
2437 };
2438
2439 if (cf_section_name2(cs) != NULL) {
2440 cf_log_err(cs, "Unexpected argument to 'transaction' section");
2441 return NULL;
2442 }
2443
2444 /*
2445 * The transaction is empty, ignore it.
2446 */
2447 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
2448
2449 if (!transaction_ok(cs)) return NULL;
2450
2451 /*
2452 * Any failure is return, not continue.
2453 */
2454 compile_copy_context(&unlang_ctx2, unlang_ctx);
2455
2460
2461 g = group_allocate(parent, cs, &transaction);
2462 if (!g) return NULL;
2463
2465 c->debug_name = c->name = cf_section_name1(cs);
2466
2467 if (!compile_children(g, &unlang_ctx2, false)) return NULL;
2468
2469 /*
2470 * The default for a failed transaction is to continue on
2471 * failure.
2472 */
2476
2478
2479 return c;
2480}
2481
2483{
2485 unlang_group_t *g;
2486 unlang_t *c;
2487 CONF_SECTION *next;
2488
2489 static unlang_ext_t const ext = {
2491 .len = sizeof(unlang_try_t),
2492 .type_name = "unlang_try_t",
2493 };
2494
2495 /*
2496 * The transaction is empty, ignore it.
2497 */
2498 if (!cf_item_next(cs, NULL)) {
2499 cf_log_err(cs, "'try' sections cannot be empty");
2500 return NULL;
2501 }
2502
2503 if (cf_section_name2(cs) != NULL) {
2504 cf_log_err(cs, "Unexpected argument to 'try' section");
2505 return NULL;
2506 }
2507
2509 if (!next || (strcmp(cf_section_name1(next), "catch") != 0)) {
2510 cf_log_err(cs, "'try' sections must be followed by a 'catch'");
2511 return NULL;
2512 }
2513
2514 g = group_allocate(parent, cs, &ext);
2515 if (!g) return NULL;
2516
2518 c->debug_name = c->name = cf_section_name1(cs);
2519
2520 return compile_children(g, unlang_ctx, true);
2521}
2522
2523static int catch_argv(CONF_SECTION *cs, unlang_catch_t *ca, char const *name)
2524{
2525 int rcode;
2526
2528 if (rcode < 0) {
2529 cf_log_err(cs, "Unknown rcode '%s'.", name);
2530 return -1;
2531 }
2532
2533 if (ca->catching[rcode]) {
2534 cf_log_err(cs, "Duplicate rcode '%s'.", name);
2535 return -1;
2536 }
2537
2538 ca->catching[rcode] = true;
2539
2540 return 0;
2541}
2542
2544{
2546 unlang_group_t *g;
2547 unlang_t *c;
2548 unlang_catch_t *ca;
2549
2550 static unlang_ext_t const ext = {
2552 .len = sizeof(unlang_catch_t),
2553 .type_name = "unlang_catch_t",
2554 };
2555
2556 g = group_allocate(parent, cs, &ext);
2557 if (!g) return NULL;
2558
2560 c->debug_name = c->name = cf_section_name1(cs);
2561
2562 ca = unlang_group_to_catch(g);
2563
2564 /*
2565 * No arg2: catch all errors
2566 */
2567 if (!cf_section_name2(cs)) {
2568 ca->catching[RLM_MODULE_REJECT] = true;
2569 ca->catching[RLM_MODULE_FAIL] = true;
2570 ca->catching[RLM_MODULE_INVALID] = true;
2571 ca->catching[RLM_MODULE_DISALLOW] = true;
2572
2573 } else {
2574 int i;
2575 char const *name = cf_section_name2(cs);
2576
2577 if (catch_argv(cs, ca, name) < 0) {
2578 talloc_free(c);
2579 return NULL;
2580 }
2581
2582 for (i = 0; (name = cf_section_argv(cs, i)) != NULL; i++) {
2583 if (catch_argv(cs, ca, name) < 0) {
2584 talloc_free(c);
2585 return NULL;
2586 }
2587 }
2588 }
2589
2590 /*
2591 * @todo - Else parse and limit the things we catch
2592 */
2593
2594 return compile_children(g, unlang_ctx, true);
2595}
2596
2597
2598static int8_t case_cmp(void const *one, void const *two)
2599{
2600 unlang_case_t const *a = (unlang_case_t const *) one; /* may not be talloc'd! See switch.c */
2601 unlang_case_t const *b = (unlang_case_t const *) two; /* may not be talloc'd! */
2602
2603 return fr_value_box_cmp(tmpl_value(a->vpt), tmpl_value(b->vpt));
2604}
2605
2606static uint32_t case_hash(void const *data)
2607{
2608 unlang_case_t const *a = (unlang_case_t const *) data; /* may not be talloc'd! */
2609
2610 return fr_value_box_hash(tmpl_value(a->vpt));
2611}
2612
2613static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
2614{
2615 unlang_case_t const *a = (unlang_case_t const *) data; /* may not be talloc'd! */
2616
2617 return fr_value_box_to_key(out, outlen, tmpl_value(a->vpt));
2618}
2619
2621
2623{
2625 CONF_ITEM *subci;
2626 fr_token_t token;
2627 char const *name1, *name2;
2628
2629 unlang_group_t *g;
2630 unlang_switch_t *gext;
2631
2632 unlang_t *c;
2633 ssize_t slen;
2634
2635 tmpl_rules_t t_rules;
2636
2638 fr_htrie_type_t htype;
2639
2640 static unlang_ext_t const switch_ext = {
2642 .len = sizeof(unlang_switch_t),
2643 .type_name = "unlang_switch_t",
2644 .pool_headers = TMPL_POOL_DEF_HEADERS,
2645 .pool_len = TMPL_POOL_DEF_LEN
2646 };
2647
2648 /*
2649 * We allow unknown attributes here.
2650 */
2651 t_rules = *(unlang_ctx->rules);
2652 t_rules.attr.allow_unknown = true;
2653 RULES_VERIFY(&t_rules);
2654
2655 name2 = cf_section_name2(cs);
2656 if (!name2) {
2657 cf_log_err(cs, "You must specify a variable to switch over for 'switch'");
2658 return NULL;
2659 }
2660
2661 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
2662
2663 g = group_allocate(parent, cs, &switch_ext);
2664 if (!g) return NULL;
2665
2666 gext = unlang_group_to_switch(g);
2667
2668 /*
2669 * Create the template. All attributes and xlats are
2670 * defined by now.
2671 *
2672 * The 'case' statements need g->vpt filled out to ensure
2673 * that the data types match.
2674 */
2675 token = cf_section_name2_quote(cs);
2676
2677 if ((token == T_BARE_WORD) && tmpl_require_enum_prefix) {
2678 slen = tmpl_afrom_attr_substr(gext, NULL, &gext->vpt,
2679 &FR_SBUFF_IN(name2, strlen(name2)),
2680 NULL,
2681 &t_rules);
2682 } else {
2683 slen = tmpl_afrom_substr(gext, &gext->vpt,
2684 &FR_SBUFF_IN(name2, strlen(name2)),
2685 token,
2686 NULL,
2687 &t_rules);
2688 }
2689 if (!gext->vpt) {
2690 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'switch'", name2);
2691 talloc_free(g);
2692 return NULL;
2693 }
2694
2696 c->name = "switch";
2697 c->debug_name = talloc_typed_asprintf(c, "switch %s", name2);
2698
2699 /*
2700 * Fixup the template before compiling the children.
2701 * This is so that compile_case() can do attribute type
2702 * checks / casts against us.
2703 */
2704 if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
2705 error:
2706 talloc_free(g);
2707 return NULL;
2708 }
2709
2710 if (tmpl_is_list(gext->vpt)) {
2711 cf_log_err(cs, "Cannot use list for 'switch' statement");
2712 goto error;
2713 }
2714
2715 if (tmpl_contains_regex(gext->vpt)) {
2716 cf_log_err(cs, "Cannot use regular expression for 'switch' statement");
2717 goto error;
2718 }
2719
2720 if (tmpl_is_data(gext->vpt)) {
2721 cf_log_err(cs, "Cannot use constant data for 'switch' statement");
2722 goto error;
2723 }
2724
2725 if (!tmpl_is_attr(gext->vpt)) {
2726 if (tmpl_cast_set(gext->vpt, FR_TYPE_STRING) < 0) {
2727 cf_log_perr(cs, "Failed setting cast type");
2728 goto error;
2729 }
2730 }
2731
2733 if (tmpl_rules_cast(gext->vpt)) {
2734 type = tmpl_rules_cast(gext->vpt);
2735
2736 } else if (tmpl_is_attr(gext->vpt)) {
2737 type = tmpl_attr_tail_da(gext->vpt)->type;
2738 }
2739
2740 htype = fr_htrie_hint(type);
2741 if (htype == FR_HTRIE_INVALID) {
2742 cf_log_err(cs, "Invalid data type '%s' used for 'switch' statement",
2744 goto error;
2745 }
2746
2747 gext->ht = fr_htrie_alloc(gext, htype,
2751 NULL);
2752 if (!gext->ht) {
2753 cf_log_err(cs, "Failed initializing internal data structures");
2754 goto error;
2755 }
2756
2757 /*
2758 * Walk through the children of the switch section,
2759 * ensuring that they're all 'case' statements, and then compiling them.
2760 */
2761 for (subci = cf_item_next(cs, NULL);
2762 subci != NULL;
2763 subci = cf_item_next(cs, subci)) {
2764 CONF_SECTION *subcs;
2765 unlang_t *single;
2766 unlang_case_t *case_gext;
2767
2768 if (!cf_item_is_section(subci)) {
2769 if (!cf_item_is_pair(subci)) continue;
2770
2771 cf_log_err(subci, "\"switch\" sections can only have \"case\" subsections");
2772 goto error;
2773 }
2774
2775 subcs = cf_item_to_section(subci); /* can't return NULL */
2776 name1 = cf_section_name1(subcs);
2777
2778 if (strcmp(name1, "case") != 0) {
2779 /*
2780 * We finally support "default" sections for "switch".
2781 */
2782 if (strcmp(name1, "default") == 0) {
2783 if (cf_section_name2(subcs) != 0) {
2784 cf_log_err(subci, "\"default\" sections cannot have a match argument");
2785 goto error;
2786 }
2787 goto handle_default;
2788 }
2789
2790 cf_log_err(subci, "\"switch\" sections can only have \"case\" subsections");
2791 goto error;
2792 }
2793
2794 name2 = cf_section_name2(subcs);
2795 if (!name2) {
2796 handle_default:
2797 if (gext->default_case) {
2798 cf_log_err(subci, "Cannot have two 'default' case statements");
2799 goto error;
2800 }
2801 }
2802
2803 /*
2804 * Compile the subsection.
2805 */
2806 single = compile_case(c, unlang_ctx, subci);
2807 if (!single) goto error;
2808
2809 fr_assert(single->type == UNLANG_TYPE_CASE);
2810
2811 /*
2812 * Remember the "default" section, and insert the
2813 * non-default "case" into the htrie.
2814 */
2815 case_gext = unlang_group_to_case(unlang_generic_to_group(single));
2816 if (!case_gext->vpt) {
2817 gext->default_case = single;
2818
2819 } else if (!fr_htrie_insert(gext->ht, single)) {
2820 single = fr_htrie_find(gext->ht, single);
2821
2822 /*
2823 * @todo - look up the key and get the previous one?
2824 */
2825 cf_log_err(subci, "Failed inserting 'case' statement. Is there a duplicate?");
2826
2827 if (single) cf_log_err(unlang_generic_to_group(single)->cs, "Duplicate may be here.");
2828
2829 goto error;
2830 }
2831
2832 *g->tail = single;
2833 g->tail = &single->next;
2834 g->num_children++;
2835 }
2836
2838
2839 return c;
2840}
2841
2843{
2845 int i;
2846 char const *name2;
2847 unlang_t *c;
2848 unlang_group_t *case_g;
2849 unlang_case_t *case_gext;
2850 tmpl_t *vpt = NULL;
2851 tmpl_rules_t t_rules;
2852
2853 static unlang_ext_t const case_ext = {
2855 .len = sizeof(unlang_case_t),
2856 .type_name = "unlang_case_t",
2857 };
2858
2859 /*
2860 * We allow unknown attributes here.
2861 */
2862 t_rules = *(unlang_ctx->rules);
2863 t_rules.attr.allow_unknown = true;
2864 RULES_VERIFY(&t_rules);
2865
2866 if (!parent || (parent->type != UNLANG_TYPE_SWITCH)) {
2867 cf_log_err(cs, "\"case\" statements may only appear within a \"switch\" section");
2868 return NULL;
2869 }
2870
2871 /*
2872 * case THING means "match THING"
2873 * case means "match anything"
2874 */
2875 name2 = cf_section_name2(cs);
2876 if (name2) {
2877 ssize_t slen;
2878 fr_token_t quote;
2879 unlang_group_t *switch_g;
2880 unlang_switch_t *switch_gext;
2881
2882 switch_g = unlang_generic_to_group(parent);
2883 switch_gext = unlang_group_to_switch(switch_g);
2884
2885 fr_assert(switch_gext->vpt != NULL);
2886
2887 /*
2888 * We need to cast case values to match
2889 * what we're switching over, otherwise
2890 * integers of different widths won't
2891 * match.
2892 */
2893 t_rules.cast = tmpl_expanded_type(switch_gext->vpt);
2894
2895 /*
2896 * Need to pass the attribute from switch
2897 * to tmpl rules so we can convert the
2898 * case string to an integer value.
2899 */
2900 if (tmpl_is_attr(switch_gext->vpt)) {
2901 fr_dict_attr_t const *da = tmpl_attr_tail_da(switch_gext->vpt);
2902 if (da->flags.has_value) t_rules.enumv = da;
2903 }
2904
2905 quote = cf_section_name2_quote(cs);
2906
2907 slen = tmpl_afrom_substr(cs, &vpt,
2908 &FR_SBUFF_IN(name2, strlen(name2)),
2909 quote,
2910 NULL,
2911 &t_rules);
2912 if (!vpt) {
2913 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'case'", name2);
2914 return NULL;
2915 }
2916
2917 /*
2918 * Bare word strings are attribute references when tmpl_require_enum_prefix=yes
2919 */
2921 fail_attr:
2922 cf_log_err(cs, "arguments to 'case' statements MUST NOT be attribute references.");
2923 goto fail;
2924 }
2925
2927 cf_log_err(cs, "arguments to 'case' statements MUST be static data.");
2928 fail:
2930 return NULL;
2931 }
2932
2933 /*
2934 * When tmpl_require_enum_prefix=yes, references to unresolved attributes
2935 * are instead compiled as "bare word" strings. Which we now forbid.
2936 */
2938 goto fail_attr;
2939 }
2940
2941 } /* else it's a default 'case' statement */
2942
2943 /*
2944 * If we were asked to match something, then we MUST
2945 * match it, even if the section is empty. Otherwise we
2946 * will silently skip the match, and then fall through to
2947 * the "default" statement.
2948 */
2949 c = compile_section(parent, unlang_ctx, cs, &case_ext);
2950 if (!c) {
2952 return NULL;
2953 }
2954
2955 case_g = unlang_generic_to_group(c);
2956 case_gext = unlang_group_to_case(case_g);
2957 case_gext->vpt = talloc_steal(case_gext, vpt);
2958
2959 /*
2960 * Set all of it's codes to return, so that
2961 * when we pick a 'case' statement, we don't
2962 * fall through to processing the next one.
2963 */
2964 for (i = 0; i < RLM_MODULE_NUMCODES; i++) c->actions.actions[i] = MOD_ACTION_RETURN;
2965
2966 return c;
2967}
2968
2970{
2972 char const *name2;
2973 unlang_t *c;
2974 unlang_group_t *g;
2975 unlang_timeout_t *gext;
2977 tmpl_t *vpt = NULL;
2978 fr_token_t token;
2979
2980 static unlang_ext_t const timeout_ext = {
2982 .len = sizeof(unlang_timeout_t),
2983 .type_name = "unlang_timeout_t",
2984 };
2985
2986 /*
2987 * Timeout <time ref>
2988 */
2989 name2 = cf_section_name2(cs);
2990 if (!name2) {
2991 cf_log_err(cs, "You must specify a time value for 'timeout'");
2992 return NULL;
2993 }
2994
2995 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
2996
2997 g = group_allocate(parent, cs, &timeout_ext);
2998 if (!g) return NULL;
2999
3000 gext = unlang_group_to_timeout(g);
3001
3002 token = cf_section_name2_quote(cs);
3003
3004 if ((token == T_BARE_WORD) && isdigit((uint8_t) *name2)) {
3005 if (fr_time_delta_from_str(&timeout, name2, strlen(name2), FR_TIME_RES_SEC) < 0) {
3006 cf_log_err(cs, "Failed parsing time delta %s - %s",
3007 name2, fr_strerror());
3008 return NULL;
3009 }
3010 } else {
3011 ssize_t slen;
3012 tmpl_rules_t t_rules;
3013
3014 /*
3015 * We don't allow unknown attributes here.
3016 */
3017 t_rules = *(unlang_ctx->rules);
3018 t_rules.attr.allow_unknown = false;
3019 RULES_VERIFY(&t_rules);
3020
3021 slen = tmpl_afrom_substr(gext, &vpt,
3022 &FR_SBUFF_IN(name2, strlen(name2)),
3023 token,
3024 NULL,
3025 &t_rules);
3026 if (!vpt) {
3027 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'timeout'", name2);
3028 talloc_free(g);
3029 return NULL;
3030 }
3031
3032 /*
3033 * Fixup the tmpl so that we know it's somewhat sane.
3034 */
3035 if (!pass2_fixup_tmpl(gext, &vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
3036 error:
3037 talloc_free(g);
3038 return NULL;
3039 }
3040
3041 if (tmpl_is_list(vpt)) {
3042 cf_log_err(cs, "Cannot use list as argument for 'timeout' statement");
3043 goto error;
3044 }
3045
3046 if (tmpl_contains_regex(vpt)) {
3047 cf_log_err(cs, "Cannot use regular expression as argument for 'timeout' statement");
3048 goto error;
3049 }
3050
3051 /*
3052 * Attribute or data MUST be cast to TIME_DELTA.
3053 */
3055 cf_log_perr(cs, "Failed setting cast type");
3056 goto error;
3057 }
3058 }
3059
3060 /*
3061 * Compile the contents of a "timeout".
3062 */
3063 c = compile_section(parent, unlang_ctx, cs, &timeout_ext);
3064 if (!c) return NULL;
3065
3067 gext = unlang_group_to_timeout(g);
3068 gext->timeout = timeout;
3069 gext->vpt = vpt;
3070
3071 return c;
3072}
3073
3075{
3077 char const *name2;
3078 unlang_t *c;
3079 unlang_group_t *g;
3080 unlang_limit_t *gext;
3081 tmpl_t *vpt = NULL;
3082 uint32_t limit = 0;
3083 fr_token_t token;
3084 ssize_t slen;
3085 tmpl_rules_t t_rules;
3086
3087 static unlang_ext_t const limit_ext = {
3089 .len = sizeof(unlang_limit_t),
3090 .type_name = "unlang_limit_t",
3091 };
3092
3093 /*
3094 * limit <number>
3095 */
3096 name2 = cf_section_name2(cs);
3097 if (!name2) {
3098 cf_log_err(cs, "You must specify a value for 'limit'");
3099 return NULL;
3100 }
3101
3102 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
3103
3104 g = group_allocate(parent, cs, &limit_ext);
3105 if (!g) return NULL;
3106
3107 gext = unlang_group_to_limit(g);
3108
3109 token = cf_section_name2_quote(cs);
3110
3111 /*
3112 * We don't allow unknown attributes here.
3113 */
3114 t_rules = *(unlang_ctx->rules);
3115 t_rules.attr.allow_unknown = false;
3116 RULES_VERIFY(&t_rules);
3117
3118 slen = tmpl_afrom_substr(gext, &vpt,
3119 &FR_SBUFF_IN(name2, strlen(name2)),
3120 token,
3121 NULL,
3122 &t_rules);
3123 if (!vpt) {
3124 syntax_error:
3125 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'foreach'", name2);
3126 talloc_free(g);
3127 return NULL;
3128 }
3129
3130 /*
3131 * Fixup the tmpl so that we know it's somewhat sane.
3132 */
3133 if (!pass2_fixup_tmpl(gext, &vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
3134 error:
3135 talloc_free(g);
3136 return NULL;
3137 }
3138
3139 if (tmpl_is_list(vpt)) {
3140 cf_log_err(cs, "Cannot use list as argument for 'limit' statement");
3141 goto error;
3142 }
3143
3144 if (tmpl_contains_regex(vpt)) {
3145 cf_log_err(cs, "Cannot use regular expression as argument for 'limit' statement");
3146 goto error;
3147 }
3148
3149 if (tmpl_is_data(vpt) && (token == T_BARE_WORD)) {
3150 fr_value_box_t box;
3151
3152 if (fr_value_box_cast(NULL, &box, FR_TYPE_UINT32, NULL, tmpl_value(vpt)) < 0) goto syntax_error;
3153
3154 limit = box.vb_uint32;
3155
3156 } else {
3157 /*
3158 * Attribute or data MUST be cast to a 32-bit unsigned number.
3159 */
3160 if (tmpl_cast_set(vpt, FR_TYPE_UINT32) < 0) {
3161 cf_log_perr(cs, "Failed setting cast type");
3162 goto error;
3163 }
3164 }
3165
3166 /*
3167 * Compile the contents of a "limit".
3168 */
3169 c = compile_section(parent, unlang_ctx, cs, &limit_ext);
3170 if (!c) return NULL;
3171
3173 gext = unlang_group_to_limit(g);
3174 gext->limit = limit;
3175 gext->vpt = vpt;
3176
3177 return c;
3178}
3179
3181{
3183 fr_token_t token;
3184 char const *name2;
3185 char const *type_name, *variable_name;
3187 unlang_t *c;
3188
3189 fr_type_t key_type;
3190 char const *key_name;
3191
3192 unlang_group_t *g;
3193 unlang_foreach_t *gext;
3194
3195 ssize_t slen;
3196 tmpl_t *vpt;
3197 fr_dict_attr_t const *da = NULL;
3198
3199 tmpl_rules_t t_rules;
3200 unlang_compile_t unlang_ctx2;
3201
3202 static unlang_ext_t const foreach_ext = {
3204 .len = sizeof(unlang_foreach_t),
3205 .type_name = "unlang_foreach_t",
3206 .pool_headers = TMPL_POOL_DEF_HEADERS,
3207 .pool_len = TMPL_POOL_DEF_LEN
3208 };
3209
3210 /*
3211 * Ignore empty "foreach" blocks, and don't even sanity check their arguments.
3212 */
3213 if (!cf_item_next(cs, NULL)) {
3214 return UNLANG_IGNORE;
3215 }
3216
3217 /*
3218 * We allow unknown attributes here.
3219 */
3220 t_rules = *(unlang_ctx->rules);
3221 t_rules.attr.allow_unknown = true;
3222 t_rules.attr.allow_wildcard = true;
3223 RULES_VERIFY(&t_rules);
3224
3225 name2 = cf_section_name2(cs);
3226 fr_assert(name2 != NULL); /* checked in cf_file.c */
3227
3228 /*
3229 * Allocate a group for the "foreach" block.
3230 */
3231 g = group_allocate(parent, cs, &foreach_ext);
3232 if (!g) return NULL;
3233
3235
3236 /*
3237 * Create the template. If we fail, AND it's a bare word
3238 * with &Foo-Bar, it MAY be an attribute defined by a
3239 * module. Allow it for now. The pass2 checks below
3240 * will fix it up.
3241 */
3242 token = cf_section_name2_quote(cs);
3243 if (token != T_BARE_WORD) {
3244 cf_log_err(cs, "Data being looped over in 'foreach' must be an attribute reference or dynamic expansion, not a string");
3245 goto fail;
3246 }
3247
3248 slen = tmpl_afrom_substr(g, &vpt,
3249 &FR_SBUFF_IN(name2, strlen(name2)),
3250 token,
3251 NULL,
3252 &t_rules);
3253 if (!vpt) {
3254 cf_canonicalize_error(cs, slen, "Failed parsing argument to 'foreach'", name2);
3255 fail:
3256 talloc_free(g);
3257 return NULL;
3258 }
3259
3260 /*
3261 * If we don't have a negative return code, we must have a vpt
3262 * (mostly to quiet coverity).
3263 */
3264 fr_assert(vpt);
3265
3266 if (tmpl_is_attr(vpt)) {
3268 cf_log_warn(cs, "Attribute reference should be updated to use %s[*]", vpt->name);
3270 }
3271
3272 if (tmpl_attr_tail_num(vpt) != NUM_ALL) {
3273 cf_log_err(cs, "MUST NOT use instance selectors in 'foreach'");
3274 goto fail;
3275 }
3276
3277 } else if (!tmpl_contains_xlat(vpt)) {
3278 cf_log_err(cs, "Invalid contents in 'foreach (...)', it must be an attribute reference or a dynamic expansion");
3279 goto fail;
3280 }
3281
3282 gext = unlang_group_to_foreach(g);
3283 gext->vpt = vpt;
3284
3285 c->name = "foreach";
3286 MEM(c->debug_name = talloc_typed_asprintf(c, "foreach %s", name2));
3287
3288 /*
3289 * Copy over the compilation context. This is mostly
3290 * just to ensure that retry is handled correctly.
3291 * i.e. reset.
3292 */
3293 compile_copy_context(&unlang_ctx2, unlang_ctx);
3294
3295 /*
3296 * Then over-write the new compilation context.
3297 */
3298 unlang_ctx2.section_name1 = "foreach";
3299 unlang_ctx2.section_name2 = name2;
3300 unlang_ctx2.rules = &t_rules;
3301 t_rules.parent = unlang_ctx->rules;
3302
3303 /*
3304 * If we have "type name", then define a local variable of that name.
3305 */
3306 type_name = cf_section_argv(cs, 0); /* AFTER name1, name2 */
3307
3308 key_name = cf_section_argv(cs, 2);
3309 if (key_name) {
3310 key_type = fr_table_value_by_str(fr_type_table, key_name, FR_TYPE_VOID);
3311 } else {
3312 key_type = FR_TYPE_VOID;
3313 }
3314 key_name = cf_section_argv(cs, 3);
3315
3316 if (tmpl_is_xlat(vpt)) {
3317 if (!type_name) {
3318 /*
3319 * @todo - find a way to get the data type.
3320 */
3321 cf_log_err(cs, "Dynamic expansions MUST specify a data type for the variable");
3322 return NULL;
3323 }
3324
3326 if (!fr_type_is_leaf(type)) {
3327 cf_log_err(cs, "Dynamic expansions MUST specify a non-structural data type for the variable");
3328 return NULL;
3329 }
3330
3331 if ((key_type != FR_TYPE_VOID) && !fr_type_is_numeric(key_type)) {
3332 cf_log_err(cs, "Invalid data type '%s' for 'key' variable - it should be numeric", fr_type_to_str(key_type));
3333 return NULL;
3334 }
3335
3336 goto get_name;
3337 } else {
3339
3340 if ((key_type != FR_TYPE_VOID) && (key_type != FR_TYPE_STRING)) {
3341 cf_log_err(cs, "Invalid data type '%s' for 'key' variable - it should be 'string'", fr_type_to_str(key_type));
3342 return NULL;
3343 }
3344 }
3345
3346 if (type_name) {
3347 unlang_variable_t *var;
3348
3351
3352 /*
3353 * foreach string foo (&tlv-thing.[*]) { ... }
3354 */
3356 goto get_name;
3357 }
3358
3359 da = tmpl_attr_tail_da(vpt);
3360
3361 if (type == FR_TYPE_NULL) {
3362 type = da->type;
3363
3364 } else if (fr_type_is_leaf(type) != fr_type_is_leaf(da->type)) {
3365 incompatible:
3366 cf_log_err(cs, "Incompatible data types in foreach variable (%s), and reference %s being looped over (%s)",
3367 fr_type_to_str(type), da->name, fr_type_to_str(da->type));
3368 goto fail;
3369
3370 } else if (fr_type_is_structural(type) && (type != da->type)) {
3371 goto incompatible;
3372 }
3373
3374 get_name:
3375 variable_name = cf_section_argv(cs, 1);
3376
3377 /*
3378 * Define the local variables.
3379 */
3380 g->variables = var = talloc_zero(g, unlang_variable_t);
3381 if (!var) goto fail;
3382
3383 var->dict = fr_dict_protocol_alloc(unlang_ctx->rules->attr.dict_def);
3384 if (!var->dict) goto fail;
3385
3386 var->root = fr_dict_root(var->dict);
3387
3388 var->max_attr = 1;
3389
3390 if (define_local_variable(cf_section_to_item(cs), var, &t_rules, type, variable_name, da) < 0) goto fail;
3391
3392 t_rules.attr.dict_def = var->dict;
3393 t_rules.attr.namespace = NULL;
3394
3395 /*
3396 * And ensure we have the key.
3397 */
3398 gext->value = fr_dict_attr_by_name(NULL, var->root, variable_name);
3399 fr_assert(gext->value != NULL);
3400
3401 /*
3402 * Define the local key variable. Note that we don't copy any children.
3403 */
3404 if (key_type != FR_TYPE_VOID) {
3405 if (define_local_variable(cf_section_to_item(cs), var, &t_rules, key_type, key_name, NULL) < 0) goto fail;
3406
3407 gext->key = fr_dict_attr_by_name(NULL, var->root, key_name);
3408 fr_assert(gext->key != NULL);
3409 }
3410 }
3411
3412 if (!compile_children(g, &unlang_ctx2, true)) return NULL;
3413
3414 return c;
3415}
3416
3418{
3419 unlang_t *foreach;
3420
3421 static unlang_ext_t const break_ext = {
3423 .len = sizeof(unlang_group_t),
3424 .type_name = "unlang_group_t",
3425 };
3426
3427 for (foreach = parent; foreach != NULL; foreach = foreach->parent) {
3428 /*
3429 * A "break" inside of a "policy" is an error.
3430 * We CANNOT allow "break" inside of a policy to
3431 * affect a "foreach" loop outside of that
3432 * policy.
3433 */
3434 if (foreach->type == UNLANG_TYPE_POLICY) goto fail;
3435
3436 if (foreach->type == UNLANG_TYPE_FOREACH) break;
3437 }
3438
3439 if (!foreach) {
3440 fail:
3441 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
3442 return NULL;
3443 }
3444
3445 parent->closed = true;
3446
3447 return compile_empty(parent, unlang_ctx, NULL, &break_ext);
3448}
3449
3451{
3452 unlang_t *subrequest;
3453
3454 static unlang_ext_t const detach_ext = {
3456 .len = sizeof(unlang_group_t),
3457 .type_name = "unlang_group_t",
3458 };
3459
3460 for (subrequest = parent;
3461 subrequest != NULL;
3462 subrequest = subrequest->parent) {
3463 if (subrequest->type == UNLANG_TYPE_SUBREQUEST) break;
3464 }
3465
3466 if (!subrequest) {
3467 cf_log_err(ci, "'detach' can only be used inside of a 'subrequest' section.");
3468 return NULL;
3469 }
3470
3471 /*
3472 * This really overloads the functionality of
3473 * cf_item_next().
3474 */
3475 if ((parent == subrequest) && !cf_item_next(ci, ci)) {
3476 cf_log_err(ci, "'detach' cannot be used as the last entry in a section, as there is nothing more to do");
3477 return NULL;
3478 }
3479
3480 return compile_empty(parent, unlang_ctx, NULL, &detach_ext);
3481}
3482
3484{
3485 static unlang_ext_t const return_ext = {
3487 .len = sizeof(unlang_group_t),
3488 .type_name = "unlang_group_t",
3489 };
3490
3491 /*
3492 * These types are all parallel, and therefore can have a "return" in them.
3493 */
3494 switch (parent->type) {
3498 break;
3499
3500 default:
3501 parent->closed = true;
3502 break;
3503 }
3504
3505 return compile_empty(parent, unlang_ctx, NULL, &return_ext);
3506}
3507
3509{
3510 CONF_PAIR *cp = cf_item_to_pair(ci);
3511 unlang_t *c;
3512 unlang_tmpl_t *ut;
3513 ssize_t slen;
3514 char const *p = cf_pair_attr(cp);
3515 tmpl_t *vpt;
3516
3517 ut = talloc_zero(parent, unlang_tmpl_t);
3518
3519 c = unlang_tmpl_to_generic(ut);
3520 c->parent = parent;
3521 c->next = NULL;
3522 c->name = p;
3523 c->debug_name = c->name;
3525 c->ci = CF_TO_ITEM(cp);
3526
3527 RULES_VERIFY(unlang_ctx->rules);
3528 slen = tmpl_afrom_substr(ut, &vpt,
3529 &FR_SBUFF_IN(p, talloc_array_length(p) - 1),
3531 NULL,
3532 unlang_ctx->rules);
3533 if (!vpt) {
3534 cf_canonicalize_error(cp, slen, "Failed parsing expansion", p);
3535 talloc_free(ut);
3536 return NULL;
3537 }
3538 ut->tmpl = vpt; /* const issues */
3539
3541 return c;
3542}
3543
3545 L(""),
3546 L("{"),
3547);
3548
3550 unlang_ext_t const *ext)
3551{
3552 unlang_t *c;
3553
3554 unlang_group_t *g;
3555 unlang_cond_t *gext;
3556
3557 xlat_exp_head_t *head = NULL;
3558 bool is_truthy = false, value = false;
3559 xlat_res_rules_t xr_rules = {
3561 .dict_def = unlang_ctx->rules->attr.dict_def,
3562 },
3563 };
3564
3565 if (!cf_section_name2(cs)) {
3566 cf_log_err(cs, "'%s' without condition", unlang_ops[ext->type].name);
3567 return NULL;
3568 }
3569
3570 /*
3571 * Migration support.
3572 */
3573 {
3574 char const *name2 = cf_section_name2(cs);
3575 ssize_t slen;
3576
3577 tmpl_rules_t t_rules = (tmpl_rules_t) {
3578 .parent = unlang_ctx->rules->parent,
3579 .attr = {
3580 .dict_def = xr_rules.tr_rules->dict_def,
3581 .list_def = request_attr_request,
3582 .allow_unresolved = true,
3583 .allow_unknown = true
3584 }
3585 };
3586
3587 fr_sbuff_parse_rules_t p_rules = { };
3588
3589 p_rules.terminals = &if_terminals;
3590
3591 slen = xlat_tokenize_condition(cs, &head, &FR_SBUFF_IN(name2, strlen(name2)), &p_rules, &t_rules);
3592 if (slen <= 0) {
3593 cf_canonicalize_error(cs, slen, "Failed parsing condition", name2);
3594 return NULL;
3595 }
3596
3597 /*
3598 * Resolve the xlat first.
3599 */
3600 if (xlat_resolve(head, &xr_rules) < 0) {
3601 cf_log_err(cs, "Failed resolving condition - %s", fr_strerror());
3602 return NULL;
3603 }
3604
3606
3607 /*
3608 * If the condition is always false, we don't compile the
3609 * children.
3610 */
3611 if (is_truthy && !value) {
3612 cf_log_debug_prefix(cs, "Skipping contents of '%s' as it is always 'false'",
3613 unlang_ops[ext->type].name);
3614
3615 /*
3616 * Free the children, which frees any xlats,
3617 * conditions, etc. which were defined, but are
3618 * now entirely unused.
3619 *
3620 * However, we still need to cache the conditions, as they will be accessed at run-time.
3621 */
3622 c = compile_empty(parent, unlang_ctx, cs, ext);
3624 } else {
3625 c = compile_section(parent, unlang_ctx, cs, ext);
3626 }
3627 }
3628
3629 if (!c) return NULL;
3631
3633 gext = unlang_group_to_cond(g);
3634
3635 gext->head = head;
3636 gext->is_truthy = is_truthy;
3637 gext->value = value;
3638
3639 return c;
3640}
3641
3643{
3644 static unlang_ext_t const if_ext = {
3646 .len = sizeof(unlang_cond_t),
3647 .type_name = "unlang_cond_t",
3648 .pool_headers = 1 + 1 + (TMPL_POOL_DEF_HEADERS * 2),
3649 .pool_len = sizeof(map_t) + (TMPL_POOL_DEF_LEN * 2)
3650 };
3651
3653}
3654
3656{
3657 static unlang_ext_t const elsif_ext = {
3659 .len = sizeof(unlang_cond_t),
3660 .type_name = "unlang_cond_t",
3661 .pool_headers = 1 + 1 + (TMPL_POOL_DEF_HEADERS * 2),
3662 .pool_len = sizeof(map_t) + (TMPL_POOL_DEF_LEN * 2)
3663 };
3664
3666}
3667
3669{
3671
3672 static unlang_ext_t const else_ext = {
3674 .len = sizeof(unlang_group_t),
3675 .type_name = "unlang_group_t"
3676 };
3677
3678 if (cf_section_name2(cs)) {
3679 cf_log_err(cs, "'else' cannot have a condition");
3680 return NULL;
3681 }
3682
3683 return compile_section(parent, unlang_ctx, cs, &else_ext);
3684}
3685
3686/*
3687 * redundant, load-balance and parallel have limits on what can
3688 * go in them.
3689 */
3690static bool validate_limited_subsection(CONF_SECTION *cs, char const *name)
3691{
3692 CONF_ITEM *ci;
3693
3694 for (ci=cf_item_next(cs, NULL);
3695 ci != NULL;
3696 ci=cf_item_next(cs, ci)) {
3697 /*
3698 * If we're a redundant, etc. group, then the
3699 * intention is to call modules, rather than
3700 * processing logic. These checks aren't
3701 * *strictly* necessary, but they keep the users
3702 * from doing crazy things.
3703 */
3704 if (cf_item_is_section(ci)) {
3705 CONF_SECTION *subcs = cf_item_to_section(ci);
3706 char const *name1 = cf_section_name1(subcs);
3707
3708 /*
3709 * Allow almost anything except "else"
3710 * statements. The normal processing
3711 * falls through from "if" to "else", and
3712 * we can't do that for redundant and
3713 * load-balance sections.
3714 */
3715 if ((strcmp(name1, "else") == 0) ||
3716 (strcmp(name1, "elsif") == 0)) {
3717 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
3718 name, name1);
3719 return false;
3720 }
3721 continue;
3722 }
3723
3724 if (cf_item_is_pair(ci)) {
3725 CONF_PAIR *cp = cf_item_to_pair(ci);
3726
3727 if (cf_pair_operator(cp) == T_OP_CMP_TRUE) return true;
3728
3729 if (cf_pair_value(cp) != NULL) {
3730 cf_log_err(cp, "Unknown keyword '%s', or invalid location", cf_pair_attr(cp));
3731 return false;
3732 }
3733 }
3734 }
3735
3736 return true;
3737}
3738
3739
3741{
3743 unlang_t *c;
3744
3745 static unlang_ext_t const redundant_ext = {
3747 .len = sizeof(unlang_group_t),
3748 .type_name = "unlang_group_t"
3749 };
3750
3751 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
3752
3754 return NULL;
3755 }
3756
3757 c = compile_section(parent, unlang_ctx, cs, &redundant_ext);
3758 if (!c) return NULL;
3759
3760 /*
3761 * We no longer care if "redundant" sections have a name. If they do, it's ignored.
3762 */
3763
3764 return c;
3765}
3766
3768 unlang_ext_t const *ext)
3769{
3770 char const *name2;
3771 unlang_t *c;
3772 unlang_group_t *g;
3774
3775 tmpl_rules_t t_rules;
3776
3777 /*
3778 * We allow unknown attributes here.
3779 */
3780 t_rules = *(unlang_ctx->rules);
3781 t_rules.attr.allow_unknown = true;
3782 RULES_VERIFY(&t_rules);
3783
3784 /*
3785 * No children? Die!
3786 */
3787 if (!cf_item_next(cs, NULL)) {
3788 cf_log_err(cs, "%s sections cannot be empty", unlang_ops[ext->type].name);
3789 return NULL;
3790 }
3791
3792 if (!validate_limited_subsection(cs, cf_section_name1(cs))) return NULL;
3793
3794 c = compile_section(parent, unlang_ctx, cs, ext);
3795 if (!c) return NULL;
3796
3798
3799 /*
3800 * Allow for keyed load-balance / redundant-load-balance sections.
3801 */
3802 name2 = cf_section_name2(cs);
3803
3804 /*
3805 * Inside of the "modules" section, it's a virtual
3806 * module. The name is a module name, not a key.
3807 */
3808 if (name2) {
3809 if (strcmp(cf_section_name1(cf_item_to_section(cf_parent(cs))), "modules") == 0) name2 = NULL;
3810 }
3811
3812 if (name2) {
3814 ssize_t slen;
3815
3816 /*
3817 * Create the template. All attributes and xlats are
3818 * defined by now.
3819 */
3822 slen = tmpl_afrom_substr(gext, &gext->vpt,
3823 &FR_SBUFF_IN(name2, strlen(name2)),
3824 type,
3825 NULL,
3826 &t_rules);
3827 if (!gext->vpt) {
3828 cf_canonicalize_error(cs, slen, "Failed parsing argument", name2);
3829 talloc_free(g);
3830 return NULL;
3831 }
3832
3833 fr_assert(gext->vpt != NULL);
3834
3835 /*
3836 * Fixup the templates
3837 */
3838 if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
3839 talloc_free(g);
3840 return NULL;
3841 }
3842
3843 switch (gext->vpt->type) {
3844 default:
3845 cf_log_err(cs, "Invalid type in '%s': data will not result in a load-balance key", name2);
3846 talloc_free(g);
3847 return NULL;
3848
3849 /*
3850 * Allow only these ones.
3851 */
3852 case TMPL_TYPE_XLAT:
3853 case TMPL_TYPE_ATTR:
3854 case TMPL_TYPE_EXEC:
3855 break;
3856 }
3857 }
3858
3859 return c;
3860}
3861
3863{
3864 static unlang_ext_t const load_balance_ext = {
3866 .len = sizeof(unlang_load_balance_t),
3867 .type_name = "unlang_load_balance_t"
3868 };
3869
3871}
3872
3873
3875{
3876 static unlang_ext_t const redundant_load_balance_ext = {
3878 .len = sizeof(unlang_load_balance_t),
3879 .type_name = "unlang_load_balance_t"
3880 };
3881
3882 return compile_load_balance_subsection(parent, unlang_ctx, cf_item_to_section(ci), &redundant_load_balance_ext);
3883}
3884
3886{
3888 unlang_t *c;
3889 char const *name2;
3890
3891 unlang_group_t *g;
3892 unlang_parallel_t *gext;
3893
3894 bool clone = true;
3895 bool detach = false;
3896
3897 static unlang_ext_t const parallel_ext = {
3899 .len = sizeof(unlang_parallel_t),
3900 .type_name = "unlang_parallel_t"
3901 };
3902
3903 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
3904
3905 /*
3906 * Parallel sections can create empty children, if the
3907 * admin demands it. Otherwise, the principle of least
3908 * surprise is to copy the whole request, reply, and
3909 * config items.
3910 */
3911 name2 = cf_section_name2(cs);
3912 if (name2) {
3913 if (strcmp(name2, "empty") == 0) {
3914 clone = false;
3915
3916 } else if (strcmp(name2, "detach") == 0) {
3917 detach = true;
3918
3919 } else {
3920 cf_log_err(cs, "Invalid argument '%s'", name2);
3921 return NULL;
3922 }
3923
3924 }
3925
3926 /*
3927 * We can do "if" in parallel with other "if", but we
3928 * cannot do "else" in parallel with "if".
3929 */
3931 return NULL;
3932 }
3933
3934 c = compile_section(parent, unlang_ctx, cs, &parallel_ext);
3935 if (!c) return NULL;
3936
3938 gext = unlang_group_to_parallel(g);
3939 gext->clone = clone;
3940 gext->detach = detach;
3941
3942 return c;
3943}
3944
3946{
3948 char const *name2;
3949
3950 unlang_t *c;
3951
3952 unlang_group_t *g;
3953 unlang_subrequest_t *gext;
3954
3955 unlang_compile_t unlang_ctx2;
3956
3957 tmpl_rules_t t_rules;
3958 fr_dict_autoload_talloc_t *dict_ref = NULL;
3959
3960 fr_dict_t const *dict;
3961 fr_dict_attr_t const *da = NULL;
3962 fr_dict_enum_value_t const *type_enum = NULL;
3963
3964 char *namespace = NULL;
3965 char const *packet_name = NULL;
3966 char *p = NULL;
3967
3968 tmpl_t *vpt = NULL, *src_vpt = NULL, *dst_vpt = NULL;
3969
3970 static unlang_ext_t const subrequest_ext = {
3972 .len = sizeof(unlang_subrequest_t),
3973 .type_name = "unlang_subrequest_t",
3974 .pool_headers = (TMPL_POOL_DEF_HEADERS * 3),
3975 .pool_len = (TMPL_POOL_DEF_LEN * 3)
3976 };
3977
3978 /*
3979 * subrequest { ... }
3980 *
3981 * Create a subrequest which is of the same dictionary
3982 * and packet type as the current request.
3983 *
3984 * We assume that the Packet-Type attribute exists.
3985 */
3986 name2 = cf_section_name2(cs);
3987 if (!name2) {
3988 dict = unlang_ctx->rules->attr.dict_def;
3989 packet_name = name2 = unlang_ctx->section_name2;
3990 goto get_packet_type;
3991 }
3992
3994 cf_log_err(cs, "The arguments to 'subrequest' must be a name or an attribute reference");
3995 return NULL;
3996 }
3997
3998 /*
3999 * ::enum is this dictionary, "Packet-Type = ::enum"
4000 */
4001 if ((name2[0] == ':') && (name2[1] == ':')) {
4002 dict = unlang_ctx->rules->attr.dict_def;
4003 packet_name = name2;
4004 goto get_packet_type;
4005 }
4006
4007 /*
4008 * If !tmpl_require_enum_prefix, '&' means "attribute reference".
4009 *
4010 * Or, bare word means "attribute reference".
4011 */
4012 if ((name2[0] == '&') ||
4013 (tmpl_require_enum_prefix && ((p = strchr(name2, ':')) == NULL))) {
4014 ssize_t slen;
4015
4016 slen = tmpl_afrom_attr_substr(parent, NULL, &vpt,
4017 &FR_SBUFF_IN(name2, talloc_array_length(name2) - 1),
4018 NULL, unlang_ctx->rules);
4019 if (slen <= 0) {
4020 cf_log_perr(cs, "Invalid argument to 'subrequest', failed parsing packet-type");
4021 return NULL;
4022 }
4023
4025
4026 /*
4027 * Anything resembling an integer or string is
4028 * OK. Nothing else makes sense.
4029 */
4030 switch (tmpl_attr_tail_da(vpt)->type) {
4032 case FR_TYPE_STRING:
4033 break;
4034
4035 default:
4036 cf_log_err(cs, "Invalid data type for attribute %s. "
4037 "Must be an integer type or string", name2 + 1);
4039 return NULL;
4040 }
4041
4042 dict = unlang_ctx->rules->attr.dict_def;
4043 packet_name = NULL;
4044 goto get_packet_type;
4045 }
4046
4047 /*
4048 * subrequest foo::bar { ... }
4049 *
4050 * Change to dictionary "foo", packet type "bar".
4051 */
4052 if (p) {
4053 if (p[1] != ':') {
4054 cf_log_err(cs, "Invalid syntax in namespace::enum");
4055 return NULL;
4056 }
4057
4058 MEM(namespace = talloc_strdup(parent, name2)); /* get a modifiable copy */
4059
4060 p = namespace + (p - name2);
4061 *p = '\0';
4062 p += 2;
4063 packet_name = p;
4064
4065 dict = fr_dict_by_protocol_name(namespace);
4066 if (!dict) {
4067 dict_ref = fr_dict_autoload_talloc(NULL, &dict, namespace);
4068 if (!dict_ref) {
4069 cf_log_err(cs, "Unknown namespace '%s'", namespace);
4070 talloc_free(namespace);
4071 return NULL;
4072 }
4073 }
4074
4075 goto get_packet_type;
4076 }
4077
4078 /*
4079 * subrequest foo { ... }
4080 *
4081 * Change packet types without changing dictionaries.
4082 */
4083 p = strchr(name2, '.');
4084 if (!p) {
4085 dict = unlang_ctx->rules->attr.dict_def;
4086 packet_name = name2;
4087
4088 } else if (!tmpl_require_enum_prefix) {
4089 /*
4090 * subrequest foo.bar { ... }
4091 *
4092 * Change to dictionary "foo", packet type "bar".
4093 */
4094 MEM(namespace = talloc_strdup(parent, name2)); /* get a modifiable copy */
4095
4096 p = namespace + (p - name2);
4097 *(p++) = '\0';
4098 packet_name = p;
4099
4100 dict = fr_dict_by_protocol_name(namespace);
4101 if (!dict) {
4102 dict_ref = fr_dict_autoload_talloc(NULL, &dict, namespace);
4103 if (!dict_ref) {
4104 cf_log_err(cs, "Unknown namespace '%s'", namespace);
4105 talloc_free(namespace);
4106 return NULL;
4107 }
4108 }
4109
4110 WARN("Deprecated syntax 'subrequest %s ...'", name2);
4111 WARN(" please switch to 'subrequest %s::%s ...", namespace, packet_name);
4112
4113 } else {
4114 /*
4115 * We have tmpl_require_enum prefix, so bare word foo.bar is "attribute foo,
4116 * sub-attribute bar"
4117 */
4118 dict = unlang_ctx->rules->attr.dict_def;
4119 packet_name = name2;
4120 }
4121
4122 /*
4123 * Use dict name instead of "namespace", because "namespace" can be omitted.
4124 */
4125get_packet_type:
4126 da = fr_dict_attr_by_name(NULL, fr_dict_root(dict), "Packet-Type");
4127 if (!da) {
4128 cf_log_err(cs, "No such attribute 'Packet-Type' in namespace '%s'", fr_dict_root(dict)->name);
4129 error:
4130 talloc_free(namespace);
4132 talloc_free(dict_ref);
4133 return NULL;
4134 }
4135
4136 if (packet_name) {
4137 /*
4138 * Allow ::enum-name for packet types
4139 */
4140 if ((packet_name[0] == ':') && (packet_name[1] == ':')) packet_name += 2;
4141
4142 type_enum = fr_dict_enum_by_name(da, packet_name, -1);
4143 if (!type_enum) {
4144 cf_log_err(cs, "No such value '%s' for attribute 'Packet-Type' in namespace '%s'",
4145 packet_name, fr_dict_root(dict)->name);
4146 goto error;
4147 }
4148 }
4149
4150 /*
4151 * No longer needed
4152 */
4153 talloc_free(namespace);
4154
4155 /*
4156 * Source and destination arguments
4157 */
4158 {
4159 char const *dst, *src;
4160
4161 src = cf_section_argv(cs, 0);
4162 if (src) {
4163 RULES_VERIFY(unlang_ctx->rules);
4164
4165 (void) tmpl_afrom_substr(parent, &src_vpt,
4166 &FR_SBUFF_IN(src, talloc_array_length(src) - 1),
4167 cf_section_argv_quote(cs, 0), NULL, unlang_ctx->rules);
4168 if (!src_vpt) {
4169 cf_log_perr(cs, "Invalid argument to 'subrequest', failed parsing src");
4170 goto error;
4171 }
4172
4173 if (!tmpl_contains_attr(src_vpt)) {
4174 cf_log_err(cs, "Invalid argument to 'subrequest' src must be an attr or list, got %s",
4175 tmpl_type_to_str(src_vpt->type));
4176 talloc_free(src_vpt);
4177 goto error;
4178 }
4179
4180 dst = cf_section_argv(cs, 1);
4181 if (dst) {
4182 RULES_VERIFY(unlang_ctx->rules);
4183
4184 (void) tmpl_afrom_substr(parent, &dst_vpt,
4185 &FR_SBUFF_IN(dst, talloc_array_length(dst) - 1),
4186 cf_section_argv_quote(cs, 1), NULL, unlang_ctx->rules);
4187 if (!dst_vpt) {
4188 cf_log_perr(cs, "Invalid argument to 'subrequest', failed parsing dst");
4189 goto error;
4190 }
4191
4192 if (!tmpl_contains_attr(dst_vpt)) {
4193 cf_log_err(cs, "Invalid argument to 'subrequest' dst must be an "
4194 "attr or list, got %s",
4195 tmpl_type_to_str(src_vpt->type));
4196 talloc_free(src_vpt);
4197 talloc_free(dst_vpt);
4198 goto error;
4199 }
4200 }
4201 }
4202 }
4203
4204 if (!cf_item_next(cs, NULL)) {
4206 talloc_free(src_vpt);
4207 talloc_free(dst_vpt);
4208 return UNLANG_IGNORE;
4209 }
4210
4211 t_rules = *unlang_ctx->rules;
4212 t_rules.parent = unlang_ctx->rules;
4213 t_rules.attr.dict_def = dict;
4214 t_rules.attr.allow_foreign = false;
4215
4216 /*
4217 * Copy over the compilation context. This is mostly
4218 * just to ensure that retry is handled correctly.
4219 * i.e. reset.
4220 */
4221 compile_copy_context(&unlang_ctx2, unlang_ctx);
4222
4223 /*
4224 * Then over-write the new compilation context.
4225 */
4226 unlang_ctx2.section_name1 = "subrequest";
4227 unlang_ctx2.section_name2 = name2;
4228 unlang_ctx2.rules = &t_rules;
4229
4230 /*
4231 * Compile the subsection with a *different* default dictionary.
4232 */
4233 c = compile_section(parent, &unlang_ctx2, cs, &subrequest_ext);
4234 if (!c) return NULL;
4235
4236 /*
4237 * Set the dictionary and packet information, which tells
4238 * unlang_subrequest() how to process the request.
4239 */
4242
4243 if (dict_ref) {
4244 /*
4245 * Parent the dictionary reference correctly now that we
4246 * have the section with the dependency. This should
4247 * be fast as dict_ref has no siblings.
4248 */
4249 talloc_steal(gext, dict_ref);
4250 }
4251 if (vpt) gext->vpt = talloc_steal(gext, vpt);
4252
4253 gext->dict = dict;
4254 gext->attr_packet_type = da;
4255 gext->type_enum = type_enum;
4256 gext->src = src_vpt;
4257 gext->dst = dst_vpt;
4258
4259 return c;
4260}
4261
4262
4264{
4266 virtual_server_t const *vs;
4267 unlang_t *c;
4268
4269 unlang_group_t *g;
4270 unlang_call_t *gext;
4271
4273 char const *server;
4274 CONF_SECTION *server_cs;
4275 fr_dict_t const *dict;
4277
4278 static unlang_ext_t const call_ext = {
4280 .len = sizeof(unlang_call_t),
4281 .type_name = "unlang_call_t",
4282 };
4283
4284 server = cf_section_name2(cs);
4285 if (!server) {
4286 cf_log_err(cs, "You MUST specify a server name for 'call <server> { ... }'");
4287 return NULL;
4288 }
4289
4291 if (type != T_BARE_WORD) {
4292 cf_log_err(cs, "The arguments to 'call' cannot be a quoted string or a dynamic value");
4293 return NULL;
4294 }
4295
4296 vs = virtual_server_find(server);
4297 if (!vs) {
4298 cf_log_err(cs, "Unknown virtual server '%s'", server);
4299 return NULL;
4300 }
4301
4302 server_cs = virtual_server_cs(vs);
4303
4304 /*
4305 * The dictionaries are not compatible, forbid it.
4306 */
4307 dict = virtual_server_dict_by_name(server);
4308 if (!dict) {
4309 cf_log_err(cs, "Cannot call virtual server '%s', failed retrieving its namespace",
4310 server);
4311 return NULL;
4312 }
4313 if ((dict != fr_dict_internal()) && fr_dict_internal() &&
4314 unlang_ctx->rules->attr.dict_def && !fr_dict_compatible(unlang_ctx->rules->attr.dict_def, dict)) {
4315 cf_log_err(cs, "Cannot call server %s with namespace '%s' from namespaces '%s' - they have incompatible protocols",
4316 server, fr_dict_root(dict)->name, fr_dict_root(unlang_ctx->rules->attr.dict_def)->name);
4317 return NULL;
4318 }
4319
4320 attr_packet_type = fr_dict_attr_by_name(NULL, fr_dict_root(dict), "Packet-Type");
4321 if (!attr_packet_type) {
4322 cf_log_err(cs, "Cannot call server %s with namespace '%s' - it has no Packet-Type attribute",
4323 server, fr_dict_root(dict)->name);
4324 return NULL;
4325 }
4326
4327 c = compile_section(parent, unlang_ctx, cs, &call_ext);
4328 if (!c) return NULL;
4329
4330 /*
4331 * Set the virtual server name, which tells unlang_call()
4332 * which virtual server to call.
4333 */
4335 gext = unlang_group_to_call(g);
4336 gext->server_cs = server_cs;
4338
4339 return c;
4340}
4341
4342
4344{
4346 unlang_t *c;
4347
4348 unlang_group_t *g;
4349 unlang_caller_t *gext;
4350
4352 char const *name;
4353 fr_dict_t const *dict;
4354 unlang_compile_t unlang_ctx2;
4355 tmpl_rules_t parent_rules, t_rules;
4356
4357 fr_dict_autoload_talloc_t *dict_ref = NULL;
4358
4359 static unlang_ext_t const caller_ext = {
4361 .len = sizeof(unlang_caller_t),
4362 .type_name = "unlang_caller_t",
4363 };
4364
4365 name = cf_section_name2(cs);
4366 if (!name) {
4367 cf_log_err(cs, "You MUST specify a protocol name for 'caller <protocol> { ... }'");
4368 return NULL;
4369 }
4370
4372 if (type != T_BARE_WORD) {
4373 cf_log_err(cs, "The argument to 'caller' cannot be a quoted string or a dynamic value");
4374 return NULL;
4375 }
4376
4378 if (!dict) {
4379 dict_ref = fr_dict_autoload_talloc(NULL, &dict, name);
4380 if (!dict_ref) {
4381 cf_log_perr(cs, "Unknown protocol '%s'", name);
4382 return NULL;
4383 }
4384 }
4385
4386 /*
4387 * Create a new parent context with the new dictionary.
4388 */
4389 memcpy(&parent_rules, unlang_ctx->rules, sizeof(parent_rules));
4390 memcpy(&t_rules, unlang_ctx->rules, sizeof(t_rules));
4391 parent_rules.attr.dict_def = dict;
4392 t_rules.parent = &parent_rules;
4393
4394 /*
4395 * We don't want to modify the context we were passed, so
4396 * we just clone it
4397 */
4398 memcpy(&unlang_ctx2, unlang_ctx, sizeof(unlang_ctx2));
4399 unlang_ctx2.rules = &t_rules;
4400 unlang_ctx2.section_name1 = "caller";
4401 unlang_ctx2.section_name2 = name;
4402
4403 c = compile_section(parent, &unlang_ctx2, cs, &caller_ext);
4404 if (!c) {
4405 talloc_free(dict_ref);
4406 return NULL;
4407 }
4408
4409 /*
4410 * Set the virtual server name, which tells unlang_call()
4411 * which virtual server to call.
4412 */
4414 gext = unlang_group_to_caller(g);
4415 gext->dict = dict;
4416
4417 if (dict_ref) {
4418 /*
4419 * Parent the dictionary reference correctly now that we
4420 * have the section with the dependency. This should
4421 * be fast as dict_ref has no siblings.
4422 */
4423 talloc_steal(gext, dict_ref);
4424 }
4425
4426 if (!g->num_children) {
4427 talloc_free(c);
4428 return UNLANG_IGNORE;
4429 }
4430
4431 return c;
4432}
4433
4435 CONF_SECTION *subcs,
4436 bool policy)
4437{
4438 unlang_compile_t unlang_ctx2;
4439 unlang_t *c;
4440
4441 static unlang_ext_t const policy_ext = {
4443 .len = sizeof(unlang_group_t),
4444 .type_name = "unlang_group_t",
4445 };
4446
4447 static unlang_ext_t const group_ext = {
4449 .len = sizeof(unlang_group_t),
4450 .type_name = "unlang_group_t",
4451 };
4452
4453 /*
4454 * module.c takes care of ensuring that this is:
4455 *
4456 * group foo { ...
4457 * load-balance foo { ...
4458 * redundant foo { ...
4459 * redundant-load-balance foo { ...
4460 *
4461 * We can just recurse to compile the section as
4462 * if it was found here.
4463 */
4464 if (cf_section_name2(subcs)) {
4466
4467 if (policy) {
4468 cf_log_err(subcs, "Unexpected second name in policy");
4469 return NULL;
4470 }
4471
4472 c = compile_item(parent, &unlang_ctx2, cf_section_to_item(subcs));
4473
4474 } else {
4476
4477 /*
4478 * We have:
4479 *
4480 * foo { ...
4481 *
4482 * So we compile it like it was:
4483 *
4484 * group foo { ...
4485 */
4486 c = compile_section(parent, &unlang_ctx2, subcs,
4487 policy ? &policy_ext : &group_ext);
4488 }
4489 if (!c) return NULL;
4491
4492 /*
4493 * Return the compiled thing if we can.
4494 */
4495 if (!cf_item_is_section(ci)) return c;
4496
4497 /*
4498 * Else we have a reference to a policy, and that reference
4499 * over-rides the return codes for the policy!
4500 */
4501 if (!unlang_compile_actions(&c->actions, cf_item_to_section(ci), false)) {
4502 talloc_free(c);
4503 return NULL;
4504 }
4505
4506 return c;
4507}
4508
4509/** Load a named module from the virtual module list, or from the "policy" subsection.
4510 *
4511 * If it's "foo.method", look for "foo", and return "method" as the method
4512 * we wish to use, instead of the input component.
4513 *
4514 * @param[in] ci Configuration item to check
4515 * @param[in] real_name Complete name string e.g. foo.authorize.
4516 * @param[in] virtual_name Virtual module name e.g. foo.
4517 * @param[in] method_name Method override (may be NULL) or the method
4518 * name e.g. authorize.
4519 * @param[out] policy whether or not this thing was a policy
4520 * @return the CONF_SECTION specifying the virtual module.
4521 */
4523 UNUSED char const *real_name, char const *virtual_name, char const *method_name,
4524 bool *policy)
4525{
4526 CONF_SECTION *cs, *subcs, *conf_root;
4527 CONF_ITEM *loop;
4528#if 0
4529 char buffer[256];
4530#endif
4531 *policy = false;
4532 conf_root = cf_root(ci);
4533
4534 /*
4535 * Look for "foo" as a virtual server. If we find it,
4536 * AND there's no method name, we've found the right
4537 * thing.
4538 *
4539 * Found "foo". Load it as "foo", or "foo.method".
4540 *
4541 * Return it to the caller, with the updated method.
4542 */
4543 subcs = module_rlm_virtual_by_name(virtual_name);
4544 if (subcs) goto check_for_loop;
4545
4546 /*
4547 * Look for it in "policy".
4548 *
4549 * If there's no policy section, we can't do anything else.
4550 */
4551 cs = cf_section_find(conf_root, "policy", NULL);
4552 if (!cs) return NULL;
4553
4554 *policy = true;
4555
4556 /*
4557 * "foo.authorize" means "load policy "foo" as method "authorize".
4558 *
4559 * And bail out if there's no policy "foo".
4560 */
4561 if (method_name) {
4562 subcs = cf_section_find(cs, virtual_name, NULL);
4563 if (!subcs) return NULL;
4564
4565 goto check_for_loop;
4566 }
4567
4568 /*
4569 * "foo" means "look for foo.component" first, to allow
4570 * method overrides. If that's not found, just look for
4571 * a policy "foo".
4572 *
4573 * FIXME - This has been broken since we switched to named
4574 * module sections. We should take the name1/name2 from the
4575 * unlang ctx and use that to form the name we search for.
4576 */
4577#if 0
4578 snprintf(buffer, sizeof(buffer), "%s.%s", virtual_name, comp2str[method]);
4579#endif
4580 subcs = cf_section_find(cs, virtual_name, NULL);
4581 if (!subcs) subcs = cf_section_find(cs, virtual_name, NULL);
4582 if (!subcs) return NULL;
4583
4584check_for_loop:
4585 /*
4586 * Check that we're not creating a loop. We may
4587 * be compiling an "sql" module reference inside
4588 * of an "sql" policy. If so, we allow the
4589 * second "sql" to refer to the module.
4590 */
4591 for (loop = cf_parent(ci);
4592 loop && subcs;
4593 loop = cf_parent(loop)) {
4594 if (loop == cf_section_to_item(subcs)) {
4595 return NULL;
4596 }
4597 }
4598
4599 return subcs;
4600}
4601
4603{
4604 unlang_t *c;
4605 unlang_module_t *m;
4606 fr_slen_t slen;
4607
4608 MEM(m = talloc_zero(parent, unlang_module_t));
4609 slen = module_rlm_by_name_and_method(m, &m->mmc,
4610 unlang_ctx->vs,
4611 &(section_name_t){ .name1 = unlang_ctx->section_name1, .name2 = unlang_ctx->section_name2 },
4612 &FR_SBUFF_IN(name, strlen(name)),
4613 unlang_ctx->rules);
4614 if (slen < 0) {
4615 cf_log_perr(ci, "Failed compiling module call");
4616 talloc_free(m);
4617 return NULL;
4618 }
4619
4621 c->parent = parent;
4622 c->next = NULL;
4623
4624 c->name = talloc_typed_strdup(c, name);
4625 c->debug_name = c->name;
4627 c->ci = ci;
4628
4629 /*
4630 * Set the default actions for this module.
4631 */
4632 c->actions = m->mmc.mi->actions;
4633
4634 /*
4635 * Add in the default actions for this section.
4636 */
4638
4639 /*
4640 * Parse the method environment for this module / method
4641 */
4642 if (m->mmc.mmb.method_env) {
4644
4645 fr_assert_msg(method_env->inst_size, "Method environment for module %s, method %s %s declared, "
4646 "but no inst_size set",
4647 m->mmc.mi->name, unlang_ctx->section_name1, unlang_ctx->section_name2);
4648
4649 if (!unlang_ctx->rules) {
4650 cf_log_err(ci, "Failed compiling %s - no rules", m->mmc.mi->name);
4651 goto error;
4652 }
4654 unlang_ctx->rules, m->mmc.mi->conf,
4655 &(call_env_ctx_t){
4656 .type = CALL_ENV_CTX_TYPE_MODULE,
4657 .mi = m->mmc.mi,
4658 .asked = &m->mmc.asked
4659 });
4660 if (!m->call_env) {
4661 error:
4662 talloc_free(m);
4663 return NULL;
4664 }
4665 }
4666
4667 /*
4668 * If a module reference is a section, then the section
4669 * should contain action over-rides. We add those here.
4670 */
4671 if (cf_item_is_section(ci) &&
4673 (m->mmc.mi->exported->flags & MODULE_TYPE_RETRY) != 0)) goto error;
4674
4675 return c;
4676}
4677
4678typedef unlang_t *(*unlang_op_compile_t)(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci);
4679
4681 { L("call"), (void *) compile_call },
4682 { L("caller"), (void *) compile_caller },
4683 { L("case"), (void *) compile_case },
4684 { L("catch"), (void *) compile_catch },
4685 { L("else"), (void *) compile_else },
4686 { L("elsif"), (void *) compile_elsif },
4687 { L("foreach"), (void *) compile_foreach },
4688 { L("group"), (void *) compile_group },
4689 { L("if"), (void *) compile_if },
4690 { L("limit"), (void *) compile_limit },
4691 { L("load-balance"), (void *) compile_load_balance },
4692 { L("map"), (void *) compile_map },
4693 { L("parallel"), (void *) compile_parallel },
4694 { L("redundant"), (void *) compile_redundant },
4695 { L("redundant-load-balance"), (void *) compile_redundant_load_balance },
4696 { L("subrequest"), (void *) compile_subrequest },
4697 { L("switch"), (void *) compile_switch },
4698 { L("timeout"), (void *) compile_timeout },
4699 { L("transaction"), (void *) compile_transaction },
4700 { L("try"), (void *) compile_try },
4701 { L("update"), (void *) compile_update },
4702};
4704
4706 { L("break"), (void *) compile_break },
4707 { L("detach"), (void *) compile_detach },
4708 { L("return"), (void *) compile_return },
4709};
4711
4712extern int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src);
4713
4715 fr_dict_attr_t const *ref)
4716{
4717 fr_dict_attr_t const *da;
4718 fr_slen_t len;
4719
4720 fr_dict_attr_flags_t flags = {
4721 .internal = true,
4722 .local = true,
4723 };
4724
4725 /*
4726 * No overlap with list names.
4727 */
4729 fail_list:
4730 cf_log_err(ci, "Local variable '%s' cannot be a list reference.", name);
4731 return -1;
4732 }
4733
4734 len = strlen(name);
4735 if (tmpl_attr_list_from_substr(&da, &FR_SBUFF_IN(name, len)) == len) goto fail_list;
4736
4737 /*
4738 * No keyword section names.
4739 */
4741 fail_unlang:
4742 cf_log_err(ci, "Local variable '%s' cannot be an unlang keyword.", name);
4743 return -1;
4744 }
4745
4746 /*
4747 * No simple keyword names.
4748 */
4749 if (fr_table_value_by_str(unlang_pair_keywords, name, NULL) != NULL) goto fail_unlang;
4750
4751 /*
4752 * No protocol names.
4753 */
4754 if (fr_dict_by_protocol_name(name) != NULL) {
4755 cf_log_err(ci, "Local variable '%s' cannot be an existing protocol name.", name);
4756 return -1;
4757 }
4758
4759 /*
4760 * No overlap with attributes in the current dictionary. The lookup in var->root will also check
4761 * the current dictionary, so the check here is really only for better error messages.
4762 */
4763 if (t_rules && t_rules->parent && t_rules->parent->attr.dict_def) {
4764 da = fr_dict_attr_by_name(NULL, fr_dict_root(t_rules->parent->attr.dict_def), name);
4765 if (da) {
4766 cf_log_err(ci, "Local variable '%s' duplicates a dictionary attribute.", name);
4767 return -1;
4768 }
4769 }
4770
4771 /*
4772 * No data types.
4773 */
4775 cf_log_err(ci, "Invalid variable name '%s'.", name);
4776 return -1;
4777 }
4778
4779 /*
4780 * No dups of local variables.
4781 */
4782 da = fr_dict_attr_by_name(NULL, var->root, name);
4783 if (da) {
4784 cf_log_err(ci, "Duplicate variable name '%s'.", name);
4785 return -1;
4786 }
4787
4788 if (fr_dict_attr_add(var->dict, var->root, name, var->max_attr, type, &flags) < 0) {
4789 fail:
4790 cf_log_err(ci, "Failed adding variable '%s' - %s", name, fr_strerror());
4791 return -1;
4792 }
4793 da = fr_dict_attr_by_name(NULL, var->root, name);
4794 fr_assert(da != NULL);
4795
4796 /*
4797 * Copy the children over.
4798 */
4800 fr_fatal_assert(ref != NULL);
4801
4802 if (fr_dict_attr_acopy_local(da, ref) < 0) goto fail;
4803 }
4804
4805 var->max_attr++;
4806
4807 return 0;
4808}
4809
4810/*
4811 * Compile one unlang instruction
4812 */
4814{
4815 char const *name, *p;
4816 CONF_SECTION *cs, *subcs, *modules;
4817 char const *realname;
4818 unlang_compile_t unlang_ctx2;
4819 bool policy;
4820 unlang_op_compile_t compile;
4821 unlang_t *c;
4822 bool ignore_notfound = false;
4823
4824 if (cf_item_is_section(ci)) {
4825 cs = cf_item_to_section(ci);
4826 name = cf_section_name1(cs);
4827
4829 if (compile) {
4830 unlang_op_t *op;
4831
4832 c = compile(parent, unlang_ctx, ci);
4833 allocate_number:
4834 if (!c) return NULL;
4835 if (c == UNLANG_IGNORE) return UNLANG_IGNORE;
4836
4837 c->number = unlang_number++;
4838
4839 /*
4840 * Only insert the per-thread allocation && instantiation if it's used.
4841 */
4842 op = &unlang_ops[c->type];
4843 if (!op->thread_inst_size) return c;
4844
4846 cf_log_err(ci, "Instruction \"%s\" number %u has conflict with previous one.",
4847 c->debug_name, c->number);
4848 talloc_free(c);
4849 return NULL;
4850 }
4851
4852 return c;
4853 }
4854
4855 /*
4856 * Forbid pair keywords as section names, e.g. "break { ... }"
4857 */
4858 if (fr_table_value_by_str(unlang_pair_keywords, name, NULL) != NULL) {
4859 cf_log_err(ci, "Syntax error after keyword '%s' - unexpected '{'", name);
4860 return NULL;
4861 }
4862
4863 /* else it's something like sql { fail = 1 ...} */
4864 goto check_for_module;
4865
4866 } else if (cf_item_is_pair(ci)) {
4867 /*
4868 * Else it's a module reference such as "sql", OR
4869 * one of the few bare keywords that we allow.
4870 */
4871 CONF_PAIR *cp = cf_item_to_pair(ci);
4872
4873 name = cf_pair_attr(cp);
4874
4875 /*
4876 * We cannot have assignments or actions here.
4877 */
4878 if (cf_pair_value(cp) != NULL) {
4879 cf_log_err(ci, "Entry is not a reference to a module");
4880 return NULL;
4881 }
4882
4883 /*
4884 * In-place xlat's via %{...}.
4885 *
4886 * This should really be removed from the server.
4887 */
4888 if ((name[0] == '%') ||
4891 goto allocate_number;
4892 }
4893
4894 compile = (unlang_op_compile_t)fr_table_value_by_str(unlang_pair_keywords, name, NULL); /* Cast for -Wpedantic */
4895 if (compile) {
4896 c = compile(parent, unlang_ctx, ci);
4897 goto allocate_number;
4898 }
4899
4900 /*
4901 * Forbid section keywords as pair names, e.g. bare "update"
4902 */
4904 cf_log_err(ci, "Syntax error after keyword '%s' - expected '{'", name);
4905 return NULL;
4906 }
4907
4908 goto check_for_module;
4909 } else {
4910 cf_log_err(ci, "Asked to compile unknown conf type");
4911 return NULL; /* who knows what it is... */
4912 }
4913
4914check_for_module:
4915 /*
4916 * We now have a name. It can be one of two forms. A
4917 * bare module name, or a section named for the module,
4918 * with over-rides for the return codes.
4919 *
4920 * The name can refer to a real module, in the "modules"
4921 * section. In that case, the name will be either the
4922 * first or second name of the sub-section of "modules".
4923 *
4924 * Or, the name can refer to a policy, in the "policy"
4925 * section. In that case, the name will be first of the
4926 * sub-section of "policy".
4927 *
4928 * Or, the name can refer to a "module.method", in which
4929 * case we're calling a different method than normal for
4930 * this section.
4931 *
4932 * Or, the name can refer to a virtual module, in the
4933 * "modules" section. In that case, the name will be
4934 * name2 of the CONF_SECTION.
4935 *
4936 * We try these in sequence, from the bottom up. This is
4937 * so that virtual modules and things in "policy" can
4938 * over-ride calls to real modules.
4939 */
4940
4941
4942 /*
4943 * Try:
4944 *
4945 * policy { ... name { .. } .. }
4946 * policy { ... name.method { .. } .. }
4947 */
4948 p = strrchr(name, '.');
4949 if (!p) {
4950 subcs = virtual_module_find_cs(ci, name, name, NULL, &policy);
4951 } else {
4952 char buffer[256];
4953
4954 strlcpy(buffer, name, sizeof(buffer));
4955 buffer[p - name] = '\0';
4956
4957 subcs = virtual_module_find_cs(ci, name,
4958 buffer, buffer + (p - name) + 1, &policy);
4959 }
4960
4961 /*
4962 * We've found the thing which defines this "function".
4963 * It MUST be a sub-section.
4964 *
4965 * i.e. it refers to a a subsection in "policy".
4966 */
4967 if (subcs) {
4968 c = compile_function(parent, unlang_ctx, ci, subcs, policy);
4969 goto allocate_number;
4970 }
4971
4972 /*
4973 * Not a function. It must be a real module.
4974 */
4975 modules = cf_section_find(cf_root(ci), "modules", NULL);
4976 if (!modules) {
4977 cf_log_err(ci, "Failed compiling \"%s\" as a module or policy as no modules are enabled", name);
4978 cf_log_err(ci, "Please verify that modules { ... } section is present in the server configuration");
4979 return NULL;
4980 }
4981
4982 realname = name;
4983
4984 /*
4985 * Try to load the optional module.
4986 */
4987 if (*realname == '-') {
4988 ignore_notfound = true;
4989 realname++;
4990 }
4991
4992 /*
4993 * Set the child compilation context BEFORE parsing the
4994 * module name and method. The lookup function will take
4995 * care of returning the appropriate component, name1,
4996 * name2, etc.
4997 */
4999 c = compile_module(parent, &unlang_ctx2, ci, realname);
5000 if (c) goto allocate_number;
5001
5002 if (ignore_notfound) {
5003 cf_log_warn(ci, "Ignoring \"%s\" as the \"%s\" module is not enabled, "
5004 "or the method does not exist", name, realname);
5005 return UNLANG_IGNORE;
5006 }
5007
5008 return NULL;
5009}
5010
5011/** Compile an unlang section for a virtual server
5012 *
5013 * @param[in] vs Virtual server to compile section for.
5014 * @param[in] cs containing the unlang calls to compile.
5015 * @param[in] actions Actions to use for the unlang section.
5016 * @param[in] rules Rules to use for the unlang section.
5017 * @param[out] instruction Pointer to store the compiled unlang section.
5018 * @return
5019 * - 0 on success.
5020 * - -1 on error.
5021 */
5023 CONF_SECTION *cs, unlang_mod_actions_t const * actions, tmpl_rules_t const *rules, void **instruction)
5024{
5025 unlang_t *c;
5026 tmpl_rules_t my_rules;
5027 char const *name1, *name2;
5028 CONF_DATA const *cd;
5029 static unlang_ext_t const group_ext = {
5031 .len = sizeof(unlang_group_t),
5032 .type_name = "unlang_group_t",
5033 };
5034
5035 /*
5036 * Don't compile it twice, and don't print out debug
5037 * messages twice.
5038 */
5039 cd = cf_data_find(cs, unlang_group_t, NULL);
5040 if (cd) {
5041 if (instruction) *instruction = cf_data_value(cd);
5042 return 1;
5043 }
5044
5045 name1 = cf_section_name1(cs);
5046 name2 = cf_section_name2(cs);
5047
5048 if (!name2) name2 = "";
5049
5050 cf_log_debug(cs, "Compiling policies in - %s %s {...}", name1, name2);
5051
5052 /*
5053 * Ensure that all compile functions get valid rules.
5054 */
5055 if (!rules) {
5056 memset(&my_rules, 0, sizeof(my_rules));
5057 rules = &my_rules;
5058 }
5059
5060 c = compile_section(NULL,
5062 .vs = vs,
5063 .section_name1 = cf_section_name1(cs),
5064 .section_name2 = cf_section_name2(cs),
5065 .actions = *actions,
5066 .rules = rules
5067 },
5068 cs, &group_ext);
5069 if (!c) return -1;
5070
5071 if (DEBUG_ENABLED4) unlang_dump(c, 2);
5072
5073 /*
5074 * Associate the unlang with the configuration section,
5075 * and free the unlang code when the configuration
5076 * section is freed.
5077 */
5078 cf_data_add(cs, c, NULL, true);
5079 if (instruction) *instruction = c;
5080
5081 return 0;
5082}
5083
5084
5085/** Check if name is an unlang keyword
5086 *
5087 * @param[in] name to check.
5088 * @return
5089 * - true if it is a keyword.
5090 * - false if it's not a keyword.
5091 */
5093{
5094 if (!name || !*name) return false;
5095
5096 if (fr_table_value_by_str(unlang_section_keywords, name, NULL) != NULL) return true;
5097
5098 return (fr_table_value_by_str(unlang_pair_keywords, name, NULL) != NULL);
5099}
5100
5101/*
5102 * These are really unlang_foo_t, but that's fine...
5103 */
5104static int8_t instruction_cmp(void const *one, void const *two)
5105{
5106 unlang_t const *a = one;
5107 unlang_t const *b = two;
5108
5109 return CMP(a->number, b->number);
5110}
5111
5112
5113void unlang_compile_init(TALLOC_CTX *ctx)
5114{
5116}
5117
5118
5119/** Create thread-specific data structures for unlang
5120 *
5121 */
5122int unlang_thread_instantiate(TALLOC_CTX *ctx)
5123{
5125 unlang_t *instruction;
5126
5127 if (unlang_thread_array) {
5128 fr_strerror_const("already initialized");
5129 return -1;
5130 }
5131
5132 MEM(unlang_thread_array = talloc_zero_array(ctx, unlang_thread_t, unlang_number + 1));
5133// talloc_set_destructor(unlang_thread_array, _unlang_thread_array_free);
5134
5135 /*
5136 * Instantiate each instruction with thread-specific data.
5137 */
5138 for (instruction = fr_rb_iter_init_inorder(&iter, unlang_instruction_tree);
5139 instruction;
5140 instruction = fr_rb_iter_next_inorder(&iter)) {
5141 unlang_op_t *op;
5142
5143 unlang_thread_array[instruction->number].instruction = instruction;
5144
5145 op = &unlang_ops[instruction->type];
5146
5148
5149 /*
5150 * Allocate any thread-specific instance data.
5151 */
5152 MEM(unlang_thread_array[instruction->number].thread_inst = talloc_zero_array(unlang_thread_array, uint8_t, op->thread_inst_size));
5153 talloc_set_name_const(unlang_thread_array[instruction->number].thread_inst, op->thread_inst_type);
5154
5155 if (op->thread_instantiate && (op->thread_instantiate(instruction, unlang_thread_array[instruction->number].thread_inst) < 0)) {
5156 return -1;
5157 }
5158 }
5159
5160 return 0;
5161}
5162
5163/** Get the thread-instance data for an instruction.
5164 *
5165 * @param[in] instruction the instruction to use
5166 * @return a pointer to thread-local data
5167 */
5168void *unlang_thread_instance(unlang_t const *instruction)
5169{
5170 if (!instruction->number || !unlang_thread_array) return NULL;
5171
5172 fr_assert(instruction->number <= unlang_number);
5173
5174 return unlang_thread_array[instruction->number].thread_inst;
5175}
5176
5177#ifdef WITH_PERF
5179{
5180 unlang_thread_t *t;
5181 fr_time_t now;
5182 unlang_t const *instruction = frame->instruction;
5183
5184 if (!instruction->number || !unlang_thread_array) return;
5185
5186 fr_assert(instruction->number <= unlang_number);
5187
5188 t = &unlang_thread_array[instruction->number];
5189
5190 t->use_count++;
5191 t->yielded++; // everything starts off as yielded
5192 now = fr_time();
5193
5194 fr_time_tracking_start(NULL, &frame->tracking, now);
5195 fr_time_tracking_yield(&frame->tracking, fr_time());
5196}
5197
5199{
5200 unlang_t const *instruction = frame->instruction;
5201 unlang_thread_t *t;
5202
5203 if (!instruction->number || !unlang_thread_array) return;
5204
5205 t = &unlang_thread_array[instruction->number];
5206 t->yielded++;
5207 t->running--;
5208
5209 fr_time_tracking_yield(&frame->tracking, fr_time());
5210}
5211
5213{
5214 unlang_t const *instruction = frame->instruction;
5215 unlang_thread_t *t;
5216
5217 if (!instruction->number || !unlang_thread_array) return;
5218
5219 if (frame->tracking.state != FR_TIME_TRACKING_YIELDED) return;
5220
5221 t = &unlang_thread_array[instruction->number];
5222 t->running++;
5223 t->yielded--;
5224
5225 fr_time_tracking_resume(&frame->tracking, fr_time());
5226}
5227
5229{
5230 unlang_t const *instruction = frame->instruction;
5231 unlang_thread_t *t;
5232
5233 if (!instruction || !instruction->number || !unlang_thread_array) return;
5234
5235 fr_assert(instruction->number <= unlang_number);
5236
5237 t = &unlang_thread_array[instruction->number];
5238
5239 if (frame->tracking.state == FR_TIME_TRACKING_YIELDED) {
5240 t->yielded--;
5241 fr_time_tracking_resume(&frame->tracking, fr_time());
5242 } else {
5243 t->running--;
5244 }
5245
5246 fr_time_tracking_end(NULL, &frame->tracking, fr_time());
5247 t->tracking.running_total = fr_time_delta_add(t->tracking.running_total, frame->tracking.running_total);
5248 t->tracking.waiting_total = fr_time_delta_add(t->tracking.waiting_total, frame->tracking.waiting_total);
5249}
5250
5251
5252static void unlang_perf_dump(fr_log_t *log, unlang_t const *instruction, int depth)
5253{
5254 unlang_group_t const *g;
5255 unlang_thread_t *t;
5256 char const *file;
5257 int line;
5258
5259 if (!instruction || !instruction->number) return;
5260
5261 /*
5262 * These are generally pushed onto the stack, and therefore ignored.
5263 */
5264 if (instruction->type == UNLANG_TYPE_TMPL) return;
5265
5266 /*
5267 * Everything else is an unlang_group_t;
5268 */
5269 g = unlang_generic_to_group(instruction);
5270
5271 if (!g->cs) return;
5272
5273 file = cf_filename(g->cs);
5274 line = cf_lineno(g->cs);
5275
5276 if (depth) {
5277 fr_log(log, L_DBG, file, line, "%.*s", depth, unlang_spaces);
5278 }
5279
5280 if (unlang_ops[instruction->type].debug_braces) {
5281 fr_log(log, L_DBG, file, line, "%s { #", instruction->debug_name);
5282 } else {
5283 fr_log(log, L_DBG, file, line, "%s #", instruction->debug_name);
5284 }
5285
5286 t = &unlang_thread_array[instruction->number];
5287
5288 fr_log(log, L_DBG, file, line, "count=%" PRIu64 " cpu_time=%" PRId64 " yielded_time=%" PRId64 ,
5289 t->use_count, fr_time_delta_unwrap(t->tracking.running_total), fr_time_delta_unwrap(t->tracking.waiting_total));
5290
5291 if (g->children) {
5292 unlang_t *child;
5293
5294 for (child = g->children; child != NULL; child = child->next) {
5295 unlang_perf_dump(log, child, depth + 1);
5296 }
5297 }
5298
5299 if (unlang_ops[instruction->type].debug_braces) {
5300 if (depth) {
5301 fr_log(log, L_DBG, file, line, "%.*s", depth, unlang_spaces);
5302 }
5303
5304 fr_log(log, L_DBG, file, line, "}");
5305 }
5306}
5307
5308void unlang_perf_virtual_server(fr_log_t *log, char const *name)
5309{
5310
5312 CONF_SECTION *cs;
5313 CONF_ITEM *ci;
5314 char const *file;
5315 int line;
5316
5317 if (!vs) return;
5318
5319 cs = virtual_server_cs(vs);
5320
5321 file = cf_filename(cs);
5322 line = cf_lineno(cs);
5323
5324 fr_log(log, L_DBG, file, line, " server %s {\n", name);
5325
5326 /*
5327 * Loop over the children of the virtual server, checking for unlang_t;
5328 */
5329 for (ci = cf_item_next(cs, NULL);
5330 ci != NULL;
5331 ci = cf_item_next(cs, ci)) {
5332 char const *name1, *name2;
5333 unlang_t *instruction;
5334 CONF_SECTION *subcs;
5335
5336 if (!cf_item_is_section(ci)) continue;
5337
5338 instruction = (unlang_t *)cf_data_value(cf_data_find(ci, unlang_group_t, NULL));
5339 if (!instruction) continue;
5340
5341 subcs = cf_item_to_section(ci);
5342 name1 = cf_section_name1(subcs);
5343 name2 = cf_section_name2(subcs);
5344 file = cf_filename(ci);
5345 line = cf_lineno(ci);
5346
5347 if (!name2) {
5348 fr_log(log, L_DBG, file, line, " %s {\n", name1);
5349 } else {
5350 fr_log(log, L_DBG, file, line, " %s %s {\n", name1, name2);
5351 }
5352
5353 unlang_perf_dump(log, instruction, 2);
5354
5355 fr_log(log, L_DBG, file, line, " }\n");
5356 }
5357
5358 fr_log(log, L_DBG, file, line, "}\n");
5359}
5360#endif
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
int const char int line
Definition acutest.h:702
#define RCSID(id)
Definition build.h:483
#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:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
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:736
size_t inst_size
Size of per call env.
Definition call_env.h:240
CONF_SECTION * server_cs
Config section of the virtual server being executed.
Definition call_priv.h:39
fr_dict_attr_t const * attr_packet_type
Attribute used to specify packet type and sections run in the server_cs.
Definition call_priv.h:41
static unlang_call_t * unlang_group_to_call(unlang_group_t *g)
Cast a group structure to the call keyword extension.
Definition call_priv.h:48
Entry point into a proto_ module.
Definition call_priv.h:36
static unlang_caller_t * unlang_group_to_caller(unlang_group_t *g)
Cast a group structure to the caller keyword extension.
Definition caller_priv.h:40
fr_dict_t const * dict
Definition caller_priv.h:34
Declarations for the "catch" keyword.
static unlang_catch_t * unlang_group_to_catch(unlang_group_t *g)
Cast a group structure to the transaction keyword extension.
Definition catch_priv.h:43
bool catching[RLM_MODULE_NUMCODES]
Definition catch_priv.h:35
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Definition cf_file.c:3619
Internal data that is associated with a configuration section.
Definition cf_priv.h:124
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:632
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
Definition cf_util.c:1623
fr_token_t cf_section_argv_quote(CONF_SECTION const *cs, int argc)
Return the quoting for one of the variadic arguments.
Definition cf_util.c:1260
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1185
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1763
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:738
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition cf_util.c:1279
CONF_SECTION * cf_section_next(CONF_SECTION const *cs, CONF_SECTION const *curr)
Return the next child that's a CONF_SECTION.
Definition cf_util.c:997
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1171
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:1028
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:684
void cf_section_add_name2_quote(CONF_SECTION *cs, fr_token_t token)
Set the quoting of the name2 identifier.
Definition cf_util.c:1242
bool cf_item_is_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
Definition cf_util.c:646
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1608
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition cf_util.c:1638
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:618
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
Return variadic argument at the specified index.
Definition cf_util.c:1213
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:664
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1230
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1594
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:722
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1578
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_lineno(_cf)
Definition cf_util.h:104
#define cf_item_insert_after(_parent, _prev, _child)
Definition cf_util.h:86
#define cf_data_add(_cf, _data, _name, _free)
Definition cf_util.h:255
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:244
#define cf_log_debug_prefix(_cf, _fmt,...)
Definition cf_util.h:306
#define cf_lineno_set(_ci, _lineno)
Definition cf_util.h:131
#define cf_data_remove(_cf, _type, _name)
Remove an item from a parent by type and name.
Definition cf_util.h:267
#define cf_root(_cf)
Definition cf_util.h:98
#define cf_section_free_children(_x)
Definition cf_util.h:196
#define cf_parent(_cf)
Definition cf_util.h:101
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:367
#define cf_item_remove(_parent, _child)
Definition cf_util.h:89
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:296
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:140
#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_set(_ci, _filename)
Definition cf_util.h:128
#define cf_filename(_cf)
Definition cf_util.h:107
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:290
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:292
#define cf_item_next(_ci, _curr)
Definition cf_util.h:92
static int compile_action_pair(unlang_mod_actions_t *actions, CONF_PAIR *cp)
Definition compile.c:1711
static unlang_t * compile_elsif(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3655
static unlang_t * compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci)
Definition compile.c:4813
bool unlang_compile_is_keyword(const char *name)
Check if name is an unlang keyword.
Definition compile.c:5092
void unlang_compile_init(TALLOC_CTX *ctx)
Definition compile.c:5113
static unlang_t * compile_function(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci, CONF_SECTION *subcs, bool policy)
Definition compile.c:4434
static void unlang_dump(unlang_t *instruction, int depth)
Definition compile.c:298
static unlang_t * compile_module(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci, char const *name)
Definition compile.c:4602
#define RULES_VERIFY(_rules)
Definition compile.c:151
tmpl_rules_t const * rules
Definition compile.c:103
static unlang_t * compile_empty(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs, unlang_ext_t const *ext)
Definition compile.c:1955
bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *action_cs, bool module_retry)
Definition compile.c:1847
static unlang_t * compile_redundant_load_balance(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3874
static unlang_t * compile_call(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:4263
static unlang_t * compile_section(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs, unlang_ext_t const *ext)
Definition compile.c:2289
static unlang_t * compile_update_to_edit(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs)
Definition compile.c:918
static int compile_map_name(unlang_group_t *g)
Definition compile.c:670
static fr_table_ptr_sorted_t unlang_pair_keywords[]
Definition compile.c:4705
static unlang_t * compile_load_balance_subsection(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs, unlang_ext_t const *ext)
Definition compile.c:3767
static unlang_t * compile_caller(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:4343
static unlang_t * compile_break(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3417
int unlang_thread_instantiate(TALLOC_CTX *ctx)
Create thread-specific data structures for unlang.
Definition compile.c:5122
static unlang_t * compile_redundant(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3740
static uint32_t case_hash(void const *data)
Definition compile.c:2606
bool tmpl_require_enum_prefix
static char const unlang_spaces[]
Definition compile.c:131
static bool transaction_ok(CONF_SECTION *cs)
Limit the operations which can appear in a transaction.
Definition compile.c:2364
static unlang_t * compile_else(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3668
static int edit_pair_alloc(CONF_SECTION *cs, CONF_PAIR *original, char const *attr, fr_token_t op, char const *value, fr_token_t list_op)
Definition compile.c:872
static unlang_t * compile_children(unlang_group_t *g, unlang_compile_t *unlang_ctx_in, bool set_action_defaults)
Definition compile.c:2047
static unlang_t * compile_case(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:2842
#define UPDATE_CTX2
Definition compile.c:126
static int compile_variable(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_PAIR *cp, tmpl_rules_t *t_rules)
Compile a variable definition.
Definition compile.c:1624
static unlang_t * compile_subrequest(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3945
static int8_t instruction_cmp(void const *one, void const *two)
Definition compile.c:5104
static bool validate_limited_subsection(CONF_SECTION *cs, char const *name)
Definition compile.c:3690
int unlang_fixup_update(map_t *map, void *ctx)
Validate and fixup a map that's part of an update section.
Definition compile.c:470
static bool compile_retry_section(unlang_mod_actions_t *actions, CONF_ITEM *ci)
Definition compile.c:1769
static int catch_argv(CONF_SECTION *cs, unlang_catch_t *ca, char const *name)
Definition compile.c:2523
static unlang_t * compile_catch(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:2543
static unlang_t * compile_return(unlang_t *parent, unlang_compile_t *unlang_ctx, UNUSED CONF_ITEM const *ci)
Definition compile.c:3483
static unlang_t * compile_limit(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3074
char const * section_name2
Definition compile.c:101
#define UNLANG_IGNORE
Definition compile.c:60
static const bool edit_list_sub_op[T_TOKEN_LAST]
Definition compile.c:1253
size_t mod_rcode_table_len
Definition compile.c:94
static int 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:4714
static unlang_t * compile_update(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:1177
static unlang_t * compile_if(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3642
static bool pass2_fixup_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules)
Definition compile.c:272
static CONF_SECTION * virtual_module_find_cs(CONF_ITEM *ci, UNUSED char const *real_name, char const *virtual_name, char const *method_name, bool *policy)
Load a named module from the virtual module list, or from the "policy" subsection.
Definition compile.c:4522
static void compile_action_defaults(unlang_t *c, unlang_compile_t *unlang_ctx)
Definition compile.c:625
static unlang_t * compile_group(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:2332
static void compile_copy_context(unlang_compile_t *dst, unlang_compile_t const *src)
Definition compile.c:111
static unlang_t * compile_parallel(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3885
static const fr_sbuff_term_t if_terminals
Definition compile.c:3544
static bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules)
Definition compile.c:245
static unlang_t * compile_if_subsection(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs, unlang_ext_t const *ext)
Definition compile.c:3549
static unsigned int unlang_number
Definition compile.c:64
static bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
Definition compile.c:153
static unlang_t * compile_foreach(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3180
static int unlang_fixup_map(map_t *map, UNUSED void *ctx)
Validate and fixup a map that's part of an map section.
Definition compile.c:404
static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
Definition compile.c:2613
virtual_server_t const * vs
Virtual server we're compiling in the context of.
Definition compile.c:97
static unlang_t * compile_transaction(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:2426
static unlang_t * compile_timeout(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:2969
static unlang_t * compile_detach(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3450
static int transaction_keywords_len
Definition compile.c:2360
static fr_rb_tree_t * unlang_instruction_tree
Definition compile.c:78
static unlang_group_t * group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_ext_t const *ext)
Definition compile.c:597
static unlang_t * compile_switch(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:2622
static int unlang_section_keywords_len
Definition compile.c:4703
unlang_t *(* unlang_op_compile_t)(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:4678
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:1087
static unlang_t * compile_try(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:2482
static fr_table_num_sorted_t transaction_keywords[]
Definition compile.c:2345
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:82
static unlang_t * compile_edit_section(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs)
Compile one edit section.
Definition compile.c:1366
static unlang_t * compile_load_balance(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:3862
static int edit_section_alloc(CONF_SECTION *parent, CONF_SECTION **child, char const *name1, fr_token_t op)
Definition compile.c:858
static int unlang_pair_keywords_len
Definition compile.c:4710
static int unlang_attr_rules_verify(tmpl_attr_rules_t const *rules)
Definition compile.c:133
static fr_table_ptr_sorted_t unlang_section_keywords[]
Definition compile.c:4680
static int8_t case_cmp(void const *one, void const *two)
Definition compile.c:2598
void * unlang_thread_instance(unlang_t const *instruction)
Get the thread-instance data for an instruction.
Definition compile.c:5168
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:1274
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:5022
static _Thread_local unlang_thread_t * unlang_thread_array
Definition compile.c:71
static unlang_t * compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
Definition compile.c:717
static 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:181
char const * section_name1
Definition compile.c:100
#define T(_x)
Definition compile.c:1251
unlang_mod_actions_t actions
Definition compile.c:102
static unlang_t * compile_tmpl(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci)
Definition compile.c:3508
static bool compile_action_subsection(unlang_t *c, CONF_SECTION *cs, CONF_SECTION *subcs)
Definition compile.c:1996
static unlang_t * compile_edit_pair(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_PAIR *cp)
Compile one edit pair.
Definition compile.c:1531
static int unlang_rules_verify(tmpl_rules_t const *rules)
Definition compile.c:142
xlat_exp_head_t * head
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:210
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:156
#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:167
#define MEM(x)
Definition debug.h:36
static fr_dict_attr_t const * attr_packet_type
Definition dhcpclient.c:89
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
#define fr_dict_autoload_talloc(_ctx, _dict_out, _proto)
Definition dict.h:856
int fr_dict_attr_acopy_local(fr_dict_attr_t const *dst, fr_dict_attr_t const *src)
Definition dict_util.c:1060
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:3263
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:2619
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:87
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3395
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4610
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition dict_util.c:2577
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:1712
fr_dict_t * fr_dict_protocol_alloc(fr_dict_t const *parent)
Allocate a new local dictionary.
Definition dict_util.c:3961
Values of the encryption flags.
Value of an enumerated attribute.
Definition dict.h:227
Test enumeration values.
Definition dict_test.h:92
Structure used to managed the lifetime of a dictionary.
Definition dict_util.c:4196
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
static unlang_foreach_t * unlang_group_to_foreach(unlang_group_t *g)
Cast a group structure to the foreach keyword extension.
fr_dict_attr_t const * value
value variable in the foreach loop
fr_dict_attr_t const * key
key variable for the foreach loop
uint32_t(* fr_hash_t)(void const *)
Definition hash.h:36
fr_htrie_t * fr_htrie_alloc(TALLOC_CTX *ctx, fr_htrie_type_t type, fr_hash_t hash_data, fr_cmp_t cmp_data, fr_trie_key_t get_key, fr_free_t free_data)
An abstraction over our internal hashes, rb trees, and prefix tries.
Definition htrie.c:92
fr_htrie_type_t
Definition htrie.h:49
@ FR_HTRIE_INVALID
Definition htrie.h:50
static fr_htrie_type_t fr_htrie_hint(fr_type_t type)
Definition htrie.h:149
static bool fr_htrie_insert(fr_htrie_t *ht, void const *data)
Insert data into a htrie.
Definition htrie.h:112
static void * fr_htrie_find(fr_htrie_t *ht, void const *data)
Find data in a htrie.
Definition htrie.h:104
#define DEBUG_ENABLED4
True if global debug level 1-3 messages are enabled.
Definition log.h:260
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition log.h:259
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:1045
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:109
int map_afrom_cs(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.
Definition map.c:1014
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:1238
ssize_t map_print(fr_sbuff_t *out, map_t const *map)
Print a map to a string.
Definition map.c:2295
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:70
talloc_free(reap)
int fr_debug_lvl
Definition log.c:43
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:583
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
uint32_t limit
Definition limit_priv.h:34
static unlang_limit_t * unlang_group_to_limit(unlang_group_t *g)
Cast a group structure to the limit keyword extension.
Definition limit_priv.h:40
tmpl_t * vpt
Definition limit_priv.h:33
static unlang_load_balance_t * unlang_group_to_load_balance(unlang_group_t *g)
Cast a group structure to the load_balance keyword extension.
bool main_config_migrate_option_get(char const *name)
struct map_s map_t
Definition map.h:33
map_proc_inst_t * proc_inst
Definition map_priv.h:35
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
map_proc_t * map_proc_find(char const *name)
Find a map processor by name.
Definition map_proc.c:87
map_proc_inst_t * map_proc_instantiate(TALLOC_CTX *ctx, map_proc_t const *proc, CONF_SECTION *cs, tmpl_t const *src, map_list_t const *maps)
Create a new map proc instance.
Definition map_proc.c:210
fr_value_box_safe_for_t map_proc_literals_safe_for(map_proc_t const *proc)
Definition map_proc.c:75
Map processor registration.
Map processor instance.
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
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
int8_t(* fr_cmp_t)(void const *a, void const *b)
Definition misc.h:38
int strcasecmp(char *s1, char *s2)
Definition missing.c:66
Unlang module actions.
@ MOD_ACTION_RETURN
Definition mod_action.h:40
@ MOD_ACTION_REJECT
Definition mod_action.h:41
@ MOD_PRIORITY_MAX
Definition mod_action.h:58
@ MOD_ACTION_RETRY
Definition mod_action.h:42
@ MOD_PRIORITY_MIN
Definition mod_action.h:44
fr_retry_config_t retry
Definition mod_action.h:63
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:62
Declarations for the unlang module interface.
static unlang_t * unlang_module_to_generic(unlang_module_t *p)
static unlang_module_t * unlang_generic_to_module(unlang_t const *p)
Definition module_priv.h:94
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:569
CONF_SECTION * module_rlm_virtual_by_name(char const *asked_name)
Definition module_rlm.c:810
module_instance_t * mi
The process modules also push module calls onto the stack for execution.
Definition module_rlm.h:63
module_method_binding_t mmb
Method we're calling.
Definition module_rlm.h:70
Declarations for the unlang "parallel" keyword.
static unlang_parallel_t * unlang_group_to_parallel(unlang_group_t *g)
Cast a group structure to the parallel keyword extension.
bool detach
are we creating the child detached
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
Definition print.c:227
size_t fr_snprint_len(char const *in, ssize_t inlen, char quote)
Find the length of the buffer required to fully escape a string with fr_prints.
Definition print.c:409
static const char * packet_name[]
#define fr_assert(_expr)
Definition rad_assert.h:38
#define WARN(fmt,...)
Definition radclient.h:47
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:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:49
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:51
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:48
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:50
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:44
fr_dict_attr_t const * request_attr_request
Definition request.c:45
static const call_env_method_t method_env
Definition rlm_detail.c:465
static char const * name
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:192
#define FR_SBUFF_OUT(_start, _len_or_end)
Set of terminal elements.
Section name identifier.
Definition section.h:44
char const * name
Instance name e.g. user_database.
Definition module.h:335
@ MODULE_TYPE_RETRY
can handle retries
Definition module.h:50
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:227
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:329
unlang_mod_actions_t actions
default actions and retries.
Definition module.h:303
call_env_method_t const * method_env
Method specific call_env.
Definition module.h:177
module_t * exported
Public module structure.
Definition module.h:276
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
Definition tmpl.h:896
#define tmpl_contains_xlat(vpt)
Definition tmpl.h:231
#define TMPL_VERIFY(_vpt)
Definition tmpl.h:969
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:645
#define tmpl_is_xlat(vpt)
Definition tmpl.h:215
#define tmpl_is_attr_unresolved(vpt)
Definition tmpl.h:224
static bool tmpl_attr_tail_is_unspecified(tmpl_t const *vpt)
Return true if the last attribute reference is "unspecified".
Definition tmpl.h:737
static fr_slen_t vpt
Definition tmpl.h:1272
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules))
Attempt to resolve functions and attributes in xlats and attribute references.
#define tmpl_value(_tmpl)
Definition tmpl.h:948
fr_table_num_sorted_t const tmpl_request_ref_table[]
Map keywords to tmpl_request_ref_t values.
tmpl_t * tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len)
Create a new heap allocated tmpl_t.
#define tmpl_contains_regex(vpt)
Definition tmpl.h:230
fr_value_box_safe_for_t literals_safe_for
safe_for value assigned to literal values in xlats, execs, and data.
Definition tmpl.h:356
#define tmpl_is_attr(vpt)
Definition tmpl.h:213
#define NUM_ALL
Definition tmpl.h:400
fr_dict_attr_t const * enumv
Enumeration attribute used to resolve enum values.
Definition tmpl.h:347
tmpl_rules_t const * parent
for parent / child relationships
Definition tmpl.h:342
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
Definition tmpl.h:915
#define tmpl_rules_cast(_tmpl)
Definition tmpl.h:953
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_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
Definition tmpl.h:189
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition tmpl.h:146
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition tmpl.h:150
@ TMPL_TYPE_NULL
Has no value.
Definition tmpl.h:138
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition tmpl.h:154
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition tmpl.h:142
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition tmpl.h:183
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
Definition tmpl.h:197
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function 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:828
#define NUM_COUNT
Definition tmpl.h:401
#define tmpl_contains_attr(vpt)
Definition tmpl.h:229
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.
bool at_runtime
Produce an ephemeral/runtime tmpl.
Definition tmpl.h:353
static bool tmpl_is_list(tmpl_t const *vpt)
Definition tmpl.h:931
ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, fr_sbuff_t *name, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
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...
#define tmpl_is_data(vpt)
Definition tmpl.h:211
fr_dict_t const * dict_def
Alternative default dictionary to use if vpt->rules->dict_def is NULL.
Definition tmpl.h:374
#define TMPL_POOL_DEF_HEADERS
Define manipulation functions for the attribute reference list.
Definition tmpl.h:495
#define NUM_UNSPEC
Definition tmpl.h:399
static size_t tmpl_attr_num_elements(tmpl_t const *vpt)
The number of attribute references contained within a tmpl.
Definition tmpl.h:907
#define tmpl_value_type(_tmpl)
Definition tmpl.h:950
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:222
fr_type_t cast
Whether there was an explicit cast.
Definition tmpl.h:349
#define TMPL_POOL_DEF_LEN
How many additional bytes to allocate in a pool for a tmpl_t.
Definition tmpl.h:500
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:344
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:812
#define tmpl_is_null(vpt)
Definition tmpl.h:210
struct tmpl_res_rules_s tmpl_res_rules_t
Definition tmpl.h:240
static char const * tmpl_list_name(fr_dict_attr_t const *list, char const *def)
Return the name of a tmpl list or def if list not provided.
Definition tmpl.h:926
@ REQUEST_UNKNOWN
Unknown request.
Definition tmpl.h:97
struct tmpl_rules_s tmpl_rules_t
Definition tmpl.h:236
#define tmpl_is_regex_xlat_unresolved(vpt)
Definition tmpl.h:226
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.
int tmpl_cast_set(tmpl_t *vpt, fr_type_t type)
Set a cast for a tmpl.
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Definition tmpl_eval.c:209
Similar to tmpl_rules_t, but used to specify parameters that may change during subsequent resolution ...
Definition tmpl.h:373
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:341
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
Define entry and head types for tmpl request references.
Definition tmpl.h:284
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
Definition tmpl.h:307
uint8_t allow_foreign
Allow arguments not found in dict_def.
Definition tmpl.h:327
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:285
uint8_t allow_wildcard
Allow the special case of .
Definition tmpl.h:324
uint8_t allow_unknown
Allow unknown attributes i.e.
Definition tmpl.h:316
static unlang_subrequest_t * unlang_group_to_subrequest(unlang_group_t *g)
Cast a group structure to the subrequest keyword extension.
tmpl_t * vpt
Value to expand to find the value to place into the packet-type attribute.
fr_dict_attr_t const * attr_packet_type
Packet-type attribute in the subrequest protocol.
tmpl_t * src
Pairs to copy into the subrequest request list.
fr_dict_t const * dict
Dictionary of the subrequest protocol.
tmpl_t * dst
Where to copy pairs from the reply list in the subrequest to.
fr_dict_enum_value_t const * type_enum
Static enumeration value for attr_packet_type.
fr_htrie_t * ht
Definition switch_priv.h:36
static unlang_switch_t * unlang_group_to_switch(unlang_group_t *g)
Cast a group structure to the switch keyword extension.
Definition switch_priv.h:42
unlang_t * default_case
Definition switch_priv.h:34
tmpl_t * vpt
Definition switch_priv.h:57
static unlang_case_t * unlang_group_to_case(unlang_group_t *g)
Cast a group structure to the case keyword extension.
Definition switch_priv.h:63
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
#define fr_table_value_by_substr(_table, _name, _name_len, _def)
Convert a partial string to a value using an ordered or sorted table.
Definition table.h:693
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
An element in a lexicographically sorted array of name to ptr mappings.
Definition table.h:65
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:492
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:445
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:449
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
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_delta_ispos(_a)
Definition time.h:290
@ FR_TIME_RES_SEC
Definition time.h:50
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"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.
fr_time_delta_t timeout
static unlang_timeout_t * unlang_group_to_timeout(unlang_group_t *g)
Cast a group structure to the timeout keyword extension.
const bool fr_assignment_op[T_TOKEN_LAST]
Definition token.c:168
const bool fr_list_assignment_op[T_TOKEN_LAST]
Definition token.c:185
fr_table_num_ordered_t const fr_tokens_table[]
Definition token.c:33
char const * fr_tokens[T_TOKEN_LAST]
Definition token.c:78
const bool fr_comparison_op[T_TOKEN_LAST]
Definition token.c:198
const bool fr_binary_op[T_TOKEN_LAST]
Definition token.c:216
enum fr_token fr_token_t
@ T_OP_SUB_EQ
Definition token.h:70
@ T_INVALID
Definition token.h:39
@ T_SINGLE_QUOTED_STRING
Definition token.h:122
@ T_OP_CMP_TRUE
Definition token.h:104
@ T_BARE_WORD
Definition token.h:120
@ T_OP_EQ
Definition token.h:83
@ T_BACK_QUOTED_STRING
Definition token.h:123
@ T_OP_SET
Definition token.h:84
@ T_OP_NE
Definition token.h:97
@ T_OP_ADD_EQ
Definition token.h:69
@ T_OP_CMP_FALSE
Definition token.h:105
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
@ T_OP_CMP_EQ
Definition token.h:106
@ T_OP_LE
Definition token.h:100
@ T_OP_GE
Definition token.h:98
@ T_OP_GT
Definition token.h:99
@ T_OP_LT
Definition token.h:101
@ T_OP_PREPEND
Definition token.h:85
#define T_TOKEN_LAST
Definition token.h:129
Declarations for unlang transactions.
int(* fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data)
Definition trie.h:56
Declaration for unlang try.
tmpl_res_rules_t const * tr_rules
tmpl resolution rules.
Definition xlat.h:163
static fr_slen_t e_rules bool xlat_is_truthy(xlat_exp_head_t const *head, bool *out)
Allow callers to see if an xlat is truthy.
Definition xlat_expr.c:3188
static fr_slen_t head
Definition xlat.h:422
int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
Walk over an xlat tree recursively, resolving any unresolved functions or references.
fr_slen_t xlat_tokenize_condition(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
Definition xlat_expr.c:3171
#define unlang_frame_perf_resume(_x)
unlang_t * next
Next node (executed on UNLANG_ACTION_EXECUTE_NEXT et al).
CONF_SECTION * cs
char const * debug_name
Printed in log messages when the node is executed.
char const * type_name
Talloc type name.
void * state
Stack frame specialisations.
unlang_mod_actions_t actions
Priorities, etc. for the various return codes.
unlang_t * parent
Previous node.
char const * thread_inst_type
fr_dict_attr_t const * root
the root of our dictionary
#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)
unlang_t ** tail
pointer to the tail which gets updated
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
char const * name
Unknown...
@ UNLANG_TYPE_SWITCH
Switch section.
Definition unlang_priv.h:57
@ UNLANG_TYPE_TRANSACTION
transactions for editing lists
Definition unlang_priv.h:70
@ UNLANG_TYPE_SUBREQUEST
create a child subrequest
Definition unlang_priv.h:64
@ UNLANG_TYPE_UPDATE
Update block.
Definition unlang_priv.h:56
@ UNLANG_TYPE_ELSIF
!Condition && Condition.
Definition unlang_priv.h:55
@ UNLANG_TYPE_ELSE
!Condition.
Definition unlang_priv.h:54
@ UNLANG_TYPE_LOAD_BALANCE
Load balance section.
Definition unlang_priv.h:50
@ UNLANG_TYPE_DETACH
detach a child
Definition unlang_priv.h:65
@ UNLANG_TYPE_GROUP
Grouping section.
Definition unlang_priv.h:48
@ UNLANG_TYPE_POLICY
Policy section.
Definition unlang_priv.h:73
@ UNLANG_TYPE_TMPL
asynchronously expand a tmpl_t
Definition unlang_priv.h:75
@ UNLANG_TYPE_CASE
Case section (within a UNLANG_TYPE_SWITCH).
Definition unlang_priv.h:58
@ UNLANG_TYPE_LIMIT
limit number of requests in a section
Definition unlang_priv.h:69
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH).
Definition unlang_priv.h:60
@ UNLANG_TYPE_TRY
try / catch blocks
Definition unlang_priv.h:71
@ UNLANG_TYPE_CALL
call another virtual server
Definition unlang_priv.h:66
@ UNLANG_TYPE_RETURN
Return statement.
Definition unlang_priv.h:61
@ UNLANG_TYPE_REDUNDANT
exactly like group, but with different default return codes
Definition unlang_priv.h:49
@ UNLANG_TYPE_MAX
Definition unlang_priv.h:77
@ UNLANG_TYPE_IF
Condition.
Definition unlang_priv.h:53
@ UNLANG_TYPE_XLAT
Represents one level of an xlat expansion.
Definition unlang_priv.h:74
@ UNLANG_TYPE_NULL
unlang type not set.
Definition unlang_priv.h:45
@ UNLANG_TYPE_MAP
Mapping section (like UNLANG_TYPE_UPDATE, but uses values from a map_proc_t call).
Definition unlang_priv.h:62
@ UNLANG_TYPE_CALLER
conditionally check parent dictionary type
Definition unlang_priv.h:67
@ UNLANG_TYPE_TIMEOUT
time-based timeouts.
Definition unlang_priv.h:68
@ UNLANG_TYPE_MODULE
Module method.
Definition unlang_priv.h:46
@ UNLANG_TYPE_REDUNDANT_LOAD_BALANCE
Redundant load balance section.
Definition unlang_priv.h:51
@ UNLANG_TYPE_CATCH
catch a previous try
Definition unlang_priv.h:72
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
Definition unlang_priv.h:47
@ UNLANG_TYPE_EDIT
edit VPs in place. After 20 years!
Definition unlang_priv.h:76
@ UNLANG_TYPE_FOREACH
Foreach section.
Definition unlang_priv.h:59
@ UNLANG_TYPE_PARALLEL
execute statements in parallel
Definition unlang_priv.h:52
unlang_t const * instruction
The unlang node we're evaluating.
bool debug_braces
Whether the operation needs to print braces in debug mode.
size_t len
Total length of the unlang_group_t + specialisation struct.
unlang_type_t type
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 operation.
#define unlang_frame_perf_yield(_x)
size_t pool_len
How much additional space to allocate for extensions.
unsigned pool_headers
How much additional space to allocate for chunk headers.
#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
tmpl_t const * tmpl
unlang_type_t type
The specialisation of this node.
unlang_t * children
Children beneath this group.
size_t thread_inst_size
void * thread_inst
thread-specific instance data
Describes how to allocate an unlang_group_t with additional memory keyword specific 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:851
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:554
#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:371
#define fr_type_is_numeric(_x)
Definition types.h:361
#define FR_TYPE_INTEGER_EXCEPT_BOOL
Definition types.h:283
#define fr_type_is_leaf(_x)
Definition types.h:372
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition value.c:6129
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:3352
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:676
int fr_value_box_to_key(uint8_t **out, size_t *outlen, fr_value_box_t const *value)
Get a key from a value box.
Definition value.c:2084
static fr_slen_t data
Definition value.h:1265
static size_t char ** out
Definition value.h:997
fr_dict_t const * virtual_server_dict_by_name(char const *virtual_server)
Return the namespace for the named virtual server.
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.
static bool is_truthy(xlat_exp_t *node, bool *out)