]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tmpfiles: add ^ line modifier for loading file contents from specific credential
authorLennart Poettering <lennart@poettering.net>
Wed, 13 Jul 2022 12:55:45 +0000 (14:55 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 20 Jul 2022 21:53:22 +0000 (23:53 +0200)
man/tmpfiles.d.xml
src/tmpfiles/tmpfiles.c

index 79d0ff6bddf5657b1624ed98d8e8662a4dddb9db..15b5148622cbfe4994bdfa47dd7c3e4913fc4ce1 100644 (file)
@@ -160,9 +160,10 @@ L     /tmp/foobar -    -    -     -   /dev/null</programlisting>
     <refsect2>
       <title>Type</title>
 
-      <para>The type consists of a single letter and optionally a plus sign (<literal>+</literal>),
-      exclamation mark (<literal>!</literal>), minus sign (<literal>-</literal>), equals sign
-      (<literal>=</literal>) and/or tilde character (<literal>~</literal>).</para>
+      <para>The type consists of a single letter and optionally one or emore modifier characters: a plus sign
+      (<literal>+</literal>), exclamation mark (<literal>!</literal>), minus sign (<literal>-</literal>),
+      equals sign (<literal>=</literal>), tilde character (<literal>~</literal>) and/or caret
+      (<literal>^</literal>).</para>
 
       <para>The following line types are understood:</para>
 
@@ -493,9 +494,19 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
       <para>If the tilde character (<literal>~</literal>) is used, the argument (i.e. 6th) column is <ulink
       url="https://www.rfc-editor.org/rfc/rfc4648.html">Base64 decoded</ulink> before use. This modifier is
       only supported on line types that can write file contents, i.e. <varname>f</varname>,
-      <varname>f+</varname>, <varname>w</varname>. This is useful for writing arbitrary binary data
-      (including newlines and NUL bytes) to files. Note that if this switch is used, the argument is not
-      subject to specifier expansion, neither before nor after Base64 decoding.</para>
+      <varname>f+</varname>, <varname>w</varname>, <varname>+</varname>. This is useful for writing arbitrary
+      binary data (including newlines and NUL bytes) to files. Note that if this switch is used, the argument
+      is not subject to specifier expansion, neither before nor after Base64 decoding.</para>
+
+      <para>If the caret character (<literal>^</literal>) is used, the argument (i.e. 6th) column takes a
+      service credential name to read the argument data from. See <ulink
+      url="https://systemd.io/CREDENTIALS">System and Service Credentials</ulink> for details about the
+      credentials concept. This modifier is only supported on line types that can write file contents,
+      i.e. <varname>f</varname>, <varname>f+</varname>, <varname>w</varname>, <varname>w+</varname>. This is
+      useful for writing arbitrary files with contents sourced from elsewhere, including from VM or container
+      managers further up. If the specified credential is not set for the <command>systemd-tmpfiles</command>
+      service, the line is silently skipped. If <literal>^</literal> and <literal>~</literal> are combined
+      Base64 decoding is applied to the credential contents.</para>
 
       <para>Note that for all line types that result in creation of any kind of file node
       (i.e. <varname>f</varname>/<varname>F</varname>,
index e2451f1b9586e5997d6039b72a03c5b38ddf460d..07432a1e51ecc0d34378da1aa2f2bb918255a783 100644 (file)
@@ -2978,7 +2978,7 @@ static int parse_line(
         ItemArray *existing;
         OrderedHashmap *h;
         int r, pos;
-        bool append_or_force = false, boot = false, allow_failure = false, try_replace = false, unbase64 = false;
+        bool append_or_force = false, boot = false, allow_failure = false, try_replace = false, unbase64 = false, from_cred = false;
 
         assert(fname);
         assert(line >= 1);
@@ -3051,6 +3051,8 @@ static int parse_line(
                         try_replace = true;
                 else if (action[pos] == '~' && !unbase64)
                         unbase64 = true;
+                else if (action[pos] == '^' && !from_cred)
+                        from_cred = true;
                 else {
                         *invalid_config = true;
                         return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Unknown modifiers in command '%s'", action);
@@ -3240,13 +3242,8 @@ static int parse_line(
         if (!should_include_path(i.path))
                 return 0;
 
-        if (unbase64) {
-                if (i.argument) {
-                        r = unbase64mem(i.argument, SIZE_MAX, &i.binary_argument, &i.binary_argument_size);
-                        if (r < 0)
-                                return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to base64 decode specified argument '%s': %m", i.argument);
-                }
-        } else {
+        if (!unbase64) {
+                /* Do specifier expansion except if base64 mode is enabled */
                 r = specifier_expansion_from_arg(specifier_table, &i);
                 if (r == -ENXIO)
                         return log_unresolvable_specifier(fname, line);
@@ -3257,6 +3254,35 @@ static int parse_line(
                 }
         }
 
+        if (from_cred) {
+                if (!i.argument)
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Reading from credential requested, but no credential name specified.");
+                if (!credential_name_valid(i.argument))
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Credential name not valid: %s", i.argument);
+
+                r = read_credential(i.argument, &i.binary_argument, &i.binary_argument_size);
+                if (IN_SET(r, -ENXIO, -ENOENT)) {
+                        /* Silently skip over lines that have no credentials passed */
+                        log_syntax(NULL, LOG_INFO, fname, line, 0, "Credential '%s' not specified, skipping line.", i.argument);
+                        return 0;
+                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to read credential '%s': %m", i.argument);
+        }
+
+        /* If base64 decoding is requested, do so now */
+        if (unbase64 && item_binary_argument(&i)) {
+                _cleanup_free_ void *data = NULL;
+                size_t data_size = 0;
+
+                r = unbase64mem(item_binary_argument(&i), item_binary_argument_size(&i), &data, &data_size);
+                if (r < 0)
+                        return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to base64 decode specified argument '%s': %m", i.argument);
+
+                free_and_replace(i.binary_argument, data);
+                i.binary_argument_size = data_size;
+        }
+
         if (!empty_or_root(arg_root)) {
                 char *p;