]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add better support for async maps
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 31 May 2025 19:25:12 +0000 (13:25 -0600)
committerNick Porter <nick@portercomputing.co.uk>
Wed, 18 Jun 2025 12:53:02 +0000 (13:53 +0100)
We really don't want to push additional frames if we can help it

src/bin/unit_test_module.c
src/lib/server/map_proc.c
src/lib/server/map_proc.h
src/lib/unlang/map.c
src/lib/unlang/map.h [new file with mode: 0644]
src/modules/rlm_client/rlm_client.c
src/modules/rlm_csv/rlm_csv.c
src/modules/rlm_json/rlm_json.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_sql/rlm_sql.c

index ca71795045045e34fc6dd5b53a4afc1da96d91f1..1725568e5c8bf01f248c86e21a3bf7db03364591 100644 (file)
@@ -592,11 +592,11 @@ static int map_proc_verify(CONF_SECTION *cs, UNUSED void const *mod_inst, UNUSED
        return 0;
 }
 
-static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void const *mod_inst, UNUSED void *proc_inst,
+static unlang_action_t mod_map_proc(unlang_result_t *p_result, UNUSED map_ctx_t const *mpctx,
                                    UNUSED request_t *request, UNUSED fr_value_box_list_t *src,
                                    UNUSED map_list_t const *maps)
 {
-       RETURN_MODULE_FAIL;
+       RETURN_UNLANG_FAIL;
 }
 
 static request_t *request_clone(request_t *old, int number, CONF_SECTION *server_cs)
index 4d4034b484575e6c2427cf14c1de3b7a572ac5e3..2826ce6758e0acc34fe2195f1805473fca5df4c0 100644 (file)
@@ -225,20 +225,3 @@ map_proc_inst_t *map_proc_instantiate(TALLOC_CTX *ctx, map_proc_t const *proc,
 
        return inst;
 }
