From: Nick Porter Date: Thu, 24 Jul 2025 10:54:00 +0000 (+0100) Subject: Add `map list` as a "builtin" map X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e83d18cf34d9a947b97cd7b72bf9429b045279b2;p=thirdparty%2Ffreeradius-server.git Add `map list` as a "builtin" map --- diff --git a/src/lib/unlang/all.mk b/src/lib/unlang/all.mk index d88675e394..0881c9e2db 100644 --- a/src/lib/unlang/all.mk +++ b/src/lib/unlang/all.mk @@ -20,6 +20,7 @@ SOURCES := base.c \ limit.c \ load_balance.c \ map.c \ + map_builtin.c \ mod_action.c \ module.c \ parallel.c \ @@ -55,6 +56,6 @@ LOG_ID_LIB := 2 # different pieces of this library $(call DEFINE_LOG_ID_SECTION,compile, 1,compile.c) -$(call DEFINE_LOG_ID_SECTION,keywords, 2,call.c caller.c condition.c detach.c foreach.c function.c group.c io.c load_balance.c map.c module.c parallel.c return.c subrequest.c subrequest_child.c switch.c) +$(call DEFINE_LOG_ID_SECTION,keywords, 2,call.c caller.c condition.c detach.c foreach.c function.c group.c io.c load_balance.c map.c map_builtin.c module.c parallel.c return.c subrequest.c subrequest_child.c switch.c) $(call DEFINE_LOG_ID_SECTION,interpret, 3, interpret.c interpret_synchronous.c) $(call DEFINE_LOG_ID_SECTION,expand, 4,tmpl.c xlat.c xlat_builtin.c xlat_eval.c xlat_inst.c xlat_pair.c xlat_tokenize.c) diff --git a/src/lib/unlang/base.c b/src/lib/unlang/base.c index 7358bf6963..e68b0a20ef 100644 --- a/src/lib/unlang/base.c +++ b/src/lib/unlang/base.c @@ -112,6 +112,11 @@ static int _unlang_global_init(UNUSED void *uctx) return -1; } + /* + * Initialise global maps + */ + if (map_global_init() < 0) goto fail; + unlang_interpret_init_global(unlang_ctx); /* diff --git a/src/lib/unlang/map.h b/src/lib/unlang/map.h index f44c18ce56..e84e1b12a2 100644 --- a/src/lib/unlang/map.h +++ b/src/lib/unlang/map.h @@ -44,6 +44,12 @@ typedef void (*unlang_map_signal_t)(map_ctx_t const *mpctx, request_t *request, 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); + +/* + * map_builtin.c + */ +int map_global_init(void); + #ifdef __cplusplus } #endif diff --git a/src/lib/unlang/map_builtin.c b/src/lib/unlang/map_builtin.c new file mode 100644 index 0000000000..6ba4df1d08 --- /dev/null +++ b/src/lib/unlang/map_builtin.c @@ -0,0 +1,134 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @file map_builtin.c + * @brief Built in map expansions. + * + * @copyright 2025 Network RADIUS SAS (legal@networkradius.com) + */ + + +RCSID("$Id$") + +#include +#include "map.h" + +static TALLOC_CTX *map_ctx; + +static int list_map_verify(CONF_SECTION *cs, UNUSED void const *mod_inst, UNUSED void *proc_inst, + tmpl_t const *src, UNUSED map_list_t const *maps) +{ + if (!src) { + cf_log_err(cs, "Missing source of value list"); + return -1; + } + + return 0; +} + +static int _list_map_proc_get_value(TALLOC_CTX *ctx, fr_pair_list_t *out, + request_t *request, map_t const *map, void *uctx) +{ + fr_pair_t *vp; + fr_value_box_t *value = talloc_get_type_abort(uctx, fr_value_box_t); + + vp = fr_pair_afrom_da_nested(ctx, out, tmpl_attr_tail_da(map->lhs)); + if (!vp) return -1; + + if (fr_value_box_cast(vp, &vp->data, vp->data.type, vp->da, value) < 0) { + RPEDEBUG("Failed casting \"%pV\" for attribute %s", value, vp->da->name); + fr_pair_delete(out, vp); + return -1; + } + + return 0; +} + +/** Map a list of value boxes to attributes using the index number in the list. + */ +static unlang_action_t mod_list_map_proc(unlang_result_t *p_result, UNUSED map_ctx_t const *mpctx, request_t *request, + fr_value_box_list_t *in, map_list_t const *maps) +{ + rlm_rcode_t rcode = RLM_MODULE_NOOP; + fr_value_box_t *vb = NULL; + fr_value_box_t **values; + size_t index, i = 0, value_count = fr_value_box_list_num_elements(in); + TALLOC_CTX *local = talloc_new(NULL); + map_t *map = NULL; + + if (value_count == 0) goto finish; + /* + * Use an array to point to the list entries so we don't + * repeatedly walk the list to find each index in the map. + */ + MEM(values = talloc_array(local, fr_value_box_t *, value_count)); + while ((vb = fr_value_box_list_next(in, vb))) values[i++] = vb; + + /* + * Indexes are zero offset - so reduce value_count to the max index. + */ + value_count --; + + while ((map = map_list_next(maps, map))) { + if (tmpl_aexpand(local, &index, request, map->rhs, NULL, NULL) < 0) { + RPERROR("Failed expanding map RHS"); + rcode = RLM_MODULE_FAIL; + goto finish; + } + if (index > value_count) { + RWARN("Asked for index %ld when max is %ld.", index, value_count); + continue; + } + if (values[index]->type == FR_TYPE_NULL) { + RDEBUG2("Skipping null value for index %ld.", index); + continue; + } + + if (map_to_request(request, map, _list_map_proc_get_value, values[index]) < 0) { + rcode = RLM_MODULE_FAIL; + goto finish; + } + rcode = RLM_MODULE_UPDATED; + } + +finish: + talloc_free(local); + + RETURN_UNLANG_RCODE(rcode); +} + +static int _map_global_init(UNUSED void *uctx) +{ + map_ctx = talloc_init("map"); + map_proc_register(map_ctx, NULL, "list", mod_list_map_proc, list_map_verify, 0, FR_VALUE_BOX_SAFE_FOR_ANY); + return 0; +} + +static int _map_global_free(UNUSED void *uctx) +{ + talloc_free(map_ctx); + return 0; +} + +int map_global_init(void) +{ + int ret; + fr_atexit_global_once_ret(&ret, _map_global_init, _map_global_free, NULL); + return ret; +} diff --git a/src/lib/unlang/unlang_priv.h b/src/lib/unlang/unlang_priv.h index 291fdb2033..95bb2105a8 100644 --- a/src/lib/unlang/unlang_priv.h +++ b/src/lib/unlang/unlang_priv.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #ifdef __cplusplus