From: Alan T. DeKok Date: Thu, 23 Jun 2022 19:50:38 +0000 (-0400) Subject: hoist casts when hoisting xlats X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5f0b15f2086278fc5170aa11c28ac8b9644af25;p=thirdparty%2Ffreeradius-server.git hoist casts when hoisting xlats and update tests which now have casts all over the place --- diff --git a/src/lib/unlang/xlat_expr.c b/src/lib/unlang/xlat_expr.c index 36745344724..71fea972e3c 100644 --- a/src/lib/unlang/xlat_expr.c +++ b/src/lib/unlang/xlat_expr.c @@ -1943,9 +1943,15 @@ static ssize_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_ * Don't keep an intermediate tmpl for xlats. Just hoist * the xlat to be a child of this node. Exec and regexes * are left alone, as they are handled by different code. + * + * However, we also add a cast if the tmpl had a cast. + * And if there was no cast, but the input was a string, + * then we cast the result to a string, too. */ if (tmpl_contains_xlat(vpt) && !tmpl_is_exec(vpt) && !tmpl_contains_regex(vpt)) { xlat_exp_head_t *xlat = tmpl_xlat(vpt); + xlat_exp_t *cast; + fr_type_t type; talloc_steal(node, xlat); node->fmt = talloc_typed_strdup(node, node->fmt); @@ -1957,6 +1963,19 @@ static ssize_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_ node->flags = xlat->flags; + if (quote != T_BARE_WORD) { + if (tmpl_rules_cast(vpt) != FR_TYPE_NULL) { + type = tmpl_rules_cast(vpt); + } else { + type = FR_TYPE_STRING; + } + + MEM(cast = expr_cast_alloc(head, type)); + + xlat_func_append_arg(cast, node); + node = cast; + } + } else { /* * Else we're not hoisting, set the node to the VPT diff --git a/src/lib/unlang/xlat_purify.c b/src/lib/unlang/xlat_purify.c index 7fd44156e95..aa8d194eccd 100644 --- a/src/lib/unlang/xlat_purify.c +++ b/src/lib/unlang/xlat_purify.c @@ -42,7 +42,7 @@ static void xlat_value_list_to_xlat(xlat_exp_head_t *head, fr_value_box_list_t * talloc_free(box); if (node->data.type == FR_TYPE_STRING) { - node->quote = T_SINGLE_QUOTED_STRING; + node->quote = T_DOUBLE_QUOTED_STRING; node->fmt = node->data.vb_strvalue; } else { node->quote = T_BARE_WORD; diff --git a/src/tests/unit/xlat/cond_base.txt b/src/tests/unit/xlat/cond_base.txt index 59c4914c5ab..e553022481d 100644 --- a/src/tests/unit/xlat/cond_base.txt +++ b/src/tests/unit/xlat/cond_base.txt @@ -90,6 +90,9 @@ match ((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)) xlat_purify (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)) match (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)) +#xlat_purify (!&User-Name == &User-Password || &Filter-Id == &Reply-Message) +#match (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)) + # different from the previous ones. xlat_purify (!((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))) match !((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)) @@ -221,7 +224,7 @@ match (&Session-Timeout == '10') # @todo - yuck. Suppress full path? # xlat_purify &Event-Timestamp == "January 1, 2012 %{User-Name}" -match (&Event-Timestamp == "January 1, 2012 %{Request[0].User-Name}") +match (&Event-Timestamp == %(cast:string "January 1, 2012 %{Request[0].User-Name}")) # This one is NOT an expansion, so it's parsed into normal form xlat_purify &Event-Timestamp == 'January 1 2012' @@ -310,18 +313,13 @@ xlat_purify ('foo' == 'foo') match true # -# @todo - if the types are incompatible, what to do? +# MD4 hash is not equal to other things # -# Cannot compare incompatible types xlat_purify ("foo" == "%{md4: foo}") -match NULL +match false -# -# @todo - maybe we just want to allow this? -# -# Cannot compare incompatible types xlat_purify ("foo bar" == "%{md4: foo}") -match NULL +match false xlat_purify ("foo" == "bar") match false @@ -337,8 +335,14 @@ match false xlat_purify (&User-Name == "bob") match (&User-Name == "bob") +xlat_purify (&User-Name == %{md4: blah}) +match (&User-Name == 0x544924d05ec4481925ba3749a096a0a7) + +xlat_purify (&User-Name == (string) %{md4: blah}) +match (&User-Name == 0x544924d05ec4481925ba3749a096a0a7) + xlat_purify (&User-Name == "%{md4: blah}") -match (&User-Name == "0x544924d05ec4481925ba3749a096a0a7") +match (&User-Name == "TI$\320^\304H\031\%\2727I\240\226\240\247") xlat_purify 127.0.0.1 == 2130706433 match true @@ -430,8 +434,13 @@ match ("foo" == &User-Name) # This used to be expr, but expr isn't a builtin, so it failed... +# +# @todo - arguably this is a failed thing, we should get: +# +# ERROR: Failed casting 0x002ade8665c69219ca16bd108d92c8d5 to data type uint32: Invalid cast from octets to uint32. Source length 16 is greater than destination type size 4 +# xlat_purify "%{md4: 1 + 1}" < &NAS-Port -match ("0x002ade8665c69219ca16bd108d92c8d5" < &NAS-Port) +match (%(cast:uint32 "%{md4: 1 + 1}") < &NAS-Port) # # The string gets parsed as an IP address. @@ -464,7 +473,7 @@ match ((ipaddr)&PMIP6-Home-IPv4-HoA == &Framed-IP-Address) # but these are allowed xlat_purify &Tmp-uint64-0 == "%{module: foo}" -match ((ether)&Tmp-uint64-0 == "%{module: foo}") +match ((ether)&Tmp-uint64-0 == %(cast:string "%{module: foo}")) xlat_purify &Filter-Id == &Framed-IP-Address match ((ipaddr)&Filter-Id == &Framed-IP-Address) @@ -493,7 +502,7 @@ match (&User-Name[n] == "bob") #match &Foo-Bar xlat_purify &Acct-Input-Octets > "%{Session-Timeout}" -match (&Acct-Input-Octets > "%{Request[0].Session-Timeout}") +match (&Acct-Input-Octets > %(cast:string "%{Request[0].Session-Timeout}")) xlat_purify &Acct-Input-Octets > &Session-Timeout match (&Acct-Input-Octets > &Session-Timeout) @@ -732,4 +741,4 @@ match %{rcode:'handled'} count -match 300 +match 304 diff --git a/src/tests/unit/xlat/purify.txt b/src/tests/unit/xlat/purify.txt index fec1407871a..d3e8b8c497e 100644 --- a/src/tests/unit/xlat/purify.txt +++ b/src/tests/unit/xlat/purify.txt @@ -166,7 +166,7 @@ match (&Reply-Message == "foo") # Strings are single quoted # xlat_purify &Filter-Id == ("foo" + "bar") -match (&Filter-Id == 'foobar') +match (&Filter-Id == "foobar") xlat_purify !&User-Name match !&User-Name