The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
tmpl_tokenize.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: 6d6d65a26488c2c79b0252be5445096d23bc9032 $
19  *
20  * @brief #fr_pair_t template functions
21  * @file src/lib/server/tmpl_tokenize.c
22  *
23  * @ingroup AVP
24  *
25  * @copyright 2014-2020 The FreeRADIUS server project
26  */
27 RCSID("$Id: 6d6d65a26488c2c79b0252be5445096d23bc9032 $")
28 
29 #define _TMPL_PRIVATE 1
30 
31 #include <freeradius-devel/server/tmpl.h>
32 #include <freeradius-devel/server/base.h>
33 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
34 
35 #include <freeradius-devel/util/debug.h>
36 #include <freeradius-devel/util/base16.h>
37 #include <freeradius-devel/util/misc.h>
38 
39 #include <freeradius-devel/util/sbuff.h>
40 #include <freeradius-devel/util/value.h>
41 
42 #include <ctype.h>
43 
44 /** Define a global variable for specifying a default request reference
45  *
46  * @param[in] _name what the global variable should be called.
47  * @param[in] _ref one of the values of tmpl_request_ref_t
48  * - REQUEST_CURRENT
49  * - REQUEST_OUTER,
50  * - REQUEST_PARENT,
51  * - REQUEST_UNKNOWN
52  */
53 #define TMPL_REQUEST_REF_DEF(_name, _ref) \
54 static tmpl_request_t _name ## _entry = { \
55  .entry = { \
56  .entry = { \
57  .next = &_name.head.entry, \
58  .prev = &_name.head.entry \
59  } \
60  }, \
61  .request = _ref \
62 }; \
63 FR_DLIST_HEAD(tmpl_request_list) _name = { \
64  .head = { \
65  .offset = offsetof(tmpl_request_t, entry), \
66  .entry = { \
67  .next = &_name ## _entry.entry.entry, \
68  .prev = &_name ## _entry.entry.entry, \
69  }, \
70  .num_elements = 1, \
71  } \
72 }
73 
74 /** Use the current request as the default
75  *
76  * Used as .attr.request_def = \&tmpl_request_def_current;
77  */
78 TMPL_REQUEST_REF_DEF(tmpl_request_def_current, REQUEST_CURRENT);
79 
80 /** Use the outer request as the default
81  *
82  * Used as .attr.request_def = \&tmpl_request_def_outer;
83  */
84 TMPL_REQUEST_REF_DEF(tmpl_request_def_outer, REQUEST_OUTER);
85 
86 /** Use the parent request as the default
87  *
88  * Used as .attr.request_def = \&tmpl_request_def_parent;
89  */
90 TMPL_REQUEST_REF_DEF(tmpl_request_def_parent, REQUEST_PARENT);
91 
92 /** Default parser rules
93  *
94  * Because this is getting to be a ridiculous number of parsing rules
95  * to pass in via arguments.
96  *
97  * Defaults are used if a NULL rules pointer is passed to the parsing function.
98  */
99 #define DEFAULT_RULES tmpl_rules_t const default_rules = { .attr = { .list_def = request_attr_request }}
100 
101 
102 /* clang-format off */
103 /** Map #tmpl_type_t values to descriptive strings
104  */
106  { L("uninitialised"), TMPL_TYPE_UNINITIALISED },
107 
108  { L("null"), TMPL_TYPE_NULL },
109  { L("data"), TMPL_TYPE_DATA },
110 
111  { L("attr"), TMPL_TYPE_ATTR },
112 
113  { L("exec"), TMPL_TYPE_EXEC },
114  { L("xlat"), TMPL_TYPE_XLAT },
115 
116  { L("regex"), TMPL_TYPE_REGEX },
117  { L("regex-uncompiled"), TMPL_TYPE_REGEX_UNCOMPILED },
118  { L("regex-xlat"), TMPL_TYPE_REGEX_XLAT },
119 
120  { L("data-unresolved"), TMPL_TYPE_DATA_UNRESOLVED },
121  { L("attr-unresolved"), TMPL_TYPE_ATTR_UNRESOLVED },
122  { L("exec-unresolved"), TMPL_TYPE_EXEC_UNRESOLVED },
123  { L("xlat-unresolved"), TMPL_TYPE_XLAT_UNRESOLVED },
124  { L("regex-unresolved"), TMPL_TYPE_REGEX_XLAT_UNRESOLVED }
125 };
127 
128 /** Attr ref types
129  */
131  { L("normal"), TMPL_ATTR_TYPE_NORMAL },
132  { L("unspecified"), TMPL_ATTR_TYPE_UNSPEC },
133  { L("unknown"), TMPL_ATTR_TYPE_UNKNOWN },
134  { L("unresolved"), TMPL_ATTR_TYPE_UNRESOLVED }
135 };
137 
138 /** Map keywords to #tmpl_request_ref_t values
139  */
141  { L("current"), REQUEST_CURRENT },
142  { L("outer"), REQUEST_OUTER },
143  { L("parent"), REQUEST_PARENT },
144 };
146 
147 
148 /** Special attribute reference indexes
149  */
151  { L("*"), NUM_ALL },
152  { L("#"), NUM_COUNT },
153  { L("u"), NUM_UNSPEC },
154  { L("n"), NUM_LAST }
155 };
157 /* clang-format on */
158 
159 static void attr_to_raw(tmpl_t *vpt, tmpl_attr_t *ref);
160 
161 /*
162  * Can't use |= or ^= else we get out of range errors
163  */
164 #define UNRESOLVED_SET(_flags) (*(_flags) = (*(_flags) | TMPL_FLAG_UNRESOLVED))
165 #define RESOLVED_SET(_flags) (*(_flags) = (*(_flags) & ~TMPL_FLAG_UNRESOLVED))
166 
167 /** Verify, after skipping whitespace, that a substring ends in a terminal char, or ends without further chars
168  *
169  * @param[in] in the sbuff to check.
170  * @param[in] p_rules to use terminals from.
171  * @return
172  * - true if substr is terminated correctly.
173  * - false if subst is not terminated correctly.
174  */
175 static inline bool CC_HINT(always_inline) tmpl_substr_terminal_check(fr_sbuff_t *in,
176  fr_sbuff_parse_rules_t const *p_rules)
177 {
179  bool ret;
180 
181  if (!fr_sbuff_extend(in)) return true; /* we're at the end of the string */
182  if (!p_rules || !p_rules->terminals) return false; /* more stuff to parse but don't have a terminal set */
183 
184  fr_sbuff_marker(&m, in);
185  ret = fr_sbuff_is_terminal(in, p_rules->terminals);
186  fr_sbuff_set(in, &m);
187  fr_sbuff_marker_release(&m);
188  return ret;
189 }
190 
191 void tmpl_attr_ref_debug(const tmpl_attr_t *ar, int i)
192 {
193  char buffer[sizeof(STRINGIFY(INT16_MAX)) + 1];
194 
195  snprintf(buffer, sizeof(buffer), "%i", ar->ar_num);
196 
197  switch (ar->type) {
201  if (!ar->da) {
202  FR_FAULT_LOG("\t[%u] %s null%s%s%s",
203  i,
204  fr_table_str_by_value(attr_table, ar->type, "<INVALID>"),
205  ar->ar_num != NUM_UNSPEC ? "[" : "",
206  ar->ar_num != NUM_UNSPEC ? fr_table_str_by_value(attr_num_table, ar->ar_num, buffer) : "",
207  ar->ar_num != NUM_UNSPEC ? "]" : "");
208  return;
209  }
210 
211  FR_FAULT_LOG("\t[%u] %s %s %s%s%s%s (%p) attr %u",
212  i,
213  fr_table_str_by_value(attr_table, ar->type, "<INVALID>"),
214  fr_type_to_str(ar->da->type),
215  ar->da->name,
216  ar->ar_num != NUM_UNSPEC ? "[" : "",
217  ar->ar_num != NUM_UNSPEC ? fr_table_str_by_value(attr_num_table, ar->ar_num, buffer) : "",
218  ar->ar_num != NUM_UNSPEC ? "]" : "",
219  ar->da,
220  ar->da->attr
221  );
222  FR_FAULT_LOG("\t is_raw : %s", ar_is_raw(ar) ? "yes" : "no");
223  FR_FAULT_LOG("\t is_unknown : %s", ar_is_unknown(ar) ? "yes" : "no");
224  if (ar->ar_parent) FR_FAULT_LOG("\t parent : %s (%p)", ar->ar_parent->name, ar->ar_parent);
225  break;
226 
227 
229  /*
230  * Type reveals unresolved status
231  * so we don't need to add it explicitly
232  */
233  FR_FAULT_LOG("\t[%u] %s %s%s%s%s",
234  i,
235  fr_table_str_by_value(attr_table, ar->type, "<INVALID>"),
236  ar->ar_unresolved,
237  ar->ar_num != NUM_UNSPEC ? "[" : "",
238  ar->ar_num != NUM_UNSPEC ? fr_table_str_by_value(attr_num_table, ar->ar_num, buffer) : "",
239  ar->ar_num != NUM_UNSPEC ? "]" : "");
240  if (ar->ar_parent) FR_FAULT_LOG("\t parent : %s", ar->ar_parent->name);
241  if (ar->ar_unresolved_namespace) FR_FAULT_LOG("\t namespace : %s", ar->ar_unresolved_namespace->name);
242  break;
243 
244  default:
245  FR_FAULT_LOG("\t[%u] Bad type %s(%u)",
246  i, fr_table_str_by_value(attr_table, ar->type, "<INVALID>"), ar->type);
247  break;
248  }
249 }
250 
251 void tmpl_attr_ref_list_debug(FR_DLIST_HEAD(tmpl_attr_list) const *ar_head)
252 {
253  tmpl_attr_t *ar = NULL;
254  unsigned int i = 0;
255 
256  FR_FAULT_LOG("attribute references:");
257  /*
258  * Print all the attribute references
259  */
260  while ((ar = tmpl_attr_list_next(ar_head, ar))) {
261  tmpl_attr_ref_debug(ar, i);
262  i++;
263  }
264 }
265 
267 {
268  tmpl_request_t *rr = NULL;
269  unsigned int i = 0;
270 
271  switch (vpt->type) {
272  case TMPL_TYPE_ATTR:
274  break;
275 
276  default:
277  FR_FAULT_LOG("%s can't print tmpls of type %s", __FUNCTION__,
278  tmpl_type_to_str(vpt->type));
279  return;
280  }
281 
282  FR_FAULT_LOG("tmpl_t %s (%.8x) \"%pV\" (%p)",
283  tmpl_type_to_str(vpt->type),
284  vpt->type,
285  fr_box_strvalue_len(vpt->name, vpt->len), vpt);
286 
288  FR_FAULT_LOG("\tquote : %s", fr_table_str_by_value(fr_token_quotes_table, vpt->quote, "<INVALID>"));
289 
290  FR_FAULT_LOG("request references:");
291 
292  /*
293  * Print all the request references
294  */
295  while ((rr = tmpl_request_list_next(&vpt->data.attribute.rr, rr))) {
296  FR_FAULT_LOG("\t[%u] %s (%u)", i,
298  i++;
299  }
300 
301  FR_FAULT_LOG("list: %s", tmpl_list_name(tmpl_list(vpt), "<INVALID>"));
303 }
304 
305 void tmpl_debug(tmpl_t const *vpt)
306 {
307  switch (vpt->type) {
308  case TMPL_TYPE_ATTR:
311  return;
312 
313  default:
314  break;
315  }
316 
317  FR_FAULT_LOG("tmpl_t %s (%.8x) \"%pR\" (%p)",
318  tmpl_type_to_str(vpt->type),
319  vpt->type,
320  fr_box_strvalue_len(vpt->name, vpt->len), vpt);
321 
323  FR_FAULT_LOG("\tquote : %s", fr_table_str_by_value(fr_token_quotes_table, vpt->quote, "<INVALID>"));
324  switch (vpt->type) {
325  case TMPL_TYPE_NULL:
326  return;
327 
328  case TMPL_TYPE_DATA:
330  FR_FAULT_LOG("\tlen : %zu", tmpl_value_length(vpt));
331  FR_FAULT_LOG("\tvalue : %pV", tmpl_value(vpt));
332 
333  if (tmpl_value_enumv(vpt)) FR_FAULT_LOG("\tenumv : %s (%p)",
335  return;
336 
337  case TMPL_TYPE_XLAT:
338  case TMPL_TYPE_EXEC:
340  {
341  char *str;
342 
343  xlat_aprint(NULL, &str, tmpl_xlat(vpt), NULL);
344 
345  FR_FAULT_LOG("\texpansion : %pR", fr_box_strvalue_buffer(str));
346 
347  talloc_free(str);
348  }
349  break;
350 
351  case TMPL_TYPE_REGEX:
352  {
353  FR_FAULT_LOG("\tpattern : %pR", fr_box_strvalue_len(vpt->name, vpt->len));
354  }
355  break;
356 
357  default:
358  if (tmpl_needs_resolving(vpt)) {
360  FR_FAULT_LOG("\tunescaped : %pR", fr_box_strvalue_buffer(vpt->data.unescaped));
361  FR_FAULT_LOG("\tlen : %zu", talloc_array_length(vpt->data.unescaped) - 1);
362  } else {
363  FR_FAULT_LOG("\tunresolved : %pR", fr_box_strvalue_len(vpt->name, vpt->len));
364  FR_FAULT_LOG("\tlen : %zu", vpt->len);
365  }
366  } else {
367  FR_FAULT_LOG("debug nyi");
368  }
369  break;
370  }
371 }
372 
373 /** @name Parse list and request qualifiers to #fr_pair_list_t and #tmpl_request_ref_t values
374  *
375  * These functions also resolve #fr_pair_list_t and #tmpl_request_ref_t values to #request_t
376  * structs and the head of #fr_pair_t lists in those structs.
377  *
378  * For adding new #fr_pair_t to the lists, the #tmpl_list_ctx function can be used
379  * to obtain the appropriate TALLOC_CTX pointer.
380  *
381  * @note These don't really have much to do with #tmpl_t. They're in the same
382  * file as they're used almost exclusively by the tmpl_* functions.
383  * @{
384  */
385 
386 /** Parse one a single list reference
387  *
388  * @param[out] da_p attribute representing a list.
389  * @param[in] in Sbuff to read request references from.
390  * @return
391  * - > 0 the number of bytes parsed.
392  * - 0 no list qualifier found.
393  */
395 {
396  fr_dict_attr_t const *da;
397  fr_sbuff_t our_in = FR_SBUFF(in);
398 
399  if (((fr_sbuff_adv_past_strcase(&our_in, request_attr_request->name, request_attr_request->name_len)) &&
400  (da = request_attr_request)) ||
401  ((fr_sbuff_adv_past_strcase(&our_in, request_attr_reply->name, request_attr_reply->name_len)) &&
402  (da = request_attr_reply)) ||
404  (da = request_attr_control)) ||
405  ((fr_sbuff_adv_past_strcase(&our_in, request_attr_state->name, request_attr_state->name_len)) &&
406  (da = request_attr_state))) {
407  /* note: no local variables */
408  *da_p = da;
409  FR_SBUFF_SET_RETURN(in, &our_in);
410  }
411 
412  return 0;
413 }
414 
415  /** Allocate a new request reference and add it to the end of the attribute reference list
416  *
417  */
418 static inline CC_HINT(always_inline) CC_HINT(nonnull(2,3))
419 void tmpl_request_ref_list_copy(TALLOC_CTX *ctx,
420  FR_DLIST_HEAD(tmpl_request_list) *out, FR_DLIST_HEAD(tmpl_request_list) const *in)
421 {
422  tmpl_request_t *rr = NULL;
423  tmpl_request_t *n_rr = NULL;
424 
425  /*
426  * Duplicate the complete default list
427  */
428  while ((rr = tmpl_request_list_next(in, rr))) {
429  MEM(n_rr = talloc(ctx, tmpl_request_t));
430  *n_rr = (tmpl_request_t){
431  .request = rr->request
432  };
433  tmpl_request_list_insert_tail(out, n_rr);
434  ctx = n_rr; /* Chain the contexts */
435  }
436 }
437 
438  /** Allocate a new request reference list and copy request references into it
439  *
440  */
441 static inline CC_HINT(always_inline) CC_HINT(nonnull(2,3))
442 void tmpl_request_ref_list_acopy(TALLOC_CTX *ctx,
443  FR_DLIST_HEAD(tmpl_request_list) **out, FR_DLIST_HEAD(tmpl_request_list) const *in)
444 {
445  FR_DLIST_HEAD(tmpl_request_list) *rql;
446 
447  MEM(rql = talloc_zero(ctx, FR_DLIST_HEAD(tmpl_request_list)));
448  tmpl_request_list_talloc_init(rql);
449 
450  tmpl_request_ref_list_copy(rql, rql, in);
451 
452  *out = rql;
453 }
454 
455 /** Dump a request list to stderr
456  *
457  */
458 void tmpl_request_ref_list_debug(FR_DLIST_HEAD(tmpl_request_list) const *rql)
459 {
460  tmpl_request_t *rr = NULL;
461 
462  while ((rr = tmpl_request_list_next(rql, rr))) {
463  FR_FAULT_LOG("request - %s (%u)",
465  rr->request);
466  }
467 }
468 
469 /** Compare a list of request qualifiers
470  *
471  * @param[in] a first list. If NULL tmpl_request_def_current will be used.
472  * @param[in] b second list. If NULL tmpl_request_def_current will be used.
473  * @return
474  * - >0 a > b
475  * - 0 a == b
476  * - <0 a < b
477  */
478 int8_t tmpl_request_ref_list_cmp(FR_DLIST_HEAD(tmpl_request_list) const *a, FR_DLIST_HEAD(tmpl_request_list) const *b)
479 {
480  tmpl_request_t *a_rr = NULL, *b_rr = NULL;
481 
482  /*
483  * NULL, uninit, empty are all equivalent
484  * to tmpl_request_def_current.
485  *
486  * We need all these equivalent checks to
487  * deal with uninitialised tmpl rules.
488  */
489  if (!a || !tmpl_request_list_initialised(a) || tmpl_request_list_empty(a)) a = &tmpl_request_def_current;
490  if (!b || !tmpl_request_list_initialised(b) || tmpl_request_list_empty(b)) b = &tmpl_request_def_current;
491 
492  /*
493  * Fast path...
494  */
495  if (a == b) return 0;
496 
497  for (;;) {
498  a_rr = tmpl_request_list_next(a, a_rr);
499  b_rr = tmpl_request_list_next(b, b_rr);
500 
501  if (!a_rr || !b_rr) return CMP(tmpl_request_list_num_elements(a), tmpl_request_list_num_elements(b));
502 
503  CMP_RETURN(a_rr, b_rr, request);
504  }
505 }
506 
507 /** Parse one or more request references, writing the list to out
508  *
509  * @param[in] ctx to allocate request refs in.
510  * @param[out] err If !NULL where to write the parsing error.
511  * @param[in] out The list to write to.
512  * @param[in] in Sbuff to read request references from.
513  * @param[in] p_rules Parse rules.
514  * @param[in] t_rules Default list and other rules.
515  * @param[out] namespace the namespace to use
516  * @return
517  * - >= 0 the number of bytes parsed.
518  * - <0 negative offset for where the error occurred
519  */
521  FR_DLIST_HEAD(tmpl_request_list) *out,
522  fr_sbuff_t *in,
523  fr_sbuff_parse_rules_t const *p_rules,
524  tmpl_rules_t const *t_rules,
525  fr_dict_attr_t const **namespace)
526 {
527  tmpl_request_ref_t ref;
528  tmpl_request_t *rr;
529  size_t ref_len;
530  fr_sbuff_t our_in = FR_SBUFF(in);
531  tmpl_request_t *tail = tmpl_request_list_tail(out);
532  unsigned int depth = 0;
534  tmpl_attr_rules_t const *at_rules;
536 
537  if (!t_rules) {
538  at_rules = &default_rules.attr;
539  } else {
540  at_rules = &t_rules->attr;
541  }
542 
543  /*
544  * The caller wants to know the default namespace for
545  * resolving the attribute.
546  *
547  * @todo - why not use dict_def if it's set? Tho TBH we
548  * should probably just remove dict_def, and always use "namespace".
549  */
550  if (namespace) {
551  if (at_rules->namespace) {
552  *namespace = at_rules->namespace;
553  } else {
554  *namespace = NULL;
555  }
556  }
557 
558  /*
559  * We could make the caller do this but as this
560  * function is intended to help populate tmpl rules,
561  * just be nice...
562  */
563  if (!tmpl_request_list_initialised(out)) tmpl_request_list_talloc_init(out);
564 
565  fr_sbuff_marker(&m, &our_in);
567  bool end;
568 
569  /*
570  * Search for a known request reference like
571  * 'current', or 'parent'.
572  */
574 
575  /*
576  * No match
577  */
578  if (ref_len == 0) {
579  /*
580  * If depth == 0, we're at the start
581  * so just use the default request
582  * reference.
583  */
584  default_ref:
585  if ((depth == 0) && at_rules->request_def) {
586  tmpl_request_ref_list_copy(ctx, out, at_rules->request_def);
587  }
588  break;
589  }
590 
591  /*
592  * We don't want to misidentify the list
593  * as being part of an attribute.
594  */
595  if (!fr_sbuff_is_char(&our_in, '.') && (fr_sbuff_is_in_charset(&our_in, fr_dict_attr_allowed_chars) || !tmpl_substr_terminal_check(&our_in, p_rules))) {
596  goto default_ref;
597  }
598 
599  if (depth == 0) {
600  if (at_rules->namespace || (at_rules->list_presence == TMPL_ATTR_LIST_FORBID)) {
601  fr_strerror_const("List qualifiers are not allowed here");
603 
604  fr_sbuff_set(&our_in, in); /* Marker at the start */
605  error:
606  tmpl_request_list_talloc_free_to_tail(out, tail);
607  FR_SBUFF_ERROR_RETURN(&our_in);
608  }
609  }
610 
611  /*
612  * If the caller is asking for a namespace, then walk back up the tmpl_rules_t to find a parent namespace.
613  */
614  if (namespace && t_rules && t_rules->parent) {
615  t_rules = t_rules->parent;
616 
617  switch (ref) {
618  case REQUEST_OUTER:
619  while (t_rules->parent) t_rules = t_rules->parent; /* Walk back to the root */
620  FALL_THROUGH;
621 
622  case REQUEST_PARENT:
623  if (t_rules->attr.namespace) {
624  *namespace = t_rules->attr.namespace;
625  } else if (t_rules->attr.dict_def) {
626  *namespace = fr_dict_root(t_rules->attr.dict_def);
627  } else {
628  *namespace = NULL;
629  }
630  break;
631 
632  default:
633  break;
634  }
635  }
636 
637  /*
638  * Add a new entry to the dlist
639  */
640  MEM(rr = talloc(ctx, tmpl_request_t));
641  *rr = (tmpl_request_t){
642  .request = ref
643  };
644  tmpl_request_list_insert_tail(out, rr);
645 
646  /*
647  * Advance past the separator (if there is one)
648  */
649  end = !fr_sbuff_next_if_char(&our_in, '.');
650 
651  /*
652  * Update to the last successfully parsed component
653  *
654  * This makes it easy to backtrack from refs like
655  *
656  * parent.outer-realm-name
657  */
658  fr_sbuff_set(&m, &our_in);
659 
660  if (end) break;
661  }
662 
663  /*
664  * Nesting level too deep
665  */
667  fr_strerror_const("Request ref nesting too deep");
669  goto error; /* Leave marker at the end */
670  }
671 
672  FR_SBUFF_SET_RETURN(in, &m);
673 }
674 
675 /** Parse one or more request references, allocing a new list and adding the references to it
676  *
677  * This can be used to create request ref lists for rules and for tmpls.
678  *
679  * @param[in] ctx to allocate request refs in.
680  * @param[out] err If !NULL where to write the parsing error.
681  * @param[out] out The new list.
682  * @param[in] in Sbuff to read request references from.
683  * @return
684  * - >= 0 the number of bytes parsed.
685  * - <0 negative offset for where the error occurred
686  */
688  FR_DLIST_HEAD(tmpl_request_list) **out,
689  fr_sbuff_t *in)
690 {
691  fr_slen_t slen;
692 
693  FR_DLIST_HEAD(tmpl_request_list) *rql;
694 
695  MEM(rql = talloc_zero(ctx, FR_DLIST_HEAD(tmpl_request_list)));
696  tmpl_request_list_talloc_init(rql);
697 
698  slen = tmpl_request_ref_list_from_substr(rql, err, rql, in, NULL, NULL, NULL);
699  if (slen < 0) {
700  talloc_free(rql);
701  return slen;
702  }
703 
704  *out = rql;
705 
706  return slen;
707 }
708 /** @} */
709 
710 /** @name Alloc or initialise #tmpl_t
711  *
712  * @note Should not usually be called outside of tmpl_* functions, use one of
713  * the tmpl_*from_* functions instead.
714  * @{
715  */
716 
717 /** Initialise fields inside a tmpl depending on its type
718  *
719  */
720 static inline CC_HINT(always_inline) void tmpl_type_init(tmpl_t *vpt, tmpl_type_t type)
721 {
722 
723  switch (type) {
724 #ifndef HAVE_REGEX
725  case TMPL_TYPE_REGEX:
729  fr_assert(0);
730  return;
731 #endif
732 
733  case TMPL_TYPE_ATTR:
735  tmpl_attr_list_talloc_init(tmpl_attr(vpt));
736  tmpl_request_list_talloc_init(&vpt->data.attribute.rr);
737  break;
738 
739  default:
740  break;
741  }
742  vpt->type = type;
743  }
744 
745 /** Set the name on a pre-initialised tmpl
746  *
747  * @param[in] vpt to set the name for.
748  * @param[in] quote Original quoting around the name.
749  * @param[in] fmt string.
750  * @param[in] ... format arguments.
751  */
752 void tmpl_set_name_printf(tmpl_t *vpt, fr_token_t quote, char const *fmt, ...)
753 {
754  va_list ap;
755  char const *old = NULL;
756 
757  if (vpt->type != TMPL_TYPE_UNINITIALISED) old = vpt->name;
758 
759  va_start(ap, fmt);
760  vpt->name = fr_vasprintf(vpt, fmt, ap);
761  vpt->quote = quote;
762  vpt->len = talloc_array_length(vpt->name) - 1;
763  va_end(ap);
764 
765  talloc_const_free(old); /* Free name last so it can be used in the format string */
766 }
767 
768 /** Set the name on a pre-initialised tmpl
769  *
770  * @param[in] vpt to set the name for.
771  * @param[in] quote Original quoting around the name.
772  * @param[in] name of the #tmpl_t.
773  * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
774  * If < 0 strlen will be used to determine the length.
775  */
776 void tmpl_set_name_shallow(tmpl_t *vpt, fr_token_t quote, char const *name, ssize_t len)
777 {
779 
780  vpt->name = name;
781  vpt->len = len < 0 ? strlen(name) : (size_t)len;
782  vpt->quote = quote;
783 }
784 
785 /** Set the name on a pre-initialised tmpl
786  *
787  * @param[in] vpt to set the name for.
788  * @param[in] quote Original quoting around the name.
789  * @param[in] name of the #tmpl_t.
790  * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
791  * If < 0 strlen will be used to determine the length.
792  */
793 void tmpl_set_name(tmpl_t *vpt, fr_token_t quote, char const *name, ssize_t len)
794 {
796 
797  talloc_const_free(vpt->name);
798 
799  vpt->name = talloc_bstrndup(vpt, name, len < 0 ? strlen(name) : (size_t)len);
800  vpt->len = talloc_array_length(vpt->name) - 1;
801  vpt->quote = quote;
802 }
803 
804 /** Change the default dictionary in the tmpl's resolution rules
805  *
806  * @param[in] vpt to alter.
807  * @param[in] dict to set.
808  */
810 {
811  vpt->rules.attr.dict_def = dict;
812 }
813 
814 /** Set escape parameters for the tmpl output
815  *
816  * @param[in] vpt to alter.
817  * @param[in] escape to set.
818  */
820 {
821  vpt->rules.escape = *escape;
822 }
823 
824 /** Change the default dictionary in the tmpl's resolution rules
825  *
826  * @param[in] vpt to alter.
827  * @param[in] xlat to set.
828  */
830 {
831  fr_assert(vpt->type == TMPL_TYPE_XLAT);
832 
833  tmpl_xlat(vpt) = xlat;
834 }
835 
836 
837 /** Initialise a tmpl using a format string to create the name
838  *
839  * @param[in] vpt to initialise.
840  * @param[in] type of tmpl to initialise.
841  * @param[in] quote Original quoting around the name.
842  * @param[in] fmt string.
843  * @param[in] ... format arguments.
844  * @return A pointer to the newly initialised tmpl.
845  */
847 {
848  va_list ap;
849 
850  memset(vpt, 0, sizeof(*vpt));
852 
853  va_start(ap, fmt);
854  vpt->name = fr_vasprintf(vpt, fmt, ap);
855  vpt->len = talloc_array_length(vpt->name) - 1;
856  vpt->quote = quote;
857  va_end(ap);
858 
859  return vpt;
860 }
861 
862 /** Initialise a tmpl without copying the input name string
863  *
864  * @note Name is not talloc_strdup'd or memcpy'd so must be available, and must not change
865  * for the lifetime of the #tmpl_t.
866  *
867  * @param[out] vpt to initialise.
868  * @param[in] type to set in the #tmpl_t.
869  * @param[in] quote The type of quoting around the template name.
870  * @param[in] name of the #tmpl_t.
871  * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
872  * If < 0 strlen will be used to determine the length.
873  * @param[in] t_rules used during parsing.
874  * @return a pointer to the initialised #tmpl_t. The same value as vpt.
875  */
877  char const *name, ssize_t len, tmpl_rules_t const *t_rules)
878 {
879  memset(vpt, 0, sizeof(*vpt));
881  tmpl_set_name_shallow(vpt, quote, name, len);
882  if (t_rules) vpt->rules = *t_rules;
883 
884  return vpt;
885 }
886 
887 /** Initialise a tmpl using a literal string to create the name
888  *
889  * @param[in] vpt to initialise.
890  * @param[in] type of tmpl to initialise.
891  * @param[in] quote Original quoting around the name.
892  * @param[in] name to set for the tmpl.
893  * @param[in] len Name length. If < 0 strlen will be used
894  * to determine the name.
895  * @param[in] t_rules used during parsing.
896  * @return A pointer to the newly initialised tmpl.
897  */
899  char const *name, ssize_t len, tmpl_rules_t const *t_rules)
900 {
901  memset(vpt, 0, sizeof(*vpt));
903  tmpl_set_name(vpt, quote, name, len);
904  if (t_rules) vpt->rules = *t_rules;
905 
906  return vpt;
907 }
908 
909 /** Create a new heap allocated #tmpl_t
910  *
911  * Must be later initialised with a tmpl_init_* function.
912  *
913  * This function is provided to allow tmpls to be pre-allocated for talloc purposes before
914  * their name is known.
915  */
916 static inline CC_HINT(always_inline) tmpl_t *tmpl_alloc_null(TALLOC_CTX *ctx)
917 {
918  tmpl_t *vpt;
919 
920  /*
921  * Allocate enough memory to hold at least
922  * one attribute reference and one request
923  * reference.
924  */
925  MEM(vpt = talloc_pooled_object(ctx, tmpl_t, 2, sizeof(tmpl_request_t) + sizeof(tmpl_attr_t)));
927 
928  return vpt;
929 }
930 
931 /** Create a new heap allocated #tmpl_t
932  *
933  * @param[in,out] ctx to allocate in.
934  * @param[in] type to set in the #tmpl_t.
935  * @param[in] name of the #tmpl_t (will be copied to a new talloc buffer parented
936  * by the #tmpl_t).
937  * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
938  * If < 0 strlen will be used to determine the length.
939  * @param[in] quote The type of quoting around the template name.
940  * @return the newly allocated #tmpl_t.
941  */
942 tmpl_t *tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len)
943 {
944  tmpl_t *vpt;
945 
946  vpt = tmpl_alloc_null(ctx);
947  memset(vpt, 0, sizeof(*vpt));
948 
950  if (name) tmpl_set_name(vpt, quote, name, len);
951 
952  return vpt;
953 }
954 /** @} */
955 
956 /** @name Create new #tmpl_t from a string
957  *
958  * @{
959  */
960 
961 /** Allocate a new attribute reference and add it to the end of the attribute reference list
962  *
963  */
965 {
966  tmpl_attr_t *ar;
967  TALLOC_CTX *ctx;
968 
969  if (tmpl_attr_list_num_elements(tmpl_attr(vpt)) == 0) {
970  ctx = vpt;
971  } else {
972  ctx = tmpl_attr_list_tail(tmpl_attr(vpt));
973  }
974 
975  MEM(ar = talloc(ctx, tmpl_attr_t));
976  *ar = (tmpl_attr_t){
977  .type = type,
978  .filter = {
979  .num = NUM_UNSPEC
980  }
981  };
982  tmpl_attr_list_insert_tail(tmpl_attr(vpt), ar);
983 
984  return ar;
985 }
986 
987 /** Create a #tmpl_t from a #fr_value_box_t
988  *
989  * @param[in,out] ctx to allocate #tmpl_t in.
990  * @param[out] out Where to write pointer to new #tmpl_t.
991  * @param[in] data to convert.
992  * @param[in] steal If true, any buffers are moved to the new
993  * ctx instead of being duplicated.
994  * @return
995  * - 0 on success.
996  * - -1 on failure.
997  */
998 int tmpl_afrom_value_box(TALLOC_CTX *ctx, tmpl_t **out, fr_value_box_t *data, bool steal)
999 {
1000  char *name;
1001  fr_slen_t slen;
1002  tmpl_t *vpt;
1004 
1005  MEM(vpt = talloc(ctx, tmpl_t));
1007  if (slen < 0) {
1008  error:
1009  talloc_free(vpt);
1010  return -1;
1011  }
1012 
1013  tmpl_init_shallow(vpt, TMPL_TYPE_DATA, quote, name, slen, NULL);
1014 
1015  if (steal) {
1016  if (fr_value_box_steal(vpt, tmpl_value(vpt), data) < 0) goto error;
1017  } else {
1018  if (fr_value_box_copy(vpt, tmpl_value(vpt), data) < 0) goto error;
1019  }
1020  *out = vpt;
1021 
1022  return 0;
1023 }
1024 
1025 /** Copy a list of attribute and request references from one tmpl to another
1026  *
1027  */
1028 int tmpl_attr_copy(tmpl_t *dst, tmpl_t const *src)
1029 {
1030  tmpl_attr_t *src_ar = NULL, *dst_ar;
1031 
1032  /*
1033  * Clear any existing attribute references
1034  */
1035  if (tmpl_attr_list_num_elements(tmpl_attr(dst)) > 0) tmpl_attr_list_talloc_reverse_free(tmpl_attr(dst));
1036 
1037  while ((src_ar = tmpl_attr_list_next(tmpl_attr(src), src_ar))) {
1038  dst_ar = tmpl_attr_add(dst, src_ar->type);
1039 
1040  switch (src_ar->type) {
1041  case TMPL_ATTR_TYPE_NORMAL:
1042  dst_ar->ar_da = src_ar->ar_da;
1043  break;
1044 
1045  case TMPL_ATTR_TYPE_UNSPEC: /* Nothing to copy */
1046  break;
1047 
1049  dst_ar->ar_unknown = fr_dict_unknown_copy(dst_ar, src_ar->ar_unknown);
1050  break;
1051 
1053  dst_ar->ar_unresolved = talloc_bstrdup(dst_ar, src_ar->ar_unresolved);
1054  break;
1055 
1056  default:
1057  if (!fr_cond_assert(0)) return -1;
1058  }
1059  dst_ar->ar_num = src_ar->ar_num;
1060  dst_ar->ar_filter_type = src_ar->ar_filter_type;
1061  dst_ar->parent = src_ar->parent;
1062  }
1063 
1064  /*
1065  * Clear any existing request references
1066  * and copy the ones from the source.
1067  */
1068  tmpl_request_list_talloc_reverse_free(&dst->data.attribute.rr);
1069  tmpl_request_ref_list_copy(dst, &dst->data.attribute.rr, &src->data.attribute.rr);
1070 
1071  TMPL_ATTR_VERIFY(dst);
1072 
1073  return 0;
1074 }
1075 
1076 /** Replace the current attribute reference
1077  *
1078  */
1080 {
1081  tmpl_attr_t *ref;
1082 
1084 
1085  /*
1086  * Clear any existing references
1087  */
1088  if (tmpl_attr_list_num_elements(tmpl_attr(vpt)) > 0) {
1089  tmpl_attr_list_talloc_reverse_free(tmpl_attr(vpt));
1090  }
1091 
1092  /*
1093  * Unknown attributes get copied
1094  */
1095  if (da->flags.is_unknown) {
1097  ref->da = ref->ar_unknown = fr_dict_unknown_copy(vpt, da);
1098  } else {
1100  ref->da = da;
1101  }
1102  ref->ar_parent = fr_dict_root(fr_dict_by_da(da)); /* Parent is the root of the dictionary */
1103 
1105 
1106  return 0;
1107 }
1108 
1109 /** Replace the leaf attribute only
1110  *
1111  */
1113 {
1114  tmpl_attr_t *ref, *parent = NULL;
1115 
1118 
1119  /*
1120  * Clear any existing references
1121  */
1122  if (tmpl_attr_list_num_elements(tmpl_attr(vpt)) > 0) {
1123  if (tmpl_attr_list_num_elements(tmpl_attr(vpt)) > 1) {
1124  ref = tmpl_attr_list_tail(tmpl_attr(vpt));
1125  parent = tmpl_attr_list_prev(tmpl_attr(vpt), ref);
1126 
1127  if (!fr_dict_attr_common_parent(parent->ar_da, da, true)) {
1128  fr_strerror_const("New leaf da and old leaf da do not share the same ancestor");
1129  return -1;
1130  }
1131  } else {
1132  ref = tmpl_attr_list_tail(tmpl_attr(vpt));
1133  }
1134 
1135  /*
1136  * Free old unknown and unresolved attributes...
1137  */
1138  talloc_free_children(ref);
1139  } else {
1140  ref = tmpl_attr_add(vpt, da->flags.is_unknown ? TMPL_ATTR_TYPE_UNKNOWN : TMPL_ATTR_TYPE_NORMAL);
1141  }
1142 
1143 
1144  /*
1145  * Unknown attributes get copied
1146  */
1147  if (da->flags.is_unknown) {
1149  ref->da = ref->ar_unknown = fr_dict_unknown_copy(vpt, da);
1150  } else {
1151  ref->type = TMPL_ATTR_TYPE_NORMAL;
1152  ref->da = da;
1153  }
1154  /*
1155  * FIXME - Should be calculated from existing ar
1156  */
1157  ref->ar_parent = fr_dict_root(fr_dict_by_da(da)); /* Parent is the root of the dictionary */
1158 
1160 
1161  return 0;
1162 }
1163 
1164 void tmpl_attr_set_leaf_num(tmpl_t *vpt, int16_t num)
1165 {
1166  tmpl_attr_t *ar;
1167 
1169 
1170  if (tmpl_attr_list_num_elements(tmpl_attr(vpt)) == 0) {
1172  } else {
1173  ar = tmpl_attr_list_tail(tmpl_attr(vpt));
1174  }
1175 
1176  ar->ar_num = num;
1177 
1179 }
1180 
1181 /** Rewrite the leaf's instance number
1182  *
1183  */
1184 void tmpl_attr_rewrite_leaf_num(tmpl_t *vpt, int16_t from, int16_t to)
1185 {
1186  tmpl_attr_t *ref = NULL;
1187 
1189 
1190  if (tmpl_attr_list_num_elements(tmpl_attr(vpt)) == 0) return;
1191 
1192  ref = tmpl_attr_list_tail(tmpl_attr(vpt));
1193  if (ref->ar_num == from) ref->ar_num = to;
1194 
1196 }
1197 
1198 /** Rewrite all instances of an array number
1199  *
1200  */
1201 void tmpl_attr_rewrite_num(tmpl_t *vpt, int16_t from, int16_t to)
1202 {
1203  tmpl_attr_t *ref = NULL;
1204 
1206 
1207  while ((ref = tmpl_attr_list_next(tmpl_attr(vpt), ref))) if (ref->ar_num == from) ref->ar_num = to;
1208 
1210 }
1211 
1212 /** Set the request for an attribute ref
1213  *
1214  */
1215 void tmpl_attr_set_request_ref(tmpl_t *vpt, FR_DLIST_HEAD(tmpl_request_list) const *request_def)
1216 {
1217  fr_assert_msg(tmpl_is_attr(vpt), "Expected tmpl type 'attr', got '%s'",
1218  tmpl_type_to_str(vpt->type));
1219 
1220  /*
1221  * Clear any existing request references
1222  */
1223  tmpl_request_list_talloc_reverse_free(&vpt->data.attribute.rr);
1224  tmpl_request_ref_list_copy(vpt, &vpt->data.attribute.rr, request_def);
1225 
1227 }
1228 
1230 {
1231  tmpl_attr_t *ref = tmpl_attr_list_head(tmpl_attr(vpt));
1232  if (tmpl_attr_is_list_attr(ref)) ref->da = list;
1233 
1235 }
1236 
1237 /** Create a new tmpl from a list tmpl and a da
1238  *
1239  */
1240 int tmpl_attr_afrom_list(TALLOC_CTX *ctx, tmpl_t **out, tmpl_t const *list, fr_dict_attr_t const *da)
1241 {
1242  tmpl_t *vpt;
1243  tmpl_attr_t *ar;
1244 
1245  char attr[256];
1246  ssize_t slen;
1247 
1248  MEM(vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, T_BARE_WORD, NULL, 0));
1249 
1250  /*
1251  * Copies request refs and the list ref
1252  */
1253  tmpl_attr_copy(vpt, list);
1254  tmpl_attr_set_list(vpt, tmpl_list(list)); /* Remove when lists are attributes */
1256  ar->ar_da = da;
1257  ar->ar_parent = fr_dict_root(fr_dict_by_da(da));
1259 
1260  /*
1261  * We need to rebuild the attribute name, to be the
1262  * one we copied from the source list.
1263  */
1264  slen = tmpl_print(&FR_SBUFF_OUT(attr, sizeof(attr)), vpt, TMPL_ATTR_REF_PREFIX_YES,
1265  fr_value_escape_by_quote[list->quote]);
1266  if (slen < 0) {
1267  fr_strerror_printf("Serialized attribute too long. Must be < "
1268  STRINGIFY(sizeof(attr)) " bytes, got %zu bytes", (size_t)-slen);
1269  talloc_free(vpt);
1270  return -1;
1271  }
1272 
1273  vpt->len = (size_t)slen;
1274  vpt->name = talloc_typed_strdup(vpt, attr);
1275  vpt->quote = T_BARE_WORD;
1276 
1278 
1279  *out = vpt;
1280 
1281  return 0;
1282 }
1283 /** @} */
1284 
1285 /** Insert an attribute reference into a tmpl
1286  *
1287  * Not all attribute references can be used to create new attributes,
1288  * for example those accessing instance > 0 or those that resolve
1289  * to special indexes.
1290  *
1291  * We mark up these references and their parents as resolve only
1292  * meaning that if any code needs to use a reference chain to build
1293  * out a pair tree, it bails out early.
1294  *
1295  * @param[in] vpt containing the reference list.
1296  * @param[in] ar to insert and check.
1297  */
1298 static inline CC_HINT(always_inline) void tmpl_attr_insert(tmpl_t *vpt, tmpl_attr_t *ar)
1299 {
1300  /*
1301  * Insert the reference into the list.
1302  */
1303  tmpl_attr_list_insert_tail(tmpl_attr(vpt), ar);
1304 
1305  switch (ar->ar_num) {
1306  case 0:
1307  case NUM_UNSPEC:
1308  break;
1309 
1310  default:
1311  ar->resolve_only = true;
1312  while ((ar = tmpl_attr_list_prev(tmpl_attr(vpt), ar))) ar->resolve_only = true;
1313  break;
1314  }
1315 }
1316 
1317 /** Parse array subscript and in future other filters
1318  *
1319  * @param[out] err Parse error code.
1320  * @param[in] ar to populate filter for.
1321  * @param[in] name containing more attribute ref data.
1322  * @param[in] at_rules see tmpl_attr_afrom_attr_substr.
1323  * @return
1324  * - >0 if a filter was parsed.
1325  * - 0 if no filter was available.
1326  * - <0 on filter parse error.
1327  */
1329  fr_sbuff_t *name, tmpl_attr_rules_t const *at_rules)
1330 {
1331  fr_sbuff_t our_name = FR_SBUFF(name);
1332 
1333  /*
1334  * Parse array subscript (and eventually complex filters)
1335  */
1336  if (!fr_sbuff_next_if_char(&our_name, '[')) return 0;
1337 
1338  if (at_rules->disallow_filters || tmpl_attr_is_list_attr(ar)) {
1339  fr_strerror_const("Filters not allowed here");
1341  fr_sbuff_set_to_start(&our_name);
1342  FR_SBUFF_ERROR_RETURN(&our_name);
1343  }
1344 
1345  ar->ar_filter_type = TMPL_ATTR_FILTER_TYPE_INDEX;
1346  fr_sbuff_switch(&our_name, '\0') {
1347  case '#':
1348  ar->ar_num = NUM_COUNT;
1349  fr_sbuff_next(&our_name);
1350  break;
1351 
1352  case '*':
1353  ar->ar_num = NUM_ALL;
1354  fr_sbuff_next(&our_name);
1355  break;
1356 
1357  case 'n':
1358  ar->ar_num = NUM_LAST;
1359  fr_sbuff_next(&our_name);
1360  break;
1361 
1362  /* Used as EOB here */
1363  missing_closing:
1364  case '\0':
1365  fr_strerror_const("No closing ']' for array index");
1367  error:
1368  FR_SBUFF_ERROR_RETURN(&our_name);
1369 
1370  default:
1371  {
1373  fr_sbuff_t tmp = FR_SBUFF(&our_name);
1374  ssize_t rcode;
1375  fr_slen_t slen;
1376  tmpl_rules_t t_rules;
1377  fr_sbuff_parse_rules_t p_rules;
1378  fr_sbuff_term_t const filter_terminals = FR_SBUFF_TERMS(L("]"));
1379 
1380  rcode = fr_sbuff_out(&sberr, &ar->ar_num, &tmp);
1381  if ((rcode > 0) && (fr_sbuff_is_char(&tmp, ']'))) {
1382  if ((ar->ar_num > 1000) || (ar->ar_num < 0)) {
1383  fr_strerror_printf("Invalid array index '%hi' (should be between 0-1000)", ar->ar_num);
1384  ar->ar_num = 0;
1386  goto error;
1387  }
1388 
1389  fr_sbuff_set(&our_name, &tmp); /* Advance name _AFTER_ doing checks */
1390  break;
1391  }
1392 
1393  /*
1394  * Temporary parsing hack: &User-Name[a] does _not_ match a condition 'a'.
1395  */
1396  if (!fr_sbuff_is_char(&tmp, '&')) {
1397  fr_strerror_const("Invalid array index");
1399  goto error;
1400  }
1401 
1402  /*
1403  * For now, we don't allow filtering on leaf values. e.g.
1404  *
1405  * &User-Name[&User-Name == foo]
1406  *
1407  * @todo - find some sane way of allowing this, without mangling the xlat expression
1408  * parser too badly. The simplest way is likely to just parse the expression, and then
1409  * walk over it, complaining if it contains attribute references other than &User-Name.
1410  *
1411  * Anything else is likely too hard.
1412  *
1413  * We also want to disallow basic conditions like "true" or "false". The conditions
1414  * should only be using attribute references, and those attribute references should be
1415  * limited to certain attributes.
1416  *
1417  * And if the filter attribute is a TLV, the condition code complains with 'Nesting types
1418  * such as groups or TLVs cannot be used in condition comparisons'. This is reasonable,
1419  * as we can't currently compare things like;
1420  *
1421  * &Group-Thingy == { &foo = bar }
1422  *
1423  * Which would involve creating the RHS list, doing an element-by-element comparison, and
1424  * then returning.
1425  *
1426  * In order to fix that, we have to
1427  */
1428  if (!fr_type_is_structural(ar->ar_da->type)) {
1429  fr_strerror_printf("Invalid filter - cannot use filter on leaf attributes");
1430  ar->ar_num = 0;
1432  goto error;
1433  }
1434 
1435  fr_assert(ar->ar_da != NULL);
1436  fr_assert(fr_type_is_structural(ar->ar_da->type));
1437 
1438  tmp = FR_SBUFF(&our_name);
1439  t_rules = (tmpl_rules_t) {};
1440  t_rules.attr = *at_rules;
1441  t_rules.attr.namespace = ar->ar_da;
1442 
1443  p_rules = (fr_sbuff_parse_rules_t) {
1444  .terminals = &filter_terminals,
1445  .escapes = NULL
1446  };
1447 
1448  /*
1449  * Check if it's a condition.
1450  */
1451  slen = xlat_tokenize_condition(ar, &ar->ar_cond, &tmp, &p_rules, &t_rules);
1452  if (slen < 0) {
1453  goto error;
1454  }
1455 
1456  ar->ar_filter_type = TMPL_ATTR_FILTER_TYPE_CONDITION;
1457  fr_sbuff_set(&our_name, &tmp); /* Advance name _AFTER_ doing checks */
1458  break;
1459  }
1460  }
1461 
1462  /*
1463  * Always advance here, so the error
1464  * marker points to the bad char.
1465  */
1466  if (!fr_sbuff_next_if_char(&our_name, ']')) goto missing_closing;
1467 
1468  FR_SBUFF_SET_RETURN(name, &our_name);
1469 }
1470 
1471 extern fr_dict_attr_t const *tmpl_attr_unspec;
1472 
1473 static inline CC_HINT(nonnull(3,4))
1475  tmpl_t *vpt,
1476  fr_sbuff_t *name, tmpl_attr_rules_t const *at_rules)
1477 {
1478  fr_slen_t slen;
1479 
1480  *ar = (tmpl_attr_t){
1481  .ar_num = NUM_UNSPEC, /* May be changed by tmpl_attr_parse_filter */
1482  .ar_type = TMPL_ATTR_TYPE_UNSPEC,
1483  .ar_da = tmpl_attr_unspec,
1484  };
1485 
1486  slen = tmpl_attr_parse_filter(err, ar, name, at_rules);
1487  if (slen < 0) {
1488  talloc_free(ar);
1489  return slen;
1490  /*
1491  * No filters and no previous elements is the equivalent of '&'
1492  * which is not allowed.
1493  *
1494  * &[<filter>] is allowed as this lets us perform filtering operations
1495  * at the root.
1496  */
1497  } else if ((slen == 0) && (tmpl_attr_num_elements(vpt) == 0)) {
1498  fr_strerror_const("Invalid attribute name");
1500  return -1;
1501  }
1502 
1503  tmpl_attr_insert(vpt, ar);
1504 
1505  return slen;
1506 }
1507 
1508 /** Parse an unresolved attribute, i.e. one which can't be found in the current dictionary
1509  *
1510  * This function calls itself recursively to process additional OID
1511  * components once we've failed to resolve one component.
1512  *
1513  * @note Do not call directly.
1514  *
1515  * @param[in] ctx to allocate new attribute reference in.
1516  * @param[out] err Parse error.
1517  * @param[in,out] vpt to append this reference to.
1518  * @param[in] parent Last known parent.
1519  * @param[in] namespace in which the attribute will be resolved.
1520  * @param[in] name to parse.
1521  * @param[in] at_rules see tmpl_attr_afrom_attr_substr.
1522  * @return
1523  * - <0 on error.
1524  * - 0 on success.
1525  */
1526 static inline CC_HINT(nonnull(3,6))
1528  tmpl_t *vpt,
1529  fr_dict_attr_t const *parent, fr_dict_attr_t const *namespace,
1530  fr_sbuff_t *name, tmpl_attr_rules_t const *at_rules)
1531 {
1532  tmpl_attr_t *ar = NULL, *ar_curr;
1533  fr_sbuff_t our_name = FR_SBUFF(name);
1534  fr_slen_t slen;
1535  char *unresolved;
1536 
1537  /*
1538  * Point we free from if something goes wrong.
1539  */
1540  ar_curr = tmpl_attr_list_tail(tmpl_attr(vpt));
1541  for (;;) {
1542  MEM(ar = talloc(ctx, tmpl_attr_t));
1543  /*
1544  * Copy out a string of allowed dictionary chars to form
1545  * the unresolved attribute name.
1546  *
1547  * This will be resolved later (outside of this function).
1548  */
1549  slen = fr_sbuff_out_abstrncpy_allowed(ar, &unresolved,
1550  &our_name, FR_DICT_ATTR_MAX_NAME_LEN + 1,
1552  if (slen == 0) {
1553  slen = tmpl_attr_ref_from_unspecified_substr(ar, err, vpt, &our_name, at_rules);
1554  if (slen < 0) {
1555  fr_sbuff_advance(&our_name, +slen);
1556  error:
1557  talloc_free(ar);
1558  tmpl_attr_list_talloc_free_to_tail(tmpl_attr(vpt), ar_curr);
1559  return -1;
1560  }
1561  return fr_sbuff_set(name, &our_name);
1562  } else if (slen > FR_DICT_ATTR_MAX_NAME_LEN) {
1563  fr_strerror_const("Attribute name is too long");
1565  goto error;
1566  }
1567 
1568  *ar = (tmpl_attr_t){
1569  .ar_num = NUM_UNSPEC,
1570  .ar_type = TMPL_ATTR_TYPE_UNRESOLVED,
1571  .ar_unresolved = unresolved,
1572  .ar_unresolved_namespace = namespace,
1573  .ar_parent = parent
1574  };
1575 
1576  if (tmpl_attr_parse_filter(err, ar, &our_name, at_rules) < 0) goto error;
1577 
1578  /*
1579  * Insert the ar into the list of attribute references
1580  */
1581  tmpl_attr_insert(vpt, ar);
1582 
1583  /*
1584  * Once one OID component is created as unresolved all
1585  * future OID components are also unresolved.
1586  */
1587  if (!fr_sbuff_next_if_char(&our_name, '.')) break;
1588  }
1589 
1590  /*
1591  * Mark the tmpl up as an unresolved attribute reference
1592  * the attribute reference will be resolved later.
1593  */
1595 
1596  return fr_sbuff_set(name, &our_name);
1597 }
1598 
1599 /*
1600  * Add attr_ref when we've parsed an intermediate dictionary name
1601  * which is itself a ref.
1602  */
1603 static void tmpl_attr_ref_fixup(TALLOC_CTX *ctx, tmpl_t *vpt, fr_dict_attr_t const *da, fr_dict_attr_t const *parent)
1604 {
1605  tmpl_attr_t *ar;
1606 
1607  if (tmpl_attr_tail_da(vpt) == da) return;
1608 
1609  if (da->parent != parent) tmpl_attr_ref_fixup(ctx, vpt, da->parent, parent);
1610 
1611  MEM(ar = talloc(ctx, tmpl_attr_t));
1612  *ar = (tmpl_attr_t) {
1613  .ar_num = NUM_UNSPEC,
1614  .ar_type = TMPL_ATTR_TYPE_NORMAL,
1615  .ar_da = da,
1616  .ar_parent = da->parent,
1617  };
1618 
1619  tmpl_attr_insert(vpt, ar);
1620 }
1621 
1622 /** Parse an attribute reference, either an OID or attribute name
1623  *
1624  * @note Do not call directly.
1625  *
1626  * @param[in] ctx to allocate new attribute reference in.
1627  * @param[out] err Parse error.
1628  * @param[in,out] vpt to append this reference to.
1629  * @param[in] parent Parent where the attribute will be placed (group, struct, tlv, etc).
1630  * @param[in] namespace Where the child attribute will be parsed from (dict root, struct member, TLV child, etc)
1631  * @param[in] name to parse.
1632  * @param[in] p_rules Formatting rules used to check for trailing garbage.
1633  * @param[in] at_rules which places constraints on attribute reference parsing.
1634  * Rules interpreted by this function is:
1635  * - allow_unknown - If false unknown OID components
1636  * result in a parse error.
1637  * - allow_unresolved - If false unknown attribute names
1638  * result in a parse error.
1639  * - allow_foreign - If an attribute resolves in a dictionary
1640  * that does not match the parent
1641  * (exception being FR_TYPE_GROUP) then that results
1642  * in a parse error.
1643  * @param[in] depth How deep we are. Used to check for maximum nesting level.
1644  * @return
1645  * - <0 on error.
1646  * - 0 on success.
1647  */
1648 static inline int tmpl_attr_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err,
1649  tmpl_t *vpt,
1650  fr_dict_attr_t const *parent, fr_dict_attr_t const *namespace,
1651  fr_sbuff_t *name,
1652  fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *at_rules,
1653  unsigned int depth)
1654 {
1655  uint32_t oid = 0;
1656  tmpl_attr_t *ar = NULL;
1657  fr_dict_attr_t const *da;
1658  fr_sbuff_marker_t m_s;
1659  fr_dict_attr_err_t dict_err;
1660  fr_dict_attr_t const *our_parent = parent;
1661 
1662  fr_sbuff_marker(&m_s, name);
1663 
1664  if (depth > FR_DICT_MAX_TLV_STACK) {
1665  fr_strerror_const("Attribute nesting too deep");
1667  error:
1668  talloc_free(ar);
1669  fr_sbuff_marker_release(&m_s);
1671  }
1672 
1673  /*
1674  * Input too short
1675  */
1676  if (!fr_sbuff_extend(name)) {
1677  fr_strerror_const("Missing attribute reference");
1679  goto error;
1680  }
1681 
1682  /*
1683  * Maybe there's no child namespace (struct member, tlv child, etc). In which case we must
1684  * search from the default dictionary root.
1685  *
1686  * This search is probably wrong in some cases. See the comments below around FR_TYPE_GROUP.
1687  *
1688  * If we change out the dictionaries, we should arguably also change dict_def in the
1689  * tmpl_attr_rules_t. On top of that, the "dict_attr_search" functions take a #fr_dict_t
1690  * pointer, and not a pointer to the dict root. So we can't pass them a namespace.
1691  */
1692  if (!namespace) {
1693  fr_assert(parent == NULL);
1694 
1695  (void)fr_dict_attr_search_by_qualified_name_substr(&dict_err, &da,
1696  at_rules->dict_def,
1697  name, p_rules ? p_rules->terminals : NULL,
1698  true,
1699  at_rules->allow_foreign);
1700  /*
1701  * The attribute was found either in the dict_def root, OR in the internal root, OR if
1702  * !dict_def && allow_foreign, in some other dictionary root.
1703  *
1704  * Otherwise we're still not sure what the attribute is. It may end up being an
1705  * unresolved one.
1706  */
1707  if (da) {
1708  our_parent = da->parent;
1709 
1710  if (!our_parent->flags.is_root) {
1711  tmpl_attr_ref_fixup(ctx, vpt, our_parent, fr_dict_root(da->dict));
1712  }
1713  }
1714  } else {
1715  fr_assert(parent != NULL);
1716 
1717  /*
1718  * Otherwise we're resolving the next piece in the context of where-ever we ended up from
1719  * parsing the last bit.
1720  *
1721  * The "parent" could be the same as "namespace", if both are at a dictionary root, OR
1722  * both are from a struct / tlv attribute.
1723 
1724  * Or, "parent" could be a grouping attribute (e.g. request), and "namespace" could be
1725  * the dictionary root.
1726  */
1727  (void)fr_dict_attr_by_name_substr(&dict_err,
1728  &da,
1729  namespace,
1730  name,
1731  p_rules ? p_rules->terminals : NULL);
1732 
1733  /*
1734  * Allow fallback to internal attributes
1735  * if the parent was a group, and we're
1736  * allowing internal resolution.
1737  *
1738  * Discard any errors here... It's more
1739  * useful to have the original.
1740  */
1741  if (!da) {
1742  ar = tmpl_attr_list_tail(&vpt->data.attribute.ar);
1743  if (!ar || ((ar->type == TMPL_ATTR_TYPE_NORMAL) && (ar->ar_da->type == FR_TYPE_GROUP))) {
1744  fr_dict_attr_t const *internal_root = fr_dict_root(fr_dict_internal());
1745 
1746  (void)fr_dict_attr_by_name_substr(NULL,
1747  &da, internal_root,
1748  name,
1749  p_rules ? p_rules->terminals : NULL);
1750  if (da) {
1751  dict_err = FR_DICT_ATTR_OK;
1752  our_parent = internal_root;
1753  }
1754  }
1755  ar = NULL;
1756 
1757  } else {
1758  /*
1759  * If we searched in a local dictionary, but found a real attribute
1760  * switch the namespace.
1761  */
1762  if (!da->flags.local && namespace->flags.local) namespace = our_parent = fr_dict_root(da->dict);
1763 
1764  /*
1765  * We had an alias in the same namespace,
1766  * go add more things in.
1767  */
1768  if (da->parent != our_parent) {
1769  fr_assert(namespace == our_parent);
1770  tmpl_attr_ref_fixup(ctx, vpt, da->parent, our_parent);
1771  }
1772  }
1773  }
1774 
1775  /*
1776  * Fatal errors related to nesting...
1777  */
1778  switch (dict_err) {
1780  fr_assert(our_parent != NULL);
1781  if (our_parent->flags.is_unknown) break;
1782  goto error;
1783 
1785  goto error;
1786 
1787  default:
1788  if (!da) break;
1789 
1790  /*
1791  * The named component was a known attribute
1792  * so record it as a normal attribute
1793  * reference.
1794  */
1795  fr_assert(our_parent != NULL);
1796  goto alloc_ar;
1797  }
1798 
1799  /*
1800  * At this point we haven't found a known attribute. What remains MUST be an OID component, OR an
1801  * unresolved attribute.
1802  *
1803  * The default is to parse the OIDs in the current namespace. If there is none, then we parse
1804  * the OIDs and unresolved attributes in the dict_def. And if that doesn't exist, in the
1805  * internal dictionaries.
1806  *
1807  * Note that we do NOT allow unknown attributes in the internal dictionary. Those attributes are
1808  * generally just DEFINEs, and their numbers have no meaning.
1809  */
1810  if (!namespace) {
1811  if (at_rules->dict_def) {
1812  our_parent = namespace = fr_dict_root(at_rules->dict_def);
1813  } else {
1814  our_parent = namespace = fr_dict_root(fr_dict_internal());
1815  }
1816  }
1817 
1818  fr_assert(our_parent != NULL);
1819  fr_assert(namespace != NULL);
1820 
1821  /*
1822  * See if the ref begins with an unsigned integer
1823  * if it does it's probably an OID component
1824  *
1825  * .<oid>
1826  */
1827  if (fr_sbuff_out(NULL, &oid, name) > 0) {
1828  fr_strerror_clear(); /* Clear out any existing errors */
1829 
1830  if (fr_dict_by_da(namespace) == fr_dict_internal()) goto disallow_unknown;
1831 
1832  /*
1833  * The OID component was a known attribute
1834  * so record it as a normal attribute
1835  * reference.
1836  */
1837  da = fr_dict_attr_child_by_num(namespace, oid);
1838  if (da) goto alloc_ar;
1839 
1840  if (!at_rules->allow_unknown) {
1841  disallow_unknown:
1842  fr_strerror_const("Unknown attributes not allowed here");
1844  fr_sbuff_set(name, &m_s);
1845  goto error;
1846  }
1847 
1848  /*
1849  * If it's numeric and not a known attribute
1850  * then we create an unknown attribute with
1851  * the specified attribute number.
1852  */
1853 
1854  /*
1855  * VSAs have VENDORs as children. All others are just normal things.
1856  */
1857  switch (namespace->type) {
1858  case FR_TYPE_VSA:
1859  da = fr_dict_unknown_vendor_afrom_num(ar, namespace, oid);
1860  break;
1861 
1862  default:
1863  da = fr_dict_unknown_attr_afrom_num(ar, namespace, oid);
1864  break;
1865  }
1866 
1867  if (!da) {
1868  if (err) *err = TMPL_ATTR_ERROR_UNKNOWN_NOT_ALLOWED; /* strerror set by dict function */
1869  goto error;
1870  }
1871 
1872  MEM(ar = talloc(ctx, tmpl_attr_t));
1873  *ar = (tmpl_attr_t){
1874  .ar_num = NUM_UNSPEC,
1875  .ar_type = TMPL_ATTR_TYPE_UNKNOWN,
1876  .ar_unknown = UNCONST(fr_dict_attr_t *, da),
1877  .ar_da = da,
1878  .ar_parent = our_parent,
1879  };
1880  goto do_suffix;
1881  }
1882 
1883  /*
1884  * Can't parse it as an attribute, might be a literal string
1885  * let the caller decide.
1886  *
1887  * Don't alter the fr_strerror buffer, may contain useful
1888  * errors from the dictionary code.
1889  */
1890  if (!at_rules->allow_unresolved && !(at_rules->allow_wildcard && fr_sbuff_is_char(name, '['))) {
1891  fr_strerror_const_push("Unresolved attributes are not allowed here");
1893  fr_sbuff_set(name, &m_s);
1894  goto error;
1895  }
1896 
1897  fr_sbuff_marker_release(&m_s);
1898 
1899  /*
1900  * Once we hit one unresolved attribute we have to treat
1901  * the rest of the components are unresolved as well.
1902  */
1903  return tmpl_attr_ref_afrom_unresolved_substr(ctx, err, vpt, our_parent, namespace, name, at_rules);
1904 
1905 alloc_ar:
1906  /*
1907  * We have a da, remove any of the errors recorded from failed
1908  * searches to find the attribute to avoid misleading messages
1909  * if something else fails.
1910  */
1912 
1913  MEM(ar = talloc(ctx, tmpl_attr_t));
1914  *ar = (tmpl_attr_t) {
1915  .ar_num = NUM_UNSPEC,
1916  .ar_type = TMPL_ATTR_TYPE_NORMAL,
1917  .ar_da = da,
1918  .ar_parent = our_parent,
1919  };
1920 
1921 do_suffix:
1922  /*
1923  * Parse the attribute reference filter
1924  *
1925  * Error out immediately if the filter is bad
1926  * otherwise determine whether to keep the
1927  * attribute reference or omit it based on:
1928  *
1929  * - Whether there was a filter present.
1930  * - The type of attribute.
1931  * - If this is the leaf attribute reference.
1932  */
1933  if (tmpl_attr_parse_filter(err, ar, name, at_rules) < 0) goto error;
1934 
1935  /*
1936  * Local variables are always unitary.
1937  *
1938  * [0] is allowed, as is [n], [*], and [#]. But [1], etc. aren't allowed.
1939  */
1940  if (da->flags.local && (ar->ar_num > 0)) {
1941  fr_strerror_printf("Invalid array reference for local variable");
1943  fr_sbuff_set(name, &m_s);
1944  goto error;
1945  }
1946 
1947  /*
1948  * At the end of the attribute reference. If there's a
1949  * trailing '.' then there's another attribute reference
1950  * we need to parse, otherwise we're done.
1951  */
1952  fr_sbuff_marker_release(&m_s);
1953  fr_sbuff_marker(&m_s, name);
1954 
1955  if (fr_sbuff_next_if_char(name, '.')) {
1956  fr_dict_attr_t const *ref;
1957 
1958  switch (da->type) {
1959  case FR_TYPE_GROUP:
1960  ref = fr_dict_attr_ref(da);
1961 
1962  /*
1963  * If the ref is outside of the internal namespace, then we use it.
1964  *
1965  * If the ref is inside of the internal namespace (e.g. "request"), then we do
1966  * something else.
1967  *
1968  * If we were given a root dictionary on input, use that. We have to follow this
1969  * dictionary because this function calls itself recursively, WITHOUT updating
1970  * "dict_def" in the attr_rules. So the dict-def there is whatever got passed
1971  * into tmpl_afrom_attr_substr(), BEFORE the "parent.parent.parent..." parsing.
1972  * Which means that in many cases, the "dict_def" is completely irrelevant.
1973  *
1974  * If there is no parent on input, then we just use dict_def.
1975  *
1976  * Otherwise we search through all of the dictionaries.
1977  *
1978  * Note that we cannot put random protocol attributes into an internal attribute
1979  * of type "group".
1980  */
1981  if (ref != fr_dict_root(fr_dict_internal())) {
1982  our_parent = namespace = ref;
1983 
1984  } else if (parent && parent->flags.is_root) {
1985  our_parent = namespace = parent;
1986 
1987  } else if (at_rules->dict_def) {
1988  our_parent = namespace = fr_dict_root(at_rules->dict_def);
1989 
1990  } else {
1991  our_parent = namespace = NULL;
1992  }
1993  break;
1994 
1995  case FR_TYPE_STRUCT:
1996  case FR_TYPE_TLV:
1997  case FR_TYPE_VENDOR:
1998  case FR_TYPE_VSA:
1999  is_union:
2000  /*
2001  * Structural types are parented and namespaced from their parent da.
2002  */
2003  namespace = our_parent = da;
2004  break;
2005 
2006  default:
2007  /*
2008  * Key fields can have children, because we really don't know how else to
2009  * represent the child structures.
2010  */
2011  if (fr_dict_attr_is_key_field(da)) goto is_union;
2012 
2013  fr_strerror_printf("Parent type of nested attribute %s must be of type "
2014  "\"struct\", \"tlv\", \"vendor\", \"vsa\" or \"group\", got \"%s\"",
2015  da->name,
2016  fr_type_to_str(da->type));
2017  fr_sbuff_set(name, &m_s);
2018  goto error;
2019  }
2020 
2021  if (ar) tmpl_attr_insert(vpt, ar);
2022 
2023  if (tmpl_attr_afrom_attr_substr(ctx, err, vpt, our_parent, namespace, name, p_rules, at_rules, depth + 1) < 0) {
2024  if (ar) {
2025  tmpl_attr_list_talloc_free_tail(&vpt->data.attribute.ar); /* Remove and free ar */
2026  ar = NULL;
2027  }
2028  goto error;
2029  }
2030 
2031  /*
2032  * If it's a leaf we always insert the attribute
2033  * reference into the list, even if it's a
2034  * nesting attribute.
2035  *
2036  * This is useful for nested edit sections
2037  * where the tmpl might be the name of a new
2038  * subsection.
2039  */
2040  } else {
2041  tmpl_attr_insert(vpt, ar);
2042  }
2043 
2044  /*
2045  * Remove unnecessary casts.
2046  */
2048  (tmpl_rules_cast(vpt) == tmpl_attr_tail_da(vpt)->type)) vpt->rules.cast = FR_TYPE_NULL;
2049 
2050  fr_sbuff_marker_release(&m_s);
2051  return 0;
2052 }
2053 
2054 /** Parse a string into a TMPL_TYPE_ATTR_* type #tmpl_t
2055  *
2056  * @param[in,out] ctx to allocate #tmpl_t in.
2057  * @param[out] err May be NULL. Provides the exact error that the parser hit
2058  * when processing the attribute ref.
2059  * @param[out] out Where to write pointer to new #tmpl_t.
2060  * @param[in] name of attribute including #tmpl_request_ref_t and #fr_pair_list_t qualifiers.
2061  * @param[in] p_rules Formatting rules used to check for trailing garbage.
2062  * @param[in] t_rules Rules which control parsing:
2063  * - dict_def The default dictionary to use if attributes
2064  * are unqualified.
2065  * - request_def The default #request_t to set if no
2066  * #tmpl_request_ref_t qualifiers are found in name.
2067  * - list_def The default list to set if no #fr_pair_list_t
2068  * qualifiers are found in the name.
2069  * - allow_unknown If true attributes in the format accepted by
2070  * #fr_dict_unknown_afrom_oid_substr will be allowed,
2071  * even if they're not in the main dictionaries.
2072  * If an unknown attribute is found a #TMPL_TYPE_ATTR
2073  * #tmpl_t will be produced.
2074  * If #tmpl_afrom_attr_substr is being called on
2075  * startup, the #tmpl_t may be passed to
2076  * #tmpl_attr_unknown_add to
2077  * add the unknown attribute to the main dictionary.
2078  * If the unknown attribute is not added to
2079  * the main dictionary the #tmpl_t cannot be used
2080  * to search for a #fr_pair_t in a #request_t.
2081  * - allow_unresolved If true, we don't generate a parse error on
2082  * unknown attributes. If an unknown attribute is
2083  * found a #TMPL_TYPE_ATTR_UNRESOLVED
2084  * #tmpl_t will be produced.
2085  * - allow_foreign If true, allow attribute names to be qualified
2086  * with a protocol outside of the passed dict_def.
2087  * - disallow_filters
2088  *
2089  * @see REMARKER to produce pretty error markers from the return value.
2090  *
2091  * @return
2092  * - <= 0 on error (offset as negative integer)
2093  * - > 0 on success (number of bytes parsed).
2094  */
2096  tmpl_t **out, fr_sbuff_t *name,
2097  fr_sbuff_parse_rules_t const *p_rules,
2098  tmpl_rules_t const *t_rules)
2099 {
2100  int ret;
2101  tmpl_t *vpt;
2102  fr_sbuff_t our_name = FR_SBUFF(name); /* Take a local copy in case we need to back track */
2103  bool ref_prefix = false;
2104  bool is_raw = false;
2105  tmpl_attr_rules_t const *at_rules;
2106  fr_sbuff_marker_t m_l;
2107  fr_dict_attr_t const *namespace;
2108  DEFAULT_RULES;
2109 
2110  if (!t_rules) t_rules = &default_rules;
2111  at_rules = &t_rules->attr;
2112 
2113  if (err) *err = TMPL_ATTR_ERROR_NONE;
2114 
2115  if (!fr_sbuff_extend(&our_name)) {
2116  fr_strerror_const("Empty attribute reference");
2117  if (err) *err = TMPL_ATTR_ERROR_EMPTY;
2118  FR_SBUFF_ERROR_RETURN(&our_name);
2119  }
2120 
2121  /*
2122  * Check to see if we expect a reference prefix
2123  */
2124  switch (at_rules->prefix) {
2126  if (!fr_sbuff_next_if_char(&our_name, '&')) {
2127  fr_strerror_const("Invalid attribute reference, missing '&' prefix");
2129  FR_SBUFF_ERROR_RETURN(&our_name);
2130  }
2131 
2132  break;
2133 
2135  if (fr_sbuff_is_char(&our_name, '&')) {
2136  fr_strerror_const("Attribute references used here must not have a '&' prefix");
2138  FR_SBUFF_ERROR_RETURN(&our_name);
2139  }
2140  break;
2141 
2143  /*
2144  * '&' prefix can be there, but doesn't have to be
2145  */
2146  (void) fr_sbuff_next_if_char(&our_name, '&');
2147  break;
2148  }
2149 
2150  MEM(vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, T_BARE_WORD, NULL, 0));
2151  vpt->data.attribute.ref_prefix = ref_prefix;
2152 
2153  /*
2154  * The "raw." prefix marks up the leaf attribute
2155  * as unknown if it wasn't already which allows
2156  * users to stick whatever they want in there as
2157  * a value.
2158  */
2159  if (fr_sbuff_adv_past_strcase_literal(&our_name, "raw.")) is_raw = true;
2160 
2161  /*
2162  * Parse one or more request references
2163  */
2165  &vpt->data.attribute.rr,
2166  &our_name,
2167  p_rules,
2168  t_rules,
2169  &namespace);
2170  if (ret < 0) {
2171  error:
2172  *out = NULL;
2173  talloc_free(vpt);
2174  FR_SBUFF_ERROR_RETURN(&our_name);
2175  }
2176 
2177  fr_sbuff_marker(&m_l, &our_name);
2178 
2179  /*
2180  * Parse the list and / or attribute reference
2181  */
2183  vpt,
2184  namespace, namespace,
2185  &our_name, p_rules, at_rules, 0);
2186  if (ret < 0) goto error;
2187 
2188  /*
2189  * Check to see if the user wants the leaf
2190  * attribute to be raw.
2191  *
2192  * We can only do the conversion now _if_
2193  * the complete hierarchy has been resolved
2194  * otherwise we'll need to do the conversion
2195  * later.
2196  */
2197  if (tmpl_is_attr(vpt) && is_raw) tmpl_attr_to_raw(vpt);
2198 
2199  /*
2200  * Local variables cannot be given a list modifier.
2201  */
2203  tmpl_attr_t *ar = tmpl_attr_list_head(tmpl_attr(vpt));
2204  bool is_local = ar->ar_da->flags.local;
2205 
2206  for (; ar != NULL;
2207  ar = tmpl_attr_list_next(tmpl_attr(vpt), ar)) {
2208  if (!ar->ar_da->flags.local ||
2209  (ar->ar_da->flags.local && is_local)) continue;
2210 
2211  fr_strerror_printf("Local attributes cannot be used in any list");
2213  fr_sbuff_set(&our_name, &m_l);
2214  goto error;
2215  }
2216 
2217  /*
2218  * That being said, local variables are named "foo", but are always put into the local list.
2219  */
2220  if (is_local) {
2221  MEM(ar = talloc(vpt, tmpl_attr_t));
2222  *ar = (tmpl_attr_t){
2223  .ar_type = TMPL_ATTR_TYPE_NORMAL,
2224  .ar_da = request_attr_local,
2225  .ar_parent = fr_dict_root(fr_dict_internal())
2226  };
2227 
2228  /*
2229  * Prepend the local list ref so it gets evaluated
2230  * first.
2231  */
2232  tmpl_attr_list_insert_head(tmpl_attr(vpt), ar);
2233  }
2234  }
2235 
2236  /*
2237  * Check whether the tmpl has a list qualifier.
2238  */
2239  switch (at_rules->list_presence) {
2240  case TMPL_ATTR_LIST_ALLOW:
2241  break;
2242 
2243  case TMPL_ATTR_LIST_FORBID:
2244  if (tmpl_attr_is_list_attr(tmpl_attr_list_head(tmpl_attr(vpt)))) {
2245  fr_strerror_const("List qualifiers are not allowed here.");
2247  goto error;
2248  }
2249  break;
2250 
2252  if (!tmpl_attr_is_list_attr(tmpl_attr_list_head(tmpl_attr(vpt)))) {
2253  fr_strerror_const("List qualifier is required, but no list was found.");
2255  goto error;
2256  }
2257  break;
2258  }
2259 
2260  /*
2261  * If we're using lists, ensure that the default list is specified.
2262  */
2263  if (!tmpl_attr_is_list_attr(tmpl_attr_list_head(tmpl_attr(vpt)))) {
2264  tmpl_attr_t *ar;
2265 
2266  MEM(ar = talloc(vpt, tmpl_attr_t));
2267  *ar = (tmpl_attr_t){
2268  .ar_type = TMPL_ATTR_TYPE_NORMAL,
2269  .ar_parent = fr_dict_root(fr_dict_internal())
2270  };
2271 
2272  fr_assert(at_rules->list_def);
2273  ar->ar_da = at_rules->list_def;
2274 
2275  /*
2276  * Prepend the list ref so it gets evaluated
2277  * first.
2278  */
2279  tmpl_attr_list_insert_head(tmpl_attr(vpt), ar);
2280  }
2281 
2282  tmpl_set_name(vpt, T_BARE_WORD, fr_sbuff_start(&our_name), fr_sbuff_used(&our_name));
2283  vpt->rules = *t_rules; /* Record the rules */
2284 
2285  /*
2286  * If there are actual requests, duplicate them
2287  * and move them into the list.
2288  *
2289  * A NULL request_def pointer is equivalent to the
2290  * current request.
2291  */
2292  if (t_rules->attr.request_def) {
2293  tmpl_request_ref_list_acopy(vpt, &vpt->rules.attr.request_def, t_rules->attr.request_def);
2294  }
2295 
2296  if (tmpl_is_attr(vpt)) {
2297  tmpl_attr_t *ar;
2298 
2299  /*
2300  * Suppress useless casts.
2301  */
2303  vpt->rules.cast = FR_TYPE_NULL;
2304  }
2305 
2306  /*
2307  * Ensure that the list is set correctly, so that
2308  * the returned vpt just doesn't just match the
2309  * input rules, it is also internally consistent.
2310  */
2311  ar = tmpl_attr_list_head(tmpl_attr(vpt));
2312  fr_assert(ar != NULL);
2313 
2314  if (tmpl_attr_is_list_attr(ar)) vpt->rules.attr.list_def = ar->ar_da;
2315  }
2316 
2317  if (!tmpl_substr_terminal_check(&our_name, p_rules)) {
2318  fr_strerror_const("Unexpected text after attribute reference");
2320  goto error;
2321  }
2322 
2323  /*
2324  * If everything was resolved correctly
2325  * we now need to check the cast type.
2326  */
2327  if (!tmpl_needs_resolving(vpt) && !fr_type_is_null(t_rules->cast) &&
2328  !fr_type_cast(t_rules->cast, tmpl_attr_tail_da(vpt)->type)) {
2329  fr_strerror_printf("Cannot cast type '%s' to '%s'",
2332  fr_sbuff_set_to_start(&our_name);
2333  goto error;
2334  }
2335 
2336  TMPL_VERIFY(vpt); /* Because we want to ensure we produced something sane */
2337 
2338  *out = vpt;
2339  FR_SBUFF_SET_RETURN(name, &our_name);
2340 }
2341 
2342 /** Parse a string into a TMPL_TYPE_ATTR_* type #tmpl_t
2343  *
2344  * @param[in,out] ctx to allocate #tmpl_t in.
2345  * @param[out] err May be NULL. Provides the exact error that the parser hit
2346  * when processing the attribute ref.
2347  * @param[out] out Where to write pointer to new #tmpl_t.
2348  * @param[in] name of attribute including #tmpl_request_ref_t and #fr_pair_list_t qualifiers.
2349  * @param[in] t_rules Rules which control parsing. See tmpl_afrom_attr_substr() for details.
2350  *
2351  * @note Unlike #tmpl_afrom_attr_substr this function will error out if the entire
2352  * name string isn't parsed.
2353  */
2355  tmpl_t **out, char const *name, tmpl_rules_t const *t_rules)
2356 {
2357  ssize_t slen, name_len;
2358  DEFAULT_RULES;
2359 
2360  if (!t_rules) t_rules = &default_rules; /* Use the defaults */
2361 
2362  name_len = strlen(name);
2363  slen = tmpl_afrom_attr_substr(ctx, err, out, &FR_SBUFF_IN(name, name_len), NULL, t_rules);
2364  if (slen <= 0) return slen;
2365 
2366  if (!fr_cond_assert(*out)) return -1;
2367 
2368  if (slen != name_len) {
2369  /* This looks wrong, but it produces meaningful errors for unknown attrs */
2370  fr_strerror_printf("Unexpected text after %s",
2371  tmpl_type_to_str((*out)->type));
2372  return -slen;
2373  }
2374 
2375  TMPL_VERIFY(*out);
2376 
2377  return slen;
2378 }
2379 
2380 /** Create TMPL_TYPE_DATA from a string
2381  *
2382  * @param[in] ctx to allocate tmpl to.
2383  * @param[out] out where to write tmpl.
2384  * @param[in] in sbuff to parse.
2385  * @param[in] quote surrounding the operand to parse.
2386  * @param[in] t_rules specifying the cast and any enumeration values.
2387  * @param[in] allow_enum Whether parsing the value as an enum should be allowed.
2388  * @param[in] p_rules formatting rules.
2389  * @return
2390  * - <0 on error
2391  * - >=0 on success.
2392  */
2394  fr_token_t quote,
2395  tmpl_rules_t const *t_rules, bool allow_enum,
2396  fr_sbuff_parse_rules_t const *p_rules)
2397 {
2398  fr_sbuff_t our_in = FR_SBUFF(in);
2399  fr_value_box_t tmp;
2400  tmpl_t *vpt;
2401  fr_type_t cast = FR_TYPE_STRING;
2402 
2403  if (!fr_type_is_null(t_rules->cast)) cast = t_rules->cast;
2404 
2405  if (!fr_type_is_leaf(cast)) {
2406  fr_strerror_printf("%s is not a valid cast type",
2407  fr_type_to_str(cast));
2408  FR_SBUFF_ERROR_RETURN(&our_in);
2409  }
2410 
2411  vpt = tmpl_alloc_null(ctx);
2412  if (fr_value_box_from_substr(vpt, &tmp,
2413  cast, allow_enum ? t_rules->enumv : NULL,
2414  &our_in, p_rules, false) < 0) {
2415  talloc_free(vpt);
2416  FR_SBUFF_ERROR_RETURN(&our_in);
2417  }
2419 
2420  tmpl_init(vpt, TMPL_TYPE_DATA, quote, fr_sbuff_start(&our_in), fr_sbuff_used(&our_in), t_rules);
2421 
2423 
2424  *out = vpt;
2425 
2426  if (cast == tmpl_value_type(vpt)) vpt->rules.cast = FR_TYPE_NULL;
2427 
2428  TMPL_VERIFY(vpt);
2429 
2430  FR_SBUFF_SET_RETURN(in, &our_in);
2431 }
2432 
2433 /** Parse a truth value
2434  *
2435  * @param[in] ctx to allocate tmpl to.
2436  * @param[out] out where to write tmpl.
2437  * @param[in] in sbuff to parse.
2438  * @param[in] p_rules formatting rules.
2439  * @return
2440  * - < 0 sbuff does not contain a boolean value.
2441  * - > 0 how many bytes were parsed.
2442  */
2444  fr_sbuff_parse_rules_t const *p_rules)
2445 {
2446  fr_sbuff_t our_in = FR_SBUFF(in);
2447  bool a_bool;
2448  tmpl_t *vpt;
2449 
2450  if (fr_sbuff_out(NULL, &a_bool, &our_in) < 0) {
2451  fr_strerror_const("Not a boolean value");
2452  return 0;
2453  }
2454 
2455  if (!tmpl_substr_terminal_check(&our_in, p_rules)) {
2456  fr_strerror_const("Unexpected text after bool");
2458  }
2459 
2461 
2462  fr_value_box_init(&vpt->data.literal, FR_TYPE_BOOL, NULL, false);
2463  vpt->data.literal.vb_bool = a_bool;
2464 
2465  *out = vpt;
2466 
2467  FR_SBUFF_SET_RETURN(in, &our_in);
2468 }
2469 
2470 /** Parse bareword as an octet string
2471  *
2472  * @param[in] ctx to allocate tmpl to.
2473  * @param[out] out where to write tmpl.
2474  * @param[in] in sbuff to parse.
2475  * @param[in] p_rules formatting rules.
2476  * @return
2477  * - < 0 negative offset where parse error occurred.
2478  * - 0 sbuff does not contain a hex string.
2479  * - > 0 how many bytes were parsed.
2480  */
2482  fr_sbuff_parse_rules_t const *p_rules)
2483 {
2484  fr_sbuff_t our_in = FR_SBUFF(in);
2485  tmpl_t *vpt;
2486  char *hex;
2487  size_t binlen, len;
2488  uint8_t *bin;
2489 
2490  if (!fr_sbuff_adv_past_strcase_literal(&our_in, "0x")) return 0;
2491 
2492  MEM(vpt = tmpl_alloc(ctx, TMPL_TYPE_DATA, T_BARE_WORD, NULL, 0));
2493 
2494  /*
2495  * This allows stream parsing to work correctly
2496  * we could be less lazy and copy hex data in
2497  * chunks, but never mind...
2498  */
2499  len = fr_sbuff_out_abstrncpy_allowed(vpt, &hex, &our_in, SIZE_MAX, sbuff_char_class_hex);
2500  if (len & 0x01) {
2501  fr_strerror_const("Hex string not even length");
2502  error:
2503  talloc_free(vpt);
2504  FR_SBUFF_ERROR_RETURN(&our_in);
2505  }
2506  if (len == 0) {
2507  fr_strerror_const("Zero length hex string is invalid");
2508  goto error;
2509  }
2510 
2511  if (!tmpl_substr_terminal_check(&our_in, p_rules)) {
2512  fr_strerror_const("Unexpected text after hex string");
2513  goto error;
2514  }
2515 
2516  bin = (uint8_t *)hex;
2517  binlen = len / 2;
2518 
2520 
2521  (void)fr_base16_decode(NULL, &FR_DBUFF_TMP(bin, binlen), &FR_SBUFF_IN(hex, len), false);
2522  MEM(bin = talloc_realloc_size(vpt, bin, binlen)); /* Realloc to the correct length */
2523  (void)fr_value_box_memdup_shallow(&vpt->data.literal, NULL, bin, binlen, false);
2524 
2525  *out = vpt;
2526 
2527  FR_SBUFF_SET_RETURN(in, &our_in);
2528 }
2529 
2530 /** Parse bareword as an IPv4 address or prefix
2531  *
2532  * @param[in] ctx to allocate tmpl to.
2533  * @param[out] out where to write tmpl.
2534  * @param[in] in sbuff to parse.
2535  * @param[in] p_rules formatting rules.
2536  * @return
2537  * - < 0 sbuff does not contain an IPv4 address or prefix.
2538  * - > 0 how many bytes were parsed.
2539  */
2541  fr_sbuff_parse_rules_t const *p_rules)
2542 {
2543  tmpl_t *vpt;
2544  fr_sbuff_t our_in = FR_SBUFF(in);
2545  uint8_t octet;
2546  fr_type_t type;
2547 
2548  /*
2549  * Check for char sequence
2550  *
2551  * xxx.xxx.xxx.xxx
2552  */
2553  if (!(fr_sbuff_out(NULL, &octet, &our_in) && fr_sbuff_next_if_char(&our_in, '.') &&
2554  fr_sbuff_out(NULL, &octet, &our_in) && fr_sbuff_next_if_char(&our_in, '.') &&
2555  fr_sbuff_out(NULL, &octet, &our_in) && fr_sbuff_next_if_char(&our_in, '.') &&
2556  fr_sbuff_out(NULL, &octet, &our_in))) {
2557  error:
2558  FR_SBUFF_ERROR_RETURN(&our_in);
2559  }
2560 
2561  /*
2562  * If it has a trailing '/' then it's probably
2563  * an IP prefix.
2564  */
2565  if (fr_sbuff_next_if_char(&our_in, '/')) {
2566  if (fr_sbuff_out(NULL, &octet, &our_in) < 0) {
2567  fr_strerror_const("IPv4 CIDR mask malformed");
2568  goto error;
2569  }
2570 
2571  if (octet > 32) {
2572  fr_strerror_const("IPv4 CIDR mask too high");
2573  goto error;
2574  }
2575 
2577  } else {
2579  }
2580 
2581  if (!tmpl_substr_terminal_check(&our_in, p_rules)) {
2582  fr_strerror_const("Unexpected text after IPv4 string or prefix");
2583  goto error;
2584  }
2585 
2587  if (fr_value_box_from_substr(vpt, &vpt->data.literal, type, NULL,
2588  &FR_SBUFF_REPARSE(&our_in),
2589  NULL, false) < 0) {
2590  talloc_free(vpt);
2591  goto error;
2592  }
2593  *out = vpt;
2594 
2595  FR_SBUFF_SET_RETURN(in, &our_in);
2596 }
2597 
2598 /** Parse bareword as an IPv6 address or prefix
2599  *
2600  * @param[in] ctx to allocate tmpl to.
2601  * @param[out] out where to write tmpl.
2602  * @param[in] in sbuff to parse.
2603  * @param[in] p_rules formatting rules.
2604  * @return
2605  * - < 0 sbuff does not contain an IPv4 address or prefix.
2606  * - > 0 how many bytes were parsed.
2607  */
2609  fr_sbuff_parse_rules_t const *p_rules)
2610 {
2611  tmpl_t *vpt;
2612  fr_sbuff_t our_in = FR_SBUFF(in);
2614  fr_type_t type;
2615  size_t len;
2616  char *sep_a, *sep_b;
2617 
2618  static bool ipv6_chars[UINT8_MAX + 1] = {
2619  ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
2620  ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
2621  ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
2622  ['f'] = true,
2623  ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true,
2624  ['F'] = true,
2625  [':'] = true, ['.'] = true
2626  };
2627 
2628  /*
2629  * Drop a marker to pin the start of the
2630  * address in the buffer.
2631  */
2632  fr_sbuff_marker(&m, &our_in);
2633 
2634  /*
2635  * Check for something looking like an IPv6 address
2636  *
2637  * Minimum string is '::'
2638  */
2639  len = fr_sbuff_adv_past_allowed(&our_in, FR_IPADDR_STRLEN + 1, ipv6_chars, NULL);
2640  if ((len < 2) || (len > FR_IPADDR_STRLEN)) {
2641  error:
2642  FR_SBUFF_ERROR_RETURN(&our_in);
2643  }
2644 
2645  /*
2646  * Got ':' after '.', this isn't allowed.
2647  *
2648  * We need this check else IPv4 gets parsed
2649  * as blank IPv6 address.
2650  */
2651  sep_a = memchr(fr_sbuff_current(&m), '.', len);
2652  if (sep_a && (!(sep_b = memchr(fr_sbuff_current(&m), ':', len)) || (sep_b > sep_a))) {
2653  fr_strerror_const("First IPv6 component separator was a '.'");
2654  goto error;
2655  }
2656 
2657  /*
2658  * The v6 parse function will happily turn
2659  * integers into v6 addresses *sigh*.
2660  */
2661  sep_a = memchr(fr_sbuff_current(&m), ':', len);
2662  if (!sep_a) {
2663  fr_strerror_const("No IPv6 component separator");
2664  goto error;
2665  }
2666 
2667  /*
2668  * Handle scope
2669  */
2670  if (fr_sbuff_next_if_char(&our_in, '%')) {
2671  len = fr_sbuff_adv_until(&our_in, IFNAMSIZ + 1, p_rules->terminals, '\0');
2672  if ((len < 1) || (len > IFNAMSIZ)) {
2673  fr_strerror_const("IPv6 scope too long");
2674  goto error;
2675  }
2676  }
2677 
2678  /*
2679  * ...and finally the prefix.
2680  */
2681  if (fr_sbuff_next_if_char(&our_in, '/')) {
2682  uint8_t mask;
2683 
2684  if (fr_sbuff_out(NULL, &mask, &our_in) < 0) {
2685  fr_strerror_const("IPv6 CIDR mask malformed");
2686  goto error;
2687  }
2688  if (mask > 128) {
2689  fr_strerror_const("IPv6 CIDR mask too high");
2690  goto error;
2691  }
2692 
2694  } else {
2696  }
2697 
2698  if (!tmpl_substr_terminal_check(&our_in, p_rules)) {
2699  fr_strerror_const("Unexpected text after IPv6 string or prefix");
2700  goto error;
2701  }
2702 
2704  if (fr_value_box_from_substr(vpt, &vpt->data.literal, type, NULL,
2705  &FR_SBUFF_REPARSE(&our_in),
2706  NULL, false) < 0) {
2707  talloc_free(vpt);
2708  goto error;
2709  }
2710  *out = vpt;
2711 
2712  FR_SBUFF_SET_RETURN(in, &our_in);
2713 }
2714 
2715 
2716 /** Try and parse signed or unsigned integers
2717  *
2718  * @param[in] ctx to allocate tmpl to.
2719  * @param[out] out where to write tmpl.
2720  * @param[in] in sbuff to parse.
2721  * @param[in] p_rules formatting rules.
2722  * @return
2723  * - < 0 sbuff does not contain a mac address.
2724  * - > 0 how many bytes were parsed.
2725  */
2727  fr_sbuff_parse_rules_t const *p_rules)
2728 {
2729  tmpl_t *vpt;
2730  fr_sbuff_t our_in = FR_SBUFF(in);
2731  uint8_t buff[6];
2732  fr_dbuff_t dbuff;
2733  fr_value_box_t *vb;
2735 
2736  fr_dbuff_init(&dbuff, buff, sizeof(buff));
2737 
2738  fr_base16_decode(&err, &dbuff, &our_in, true);
2739  if (err != FR_SBUFF_PARSE_OK) return 0;
2740 
2741  if (!fr_sbuff_next_if_char(&our_in, ':')) return 0;
2742 
2743  fr_base16_decode(&err, &dbuff, &our_in, true);
2744  if (err != FR_SBUFF_PARSE_OK) return 0;
2745 
2746  if (!fr_sbuff_next_if_char(&our_in, ':')) return 0;
2747 
2748  fr_base16_decode(&err, &dbuff, &our_in, true);
2749  if (err != FR_SBUFF_PARSE_OK) return 0;
2750 
2751  if (!fr_sbuff_next_if_char(&our_in, ':')) return 0;
2752 
2753  fr_base16_decode(&err, &dbuff, &our_in, true);
2754  if (err != FR_SBUFF_PARSE_OK) return 0;
2755 
2756  if (!fr_sbuff_next_if_char(&our_in, ':')) return 0;
2757 
2758  fr_base16_decode(&err, &dbuff, &our_in, true);
2759  if (err != FR_SBUFF_PARSE_OK) return 0;
2760 
2761  if (!fr_sbuff_next_if_char(&our_in, ':')) return 0;
2762 
2763  fr_base16_decode(&err, &dbuff, &our_in, true);
2764  if (err != FR_SBUFF_PARSE_OK) return 0;
2765 
2766  if (!tmpl_substr_terminal_check(&our_in, p_rules)) {
2767  fr_strerror_const("Unexpected text after mac address");
2768  return 0;
2769  }
2770 
2772  T_BARE_WORD, fr_sbuff_start(&our_in), fr_sbuff_used(&our_in)));
2773  vb = tmpl_value(vpt);
2774 
2775  fr_value_box_init(vb, FR_TYPE_ETHERNET, NULL, false);
2776  memcpy(vb->vb_ether, buff, sizeof(vb->vb_ether));
2777 
2778  *out = vpt;
2779 
2780  FR_SBUFF_SET_RETURN(in, &our_in);
2781 }
2782 
2783 /** Try and parse signed or unsigned integers
2784  *
2785  * @param[in] ctx to allocate tmpl to.
2786  * @param[out] out where to write tmpl.
2787  * @param[in] in sbuff to parse.
2788  * @param[in] p_rules formatting rules.
2789  * @return
2790  * - < 0 sbuff does not contain an integer.
2791  * - > 0 how many bytes were parsed.
2792  */
2794  fr_sbuff_parse_rules_t const *p_rules)
2795 {
2796  tmpl_t *vpt;
2797  fr_sbuff_t our_in = FR_SBUFF(in);
2798  ssize_t slen;
2799  fr_value_box_t *vb;
2800 
2801  /*
2802  * Pick the narrowest signed type
2803  */
2804  if (fr_sbuff_is_char(&our_in, '-')) {
2805  int64_t a_int;
2806 
2807  slen = fr_sbuff_out(NULL, &a_int, &our_in);
2808  if (slen <= 0) return 0;
2809 
2810  if (!tmpl_substr_terminal_check(&our_in, p_rules)) {
2811  fr_strerror_const("Unexpected text after signed integer");
2812  error:
2813  FR_SBUFF_ERROR_RETURN(&our_in);
2814  }
2815 
2817  T_BARE_WORD, fr_sbuff_start(&our_in), fr_sbuff_used(&our_in)));
2818  vb = tmpl_value(vpt);
2819  if (a_int >= INT8_MIN) {
2820  fr_value_box_init(vb, FR_TYPE_INT8, NULL, false);
2821  vb->vb_int8 = (int8_t)a_int;
2822  } else if (a_int >= INT16_MIN) {
2823  fr_value_box_init(vb, FR_TYPE_INT16, NULL, false);
2824  vb->vb_int16 = (int16_t)a_int;
2825  } else if (a_int >= INT32_MIN) {
2826  fr_value_box_init(vb, FR_TYPE_INT32, NULL, false);
2827  vb->vb_int32 = (int32_t)a_int;
2828  } else {
2829  fr_value_box_init(vb, FR_TYPE_INT64, NULL, false);
2830  vb->vb_int64 = (int64_t)a_int;
2831  }
2832  /*
2833  * Pick the narrowest unsigned type
2834  */
2835  } else {
2836  uint64_t a_uint;
2837 
2838  slen = fr_sbuff_out(NULL, &a_uint, &our_in);
2839  if (slen <= 0) return slen;
2840 
2841  if (!tmpl_substr_terminal_check(&our_in, p_rules)) {
2842  fr_strerror_const("Unexpected text after unsigned integer");
2843  goto error;
2844  }
2845 
2847  T_BARE_WORD, fr_sbuff_start(&our_in), fr_sbuff_used(&our_in)));
2848  vb = tmpl_value(vpt);
2849  if (a_uint <= UINT8_MAX) {
2850  fr_value_box_init(vb, FR_TYPE_UINT8, NULL, false);
2851  vb->vb_uint8 = (uint8_t)a_uint;
2852  } else if (a_uint <= UINT16_MAX) {
2853  fr_value_box_init(vb, FR_TYPE_UINT16, NULL, false);
2854  vb->vb_uint16 = (uint16_t)a_uint;
2855  } else if (a_uint <= UINT32_MAX) {
2856  fr_value_box_init(vb, FR_TYPE_UINT32, NULL, false);
2857  vb->vb_uint32 = (uint32_t)a_uint;
2858  } else {
2859  fr_value_box_init(vb, FR_TYPE_UINT64, NULL, false);
2860  vb->vb_uint64 = (uint64_t)a_uint;
2861  }
2862  }
2863 
2864  *out = vpt;
2865 
2866  FR_SBUFF_SET_RETURN(in, &our_in);
2867 }
2868 
2870  fr_sbuff_parse_rules_t const *p_rules)
2871 {
2872  tmpl_t *vpt;
2873  fr_sbuff_t our_in = FR_SBUFF(in);
2874  double a_float;
2875  ssize_t slen;
2876  fr_value_box_t *vb;
2877 
2878  slen = fr_sbuff_out(NULL, &a_float, &our_in);
2879  if (slen <= 0) return 0;
2880 
2881  if (!tmpl_substr_terminal_check(&our_in, p_rules)) {
2882  fr_strerror_const("Unexpected text after float");
2883  FR_SBUFF_ERROR_RETURN(&our_in);
2884  }
2885 
2887  T_BARE_WORD, fr_sbuff_start(&our_in), fr_sbuff_used(&our_in)));
2888  vb = tmpl_value(vpt);
2889  fr_value_box_init(vb, FR_TYPE_FLOAT64, NULL, false);
2890  vb->vb_float64 = a_float;
2891 
2892  *out = vpt;
2893 
2894  FR_SBUFF_SET_RETURN(in, &our_in);
2895 }
2896 
2897 static ssize_t tmpl_afrom_time_delta(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in,
2898  fr_sbuff_parse_rules_t const *p_rules)
2899 {
2900  tmpl_t *vpt;
2901  fr_sbuff_t our_in = FR_SBUFF(in);
2902  fr_time_delta_t a_delta;
2903  fr_slen_t slen;
2904  fr_value_box_t *vb;
2905 
2906  slen = fr_time_delta_from_substr(&a_delta, &our_in, FR_TIME_RES_SEC, true, p_rules ? p_rules->terminals : NULL);
2907  if (slen <= 0) return 0;
2908 
2910  T_BARE_WORD, fr_sbuff_start(&our_in), fr_sbuff_used(&our_in)));
2911  vb = tmpl_value(vpt);
2912  fr_value_box_init(vb, FR_TYPE_TIME_DELTA, NULL, false);
2913  vb->vb_time_delta = a_delta;
2914 
2915  *out = vpt;
2916 
2917  FR_SBUFF_SET_RETURN(in, &our_in);
2918 }
2919 
2920 /*
2921  * ::value
2922  *
2923  * Treated as enum name. Note that this check MUST be done after the test for IPv6, as
2924  * "::1" is an allowed IPv6 address.
2925  *
2926  * @todo - Mark this up as an enum name? Or do we really care? Maybe we want to allow
2927  *
2928  * Service-Type == 'Framed-User'
2929  *
2930  * or
2931  *
2932  * Service-Type == "Framed-User'
2933  *
2934  * as the second one allows for xlat expansions of enum names.
2935  *
2936  * We probably do want to forbid the single-quoted form of enums,
2937  * as that doesn't seem to make sense.
2938  *
2939  * We also need to distinguish unresolved bare words as enums
2940  * (with :: prefix) from unresolved attributes without an & prefix.
2941  */
2942 static ssize_t tmpl_afrom_enum(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in,
2943  fr_sbuff_parse_rules_t const *p_rules,
2944  tmpl_rules_t const *t_rules)
2945 {
2946  tmpl_t *vpt;
2947  char *str;
2948  fr_sbuff_parse_error_t sberr;
2949  fr_sbuff_t our_in = FR_SBUFF(in);
2950 
2951  if (fr_sbuff_is_str_literal(&our_in, "::")) {
2952  (void) fr_sbuff_advance(&our_in, 2);
2953 
2954  } else if (!t_rules->enumv) {
2955  return 0;
2956  }
2957 
2958  vpt = tmpl_alloc_null(ctx);
2959 
2960  /*
2961  * If it doesn't match any other type of bareword, parse it as an enum name.
2962  *
2963  * Note that we don't actually try to resolve the enum name. The caller is responsible
2964  * for doing that.
2965  */
2966  if (fr_dict_enum_name_afrom_substr(vpt, &str, &sberr, &our_in, p_rules ? p_rules->terminals : NULL) < 0) {
2967  /*
2968  * Produce our own errors which make
2969  * more sense in the context of tmpls
2970  */
2971  switch (sberr) {
2973  fr_strerror_const("No operand found. Expected &ref, literal, "
2974  "'quoted literal', \"%{expansion}\", or enum value");
2975  break;
2976 
2978  fr_strerror_const("enum values must contain at least one alpha character");
2979  break;
2980 
2981  default:
2982  fr_strerror_const("Unexpected text after enum value. Expected operator");
2983  break;
2984  }
2985 
2986  talloc_free(vpt);
2987  FR_SBUFF_ERROR_RETURN(&our_in);
2988  }
2989 
2990  /*
2991  * If there's a valid enum name, then we use it. Otherwise we leave name resolution to run time.
2992  */
2993  if (t_rules->enumv) {
2995 
2996  dv = fr_dict_enum_by_name(t_rules->enumv, str, -1);
2997  if (dv) {
2999  fr_sbuff_start(&our_in), fr_sbuff_used(&our_in), t_rules);
3000  (void) fr_value_box_copy(vpt, &vpt->data.literal, dv->value);
3001 
3002  *out = vpt;
3003  FR_SBUFF_SET_RETURN(in, &our_in);
3004  }
3005  }
3006 
3007  /*
3008  * Either there's no enum, or the enum name didn't match one of the listed ones. There's no
3009  * point in waiting for an enum which might be declared later. That's not possible, so we fall
3010  * back to parsing the various data types.
3011  */
3012  if (t_rules->at_runtime) return 0;
3013 
3015  fr_sbuff_start(&our_in), fr_sbuff_used(&our_in), t_rules);
3016  vpt->data.unescaped = str;
3017  *out = vpt;
3018 
3019  FR_SBUFF_SET_RETURN(in, &our_in);
3020 }
3021 
3022 /** Convert an arbitrary string into a #tmpl_t
3023  *
3024  * @note Unlike #tmpl_afrom_attr_str return code 0 doesn't necessarily indicate failure,
3025  * may just mean a 0 length string was parsed. Check to see if the function emitted
3026  * a #tmpl_t in *out.
3027  *
3028  * @note xlats and regexes are left uncompiled. This is to support the two pass parsing
3029  * done by the modcall code. Compilation on pass1 of that code could fail, as
3030  * attributes or xlat functions registered by modules may not be available (yet).
3031  *
3032  * @note For details of attribute parsing see #tmpl_afrom_attr_substr.
3033  *
3034  * @param[in,out] ctx To allocate #tmpl_t in.
3035  * @param[out] out Where to write the pointer to the new #tmpl_t.
3036  * @param[in] in String to parse.
3037  * @param[in] quote Quoting around the tmpl. Determines what we
3038  * attempt to parse the string as.
3039  * @param[in] p_rules Formatting rules for the tmpl.
3040  * @param[in] t_rules Validation rules for attribute references.
3041  * @return
3042  * - < 0 on error (offset as negative integer)
3043  * - >= 0 on success (number of bytes parsed).
3044  *
3045  * @see REMARKER to produce pretty error markers from the return value.
3046  *
3047  * @see tmpl_afrom_attr_substr
3048  */
3050  fr_sbuff_t *in, fr_token_t quote,
3051  fr_sbuff_parse_rules_t const *p_rules,
3052  tmpl_rules_t const *t_rules)
3053 {
3054  fr_sbuff_t our_in = FR_SBUFF(in);
3055 
3056  fr_slen_t slen;
3057  fr_sbuff_parse_error_t sberr;
3058  char *str;
3059 
3060  tmpl_t *vpt = NULL;
3061  DEFAULT_RULES;
3062 
3063  if (!t_rules) t_rules = &default_rules; /* Use the defaults */
3064 
3065  *out = NULL;
3066 
3067  switch (quote) {
3068  case T_BARE_WORD:
3069  /*
3070  * Skip other bareword types if
3071  * we find a '&' prefix.
3072  */
3073  if (fr_sbuff_is_char(&our_in, '&')) return tmpl_afrom_attr_substr(ctx, NULL, out, in,
3074  p_rules, t_rules);
3075 
3076  /*
3077  * Allow bareword xlats if we
3078  * find a '%' prefix.
3079  */
3080  if (fr_sbuff_is_char(&our_in, '%')) {
3082  xlat_exp_head_t *head = NULL;
3083 
3084  vpt = tmpl_alloc_null(ctx);
3085  slen = xlat_tokenize(vpt, &head, &our_in, p_rules, t_rules, t_rules->literals_safe_for);
3086  if (slen <= 0) FR_SBUFF_ERROR_RETURN(&our_in);
3087 
3089 
3090  tmpl_init(vpt, type, quote, fr_sbuff_start(&our_in), slen, t_rules);
3091  vpt->data.xlat.ex = head;
3092 
3093  *out = vpt;
3094 
3095  TMPL_VERIFY(vpt);
3096 
3097  FR_SBUFF_SET_RETURN(in, &our_in);
3098  }
3099 
3100  /*
3101  * Deal with explicit casts...
3102  */
3103  if (!fr_type_is_null(t_rules->cast)) return tmpl_afrom_value_substr(ctx, out, in, quote,
3104  t_rules, true, p_rules);
3105 
3106  /*
3107  * We're at runtime and have a data type. Just parse it as that data type, without doing
3108  * endless "maybe it's this thing" attempts.
3109  */
3110  if (t_rules->at_runtime && t_rules->enumv) {
3111  tmpl_rules_t my_t_rules = *t_rules;
3112 
3113  fr_assert(fr_type_is_leaf(t_rules->enumv->type));
3114 
3115  my_t_rules.cast = my_t_rules.enumv->type;
3116 
3117  return tmpl_afrom_value_substr(ctx, out, in, quote, &my_t_rules, true, p_rules);
3118  }
3119 
3120  /*
3121  * See if it's a boolean value
3122  */
3123  slen = tmpl_afrom_bool_substr(ctx, out, &our_in, p_rules);
3124  if (slen > 0) {
3125  done_bareword:
3126  TMPL_VERIFY(*out);
3127 
3128  FR_SBUFF_SET_RETURN(in, &our_in);
3129  }
3130  fr_assert(!*out);
3131 
3132  /*
3133  * See if it's an octets string
3134  */
3135  slen = tmpl_afrom_octets_substr(ctx, out, &our_in, p_rules);
3136  if (slen > 0) goto done_bareword;
3137  fr_assert(!*out);
3138 
3139  /*
3140  * See if it's a mac address
3141  *
3142  * Needs to be before IPv6 as the pton functions
3143  * are too greedy, and on macOS will happily
3144  * convert a mac address to an IPv6 address.
3145  */
3146  slen = tmpl_afrom_ether_substr(ctx, out, &our_in, p_rules);
3147  if (slen > 0) goto done_bareword;
3148  fr_assert(!*out);
3149 
3150  /*
3151  * See if it's an IPv4 address or prefix
3152  */
3153  slen = tmpl_afrom_ipv4_substr(ctx, out, &our_in, p_rules);
3154  if (slen > 0) goto done_bareword;
3155  fr_assert(!*out);
3156 
3157  /*
3158  * See if it's an IPv6 address or prefix
3159  */
3160  slen = tmpl_afrom_ipv6_substr(ctx, out, &our_in, p_rules);
3161  if (slen > 0) goto done_bareword;
3162  fr_assert(!*out);
3163 
3164  slen = tmpl_afrom_enum(ctx, out, &our_in, p_rules, t_rules);
3165  if (slen > 0) goto done_bareword;
3166  fr_assert(!*out);
3167 
3168  /*
3169  * See if it's a integer
3170  */
3171  slen = tmpl_afrom_integer_substr(ctx, out, &our_in, p_rules);
3172  if (slen > 0) goto done_bareword;
3173  fr_assert(!*out);
3174 
3175  /*
3176  * See if it's a float
3177  */
3178  slen = tmpl_afrom_float_substr(ctx, out, &our_in, p_rules);
3179  if (slen > 0) goto done_bareword;
3180  fr_assert(!*out);
3181 
3182  /*
3183  * See if it's a time delta
3184  *
3185  * We do this after floats and integers so that
3186  * they get parsed as integer and float types
3187  * and not time deltas.
3188  */
3189  slen = tmpl_afrom_time_delta(ctx, out, &our_in, p_rules);
3190  if (slen > 0) goto done_bareword;
3191  fr_assert(!*out);
3192 
3193  /*
3194  * See if it's an attribute reference
3195  * without the prefix.
3196  */
3197  slen = tmpl_afrom_attr_substr(ctx, NULL, out, &our_in, p_rules, t_rules);
3198  if (slen > 0) goto done_bareword;
3199  fr_assert(!*out);
3200 
3201  /*
3202  * Attempt to resolve enumeration values
3203  */
3204  vpt = tmpl_alloc_null(ctx);
3205 
3206  /*
3207  * If it doesn't match any other type of bareword, parse it as an enum name.
3208  *
3209  * Note that we don't actually try to resolve the enum name. The caller is responsible
3210  * for doing that.
3211  */
3212  if (fr_dict_enum_name_afrom_substr(vpt, &str, &sberr, &our_in, p_rules ? p_rules->terminals : NULL) < 0) {
3213  /*
3214  * Produce our own errors which make
3215  * more sense in the context of tmpls
3216  */
3217  switch (sberr) {
3219  fr_strerror_const("No operand found. Expected &ref, literal, "
3220  "'quoted literal', \"%{expansion}\", or enum value");
3221  break;
3222 
3224  fr_strerror_const("enum values must contain at least one alpha character");
3225  break;
3226 
3227  default:
3228  fr_strerror_const("Unexpected text after enum value. Expected operator");
3229  break;
3230  }
3231 
3232  talloc_free(vpt);
3233  FR_SBUFF_ERROR_RETURN(&our_in);
3234  }
3235 
3237  fr_sbuff_start(&our_in), fr_sbuff_used(&our_in), t_rules);
3238  vpt->data.unescaped = str;
3239  *out = vpt;
3240 
3241  FR_SBUFF_SET_RETURN(in, &our_in);
3242 
3244  /*
3245  * Single quoted strings can be cast
3246  * to a specific data type immediately
3247  * as they cannot contain expansions.
3248  */
3249  if (!fr_type_is_null(t_rules->cast)) return tmpl_afrom_value_substr(ctx, out, in, quote,
3250  t_rules, false,
3251  p_rules);
3252  vpt = tmpl_alloc_null(ctx);
3253  slen = fr_sbuff_out_aunescape_until(vpt, &str, &our_in, SIZE_MAX,
3254  p_rules ? p_rules->terminals : NULL,
3255  p_rules ? p_rules->escapes : NULL);
3256  tmpl_init(vpt, TMPL_TYPE_DATA_UNRESOLVED, quote, fr_sbuff_start(&our_in), slen, t_rules);
3257  vpt->data.unescaped = str;
3258  break;
3259 
3261  {
3262  xlat_exp_head_t *head = NULL;
3264 
3265  vpt = tmpl_alloc_null(ctx);
3266 
3267  slen = xlat_tokenize(vpt, &head, &our_in, p_rules, t_rules, t_rules->literals_safe_for);
3268  if (slen < 0) FR_SBUFF_ERROR_RETURN(&our_in);
3269 
3270  /*
3271  * If the string doesn't contain an xlat,
3272  * and we want to cast it as a specific
3273  * type, then do the conversion now.
3274  */
3275  if (xlat_is_literal(head)) {
3276  if (!fr_type_is_null(t_rules->cast)) {
3277  talloc_free(vpt); /* Also frees any nodes */
3278 
3279  return tmpl_afrom_value_substr(ctx, out,
3280  in, quote,
3281  t_rules, false, p_rules);
3282  }
3283 
3284  /*
3285  * If the string doesn't contain an xlat
3286  * and there's no cast, we just store
3287  * the string for conversion later.
3288  */
3289  if (xlat_to_string(vpt, &str, &head)) {
3290  TALLOC_FREE(head);
3291 
3293  fr_sbuff_start(&our_in), slen, t_rules);
3294  vpt->data.unescaped = str; /* Store the unescaped string for parsing later */
3295  break;
3296  }
3297  }
3298 
3299  /*
3300  * If the string actually contains an xlat
3301  * store the compiled xlat.
3302  */
3304 
3305  tmpl_init(vpt, type, quote, fr_sbuff_start(&our_in), slen, t_rules);
3306  vpt->data.xlat.ex = head;
3307  }
3308  break;
3309 
3310  case T_BACK_QUOTED_STRING:
3311  {
3313  xlat_exp_head_t *head = NULL;
3314 
3315  vpt = tmpl_alloc_null(ctx);
3316 
3317  /*
3318  * Ensure that we pre-parse the exec string.
3319  * This allows us to catch parse errors as early
3320  * as possible.
3321  *
3322  * FIXME - We need an ephemeral version of this
3323  * too.
3324  */
3325  slen = xlat_tokenize_argv(vpt, &head, &our_in, NULL, p_rules, t_rules, false, false);
3326  if ((slen <= 0) || !head) {
3327  talloc_free(vpt);
3328  FR_SBUFF_ERROR_RETURN(&our_in);
3329  }
3330 
3331  /*
3332  * Ensure any xlats produced are bootstrapped
3333  * so that their instance data will be created.
3334  */
3335  if (xlat_finalize(head, t_rules->xlat.runtime_el) < 0) {
3336  fr_strerror_const("Failed to bootstrap xlat");
3337  FR_SBUFF_ERROR_RETURN(&our_in);
3338  }
3339 
3341 
3342  tmpl_init(vpt, type, quote, fr_sbuff_start(&our_in), slen, t_rules);
3343  vpt->data.xlat.ex = head;
3344  }
3345  break;
3346 
3348  {
3349  xlat_exp_head_t *head = NULL;
3351 
3352  if (!fr_type_is_null(t_rules->cast)) {
3353  fr_strerror_const("Casts cannot be used with regular expressions");
3354  fr_sbuff_set_to_start(&our_in); /* Point to the cast */
3355  FR_SBUFF_ERROR_RETURN(&our_in);
3356  }
3357 
3358  vpt = tmpl_alloc_null(ctx);
3359 
3360  slen = xlat_tokenize(vpt, &head, &our_in, p_rules, t_rules, t_rules->literals_safe_for);
3361  if (slen < 0) FR_SBUFF_ERROR_RETURN(&our_in);
3362 
3363  /*
3364  * Check if the string actually contains an xlat
3365  * if it doesn't, we unfortunately still
3366  * can't compile the regex here, as we don't know if
3367  * it should be ephemeral or what flags should be used
3368  * during the compilation.
3369  *
3370  * The caller will need to do the compilation after we
3371  * return.
3372  */
3373  if (xlat_to_string(vpt, &str, &head)) {
3375  fr_sbuff_start(&our_in), slen, t_rules);
3376  vpt->data.unescaped = str; /* Store the unescaped string for compilation later */
3377  break;
3378  }
3379  /*
3380  * Mark the regex up as a regex-xlat which
3381  * will need expanding before evaluation, and can never
3382  * be pre-compiled.
3383  */
3385 
3386  tmpl_init(vpt, type, quote, fr_sbuff_start(&our_in), slen, t_rules);
3387  vpt->data.xlat.ex = head;
3388  }
3389  break;
3390 
3391  default:
3392  fr_assert_msg(0, "Unknown quote type %i", quote);
3393  FR_SBUFF_ERROR_RETURN(&our_in);
3394  }
3395 
3396  TMPL_VERIFY(vpt);
3397  *out = vpt;
3398 
3399  FR_SBUFF_SET_RETURN(in, &our_in);
3400 }
3401 
3402 /** Copy a tmpl
3403  *
3404  * Fully duplicates the contents of a tmpl including any nested attribute
3405  * references.
3406  *
3407  * @param[in] ctx to perform allocations under.
3408  * @param[in] in tmpl to duplicate.
3409  * @return
3410  * - NULL on error.
3411  * - A new tmpl on success.
3412  */
3413 tmpl_t *tmpl_copy(TALLOC_CTX *ctx, tmpl_t const *in)
3414 {
3415  tmpl_t *vpt;
3416 
3417  MEM(vpt = tmpl_alloc(ctx, in->type, in->quote, in->name, in->len));
3418  vpt->rules = in->rules;
3419 
3420  /*
3421  * Copy over the unescaped data
3422  */
3424  if (unlikely(!(vpt->data.unescaped = talloc_bstrdup(vpt, in->data.unescaped)))) {
3425  error:
3426  talloc_free(vpt);
3427  return NULL;
3428  }
3429  }
3430 
3431  /*
3432  * Copy attribute references
3433  */
3434  if (tmpl_contains_attr(vpt) && unlikely(tmpl_attr_copy(vpt, in) < 0)) goto error;
3435 
3436  /*
3437  * Copy flags for all regex flavours (and possibly recompile the regex)
3438  */
3439  if (tmpl_contains_regex(vpt)) {
3440  vpt->data.reg_flags = in->data.reg_flags;
3441 
3442  /*
3443  * If the tmpl contains a _compiled_ regex
3444  * then convert it back to an uncompiled
3445  * regex and recompile.
3446  *
3447  * Most of the regex libraries don't allow
3448  * copying compiled expressions.
3449  */
3450  if (tmpl_is_regex(vpt)) {
3452  if (unlikely(!(vpt->data.unescaped = talloc_bstrdup(vpt, in->data.reg.src)))) goto error;
3453  if (unlikely(tmpl_regex_compile(vpt, vpt->data.reg.subcaptures) < 0)) goto error;
3454  return vpt;
3455  }
3456  }
3457 
3458  /*
3459  * Copy the xlat component.
3460  *
3461  * @todo - in general we can't copy an xlat, as the instances need resolving!
3462  *
3463  * We add an assertion here because nothing allocates the head, and we need it.
3464  */
3465  if (tmpl_contains_xlat(vpt)) {
3466  fr_assert(vpt->data.xlat.ex != NULL);
3467 
3468  if (unlikely(xlat_copy(vpt, vpt->data.xlat.ex, in->data.xlat.ex) < 0)) goto error;
3469  }
3470 
3471  return vpt;
3472 }
3473 
3474 /** Parse a cast specifier
3475  *
3476  * Note that casts are
3477  *
3478  * (foo)
3479  *
3480  * and NOT
3481  *
3482  * ( foo )
3483  *
3484  * Not for any particular reason, but to emphasize a bit that they're
3485  * not mathematical expressions.
3486  *
3487  * @param[out] rules to set the cast type in.
3488  * @param[in] in String containing the cast marker.
3489  * @return
3490  * - 0 no cast specifier found.
3491  * - >0 the number of bytes parsed.
3492  * - <0 offset of parse error.
3493  */
3495 {
3496  char close = '\0';
3497  fr_sbuff_t our_in = FR_SBUFF(in);
3499  fr_type_t cast;
3500  ssize_t slen;
3501 
3502  if (fr_sbuff_next_if_char(&our_in, '<')) {
3503  close = '>';
3504 
3505  } else if (fr_sbuff_next_if_char(&our_in, '(')) {
3506  close = ')';
3507 
3508  } else {
3509  if (rules) rules->cast = FR_TYPE_NULL;
3510  return 0;
3511  }
3512 
3513  fr_sbuff_marker(&m, &our_in);
3515  if (fr_type_is_null(cast)) {
3516  fr_strerror_const("Unknown data type");
3517  FR_SBUFF_ERROR_RETURN(&our_in);
3518  }
3519  if (fr_type_is_non_leaf(cast)) {
3520  fr_strerror_printf("Forbidden data type '%s' in cast", fr_type_to_str(cast));
3522  }
3523 
3524  if (!fr_sbuff_next_if_char(&our_in, close)) {
3525  fr_strerror_const("Unterminated cast");
3526  FR_SBUFF_ERROR_RETURN(&our_in);
3527  }
3528  fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
3529 
3530  if (rules) rules->cast = cast;
3531 
3532  FR_SBUFF_SET_RETURN(in, &our_in);
3533 }
3534 
3535 /** Set a cast for a tmpl
3536  *
3537  * @param[in,out] vpt to set cast for.
3538  * @param[in] dst_type to set.
3539  * @return
3540  * - 0 on success.
3541  * - -1 on failure.
3542  */
3544 {
3545  fr_type_t src_type;
3546 
3547  switch (dst_type) {
3548  default:
3549  fr_strerror_printf("Forbidden data type '%s' in cast",
3550  fr_type_to_str(dst_type));
3551  return -1;
3552 
3553  /*
3554  * We can always remove a cast.
3555  */
3556  case FR_TYPE_NULL:
3557  goto done;
3558 
3559  /*
3560  * Only "base" data types are allowed. Structural types
3561  * and horrid WiMAX crap is forbidden.
3562  */
3563  case FR_TYPE_LEAF:
3564  break;
3565  }
3566 
3567  switch (vpt->type) {
3568  /*
3569  * This should have been fixed before we got here.
3570  */
3572 
3573  /*
3574  * By default, tmpl types cannot be cast to anything.
3575  */
3576  default:
3577  fr_strerror_const("Cannot use cast here.");
3578  return -1;
3579 
3580  /*
3581  * These tmpl types are effectively of data type
3582  * "string", so they can be cast to anything.
3583  */
3584  case TMPL_TYPE_XLAT:
3585  case TMPL_TYPE_EXEC:
3589  break;
3590 
3591  case TMPL_TYPE_DATA:
3592  src_type = tmpl_value_type(vpt);
3593  goto check_types;
3594 
3595  case TMPL_TYPE_ATTR:
3596  src_type = tmpl_attr_tail_da(vpt)->type;
3597 
3598 
3599  /*
3600  * Suppress casts where they are duplicate.
3601  */
3602  check_types:
3603  if (src_type == dst_type) {
3605  return 0;
3606  }
3607 
3608  if (!fr_type_cast(dst_type, src_type)) {
3609  fr_strerror_printf("Cannot cast type '%s' to '%s'",
3610  fr_type_to_str(src_type),
3611  fr_type_to_str(dst_type));
3612  return -1;
3613  }
3614  break;
3615  }
3616 
3617 done:
3618  vpt->rules.cast = dst_type;
3619  return 0;
3620 }
3621 
3622 #ifdef HAVE_REGEX
3623 /** Parse a set of regular expression flags
3624  *
3625  * @param[out] vpt Write the flags to the regex flags field in this #tmpl_t.
3626  * @param[in] in Where to parse the flag string from.
3627  * @param[in] terminals That mark the end of the regex flag string.
3628  * @return
3629  * - 0 no flags found.
3630  * - >0 the number of bytes of flags parsed.
3631  * - <0 offset of parse error.
3632  */
3633 ssize_t tmpl_regex_flags_substr(tmpl_t *vpt, fr_sbuff_t *in, fr_sbuff_term_t const *terminals)
3634 {
3635  fr_slen_t slen;
3636  int err = 0;
3637 
3639 
3640  slen = regex_flags_parse(&err, &vpt->data.reg_flags, in, terminals, true);
3641  switch (err) {
3642  case 0:
3643  break;
3644 
3645  case -1: /* Non-flag and non-terminal */
3646  case -2: /* Duplicate flag */
3647  return slen;
3648  }
3649 
3650  return slen;
3651 }
3652 #endif
3653 
3654 /** @name Change a #tmpl_t type, usually by casting or resolving a reference
3655  *
3656  * #tmpl_cast_in_place can be used to convert #TMPL_TYPE_DATA_UNRESOLVED to a #TMPL_TYPE_DATA of a
3657  * specified #fr_type_t.
3658  *
3659  * #tmpl_attr_unknown_add converts a #TMPL_TYPE_ATTR with an unknown #fr_dict_attr_t to a
3660  * #TMPL_TYPE_ATTR with a known #fr_dict_attr_t, by adding the unknown #fr_dict_attr_t to the main
3661  * dictionary, and updating the ``tmpl_attr_tail_da`` pointer.
3662  * @{
3663  */
3664 
3665 /** Determine the correct quoting after a cast
3666  *
3667  * @param[in] existing_quote Exiting quotation type.
3668  * @param[in] type Cast type.
3669  * @param[in] enumv Enumeration values.
3670  * @param[in] unescaped The unescaped value of an enumeration.
3671  * @param[in] unescaped_len Length of unescaped.
3672  */
3673 static inline CC_HINT(always_inline)
3675  fr_type_t type, fr_dict_attr_t const *enumv,
3676  char const *unescaped, size_t unescaped_len)
3677 {
3678  if (!fr_type_is_string(type)) return T_BARE_WORD;
3679 
3680  if (enumv && fr_dict_enum_by_name(enumv, unescaped, unescaped_len)) return T_BARE_WORD;
3681 
3682  /*
3683  * Leave the original quoting if it's
3684  * single or double, else default to
3685  * single quoting.
3686  */
3687  switch (existing_quote) {
3690  return existing_quote;
3691 
3692  default:
3693  return T_SINGLE_QUOTED_STRING;
3694  }
3695 }
3696 
3697 
3698 /** Convert #tmpl_t of type #TMPL_TYPE_DATA_UNRESOLVED or #TMPL_TYPE_DATA to #TMPL_TYPE_DATA of type specified
3699  *
3700  * @note Conversion is done in place.
3701  * @note Irrespective of whether the #tmpl_t was #TMPL_TYPE_DATA_UNRESOLVED or #TMPL_TYPE_DATA,
3702  * on successful cast it will be #TMPL_TYPE_DATA.
3703  *
3704  * @param[in,out] vpt The template to modify. Must be of type #TMPL_TYPE_DATA_UNRESOLVED
3705  * or #TMPL_TYPE_DATA.
3706  * @param[in] type to cast to.
3707  * @param[in] enumv Enumerated dictionary values associated with a #fr_dict_attr_t.
3708  * @return
3709  * - 0 on success.
3710  * - -1 on failure.
3711  */
3713 {
3714  TMPL_VERIFY(vpt);
3715 
3717 
3718  switch (vpt->type) {
3720  {
3721  char *unescaped = vpt->data.unescaped;
3722 
3723  /*
3724  * We're trying to convert an unresolved (bareword)
3725  * tmpl to octets.
3726  *
3727  * tmpl_afrom_substr uses the 0x prefix as type
3728  * inference, so if it was a hex string the tmpl
3729  * type would not have fallen through to
3730  * unresolved.
3731  *
3732  * That means if we're trying to resolve it here
3733  * it's really a printable string, not a sequence
3734  * of hexits, so we just want the binary
3735  * representation of that string, and not the hex
3736  * to bin conversion.
3737  */
3738  if (fr_type_is_octets(type)) {
3739  if (fr_value_box_memdup(vpt, &vpt->data.literal, enumv,
3740  (uint8_t const *)unescaped, talloc_array_length(unescaped) - 1,
3741  false) < 0) return -1;
3742  } else {
3743  if (fr_value_box_from_str(vpt, &vpt->data.literal, type,
3744  enumv,
3745  unescaped, talloc_array_length(unescaped) - 1,
3746  NULL, false) < 0) return -1;
3747  }
3748  vpt->type = TMPL_TYPE_DATA;
3749  vpt->quote = tmpl_cast_quote(vpt->quote, type, enumv,
3750  unescaped, talloc_array_length(unescaped) - 1);
3751  talloc_free(unescaped);
3752 
3753  /*
3754  * The data is now of the correct type, so we don't need to keep a cast.
3755  */
3756  vpt->rules.cast = FR_TYPE_NULL;
3757  }
3758  break;
3759 
3760  case TMPL_TYPE_DATA:
3761  {
3762  if (type == tmpl_value_type(vpt)) return 0; /* noop */
3763 
3764  /*
3765  * Enumerations aren't used when casting between
3766  * data types. They're only used when processing
3767  * unresolved tmpls.
3768  *
3769  * i.e. TMPL_TYPE_DATA_UNRESOLVED != TMPL_TYPE_DATA(FR_TYPE_STRING)
3770  */
3771  if (fr_value_box_cast_in_place(vpt, &vpt->data.literal, type, NULL) < 0) return -1;
3772 
3773  /*
3774  * Strings get quoted, everything else is a bare
3775  * word...
3776  */
3777  if (fr_type_is_string(type)) {
3778  vpt->quote = T_SINGLE_QUOTED_STRING;
3779  } else {
3780  vpt->quote = T_BARE_WORD;
3781  }
3782 
3783  /*
3784  * The data is now of the correct type, so we don't need to keep a cast.
3785  */
3786  vpt->rules.cast = FR_TYPE_NULL;
3787  }
3788  break;
3789 
3790  case TMPL_TYPE_ATTR:
3791  /*
3792  * Suppress casts to the same type.
3793  */
3794  if (tmpl_attr_tail_da(vpt)->type == type) {
3795  vpt->rules.cast = FR_TYPE_NULL;
3796  break;
3797  }
3798  FALL_THROUGH;
3799 
3801  vpt->rules.cast = type;
3802  break;
3803 
3804  default:
3805  fr_assert(0);
3806  }
3807  TMPL_VERIFY(vpt);
3808 
3809  return 0;
3810 }
3811 
3812 /** Resolve an unresolved attribute
3813  *
3814  * Multi-pass parsing fixups for attribute references.
3815  *
3816  * @param[in] vpt to resolve.
3817  * @param[in] tr_rules Combined with the original parse rules for
3818  * additional resolution passes.
3819  * @return
3820  * - 0 if all references were resolved.
3821  * - -1 if there are unknown attributes which need
3822  * adding to the global dictionary first.
3823  * - -2 if there are attributes we couldn't resolve.
3824  */
3825 static inline CC_HINT(always_inline) int tmpl_attr_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
3826 {
3827  tmpl_attr_t *ar = NULL, *next, *prev;
3828  fr_dict_attr_t const *da, *namespace;
3829  fr_dict_t const *dict_def;
3830 
3832 
3833  TMPL_VERIFY(vpt);
3834 
3835  dict_def = vpt->rules.attr.dict_def;
3836  if (!dict_def || tr_rules->force_dict_def) dict_def = tr_rules->dict_def;
3837 
3838  /*
3839  * First component is special because we may need
3840  * to search for it in multiple dictionaries.
3841  *
3842  * This emulates what's done in the initial
3843  * tokenizer function.
3844  */
3845  ar = tmpl_attr_list_head(tmpl_attr(vpt));
3846  if (ar->type == TMPL_ATTR_TYPE_UNRESOLVED) {
3848  &da,
3849  dict_def,
3850  &FR_SBUFF_IN(ar->ar_unresolved,
3851  talloc_array_length(ar->ar_unresolved) - 1),
3852  NULL,
3853  true,
3854  vpt->rules.attr.allow_foreign);
3855  if (!da) return -2; /* Can't resolve, maybe the caller can resolve later */
3856 
3857  ar->ar_type = TMPL_ATTR_TYPE_NORMAL;
3858  ar->ar_da = da;
3859  ar->ar_parent = fr_dict_root(fr_dict_by_da(da));
3860 
3861  /*
3862  * Record the dictionary that was
3863  * successfully used for resolution.
3864  */
3865  vpt->rules.attr.dict_def = tr_rules->dict_def;
3866 
3867  /*
3868  * Reach into the next reference
3869  * and correct its parent and
3870  * namespace.
3871  */
3872  next = tmpl_attr_list_next(tmpl_attr(vpt), ar);
3873  if (next) {
3874  next->ar_parent = da;
3875  next->ar_unresolved_namespace = da;
3876  }
3877  }
3878 
3879  /*
3880  * Loop, resolving each unresolved attribute in turn
3881  */
3882  while ((ar = tmpl_attr_list_next(tmpl_attr(vpt), ar))) {
3883  switch (ar->type) {
3884  case TMPL_ATTR_TYPE_NORMAL:
3885  case TMPL_ATTR_TYPE_UNSPEC:
3886  continue; /* Don't need to resolve */
3887 
3889  return -1; /* Unknown attributes must be resolved first */
3890 
3891  default:
3892  break;
3893  }
3894 
3895  prev = tmpl_attr_list_prev(tmpl_attr(vpt), ar);
3896 
3897  /*
3898  * If the parent is a list AR, then use the default dictionary for the namespace
3899  */
3900  namespace = (prev && dict_def && tmpl_attr_is_list_attr(prev)) ? fr_dict_root(dict_def) : ar->ar_unresolved_namespace;
3901 
3902  (void)fr_dict_attr_by_name_substr(NULL,
3903  &da,
3904  namespace,
3905  &FR_SBUFF_IN(ar->ar_unresolved,
3906  talloc_array_length(ar->ar_unresolved) - 1),
3907  NULL);
3908  /*
3909  * Still can't resolve, check to see if
3910  * the last attribute reference was a
3911  * group.
3912  *
3913  * If it was, then we may be able to
3914  * fall back to resolving the attribute
3915  * in the internal dictionary.
3916  */
3917  if (!da) {
3918  if (prev && (prev->ar_da->type == FR_TYPE_GROUP)) {
3919  (void)fr_dict_attr_by_name_substr(NULL,
3920  &da,
3922  &FR_SBUFF_IN(ar->ar_unresolved,
3923  talloc_array_length(ar->ar_unresolved) - 1),
3924  NULL);
3925  }
3926  if (!da) return -2;
3927  }
3928 
3929  /*
3930  * Known attribute, just rewrite.
3931  */
3932  ar->ar_type = TMPL_ATTR_TYPE_NORMAL;
3933  ar->ar_da = da;
3934 
3935  /*
3936  * Parent should have been corrected in
3937  * the previous loop iteration.
3938  */
3939  fr_assert(ar->ar_parent && !ar->ar_parent->flags.is_unknown);
3940 
3941  /*
3942  * Reach into the next reference
3943  * and correct its parent.
3944  */
3945  next = tmpl_attr_list_next(tmpl_attr(vpt), ar);
3946  if (next) {
3947  next->ar_parent = da;
3948  next->ar_unresolved_namespace = da;
3949  }
3950 
3951  /*
3952  * Remove redundant attributes
3953  *
3954  * If it's not a group or does not specify
3955  * an index, the ar is redundant and should
3956  * be removed.
3957  */
3958  prev = tmpl_attr_list_prev(tmpl_attr(vpt), ar);
3959  if (prev && (prev->ar_da->type != FR_TYPE_GROUP) && (prev->ar_num == NUM_UNSPEC)) {
3960  tmpl_attr_list_remove(tmpl_attr(vpt), prev);
3961  ar->ar_parent = prev->ar_parent;
3962  talloc_free(prev);
3963  }
3964  }
3965 
3966  RESOLVED_SET(&vpt->type);
3967  TMPL_VERIFY(vpt);
3968 
3969  return 0;
3970 }
3971 
3972 /** Resolve an unresolved xlat, i.e. one containing unresolved attribute references or xlat functions
3973  *
3974  * Multi-pass parsing fixups for attribute references.
3975  *
3976  * Works for base types:
3977  * - TMPL_TYPE_XLAT
3978  * - TMPL_TYPE_EXEC
3979  * - TMPL_TYPE_REGEX_XLAT
3980  *
3981  * @param[in] vpt Containing the xlat expansion to resolve.
3982  * @param[in] tr_rules Combined with the original parse rules for
3983  * additional resolution passes.
3984  * @return
3985  * - 0 on success.
3986  * - -1 on failure.
3987  */
3988 static inline CC_HINT(always_inline)
3990 {
3991  if (xlat_resolve(vpt->data.xlat.ex,
3992  &(xlat_res_rules_t){
3993  .tr_rules = tr_rules,
3994  .allow_unresolved = false
3995  }) < 0) return -1;
3996 
3997  fr_assert(!xlat_needs_resolving(vpt->data.xlat.ex));
3998 
3999  RESOLVED_SET(&vpt->type);
4000  TMPL_VERIFY(vpt);
4001 
4002  return 0;
4003 }
4004 
4005 /** Attempt to resolve functions and attributes in xlats and attribute references
4006  *
4007  * @note If resolution is successful, the rules->attr.dict_def field will be modified to
4008  * reflect the dictionary resolution was successful in.
4009  *
4010  * @param[in,out] vpt to resolve. Should be of type TMPL_TYPE_XLAT_UNRESOLVED
4011  * or TMPL_TYPE_ATTR_UNRESOLVED. All other types will be
4012  * noops.
4013  * @param[in] tr_rules Combined with the original parse rules for
4014  * additional resolution passes.
4015  * @return
4016  * - 0 on success.
4017  * - -1 on failure.
4018  */
4019 int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
4020 {
4021  static tmpl_res_rules_t const default_tr_rules;
4022 
4023  int ret = 0;
4024 
4025  if (!tmpl_needs_resolving(vpt)) return 0; /* Nothing to do */
4026 
4027  if (!tr_rules) tr_rules = &default_tr_rules;
4028 
4029  /*
4030  * Sanity check. There shouldn't be conflicting
4031  * enumvs between the original rules and resolution
4032  * rules.
4033  *
4034  * Either the enumv was available during parsing
4035  * and shouldn't have changed during subsequent
4036  * resolution passes, or it wasn't available at
4037  * parse-time, but now is.
4038  */
4039  if (tr_rules->enumv && tmpl_rules_enumv(vpt) && !tmpl_rules_enumv(vpt)->flags.is_unknown &&
4040  (tr_rules->enumv != tmpl_rules_enumv(vpt))) {
4041  fr_strerror_printf("mismatch between parse-time enumv '%s' and resolution-time enumv '%s'",
4042  tmpl_rules_enumv(vpt)->name, tr_rules->enumv->name);
4043 
4044  return -1;
4045  }
4046 
4047  /*
4048  * The xlat component of the #tmpl_t needs resolving.
4049  *
4050  * This includes exec tmpls, which are largely xlats
4051  * "under the hood".
4052  */
4053  if (tmpl_contains_xlat(vpt)) {
4054  ret = tmpl_xlat_resolve(vpt, tr_rules);
4055 
4056  /*
4057  * The attribute reference needs resolving.
4058  */
4059  } else if (tmpl_contains_attr(vpt)) {
4060  fr_type_t dst_type = tmpl_rules_cast(vpt);
4061 
4062  fr_assert(vpt->quote == T_BARE_WORD); /* 'User-Name' or "User-Name" is not allowed. */
4063 
4064  ret = tmpl_attr_resolve(vpt, tr_rules);
4065  if (ret < 0) return ret;
4066 
4067  if (dst_type == tmpl_attr_tail_da(vpt)->type) {
4068  vpt->rules.cast = FR_TYPE_NULL;
4069  }
4070 
4071  /*
4072  * Convert unresolved tmpls into enumvs, or failing that, string values.
4073  *
4074  * Unresolved tmpls are by definition TMPL_TYPE_DATA.
4075  */
4076  } else if (tmpl_is_data_unresolved(vpt)) {
4077  fr_type_t dst_type = tmpl_rules_cast(vpt);
4078  fr_dict_attr_t const *enumv = tmpl_rules_enumv(vpt);
4079 
4080  /*
4081  * If there wasn't an enumv set in the
4082  * original rules, and we now have one
4083  * (possibly because the other side of a
4084  * binary expression has been resolved),
4085  * then use the new enumv.
4086  */
4087  if (!enumv) enumv = tr_rules->enumv;
4088 
4089  /*
4090  * If we've got no explicit casting to do
4091  * check if we've got either an existing
4092  * enumv, or one which came in from the
4093  * resolution rules, and infer our data type
4094  * from that.
4095  */
4096  if (fr_type_is_null(dst_type)) {
4097  /*
4098  * Infer the cast from the enumv type.
4099  */
4100  if (enumv) {
4101  dst_type = enumv->type;
4102  } else {
4103  dst_type = FR_TYPE_STRING; /* Default to strings */
4104  }
4105  }
4106 
4107  /*
4108  * tmpl_cast_in_place first resolves using
4109  * the enumv, _then_ casts using the type.
4110  */
4111  if (tmpl_cast_in_place(vpt, dst_type, enumv) < 0) return -1;
4112 
4113  TMPL_VERIFY(vpt);
4114  /*
4115  * Catch any other cases of unresolved things
4116  * we need to address. We put the assert here
4117  * so we don't end up running inappropriate
4118  * code for non-debug builds.
4119  */
4120  } else {
4121  fr_assert(0);
4122  }
4123 
4124  return ret;
4125 }
4126 
4127 /** Reset the tmpl, leaving only the name in place
4128  *
4129  * After calling this function, the tmpl type will revert to TMPL_TYPE_DATA_UNRESOLVED
4130  * and only the name and quoting will be preserved.
4131  *
4132  * @param[in] vpt to reset.
4133  */
4135 {
4136  tmpl_t tmp = {
4137  .type = TMPL_TYPE_DATA_UNRESOLVED,
4138  .name = vpt->name,
4139  .len = vpt->len,
4140  .quote = vpt->quote
4141  };
4142 
4143  switch (vpt->type) {
4145  case TMPL_TYPE_MAX:
4146  fr_assert(0);
4147  break;
4148 
4149  case TMPL_TYPE_NULL:
4152  break;
4153 
4154  case TMPL_TYPE_DATA:
4155  fr_value_box_clear(&vpt->data.literal);
4156  break;
4157 
4158  /*
4159  * These types contain dynamically allocated
4160  * attribute and request references.
4161  */
4162  case TMPL_TYPE_ATTR:
4164  tmpl_attr_list_talloc_free(tmpl_attr(vpt));
4165  tmpl_request_list_talloc_free(&vpt->data.attribute.rr);
4166  break;
4167 
4168  /*
4169  * These all store an xlat expansion
4170  */
4171  case TMPL_TYPE_EXEC:
4172  case TMPL_TYPE_XLAT:
4173  case TMPL_TYPE_REGEX_XLAT:
4177  TALLOC_FREE(vpt->data.xlat.ex);
4178  break;
4179 
4180  case TMPL_TYPE_REGEX:
4181  talloc_free(vpt->data.reg.ex);
4182  break;
4183 
4184  }
4185 
4186  memcpy(vpt, &tmp, sizeof(*vpt));
4187 
4188  TMPL_VERIFY(vpt);
4189 }
4190 
4191 /** Convert an attribute reference to an xlat expansion
4192  *
4193  * This is where a user attempts to use an attribute reference which is actually
4194  * a virtual attribute.
4195  *
4196  * @param[in] ctx to convert new tmpl in.
4197  * @param[in,out] vpt_p pointer to #tmpl_t of TMPL_TYPE_ATTR | TMPL_TYPE_ATTR_UNPARSED.
4198  */
4199 int tmpl_attr_to_xlat(TALLOC_CTX *ctx, tmpl_t **vpt_p)
4200 {
4201 
4202  tmpl_t *vpt;
4203  tmpl_t *attr = *vpt_p;
4204 
4205  /*
4206  * First alloc a new tmpl to hold the xlat expansion
4207  */
4208  vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, attr->quote, attr->name, attr->len);
4209 
4210  /*
4211  * ...then wrap the old tmpl_t in an xlat expansion
4212  * doing conversion to a virtual attribute if necessary.
4213  */
4214  if (xlat_from_tmpl_attr(vpt, &vpt->data.xlat.ex, vpt_p) < 0) {
4215  talloc_free(vpt);
4216  return -1;
4217  }
4218 
4219  if (xlat_needs_resolving(vpt->data.xlat.ex)) UNRESOLVED_SET(&vpt->type);
4220 
4221  *vpt_p = vpt;
4222 
4223  return 0;
4224 }
4225 
4226 static void attr_to_raw(tmpl_t *vpt, tmpl_attr_t *ref)
4227 {
4228  if (!ref) return;
4229 
4230  switch (ref->type) {
4231  case TMPL_ATTR_TYPE_NORMAL:
4232  {
4233  ref->da = ref->ar_unknown = fr_dict_unknown_afrom_da(vpt, ref->da);
4234  ref->ar_unknown->type = FR_TYPE_OCTETS;
4235  ref->is_raw = 1;
4236  ref->ar_unknown->flags.is_unknown = 1;
4238  }
4239  break;
4240  case TMPL_ATTR_TYPE_UNSPEC: /* noop */
4241  break;
4242 
4244  ref->ar_unknown->type = FR_TYPE_OCTETS;
4245  ref->is_raw = 1;
4246  break;
4247 
4249  ref->is_raw = true;
4250  break;
4251  }
4252 
4254 }
4255 
4256 /** Convert the leaf attribute of a tmpl to a unknown/raw type
4257  *
4258  */
4260 {
4261  attr_to_raw(vpt, tmpl_attr_list_tail(tmpl_attr(vpt)));
4262 }
4263 
4264 /** Add an unknown #fr_dict_attr_t specified by a #tmpl_t to the main dictionary
4265  *
4266  * @param vpt to add. ``tmpl_attr_tail_da`` pointer will be updated to point to the
4267  * #fr_dict_attr_t inserted into the dictionary.
4268  * @return
4269  * - 1 noop (did nothing) - Not possible to convert tmpl.
4270  * - 0 on success.
4271  * - -1 on failure.
4272  */
4274 {
4275  tmpl_attr_t *ar = NULL, *next = NULL;
4276 
4277  if (!vpt) return 1;
4278 
4279  /*
4280  * Can't do this for expressions parsed at runtime
4281  */
4282  if (vpt->rules.at_runtime) return 1;
4283 
4285 
4286  TMPL_VERIFY(vpt);
4287 
4288  if (!tmpl_attr_tail_is_unknown(vpt)) return 1; /* Ensure at least the leaf is unknown */
4289 
4290  while ((ar = tmpl_attr_list_next(tmpl_attr(vpt), ar))) {
4291  fr_dict_attr_t const *unknown, *known;
4292 
4293  switch (ar->type) {
4294  case TMPL_ATTR_TYPE_NORMAL: /* Skip */
4295  case TMPL_ATTR_TYPE_UNSPEC:
4296  continue;
4297 
4298  case TMPL_ATTR_TYPE_UNRESOLVED: /* Shouldn't have been called */
4299  fr_strerror_const("Remaining attributes are unresolved");
4300  return -1;
4301 
4303  break;
4304  }
4305 
4306  unknown = ar->ar_unknown;
4307  known = fr_dict_unknown_add(fr_dict_unconst(fr_dict_by_da(unknown)), unknown);
4308  if (!known) return -1;
4309 
4310  /*
4311  * Fixup the parent of the next unknown
4312  * now it's known.
4313  */
4314  next = tmpl_attr_list_next(tmpl_attr(vpt), ar);
4315  if (next && (next->type == TMPL_ATTR_TYPE_UNKNOWN) &&
4316  (next->ar_da->parent == unknown)) {
4318  known) < 0) return -1;
4319  next->ar_parent = known;
4320  }
4321 
4322  /*
4323  * Convert the ref to a normal type.
4324  * At runtime there should be no
4325  * "unknown" references as they should
4326  * have all been added to a
4327  * dictionary.
4328  */
4330 
4331  /*
4332  * If the attribute is *NOT* raw then
4333  * swap the canonical unknown with the
4334  * one that was previously associated
4335  * with the tmpl.
4336  *
4337  * This establishes the unknown attribute
4338  * in the dictionary if it was really
4339  * unknown whilst not mucking up the
4340  * types for raw attributes.
4341  */
4342  if (!ar_is_raw(ar)) {
4343  fr_dict_unknown_free(&ar->ar_da);
4344  ar->ar_da = known;
4345  } else if (!fr_cond_assert(!next)) {
4346  fr_strerror_const("Only the leaf may be raw");
4347  return -1;
4348  }
4349  }
4350 
4351  return 0;
4352 }
4353 
4354 /** Add an unresolved #fr_dict_attr_t specified by a #tmpl_t to the main dictionary
4355  *
4356  * @note fr_dict_attr_add will not return an error if the attribute already exists
4357  * meaning that multiple #tmpl_t specifying the same attribute can be
4358  * passed to this function to be fixed up, so long as the type and flags
4359  * are identical.
4360  *
4361  * @param[in] dict_def Default dictionary to use if none is
4362  * specified by the tmpl_attr_tail_unresolved.
4363  * @param[in] vpt specifying unresolved attribute to add.
4364  * ``tmpl_attr_tail_da`` pointer will be updated to
4365  * point to the #fr_dict_attr_t inserted
4366  * into the dictionary. Lists and requests
4367  * will be preserved.
4368  * @param[in] type to define unresolved attribute as.
4369  * @param[in] flags to define unresolved attribute with.
4370  * @return
4371  * - 1 noop (did nothing) - Not possible to convert tmpl.
4372  * - 0 on success.
4373  * - -1 on failure.
4374  */
4376  fr_type_t type, fr_dict_attr_flags_t const *flags)
4377 {
4378  fr_dict_attr_t const *da;
4379 
4380  if (!vpt) return -1;
4381 
4382  TMPL_VERIFY(vpt);
4383 
4384  if (!tmpl_is_attr_unresolved(vpt)) return 1;
4385 
4386  if (fr_dict_attr_add(dict_def,
4388  return -1;
4389  }
4391  if (!da) return -1;
4392 
4393  if (type != da->type) {
4394  fr_strerror_printf("Attribute %s of type %s already defined with type %s",
4395  da->name, fr_type_to_str(type),
4396  fr_type_to_str(da->type));
4397  return -1;
4398  }
4399 
4400  if (memcmp(flags, &da->flags, sizeof(*flags)) != 0) {
4401  fr_strerror_printf("Attribute %s already defined with different flags", da->name);
4402  return -1;
4403  }
4404 
4405  tmpl_attr_set_da(vpt, da);
4406  vpt->type = TMPL_TYPE_ATTR;
4407 
4408  return 0;
4409 }
4410 
4411 #ifdef HAVE_REGEX
4412 /** Convert a TMPL_TYPE_REGEX_UNCOMPILED into a TMPL_TYPE_REGEX
4413  *
4414  * Other regex types become noops.
4415  */
4416 ssize_t tmpl_regex_compile(tmpl_t *vpt, bool subcaptures)
4417 {
4418  ssize_t slen;
4419  char *unescaped = vpt->data.unescaped;
4420 
4421  if (tmpl_is_regex_xlat(vpt) || tmpl_is_regex(vpt)) return 0; /* Don't need compiling */
4422 
4424 
4425  slen = regex_compile(vpt, &vpt->data.reg.ex,
4426  unescaped, talloc_array_length(unescaped) - 1,
4427  &vpt->data.reg_flags, subcaptures, vpt->rules.at_runtime);
4428  if (slen <= 0) return vpt->quote != T_BARE_WORD ? slen - 1 : slen; /* Account for the quoting */
4429 
4430  vpt->type = TMPL_TYPE_REGEX;
4431  vpt->data.reg.src = unescaped; /* Keep this around for debugging and copying */
4432  vpt->data.reg.subcaptures = subcaptures;
4433 
4434  TMPL_VERIFY(vpt);
4435 
4436  return slen;
4437 }
4438 #endif
4439 /** @} */
4440 
4441 /** @name Print the contents of a #tmpl_t
4442  * @{
4443  */
4445 {
4446  fr_sbuff_t our_out = FR_SBUFF(out);
4447  tmpl_request_t *rr = tmpl_request_list_head(rql);
4448 
4449  /*
4450  * Print request references
4451  */
4452  while (rr) {
4453  FR_SBUFF_IN_TABLE_STR_RETURN(&our_out, tmpl_request_ref_table, rr->request, "<INVALID>");
4454  rr = tmpl_request_list_next(rql, rr);
4455  if (rr) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
4456  }
4457 
4458  FR_SBUFF_SET_RETURN(out, &our_out);
4459 }
4460 
4461 /** Print an attribute or list #tmpl_t to a string
4462  *
4463  * This function is the direct counterpart to #tmpl_afrom_attr_substr.
4464  *
4465  * @param[in] out Where to write the presentation format #tmpl_t string.
4466  * @param[in] vpt to print.
4467  * @param[in] ar_prefix Whether to print the '&' at the beginning of attribute
4468  * references.
4469  * - TMPL_ATTR_REF_PREFIX_YES - always print.
4470  * - TMPL_ATTR_REF_PREFIX_NO - never print.
4471  * - TMPL_ATTR_REF_PREFIX_AUTO - print if the original tmpl
4472  * was prefixed.
4473  * @return
4474  * - >0 the number of bytes written to the out buffer.
4475  * - 0 invalid argument.
4476  * - <0 the number of bytes we would have needed to complete the print.
4477  */
4479 {
4480  tmpl_attr_t *ar = NULL;
4482  fr_sbuff_t our_out = FR_SBUFF(out);
4483  fr_slen_t slen;
4484 
4485  TMPL_VERIFY(vpt);
4486 
4487  /*
4488  * Only print things we can print...
4489  */
4490  switch (vpt->type) {
4492  case TMPL_TYPE_ATTR:
4493  break;
4494 
4495  default:
4496  fr_assert(0);
4497  return 0;
4498  }
4499 
4500  /*
4501  * Handle printing the request reference
4502  * prefix.
4503  */
4505  ((ar_prefix == TMPL_ATTR_REF_PREFIX_AUTO) && vpt->data.attribute.ref_prefix)) {
4506  FR_SBUFF_IN_CHAR_RETURN(&our_out, '&');
4507  }
4508 
4509  /*
4510  * Print request references
4511  */
4512  slen = tmpl_request_ref_list_print(&our_out, &vpt->data.attribute.rr);
4513  if (slen > 0) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
4514  if (slen < 0) return slen;
4515 
4516  /*
4517  *
4518  * If the leaf attribute is unknown and raw we
4519  * add the raw. prefix.
4520  *
4521  * If the leaf attribute is unknown and not raw
4522  * we add the .unknown prefix.
4523  *
4524  */
4526 
4527  /*
4528  * Print attribute identifiers
4529  */
4530  ar = NULL;
4531  while ((ar = tmpl_attr_list_next(tmpl_attr(vpt), ar))) {
4532  switch(ar->type) {
4533  case TMPL_ATTR_TYPE_UNSPEC:
4534  break;
4535 
4536  case TMPL_ATTR_TYPE_NORMAL:
4538  {
4539  int i, depth = 0;
4540 
4541  fr_assert(ar->ar_parent); /* All normal and unknown attributes must have parents */
4542 
4543  fr_proto_da_stack_build_partial(&stack, ar->ar_parent, ar->ar_da);
4544 
4545  /*
4546  * First component in the list has everything built
4547  */
4548  if (ar == tmpl_attr_list_head(tmpl_attr(vpt))) {
4549  depth = ar->ar_parent->depth - 1; /* Adjust for array index */
4550  /*
4551  * Everything else skips the first component
4552  */
4553  } else {
4554  depth = ar->ar_parent->depth;
4555  }
4556 
4557  /*
4558  * Root attributes will be skipped by the build
4559  * function, so da[0] contains the attribute
4560  * we're looking for.
4561  */
4562  if (depth < 0) depth = 0;
4563 
4564  /*
4565  * Print from our parent depth to the AR we're processing
4566  *
4567  * For refs we skip the attribute pointed to be the ref
4568  * and just print its children.
4569  *
4570  * In addition skip printing "request." in most cases.
4571  */
4572  if ((stack.da[depth] == request_attr_request) && tmpl_attr_list_next(tmpl_attr(vpt), ar) &&
4573  (ar->filter.type == TMPL_ATTR_FILTER_TYPE_NONE)) continue;
4574 
4575  for (i = depth; (unsigned int)i < ar->ar_da->depth; i++) {
4576  FR_SBUFF_IN_STRCPY_RETURN(&our_out, stack.da[i]->name);
4577 
4578  /*
4579  * Print intermediary separators
4580  * if necessary.
4581  */
4582  if (((unsigned int)i + 1) < ar->ar_da->depth) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
4583  }
4584  }
4585  break;
4586 
4587  /*
4588  * For unresolved attribute we print the raw identifier we
4589  * got when parsing the tmpl.
4590  */
4592  {
4593  unsigned int i, depth;
4594 
4595  /*
4596  * This is the first unresolved component in a potential
4597  * chain of unresolved components. Print the path up to
4598  * the last known parent.
4599  */
4600  if (ar->ar_parent && !ar->ar_parent->flags.is_root) {
4601  fr_proto_da_stack_build_partial(&stack, ar->ar_parent, ar->ar_parent);
4602  if (ar->ar_parent->flags.is_root) {
4603  depth = 0;
4604  } else {
4605  depth = ar->ar_parent->depth - 1;
4606  }
4607 
4608  for (i = depth; i < ar->ar_parent->depth; i++) {
4609  FR_SBUFF_IN_STRCPY_RETURN(&our_out, stack.da[i]->name);
4610  FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
4611  }
4612  }
4613  /*
4614  * Then print the unresolved component
4615  */
4616  FR_SBUFF_IN_BSTRCPY_BUFFER_RETURN(&our_out, ar->ar_unresolved);
4617  break;
4618  }
4619  }
4620 
4621  if (ar_filter_is_none(ar)) {
4622  /* do nothing */
4623 
4624  } else if (ar_filter_is_num(ar)) {
4625  switch (ar->ar_num) {
4626  case NUM_UNSPEC:
4627  break;
4628 
4629  case NUM_ALL:
4630  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "[*]");
4631  break;
4632 
4633  case NUM_COUNT:
4634  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "[#]");
4635  break;
4636 
4637  case NUM_LAST:
4638  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "[n]");
4639  break;
4640 
4641  default:
4642  FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "[%i]", ar->ar_num);
4643  break;
4644  }
4645 
4646  } else if (ar_filter_is_cond(ar)) {
4647  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "[");
4648  (void) xlat_print(&our_out, ar->ar_cond, NULL);
4649  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "]");
4650 
4651  } else {
4652  fr_assert(0);
4653  }
4654 
4655  if (tmpl_attr_list_next(tmpl_attr(vpt), ar)) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
4656  }
4657  FR_SBUFF_SET_RETURN(out, &our_out);
4658 }
4659 
4660 /** Print a #tmpl_t to a string
4661  *
4662  * This function should primarily be used for regenerating vpt->name when the contents
4663  * of the #tmpl_t is changed programmatically, or when the #tmpl_t is being serialized
4664  * in some non-standard way, i.e. as a value for a field in a database.
4665  *
4666  * This function is the direct counterpart to #tmpl_afrom_substr.
4667  *
4668  * @note Does not print flags for regular expressions, as the quoting char is needed
4669  * to separate the elements of the expression.
4670  * Call regex_flags_print to write the flags values to the output buffer.
4671  *
4672  * @param[out] out Where to write the presentation format #tmpl_t string.
4673  * @param[in] vpt to print.
4674  * @param[in] ar_prefix Whether to print the '&' at the beginning of attribute
4675  * references.
4676  * - TMPL_ATTR_REF_PREFIX_YES - always print.
4677  * - TMPL_ATTR_REF_PREFIX_NO - never print.
4678  * - TMPL_ATTR_REF_PREFIX_AUTO - print if the original tmpl
4679  * was prefixed.
4680  * @param[in] e_rules Escaping rules used to print strings.
4681  * @return
4682  * - >0 the number of bytes written to the out buffer.
4683  * - 0 invalid argument.
4684  * - <0 the number of bytes we would have needed to complete the print.
4685  */
4688 {
4689  fr_sbuff_t our_out = FR_SBUFF(out);
4690 
4691  TMPL_VERIFY(vpt);
4692 
4693  switch (vpt->type) {
4695  case TMPL_TYPE_ATTR:
4697  break;
4698 
4699  case TMPL_TYPE_DATA:
4700  FR_SBUFF_RETURN(fr_value_box_print, &our_out, tmpl_value(vpt), e_rules);
4701  break;
4702 
4703  case TMPL_TYPE_REGEX:
4704  FR_SBUFF_IN_BSTRNCPY_RETURN(&our_out, vpt->name, vpt->len); /* Fixme - double escapes */
4705  break;
4706 
4708  FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(&our_out, vpt->data.unescaped, e_rules);
4709  break;
4710 
4712  case TMPL_TYPE_NULL:
4713  case TMPL_TYPE_MAX:
4714  fr_sbuff_terminate(out);
4715  break;
4716 
4717  /*
4718  * The remaining types will either
4719  * be xlat expansions, or need
4720  * resolving, in which case the
4721  * unescaped string is available
4722  * in vpt->unescaped.
4723  */
4724  default:
4725  if (tmpl_contains_xlat(vpt)) {
4726  FR_SBUFF_RETURN(xlat_print, &our_out, tmpl_xlat(vpt), e_rules);
4727  break;
4728  }
4729 
4730  if (tmpl_needs_resolving(vpt)) {
4731  FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(&our_out, vpt->data.unescaped, e_rules);
4732  break;
4733  }
4734 
4735  fr_assert_fail("Can't print invalid tmpl type %s", tmpl_type_to_str(vpt->type));
4736 
4737  /*
4738  * Ensure we do something sane for non-debug builds
4739  */
4740  fr_sbuff_terminate(out);
4741  return 0;
4742  }
4743 
4744  FR_SBUFF_SET_RETURN(out, &our_out);
4745 }
4746 
4747 /** Print a #tmpl_t to a string with quotes
4748  *
4749  * This function should be used when the tmpl is embedded in some other construct
4750  * in the server's configuration.
4751  *
4752  * It adds standard quoting around tmpl's used as operands in expressions and applies
4753  * the correct escaping rules.
4754  *
4755  * @param[out] out Where to write the presentation format #tmpl_t string.
4756  * @param[in] vpt to print.
4757  * @param[in] ar_prefix Whether to print the '&' at the beginning of attribute
4758  * references.
4759  * - TMPL_ATTR_REF_PREFIX_YES - always print.
4760  * - TMPL_ATTR_REF_PREFIX_NO - never print.
4761  * - TMPL_ATTR_REF_PREFIX_AUTO - print if the original tmpl
4762  * was prefixed.
4763  * @return
4764  * - >0 the number of bytes written to the out buffer.
4765  * - 0 invalid argument.
4766  * - <0 the number of bytes we would have needed to complete the print.
4767  */
4769 {
4770  fr_sbuff_t our_out = FR_SBUFF(out);
4771 
4772  char quote = fr_token_quote[vpt->quote];
4773 
4774  if (quote != '\0') FR_SBUFF_IN_CHAR_RETURN(&our_out, quote);
4775  FR_SBUFF_RETURN(tmpl_print, &our_out, vpt,
4777  if (quote != '\0') FR_SBUFF_IN_CHAR_RETURN(&our_out, quote);
4778 
4779  /*
4780  * Optionally print the flags
4781  */
4782  if (vpt->type & TMPL_FLAG_REGEX) FR_SBUFF_RETURN(regex_flags_print, &our_out, tmpl_regex_flags(vpt));
4783 
4784  FR_SBUFF_SET_RETURN(out, &our_out);
4785 }
4786 /** @} */
4787 
4788 
4789 #ifdef WITH_VERIFY_PTR
4790 /** Used to check whether areas of a tmpl_t are zeroed out
4791  *
4792  * @param ptr Offset to begin checking at.
4793  * @param len How many bytes to check.
4794  * @return
4795  * - Pointer to the first non-zero byte.
4796  * - NULL if all bytes were zero.
4797  */
4798 static uint8_t const *is_zeroed(uint8_t const *ptr, size_t len)
4799 {
4800  size_t i;
4801 
4802  for (i = 0; i < len; i++) {
4803  if (ptr[i] != 0x00) return ptr + i;
4804  }
4805 
4806  return NULL;
4807 }
4808 
4809 /** Verify that unused regions of the struct are zeroed out
4810  *
4811  */
4812 #define CHECK_ZEROED(_vpt, _field) is_zeroed(((uint8_t const *)&(_vpt)->data) + sizeof((_vpt)->data._field), sizeof((_vpt)->data) - sizeof((_vpt)->data._field))
4813 
4814 
4815 /** Print hex data
4816  *
4817  */
4818 #define PRINT_NON_ZEROED(_vpt, _field, _nz_ptr) \
4819 do { \
4820  DEBUG("Expected live portion %p-%p (0-%zu)", \
4821  _vpt, \
4822  (uint8_t const *)&(_vpt)->data + sizeof((_vpt)->data._field), \
4823  sizeof((_vpt)->data._field)); \
4824  DEBUG("Expected zero portion %p-%p (%zu-%zu)", \
4825  (uint8_t const *)&(_vpt)->data + sizeof((_vpt)->data._field), \
4826  (uint8_t const *)&(_vpt)->data + sizeof((_vpt)->data), \
4827  sizeof((_vpt)->data._field), sizeof((_vpt)->data)); \
4828  HEX_MARKER1((uint8_t const *)&vpt->data, sizeof(vpt->data), nz - (uint8_t const *)&vpt->data, "non-zero memory", ""); \
4829 } while (0)
4830 
4831 
4832 /** Verify the attribute reference in a tmpl_t make sense
4833  *
4834  * @note If the attribute reference is is invalid, causes the server to exit.
4835  *
4836  * @param file obtained with __FILE__.
4837  * @param line obtained with __LINE__.
4838  * @param vpt to check.
4839  */
4840 void tmpl_attr_verify(char const *file, int line, tmpl_t const *vpt)
4841 {
4842  tmpl_attr_t *ar = NULL;
4843  tmpl_attr_t *slow = NULL, *fast = NULL;
4844  tmpl_attr_t *seen_unknown = NULL;
4845  tmpl_attr_t *seen_unresolved = NULL;
4846 
4848 
4849  /*
4850  * Loop detection
4851  */
4852  while ((slow = tmpl_attr_list_next(tmpl_attr(vpt), slow)) &&
4853  (fast = tmpl_attr_list_next(tmpl_attr(vpt), fast))) {
4854 
4855  /*
4856  * Advances twice as fast as slow...
4857  */
4858  fast = tmpl_attr_list_next(tmpl_attr(vpt), fast);
4859  fr_fatal_assert_msg(fast != slow,
4860  "CONSISTENCY CHECK FAILED %s[%u]: Looping reference list found. "
4861  "Fast pointer hit slow pointer at \"%s\"",
4862  file, line,
4863  slow->type == TMPL_ATTR_TYPE_UNRESOLVED ? slow->ar_unresolved :
4864  slow->da ? slow->da->name : "(null-attr)");
4865  }
4866 
4867  /*
4868  * Lineage type check
4869  *
4870  * Known attribute cannot come after unresolved or unknown attributes
4871  * Unknown attributes cannot come after unresolved attributes
4872  */
4873  if (!tmpl_is_list(vpt)) while ((ar = tmpl_attr_list_next(tmpl_attr(vpt), ar))) {
4874  switch (ar->type) {
4875  case TMPL_ATTR_TYPE_NORMAL:
4876  if (seen_unknown) {
4878  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: "
4879  "TMPL_TYPE_ATTR known attribute \"%s\" "
4880  "occurred after unknown attribute %s "
4881  "in attr ref list",
4882  file, line,
4883  ar->da->name,
4884  ar->unknown.da->name);
4885  }
4886  if (seen_unresolved) {
4888  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: "
4889  "TMPL_TYPE_ATTR known attribute \"%s\" "
4890  "occurred after unresolved attribute \"%s\""
4891  "in attr ref list",
4892  file, line,
4893  ar->da->name,
4894  ar->ar_unresolved);
4895  }
4896  fr_fatal_assert_msg(ar->ar_parent,
4897  "CONSISTENCY CHECK FAILED %s[%u]: attr ref missing parent",
4898  file, line);
4899  break;
4900 
4901  case TMPL_ATTR_TYPE_UNSPEC:
4902  if (seen_unknown) {
4904  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: "
4905  "TMPL_TYPE_ATTR unspecified attribute "
4906  "occurred after unknown attribute %s "
4907  "in attr ref list",
4908  file, line,
4909  ar->unknown.da->name);
4910  }
4911  if (seen_unresolved) {
4913  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: "
4914  "TMPL_TYPE_ATTR unspecified attribute "
4915  "occurred after unresolved attribute \"%s\""
4916  "in attr ref list",
4917  file, line,
4918  ar->ar_unresolved);
4919  }
4920  break;
4921 
4923  seen_unresolved = ar;
4924  fr_fatal_assert_msg(ar->ar_unresolved_namespace,
4925  "CONSISTENCY CHECK FAILED %s[%u]: unresolved attr ref missing namespace",
4926  file, line);
4927  break;
4928 
4930  seen_unknown = ar;
4931  if (seen_unresolved) {
4933  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: "
4934  "TMPL_TYPE_ATTR unknown attribute \"%s\" "
4935  "occurred after unresolved attribute %s "
4936  "in attr ref list",
4937  file, line, ar->da->name,
4938  ar->ar_unresolved);
4939  }
4940  break;
4941  }
4942  }
4943 }
4944 
4945 /** Verify fields of a tmpl_t make sense
4946  *
4947  * @note If the #tmpl_t is invalid, causes the server to exit.
4948  *
4949  * @param file obtained with __FILE__.
4950  * @param line obtained with __LINE__.
4951  * @param vpt to check.
4952  */
4953 void tmpl_verify(char const *file, int line, tmpl_t const *vpt)
4954 {
4955  uint8_t const *nz;
4956 
4957  fr_assert(vpt);
4958 
4959  if (tmpl_is_uninitialised(vpt)) {
4960  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: tmpl_t type was "
4961  "TMPL_TYPE_UNINITIALISED (uninitialised)", file, line);
4962  }
4963 
4964  if (vpt->type >= TMPL_TYPE_MAX) {
4965  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: tmpl_t type was %i "
4966  "(outside range of tmpl_type_table)", file, line, vpt->type);
4967  }
4968 
4969  if (!vpt->name && (vpt->quote != T_INVALID)) {
4970  char quote = vpt->quote >= T_TOKEN_LAST ? '?' : fr_token_quote[vpt->quote];
4971 
4972  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: Quote type '%c' (%i) was set for NULL name",
4973  file, line, quote, vpt->quote);
4974  }
4975 
4976  if (vpt->name && (vpt->quote == T_INVALID)) {
4977  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: No quoting type was set for name \"%.*s\"",
4978  file, line, (int)vpt->len, vpt->name);
4979  }
4980 
4981  /*
4982  * Do a memcmp of the bytes after where the space allocated for
4983  * the union member should have ended and the end of the union.
4984  * These should always be zero if the union has been initialised
4985  * properly.
4986  *
4987  * If they're still all zero, do TMPL_TYPE specific checks.
4988  */
4989  switch (vpt->type) {
4990  case TMPL_TYPE_NULL:
4991  if ((nz = is_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data)))) {
4992  HEX_MARKER1((uint8_t const *)&vpt->data, sizeof(vpt->data),
4993  nz - (uint8_t const *)&vpt->data, "non-zero memory", "");
4994  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_NULL "
4995  "has non-zero bytes in its data union", file, line);
4996  }
4997  break;
4998 
5000  if (!vpt->data.unescaped) {
5001  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA_UNRESOLVED "
5002  "unescaped field is NULL", file, line);
5003  }
5004  break;
5005 
5007  if (!vpt->data.xlat.ex) {
5008  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT "
5009  "has a NULL xlat.ex field", file, line);
5010 
5011  }
5012 
5013  if (!xlat_needs_resolving(vpt->data.xlat.ex)) {
5014  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT_UNRESOLVED "
5015  "does not have 'needs resolving' flag set", file, line);
5016  }
5017  break;
5018 
5019  case TMPL_TYPE_XLAT:
5020  if (!vpt->data.xlat.ex) {
5021  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT "
5022  "has a NULL xlat.ex field", file, line);
5023 
5024  }
5025  break;
5026 
5027 /* @todo When regexes get converted to xlat the flags field of the regex union is used
5028  case TMPL_TYPE_XLAT_UNRESOLVED:
5029  if (is_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
5030  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT_UNRESOLVED "
5031  "has non-zero bytes in its data union", file, line);
5032  }
5033  break;
5034 
5035  case TMPL_TYPE_XLAT:
5036  if (CHECK_ZEROED(vpt, xlat)) {
5037  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT "
5038  "has non-zero bytes after the data.xlat pointer in the union", file, line);
5039  }
5040  break;
5041 */
5042 
5043  case TMPL_TYPE_EXEC:
5045  /* tmpl_xlat(vpt) can be initialized */
5046  break;
5047 
5049  if ((tmpl_attr_list_num_elements(tmpl_attr(vpt)) > 0) &&
5050  ((tmpl_attr_t *)tmpl_attr_list_tail(tmpl_attr(vpt)))->da) {
5051 #ifndef NDEBUG
5053 #endif
5054  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR_UNRESOLVED contains %u "
5055  "references", file, line, tmpl_attr_list_num_elements(tmpl_attr(vpt)));
5056  }
5057  break;
5058 
5059  case TMPL_TYPE_ATTR:
5060  if ((nz = CHECK_ZEROED(vpt, attribute))) {
5061  PRINT_NON_ZEROED(vpt, attribute, nz);
5062  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
5063  "has non-zero bytes after the data.attribute struct in the union",
5064  file, line);
5065  }
5066 
5068  fr_assert(vpt->rules.cast == FR_TYPE_NULL);
5069  break;
5070  }
5071 
5074  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
5075  "da is marked as unknown, but address is not equal to the template's "
5076  "unknown da pointer", file, line);
5077  }
5078  /*
5079  * Raw attributes may not have been added to the dictionary yet
5080  */
5081  } else {
5082  fr_dict_attr_t const *da;
5083  fr_dict_t const *dict;
5084 
5085  /*
5086  * Attribute may be present with multiple names
5087  */
5089  if (!dict) {
5090  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
5091  "attribute \"%s\" (%s) not rooted in a dictionary",
5094  }
5095 
5096  da = tmpl_attr_tail_da(vpt);
5097  if (!tmpl_attr_tail_is_raw(vpt) && (da != tmpl_attr_tail_da(vpt))) {
5098  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
5099  "dictionary pointer %p \"%s\" (%s) "
5100  "and global dictionary pointer %p \"%s\" (%s) differ",
5101  file, line,
5104  da, da->name,
5105  fr_type_to_str(da->type));
5106  }
5107 
5108  tmpl_attr_verify(file, line, vpt);
5109  }
5110  break;
5111 
5112  case TMPL_TYPE_DATA:
5113  if ((nz = CHECK_ZEROED(vpt, literal))) {
5114  PRINT_NON_ZEROED(vpt, literal, nz);
5115  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA "
5116  "has non-zero bytes after the data.literal struct in the union",
5117  file, line);
5118  }
5119 
5121  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA type was "
5122  "FR_TYPE_NULL (uninitialised)", file, line);
5123  }
5124 
5125  if (tmpl_value_type(vpt) >= FR_TYPE_MAX) {
5126  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA type was "
5127  "%i (outside the range of fr_type_ts)", file, line, tmpl_value_type(vpt));
5128  }
5129  /*
5130  * Unlike fr_pair_ts we can't guarantee that fr_pair_t_TMPL buffers will
5131  * be talloced. They may be allocated on the stack or in global variables.
5132  */
5133  switch (tmpl_value_type(vpt)) {
5134  case FR_TYPE_STRING:
5135  if (tmpl_value(vpt)->vb_strvalue[tmpl_value_length(vpt)] != '\0') {
5136  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA char buffer not \\0 "
5137  "terminated", file, line);
5138  }
5139  break;
5140 
5141  case FR_TYPE_STRUCTURAL:
5142  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA is of type TLV",
5143  file, line);
5144 
5145  default:
5146  break;
5147  }
5148 
5149  break;
5150 
5152  case TMPL_TYPE_REGEX_XLAT:
5154 #ifndef HAVE_REGEX
5155  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_XLAT_UNRESOLVED - No regex support",
5156  file, line);
5157 #endif
5158  break;
5159 
5160  case TMPL_TYPE_REGEX:
5161 #ifdef HAVE_REGEX
5162  if (tmpl_regex(vpt) == NULL) {
5163  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
5164  "reg.ex field was NULL", file, line);
5165  }
5166 #else
5167  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX - No regex support",
5168  file, line);
5169 #endif
5170  break;
5171 
5173  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_UNINITIALISED", file, line);
5174 
5175  case TMPL_TYPE_MAX:
5176  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_MAX", file, line);
5177  }
5178 }
5179 #endif
5180 
5181 #define return_P(_x) fr_strerror_const(_x);goto return_p
5182 
5183 /** Preparse a string in preparation for passing it to tmpl_afrom_substr()
5184  *
5185  * Note that the input string is not modified, which means that the
5186  * tmpl_afrom_substr() function MUST un-escape it.
5187  *
5188  * The caller should pass 'out' and 'outlen' to tmpl_afrom_substr()
5189  * as 'in' and 'inlen'. The caller should also pass 'type'.
5190  * The caller should also pass do_unescape=true.
5191  *
5192  * @param[out] out start of the string to parse
5193  * @param[out] outlen length of the string to parse
5194  * @param in where we start looking for the string
5195  * @param inlen length of the input string
5196  * @param[out] type token type of the string.
5197  * @param[out] castda NULL if casting is not allowed, otherwise the cast
5198  * @param require_regex whether or not to require regular expressions
5199  * @param allow_xlat whether or not "bare" xlat's are allowed
5200  * @return
5201  * - > 0, amount of parsed string to skip, to get to the next token
5202  * - <=0, -offset in 'start' where the parse error was located
5203  */
5204 ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t inlen,
5205  fr_token_t *type,
5206  fr_dict_attr_t const **castda, bool require_regex, bool allow_xlat)
5207 {
5208  char const *p = in, *end = in + inlen;
5209  char quote;
5210  char close;
5211  int depth;
5212 
5213  *type = T_INVALID;
5214  if (castda) *castda = NULL;
5215 
5216  while (isspace((uint8_t) *p) && (p < end)) p++;
5217  if (p >= end) return p - in;
5218 
5219  if (*p == '<') {
5220  fr_type_t cast;
5221  char const *q;
5222 
5223  if (!castda) {
5224  fr_strerror_const("Unexpected cast");
5225  return_p:
5226  return -(p - in);
5227  }
5228 
5229  p++;
5230  fr_skip_whitespace(p);
5231 
5232  for (q = p; *q && !isspace((uint8_t) *q) && (*q != '>'); q++) {
5233  /* nothing */
5234  }
5235 
5237  if (fr_type_is_null(cast)) {
5238  return_P("Unknown data type");
5239  }
5240 
5241  /*
5242  * We can only cast to basic data types. Complex ones
5243  * are forbidden.
5244  */
5245  if (fr_type_is_non_leaf(cast)) {
5246  return_P("Forbidden data type in cast");
5247  }
5248 
5249  *castda = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_CAST_BASE + cast);
5250  if (!*castda) {
5251  return_P("Cannot cast to this data type");
5252  }
5253 
5254  p = q;
5255  fr_skip_whitespace(p);
5256  if (*p != '>') {
5257  return_P("Expected '>'");
5258  }
5259  p++;
5260 
5261  fr_skip_whitespace(p);
5262  }
5263 
5264  if (require_regex) {
5265  if (castda && *castda) {
5266  p++;
5267  return_P("Invalid cast before regular expression");
5268  }
5269 
5270  /*
5271  * Allow this which is sometimes clearer.
5272  */
5273  if (*p == 'm') {
5274  p++;
5275  quote = *(p++);
5276  *type = T_OP_REG_EQ;
5277  goto skip_string;
5278  }
5279 
5280  if (*p != '/') {
5281  return_P("Expected regular expression");
5282  }
5283  } /* else treat '/' as any other character */
5284 
5285  switch (*p) {
5286  /*
5287  * Allow bare xlat's
5288  */
5289  case '%':
5290  if (!allow_xlat) {
5291  return_P("Unexpected expansion");
5292  }
5293 
5294  if ((p[1] != '{') && (p[1] != '(')) {
5295  char const *q;
5296 
5297  q = p + 1;
5298 
5299  /*
5300  * New xlat syntax: %foo(...)
5301  */
5302  while ((q < end) && (isalnum((int) *q) || (*q == '.') || (*q == '_') || (*q == '-'))) {
5303  q++;
5304  }
5305 
5306  if (*q != '(') {
5307  p++;
5308  return_P("Invalid character after '%'");
5309  }
5310 
5311  /*
5312  * Return the whole %foo(...) string.
5313  */
5314  *out = p;
5315  if (*type == T_INVALID) *type = T_BARE_WORD;
5316  close = ')';
5317 
5318  p = q + 1;
5319  depth = 1;
5320  goto loop;
5321  }
5322 
5323  /*
5324  * For now, %{...} / %(...) is treated as a double-quoted
5325  * string. Once we clean other things up, the
5326  * xlats will be treated as strongly typed values
5327  * / lists on their own.
5328  */
5329  if (*type == T_INVALID) *type = T_BARE_WORD;
5330  depth = 0;
5331  close = (p[1] == '{') ? '}' : ')';
5332 
5333  /*
5334  * Xlat's are quoted by %{...} / %(...) nesting, not by
5335  * escapes, so we need to do special escaping.
5336  */
5337  *out = p;
5338  loop:
5339  while (*p) {
5340  /*
5341  * End of expansion. Return the entire
5342  * expansion, including the enclosing %{}
5343  * characters.
5344  */
5345  if ((*p == '}') || (*p == ')')) {
5346  bool match = (*p == close);
5347 
5348  p++;
5349  depth--;
5350 
5351  if (depth == 0) {
5352  if (!match) break;
5353 
5354  *outlen = p - (*out);
5355  return p - in;
5356  }
5357  continue;
5358  }
5359 
5360  if (*p == '\\') {
5361  p++;
5362  if (!p[1]) {
5363  return_P("End of string after escape");
5364  }
5365 
5366  p++;
5367  continue;
5368  }
5369 
5370  if ((p[0] == '%') && ((p[1] == '{') || (p[1] == '('))) {
5371  if (!p[2]) {
5372  return_P("End of string after expansion");
5373  }
5374 
5375  p += 2;
5376  depth++;
5377  continue;
5378  }
5379 
5380  /*
5381  * Allow (...) and {...}
5382  */
5383  if ((*p == '{') || (*p == '(')) {
5384  p++;
5385  depth++;
5386  continue;
5387  }
5388 
5389  p++;
5390  }
5391 
5392  /*
5393  * End of input without end of string.
5394  * Point the error to the start of the string.
5395  */
5396  p = *out;
5397  return_P("Unterminated expansion");
5398 
5399  case '/':
5400  if (!require_regex) goto bare_word;
5401 
5402  quote = *(p++);
5403  *type = T_OP_REG_EQ;
5404  goto skip_string;
5405 
5406  case '\'':
5407  quote = *(p++);
5409  goto skip_string;
5410 
5411  case '`':
5412  quote = *(p++);
5414  goto skip_string;
5415 
5416  case '"':
5417  quote = *(p++);
5419 
5420  /*
5421  * We're not trying to do a *correct* parsing of
5422  * every string here. We're trying to do a
5423  * simple parse that isn't wrong. We therefore
5424  * accept most anything that's vaguely well
5425  * formed, and rely on the next stage to do a
5426  * more rigorous check.
5427  */
5428  skip_string:
5429  *out = p;
5430  while (*p) {
5431  /*
5432  * End of string. Tell the caller the
5433  * length of the data inside of the
5434  * string, and return the number of
5435  * characters to skip.
5436  */
5437  if (*p == quote) {
5438  *outlen = p - (*out);
5439  p++;
5440  return p - in;
5441  }
5442 
5443  if (*p == '\\') {
5444  p++;
5445  if (!p[1]) {
5446  return_P("End of string after escape");
5447  }
5448  }
5449  p++;
5450  }
5451 
5452  /*
5453  * End of input without end of string.
5454  * Point the error to the start of the string.
5455  */
5456  p = *out;
5457  return_P("Unterminated string");
5458 
5459  case '&':
5460  *out = p; /* the output string starts with '&' */
5461  p++;
5462  quote = '[';
5463  goto skip_word;
5464 
5465  default:
5466  bare_word:
5467  *out = p;
5468  quote = '\0';
5469 
5470  skip_word:
5471  *type = T_BARE_WORD;
5472  depth = 0;
5473 
5474  /*
5475  * Allow *most* things. But stop on spaces and special characters.
5476  */
5477  while (*p) {
5478  if (isspace((uint8_t) *p)) {
5479  break;
5480  }
5481 
5482  if (*p == '$') {
5483  if (p[1] == '{') {
5484  p += 2;
5485  depth++;
5486  continue;
5487 
5488  } else if ((p[1] == 'E') &&
5489  (p[2] == 'N') &&
5490  (p[3] == 'V') &&
5491  (p[4] == '{')) {
5492  p += 5;
5493  depth++;
5494  continue;
5495 
5496  } else {
5497  /*
5498  * Bare '$' is wrong...
5499  */
5500  break;
5501  }
5502  }
5503 
5504  if (*p == '%') {
5505  if (p[1] == '{') {
5506  p += 2;
5507  depth++;
5508  continue;
5509  }
5510 
5511  p++;
5512  continue;
5513  }
5514 
5515  /*
5516  * If we're inside of a ${...} expansion,
5517  * then allow everything until the
5518  * closing '}'. This means that we can
5519  * do ${foo[bar].baz}, among other
5520  * thingds.
5521  */
5522  if (depth > 0) {
5523  if (*p == '}') {
5524  depth--;
5525  }
5526 
5527  p++;
5528  continue;
5529  }
5530 
5531  /*
5532  * '-' is special. We allow it for
5533  * attribute names, BUT it's a
5534  * terminating token if the NEXT
5535  * character is '='.
5536  *
5537  * We have the same criteria for IPv6
5538  * addresses and tagged attributes. ':'
5539  * is allowed, but ':=' is a breaking
5540  * token.
5541  */
5542  if ((*p == '-') || (*p == ':')) {
5543  if (p[1] == '=') break;
5544  p++;
5545  continue;
5546  }
5547 
5548  /*
5549  * Allowed in attribute names, and/or
5550  * host names and IP addresses, and IPv6 addresses.
5551  */
5552  if ((*p == '.') || (*p == '/') || (*p == '_') || (*p == '*') ||
5553  (*p == ']') || (*p == '@')) {
5554  p++;
5555  continue;
5556  }
5557 
5558  /*
5559  * [...] is an IPv6 address.
5560  */
5561  if ((p == in) && (*p == '[')) {
5562  p++;
5563  continue;
5564  }
5565 
5566  /*
5567  * Allow letters and numbers
5568  */
5569  if (((*p >= 'a') && (*p <= 'z')) ||
5570  ((*p >= 'A') && (*p <= 'Z')) ||
5571  ((*p >= '0') && (*p <= '9'))) {
5572  p++;
5573  continue;
5574  }
5575 
5576  /*
5577  * Allow UTF-8 sequences.
5578  */
5579  if (*(uint8_t const *)p > 0x80) {
5580  p++;
5581  continue;
5582  }
5583 
5584  /*
5585  * If it's an attribute reference, allow
5586  * a few more things inside of a "[...]"
5587  * block.
5588  */
5589  if (*p == quote) {
5590  p++;
5591 
5592  /*
5593  * Allow [#], etc. But stop
5594  * immediately after the ']'.
5595  */
5596  if ((*p == '#') || (*p == '*') || (*p == 'n')) {
5597  p++;
5598 
5599  } else {
5600  /*
5601  * Allow numbers as array indexes
5602  */
5603  while ((*p >= '0') && (*p <= '9')) {
5604  p++;
5605  }
5606 
5607  if (*p != ']') {
5608  return_P("Array index is not an integer");
5609  }
5610  }
5611 
5612  if (*p == ']') {
5613  p++;
5614  continue;
5615  }
5616  }
5617 
5618  /*
5619  * Everything else is a breaking token
5620  */
5621  break;
5622  }
5623 
5624  /*
5625  * Give some slightly better error messages.
5626  */
5627  if (*p == '\\') {
5628  return_P("Unexpected escape");
5629  }
5630 
5631  if ((*p == '"') || (*p == '\'') || (*p == '`')) {
5632  return_P("Unexpected start of string");
5633  }
5634 
5635  if (p == *out) {
5636  return_P("Empty string is invalid");
5637  }
5638 
5639  *outlen = p - (*out);
5640  break;
5641  }
5642 
5643  return p - in;
5644 }
5645 
5646 /** Return whether or not async is required for this tmpl.
5647  *
5648  * If the tmpl is needs_async, then it is async
5649  * If the tmpl is not needs_async, then it will not yield
5650  *
5651  * If the tmpl yields, then async is required.
5652  */
5654 {
5655  switch (vpt->type) {
5656  case TMPL_TYPE_EXEC: /* we don't have "exec no-wait" here */
5657  case TMPL_TYPE_XLAT_UNRESOLVED: /* we have no idea, so be safe */
5658 #ifndef HAVE_REGEX
5660 #endif
5661  return true;
5662 
5663 #ifndef HAVE_REGEX
5664  case TMPL_TYPE_REGEX_XLAT:
5665 #endif
5666  case TMPL_TYPE_XLAT: /* synchronous xlats use unlang_interpret_synchronous() */
5667  default:
5668  return false;
5669  }
5670 }
5671 
5672 /** Initialize a set of rules from a parent set of rules, and a parsed tmpl_t
5673  *
5674  */
5676 {
5677  fr_dict_attr_t const *da;
5678  fr_dict_attr_t const *ref;
5679  fr_dict_t const *dict, *internal;
5680 
5681  *out = *parent;
5682  /* don't set ->parent=parent, that is only for switching subrequest, etc. */
5683 
5684  if (!tmpl_is_attr(vpt)) return;
5685 
5686  da = tmpl_attr_tail_da(vpt);
5687 
5688  /*
5689  * The input tmpl is a leaf. We must parse the child as
5690  * a normal attribute reference (as with the parent tmpl).
5691  */
5692  if (!fr_type_structural[da->type]) {
5693  return;
5694  }
5695 
5696  if (vpt->rules.attr.request_def) {
5697  tmpl_request_ref_list_acopy(ctx, &out->attr.request_def, vpt->rules.attr.request_def);
5698  }
5699  out->attr.list_def = tmpl_list(vpt);
5700 
5701  /*
5702  * Parse the child attributes in the context of the parent struct / tlv / whatever.
5703  */
5704  if (da->type != FR_TYPE_GROUP) {
5705  out->attr.dict_def = fr_dict_by_da(da);
5706  out->attr.namespace = da;
5707  return;
5708  }
5709 
5710  ref = fr_dict_attr_ref(da);
5711  dict = fr_dict_by_da(ref);
5712  internal = fr_dict_internal();
5713 
5714  /*
5715  * Groups MAY change dictionaries. If so, then swap the dictionary and the parent.
5716  */
5717  if ((dict != internal) && (dict != out->attr.dict_def)) {
5718  out->attr.dict_def = dict;
5719  out->attr.namespace = ref;
5720  }
5721 
5722  /*
5723  * Otherwise the reference is swapping FROM a protocol
5724  * dictionary TO the internal dictionary, and TO an
5725  * internal group. We fall back to leaving well enough
5726  * alone, and leave things as-is. This allows internal
5727  * grouping attributes to appear anywhere.
5728  */
5729 }
5730 
5731 static void tmpl_attr_rules_debug(tmpl_attr_rules_t const *at_rules)
5732 {
5733  FR_FAULT_LOG("\tdict_def = %s", at_rules->dict_def ? fr_dict_root(at_rules->dict_def)->name : "");
5734  FR_FAULT_LOG("\tnamespace = %s", at_rules->namespace ? at_rules->namespace->name : "");
5735 
5736  FR_FAULT_LOG("\tlist_def = %s", at_rules->list_def ? at_rules->list_def->name : "");
5737 
5738  FR_FAULT_LOG("\tallow_unknown = %u", at_rules->allow_unknown);
5739  FR_FAULT_LOG("\tallow_unresolved = %u", at_rules->allow_unresolved);
5740  FR_FAULT_LOG("\tallow_wildcard = %u", at_rules->allow_wildcard);
5741  FR_FAULT_LOG("\tallow_foreign = %u", at_rules->allow_foreign);
5742  FR_FAULT_LOG("\tdisallow_filters = %u", at_rules->disallow_filters);
5743 }
5744 
5745 
5746 void tmpl_rules_debug(tmpl_rules_t const *rules)
5747 {
5748  FR_FAULT_LOG("\tparent = %p", rules->parent);
5749  FR_FAULT_LOG(" attr {");
5750  tmpl_attr_rules_debug(&rules->attr);
5751  FR_FAULT_LOG(" }");
5752  FR_FAULT_LOG("\tenumv = %s", rules->enumv ? rules->enumv->name : "");
5753  FR_FAULT_LOG("\tcast = %s", fr_type_to_str(rules->cast));
5754  FR_FAULT_LOG("\tat_runtime = %u", rules->at_runtime);
5755 }
static int const char char buffer[256]
Definition: acutest.h:574
int const char * file
Definition: acutest.h:702
va_end(args)
static int const char * fmt
Definition: acutest.h:573
int const char int line
Definition: acutest.h:702
va_start(args, fmt)
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition: base16.h:95
static fr_dict_t * dict
Definition: fuzzer.c:46
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define STRINGIFY(x)
Definition: build.h:195
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition: build.h:119
#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 unlikely(_x)
Definition: build.h:378
#define NUM_ELEMENTS(_t)
Definition: build.h:335
static char const * skip_word(char const *text)
Definition: command.c:1872
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition: dbuff.h:354
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:189
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#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_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition: debug.h:214
#define FR_FAULT_LOG(_fmt,...)
Definition: debug.h:49
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:182
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
Definition: dict_unknown.c:148
fr_slen_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *name, fr_sbuff_term_t const *tt))
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
Definition: dict_util.c:4191
static fr_slen_t err
Definition: dict.h:645
static fr_dict_attr_t * fr_dict_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Definition: dict.h:428
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 const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters that are allowed in dictionary attribute names.
Definition: dict_util.c:45
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition: dict_util.c:1631
fr_dict_attr_t const * fr_dict_unknown_add(fr_dict_t *dict, fr_dict_attr_t const *old)
Converts an unknown to a known by adding it to the internal dictionaries.
Definition: dict_unknown.c:38
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
int fr_dict_attr_unknown_parent_to_known(fr_dict_attr_t *da, fr_dict_attr_t const *parent)
Fixup the parent of an unknown attribute using an equivalent known attribute.
Definition: dict_unknown.c:536
fr_value_box_t const * value
Enum value (what name maps to).
Definition: dict.h:213
fr_dict_t const * fr_dict_by_da(fr_dict_attr_t const *da)
Attempt to locate the protocol dictionary containing an attribute.
Definition: dict_util.c:2203
fr_slen_t fr_dict_attr_search_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *name, fr_sbuff_term_t const *tt, bool internal, bool foreign))
Locate a qualified fr_dict_attr_t by its name and a dictionary qualifier.
Definition: dict_util.c:2572
fr_dict_attr_t * fr_dict_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor))
Build an unknown vendor, parented by a VSA attribute.
Definition: dict_unknown.c:272
fr_dict_attr_t * fr_dict_unknown_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Copy a known or unknown attribute to produce an unknown attribute with the specified name.
Definition: dict_unknown.c:226
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
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition: dict_util.c:4179
fr_slen_t fr_dict_attr_search_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *name, fr_sbuff_term_t const *tt, bool internal, bool foreign))
Locate a fr_dict_attr_t by its name in the top level namespace of a dictionary.
Definition: dict_util.c:2601
static fr_slen_t fr_dict_enum_name_afrom_substr(TALLOC_CTX *ctx, char **out, fr_sbuff_parse_error_t *err, fr_sbuff_t *in, fr_sbuff_term_t const *tt) 1(fr_dict_enum_name_from_substr
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition: dict.h:384
fr_dict_attr_err_t
Errors returned by attribute lookup functions.
Definition: dict.h:272
@ FR_DICT_ATTR_OK
No error.
Definition: dict.h:273
@ FR_DICT_ATTR_NOT_DESCENDENT
Attribute is not a descendent of the parent attribute.
Definition: dict.h:279
@ FR_DICT_ATTR_NO_CHILDREN
Child lookup in attribute with no children.
Definition: dict.h:283
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:2925
#define fr_dict_attr_is_key_field(_da)
Definition: dict.h:149
static fr_slen_t in
Definition: dict.h:645
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:345
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition: dict.h:364
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
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition: dict_ext.h:164
#define FR_IPADDR_STRLEN
Like INET6_ADDRSTRLEN but includes space for the textual Zone ID.
Definition: inet.h:89
#define HEX_MARKER1(_data, _len, _slen, _error, _fmt,...)
Definition: log.h:741
talloc_free(reap)
static char * stack[MAX_STACK]
Definition: radmin.c:158
typedef FR_DLIST_HEAD(map_list) map_list_t
Given these are used in so many places, it's more friendly to have a proper type.
tmpl_attr_prefix_t
Definition: merged_model.c:228
@ TMPL_ATTR_REF_PREFIX_NO
Attribute refs have no '&' prefix.
Definition: merged_model.c:230
@ TMPL_ATTR_REF_PREFIX_AUTO
Attribute refs may have a '&' prefix.
Definition: merged_model.c:231
@ TMPL_ATTR_REF_PREFIX_YES
Attribute refs must have '&' prefix.
Definition: merged_model.c:229
unsigned short uint16_t
Definition: merged_model.c:31
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_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_INT8
8 Bit signed integer.
Definition: merged_model.c:103
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
Definition: merged_model.c:93
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
Definition: merged_model.c:89
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_MAX
Number of defined data types.
Definition: merged_model.c:130
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
@ FR_TYPE_UINT16
16 Bit unsigned integer.
Definition: merged_model.c:98
@ FR_TYPE_INT64
64 Bit signed integer.
Definition: merged_model.c:106
@ FR_TYPE_INT16
16 Bit signed integer.
Definition: merged_model.c:104
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
Definition: merged_model.c:119
@ FR_TYPE_INT32
32 Bit signed integer.
Definition: merged_model.c:105
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
Definition: merged_model.c:122
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
Definition: merged_model.c:87
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
@ FR_TYPE_FLOAT64
Double precision floating point.
Definition: merged_model.c:109
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
ssize_t fr_slen_t
Definition: merged_model.c:35
unsigned long int size_t
Definition: merged_model.c:25
#define UINT8_MAX
Definition: merged_model.c:32
fr_sbuff_parse_error_t
Definition: merged_model.c:45
@ FR_SBUFF_PARSE_ERROR_NOT_FOUND
String does not contain a token matching the output type.
Definition: merged_model.c:47
@ FR_SBUFF_PARSE_ERROR_FORMAT
Format of data was invalid.
Definition: merged_model.c:50
@ FR_SBUFF_PARSE_OK
No error.
Definition: merged_model.c:46
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition: misc.h:59
char * fr_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
Definition: print.c:853
void fr_proto_da_stack_build_partial(fr_da_stack_t *stack, fr_dict_attr_t const *parent, fr_dict_attr_t const *da)
Complete the DA stack for a child attribute.
Definition: proto.c:159
static bool done
Definition: radclient.c:80
static uint32_t mask
Definition: rbmonkey.c:39
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
fr_dict_attr_t const * request_attr_control
Definition: request.c:43
fr_dict_attr_t const * request_attr_local
Definition: request.c:45
fr_dict_attr_t const * request_attr_state
Definition: request.c:44
fr_dict_attr_t const * request_attr_reply
Definition: request.c:42
static char const * name
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static UINT8_MAX+1], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
Definition: sbuff.c:1736
bool const sbuff_char_class_hex[UINT8_MAX+1]
Definition: sbuff.c:86
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition: sbuff.c:2111
size_t fr_sbuff_adv_past_strcase(fr_sbuff_t *sbuff, char const *needle, size_t needle_len)
Return true and advance past the end of the needle if needle occurs next in the sbuff.
Definition: sbuff.c:1702
size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr)
Wind position until we hit a character in the terminal set.
Definition: sbuff.c:1811
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition: sbuff.c:2047
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_out_by_longest_prefix(_match_len, _out, _table, _sbuff, _def)
#define FR_SBUFF_IN_TABLE_STR_RETURN(_sbuff, _table, _number, _def)
#define fr_sbuff_is_str_literal(_sbuff, _str)
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
#define fr_sbuff_adv_past_strcase_literal(_sbuff, _needle)
#define fr_sbuff_current(_sbuff_or_marker)
#define FR_SBUFF_REPARSE(_sbuff_or_marker)
#define FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(...)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition: sbuff.h:167
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#define fr_sbuff_extend(_sbuff_or_marker)
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_IN_SPRINTF_RETURN(...)
#define FR_SBUFF(_sbuff_or_marker)
#define FR_SBUFF_IN_BSTRNCPY_RETURN(...)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_out(_err, _out, _in)
#define fr_sbuff_switch(_sbuff_or_marker, _eob)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_IN_STRCPY_RETURN(...)
#define FR_SBUFF_IN_BSTRCPY_BUFFER_RETURN(...)
Set of terminal elements.
Definition: merged_model.c:161
static fr_slen_t ar_prefix
Definition: tmpl.h:1267
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_contains_xlat(vpt)
Definition: tmpl.h:231
#define TMPL_VERIFY(_vpt)
Definition: tmpl.h:953
#define tmpl_value_length(_tmpl)
Definition: tmpl.h:933
#define tmpl_is_uninitialised(vpt)
Helpers to verify the type of tmpl_t.
Definition: tmpl.h:208
#define tmpl_is_attr_unresolved(vpt)
Definition: tmpl.h:224
enum requests_ref_e tmpl_request_ref_t
static bool tmpl_attr_tail_is_unspecified(tmpl_t const *vpt)
Return true if the last attribute reference is "unspecified".
Definition: tmpl.h:721
#define NUM_LAST
Definition: tmpl.h:402
#define tmpl_rules_enumv(_tmpl)
Definition: tmpl.h:938
static fr_slen_t vpt
Definition: tmpl.h:1260
static bool tmpl_attr_tail_is_normal(tmpl_t const *vpt)
Return true if the last attribute reference is "normal".
Definition: tmpl.h:705
#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
#define ar_is_unknown(_ar)
Definition: tmpl.h:504
static bool tmpl_attr_tail_is_unknown(tmpl_t const *vpt)
Return true if the last attribute reference is "unknown".
Definition: tmpl.h:737
#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 ar_is_raw(_ar)
Definition: tmpl.h:506
#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_value_enumv(_tmpl)
Definition: tmpl.h:935
#define tmpl_xlat(_tmpl)
Definition: tmpl.h:925
static fr_dict_attr_t const * tmpl_attr_tail_unknown(tmpl_t const *vpt)
Return the last attribute reference unknown da.
Definition: tmpl.h:848
static bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar)
Return true if the tmpl_attr is one of the list types.
Definition: tmpl.h:674
#define ar_filter_is_num(_ar)
Definition: tmpl.h:513
#define tmpl_rules_cast(_tmpl)
Definition: tmpl.h:937
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
Definition: tmpl.h:162
@ TMPL_TYPE_MAX
Marker for the last tmpl type.
Definition: tmpl.h:203
@ 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_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
Definition: tmpl.h:201
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition: tmpl.h:142
@ TMPL_TYPE_REGEX
Compiled (and possibly JIT'd) regular expression.
Definition: tmpl.h:158
@ 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_REGEX_XLAT
A regex containing xlat expansions.
Definition: tmpl.h:166
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
Definition: tmpl.h:193
@ TMPL_TYPE_UNINITIALISED
Uninitialised.
Definition: tmpl.h:134
#define tmpl_is_regex_xlat(vpt)
Definition: tmpl.h:220
#define NUM_COUNT
Definition: tmpl.h:401
#define tmpl_assert_type(_cond)
Convenience macro for printing a meaningful assert message when we get a bad tmpl type.
Definition: tmpl.h:615
#define tmpl_contains_attr(vpt)
Definition: tmpl.h:229
#define ar_da
Definition: tmpl.h:496
#define TMPL_FLAG_REGEX
Is a type of regular expression.
Definition: tmpl.h:116
#define ar_filter_is_cond(_ar)
Definition: tmpl.h:514
tmpl_xlat_rules_t xlat
Rules/data for parsing xlats.
Definition: tmpl.h:345
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
#define TMPL_ATTR_VERIFY(_vpt)
Definition: tmpl.h:952
bool force_dict_def
Use supplied dict_def even if original vpt->rules->dict_def was not NULL.
Definition: tmpl.h:379
#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 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
#define tmpl_value_type(_tmpl)
Definition: tmpl.h:934
#define tmpl_attr(_tmpl)
Definition: tmpl.h:649
tmpl_attr_error_t
Definition: tmpl.h:996
@ TMPL_ATTR_ERROR_INVALID_ARRAY_INDEX
Invalid array index.
Definition: tmpl.h:1015
@ TMPL_ATTR_ERROR_LIST_NOT_ALLOWED
List qualifier is not allowed here.
Definition: tmpl.h:1000
@ TMPL_ATTR_ERROR_UNRESOLVED_NOT_ALLOWED
Attribute couldn't be found in the dictionaries.
Definition: tmpl.h:1006
@ TMPL_ATTR_ERROR_BAD_CAST
Specified cast was invalid.
Definition: tmpl.h:1019
@ TMPL_ATTR_ERROR_INVALID_NAME
Attribute ref length is zero, or longer than the maximum.
Definition: tmpl.h:1008
@ TMPL_ATTR_ERROR_MISSING_TERMINATOR
Unexpected text found after attribute reference.
Definition: tmpl.h:1018
@ TMPL_ATTR_ERROR_LIST_MISSING
List qualifier is required, but missing.
Definition: tmpl.h:1001
@ TMPL_ATTR_ERROR_NONE
No error.
Definition: tmpl.h:997
@ TMPL_ATTR_ERROR_FOREIGN_NOT_ALLOWED
Attribute resolved in a dictionary different to the one specified.
Definition: tmpl.h:1012
@ TMPL_ATTR_ERROR_UNKNOWN_NOT_ALLOWED
Attribute specified as OID, could not be found in the dictionaries, and is disallowed because 'disall...
Definition: tmpl.h:1002
@ TMPL_ATTR_ERROR_FILTER_NOT_ALLOWED
Filters disallowed by rules.
Definition: tmpl.h:1014
@ TMPL_ATTR_ERROR_EMPTY
Attribute ref contains no data.
Definition: tmpl.h:998
@ TMPL_ATTR_ERROR_NESTING_TOO_DEEP
Too many levels of nesting.
Definition: tmpl.h:1017
@ TMPL_ATTR_ERROR_BAD_PREFIX
Missing '&' or has '&' when it shouldn't.
Definition: tmpl.h:999
#define tmpl_is_data_unresolved(vpt)
Definition: tmpl.h:222
fr_type_t cast
Whether there was an explicit cast.
Definition: tmpl.h:349
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition: tmpl.h:344
static char const * tmpl_attr_tail_unresolved(tmpl_t const *vpt)
Return the last attribute reference unresolved da.
Definition: tmpl.h:864
@ TMPL_ATTR_LIST_REQUIRE
Attribute refs are required to have a list.
Definition: tmpl.h:276
@ TMPL_ATTR_LIST_ALLOW
Attribute refs are allowed to have a list.
Definition: tmpl.h:274
@ TMPL_ATTR_LIST_FORBID
Attribute refs are forbidden from having a list.
Definition: tmpl.h:275
enum tmpl_type_e tmpl_type_t
Types of tmpl_t.
#define tmpl_is_regex(vpt)
Definition: tmpl.h:218
static bool tmpl_attr_tail_is_raw(tmpl_t const *vpt)
Return true if the last attribute reference is "raw".
Definition: tmpl.h:769
@ REQUEST_OUTER
request_t containing the outer layer of the EAP conversation.
Definition: tmpl.h:92
@ REQUEST_PARENT
Parent (whatever it is).
Definition: tmpl.h:96
@ REQUEST_UNKNOWN
Unknown request.
Definition: tmpl.h:97
@ REQUEST_CURRENT
The current request (default).
Definition: tmpl.h:91
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
#define tmpl_is_regex_uncompiled(vpt)
Definition: tmpl.h:219
fr_dict_attr_t const * enumv
for resolving T_BARE_WORD
Definition: tmpl.h:382
#define TMPL_MAX_REQUEST_REF_NESTING
The maximum number of request references allowed.
Definition: tmpl.h:85
tmpl_attr_type_t
Definition: tmpl.h:385
@ TMPL_ATTR_TYPE_UNSPEC
No attribute was specified as this level only a filter.
Definition: tmpl.h:387
@ TMPL_ATTR_TYPE_NORMAL
Normal, resolved, attribute ref.
Definition: tmpl.h:386
@ TMPL_ATTR_TYPE_UNKNOWN
We have an attribute number but it doesn't match anything in the dictionary, or isn't a child of the ...
Definition: tmpl.h:389
@ TMPL_ATTR_TYPE_UNRESOLVED
We have a name, but nothing else to identify the attribute.
Definition: tmpl.h:394
@ TMPL_ATTR_FILTER_TYPE_INDEX
Filter is an index type.
Definition: tmpl.h:414
@ TMPL_ATTR_FILTER_TYPE_CONDITION
Filter is a condition.
Definition: tmpl.h:415
@ TMPL_ATTR_FILTER_TYPE_NONE
No filter present.
Definition: tmpl.h:413
fr_event_list_t * runtime_el
The eventlist to use for runtime instantiation of xlats.
Definition: tmpl.h:333
#define tmpl_needs_resolving(vpt)
Definition: tmpl.h:228
tmpl_attr_filter_type_t _CONST type
Type of filter this is.
Definition: tmpl.h:419
#define ar_filter_is_none(_ar)
Definition: tmpl.h:512
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
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
static char const hex[]
Definition: smbencrypt.c:35
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)
fr_aka_sim_id_type_t type
Define entry and head types for tmpl request references.
Definition: tmpl.h:284
tmpl_attr_list_presence_t list_presence
Whether the attribute reference can have a list, forbid it, or require it.
Definition: tmpl.h:313
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
Definition: tmpl.h:307
uint8_t disallow_filters
disallow filters.
Definition: tmpl.h:329
uint8_t allow_unresolved
Allow attributes that look valid but were not found in the dictionaries.
Definition: tmpl.h:319
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_attr_prefix_t prefix
Whether the attribute reference requires a prefix.
Definition: tmpl.h:310
An element in a list of nested attribute references.
Definition: tmpl.h:427
unsigned int _CONST resolve_only
This reference and those before it.
Definition: tmpl.h:450
unsigned int _CONST is_raw
Definition: tmpl.h:453
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
Definition: tmpl.h:431
fr_dict_attr_t const *_CONST parent
The parent we used when trying to resolve the attribute originally.
Definition: tmpl.h:445
tmpl_attr_filter_t _CONST filter
Filter associated with the attribute reference.
Definition: tmpl.h:457
tmpl_attr_type_t _CONST type
is a raw reference
Definition: tmpl.h:455
Define manipulation functions for the attribute reference list.
Definition: tmpl.h:468
tmpl_request_ref_t _CONST request
Definition: tmpl.h:472
#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 an arbitrarily ordered array of name to num mappings.
Definition: table.h:53
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
char * talloc_bstrdup(TALLOC_CTX *ctx, char const *in)
Binary safe strdup function.
Definition: talloc.c:424
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_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition: talloc.c:452
#define talloc_get_type_abort_const
Definition: talloc.h:270
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition: talloc.h:212
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition: talloc.h:168
fr_slen_t fr_time_delta_from_substr(fr_time_delta_t *out, fr_sbuff_t *in, fr_time_res_t hint, bool no_trailing, fr_sbuff_term_t const *tt)
Create fr_time_delta_t from a string.
Definition: time.c:214
@ FR_TIME_RES_SEC
Definition: time.h:50
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
Escaping rules for tmpls.
Definition: tmpl_escape.h:80
int8_t tmpl_request_ref_list_cmp(FR_DLIST_HEAD(tmpl_request_list) const *a, FR_DLIST_HEAD(tmpl_request_list) const *b)
Compare a list of request qualifiers.
static ssize_t tmpl_afrom_time_delta(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
void tmpl_request_ref_list_debug(FR_DLIST_HEAD(tmpl_request_list) const *rql)
Dump a request list to stderr.
fr_slen_t tmpl_request_ref_list_print(fr_sbuff_t *out, FR_DLIST_HEAD(tmpl_request_list) const *rql)
void tmpl_attr_set_list(tmpl_t *vpt, fr_dict_attr_t const *list)
fr_slen_t tmpl_request_ref_list_afrom_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, FR_DLIST_HEAD(tmpl_request_list) **out, fr_sbuff_t *in)
Parse one or more request references, allocing a new list and adding the references to it.
static fr_table_num_sorted_t const attr_num_table[]
Special attribute reference indexes.
void tmpl_unresolve(tmpl_t *vpt)
Reset the tmpl, leaving only the name in place.
void tmpl_set_xlat(tmpl_t *vpt, xlat_exp_head_t *xlat)
Change the default dictionary in the tmpl's resolution rules.
void tmpl_attr_rewrite_num(tmpl_t *vpt, int16_t from, int16_t to)
Rewrite all instances of an array number.
static void tmpl_type_init(tmpl_t *vpt, tmpl_type_t type)
Initialise fields inside a tmpl depending on its type.
#define RESOLVED_SET(_flags)
static fr_slen_t tmpl_attr_ref_afrom_unresolved_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t *vpt, fr_dict_attr_t const *parent, fr_dict_attr_t const *namespace, fr_sbuff_t *name, tmpl_attr_rules_t const *at_rules)
Parse an unresolved attribute, i.e.
void tmpl_attr_set_request_ref(tmpl_t *vpt, FR_DLIST_HEAD(tmpl_request_list) const *request_def)
Set the request for an attribute ref.
void tmpl_set_name_printf(tmpl_t *vpt, fr_token_t quote, char const *fmt,...)
Set the name on a pre-initialised tmpl.
int tmpl_attr_set_da(tmpl_t *vpt, fr_dict_attr_t const *da)
Replace the current attribute reference.
static fr_table_num_ordered_t const attr_table[]
Attr ref types.
static int tmpl_xlat_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
Resolve an unresolved xlat, i.e.
fr_table_num_sorted_t const tmpl_request_ref_table[]
Map keywords to tmpl_request_ref_t values.
fr_slen_t tmpl_print(fr_sbuff_t *out, tmpl_t const *vpt, tmpl_attr_prefix_t ar_prefix, fr_sbuff_escape_rules_t const *e_rules)
Print a tmpl_t to a string.
int tmpl_afrom_value_box(TALLOC_CTX *ctx, tmpl_t **out, fr_value_box_t *data, bool steal)
Create a tmpl_t from a fr_value_box_t.
int tmpl_attr_unknown_add(tmpl_t *vpt)
Add an unknown fr_dict_attr_t specified by a tmpl_t to the main dictionary.
void tmpl_set_escape(tmpl_t *vpt, tmpl_escape_t const *escape)
Set escape parameters for the tmpl output.
bool tmpl_async_required(tmpl_t const *vpt)
Return whether or not async is required for this tmpl.
static tmpl_t * tmpl_alloc_null(TALLOC_CTX *ctx)
Create a new heap allocated tmpl_t.
void tmpl_rules_child_init(TALLOC_CTX *ctx, tmpl_rules_t *out, tmpl_rules_t const *parent, tmpl_t *vpt)
Initialize a set of rules from a parent set of rules, and a parsed tmpl_t.
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.
static fr_slen_t tmpl_attr_ref_from_unspecified_substr(tmpl_attr_t *ar, tmpl_attr_error_t *err, tmpl_t *vpt, fr_sbuff_t *name, tmpl_attr_rules_t const *at_rules)
static void attr_to_raw(tmpl_t *vpt, tmpl_attr_t *ref)
static void tmpl_attr_insert(tmpl_t *vpt, tmpl_attr_t *ar)
Insert an attribute reference into a tmpl.
int tmpl_cast_set(tmpl_t *vpt, fr_type_t dst_type)
Set a cast for a tmpl.
static fr_slen_t tmpl_afrom_ipv4_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
Parse bareword as an IPv4 address or prefix.
void tmpl_set_name(tmpl_t *vpt, fr_token_t quote, char const *name, ssize_t len)
Set the name on a pre-initialised tmpl.
int tmpl_attr_afrom_list(TALLOC_CTX *ctx, tmpl_t **out, tmpl_t const *list, fr_dict_attr_t const *da)
Create a new tmpl from a list tmpl and a da.
void tmpl_attr_to_raw(tmpl_t *vpt)
Convert the leaf attribute of a tmpl to a unknown/raw type.
ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t inlen, fr_token_t *type, fr_dict_attr_t const **castda, bool require_regex, bool allow_xlat)
Preparse a string in preparation for passing it to tmpl_afrom_substr()
tmpl_t * tmpl_copy(TALLOC_CTX *ctx, tmpl_t const *in)
Copy a tmpl.
void tmpl_attr_ref_debug(const tmpl_attr_t *ar, int i)
static bool tmpl_substr_terminal_check(fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
Verify, after skipping whitespace, that a substring ends in a terminal char, or ends without further ...
static void tmpl_request_ref_list_copy(TALLOC_CTX *ctx, FR_DLIST_HEAD(tmpl_request_list) *out, FR_DLIST_HEAD(tmpl_request_list) const *in)
Allocate a new request reference and add it to the end of the attribute reference list.
static void tmpl_attr_rules_debug(tmpl_attr_rules_t const *at_rules)
tmpl_t * tmpl_init_shallow(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len, tmpl_rules_t const *t_rules)
Initialise a tmpl without copying the input name string.
#define TMPL_REQUEST_REF_DEF(_name, _ref)
Define a global variable for specifying a default request reference.
Definition: tmpl_tokenize.c:53
#define UNRESOLVED_SET(_flags)
void tmpl_debug(tmpl_t const *vpt)
void tmpl_set_name_shallow(tmpl_t *vpt, fr_token_t quote, char const *name, ssize_t len)
Set the name on a pre-initialised tmpl.
fr_slen_t tmpl_attr_print(fr_sbuff_t *out, tmpl_t const *vpt, tmpl_attr_prefix_t ar_prefix)
Print an attribute or list tmpl_t to a string.
static tmpl_attr_t * tmpl_attr_add(tmpl_t *vpt, tmpl_attr_type_t type)
Allocate a new attribute reference and add it to the end of the attribute reference list.
static int tmpl_attr_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t *vpt, fr_dict_attr_t const *parent, fr_dict_attr_t const *namespace, fr_sbuff_t *name, fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *at_rules, unsigned int depth)
Parse an attribute reference, either an OID or attribute name.
static fr_slen_t tmpl_afrom_ipv6_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
Parse bareword as an IPv6 address or prefix.
static fr_slen_t tmpl_afrom_bool_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
Parse a truth value.
static size_t attr_num_table_len
#define return_P(_x)
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, char const *name, tmpl_rules_t const *t_rules)
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
fr_slen_t tmpl_print_quoted(fr_sbuff_t *out, tmpl_t const *vpt, tmpl_attr_prefix_t ar_prefix)
Print a tmpl_t to a string with quotes.
void tmpl_attr_ref_list_debug(FR_DLIST_HEAD(tmpl_attr_list) const *ar_head)
ssize_t tmpl_cast_from_substr(tmpl_rules_t *rules, fr_sbuff_t *in)
Parse a cast specifier.
void tmpl_attr_rewrite_leaf_num(tmpl_t *vpt, int16_t from, int16_t to)
Rewrite the leaf's instance number.
static fr_slen_t tmpl_request_ref_list_from_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, FR_DLIST_HEAD(tmpl_request_list) *out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_dict_attr_t const **namespace)
Parse one or more request references, writing the list to out.
void tmpl_rules_debug(tmpl_rules_t const *rules)
int tmpl_attr_copy(tmpl_t *dst, tmpl_t const *src)
Copy a list of attribute and request references from one tmpl to another.
static ssize_t tmpl_afrom_ether_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
Try and parse signed or unsigned integers.
static ssize_t tmpl_afrom_float_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
static fr_slen_t tmpl_afrom_octets_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
Parse bareword as an octet string.
size_t tmpl_type_table_len
static int tmpl_attr_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
Resolve an unresolved attribute.
static ssize_t tmpl_afrom_enum(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
int tmpl_attr_set_leaf_da(tmpl_t *vpt, fr_dict_attr_t const *da)
Replace the leaf attribute only.
tmpl_t * tmpl_init_printf(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *fmt,...)
Initialise a tmpl using a format string to create the name.
fr_slen_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.
static fr_token_t tmpl_cast_quote(fr_token_t existing_quote, fr_type_t type, fr_dict_attr_t const *enumv, char const *unescaped, size_t unescaped_len)
Determine the correct quoting after a cast.
fr_dict_attr_t const * tmpl_attr_unspec
Placeholder attribute for uses of unspecified attribute references.
Definition: tmpl_eval.c:59
static fr_slen_t tmpl_afrom_value_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, tmpl_rules_t const *t_rules, bool allow_enum, fr_sbuff_parse_rules_t const *p_rules)
Create TMPL_TYPE_DATA from a string.
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
Attempt to resolve functions and attributes in xlats and attribute references.
void tmpl_set_dict_def(tmpl_t *vpt, fr_dict_t const *dict)
Change the default dictionary in the tmpl's resolution rules.
static void tmpl_request_ref_list_acopy(TALLOC_CTX *ctx, FR_DLIST_HEAD(tmpl_request_list) **out, FR_DLIST_HEAD(tmpl_request_list) const *in)
Allocate a new request reference list and copy request references into it.
static fr_slen_t tmpl_afrom_integer_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules)
Try and parse signed or unsigned integers.
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...
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.
static void tmpl_attr_ref_fixup(TALLOC_CTX *ctx, tmpl_t *vpt, fr_dict_attr_t const *da, fr_dict_attr_t const *parent)
static fr_slen_t tmpl_attr_parse_filter(tmpl_attr_error_t *err, tmpl_attr_t *ar, fr_sbuff_t *name, tmpl_attr_rules_t const *at_rules)
Parse array subscript and in future other filters.
int tmpl_attr_to_xlat(TALLOC_CTX *ctx, tmpl_t **vpt_p)
Convert an attribute reference to an xlat expansion.
fr_slen_t tmpl_attr_list_from_substr(fr_dict_attr_t const **da_p, fr_sbuff_t *in)
Parse one a single list reference.
#define DEFAULT_RULES
Default parser rules.
Definition: tmpl_tokenize.c:99
fr_table_num_ordered_t const tmpl_type_table[]
Map tmpl_type_t values to descriptive strings.
tmpl_t * tmpl_init(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len, tmpl_rules_t const *t_rules)
Initialise a tmpl using a literal string to create the name.
void tmpl_attr_debug(tmpl_t const *vpt)
void tmpl_attr_set_leaf_num(tmpl_t *vpt, int16_t num)
static size_t attr_table_len
int tmpl_attr_tail_unresolved_add(fr_dict_t *dict_def, tmpl_t *vpt, fr_type_t type, fr_dict_attr_flags_t const *flags)
Add an unresolved fr_dict_attr_t specified by a tmpl_t to the main dictionary.
size_t tmpl_request_ref_table_len
fr_table_num_sorted_t const fr_token_quotes_table[]
Definition: token.c:66
const char fr_token_quote[T_TOKEN_LAST]
Convert tokens back to a quoting character.
Definition: token.c:156
enum fr_token fr_token_t
@ T_INVALID
Definition: token.h:39
@ T_SINGLE_QUOTED_STRING
Definition: token.h:122
@ T_BARE_WORD
Definition: token.h:120
@ T_BACK_QUOTED_STRING
Definition: token.h:123
@ T_OP_REG_EQ
Definition: token.h:102
@ T_DOUBLE_QUOTED_STRING
Definition: token.h:121
@ T_SOLIDUS_QUOTED_STRING
Definition: token.h:124
#define T_TOKEN_LAST
Definition: token.h:129
close(uq->fd)
bool xlat_needs_resolving(xlat_exp_head_t const *head)
Check to see if the expansion needs resolving.
bool xlat_is_literal(xlat_exp_head_t const *head)
Check to see if the expansion consists entirely of value-box elements.
int xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **head, tmpl_t **vpt_p)
Convert attr tmpl to an xlat for &attr[*].
fr_slen_t xlat_print(fr_sbuff_t *in, xlat_exp_head_t const *node, fr_sbuff_escape_rules_t const *e_rules)
Reconstitute an xlat expression from its constituent nodes.
fr_slen_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, xlat_t const *xlat, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, bool comma, bool allow_attr)
Tokenize an xlat expansion into a series of XLAT_TYPE_CHILD arguments.
static fr_slen_t head
Definition: xlat.h:408
static fr_slen_t xlat_aprint(TALLOC_CTX *ctx, char **out, xlat_exp_head_t const *head, fr_sbuff_escape_rules_t const *e_rules) 1(xlat_print
bool xlat_to_string(TALLOC_CTX *ctx, char **str, xlat_exp_head_t **head)
Convert an xlat node to an unescaped literal string and free the original node.
#define xlat_copy(_ctx, _out, _in)
Definition: xlat.h:445
fr_slen_t xlat_tokenize(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, fr_value_box_safe_for_t literals_safe_for)
Tokenize an xlat expansion.
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.
int xlat_finalize(xlat_exp_head_t *head, fr_event_list_t *runtime_el)
Bootstrap static xlats, or instantiate ephemeral ones.
Definition: xlat_inst.c:690
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
static fr_slen_t parent
Definition: pair.h:844
Structure for holding the stack of dictionary attributes being encoded.
Definition: proto.h:54
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition: strerror.c:577
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const_push(_msg)
Definition: strerror.h:227
#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
bool fr_type_cast(fr_type_t dst, fr_type_t src)
Return if we're allowed to cast the types.
Definition: types.c:283
bool const fr_type_structural[FR_TYPE_MAX+1]
Definition: types.c:183
#define fr_type_is_non_leaf(_x)
Definition: types.h:373
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_octets(_x)
Definition: types.h:328
#define fr_type_is_structural(_x)
Definition: types.h:371
#define fr_type_is_string(_x)
Definition: types.h:327
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
#define fr_type_is_null(_x)
Definition: types.h:326
#define fr_type_is_leaf(_x)
Definition: types.h:372
#define FR_TYPE_LEAF
Definition: types.h:297
ssize_t fr_value_box_from_substr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
Convert string value to a fr_value_box_t type.
Definition: value.c:4751
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules, bool tainted)
Definition: value.c:5264
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition: value.c:5301
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:3689
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
Definition: value.c:3521
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
Definition: value.c:4497
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition: value.c:3783
fr_sbuff_escape_rules_t * fr_value_escape_by_quote[T_TOKEN_LAST]
Definition: value.c:441
FR_SBUFF_SET_RETURN(sbuff, &our_sbuff)
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
Definition: value.c:3807
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition: value.c:3672
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
Definition: value.c:4417
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition: value.h:1035
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
#define fr_box_strvalue_buffer(_val)
Definition: value.h:282
static fr_slen_t data
Definition: value.h:1259
#define fr_box_strvalue_len(_val, _len)
Definition: value.h:279
static size_t char fr_sbuff_t size_t inlen
Definition: value.h:984
#define vb_strvalue
Definition: value.h:234
int nonnull(2, 5))
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition: value.h:574
static size_t char ** out
Definition: value.h:984