25RCSID(
"$Id: 3dbd687a6a373ce0672dc87d74849dbc8f59bd6c $")
27#include <freeradius-devel/server/tmpl_dcursor.h>
28#include <freeradius-devel/server/rcode.h>
29#include <freeradius-devel/unlang/action.h>
30#include <freeradius-devel/unlang/unlang_priv.h>
31#include <freeradius-devel/unlang/xlat_func.h>
37#define BUFFER_SIZE (256)
104 if (
vp->
da->parent != from_parent) {
105 if (
vp->
da->flags.internal) {
113 if (!child)
continue;
164 if (!state->
key)
return 0;
171 RDEBUG(
"Failed casting 'foreach' key variable '%s' from %u", state->
key->
da->name, state->
index);
194 RDEBUG(
"Failed casting 'foreach' iteration variable '%s' from %pV", state->
value->
da->name, box);
213 RDEBUG(
"Failed expanding 'foreach' list");
227 RDEBUG(
"Failed casting 'foreach' iteration variable '%s' from %pV", state->
value->
da->name, box);
249 fr_value_box_list_init(&state->
list);
252 REDEBUG(
"Failed starting expansion of %s", state->
vpt->name);
268 if (!state->
key)
return;
270 switch (state->
key->vp_type) {
272 state->
key->vp_uint32++;
303 if (
vp->vp_type == state->
value->vp_type) {
344 if (state->
value->vp_type !=
vp->vp_type)
goto next;
356 RDEBUG(
"Failed casting 'foreach' iteration variable '%s' from %pP", state->
value->
da->name,
vp);
396 REDEBUG(
"Cannot do nested 'foreach' loops over the same attribute %pP",
vp);
424 if (state->
value->vp_type !=
vp->vp_type) {
440 RDEBUG(
"Failed casting 'foreach' iteration variable '%s' from %pP", state->
value->
da->name,
vp);
475 state->
indent = request->log.indent.unlang;
500 REDEBUG(
"Failed creating %s", gext->
key->name);
520 unsigned int break_depth;
555 char const *type_name, *variable_name;
560 char const *key_name;
606 cf_log_err(cs,
"Data being looped over in 'foreach' must be an attribute reference or dynamic expansion, not a string");
632 cf_log_warn(cs,
"Attribute reference should be updated to use %s[*]",
vpt->name);
642 cf_log_err(cs,
"Invalid content in 'foreach (...)', it must be an attribute reference or a dynamic expansion");
664 unlang_ctx2.
rules = &t_rules;
682 cf_log_err(cs,
"Dynamic expansions MUST specify a data type for the variable");
695 cf_log_err(cs,
"Unable to determine return data type from dynamic expansion");
700 cf_log_err(cs,
"Dynamic expansions MUST specify a non-structural data type for the variable");
714 cf_log_err(cs,
"Invalid data type '%s' for 'key' variable - it should be 'string' or 'uint32'",
fr_type_to_str(key_type));
739 cf_log_err(cs,
"Incompatible data types in foreach variable (%s), and reference %s being looped over (%s)",
754 if (!var)
goto error;
757 if (!var->
dict)
goto error;
766 t_rules.
attr.namespace = NULL;
793 for (unlang =
parent; unlang != NULL; unlang = unlang->
parent) {
804 cf_log_err(ci,
"Invalid location for 'break' - it can only be used inside 'foreach' or 'switch'");
818 for (unlang =
parent; unlang != NULL; unlang = unlang->
parent) {
829 cf_log_err(ci,
"Invalid location for 'continue' - it can only be used inside 'foreach'");
850 .unlang_name =
"unlang_foreach_t",
865 .unlang_name =
"unlang_group_t",
877 .unlang_name =
"unlang_group_t",
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_EXECUTE_NEXT
Execute the next unlang_t.
#define RULES_VERIFY(_cs, _rules)
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
Return variadic argument at the specified index.
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
#define cf_log_err(_cf, _fmt,...)
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
#define cf_item_next(_parent, _curr)
#define cf_log_warn(_cf, _fmt,...)
unlang_t * unlang_compile_children(unlang_group_t *g, unlang_compile_ctx_t *unlang_ctx_in)
unlang_t * unlang_compile_empty(unlang_t *parent, UNUSED unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
unlang_group_t * unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_type_t type)
int unlang_define_local_variable(CONF_ITEM *ci, unlang_variable_t *var, tmpl_rules_t *t_rules, fr_type_t type, char const *name, fr_dict_attr_t const *ref)
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_t * fr_dict_protocol_alloc(fr_dict_t const *parent)
Allocate a new local dictionary.
static int unlang_foreach_pair_copy(fr_pair_t *to, fr_pair_t *from, fr_dict_attr_t const *from_parent)
uint32_t index
for xlat results
static void unlang_foreach_attr_key_update(UNUSED request_t *request, unlang_frame_state_foreach_t *state)
char * buffer
for key values
unlang_result_t exp_result
for xlat expansion
static unlang_t * unlang_compile_break(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_action_t unlang_foreach(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
fr_dcursor_t cursor
Used to track our place in the list.
tmpl_t const * vpt
pointer to the vpt
fr_pair_t * key
local variable which contains the key
static unlang_action_t unlang_foreach_attr_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame, unlang_frame_state_foreach_t *state)
static unlang_action_t unlang_foreach_xlat_expanded(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
fr_value_box_list_t list
value box list for looping over xlats
static unlang_action_t unlang_foreach_xlat_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame, unlang_frame_state_foreach_t *state)
fr_pair_t * value
local variable which contains the value
tmpl_dcursor_ctx_t cc
tmpl cursor state
int indent
for catching indentation issues
request_t * request
The current request.
static unlang_action_t unlang_foreach_xlat_next(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
static unlang_action_t unlang_continue(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
static unlang_action_t unlang_break(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
static unlang_action_t unlang_foreach_attr_next(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
static unlang_t * unlang_compile_continue(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * unlang_compile_foreach(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
void unlang_foreach_init(void)
static int unlang_foreach_xlat_key_update(request_t *request, unlang_frame_state_foreach_t *state)
static int _free_unlang_frame_state_foreach(unlang_frame_state_foreach_t *state)
Ensure request data is pulled out of the request if the frame is popped.
static unlang_foreach_t * unlang_group_to_foreach(unlang_group_t *g)
Cast a group structure to the foreach keyword extension.
fr_dict_attr_t const * value
value variable in the foreach loop
fr_dict_attr_t const * key
key variable for the foreach loop
unlang_action_t unlang_interpret_push_children(unlang_result_t *p_result, request_t *request, rlm_rcode_t default_rcode, bool do_next_sibling)
Push the children of the current frame onto a new frame onto the stack.
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
static TALLOC_CTX * unlang_ctx
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
static char * stack[MAX_STACK]
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_GROUP
A grouping of other attributes.
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
fr_pair_t * fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Create a new valuepair.
#define RETURN_UNLANG_FAIL
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
#define RETURN_UNLANG_NOOP
Declarations for the "return" keyword, used to implement other keywords.
#define FR_SBUFF_IN(_start, _len_or_end)
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
#define tmpl_contains_xlat(vpt)
#define tmpl_is_xlat(vpt)
static bool tmpl_attr_tail_is_unspecified(tmpl_t const *vpt)
Return true if the last attribute reference is "unspecified".
#define tmpl_is_attr(vpt)
tmpl_rules_t const * parent
for parent / child relationships
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.
#define TMPL_POOL_DEF_HEADERS
Define manipulation functions for the attribute reference list.
void tmpl_attr_rewrite_leaf_num(tmpl_t *vpt, int16_t num)
Rewrite the leaf's instance number.
#define TMPL_POOL_DEF_LEN
How many additional bytes to allocate in a pool for a tmpl_t.
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.
Optional arguments passed to vp_tmpl functions.
fr_aka_sim_id_type_t type
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
uint8_t allow_wildcard
Allow the special case of .
uint8_t allow_unknown
Allow unknown attributes i.e.
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
ssize_t tmpl_dcursor_print(fr_sbuff_t *out, tmpl_dcursor_ctx_t const *cc)
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.
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.
#define XLAT_RESULT_SUCCESS(_p_result)
fr_type_t xlat_data_type(xlat_exp_head_t const *head)
unlang_result_t section_result
The aggregate result of executing all siblings in this section.
static unlang_action_t unwind_to_op_flag(unsigned int *depth_p, unlang_stack_t *stack, unlang_op_flag_t flag)
Mark the entire stack as cancelled.
#define UNLANG_NEXT_SIBLING
static void repeatable_clear(unlang_stack_frame_t *frame)
char const * debug_name
Printed in log messages when the node is executed.
void * state
Stack frame specialisations.
tmpl_rules_t const * rules
unlang_t * parent
Previous node.
fr_dict_attr_t const * root
the root of our dictionary
static void unlang_compile_ctx_copy(unlang_compile_ctx_t *dst, unlang_compile_ctx_t const *src)
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
char const * section_name1
char const * name
Unknown...
@ UNLANG_TYPE_CONTINUE
Break statement (within a UNLANG_TYPE_FOREACH).
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH or UNLANG_TYPE_CASE).
@ UNLANG_TYPE_FOREACH
Foreach section.
static void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
Mark the current stack frame up for repeat, and set a new process function.
unlang_t const * instruction
The unlang node we're evaluating.
unlang_variable_t * variables
rarely used, so we don't usually need it
char const * name
Name of the keyword.
int max_attr
1..N local attributes have been defined
fr_dict_t * dict
our dictionary
@ UNLANG_OP_FLAG_RETURN_POINT
Return point.
@ UNLANG_OP_FLAG_SINGLE_WORD
the operation is parsed and compiled as a single word
@ UNLANG_OP_FLAG_CONTINUE_POINT
Continue point.
@ UNLANG_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_BREAK_POINT
Break point.
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
char const * section_name2
unlang_op_flag_t flag
Interpreter flags for this operation.
Generic representation of a grouping.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
#define fr_type_is_structural(_x)
#define fr_type_is_numeric(_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.
#define DOC_KEYWORD_REF(_x)
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
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.
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
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.
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
String expansion ("translation").