1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

core: Add support for renaming credentials with ImportCredential=

This allows for "per-instance" credentials for units. The use case
is best explained with an example. Currently all our getty units
have the following stanzas in their unit file:

"""
ImportCredential=agetty.*
ImportCredential=login.*
"""

This means that setting agetty.autologin=root as a system credential
will make every instance of our all our getty units autologin as the
root user. This prevents us from doing autologin on /dev/hvc0 while
still requiring manual login on all other ttys.

To solve the issue, we introduce support for renaming credentials with
ImportCredential=. This will allow us to add the following to e.g.
serial-getty@.service:

"""
ImportCredential=tty.serial.%I.agetty.*:agetty.
ImportCredential=tty.serial.%I.login.*:login.
"""

which for serial-getty@hvc0.service will make the service manager read
all credentials of the form "tty.serial.hvc0.agetty.xxx" and pass them
to the service in the form "agetty.xxx" (same goes for login). We can
apply the same to each of the getty units to allow setting agetty and
login credentials for individual ttys instead of globally.
This commit is contained in:
Daan De Meyer 2024-07-30 16:16:26 +02:00
parent 3de13e6148
commit 831f208783
12 changed files with 341 additions and 47 deletions

View File

@ -3187,6 +3187,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as ImportCredential = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) ImportCredentialEx = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as SupplementaryGroups = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PAMName = '...';
@ -3800,6 +3802,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property ImportCredential is not documented!-->
<!--property ImportCredentialEx is not documented!-->
<!--property SupplementaryGroups is not documented!-->
<!--property PAMName is not documented!-->
@ -4488,6 +4492,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="ImportCredential"/>
<variablelist class="dbus-property" generated="True" extra-ref="ImportCredentialEx"/>
<variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
<variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@ -5312,6 +5318,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as ImportCredential = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) ImportCredentialEx = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as SupplementaryGroups = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PAMName = '...';
@ -5939,6 +5947,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<!--property ImportCredential is not documented!-->
<!--property ImportCredentialEx is not documented!-->
<!--property SupplementaryGroups is not documented!-->
<!--property PAMName is not documented!-->
@ -6603,6 +6613,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<variablelist class="dbus-property" generated="True" extra-ref="ImportCredential"/>
<variablelist class="dbus-property" generated="True" extra-ref="ImportCredentialEx"/>
<variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
<variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@ -7291,6 +7303,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as ImportCredential = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) ImportCredentialEx = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as SupplementaryGroups = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PAMName = '...';
@ -7844,6 +7858,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<!--property ImportCredential is not documented!-->
<!--property ImportCredentialEx is not documented!-->
<!--property SupplementaryGroups is not documented!-->
<!--property PAMName is not documented!-->
@ -8420,6 +8436,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<variablelist class="dbus-property" generated="True" extra-ref="ImportCredential"/>
<variablelist class="dbus-property" generated="True" extra-ref="ImportCredentialEx"/>
<variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
<variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@ -9231,6 +9249,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as ImportCredential = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) ImportCredentialEx = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as SupplementaryGroups = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PAMName = '...';
@ -9770,6 +9790,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<!--property ImportCredential is not documented!-->
<!--property ImportCredentialEx is not documented!-->
<!--property SupplementaryGroups is not documented!-->
<!--property PAMName is not documented!-->
@ -10332,6 +10354,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<variablelist class="dbus-property" generated="True" extra-ref="ImportCredential"/>
<variablelist class="dbus-property" generated="True" extra-ref="ImportCredentialEx"/>
<variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
<variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@ -12099,8 +12123,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>ExecMainHandoffTimestampMonotonic</varname>, and
<varname>ExecMainHandoffTimestamp</varname> were added in version 256.</para>
<para><varname>StatusBusError</varname>,
<varname>StatusVarlinkError</varname>, and
<varname>PrivateTmpEx</varname> were added in version 257.</para>
<varname>StatusVarlinkError</varname>,
<varname>PrivateTmpEx</varname>, and
<varname>ImportCredentialEx</varname> were added in version 257.</para>
</refsect2>
<refsect2>
<title>Socket Unit Objects</title>
@ -12137,7 +12162,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>EffectiveTasksMax</varname>,
<varname>MemoryZSwapWriteback</varname>, and
<varname>PassFileDescriptorsToExec</varname> were added in version 256.</para>
<para><varname>PrivateTmpEx</varname> was added in version 257.</para>
<para><varname>PrivateTmpEx</varname>, and
<varname>ImportCredentialEx</varname> were added in version 257.</para>
</refsect2>
<refsect2>
<title>Mount Unit Objects</title>
@ -12171,7 +12197,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>EffectiveMemoryMax</varname>,
<varname>EffectiveTasksMax</varname>, and
<varname>MemoryZSwapWriteback</varname> were added in version 256.</para>
<para><varname>PrivateTmpEx</varname> was added in version 257.</para>
<para><varname>PrivateTmpEx</varname>, and
<varname>ImportCredentialEx</varname> were added in version 257.</para>
</refsect2>
<refsect2>
<title>Swap Unit Objects</title>
@ -12205,7 +12232,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>EffectiveMemoryMax</varname>,
<varname>EffectiveTasksMax</varname>, and
<varname>MemoryZSwapWriteback</varname> were added in version 256.</para>
<para><varname>PrivateTmpEx</varname> was added in version 257.</para>
<para><varname>PrivateTmpEx</varname>, and
<varname>ImportCredentialEx</varname> were added in version 257.</para>
</refsect2>
<refsect2>
<title>Slice Unit Objects</title>

View File

@ -3520,6 +3520,18 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
<literal>[]</literal> wildcards are not permitted, nor are <literal>*</literal> wildcards anywhere
except at the end of the glob expression.</para>
<para>Optionally, the credential name or glob may be followed by a colon followed by a rename pattern.
If specified, all credentials matching the credential name or glob are renamed according to the given
pattern. For example, if <literal>ImportCredential=my.original.cred:my.renamed.cred</literal> is
specified, the service manager will read the <literal>my.original.cred</literal> credential and make
it available as the <literal>my.renamed.cred</literal> credential to the service. Similarly, if
<literal>ImportCredential=my.original.*:my.renamed.</literal> is specified, the service manager will
read all credentials starting with <literal>my.original.</literal> and make them available as
<literal>my.renamed.xxx</literal> to the service.</para>
<para>If <varname>ImportCredential=</varname> is specified multiple times and multiple credentials
end up with the same name after renaming, the first one is kept and later ones are dropped.</para>.
<para>When multiple credentials of the same name are found, credentials found by
<varname>LoadCredential=</varname> and <varname>LoadCredentialEncrypted=</varname> take priority over
credentials found by <varname>ImportCredential=</varname>.</para>

View File

@ -688,6 +688,66 @@ static int property_get_load_credential(
return sd_bus_message_close_container(reply);
}
static int property_get_import_credential(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
ExecContext *c = ASSERT_PTR(userdata);
ExecImportCredential *ic;
int r;
assert(bus);
assert(property);
assert(reply);
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return r;
ORDERED_SET_FOREACH(ic, c->import_credentials) {
r = sd_bus_message_append(reply, "s", ic->glob);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int property_get_import_credential_ex(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
ExecContext *c = ASSERT_PTR(userdata);
ExecImportCredential *ic;
int r;
assert(bus);
assert(property);
assert(reply);
r = sd_bus_message_open_container(reply, 'a', "(ss)");
if (r < 0)
return r;
ORDERED_SET_FOREACH(ic, c->import_credentials) {
r = sd_bus_message_append(reply, "(ss)", ic->glob, ic->rename);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int property_get_root_hash(
sd_bus *bus,
const char *path,
@ -1068,7 +1128,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("SetCredentialEncrypted", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LoadCredential", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LoadCredentialEncrypted", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ImportCredential", "as", bus_property_get_string_set, offsetof(ExecContext, import_credentials), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ImportCredential", "as", property_get_import_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ImportCredentialEx", "a(ss)", property_get_import_credential_ex, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
@ -2142,33 +2203,41 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (streq(name, "ImportCredential")) {
bool isempty = true;
} else if (STR_IN_SET(name, "ImportCredential", "ImportCredentialEx")) {
bool empty = true, ex = streq(name, "ImportCredentialEx");
r = sd_bus_message_enter_container(message, 'a', "s");
r = sd_bus_message_enter_container(message, 'a', ex ? "(ss)" : "s");
if (r < 0)
return r;
for (;;) {
const char *s;
const char *glob, *rename = NULL;
r = sd_bus_message_read(message, "s", &s);
if (ex)
r = sd_bus_message_read(message, "(ss)", &glob, &rename);
else
r = sd_bus_message_read(message, "s", &glob);
if (r < 0)
return r;
if (r == 0)
break;
if (!credential_glob_valid(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential name or glob is invalid: %s", s);
if (!credential_glob_valid(glob))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential name or glob is invalid: %s", glob);
isempty = false;
if (rename && !credential_name_valid(rename))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential name is invalid: %s", rename);
empty = false;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = set_put_strdup(&c->import_credentials, s);
r = exec_context_put_import_credential(c, glob, rename);
if (r < 0)
return r;
(void) unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, s);
(void) unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
"ImportCredential=%s%s%s",
glob, rename ? ":" : "", strempty(rename));
}
}
@ -2176,8 +2245,8 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) {
c->import_credentials = set_free_free(c->import_credentials);
if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
c->import_credentials = ordered_set_free(c->import_credentials);
(void) unit_write_settingf(u, flags, name, "%s=", name);
}

View File

@ -38,6 +38,37 @@ ExecLoadCredential* exec_load_credential_free(ExecLoadCredential *lc) {
return mfree(lc);
}
ExecImportCredential* exec_import_credential_free(ExecImportCredential *ic) {
if (!ic)
return NULL;
free(ic->glob);
free(ic->rename);
return mfree(ic);
}
static void exec_import_credential_hash_func(const ExecImportCredential *ic, struct siphash *state) {
assert(ic);
assert(state);
siphash24_compress_string(ic->glob, state);
if (ic->rename)
siphash24_compress_string(ic->rename, state);
}
static int exec_import_credential_compare_func(const ExecImportCredential *a, const ExecImportCredential *b) {
int r;
assert(a);
assert(b);
r = strcmp(a->glob, b->glob);
if (r != 0)
return r;
return strcmp_ptr(a->rename, b->rename);
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
exec_set_credential_hash_ops,
char, string_hash_func, string_compare_func,
@ -48,6 +79,13 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
char, string_hash_func, string_compare_func,
ExecLoadCredential, exec_load_credential_free);
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
exec_import_credential_hash_ops,
ExecImportCredential,
exec_import_credential_hash_func,
exec_import_credential_compare_func,
exec_import_credential_free);
int exec_context_put_load_credential(ExecContext *c, const char *id, const char *path, bool encrypted) {
ExecLoadCredential *old;
int r;
@ -140,6 +178,39 @@ int exec_context_put_set_credential(
return 0;
}
int exec_context_put_import_credential(ExecContext *c, const char *glob, const char *rename) {
_cleanup_(exec_import_credential_freep) ExecImportCredential *ic = NULL;
int r;
assert(c);
rename = empty_to_null(rename);
ic = new(ExecImportCredential, 1);
if (!ic)
return -ENOMEM;
*ic = (ExecImportCredential) {
.glob = strdup(glob),
.rename = rename ? strdup(rename) : NULL,
};
if (!ic->glob || (rename && !ic->rename))
return -ENOMEM;
if (ordered_set_contains(c->import_credentials, ic))
return 0;
r = ordered_set_ensure_put(&c->import_credentials, &exec_import_credential_hash_ops, ic);
if (r < 0) {
assert(r != -EEXIST);
return r;
}
TAKE_PTR(ic);
return 0;
}
bool exec_params_need_credentials(const ExecParameters *p) {
assert(p);
@ -151,7 +222,7 @@ bool exec_context_has_credentials(const ExecContext *c) {
return !hashmap_isempty(c->set_credentials) ||
!hashmap_isempty(c->load_credentials) ||
!set_isempty(c->import_credentials);
!ordered_set_isempty(c->import_credentials);
}
bool exec_context_has_encrypted_credentials(const ExecContext *c) {
@ -381,7 +452,7 @@ static int maybe_decrypt_and_write_credential(
}
static int load_credential_glob(
const char *path,
const ExecImportCredential *ic,
bool encrypted,
char * const *search_path,
ReadFullFileFlags flags,
@ -393,7 +464,7 @@ static int load_credential_glob(
int r;
assert(path);
assert(ic);
assert(search_path);
assert(write_dfd >= 0);
assert(left);
@ -402,7 +473,7 @@ static int load_credential_glob(
_cleanup_globfree_ glob_t pglob = {};
_cleanup_free_ char *j = NULL;
j = path_join(*d, path);
j = path_join(*d, ic->glob);
if (!j)
return -ENOMEM;
@ -421,6 +492,16 @@ static int load_credential_glob(
if (r < 0)
return log_debug_errno(r, "Failed to extract filename from '%s': %m", *p);
if (ic->rename) {
_cleanup_free_ char *renamed = NULL;
renamed = strjoin(ic->rename, fn + strlen(ic->glob) - !!endswith(ic->glob, "*"));
if (!renamed)
return log_oom_debug();
free_and_replace(fn, renamed);
}
if (faccessat(write_dfd, fn, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) {
log_debug("Skipping credential with duplicated ID %s at %s", fn, *p);
continue;
@ -661,7 +742,7 @@ static int acquire_credentials(
uint64_t left = CREDENTIALS_TOTAL_SIZE_MAX;
_cleanup_close_ int dfd = -EBADF;
const char *ic;
ExecImportCredential *ic;
ExecLoadCredential *lc;
ExecSetCredential *sc;
int r;
@ -736,7 +817,7 @@ static int acquire_credentials(
/* Next, look for system credentials and credentials in the credentials store. Note that these do not
* override any credentials found earlier. */
SET_FOREACH(ic, context->import_credentials) {
ORDERED_SET_FOREACH(ic, context->import_credentials) {
_cleanup_free_ char **search_path = NULL;
search_path = credential_search_path(params, CREDENTIAL_SEARCH_PATH_TRUSTED);

View File

@ -25,12 +25,20 @@ typedef struct ExecSetCredential {
size_t size;
} ExecSetCredential;
typedef struct ExecImportCredential {
char *glob;
char *rename;
} ExecImportCredential;
ExecSetCredential* exec_set_credential_free(ExecSetCredential *sc);
DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSetCredential*, exec_set_credential_free);
ExecLoadCredential* exec_load_credential_free(ExecLoadCredential *lc);
DEFINE_TRIVIAL_CLEANUP_FUNC(ExecLoadCredential*, exec_load_credential_free);
ExecImportCredential* exec_import_credential_free(ExecImportCredential *lc);
DEFINE_TRIVIAL_CLEANUP_FUNC(ExecImportCredential*, exec_import_credential_free);
int exec_context_put_load_credential(ExecContext *c, const char *id, const char *path, bool encrypted);
int exec_context_put_set_credential(
ExecContext *c,
@ -38,6 +46,7 @@ int exec_context_put_set_credential(
void *data_consume,
size_t size,
bool encrypted);
int exec_context_put_import_credential(ExecContext *c, const char *glob, const char *rename);
bool exec_params_need_credentials(const ExecParameters *p);

View File

@ -2554,13 +2554,14 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
return r;
}
if (!set_isempty(c->import_credentials)) {
char *ic;
SET_FOREACH(ic, c->import_credentials) {
r = serialize_item(f, "exec-context-import-credentials", ic);
if (r < 0)
return r;
}
ExecImportCredential *ic;
ORDERED_SET_FOREACH(ic, c->import_credentials) {
r = serialize_item_format(f, "exec-context-import-credentials", "%s%s%s",
ic->glob,
ic->rename ? " " : "",
strempty(ic->rename));
if (r < 0)
return r;
}
r = serialize_image_policy(f, "exec-context-root-image-policy", c->root_image_policy);
@ -3688,11 +3689,15 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
if (r < 0)
return r;
} else if ((val = startswith(l, "exec-context-import-credentials="))) {
r = set_ensure_allocated(&c->import_credentials, &string_hash_ops);
_cleanup_free_ char *glob = NULL, *rename = NULL;
r = extract_many_words(&val, " ", EXTRACT_DONT_COALESCE_SEPARATORS, &glob, &rename);
if (r < 0)
return r;
if (r == 0)
return -EINVAL;
r = set_put_strdup(&c->import_credentials, val);
r = exec_context_put_import_credential(c, glob, rename);
if (r < 0)
return r;
} else if ((val = startswith(l, "exec-context-root-image-policy="))) {

View File

@ -630,7 +630,7 @@ void exec_context_done(ExecContext *c) {
c->load_credentials = hashmap_free(c->load_credentials);
c->set_credentials = hashmap_free(c->set_credentials);
c->import_credentials = set_free_free(c->import_credentials);
c->import_credentials = ordered_set_free(c->import_credentials);
c->root_image_policy = image_policy_free(c->root_image_policy);
c->mount_image_policy = image_policy_free(c->mount_image_policy);

View File

@ -26,6 +26,7 @@ typedef struct Manager Manager;
#include "nsflags.h"
#include "numa-util.h"
#include "open-file.h"
#include "ordered-set.h"
#include "path-util.h"
#include "runtime-scope.h"
#include "set.h"
@ -363,7 +364,7 @@ struct ExecContext {
Hashmap *set_credentials; /* output id → ExecSetCredential */
Hashmap *load_credentials; /* output id → ExecLoadCredential */
Set *import_credentials;
OrderedSet *import_credentials; /* ExecImportCredential */
ImagePolicy *root_image_policy, *mount_image_policy, *extension_image_policy;
};

View File

@ -153,7 +153,7 @@
{{type}}.SetCredentialEncrypted, config_parse_set_credential, 1, offsetof({{type}}, exec_context)
{{type}}.LoadCredential, config_parse_load_credential, 0, offsetof({{type}}, exec_context)
{{type}}.LoadCredentialEncrypted, config_parse_load_credential, 1, offsetof({{type}}, exec_context)
{{type}}.ImportCredential, config_parse_import_credential, 0, offsetof({{type}}, exec_context.import_credentials)
{{type}}.ImportCredential, config_parse_import_credential, 0, offsetof({{type}}, exec_context)
{{type}}.TimeoutCleanSec, config_parse_sec, 0, offsetof({{type}}, exec_context.timeout_clean_usec)
{% if HAVE_PAM %}
{{type}}.PAMName, config_parse_unit_string_printf, 0, offsetof({{type}}, exec_context.pam_name)

View File

@ -4895,8 +4895,7 @@ int config_parse_import_credential(
void *data,
void *userdata) {
_cleanup_free_ char *s = NULL;
Set** import_credentials = ASSERT_PTR(data);
ExecContext *context = ASSERT_PTR(data);
Unit *u = userdata;
int r;
@ -4906,23 +4905,40 @@ int config_parse_import_credential(
if (isempty(rvalue)) {
/* Empty assignment resets the list */
*import_credentials = set_free_free(*import_credentials);
context->import_credentials = ordered_set_free(context->import_credentials);
return 0;
}
r = unit_cred_printf(u, rvalue, &s);
const char *p = rvalue;
_cleanup_free_ char *word = NULL, *glob = NULL;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r == -ENOMEM)
return log_oom();
if (r <= 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
return 0;
}
r = unit_cred_printf(u, word, &glob);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
return 0;
}
if (!credential_glob_valid(s)) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name or glob \"%s\" not valid, ignoring.", s);
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
return 0;
}
r = set_put_strdup(import_credentials, s);
if (!credential_glob_valid(glob)) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name or glob \"%s\" not valid, ignoring.", glob);
return 0;
}
if (!isempty(p) && !credential_name_valid(p)) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name \"%s\" not valid, ignoring.", p);
return 0;
}
r = exec_context_put_import_credential(context, glob, p);
if (r < 0)
return log_error_errno(r, "Failed to store credential name '%s': %m", rvalue);
return log_error_errno(r, "Failed to store import credential '%s': %m", rvalue);
return 0;
}

View File

@ -1310,6 +1310,49 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
return 1;
}
if (streq(field, "ImportCredentialEx")) {
r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append_basic(m, 's', field);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'v', "a(ss)");
if (r < 0)
return bus_log_create_error(r);
if (isempty(eq))
r = sd_bus_message_append(m, "a(ss)", 0);
else {
_cleanup_free_ char *word = NULL;
const char *p = eq;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
r = sd_bus_message_append(m, "a(ss)", 1, word, p);
}
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
return 1;
}
if (streq(field, "LogExtraFields")) {
r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)

View File

@ -289,6 +289,36 @@ systemd-run -p "ImportCredential=test.creds.*" \
'${CREDENTIALS_DIRECTORY}/test.creds.third' >/tmp/ts54-concat
cmp /tmp/ts54-concat <(echo -n abc)
# Check that renaming with globs works as expected.
systemd-run -p "ImportCredentialEx=test.creds.*:renamed.creds." \
--unit=test-54-ImportCredential.service \
-p DynamicUser=1 \
--wait \
--pipe \
cat '${CREDENTIALS_DIRECTORY}/renamed.creds.first' \
'${CREDENTIALS_DIRECTORY}/renamed.creds.second' \
'${CREDENTIALS_DIRECTORY}/renamed.creds.third' >/tmp/ts54-concat
cmp /tmp/ts54-concat <(echo -n abc)
# Check that renaming without globs works as expected.
systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \
--unit=test-54-ImportCredential.service \
-p DynamicUser=1 \
--wait \
--pipe \
cat '${CREDENTIALS_DIRECTORY}/renamed.creds.first' >/tmp/ts54-concat
cmp /tmp/ts54-concat <(echo -n a)
# Test that multiple renames are processed in the correct order.
systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \
-p "ImportCredentialEx=test.creds.second:renamed.creds.first" \
--unit=test-54-ImportCredential.service \
-p DynamicUser=1 \
--wait \
--pipe \
cat '${CREDENTIALS_DIRECTORY}/renamed.creds.first' >/tmp/ts54-concat
cmp /tmp/ts54-concat <(echo -n a)
# Now test encrypted credentials (only supported when built with OpenSSL though)
if systemctl --version | grep -q -- +OPENSSL ; then
echo -n $RANDOM >/tmp/test-54-plaintext