From: Nick Porter Date: Tue, 28 Feb 2023 10:20:17 +0000 (+0000) Subject: Define method_env_parse() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cfa3a7974d942a996b55a8dc080fd9654e0d4a58;p=thirdparty%2Ffreeradius-server.git Define method_env_parse() --- diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index 16e79cd4f09..863d70c5266 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -4657,6 +4657,116 @@ 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, "")); + 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; +} static unlang_t *compile_module(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci, module_instance_t *inst, module_method_t method, diff --git a/src/lib/unlang/module_priv.h b/src/lib/unlang/module_priv.h index 6c408e08835..fb06afff439 100644 --- a/src/lib/unlang/module_priv.h +++ b/src/lib/unlang/module_priv.h @@ -36,6 +36,9 @@ 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. + 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 + ///< to be allocated from. } unlang_module_t; /** A module stack entry