-
-/** Evaluate a set of maps using the specified map processor
- *
- * Evaluate the map processor src template, then call a map processor function to do
- * something with the expanded src template and map the result to attributes in the request.
- *
- * @param[out] p_result                Result code of evaluating the map.
- * @param[in] request          The current request.
- * @param[in] inst             of a map processor.
- * @param[in,out] result       Result of expanding the map input.  May be consumed
- *                             by the map processor.
- * @return one of UNLANG_ACTION_*
- */
-unlang_action_t map_proc(rlm_rcode_t *p_result, request_t *request, map_proc_inst_t const *inst, fr_value_box_list_t *result)
-{
-       return inst->proc->evaluate(p_result, inst->proc->mod_inst, inst->data, request, result, inst->maps);
-}
index 9a83cda76547c661cf50dd9bc488b6f8d6c442ef..08832c95f57c50d6928938a323c77767724cec0f 100644 (file)
@@ -46,21 +46,29 @@ typedef struct map_proc_inst map_proc_inst_t;
 extern "C" {
 #endif
 
+/** Temporary structure to hold arguments for map calls
+ *
+ */
+typedef struct {
+       void                    *rctx;          //!< Resume ctx that a module previously set.
+       void const              *moi;           //!< Map module instance.
+       void const              *mpi;           //!< Map processor instance.
+} map_ctx_t;
+
 /** Function to evaluate the src string and map the result to server attributes
  *
  * @param[out] p_result                Result of applying the map:
  *     - #RLM_MODULE_NOOP - If no data available for given src, or no mappings matched available data.
  *     - #RLM_MODULE_UPDATED - If new pairs were added to the request.
  *     - #RLM_MODULE_FAIL - If an error occurred performing the mapping.
- * @param[in] mod_inst         Instance of the module that registered the map_proc.
- * @param[in] proc_inst                Map proc data created by #map_proc_instantiate_t.
+ * @param[in] mpctx            Call ctx for the map processor.
  * @param[in] request          The current request.
  * @param[in,out] result       Input data for the map processor.  May be consumed by the
  *                             map processor.
  * @param[in] maps             Head of the list of maps to process.
  * @return one of UNLANG_ACTION_*
  */
-typedef unlang_action_t (*map_proc_func_t)(rlm_rcode_t *p_result, void const *mod_inst, void *proc_inst, request_t *request,
+typedef 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);
 
 /** Allocate new instance data for a map processor
@@ -89,9 +97,6 @@ int           map_proc_unregister(char const *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);
-
-unlang_action_t        map_proc(rlm_rcode_t *p_result, request_t *request, map_proc_inst_t const *inst, fr_value_box_list_t *src);
-
 #ifdef __cplusplus
 }
 #endif
index 7871a1110504f8c667295536815926a25b9fbc6e..8ccab42c2be9ec5be9bfba24747f1d43c27881e8 100644 (file)
@@ -28,8 +28,9 @@
 RCSID("$Id$")
 
 #include <freeradius-devel/server/base.h>
+#include <freeradius-devel/server/map.h>
 #include <freeradius-devel/unlang/tmpl.h>
-
+#include <freeradius-devel/unlang/map.h>
 
 #include "map_priv.h"
 
@@ -43,23 +44,41 @@ typedef enum {
  *
  */
 typedef struct {
-       fr_dcursor_t            maps;                           //!< Cursor of maps to evaluate.
+       fr_dcursor_t                    maps;                   //!< Cursor of maps to evaluate.
 
-       fr_dlist_head_t         vlm_head;                       //!< Head of list of VP List Mod.
+       fr_dlist_head_t                 vlm_head;               //!< Head of list of VP List Mod.
 
-       fr_value_box_list_t     lhs_result;                     //!< Result of expanding the LHS
-       fr_value_box_list_t     rhs_result;                     //!< Result of expanding the RHS.
+       fr_value_box_list_t             lhs_result;             //!< Result of expanding the LHS
+       fr_value_box_list_t             rhs_result;             //!< Result of expanding the RHS.
 
-       unlang_update_state_t   state;                          //!< What we're currently doing.
+       unlang_update_state_t           state;                  //!< What we're currently doing.
 } unlang_frame_state_update_t;
 
 /** State of a map block
  *
  */
 typedef struct {
-       fr_value_box_list_t     src_result;                     //!< Result of expanding the map source.
+       fr_value_box_list_t             src_result;             //!< Result of expanding the map source.
+
+       /** @name Resumption and signalling
+        * @{
+        */
+       void                            *rctx;                  //!< for resume / signal
+       map_proc_func_t                 resume;                 //!< resumption handler
+       unlang_map_signal_t             signal;                 //!< for signal handlers
+       fr_signal_t                     sigmask;                //!< Signals to block.
+
+       /** @} */
 } unlang_frame_state_map_proc_t;
 
+/** Wrapper to create a map_ctx_t as a compound literal
+ *
+ * @param[in] _mod_inst        of the module being called.
+ * @param[in] _map_inst        of the map being called.
+ * @param[in] _rctx    Resume ctx (if any).
+ */
+#define MAP_CTX(_mod_inst, _map_inst, _rctx) &(map_ctx_t){ .moi = _mod_inst, .mpi = _map_inst, .rctx = _rctx }
+
 /** Apply a list of modifications on one or more fr_pair_t lists.
  *
  * @param[in] request  The current request.
@@ -274,7 +293,7 @@ static unlang_action_t unlang_update_state_init(unlang_result_t *p_result, reque
        return list_mod_create(p_result, request, frame);
 }
 
-static unlang_action_t map_proc_resume(UNUSED unlang_result_t *p_result, UNUSED request_t *request,
+static unlang_action_t map_proc_resume(unlang_result_t *p_result, request_t *request,
 #ifdef WITH_VERIFY_PTR
                                       unlang_stack_frame_t *frame
 #else
@@ -282,11 +301,68 @@ static unlang_action_t map_proc_resume(UNUSED unlang_result_t *p_result, UNUSED
 #endif
                                      )
 {
-#ifdef WITH_VERIFY_PTR
+       unlang_frame_state_map_proc_t   *state = talloc_get_type_abort(frame->state, unlang_frame_state_map_proc_t);
        unlang_frame_state_map_proc_t   *map_proc_state = talloc_get_type_abort(frame->state, unlang_frame_state_map_proc_t);
+       map_proc_func_t                 resume;
+       unlang_group_t                  *g = unlang_generic_to_group(frame->instruction);
+       unlang_map_t                    *gext = unlang_group_to_map(g);
+       map_proc_inst_t                 *inst = gext->proc_inst;
+       unlang_action_t                 ua = UNLANG_ACTION_CALCULATE_RESULT;
+
+#ifdef WITH_VERIFY_PTR
        VALUE_BOX_LIST_VERIFY(&map_proc_state->src_result);
 #endif
-       return UNLANG_ACTION_CALCULATE_RESULT;
+       resume = state->resume;
+       state->resume = NULL;
+
+       /*
+        *      Call any map resume function
+        */
+       if (resume) ua = resume(p_result, MAP_CTX(inst->proc->mod_inst, inst->data, state->rctx),
+                               request, &map_proc_state->src_result, inst->maps);
+       return ua;
+}
+
+/** Yield a request back to the interpreter from within a module
+ *
+ * This passes control of the request back to the unlang interpreter, setting
+ * callbacks to execute when the request is 'signalled' asynchronously, or whatever
+ * timer or I/O event the module was waiting for occurs.
+ *
+ * @note The module function which calls #unlang_module_yield should return control
+ *     of the C stack to the unlang interpreter immediately after calling #unlang_module_yield.
+ *     A common pattern is to use ``return unlang_module_yield(...)``.
+ *
+ * @param[in] request          The current request.
+ * @param[in] resume           Called on unlang_interpret_mark_runnable().
+ * @param[in] signal           Called on unlang_action().
+ * @param[in] sigmask          Set of signals to block.
+ * @param[in] rctx             to pass to the callbacks.
+ * @return
+ *     - UNLANG_ACTION_YIELD.
+ */
+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)
+{
+       unlang_stack_t                  *stack = request->stack;
+       unlang_stack_frame_t            *frame = &stack->frame[stack->depth];
+       unlang_frame_state_map_proc_t   *state = talloc_get_type_abort(frame->state, unlang_frame_state_map_proc_t);
+
+       REQUEST_VERIFY(request);        /* Check the yielded request is sane */
+
+       state->rctx = rctx;
+       state->resume = resume;
+       state->signal = signal;
+       state->sigmask = sigmask;
+
+       /*
+        *      We set the repeatable flag here,
+        *      so that the resume function is always
+        *      called going back up the stack.
+        */
+       frame_repeat(frame, map_proc_resume);
+
+       return UNLANG_ACTION_YIELD;
 }
 
 static unlang_action_t map_proc_apply(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
@@ -301,7 +377,9 @@ static unlang_action_t map_proc_apply(unlang_result_t *p_result, request_t *requ
 
        VALUE_BOX_LIST_VERIFY(&map_proc_state->src_result);
        frame_repeat(frame, map_proc_resume);
-       return map_proc(&p_result->rcode, request, gext->proc_inst, &map_proc_state->src_result);
+
+       return inst->proc->evaluate(p_result, MAP_CTX(inst->proc->mod_inst, inst->data, NULL),
+                                   request, &map_proc_state->src_result, inst->maps);
 }
 
 static unlang_action_t unlang_map_state_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
diff --git a/src/lib/unlang/map.h b/src/lib/unlang/map.h
new file mode 100644 (file)
index 0000000..f44c18c
--- /dev/null
@@ -0,0 +1,49 @@
+#pragma once
+/*
+ *  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, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * $Id$
+ *
+ * @file unlang/map.h
+ *
+ * @copyright 2025 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <freeradius-devel/server/signal.h>
+#include <freeradius-devel/server/request.h>
+#include <freeradius-devel/server/map.h>
+#include <freeradius-devel/server/map_proc.h>
+#include <freeradius-devel/unlang/interpret.h>
+
+/** A callback when the request gets a fr_signal_t.
+ *
+ * @note The callback is automatically removed on unlang_interpret_mark_runnable().
+ *
+ * @param[in] mpctx            calling context for the map function.
+ * @param[in] request          The current request.
+ * @param[in] action           which is signalling the request.
+ */
+typedef void (*unlang_map_signal_t)(map_ctx_t const *mpctx, request_t *request, fr_signal_t action);
+
+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);
+#ifdef __cplusplus
+}
+#endif
index b0004a750281a39192edce426605ee0e02c9586e..4e0a5011e5cd7d104ae728e5fd0d3e57495f5e43 100644 (file)
@@ -108,15 +108,14 @@ static int _map_proc_client_get_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request
  *                             - #RLM_MODULE_NOOP no rows were returned.
  *                             - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
  *                             - #RLM_MODULE_FAIL if an error occurred.
