* We don't have (or need yet) cf_pair_parse_pass2(), so we just
* do it for tmpls.
*/
-static int cf_parse_tmpl_pass2(UNUSED CONF_SECTION *cs, tmpl_t **out, CONF_PAIR *cp, fr_type_t type, bool attribute)
+static int cf_parse_tmpl_pass2(UNUSED CONF_SECTION *cs, tmpl_t **out, CONF_PAIR *cp, fr_type_t type,
+ bool attribute, fr_dict_t const *dict_def)
{
tmpl_t *vpt = *out;
fr_assert(vpt); /* We need something to resolve */
- if (tmpl_resolve(vpt) < 0) {
+ if (tmpl_resolve(vpt, &(tmpl_res_rules_t){ .dict_def = dict_def, .force_dict_def = (dict_def != NULL)}) < 0) {
cf_log_perr(cp, "Failed processing configuration item '%s'", cp->attr);
return -1;
}
* Parse the pair into a template
*/
} else if (is_tmpl && !multi) {
- if (cf_parse_tmpl_pass2(cs, (tmpl_t **)data, cp, type, attribute) < 0) {
+ if (cf_parse_tmpl_pass2(cs, (tmpl_t **)data, cp, type, attribute, dict) < 0) {
return -1;
}
for (i = 0; i < talloc_array_length(array); i++, cp = cf_pair_find_next(cs, cp, name)) {
if (!cp) break;
- if (cf_parse_tmpl_pass2(cs, &array[i], cp, type, attribute) < 0) {
+ if (cf_parse_tmpl_pass2(cs, &array[i], cp, type, attribute, dict) < 0) {
return -1;
}
}
* for string data without xlat. Instead, it
* creates TMPL_TYPE_UNRESOLVED.
*/
- if (tmpl_resolve(map->lhs) < 0) {
+ if (tmpl_resolve(map->lhs, NULL) < 0) {
fr_sbuff_set(&our_in, &m_lhs); /* Marker points to LHS */
goto error;
}
* for string data without xlat. Instead, it
* creates TMPL_TYPE_UNRESOLVED.
*/
- if (tmpl_resolve(map->rhs) < 0) {
+ if (tmpl_resolve(map->rhs, NULL) < 0) {
fr_sbuff_set(&our_in, &m_rhs); /* Marker points to RHS */
goto error;
}
extern fr_table_num_ordered_t const tmpl_type_table[];
extern size_t tmpl_type_table_len;
-
typedef struct tmpl_rules_s tmpl_rules_t;
+typedef struct tmpl_res_rules_s tmpl_res_rules_t;
typedef struct tmpl_s tmpl_t;
#include <freeradius-devel/unlang/xlat.h>
///< a prefix.
};
+/** Similar to tmpl_rules_t, but used to specify parameters that may change during subsequent resolution passes
+ *
+ * When a tmpl is parsed initially the rules are stored in the #tmpl_t.
+ *
+ * During subsequent resolution phases where unresolved attributes are resolved to dictionary
+ * attributes the initial #tmpl_rules_t is used to control resolution.
+ *
+ * In some instances however (primarily policies), some rules may need change between initial
+ * parsing and subsequent resolution phases.
+ *
+ * This structure holds rules which may override the tmpl_rules_s during subsequent resolution passes.
+ */
+struct tmpl_res_rules_s {
+ fr_dict_t const *dict_def; //!< Alternative default dictionary to use if
+ ///< vpt->rules->dict_def is NULL.
+ //!< Will be written to vpt->rules->dict_def
+ ///< if used.
+
+ bool force_dict_def; //!< Use supplied dict_def even if original
+ ///< vpt->rules->dict_def was not NULL.
+};
+
typedef enum {
TMPL_ATTR_TYPE_NORMAL = 0, //!< Normal, resolved, attribute ref.
TMPL_ATTR_TYPE_UNKNOWN, //!< We have an attribute number but
*/
int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv);
-int tmpl_resolve(tmpl_t *vpt) CC_HINT(nonnull);
+int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules) CC_HINT(nonnull(1));
void tmpl_unresolve(tmpl_t *vpt) CC_HINT(nonnull);
*
* Multi-pass parsing fixups for attribute references.
*
- * @param[in] vpt to resolve.
+ * @param[in] vpt to resolve.
+ * @param[in] tr_rules Combined with the original parse rules for
+ * additional resolution passes.
* @return
* - 0 if all references were resolved.
* - -1 if there are unknown attributes which need
* adding to the global dictionary first.
* - -2 if there are attributes we couldn't resolve.
*/
-static inline CC_HINT(always_inline) int tmpl_attr_resolve(tmpl_t *vpt)
+static inline CC_HINT(always_inline) int tmpl_attr_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
{
tmpl_attr_t *ar = NULL, *next, *prev;
fr_dict_attr_t const *da;
+ fr_dict_t const *dict_def;
fr_assert(tmpl_is_attr_unresolved(vpt));
TMPL_VERIFY(vpt);
+ dict_def = vpt->rules.dict_def;
+ if (!tr_rules->dict_def || tr_rules->force_dict_def) dict_def = tr_rules->dict_def;
+
/*
* First component is special becase we may need
* to search for it in multiple dictionaries.
if (ar->type == TMPL_ATTR_TYPE_UNRESOLVED) {
(void)fr_dict_attr_search_by_name_substr(NULL,
&da,
- vpt->rules.dict_def,
+ dict_def,
&FR_SBUFF_IN(ar->ar_unresolved,
talloc_array_length(ar->ar_unresolved) - 1),
NULL,
ar->ar_da = da;
ar->ar_parent = fr_dict_root(fr_dict_by_da(da));
+ /*
+ * Record the dictionary that was
+ * successfully used for resolution.
+ */
+ vpt->rules.dict_def = tr_rules->dict_def;
+
/*
* Reach into the next reference
* and correct its parent and
* - TMPL_TYPE_EXEC
* - TMPL_TYPE_REGEX_XLAT
*
- * @param[in] vpt Containing the xlat expansion to resolve.
+ * @param[in] vpt Containing the xlat expansion to resolve.
+ * @param[in] tr_rules Combined with the original parse rules for
+ * additional resolution passes.
* @return
* - 0 on success.
* - -1 on failure.
*/
-static inline CC_HINT(always_inline) int tmpl_xlat_resolve(tmpl_t *vpt)
+static inline CC_HINT(always_inline)
+int tmpl_xlat_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
{
- if (xlat_resolve(&vpt->data.xlat.ex, &vpt->data.xlat.flags, false) < 0) return -1;
+ if (xlat_resolve(&vpt->data.xlat.ex, &vpt->data.xlat.flags,
+ &(xlat_res_rules_t){
+ .tr_rules = tr_rules,
+ .allow_unresolved = false
+ }) < 0) return -1;
RESOLVED_SET(&vpt->type);
TMPL_VERIFY(vpt);
/** Attempt to resolve functions and attributes in xlats and attribute references
*
- * @param[in,out] vpt to resolve. Should be of type TMPL_TYPE_XLAT_UNRESOLVED
- * or TMPL_TYPE_ATTR_UNRESOLVED. All other types will be
- * noops.
+ * @note If resolution is successful, the rules->dict_def field will be modified to
+ * reflect the dictionary resolution was successful in.
+ *
+ * @param[in,out] vpt to resolve. Should be of type TMPL_TYPE_XLAT_UNRESOLVED
+ * or TMPL_TYPE_ATTR_UNRESOLVED. All other types will be
+ * noops.
+ * @param[in] tr_rules Combined with the original parse rules for
+ * additional resolution passes.
* @return
* - 0 on success.
* - -1 on failure.
*/
-int tmpl_resolve(tmpl_t *vpt)
+int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
{
+ static tmpl_res_rules_t const default_tr_rules;
+
int ret = 0;
if (!tmpl_needs_resolving(vpt)) return 0; /* Nothing to do */
+ if (!tr_rules) tr_rules = &default_tr_rules;
+
/*
* The xlat component of the #tmpl_t needs resolving.
*/
if (tmpl_contains_xlat(vpt)) {
- ret = tmpl_xlat_resolve(vpt);
+ ret = tmpl_xlat_resolve(vpt, tr_rules);
/*
* The attribute reference needs resolving.
*/
} else if (tmpl_contains_attr(vpt)) {
- ret = tmpl_attr_resolve(vpt);
+ ret = tmpl_attr_resolve(vpt, tr_rules);
/*
* Convert unresolved tmpls into literal string values.
/*
* Fixup any other tmpl types
*/
- if (tmpl_resolve(vpt) < 0) {
+ if (tmpl_resolve(vpt, &(tmpl_res_rules_t){ .dict_def = dict, .force_dict_def = (dict != NULL)}) < 0) {
cf_log_perr(ci, NULL);
return false;
}
void *uctx; //!< Argument to pass to escape callback.
} xlat_arg_parser_t;
+typedef struct {
+ tmpl_res_rules_t const *tr_rules; //!< tmpl resolution rules.
+ bool allow_unresolved; //!< If false, all resolution steps must be completed
+ ///< this round, otherwise an error will be produced.
+} xlat_res_rules_t;
+
#define XLAT_ARG_PARSER_TERMINATOR { .required = false, .concat = false, .single = false, .variadic = false, \
.type = FR_TYPE_NULL, .func = NULL, .uctx = NULL }
bool xlat_to_literal(TALLOC_CTX *ctx, char **str, xlat_exp_t **head);
-int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved);
+int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, xlat_res_rules_t const *xr_rules);
#define XLAT_DEFAULT_BUF_LEN 2048
*
* @param[in,out] head of xlat tree to resolve.
* @param[in,out] flags that control evaluation and parsing.
- * @param[in] allow_unresolved Don't error out if we can't resolve a function or attribute.
+ * @param[in] xr_rules Specifies rules to use for resolution passes after initial
+ * tokenization.
* @return
* - 0 on success.
* - -1 on failure.
*/
-int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved)
+int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, xlat_res_rules_t const *xr_rules)
{
- xlat_exp_t *node;
- xlat_flags_t our_flags;
+ static xlat_res_rules_t xr_default;
+ xlat_exp_t *node;
+ xlat_flags_t our_flags;
if (!flags->needs_resolving) return 0; /* Already done */
+ if (!xr_rules) xr_rules = &xr_default;
+
our_flags = *flags;
our_flags.needs_resolving = false; /* We flip this if not all resolutions are successful */
switch (node->type) {
case XLAT_GROUP:
- return xlat_resolve(&node->child, &node->flags, allow_unresolved);
+ return xlat_resolve(&node->child, &node->flags, xr_rules);
/*
* Alternate expansion a || b
{
xlat_flags_t child_flags = node->flags, alt_flags = node->flags;
- if ((xlat_resolve(&node->child, &child_flags, allow_unresolved) < 0) ||
- (xlat_resolve(&node->alternate, &alt_flags, allow_unresolved) < 0)) return -1;
+ if ((xlat_resolve(&node->child, &child_flags, xr_rules) < 0) ||
+ (xlat_resolve(&node->alternate, &alt_flags, xr_rules) < 0)) return -1;
xlat_flags_merge(&child_flags, &alt_flags);
node->flags = child_flags;
* A resolved function with unresolved args
*/
case XLAT_FUNC:
- if (xlat_resolve(&node->child, &node->flags, allow_unresolved) < 0) return -1;
+ if (xlat_resolve(&node->child, &node->flags, xr_rules) < 0) return -1;
xlat_flags_merge(&our_flags, &node->flags);
break;
* We can't tell if it's just the function
* that needs resolving or its children too.
*/
- if (xlat_resolve(&node->child, &child_flags, allow_unresolved) < 0) return -1;
+ if (xlat_resolve(&node->child, &child_flags, xr_rules) < 0) return -1;
/*
* Try and find the function
/*
* FIXME - Produce proper error with marker
*/
- if (!allow_unresolved) {
+ if (!xr_rules->allow_unresolved) {
fr_strerror_printf("Failed resolving function \"%pV\"",
fr_box_strvalue_buffer(node->fmt));
return -1;
/*
* Try and resolve (in-place) as an attribute
*/
- if ((tmpl_resolve(node->attr) < 0) || (node->attr->type != TMPL_TYPE_ATTR)) {
+ if ((tmpl_resolve(node->attr, xr_rules->tr_rules) < 0) ||
+ (node->attr->type != TMPL_TYPE_ATTR)) {
/*
* FIXME - Produce proper error with marker
*/
- if (!allow_unresolved) {
+ if (!xr_rules->allow_unresolved) {
error_unresolved:
fr_strerror_printf_push("Failed resolving attribute in expansion %%{%s}",
node->fmt);
break;
case XLAT_ATTRIBUTE:
- if (!allow_unresolved) goto error_unresolved;
+ if (!xr_rules->allow_unresolved) goto error_unresolved;
break;
default: