26RCSID(
"$Id: f0fdccaac1d76ad07538a40959b7563e6c273ff3 $")
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/unlang/xlat_priv.h>
30#include <freeradius-devel/util/calc.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/server/tmpl_dcursor.h>
36# define XLAT_DEBUG(_fmt, ...) DEBUG3("%s[%i] "_fmt, __FILE__, __LINE__, ##__VA_ARGS__)
38# define XLAT_DEBUG(...)
83 if (!
head->call.args) {
85 head->call.args->is_argv =
true;
97 talloc_steal(group->group, node);
331 a = fr_value_box_list_head(
in);
339 b = fr_value_box_list_next(
in, a);
347 if (fr_value_box_list_num_elements(&a->vb_group) > 1) {
348 REDEBUG(
"Expected one value as the first argument, got %u",
349 fr_value_box_list_num_elements(&a->vb_group));
352 a = fr_value_box_list_head(&a->vb_group);
354 if (fr_value_box_list_num_elements(&b->vb_group) > 1) {
355 REDEBUG(
"Expected one value as the second argument, got %u",
356 fr_value_box_list_num_elements(&b->vb_group));
359 b = fr_value_box_list_head(&b->vb_group);
381 if (enumv) dst->enumv = enumv;
388#define XLAT_BINARY_FUNC(_name, _op) \
389static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
390 xlat_ctx_t const *xctx, \
391 request_t *request, fr_value_box_list_t *in) \
393 return xlat_binary_op(ctx, out, xctx, request, in, _op, FR_TYPE_NULL, NULL); \
479 a = fr_value_box_list_head(
in);
485 b = fr_value_box_list_next(
in, a);
513#define XLAT_CMP_FUNC(_name, _op) \
514static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
515 xlat_ctx_t const *xctx, \
516 request_t *request, fr_value_box_list_t *in) \
518 return xlat_cmp_op(ctx, out, xctx, request, in, _op); \
568 if (!child)
goto done;
577 if (!child)
goto done;
623 inst->op = xctx->
ex->call.func->token;
624 inst->regex_flags = tmpl_regex_flags(regex->vpt);
626 inst->xlat = talloc_steal(
inst, regex);
646 inst->regex = tmpl_regex(regex->vpt);
697 fr_regmatch_t *regmatch;
707 arg = fr_value_box_list_head(
in);
711 subcaptures = regex_subcapture_count(*preg);
712 if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1;
713 MEM(regmatch = regex_match_data_alloc(NULL, subcaptures));
715 while ((vb = fr_value_box_list_pop_head(&arg->vb_group)) != NULL) {
717 subject = vb->vb_strvalue;
722 fr_value_box_list_t list;
724 fr_value_box_list_init(&list);
725 fr_value_box_list_insert_head(&list, vb);
735 RPEDEBUG(
"Failed concatenating regular expression string");
747 ret = regex_exec(*preg, subject,
len, regmatch);
757 regex_sub_to_request(
request, NULL, NULL, NULL);
761 regex_sub_to_request(
request, preg, ®match, &safety);
784 regex_t *preg = NULL;
804 RPEDEBUG(
"Failed concatenating regular expression string");
811 tmpl_regex_flags(
inst->xlat->vpt),
true,
true);
830 preg = tmpl_regex(
inst->xlat->vpt);
836 fr_value_box_list_init(&rctx->
list);
850#define XLAT_REGEX_FUNC(_name, _op) \
851static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
852 xlat_ctx_t const *xctx, \
853 request_t *request, fr_value_box_list_t *in) \
855 return xlat_regex_op(ctx, out, xctx, request, in, _op); \
870 regex = fr_value_box_list_pop_head(
in);
874 slen = regex_compile(ctx, &preg, regex->vb_strvalue, regex->vb_length,
877 RPEDEBUG(
"Failed parsing regular expression %pV", regex);
915 head = node->call.args;
930 for (i = 0; i <
inst->argc; i++) {
932 if (i == (
inst->argc - 1))
break;
956 if (!
head->flags.pure)
return false;
986 if (!*result)
return true;
1013 (void) talloc_steal(
head, node);
1039 for (i = 0; i <
inst->argc; i++) {
1044 if (
inst->argv[i]->flags.can_purify) {
1068 if (result)
return 0;
1074 if (((i + 1) ==
inst->argc) && (deleted == i))
break;
1076 TALLOC_FREE(
inst->argv[i]);
1080 if (!deleted)
return 0;
1088 while (i < (
inst->argc - deleted)) {
1089 if (j >=
inst->argc)
break;
1091 if (
inst->argv[i]) {
1099 if (j < 0) j = i + 1;
1105 while (j < inst->argc) {
1106 if (
inst->argv[j])
break;
1114 inst->argv[j++] = NULL;
1117 inst->argc -= deleted;
1119 if (
inst->argc > 1)
return 0;
1124 group =
inst->argv[0];
1126 talloc_steal(node, group);
1140 node->group = group;
1199 if (!fr_value_box_list_num_elements(
in))
return false;
1256 if (match)
goto done;
1258 fr_value_box_list_talloc_free(&rctx->
list);
1297 if (!fr_value_box_list_num_elements(
in))
return false;
1322 if (!found)
return false;
1361 TALLOC_FREE(rctx->
box);
1365 fr_value_box_list_talloc_free(&rctx->
list);
1397 if (xctx->
ex->call.func->token ==
T_LOR) {
1399 inst->stop_on_match =
true;
1402 inst->stop_on_match =
false;
1423 if (
inst->stop_on_match) {
1427 rctx->
box->vb_bool =
true;
1429 fr_value_box_list_init(&rctx->
list);
1438 { .
required =
true, .single =
true, .concat =
true },
1452 group = fr_value_box_list_head(
in);
1453 vb = fr_value_box_list_head(&group->vb_group);
1492 group = fr_value_box_list_head(
in);
1493 vb = fr_value_box_list_head(&group->vb_group);
1504 dst->vb_bool =
true;
1569 rcode = &rcode_arg->data;
1571 switch (rcode->type) {
1576 ERROR(
"Unknown rcode '%pV'", rcode);
1591 ERROR(
"Invalid value for rcode '%pV'", rcode);
1598 inst->rcode = rcode->vb_uint8;
1626 if (slen < 0)
return slen;
1664 if (fr_value_box_list_num_elements(
args) == 0) {
1666 RDEBUG(
"Request rcode is '%s'",
1671 rcode =
inst->rcode;
1676 REDEBUG(
"Invalid rcode '%pV'", arg_rcode);
1681 RDEBUG3(
"Request rcode is '%s'",
1686 vb->vb_bool = (
request->rcode == rcode);
1774 inst->vpt = talloc_steal(
inst, node->vpt);
1797 dst->vb_bool = (
vp != NULL);
1828#undef XLAT_REGISTER_BINARY_OP
1829#define XLAT_REGISTER_BINARY_OP(_op, _name) \
1831 if (unlikely((xlat = xlat_func_register(NULL, "op_" STRINGIFY(_name), xlat_func_op_ ## _name, FR_TYPE_VOID)) == NULL)) return -1; \
1832 xlat_func_args_set(xlat, binary_op_xlat_args); \
1833 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL | XLAT_FUNC_FLAG_PRIVATE); \
1834 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1835 xlat->token = _op; \
1838#undef XLAT_REGISTER_BINARY_CMP
1839#define XLAT_REGISTER_BINARY_CMP(_op, _name) \
1841 if (unlikely((xlat = xlat_func_register(NULL, "cmp_" STRINGIFY(_name), xlat_func_cmp_ ## _name, FR_TYPE_BOOL)) == NULL)) return -1; \
1842 xlat_func_args_set(xlat, binary_cmp_xlat_args); \
1843 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL | XLAT_FUNC_FLAG_PRIVATE); \
1844 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1845 xlat_func_resolve_set(xlat, xlat_expr_resolve_binary); \
1846 xlat->token = _op; \
1849#undef XLAT_REGISTER_NARY_OP
1850#define XLAT_REGISTER_NARY_OP(_op, _name, _func_name) \
1852 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _func_name, FR_TYPE_VOID)) == NULL)) return -1; \
1853 xlat_func_instantiate_set(xlat, xlat_instantiate_ ## _func_name, xlat_ ## _func_name ## _inst_t, NULL, NULL); \
1854 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL | XLAT_FUNC_FLAG_PRIVATE); \
1855 xlat_func_print_set(xlat, xlat_expr_print_nary); \
1856 xlat_purify_func_set(xlat, xlat_expr_logical_purify); \
1857 xlat->token = _op; \
1860#undef XLAT_REGISTER_REGEX_OP
1861#define XLAT_REGISTER_REGEX_OP(_op, _name) \
1863 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _name, FR_TYPE_BOOL)) == NULL)) return -1; \
1864 xlat_func_args_set(xlat, regex_op_xlat_args); \
1865 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL | XLAT_FUNC_FLAG_PRIVATE); \
1866 xlat_func_instantiate_set(xlat, xlat_instantiate_regex, xlat_regex_inst_t, NULL, NULL); \
1867 xlat_func_print_set(xlat, xlat_expr_print_regex); \
1868 xlat->token = _op; \
1871#define XLAT_REGISTER_BOOL(_xlat, _func, _arg, _ret_type) \
1873 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, _ret_type)) == NULL)) return -1; \
1874 xlat_func_args_set(xlat, _arg); \
1875 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
1878#define XLAT_REGISTER_UNARY(_op, _xlat, _func) \
1880 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, FR_TYPE_VOID)) == NULL)) return -1; \
1881 xlat_func_args_set(xlat, unary_op_xlat_args); \
1882 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL | XLAT_FUNC_FLAG_PRIVATE); \
1883 xlat_func_print_set(xlat, xlat_expr_print_unary); \
1884 xlat->token = _op; \
1967 [
T_OR ] =
L(
"op_or"),
1972 [
T_LAND ] =
L(
"logical_and"),
1973 [
T_LOR ] =
L(
"logical_or"),
2016#define P(_x, _y) (((_x) << 4) | (_y))
2072#define fr_sbuff_skip_whitespace(_x) \
2074 while (isspace(fr_sbuff_uint8(_x, '\0'))) fr_sbuff_advance(_x, 1); \
2078 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2079 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2080 fr_sbuff_parse_rules_t
const *input_rules,
bool cond) CC_HINT(
nonnull(1,2,3,4,5));
2083 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2084 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond) CC_HINT(
nonnull(1,2,3,4,5));
2087 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2088 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond) CC_HINT(
nonnull(1,2,3,4,5));
2113 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2114 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2126 t_rules = &our_t_rules;
2137 goto check_for_double;
2151 goto check_for_double;
2158 goto check_for_double;
2190 unary->call.args->is_argv =
true;
2192 if (
tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, out_c, (c ==
'!')) <= 0) {
2203 unary->flags.can_purify = (unary->call.func->flags.pure && unary->call.args->flags.pure) | unary->call.args->flags.can_purify;
2249 node->data.vb_uint8 =
type;
2252 (void) talloc_steal(cast, child);
2319 fr_sbuff_parse_rules_t
const *bracket_rules)
2333 t_rules = &our_t_rules;
2340 fr_sbuff_marker(&opand_m, &our_in);
2349 if (!fr_sbuff_is_str(&our_in,
"m'", 2)) {
2389 fr_sbuff_marker(&flag, &our_in);
2390 if (tmpl_regex_flags_substr(
vpt, &our_in, bracket_rules->terminals) < 0) {
2402 slen = tmpl_regex_compile(
vpt,
true);
2403 if (slen <= 0)
goto error;
2406 node->
quote = quote;
2425 if (slen <= 0)
return 0;
2450 node->call.func = func;
2475 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2476 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2503 cast_type = our_t_rules.
cast;
2504 enumv = our_t_rules.
enumv;
2520 our_t_rules.
enumv = enumv = NULL;
2535 our_t_rules.
enumv = NULL;
2576 fr_sbuff_marker(&opand_m, &our_in);
2582 p_rules = bracket_rules;
2611 if (node->data.
type != cast_type) {
2786#ifdef STATIC_ANALYZER
2787 if (!node)
return false;
2822 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2823 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2824 fr_sbuff_parse_rules_t
const *input_rules,
bool cond)
2839 t_rules = &our_t_rules;
2843 fr_sbuff_marker(&m_lhs, &our_in);
2848 slen =
tokenize_unary(
head, &lhs, &our_in, p_rules, t_rules, bracket_rules, &c, cond);
2883 if (!bracket_rules) {
2900 fr_sbuff_marker(&m_op, &our_in);
2940 if (((c ==
'!') || (c ==
'~')) && (op !=
T_LAND) && (op !=
T_LOR)) {
2941 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]);
2948 fr_sbuff_marker(&m_rhs, &our_in);
2960 switch (lhs->
type) {
3001 fr_strerror_const(
"Function (or cast) needs to return data type 'string' in order to be used with regular expressions");
3035 if (!rhs)
goto done;
3043 if ((lhs->
type ==
XLAT_FUNC) && (lhs->call.func->token == op)) {
3046 lhs->call.args->
flags.
can_purify |= rhs->flags.can_purify | rhs->flags.pure;
3080 if (rcode < 0)
goto fail_lhs;
3105 node->call.args->flags.can_purify |= arg->flags.can_purify | arg->flags.pure;
3106 if (node->call.args->flags.can_purify)
break;
3108 node->flags.can_purify = node->call.args->flags.can_purify;
3111 node->flags.can_purify = (node->call.func->flags.pure && node->call.args->flags.pure) | node->call.args->flags.can_purify;
3145 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
bool cond)
3148 fr_sbuff_parse_rules_t *bracket_rules = NULL;
3149 fr_sbuff_parse_rules_t *terminal_rules = NULL;
3159 MEM(bracket_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3160 MEM(terminal_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3162 *bracket_rules = *p_rules;
3163 *terminal_rules = *p_rules;
3165 if (p_rules->terminals) {
3176 terminal_rules->terminals,
3180 if (!t_rules) t_rules = &my_rules;
3225 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3230 if (slen < 0)
return slen;
3232#ifdef STATIC_ANALYZER
3237 if (!
out)
return -1;
3253 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3258 if (slen < 0)
return slen;
3260#ifdef STATIC_ANALYZER
3261 if (!
out)
return -1;
3295 if (!
head->flags.pure)
goto return_false;
static uint8_t request[4]
#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.
#define fr_dcursor_list(_cursor)
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
bool const fr_dict_attr_allowed_chars[SBUFF_CHAR_CLASS]
Characters allowed in a single dictionary attribute name.
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 void * fr_dlist_pop_head(fr_dlist_head_t *list_head)
Remove the head item in a list.
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,...)
@ 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.
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 const sbuff_char_word[SBUFF_CHAR_CLASS]
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_is_str_literal(_sbuff, _str)
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#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 fr_sbuff_uint8(_sbuff_or_marker, _eob)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define fr_sbuff_used(_sbuff_or_marker)
#define fr_sbuff_behind(_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)
#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_rules_cast(_tmpl)
#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_rules_copy_depth(_out, _in)
Copy parse rules for a nested parse, and increment the depth field.
void tmpl_debug(FILE *fp, tmpl_t const *vpt)
#define tmpl_value_type(_tmpl)
static fr_type_t tmpl_cast_get(tmpl_t *vpt)
#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.
bool tmpl_rules_depth_exceeded(tmpl_rules_t const *t_rules)
True when a parse has nested past the point where the stack is safe.
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.
unsigned int allow_unresolved
Allow attributes that look valid but were not found in the dictionaries.
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, unlang_result_t *p_result, 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_type_t type
Type to cast argument to.
#define XLAT_HEAD_VERIFY(_head)
unsigned int pure
has no external side effects, true for BOX, LITERAL, and some functions
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.
unsigned int concat
Concat boxes together.
#define XLAT_RESULT_SUCCESS(_p_result)
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
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.
int xlat_flatten_to_argv(TALLOC_CTX *ctx, xlat_exp_head_t ***argv, xlat_exp_head_t *head)
Turn am xlat list into an argv[] array, and nuke the input list.
unsigned int required
Argument must be present, and non-empty.
#define XLAT_VERIFY(_node)
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.
unsigned int can_purify
if the xlat has a pure function with pure arguments.
unsigned int constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
unsigned int needs_resolving
Needs pass2 resolution.
int xlat_instance_unregister_func(xlat_exp_t *node)
Remove a node from the list of xlat instance data.
fr_type_t xlat_node_data_type(xlat_exp_t const *node)
Definition for a single argument consumed by an xlat function.
Flags that control resolution and evaluation.
#define add(_type, _out, _in)
#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.
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.
ssize_t fr_value_box_list_concat_as_string(fr_value_box_safety_t *safety, 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_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.
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.
static fr_sbuff_err_t char size_t fr_sbuff_t * in
fr_value_box_safe_for_t safe_for
A unique value to indicate if that value box is safe for consumption by a particular module for a par...
#define fr_box_strvalue_len(_val, _len)
static fr_sbuff_err_t char ** out
static fr_sbuff_err_t char size_t * len
#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)
#define FR_VALUE_BOX_SAFE_FOR_ANY
void xlat_exp_set_vpt(xlat_exp_t *node, tmpl_t *vpt)
Set the tmpl for a node, along with flags and the name.
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_func(xlat_exp_t *node, xlat_t const *func, fr_dict_t const *dict)
Set the function for a node.
void xlat_exp_set_name_shallow(xlat_exp_t *node, char const *fmt)
Set the format string for an xlat node from a pre-existing buffer.
int xlat_regex_escape(fr_value_box_t *vb, UNUSED void *uctx)
Escape a value box so that it is safe to use as a regular expression.
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 xlat_action_t xlat_func_regex_search(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
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 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_rcode(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_term_t const *terminals)
static size_t expr_quote_table_len
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)
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 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)
unlang_result_t last_result
static fr_table_num_sorted_t const expr_quote_table[]
#define XLAT_REGISTER_BINARY_OP(_op, _name)
#define XLAT_REGEX_FUNC(_name, _op)
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 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 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))
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 xlat_exp_t * expr_cast_alloc(TALLOC_CTX *ctx, fr_type_t type, xlat_exp_t *child)
Allocate a specific cast node.
static xlat_arg_parser_t const regex_search_xlat_args[]
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_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)
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))
unlang_result_t last_result
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)
static xlat_action_t xlat_regex_do_op(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.
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_slen_t xlat_tokenize_word(TALLOC_CTX *ctx, xlat_exp_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
fr_token_t quote
Type of quoting around XLAT_GROUP types.
@ XLAT_TMPL
xlat attribute
@ XLAT_GROUP
encapsulated string of xlats
bool deprecated
this function was deprecated
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)