- * @param[in] mod_inst         NULL.
- * @param[in] proc_inst                NULL.
+ * @param[in] mpctx            NULL
  * @param[in] request          The current request.
  * @param[in] client_override  If NULL, use the current client, else use the client matching
  *                             the ip given.
  * @param[in] maps             Head of the map list.
  * @return UNLANG_ACTION_CALCULATE_RESULT
  */
-static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const *mod_inst, UNUSED void *proc_inst,
+static unlang_action_t map_proc_client(unlang_result_t *p_result, UNUSED map_ctx_t const *mpctx,
                                       request_t *request, fr_value_box_list_t *client_override, map_list_t const *maps)
 {
        rlm_rcode_t             rcode = RLM_MODULE_OK;
@@ -138,7 +137,7 @@ static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const
                                                      FR_VALUE_BOX_LIST_FREE, true,
                                                      SIZE_MAX) < 0) {
                        REDEBUG("Failed concatenating input data");
-                       RETURN_MODULE_FAIL;
+                       RETURN_UNLANG_FAIL;
                }
                client_str = client_override_head->vb_strvalue;
 
@@ -173,7 +172,7 @@ static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const
                client = client_from_request(request);
                if (!client) {
                        REDEBUG("No client associated with this request");
-                       RETURN_MODULE_FAIL;
+                       RETURN_UNLANG_FAIL;
                }
        }
        uctx.cs = client->cs;
