summaryrefslogtreecommitdiffstats
path: root/doc/antora/modules/unlang/pages/xlat/builtin.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'doc/antora/modules/unlang/pages/xlat/builtin.adoc')
-rw-r--r--doc/antora/modules/unlang/pages/xlat/builtin.adoc891
1 files changed, 891 insertions, 0 deletions
diff --git a/doc/antora/modules/unlang/pages/xlat/builtin.adoc b/doc/antora/modules/unlang/pages/xlat/builtin.adoc
new file mode 100644
index 0000000..f236a57
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/xlat/builtin.adoc
@@ -0,0 +1,891 @@
+= Built-In Expansions
+
+In addition to storing attribute references, the server has a number
+of built-in expansions. These expansions act largely as functions
+which operate on inputs, and produce an output.
+
+
+
+== Attribute Manipulation
+
+=== %{length: ... }
+
+The `length` expansion returns the size of the input as an integer.
+When the input is a string, then the output is identical to the
+`strlen` expansion.
+
+When the input is an attribute reference, the output is the size of
+the attributes data as encoded "on the wire".
+
+.Return: _size_
+
+.Determining the length of fixed and variable length attributes
+====
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Caipirinha"
+ &Framed-IP-Address := 192.0.2.1
+}
+
+update reply {
+ &Reply-Message := "The length of %{control:Tmp-String-0} is %{length:&control:Tmp-String-0}"
+ &Reply-Message += "The length of %{control:Framed-IP-Address} is %{length:&control:Framed-IP-Address}"
+}
+----
+
+.Output
+....
+The length of Caipirinha is 10
+The length of 192.168.0.2 is 4
+....
+====
+
+`length` is built in to the server core.
+
+
+
+=== %{integer:<&ref>}
+
+Print the value of the attribute an integer.
+
+In normal operation, `integer` attributes are printed using the name
+given by a `VALUE` statement in a dictionary. Similarly, date
+attributes are printed as dates, i.e., "January 1 2010.
+
+The `integer` expansion applies only to attributes which can be
+converted to an integer. For all other inputs, it returns `0`.
+
+A common usage is to find the difference between two dates.
+
+For example, if a request contains `Service-Type = Login-User`, the
+expansion of `%{integer:&Service-Type}` will yield `1`, which is the
+value associated with the `Login-User` name. Using
+`%{integer:&Event-Timestamp}` will return the event timestamp as an
+unsigned 32-bit number.
+
+.Return: _string_
+
+.Determining the integer value of an enumerated attribute
+====
+[source,unlang]
+----
+update {
+ &control:Service-Type := Login-User
+}
+update reply {
+ &Reply-Message := "The value of Service-Type is %{integer:&control:Service-Type}"
+}
+----
+
+.Output
+
+```
+The value of Service-Type is 1
+```
+====
+
+`integer` is built in to the server core.
+
+
+
+=== %{rand:<number>}
+
+Generate random number from `0` to `<number>-1`.
+
+.Return: _uint64_
+
+.Generating a random number between 0 and 511
+====
+[source,unlang]
+----
+update reply {
+ &Reply-Message := "The random number is %{rand:512}"
+}
+----
+
+.Output
+
+```
+The random number is 347
+```
+====
+
+`rand` is provided by the `rlm_expr` module.
+
+
+
+=== %{tag:<attribute ref>}
+
+CAUTION: This expansion is deprecated and will likely be removed.
+
+Returns a list of tags for any attributes found using ``<attribute ref>``.
+
+.Return: _int8_
+
+.Determining the tag value of the second instance of the `radius.Tunnel-Server-Endpoint` attribute
+====
+[source,unlang]
+----
+update request {
+ &Tunnel-Server-Endpoint := '192.0.1.1'
+ &Tunnel-Server-Endpoint:1 := '192.0.5.2'
+ &Tunnel-Server-Endpoint:1 += '192.0.3.8'
+ &Tunnel-Server-Endpoint:2 := '192.0.2.1'
+ &Tunnel-Server-Endpoint:2 += '192.0.3.4'
+}
+
+update reply {
+ &Reply-Message := "The tag value of the second instance of Tunnel-Server-Enpoint is %{request:Tunnel-Server-Endpoint[1]}"
+}
+----
+
+.Output
+
+```
+The tag value of the second instance of Tunnel-Server-Enpoint is 192.0.5.2
+```
+====
+
+`tag` is built in to the server core.
+
+
+
+=== %{string:<data>}
+
+Convert input to a string (if possible). For _octets_ type attributes, this
+means interpreting the data as a UTF8 string, and inserting octal escape
+sequences where appropriate.
+
+For other types, this means printing the value in its _presentation_ format,
+i.e. dotted quads for IPv4 addresses, link:https://en.wikipedia.org/wiki/ISO_8601[ISO 8601]
+time for date types, enumeration values for attributes such as `radius.Service-Type` etc.
+
+.Return: _string_
+
+.String interpolation using the raw octets value of Tmp-Octets-0, and the stringified version
+====
+[source,unlang]
+----
+update control {
+ &Tmp-Octets-0 := 0x7465737431
+}
+update reply {
+ &Reply-Message := "The string value of %{control:Tmp-Octets-0} is %{string:%{control:Tmp-Octets-0}}"
+}
+----
+====
+
+.Output
+
+```
+The string value of 0x7465737431 is test1
+```
+
+`string` is built in to the server core.
+
+
+
+== Server Manipulation
+
+=== %{config:<key>}
+
+Refers to a variable in the configuration file. See the documentation
+on configuration file references.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+"Server installed in %{config:prefix}"
+"Module rlm_exec.shell_escape = %{config:modules.exec.shell_escape}"
+----
+
+.Output
+
+```
+Server installed in /opt/freeradius
+Module rlm_exec.shell_escape = yes
+```
+
+`config` is built in to the server core.
+
+
+
+=== %{client:<key>}
+
+Refers to a variable that was defined in the client section for the
+current client. See the sections `client { ... }` in `clients.conf`.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+"The client ipaddr is %{client:ipaddr}"
+----
+
+.Output
+
+```
+The client ipaddr is 192.168.5.9
+```
+
+`client` is built in to the server core.
+
+
+
+=== %{debug:<level>}
+
+Dynamically change the debug level to something high, recording the old level.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+authorize {
+ if (&request:User-Name == "bob") {
+ "%{debug:4}"
+ } else {
+ "%{debug:0}"
+ }
+ ...
+}
+----
+
+.Output (_extra informations only for that condition_)
+
+```
+...
+(0) authorize {
+(0) if (&request:User-Name == "bob") {
+(0) EXPAND %{debug:4}
+(0) --> 2
+(0) } # if (&request:User-Name == "bob") (...)
+(0) filter_username {
+(0) if (&State) {
+(0) ...
+(0) }
+...
+```
+
+`debug` is built in to the server core.
+
+
+
+=== %{debug_attr:<list:[index]>}
+
+Print to debug output all instances of current attribute, or all attributes in a list.
+expands to a zero-length string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+authorize {
+ if (&request:User-Name == "bob") {
+ "%{debug_attr:request[*]}"
+ }
+ ...
+}
+----
+
+.Output
+
+```
+...
+(0) authorize {
+(0) if (&request:User-Name == "bob") {
+(0) Attributes matching "request[*]"
+(0) &request:User-Name = bob
+(0) &request:User-Password = hello
+(0) &request:NAS-IP-Address = 127.0.1.1
+(0) &request:NAS-Port = 1
+(0) &request:Message-Authenticator = 0x9210ee447a9f4c522f5300eb8fc15e14
+(0) EXPAND %{debug_attr:request[*]}
+(0) } # if (&request:User-Name == "bob") (...)
+...
+```
+
+`debug_attr` is built in to the server core.
+
+
+
+== String manipulation
+
+=== %{lpad:<&ref> <val> <char>}
+
+Left-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "123"
+}
+update reply {
+ &Reply-Message := "Maximum should be %{lpad:&control:Tmp-String-0 11 0}"
+}
+----
+
+.Output
+
+```
+Maximum should be 00000000123
+```
+
+`lpad` is provided by the `rlm_expr` module.
+
+
+
+=== %{rpad:<&ref> <val> <char>}
+
+Right-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "123"
+}
+update reply {
+ &Reply-Message := "Maximum should be %{rpad:&control:Tmp-String-0 11 0}"
+}
+----
+
+.Output
+
+```
+Maximum should be 12300000000
+```
+
+`rpad` is provided by the `rlm_expr` module.
+
+
+
+=== %{pairs:<&list:[*]>}
+
+Serialize attributes as comma-delimited string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "This is a string"
+ &control:Tmp-String-0 += "This is another one"
+}
+
+update reply {
+ &Reply-Message := "Serialize output: %{pairs:&control[*]}"
+}
+----
+
+.Output
+
+```
+Serialize output: Tmp-String-0 = \"This is a string\"Tmp-String-0 = \"This is another one\"
+```
+
+`pairs` is provided by the `rlm_expr` module.
+
+
+
+=== %{randstr: ...}
+
+Get random string built from character classes.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update reply {
+ &Reply-Message := "The random string output is %{randstr:aaaaaaaa}"
+}
+----
+
+.Output
+
+```
+The random string output is 4Uq0gPyG
+```
+
+`randstr` is provided by the `rlm_expr` module.
+
+
+
+=== %{strlen: ... }
+
+Length of given string.
+
+.Return: _integer_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Caipirinha"
+}
+update reply {
+ &Reply-Message := "The length of %{control:Tmp-String-0} is %{strlen:&control:Tmp-String-0}"
+}
+----
+
+.Output
+
+```
+The length of Caipirinha is 21
+```
+
+`strlen` is built in to the server core.
+
+
+
+=== %{tolower: ... }
+
+Dynamically expands the string and returns the lowercase version of
+it. This definition is only available in version 2.1.10 and later.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "CAIPIRINHA"
+}
+update reply {
+ &Reply-Message := "tolower of %{control:Tmp-String-0} is %{tolower:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+tolower of CAIPIRINHA is caipirinha
+```
+
+`tolower` is provided by the `rlm_expr` module.
+
+
+
+=== %{toupper: ... }
+
+Dynamically expands the string and returns the uppercase version of
+it. This definition is only available in version 2.1.10 and later.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "caipirinha"
+}
+update reply {
+ &Reply-Message := "toupper of %{control:Tmp-String-0} is %{toupper:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+toupper of caipirinha is CAIPIRINHA
+```
+
+`toupper` is provided by the `rlm_expr` module.
+
+
+
+== String Conversion
+
+=== %{base64: ... }
+
+Encode a string using Base64.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Caipirinha"
+}
+update reply {
+ &Reply-Message := "The base64 of %{control:Tmp-String-0} is %{base64:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The base64 of foo is Q2FpcGlyaW5oYQ==
+```
+
+`base64` is provided by the `rlm_expr` module.
+
+
+
+=== %{base64tohex: ... }
+
+Decode a base64 string (e.g. previously encoded using `base64`) to
+hex.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Q2FpcGlyaW5oYQ=="
+}
+update reply {
+ &Reply-Message := "The base64tohex of %{control:Tmp-String-0} is %{base64tohex:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The base64decode of Q2FpcGlyaW5oYQ== is 436169706972696e6861
+```
+
+`base64tohex` is provided by the `rlm_expr` module.
+
+
+
+=== %{hex: ... }
+
+Convert to hex.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "12345"
+}
+update reply {
+ &Reply-Message := "The value of %{control:Tmp-String-0} in hex is %{hex:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The value of 12345 in hex is 3132333435
+```
+
+`hex` is built in to the server core.
+
+
+
+=== %{urlquote: ... }
+
+Quote URL special characters.
+
+.Return: _string_.
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "http://example.org/"
+}
+update reply {
+ &Reply-Message += "The urlquote of %{control:Tmp-String-0} is %{urlquote:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The urlquote of http://example.org/ is http%3A%2F%2Fexample.org%2F
+```
+
+`urlquote` is provided by the `rlm_expr` module.
+
+
+
+=== %{urlunquote: ... }
+
+Unquote URL special characters.
+
+.Return: _string_.
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "http%%3A%%2F%%2Fexample.org%%2F" # Attention for the double %.
+}
+update reply {
+ &Reply-Message += "The urlunquote of %{control:Tmp-String-0} is %{urlunquote:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The urlunquote of http%3A%2F%2Fexample.org%2F is http://example.org/
+```
+
+`urlunquote` is provided by the `rlm_expr` module.
+
+
+
+== Hashing and Encryption
+
+=== %{hmacmd5:<shared_key> <string>}
+
+Generate `HMAC-MD5` of string.
+
+.Return: _octal_
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "mykey"
+ &control:Tmp-String-1 := "Caipirinha"
+}
+update {
+ &control:Tmp-Octets-0 := "%{hmacmd5:%{control:Tmp-String-0} %{control:Tmp-String-1}}"
+}
+
+update reply {
+ &Reply-Message := "The HMAC-MD5 of %{control:Tmp-String-1} in octets is %{control:Tmp-Octets-0}"
+ &Reply-Message += "The HMAC-MD5 of %{control:Tmp-String-1} in hex is %{hex:control:Tmp-Octets-0}"
+}
+----
+
+.Output
+
+```
+The HMAC-MD5 of Caipirinha in octets is \317}\264@K\216\371\035\304\367\202,c\376\341\203
+The HMAC-MD5 of Caipirinha in hex is 636f6e74726f6c3a546d702d4f63746574732d30
+```
+
+`hmacmd5` is provided by the `rlm_expr` module.
+
+
+
+=== %{hmacsha1:<shared_key> <string>}
+
+Generate `HMAC-SHA1` of string.
+
+.Return: _octal_
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "mykey"
+ &control:Tmp-String-1 := "Caipirinha"
+}
+update {
+ &control:Tmp-Octets-0 := "%{hmacsha1:%{control:Tmp-String-0} %{control:Tmp-String-1}}"
+}
+
+update reply {
+ &Reply-Message := "The HMAC-SHA1 of %{control:Tmp-String-1} in octets is %{control:Tmp-Octets-0}"
+ &Reply-Message += "The HMAC-SHA1 of %{control:Tmp-String-1} in hex is %{hex:control:Tmp-Octets-0}"
+}
+----
+
+.Output
+
+```
+The HMAC-SHA1 of Caipirinha in octets is \311\007\212\234j\355\207\035\225\256\372ʙ>R\"\341\351O)
+The HMAC-SHA1 of Caipirinha in hex is 636f6e74726f6c3a546d702d4f63746574732d30
+```
+
+`hmacsha1` is provided by the `rlm_expr` module.
+
+
+
+=== %{md5: ... }
+
+Dynamically expands the string and performs an MD5 hash on it. The
+result is binary data.
+
+.Return: _binary data_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Caipirinha"
+}
+update reply {
+ &Reply-Message := "md5 of %{control:Tmp-String-0} is octal=%{md5:%{control:Tmp-String-0}}"
+ &Reply-Message := "md5 of %{control:Tmp-String-0} is hex=%{hex:%{md5:%{control:Tmp-String-0}}}"
+}
+----
+
+.Output
+
+```
+md5 of Caipirinha is octal=\024\204\013md||\230\243\3472\3703\330n\251
+md5 of Caipirinha is hex=14840b6d647c7c98a3e732f833d86ea9
+```
+
+`md5` is provided by the `rlm_expr` module.
+
+
+
+== Miscellaneous Expansions
+
+=== +%{0}+..+%{32}+
+
+`%{0}` expands to the portion of the subject that matched the last regular
+expression evaluated. `%{1}`..`%{32}` expand to the contents of any capture
+groups in the pattern.
+
+Every time a regular expression is evaluated, whether it matches or not,
+the numbered capture group values will be cleared.
+
+
+
+=== +%{regex:<named capture group>}+
+
+Return named subcapture value from the last regular expression evaluated.
+
+Results of named capture groups are available using the `%{regex:<named capture
+group>}` expansion. They will also be accessible using the numbered expansions
+described xref:builtin.adoc#_0_32[above].
+
+Every time a regular expression is evaluated, whether it matches or not,
+the named capture group values will be cleared.
+
+[NOTE]
+====
+This expansion is only available if the server is built with libpcre or libpcre2.
+Use the output of `radiusd -Xxv` to determine which regular expression library in use.
+
+....
+...
+Debug : regex-pcre : no
+Debug : regex-pcre2 : yes
+Debug : regex-posix : no
+Debug : regex-posix-extended : no
+Debug : regex-binsafe : yes
+...
+Debug : pcre2 : 10.33 (2019-04-16) - retrieved at build time
+....
+====
+
+`regex` is built in to the server core.
+
+
+
+=== +%{nexttime:<time>}+
+
+Calculate number of seconds until next n hour(`s`), day(`s`), week(`s`), year(`s`).
+
+.Return: _string_
+
+.Example:
+
+With the current time at 16:18, `%{nexttime:1h}` will expand to `2520`.
+
+[source,unlang]
+----
+update reply {
+ &Reply-Message := "You should wait for %{nexttime:1h}s"
+}
+----
+
+.Output
+
+```
+You should wait for 2520s
+```
+
+`nexttime` is provided by the `rlm_expr` module.
+
+
+
+=== +%{Packet-Type}+
+
+The packet type (`Access-Request`, etc.)
+
+
+
+=== +%{Packet-Src-IP-Address} and %{Packet-Src-IPv6-Address}+
+
+The source IPv4 or IPv6 address of the packet. See also the expansions
+`%{client:ipaddr}` and `%{client:ipv6addr}`. The two expansions
+should be identical, unless `%{client:ipaddr}` contains a DNS hostname.
+
+
+
+=== +%{Packet-Dst-IP-Address} and %{Packet-Dst-IPv6-Address}+
+
+The destination IPv4 or IPv6 address of the packet. See also the
+expansions `%{listen:ipaddr}` and `%{listen:ipv6addr}`. If the socket
+is listening on a "wildcard" address, then these two expansions will be
+different, as follows: the `%{listen:ipaddr}` will be the wildcard
+address and `%{Packet-DST-IP-Address}` will be the unicast address to
+which the packet was sent.
+
+
+
+=== +%{Packet-Src-Port} and %{Packet-Dst-Port}+
+
+The source/destination ports associated with the packet.
+
+.Return: _string_.
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "user@example.com"
+}
+
+if (&control:Tmp-String-0 =~ /^(?<login>(.*))@(?<domain>(.*))$/) {
+ update reply {
+ &Reply-Message := "The %{control:Tmp-String-0} { login=%{regex:login}, domain=%{regex:domain} }"
+ }
+}
+----
+
+.Output
+
+```
+The user@example.com { login=user, domain=example.com }
+```
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.