27RCSID(
"$Id: a9c70ea5e710c115ba57d1730a6eee1e9a47ef9c $")
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>
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);
317 a = fr_value_box_list_head(
in);
323 b = fr_value_box_list_next(
in, a);
331 if (fr_value_box_list_num_elements(&a->vb_group) > 1) {
332 REDEBUG(
"Expected one value as the first argument, got %u",
333 fr_value_box_list_num_elements(&a->vb_group));
336 a = fr_value_box_list_head(&a->vb_group);
338 if (fr_value_box_list_num_elements(&b->vb_group) > 1) {
339 REDEBUG(
"Expected one value as the second argument, got %u",
340 fr_value_box_list_num_elements(&b->vb_group));
343 b = fr_value_box_list_head(&b->vb_group);
366 if (enumv) dst->enumv = enumv;
373#define XLAT_BINARY_FUNC(_name, _op) \
374static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
375 xlat_ctx_t const *xctx, \
376 request_t *request, fr_value_box_list_t *in) \
378 return xlat_binary_op(ctx, out, xctx, request, in, _op, FR_TYPE_NULL, NULL); \
458 a = fr_value_box_list_head(
in);
464 b = fr_value_box_list_next(
in, a);
492#define XLAT_CMP_FUNC(_name, _op) \
493static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
494 xlat_ctx_t const *xctx, \
495 request_t *request, fr_value_box_list_t *in) \
497 return xlat_cmp_op(ctx, out, xctx, request, in, _op); \
600 inst->op = xctx->
ex->call.func->token;
601 inst->regex_flags = tmpl_regex_flags(regex->vpt);
603 inst->xlat = talloc_steal(
inst, regex);
623 inst->regex = tmpl_regex(regex->vpt);
669 fr_regmatch_t *regmatch;
679 arg = fr_value_box_list_head(
in);
683 subcaptures = regex_subcapture_count(*preg);
684 if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1;
685 MEM(regmatch = regex_match_data_alloc(NULL, subcaptures));
687 while ((vb = fr_value_box_list_pop_head(&arg->vb_group)) != NULL) {
689 subject = vb->vb_strvalue;
694 fr_value_box_list_t list;
696 fr_value_box_list_init(&list);
697 fr_value_box_list_insert_head(&list, vb);
707 RPEDEBUG(
"Failed concatenating regular expression string");
719 ret = regex_exec(*preg, subject, len, regmatch);
728 regex_sub_to_request(request, NULL, NULL, NULL);
732 regex_sub_to_request(request, preg, ®match, &safety);
759 regex_t *preg = NULL;
779 RPEDEBUG(
"Failed concatenating regular expression string");
786 tmpl_regex_flags(
inst->xlat->vpt),
true,
true);
805 preg = tmpl_regex(
inst->xlat->vpt);
811 fr_value_box_list_init(&rctx->
list);
825#define XLAT_REGEX_FUNC(_name, _op) \
826static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
827 xlat_ctx_t const *xctx, \
828 request_t *request, fr_value_box_list_t *in) \
830 return xlat_regex_op(ctx, out, xctx, request, in, _op); \
847 regex = fr_value_box_list_pop_head(
in);
851 slen = regex_compile(ctx, &preg, regex->vb_strvalue, regex->vb_length,
854 RPEDEBUG(
"Failed parsing regular expression %pV", regex);
892 head = node->call.args;
907 for (i = 0; i <
inst->argc; i++) {
909 if (i == (
inst->argc - 1))
break;
933 if (!
head->flags.pure)
return false;
963 if (!*result)
return true;
990 (void) talloc_steal(
head, node);
1016 for (i = 0; i <
inst->argc; i++) {
1021 if (
inst->argv[i]->flags.can_purify) {
1045 if (result)
return 0;
1051 if (((i + 1) ==
inst->argc) && (deleted == i))
break;
1053 TALLOC_FREE(
inst->argv[i]);
1057 if (!deleted)
return 0;
1065 while (i < (
inst->argc - deleted)) {
1066 if (
inst->argv[i]) {
1074 if (j < 0) j = i + 1;
1080 while (j < inst->argc) {
1081 if (
inst->argv[j])
break;
1089 inst->argv[j++] = NULL;
1092 inst->argc -= deleted;
1094 if (
inst->argc > 1)
return 0;
1099 group =
inst->argv[0];
1101 talloc_steal(node, group);
1115 node->group = group;
1174 if (!fr_value_box_list_num_elements(
in))
return false;
1231 if (match)
goto done;
1233 fr_value_box_list_talloc_free(&rctx->
list);
1272 if (!fr_value_box_list_num_elements(
in))
return false;
1297 if (!found)
return false;
1337 fr_value_box_list_talloc_free(&rctx->
list);
1368 if (xctx->
ex->call.func->token ==
T_LOR) {
1370 inst->stop_on_match =
true;
1373 inst->stop_on_match =
false;
1394 if (
inst->stop_on_match) {
1398 rctx->
box->vb_bool =
true;
1400 fr_value_box_list_init(&rctx->
list);
1409 { .
required =
true, .single =
true, .concat =
true },
1423 group = fr_value_box_list_head(
in);
1424 vb = fr_value_box_list_head(&group->vb_group);
1463 group = fr_value_box_list_head(
in);
1464 vb = fr_value_box_list_head(&group->vb_group);
1475 dst->vb_bool =
true;
1540 rcode = &rcode_arg->data;
1542 switch (rcode->type) {
1547 ERROR(
"Unknown rcode '%pV'", rcode);
1562 ERROR(
"Invalid value for rcode '%pV'", rcode);
1569 inst->rcode = rcode->vb_uint8;
1597 if (slen < 0)
return slen;
1634 if (fr_value_box_list_num_elements(
args) == 0) {
1636 rcode =
inst->rcode;
1641 REDEBUG(
"Invalid rcode '%pV'", arg_rcode);
1646 RDEBUG3(
"Request rcode is '%s'",
1651 vb->vb_bool = (request->rcode == rcode);
1739 inst->vpt = talloc_steal(
inst, node->vpt);
1762 dst->vb_bool = (
vp != NULL);
1793#undef XLAT_REGISTER_BINARY_OP
1794#define XLAT_REGISTER_BINARY_OP(_op, _name) \
1796 if (unlikely((xlat = xlat_func_register(NULL, "op_" STRINGIFY(_name), xlat_func_op_ ## _name, FR_TYPE_VOID)) == NULL)) return -1; \
1797 xlat_func_args_set(xlat, binary_op_xlat_args); \
1798 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1799 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1800 xlat->token = _op; \
1803#undef XLAT_REGISTER_BINARY_CMP
1804#define XLAT_REGISTER_BINARY_CMP(_op, _name) \
1806 if (unlikely((xlat = xlat_func_register(NULL, "cmp_" STRINGIFY(_name), xlat_func_cmp_ ## _name, FR_TYPE_BOOL)) == NULL)) return -1; \
1807 xlat_func_args_set(xlat, binary_cmp_xlat_args); \
1808 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1809 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1810 xlat_func_resolve_set(xlat, xlat_expr_resolve_binary); \
1811 xlat->token = _op; \
1814#undef XLAT_REGISTER_NARY_OP
1815#define XLAT_REGISTER_NARY_OP(_op, _name, _func_name) \
1817 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _func_name, FR_TYPE_VOID)) == NULL)) return -1; \
1818 xlat_func_instantiate_set(xlat, xlat_instantiate_ ## _func_name, xlat_ ## _func_name ## _inst_t, NULL, NULL); \
1819 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1820 xlat_func_print_set(xlat, xlat_expr_print_nary); \
1821 xlat_purify_func_set(xlat, xlat_expr_logical_purify); \
1822 xlat->token = _op; \
1825#undef XLAT_REGISTER_REGEX_OP
1826#define XLAT_REGISTER_REGEX_OP(_op, _name) \
1828 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _name, FR_TYPE_BOOL)) == NULL)) return -1; \
1829 xlat_func_args_set(xlat, regex_op_xlat_args); \
1830 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1831 xlat_func_instantiate_set(xlat, xlat_instantiate_regex, xlat_regex_inst_t, NULL, NULL); \
1832 xlat_func_print_set(xlat, xlat_expr_print_regex); \
1833 xlat->token = _op; \
1836#define XLAT_REGISTER_BOOL(_xlat, _func, _arg, _ret_type) \
1838 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, _ret_type)) == NULL)) return -1; \
1839 xlat_func_args_set(xlat, _arg); \
1840 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
1843#define XLAT_REGISTER_UNARY(_op, _xlat, _func) \
1845 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, FR_TYPE_VOID)) == NULL)) return -1; \
1846 xlat_func_args_set(xlat, unary_op_xlat_args); \
1847 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1848 xlat_func_print_set(xlat, xlat_expr_print_unary); \
1849 xlat->token = _op; \
1927 [
T_OR ] =
L(
"op_or"),
1932 [
T_LAND ] =
L(
"logical_and"),
1933 [
T_LOR ] =
L(
"logical_or"),
1976#define P(_x, _y) (((_x) << 4) | (_y))
2032#define fr_sbuff_skip_whitespace(_x) \
2034 while (isspace((uint8_t) fr_sbuff_char(_x, '\0'))) fr_sbuff_advance(_x, 1); \
2038 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2039 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2040 fr_sbuff_parse_rules_t
const *input_rules,
bool cond) CC_HINT(
nonnull(1,2,3,4,5));
2043 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2044 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond) CC_HINT(
nonnull(1,2,3,4,5));
2047 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2048 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond) CC_HINT(
nonnull(1,2,3,4,5));
2073 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2074 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2092 goto check_for_double;
2106 goto check_for_double;
2113 goto check_for_double;
2145 unary->call.args->is_argv =
true;
2147 if (
tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, out_c, (c ==
'!')) <= 0) {
2158 unary->flags.can_purify = (unary->call.func->flags.pure && unary->call.args->flags.pure) | unary->call.args->flags.can_purify;
2203 node->data.vb_uint8 =
type;
2206 (void) talloc_steal(cast, child);
2224 fr_sbuff_marker(&m, &our_in);
2254 fr_sbuff_parse_rules_t
const *bracket_rules)
2270 fr_sbuff_marker(&opand_m, &our_in);
2279 if (!fr_sbuff_is_str(&our_in,
"m'", 2)) {
2319 fr_sbuff_marker(&flag, &our_in);
2320 if (tmpl_regex_flags_substr(
vpt, &our_in, bracket_rules->terminals) < 0) {
2332 slen = tmpl_regex_compile(
vpt,
true);
2333 if (slen <= 0)
goto error;
2336 node->
quote = quote;
2355 if (slen <= 0)
return 0;
2372 node->call.func = func;
2396 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2397 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2420 our_t_rules = *t_rules;
2422 cast_type = our_t_rules.
cast;
2423 enumv = our_t_rules.
enumv;
2439 our_t_rules.
enumv = enumv = NULL;
2454 our_t_rules.
enumv = NULL;
2495 fr_sbuff_marker(&opand_m, &our_in);
2501 p_rules = bracket_rules;
2528 if (node->data.
type != cast_type) {
2702#ifdef STATIC_ANALYZER
2703 if (!node)
return false;
2738 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2739 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2740 fr_sbuff_parse_rules_t
const *input_rules,
bool cond)
2754 fr_sbuff_marker(&m_lhs, &our_in);
2759 slen =
tokenize_unary(
head, &lhs, &our_in, p_rules, t_rules, bracket_rules, &c, cond);
2793 if (!bracket_rules) {
2810 fr_sbuff_marker(&m_op, &our_in);
2850 if (((c ==
'!') || (c ==
'~')) && (op !=
T_LAND) && (op !=
T_LOR)) {
2851 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]);
2858 fr_sbuff_marker(&m_rhs, &our_in);
2870 switch (lhs->
type) {
2942 if (!rhs)
goto done;
2948 if ((lhs->
type ==
XLAT_FUNC) && (lhs->call.func->token == op)) {
2951 lhs->call.args->
flags.
can_purify |= rhs->flags.can_purify | rhs->flags.pure;
2985 if (rcode < 0)
goto fail_lhs;
3010 node->call.args->flags.can_purify |= arg->flags.can_purify | arg->flags.pure;
3011 if (node->call.args->flags.can_purify)
break;
3013 node->flags.can_purify = node->call.args->flags.can_purify;
3016 node->flags.can_purify = (node->call.func->flags.pure && node->call.args->flags.pure) | node->call.args->flags.can_purify;
3049 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
bool cond)
3052 fr_sbuff_parse_rules_t *bracket_rules = NULL;
3053 fr_sbuff_parse_rules_t *terminal_rules = NULL;
3063 MEM(bracket_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3064 MEM(terminal_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3066 *bracket_rules = *p_rules;
3067 *terminal_rules = *p_rules;
3069 if (p_rules->terminals) {
3080 terminal_rules->terminals,
3084 if (!t_rules) t_rules = &my_rules;
3125 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3130 if (slen < 0)
return slen;
3132#ifdef STATIC_ANALYZER
3137 if (!
out)
return -1;
3153 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3158 if (slen < 0)
return slen;
3160#ifdef STATIC_ANALYZER
3161 if (!
out)
return -1;
3195 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.
bool const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters that are allowed in dictionary attribute names.
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 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_diff(_a, _b)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_char(_sbuff_or_marker, _eob)
#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(_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)
void tmpl_debug(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.
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
uint8_t allow_unresolved
Allow attributes that look valid but were not found in the dictionaries.
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, 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.
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.
#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
uint8_t required
Argument must be present, and non-empty.
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.
uint8_t concat
Concat boxes together.
uint8_t needs_resolving
Needs pass2 resolution.
#define XLAT_VERIFY(_node)
uint8_t can_purify
if the xlat has a pure function with pure arguments.
uint8_t pure
has no external side effects, true for BOX, LITERAL, and some functions
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.
uint8_t constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
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.
ssize_t fr_value_box_list_concat_as_string(fr_value_box_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.
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.
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_safety_copy(fr_value_box_t *out, fr_value_box_t const *in)
Copy the safety values from one box to another.
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_value_box_mark_safe_for(_box, _safe_for)
#define fr_box_strvalue_len(_val, _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)
static size_t char ** out
#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.
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 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)
static ssize_t tokenize_rcode(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_term_t const *terminals)
#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
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)