]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Fix protocol attributes in xlats in policies
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 3 Nov 2021 01:56:33 +0000 (21:56 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 3 Nov 2021 01:56:33 +0000 (21:56 -0400)
src/lib/server/cf_parse.c
src/lib/server/map.c
src/lib/server/tmpl.h
src/lib/server/tmpl_tokenize.c
src/lib/unlang/compile.c
src/lib/unlang/xlat.h
src/lib/unlang/xlat_tokenize.c

index 99dd53d41f9a1ea617cbb711ed42edf8ed539e6e..95af1df0b1223870895aa75df7eb923bbe351856 100644 (file)
@@ -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;
                                }
                        }
index c19708177501f8bf59198e4d60458545e20ee554..4fd080e948016b4c1ed878064b17527d0f49edac 100644 (file)
@@ -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;
                }
index da1cf385e237cff4b9f2d62b34862dabf32398b8..082937d7ee2aa62e5055dcc732c016ee613620fe 100644 (file)
@@ -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 <freeradius-devel/unlang/xlat.h>
@@ -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);
 
index 6f8f9fc6c80caad68a5655022dbe8ef51c1162bc..5f64392b6c66102a7df049a83c67ac26b2f41560 100644 (file)
@@ -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.
index f734cc247e500e384eee2f19aed4994349cd2a49..554f40be99af726bbe012bb4485f571239008702 100644 (file)
@@ -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;
        }
index b6cdf4c60556471ccbd9269b39c29df72533233b..58bc4a15ebaff93ff2a4e0ca156b0f76477d63df 100644 (file)
@@ -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
index a28e3c6abb8c6c454a275e988c6b901103399b9a..3385704061fca75086611ee43f4883555301f77e 100644 (file)
@@ -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: