29 RCSID(
"$Id: 8d8f0ac870f4756f53b86c941de5ea59577b1e65 $")
31 #include <freeradius-devel/server/exec.h>
32 #include <freeradius-devel/server/map.h>
33 #include <freeradius-devel/server/paircmp.h>
34 #include <freeradius-devel/server/tmpl_dcursor.h>
36 #include <freeradius-devel/util/debug.h>
37 #include <freeradius-devel/util/misc.h>
38 #include <freeradius-devel/util/pair_legacy.h>
40 #include <freeradius-devel/protocol/radius/rfc2865.h>
41 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
49 map_list_init(&mod->
mod);
56 map = talloc_zero(ctx,
map_t);
57 map_list_init(&map->
child);
87 if (!mod)
return NULL;
89 mod->
op = mutated->
op;
95 map_list_insert_tail(&
n->mod, mod);
128 if (!mod)
return NULL;
137 map_list_insert_tail(&
n->mod, mod);
169 if (!mod)
return NULL;
172 mod->
op = mutated->
op;
191 map_list_insert_tail(&
n->mod, mod);
212 RPEDEBUG(
"Mapping \"%.*s\" -> \"%.*s\" cannot be performed",
213 (
int)map->
rhs->len, map->
rhs->name, (
int)map->
lhs->len, map->
lhs->name);
220 REDEBUG(
"Mapping \"%.*s\" -> \"%.*s\" cannot be performed due to to invalid list qualifier \"%s\"",
221 (
int)map->
rhs->len, map->
rhs->name, (
int)map->
lhs->len, map->
lhs->name,
253 fr_value_box_list_t *lhs_result, fr_value_box_list_t *rhs_result)
257 map_t const *mutated = original;
260 fr_value_box_list_t
head;
261 TALLOC_CTX *tmp_ctx = NULL;
272 fr_value_box_list_init(&
head);
277 switch (original->
lhs->type) {
294 fr_value_box_t *lhs_result_head = fr_value_box_list_head(lhs_result);
300 memcpy(&map_tmp, original,
sizeof(map_tmp));
303 tmp_ctx = talloc_new(NULL);
305 fr_assert(!fr_value_box_list_empty(lhs_result));
315 RPEDEBUG(
"Left side expansion failed");
316 fr_value_box_list_talloc_free(lhs_result);
323 .dict_def = request->dict,
324 .list_def = request_attr_request,
325 .prefix = TMPL_ATTR_REF_PREFIX_NO
329 RPEDEBUG(
"Left side expansion result \"%s\" is not an attribute reference",
330 lhs_result_head->vb_strvalue);
331 fr_value_box_list_talloc_free(lhs_result);
353 mod->
lhs = mutated->lhs;
354 mod->
op = mutated->op;
355 mod->
rhs = mutated->rhs;
356 map_list_insert_tail(&
n->mod, mod);
372 if (!list)
goto error;
397 if (!n_mod)
goto error;
399 n_mod->
op = mutated->op;
407 if (!n_mod->
lhs)
goto error;
420 if (!n_mod->
rhs)
goto error;
428 map_list_insert_tail(&
n->mod, n_mod);
454 mutated->rhs->name, mutated->rhs->len,
469 switch (mutated->rhs->type) {
487 if (fr_value_box_list_empty(rhs_result)) {
505 (void)
fr_dcursor_init(&from, fr_value_box_list_dlist_head(rhs_result));
526 n_vb = talloc_steal(
n, vb);
541 fr_assert(fr_value_box_list_empty(rhs_result));
554 if (!
vp)
switch (
err) {
571 RPEDEBUG(
"Failed resolving attribute source");
616 fr_assert(fr_value_box_list_empty(rhs_result));
670 fr_value_box_t *rhs_result_head = fr_value_box_list_head(rhs_result);
687 if (fr_value_box_list_empty(rhs_result)) {
688 RPEDEBUG(
"Cannot assign empty value to \"%s\"", mutated->lhs->name);
700 RPEDEBUG(
"Right side expansion failed");
701 fr_value_box_list_talloc_free(rhs_result);
716 RDEBUG2(
"No pairs returned by exec");
725 .request_def = tmpl_request(mutated->lhs),
731 RPEDEBUG(
"Failed converting VP to map");
738 RPEDEBUG(
"Program output cannot request execution of another program for attribute %s",
vp->
da->name);
746 RPEDEBUG(
"Program output cannot request regular expression matching for attribute %s",
vp->
da->name);
753 map_list_insert_tail(&
n->mod, mod);
779 fr_value_box_list_talloc_free(&
head);
791 if (talloc_parent(mutated->lhs) == tmp_ctx) talloc_steal(
n, mutated->lhs);
828 mod = map_list_head(&vlm->
mod);
829 if (map_list_num_elements(&vlm->
mod) == 1) {
841 mod = map_list_next(&vlm->
mod, mod)) {
864 char const *quote =
"";
882 switch (map->
rhs->type) {
890 rhs =
fr_asprintf(request,
"%s%pV%s", quote, vb, quote);
894 rhs =
fr_asprintf(request,
"%s -> %s%pV%s", map->
rhs->name, quote, vb, quote);
902 switch (map->
lhs->type) {
926 map_t const *map = vlm->
map, *mod = NULL;
935 memset(&cc, 0,
sizeof(cc));
943 while ((mod = map_list_next(&vlm->
mod, mod))) {
964 mod = map_list_head(&vlm->
mod);
1003 bool exists =
false;
1079 if (!found)
goto finish;
1112 if (!found)
goto finish;
1182 RDEBUG3(
"Refusing to overwrite (use :=)");
1191 if (!found)
goto do_add;
1227 if (!found)
goto finish;
static void * fr_dcursor_remove(fr_dcursor_t *cursor)
Remove the current item.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
static void fr_dcursor_merge(fr_dcursor_t *cursor, fr_dcursor_t *to_append)
Moves items from one cursor to another.
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
static void fr_dcursor_free_item(fr_dcursor_t *cursor)
talloc_free the current item
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
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 RPEDEBUG(fmt,...)
int map_afrom_vp(TALLOC_CTX *ctx, map_t **out, fr_pair_t *vp, tmpl_rules_t const *rules)
Convert a fr_pair_t into a map.
map_t const * map
Original map describing the change to be made.
map_list_t mod
New map containing the destination (LHS) and values (RHS).
static vp_list_mod_t * list_mod_generic_afrom_map(TALLOC_CTX *ctx, map_t const *original, map_t const *mutated)
Allocate a 'generic' vp_list_mod_t.
static vp_list_mod_t * list_mod_empty_string_afrom_map(TALLOC_CTX *ctx, map_t const *original, map_t const *mutated)
Allocate an 'empty_string' vp_list_mod_t.
static void map_list_mod_debug(request_t *request, map_t const *map, map_t const *mod, fr_value_box_t const *vb)
Print debug for a modification map.
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.
static fr_pair_t * map_list_mod_to_vp(TALLOC_CTX *ctx, tmpl_t const *attr, fr_value_box_t const *value)
static fr_pair_list_t * map_check_src_or_dst(request_t *request, map_t const *map, tmpl_t const *src_dst)
Check that the destination list is currently value.
static vp_list_mod_t * list_mod_alloc(TALLOC_CTX *ctx)
static vp_list_mod_t * list_mod_delete_afrom_map(TALLOC_CTX *ctx, map_t const *original, map_t const *mutated)
Allocate a 'delete' vp_list_mod_t.
static void map_list_mod_to_vps(TALLOC_CTX *ctx, fr_pair_list_t *list, vp_list_mod_t const *vlm)
Allocate one or more fr_pair_ts from a vp_list_mod_t.
int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, request_t *request, map_t const *original, 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 map_t * map_alloc(TALLOC_CTX *ctx)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
void fr_pair_list_afrom_box(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_t const *dict, fr_value_box_t *box)
Parse a list of VPs from a value box.
int8_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da, and tag.
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
#define RDEBUG_ENABLED2()
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
#define tmpl_is_xlat(vpt)
TALLOC_CTX * tmpl_list_ctx(request_t *request, fr_dict_attr_t const *list)
Return the correct TALLOC_CTX to alloc fr_pair_t in, for a list.
#define tmpl_value(_tmpl)
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.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
#define tmpl_is_attr(vpt)
#define tmpl_is_exec(vpt)
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.
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
@ TMPL_TYPE_NULL
Has no value.
@ TMPL_TYPE_EXEC
Callout to an external script or program.
@ TMPL_TYPE_DATA
Value in native boxed format.
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
static bool tmpl_attr_tail_da_is_structural(tmpl_t const *vpt)
Return true if the the last attribute reference is a structural attribute.
fr_pair_list_t * tmpl_list_head(request_t *request, fr_dict_attr_t const *list)
Resolve attribute fr_pair_list_t value to an attribute list.
static bool tmpl_is_list(tmpl_t const *vpt)
#define tmpl_is_data(vpt)
#define tmpl_value_type(_tmpl)
int tmpl_request_ptr(request_t **request, FR_DLIST_HEAD(tmpl_request_list) const *rql)
Resolve a tmpl_request_ref_t to a request_t.
#define tmpl_is_data_unresolved(vpt)
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
int tmpl_attr_copy(tmpl_t *dst, tmpl_t const *src)
Copy a list of attribute and request references from one tmpl to another.
#define tmpl_is_null(vpt)
int tmpl_attr_set_leaf_da(tmpl_t *vpt, fr_dict_attr_t const *da)
Replace the leaf attribute only.
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
tmpl_t * tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len)
Create a new heap allocated tmpl_t.
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_token_t op
The operator that controls insertion of the dst attribute.
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
map_list_t child
parent map, for nested ones
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
fr_type_t cast
Cast value to this type.
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
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_str_by_value(_table, _number, _def)
Convert an integer to a string.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
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.
fr_table_num_ordered_t const fr_tokens_table[]
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
#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.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
void fr_pair_list_prepend(fr_pair_list_t *dst, fr_pair_list_t *src)
Move a list of fr_pair_t from a temporary list to the head of a destination list.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules, bool tainted)
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.
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
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.
int fr_value_box_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two attributes using an operator.
fr_sbuff_unescape_rules_t * fr_value_unescape_by_quote[T_TOKEN_LAST]
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 fr_box_strvalue_len(_val, _len)
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
static size_t char ** out