From: Arran Cudbard-Bell Date: Wed, 3 Nov 2021 01:56:33 +0000 (-0400) Subject: Fix protocol attributes in xlats in policies X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c1c07bb9faec066c171f2856482c6b460098163b;p=thirdparty%2Ffreeradius-server.git Fix protocol attributes in xlats in policies --- diff --git a/src/lib/server/cf_parse.c b/src/lib/server/cf_parse.c index 99dd53d41f9..95af1df0b12 100644 --- a/src/lib/server/cf_parse.c +++ b/src/lib/server/cf_parse.c @@ -1315,13 +1315,14 @@ finish: * 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; } @@ -1526,7 +1527,7 @@ int cf_section_parse_pass2(void *base, CONF_SECTION *cs) * 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; } @@ -1538,7 +1539,7 @@ int cf_section_parse_pass2(void *base, CONF_SECTION *cs) 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; } } diff --git a/src/lib/server/map.c b/src/lib/server/map.c index c1970817750..4fd080e9480 100644 --- a/src/lib/server/map.c +++ b/src/lib/server/map.c @@ -439,7 +439,7 @@ ssize_t map_afrom_substr(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, fr_sbuf * 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; } @@ -572,7 +572,7 @@ parse_rhs: * 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; } diff --git a/src/lib/server/tmpl.h b/src/lib/server/tmpl.h index da1cf385e23..082937d7ee2 100644 --- a/src/lib/server/tmpl.h +++ b/src/lib/server/tmpl.h @@ -247,8 +247,8 @@ typedef enum tmpl_type_e { 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 @@ -322,6 +322,28 @@ struct tmpl_rules_s { ///< 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 @@ -928,7 +950,7 @@ ssize_t tmpl_regex_flags_substr(tmpl_t *vpt, fr_sbuff_t *in, */ 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); diff --git a/src/lib/server/tmpl_tokenize.c b/src/lib/server/tmpl_tokenize.c index 6f8f9fc6c80..5f64392b6c6 100644 --- a/src/lib/server/tmpl_tokenize.c +++ b/src/lib/server/tmpl_tokenize.c @@ -3081,22 +3081,28 @@ int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv) * * 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. @@ -3108,7 +3114,7 @@ static inline CC_HINT(always_inline) int tmpl_attr_resolve(tmpl_t *vpt) 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, @@ -3120,6 +3126,12 @@ static inline CC_HINT(always_inline) int tmpl_attr_resolve(tmpl_t *vpt) 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 @@ -3234,14 +3246,21 @@ static inline CC_HINT(always_inline) int tmpl_attr_resolve(tmpl_t *vpt) * - 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); @@ -3251,29 +3270,38 @@ static inline CC_HINT(always_inline) int tmpl_xlat_resolve(tmpl_t *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. diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index f734cc247e5..554f40be99a 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -240,7 +240,7 @@ static bool pass2_fixup_tmpl(TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *c /* * 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; } diff --git a/src/lib/unlang/xlat.h b/src/lib/unlang/xlat.h index b6cdf4c6055..58bc4a15eba 100644 --- a/src/lib/unlang/xlat.h +++ b/src/lib/unlang/xlat.h @@ -123,6 +123,12 @@ typedef struct { 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 } @@ -352,7 +358,7 @@ bool xlat_is_literal(xlat_exp_t const *head); 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 diff --git a/src/lib/unlang/xlat_tokenize.c b/src/lib/unlang/xlat_tokenize.c index a28e3c6abb8..3385704061f 100644 --- a/src/lib/unlang/xlat_tokenize.c +++ b/src/lib/unlang/xlat_tokenize.c @@ -1583,18 +1583,22 @@ bool xlat_to_literal(TALLOC_CTX *ctx, char **str, xlat_exp_t **head) * * @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 */ @@ -1603,7 +1607,7 @@ int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved) 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 @@ -1614,8 +1618,8 @@ int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved) { 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; @@ -1626,7 +1630,7 @@ int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved) * 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; @@ -1643,7 +1647,7 @@ int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved) * 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 @@ -1653,7 +1657,7 @@ int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved) /* * 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; @@ -1732,11 +1736,12 @@ int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved) /* * 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); @@ -1760,7 +1765,7 @@ int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved) break; case XLAT_ATTRIBUTE: - if (!allow_unresolved) goto error_unresolved; + if (!xr_rules->allow_unresolved) goto error_unresolved; break; default: