]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move more functions to their own files
authorAlan T. DeKok <aland@freeradius.org>
Mon, 16 Oct 2023 13:04:08 +0000 (09:04 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 16 Oct 2023 13:04:08 +0000 (09:04 -0400)
doc/antora/modules/reference/nav.adoc
doc/antora/modules/reference/pages/xlat/builtin.adoc
doc/antora/modules/reference/pages/xlat/conversion.adoc [new file with mode: 0644]
doc/antora/modules/reference/pages/xlat/hash.adoc [new file with mode: 0644]
doc/antora/modules/reference/pages/xlat/interpreter.adoc [new file with mode: 0644]
doc/antora/modules/reference/pages/xlat/string.adoc [new file with mode: 0644]

index d8c39c95e64e1756642cfe55329a867272d1402e..3ae10bcd91ac0f1ced3663c5f580167ff941cdfb 100644 (file)
 
 ** xref:xlat/index.adoc[Dynamic Expansion]
 *** xref:xlat/alternation.adoc[Alternation Syntax]
+*** xref:xlat/conversion.adoc[Data Conversion]
 *** xref:xlat/deprecated.adoc[Deprecated Functions]
 *** xref:xlat/file.adoc[File handling]
 *** xref:xlat/function.adoc[Function Syntax]
+*** xref:xlat/hash.adoc[Hashing]
+*** xref:xlat/interpreter.adoc[Interpreter State and Debugging]
 *** xref:xlat/log.adoc[Logging Functions]
 *** xref:xlat/protocol.adoc[Protocol Encoding and Decoding]
+*** xref:xlat/string.adoc[String Handling]
 *** xref:xlat/builtin.adoc[Built-in Expansions]
 *** xref:xlat/character.adoc[Single Letter Expansions]
 *** xref:xlat/attribute.adoc[Attribute References]
index a22a0d1f2ce617a975ca9e90bddff2757c5a0e6b..8ea9512c80235a17877e29a6be8caee0dd0d52c3 100644 (file)
@@ -57,35 +57,6 @@ The random number is 347
 ```
 ====
 
-== Interpreter State
-
-The state of the interpreter can be queried via the
-`%interpeter(<name>)` expansion.  The individual expansions are
-documented below.
-
-Each expansion given here can be prefixed with one or more dot (`.`)
-characters.  These dots allow the expansion to refer to the current
-request via a `name`, or the parent request via `.name`.  If there is
-no parent, the expansion returns the string `<underflow>`.
-
-=== %interpeter('module')
-
-The current module being executed.  If the expansions is done in an
-`unlang` statement and outside of any module, it returns the name of
-the previous module which was executed.
-
-=== %interpeter('processing_stage')
-
-Which section of a virtual server is processing the request.
-
-=== %interpeter('rcode')
-
-The current interpreter return code, e.g. `handle`, or `ok`, etc.
-
-=== %interpeter('server')
-
-The name of the virtual server which is running the request.
-
 == Server Configuration
 
 === %config(<key>)
@@ -110,575 +81,6 @@ Server installed in /opt/freeradius
 Module rlm_exec.shell_escape = yes
 ```
 
-=== %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
-```
-
-=== %debug(<level>)
-
-Dynamically change the debug level to something high, recording the old level.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-recv Access-Request {
-    if (&request.User-Name == "bob") {
-        "%debug(4)"
-    } else {
-        "%debug(0)"
-    }
-    ...
-}
-----
-
-.Output (_extra informations only for that condition_)
-
-```
-...
-(0)  recv Access-Request {
-(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_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]
-----
-recv Access-Request {
-    if (&request.User-Name == "bob") {
-        "%debug_attr(request[*])"
-    }
-    ...
-}
-----
-
-.Output
-
-```
-...
-(0)  recv Access-Request {
-(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") (...)
-...
-```
-
-=== %interpreter(<state>)
-
-Get information about the interpreter state.
-
-[options="header,autowidth"]
-|===
-| State      | Description
-| `name`     | Name of the instruction.
-| `type`     | Unlang type.
-| `depth`    | How deep the current stack is.
-| `line`     | Line number of the current section.
-| `filename` | Filename of the current section.
-|===
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-"Failure in test at line %interpreter(...filename):%interpreter(...line)"
-----
-
-.Output
-
-```
-Failure in test at line /path/raddb/sites-enaled/default:231
-```
-
-== String manipulation
-
-=== %concat(<&ref:[idx]>, <delim>)
-
-Used to join two or more attributes, separated by an optional delimiter.
-
-.Return: _string_
-
-In most cases, `%concat(...)` is only useful inside of a dynamically
-expanded string.  If you need to concatenate strings together in a policy, just use `+`.
-
-.Example
-
-[source,unlang]
-----
-&control += {
-       &Tmp-String-0 = "aaa"
-       &Tmp-String-0 = "bb"
-       &Tmp-String-0 = "c"
-}
-
-&reply += {
-    &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ', ')"
-    &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ',')"
-}
-----
-
-.Output
-
-```
-aaa, bb, c
-aaa,bb,c
-```
-
-.Using "+"
-[source,unlang]
-----
-string foo
-
-&foo += { "a", "c", "c", "d" } # abcd
-
-&foo += &control.Tmp-String-0[*]
-----
-
-
-=== %explode(<&ref>, <delim>)
-
-Split an string into multiple new strings based on a delimiter.
-
-This expansion is the opposite of `%concat( ... )`.
-
-.Return: _the number exploded list of strings_.
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "bob.toba@domain.com"
-
-&control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
-
-&reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
-----
-
-.Output
-
-```
-Welcome bob.toba
-```
-
-=== %lpad(<string>, <val>, <char>)
-
-Left-pad a string.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "123"
-
-&reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
-----
-
-.Output
-
-```
-Maximum should be 00000000123
-```
-
-=== %rpad(<string>, <val>, <char>)
-
-Right-pad a string.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "123"
-
-&reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
-----
-
-.Output
-
-```
-Maximum should be 12300000000
-```
-
-=== %pairs(<list>.[*])
-
-Serialize attributes as comma-delimited string.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := { "This is a string", "This is another one" }
-&reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
-----
-
-.Output
-
-```
-Serialize output: Tmp-String-0 = "\"This is a string\", Tmp-String-0 = \"This is another one\""
-```
-
-=== %randstr( ...)
-
-Get random string built from character classes.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&reply.Reply-Message := "The random string output is %randstr(aaaaaaaa}"
-----
-
-.Output
-
-```
-The random string output is 4Uq0gPyG
-```
-
-=== %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]
-----
-&control.Tmp-String-0 := "CAIPIRINHA"
-&reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
-----
-
-.Output
-
-```
-tolower of CAIPIRINHA is caipirinha
-```
-
-=== %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]
-----
-&control.Tmp-String-0 := "caipirinha"
-&reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
-----
-
-.Output
-
-```
-toupper of caipirinha is CAIPIRINHA
-```
-
-== Data Conversion
-
-=== %base64.encode( ... )
-
-Encode a string using Base64.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "Caipirinha"
-&reply.Reply-Message := "The base64 of %{control.Tmp-String-0} is %base64.encode(%{control.Tmp-String-0})"
-----
-
-.Output
-
-```
-The base64 of foo is Q2FpcGlyaW5oYQ==
-```
-
-=== %base64.decode( ... )
-
-Decode a string previously encoded using Base64.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "Q2FpcGlyaW5oYQ=="
-&reply.Reply-Message := "The base64.decode of %{control.Tmp-String-0} is %base64.decode(%{control.Tmp-String-0})"
-----
-
-.Output
-
-```
-The base64.decode of Q2FpcGlyaW5oYQ== is Caipirinha
-```
-
-=== %bin( ... )
-
-Convert string to binary.
-
-.Return: _octal_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "10"
-&reply.Reply-Message := "The %{control.Tmp-String-0} in binary is %bin(%{control.Tmp-String-0})"
-----
-
-.Output
-
-```
-The 10 in binary is \020
-```
-
-=== %hex( ... )
-
-Convert to hex.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "12345"
-&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
-```
-
-=== %urlquote( ... )
-
-Quote URL special characters.
-
-.Return: _string_.
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "http://example.org/"
-&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
-```
-
-=== %urlunquote( ... )
-
-Unquote URL special characters.
-
-.Return: _string_.
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "http%%3A%%2F%%2Fexample.org%%2F" # Attention for the double %.
-&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/
-```
-
-== Hashing and Encryption
-
-=== %hmacmd5(<shared_key> <string>)
-
-Generate `HMAC-MD5` of string.
-
-.Return: _octal_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "mykey"
-&control.Tmp-String-1 := "Caipirinha"
-&reply.control.Tmp-Octets-0 := "%hmacmd5(%{control.Tmp-String-0} %{control.Tmp-String-1})"
-
-&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
-```
-
-=== %hmacsha1(<shared_key>, <string>)
-
-Generate `HMAC-SHA1` of string.
-
-.Return: _octal_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "mykey"
-&control.Tmp-String-1 := "Caipirinha"
-&control.Tmp-Octets-0 := "%hmacsha1(%{control.Tmp-String-0}, %{control.Tmp-String-1})"
-
-&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
-```
-
-=== %md5( ... )
-
-Dynamically expands the string and performs an MD5 hash on it. The
-result is binary data.
-
-.Return: _binary data_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "Caipirinha"
-&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
-```
-
-=== Other Hashing Functions
-
-The following hashes are supported for all versions of OpenSSL.
-
-* `%md2( ... }`
-* `%md4( ... }`
-* `%md5( ... }`
-* `%sha1( ... }`
-* `%sha224( ... }`
-* `%sha256( ... }`
-* `%sha384( ... }`
-* `%sha512( ... }`
-
-The following hashes are supported for when OpenSSL 1.1.1 or greater
-is installed.  This version adds support for the `sha3` and `blake`
-families of digest functions.
-
-* `%blake2s_256( ... )`
-* `%blake2b_512( ... )`
-* `%sha2_224( ... )`
-* `%sha2_256( ... )`
-* `%sha2_384( ... )`
-* `%sha2_512( ... )`
-* `%sha3_224( ... )`
-* `%sha3_256( ... )`
-* `%sha3_384( ... )`
-* `%sha3_512( ... )`
-
-.Return: _octal_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "Caipirinha"
-&reply += {
-    &Reply-Message = "The md5 of %{control.Tmp-String-0} in octal is %md5(%{control.Tmp-String-0}}"
-    &Reply-Message = "The md5 of %{control.Tmp-String-0} in hex is %hex(%md5(%{control.Tmp-String-0}}}"
-}
-----
-
-.Output
-
-```
-The md5 of Caipirinha in octal is \024\204\013md||\230\243\3472\3703\330n\251
-The md5 of Caipirinha in hex is 14840b6d647c7c98a3e732f833d86ea9
-```
-
 == Miscellaneous Expansions
 
 === %{0}+..+%{32}
diff --git a/doc/antora/modules/reference/pages/xlat/conversion.adoc b/doc/antora/modules/reference/pages/xlat/conversion.adoc
new file mode 100644 (file)
index 0000000..c837460
--- /dev/null
@@ -0,0 +1,130 @@
+= Data Conversion
+
+The following functions perform conversion to/from different types of data encoding.
+
+== %base64.encode( ... )
+
+Encode a string using Base64.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "Caipirinha"
+&reply.Reply-Message := "The base64 of %{control.Tmp-String-0} is %base64.encode(%{control.Tmp-String-0})"
+----
+
+.Output
+
+```
+The base64 of foo is Q2FpcGlyaW5oYQ==
+```
+
+== %base64.decode( ... )
+
+Decode a string previously encoded using Base64.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "Q2FpcGlyaW5oYQ=="
+&reply.Reply-Message := "The base64.decode of %{control.Tmp-String-0} is %base64.decode(%{control.Tmp-String-0})"
+----
+
+.Output
+
+```
+The base64.decode of Q2FpcGlyaW5oYQ== is Caipirinha
+```
+
+== %bin( ... )
+
+Convert string to binary.
+
+.Return: _octal_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "10"
+&reply.Reply-Message := "The %{control.Tmp-String-0} in binary is %bin(%{control.Tmp-String-0})"
+----
+
+.Output
+
+```
+The 10 in binary is \020
+```
+
+== %hex( ... )
+
+Convert to hex.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "12345"
+&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
+```
+
+== %urlquote( ... )
+
+Quote URL special characters.
+
+.Return: _string_.
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "http://example.org/"
+&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
+```
+
+== %urlunquote( ... )
+
+Unquote URL special characters.
+
+.Return: _string_.
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "http%%3A%%2F%%2Fexample.org%%2F" # Attention for the double %.
+&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/
+```
+
+// Copyright (C) 2023 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
diff --git a/doc/antora/modules/reference/pages/xlat/hash.adoc b/doc/antora/modules/reference/pages/xlat/hash.adoc
new file mode 100644 (file)
index 0000000..7f260e4
--- /dev/null
@@ -0,0 +1,135 @@
+= Hashing
+
+The following functions perform hashing.
+
+Note that the server supports insecure hashing methods such as MD5 and
+SHA1.  These functions are here for historical compatibility and
+completeness.
+
+== %hmacmd5(<shared_key>, <string>)
+
+Generate `HMAC-MD5` of string.
+
+.Return: _octal_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "mykey"
+&control.Tmp-String-1 := "Caipirinha"
+&reply.control.Tmp-Octets-0 := "%hmacmd5(%{control.Tmp-String-0} %{control.Tmp-String-1})"
+
+&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
+```
+
+== %hmacsha1(<shared_key>, <string>)
+
+Generate `HMAC-SHA1` of string.
+
+.Return: _octal_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "mykey"
+&control.Tmp-String-1 := "Caipirinha"
+&control.Tmp-Octets-0 := "%hmacsha1(%{control.Tmp-String-0}, %{control.Tmp-String-1})"
+
+&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
+```
+
+== %md5( ... )
+
+Dynamically expands the string and performs an MD5 hash on it. The
+result is binary data.
+
+.Return: _binary data_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "Caipirinha"
+&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
+```
+
+=== Other Hashing Functions
+
+The following hashes are supported for all versions of OpenSSL.
+
+* `%md2( ... }`
+* `%md4( ... }`
+* `%md5( ... }`
+* `%sha1( ... }`
+* `%sha224( ... }`
+* `%sha256( ... }`
+* `%sha384( ... }`
+* `%sha512( ... }`
+
+The following hashes are supported for when OpenSSL 1.1.1 or greater
+is installed.  This version adds support for the `sha3` and `blake`
+families of digest functions.
+
+* `%blake2s_256( ... )`
+* `%blake2b_512( ... )`
+* `%sha2_224( ... )`
+* `%sha2_256( ... )`
+* `%sha2_384( ... )`
+* `%sha2_512( ... )`
+* `%sha3_224( ... )`
+* `%sha3_256( ... )`
+* `%sha3_384( ... )`
+* `%sha3_512( ... )`
+
+.Return: _octal_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "Caipirinha"
+&reply += {
+    &Reply-Message = "The md5 of %{control.Tmp-String-0} in octal is %md5(%{control.Tmp-String-0}}"
+    &Reply-Message = "The md5 of %{control.Tmp-String-0} in hex is %hex(%md5(%{control.Tmp-String-0}}}"
+}
+----
+
+.Output
+
+```
+The md5 of Caipirinha in octal is \024\204\013md||\230\243\3472\3703\330n\251
+The md5 of Caipirinha in hex is 14840b6d647c7c98a3e732f833d86ea9
+```
+
diff --git a/doc/antora/modules/reference/pages/xlat/interpreter.adoc b/doc/antora/modules/reference/pages/xlat/interpreter.adoc
new file mode 100644 (file)
index 0000000..7acdaa7
--- /dev/null
@@ -0,0 +1,147 @@
+= Interpreter
+
+The following functions allow inspection and/or manipulation of the `unlang` interpreter as it is running.
+
+== Debug Functions
+
+The following functions allow changing the debug level, or printing out specific lists of attributes.
+
+=== %debug(<level>)
+
+Dynamically change the debug level to something high, recording the old level.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+recv Access-Request {
+    if (&request.User-Name == "bob") {
+        "%debug(4)"
+    } else {
+        "%debug(0)"
+    }
+    ...
+}
+----
+
+.Output (_extra informations only for that condition_)
+
+```
+...
+(0)  recv Access-Request {
+(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_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]
+----
+recv Access-Request {
+    if (&request.User-Name == "bob") {
+        "%debug_attr(request[*])"
+    }
+    ...
+}
+----
+
+.Output
+
+```
+...
+(0)  recv Access-Request {
+(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") (...)
+...
+```
+
+== State
+
+The state of the interpreter can be queried via the
+`%interpeter(<name>)` expansion.  The individual expansions are
+documented below.
+
+Each expansion given here can be prefixed with one or more dot (`.`)
+characters.  These dots allow the expansion to refer to the current
+request via a `name`, or the parent request via `.name`.  If there is
+no parent, the expansion returns the string `<underflow>`.
+
+For example `'filename'` is the name of the current file being
+executed, while `'..filename'` is the filename of the parent request.
+
+== %interpeter('filename')
+
+Which filename is currently being executed.
+
+== %interpeter('line')
+
+The line number in the current file being executed.
+
+== %interpeter('processing_stage')
+
+Which section of a virtual server is processing the request.
+
+
+== %interpeter('module')
+
+The current module being executed.  If the expansions is done in an
+`unlang` statement and outside of any module, it returns the name of
+the previous module which was executed.
+
+== %interpeter('processing_stage')
+
+Which section of a virtual server is processing the request.
+
+== %interpeter('rcode')
+
+The current interpreter return code, e.g. `handle`, or `ok`, etc.
+
+== %interpeter('server')
+
+The name of the virtual server which is running the request.
+
+=== %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
+```
+
+// Copyright (C) 2023 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
diff --git a/doc/antora/modules/reference/pages/xlat/string.adoc b/doc/antora/modules/reference/pages/xlat/string.adoc
new file mode 100644 (file)
index 0000000..1abf515
--- /dev/null
@@ -0,0 +1,194 @@
+= String manipulation
+
+The following functions perform string manipulation.
+
+== %concat(<&ref:[idx]>, <delim>)
+
+Used to join two or more attributes, separated by an optional delimiter.
+
+.Return: _string_
+
+In most cases, `%concat(...)` is only useful inside of a dynamically
+expanded string.  If you need to concatenate strings together in a policy, just use `+`.
+
+.Example
+
+[source,unlang]
+----
+&control += {
+       &Tmp-String-0 = "aaa"
+       &Tmp-String-0 = "bb"
+       &Tmp-String-0 = "c"
+}
+
+&reply += {
+    &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ', ')"
+    &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ',')"
+}
+----
+
+.Output
+
+```
+aaa, bb, c
+aaa,bb,c
+```
+
+.Using "+"
+[source,unlang]
+----
+string foo
+
+&foo += { "a", "c", "c", "d" } # abcd
+
+&foo += &control.Tmp-String-0[*]
+----
+
+== %explode(<&ref>, <delim>)
+
+Split an string into multiple new strings based on a delimiter.
+
+This expansion is the opposite of `%concat( ... )`.
+
+.Return: _the number exploded list of strings_.
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "bob.toba@domain.com"
+
+&control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
+
+&reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
+----
+
+.Output
+
+```
+Welcome bob.toba
+```
+
+== %lpad(<string>, <val>, <char>)
+
+Left-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "123"
+
+&reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
+----
+
+.Output
+
+```
+Maximum should be 00000000123
+```
+
+== %rpad(<string>, <val>, <char>)
+
+Right-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "123"
+
+&reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
+----
+
+.Output
+
+```
+Maximum should be 12300000000
+```
+
+== %pairs(<list>.[*])
+
+Serialize attributes as comma-delimited string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := { "This is a string", "This is another one" }
+&reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
+----
+
+.Output
+
+```
+Serialize output: Tmp-String-0 = "\"This is a string\", Tmp-String-0 = \"This is another one\""
+```
+
+== %randstr( ...)
+
+Get random string built from character classes.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&reply.Reply-Message := "The random string output is %randstr(aaaaaaaa}"
+----
+
+.Output
+
+```
+The random string output is 4Uq0gPyG
+```
+
+== %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]
+----
+&control.Tmp-String-0 := "CAIPIRINHA"
+&reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
+----
+
+.Output
+
+```
+tolower of CAIPIRINHA is caipirinha
+```
+
+== %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]
+----
+&control.Tmp-String-0 := "caipirinha"
+&reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
+----
+
+.Output
+
+```
+toupper of caipirinha is CAIPIRINHA
+```
+