]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Change module environment to more generic call environment (#4998)
authorNick Porter <nick@portercomputing.co.uk>
Thu, 18 May 2023 16:14:57 +0000 (17:14 +0100)
committerGitHub <noreply@github.com>
Thu, 18 May 2023 16:14:57 +0000 (12:14 -0400)
* Move module_env_t to its own header and rename to call_env_t

* Move and rename module_env_parsed_t

* Rename module mod_env_ctx to call_env_ctx

* Move and rename module_method_env_t

* Move and rename module env helper macros

* Move and rename module env parsing functions and make more generic

* Rework expanding of call environments to make it generic

* Add a call_method_env to xlat_t

Along with associated registration function

* Add dictionary to xlat function call for resolving module env

* Parse xlat call env when allocating instance data

* Add env_data to xlat frame state, xlat_ctx_t and supporting macro

* Add expansion of call env to unlang_xlat_repeat

* Rename mod/module _env -> call_env in rlm_ldap

* Rename module / mod _env -> call_env in rlm_smtp

* Rename module_env -> call_env in rlm_files

23 files changed:
src/lib/server/module.h
src/lib/server/module_rlm.c
src/lib/server/module_rlm.h
src/lib/unlang/all.mk
src/lib/unlang/call_env.c [new file with mode: 0644]
src/lib/unlang/call_env.h [new file with mode: 0644]
src/lib/unlang/compile.c
src/lib/unlang/module.c
src/lib/unlang/module_priv.h
src/lib/unlang/xlat.c
src/lib/unlang/xlat.h
src/lib/unlang/xlat_ctx.h
src/lib/unlang/xlat_eval.c
src/lib/unlang/xlat_func.c
src/lib/unlang/xlat_func.h
src/lib/unlang/xlat_inst.c
src/lib/unlang/xlat_priv.h
src/lib/unlang/xlat_tokenize.c
src/modules/rlm_files/rlm_files.c
src/modules/rlm_ldap/groups.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_ldap/rlm_ldap.h
src/modules/rlm_smtp/rlm_smtp.c

index 3d00700dad54468f990f7f20076c4ec7c4d0f568..06d51173d99717c9ff1f2be9f7bdf11fd718b73d 100644 (file)
@@ -35,15 +35,13 @@ extern "C" {
 #include <freeradius-devel/server/module_ctx.h>
 #include <freeradius-devel/unlang/action.h>
 #include <freeradius-devel/unlang/compile.h>
+#include <freeradius-devel/unlang/call_env.h>
 #include <freeradius-devel/util/event.h>
 
 typedef struct module_s                                module_t;
 typedef struct module_method_name_s            module_method_name_t;
 typedef struct module_instance_s               module_instance_t;
 typedef struct module_thread_instance_s                module_thread_instance_t;
-typedef struct module_env_s                    module_env_t;
-typedef struct module_env_parsed_s             module_env_parsed_t;
-typedef struct module_method_env_s             module_method_env_t;
 typedef struct module_list_t                   module_list_t;
 
 #define MODULE_TYPE_THREAD_SAFE                (0 << 0)        //!< Module is threadsafe.
@@ -120,15 +118,6 @@ typedef int (*module_thread_detach_t)(module_thread_inst_ctx_t const *mctx);
 extern "C" {
 #endif
 
-FR_DLIST_TYPES(mod_env_parsed)
-FR_DLIST_TYPEDEFS(mod_env_parsed, mod_env_parsed_head_t, mod_env_parsed_entry_t)
-
-struct module_method_env_s {
-       size_t                          inst_size;              //!< Size of per call module env.
-       char const                      *inst_type;             //!< Type of per call module env.
-       module_env_t const              *env;                   //!< Parsing rules for module method env.
-};
-
 /** Named methods exported by a module
  *
  */
@@ -137,7 +126,7 @@ struct module_method_name_s {
        char const                      *name2;                 //!< The packet type i.e Access-Request, Access-Reject.
 
        module_method_t                 method;                 //!< Module method to call
-       module_method_env_t const       *method_env;            //!< Call specific conf parsing.
+       call_method_env_t const         *method_env;            //!< Call specific conf parsing.
 };
 
 #define MODULE_NAME_TERMINATOR { NULL }
@@ -235,153 +224,6 @@ struct module_thread_instance_s {
        uint64_t                        active_callers; //! number of active callers.  i.e. number of current yields
 };
 
-typedef enum {
-       MOD_ENV_TYPE_VALUE_BOX = 1,
-       MOD_ENV_TYPE_VALUE_BOX_LIST
-} mod_env_dest_t;
-
-/** Per method module config
- *
- * Similar to a CONF_PARSER used to hold details of conf pairs
- * which are evaluated per call for each module method.
- *
- * This allows the conf pairs to be evaluated within the appropriate context
- * and use the appropriate dictionaries for where the module is in use.
- */
-struct module_env_s {
-       char const      *name;          //!< Of conf pair to pass to tmpl_tokenizer.
-       char const      *dflt;          //!< Default string to pass to the tmpl_tokenizer if no CONF_PAIR found.
-       fr_token_t      dflt_quote;     //!< Default quoting for the default string.
-
-       uint32_t        type;           //!< To cast boxes to. Also contains flags controlling parser behaviour.
-
-       size_t          offset;         //!< Where to write results in the output structure when the tmpls are evaluated.
-
-       union {
-               struct {
-                       bool            required;       //!< Tmpl must produce output
-                       bool            concat;         //!< If the tmpl produced multiple boxes they should be concatenated.
-                       bool            single;         //!< If the tmpl produces more than one box this is an error.
-                       bool            multi;          //!< Multiple instances of the conf pairs are allowed.  Resulting
-                                                       ///< boxes are stored in an array - one entry per conf pair.
-                       bool            nullable;       //!< Tmpl expansions are allowed to produce no output.
-                       mod_env_dest_t  type;           //!< Type of structure boxes will be written to.
-                       size_t          size;           //!< Size of structure boxes will be written to.
-                       char const      *type_name;     //!< Name of structure type boxes will be written to.
-                       size_t          tmpl_offset;    //!< Where to write pointer to tmpl in the output structure.  Optional.
-               } pair;
-
-               struct {
-                       char const              *ident2;        //!< Second identifier for a section
-                       module_env_t const      *subcs;         //!< Nested definitions for subsection.
-               } section;
-       };
-};
-
-#define MODULE_ENV_TERMINATOR { NULL }
-
-struct module_env_parsed_s {
-       mod_env_parsed_entry_t  entry;          //!< Entry in list of parsed module_env.
-       tmpl_t                  *tmpl;          //!< Tmpl produced from parsing conf pair.
-       size_t                  opt_count;      //!< Number of instances found of this option.
-       size_t                  multi_index;    //!< Array index for this instance.
-       module_env_t const      *rule;          //!< Used to produce this.
-};
-
-FR_DLIST_FUNCS(mod_env_parsed, module_env_parsed_t, entry)
-
-/** Derive whether tmpl can only emit a single box.
- */
-#define FR_MODULE_ENV_SINGLE(_s, _f, _c) \
-_Generic((((_s *)NULL)->_f), \
-       fr_value_box_t                  : __builtin_choose_expr(_c, false, true), \
-       fr_value_box_t *                : __builtin_choose_expr(_c, false, true), \
-       fr_value_box_list_t             : false, \
-       fr_value_box_list_t *           : false \
-)
-
-/** Derive whether multi conf pairs are allowed from target field type.
- */
-#define FR_MODULE_ENV_MULTI(_s, _f) \
-_Generic((((_s *)NULL)->_f), \
-       fr_value_box_t                  : false, \
-       fr_value_box_t *                : true, \
-       fr_value_box_list_t             : false, \
-       fr_value_box_list_t *           : true \
-)
-
-/** Only FR_TYPE_STRING and FR_TYPE_OCTETS can be concatenated.
- */
-#define FR_MODULE_ENV_CONCAT(_c, _ct) \
-__builtin_choose_expr(FR_BASE_TYPE(_ct) == FR_TYPE_STRING, _c, \
-__builtin_choose_expr(FR_BASE_TYPE(_ct) == FR_TYPE_OCTETS, _c, \
-__builtin_choose_expr(_c, (void)0, false)))
-
-/** Mapping from field types to destination type enum
- */
-#define FR_MODULE_ENV_DST_TYPE(_s, _f) \
-_Generic((((_s *)NULL)->_f), \
-       fr_value_box_t                  : MOD_ENV_TYPE_VALUE_BOX, \
-       fr_value_box_t *                : MOD_ENV_TYPE_VALUE_BOX, \
-       fr_value_box_list_t             : MOD_ENV_TYPE_VALUE_BOX_LIST, \
-       fr_value_box_list_t *           : MOD_ENV_TYPE_VALUE_BOX_LIST \
-)
-
-#define FR_MODULE_ENV_DST_SIZE(_s, _f) \
-_Generic((((_s *)NULL)->_f), \
-       fr_value_box_t                  : sizeof(fr_value_box_t), \
-       fr_value_box_t *                : sizeof(fr_value_box_t), \
-       fr_value_box_list_t             : sizeof(fr_value_box_list_t), \
-       fr_value_box_list_t *           : sizeof(fr_value_box_list_t) \
-)
-
-#define FR_MODULE_ENV_DST_TYPE_NAME(_s, _f) \
-_Generic((((_s *)NULL)->_f), \
-       fr_value_box_t                  : "fr_value_box_t", \
-       fr_value_box_t *                : "fr_value_box_t", \
-       fr_value_box_list_t             : "fr_value_box_list_t", \
-       fr_value_box_list_t *           : "fr_value_box_list_t" \
-)
-
-#define FR_MODULE_ENV_OFFSET(_name, _cast_type, _struct, _field, _dflt, _dflt_quote, _required, _nullable, _concat) \
-       .name = _name, \
-       .type = _cast_type, \
-       .offset = offsetof(_struct, _field), \
-       .dflt = _dflt, \
-       .dflt_quote = _dflt_quote, \
-       .pair = { .required = _required, \
-                 .concat = FR_MODULE_ENV_CONCAT(_concat, _cast_type), \
-                 .single = FR_MODULE_ENV_SINGLE(_struct, _field, _concat), \
-                 .multi = FR_MODULE_ENV_MULTI(_struct, _field), \
-                 .nullable = _nullable, \
-                 .type = FR_MODULE_ENV_DST_TYPE(_struct, _field), \
-                 .size = FR_MODULE_ENV_DST_SIZE(_struct, _field), \
-                 .type_name = FR_MODULE_ENV_DST_TYPE_NAME(_struct, _field) }
-
-/** Version of the above which sets optional field for pointer to tmpl
- */
-#define FR_MODULE_ENV_TMPL_OFFSET(_name, _cast_type, _struct, _field, _tmpl_field, _dflt, _dflt_quote, _required, _nullable, _concat) \
-       .name = _name, \
-       .type = _cast_type, \
-       .offset = offsetof(_struct, _field), \
-       .dflt = _dflt, \
-       .dflt_quote = _dflt_quote, \
-       .pair = { .required = _required, \
-                 .concat = FR_MODULE_ENV_CONCAT(_concat, _cast_type), \
-                 .single = FR_MODULE_ENV_SINGLE(_struct, _field, _concat), \
-                 .multi = FR_MODULE_ENV_MULTI(_struct, _field), \
-                 .nullable = _nullable, \
-                 .type = FR_MODULE_ENV_DST_TYPE(_struct, _field), \
-                 .size = FR_MODULE_ENV_DST_SIZE(_struct, _field), \
-                 .type_name = FR_MODULE_ENV_DST_TYPE_NAME(_struct, _field), \
-                 .tmpl_offset = offsetof(_struct, _tmpl_field) }
-
-#define FR_MODULE_ENV_SUBSECTION(_name, _ident2, _subcs ) \
-       .name = _name, \
-       .type = FR_TYPE_SUBSECTION, \
-       .section = { .ident2 = _ident2, \
-                    .subcs = _subcs }
-
 /** A list of modules
  *
  * This allows modules to be instantiated and freed in phases,
index 7fd80c073a760612908de15d788dd6143d9cd5aa..4992d72c96d693a58df23b786cc55dc932dc9058 100644 (file)
@@ -431,7 +431,7 @@ bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_
  *
  *  If the module exists but the method doesn't exist, then `method` is set to NULL.
  */
-module_instance_t *module_rlm_by_name_and_method(module_method_t *method, module_method_env_t const **method_env,
+module_instance_t *module_rlm_by_name_and_method(module_method_t *method, call_method_env_t const **method_env,
                                                 UNUSED rlm_components_t *component,
                                                 char const **name1, char const **name2,
                                                 char const *name)
index e01450c8410c113124aece5ddac922bca965631a..4eb10f38aeecdc0decbbd922aea6d989b54f0697 100644 (file)
@@ -84,7 +84,7 @@ bool          module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type
  *
  * @{
  */
-module_instance_t      *module_rlm_by_name_and_method(module_method_t *method, module_method_env_t const ** method_env,
+module_instance_t      *module_rlm_by_name_and_method(module_method_t *method, call_method_env_t const ** method_env,
                                                   rlm_components_t *component,
                                                   char const **name1, char const **name2,
                                                   char const *asked_name);
index 460c3dc32ff3069883666b7e8a94e32fc6c4f52a..821a6023c0a29312b953bbc6b470d68b59068404 100644 (file)
@@ -2,6 +2,7 @@ TARGET          := libfreeradius-unlang$(L)
 
 SOURCES        :=      base.c \
                call.c \
+               call_env.c \
                caller.c \
                compile.c \
                condition.c \
diff --git a/src/lib/unlang/call_env.c b/src/lib/unlang/call_env.c
new file mode 100644 (file)
index 0000000..5461544
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ *   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 unlang/call_env.c
+ * @brief Call environment parsing functions
+ *
+ * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/server/log.h>
+#include <freeradius-devel/unlang/tmpl.h>
+#include <freeradius-devel/unlang/function.h>
+#include <freeradius-devel/unlang/interpret.h>
+#include "call_env.h"
+
+/** Parse per call env
+ *
+ * Used for config options which must be parsed in the context in which
+ * the module is being called.
+ *
+ * @param[in] ctx              To allocate parsed environment in.
+ * @param[out] parsed          Where to write parsed environment.
+ * @param[in] name             Module name for error messages.
+ * @param[in] dict_def         Default dictionary to use when tokenizing tmpls.
+ * @param[in] cs               Module config.
+ * @param[in] call_env         to parse.
+ * @return
+ *     - 0 on success;
+ *     - <0 on failure;
+ */
+int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char const *name, fr_dict_t const *dict_def,
+                  CONF_SECTION const *cs, call_env_t const *call_env) {
+       CONF_PAIR const         *cp, *next;
+       call_env_parsed_t       *call_env_parsed;
+       ssize_t                 len, opt_count, multi_index;
+       char const              *value;
+       fr_token_t              quote;
+       fr_type_t               type;
+
+       while (call_env->name) {
+               if (FR_BASE_TYPE(call_env->type) == FR_TYPE_SUBSECTION) {
+                       CONF_SECTION const *subcs;
+                       subcs = cf_section_find(cs, call_env->name, call_env->section.ident2);
+                       if (!subcs) goto next;
+
+                       if (call_env_parse(ctx, parsed, name, dict_def, subcs, call_env->section.subcs) < 0) return -1;
+                       goto next;
+               }
+
+               cp = cf_pair_find(cs, call_env->name);
+
+               if (!cp && !call_env->dflt) {
+                       if (!call_env->pair.required) goto next;
+
+                       cf_log_err(cs, "Module %s missing required option %s", name, call_env->name);
+                       return -1;
+               }
+
+               /*
+                *      Check for additional conf pairs and error
+                *      if there is one and multi is not allowed.
+                */
+               if (!call_env->pair.multi && ((next = cf_pair_find_next(cs, cp, call_env->name)))) {
+                       cf_log_err(cf_pair_to_item(next), "Invalid duplicate configuration item '%s'", call_env->name);
+                       return -1;
+               }
+
+               opt_count = cf_pair_count(cs, call_env->name);
+               if (opt_count == 0) opt_count = 1;
+
+               for (multi_index = 0; multi_index < opt_count; multi_index ++) {
+                       MEM(call_env_parsed = talloc_zero(ctx, call_env_parsed_t));
+                       call_env_parsed->rule = call_env;
+                       call_env_parsed->opt_count = opt_count;
+                       call_env_parsed->multi_index = multi_index;
+
+                       if (cp) {
+                               value = cf_pair_value(cp);
+                               len = talloc_array_length(value) - 1;
+                               quote = cf_pair_value_quote(cp);
+                       } else {
+                               value = call_env->dflt;
+                               len = strlen(value);
+                               quote = call_env->dflt_quote;
+                       }
+
+                       type = FR_BASE_TYPE(call_env->type);
+                       if (tmpl_afrom_substr(call_env_parsed, &call_env_parsed->tmpl, &FR_SBUFF_IN(value, len),
+                                             quote, NULL, &(tmpl_rules_t){
+                                                       .cast = (type == FR_TYPE_VOID ? FR_TYPE_NULL : type),
+                                                       .attr = {
+                                                               .list_def = request_attr_request,
+                                                               .dict_def = dict_def
+                                                       }
+                                               }) < 0) {
+                       error:
+                               talloc_free(call_env_parsed);
+                               cf_log_perr(cp, "Failed to parse '%s' for %s", cf_pair_value(cp), call_env->name);
+                               return -1;
+                       }
+
+                       /*
+                        *      Ensure only valid TMPL types are produced.
+                        */
+                       switch (call_env_parsed->tmpl->type) {
+                       case TMPL_TYPE_ATTR:
+                       case TMPL_TYPE_DATA:
+                       case TMPL_TYPE_EXEC:
+                       case TMPL_TYPE_XLAT:
+                               break;
+
+                       default:
+                               cf_log_err(cp, "'%s' expands to invalid tmpl type %s", value,
+                                          fr_table_str_by_value(tmpl_type_table, call_env_parsed->tmpl->type, "<INVALID>"));
+                               goto error;
+                       }
+
+                       call_env_parsed_insert_tail(parsed, call_env_parsed);
+
+                       cp = cf_pair_find_next(cs, cp, call_env->name);
+               }
+       next:
+               call_env++;
+       }
+
+       return 0;
+}
+
+/**  Perform a quick assessment of how many parsed call env will be produced.
+ *
+ * @param[in,out] vallen       Where to write the sum of the length of pair values.
+ * @param[in] cs               Conf section to search for pairs.
+ * @param[in] call_env         to parse.
+ * @return Number of parsed_call_env expected to be required.
+ */
+size_t call_env_count(size_t *vallen, CONF_SECTION const *cs, call_env_t const *call_env) {
+       size_t  pair_count, tmpl_count = 0;
+       CONF_PAIR const *cp;
+
+       while (call_env->name) {
+               if (FR_BASE_TYPE(call_env->type) == FR_TYPE_SUBSECTION) {
+                       CONF_SECTION const *subcs;
+                       subcs = cf_section_find(cs, call_env->name, call_env->section.ident2);
+                       if (!subcs) goto next;
+
+                       tmpl_count += call_env_count(vallen, subcs, call_env->section.subcs);
+                       goto next;
+               }
+               pair_count = 0;
+               cp = NULL;
+               while ((cp = cf_pair_find_next(cs, cp, call_env->name))) {
+                       pair_count++;
+                       *vallen += talloc_array_length(cf_pair_value(cp));
+               }
+               if (!pair_count && call_env->dflt) {
+                       pair_count = 1;
+                       *vallen += strlen(call_env->dflt);
+               }
+               tmpl_count += pair_count;
+       next:
+               call_env++;
+       }
+
+       return tmpl_count;
+}
+
+/** Parse the result of call_env tmpl expansion
+ */
+static inline CC_HINT(always_inline) int call_env_value_parse(TALLOC_CTX *ctx, request_t *request, void *out,
+                                                             void **tmpl_out, call_env_parsed_t const *env,
+                                                             fr_value_box_list_t *tmpl_expanded)
+{
+       fr_value_box_t  *vb = fr_value_box_list_head(tmpl_expanded);
+
+       if (!vb) {
+               if (!env->rule->pair.nullable) {
+                       RPEDEBUG("Failed to evaluate required module option %s", env->rule->name);
+                       return -1;
+               }
+               return 0;
+       }
+
+       /*
+        *      Concatenate multiple boxes if needed
+        */
+       if (env->rule->pair.concat &&
+           fr_value_box_list_concat_in_place(vb, vb, tmpl_expanded, FR_BASE_TYPE(env->rule->type),
+                                             FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0 ) {
+               RPEDEBUG("Failed concatenating values for %s", env->rule->name);
+               return -1;
+       }
+
+       if (env->rule->pair.single && (fr_value_box_list_num_elements(tmpl_expanded) > 1)) {
+               RPEDEBUG("%d values found for %s.  Only one is allowed",
+                        fr_value_box_list_num_elements(tmpl_expanded), env->rule->name);
+               return -1;
+       }
+
+       while ((vb = fr_value_box_list_pop_head(tmpl_expanded))) {
+               switch (env->rule->pair.type) {
+               case CALL_ENV_TYPE_VALUE_BOX:
+                       fr_value_box_copy_shallow(ctx, (fr_value_box_t *)(out), vb);
+                       break;
+
+               case CALL_ENV_TYPE_VALUE_BOX_LIST:
+                       if (!fr_value_box_list_initialised((fr_value_box_list_t *)out)) fr_value_box_list_init((fr_value_box_list_t *)out);
+                       fr_value_box_list_insert_tail((fr_value_box_list_t *)out, vb);
+                       break;
+               }
+       }
+
+       if (tmpl_out) *tmpl_out = env->tmpl;
+
+       return 0;
+}
+
+/** Context to keep track of expansion of call environments
+ *
+ */
+typedef struct {
+       call_env_parsed_head_t const    *call_env_parsed;       //!< Head of the parsed list of tmpls to expand.
+       call_env_parsed_t const         *last_expanded;         //!< The last expanded tmpl.
+       fr_value_box_list_t             tmpl_expanded;          //!< List to write value boxes to as tmpls are expanded.
+       void                            **env_data;             //!< Final destination structure for value boxes.
+} call_env_ctx_t;
+
+/** Start the expansion of a call environment tmpl.
+ *
+ */
+static unlang_action_t call_env_expand_start(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
+{
+       call_env_ctx_t  *call_env_ctx = talloc_get_type_abort(uctx, call_env_ctx_t);
+       TALLOC_CTX      *ctx;
+       call_env_parsed_t const *env;
+       void            *out;
+
+       call_env_ctx->last_expanded = call_env_parsed_next(call_env_ctx->call_env_parsed, call_env_ctx->last_expanded);
+       if (!call_env_ctx->last_expanded) return UNLANG_ACTION_CALCULATE_RESULT;
+
+       ctx = *call_env_ctx->env_data;
+       env = call_env_ctx->last_expanded;
+
+       /*
+        *      Multi pair options should allocate boxes in the context of the array
+        */
+       if (env->rule->pair.multi) {
+               out = ((uint8_t *)(*call_env_ctx->env_data)) + env->rule->offset;
+
+               /*
+                *      For multi pair options, allocate the array before expanding the first entry.
+                */
+               if (env->multi_index == 0) {
+                       void *array;
+                       MEM(array = _talloc_zero_array((*call_env_ctx->env_data), env->rule->pair.size,
+                                                      env->opt_count, env->rule->pair.type_name));
+                       *(void **)out = array;
+               }
+               ctx = *(void **)out;
+       }
+
+       if (unlang_tmpl_push(ctx, &call_env_ctx->tmpl_expanded, request, call_env_ctx->last_expanded->tmpl,
+                            NULL) < 0) return UNLANG_ACTION_FAIL;
+
+       return UNLANG_ACTION_PUSHED_CHILD;
+}
+
+/** Extract expanded call environment tmpl and store in env_data
+ *
+ * If there are more tmpls to expand, push the next expansion.
+ */
+static unlang_action_t call_env_expand_repeat(UNUSED rlm_rcode_t *p_result, UNUSED int *priority,
+                                             request_t *request, void *uctx)
+{
+       void                    *out, *tmpl_out = NULL;
+       call_env_ctx_t          *call_env_ctx = talloc_get_type_abort(uctx, call_env_ctx_t);
+       call_env_parsed_t       const *env;
+
+       env = call_env_ctx->last_expanded;
+       if (!env) return UNLANG_ACTION_CALCULATE_RESULT;
+
+       /*
+        *      Find the location of the output
+        */
+       out = ((uint8_t*)(*call_env_ctx->env_data)) + env->rule->offset;
+
+       /*
+        *      If this is a multi pair option, the output is an array.
+        *      Find the correct offset in the array
+        */
+       if (env->rule->pair.multi) {
+               void *array = *(void **)out;
+               out = ((uint8_t *)array) + env->rule->pair.size * env->multi_index;
+       }
+
+       if (env->rule->pair.tmpl_offset) tmpl_out = ((uint8_t *)call_env_ctx->env_data) + env->rule->pair.tmpl_offset;
+
+       if (call_env_value_parse(*call_env_ctx->env_data, request, out, tmpl_out, env,
+                                &call_env_ctx->tmpl_expanded) < 0) return UNLANG_ACTION_FAIL;
+
+       if (!call_env_parsed_next(call_env_ctx->call_env_parsed, env)) return UNLANG_ACTION_CALCULATE_RESULT;
+
+       return unlang_function_push(request, call_env_expand_start, call_env_expand_repeat, NULL, 0, UNLANG_SUB_FRAME,
+                                   call_env_ctx);
+}
+
+/** Initialise the expansion of a call environment
+ *
+ * @param[in] ctx              in which to allocate destination structure for resulting value boxes.
+ * @param[in] request          Current request.
+ * @param[in,out] env_data     Where the destination structure should be created.
+ * @param[in] call_env         Call environment being expanded.
+ * @param[in] call_env_parsed  Parsed tmpls for the call environment.
+ */
+unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, void **env_data, call_method_env_t const *call_env,
+                               call_env_parsed_head_t const *call_env_parsed)
+{
+       call_env_ctx_t  *call_env_ctx;
+
+       MEM(call_env_ctx = talloc_zero(ctx, call_env_ctx_t));
+       MEM(*env_data = talloc_zero_array(ctx, uint8_t, call_env->inst_size));
+       talloc_set_name_const(*env_data, call_env->inst_type);
+       call_env_ctx->env_data = env_data;
+       call_env_ctx->call_env_parsed = call_env_parsed;
+       fr_value_box_list_init(&call_env_ctx->tmpl_expanded);
+
+       return unlang_function_push(request, call_env_expand_start, call_env_expand_repeat, NULL, 0, UNLANG_SUB_FRAME,
+                                   call_env_ctx);
+}
diff --git a/src/lib/unlang/call_env.h b/src/lib/unlang/call_env.h
new file mode 100644 (file)
index 0000000..1ca2acd
--- /dev/null
@@ -0,0 +1,205 @@
+#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/call_env.h
+ * @brief Structures and functions for handling call environments.
+ *
+ * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
+ */
+RCSIDH(call_env_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <freeradius-devel/util/dlist.h>
+#include <freeradius-devel/server/cf_parse.h>
+
+typedef struct call_env_s              call_env_t;
+typedef struct call_env_parsed_s       call_env_parsed_t;
+typedef struct call_method_env_s       call_method_env_t;
+
+FR_DLIST_TYPES(call_env_parsed)
+FR_DLIST_TYPEDEFS(call_env_parsed, call_env_parsed_head_t, call_env_parsed_entry_t)
+
+typedef enum {
+       CALL_ENV_TYPE_VALUE_BOX = 1,
+       CALL_ENV_TYPE_VALUE_BOX_LIST
+} call_env_dest_t;
+
+/** Per method call config
+ *
+ * Similar to a CONF_PARSER used to hold details of conf pairs
+ * which are evaluated per call for each module method / xlat.
+ *
+ * This allows the conf pairs to be evaluated within the appropriate context
+ * and use the appropriate dictionaries for where the module is in use.
+ */
+struct call_env_s {
+       char const      *name;          //!< Of conf pair to pass to tmpl_tokenizer.
+       char const      *dflt;          //!< Default string to pass to the tmpl_tokenizer if no CONF_PAIR found.
+       fr_token_t      dflt_quote;     //!< Default quoting for the default string.
+
+       uint32_t        type;           //!< To cast boxes to. Also contains flags controlling parser behaviour.
+
+       size_t          offset;         //!< Where to write results in the output structure when the tmpls are evaluated.
+
+       union {
+               struct {
+                       bool            required;       //!< Tmpl must produce output
+                       bool            concat;         //!< If the tmpl produced multiple boxes they should be concatenated.
+                       bool            single;         //!< If the tmpl produces more than one box this is an error.
+                       bool            multi;          //!< Multiple instances of the conf pairs are allowed.  Resulting
+                                                       ///< boxes are stored in an array - one entry per conf pair.
+                       bool            nullable;       //!< Tmpl expansions are allowed to produce no output.
+                       call_env_dest_t type;           //!< Type of structure boxes will be written to.
+                       size_t          size;           //!< Size of structure boxes will be written to.
+                       char const      *type_name;     //!< Name of structure type boxes will be written to.
+                       size_t          tmpl_offset;    //!< Where to write pointer to tmpl in the output structure.  Optional.
+               } pair;
+
+               struct {
+                       char const              *ident2;        //!< Second identifier for a section
+                       call_env_t const        *subcs;         //!< Nested definitions for subsection.
+               } section;
+       };
+};
+
+#define CALL_ENV_TERMINATOR { NULL }
+
+struct call_env_parsed_s {
+       call_env_parsed_entry_t entry;          //!< Entry in list of parsed call_env.
+       tmpl_t                  *tmpl;          //!< Tmpl produced from parsing conf pair.
+       size_t                  opt_count;      //!< Number of instances found of this option.
+       size_t                  multi_index;    //!< Array index for this instance.
+       call_env_t const        *rule;          //!< Used to produce this.
+};
+
+FR_DLIST_FUNCS(call_env_parsed, call_env_parsed_t, entry)
+
+struct call_method_env_s {
+       size_t                  inst_size;      //!< Size of per call env.
+       char const              *inst_type;     //!< Type of per call env.
+       call_env_t const        *env;           //!< Parsing rules for call method env.
+};
+
+/** Derive whether tmpl can only emit a single box.
+ */
+#define FR_CALL_ENV_SINGLE(_s, _f, _c) \
+_Generic((((_s *)NULL)->_f), \
+       fr_value_box_t                  : __builtin_choose_expr(_c, false, true), \
+       fr_value_box_t *                : __builtin_choose_expr(_c, false, true), \
+       fr_value_box_list_t             : false, \
+       fr_value_box_list_t *           : false \
+)
+
+/** Derive whether multi conf pairs are allowed from target field type.
+ */
+#define FR_CALL_ENV_MULTI(_s, _f) \
+_Generic((((_s *)NULL)->_f), \
+       fr_value_box_t                  : false, \
+       fr_value_box_t *                : true, \
+       fr_value_box_list_t             : false, \
+       fr_value_box_list_t *           : true \
+)
+
+/** Only FR_TYPE_STRING and FR_TYPE_OCTETS can be concatenated.
+ */
+#define FR_CALL_ENV_CONCAT(_c, _ct) \
+__builtin_choose_expr(FR_BASE_TYPE(_ct) == FR_TYPE_STRING, _c, \
+__builtin_choose_expr(FR_BASE_TYPE(_ct) == FR_TYPE_OCTETS, _c, \
+__builtin_choose_expr(_c, (void)0, false)))
+
+/** Mapping from field types to destination type enum
+ */
+#define FR_CALL_ENV_DST_TYPE(_s, _f) \
+_Generic((((_s *)NULL)->_f), \
+       fr_value_box_t                  : CALL_ENV_TYPE_VALUE_BOX, \
+       fr_value_box_t *                : CALL_ENV_TYPE_VALUE_BOX, \
+       fr_value_box_list_t             : CALL_ENV_TYPE_VALUE_BOX_LIST, \
+       fr_value_box_list_t *           : CALL_ENV_TYPE_VALUE_BOX_LIST \
+)
+
+#define FR_CALL_ENV_DST_SIZE(_s, _f) \
+_Generic((((_s *)NULL)->_f), \
+       fr_value_box_t                  : sizeof(fr_value_box_t), \
+       fr_value_box_t *                : sizeof(fr_value_box_t), \
+       fr_value_box_list_t             : sizeof(fr_value_box_list_t), \
+       fr_value_box_list_t *           : sizeof(fr_value_box_list_t) \
+)
+
+#define FR_CALL_ENV_DST_TYPE_NAME(_s, _f) \
+_Generic((((_s *)NULL)->_f), \
+       fr_value_box_t                  : "fr_value_box_t", \
+       fr_value_box_t *                : "fr_value_box_t", \
+       fr_value_box_list_t             : "fr_value_box_list_t", \
+       fr_value_box_list_t *           : "fr_value_box_list_t" \
+)
+
+#define FR_CALL_ENV_OFFSET(_name, _cast_type, _struct, _field, _dflt, _dflt_quote, _required, _nullable, _concat) \
+       .name = _name, \
+       .type = _cast_type, \
+       .offset = offsetof(_struct, _field), \
+       .dflt = _dflt, \
+       .dflt_quote = _dflt_quote, \
+       .pair = { .required = _required, \
+                 .concat = FR_CALL_ENV_CONCAT(_concat, _cast_type), \
+                 .single = FR_CALL_ENV_SINGLE(_struct, _field, _concat), \
+                 .multi = FR_CALL_ENV_MULTI(_struct, _field), \
+                 .nullable = _nullable, \
+                 .type = FR_CALL_ENV_DST_TYPE(_struct, _field), \
+                 .size = FR_CALL_ENV_DST_SIZE(_struct, _field), \
+                 .type_name = FR_CALL_ENV_DST_TYPE_NAME(_struct, _field) }
+
+/** Version of the above which sets optional field for pointer to tmpl
+ */
+#define FR_CALL_ENV_TMPL_OFFSET(_name, _cast_type, _struct, _field, _tmpl_field, _dflt, _dflt_quote, _required, _nullable, _concat) \
+       .name = _name, \
+       .type = _cast_type, \
+       .offset = offsetof(_struct, _field), \
+       .dflt = _dflt, \
+       .dflt_quote = _dflt_quote, \
+       .pair = { .required = _required, \
+                 .concat = FR_CALL_ENV_CONCAT(_concat, _cast_type), \
+                 .single = FR_CALL_ENV_SINGLE(_struct, _field, _concat), \
+                 .multi = FR_CALL_ENV_MULTI(_struct, _field), \
+                 .nullable = _nullable, \
+                 .type = FR_CALL_ENV_DST_TYPE(_struct, _field), \
+                 .size = FR_CALL_ENV_DST_SIZE(_struct, _field), \
+                 .type_name = FR_CALL_ENV_DST_TYPE_NAME(_struct, _field), \
+                 .tmpl_offset = offsetof(_struct, _tmpl_field) }
+
+#define FR_CALL_ENV_SUBSECTION(_name, _ident2, _subcs ) \
+       .name = _name, \
+       .type = FR_TYPE_SUBSECTION, \
+       .section = { .ident2 = _ident2, \
+                    .subcs = _subcs }
+
+int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char const *name, fr_dict_t const *dict_def,
+                  CONF_SECTION const *cs, call_env_t const *call_env);
+
+size_t call_env_count(size_t *vallen, CONF_SECTION const *cs, call_env_t const *call_env);
+
+unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, void **env_data, call_method_env_t const *call_env,
+                               call_env_parsed_head_t const *call_env_parsed);
+
+#ifdef __cplusplus
+}
+#endif
index fb5a4da8411506671a8955fce344082098d6fdb7..1699edc7aba970500938185b682364b8e62dcb23 100644 (file)
@@ -4655,158 +4655,9 @@ check_for_loop:
        return subcs;
 }
 
-/** Parse per call module env
- *
- * Used for config options which must be parsed in the context in which
- * the module is being called.
- *
- * @param[in] single           Module call being compiled.
- * @param[in] unlang_ctx       Current compilation context.
- * @param[in] cs               Module config.
- * @param[in] module_env       to parse.
- * @return
- *     - 0 on success;
- *     - <0 on failure;
- */
-static int method_env_parse(unlang_module_t *single, unlang_compile_t *unlang_ctx, CONF_SECTION const *cs,
-                           module_env_t const *module_env) {
-       CONF_PAIR const         *cp, *next;
-       module_env_parsed_t     *module_env_parsed;
-       ssize_t                 len, opt_count, multi_index;
-       char const              *value;
-       fr_token_t              quote;
-       fr_type_t               type;
-
-       while (module_env->name) {
-               if (FR_BASE_TYPE(module_env->type) == FR_TYPE_SUBSECTION) {
-                       CONF_SECTION const *subcs;
-                       subcs = cf_section_find(cs, module_env->name, module_env->section.ident2);
-                       if (!subcs) goto next;
-
-                       if (method_env_parse(single, unlang_ctx, subcs, module_env->section.subcs) < 0) return -1;
-                       goto next;
-               }
-
-               cp = cf_pair_find(cs, module_env->name);
-
-               if (!cp && !module_env->dflt) {
-                       if (!module_env->pair.required) goto next;
-
-                       cf_log_err(cs, "Module %s missing required option %s", single->self.name, module_env->name);
-                       return -1;
-               }
-
-               /*
-                *      Check for additional conf pairs and error
-                *      if there is one and multi is not allowed.
-                */
-               if (!module_env->pair.multi && ((next = cf_pair_find_next(cs, cp, module_env->name)))) {
-                       cf_log_err(cf_pair_to_item(next), "Invalid duplicate configuration item '%s'", module_env->name);
-                       return -1;
-               }
-
-               opt_count = cf_pair_count(cs, module_env->name);
-               if (opt_count == 0) opt_count = 1;
-
-               for (multi_index = 0; multi_index < opt_count; multi_index ++) {
-                       MEM(module_env_parsed = talloc_zero(single->mod_env_ctx, module_env_parsed_t));
-                       module_env_parsed->rule = module_env;
-                       module_env_parsed->opt_count = opt_count;
-                       module_env_parsed->multi_index = multi_index;
-
-                       if (cp) {
-                               value = cf_pair_value(cp);
-                               len = talloc_array_length(value) - 1;
-                               quote = cf_pair_value_quote(cp);
-                       } else {
-                               value = module_env->dflt;
-                               len = strlen(value);
-                               quote = module_env->dflt_quote;
-                       }
-
-                       type = FR_BASE_TYPE(module_env->type);
-                       if (tmpl_afrom_substr(module_env_parsed, &module_env_parsed->tmpl, &FR_SBUFF_IN(value, len),
-                                             quote, NULL, &(tmpl_rules_t){
-                                                       .cast = (type == FR_TYPE_VOID ? FR_TYPE_NULL : type),
-                                                       .attr = {
-                                                               .list_def = request_attr_request,
-                                                               .dict_def = unlang_ctx->rules->attr.dict_def
-                                                       }
-                                               }) < 0) {
-                       error:
-                               talloc_free(module_env_parsed);
-                               cf_log_perr(cp, "Failed to parse '%s' for %s", cf_pair_value(cp), module_env->name);
-                               return -1;
-                       }
-
-                       /*
-                        *      Ensure only valid TMPL types are produced.
-                        */
-                       switch (module_env_parsed->tmpl->type) {
-                       case TMPL_TYPE_ATTR:
-                       case TMPL_TYPE_DATA:
-                       case TMPL_TYPE_EXEC:
-                       case TMPL_TYPE_XLAT:
-                               break;
-
-                       default:
-                               cf_log_err(cp, "'%s' expands to invalid tmpl type %s", value,
-                                          fr_table_str_by_value(tmpl_type_table, module_env_parsed->tmpl->type, "<INVALID>"));
-                               goto error;
-                       }
-
-                       mod_env_parsed_insert_tail(&single->mod_env_parsed, module_env_parsed);
-
-                       cp = cf_pair_find_next(cs, cp, module_env->name);
-               }
-       next:
-               module_env++;
-       }
-
-       return 0;
-}
-
-/**  Perform a quick assesment of how many parsed module env will be produced.
- *
- * @param[in,out] vallen       Where to write the sum of the length of pair values.
- * @param[in] cs               Conf section to search for pairs.
- * @param[in] module_env       to parse.
- * @return Number of parsed_module_env expected to be required.
- */
-static size_t method_env_count(size_t *vallen, CONF_SECTION const *cs, module_env_t const *module_env) {
-       size_t  pair_count, tmpl_count = 0;
-       CONF_PAIR const *cp;
-
-       while (module_env->name) {
-               if (FR_BASE_TYPE(module_env->type) == FR_TYPE_SUBSECTION) {
-                       CONF_SECTION const *subcs;
-                       subcs = cf_section_find(cs, module_env->name, module_env->section.ident2);
-                       if (!subcs) goto next;
-
-                       tmpl_count += method_env_count(vallen, subcs, module_env->section.subcs);
-                       goto next;
-               }
-               pair_count = 0;
-               cp = NULL;
-               while ((cp = cf_pair_find_next(cs, cp, module_env->name))) {
-                       pair_count++;
-                       *vallen += talloc_array_length(cf_pair_value(cp));
-               }
-               if (!pair_count && module_env->dflt) {
-                       pair_count = 1;
-                       *vallen += strlen(module_env->dflt);
-               }
-               tmpl_count += pair_count;
-       next:
-               module_env++;
-       }
-
-       return tmpl_count;
-}
-
 static unlang_t *compile_module(unlang_t *parent, unlang_compile_t *unlang_ctx,
                                CONF_ITEM *ci, module_instance_t *inst, module_method_t method,
-                               module_method_env_t const *method_env, char const *realname)
+                               call_method_env_t const *method_env, char const *realname)
 {
        module_rlm_t const *mrlm = module_rlm_from_module(inst->module);
        unlang_t *c;
@@ -4869,12 +4720,13 @@ static unlang_t *compile_module(unlang_t *parent, unlang_compile_t *unlang_ctx,
                 *      The pool size is a rough estimate based on each tmpl also allocating at least two children,
                 *      for which we allow twice the length of the value to be parsed.
                 */
-               count = method_env_count(&vallen, inst->dl_inst->conf, method_env->env);
-               MEM(single->mod_env_ctx = _talloc_pooled_object(single, 0, "mod_env_ctx", count * 4,
-                                               (sizeof(module_env_parsed_t) + sizeof(tmpl_t)) * count + vallen * 2));
+               count = call_env_count(&vallen, inst->dl_inst->conf, method_env->env);
+               MEM(single->call_env_ctx = _talloc_pooled_object(single, 0, "call_env_ctx", count * 4,
+                                               (sizeof(call_env_parsed_t) + sizeof(tmpl_t)) * count + vallen * 2));
 
-               mod_env_parsed_init(&single->mod_env_parsed);
-               if (method_env_parse(single, unlang_ctx, inst->dl_inst->conf, method_env->env) < 0) {
+               call_env_parsed_init(&single->call_env_parsed);
+               if (call_env_parse(single->call_env_ctx, &single->call_env_parsed, single->self.name,
+                                  unlang_ctx->rules->attr.dict_def, inst->dl_inst->conf, method_env->env) < 0) {
                error:
                        talloc_free(c);
                        return NULL;
@@ -4942,7 +4794,7 @@ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
        bool                    policy;
        unlang_op_compile_t     compile;
        unlang_t                *c;
-       module_method_env_t const       *method_env = NULL;
+       call_method_env_t const *method_env = NULL;
 
        if (cf_item_is_section(ci)) {
                cs = cf_item_to_section(ci);
index f2f9f1b2ac25a9793d2f998471ea011e5b6f0374..4c758064308fd1bc2c93e4227032e94af67f6659 100644 (file)
@@ -875,57 +875,6 @@ static void unlang_module_event_retry_handler(UNUSED fr_event_list_t *el, fr_tim
        frame->signal(request, frame, FR_SIGNAL_TIMEOUT);
 }
 
-/** Parse the result of module_env tmpl expansion
- */
-static inline CC_HINT(always_inline) int module_env_value_parse(request_t *request, void *out, void **tmpl_out,
-                                                               unlang_frame_state_module_t *state) {
-       fr_value_box_t                  *vb;
-       module_env_parsed_t const       *env = state->last_expanded;
-
-       vb = fr_value_box_list_head(&state->tmpl_expanded);
-
-       if (!vb) {
-               if (!env->rule->pair.nullable) {
-                       RPEDEBUG("Failed to evaluate required module option %s", env->rule->name);
-                       return -1;
-               }
-               return 0;
-       }
-
-       /*
-        *      Concatenate multiple boxes if needed
-        */
-       if (env->rule->pair.concat &&
-           fr_value_box_list_concat_in_place(vb, vb, &state->tmpl_expanded, FR_BASE_TYPE(env->rule->type),
-                                             FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0 ) {
-               RPEDEBUG("Failed concatenating values for %s", env->rule->name);
-               return -1;
-       }
-
-       if (env->rule->pair.single && (fr_value_box_list_num_elements(&state->tmpl_expanded) > 1)) {
-               RPEDEBUG("%d values found for %s.  Only one is allowed",
-                        fr_value_box_list_num_elements(&state->tmpl_expanded), env->rule->name);
-               return -1;
-       }
-
-       while ((vb = fr_value_box_list_pop_head(&state->tmpl_expanded))) {
-               switch (env->rule->pair.type) {
-               case MOD_ENV_TYPE_VALUE_BOX:
-                       fr_value_box_copy_shallow(state->env_data, (fr_value_box_t *)(out), vb);
-                       break;
-
-               case MOD_ENV_TYPE_VALUE_BOX_LIST:
-                       if (!fr_value_box_list_initialised((fr_value_box_list_t *)out)) fr_value_box_list_init((fr_value_box_list_t *)out);
-                       fr_value_box_list_insert_tail((fr_value_box_list_t *)out, vb);
-                       break;
-               }
-       }
-
-       if (tmpl_out) *tmpl_out = env->tmpl;
-
-       return 0;
-}
-
 static unlang_action_t unlang_module(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
 {
        unlang_module_t                 *mc;
@@ -961,93 +910,21 @@ static unlang_action_t unlang_module(rlm_rcode_t *p_result, request_t *request,
                goto done;
        }
 
-       if (mc->method_env) {
-               void                            *out, **array, *tmpl_out = NULL;
-               module_env_parsed_t const       *env;
-               TALLOC_CTX                      *ctx;
-
-               switch (state->env_state) {
-               /*
-                *      We have a method env and this is the first call.
-                *      Allocate the data structure.
-                */
-               case MOD_ENV_EXP_INIT:
-                       MEM(state->env_data = talloc_zero_array(state, uint8_t, mc->method_env->inst_size));
-                       talloc_set_name_const(state->env_data, mc->method_env->inst_type);
-                       fr_value_box_list_init(&state->tmpl_expanded);
-                       state->env_state = MOD_ENV_EXP_PROC;
-                       break;
-
-               /*
-                *      Processing of module env is underway, parse the
-                *      value returned but the last expansion.
-                */
-               case MOD_ENV_EXP_PROC:
-                       env = state->last_expanded;
-
-                       /*
-                        *      Find the location of the output
-                        */
-                       out = ((uint8_t *)state->env_data) + env->rule->offset;
-
-                       /*
-                        *      If this is a multi pair option, the output is an array.
-                        *      Find the correct offset in the array.
-                        */
-                       if (env->rule->pair.multi) {
-                               array = *(void **)out;
-                               out = ((uint8_t *)array) + env->rule->pair.size * env->multi_index;
-                       }
+       if (mc->method_env && !state->env_data) {
+               ua = call_env_expand(state, request, &state->env_data, mc->method_env, &mc->call_env_parsed);
+               switch (ua) {
+               case UNLANG_ACTION_FAIL:
+                       goto fail;
 
-                       if (env->rule->pair.tmpl_offset) tmpl_out = ((uint8_t *)state->env_data) + env->rule->pair.tmpl_offset;
+               case UNLANG_ACTION_PUSHED_CHILD:
+                       frame_repeat(frame, unlang_module);
+                       return UNLANG_ACTION_PUSHED_CHILD;
 
-                       if (module_env_value_parse(request, out, tmpl_out, state) < 0) {
-                               ua = UNLANG_ACTION_FAIL;
-                               goto fail;
-                       }
+               default:
                        break;
-
-               case MOD_ENV_EXP_DONE:
-                       goto expansion_done;
                }
-
-               /*
-                *      Look for the next tmpl to expand
-                */
-               state->last_expanded = mod_env_parsed_next(&mc->mod_env_parsed, state->last_expanded);
-               if (!state->last_expanded) {
-                       state->env_state = MOD_ENV_EXP_DONE;
-                       goto expansion_done;
-               }
-               env = state->last_expanded;
-               ctx = state->env_data;
-
-               /*
-                *      Multi pair options should allocate boxes in the context of the array
-                */
-               if (env->rule->pair.multi) {
-                       out = ((uint8_t *)state->env_data) + env->rule->offset;
-
-                       /*
-                        *      For multi pair options, allocate the array before expanding the first entry.
-                        */
-                       if (env->multi_index == 0) {
-                               MEM(array = _talloc_zero_array(state->env_data, env->rule->pair.size,
-                                                              env->opt_count, env->rule->pair.type_name));
-                               *(void **)out = array;
-                       }
-                       ctx = *(void **)out;
-               }
-
-               frame_repeat(frame, unlang_module);
-               if (unlang_tmpl_push(ctx, &state->tmpl_expanded, request, state->last_expanded->tmpl, NULL) < 0) {
-                       ua = UNLANG_ACTION_FAIL;
-                       goto fail;
-               }
-               return UNLANG_ACTION_PUSHED_CHILD;
        }
 
-expansion_done:
        /*
         *      Grab the thread/module specific data if any exists.
         */
index 1faf1f294bf62147b26079874945aec2803cf02b..b1122159a50f4723a2134aa68927febb438860b0 100644 (file)
@@ -36,21 +36,12 @@ typedef struct {
        unlang_t                        self;                   //!< Common fields in all #unlang_t tree nodes.
        module_instance_t               *instance;              //!< Global instance of the module we're calling.
        module_method_t                 method;                 //!< The entry point into the module.
-       module_method_env_t const       *method_env;            //!< Module environment for this method.
-       mod_env_parsed_head_t           mod_env_parsed;         //!< The per call parsed module environment.
-       TALLOC_CTX                      *mod_env_ctx;           //!< A talloc pooled object for parsed module env
+       call_method_env_t const         *method_env;            //!< Call environment for this method.
+       call_env_parsed_head_t          call_env_parsed;        //!< The per call parsed call environment.
+       TALLOC_CTX                      *call_env_ctx;          //!< A talloc pooled object for parsed call env
                                                                ///< to be allocated from.
 } unlang_module_t;
 
-/** What state the module env for the current call is in.
- *
- */
-typedef enum {
-       MOD_ENV_EXP_INIT = 0,           //!< Expansion not yet started.
-       MOD_ENV_EXP_PROC,               //!< Expansion in progress.
-       MOD_ENV_EXP_DONE                //!< All expansions done.
-} module_env_state_t;
-
 /** A module stack entry
  *
  * Represents a single module call on the unlang stack.
@@ -63,9 +54,6 @@ typedef struct {
                                                                ///< shared between all threads, so we can't
                                                                ///< cache thread-specific data in the #unlang_t.
 
-       module_env_state_t              env_state;              //!< State of the current call module_env.
-       module_env_parsed_t const       *last_expanded;         //!< Last environment tmpl expanded.
-       fr_value_box_list_t             tmpl_expanded;          //!< Value boxes produced by last expanded tmpl.
        void                            *env_data;              //!< Expanded per call module environment tmpls.
 
 #ifndef NDEBUG
index 91720793a0787cf2d426028b77ec0c612c790693..ce663ca251fd147110e9d82c60d228a8279a9032 100644 (file)
@@ -45,6 +45,7 @@ typedef struct {
 
        rindent_t               indent;                         //!< indentation
 
+       void                    *env_data;                      //!< Expanded per call environment tmpls.
        /*
         *      For func and alternate
         */
@@ -118,7 +119,7 @@ static void unlang_xlat_event_timeout_handler(UNUSED fr_event_list_t *el, fr_tim
         */
        ev->timeout(XLAT_CTX(ev->inst->data,
                             ev->thread->data,
-                            ev->thread->mctx,
+                            ev->thread->mctx, NULL,
                             UNCONST(void *, ev->rctx)),
                             ev->request, now);
 
@@ -304,8 +305,28 @@ static unlang_action_t unlang_xlat_repeat(rlm_rcode_t *p_result, request_t *requ
        xlat_action_t                   xa;
        xlat_exp_head_t const           *child = NULL;
 
+       /*
+        *      If the xlat is a function with a method_env, expand it before calling the function.
+        */
+       if ((state->exp->type == XLAT_FUNC) && state->exp->call.func->call_env && !state->env_data) {
+               unlang_action_t ua = call_env_expand(state, request, &state->env_data,
+                                                    state->exp->call.func->call_env,
+                                                    &state->exp->call.inst->call_env_parsed);
+               switch (ua) {
+               case UNLANG_ACTION_FAIL:
+                       goto fail;
+
+               case UNLANG_ACTION_PUSHED_CHILD:
+                       frame_repeat(frame, unlang_xlat_repeat);
+                       return UNLANG_ACTION_PUSHED_CHILD;
+
+               default:
+                       break;
+               }
+       }
+
        xa = xlat_frame_eval_repeat(state->ctx, &state->values, &child,
-                                   &state->alternate, request, state->head, &state->exp, &state->out);
+                                   &state->alternate, request, state->head, &state->exp, state->env_data, &state->out);
        switch (xa) {
        case XLAT_ACTION_PUSH_CHILD:
                fr_assert(child);
index 0077ae5b39b4b923c9de607bc432b89aaa7d529e..f9aba933c28c57d6df950971f4a622ff2d4f5585 100644 (file)
@@ -65,6 +65,7 @@ typedef size_t (*xlat_escape_legacy_t)(request_t *request, char *out, size_t out
 #include <freeradius-devel/util/time.h>
 #include <freeradius-devel/util/value.h>
 
+#include <freeradius-devel/unlang/call_env.h>
 #include <freeradius-devel/unlang/xlat_ctx.h>
 
 /** Instance data for an xlat expansion node
@@ -78,6 +79,9 @@ struct xlat_inst {
 
        xlat_exp_t              *node;          //!< Node this data relates to.
        void                    *data;          //!< xlat node specific instance data.
+       call_env_parsed_head_t  call_env_parsed;        //!< The per call parsed environment.
+       TALLOC_CTX              *call_env_ctx;  //!< A talloc pooled object for parsed call env
+                                               ///< to be allocated from.
 };
 
 /** Thread specific instance data for xlat expansion node
index cd88fa6b4d41e4adc4c7aa9a079355518c70d2c6..19ca0961a7f755875f1b144bf238667eb012a413 100644 (file)
@@ -43,6 +43,7 @@ typedef struct {
        void const                      *inst;                  //!< xlat instance data.
        void                            *thread;                //!< xlat threadinstance data.
        module_ctx_t const              *mctx;                  //!< Synthesised module calling ctx.
+       void                            *env_data;              //!< Expanded module env data.
        void                            *rctx;                  //!< Resume context.
 } xlat_ctx_t;
 
@@ -79,9 +80,11 @@ typedef struct {
  * @param[in] _inst    Instance data of the module being called.
  * @param[in] _thread  Instance data of the thread being called.
  * @param[in] _mctx    Module ctx.
+ * @param[in] _env_data        Expanded module env.
  * @param[in] _rctx    resume ctx data.
  */
-#define XLAT_CTX(_inst, _thread, _mctx, _rctx) &(xlat_ctx_t){ .inst = _inst, .thread = _thread, .mctx = _mctx, .rctx = _rctx }
+#define XLAT_CTX(_inst, _thread, _mctx, _env_data, _rctx) &(xlat_ctx_t){ .inst = _inst, .thread = _thread, \
+                                                           .mctx = _mctx, .env_data = _env_data, .rctx = _rctx }
 
 /** Wrapper to create a xlat_inst_ctx_t as a compound literal
  *
index 77d3b211c0b7254ec183606baccf3a60835f44b5..ea81109d47e34c462de44fbf3dae91d24889441c 100644 (file)
@@ -796,7 +796,7 @@ void xlat_signal(xlat_func_signal_t signal, xlat_exp_t const *exp,
 {
        xlat_thread_inst_t *t = xlat_thread_instance_find(exp);
 
-       signal(XLAT_CTX(exp->call.inst, t->data, t->mctx, rctx), request, action);
+       signal(XLAT_CTX(exp->call.inst, t->data, t->mctx, NULL, rctx), request, action);
 }
 
 /** Call an xlat's resumption method
@@ -835,11 +835,11 @@ xlat_action_t xlat_frame_eval_resume(TALLOC_CTX *ctx, fr_dcursor_t *out,
        VALUE_BOX_TALLOC_LIST_VERIFY(result);
 
        if (node->type != XLAT_FUNC) {
-               xa = resume(ctx, out, XLAT_CTX(NULL, NULL, NULL, rctx), request, result);
+               xa = resume(ctx, out, XLAT_CTX(NULL, NULL, NULL, NULL, rctx), request, result);
        } else {
                xlat_thread_inst_t *t;
                t = xlat_thread_instance_find(node);
-               xa = resume(ctx, out, XLAT_CTX(node->call.inst->data, t->data, t->mctx, rctx), request, result);
+               xa = resume(ctx, out, XLAT_CTX(node->call.inst->data, t->data, t->mctx, NULL, rctx), request, result);
                VALUE_BOX_TALLOC_LIST_VERIFY(result);
 
                RDEBUG2("| %%%c%s:...%c",
@@ -892,12 +892,13 @@ xlat_action_t xlat_frame_eval_resume(TALLOC_CTX *ctx, fr_dcursor_t *out,
  * @param[in] head             of the list to evaluate
  * @param[in,out] in           xlat node to evaluate.  Advanced as we process
  *                             additional #xlat_exp_t.
+ * @param[in] env_data         Expanded module env.
  * @param[in] result           of a previous nested evaluation.
  */
 xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
                                     xlat_exp_head_t const **child, bool *alternate,
                                     request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in,
-                                    fr_value_box_list_t *result)
+                                    void *env_data, fr_value_box_list_t *result)
 {
        xlat_exp_t const        *node = *in;
 
@@ -941,7 +942,7 @@ xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
 
                VALUE_BOX_TALLOC_LIST_VERIFY(result);
                xa = node->call.func->func(ctx, out,
-                                          XLAT_CTX(node->call.inst->data, t->data, t->mctx, NULL),
+                                          XLAT_CTX(node->call.inst->data, t->data, t->mctx, env_data, NULL),
                                           request, result);
                VALUE_BOX_TALLOC_LIST_VERIFY(result);
 
@@ -1236,7 +1237,7 @@ xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_
 
                        xlat_debug_log_expansion(request, node, NULL, __LINE__);
                        xa = node->call.func->func(ctx, out,
-                                                  XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL),
+                                                  XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL, NULL),
                                                   request, NULL);
                        fr_dcursor_next(out);
 
@@ -1262,7 +1263,7 @@ xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_
                         *      If there's no children we can just
                         *      call the function directly.
                         */
-                       xa = xlat_frame_eval_repeat(ctx, out, child, NULL, request, head, in, &result);
+                       xa = xlat_frame_eval_repeat(ctx, out, child, NULL, request, head, in, NULL, &result);
                        if (xa != XLAT_ACTION_DONE || (!*in)) goto finish;
                        continue;
 
index 728e9139aaa4b90696096bb0d1af98c09f1c3d34..5de229bab30c4a6d356c72e20046a1515e0ea7b7 100644 (file)
@@ -337,6 +337,16 @@ int xlat_func_mono_set(xlat_t *x, xlat_arg_parser_t const args[])
        return 0;
 }
 
+/** Register call environment of an xlat
+ *
+ * @param[in,out] x            to have it's module method env registered.
+ * @param[in] env              to be registered.
+ */
+void xlat_func_call_env_set(xlat_t *x, call_method_env_t const *env)
+{
+       x->call_env = env;
+}
+
 /** Specify flags that alter the xlat's behaviour
  *
  * @param[in] x                        xlat to set flags for.
index e4146ec3fdf82e9f3089b8dc8eb14d7eb6a28939..7d23b1f20b0058ebf3acf2325c7bdb6d647c8c40 100644 (file)
@@ -60,6 +60,8 @@ int           xlat_func_args_set(xlat_t *xlat, xlat_arg_parser_t const args[]) CC_HINT(no
 
 int            xlat_func_mono_set(xlat_t *xlat, xlat_arg_parser_t const *arg) CC_HINT(nonnull);
 
+void           xlat_func_call_env_set(xlat_t *x, call_method_env_t const *env) CC_HINT(nonnull);
+
 void           xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags) CC_HINT(nonnull);
 
 void           xlat_func_print_set(xlat_t *xlat, xlat_print_t func);
index 580424a295202c7b1b841da96c2ded427bd9477e..9713b0a7a1a9b0111f4ade4f960976d99271dd9d 100644 (file)
@@ -245,6 +245,27 @@ static xlat_inst_t *xlat_inst_alloc(xlat_exp_t *node)
                }
        }
 
+       /*
+        *      If the xlat has a call env defined, parse it.
+        */
+       if (call->func->call_env) {
+               size_t                  count, vallen = 0;
+               CONF_SECTION            *cs = call->func->mctx->inst->conf;
+               call_method_env_t const *call_env = call->func->call_env;
+
+               count = call_env_count(&vallen, cs, call_env->env);
+               MEM(xi->call_env_ctx = _talloc_pooled_object(xi, 0, "call_env_ctx", count * 4,
+                                       (sizeof(call_env_parsed_t) + sizeof(tmpl_t)) * count + vallen * 2));
+               call_env_parsed_init(&xi->call_env_parsed);
+               if (call_env_parse(xi->call_env_ctx, &xi->call_env_parsed, call->func->mctx->inst->name,
+                                  call->dict, call->func->mctx->inst->conf, call_env->env) < 0) {
+                       talloc_free(xi);
+                       return NULL;
+               }
+               fr_assert_msg(call_env->inst_size, "Method environment for module %s, xlat %s declared, "
+                             "but no inst_size set", call->func->mctx->inst->name, call->func->name);
+       }
+
        return xi;
 }
 
index 01118271a7bc39dee036cfa1e38d145719648984..f49aa329327bc487a282928ee7c1084c89af2b8c 100644 (file)
@@ -88,6 +88,10 @@ typedef struct xlat_s {
        xlat_input_type_t       input_type;             //!< Type of input used.
        xlat_arg_parser_t const *args;                  //!< Definition of args consumed.
 
+       call_method_env_t const *call_env;              //!< Optional tmpl expansions performed before calling the
+                                                       ///< xlat.  Typically used for xlats which refer to tmpls
+                                                       ///< in their module config.
+
        fr_type_t               return_type;            //!< Function is guaranteed to return one or more boxes
                                                        ///< of this type.  If the return type is FR_TYPE_VOID
                                                        ///< then the xlat function can return any type of output.
@@ -128,6 +132,8 @@ typedef struct {
                                                        ///< into the instance tree.
        xlat_input_type_t       input_type;             //!< The input type used inferred from the
                                                        ///< bracketing style.
+
+       fr_dict_t const         *dict;                  //!< Dictionary to use when resolving module env tmpls
 } xlat_call_t;
 
 /** An xlat expansion node
@@ -295,7 +301,7 @@ xlat_action_t       xlat_frame_eval_resume(TALLOC_CTX *ctx, fr_dcursor_t *out,
 xlat_action_t  xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
                                       xlat_exp_head_t const **child, bool *alternate,
                                       request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in,
-                                      fr_value_box_list_t *result) CC_HINT(nonnull(1,2,3,5));
+                                      void *env_data, fr_value_box_list_t *result) CC_HINT(nonnull(1,2,3,5));
 
 xlat_action_t  xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_t const **child,
                                request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in);
index 146d9b0eeaff8b58b667daa05d51048e6c7acd1e..6934d7da5e2a1d80650b54f248df1a6b033dcbcf 100644 (file)
@@ -322,6 +322,7 @@ static inline int xlat_tokenize_function_mono(xlat_exp_head_t *head,
                        return -1;
                }
                node->call.func = func;
+               if (t_rules) node->call.dict = t_rules->attr.dict_def;
                node->flags = func->flags;
        }
 
@@ -582,6 +583,7 @@ int xlat_tokenize_function_args(xlat_exp_head_t *head, fr_sbuff_t *in,
                        return -1;
                }
                node->call.func = func;
+               if (t_rules) node->call.dict = t_rules->attr.dict_def;
                node->flags = func->flags;
        }
 
@@ -1865,6 +1867,7 @@ int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
                        }
 
                        xlat_exp_set_type(node, XLAT_FUNC);
+                       node->call.dict = xr_rules->tr_rules->dict_def;
 
                        /*
                         *      Check input arguments of our freshly
index c4d5dbe9c558b45d5f00140e715c56599b69fed8..21898f0eef62d624a0d979938952136cdb8d84db 100644 (file)
@@ -674,16 +674,16 @@ static unlang_action_t CC_HINT(nonnull) mod_post_auth(rlm_rcode_t *p_result, mod
  *     it is still evaluated during module instantiation to determine the tree type in use
  *     so more restructuring is needed to make the module protocol agnostic.
  */
-static const module_env_t module_env[] = {
-       { FR_MODULE_ENV_OFFSET("key", FR_TYPE_VOID, rlm_files_env_t, key, "%{%{Stripped-User-Name}:-%{User-Name}}",
-                              T_DOUBLE_QUOTED_STRING, true, false, false) },
-       MODULE_ENV_TERMINATOR
+static const call_env_t call_env[] = {
+       { FR_CALL_ENV_OFFSET("key", FR_TYPE_VOID, rlm_files_env_t, key, "%{%{Stripped-User-Name}:-%{User-Name}}",
+                            T_DOUBLE_QUOTED_STRING, true, false, false) },
+       CALL_ENV_TERMINATOR
 };
 
-static const module_method_env_t method_env = {
+static const call_method_env_t method_env = {
        .inst_size = sizeof(rlm_files_env_t),
        .inst_type = "rlm_files_env_t",
-       .env = module_env
+       .env = call_env
 };
 
 /* globally exported name */
index cba18c7557d47f0f2e6df1cd0e482662a75b20cf..6e52b18276f56592e6bef79ad2efb71319b10585 100644 (file)
@@ -535,7 +535,7 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, request_t *req
        MEM(group_ctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), ldap_group_userobj_ctx_t));
        group_ctx->inst = inst;
        group_ctx->ttrunk = ttrunk;
-       group_ctx->base_dn = &autz_ctx->mod_env->group_base;
+       group_ctx->base_dn = &autz_ctx->call_env->group_base;
        group_ctx->list_ctx = tmpl_list_ctx(request, request_attr_control);
        fr_assert(group_ctx->list_ctx != NULL);
 
@@ -755,7 +755,7 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, request_t *re
                RETURN_MODULE_OK;
        }
 
-       if (autz_ctx->mod_env->group_base.type != FR_TYPE_STRING) {
+       if (autz_ctx->call_env->group_base.type != FR_TYPE_STRING) {
                REDEBUG("Missing group base_dn");
                RETURN_MODULE_INVALID;
        }
@@ -763,7 +763,7 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, request_t *re
        MEM(group_ctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), ldap_group_groupobj_ctx_t));
        group_ctx->inst = inst;
        group_ctx->ttrunk = autz_ctx->ttrunk;
-       group_ctx->base_dn = &autz_ctx->mod_env->group_base;
+       group_ctx->base_dn = &autz_ctx->call_env->group_base;
 
        if (fr_ldap_xlat_filter(request, filters, NUM_ELEMENTS(filters),
                                group_ctx->filter, sizeof(group_ctx->filter)) < 0) {
index 2bcd428c7371928d415411f6b1fb835ec0b51831..ef3696005c65831d24379b3d3f9c6a31bf0bbd76 100644 (file)
@@ -49,23 +49,23 @@ typedef struct {
        fr_value_box_t  user_sasl_authname;
        fr_value_box_t  user_sasl_proxy;
        fr_value_box_t  user_sasl_realm;
-} ldap_auth_mod_env_t;
+} ldap_auth_call_env_t;
 
 typedef struct {
        fr_value_box_t  user_base;
        fr_value_box_t  user_filter;
-} ldap_usermod_mod_env_t;
-
-static const module_env_t sasl_module_env[] = {
-       { FR_MODULE_ENV_OFFSET("mech", FR_TYPE_STRING, ldap_auth_mod_env_t, user_sasl_mech,
-                              NULL, T_INVALID, false, false, false) },
-       { FR_MODULE_ENV_OFFSET("authname", FR_TYPE_STRING, ldap_auth_mod_env_t, user_sasl_authname,
-                              NULL, T_INVALID, false, false, false) },
-       { FR_MODULE_ENV_OFFSET("proxy", FR_TYPE_STRING, ldap_auth_mod_env_t, user_sasl_proxy,
-                              NULL, T_INVALID, false, true, false) },
-       { FR_MODULE_ENV_OFFSET("realm", FR_TYPE_STRING, ldap_auth_mod_env_t, user_sasl_realm,
-                              NULL, T_INVALID, false, true, false) },
-       MODULE_ENV_TERMINATOR
+} ldap_usermod_call_env_t;
+
+static const call_env_t sasl_call_env[] = {
+       { FR_CALL_ENV_OFFSET("mech", FR_TYPE_STRING, ldap_auth_call_env_t, user_sasl_mech,
+                            NULL, T_INVALID, false, false, false) },
+       { FR_CALL_ENV_OFFSET("authname", FR_TYPE_STRING, ldap_auth_call_env_t, user_sasl_authname,
+                            NULL, T_INVALID, false, false, false) },
+       { FR_CALL_ENV_OFFSET("proxy", FR_TYPE_STRING, ldap_auth_call_env_t, user_sasl_proxy,
+                            NULL, T_INVALID, false, true, false) },
+       { FR_CALL_ENV_OFFSET("realm", FR_TYPE_STRING, ldap_auth_call_env_t, user_sasl_realm,
+                            NULL, T_INVALID, false, true, false) },
+       CALL_ENV_TERMINATOR
 };
 
 static CONF_PARSER profile_config[] = {
@@ -73,12 +73,12 @@ static CONF_PARSER profile_config[] = {
        CONF_PARSER_TERMINATOR
 };
 
-static const module_env_t autz_profile_module_env[] = {
-       { FR_MODULE_ENV_OFFSET("default", FR_TYPE_STRING, ldap_autz_mod_env_t, default_profile,
-                              NULL, T_INVALID, false, false, true) },
-       { FR_MODULE_ENV_OFFSET("filter", FR_TYPE_STRING, ldap_autz_mod_env_t, profile_filter,
-                              "(&)", T_SINGLE_QUOTED_STRING, false, false, true ) },   //!< Correct filter for when the DN is known.
-       MODULE_ENV_TERMINATOR
+static const call_env_t autz_profile_call_env[] = {
+       { FR_CALL_ENV_OFFSET("default", FR_TYPE_STRING, ldap_autz_call_env_t, default_profile,
+                            NULL, T_INVALID, false, false, true) },
+       { FR_CALL_ENV_OFFSET("filter", FR_TYPE_STRING, ldap_autz_call_env_t, profile_filter,
+                            "(&)", T_SINGLE_QUOTED_STRING, false, false, true ) },     //!< Correct filter for when the DN is known.
+       CALL_ENV_TERMINATOR
 };
 
 /*
@@ -95,29 +95,29 @@ static CONF_PARSER user_config[] = {
        CONF_PARSER_TERMINATOR
 };
 
-static const module_env_t auth_user_module_env[] = {
-       { FR_MODULE_ENV_OFFSET("base_dn", FR_TYPE_STRING, ldap_auth_mod_env_t, user_base,
-                              "", T_SINGLE_QUOTED_STRING, true, false, true) },
-       { FR_MODULE_ENV_OFFSET("filter", FR_TYPE_STRING, ldap_auth_mod_env_t, user_filter,
-                              NULL, T_INVALID, false, true, true) },
-       { FR_MODULE_ENV_SUBSECTION("sasl", NULL, sasl_module_env) },
-       MODULE_ENV_TERMINATOR
+static const call_env_t auth_user_call_env[] = {
+       { FR_CALL_ENV_OFFSET("base_dn", FR_TYPE_STRING, ldap_auth_call_env_t, user_base,
+                            "", T_SINGLE_QUOTED_STRING, true, false, true) },
+       { FR_CALL_ENV_OFFSET("filter", FR_TYPE_STRING, ldap_auth_call_env_t, user_filter,
+                            NULL, T_INVALID, false, true, true) },
+       { FR_CALL_ENV_SUBSECTION("sasl", NULL, sasl_call_env) },
+       CALL_ENV_TERMINATOR
 };
 
-static const module_env_t autz_user_module_env[] = {
-       { FR_MODULE_ENV_OFFSET("base_dn", FR_TYPE_STRING, ldap_autz_mod_env_t, user_base,
-                              "", T_SINGLE_QUOTED_STRING, true, false, true) },
-       { FR_MODULE_ENV_OFFSET("filter", FR_TYPE_STRING, ldap_autz_mod_env_t, user_filter,
-                              NULL, T_INVALID, false, true, true) },
-       MODULE_ENV_TERMINATOR
+static const call_env_t autz_user_call_env[] = {
+       { FR_CALL_ENV_OFFSET("base_dn", FR_TYPE_STRING, ldap_autz_call_env_t, user_base,
+                            "", T_SINGLE_QUOTED_STRING, true, false, true) },
+       { FR_CALL_ENV_OFFSET("filter", FR_TYPE_STRING, ldap_autz_call_env_t, user_filter,
+                            NULL, T_INVALID, false, true, true) },
+       CALL_ENV_TERMINATOR
 };
 
-static const module_env_t usermod_user_module_env[] = {
-       { FR_MODULE_ENV_OFFSET("base_dn", FR_TYPE_STRING, ldap_usermod_mod_env_t, user_base,
-                              "", T_SINGLE_QUOTED_STRING, true, false, true) },
-       { FR_MODULE_ENV_OFFSET("filter", FR_TYPE_STRING, ldap_usermod_mod_env_t, user_filter,
-                              NULL, T_INVALID, false, true, true) },
-       MODULE_ENV_TERMINATOR
+static const call_env_t usermod_user_call_env[] = {
+       { FR_CALL_ENV_OFFSET("base_dn", FR_TYPE_STRING, ldap_usermod_call_env_t, user_base,
+                            "", T_SINGLE_QUOTED_STRING, true, false, true) },
+       { FR_CALL_ENV_OFFSET("filter", FR_TYPE_STRING, ldap_usermod_call_env_t, user_filter,
+                            NULL, T_INVALID, false, true, true) },
+       CALL_ENV_TERMINATOR
 };
 
 /*
@@ -139,10 +139,10 @@ static CONF_PARSER group_config[] = {
        CONF_PARSER_TERMINATOR
 };
 
-static const module_env_t autz_group_module_env[] = {
-       { FR_MODULE_ENV_OFFSET("base_dn", FR_TYPE_STRING, ldap_autz_mod_env_t, group_base,
-                              NULL, T_INVALID, false, false, true) },
-       MODULE_ENV_TERMINATOR
+static const call_env_t autz_group_call_env[] = {
+       { FR_CALL_ENV_OFFSET("base_dn", FR_TYPE_STRING, ldap_autz_call_env_t, group_base,
+                            NULL, T_INVALID, false, false, true) },
+       CALL_ENV_TERMINATOR
 };
 
 /*
@@ -196,41 +196,41 @@ static const CONF_PARSER module_config[] = {
 };
 
 /*
- *     Method specific module environments
+ *     Method specific call environments
  */
-static const module_env_t authenticate_module_env[] = {
-       { FR_MODULE_ENV_SUBSECTION("user", NULL, auth_user_module_env) },
-       MODULE_ENV_TERMINATOR
+static const call_env_t authenticate_call_env[] = {
+       { FR_CALL_ENV_SUBSECTION("user", NULL, auth_user_call_env) },
+       CALL_ENV_TERMINATOR
 };
 
-static const module_env_t authorize_module_env[] = {
-       { FR_MODULE_ENV_SUBSECTION("user", NULL, autz_user_module_env) },
-       { FR_MODULE_ENV_SUBSECTION("group", NULL, autz_group_module_env) },
-       { FR_MODULE_ENV_SUBSECTION("profile", NULL, autz_profile_module_env) },
-       MODULE_ENV_TERMINATOR
+static const call_env_t authorize_call_env[] = {
+       { FR_CALL_ENV_SUBSECTION("user", NULL, autz_user_call_env) },
+       { FR_CALL_ENV_SUBSECTION("group", NULL, autz_group_call_env) },
+       { FR_CALL_ENV_SUBSECTION("profile", NULL, autz_profile_call_env) },
+       CALL_ENV_TERMINATOR
 };
 
-static const module_env_t usermod_module_env[] = {
-       { FR_MODULE_ENV_SUBSECTION("user", NULL, usermod_user_module_env) },
-       MODULE_ENV_TERMINATOR
+static const call_env_t usermod_call_env[] = {
+       { FR_CALL_ENV_SUBSECTION("user", NULL, usermod_user_call_env) },
+       CALL_ENV_TERMINATOR
 };
 
-static const module_method_env_t authenticate_method_env = {
-       .inst_size = sizeof(ldap_auth_mod_env_t),
-       .inst_type = "ldap_auth_mod_env_t",
-       .env = authenticate_module_env
+static const call_method_env_t authenticate_method_env = {
+       .inst_size = sizeof(ldap_auth_call_env_t),
+       .inst_type = "ldap_auth_call_env_t",
+       .env = authenticate_call_env
 };
 
-static const module_method_env_t authorize_method_env = {
-       .inst_size = sizeof(ldap_autz_mod_env_t),
-       .inst_type = "ldap_autz_mod_env_t",
-       .env = authorize_module_env
+static const call_method_env_t authorize_method_env = {
+       .inst_size = sizeof(ldap_autz_call_env_t),
+       .inst_type = "ldap_autz_call_env_t",
+       .env = authorize_call_env
 };
 
-static const module_method_env_t usermod_method_env = {
-       .inst_size = sizeof(ldap_usermod_mod_env_t),
-       .inst_type = "ldap_usermod_mod_env_t",
-       .env = usermod_module_env
+static const call_method_env_t usermod_method_env = {
+       .inst_size = sizeof(ldap_usermod_call_env_t),
+       .inst_type = "ldap_usermod_call_env_t",
+       .env = usermod_call_env
 };
 
 static fr_dict_t const *dict_freeradius;
@@ -280,7 +280,7 @@ typedef struct {
        char const              *password;
        rlm_ldap_t const        *inst;
        fr_ldap_thread_t        *thread;
-       ldap_auth_mod_env_t     *mod_env;
+       ldap_auth_call_env_t    *call_env;
 } ldap_auth_ctx_t;
 
 /** Holds state of in progress async profile lookups
@@ -298,7 +298,7 @@ typedef struct {
  */
 typedef struct {
        rlm_ldap_t const        *inst;
-       ldap_usermod_mod_env_t  *mod_env;
+       ldap_usermod_call_env_t *call_env;
        char const              *dn;
        char                    *passed[LDAP_MAX_ATTRMAP * 2];
        LDAPMod                 *mod_p[LDAP_MAX_ATTRMAP + 1];
@@ -1008,8 +1008,8 @@ static unlang_action_t mod_authenticate_start(rlm_rcode_t *p_result, UNUSED int
                                          inst->handle_config.admin_password, request, &inst->handle_config);
        if (!ttrunk) RETURN_MODULE_FAIL;
 
-       return rlm_ldap_find_user_async(auth_ctx, auth_ctx->inst, request, &auth_ctx->mod_env->user_base,
-                                       &auth_ctx->mod_env->user_filter, ttrunk, NULL, NULL);
+       return rlm_ldap_find_user_async(auth_ctx, auth_ctx->inst, request, &auth_ctx->call_env->user_base,
+                                       &auth_ctx->call_env->user_filter, ttrunk, NULL, NULL);
 }
 
 /** Initiate async LDAP bind to authenticate user
@@ -1037,13 +1037,13 @@ static unlang_action_t mod_authenticate_resume(rlm_rcode_t *p_result, UNUSED int
        /*
         *      Attempt a bind using the thread specific trunk for bind auths
         */
-       if (auth_ctx->mod_env->user_sasl_mech.type == FR_TYPE_STRING) {
+       if (auth_ctx->call_env->user_sasl_mech.type == FR_TYPE_STRING) {
 #ifdef WITH_SASL
-               ldap_auth_mod_env_t *mod_env = auth_ctx->mod_env;
-               if (fr_ldap_sasl_bind_auth_async(request, auth_ctx->thread, mod_env->user_sasl_mech.vb_strvalue,
-                                                auth_ctx->dn, mod_env->user_sasl_authname.vb_strvalue,
-                                                auth_ctx->password, mod_env->user_sasl_proxy.vb_strvalue,
-                                                mod_env->user_sasl_realm.vb_strvalue) < 0) goto fail;
+               ldap_auth_call_env_t *call_env = auth_ctx->call_env;
+               if (fr_ldap_sasl_bind_auth_async(request, auth_ctx->thread, call_env->user_sasl_mech.vb_strvalue,
+                                                auth_ctx->dn, call_env->user_sasl_authname.vb_strvalue,
+                                                auth_ctx->password, call_env->user_sasl_proxy.vb_strvalue,
+                                                call_env->user_sasl_realm.vb_strvalue) < 0) goto fail;
 #else
                RDEBUG("Configuration item 'sasl.mech' is not supported.  "
                       "The linked version of libldap does not provide ldap_sasl_bind( function");
@@ -1060,7 +1060,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
        rlm_ldap_t const        *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_ldap_t);
        fr_ldap_thread_t        *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t);
        ldap_auth_ctx_t         *auth_ctx;
-       ldap_auth_mod_env_t     *mod_env = talloc_get_type_abort(mctx->env_data, ldap_auth_mod_env_t);
+       ldap_auth_call_env_t    *call_env = talloc_get_type_abort(mctx->env_data, ldap_auth_call_env_t);
 
        fr_pair_t *username, *password;
 
@@ -1112,7 +1112,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
                .password = password->vp_strvalue,
                .thread = thread,
                .inst = inst,
-               .mod_env = mod_env
+               .call_env = call_env
        };
 
        /*
@@ -1224,7 +1224,7 @@ static unlang_action_t rlm_ldap_map_profile(request_t *request, ldap_autz_ctx_t
        }
 
        return fr_ldap_trunk_search(&ret, profile_ctx, &profile_ctx->query, request, ttrunk, dn,
-                                   LDAP_SCOPE_BASE, autz_ctx->mod_env->profile_filter.vb_strvalue,
+                                   LDAP_SCOPE_BASE, autz_ctx->call_env->profile_filter.vb_strvalue,
                                    expanded->attrs, NULL, NULL, true);
 }
 
@@ -1235,8 +1235,8 @@ static unlang_action_t mod_authorize_start(UNUSED rlm_rcode_t *p_result, UNUSED
                                           request_t *request, void *uctx)
 {
        ldap_autz_ctx_t *autz_ctx = talloc_get_type_abort(uctx, ldap_autz_ctx_t);
-       return rlm_ldap_find_user_async(autz_ctx, autz_ctx->inst, request, &autz_ctx->mod_env->user_base,
-                                       &autz_ctx->mod_env->user_filter, autz_ctx->ttrunk, autz_ctx->expanded.attrs,
+       return rlm_ldap_find_user_async(autz_ctx, autz_ctx->inst, request, &autz_ctx->call_env->user_base,
+                                       &autz_ctx->call_env->user_filter, autz_ctx->ttrunk, autz_ctx->expanded.attrs,
                                        &autz_ctx->query);
 }
 
@@ -1263,7 +1263,7 @@ static unlang_action_t mod_authorize_resume(rlm_rcode_t *p_result, UNUSED int *p
 {
        ldap_autz_ctx_t         *autz_ctx = talloc_get_type_abort(uctx, ldap_autz_ctx_t);
        rlm_ldap_t const        *inst = talloc_get_type_abort_const(autz_ctx->inst, rlm_ldap_t);
-       ldap_autz_mod_env_t     *mod_env = talloc_get_type_abort(autz_ctx->mod_env, ldap_autz_mod_env_t);
+       ldap_autz_call_env_t    *call_env = talloc_get_type_abort(autz_ctx->call_env, ldap_autz_call_env_t);
        int                     ldap_errno;
        rlm_rcode_t             rcode = RLM_MODULE_OK;
        LDAP                    *handle = fr_ldap_handle_thread_local();
@@ -1393,11 +1393,11 @@ static unlang_action_t mod_authorize_resume(rlm_rcode_t *p_result, UNUSED int *p
                /*
                 *      Apply ONE user profile, or a default user profile.
                 */
-               if (mod_env->default_profile.type == FR_TYPE_STRING) {
+               if (call_env->default_profile.type == FR_TYPE_STRING) {
                        unlang_action_t ret;
 
                        REPEAT_MOD_AUTHORIZE_RESUME;
-                       ret = rlm_ldap_map_profile(request, autz_ctx, mod_env->default_profile.vb_strvalue,
+                       ret = rlm_ldap_map_profile(request, autz_ctx, call_env->default_profile.vb_strvalue,
                                                   &autz_ctx->expanded);
                        switch (ret) {
                        case UNLANG_ACTION_FAIL:
@@ -1494,7 +1494,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
        fr_ldap_thread_t        *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t);
        ldap_autz_ctx_t         *autz_ctx;
        fr_ldap_map_exp_t       *expanded;
-       ldap_autz_mod_env_t     *mod_env = talloc_get_type_abort(mctx->env_data, ldap_autz_mod_env_t);
+       ldap_autz_call_env_t    *call_env = talloc_get_type_abort(mctx->env_data, ldap_autz_call_env_t);
 
        MEM(autz_ctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), ldap_autz_ctx_t));
        talloc_set_destructor(autz_ctx, autz_ctx_free);
@@ -1533,7 +1533,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
 
        autz_ctx->dlinst = mctx->inst;
        autz_ctx->inst = inst;
-       autz_ctx->mod_env = mod_env;
+       autz_ctx->call_env = call_env;
        autz_ctx->status = LDAP_AUTZ_FIND;
 
        if (unlang_function_push(request, mod_authorize_start, mod_authorize_resume, mod_authorize_cancel,
@@ -1550,8 +1550,8 @@ static unlang_action_t user_modify_start(UNUSED rlm_rcode_t *p_result, UNUSED in
 {
        ldap_user_modify_ctx_t  *usermod_ctx = talloc_get_type_abort(uctx, ldap_user_modify_ctx_t);
 
-       return rlm_ldap_find_user_async(usermod_ctx, usermod_ctx->inst, request, &usermod_ctx->mod_env->user_base,
-               &usermod_ctx->mod_env->user_filter, usermod_ctx->ttrunk, NULL, NULL);
+       return rlm_ldap_find_user_async(usermod_ctx, usermod_ctx->inst, request, &usermod_ctx->call_env->user_base,
+               &usermod_ctx->call_env->user_filter, usermod_ctx->ttrunk, NULL, NULL);
 }
 
 /** Cancel an in progress user modification.
@@ -1631,11 +1631,11 @@ static unlang_action_t user_modify_resume(rlm_rcode_t *p_result, UNUSED int *pri
  * @param[in] inst             rlm_ldap instance.
  * @param[in] request          Current request.
  * @param[in] section          that holds the map to process.
- * @param[in] mod_env          Module environment.  Contains expanded base and filter to find user.
+ * @param[in] call_env         Call environment.  Contains expanded base and filter to find user.
  * @return one of the RLM_MODULE_* values.
  */
 static unlang_action_t user_modify(rlm_rcode_t *p_result, rlm_ldap_t const *inst, request_t *request,
-                                  ldap_acct_section_t *section, ldap_usermod_mod_env_t *mod_env)
+                                  ldap_acct_section_t *section, ldap_usermod_call_env_t *call_env)
 {
        rlm_rcode_t             rcode = RLM_MODULE_FAIL;
        fr_ldap_thread_t        *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t);
@@ -1686,7 +1686,7 @@ static unlang_action_t user_modify(rlm_rcode_t *p_result, rlm_ldap_t const *inst
        MEM(usermod_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), ldap_user_modify_ctx_t));
        *usermod_ctx = (ldap_user_modify_ctx_t) {
                .inst = inst,
-               .mod_env = mod_env
+               .call_env = call_env
        };
 
        /*
@@ -1832,9 +1832,9 @@ error:
 static unlang_action_t CC_HINT(nonnull) mod_accounting(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
 {
        rlm_ldap_t const *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_ldap_t);
-       ldap_usermod_mod_env_t  *mod_env = talloc_get_type_abort(mctx->env_data, ldap_usermod_mod_env_t);
+       ldap_usermod_call_env_t *call_env = talloc_get_type_abort(mctx->env_data, ldap_usermod_call_env_t);
 
-       if (inst->accounting) return user_modify(p_result, inst, request, inst->accounting, mod_env);
+       if (inst->accounting) return user_modify(p_result, inst, request, inst->accounting, call_env);
 
        RETURN_MODULE_NOOP;
 }
@@ -1842,9 +1842,9 @@ static unlang_action_t CC_HINT(nonnull) mod_accounting(rlm_rcode_t *p_result, mo
 static unlang_action_t CC_HINT(nonnull) mod_post_auth(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
 {
        rlm_ldap_t const *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_ldap_t);
-       ldap_usermod_mod_env_t  *mod_env = talloc_get_type_abort(mctx->env_data, ldap_usermod_mod_env_t);
+       ldap_usermod_call_env_t *call_env = talloc_get_type_abort(mctx->env_data, ldap_usermod_call_env_t);
 
-       if (inst->postauth) return user_modify(p_result, inst, request, inst->postauth, mod_env);
+       if (inst->postauth) return user_modify(p_result, inst, request, inst->postauth, call_env);
 
        RETURN_MODULE_NOOP;
 }
index d8d8311a2e024f9ba42778a90bd5c22df7031928..4f44c46f412f4ede7833f4a29888248b7ff5afa1 100644 (file)
@@ -137,7 +137,7 @@ typedef struct {
                                                        //!< No value should be set if profiles are not being used
                                                        //!< as there is an associated performance penalty.
        fr_value_box_t  profile_filter;                 //!< Filter to use when searching for profiles.
-} ldap_autz_mod_env_t;
+} ldap_autz_call_env_t;
 
 /** State list for resumption of authorization
  *
@@ -164,7 +164,7 @@ typedef struct {
        fr_ldap_map_exp_t       expanded;
        fr_ldap_query_t         *query;
        fr_ldap_thread_trunk_t  *ttrunk;
-       ldap_autz_mod_env_t     *mod_env;
+       ldap_autz_call_env_t    *call_env;
        LDAPMessage             *entry;
        ldap_autz_status_t      status;
        struct berval           **profile_values;
index 3786d67b425b297e91a357ab0d7c75ff698decef..3537ceb8bbdc81aea48e2f9dbe7b3db7a0114932 100644 (file)
@@ -838,7 +838,7 @@ static unlang_action_t CC_HINT(nonnull) mod_mail(rlm_rcode_t *p_result, module_c
 {
        rlm_smtp_t const                *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_smtp_t);
        rlm_smtp_thread_t               *t = talloc_get_type_abort(mctx->thread, rlm_smtp_thread_t);
-       rlm_smtp_env_t                  *mod_env = talloc_get_type_abort(mctx->env_data, rlm_smtp_env_t);
+       rlm_smtp_env_t                  *call_env = talloc_get_type_abort(mctx->env_data, rlm_smtp_env_t);
        fr_curl_io_request_t            *randle = NULL;
        fr_mail_ctx_t                   *mail_ctx;
        const char                      *envelope_address;
@@ -866,9 +866,9 @@ static unlang_action_t CC_HINT(nonnull) mod_mail(rlm_rcode_t *p_result, module_c
         *      a onetime connection is used, otherwise a persistent one
         *      can be used.
         */
-       randle = (mod_env->username_tmpl &&
-                 !tmpl_is_data(mod_env->username_tmpl)) ? smtp_slab_reserve(t->slab_onetime) :
-                                                          smtp_slab_reserve(t->slab_persist);
+       randle = (call_env->username_tmpl &&
+                 !tmpl_is_data(call_env->username_tmpl)) ? smtp_slab_reserve(t->slab_onetime) :
+                                                           smtp_slab_reserve(t->slab_persist);
        if (!randle) {
                RDEBUG2("A handle could not be allocated for the request");
                RETURN_MODULE_FAIL;
@@ -888,12 +888,12 @@ static unlang_action_t CC_HINT(nonnull) mod_mail(rlm_rcode_t *p_result, module_c
        FR_CURL_REQUEST_SET_OPTION(CURLOPT_UPLOAD, 1L);
 
        /* Set the username and password if they have been provided */
-       if (mod_env->username.vb_strvalue) {
-               FR_CURL_REQUEST_SET_OPTION(CURLOPT_USERNAME, mod_env->username.vb_strvalue);
+       if (call_env->username.vb_strvalue) {
+               FR_CURL_REQUEST_SET_OPTION(CURLOPT_USERNAME, call_env->username.vb_strvalue);
 
-               if (!mod_env->password.vb_strvalue) goto skip_auth;
+               if (!call_env->password.vb_strvalue) goto skip_auth;
 
-               FR_CURL_REQUEST_SET_OPTION(CURLOPT_PASSWORD, mod_env->password.vb_strvalue);
+               FR_CURL_REQUEST_SET_OPTION(CURLOPT_PASSWORD, call_env->password.vb_strvalue);
                RDEBUG2("Username and password set");
        }
 skip_auth:
@@ -1238,18 +1238,18 @@ static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
        return 0;
 }
 
-static const module_env_t module_env[] = {
-       { FR_MODULE_ENV_TMPL_OFFSET("username", FR_TYPE_STRING, rlm_smtp_env_t, username, username_tmpl, NULL,
+static const call_env_t call_env[] = {
+       { FR_CALL_ENV_TMPL_OFFSET("username", FR_TYPE_STRING, rlm_smtp_env_t, username, username_tmpl, NULL,
                                T_DOUBLE_QUOTED_STRING, false, true, true) },
-       { FR_MODULE_ENV_OFFSET("password", FR_TYPE_STRING, rlm_smtp_env_t, password, NULL,
+       { FR_CALL_ENV_OFFSET("password", FR_TYPE_STRING, rlm_smtp_env_t, password, NULL,
                                T_DOUBLE_QUOTED_STRING, false, true, true) },
-       MODULE_ENV_TERMINATOR
+       CALL_ENV_TERMINATOR
 };
 
-static const module_method_env_t method_env = {
+static const call_method_env_t method_env = {
        .inst_size = sizeof(rlm_smtp_env_t),
        .inst_type = "rlm_smtp_env_t",
-       .env = module_env
+       .env = call_env
 };
 
 /*