From: Alan T. DeKok Date: Thu, 20 Jan 2022 00:08:35 +0000 (-0500) Subject: add xlat_purify and tests X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6764f238fefd93a20c1d66f14ce51ee4aca96d02;p=thirdparty%2Ffreeradius-server.git add xlat_purify and tests which for now only handle xlat_expr, but that's a good enough test to catch things which had previously been missed. --- diff --git a/src/bin/unit_test_attribute.c b/src/bin/unit_test_attribute.c index bfbdcd794e..ea1ac85a26 100644 --- a/src/bin/unit_test_attribute.c +++ b/src/bin/unit_test_attribute.c @@ -2631,7 +2631,7 @@ static size_t command_xlat_normalise(command_result_t *result, command_file_ctx_ RETURN_OK(escaped_len); } -/** Parse an reprint and xlat expression expansion +/** Parse and reprint an xlat expression expansion * */ static size_t command_xlat_expr(command_result_t *result, command_file_ctx_t *cc, @@ -2664,6 +2664,43 @@ static size_t command_xlat_expr(command_result_t *result, command_file_ctx_t *cc RETURN_OK(escaped_len); } +/** Parse, purify, and reprint an xlat expression expansion + * + */ +static size_t command_xlat_purify(command_result_t *result, command_file_ctx_t *cc, + char *data, UNUSED size_t data_used, char *in, UNUSED size_t inlen) +{ + ssize_t dec_len; + xlat_exp_t *head = NULL; + size_t input_len = strlen(in), escaped_len; +// fr_sbuff_parse_rules_t p_rules = { .escapes = &fr_value_unescape_double }; + xlat_flags_t flags = { + .pure = true, + }; + + dec_len = xlat_tokenize_expression(cc->tmp_ctx, &head, &flags, &FR_SBUFF_IN(in, input_len), NULL, + &(tmpl_attr_rules_t) { + .dict_def = cc->tmpl_rules.attr.dict_def ? + cc->tmpl_rules.attr.dict_def : cc->config->dict, + .allow_unresolved = cc->tmpl_rules.attr.allow_unresolved + }); + if (dec_len <= 0) { + fr_strerror_printf_push_head("ERROR offset %d", (int) -dec_len); + + return_error: + RETURN_OK_WITH_ERROR(); + } + + if (((size_t) dec_len != input_len)) { + fr_strerror_printf_push_head("Passed in %zu characters, but only parsed %zd characters", input_len, dec_len); + goto return_error; + } + + escaped_len = xlat_print(&FR_SBUFF_OUT(data, COMMAND_OUTPUT_MAX), head, &fr_value_escape_double); + RETURN_OK(escaped_len); +} + + /** Parse an reprint and xlat argv expansion * */ @@ -2915,6 +2952,12 @@ static fr_table_ptr_sorted_t commands[] = { .description = "Parse then print an xlat expression, writing the normalised xlat expansion to the data buffer" }}, + { L("xlat_purify "), &(command_entry_t){ + .func = command_xlat_purify, + .usage = "xlat_purify ", + .description = "Parse, purify, then print an xlat expression, writing the normalised xlat expansion to the data buffer" + }}, + }; static size_t commands_len = NUM_ELEMENTS(commands); diff --git a/src/tests/unit/xlat/purify.txt b/src/tests/unit/xlat/purify.txt new file mode 100644 index 0000000000..31be80ee8b --- /dev/null +++ b/src/tests/unit/xlat/purify.txt @@ -0,0 +1,114 @@ +proto-dictionary radius + +# +# xlat_expr, but purified +# +xlat_purify 3 + 4 +match 7 + +xlat_purify 3 * 4 +match 12 + +xlat_purify 2 + 3 * 4 +match 14 + +xlat_purify 2 + 3 * 4 + 5 +match 19 + +# Same as above with brackets +xlat_purify 2 + (3 * 4) + 5 +match 19 + +# not the same +xlat_purify (2 + 3) * (4 + 5) +match 45 + +xlat_purify (2 + 3) * 4 + 5 +match 25 + +xlat_purify &NAS-Port + 5 +match (%{NAS-Port} + 5) + +xlat_purify &Framed-IP-Address & 0xffff0000 +match (%{Framed-IP-Address} & 255.255.0.0) + +xlat_purify %{Framed-IP-Address} + 4 +match (%{Framed-IP-Address} + 0.0.0.4) + +xlat_purify 1 < 4 +match yes + +xlat_purify &Service-Type == Framed-User +match (%{Service-Type} == Framed-User) + +xlat_purify 1 + (&Service-Type == Framed-User) +match (1 + (%{Service-Type} == Framed-User)) + +# +# Strings of various forms +# +xlat_purify &Filter-Id == "foo" +match (%{Filter-Id} == \"foo\") + +xlat_purify "foo" == "bar" +match no + +# note '/' is a prefix, not "divide by 24". +# and a useless cast is removed +xlat_purify &Framed-IP-Address < (ipv4prefix) 192.168.0.0/24 +match (%{Framed-IP-Address} < 192.168.0.0/24) + +xlat_purify &Framed-IP-Address < (ipv4prefix) 192.168.0.0 +match (%{Framed-IP-Address} < 192.168.0.0/32) + +# +# For IP addresses, the other side is automatically upcast to a prefix +# + +#xlat_purify &Framed-IP-Address < 192.168.0.0/24 +#match %(cmp_lt:%{Framed-IP-Address}%(cast:ipv4prefix 192.168.0.0/32)) + +# same as above, but swap the order +xlat_purify (ipv4prefix) 192.168.0.0/24 > &Framed-IP-Address +match (192.168.0.0/24 > %{Framed-IP-Address}) + +# +# Logical && and || +# +xlat_purify 1 < 2 || 4 > 3 +match yes + +xlat_purify 2 || (1 > 4) +match yes + +xlat_purify &Filter-Id +match %{Filter-Id} + +xlat_purify %{md5:foo} + "foo" +match (%{md5:foo} + \"foo\") + +# We can name the xlat's, tho we don't need to +xlat_purify %(op_add:4 3) + 6 +match ((4 + 3) + 6) + + +# +# useless casts are omitted. +# +xlat_purify 1 < (uint32) 2 +match yes + +# +# @todo - for exec, xlat, etc., if we're doing an existence check of +# string / octets, then the check is for "length>0", NOT for parsing +# the contents of the data type. +# + +# +# This should likely be a parse error at boot time? +# +xlat_purify 1 < 2 < 3 +match ERROR offset 9: Cannot compare incompatible types (bool)... < (int64)... + +count +match 51