27 RCSID(
"$Id: 6d6d65a26488c2c79b0252be5445096d23bc9032 $")
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>
53 #define TMPL_REQUEST_REF_DEF(_name, _ref) \
54 static tmpl_request_t _name ## _entry = { \
57 .next = &_name.head.entry, \
58 .prev = &_name.head.entry \
63 FR_DLIST_HEAD(tmpl_request_list) _name = { \
65 .offset = offsetof(tmpl_request_t, entry), \
67 .next = &_name ## _entry.entry.entry, \
68 .prev = &_name ## _entry.entry.entry, \
99 #define DEFAULT_RULES tmpl_rules_t const default_rules = { .attr = { .list_def = request_attr_request }}
164 #define UNRESOLVED_SET(_flags) (*(_flags) = (*(_flags) | TMPL_FLAG_UNRESOLVED))
165 #define RESOLVED_SET(_flags) (*(_flags) = (*(_flags) & ~TMPL_FLAG_UNRESOLVED))
176 fr_sbuff_parse_rules_t
const *p_rules)
182 if (!p_rules || !p_rules->terminals)
return false;
184 fr_sbuff_marker(&m,
in);
187 fr_sbuff_marker_release(&m);
224 if (ar->ar_parent)
FR_FAULT_LOG(
"\t parent : %s (%p)", ar->ar_parent->name, ar->ar_parent);
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);
260 while ((ar = tmpl_attr_list_next(ar_head, ar))) {
277 FR_FAULT_LOG(
"%s can't print tmpls of type %s", __FUNCTION__,
295 while ((rr = tmpl_request_list_next(&
vpt->data.attribute.rr, rr))) {
361 FR_FAULT_LOG(
"\tlen : %zu", talloc_array_length(
vpt->data.unescaped) - 1);
418 static inline CC_HINT(always_inline) CC_HINT(
nonnull(2,3))
428 while ((rr = tmpl_request_list_next(
in, rr))) {
433 tmpl_request_list_insert_tail(
out, n_rr);
441 static inline CC_HINT(always_inline) CC_HINT(
nonnull(2,3))
448 tmpl_request_list_talloc_init(rql);
462 while ((rr = tmpl_request_list_next(rql, rr))) {
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;
495 if (a == b)
return 0;
498 a_rr = tmpl_request_list_next(a, a_rr);
499 b_rr = tmpl_request_list_next(b, b_rr);
501 if (!a_rr || !b_rr)
return CMP(tmpl_request_list_num_elements(a), tmpl_request_list_num_elements(b));
523 fr_sbuff_parse_rules_t
const *p_rules,
532 unsigned int depth = 0;
538 at_rules = &default_rules.attr;
540 at_rules = &t_rules->
attr;
551 if (at_rules->namespace) {
552 *
namespace = at_rules->namespace;
563 if (!tmpl_request_list_initialised(
out)) tmpl_request_list_talloc_init(
out);
565 fr_sbuff_marker(&m, &our_in);
585 if ((
depth == 0) && at_rules->request_def) {
606 tmpl_request_list_talloc_free_to_tail(
out, tail);
614 if (
namespace && t_rules && t_rules->
parent) {
615 t_rules = t_rules->
parent;
623 if (t_rules->
attr.namespace) {
624 *
namespace = t_rules->attr.namespace;
644 tmpl_request_list_insert_tail(
out, rr);
696 tmpl_request_list_talloc_init(rql);
736 tmpl_request_list_talloc_init(&
vpt->data.attribute.rr);
755 char const *old = NULL;
762 vpt->len = talloc_array_length(
vpt->name) - 1;
800 vpt->len = talloc_array_length(
vpt->name) - 1;
811 vpt->rules.attr.dict_def =
dict;
821 vpt->rules.escape = *escape;
850 memset(
vpt, 0,
sizeof(*
vpt));
855 vpt->len = talloc_array_length(
vpt->name) - 1;
879 memset(
vpt, 0,
sizeof(*
vpt));
882 if (t_rules)
vpt->rules = *t_rules;
901 memset(
vpt, 0,
sizeof(*
vpt));
904 if (t_rules)
vpt->rules = *t_rules;
947 memset(
vpt, 0,
sizeof(*
vpt));
1035 if (tmpl_attr_list_num_elements(
tmpl_attr(dst)) > 0) tmpl_attr_list_talloc_reverse_free(
tmpl_attr(dst));
1037 while ((src_ar = tmpl_attr_list_next(
tmpl_attr(src), src_ar))) {
1040 switch (src_ar->
type) {
1042 dst_ar->ar_da = src_ar->ar_da;
1053 dst_ar->ar_unresolved =
talloc_bstrdup(dst_ar, src_ar->ar_unresolved);
1059 dst_ar->ar_num = src_ar->ar_num;
1060 dst_ar->ar_filter_type = src_ar->ar_filter_type;
1068 tmpl_request_list_talloc_reverse_free(&dst->data.attribute.rr);
1095 if (da->flags.is_unknown) {
1128 fr_strerror_const(
"New leaf da and old leaf da do not share the same ancestor");
1138 talloc_free_children(ref);
1147 if (da->flags.is_unknown) {
1170 if (tmpl_attr_list_num_elements(
tmpl_attr(
vpt)) == 0) {
1190 if (tmpl_attr_list_num_elements(
tmpl_attr(
vpt)) == 0)
return;
1193 if (ref->ar_num == from) ref->ar_num = to;
1207 while ((ref = tmpl_attr_list_next(
tmpl_attr(
vpt), ref)))
if (ref->ar_num == from) ref->ar_num = to;
1223 tmpl_request_list_talloc_reverse_free(&
vpt->data.attribute.rr);
1268 STRINGIFY(
sizeof(attr))
" bytes, got %zu bytes", (
size_t)-slen);
1305 switch (ar->ar_num) {
1341 fr_sbuff_set_to_start(&our_name);
1349 fr_sbuff_next(&our_name);
1354 fr_sbuff_next(&our_name);
1359 fr_sbuff_next(&our_name);
1377 fr_sbuff_parse_rules_t p_rules;
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);
1440 t_rules.
attr = *at_rules;
1441 t_rules.
attr.namespace = ar->ar_da;
1443 p_rules = (fr_sbuff_parse_rules_t) {
1444 .terminals = &filter_terminals,
1473 static inline CC_HINT(
nonnull(3,4))
1526 static inline CC_HINT(
nonnull(3,6))
1549 slen = fr_sbuff_out_abstrncpy_allowed(ar, &unresolved,
1558 tmpl_attr_list_talloc_free_to_tail(
tmpl_attr(
vpt), ar_curr);
1571 .ar_unresolved = unresolved,
1572 .ar_unresolved_namespace =
namespace,
1616 .ar_parent = da->parent,
1662 fr_sbuff_marker(&m_s,
name);
1669 fr_sbuff_marker_release(&m_s);
1697 name, p_rules ? p_rules->terminals : NULL,
1708 our_parent = da->parent;
1710 if (!our_parent->flags.is_root) {
1731 p_rules ? p_rules->terminals : NULL);
1742 ar = tmpl_attr_list_tail(&
vpt->data.attribute.ar);
1749 p_rules ? p_rules->terminals : NULL);
1752 our_parent = internal_root;
1762 if (!da->flags.local && namespace->flags.local)
namespace = our_parent =
fr_dict_root(da->dict);
1768 if (da->parent != our_parent) {
1781 if (our_parent->flags.is_unknown)
break;
1812 our_parent =
namespace =
fr_dict_root(at_rules->dict_def);
1838 if (da)
goto alloc_ar;
1857 switch (namespace->type) {
1878 .ar_parent = our_parent,
1897 fr_sbuff_marker_release(&m_s);
1918 .ar_parent = our_parent,
1940 if (da->flags.local && (ar->ar_num > 0)) {
1952 fr_sbuff_marker_release(&m_s);
1953 fr_sbuff_marker(&m_s,
name);
1982 our_parent =
namespace = ref;
1985 our_parent =
namespace =
parent;
1988 our_parent =
namespace =
fr_dict_root(at_rules->dict_def);
1991 our_parent =
namespace = NULL;
2003 namespace = our_parent = da;
2014 "\"struct\", \"tlv\", \"vendor\", \"vsa\" or \"group\", got \"%s\"",
2025 tmpl_attr_list_talloc_free_tail(&
vpt->data.attribute.ar);
2050 fr_sbuff_marker_release(&m_s);
2097 fr_sbuff_parse_rules_t
const *p_rules,
2103 bool ref_prefix =
false;
2104 bool is_raw =
false;
2110 if (!t_rules) t_rules = &default_rules;
2111 at_rules = &t_rules->
attr;
2124 switch (at_rules->
prefix) {
2151 vpt->data.attribute.ref_prefix = ref_prefix;
2165 &
vpt->data.attribute.rr,
2177 fr_sbuff_marker(&m_l, &our_name);
2184 namespace,
namespace,
2185 &our_name, p_rules, at_rules, 0);
2186 if (ret < 0)
goto error;
2204 bool is_local = ar->ar_da->flags.local;
2208 if (!ar->ar_da->flags.local ||
2209 (ar->ar_da->flags.local && is_local))
continue;
2283 vpt->rules = *t_rules;
2292 if (t_rules->
attr.request_def) {
2332 fr_sbuff_set_to_start(&our_name);
2360 if (!t_rules) t_rules = &default_rules;
2362 name_len = strlen(
name);
2364 if (slen <= 0)
return slen;
2368 if (slen != name_len) {
2396 fr_sbuff_parse_rules_t
const *p_rules)
2413 cast, allow_enum ? t_rules->
enumv : NULL,
2414 &our_in, p_rules,
false) < 0) {
2444 fr_sbuff_parse_rules_t
const *p_rules)
2463 vpt->data.literal.vb_bool = a_bool;
2482 fr_sbuff_parse_rules_t
const *p_rules)
2522 MEM(bin = talloc_realloc_size(
vpt, bin, binlen));
2541 fr_sbuff_parse_rules_t
const *p_rules)
2609 fr_sbuff_parse_rules_t
const *p_rules)
2616 char *sep_a, *sep_b;
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,
2623 [
'A'] =
true, [
'B'] =
true, [
'C'] =
true, [
'D'] =
true, [
'E'] =
true,
2625 [
':'] =
true, [
'.'] =
true
2632 fr_sbuff_marker(&m, &our_in);
2652 if (sep_a && (!(sep_b = memchr(
fr_sbuff_current(&m),
':', len)) || (sep_b > sep_a))) {
2672 if ((len < 1) || (len > IFNAMSIZ)) {
2727 fr_sbuff_parse_rules_t
const *p_rules)
2776 memcpy(vb->vb_ether,
buff,
sizeof(vb->vb_ether));
2794 fr_sbuff_parse_rules_t
const *p_rules)
2808 if (slen <= 0)
return 0;
2819 if (a_int >= INT8_MIN) {
2821 vb->vb_int8 = (int8_t)a_int;
2822 }
else if (a_int >= INT16_MIN) {
2824 vb->vb_int16 = (int16_t)a_int;
2825 }
else if (a_int >= INT32_MIN) {
2827 vb->vb_int32 = (int32_t)a_int;
2830 vb->vb_int64 = (int64_t)a_int;
2839 if (slen <= 0)
return slen;
2851 vb->vb_uint8 = (
uint8_t)a_uint;
2852 }
else if (a_uint <= UINT16_MAX) {
2855 }
else if (a_uint <= UINT32_MAX) {
2860 vb->vb_uint64 = (uint64_t)a_uint;
2870 fr_sbuff_parse_rules_t
const *p_rules)
2879 if (slen <= 0)
return 0;
2890 vb->vb_float64 = a_float;
2898 fr_sbuff_parse_rules_t
const *p_rules)
2907 if (slen <= 0)
return 0;
2913 vb->vb_time_delta = a_delta;
2943 fr_sbuff_parse_rules_t
const *p_rules,
2954 }
else if (!t_rules->
enumv) {
2974 "'quoted literal', \"%{expansion}\", or enum value");
2993 if (t_rules->
enumv) {
3016 vpt->data.unescaped = str;
3051 fr_sbuff_parse_rules_t
const *p_rules,
3063 if (!t_rules) t_rules = &default_rules;
3104 t_rules,
true, p_rules);
3115 my_t_rules.
cast = my_t_rules.
enumv->type;
3136 if (slen > 0)
goto done_bareword;
3147 if (slen > 0)
goto done_bareword;
3154 if (slen > 0)
goto done_bareword;
3161 if (slen > 0)
goto done_bareword;
3165 if (slen > 0)
goto done_bareword;
3172 if (slen > 0)
goto done_bareword;
3179 if (slen > 0)
goto done_bareword;
3190 if (slen > 0)
goto done_bareword;
3198 if (slen > 0)
goto done_bareword;
3220 "'quoted literal', \"%{expansion}\", or enum value");
3238 vpt->data.unescaped = str;
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);
3257 vpt->data.unescaped = str;
3281 t_rules,
false, p_rules);
3294 vpt->data.unescaped = str;
3326 if ((slen <= 0) || !
head) {
3354 fr_sbuff_set_to_start(&our_in);
3376 vpt->data.unescaped = str;
3418 vpt->rules =
in->rules;
3440 vpt->data.reg_flags =
in->data.reg_flags;
3453 if (
unlikely(tmpl_regex_compile(
vpt,
vpt->data.reg.subcaptures) < 0))
goto error;
3513 fr_sbuff_marker(&m, &our_in);
3530 if (rules) rules->
cast = cast;
3567 switch (
vpt->type) {
3603 if (src_type == dst_type) {
3618 vpt->rules.cast = dst_type;
3640 slen = regex_flags_parse(&
err, &
vpt->data.reg_flags,
in, terminals,
true);
3673 static inline CC_HINT(always_inline)
3676 char const *unescaped,
size_t unescaped_len)
3687 switch (existing_quote) {
3690 return existing_quote;
3718 switch (
vpt->type) {
3721 char *unescaped =
vpt->data.unescaped;
3740 (
uint8_t const *)unescaped, talloc_array_length(unescaped) - 1,
3741 false) < 0)
return -1;
3745 unescaped, talloc_array_length(unescaped) - 1,
3746 NULL,
false) < 0)
return -1;
3750 unescaped, talloc_array_length(unescaped) - 1);
3835 dict_def =
vpt->rules.attr.dict_def;
3851 talloc_array_length(ar->ar_unresolved) - 1),
3854 vpt->rules.attr.allow_foreign);
3874 next->ar_parent = da;
3875 next->ar_unresolved_namespace = da;
3882 while ((ar = tmpl_attr_list_next(
tmpl_attr(
vpt), ar))) {
3906 talloc_array_length(ar->ar_unresolved) - 1),
3923 talloc_array_length(ar->ar_unresolved) - 1),
3939 fr_assert(ar->ar_parent && !ar->ar_parent->flags.is_unknown);
3947 next->ar_parent = da;
3948 next->ar_unresolved_namespace = da;
3961 ar->ar_parent = prev->ar_parent;
3988 static inline CC_HINT(always_inline)
3993 .tr_rules = tr_rules,
3994 .allow_unresolved = false
4027 if (!tr_rules) tr_rules = &default_tr_rules;
4041 fr_strerror_printf(
"mismatch between parse-time enumv '%s' and resolution-time enumv '%s'",
4065 if (ret < 0)
return ret;
4087 if (!enumv) enumv = tr_rules->
enumv;
4101 dst_type = enumv->type;
4143 switch (
vpt->type) {
4165 tmpl_request_list_talloc_free(&
vpt->data.attribute.rr);
4177 TALLOC_FREE(
vpt->data.xlat.ex);
4186 memcpy(
vpt, &tmp,
sizeof(*
vpt));
4230 switch (ref->
type) {
4236 ref->ar_unknown->flags.is_unknown = 1;
4282 if (
vpt->rules.at_runtime)
return 1;
4290 while ((ar = tmpl_attr_list_next(
tmpl_attr(
vpt), ar))) {
4306 unknown = ar->ar_unknown;
4308 if (!known)
return -1;
4316 (next->ar_da->parent == unknown)) {
4318 known) < 0)
return -1;
4319 next->ar_parent = known;
4380 if (!
vpt)
return -1;
4393 if (
type != da->type) {
4400 if (memcmp(flags, &da->flags,
sizeof(*flags)) != 0) {
4419 char *unescaped =
vpt->data.unescaped;
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;
4431 vpt->data.reg.src = unescaped;
4432 vpt->data.reg.subcaptures = subcaptures;
4454 rr = tmpl_request_list_next(rql, rr);
4490 switch (
vpt->type) {
4514 if (slen < 0)
return slen;
4531 while ((ar = tmpl_attr_list_next(
tmpl_attr(
vpt), ar))) {
4549 depth = ar->ar_parent->depth - 1;
4554 depth = ar->ar_parent->depth;
4575 for (i =
depth; (
unsigned int)i < ar->
ar_da->depth; i++) {
4593 unsigned int i,
depth;
4600 if (ar->ar_parent && !ar->ar_parent->flags.is_root) {
4602 if (ar->ar_parent->flags.is_root) {
4605 depth = ar->ar_parent->depth - 1;
4608 for (i =
depth; i < ar->ar_parent->depth; i++) {
4625 switch (ar->ar_num) {
4648 (void)
xlat_print(&our_out, ar->ar_cond, NULL);
4693 switch (
vpt->type) {
4714 fr_sbuff_terminate(
out);
4740 fr_sbuff_terminate(
out);
4789 #ifdef WITH_VERIFY_PTR
4802 for (i = 0; i < len; i++) {
4803 if (ptr[i] != 0x00)
return ptr + i;
4812 #define CHECK_ZEROED(_vpt, _field) is_zeroed(((uint8_t const *)&(_vpt)->data) + sizeof((_vpt)->data._field), sizeof((_vpt)->data) - sizeof((_vpt)->data._field))
4818 #define PRINT_NON_ZEROED(_vpt, _field, _nz_ptr) \
4820 DEBUG("Expected live portion %p-%p (0-%zu)", \
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", ""); \
4852 while ((slow = tmpl_attr_list_next(
tmpl_attr(
vpt), slow)) &&
4860 "CONSISTENCY CHECK FAILED %s[%u]: Looping reference list found. "
4861 "Fast pointer hit slow pointer at \"%s\"",
4864 slow->
da ? slow->
da->name :
"(null-attr)");
4879 "TMPL_TYPE_ATTR known attribute \"%s\" "
4880 "occurred after unknown attribute %s "
4884 ar->unknown.
da->name);
4886 if (seen_unresolved) {
4889 "TMPL_TYPE_ATTR known attribute \"%s\" "
4890 "occurred after unresolved attribute \"%s\""
4897 "CONSISTENCY CHECK FAILED %s[%u]: attr ref missing parent",
4905 "TMPL_TYPE_ATTR unspecified attribute "
4906 "occurred after unknown attribute %s "
4909 ar->unknown.
da->name);
4911 if (seen_unresolved) {
4914 "TMPL_TYPE_ATTR unspecified attribute "
4915 "occurred after unresolved attribute \"%s\""
4923 seen_unresolved = ar;
4925 "CONSISTENCY CHECK FAILED %s[%u]: unresolved attr ref missing namespace",
4931 if (seen_unresolved) {
4934 "TMPL_TYPE_ATTR unknown attribute \"%s\" "
4935 "occurred after unresolved attribute %s "
4961 "TMPL_TYPE_UNINITIALISED (uninitialised)",
file,
line);
4966 "(outside range of tmpl_type_table)",
file,
line,
vpt->type);
4972 fr_fatal_assert_fail(
"CONSISTENCY CHECK FAILED %s[%u]: Quote type '%c' (%i) was set for NULL name",
4977 fr_fatal_assert_fail(
"CONSISTENCY CHECK FAILED %s[%u]: No quoting type was set for name \"%.*s\"",
4989 switch (
vpt->type) {
4991 if ((nz = is_zeroed((
uint8_t const *)&
vpt->data,
sizeof(
vpt->data)))) {
4993 nz - (
uint8_t const *)&
vpt->data,
"non-zero memory",
"");
4995 "has non-zero bytes in its data union",
file,
line);
5000 if (!
vpt->data.unescaped) {
5002 "unescaped field is NULL",
file,
line);
5007 if (!
vpt->data.xlat.ex) {
5009 "has a NULL xlat.ex field",
file,
line);
5015 "does not have 'needs resolving' flag set",
file,
line);
5020 if (!
vpt->data.xlat.ex) {
5022 "has a NULL xlat.ex field",
file,
line);
5049 if ((tmpl_attr_list_num_elements(
tmpl_attr(
vpt)) > 0) &&
5060 if ((nz = CHECK_ZEROED(
vpt, attribute))) {
5061 PRINT_NON_ZEROED(
vpt, attribute, nz);
5063 "has non-zero bytes after the data.attribute struct in the union",
5075 "da is marked as unknown, but address is not equal to the template's "
5091 "attribute \"%s\" (%s) not rooted in a dictionary",
5099 "dictionary pointer %p \"%s\" (%s) "
5100 "and global dictionary pointer %p \"%s\" (%s) differ",
5113 if ((nz = CHECK_ZEROED(
vpt, literal))) {
5114 PRINT_NON_ZEROED(
vpt, literal, nz);
5116 "has non-zero bytes after the data.literal struct in the union",
5122 "FR_TYPE_NULL (uninitialised)",
file,
line);
5155 fr_fatal_assert_fail(
"CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_XLAT_UNRESOLVED - No regex support",
5162 if (tmpl_regex(
vpt) == NULL) {
5164 "reg.ex field was NULL",
file,
line);
5181 #define return_P(_x) fr_strerror_const(_x);goto return_p
5206 fr_dict_attr_t const **castda,
bool require_regex,
bool allow_xlat)
5214 if (castda) *castda = NULL;
5216 while (isspace((
uint8_t) *p) && (p < end)) p++;
5217 if (p >= end)
return p -
in;
5232 for (q = p; *q && !isspace((
uint8_t) *q) && (*q !=
'>'); q++) {
5246 return_P(
"Forbidden data type in cast");
5251 return_P(
"Cannot cast to this data type");
5264 if (require_regex) {
5265 if (castda && *castda) {
5267 return_P(
"Invalid cast before regular expression");
5281 return_P(
"Expected regular expression");
5294 if ((p[1] !=
'{') && (p[1] !=
'(')) {
5302 while ((q < end) && (isalnum((
int) *q) || (*q ==
'.') || (*q ==
'_') || (*q ==
'-'))) {
5308 return_P(
"Invalid character after '%'");
5331 close = (p[1] ==
'{') ?
'}' :
')';
5345 if ((*p ==
'}') || (*p ==
')')) {
5346 bool match = (*p ==
close);
5354 *outlen = p - (*out);
5363 return_P(
"End of string after escape");
5370 if ((p[0] ==
'%') && ((p[1] ==
'{') || (p[1] ==
'('))) {
5372 return_P(
"End of string after expansion");
5383 if ((*p ==
'{') || (*p ==
'(')) {
5397 return_P(
"Unterminated expansion");
5400 if (!require_regex)
goto bare_word;
5438 *outlen = p - (*out);
5446 return_P(
"End of string after escape");
5488 }
else if ((p[1] ==
'E') &&
5542 if ((*p ==
'-') || (*p ==
':')) {
5543 if (p[1] ==
'=')
break;
5552 if ((*p ==
'.') || (*p ==
'/') || (*p ==
'_') || (*p ==
'*') ||
5553 (*p ==
']') || (*p ==
'@')) {
5561 if ((p ==
in) && (*p ==
'[')) {
5569 if (((*p >=
'a') && (*p <=
'z')) ||
5570 ((*p >=
'A') && (*p <=
'Z')) ||
5571 ((*p >=
'0') && (*p <=
'9'))) {
5579 if (*(
uint8_t const *)p > 0x80) {
5596 if ((*p ==
'#') || (*p ==
'*') || (*p ==
'n')) {
5603 while ((*p >=
'0') && (*p <=
'9')) {
5608 return_P(
"Array index is not an integer");
5631 if ((*p ==
'"') || (*p ==
'\'') || (*p ==
'`')) {
5632 return_P(
"Unexpected start of string");
5636 return_P(
"Empty string is invalid");
5639 *outlen = p - (*out);
5655 switch (
vpt->type) {
5696 if (
vpt->rules.attr.request_def) {
5706 out->attr.namespace = da;
5717 if ((
dict !=
internal) && (
dict !=
out->attr.dict_def)) {
5719 out->attr.namespace = ref;
5734 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...
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
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.
static fr_dict_attr_t * fr_dict_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
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.
bool const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters that are allowed in dictionary attribute names.
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.
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.
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_t const * fr_dict_by_da(fr_dict_attr_t const *da)
Attempt to locate the protocol dictionary containing an attribute.
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_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.
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.
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
fr_dict_t const * fr_dict_internal(void)
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
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.
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)
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.
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
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.
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_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]
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_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)
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
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_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.
#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.
static fr_slen_t ar_prefix
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
#define tmpl_contains_xlat(vpt)
#define TMPL_VERIFY(_vpt)
#define tmpl_value_length(_tmpl)
#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)
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.
#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)
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
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_attr_tail_unknown(tmpl_t const *vpt)
Return the last attribute reference unknown da.
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.
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 char const * tmpl_attr_tail_unresolved(tmpl_t const *vpt)
Return the last attribute reference unresolved 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.
#define tmpl_is_regex(vpt)
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
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
#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_INDEX
Filter is an index type.
@ TMPL_ATTR_FILTER_TYPE_CONDITION
Filter is a condition.
@ TMPL_ATTR_FILTER_TYPE_NONE
No filter present.
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)
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
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)
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.
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.
#define fr_table_value_by_substr(_table, _name, _name_len, _def)
Convert a partial string to a value using an ordered or sorted table.
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_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
#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)
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.
#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
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.
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.
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[]
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.
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)
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_structural[FR_TYPE_MAX+1]
#define fr_type_is_non_leaf(_x)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
#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)
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]
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.
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