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