From: Alan T. DeKok Date: Wed, 18 Oct 2023 20:36:05 +0000 (-0400) Subject: it helps to document this, too X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=430e891a32729efa6556720da41c8290a3dfea27;p=thirdparty%2Ffreeradius-server.git it helps to document this, too We would really like to be able to do %file.escape("foo/bar/" + %{User-Name}) but if that's an expression, then we get the entire string tainted, and thge "/" in the first part of the string are escaped. or maybe %exec("/bin/rm", "foo/bar" + %file.escape(%{User-Name})) but we can't (yet) pass expressions as function arguments. --- diff --git a/doc/antora/modules/reference/pages/xlat/file.adoc b/doc/antora/modules/reference/pages/xlat/file.adoc index 23471256cdb..403417fd7e5 100644 --- a/doc/antora/modules/reference/pages/xlat/file.adoc +++ b/doc/antora/modules/reference/pages/xlat/file.adoc @@ -6,6 +6,27 @@ The filenames can be taken from `tainted` sources, in which cases special charac 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_) + +.Return: _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 administator) 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. + +.Safely pass a filename to `%exec(...)` +==== +[source,unlang] +---- +&filename = "${logdir}/" + %file.escape(%{User-Name}) + +%exec("/bin/rm", %{filename}) +---- +==== + + == %file.exists(_string_) .Return: _bool_ diff --git a/src/tests/xlat/file.txt b/src/tests/xlat/file.txt index 4a7e33802aa..a548820d0fa 100644 --- a/src/tests/xlat/file.txt +++ b/src/tests/xlat/file.txt @@ -33,3 +33,12 @@ match yes xlat_expr %file.exists('src/tests/xlat/file/no-such-file') match no + +xlat_expr "foo/bar/" + %file.escape(%taint('..baz')) +match foo/bar/_x2e_x2ebaz + +# +# Can't do expressions as function arguments +# +xlat_expr %file.escape('foo/bar' + "/baz") +match ERROR offset 34 'Unexpected text after argument 1'