File Handling functions
The file handling functions allow for a limited number of operations on files.
The filenames can be taken from tainted
sources, in which cases special characters such as ‘/’ and ‘$’ are escaped. Any special character is replaced with an underscore, followed by the hex value of the character. Valid UTF-8 characters are allowed.
For example, the tainted
string user@freeradius.org/..
will turn into the filename user@freeradius.org_2f..
. This operation renders the filename "safe" for operations on the local file system. It is not possible for tainted
data to create files, or to perform directory traversal attacks.
%file.escape(string)
This function returns an escaped or "safe" version of the input string.
In some cases, as when using %exec(…)
, it is impossible to determine which arguments are filenames, and which are simple strings. This function allows the server to safely pass in a filename to external programs.
The returned filename is guaranteed to be safe to use. Any portion of the filename which is taken from a "safe" source (i.e. configuration files, etc. controlled by an administrator) is used as-is. Any portion of the filename which is taken from an "unsafe" source (i.e. network apckets) is escaped. The result is that characters like /
in unsafe inputs cannot be used to perform directory traversal attacks.
%exec(…)
&filename = "${logdir}/" + %file.escape(%{User-Name})
%exec("/bin/rm", %{filename})
%file.exists(string)
This function returns true
if a file exists, or false
if the file does not exist.
if %file.exists("/var/log/radius.log") {
# do things...
}
%file.head(string)
This function returns the first line of the file. If the file does not exist, or if the line is more than 256 characters in length, it fails and nothing is returned.
string line
&line := %file.head("/var/log/radius.log")
%file.rm(string)
This function removes a file. If the file exists and could be removed, it returns true
. Otherwise if the file does not exist, or if the file could not be removed, it returns `false.
if (%file.size("/var/log/radius.log") > (((uint64)1) << 20)) {
%file.rm("/var/log/radius.log")
}
%file.size(string)
This function checks the size of a file.
if (%file.size("/var/log/radius.log") > (((uint64)1) << 20)) {
%log.info("The log file is getting large!")
}
%file.tail(string, [ uint32 ])
This function returns the last line of the file. If the file does not exist, or if the line is more than 256 characters in length, it fails and nothing is returned.
The function takes an optional second argument, which is the number of lines which should be returned. The maximum number of lines which will be returned is limited to 15.
string line
&line := %file.tail("/var/log/radius.log")
&line := %file.tail("/var/log/radius.log", 2)