27RCSID(
"$Id: b8c6088f9d9f4341e692cee4b322c16ccbb5f59f $")
29#define _TMPL_PRIVATE 1
31#include <freeradius-devel/server/tmpl.h>
32#include <freeradius-devel/server/base.h>
33#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
35#include <freeradius-devel/util/debug.h>
36#include <freeradius-devel/util/base16.h>
37#include <freeradius-devel/util/misc.h>
39#include <freeradius-devel/util/sbuff.h>
40#include <freeradius-devel/util/value.h>
60#define TMPL_REQUEST_REF_DEF(_name, _ref) \
61static tmpl_request_t _name ## _entry = { \
64 .next = &_name.head.entry, \
65 .prev = &_name.head.entry \
70FR_DLIST_HEAD(tmpl_request_list) _name = { \
72 .offset = offsetof(tmpl_request_t, entry), \
74 .next = &_name ## _entry.entry.entry, \
75 .prev = &_name ## _entry.entry.entry, \
106#define DEFAULT_RULES tmpl_rules_t const default_rules = { .attr = { .list_def = request_attr_request }}
171#define UNRESOLVED_SET(_flags) (*(_flags) = (*(_flags) | TMPL_FLAG_UNRESOLVED))
172#define RESOLVED_SET(_flags) (*(_flags) = (*(_flags) & ~TMPL_FLAG_UNRESOLVED))
183 fr_sbuff_parse_rules_t
const *p_rules)
189 if (!p_rules || !p_rules->terminals)
return false;
191 fr_sbuff_marker(&m,
in);
194 fr_sbuff_marker_release(&m);
231 if (ar->ar_parent)
FR_FAULT_LOG(
"\t parent : %s (%p)", ar->ar_parent->name, ar->ar_parent);
247 if (ar->ar_parent)
FR_FAULT_LOG(
"\t parent : %s", ar->ar_parent->name);
248 if (ar->ar_unresolved_namespace)
FR_FAULT_LOG(
"\t namespace : %s", ar->ar_unresolved_namespace->name);
267 while ((ar = tmpl_attr_list_next(ar_head, ar))) {
284 FR_FAULT_LOG(
"%s can't print tmpls of type %s", __FUNCTION__,
302 while ((rr = tmpl_request_list_next(&
vpt->data.attribute.rr, rr))) {
368 FR_FAULT_LOG(
"\tlen : %zu", talloc_array_length(
vpt->data.unescaped) - 1);
425static inline CC_HINT(always_inline) CC_HINT(
nonnull(2,3))
435 while ((rr = tmpl_request_list_next(
in, rr))) {
440 tmpl_request_list_insert_tail(
out, n_rr);
448static inline CC_HINT(always_inline) CC_HINT(
nonnull(2,3))
455 tmpl_request_list_talloc_init(rql);
469 while ((rr = tmpl_request_list_next(rql, rr))) {
496 if (!a || !tmpl_request_list_initialised(a) || tmpl_request_list_empty(a)) a = &tmpl_request_def_current;
497 if (!b || !tmpl_request_list_initialised(b) || tmpl_request_list_empty(b)) b = &tmpl_request_def_current;
502 if (a == b)
return 0;
505 a_rr = tmpl_request_list_next(a, a_rr);
506 b_rr = tmpl_request_list_next(b, b_rr);
508 if (!a_rr || !b_rr)
return CMP(tmpl_request_list_num_elements(a), tmpl_request_list_num_elements(b));
530 fr_sbuff_parse_rules_t
const *p_rules,
539 unsigned int depth = 0;
545 at_rules = &default_rules.attr;
547 at_rules = &t_rules->
attr;
558 if (at_rules->namespace) {
559 *
namespace = at_rules->namespace;
570 if (!tmpl_request_list_initialised(
out)) tmpl_request_list_talloc_init(
out);
572 fr_sbuff_marker(&m, &our_in);
592 if ((
depth == 0) && at_rules->request_def) {
613 tmpl_request_list_talloc_free_to_tail(
out, tail);
621 if (
namespace && t_rules && t_rules->
parent) {
622 t_rules = t_rules->
parent;
630 if (t_rules->
attr.namespace) {
631 *
namespace = t_rules->attr.namespace;
651 tmpl_request_list_insert_tail(
out, rr);
703 tmpl_request_list_talloc_init(rql);
743 tmpl_request_list_talloc_init(&
vpt->data.attribute.rr);
762 char const *old = NULL;
769 vpt->len = talloc_array_length(
vpt->name) - 1;
807 vpt->len = talloc_array_length(
vpt->name) - 1;
818 vpt->rules.attr.dict_def = dict;
828 vpt->rules.escape = *escape;
857 memset(
vpt, 0,
sizeof(*
vpt));
862 vpt->len = talloc_array_length(
vpt->name) - 1;
886 memset(
vpt, 0,
sizeof(*
vpt));
889 if (t_rules)
vpt->rules = *t_rules;
908 memset(
vpt, 0,
sizeof(*
vpt));
911 if (t_rules)
vpt->rules = *t_rules;
954 memset(
vpt, 0,
sizeof(*
vpt));
1043 if (tmpl_attr_list_num_elements(
tmpl_attr(dst)) > 0) tmpl_attr_list_talloc_reverse_free(
tmpl_attr(dst));
1045 while ((src_ar = tmpl_attr_list_next(
tmpl_attr(src), src_ar))) {
1048 switch (src_ar->
type) {
1050 dst_ar->ar_da = src_ar->ar_da;
1061 dst_ar->ar_unresolved =
talloc_bstrdup(dst_ar, src_ar->ar_unresolved);
1067 dst_ar->ar_num = src_ar->ar_num;
1068 dst_ar->ar_filter_type = src_ar->ar_filter_type;
1076 tmpl_request_list_talloc_reverse_free(&dst->data.attribute.rr);
1103 if (da->flags.is_unknown) {
1136 fr_strerror_const(
"New leaf da and old leaf da do not share the same ancestor");
1146 talloc_free_children(ref);
1162 if (da->flags.is_unknown) {
1193 if (tmpl_attr_list_num_elements(
tmpl_attr(
vpt)) == 0)
return;
1222 tmpl_request_list_talloc_reverse_free(&
vpt->data.attribute.rr);
1255 if (da->flags.is_unknown) {
1273 STRINGIFY(
sizeof(attr))
" bytes, got %zu bytes", (
size_t)-slen);
1310 switch (ar->ar_num) {
1346 fr_sbuff_set_to_start(&our_name);
1354 fr_sbuff_next(&our_name);
1359 fr_sbuff_next(&our_name);
1383 if ((ar->ar_num > 1000) || (ar->ar_num < 0)) {
1384 fr_strerror_printf(
"Invalid array index '%hi' (should be between 0-1000)", ar->ar_num);
1413 fr_sbuff_parse_rules_t p_rules;
1450 t_rules.
attr = *at_rules;
1451 t_rules.
attr.namespace = ar->ar_da;
1453 p_rules = (fr_sbuff_parse_rules_t) {
1454 .terminals = &filter_terminals,
1462 if (slen < 0)
goto error;
1476 fr_sbuff_parse_rules_t p_rules;
1479 if (!fr_sbuff_is_str(&our_name,
"%{", 2)) {
1486 t_rules.
attr = *at_rules;
1488 p_rules = (fr_sbuff_parse_rules_t) {
1489 .terminals = &filter_terminals,
1497 if (slen < 0)
goto error;
1500 fr_strerror_const(
"Expression in attribute index cannot depend on functions which call external databases");
1516 if (fr_sbuff_is_str(&our_name,
"n]", 2)) {
1518 fr_sbuff_next(&our_name);
1529 fr_sbuff_parse_rules_t p_rules;
1534 t_rules.
attr = *at_rules;
1541 p_rules = (fr_sbuff_parse_rules_t) {
1542 .terminals = &filter_terminals,
1552 if (slen <= 0)
goto error;
1587static inline CC_HINT(
nonnull(3,4))
1640static inline CC_HINT(
nonnull(3,6))
1663 slen = fr_sbuff_out_abstrncpy_allowed(ar, &unresolved,
1672 tmpl_attr_list_talloc_free_to_tail(
tmpl_attr(
vpt), ar_curr);
1685 .ar_unresolved = unresolved,
1686 .ar_unresolved_namespace =
namespace,
1730 .ar_parent = da->parent,
1776 fr_sbuff_marker(&m_s,
name);
1783 fr_sbuff_marker_release(&m_s);
1811 name, p_rules ? p_rules->terminals : NULL,
1822 our_parent = da->parent;
1824 if (!our_parent->flags.is_root) {
1845 p_rules ? p_rules->terminals : NULL);
1856 ar = tmpl_attr_list_tail(&
vpt->data.attribute.ar);
1863 p_rules ? p_rules->terminals : NULL);
1866 our_parent = internal_root;
1876 if (!da->flags.local && namespace->flags.local)
namespace = our_parent =
fr_dict_root(da->dict);
1882 if (da->parent != our_parent) {
1895 if (our_parent->flags.is_unknown)
break;
1926 our_parent =
namespace =
fr_dict_root(at_rules->dict_def);
1942 namespace = fr_dict_unlocal(namespace);
1954 if (da)
goto alloc_ar;
1973 switch (namespace->type) {
1994 .ar_parent = our_parent,
2013 fr_sbuff_marker_release(&m_s);
2034 .ar_parent = our_parent,
2056 if (da->flags.local && (ar->ar_num > 0)) {
2068 fr_sbuff_marker_release(&m_s);
2069 fr_sbuff_marker(&m_s,
name);
2098 our_parent =
namespace = ref;
2101 our_parent =
namespace =
parent;
2104 our_parent =
namespace =
fr_dict_root(at_rules->dict_def);
2107 our_parent =
namespace = NULL;
2119 namespace = our_parent = da;
2130 "\"struct\", \"tlv\", \"vendor\", \"vsa\" or \"group\", got \"%s\"",
2141 tmpl_attr_list_talloc_free_tail(&
vpt->data.attribute.ar);
2166 fr_sbuff_marker_release(&m_s);
2213 fr_sbuff_parse_rules_t
const *p_rules,
2219 bool is_raw =
false;
2225 if (!t_rules) t_rules = &default_rules;
2226 at_rules = &t_rules->
attr;
2239 switch (at_rules->
prefix) {
2286 &
vpt->data.attribute.rr,
2298 fr_sbuff_marker(&m_l, &our_name);
2305 namespace,
namespace,
2306 &our_name, p_rules, at_rules, 0);
2307 if (ret < 0)
goto error;
2325 bool is_local = ar->ar_da->flags.local;
2329 if (!ar->ar_da->flags.local ||
2330 (ar->ar_da->flags.local && is_local))
continue;
2404 vpt->rules = *t_rules;
2413 if (t_rules->
attr.request_def) {
2453 fr_sbuff_set_to_start(&our_name);
2481 if (!t_rules) t_rules = &default_rules;
2483 name_len = strlen(
name);
2485 if (slen <= 0)
return slen;
2489 if (slen != name_len) {
2517 fr_sbuff_parse_rules_t
const *p_rules)
2534 cast, allow_enum ? t_rules->
enumv : NULL,
2535 &our_in, p_rules,
false) < 0) {
2565 fr_sbuff_parse_rules_t
const *p_rules)
2584 vpt->data.literal.vb_bool = a_bool;
2603 fr_sbuff_parse_rules_t
const *p_rules)
2643 MEM(bin = talloc_realloc_size(
vpt, bin, binlen));
2662 fr_sbuff_parse_rules_t
const *p_rules)
2730 fr_sbuff_parse_rules_t
const *p_rules)
2737 char *sep_a, *sep_b;
2739 static bool ipv6_chars[
UINT8_MAX + 1] = {
2740 [
'0'] =
true, [
'1'] =
true, [
'2'] =
true, [
'3'] =
true, [
'4'] =
true,
2741 [
'5'] =
true, [
'6'] =
true, [
'7'] =
true, [
'8'] =
true, [
'9'] =
true,
2742 [
'a'] =
true, [
'b'] =
true, [
'c'] =
true, [
'd'] =
true, [
'e'] =
true,
2744 [
'A'] =
true, [
'B'] =
true, [
'C'] =
true, [
'D'] =
true, [
'E'] =
true,
2746 [
':'] =
true, [
'.'] =
true
2753 fr_sbuff_marker(&m, &our_in);
2773 if (sep_a && (!(sep_b = memchr(
fr_sbuff_current(&m),
':', len)) || (sep_b > sep_a))) {
2793 if ((len < 1) || (len > IFNAMSIZ)) {
2848 fr_sbuff_parse_rules_t
const *p_rules)
2897 memcpy(vb->vb_ether,
buff,
sizeof(vb->vb_ether));
2915 fr_sbuff_parse_rules_t
const *p_rules)
2929 if (slen <= 0)
return 0;
2940 if (a_int >= INT8_MIN) {
2942 vb->vb_int8 = (int8_t)a_int;
2943 }
else if (a_int >= INT16_MIN) {
2945 vb->vb_int16 = (int16_t)a_int;
2946 }
else if (a_int >= INT32_MIN) {
2948 vb->vb_int32 = (int32_t)a_int;
2951 vb->vb_int64 = (int64_t)a_int;
2960 if (slen <= 0)
return slen;
2972 vb->vb_uint8 = (
uint8_t)a_uint;
2973 }
else if (a_uint <= UINT16_MAX) {
2976 }
else if (a_uint <= UINT32_MAX) {
2981 vb->vb_uint64 = (uint64_t)a_uint;
2991 fr_sbuff_parse_rules_t
const *p_rules)
3000 if (slen <= 0)
return 0;
3011 vb->vb_float64 = a_float;
3019 fr_sbuff_parse_rules_t
const *p_rules)
3028 if (slen <= 0)
return 0;
3034 vb->vb_time_delta = a_delta;
3064 fr_sbuff_parse_rules_t
const *p_rules,
3083 if (!t_rules->
enumv)
return 0;
3102 "'quoted literal', \"%{expansion}\", or enum value");
3121 if (t_rules->
enumv) {
3144 vpt->data.unescaped = str;
3179 fr_sbuff_parse_rules_t
const *p_rules,
3191 if (!t_rules) t_rules = &default_rules;
3232 t_rules,
true, p_rules);
3243 my_t_rules.
cast = my_t_rules.
enumv->type;
3264 if (slen > 0)
goto done_bareword;
3275 if (slen > 0)
goto done_bareword;
3282 if (slen > 0)
goto done_bareword;
3289 if (slen > 0)
goto done_bareword;
3293 if (slen > 0)
goto done_bareword;
3300 if (slen > 0)
goto done_bareword;
3307 if (slen > 0)
goto done_bareword;
3318 if (slen > 0)
goto done_bareword;
3326 if (slen > 0)
goto done_bareword;
3348 "'quoted literal', \"%{expansion}\", or enum value");
3366 vpt->data.unescaped = str;
3381 slen = fr_sbuff_out_aunescape_until(
vpt, &str, &our_in, SIZE_MAX,
3382 p_rules ? p_rules->terminals : NULL,
3383 p_rules ? p_rules->escapes : NULL);
3385 vpt->data.unescaped = str;
3409 t_rules,
false, p_rules);
3422 vpt->data.unescaped = str;
3454 if ((slen <= 0) || !
head) {
3482 fr_sbuff_set_to_start(&our_in);
3504 vpt->data.unescaped = str;
3546 vpt->rules =
in->rules;
3568 vpt->data.reg_flags =
in->data.reg_flags;
3581 if (
unlikely(tmpl_regex_compile(
vpt,
vpt->data.reg.subcaptures) < 0))
goto error;
3638 fr_sbuff_marker(&m, &our_in);
3655 if (rules) rules->
cast = cast;
3692 switch (
vpt->type) {
3728 if (da->type == dst_type) {
3729 if (da->flags.has_value)
goto done;
3732 src_type = da->type;
3740 if (src_type == dst_type) {
3761 vpt->rules.cast = dst_type;
3783 slen = regex_flags_parse(&
err, &
vpt->data.reg_flags,
in, terminals,
true);
3816static inline CC_HINT(always_inline)
3819 char const *unescaped,
size_t unescaped_len)
3830 switch (existing_quote) {
3833 return existing_quote;
3861 switch (
vpt->type) {
3864 char *unescaped =
vpt->data.unescaped;
3883 (
uint8_t const *)unescaped, talloc_array_length(unescaped) - 1,
3884 false) < 0)
return -1;
3888 unescaped, talloc_array_length(unescaped) - 1,
3889 NULL,
false) < 0)
return -1;
3893 unescaped, talloc_array_length(unescaped) - 1);
3979 dict_def =
vpt->rules.attr.dict_def;
3995 talloc_array_length(ar->ar_unresolved) - 1),
3998 vpt->rules.attr.allow_foreign);
4018 next->ar_parent = da;
4019 next->ar_unresolved_namespace = da;
4026 while ((ar = tmpl_attr_list_next(
tmpl_attr(
vpt), ar))) {
4050 talloc_array_length(ar->ar_unresolved) - 1),
4067 talloc_array_length(ar->ar_unresolved) - 1),
4083 fr_assert(ar->ar_parent && !ar->ar_parent->flags.is_unknown);
4091 next->ar_parent = da;
4092 next->ar_unresolved_namespace = da;
4105 ar->ar_parent = prev->ar_parent;
4132static inline CC_HINT(always_inline)
4137 .tr_rules = tr_rules,
4138 .allow_unresolved = false
4171 if (!tr_rules) tr_rules = &default_tr_rules;
4185 fr_strerror_printf(
"mismatch between parse-time enumv '%s' and resolution-time enumv '%s'",
4209 if (ret < 0)
return ret;
4231 if (!enumv) enumv = tr_rules->
enumv;
4245 dst_type = enumv->type;
4287 switch (
vpt->type) {
4309 tmpl_request_list_talloc_free(&
vpt->data.attribute.rr);
4321 TALLOC_FREE(
vpt->data.xlat.ex);
4330 memcpy(
vpt, &tmp,
sizeof(*
vpt));
4374 switch (ref->
type) {
4380 ref->ar_unknown->flags.is_unknown = 1;
4426 if (
vpt->rules.at_runtime)
return 1;
4434 while ((ar = tmpl_attr_list_next(
tmpl_attr(
vpt), ar))) {
4450 unknown = ar->ar_unknown;
4452 if (!known)
return -1;
4460 (next->ar_da->parent == unknown)) {
4462 known) < 0)
return -1;
4463 next->ar_parent = known;
4527 if (!
vpt)
return -1;
4540 if (
type != da->type) {
4547 if (memcmp(flags, &da->flags,
sizeof(*flags)) != 0) {
4566 char *unescaped =
vpt->data.unescaped;
4572 slen = regex_compile(
vpt, &
vpt->data.reg.ex,
4573 unescaped, talloc_array_length(unescaped) - 1,
4574 &
vpt->data.reg_flags, subcaptures,
vpt->rules.at_runtime);
4575 if (slen <= 0)
return vpt->quote !=
T_BARE_WORD ? slen - 1 : slen;
4578 vpt->data.reg.src = unescaped;
4579 vpt->data.reg.subcaptures = subcaptures;
4601 rr = tmpl_request_list_next(rql, rr);
4637 switch (
vpt->type) {
4661 if (slen < 0)
return slen;
4678 while ((ar = tmpl_attr_list_next(
tmpl_attr(
vpt), ar))) {
4696 depth = ar->ar_parent->depth - 1;
4701 depth = ar->ar_parent->depth;
4722 for (i =
depth; (
unsigned int)i < ar->
ar_da->depth; i++) {
4740 unsigned int i,
depth;
4747 if (ar->ar_parent && !ar->ar_parent->flags.is_root) {
4749 if (ar->ar_parent->flags.is_root) {
4752 depth = ar->ar_parent->depth - 1;
4755 for (i =
depth; i < ar->ar_parent->depth; i++) {
4772 switch (ar->ar_num) {
4795 (void)
xlat_print(&our_out, ar->ar_cond, NULL);
4840 switch (
vpt->type) {
4861 fr_sbuff_terminate(
out);
4887 fr_sbuff_terminate(
out);
4936#ifdef WITH_VERIFY_PTR
4949 for (i = 0; i < len; i++) {
4950 if (ptr[i] != 0x00)
return ptr + i;
4959#define CHECK_ZEROED(_vpt, _field) is_zeroed(((uint8_t const *)&(_vpt)->data) + sizeof((_vpt)->data._field), sizeof((_vpt)->data) - sizeof((_vpt)->data._field))
4965#define PRINT_NON_ZEROED(_vpt, _field, _nz_ptr) \
4967 DEBUG("Expected live portion %p-%p (0-%zu)", \
4969 (uint8_t const *)&(_vpt)->data + sizeof((_vpt)->data._field), \
4970 sizeof((_vpt)->data._field)); \
4971 DEBUG("Expected zero portion %p-%p (%zu-%zu)", \
4972 (uint8_t const *)&(_vpt)->data + sizeof((_vpt)->data._field), \
4973 (uint8_t const *)&(_vpt)->data + sizeof((_vpt)->data), \
4974 sizeof((_vpt)->data._field), sizeof((_vpt)->data)); \
4975 HEX_MARKER1((uint8_t const *)&vpt->data, sizeof(vpt->data), nz - (uint8_t const *)&vpt->data, "non-zero memory", ""); \
4999 while ((slow = tmpl_attr_list_next(
tmpl_attr(
vpt), slow)) &&
5007 "CONSISTENCY CHECK FAILED %s[%u]: Looping reference list found. "
5008 "Fast pointer hit slow pointer at \"%s\"",
5011 slow->da ? slow->da->
name :
"(null-attr)");
5026 "TMPL_TYPE_ATTR known attribute \"%s\" "
5027 "occurred after unknown attribute %s "
5031 ar->unknown.
da->name);
5033 if (seen_unresolved) {
5036 "TMPL_TYPE_ATTR known attribute \"%s\" "
5037 "occurred after unresolved attribute \"%s\""
5044 "CONSISTENCY CHECK FAILED %s[%u]: attr ref missing parent",
5052 "TMPL_TYPE_ATTR unspecified attribute "
5053 "occurred after unknown attribute %s "
5056 ar->unknown.
da->name);
5058 if (seen_unresolved) {
5061 "TMPL_TYPE_ATTR unspecified attribute "
5062 "occurred after unresolved attribute \"%s\""
5070 seen_unresolved = ar;
5072 "CONSISTENCY CHECK FAILED %s[%u]: unresolved attr ref missing namespace",
5078 if (seen_unresolved) {
5081 "TMPL_TYPE_ATTR unknown attribute \"%s\" "
5082 "occurred after unresolved attribute %s "
5108 "TMPL_TYPE_UNINITIALISED (uninitialised)",
file,
line);
5113 "(outside range of tmpl_type_table)",
file,
line,
vpt->type);
5119 fr_fatal_assert_fail(
"CONSISTENCY CHECK FAILED %s[%u]: Quote type '%c' (%i) was set for NULL name",
5124 fr_fatal_assert_fail(
"CONSISTENCY CHECK FAILED %s[%u]: No quoting type was set for name \"%.*s\"",
5136 switch (
vpt->type) {
5138 if ((nz = is_zeroed((
uint8_t const *)&
vpt->data,
sizeof(
vpt->data)))) {
5140 nz - (
uint8_t const *)&
vpt->data,
"non-zero memory",
"");
5142 "has non-zero bytes in its data union",
file,
line);
5147 if (!
vpt->data.unescaped) {
5149 "unescaped field is NULL",
file,
line);
5154 if (!
vpt->data.xlat.ex) {
5156 "has a NULL xlat.ex field",
file,
line);
5162 "does not have 'needs resolving' flag set",
file,
line);
5167 if (!
vpt->data.xlat.ex) {
5169 "has a NULL xlat.ex field",
file,
line);
5196 if ((tmpl_attr_list_num_elements(
tmpl_attr(
vpt)) > 0) &&
5207 if ((nz = CHECK_ZEROED(
vpt, attribute))) {
5208 PRINT_NON_ZEROED(
vpt, attribute, nz);
5210 "has non-zero bytes after the data.attribute struct in the union",
5222 "da is marked as unknown, but address is not equal to the template's "
5238 "attribute \"%s\" (%s) not rooted in a dictionary",
5246 "dictionary pointer %p \"%s\" (%s) "
5247 "and global dictionary pointer %p \"%s\" (%s) differ",
5260 if ((nz = CHECK_ZEROED(
vpt, literal))) {
5261 PRINT_NON_ZEROED(
vpt, literal, nz);
5263 "has non-zero bytes after the data.literal struct in the union",
5269 "FR_TYPE_NULL (uninitialised)",
file,
line);
5302 fr_fatal_assert_fail(
"CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_XLAT_UNRESOLVED - No regex support",
5309 if (tmpl_regex(
vpt) == NULL) {
5311 "reg.ex field was NULL",
file,
line);
5328#define return_P(_x) fr_strerror_const(_x);goto return_p
5359 while (isspace((
uint8_t) *p) && (p < end)) p++;
5360 if (p >= end)
return p -
in;
5375 while ((q < end) && (isalnum((
int) *q) || (*q ==
'.') || (*q ==
'_') || (*q ==
'-'))) {
5420 if ((*p ==
'}') || (*p ==
')')) {
5421 bool match = (*p ==
close);
5429 *outlen = p - (*out);
5438 return_P(
"End of string after escape");
5445 if ((p[0] ==
'%') && ((p[1] ==
'{') || (p[1] ==
'('))) {
5447 return_P(
"End of string after expansion");
5458 if ((*p ==
'{') || (*p ==
'(')) {
5472 return_P(
"Unterminated expansion");
5500 if ((
inlen > 3) && (p[0] == quote) && (p[1] == quote)) {
5509 if (p >= end)
goto unterminated;
5519 *outlen = p - (*out);
5525 if (((end - p) >= 3) && (p[1] == quote) && (p[2] == quote)) {
5526 *outlen = p - (*out);
5538 return_P(
"End of string after escape");
5586 }
else if ((p[1] ==
'E') &&
5640 if ((*p ==
'-') || (*p ==
':')) {
5641 if (p[1] ==
'=')
break;
5650 if ((*p ==
'.') || (*p ==
'/') || (*p ==
'_') || (*p ==
'*') ||
5651 (*p ==
']') || (*p ==
'@')) {
5659 if ((p ==
in) && (*p ==
'[')) {
5667 if (((*p >=
'a') && (*p <=
'z')) ||
5668 ((*p >=
'A') && (*p <=
'Z')) ||
5669 ((*p >=
'0') && (*p <=
'9'))) {
5677 if (*(
uint8_t const *)p > 0x80) {
5694 if ((*p ==
'#') || (*p ==
'*') || (*p ==
'n')) {
5701 while ((*p >=
'0') && (*p <=
'9')) {
5706 return_P(
"Array index is not an integer");
5729 if ((*p ==
'"') || (*p ==
'\'') || (*p ==
'`')) {
5730 return_P(
"Unexpected start of string");
5734 return_P(
"Empty string is invalid");
5737 *outlen = p - (*out);
5753 switch (
vpt->type) {
5794 if (
vpt->rules.attr.request_def) {
5804 out->attr.namespace = da;
5815 if ((dict != internal) && (dict !=
out->attr.dict_def)) {
5816 out->attr.dict_def = dict;
5817 out->attr.namespace = ref;
5832 FR_FAULT_LOG(
"\tnamespace = %s", at_rules->namespace ? at_rules->namespace->name :
"");
static int const char char buffer[256]
static int const char * fmt
#define fr_base16_decode(_err, _out, _in, _no_trailing)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define L(_str)
Helper for initialising arrays of string literals.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
static char const * skip_word(char const *text)
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
#define FR_FAULT_LOG(_fmt,...)
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
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))
unsigned int name_only
this attribute should always be referred to by name.
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
fr_dict_t const * fr_dict_by_da(fr_dict_attr_t const *da)
Attempt to locate the protocol dictionary containing an attribute.
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.
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
bool const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters that are allowed in dictionary attribute names.
static fr_dict_attr_t * fr_dict_attr_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
fr_dict_attr_t const * fr_dict_attr_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.
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.
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
fr_dict_attr_t * fr_dict_attr_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.
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
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.
fr_value_box_t const * value
Enum value (what name maps to).
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
fr_dict_t const * fr_dict_internal(void)
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.
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.
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.
fr_dict_attr_err_t
Errors returned by attribute lookup functions.
@ FR_DICT_ATTR_OK
No error.
@ FR_DICT_ATTR_NOT_DESCENDENT
Attribute is not a descendent of the parent attribute.
@ FR_DICT_ATTR_NO_CHILDREN
Child lookup in attribute with no children.
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, unsigned int attr, fr_type_t type, fr_dict_attr_flags_t const *flags))
Add an attribute to the dictionary.
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.
#define fr_dict_attr_is_key_field(_da)
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Values of the encryption flags.
Value of an enumerated attribute.
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.
#define FR_DLIST_HEAD(_name)
Expands to the type name used for the head wrapper structure.
#define FR_IPADDR_STRLEN
Like INET6_ADDRSTRLEN but includes space for the textual Zone ID.
#define HEX_MARKER1(_data, _len, _slen, _error, _fmt,...)
static char * stack[MAX_STACK]
@ TMPL_ATTR_REF_PREFIX_NO
Attribute refs have no '&' prefix.
@ TMPL_ATTR_REF_PREFIX_AUTO
Attribute refs may have a '&' prefix.
@ TMPL_ATTR_REF_PREFIX_YES
Attribute refs must have '&' prefix.
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
@ FR_SBUFF_PARSE_ERROR_NOT_FOUND
String does not contain a token matching the output type.
@ FR_SBUFF_PARSE_ERROR_FORMAT
Format of data was invalid.
@ FR_SBUFF_PARSE_OK
No error.
static uint8_t depth(fr_minmax_heap_index_t i)
char * fr_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
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.
fr_dict_attr_t const * request_attr_request
fr_dict_attr_t const * request_attr_control
fr_dict_attr_t const * request_attr_local
fr_dict_attr_t const * request_attr_state
fr_dict_attr_t const * request_attr_reply
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.
bool const sbuff_char_class_hex[UINT8_MAX+1]
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
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.
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.
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
#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_adv_past_str_literal(_sbuff, _needle)
#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.
#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_SET_RETURN(_dst, _src)
#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.
static fr_slen_t ar_prefix
#define tmpl_contains_xlat(vpt)
#define TMPL_VERIFY(_vpt)
#define tmpl_value_length(_tmpl)
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
#define tmpl_is_uninitialised(vpt)
Helpers to verify the type of tmpl_t.
#define tmpl_is_attr_unresolved(vpt)
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".
#define tmpl_rules_enumv(_tmpl)
static bool tmpl_attr_tail_is_normal(tmpl_t const *vpt)
Return true if the last attribute reference is "normal".
#define tmpl_value(_tmpl)
#define ar_is_unknown(_ar)
static bool tmpl_attr_tail_is_unknown(tmpl_t const *vpt)
Return true if the last attribute reference is "unknown".
#define tmpl_contains_regex(vpt)
fr_value_box_safe_for_t literals_safe_for
safe_for value assigned to literal values in xlats, execs, and data.
#define tmpl_is_attr(vpt)
fr_dict_attr_t const * enumv
Enumeration attribute used to resolve enum values.
tmpl_rules_t const * parent
for parent / child relationships
#define tmpl_value_enumv(_tmpl)
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
static bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar)
Return true if the tmpl_attr is one of the list types.
#define ar_filter_is_num(_ar)
#define tmpl_rules_cast(_tmpl)
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
@ TMPL_TYPE_MAX
Marker for the last tmpl type.
@ TMPL_TYPE_ATTR_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
@ TMPL_TYPE_NULL
Has no value.
@ TMPL_TYPE_EXEC
Callout to an external script or program.
@ TMPL_TYPE_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
@ TMPL_TYPE_DATA
Value in native boxed format.
@ TMPL_TYPE_REGEX
Compiled (and possibly JIT'd) regular expression.
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
@ TMPL_TYPE_REGEX_XLAT
A regex containing xlat expansions.
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
@ TMPL_TYPE_UNINITIALISED
Uninitialised.
#define tmpl_is_regex_xlat(vpt)
#define tmpl_assert_type(_cond)
Convenience macro for printing a meaningful assert message when we get a bad tmpl type.
#define tmpl_contains_attr(vpt)
#define TMPL_FLAG_REGEX
Is a type of regular expression.
#define ar_filter_is_cond(_ar)
tmpl_xlat_rules_t xlat
Rules/data for parsing xlats.
static char const * tmpl_attr_tail_unresolved(tmpl_t const *vpt)
Return the last attribute reference unresolved da.
bool at_runtime
Produce an ephemeral/runtime tmpl.
static bool tmpl_is_list(tmpl_t const *vpt)
#define TMPL_ATTR_VERIFY(_vpt)
bool force_dict_def
Use supplied dict_def even if original vpt->rules->dict_def was not NULL.
#define tmpl_is_data(vpt)
fr_dict_t const * dict_def
Alternative default dictionary to use if vpt->rules->dict_def is NULL.
static size_t tmpl_attr_num_elements(tmpl_t const *vpt)
The number of attribute references contained within a tmpl.
#define tmpl_value_type(_tmpl)
@ TMPL_ATTR_ERROR_INVALID_ARRAY_INDEX
Invalid array index.
@ TMPL_ATTR_ERROR_LIST_NOT_ALLOWED
List qualifier is not allowed here.
@ TMPL_ATTR_ERROR_UNRESOLVED_NOT_ALLOWED
Attribute couldn't be found in the dictionaries.
@ TMPL_ATTR_ERROR_BAD_CAST
Specified cast was invalid.
@ TMPL_ATTR_ERROR_INVALID_NAME
Attribute ref length is zero, or longer than the maximum.
@ TMPL_ATTR_ERROR_MISSING_TERMINATOR
Unexpected text found after attribute reference.
@ TMPL_ATTR_ERROR_LIST_MISSING
List qualifier is required, but missing.
@ TMPL_ATTR_ERROR_NONE
No error.
@ TMPL_ATTR_ERROR_FOREIGN_NOT_ALLOWED
Attribute resolved in a dictionary different to the one specified.
@ TMPL_ATTR_ERROR_UNKNOWN_NOT_ALLOWED
Attribute specified as OID, could not be found in the dictionaries, and is disallowed because 'disall...
@ TMPL_ATTR_ERROR_FILTER_NOT_ALLOWED
Filters disallowed by rules.
@ TMPL_ATTR_ERROR_EMPTY
Attribute ref contains no data.
@ TMPL_ATTR_ERROR_NESTING_TOO_DEEP
Too many levels of nesting.
@ TMPL_ATTR_ERROR_BAD_PREFIX
Missing '&' or has '&' when it shouldn't.
#define tmpl_is_data_unresolved(vpt)
fr_type_t cast
Whether there was an explicit cast.
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
@ TMPL_ATTR_LIST_REQUIRE
Attribute refs are required to have a list.
@ TMPL_ATTR_LIST_ALLOW
Attribute refs are allowed to have a list.
@ TMPL_ATTR_LIST_FORBID
Attribute refs are forbidden from having a list.
enum tmpl_type_e tmpl_type_t
Types of tmpl_t.
static fr_dict_attr_t const * tmpl_attr_tail_unknown(tmpl_t const *vpt)
Return the last attribute reference unknown da.
#define tmpl_is_regex(vpt)
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.
static bool tmpl_attr_tail_is_raw(tmpl_t const *vpt)
Return true if the last attribute reference is "raw".
@ REQUEST_OUTER
request_t containing the outer layer of the EAP conversation.
@ REQUEST_PARENT
Parent (whatever it is).
@ REQUEST_UNKNOWN
Unknown request.
@ REQUEST_CURRENT
The current request (default).
struct tmpl_rules_s tmpl_rules_t
#define tmpl_is_regex_xlat_unresolved(vpt)
#define tmpl_is_regex_uncompiled(vpt)
fr_dict_attr_t const * enumv
for resolving T_BARE_WORD
#define TMPL_MAX_REQUEST_REF_NESTING
The maximum number of request references allowed.
@ TMPL_ATTR_TYPE_UNSPEC
No attribute was specified as this level only a filter.
@ TMPL_ATTR_TYPE_NORMAL
Normal, resolved, attribute ref.
@ 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 ...
@ TMPL_ATTR_TYPE_UNRESOLVED
We have a name, but nothing else to identify the attribute.
@ TMPL_ATTR_FILTER_TYPE_TMPL
Filter is a tmpl.
@ TMPL_ATTR_FILTER_TYPE_INDEX
Filter is an index type.
@ TMPL_ATTR_FILTER_TYPE_CONDITION
Filter is a condition.
@ TMPL_ATTR_FILTER_TYPE_NONE
No filter present.
@ TMPL_ATTR_FILTER_TYPE_EXPR
Filter is an expression.
fr_event_list_t * runtime_el
The eventlist to use for runtime instantiation of xlats.
#define tmpl_needs_resolving(vpt)
tmpl_attr_filter_type_t _CONST type
Type of filter this is.
#define ar_filter_is_none(_ar)
Similar to tmpl_rules_t, but used to specify parameters that may change during subsequent resolution ...
Optional arguments passed to vp_tmpl functions.
static char buff[sizeof("18446744073709551615")+3]
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
fr_aka_sim_id_type_t type
Define entry and head types for tmpl request references.
tmpl_attr_list_presence_t list_presence
Whether the attribute reference can have a list, forbid it, or require it.
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
uint8_t disallow_filters
disallow filters.
uint8_t allow_unresolved
Allow attributes that look valid but were not found in the dictionaries.
uint8_t allow_foreign
Allow arguments not found in dict_def.
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
uint8_t allow_wildcard
Allow the special case of .
uint8_t allow_unknown
Allow unknown attributes i.e.
tmpl_attr_prefix_t prefix
Whether the attribute reference requires a prefix.
An element in a list of nested attribute references.
unsigned int _CONST resolve_only
This reference and those before it.
unsigned int _CONST is_raw
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
fr_dict_attr_t const *_CONST parent
The parent we used when trying to resolve the attribute originally.
tmpl_attr_filter_t _CONST filter
Filter associated with the attribute reference.
tmpl_attr_type_t _CONST type
is a raw reference
Define manipulation functions for the attribute reference list.
tmpl_request_ref_t _CONST request
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in an arbitrarily ordered array of name to num mappings.
An element in a lexicographically sorted array of name to num mappings.
char * talloc_bstrdup(TALLOC_CTX *ctx, char const *in)
Binary safe strdup function.
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
#define talloc_get_type_abort_const
static int talloc_const_free(void const *ptr)
Free const'd memory.
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
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.
A time delta, a difference in time measured in nanoseconds.
Escaping rules for tmpls.
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)
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.
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.
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.
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.
int tmpl_attr_unknown_add(tmpl_t *vpt)
Add an unknown fr_dict_attr_t specified by a tmpl_t to the main dictionary.
bool tmpl_require_enum_prefix
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.
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)
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.
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.
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)
void tmpl_attr_rewrite_leaf_num(tmpl_t *vpt, int16_t to)
Rewrite the leaf's instance number.
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)
ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t inlen, fr_token_t *type)
Preparse a string in preparation for passing it to tmpl_afrom_substr()
#define TMPL_REQUEST_REF_DEF(_name, _ref)
Define a global variable for specifying a default request reference.
#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 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 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 size_t attr_num_table_len
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.
static tmpl_t * tmpl_alloc_null(TALLOC_CTX *ctx)
Create a new heap allocated tmpl_t.
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.
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.
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.
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.
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...
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.
fr_table_num_ordered_t const tmpl_type_table[]
Map tmpl_type_t values to descriptive strings.
void tmpl_attr_debug(tmpl_t const *vpt)
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[]
const char fr_token_quote[T_TOKEN_LAST]
Convert tokens back to a quoting character.
@ T_SOLIDUS_QUOTED_STRING
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.
bool xlat_impure_func(xlat_exp_head_t const *head)
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 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)
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.
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)
fr_slen_t xlat_tokenize_expression(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)
Structure for holding the stack of dictionary attributes being encoded.
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const_push(_msg)
#define fr_strerror_const(_msg)
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
bool fr_type_cast(fr_type_t dst, fr_type_t src)
Return if we're allowed to cast the types.
bool const fr_type_numeric[FR_TYPE_MAX+1]
bool const fr_type_structural[FR_TYPE_MAX+1]
#define fr_type_is_non_leaf(_x)
#define fr_type_is_octets(_x)
#define fr_type_is_structural(_x)
#define fr_type_is_string(_x)
#define FR_TYPE_STRUCTURAL
#define fr_type_is_null(_x)
#define fr_type_is_leaf(_x)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
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.
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)
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.
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.
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.
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.
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.
fr_sbuff_escape_rules_t * fr_value_escape_by_quote[T_TOKEN_LAST]
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.
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
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.
#define fr_value_box_mark_safe_for(_box, _safe_for)
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)
#define fr_box_strvalue_len(_val, _len)
static size_t char fr_sbuff_t size_t inlen
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
static size_t char ** out