From: Alan T. DeKok Date: Sun, 7 Aug 2022 20:44:34 +0000 (-0400) Subject: add and use tmpl_rules_child_init() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=863ae5791fcc77032ff17efa7e5b694d9b5192b3;p=thirdparty%2Ffreeradius-server.git add and use tmpl_rules_child_init() which initializes a tmpl_rules_t from a parent tmpl_rules_t, and a tmpl_t which is a structural attribute. We want to be able to parse child attributes in the context of the parent. So that the user doesn't have to specify the entire list --- diff --git a/src/lib/server/map.c b/src/lib/server/map.c index 90b7d1f5091..716fee8395e 100644 --- a/src/lib/server/map.c +++ b/src/lib/server/map.c @@ -106,6 +106,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, fr_dict_attr_t const *da; tmpl_rules_t my_rhs_rules; tmpl_rules_t const *rhs_rules = input_rhs_rules; + TALLOC_CTX *child_ctx = NULL; *out = NULL; @@ -130,6 +131,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, fr_assert(lhs_rules->attr.list_as_attr); /* so we don't worry about list_def? */ } + MEM(child_ctx = talloc(map, uint8_t)); /* * LHS may be an expansion (that expands to an attribute reference) @@ -173,47 +175,13 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, } /* - * The caller wants the RHS attributes to be parsed in the context of the LHS. + * The caller wants the RHS attributes to be + * parsed in the context of the LHS, but only if + * the LHS attribute was a group / structural attribute. */ - if (!input_rhs_rules && lhs_rules->attr.list_as_attr && tmpl_is_attr(map->lhs)) { - da = tmpl_da(map->lhs); - - /* - * LHS is a leaf. We must parse the RHS as a full attribute reference (or raw - * data). - */ - if (!fr_type_structural[da->type]) { - break; - } - - my_rhs_rules = *lhs_rules; - my_rhs_rules.parent = lhs_rules; + if (!input_rhs_rules && lhs_rules->attr.list_as_attr) { + tmpl_rules_child_init(child_ctx, &my_rhs_rules, lhs_rules, map->lhs); rhs_rules = &my_rhs_rules; - - /* - * struct, tlv, VSA, etc. have their children in the parent attribute. - */ - if (da->type != FR_TYPE_GROUP) { - my_rhs_rules.attr.parent = da; - - } else { - fr_dict_attr_t const *ref = fr_dict_attr_ref(da); - fr_dict_t const *dict = fr_dict_by_da(ref); - - /* - * Groups live within their parent dictionary. - * - * If we're swapping away from internal to a different dictionary, then - * allow that. - * - * If we're swapping TO an internal dictionary, then leave well enough alone. - */ - if (((my_rhs_rules.attr.dict_def == fr_dict_internal()) && (dict != my_rhs_rules.attr.dict_def)) || - (dict != fr_dict_internal())) { - my_rhs_rules.attr.dict_def = dict; - my_rhs_rules.attr.parent = ref; - } - } } break; } @@ -224,7 +192,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, type = cf_pair_value_quote(cp); p_rules = value_parse_rules_unquoted[type]; /* We're not searching for quotes */ if (type == T_DOUBLE_QUOTED_STRING || type == T_BACK_QUOTED_STRING) { - slen = fr_sbuff_out_aunescape_until(map, &unescaped_value, + slen = fr_sbuff_out_aunescape_until(child_ctx, &unescaped_value, &FR_SBUFF_IN(value, talloc_array_length(value) - 1), SIZE_MAX, p_rules->terminals, p_rules->escapes); if (slen < 0) { marker_subject = value; @@ -245,7 +213,6 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, marker_subject = value; goto marker; } - TALLOC_FREE(unescaped_value); if (!map->rhs) { cf_log_perr(cp, "Failed parsing RHS"); @@ -280,13 +247,14 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, } MAP_VERIFY(map); + TALLOC_FREE(child_ctx); *out = map; return 0; error: - talloc_free(unescaped_value); + TALLOC_FREE(child_ctx); talloc_free(map); return -1; } @@ -857,8 +825,25 @@ do_children: * is used as the parsing context of the * inner section. */ - our_lhs_rules.attr.parent = tmpl_da(map->lhs); our_lhs_rules.attr.prefix = TMPL_ATTR_REF_PREFIX_NO; + our_lhs_rules.attr.parent = tmpl_da(map->lhs); + + /* + * Groups MAY change dictionaries. If so, then swap the dictionary and the parent. + */ + if (our_lhs_rules.attr.parent->type == FR_TYPE_GROUP) { + fr_dict_attr_t const *ref; + fr_dict_t const *dict, *internal; + + ref = fr_dict_attr_ref(our_lhs_rules.attr.parent); + dict = fr_dict_by_da(ref); + internal = fr_dict_internal(); + + if ((dict != internal) && (dict != our_lhs_rules.attr.dict_def)) { + our_lhs_rules.attr.dict_def = dict; + our_lhs_rules.attr.parent = ref; + } + } /* * This prints out any relevant error diff --git a/src/lib/server/tmpl.h b/src/lib/server/tmpl.h index 29d1922fb6c..35fda42d194 100644 --- a/src/lib/server/tmpl.h +++ b/src/lib/server/tmpl.h @@ -1152,6 +1152,8 @@ fr_pair_t *tmpl_get_list(request_t *request, tmpl_t const *vpt) CC_HINT(nonnull int tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *vb, tmpl_t const *vpt) CC_HINT(nonnull); +void tmpl_rules_child_init(TALLOC_CTX *ctx, tmpl_rules_t *out, tmpl_rules_t const *parent, tmpl_t *vpt) CC_HINT(nonnull); + int tmpl_global_init(void); void tmpl_global_free(void); diff --git a/src/lib/server/tmpl_tokenize.c b/src/lib/server/tmpl_tokenize.c index 16d7c25de89..010e23d6afd 100644 --- a/src/lib/server/tmpl_tokenize.c +++ b/src/lib/server/tmpl_tokenize.c @@ -2163,7 +2163,7 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, * * Eventually we'll remove TMPL_TYPE_LIST */ - if (tmpl_attr_list_num_elements(&vpt->data.attribute.ar) == 0) { + if (!t_attr_rules->list_as_attr && (tmpl_attr_list_num_elements(&vpt->data.attribute.ar) == 0)) { tmpl_attr_t *ar; MEM(ar = talloc_zero(vpt, tmpl_attr_t)); @@ -5460,3 +5460,62 @@ bool tmpl_async_required(tmpl_t const *vpt) return false; } } + +/** Initialize a set of rules from a parent set of rules, and a parsed tmpl_t + * + */ +void tmpl_rules_child_init(TALLOC_CTX *ctx, tmpl_rules_t *out, tmpl_rules_t const *parent, tmpl_t *vpt) +{ + fr_dict_attr_t const *da; + fr_dict_attr_t const *ref; + fr_dict_t const *dict, *internal; + + *out = *parent; + out->parent = parent; + + if (!tmpl_is_attr(vpt)) return; + + da = tmpl_da(vpt); + + /* + * The input tmpl is a leaf. We must parse the child as + * a normal attribute reference (as with the parent tmpl). + */ + if (!fr_type_structural[da->type]) { + return; + } + + if (vpt->rules.attr.request_def) { + tmpl_request_ref_list_acopy(ctx, &out->attr.request_def, vpt->rules.attr.request_def); + } + out->attr.list_def = tmpl_list(vpt); + + /* + * Parse the child attributes in the context of the parent struct / tlv / whatever. + */ + if (da->type != FR_TYPE_GROUP) { + out->attr.dict_def = fr_dict_by_da(da); + out->attr.parent = da; + return; + } + + ref = fr_dict_attr_ref(da); + dict = fr_dict_by_da(ref); + internal = fr_dict_internal(); + + /* + * Groups MAY change dictionaries. If so, then swap the dictionary and the parent. + */ + if ((dict != internal) && (dict != out->attr.dict_def)) { + out->attr.dict_def = dict; + out->attr.parent = ref; + } + + /* + * Otherwise the reference is swapping FROM a protocol + * dictionary TO the internal dictionary, and TO an + * internal group. We fall back to leaving well enough + * alone, and leave things as-is. This allows internal + * grouping attributes to appear anywhere. + */ +} diff --git a/src/tests/keywords/call b/src/tests/keywords/call index 3ffeaa0e4c6..79a6ea0dbd1 100644 --- a/src/tests/keywords/call +++ b/src/tests/keywords/call @@ -19,9 +19,6 @@ if (&reply.Reply-Message[1] != "call second post") { test_fail } -# -# @todo - The LHS SHOULD set the default context for the RHS. -# -&reply -= &reply.Reply-Message +&reply -= &Reply-Message[*] success diff --git a/src/tests/keywords/call-empty b/src/tests/keywords/call-empty index 703510e1f23..de8a0b7320c 100644 --- a/src/tests/keywords/call-empty +++ b/src/tests/keywords/call-empty @@ -14,9 +14,6 @@ if (&reply.Reply-Message[0] != "call second") { test_fail } -# -# @todo - The LHS SHOULD set the default context for the RHS. -# -&reply -= &reply.Reply-Message +&reply -= &Reply-Message success diff --git a/src/tests/keywords/edit-list-remove-reply b/src/tests/keywords/edit-list-remove-reply new file mode 100644 index 00000000000..ae439f1458c --- /dev/null +++ b/src/tests/keywords/edit-list-remove-reply @@ -0,0 +1,16 @@ +&reply.Reply-Message := "foo" +if (!&reply.Reply-Message) { + test_fail +} + +# +# The default list here is the LHS list, not "request". +# +&reply -= &Reply-Message[*] + +# Does not exist +if (&reply.Reply-Message) { + test_fail +} + +success