From: Alan T. DeKok Date: Wed, 26 Mar 2025 11:39:09 +0000 (-0400) Subject: fix map resolution X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=655af4f0d9c48bb37524a24812f25740255ddc84;p=thirdparty%2Ffreeradius-server.git fix map resolution the RHS of a map is NOT resolved in the context of the LHS. Instead, the RHS is really a pointer to a value. And the final value is then resolved in the context of the LHS. --- diff --git a/src/lib/server/map.c b/src/lib/server/map.c index b96c2c964e7..57f6dbd9543 100644 --- a/src/lib/server/map.c +++ b/src/lib/server/map.c @@ -319,13 +319,25 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, } /* - * If we know that the assignment is forbidden, then fail early. + * If we can resolve the RHS in the context of the LHS, + * and are allowed to do so, then do that now. * - * Note that we can do some assignment of strings to - * structural elements. The string is parsed as a list - * of edit instructions. + * The "map" keyword uses the RHS not as the value which + * is assigned to the LHS. Instead, it is a pointer to + * the value. As such, we cannot immediately resolve the + * RHS in the context of the LHS. + * + * The edit code allows string assignments to lists, and + * will interpret the string as a sequence of edit + * operations. So we skip casting strings to lists. + * + * @todo - that could arguably be done immediately here, + * and the RHS could be parsed and created as a child + * map. That would allow for more compile-time sanity + * checks. */ if (tmpl_is_attr(map->lhs) && tmpl_is_data(map->rhs) && + (!input_rhs_rules || !input_rhs_rules->attr.disallow_rhs_resolve) && fr_type_is_leaf(tmpl_attr_tail_da(map->lhs)->type)) { fr_type_t cast_type; diff --git a/src/lib/server/tmpl.h b/src/lib/server/tmpl.h index fb9473a9ba9..c6f34a2a56d 100644 --- a/src/lib/server/tmpl.h +++ b/src/lib/server/tmpl.h @@ -333,6 +333,8 @@ struct tmpl_attr_rules_s { uint8_t xlat:1 ; //!< for %{User-Name} uint8_t bare_word_enum:1; //!< for v3 compatibility. + + uint8_t disallow_rhs_resolve:1; //!< map RHS is NOT immediately resolved in the context of the LHS. }; struct tmpl_xlat_rules_s { diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index 596368f52ee..a24d432bd47 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -744,10 +744,10 @@ static unlang_t *compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx, CON }; /* - * We allow unknown attributes here. + * The RHS is NOT resolved in the context of the LHS. */ t_rules = *(unlang_ctx->rules); - t_rules.attr.allow_unknown = true; + t_rules.attr.disallow_rhs_resolve = true; RULES_VERIFY(&t_rules); modules = cf_section_find(cf_root(cs), "modules", NULL); @@ -819,7 +819,7 @@ static unlang_t *compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx, CON * This looks at cs->name2 to determine which list to update */ map_list_init(&gext->map); - rcode = map_afrom_cs(gext, &gext->map, cs, &t_rules, &t_rules, unlang_fixup_map, NULL, 256); + rcode = map_afrom_cs(gext, &gext->map, cs, unlang_ctx->rules, &t_rules, unlang_fixup_map, NULL, 256); if (rcode < 0) return NULL; /* message already printed */ if (map_list_empty(&gext->map)) { cf_log_err(cs, "'map' sections cannot be empty");