diff options
author | Daan De Meyer <daan.j.demeyer@gmail.com> | 2024-07-30 16:16:26 +0200 |
---|---|---|
committer | Daan De Meyer <daan.j.demeyer@gmail.com> | 2024-07-31 15:52:27 +0200 |
commit | 831f208783aeac443e6f2fc2efc3119535a032ef (patch) | |
tree | 8ba1bf30dcd20d9e4d0a56ecd084fa4d3ddcc39c /src/core/exec-credential.c | |
parent | exec-credential: Skip duplicate credentials in load_credential_glob() (diff) | |
download | systemd-831f208783aeac443e6f2fc2efc3119535a032ef.tar.xz systemd-831f208783aeac443e6f2fc2efc3119535a032ef.zip |
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.
Diffstat (limited to 'src/core/exec-credential.c')
-rw-r--r-- | src/core/exec-credential.c | 93 |
1 files changed, 87 insertions, 6 deletions
diff --git a/src/core/exec-credential.c b/src/core/exec-credential.c index 75eca830f8..e1b09f6718 100644 --- a/src/core/exec-credential.c +++ b/src/core/exec-credential.c @@ -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); |