27RCSID(
"$Id: c2da1069ba59b7c1e6b72fafa8c9157bd1a88048 $")
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);
318 b = fr_value_box_list_next(
in, a);
327 if (fr_value_box_list_num_elements(&a->vb_group) > 1) {
328 REDEBUG(
"Expected one value as the first argument, got %u",
329 fr_value_box_list_num_elements(&a->vb_group));
332 a = fr_value_box_list_head(&a->vb_group);
334 if (fr_value_box_list_num_elements(&b->vb_group) > 1) {
335 REDEBUG(
"Expected one value as the second argument, got %u",
336 fr_value_box_list_num_elements(&b->vb_group));
339 b = fr_value_box_list_head(&b->vb_group);
362 if (enumv) dst->enumv = enumv;
369#define XLAT_BINARY_FUNC(_name, _op) \
370static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
371 xlat_ctx_t const *xctx, \
372 request_t *request, fr_value_box_list_t *in) \
374 return xlat_binary_op(ctx, out, xctx, request, in, _op, FR_TYPE_NULL, NULL); \
454 a = fr_value_box_list_head(
in);
455 b = fr_value_box_list_next(
in, a);
481#define XLAT_CMP_FUNC(_name, _op) \
482static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
483 xlat_ctx_t const *xctx, \
484 request_t *request, fr_value_box_list_t *in) \
486 return xlat_cmp_op(ctx, out, xctx, request, in, _op); \
589 inst->op = xctx->
ex->call.func->token;
590 inst->regex_flags = tmpl_regex_flags(regex->vpt);
592 inst->xlat = talloc_steal(
inst, regex);
612 inst->regex = tmpl_regex(regex->vpt);
658 fr_regmatch_t *regmatch;
668 arg = fr_value_box_list_head(
in);
672 subcaptures = regex_subcapture_count(*preg);
673 if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1;
674 MEM(regmatch = regex_match_data_alloc(NULL, subcaptures));
676 while ((vb = fr_value_box_list_pop_head(&arg->vb_group)) != NULL) {
678 subject = vb->vb_strvalue;
683 fr_value_box_list_t list;
685 fr_value_box_list_init(&list);
686 fr_value_box_list_insert_head(&list, vb);
696 RPEDEBUG(
"Failed concatenating regular expression string");
708 ret = regex_exec(*preg, subject, len, regmatch);
717 regex_sub_to_request(request, NULL, NULL, NULL);
721 regex_sub_to_request(request, preg, ®match, &safety);
748 regex_t *preg = NULL;
768 RPEDEBUG(
"Failed concatenating regular expression string");
775 tmpl_regex_flags(
inst->xlat->vpt),
true,
true);
794 preg = tmpl_regex(
inst->xlat->vpt);
800 fr_value_box_list_init(&rctx->
list);
814#define XLAT_REGEX_FUNC(_name, _op) \
815static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
816 xlat_ctx_t const *xctx, \
817 request_t *request, fr_value_box_list_t *in) \
819 return xlat_regex_op(ctx, out, xctx, request, in, _op); \
836 regex = fr_value_box_list_pop_head(
in);
840 slen = regex_compile(ctx, &preg, regex->vb_strvalue, regex->vb_length,
843 RPEDEBUG(
"Failed parsing regular expression %pV", regex);
881 head = node->call.args;
896 for (i = 0; i <
inst->argc; i++) {
898 if (i == (
inst->argc - 1))
break;
922 if (!
head->flags.pure)
return false;
952 if (!*result)
return true;
979 (void) talloc_steal(
head, node);
1005 for (i = 0; i <
inst->argc; i++) {
1010 if (
inst->argv[i]->flags.can_purify) {
1034 if (result)
return 0;
1040 if (((i + 1) ==
inst->argc) && (deleted == i))
break;
1042 TALLOC_FREE(
inst->argv[i]);
1046 if (!deleted)
return 0;
1054 while (i < (
inst->argc - deleted)) {
1055 if (
inst->argv[i]) {
1063 if (j < 0) j = i + 1;
1069 while (j < inst->argc) {
1070 if (
inst->argv[j])
break;
1078 inst->argv[j++] = NULL;
1081 inst->argc -= deleted;
1083 if (
inst->argc > 1)
return 0;
1088 group =
inst->argv[0];
1090 talloc_steal(node, group);
1104 node->group = group;
1163 if (!fr_value_box_list_num_elements(
in))
return false;
1221 if (match)
goto done;
1223 fr_value_box_list_talloc_free(&rctx->
list);
1262 if (!fr_value_box_list_num_elements(
in))
return false;
1287 if (!found)
return false;
1328 fr_value_box_list_talloc_free(&rctx->
list);
1359 if (xctx->
ex->call.func->token ==
T_LOR) {
1361 inst->stop_on_match =
true;
1364 inst->stop_on_match =
false;
1385 if (
inst->stop_on_match) {
1389 rctx->
box->vb_bool =
true;
1391 fr_value_box_list_init(&rctx->
list);
1400 { .
required =
true, .single =
true, .concat =
true },
1414 group = fr_value_box_list_head(
in);
1415 vb = fr_value_box_list_head(&group->vb_group);
1454 group = fr_value_box_list_head(
in);
1455 vb = fr_value_box_list_head(&group->vb_group);
1466 dst->vb_bool =
true;
1531 rcode = &rcode_arg->data;
1533 switch (rcode->type) {
1538 ERROR(
"Unknown rcode '%pV'", rcode);
1553 ERROR(
"Invalid value for rcode '%pV'", rcode);
1560 inst->rcode = rcode->vb_uint8;
1588 if (slen < 0)
return slen;
1625 if (fr_value_box_list_num_elements(
args) == 0) {
1627 rcode =
inst->rcode;
1632 REDEBUG(
"Invalid rcode '%pV'", arg_rcode);
1637 RDEBUG3(
"Request rcode is '%s'",
1642 vb->vb_bool = (request->rcode == rcode);
1735 inst->vpt = talloc_steal(
inst, node->vpt);
1758 dst->vb_bool = (
vp != NULL);
1789#undef XLAT_REGISTER_BINARY_OP
1790#define XLAT_REGISTER_BINARY_OP(_op, _name) \
1792 if (unlikely((xlat = xlat_func_register(NULL, "op_" STRINGIFY(_name), xlat_func_op_ ## _name, FR_TYPE_VOID)) == NULL)) return -1; \
1793 xlat_func_args_set(xlat, binary_op_xlat_args); \
1794 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1795 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1796 xlat->token = _op; \
1799#undef XLAT_REGISTER_BINARY_CMP
1800#define XLAT_REGISTER_BINARY_CMP(_op, _name) \
1802 if (unlikely((xlat = xlat_func_register(NULL, "cmp_" STRINGIFY(_name), xlat_func_cmp_ ## _name, FR_TYPE_BOOL)) == NULL)) return -1; \
1803 xlat_func_args_set(xlat, binary_cmp_xlat_args); \
1804 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1805 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1806 xlat_func_resolve_set(xlat, xlat_expr_resolve_binary); \
1807 xlat->token = _op; \
1810#undef XLAT_REGISTER_NARY_OP
1811#define XLAT_REGISTER_NARY_OP(_op, _name, _func_name) \
1813 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _func_name, FR_TYPE_VOID)) == NULL)) return -1; \
1814 xlat_func_instantiate_set(xlat, xlat_instantiate_ ## _func_name, xlat_ ## _func_name ## _inst_t, NULL, NULL); \
1815 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1816 xlat_func_print_set(xlat, xlat_expr_print_nary); \
1817 xlat_purify_func_set(xlat, xlat_expr_logical_purify); \
1818 xlat->token = _op; \
1821#undef XLAT_REGISTER_REGEX_OP
1822#define XLAT_REGISTER_REGEX_OP(_op, _name) \
1824 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _name, FR_TYPE_BOOL)) == NULL)) return -1; \
1825 xlat_func_args_set(xlat, regex_op_xlat_args); \
1826 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1827 xlat_func_instantiate_set(xlat, xlat_instantiate_regex, xlat_regex_inst_t, NULL, NULL); \
1828 xlat_func_print_set(xlat, xlat_expr_print_regex); \
1829 xlat->token = _op; \
1832#define XLAT_REGISTER_BOOL(_xlat, _func, _arg, _ret_type) \
1834 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, _ret_type)) == NULL)) return -1; \
1835 xlat_func_args_set(xlat, _arg); \
1836 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
1839#define XLAT_REGISTER_UNARY(_op, _xlat, _func) \
1841 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, FR_TYPE_VOID)) == NULL)) return -1; \
1842 xlat_func_args_set(xlat, unary_op_xlat_args); \
1843 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1844 xlat_func_print_set(xlat, xlat_expr_print_unary); \
1845 xlat->token = _op; \
1923 [
T_OR ] =
L(
"op_or"),
1928 [
T_LAND ] =
L(
"logical_and"),
1929 [
T_LOR ] =
L(
"logical_or"),
1972#define P(_x, _y) (((_x) << 4) | (_y))
2028#define fr_sbuff_skip_whitespace(_x) \
2030 while (isspace((uint8_t) fr_sbuff_char(_x, '\0'))) fr_sbuff_advance(_x, 1); \
2034 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2035 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2036 fr_sbuff_parse_rules_t
const *input_rules,
bool cond) CC_HINT(
nonnull(1,2,3,4,5));
2039 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2040 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
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));
2069 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2070 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2088 goto check_for_double;
2102 goto check_for_double;
2109 goto check_for_double;
2141 unary->call.args->is_argv =
true;
2143 if (
tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, out_c, (c ==
'!')) <= 0) {
2154 unary->flags.can_purify = (unary->call.func->flags.pure && unary->call.args->flags.pure) | unary->call.args->flags.can_purify;
2199 node->data.vb_uint8 =
type;
2202 (void) talloc_steal(cast, child);
2220 fr_sbuff_marker(&m, &our_in);
2250 fr_sbuff_parse_rules_t
const *bracket_rules)
2266 fr_sbuff_marker(&opand_m, &our_in);
2275 if (!fr_sbuff_is_str(&our_in,
"m'", 2)) {
2315 fr_sbuff_marker(&flag, &our_in);
2316 if (tmpl_regex_flags_substr(
vpt, &our_in, bracket_rules->terminals) < 0) {
2328 slen = tmpl_regex_compile(
vpt,
true);
2329 if (slen <= 0)
goto error;
2332 node->
quote = quote;
2351 if (slen <= 0)
return 0;
2368 node->call.func = func;
2392 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2393 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2416 our_t_rules = *t_rules;
2418 cast_type = our_t_rules.
cast;
2419 enumv = our_t_rules.
enumv;
2435 our_t_rules.
enumv = enumv = NULL;
2450 our_t_rules.
enumv = NULL;
2491 fr_sbuff_marker(&opand_m, &our_in);
2497 p_rules = bracket_rules;
2524 if (node->data.
type != cast_type) {
2698#ifdef STATIC_ANALYZER
2699 if (!node)
return false;
2734 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2735 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2736 fr_sbuff_parse_rules_t
const *input_rules,
bool cond)
2750 fr_sbuff_marker(&m_lhs, &our_in);
2755 slen =
tokenize_unary(
head, &lhs, &our_in, p_rules, t_rules, bracket_rules, &c, cond);
2789 if (!bracket_rules) {
2806 fr_sbuff_marker(&m_op, &our_in);
2846 if (((c ==
'!') || (c ==
'~')) && (op !=
T_LAND) && (op !=
T_LOR)) {
2847 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]);
2854 fr_sbuff_marker(&m_rhs, &our_in);
2866 switch (lhs->
type) {
2938 if (!rhs)
goto done;
2944 if ((lhs->
type ==
XLAT_FUNC) && (lhs->call.func->token == op)) {
2947 lhs->call.args->
flags.
can_purify |= rhs->flags.can_purify | rhs->flags.pure;
2981 if (rcode < 0)
goto fail_lhs;
3006 node->call.args->flags.can_purify |= arg->flags.can_purify | arg->flags.pure;
3007 if (node->call.args->flags.can_purify)
break;
3009 node->flags.can_purify = node->call.args->flags.can_purify;
3012 node->flags.can_purify = (node->call.func->flags.pure && node->call.args->flags.pure) | node->call.args->flags.can_purify;
3045 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
bool cond)
3048 fr_sbuff_parse_rules_t *bracket_rules = NULL;
3049 fr_sbuff_parse_rules_t *terminal_rules = NULL;
3059 MEM(bracket_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3060 MEM(terminal_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3062 *bracket_rules = *p_rules;
3063 *terminal_rules = *p_rules;
3065 if (p_rules->terminals) {
3076 terminal_rules->terminals,
3080 if (!t_rules) t_rules = &my_rules;
3121 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3126 if (slen < 0)
return slen;
3128#ifdef STATIC_ANALYZER
3133 if (!
out)
return -1;
3149 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3154 if (slen < 0)
return slen;
3156#ifdef STATIC_ANALYZER
3157 if (!
out)
return -1;
3191 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, 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_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.
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)
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))
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)