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