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