@@ -213,7 +212,7 @@ static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const
        REXDENT();
 
 finish:
-       RETURN_MODULE_RCODE(rcode);
+       RETURN_UNLANG_RCODE(rcode);
 }
 
 static xlat_arg_parser_t const xlat_client_args[] = {
index aa97808a62f02a41f6ac007ffc05d1f86b4cbeed..dea47edc7ed97ed5bc269ed863bfa4ce69985da5 100644 (file)
@@ -31,7 +31,7 @@ RCSID("$Id$")
 
 #include <freeradius-devel/server/map_proc.h>
 
-static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, UNUSED void *proc_inst, request_t *request,
+static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request,
                                    fr_value_box_list_t *key, map_list_t const *maps);
 
 /*
@@ -968,22 +968,21 @@ finish:
  *                     - #RLM_MODULE_NOOP no rows were returned.
  *                     - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
  *                     - #RLM_MODULE_FAIL if an error occurred.
- * @param[in] mod_inst #rlm_csv_t.
- * @param[in] proc_inst        mapping map entries to field numbers.
+ * @param[in] mpctx    #map_ctx_t, which contains the module and map instances.
  * @param[in,out]      request The current request.
  * @param[in] key      key to look for
  * @param[in] maps     Head of the map list.
  * @return UNLANG_ACTION_CALCULATE_RESULT
  */
