28RCSID(
"$Id: 5b298157a12515b834e38c79886f4aa298e0bfb8 $")
30#include <freeradius-devel/server/base.h>
31#include <freeradius-devel/server/map.h>
32#include <freeradius-devel/unlang/tmpl.h>
33#include <freeradius-devel/unlang/map.h>
80#define MAP_CTX(_mod_inst, _map_inst, _rctx) &(map_ctx_t){ .moi = _mod_inst, .mpi = _map_inst, .rctx = _rctx }
115 TALLOC_FREE(frame->
state);
148 switch (update_state->
state) {
155 switch (map->
lhs->type) {
181 TALLOC_FREE(frame->
state);
191 if (!map->
rhs)
goto next;
195 switch (map->
rhs->type) {
201 request, map->
rhs, NULL) < 0) {
229 if (!fr_value_box_list_empty(&update_state->
rhs_result) &&
234 RPEDEBUG(
"Failed concatenating RHS expansion results");
243 fr_value_box_list_talloc_free(&update_state->
rhs_result);
248 fr_value_box_list_talloc_free(&update_state->
lhs_result);
281 (
sizeof(
tmpl_t) * 2) + 128),
285 fr_value_box_list_init(&update_state->
lhs_result);
286 fr_value_box_list_init(&update_state->
rhs_result);
297#ifdef WITH_VERIFY_PTR
312#ifdef WITH_VERIFY_PTR
397 fr_value_box_list_init(&map_proc_state->
src_result);
412 request,
inst->src, NULL, NULL) < 0) {
413 REDEBUG(
"Failed expanding map src");
417 fr_value_box_list_insert_head(&map_proc_state->
src_result, src_result);
422 request,
inst->src, NULL) < 0) {
456 if (child) *child = cs;
475 if (!original)
return 0;
486 if (*attr ==
'&') attr++;
487 cf_log_err(original,
"%s %s %s --> %s %s { %s %s %s }",
496 cf_log_err(original,
"--> %s %s { %s %s %s }",
513 char list_buffer[32];
514 char value_buffer[256];
515 char attr_buffer[256];
525 if (!group)
return NULL;
534 if (*name2 ==
'&') name2++;
535 snprintf(list_buffer,
sizeof(list_buffer),
"%s", name2);
551 char const *attr, *
value, *end;
554 cf_log_err(ci,
"Cannot specify subsections for 'update'");
571 if (*attr ==
'&') attr++;
573 end = strchr(attr,
'.');
574 if (!end) end = attr + strlen(attr);
602 (strchr(
value,
'.') == NULL) && (strchr(
value,
'[') != NULL)) {
603 char const *p = strchr(
value,
'[');
605 cf_log_err(cp,
"Cannot do array assignments for lists. Just use '%s %s %.*s'",
619 snprintf(attr_buffer,
sizeof(attr_buffer),
"%s", attr);
623 p = strchr(attr_buffer,
'.');
645 if (strchr(attr,
'[') == NULL) {
646 snprintf(value_buffer,
sizeof(value_buffer),
"%s[*]", attr);
648 snprintf(value_buffer,
sizeof(value_buffer),
"%s", attr);
682 if (
snprintf(value_buffer,
sizeof(value_buffer),
"%s.%s", list, attr) < 0) {
683 cf_log_err(cp,
"RHS of update too long to convert to edit automatically");
692 if (!attr)
goto list_op;
695 if (rcode < 0)
break;
708 cf_log_err(cp,
"Invalid operator for list assignment");
713 if (rcode < 0)
break;
715 if (strchr(attr,
'[') != 0) {
716 cf_log_err(cp,
"Cannot do filtering with array indexes");
751 cf_log_err(cp,
"Unsupported operator - cannot auto-convert to edit section");
778 cf_log_err(cs,
"The use of 'update' sections is forbidden by the server configuration");
806 map_list_init(&gext->
map);
808 if (rcode < 0)
return NULL;
809 if (map_list_empty(&gext->
map)) {
810 cf_log_err(cs,
"'update' sections cannot be empty");
861 quoted_str = talloc_array(g,
char, quoted_len);
885 switch (map->
lhs->type) {
892 cf_log_err(map->
ci,
"Left side of map must be an attribute "
893 "or an xlat (that expands to an attribute), not a %s",
898 switch (map->
rhs->type) {
908 cf_log_err(map->
ci,
"Right side of map must be an attribute, literal, xlat or exec, got type %s",
914 cf_log_err(map->
ci,
"Invalid operator \"%s\" in map section. "
915 "Only assignment or filter operators are allowed",
933 char const *tmpl_str;
953 cf_log_err(cs,
"'map' sections require a 'modules' section");
959 cf_log_err(cs,
"Failed to find map processor '%s'", name2);
984 &
FR_SBUFF_IN(tmpl_str, talloc_array_length(tmpl_str) - 1),
1011 cf_log_err(cs,
"Invalid third argument for map");
1019 map_list_init(&gext->
map);
1021 if (rcode < 0)
return NULL;
1022 if (map_list_empty(&gext->
map)) {
1023 cf_log_err(cs,
"'map' sections cannot be empty");
1034 cf_log_err(cs,
"Failed instantiating map function '%s'", name2);
1068 .unlang_name =
"unlang_map_t",
1080 .unlang_name =
"unlang_map_t",
1083 .frame_state_type =
"unlang_frame_state_map_proc_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_STOP_PROCESSING
Break out of processing the current request (unwind).
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define RULES_VERIFY(_cs, _rules)
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
fr_token_t cf_section_argv_quote(CONF_SECTION const *cs, int argc)
Return the quoting for one of the variadic arguments.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
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.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
void cf_section_add_name2_quote(CONF_SECTION *cs, fr_token_t token)
Set the quoting of the name2 identifier.
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
Return variadic argument at the specified index.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
#define cf_item_insert_after(_parent, _prev, _child)
#define cf_lineno_set(_ci, _lineno)
#define cf_item_remove(_parent, _child)
#define cf_item_next(_parent, _curr)
#define cf_log_perr(_cf, _fmt,...)
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
#define cf_filename_set(_ci, _filename)
bool pass2_fixup_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules)
unlang_group_t * unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_type_t type)
bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules)
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.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static bool fr_dlist_empty(fr_dlist_head_t const *list_head)
Check whether a list has any items.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Head of a doubly linked list.
#define RPEDEBUG(fmt,...)
int map_afrom_cs(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into an attribute map.
static TALLOC_CTX * unlang_ctx
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
map_proc_func_t resume
resumption handler
unlang_action_t unlang_map_yield(request_t *request, map_proc_func_t resume, unlang_map_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
static int fixup_map_cb(map_t *map, UNUSED void *ctx)
Validate and fixup a map that's part of an map section.
fr_value_box_list_t lhs_result
Result of expanding the LHS.
static unlang_t * unlang_compile_map(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
fr_signal_t sigmask
Signals to block.
static unlang_t * compile_update_to_edit(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs)
unlang_update_state_t state
What we're currently doing.
static unlang_action_t list_mod_apply(unlang_result_t *p_result, request_t *request)
Apply a list of modifications on one or more fr_pair_t lists.
static int compile_map_name(unlang_group_t *g)
static unlang_action_t unlang_update_state_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Execute an update block.
static int edit_pair_alloc(CONF_SECTION *cs, CONF_PAIR *original, char const *attr, fr_token_t op, char const *value, fr_token_t list_op)
void unlang_map_init(void)
static unlang_action_t list_mod_create(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Create a list of modifications to apply to one or more fr_pair_t lists.
static unlang_action_t map_proc_resume(unlang_result_t *p_result, request_t *request, UNUSED unlang_stack_frame_t *frame)
fr_dlist_head_t vlm_head
Head of list of VP List Mod.
void * rctx
for resume / signal
static unlang_action_t map_proc_apply(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
static int edit_section_alloc(CONF_SECTION *parent, CONF_SECTION **child, char const *name1, fr_token_t op)
unlang_update_state_t
map and unlang integration.
@ UNLANG_UPDATE_MAP_EXPANDED_RHS
Expand the RHS xlat or exec (if needed).
@ UNLANG_UPDATE_MAP_INIT
Start processing a map.
@ UNLANG_UPDATE_MAP_EXPANDED_LHS
Expand the LHS xlat or exec (if needed).
static unlang_action_t unlang_map_state_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
fr_dcursor_t maps
Cursor of maps to evaluate.
static unlang_t * unlang_compile_update(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
fr_value_box_list_t rhs_result
Result of expanding the RHS.
unlang_map_signal_t signal
for signal handlers
#define MAP_CTX(_mod_inst, _map_inst, _rctx)
Wrapper to create a map_ctx_t as a compound literal.
fr_value_box_list_t src_result
Result of expanding the map source.
State of an update block.
static char * stack[MAX_STACK]
bool main_config_migrate_option_get(char const *name)
map_proc_inst_t * proc_inst
static unlang_map_t * unlang_group_to_map(unlang_group_t *g)
Cast a group structure to the map keyword extension.
map_list_t map
Head of the map list.
map_proc_t * map_proc_find(char const *name)
Find a map processor by name.
map_proc_inst_t * map_proc_instantiate(TALLOC_CTX *ctx, map_proc_t const *proc, CONF_SECTION *cs, tmpl_t const *src, map_list_t const *maps)
Create a new map proc instance.
fr_value_box_safe_for_t map_proc_literals_safe_for(map_proc_t const *proc)
unlang_action_t(* map_proc_func_t)(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request, fr_value_box_list_t *result, map_list_t const *maps)
Function to evaluate the src string and map the result to server attributes.
Map processor registration.
@ FR_TYPE_STRING
String of printable characters.
int unlang_fixup_update(map_t *map, void *ctx)
Validate and fixup a map that's part of an update section.
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
size_t fr_snprint_len(char const *in, ssize_t inlen, char quote)
Find the length of the buffer required to fully escape a string with fr_prints.
#define RETURN_UNLANG_FAIL
#define RETURN_UNLANG_NOOP
#define REQUEST_VERIFY(_x)
#define FR_SBUFF_IN(_start, _len_or_end)
int map_list_mod_apply(request_t *request, vp_list_mod_t const *vlm)
Apply the output of map_to_list_mod to a request.
int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, request_t *request, map_t const *map, fr_value_box_list_t *lhs_result, fr_value_box_list_t *rhs_result)
Evaluate a map creating a new map with TMPL_TYPE_ATTR LHS and TMPL_TYPE_DATA RHS.
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
fr_table_num_sorted_t const tmpl_request_ref_table[]
Map keywords to tmpl_request_ref_t values.
fr_value_box_safe_for_t literals_safe_for
safe_for value assigned to literal values in xlats, execs, and data.
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
@ TMPL_TYPE_ATTR_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
@ 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_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
@ TMPL_TYPE_DATA
Value in native boxed format.
@ TMPL_TYPE_REGEX
Compiled (and possibly JIT'd) regular expression.
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
@ TMPL_TYPE_REGEX_XLAT
A regex containing xlat expansions.
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
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_attr_rules_t attr
Rules/data for parsing attribute references.
static char const * tmpl_list_name(fr_dict_attr_t const *list, char const *def)
Return the name of a tmpl list or def if list not provided.
@ REQUEST_UNKNOWN
Unknown request.
#define tmpl_aexpand(_ctx, _out, _request, _vpt, _escape, _escape_ctx)
Expand a tmpl to a C type, allocing a new buffer to hold the string.
fr_slen_t tmpl_attr_list_from_substr(fr_dict_attr_t const **da_p, fr_sbuff_t *in)
Parse one a single list reference.
Optional arguments passed to vp_tmpl functions.
fr_signal_t
Signals that can be generated/processed by request signal handlers.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
eap_type_t type
The preferred EAP-Type of this instance of the EAP-SIM/AKA/AKA' state machine.
fr_token_t op
The operator that controls insertion of the dst attribute.
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
CONF_ITEM * ci
Config item that the map was created from.
uint8_t disallow_rhs_resolve
map RHS is NOT immediately resolved in the context of the LHS.
uint8_t allow_wildcard
Allow the special case of .
uint8_t allow_unknown
Allow unknown attributes i.e.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
#define fr_table_value_by_substr(_table, _name, _name_len, _def)
Convert a partial string to a value using an ordered or sorted table.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
int unlang_tmpl_push(TALLOC_CTX *ctx, unlang_result_t *p_result, 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.
const bool fr_assignment_op[T_TOKEN_LAST]
fr_table_num_ordered_t const fr_tokens_table[]
char const * fr_tokens[T_TOKEN_LAST]
const bool fr_comparison_op[T_TOKEN_LAST]
void(* unlang_map_signal_t)(map_ctx_t const *mpctx, request_t *request, fr_signal_t action)
A callback when the request gets a fr_signal_t.
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.
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.
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 * name
Unknown...
@ UNLANG_TYPE_UPDATE
Update block.
@ UNLANG_TYPE_MAP
Mapping section (like UNLANG_TYPE_UPDATE, but uses values from a map_proc_t call).
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_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_RCODE_SET
Set request->rcode to the result of this operation.
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_process_t process
function to call for interpreting this stack frame
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.
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.
#define VALUE_BOX_LIST_VERIFY(_x)