]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add %file.cat() xlat
authorNick Porter <nick@portercomputing.co.uk>
Fri, 20 Jun 2025 17:23:47 +0000 (18:23 +0100)
committerNick Porter <nick@portercomputing.co.uk>
Fri, 20 Jun 2025 17:23:47 +0000 (18:23 +0100)
doc/antora/modules/reference/pages/xlat/file/cat.adoc [new file with mode: 0644]
doc/antora/modules/reference/pages/xlat/file/index.adoc
src/lib/unlang/xlat_builtin.c

diff --git a/doc/antora/modules/reference/pages/xlat/file/cat.adoc b/doc/antora/modules/reference/pages/xlat/file/cat.adoc
new file mode 100644 (file)
index 0000000..6a823e6
--- /dev/null
@@ -0,0 +1,22 @@
+= Cat
+
+The `cat` function returns the contents of a file.
+
+The function takes a second argument, which is the maximum number of bytes which should be returned.
+
+[#syntax]
+== Syntax
+
+`%file.cat(_string_, [ _uint32_ ])`
+
+.Return: _octets_
+
+.Returning the contents of a file
+====
+[source,unlang]
+----
+octets crl
+
+crl := %file.cat('/etc/ssl/certs/ca.crl')
+----
+====
index 3c8def9971557afbad2ecdbb242634450cb6ffd0..7279b16e8b1da7d49928a9ad7cb234cd42e2b4a2 100644 (file)
@@ -10,6 +10,7 @@ For example, the "unsafe" string `user@freeradius.org/..` will turn into the fil
 [options="headers, autowidth]
 |===
 | *Function*                                           | *Description*
+| xref:xlat/file/cat.adoc[cat]                         | Returns the contents of a file.
 | xref:reference:xlat/file/escape.adoc[escape]         | Returns an escaped or safe version of the input string.
 | xref:xlat/file/exists.adoc[exists]                   | Checks to see if a file exists on the filesystem.
 | xref:xlat/file/head.adoc[head]                       | Returns the first line of the file.
index db31d56d5e4cffe2f51ce9f592683074ed713b4c..0bfe45065a6a2f58204ebc9004232a069bc6238f 100644 (file)
@@ -710,6 +710,60 @@ done:
        return XLAT_ACTION_DONE;
 }
 
+static xlat_arg_parser_t const xlat_func_file_cat_args[] = {
+       { .required = true,  .concat = true, .type = FR_TYPE_STRING,
+         .func = filename_xlat_escape, .safe_for = FR_FILENAME_SAFE_FOR, .always_escape = true },
+       { .required = true, .type = FR_TYPE_UINT32, .single = true },
+       XLAT_ARG_PARSER_TERMINATOR
+};
+
+static xlat_action_t xlat_func_file_cat(TALLOC_CTX *ctx, fr_dcursor_t *out,
+                                       UNUSED xlat_ctx_t const *xctx,
+                                       request_t *request, fr_value_box_list_t *args)
+{
+       fr_value_box_t  *dst, *vb, *max_size;
+       char const      *filename;
+       ssize_t         len;
+       int             fd;
+       struct stat     buf;
+       uint8_t         *buffer;
+
+       XLAT_ARGS(args, &vb, &max_size);
+       fr_assert(vb->type == FR_TYPE_STRING);
+       filename = vb->vb_strvalue;
+
+       if (stat(filename, &buf) < 0) {
+               RPERROR("Failed checking file %s - %s", filename, fr_syserror(errno));
+               return XLAT_ACTION_FAIL;
+       }
+
+       if (buf.st_size > max_size->vb_uint32) {
+               RPERROR("File larger than specified maximum (%"PRIu64" vs %d)", buf.st_size, max_size->vb_uint32);
+               return XLAT_ACTION_FAIL;
+       }
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               RPERROR("Failed opening file %s - %s", filename, fr_syserror(errno));
+               return XLAT_ACTION_FAIL;
+       }
+
+       MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_OCTETS, false));
+       fr_value_box_mem_alloc(dst, &buffer, dst, NULL, buf.st_size, true);
+
+       len = read(fd, buffer, buf.st_size);
+       if (len < 0) {
+               RPERROR("Failed reading file %s - %s", filename, fr_syserror(errno));
+               talloc_free(dst);
+               close(fd);
+               return XLAT_ACTION_FAIL;
+       }
+       close(fd);
+
+       fr_dcursor_append(out, dst);
+
+       return XLAT_ACTION_DONE;
+}
 
 static xlat_action_t xlat_func_file_rm(TALLOC_CTX *ctx, fr_dcursor_t *out,
                                           UNUSED xlat_ctx_t const *xctx,
@@ -4313,6 +4367,7 @@ do { \
        XLAT_REGISTER_ARGS("file.rm", xlat_func_file_rm, FR_TYPE_BOOL, xlat_func_file_name_args);
        XLAT_REGISTER_ARGS("file.size", xlat_func_file_size, FR_TYPE_UINT64, xlat_func_file_name_args);
        XLAT_REGISTER_ARGS("file.tail", xlat_func_file_tail, FR_TYPE_STRING, xlat_func_file_name_count_args);
+       XLAT_REGISTER_ARGS("file.cat", xlat_func_file_cat, FR_TYPE_OCTETS, xlat_func_file_cat_args);
 
        XLAT_REGISTER_ARGS("immutable", xlat_func_immutable_attr, FR_TYPE_NULL, xlat_pair_cursor_args);
        XLAT_NEW("pairs.immutable");