tmpfiles: add ^ line modifier for loading file contents from specific credential

This commit is contained in:
Lennart Poettering 2022-07-13 14:55:45 +02:00
parent 1d77721f30
commit e52f6f6358
2 changed files with 51 additions and 14 deletions

View 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>,

View 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;