#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.
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
*
*/
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 }
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,
*
* 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)
*
* @{
*/
-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);
SOURCES := base.c \
call.c \
+ call_env.c \
caller.c \
compile.c \
condition.c \
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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
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;
* 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;
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);
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;
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.
*/
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.
///< 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
rindent_t indent; //!< indentation
+ void *env_data; //!< Expanded per call environment tmpls.
/*
* For func and alternate
*/
*/
ev->timeout(XLAT_CTX(ev->inst->data,
ev->thread->data,
- ev->thread->mctx,
+ ev->thread->mctx, NULL,
UNCONST(void *, ev->rctx)),
ev->request, now);
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);
#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
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
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;
* @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
*
{
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
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",
* @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;
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);
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);
* 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;
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.
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);
}
}
+ /*
+ * 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;
}
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.
///< 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
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);
return -1;
}
node->call.func = func;
+ if (t_rules) node->call.dict = t_rules->attr.dict_def;
node->flags = func->flags;
}
return -1;
}
node->call.func = func;
+ if (t_rules) node->call.dict = t_rules->attr.dict_def;
node->flags = func->flags;
}
}
xlat_exp_set_type(node, XLAT_FUNC);
+ node->call.dict = xr_rules->tr_rules->dict_def;
/*
* Check input arguments of our freshly
* 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 */
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);
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;
}
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) {
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[] = {
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
};
/*
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
};
/*
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
};
/*
};
/*
- * 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;
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
*/
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];
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
/*
* 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");
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;
.password = password->vp_strvalue,
.thread = thread,
.inst = inst,
- .mod_env = mod_env
+ .call_env = call_env
};
/*
}
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);
}
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);
}
{
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();
/*
* 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:
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);
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,
{
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.
* @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);
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
};
/*
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;
}
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;
}
//!< 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
*
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;
{
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;
* 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;
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:
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
};
/*