26 RCSID(
"$Id: 2805d6b685361e1715de88d8533d0a5beaa503c1 $")
28 #include <freeradius-devel/server/log.h>
29 #include <freeradius-devel/server/cf_util.h>
30 #include <freeradius-devel/server/tmpl.h>
31 #include <freeradius-devel/server/request.h>
32 #include <freeradius-devel/server/section.h>
33 #include <freeradius-devel/unlang/tmpl.h>
34 #include <freeradius-devel/unlang/function.h>
35 #include <freeradius-devel/unlang/interpret.h>
36 #include <freeradius-devel/unlang/call_env.h>
37 #include <freeradius-devel/util/token.h>
57 #if defined(DEBUG_CALL_ENV)
58 # define CALL_ENV_DEBUG(_ci, fmt, ...) cf_log_debug(_ci, fmt, ##__VA_ARGS__)
60 # define CALL_ENV_DEBUG(_ci, ...)
65 static inline CC_HINT(always_inline)
68 fr_value_box_list_t *tmpl_expanded)
75 vb = fr_value_box_list_head(tmpl_expanded);
78 RPEDEBUG(
"Failed to evaluate required module option %s = %s", env->rule->name, env->data.tmpl->name);
90 RPEDEBUG(
"Failed concatenating values for %s", env->rule->name);
94 if (
call_env_single(env->rule->flags) && (fr_value_box_list_num_elements(tmpl_expanded) > 1)) {
95 RPEDEBUG(
"%d values found for %s. Only one is allowed",
96 fr_value_box_list_num_elements(tmpl_expanded), env->rule->name);
100 while ((vb = fr_value_box_list_pop_head(tmpl_expanded))) {
101 switch (env->rule->pair.type) {
107 if (!fr_value_box_list_initialised((fr_value_box_list_t *)
out)) fr_value_box_list_init((fr_value_box_list_t *)
out);
108 fr_value_box_list_insert_tail((fr_value_box_list_t *)
out, vb);
158 if (env->
rule->pair.parsed.offset >= 0) {
177 env->
count,
"void *"));
184 switch (env->
rule->pair.parsed.type) {
210 ctx = *call_env_rctx->
data;
225 MEM(
array = _talloc_zero_array((*call_env_rctx->
data), env->
rule->pair.size,
245 void *
out = NULL, *tmpl_out = NULL;
269 if (env->
rule->pair.parsed.offset >= 0) tmpl_out = ((
uint8_t *)*call_env_rctx->
data) + env->
rule->pair.parsed.offset;
274 if (call_env_rctx->
result) *call_env_rctx->
result = result;
278 if (!call_env_parsed_next(&call_env_rctx->
call_env->
parsed, env)) {
303 call_env_rctx->
result = env_result;
305 call_env_rctx->
data = env_data;
316 static inline CC_HINT(always_inline)
322 call_env_parsed->
rule = rule;
323 call_env_parsed->
count = 1;
326 return call_env_parsed;
329 static inline CC_HINT(always_inline)
336 tmpl = parsed->data.tmpl;
337 switch (tmpl->type) {
342 cf_log_perr(ci,
"'%s' expands to %s - attribute reference required", tmpl->name,
352 cf_log_err(ci,
"'%s' expands to invalid tmpl type %s", tmpl->name,
387 *(
void **)
out = parsed_tmpl;
419 while (rule_p->
name) {
434 if (rule_p->section.func) {
443 if (rule_p->section.func(ctx, parsed, t_rules,
cf_section_to_item(subcs), cec, rule_p) < 0) {
444 cf_log_perr(cs,
"Failed parsing configuration section %s", rule_p->
name);
450 call_env_parsed_num_elements(parsed));
457 call_env_parsed = last;
458 while ((call_env_parsed = call_env_parsed_next(parsed, call_env_parsed))) {
468 if (
call_env_parse(ctx, parsed,
name, t_rules, subcs, cec, rule_p->section.subcs) < 0) {
477 if (!cp && !rule_p->pair.dflt) {
480 cf_log_err(cs,
"Missing required config item '%s'", rule_p->
name);
496 for (multi_index = 0; multi_index <
count; multi_index++) {
506 our_rules.
escape = rule_p->pair.escape;
550 if (!call_env_parsed->
data.ptr) {
560 call_env_parsed_insert_tail(parsed, call_env_parsed);
569 CALL_ENV_DEBUG(cs,
"Returning afer processing %u rules", (
unsigned int)(rule_p - rule));
585 size_t pair_count, tmpl_count = 0;
590 while (call_env->
name) {
594 if (!subcs)
goto next;
599 if (call_env->section.subcs) tmpl_count +=
call_env_count(names_len, subcs, call_env->section.subcs);
608 if (!pair_count && call_env->pair.dflt) {
610 *names_len += strlen(call_env->pair.dflt);
612 tmpl_count += pair_count;
645 memcpy(our_rules, rule,
sizeof(*our_rules));
646 call_env_parsed->
rule = our_rules;
647 call_env_parsed_insert_tail(
head, call_env_parsed);
649 return call_env_parsed;
663 parsed->
data.tmpl = tmpl;
677 parsed->
data.vb = vb;
720 call_env_parsed_remove(parsed, ptr);
765 call_env->
method = call_env_method;
766 call_env_parsed_init(&call_env->
parsed);
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
static unlang_action_t call_env_expand_repeat(rlm_rcode_t *p_result, int *priority, request_t *request, void *uctx)
call_env_parser_t const * rule
Used to produce this.
size_t count
Number of CONF_PAIRs found, matching the call_env_parser_t.
static unlang_action_t call_env_expand_start(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Start the expansion of a call environment tmpl.
call_env_parsed_t const * last_expanded
The last expanded tmpl.
static call_env_result_t call_env_result(TALLOC_CTX *ctx, request_t *request, void *out, void **tmpl_out, call_env_parsed_t const *env, fr_value_box_list_t *tmpl_expanded)
Parse the result of call_env tmpl expansion.
void call_env_parsed_free(call_env_parsed_head_t *parsed, call_env_parsed_t *ptr)
Remove a call_env_parsed_t from the list of parsed call envs.
static call_env_parsed_t * call_env_parsed_alloc(TALLOC_CTX *ctx, call_env_parser_t const *rule)
Allocates a new call env parsed struct.
#define CALL_ENV_DEBUG(_ci,...)
call_env_parsed_t * call_env_parsed_add(TALLOC_CTX *ctx, call_env_parsed_head_t *head, call_env_parser_t const *rule)
Allocate a new call_env_parsed_t structure and add it to the list of parsed call envs.
static int call_env_parsed_valid(call_env_parsed_t const *parsed, CONF_ITEM const *ci, call_env_parser_t const *rule)
int call_env_parse_pair(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, UNUSED call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
Standard function we use for parsing call env pairs.
unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, call_env_result_t *env_result, void **env_data, call_env_t const *call_env)
Initialise the expansion of a call environment.
call_env_t const * call_env
Call env being expanded.
static size_t call_env_count(size_t *names_len, CONF_SECTION const *cs, call_env_parser_t const *call_env)
Perform a quick assessment of how many parsed call env will be produced.
size_t multi_index
Array index for this instance.
void call_env_parsed_set_multi_index(call_env_parsed_t *parsed, size_t count, size_t index)
Assign a count and index to a call_env_parsed_t.
call_env_parsed_entry_t entry
Entry in list of parsed call_env_parsers.
call_env_result_t * result
Where to write the return code of callenv expansion.
static int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char const *name, tmpl_rules_t const *t_rules, CONF_SECTION const *cs, call_env_ctx_t const *cec, call_env_parser_t const *rule)
Parse per call env.
void ** data
Final destination structure for value boxes.
fr_value_box_list_t tmpl_expanded
List to write value boxes to as tmpls are expanded.
void call_env_parsed_set_data(call_env_parsed_t *parsed, void const *data)
Assign data to a call_env_parsed_t.
void call_env_parsed_set_value(call_env_parsed_t *parsed, fr_value_box_t const *vb)
Assign a value box to a call_env_parsed_t.
union call_env_parsed_s::@98 data
call_env_t * call_env_alloc(TALLOC_CTX *ctx, char const *name, call_env_method_t const *call_env_method, tmpl_rules_t const *t_rules, CONF_SECTION *cs, call_env_ctx_t const *cec)
Given a call_env_method, parse all call_env_pair_t in the context of a specific call to an xlat or mo...
void call_env_parsed_set_tmpl(call_env_parsed_t *parsed, tmpl_t const *tmpl)
Assign a tmpl to a call_env_parsed_t.
Context to keep track of expansion of call environments.
Structures and functions for handling call environments.
#define call_env_parse_missing(_flags)
call_env_flags_t flags
Flags controlling parser behaviour.
#define call_env_is_subsection(_flags)
#define call_env_required(_flags)
char const * name
Of conf pair to pass to tmpl_tokenizer.
#define call_env_nullable(_flags)
#define call_env_multi(_flags)
#define call_env_single(_flags)
#define call_env_concat(_flags)
@ CALL_ENV_RESULT_TYPE_VALUE_BOX_LIST
Output of the evaluation phase is a list of value boxes.
@ CALL_ENV_RESULT_TYPE_VALUE_BOX
Output of the evaluation phase is a single value box.
size_t inst_size
Size of per call env.
#define call_env_attribute(_flags)
call_env_parser_t const * env
Parsing rules for call method env.
char const * inst_type
Type of per call env.
#define call_env_parse_only(_flags)
#define call_env_force_quote(_flags)
call_env_parsed_head_t parsed
The per call parsed call environment.
@ CALL_ENV_PARSE_TYPE_VALUE_BOX
Output of the parsing phase is a single value box (static data).
@ CALL_ENV_PARSE_TYPE_TMPL
Output of the parsing phase is a tmpl_t.
@ CALL_ENV_PARSE_TYPE_VOID
Output of the parsing phase is undefined (a custom structure).
call_env_method_t const * method
The method this call env is for.
int(* call_env_parse_pair_t)(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, call_env_parser_t const *rule)
Callback for performing custom parsing of a CONF_PAIR.
Structure containing both a talloc pool, a list of parsed call_env_pairs.
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
unsigned int cf_pair_count(CONF_SECTION const *cs, char const *attr)
Count the number of times an attribute occurs in a parent section.
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_perr(_cf, _fmt,...)
fr_dcursor_eval_t void const * uctx
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define FR_DLIST_FUNCS(_name, _element_type, _element_entry)
Define type specific wrapper functions for dlists.
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
#define RPEDEBUG(fmt,...)
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
static size_t array[MY_ARRAY_SIZE]
rlm_rcode_t
Return codes indicating the result of the module call.
fr_dict_attr_t const * request_attr_request
#define FR_SBUFF_IN(_start, _len_or_end)
static char const * section_name_str(char const *name)
Return a printable string for the section name.
tmpl_escape_t escape
How escaping should be handled during evaluation.
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules))
Attempt to resolve functions and attributes in xlats and attribute references.
fr_value_box_safe_for_t literals_safe_for
safe_for value assigned to literal values in xlats, execs, and data.
tmpl_rules_t const * parent
for parent / child relationships
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
@ TMPL_TYPE_EXEC
Callout to an external script or program.
@ TMPL_TYPE_DATA
Value in native boxed format.
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.
fr_type_t cast
Whether there was an explicit cast.
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Optional arguments passed to vp_tmpl functions.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Functions which we wish were included in the standard talloc distribution.
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
int unlang_tmpl_push(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *tmpl, unlang_tmpl_args_t *args)
Push a tmpl onto the stack for evaluation.
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
static size_t char ** out