27RCSID(
"$Id: 236fe9d4a12a5d6097e5ea35c977c18009553c1e $")
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/unlang/xlat_priv.h>
31#include <freeradius-devel/util/calc.h>
32#include <freeradius-devel/server/tmpl_dcursor.h>
33#include <freeradius-devel/unlang/xlat_func.h>
37# define XLAT_DEBUG(_fmt, ...) DEBUG3("%s[%i] "_fmt, __FILE__, __LINE__, ##__VA_ARGS__)
39# define XLAT_DEBUG(...)
98 talloc_steal(group->group, node);
311 a = fr_value_box_list_head(
in);
312 b = fr_value_box_list_next(
in, a);
321 if (fr_value_box_list_num_elements(&a->vb_group) > 1) {
322 REDEBUG(
"Expected one value as the first argument, got %u",
323 fr_value_box_list_num_elements(&a->vb_group));
326 a = fr_value_box_list_head(&a->vb_group);
328 if (fr_value_box_list_num_elements(&b->vb_group) > 1) {
329 REDEBUG(
"Expected one value as the second argument, got %u",
330 fr_value_box_list_num_elements(&b->vb_group));
333 b = fr_value_box_list_head(&b->vb_group);
355 if (enumv) dst->enumv = enumv;
362#define XLAT_BINARY_FUNC(_name, _op) \
363static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
364 xlat_ctx_t const *xctx, \
365 request_t *request, fr_value_box_list_t *in) \
367 return xlat_binary_op(ctx, out, xctx, request, in, _op, FR_TYPE_NULL, NULL); \
398 a = fr_value_box_list_head(
in);
399 b = fr_value_box_list_next(
in, a);
425#define XLAT_CMP_FUNC(_name, _op) \
426static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
427 xlat_ctx_t const *xctx, \
428 request_t *request, fr_value_box_list_t *in) \
430 return xlat_cmp_op(ctx, out, xctx, request, in, _op); \
531 inst->op = xctx->
ex->call.func->token;
532 inst->regex_flags = tmpl_regex_flags(regex->vpt);
534 inst->xlat = talloc_steal(
inst, regex);
554 inst->regex = tmpl_regex(regex->vpt);
624 fr_regmatch_t *regmatch;
633 arg = fr_value_box_list_head(
in);
637 subcaptures = regex_subcapture_count(*preg);
638 if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1;
639 MEM(regmatch = regex_match_data_alloc(NULL, subcaptures));
641 while ((vb = fr_value_box_list_pop_head(&arg->vb_group)) != NULL) {
643 subject = vb->vb_strvalue;
647 fr_value_box_list_t list;
649 fr_value_box_list_init(&list);
650 fr_value_box_list_insert_head(&list, vb);
658 RPEDEBUG(
"Failed concatenating regular expression string");
670 ret = regex_exec(*preg, subject, len, regmatch);
679 regex_sub_to_request(request, NULL, NULL);
683 regex_sub_to_request(request, preg, ®match);
710 regex_t *preg = NULL;
730 RPEDEBUG(
"Failed concatenating regular expression string");
737 tmpl_regex_flags(
inst->xlat->vpt),
true,
true);
756 preg = tmpl_regex(
inst->xlat->vpt);
762 fr_value_box_list_init(&rctx->
list);
776#define XLAT_REGEX_FUNC(_name, _op) \
777static xlat_action_t xlat_func_ ## _name(TALLOC_CTX *ctx, fr_dcursor_t *out, \
778 xlat_ctx_t const *xctx, \
779 request_t *request, fr_value_box_list_t *in) \
781 return xlat_regex_op(ctx, out, xctx, request, in, _op); \
814 head = node->call.args;
829 for (i = 0; i <
inst->argc; i++) {
831 if (i == (
inst->argc - 1))
break;
855 if (!
head->flags.pure)
return false;
885 if (!*result)
return true;
893 talloc_free_children(
parent);
915 (void) talloc_steal(
head, node);
941 for (i = 0; i <
inst->argc; i++) {
946 if (
inst->argv[i]->flags.can_purify) {
970 if (result)
return 0;
976 if (((i + 1) ==
inst->argc) && (deleted == i))
break;
978 TALLOC_FREE(
inst->argv[i]);
982 if (!deleted)
return 0;
990 while (i < (
inst->argc - deleted)) {
999 if (j < 0) j = i + 1;
1005 while (j < inst->argc) {
1006 if (
inst->argv[j])
break;
1014 inst->argv[j++] = NULL;
1017 inst->argc -= deleted;
1019 if (
inst->argc > 1)
return 0;
1024 group =
inst->argv[0];
1026 talloc_steal(node, group);
1039 node->group = group;
1098 if (!fr_value_box_list_num_elements(
in))
return false;
1159 if (match)
goto done;
1161 fr_value_box_list_talloc_free(&rctx->
list);
1200 if (!fr_value_box_list_num_elements(
in))
return false;
1228 if (!found)
return false;
1269 fr_value_box_list_talloc_free(&rctx->
list);
1300 if (xctx->
ex->call.func->token ==
T_LOR) {
1302 inst->stop_on_match =
true;
1305 inst->stop_on_match =
false;
1326 if (
inst->stop_on_match) {
1330 rctx->
box->vb_bool =
true;
1332 fr_value_box_list_init(&rctx->
list);
1341 { .
required =
true, .single =
true, .concat =
true },
1355 group = fr_value_box_list_head(
in);
1356 vb = fr_value_box_list_head(&group->vb_group);
1395 group = fr_value_box_list_head(
in);
1396 vb = fr_value_box_list_head(&group->vb_group);
1407 dst->vb_bool =
true;
1451 if (!node)
continue;
1459 node->
quote, NULL, NULL);
1460 if (slen <= 0)
continue;
1461 if ((
size_t) slen < node->
data.vb_length)
continue;
1516 rcode = &rcode_arg->data;
1518 switch (rcode->type) {
1523 ERROR(
"Unknown rcode '%pV'", rcode);
1538 ERROR(
"Invalid value for rcode '%pV'", rcode);
1545 inst->rcode = rcode->vb_uint8;
1573 if (slen < 0)
return slen;
1610 if (fr_value_box_list_num_elements(
args) == 0) {
1612 rcode =
inst->rcode;
1617 REDEBUG(
"Invalid rcode '%pV'", arg_rcode);
1622 RDEBUG3(
"Request rcode is '%s'",
1627 vb->vb_bool = (request->rcode == rcode);
1713 inst->xlat = talloc_steal(
inst, arg->group);
1720 inst->vpt = xlat->vpt;
1737 dst->vb_bool = (
vp != NULL);
1773 RPEDEBUG(
"Failed concatenating attribute name string");
1777 vb = fr_value_box_list_head(&rctx->
list);
1782 .dict_def = request->dict,
1783 .request_def = &tmpl_request_def_current,
1784 .list_def = request_attr_request,
1785 .prefix = TMPL_ATTR_REF_PREFIX_AUTO,
1786 .allow_unknown = false,
1787 .allow_unresolved = false,
1790 if (slen <= 0)
goto fail;
1826 fr_value_box_list_init(&rctx->
list);
1840#undef XLAT_REGISTER_BINARY_OP
1841#define XLAT_REGISTER_BINARY_OP(_op, _name) \
1843 if (unlikely((xlat = xlat_func_register(NULL, "op_" STRINGIFY(_name), xlat_func_op_ ## _name, FR_TYPE_VOID)) == NULL)) return -1; \
1844 xlat_func_args_set(xlat, binary_op_xlat_args); \
1845 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1846 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1847 xlat_func_instantiate_set(xlat, xlat_function_args_to_tmpl, NULL, NULL, NULL); \
1848 xlat->token = _op; \
1851#undef XLAT_REGISTER_BINARY_CMP
1852#define XLAT_REGISTER_BINARY_CMP(_op, _name) \
1854 if (unlikely((xlat = xlat_func_register(NULL, "cmp_" STRINGIFY(_name), xlat_func_cmp_ ## _name, FR_TYPE_BOOL)) == NULL)) return -1; \
1855 xlat_func_args_set(xlat, binary_cmp_xlat_args); \
1856 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1857 xlat_func_print_set(xlat, xlat_expr_print_binary); \
1858 xlat_func_resolve_set(xlat, xlat_expr_resolve_binary); \
1859 xlat->token = _op; \
1862#undef XLAT_REGISTER_NARY_OP
1863#define XLAT_REGISTER_NARY_OP(_op, _name, _func_name) \
1865 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _func_name, FR_TYPE_VOID)) == NULL)) return -1; \
1866 xlat_func_instantiate_set(xlat, xlat_instantiate_ ## _func_name, xlat_ ## _func_name ## _inst_t, NULL, NULL); \
1867 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1868 xlat_func_print_set(xlat, xlat_expr_print_nary); \
1869 xlat_purify_func_set(xlat, xlat_expr_logical_purify); \
1870 xlat->token = _op; \
1873#undef XLAT_REGISTER_REGEX_OP
1874#define XLAT_REGISTER_REGEX_OP(_op, _name) \
1876 if (unlikely((xlat = xlat_func_register(NULL, STRINGIFY(_name), xlat_func_ ## _name, FR_TYPE_VOID)) == NULL)) return -1; \
1877 xlat_func_args_set(xlat, regex_op_xlat_args); \
1878 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1879 xlat_func_instantiate_set(xlat, xlat_instantiate_regex, xlat_regex_inst_t, NULL, NULL); \
1880 xlat_func_print_set(xlat, xlat_expr_print_regex); \
1881 xlat->token = _op; \
1884#define XLAT_REGISTER_BOOL(_xlat, _func, _arg, _ret_type) \
1886 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, _ret_type)) == NULL)) return -1; \
1887 xlat_func_args_set(xlat, _arg); \
1888 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
1891#define XLAT_REGISTER_UNARY(_op, _xlat, _func) \
1893 if (unlikely((xlat = xlat_func_register(NULL, _xlat, _func, FR_TYPE_VOID)) == NULL)) return -1; \
1894 xlat_func_args_set(xlat, unary_op_xlat_args); \
1895 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
1896 xlat_func_print_set(xlat, xlat_expr_print_unary); \
1897 xlat->token = _op; \
1970 [
T_OR ] =
L(
"op_or"),
1975 [
T_LAND ] =
L(
"logical_and"),
1976 [
T_LOR ] =
L(
"logical_or"),
2014#define P(_x, _y) (((_x) << 4) | (_y))
2070#define fr_sbuff_skip_whitespace(_x) \
2072 while (isspace((uint8_t) fr_sbuff_char(_x, '\0'))) fr_sbuff_advance(_x, 1); \
2076 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2077 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2078 fr_sbuff_parse_rules_t
const *input_rules,
bool cond);
2081 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2082 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond);
2107 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2108 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2126 goto check_for_double;
2140 goto check_for_double;
2147 goto check_for_double;
2177 unary->call.func = func;
2179 unary->flags = func->
flags;
2182 if (
tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, out_c, (c ==
'!')) <= 0) {
2193 unary->flags.can_purify = (unary->call.func->flags.pure && unary->call.args->flags.pure) | unary->call.args->flags.can_purify;
2238 node->data.vb_uint8 =
type;
2257 fr_sbuff_marker(&m, &our_in);
2287 fr_sbuff_parse_rules_t
const *bracket_rules)
2303 fr_sbuff_marker(&opand_m, &our_in);
2312 if (!fr_sbuff_is_str(&our_in,
"m'", 2)) {
2352 fr_sbuff_marker(&flag, &our_in);
2353 if (tmpl_regex_flags_substr(
vpt, &our_in, bracket_rules->terminals) < 0) {
2365 slen = tmpl_regex_compile(
vpt,
true);
2366 if (slen <= 0)
goto error;
2370 node->
quote = quote;
2391 if (slen <= 0)
return 0;
2400 node->call.func = func;
2429 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2430 fr_sbuff_parse_rules_t
const *bracket_rules,
char *out_c,
bool cond)
2454 our_t_rules = *t_rules;
2456 cast_type = our_t_rules.
cast;
2457 enumv = our_t_rules.
enumv;
2473 our_t_rules.
enumv = enumv = NULL;
2488 our_t_rules.
enumv = NULL;
2521 fr_sbuff_marker(&opand_m, &our_in);
2528 p_rules = bracket_rules;
2566 if ((p[0] == c) && (p[1] == c)) {
2588 if ((slen < 0) || ((slen == 0) && (quote ==
T_BARE_WORD))) {
2615 }
while (--triple > 0);
2638 p =
vpt->name + talloc_array_length(
vpt->name) - 2;
2641 fr_strerror_const(
"Alternation is no longer supported. Use '%{a || b}' instead of '%{a:-b}'");
2755 node->
quote = quote;
2776 if (
vpt->name[0] ==
'%') {
2850#ifdef STATIC_ANALYZER
2851 if (!node)
return false;
2886 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
2887 fr_token_t prev, fr_sbuff_parse_rules_t
const *bracket_rules,
2888 fr_sbuff_parse_rules_t
const *input_rules,
bool cond)
2902 fr_sbuff_marker(&m_lhs, &our_in);
2907 slen =
tokenize_unary(
head, &lhs, &our_in, p_rules, t_rules, bracket_rules, &c, cond);
2919#ifdef STATIC_ANALYZER
2944 if (!bracket_rules) {
2961 fr_sbuff_marker(&m_op, &our_in);
3001 if (((c ==
'!') || (c ==
'~')) && (op !=
T_LAND) && (op !=
T_LOR)) {
3002 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]);
3009 fr_sbuff_marker(&m_rhs, &our_in);
3060#ifdef STATIC_ANALYZER
3061 if (!rhs)
return -1;
3068 if ((lhs->
type ==
XLAT_FUNC) && (lhs->call.func->token == op)) {
3071 lhs->call.args->
flags.
can_purify |= rhs->flags.can_purify | rhs->flags.pure;
3105 if (rcode < 0)
goto fail_lhs;
3118 node->call.func = func;
3120 node->flags = func->
flags;
3133 node->call.args->flags.can_purify |= arg->flags.can_purify | arg->flags.pure;
3134 if (node->call.args->flags.can_purify)
break;
3136 node->flags.can_purify = node->call.args->flags.can_purify;
3139 node->flags.can_purify = (node->call.func->flags.pure && node->call.args->flags.pure) | node->call.args->flags.can_purify;
3172 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules,
bool cond)
3175 fr_sbuff_parse_rules_t *bracket_rules = NULL;
3176 fr_sbuff_parse_rules_t *terminal_rules = NULL;
3186 MEM(bracket_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3187 MEM(terminal_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
3189 *bracket_rules = *p_rules;
3190 *terminal_rules = *p_rules;
3192 if (p_rules->terminals) {
3203 terminal_rules->terminals,
3207 if (!t_rules) t_rules = &my_rules;
3229 fr_strerror_const(
"Unexpected text - attribute names must be prefixed with '&'");
3259 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3265 fr_sbuff_parse_rules_t
const *p_rules,
tmpl_rules_t const *t_rules)
3289 if (!
head->flags.pure)
goto return_false;
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define L(_str)
Helper for initialising arrays of string literals.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
int fr_value_calc_list_cmp(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_list_t const *list1, fr_token_t op, fr_value_box_list_t const *list2)
int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Calculate DST = A OP B.
int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
Calculate unary operations.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
fr_dict_t const * fr_dict_internal(void)
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static xlat_action_t xlat_func_rcode(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *args)
Return the current rcode as a string.
static xlat_action_t xlat_func_exists(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
See if a named attribute exists.
static xlat_action_t xlat_func_expr_rcode(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Match the passed rcode against request->rcode.
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
#define RPEDEBUG(fmt,...)
@ TMPL_ATTR_REF_PREFIX_NO
Attribute refs have no '&' prefix.
@ TMPL_ATTR_REF_PREFIX_YES
Attribute refs must have '&' prefix.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
#define check(_handle, _len_p)
fr_table_num_sorted_t const rcode_table[]
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
fr_sbuff_term_t * fr_sbuff_terminals_amerge(TALLOC_CTX *ctx, fr_sbuff_term_t const *a, fr_sbuff_term_t const *b)
Merge two sets of terminal strings.
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_out_by_longest_prefix(_match_len, _out, _table, _sbuff, _def)
#define fr_sbuff_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_IN(_start, _len_or_end)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
#define fr_sbuff_current(_sbuff_or_marker)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_used_total(_sbuff_or_marker)
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define fr_sbuff_is_digit(_sbuff_or_marker)
#define SBUFF_CHAR_UNPRINTABLES_EXTENDED
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define SBUFF_CHAR_UNPRINTABLES_LOW
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_IN_STRCPY_RETURN(...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Terminal element with pre-calculated lengths.
Set of terminal elements.
#define tmpl_contains_xlat(vpt)
#define tmpl_is_attr_unresolved(vpt)
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules))
Attempt to resolve functions and attributes in xlats and attribute references.
#define tmpl_value(_tmpl)
int tmpl_attr_unknown_add(tmpl_t *vpt)
Add an unknown fr_dict_attr_t specified by a tmpl_t to the main dictionary.
#define tmpl_contains_regex(vpt)
#define tmpl_is_attr(vpt)
fr_dict_attr_t const * enumv
Enumeration attribute used to resolve enum values.
#define tmpl_value_enumv(_tmpl)
#define tmpl_rules_cast(_tmpl)
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, char const *name, tmpl_rules_t const *rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
#define tmpl_contains_attr(vpt)
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
tmpl_xlat_rules_t xlat
Rules/data for parsing xlats.
static bool tmpl_is_list(tmpl_t const *vpt)
int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv))
Convert tmpl_t of type TMPL_TYPE_DATA_UNRESOLVED or TMPL_TYPE_DATA to TMPL_TYPE_DATA of type specifie...
#define tmpl_is_data(vpt)
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_slen_t xlat_print(fr_sbuff_t *in, xlat_exp_head_t const *node, fr_sbuff_escape_rules_t const *e_rules)
Reconstitute an xlat expression from its constituent nodes.
bool required
Argument must be present, and non-empty.
int xlat_flatten_compiled_argv(TALLOC_CTX *ctx, xlat_exp_head_t ***argv, xlat_exp_head_t *head)
Turn xlat_tokenize_argv() into an argv[] array, and nuke the input list.
bool concat
Concat boxes together.
static fr_slen_t xlat_aprint(TALLOC_CTX *ctx, char **out, xlat_exp_head_t const *head, fr_sbuff_escape_rules_t const *e_rules) 1(xlat_print
bool can_purify
if the xlat has a pure function with pure arguments.
int xlat_purify_op(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_exp_t *lhs, fr_token_t op, xlat_exp_t *rhs)
xlat_action_t(* xlat_func_t)(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
xlat callback function
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
bool pure
has no external side effects, true for BOX, LITERAL, and some functions
bool needs_resolving
Needs pass2 resolution.
int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
Walk over an xlat tree recursively, resolving any unresolved functions or references.
#define XLAT_ARG_PARSER_TERMINATOR
int xlat_finalize(xlat_exp_head_t *head, fr_event_list_t *runtime_el)
Bootstrap static xlats, or instantiate ephemeral ones.
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
bool constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
bool impure_func
xlat contains an impure function
int xlat_instance_unregister_func(xlat_exp_t *node)
Remove a node from the list of xlat instance data.
Definition for a single argument consumend by an xlat function.
Flags that control resolution and evaluation.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
#define fr_type_is_variable_size(_x)
#define fr_type_is_structural(_x)
#define fr_type_is_null(_x)
#define fr_type_is_leaf(_x)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
fr_sbuff_parse_rules_t const * value_parse_rules_3quoted[T_TOKEN_LAST]
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
ssize_t fr_value_box_list_concat_as_string(bool *tainted, bool *secret, fr_sbuff_t *sbuff, fr_value_box_list_t *list, char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules, fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
Concatenate a list of value boxes together.
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
#define fr_box_strvalue_len(_val, _len)
#define fr_box_is_group(_x)
#define VALUE_BOX_LIST_VERIFY(_x)
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
#define fr_value_box_list_foreach(_list_head, _iter)
static size_t char ** out
void xlat_exp_set_name(xlat_exp_t *node, char const *fmt, size_t len)
Set the format string for an xlat node.
void xlat_exp_set_name_buffer_shallow(xlat_exp_t *node, char const *fmt)
Set the format string for an xlat node from a pre-existing buffer.
void * rctx
Resume context.
xlat_exp_t * ex
Tokenized expression to use in expansion.
void const * inst
xlat instance data.
void * inst
xlat instance data to populate.
An xlat instantiation ctx.
fr_dict_attr_t const * attr_expr_bool_enum
fr_dict_attr_t const * attr_cast_base
static const fr_sbuff_escape_rules_t regex_escape_rules
tmpl_t const * vpt
the attribute reference
#define fr_sbuff_skip_whitespace(_x)
static size_t const expr_assignment_op_table_len
static fr_slen_t xlat_expr_print_binary(fr_sbuff_t *out, xlat_exp_t const *node, UNUSED void *inst, fr_sbuff_escape_rules_t const *e_rules)
#define XLAT_REGISTER_BOOL(_xlat, _func, _arg, _ret_type)
static fr_slen_t xlat_expr_print_rcode(fr_sbuff_t *out, xlat_exp_t const *node, void *instance, UNUSED fr_sbuff_escape_rules_t const *e_rules)
static xlat_action_t xlat_regex_match(TALLOC_CTX *ctx, request_t *request, fr_value_box_list_t *in, regex_t **preg, fr_dcursor_t *out, fr_token_t op)
Perform a regular expressions comparison between two operands.
static void xlat_func_append_arg(xlat_exp_t *head, xlat_exp_t *node, bool exists)
bool xlat_is_truthy(xlat_exp_head_t const *head, bool *out)
Allow callers to see if an xlat is truthy.
static xlat_action_t xlat_func_logical(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Process logical &&, ||.
xlat_exp_t * xlat
to expand
#define XLAT_BINARY_FUNC(_name, _op)
static const fr_sbuff_term_t bracket_terms
static fr_slen_t tokenize_unary(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_sbuff_parse_rules_t const *bracket_rules, char *out_c, bool cond)
bool tmpl_require_enum_prefix
static size_t expr_quote_table_len
static xlat_action_t xlat_exists_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
static int xlat_instantiate_exists(xlat_inst_ctx_t const *xctx)
static fr_slen_t xlat_expr_print_nary(fr_sbuff_t *out, xlat_exp_t const *node, void *instance, fr_sbuff_escape_rules_t const *e_rules)
int xlat_register_expressions(void)
xlat_exp_head_t * xlat
the xlat which needs expanding
static xlat_arg_parser_t const xlat_func_exists_arg[]
static xlat_action_t xlat_logical_process_arg(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Process one argument of a logical operation.
static fr_slen_t xlat_tokenize_expression_internal(TALLOC_CTX *ctx, xlat_exp_head_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, bool cond)
static int xlat_function_args_to_tmpl(xlat_inst_ctx_t const *xctx)
Convert XLAT_BOX arguments to XLAT_TMPL.
static fr_slen_t xlat_expr_print_unary(fr_sbuff_t *out, xlat_exp_t const *node, UNUSED void *inst, fr_sbuff_escape_rules_t const *e_rules)
static xlat_arg_parser_t const regex_op_xlat_args[]
static void xlat_ungroup(xlat_exp_head_t *head)
Undo work which shouldn't have been done.
static xlat_action_t xlat_func_unary_complement(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static xlat_action_t xlat_cmp_op(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in, fr_token_t op)
static const int precedence[T_TOKEN_LAST]
static xlat_action_t xlat_func_unary_minus(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static xlat_action_t xlat_logical_or_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static fr_table_num_sorted_t const expr_quote_table[]
#define XLAT_REGISTER_BINARY_OP(_op, _name)
#define XLAT_REGEX_FUNC(_name, _op)
static fr_slen_t tokenize_rcode(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in)
static xlat_action_t xlat_binary_op(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in, fr_token_t op, fr_type_t default_type, fr_dict_attr_t const *enumv)
static bool valid_type(xlat_exp_t *node)
static xlat_exp_t * expr_cast_alloc(TALLOC_CTX *ctx, fr_type_t type)
Allocate a specific cast node.
static bool xlat_logical_and(xlat_logical_rctx_t *rctx, fr_value_box_list_t const *in)
See if the input is truthy or not.
fr_value_box_t * box
output value-box
static xlat_action_t xlat_regex_op(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in, fr_token_t op)
static xlat_action_t xlat_func_unary_not(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
fr_regex_flags_t * regex_flags
static bool xlat_node_matches_bool(bool *result, xlat_exp_t *parent, xlat_exp_head_t *head, bool sense)
static int xlat_instantiate_regex(xlat_inst_ctx_t const *xctx)
static xlat_action_t xlat_func_unary_op(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in, fr_token_t op)
static int xlat_expr_resolve_binary(xlat_exp_t *node, UNUSED void *inst, xlat_res_rules_t const *xr_rules)
static const bool logical_ops[T_TOKEN_LAST]
static xlat_arg_parser_t const binary_op_xlat_args[]
static xlat_action_t xlat_attr_exists(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, tmpl_t const *vpt, bool do_free)
static xlat_arg_parser_t const binary_cmp_xlat_args[]
static const bool multivalue_ops[T_TOKEN_LAST]
static const fr_sbuff_term_elem_t binary_ops[T_TOKEN_LAST]
static bool xlat_logical_or(xlat_logical_rctx_t *rctx, fr_value_box_list_t const *in)
See if the input is truthy or not.
regex_t * regex
precompiled regex
#define XLAT_REGISTER_NARY_OP(_op, _name, _func_name)
static int xlat_instantiate_expr_rcode(xlat_inst_ctx_t const *xctx)
Convert static expr_rcode arguments into rcodes.
static void fr_value_box_init_zero(fr_value_box_t *vb, fr_type_t type)
static xlat_action_t xlat_regex_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static fr_table_num_ordered_t const expr_assignment_op_table[]
static xlat_exp_t * xlat_exists_alloc(TALLOC_CTX *ctx, xlat_exp_t *child)
Allocate a specific cast node.
static fr_slen_t expr_cast_from_substr(fr_type_t *cast, fr_sbuff_t *in)
#define XLAT_REGISTER_BINARY_CMP(_op, _name)
static xlat_arg_parser_t const xlat_func_rcode_arg[]
Takes no arguments.
static int xlat_expr_logical_purify(xlat_exp_t *node, void *instance, request_t *request)
If any argument resolves to inst->stop_on_match, the entire thing is a bool of inst->stop_on_match.
rlm_rcode_t rcode
The preparsed rcode.
static fr_slen_t xlat_expr_print_exists(fr_sbuff_t *out, xlat_exp_t const *node, void *instance, fr_sbuff_escape_rules_t const *e_rules)
static int xlat_instantiate_logical(xlat_inst_ctx_t const *xctx)
#define XLAT_REGISTER_UNARY(_op, _xlat, _func)
static xlat_arg_parser_t const unary_op_xlat_args[]
fr_slen_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
static xlat_arg_parser_t const xlat_func_expr_rcode_arg[]
static fr_slen_t tokenize_regex_rhs(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, tmpl_rules_t const *t_rules, fr_sbuff_parse_rules_t const *bracket_rules)
static fr_slen_t xlat_expr_print_regex(fr_sbuff_t *out, xlat_exp_t const *node, void *instance, fr_sbuff_escape_rules_t const *e_rules)
static const fr_sbuff_term_t operator_terms
#define XLAT_REGISTER_REGEX_OP(_op, _name)
static xlat_action_t xlat_logical_and_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static ssize_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_sbuff_parse_rules_t const *bracket_rules, char *out_c, bool cond)
static ssize_t tokenize_expression(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_token_t prev, fr_sbuff_parse_rules_t const *bracket_rules, fr_sbuff_parse_rules_t const *input_rules, bool cond)
Tokenize a mathematical operation.
#define XLAT_CMP_FUNC(_name, _op)
fr_slen_t xlat_tokenize_condition(TALLOC_CTX *ctx, xlat_exp_head_t **out, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
Holds the result of pre-parsing the rcode on startup.
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
void xlat_func_print_set(xlat_t *xlat, xlat_print_t func)
Set a print routine for an xlat function.
xlat_t * xlat_func_find(char const *in, ssize_t inlen)
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
@ XLAT_FUNC_FLAG_INTERNAL
#define xlat_exp_head_alloc(_ctx)
xlat_flags_t flags
Flags that control resolution and evaluation.
static xlat_exp_t * xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
xlat_flags_t flags
Flags that control resolution and evaluation.
fr_token_t quote
Type of quoting around XLAT_GROUP types.
@ XLAT_TMPL
xlat attribute
@ XLAT_GROUP
encapsulated string of xlats
static void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
Merge flags from child to parent.
#define xlat_exp_set_type(_node, _type)
fr_token_t token
for expressions
char const *_CONST fmt
The original format string (a talloced buffer).
ssize_t xlat_print_node(fr_sbuff_t *out, xlat_exp_head_t const *head, xlat_exp_t const *node, fr_sbuff_escape_rules_t const *e_rules, char c)
int xlat_purify_list(xlat_exp_head_t *head, request_t *request)
xlat_type_t _CONST type
type of this expansion.
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
xlat_flags_t flags
various flags
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)