27RCSID(
"$Id: 3e86bea42c69733947f6311ec47e4af7f2932485 $")
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/unlang/xlat_priv.h>
31#include <freeradius-devel/util/calc.h>
32#include <freeradius-devel/server/tmpl_dcursor.h>
33#include <freeradius-devel/unlang/xlat_func.h>
37# define XLAT_DEBUG(_fmt, ...) DEBUG3("%s[%i] "_fmt, __FILE__, __LINE__, ##__VA_ARGS__)
39# define XLAT_DEBUG(...)
98 talloc_steal(group->group, node);
311 a = fr_value_box_list_head(
in);
312 b = fr_value_box_list_next(
in, a);
321 if (fr_value_box_list_num_elements(&a->vb_group) > 1) {
322 REDEBUG(
"Expected one value as the first argument, got %u",
323 fr_value_box_list_num_elements(&a->vb_group));
326 a = fr_value_box_list_head(&a->vb_group);
328 if (fr_value_box_list_num_elements(&b->vb_group) > 1) {
329 REDEBUG(
"Expected one value as the second argument, got %u",
330 fr_value_box_list_num_elements(&b->vb_group));
333 b = fr_value_box_list_head(&b->vb_group);
355 if (enumv) dst->enumv = enumv;
362#define XLAT_BINARY_FUNC(_name, _op) \
363static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
364 xlat_ctx_t const *xctx, \
365 request_t *request, fr_value_box_list_t *in) \
367 return xlat_binary_op(ctx, out, xctx, request, in, _op, FR_TYPE_NULL, NULL); \
398 a = fr_value_box_list_head(
in);
399 b = fr_value_box_list_next(
in, a);
425#define XLAT_CMP_FUNC(_name, _op) \
426static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
427 xlat_ctx_t const *xctx, \
428 request_t *request, fr_value_box_list_t *in) \
430 return xlat_cmp_op(ctx, out, xctx, request, in, _op); \
508 inst->op = xctx->
ex->call.func->token;
509 inst->regex_flags = tmpl_regex_flags(regex->vpt);
511 inst->xlat = talloc_steal(
inst, regex);
531 inst->regex = tmpl_regex(regex->vpt);
601 fr_regmatch_t *regmatch;
610 arg = fr_value_box_list_head(
in);
614 subcaptures = regex_subcapture_count(*preg);
615 if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1;
616 MEM(regmatch = regex_match_data_alloc(NULL, subcaptures));
618 while ((vb = fr_value_box_list_pop_head(&arg->vb_group)) != NULL) {
620 subject = vb->vb_strvalue;
624 fr_value_box_list_t list;
626 fr_value_box_list_init(&list);
627 fr_value_box_list_insert_head(&list, vb);
635 RPEDEBUG(
"Failed concatenating regular expression string");
647 ret = regex_exec(*preg, subject, len, regmatch);
656 regex_sub_to_request(request, NULL, NULL);
660 regex_sub_to_request(request, preg, ®match);
687 regex_t *preg = NULL;
707 RPEDEBUG(
"Failed concatenating regular expression string");
714 tmpl_regex_flags(
inst->xlat->vpt),
true,
true);
733 preg = tmpl_regex(
inst->xlat->vpt);
739 fr_value_box_list_init(&rctx->
list);
753#define XLAT_REGEX_FUNC(_name, _op) \
754static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
755 xlat_ctx_t const *xctx, \
756 request_t *request, fr_value_box_list_t *in) \
758 return xlat_regex_op(ctx, out, xctx, request, in, _op); \
791 head = node->call.args;
806 for (i = 0; i <
inst->argc; i++) {
808 if (i == (
inst->argc - 1))
break;
832 if (!
head->flags.pure)
return false;
862 if (!*result)
return true;
870 talloc_free_children(
parent);
892 (void) talloc_steal(
head, node);
918 for (i = 0; i <
inst->argc; i++) {
923 if (
inst->argv[i]->flags.can_purify) {
947 if (result)
return 0;
953 if (((i + 1) ==
inst->argc) && (deleted == i))
break;
955 TALLOC_FREE(
inst->argv[i]);
959 if (!deleted)
return 0;
967 while (i < (
inst->argc - deleted)) {
976 if (j < 0) j = i + 1;
982 while (j < inst->argc) {
983 if (
inst->argv[j])
break;
991 inst->argv[j++] = NULL;
994 inst->argc -= deleted;
996 if (
inst->argc > 1)
return 0;
1001 group =
inst->argv[0];
1003 talloc_steal(node, group);
1016 node->group = group;
1075 if (!fr_value_box_list_num_elements(
in))
return false;
1136 if (match)
goto done;
1138 fr_value_box_list_talloc_free(&rctx->
list);
1177 if (!fr_value_box_list_num_elements(
in))
return false;
1205 if (!found)
return false;
1246 fr_value_box_list_talloc_free(&rctx->
list);
1277 if (xctx->
ex->call.func->token ==
T_LOR) {
1279 inst->stop_on_match =
true;
1282 inst->stop_on_match =
false;
1303 if (
inst->stop_on_match) {
1307 rctx->
box->vb_bool =
true;
1309 fr_value_box_list_init(&rctx->
list);
1318 { .
required =
true, .single =
true, .concat =
true },
1332 group = fr_value_box_list_head(
in);
1333 vb = fr_value_box_list_head(&group->vb_group);
1372 group = fr_value_box_list_head(
in);
1373 vb = fr_value_box_list_head(&group->vb_group);
1384 dst->vb_bool =
true;
1428 if (!node)
continue;
1436 node->
quote, NULL, NULL);
1437 if (slen <= 0)
continue;
1438 if ((
size_t) slen < node->
data.vb_length)
continue;
1493 rcode = &rcode_arg->data;
1495 switch (rcode->type) {
1500 ERROR(
"Unknown rcode '%pV'", rcode);
1515 ERROR(
"Invalid value for rcode '%pV'", rcode);
1522 inst->rcode = rcode->vb_uint8;
1550 if (slen < 0)
return slen;
1587 if (fr_value_box_list_num_elements(
args) == 0) {
1589 rcode =
inst->rcode;
1594 REDEBUG(
"Invalid rcode '%pV'", arg_rcode);
1599 RDEBUG3(
"Request rcode is '%s'",
1604 vb->vb_bool = (request->rcode == rcode);
1690 inst->xlat = talloc_steal(
inst, arg->group);
1697 inst->vpt = xlat->vpt;
1714 dst->vb_bool = (
vp != NULL);
1750 RPEDEBUG(
"Failed concatenating attribute name string");
1754 vb = fr_value_box_list_head(&rctx->
list);
1759 .dict_def = request->dict,
1760 .request_def = &tmpl_request_def_current,
1761 .list_def = request_attr_request,
1762 .prefix = TMPL_ATTR_REF_PREFIX_AUTO,
1763 .allow_unknown = false,
1764 .allow_unresolved = false,
1767 if (slen <= 0)
goto fail;
1803 fr_value_box_list_init(&rctx->
list);
1817#undef XLAT_REGISTER_BINARY_OP
1818#define XLAT_REGISTER_BINARY_OP(_op, _name) \
1820 if (unlikely((xlat = xlat_func_register(NULL, "op_" STRINGIFY(_name), xlat_func_op_ ## _name, FR_TYPE_VOID)) == NULL)) return -1; \
1821 xlat_func_args_set(xlat, binary_op_xlat_args); \
1822 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1823 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1824 xlat_func_instantiate_set(xlat, xlat_function_args_to_tmpl, NULL, NULL, NULL); \
1825 xlat->token = _op; \
1828#undef XLAT_REGISTER_BINARY_CMP
1829#define XLAT_REGISTER_BINARY_CMP(_op, _name) \
1831 if (unlikely((xlat = xlat_func_register(NULL, "cmp_" STRINGIFY(_name), xlat_func_cmp_ ## _name, FR_TYPE_BOOL)) == NULL)) return -1; \
1832 xlat_func_args_set(xlat, binary_cmp_xlat_args); \
1833 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1834 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1835 xlat_func_resolve_set(xlat, xlat_expr_resolve_binary); \
1836 xlat->token = _op; \
1839#undef XLAT_REGISTER_NARY_OP
1840#define XLAT_REGISTER_NARY_OP(_op, _name, _func_name) \
1842 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _func_name, FR_TYPE_VOID)) == NULL)) return -1; \
1843 xlat_func_instantiate_set(xlat, xlat_instantiate_ ## _func_name, xlat_ ## _func_name ## _inst_t, NULL, NULL); \
1844 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1845 xlat_func_print_set(xlat, xlat_expr_print_nary); \
1846 xlat_purify_func_set(xlat, xlat_expr_logical_purify); \
1847 xlat->token = _op; \
1850#undef XLAT_REGISTER_REGEX_OP
1851#define XLAT_REGISTER_REGEX_OP(_op, _name) \
1853 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _name, FR_TYPE_VOID)) == NULL)) return -1; \
1854 xlat_func_args_set(xlat, regex_op_xlat_args); \
1855 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1856 xlat_func_instantiate_set(xlat, xlat_instantiate_regex, xlat_regex_inst_t, NULL, NULL); \
1857 xlat_func_print_set(xlat, xlat_expr_print_regex); \
1858 xlat->token = _op; \
1861#define XLAT_REGISTER_BOOL(_xlat, _func, _arg, _ret_type) \
1863 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, _ret_type)) == NULL)) return -1; \
1864 xlat_func_args_set(xlat, _arg); \
1865 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
1868#define XLAT_REGISTER_UNARY(_op, _xlat, _func) \
1870 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, FR_TYPE_VOID)) == NULL)) return -1; \
1871 xlat_func_args_set(xlat, unary_op_xlat_args); \
1872 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1873 xlat_func_print_set(xlat, xlat_expr_print_unary); \
1874 xlat->token = _op; \
1947 [
T_OR ] =
L(
"op_or"),
1952 [
T_LAND ] =
L(
"logical_and"),
1953 [
T_LOR ] =
L(
"logical_or"),
1991#define P(_x, _y) (((_x) << 4) | (_y))
2047#define fr_sbuff_skip_whitespace(_x) \
2049 while (isspace((uint8_t) fr_sbuff_char(_x, '\0'))) fr_sbuff_advance(_x, 1); \
2053 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2054 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2055 fr_sbuff_parse_rules_t
const *input_rules,
bool cond);
2058 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2059 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond);
2084 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2085 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2103 goto check_for_double;
2117 goto check_for_double;
2124 goto check_for_double;
2154 unary->call.func = func;
2156 unary->flags = func->
flags;
2159 if (
tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, out_c, (c ==
'!')) < 0) {
2170 unary->flags.can_purify = (unary->call.func->flags.pure && unary->call.args->flags.pure) | unary->call.args->flags.can_purify;
2215 node->data.vb_uint8 =
type;
2234 fr_sbuff_marker(&m, &our_in);
2264 fr_sbuff_parse_rules_t
const *bracket_rules)
2280 fr_sbuff_marker(&opand_m, &our_in);
2289 if (!fr_sbuff_is_str(&our_in,
"m'", 2)) {
2329 fr_sbuff_marker(&flag, &our_in);
2330 if (tmpl_regex_flags_substr(
vpt, &our_in, bracket_rules->terminals) < 0) {
2342 slen = tmpl_regex_compile(
vpt,
true);
2343 if (slen <= 0)
goto error;
2347 node->
quote = quote;
2368 if (slen <= 0)
return 0;
2377 node->call.func = func;
2406 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2407 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2439 our_t_rules.
enumv = NULL;
2474 our_t_rules.
cast = cast_type;
2475 our_t_rules.
enumv = NULL;
2481 fr_sbuff_marker(&opand_m, &our_in);
2488 p_rules = bracket_rules;
2531 if ((p[0] == c) && (p[1] == c)) {
2578 }
while (--triple > 0);
2601 p =
vpt->name + talloc_array_length(
vpt->name) - 2;
2604 fr_strerror_const(
"Alternation is no longer supported. Use '%{a || b}' instead of '%{a:-b}'");
2635 if (da && (da->type == cast_type)) {
2684 node->
quote = quote;
2705 if (
vpt->name[0] ==
'%') {
2777#ifdef STATIC_ANALYZER
2778 if (!node)
return false;
2813 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2814 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2815 fr_sbuff_parse_rules_t
const *input_rules,
bool cond)
2829 fr_sbuff_marker(&m_lhs, &our_in);
2834 slen =
tokenize_unary(
head, &lhs, &our_in, p_rules, t_rules, bracket_rules, &c, cond);
2846#ifdef STATIC_ANALYZER
2871 if (!bracket_rules) {
2888 fr_sbuff_marker(&m_op, &our_in);
2928 if (((c ==
'!') || (c ==
'~')) && (op !=
T_LAND) && (op !=
T_LOR)) {
2929 fr_strerror_printf(
"Operator '%c' is only applied to the left hand side of the '%s' operation, add (..) to evaluate the operation first", c,
fr_tokens[op]);
2936 fr_sbuff_marker(&m_rhs, &our_in);
2971#ifdef STATIC_ANALYZER
2972 if (!rhs)
return -1;
2979 if ((lhs->
type ==
XLAT_FUNC) && (lhs->call.func->token == op)) {
2982 lhs->call.args->
flags.
can_purify |= rhs->flags.can_purify | rhs->flags.pure;
3016 if (rcode < 0)
goto fail_lhs;
3029 node->call.func = func;
3031 node->flags = func->
flags;
3044 node->call.args->flags.can_purify |= arg->flags.can_purify | arg->flags.pure;
3045 if (node->call.args->flags.can_purify)
break;
3047 node->flags.can_purify = node->call.args->flags.can_purify;
3050 node->flags.can_purify = (node->call.func->flags.pure && node->call.args->flags.pure) | node->call.args->flags.can_purify;
3083 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
bool cond)
3086 fr_sbuff_parse_rules_t *bracket_rules = NULL;
3087 fr_sbuff_parse_rules_t *terminal_rules = NULL;
3097 MEM(bracket_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3098 MEM(terminal_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3100 *bracket_rules = *p_rules;
3101 *terminal_rules = *p_rules;
3103 if (p_rules->terminals) {
3114 terminal_rules->terminals,
3118 if (!t_rules) t_rules = &my_rules;
3166 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3172 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3196 if (!
head->flags.pure)
goto return_false;
#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
int fr_value_calc_list_cmp(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_list_t const *list1, fr_token_t op, fr_value_box_list_t const *list2)
int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Calculate DST = A OP B.
int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
Calculate unary operations.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
fr_dict_t const * fr_dict_internal(void)
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static xlat_action_t xlat_func_rcode(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *args)
Return the current rcode as a string.
static xlat_action_t xlat_func_exists(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
See if a named attribute exists.
static xlat_action_t xlat_func_expr_rcode(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Match the passed rcode against request->rcode.
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
#define RPEDEBUG(fmt,...)
@ TMPL_ATTR_REF_PREFIX_NO
Attribute refs have no '&' prefix.
@ TMPL_ATTR_REF_PREFIX_YES
Attribute refs must have '&' prefix.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_STRING
String of printable characters.
@ 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_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
#define check(_handle, _len_p)
fr_table_num_sorted_t const rcode_table[]
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
fr_sbuff_term_t * fr_sbuff_terminals_amerge(TALLOC_CTX *ctx, fr_sbuff_term_t const *a, fr_sbuff_term_t const *b)
Merge two sets of terminal strings.
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_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define fr_sbuff_diff(_a, _b)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
#define fr_sbuff_current(_sbuff_or_marker)
#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_used_total(_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_is_digit(_sbuff_or_marker)
#define SBUFF_CHAR_UNPRINTABLES_EXTENDED
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define SBUFF_CHAR_UNPRINTABLES_LOW
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_IN_STRCPY_RETURN(...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Terminal element with pre-calculated lengths.
Set of terminal elements.
#define tmpl_contains_xlat(vpt)
#define tmpl_is_attr_unresolved(vpt)
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules))
Attempt to resolve functions and attributes in xlats and attribute references.
#define tmpl_value(_tmpl)
int tmpl_attr_unknown_add(tmpl_t *vpt)
Add an unknown fr_dict_attr_t specified by a tmpl_t to the main dictionary.
#define tmpl_contains_regex(vpt)
#define tmpl_is_attr(vpt)
fr_dict_attr_t const * enumv
Enumeration attribute used to resolve enum values.
#define tmpl_value_enumv(_tmpl)
#define tmpl_rules_cast(_tmpl)
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, char const *name, tmpl_rules_t const *rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
#define tmpl_contains_attr(vpt)
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
tmpl_xlat_rules_t xlat
Rules/data for parsing xlats.
static bool tmpl_is_list(tmpl_t const *vpt)
int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv))
Convert tmpl_t of type TMPL_TYPE_DATA_UNRESOLVED or TMPL_TYPE_DATA to TMPL_TYPE_DATA of type specifie...
#define tmpl_is_data(vpt)
#define tmpl_value_type(_tmpl)
#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.
struct tmpl_res_rules_s tmpl_res_rules_t
#define tmpl_is_regex(vpt)
fr_dict_attr_t const * enumv
for resolving T_BARE_WORD
fr_event_list_t * runtime_el
The eventlist to use for runtime instantiation of xlats.
#define tmpl_needs_resolving(vpt)
int tmpl_cast_set(tmpl_t *vpt, fr_type_t type)
Set a cast for a tmpl.
Similar to tmpl_rules_t, but used to specify parameters that may change during subsequent resolution ...
Optional arguments passed to vp_tmpl functions.
static void xor(char *out, char *in1, char *in2, int n)
static void lshift(char *d, int count, int n)
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Stores an attribute, a value and various bits of other data.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
#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.
#define talloc_get_type_abort_const
static int talloc_const_free(void const *ptr)
Free const'd memory.
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
#define tmpl_dcursor_init(_err, _ctx, _cc, _cursor, _request, _vpt)
Maintains state between cursor calls.
const char fr_token_quote[T_TOKEN_LAST]
Convert tokens back to a quoting character.
char const * fr_tokens[T_TOKEN_LAST]
const bool fr_comparison_op[T_TOKEN_LAST]
const bool fr_binary_op[T_TOKEN_LAST]
@ T_SOLIDUS_QUOTED_STRING
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
tmpl_res_rules_t const * tr_rules
tmpl resolution rules.
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 required
Argument must be present, and non-empty.
int xlat_flatten_compiled_argv(TALLOC_CTX *ctx, xlat_exp_head_t ***argv, xlat_exp_head_t *head)
Turn xlat_tokenize_argv() into an argv[] array, and nuke the input list.
bool concat
Concat boxes together.
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 can_purify
if the xlat has a pure function with pure arguments.
int xlat_purify_op(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_exp_t *lhs, fr_token_t op, xlat_exp_t *rhs)
xlat_action_t(* xlat_func_t)(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
xlat callback function
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
bool pure
has no external side effects, true for BOX, LITERAL, and some functions
bool needs_resolving
Needs pass2 resolution.
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.
#define XLAT_ARG_PARSER_TERMINATOR
int xlat_finalize(xlat_exp_head_t *head, fr_event_list_t *runtime_el)
Bootstrap static xlats, or instantiate ephemeral ones.
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
bool constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
bool impure_func
xlat contains an impure function
int xlat_instance_unregister_func(xlat_exp_t *node)
Remove a node from the list of xlat instance data.
Definition for a single argument consumend by an xlat function.
Flags that control resolution and evaluation.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
#define fr_type_is_variable_size(_x)
#define fr_type_is_structural(_x)
#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.
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
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.
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
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.
fr_sbuff_parse_rules_t const * value_parse_rules_3quoted[T_TOKEN_LAST]
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
ssize_t fr_value_box_list_concat_as_string(bool *tainted, bool *secret, fr_sbuff_t *sbuff, fr_value_box_list_t *list, char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules, fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
Concatenate a list of value boxes together.
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
#define fr_box_strvalue_len(_val, _len)
#define fr_box_is_group(_x)
#define VALUE_BOX_LIST_VERIFY(_x)
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
#define fr_value_box_list_foreach(_list_head, _iter)
static size_t char ** out
void xlat_exp_set_name(xlat_exp_t *node, char const *fmt, size_t len)
Set the format string for an xlat node.
void xlat_exp_set_name_buffer_shallow(xlat_exp_t *node, char const *fmt)
Set the format string for an xlat node from a pre-existing buffer.
void * rctx
Resume context.
xlat_exp_t * ex
Tokenized expression to use in expansion.
void const * inst
xlat instance data.
void * inst
xlat instance data to populate.
An xlat instantiation ctx.
fr_dict_attr_t const * attr_expr_bool_enum
fr_dict_attr_t const * attr_cast_base
static const fr_sbuff_escape_rules_t regex_escape_rules
tmpl_t const * vpt
the attribute reference
#define fr_sbuff_skip_whitespace(_x)
static size_t const expr_assignment_op_table_len
static fr_slen_t xlat_expr_print_binary(fr_sbuff_t *out, xlat_exp_t const *node, UNUSED void *inst, fr_sbuff_escape_rules_t const *e_rules)
#define XLAT_REGISTER_BOOL(_xlat, _func, _arg, _ret_type)
static fr_slen_t xlat_expr_print_rcode(fr_sbuff_t *out, xlat_exp_t const *node, void *instance, UNUSED fr_sbuff_escape_rules_t const *e_rules)
static xlat_action_t xlat_regex_match(TALLOC_CTX *ctx, request_t *request, fr_value_box_list_t *in, regex_t **preg, fr_dcursor_t *out, fr_token_t op)
Perform a regular expressions comparison between two operands.
static void xlat_func_append_arg(xlat_exp_t *head, xlat_exp_t *node, bool exists)
bool xlat_is_truthy(xlat_exp_head_t const *head, bool *out)
Allow callers to see if an xlat is truthy.
static xlat_action_t xlat_func_logical(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Process logical &&, ||.
xlat_exp_t * xlat
to expand
#define XLAT_BINARY_FUNC(_name, _op)
static const fr_sbuff_term_t bracket_terms
static fr_slen_t tokenize_unary(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_sbuff_parse_rules_t const *bracket_rules, char *out_c, bool cond)
bool tmpl_require_enum_prefix
static size_t expr_quote_table_len
static xlat_action_t xlat_exists_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
static int xlat_instantiate_exists(xlat_inst_ctx_t const *xctx)
static fr_slen_t xlat_expr_print_nary(fr_sbuff_t *out, xlat_exp_t const *node, void *instance, fr_sbuff_escape_rules_t const *e_rules)
int xlat_register_expressions(void)
xlat_exp_head_t * xlat
the xlat which needs expanding
static xlat_arg_parser_t const xlat_func_exists_arg[]
static xlat_action_t xlat_logical_process_arg(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Process one argument of a logical operation.
static fr_slen_t xlat_tokenize_expression_internal(TALLOC_CTX *ctx, xlat_exp_head_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, bool cond)
static int xlat_function_args_to_tmpl(xlat_inst_ctx_t const *xctx)
Convert XLAT_BOX arguments to XLAT_TMPL.
static fr_slen_t xlat_expr_print_unary(fr_sbuff_t *out, xlat_exp_t const *node, UNUSED void *inst, fr_sbuff_escape_rules_t const *e_rules)
static xlat_arg_parser_t const regex_op_xlat_args[]
static void xlat_ungroup(xlat_exp_head_t *head)
Undo work which shouldn't have been done.
static xlat_action_t xlat_func_unary_complement(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static xlat_action_t xlat_cmp_op(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in, fr_token_t op)
static const int precedence[T_TOKEN_LAST]
static xlat_action_t xlat_func_unary_minus(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static xlat_action_t xlat_logical_or_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static fr_table_num_sorted_t const expr_quote_table[]
#define XLAT_REGISTER_BINARY_OP(_op, _name)
#define XLAT_REGEX_FUNC(_name, _op)
static fr_slen_t tokenize_rcode(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in)
static xlat_action_t xlat_binary_op(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in, fr_token_t op, fr_type_t default_type, fr_dict_attr_t const *enumv)
static bool valid_type(xlat_exp_t *node)
static xlat_exp_t * expr_cast_alloc(TALLOC_CTX *ctx, fr_type_t type)
Allocate a specific cast node.
static bool xlat_logical_and(xlat_logical_rctx_t *rctx, fr_value_box_list_t const *in)
See if the input is truthy or not.
fr_value_box_t * box
output value-box
static xlat_action_t xlat_regex_op(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in, fr_token_t op)
static xlat_action_t xlat_func_unary_not(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
fr_regex_flags_t * regex_flags
static bool xlat_node_matches_bool(bool *result, xlat_exp_t *parent, xlat_exp_head_t *head, bool sense)
static int xlat_instantiate_regex(xlat_inst_ctx_t const *xctx)
static xlat_action_t xlat_func_unary_op(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in, fr_token_t op)
static int xlat_expr_resolve_binary(xlat_exp_t *node, UNUSED void *inst, xlat_res_rules_t const *xr_rules)
static const bool logical_ops[T_TOKEN_LAST]
static xlat_arg_parser_t const binary_op_xlat_args[]
static xlat_action_t xlat_attr_exists(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, tmpl_t const *vpt, bool do_free)
static xlat_arg_parser_t const binary_cmp_xlat_args[]
static const bool multivalue_ops[T_TOKEN_LAST]
static const fr_sbuff_term_elem_t binary_ops[T_TOKEN_LAST]
static bool xlat_logical_or(xlat_logical_rctx_t *rctx, fr_value_box_list_t const *in)
See if the input is truthy or not.
regex_t * regex
precompiled regex
#define XLAT_REGISTER_NARY_OP(_op, _name, _func_name)
static int xlat_instantiate_expr_rcode(xlat_inst_ctx_t const *xctx)
Convert static expr_rcode arguments into rcodes.
static void fr_value_box_init_zero(fr_value_box_t *vb, fr_type_t type)
static xlat_action_t xlat_regex_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static fr_table_num_ordered_t const expr_assignment_op_table[]
static xlat_exp_t * xlat_exists_alloc(TALLOC_CTX *ctx, xlat_exp_t *child)
Allocate a specific cast node.
static fr_slen_t expr_cast_from_substr(fr_type_t *cast, fr_sbuff_t *in)
#define XLAT_REGISTER_BINARY_CMP(_op, _name)
static xlat_arg_parser_t const xlat_func_rcode_arg[]
Takes no arguments.
static int xlat_expr_logical_purify(xlat_exp_t *node, void *instance, request_t *request)
If any argument resolves to inst->stop_on_match, the entire thing is a bool of inst->stop_on_match.
rlm_rcode_t rcode
The preparsed rcode.
static fr_slen_t xlat_expr_print_exists(fr_sbuff_t *out, xlat_exp_t const *node, void *instance, fr_sbuff_escape_rules_t const *e_rules)
static int xlat_instantiate_logical(xlat_inst_ctx_t const *xctx)
#define XLAT_REGISTER_UNARY(_op, _xlat, _func)
static xlat_arg_parser_t const unary_op_xlat_args[]
fr_slen_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
static xlat_arg_parser_t const xlat_func_expr_rcode_arg[]
static fr_slen_t tokenize_regex_rhs(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, tmpl_rules_t const *t_rules, fr_sbuff_parse_rules_t const *bracket_rules)
static fr_slen_t xlat_expr_print_regex(fr_sbuff_t *out, xlat_exp_t const *node, void *instance, fr_sbuff_escape_rules_t const *e_rules)
static const fr_sbuff_term_t operator_terms
#define XLAT_REGISTER_REGEX_OP(_op, _name)
static xlat_action_t xlat_logical_and_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static ssize_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_sbuff_parse_rules_t const *bracket_rules, char *out_c, bool cond)
static ssize_t tokenize_expression(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_token_t prev, fr_sbuff_parse_rules_t const *bracket_rules, fr_sbuff_parse_rules_t const *input_rules, bool cond)
Tokenize a mathematical operation.
#define XLAT_CMP_FUNC(_name, _op)
fr_slen_t xlat_tokenize_condition(TALLOC_CTX *ctx, xlat_exp_head_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
Holds the result of pre-parsing the rcode on startup.
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
void xlat_func_print_set(xlat_t *xlat, xlat_print_t func)
Set a print routine for an xlat function.
xlat_t * xlat_func_find(char const *in, ssize_t inlen)
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
@ XLAT_FUNC_FLAG_INTERNAL
#define xlat_exp_head_alloc(_ctx)
xlat_flags_t flags
Flags that control resolution and evaluation.
static xlat_exp_t * xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
xlat_flags_t flags
Flags that control resolution and evaluation.
fr_token_t quote
Type of quoting around XLAT_GROUP types.
@ XLAT_TMPL
xlat attribute
@ XLAT_GROUP
encapsulated string of xlats
static void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
Merge flags from child to parent.
#define xlat_exp_set_type(_node, _type)
fr_token_t token
for expressions
char const *_CONST fmt
The original format string (a talloced buffer).
ssize_t xlat_print_node(fr_sbuff_t *out, xlat_exp_head_t const *head, xlat_exp_t const *node, fr_sbuff_escape_rules_t const *e_rules, char c)
int xlat_purify_list(xlat_exp_head_t *head, request_t *request)
xlat_type_t _CONST type
type of this expansion.
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
xlat_flags_t flags
various flags
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)