-static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, UNUSED void *proc_inst, request_t *request,
+static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request,
                                    fr_value_box_list_t *key, map_list_t const *maps)
 {
-       rlm_csv_t const         *inst = talloc_get_type_abort_const(mod_inst, rlm_csv_t);
+       rlm_csv_t const         *inst = talloc_get_type_abort_const(mpctx->moi, rlm_csv_t);
        fr_value_box_t          *key_head = fr_value_box_list_head(key);
 
        if (!key_head) {
                REDEBUG("CSV key cannot be (null)");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
        if ((inst->key_data_type == FR_TYPE_OCTETS) || (inst->key_data_type == FR_TYPE_STRING)) {
@@ -992,11 +991,11 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst,
                                                      FR_VALUE_BOX_LIST_FREE, true,
                                                      SIZE_MAX) < 0) {
                        REDEBUG("Failed parsing key");
-                       RETURN_MODULE_FAIL;
+                       RETURN_UNLANG_FAIL;
                }
        }
 
-       RETURN_MODULE_RCODE(mod_map_apply(inst, request, key_head, maps));
+       RETURN_UNLANG_RCODE(mod_map_apply(inst, request, key_head, maps));
 }
 
 
index bd324f98c86e0d18eca55b18509f78a86e1d2abb..cb1c9f76ea9e2e3258007da75e453513c1e3e246 100644 (file)
@@ -444,20 +444,19 @@ static int _json_map_proc_get_value(TALLOC_CTX *ctx, fr_pair_list_t *out, reques
  *                     - #RLM_MODULE_NOOP no rows were returned or columns matched.
  *                     - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
  *                     - #RLM_MODULE_FAIL if a fault occurred.
- * @param mod_inst     unused.
- * @param proc_inst    cached jpath sequences.
+ * @param mpctx                Call context for the map processor, containing the jpath cache.
  * @param request      The current request.
  * @param json         JSON string to parse.
  * @param maps         Head of the map list.
  * @return UNLANG_ACTION_CALCULATE_RESULT
  */
-static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void const *mod_inst, void *proc_inst, request_t *request,
+static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request,
                                    fr_value_box_list_t *json, map_list_t const *maps)
 {
        rlm_rcode_t                     rcode = RLM_MODULE_UPDATED;
        struct json_tokener             *tok;
 
-       rlm_json_jpath_cache_t          *cache = proc_inst;
+       rlm_json_jpath_cache_t const    *cache = mpctx->mpi;
        map_t const                     *map = NULL;
 
        rlm_json_jpath_to_eval_t        to_eval;
@@ -467,7 +466,7 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void const *mo
 
        if (!json_head) {
                REDEBUG("JSON map input cannot be (null)");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
        if (fr_value_box_list_concat_in_place(request,
@@ -475,13 +474,13 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void const *mo
                                              FR_VALUE_BOX_LIST_FREE, true,
                                              SIZE_MAX) < 0) {
                REDEBUG("Failed concatenating input");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
        json_str = json_head->vb_strvalue;
 
        if ((talloc_array_length(json_str) - 1) == 0) {
                REDEBUG("JSON map input length must be > 0");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
        tok = json_tokener_new();
@@ -548,7 +547,7 @@ finish:
        json_object_put(to_eval.root);
        json_tokener_free(tok);
 
-       RETURN_MODULE_RCODE(rcode);
+       RETURN_UNLANG_RCODE(rcode);
 }
 
 static int mod_instantiate(module_inst_ctx_t const *mctx)
index 9b72f5279cc5899c87418a80fc188b6869b109c9..4f6df9fe73b1f34c39bb5fe8b219cac5f4ce84f7 100644 (file)
@@ -1429,17 +1429,16 @@ static int map_ctx_free(ldap_map_ctx_t *map_ctx)
  *                     - #RLM_MODULE_NOOP no rows were returned.
  *                     - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
  *                     - #RLM_MODULE_FAIL if an error occurred.
- * @param[in] mod_inst #rlm_ldap_t
- * @param[in] proc_inst unused.
+ * @param[in] mpctx module map ctx.
  * @param[in,out] request The current request.
  * @param[in] url LDAP url specifying base DN and filter.
  * @param[in] maps Head of the map list.
  * @return UNLANG_ACTION_CALCULATE_RESULT
  */
-static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, UNUSED void *proc_inst, request_t *request,
+static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request,
                                    fr_value_box_list_t *url, map_list_t const *maps)
 {
-       rlm_ldap_t const        *inst = talloc_get_type_abort_const(mod_inst, rlm_ldap_t);
+       rlm_ldap_t const        *inst = talloc_get_type_abort_const(mpctx->mpi, rlm_ldap_t);
        fr_ldap_thread_t        *thread = talloc_get_type_abort(module_thread(inst->mi)->data, fr_ldap_thread_t);
 
        LDAPURLDesc             *ldap_url;
@@ -1452,24 +1451,24 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst,
 
        if (fr_uri_escape_list(url, ldap_uri_parts, NULL) < 0) {
                RPERROR("Failed to escape LDAP map URI");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
        url_head = fr_value_box_list_head(url);
        if (!url_head) {
                REDEBUG("LDAP URL cannot be empty");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
        if (fr_value_box_list_concat_in_place(url_head, url_head, url, FR_TYPE_STRING,
                                              FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) {
                RPEDEBUG("Failed concatenating input");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
        if (!ldap_is_ldap_url(url_head->vb_strvalue)) {
                REDEBUG("Map query string does not look like a valid LDAP URI");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
        MEM(map_ctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), ldap_map_ctx_t));
@@ -1481,7 +1480,7 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst,
                RPEDEBUG("Parsing LDAP URL failed - %s", fr_ldap_url_err_to_str(ldap_url_ret));
        fail:
                talloc_free(map_ctx);
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
        ldap_url = map_ctx->ldap_url;
 
index 1f11d61ae8b262fa800f0e84605824131a9027dd..8e93a78abffd3ae79668a08ab01cee208af5b8d3 100644 (file)
@@ -202,15 +202,6 @@ typedef struct {
        sql_group_ctx_t         *group_ctx;     //!< Context used for retrieving user group membership.
 } sql_autz_ctx_t;
 
-/** Context for SQL maps
- *
- */
-typedef struct {
-       rlm_sql_t const         *inst;
-       map_list_t const        *maps;
-       fr_sql_query_t          *query_ctx;
-} sql_map_ctx_t;
-
 typedef struct {
        fr_value_box_t          user;           //!< Expansion of sql_user_name.
        fr_value_box_t          filename;       //!< File name to write SQL logs to.
@@ -716,17 +707,21 @@ static int sql_map_verify(CONF_SECTION *cs, UNUSED void const *mod_inst, UNUSED
 
 /** Process the results of an SQL map query
  *
- * @param[out] p_result        Result of applying the map.
- * @param[in] request  Current request.
- * @param[in] uctx     Map context.
- * @return One of UNLANG_ACTION_*
+ * @param p_result     Result of map expansion:
+ *                     - #RLM_MODULE_NOOP no rows were returned or columns matched.
+ *                     - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
+ *                     - #RLM_MODULE_FAIL if a fault occurred.
+ * @param mpctx                Map context, containing the module instance.
+ * @param request      The current request.
+ * @param query                string to execute.
+ * @param maps         Head of the map list.
+ * @return UNLANG_ACTION_CALCULATE_RESULT
  */
-static unlang_action_t mod_map_resume(unlang_result_t *p_result, request_t *request, void *uctx)
+static unlang_action_t mod_map_resume(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request,
+                                     UNUSED fr_value_box_list_t *query, map_list_t const *maps)
 {
-       sql_map_ctx_t           *map_ctx = talloc_get_type_abort(uctx, sql_map_ctx_t);
-       fr_sql_query_t          *query_ctx = map_ctx->query_ctx;
-       map_list_t const        *maps = map_ctx->maps;
-       rlm_sql_t const         *inst = map_ctx->inst;
+       fr_sql_query_t          *query_ctx = talloc_get_type_abort(mpctx->rctx, fr_sql_query_t);
+       rlm_sql_t const         *inst = mpctx->moi;
        map_t const             *map;
        rlm_rcode_t             rcode = RLM_MODULE_UPDATED;
        sql_rcode_t             ret;
@@ -843,7 +838,7 @@ static unlang_action_t mod_map_resume(unlang_result_t *p_result, request_t *requ
 
 finish:
        talloc_free(fields);
-       talloc_free(map_ctx);
+       talloc_free(query_ctx);
 
        RETURN_UNLANG_RCODE(rcode);
 }
@@ -854,20 +849,19 @@ finish:
  *                     - #RLM_MODULE_NOOP no rows were returned or columns matched.
  *                     - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
  *                     - #RLM_MODULE_FAIL if a fault occurred.
- * @param mod_inst #rlm_sql_t instance.
- * @param proc_inst Instance data for this specific mod_proc call (unused).
- * @param request The current request.
- * @param query string to execute.
- * @param maps Head of the map list.
+ * @param mpctx                Map context, containing the module instance.
+ * @param request      The current request.
+ * @param query                string to execute.
+ * @param maps         Head of the map list.
  * @return UNLANG_ACTION_CALCULATE_RESULT
  */
-static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, UNUSED void *proc_inst, request_t *request,
-                                   fr_value_box_list_t *query, map_list_t const *maps)
+static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request,
+                                   fr_value_box_list_t *query, UNUSED map_list_t const *maps)
 {
-       rlm_sql_t const         *inst = talloc_get_type_abort_const(mod_inst, rlm_sql_t);
+       rlm_sql_t const         *inst = talloc_get_type_abort_const(mpctx->moi, rlm_sql_t);
        rlm_sql_thread_t        *thread = talloc_get_type_abort(module_thread(inst->mi)->data, rlm_sql_thread_t);
        fr_value_box_t          *query_head = fr_value_box_list_head(query);
-       sql_map_ctx_t           *map_ctx;
+       fr_sql_query_t          *query_ctx = NULL;
        fr_value_box_t          *vb = NULL;
        rlm_sql_escape_uctx_t   *escape_uctx = NULL;
 
@@ -875,7 +869,7 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst,
 
        if (!query_head) {
                REDEBUG("Query cannot be (null)");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
        while ((vb = fr_value_box_list_next(query, vb))) {
@@ -889,22 +883,14 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst,
                                              FR_VALUE_BOX_LIST_FREE, true,
                                              SIZE_MAX) < 0) {
                RPEDEBUG("Failed concatenating input string");
-               RETURN_MODULE_FAIL;
+               RETURN_UNLANG_FAIL;
        }
 
-       MEM(map_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), sql_map_ctx_t));
-       *map_ctx = (sql_map_ctx_t) {
-               .inst = inst,
-               .maps = maps,
-       };
-
-       MEM(map_ctx->query_ctx = fr_sql_query_alloc(map_ctx, inst, request,
-                                                   thread->trunk, query_head->vb_strvalue, SQL_QUERY_SELECT));
-
-       if (unlang_function_push(NULL, request, NULL, mod_map_resume, NULL, 0,
-                                UNLANG_SUB_FRAME, map_ctx) != UNLANG_ACTION_PUSHED_CHILD) RETURN_MODULE_FAIL;
+       query_ctx = fr_sql_query_alloc(unlang_interpret_frame_talloc_ctx(request), inst, request,
+                                      thread->trunk, query_head->vb_strvalue, SQL_QUERY_SELECT);
 
-       return unlang_function_push(NULL, request, inst->select, NULL, NULL, 0, UNLANG_SUB_FRAME, map_ctx->query_ctx);
+       if (unlang_map_yield(request, mod_map_resume, NULL, 0, query_ctx) != UNLANG_ACTION_YIELD) RETURN_UNLANG_FAIL;
+       return unlang_function_push(NULL, request, inst->select, NULL, NULL, 0, UNLANG_SUB_FRAME, query_ctx);
 }
 
 /** xlat escape function for drivers which do not provide their own