From: Alan T. DeKok Date: Mon, 6 Jun 2022 19:01:24 +0000 (-0400) Subject: Remove rlm_expr, and replace with %{expr:...} as a built-in X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e17c8b68792b4b7b302237c9b87e1feb59e75d7b;p=thirdparty%2Ffreeradius-server.git Remove rlm_expr, and replace with %{expr:...} as a built-in and update the docs and tests to match. --- diff --git a/debian/freeradius-config.postinst b/debian/freeradius-config.postinst index 1ab7ab30be1..51e221ddf27 100644 --- a/debian/freeradius-config.postinst +++ b/debian/freeradius-config.postinst @@ -35,7 +35,7 @@ case "$1" in # Create links for default modules for mod in always attr_filter cache_eap chap client \ delay detail detail.log dhcpv4 digest eap \ - eap_inner echo exec expr files linelog logintime \ + eap_inner echo exec files linelog logintime \ mschap ntlm_auth pap pam passwd radutmp \ soh sradutmp stats unix unpack utf8 ; do if test ! -h /etc/freeradius/mods-enabled/$mod && \ diff --git a/doc/antora/modules/raddb/pages/mods-available/expr.adoc b/doc/antora/modules/raddb/pages/mods-available/expr.adoc index b18f43dc53f..e253ea9efd6 100644 --- a/doc/antora/modules/raddb/pages/mods-available/expr.adoc +++ b/doc/antora/modules/raddb/pages/mods-available/expr.adoc @@ -1,69 +1,10 @@ - - - - = Expr Module -This module performs mathematical calculations: - -NOTE: This module is not called directly in any section, it is -invoked through the dynamic expansion of strings. - -e.g: - - Attribute-Name = "%{expr:2 + 3 + &NAS-Port}" - -It supports the following operators (in order of precedence). - -[options="header,autowidth"] -|=== -| Operator | Description -| & | binary AND -| \| | binary OR -| << | left shift -| >> | right shift -| + | addition -| - | subtraction -| * | multiply -| / | divide -| %% | remainder -| ^ | exponentiation -| (...) | sub-expression -|=== - -Operator precedence follows the normal rules. -Division by zero means that the entire expression is invalid. - -All calculations are done on signed 63-bit integers. -e.g. `int64_t`. This should be sufficient for all normal -purposes. - - * Hex numbers are supported: 0xabcdef - * It also allows unary negation: -1 - * And twos complement: ~1 - * Otherwise numbers are decimal. - -As with all string expansions, you can nest the expansions: - - %{expr: %{NAS-Port} + 1} - %{expr: %{sql:SELECT ... } + 1} - -Attribute references are supported for integer attributes. -e.g. `&NAS-Port`. The benefit of using attribute references -is that the expression is calculated directly on the -attribute. - - - -## Configuration Settings - -This module takes no configuration. - - - -== Default Configuration +The `expr` module has been remove, and replaced with an equivalent +`%{expr:...}` in the xref:xlat/builtin.adoc[built-in expansions]. The +parameters to the `%{expr:...}` is an +xref:reference:unlang/expression.adoc[Unlang expression]. -``` -expr { -} -``` +Most people should see no change in functionality. However, the new +expressions offer significantly more operators, and work on more data +types. diff --git a/doc/antora/modules/reference/nav.adoc b/doc/antora/modules/reference/nav.adoc index 4fc7873354b..feb51d0d7d4 100644 --- a/doc/antora/modules/reference/nav.adoc +++ b/doc/antora/modules/reference/nav.adoc @@ -33,6 +33,7 @@ *** xref:unlang/condition/index.adoc[Conditional Expressions] **** xref:unlang/condition/cmp.adoc[Comparisons] +**** xref:unlang/expressions.adoc[expressions] **** xref:unlang/condition/operands.adoc[Operands] **** xref:unlang/condition/return_code.adoc[The Return Code Operator] **** xref:unlang/condition/eq.adoc[The '==' Operator] @@ -55,7 +56,7 @@ *** xref:type/string/backticks.adoc[Backtick-quoted string] *** xref:type/string/unquoted.adoc[Unquoted Strings] -** xref:xlat/index.adoc[String Expansion] +** xref:xlat/index.adoc[Dynamic Expansion] *** xref:xlat/alternation.adoc[Alternation Syntax] *** xref:xlat/builtin.adoc[Built-in Expansions] *** xref:xlat/character.adoc[Single Letter Expansions] diff --git a/doc/antora/modules/reference/pages/index.adoc b/doc/antora/modules/reference/pages/index.adoc index 34aee7b6118..2d57e729035 100644 --- a/doc/antora/modules/reference/pages/index.adoc +++ b/doc/antora/modules/reference/pages/index.adoc @@ -4,4 +4,4 @@ We have a lot of stuff * xref:type/index.adoc[Data Types] in the server * xref:unlang/index.adoc[Unlang] syntax -* xref:xlat/index.adoc[String expansions] i.e. "xlat"s. +* xref:xlat/index.adoc[Dynamic expansions] i.e. "xlat"s. diff --git a/doc/antora/modules/reference/pages/type/index.adoc b/doc/antora/modules/reference/pages/type/index.adoc index 1eed668c0f4..c054a094e71 100644 --- a/doc/antora/modules/reference/pages/type/index.adoc +++ b/doc/antora/modules/reference/pages/type/index.adoc @@ -87,24 +87,24 @@ error cases where the parsing was incorrect. The solution is to resolve these ambiguities by allowing the values to be cast to a particular type. Casting a value to a type tells the interpreter how that value should be parsed. Casting is done by -prefixing a value with the type name, surrounded by angle brackets; -`<...>`. +prefixing a value with the type name, surrounded by brackets; +`(...)`. .Syntax ---- -<...>value +(...)value ---- We can add a cast to the above example, as follows: [source,unlang] ---- -if ("%{sql:SELECT ipaddress FROM table WHERE user=%{User-Name}}" == 192.0.2.1) } +if ("%{sql:SELECT ipaddress FROM table WHERE user=%{User-Name}}" == (ipaddr)192.0.2.1) } .... } ---- -In this example, we prefix the IP address with the string ``. +In this example, we prefix the IP address with the string `(ipaddr)`. The interpreter then knows that the value `192.0.2.` should be interpreted as the data type `ipaddr`, and not as the literal string `"192.0.2."`. @@ -113,5 +113,15 @@ For a full list of data types which can be used in a cast, please see the xref:unlang/type/all_types.adoc[list of data types] page, and the "Basic Type Types" section. +In most cases, the server can automatically determine what data type +to use. The cast syntax is used when either the data type is +ambiguous, or when data should be normalized prior to comparison, or +when a specific data type is required. + +=== Compatibility + +For compatibility with version 3, the `` syntax is also +supported. We recommend, however, that people use the new syntax. + // Copyright (C) 2021 Network RADIUS SAS. Licenced under CC-by-NC 4.0. // Development of this documentation was sponsored by Network RADIUS SAS. diff --git a/doc/antora/modules/reference/pages/type/string/double.adoc b/doc/antora/modules/reference/pages/type/string/double.adoc index bc12a5ec379..ad2775e9cc7 100644 --- a/doc/antora/modules/reference/pages/type/string/double.adoc +++ b/doc/antora/modules/reference/pages/type/string/double.adoc @@ -13,7 +13,7 @@ that the double quoted strings can be dynamically expanded. The syntax run-time expansion. The difference between the two methods is that the `${...}` form is expanded when the server loads the configuration files and is valid anywhere in the configuration files. The `%{...}` -xref:xlat/index.adoc[string expansion] form is valid only in conditional +xref:xlat/index.adoc[dynamic expansion] form is valid only in conditional expressions and attribute assignments. The output of the dynamic expansion can be interpreted as a string, diff --git a/doc/antora/modules/reference/pages/unlang/condition/cmp.adoc b/doc/antora/modules/reference/pages/unlang/condition/cmp.adoc index 8c9c2d438dd..bbefd0d4cd6 100644 --- a/doc/antora/modules/reference/pages/unlang/condition/cmp.adoc +++ b/doc/antora/modules/reference/pages/unlang/condition/cmp.adoc @@ -68,16 +68,16 @@ configuration files. .Syntax [source,unlang] ---- -lhs OP rhs +(cast)lhs OP rhs ---- -The `cast` text can be any one of the standard RADIUS dictionary data +The `cast` text can be any one of the supported data types, as with the following example: .Example [source,unlang] ---- -&Class == 127.0.0.1 +(ipaddr)&Class == 127.0.0.1 ---- In this example, the `Class` attribute is treated as if it was an IPv4 @@ -90,7 +90,7 @@ done in a type-safe manner, instead of performing a string comparison. .Example [source,unlang] ---- -`/bin/echo 00` == 0 +(integer)`/bin/echo 00` == 0 ---- In this example, the string output of the `echo` program is interpreted as an @@ -100,5 +100,10 @@ the comparison will match. If the comparison had been performed via string equality checks, then the comparison would fail, because the strings `00` and `0` are different. +=== Compatibility + +For compatibility with version 3, the `` syntax is also +supported. We recommend, however, that people use the new syntax. + // Copyright (C) 2021 Network RADIUS SAS. Licenced under CC-by-NC 4.0. // Development of this documentation was sponsored by Network RADIUS SAS. diff --git a/doc/antora/modules/reference/pages/unlang/condition/regex.adoc b/doc/antora/modules/reference/pages/unlang/condition/regex.adoc index bd6b3895a9b..0d0766b8da7 100644 --- a/doc/antora/modules/reference/pages/unlang/condition/regex.adoc +++ b/doc/antora/modules/reference/pages/unlang/condition/regex.adoc @@ -142,7 +142,7 @@ When the server starts any regular expressions comparisons it finds will be pre-compiled, and if support is available, JIT'd (converted to machine code) to ensure fast execution. -If a pattern contains a xref:xlat/index.adoc[string expansion], the pattern +If a pattern contains a xref:xlat/index.adoc[dynamic expansion], the pattern cannot be compiled on startup, and will be compiled at runtime each time the expression is evaluated. The server will also turn off JITing for runtime compiled expressions, as the overhead is greater than the time that would be @@ -159,11 +159,11 @@ if (&User-Name =~ /^@%{Tmp-String-0}$/) { ==== To ensure optimal performance you should limit the number of patterns -containing xref:xlat/index.adoc[string expansions], and if using PCRE, combine +containing xref:xlat/index.adoc[dynamic expansions], and if using PCRE, combine multiple expressions operating on the same subject into a single expression using the PCRE alternation '|' operator. -.Using multiple string expansions and the PCRE alternation operator +.Using multiple dynamic expansions and the PCRE alternation operator ==== [source,unlang] ---- diff --git a/doc/antora/modules/reference/pages/unlang/edit.adoc b/doc/antora/modules/reference/pages/unlang/edit.adoc index 1ecc87f1b71..bc260bbb1d6 100644 --- a/doc/antora/modules/reference/pages/unlang/edit.adoc +++ b/doc/antora/modules/reference/pages/unlang/edit.adoc @@ -84,11 +84,11 @@ operator which is permitted is `=`. The server *will not start* if any other operator is used._ If the __ is an "in-place" list, then all of the -xref:xlat/index.adoc[string expansions] are valid, just as are +xref:xlat/index.adoc[dynamic expansions] are valid, just as are xref:reference:unlang/attr.adoc[attribute references]. As a special case, the __ can also be a string, or a -xref:xlat/index.adoc[string expansion]. If so, the string is +xref:xlat/index.adoc[dynamic expansion]. If so, the string is interpreted as a set of attribute definitions, as if it was an "in-place" list. For example, `"Filter-Id = foo"` @@ -283,7 +283,7 @@ change the attribute _value_. The __ can be a reference to another attribute (e.g. `request.Filter-Id`). If the field is a double-quoted string, -it undergoes xref:xlat/index.adoc[string expansion], and the resulting +it undergoes xref:xlat/index.adoc[dynamic expansion], and the resulting value is processed as described above. In most cases, the edit operations "do the right thing". For example, diff --git a/doc/antora/modules/reference/pages/unlang/expression.adoc b/doc/antora/modules/reference/pages/unlang/expression.adoc new file mode 100644 index 00000000000..d99ffa6fc3d --- /dev/null +++ b/doc/antora/modules/reference/pages/unlang/expression.adoc @@ -0,0 +1,110 @@ += Expressions + +Expressions can be used inside of xref:xlat/index.adoc[dynamic expansions], or inside of xref:condition/index.adoc[conditions]. + +The following operators are supported (in order of precedence). + +[options="header,autowidth"] +|=== +| Operator | Description +| & | binary AND +| \| | binary OR +| << | left shift +| >> | right shift +| + | addition +| - | subtraction +| * | multiplication +| / | division +| %% | remainder TODO +| ^ | xor +| (...) | sub-expression +|=== + +The following unary operators are also supported: + +[options="header,autowidth"] +|=== +| Operator | Description +| - | unary minus +| ~ | unary complement +| ! | unary not +|=== + +Operator precedence follows the normal rules. +Division by zero means that the entire expression is invalid. + +== Conditions + +xref:condition/index.adoc[Conditions] in expressions are also +supported. For example: + +[source,unlang] +---- +&NAS-Port = 5 + (&User-Name == "bob") +---- + +This expression will return `6` if the users name is `bob`, and `5` otherwise. + +Similarly, expressions are also supported in conditions. There is no +need to use `%{expr:...}` in conditions, as was needed in earlier +versions of the server. + +== Data Types + +The new expression parser accepts significantly more data types than +the old `rlm_expr` module. The `rlm_expr` module assumed that all +inputs were signed 64-bit integers. Any attempt to use other data +types resulted in an error. + +For example, the `+` operator can be applied to `string` and `octet` +data types. (And incidentally, `-` is the inverse of `+`!) + +[source,unlang] +---- +&Reply-Message := "foo" + "bar" +---- + +Will result in `&Reply-Message == "foobar"`. + +The suffix can then be "subtracted" off, with: + +[source,unlang] +---- +&Reply-Message -= "bar" +---- + +Will result in `&Reply-Message == "foo"` !. + +Other data types will generally yield results which make sense. For +example: + +* adding an integer to an `ipv4prefix` type will result in an `ipv4addr` data type, +* `&` and `|` will work on `string` and `octets` data types, +* Using `&` with `ipv4addr` data types an `uint32` will result in an `ipv4prefix` data type, +* `ipv4addr`s can be subtracted, and will return a number, +* `date`s can be subtracted, and will return a `time_delta`, +* operations on integers are upgraded to the next largest integer size when necessary, +* the logical operators `&&` and `||` return the value which caused them to succeed, e.g. `&Foo := (&User-Password || "help")` will return the contents of `&User-Name` if it exists, otherwise it will return the string `help`. + +In most cases, the data types are derived from the attribute +dictionaries. However, it is sometimes necessary to force the fields +(or output) of an expression to be parsed in a particular manner. + +== Casts + +xref:type/index.adoc[Type casting] is supported via the `(type)` +syntax. The old-style syntax of `` is accepted, but is +deprecated. + +[source,unlang] +---- +&NAS-Port-Id = (uint32) "%{sql: SELECT...}" + 4 +---- + +== Errors + +Mathematical operations which cause overflow, underflow, or division +by zero will return a `null` result. This result will propagate +through any calculations, so that an expression which relies on `null` +will also return `null`. + diff --git a/doc/antora/modules/reference/pages/unlang/index.adoc b/doc/antora/modules/reference/pages/unlang/index.adoc index 4e21d1ca811..525438056f7 100644 --- a/doc/antora/modules/reference/pages/unlang/index.adoc +++ b/doc/antora/modules/reference/pages/unlang/index.adoc @@ -85,12 +85,12 @@ update reply { } ---- -== String Expansions +== Dynamic Expansions -xref:xlat/index.adoc[String expansion] Using `%{...}` to perform dynamic -string expansions. (also known as xref:xlat/index.adoc[xlat]) +xref:xlat/index.adoc[Dynamic expansion] Using `%{...}` to perform dynamic +expansions. (also known as xref:xlat/index.adoc[xlat]) -String expansions are usually performed in order to get additional +Dynamic expansions are usually performed in order to get additional information which is not immediately available to the policy. This information can be taken from almost any source, including other attributes, databases, and scripts. diff --git a/doc/antora/modules/reference/pages/xlat/builtin.adoc b/doc/antora/modules/reference/pages/xlat/builtin.adoc index d7aa20cf879..28677d368cb 100644 --- a/doc/antora/modules/reference/pages/xlat/builtin.adoc +++ b/doc/antora/modules/reference/pages/xlat/builtin.adoc @@ -947,6 +947,70 @@ Debug : pcre2 : 10.33 (2019-04-16) - retrieved at build tim .... ==== +=== +%(eval:)+ + +Evaluates the string as an expansion, and returns the result. The main difference between using this expansion and just using `%{...}` is that the string being evaluated can be dynamically changed. + +.Return: _data_ + +.Example: + +[source,unlang] +---- +if (&User-Name == "bob") { + update request { + &Tmp-String-0 := "&User-Name" + } +} else { + update request { + &Tmp-String-0 := "not bob!" + } +} + +update reply { + &Reply-Message := "%{eval:&Tmp-String-0}" +} + +---- + +.Output when `&User-Name == bob` + +``` +bob +``` + +.Output when `&User-Name == not bob` + +``` +not bob! +``` + + +=== +%(expr:)+ + +Evaluates the string as an xref:reference:unlang/expression.adoc[Unlang expression], and returns the result. Please see the +xref:reference:unlang/expression.adoc[Unlang expression] page for full +documentation on expressions. + +.Return: _data_ + +.Example: + +[source,unlang] +---- +update reply + &Tmp-String-0 := "%{expr: 1 + 2}" + } +} + +---- + +.Output + +``` +3 +``` + === +%(nexttime: