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