diff --git a/src/core/execute.c b/src/core/execute.c index b3e64ade1bd..2762b102879 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2595,6 +2595,42 @@ static int write_credential( return 0; } +static char **credential_search_path( + const ExecParameters *params, + bool encrypted) { + + _cleanup_strv_free_ char **l = NULL; + + assert(params); + + /* Assemble a search path to find credentials in. We'll look in /etc/credstore/ (and similar + * directories in /usr/lib/ + /run/) for all types of credentials. If we are looking for encrypted + * credentials, also look in /etc/credstore.encrypted/ (and similar dirs). */ + + if (encrypted) { + if (strv_extend(&l, params->received_encrypted_credentials_directory) < 0) + return NULL; + + if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore.encrypted"), /* filter_duplicates= */ true) < 0) + return NULL; + } + + if (params->received_credentials_directory) + if (strv_extend(&l, params->received_credentials_directory) < 0) + return NULL; + + if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore"), /* filter_duplicates= */ true) < 0) + return NULL; + + if (DEBUG_LOGGING) { + _cleanup_free_ char *t = strv_join(l, ":"); + + log_debug("Credential search path is: %s", t); + } + + return TAKE_PTR(l); +} + static int load_credential( const ExecContext *context, const ExecParameters *params, @@ -2609,11 +2645,12 @@ static int load_credential( uint64_t *left) { ReadFullFileFlags flags = READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER; + _cleanup_strv_free_ char **search_path = NULL; _cleanup_(erase_and_freep) char *data = NULL; - _cleanup_free_ char *j = NULL, *bindname = NULL; + _cleanup_free_ char *bindname = NULL; + const char *source = NULL; bool missing_ok = true; - const char *source; - size_t size, add; + size_t size, add, maxsz; int r; assert(context); @@ -2624,10 +2661,25 @@ static int load_credential( assert(write_dfd >= 0); assert(left); - if (path_is_absolute(path) || read_dfd >= 0) { - /* If this is an absolute path (or a directory fd is specifier relative which to read), read - * the data directly from it, and support AF_UNIX sockets */ + if (read_dfd >= 0) { + /* If a directory fd is specified, then read the file directly from that dir. In this case we + * won't do AF_UNIX stuff (we simply don't want to recursively iterate down a tree of AF_UNIX + * IPC sockets). It's OK if a file vanishes here in the time we enumerate it and intend to + * open it. */ + + if (!filename_is_valid(path)) /* safety check */ + return -EINVAL; + + missing_ok = true; source = path; + + } else if (path_is_absolute(path)) { + /* If this is an absolute path, read the data directly from it, and support AF_UNIX + * sockets */ + + if (!path_is_valid(path)) /* safety check */ + return -EINVAL; + flags |= READ_FULL_FILE_CONNECT_SOCKET; /* Pass some minimal info about the unit and the credential name we are looking to acquire @@ -2636,25 +2688,50 @@ static int load_credential( return -ENOMEM; missing_ok = false; + source = path; - } else if (params->received_credentials) { - /* If this is a relative path, take it relative to the credentials we received - * ourselves. We don't support the AF_UNIX stuff in this mode, since we are operating - * on a credential store, i.e. this is guaranteed to be regular files. */ - j = path_join(params->received_credentials, path); - if (!j) + } else if (credential_name_valid(path)) { + /* If this is a relative path, take it as credential name relative to the credentials + * directory we received ourselves. We don't support the AF_UNIX stuff in this mode, since we + * are operating on a credential store, i.e. this is guaranteed to be regular files. */ + + search_path = credential_search_path(params, encrypted); + if (!search_path) return -ENOMEM; - source = j; + missing_ok = true; } else source = NULL; - if (source) + if (encrypted) + flags |= READ_FULL_FILE_UNBASE64; + + maxsz = encrypted ? CREDENTIAL_ENCRYPTED_SIZE_MAX : CREDENTIAL_SIZE_MAX; + + if (search_path) { + STRV_FOREACH(d, search_path) { + _cleanup_free_ char *j = NULL; + + j = path_join(*d, path); + if (!j) + return -ENOMEM; + + r = read_full_file_full( + AT_FDCWD, j, /* path is absolute, hence pass AT_FDCWD as nop dir fd here */ + UINT64_MAX, + maxsz, + flags, + NULL, + &data, &size); + if (r != -ENOENT) + break; + } + } else if (source) r = read_full_file_full( read_dfd, source, UINT64_MAX, - encrypted ? CREDENTIAL_ENCRYPTED_SIZE_MAX : CREDENTIAL_SIZE_MAX, - flags | (encrypted ? READ_FULL_FILE_UNBASE64 : 0), + maxsz, + flags, bindname, &data, &size); else diff --git a/src/core/execute.h b/src/core/execute.h index 43070ce1117..904e7943f32 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -406,7 +406,8 @@ struct ExecParameters { const char *cgroup_path; char **prefix; - const char *received_credentials; + const char *received_credentials_directory; + const char *received_encrypted_credentials_directory; const char *confirm_spawn; diff --git a/src/core/manager.c b/src/core/manager.c index a68324affc5..18daff66c78 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -777,9 +777,37 @@ static int manager_setup_sigchld_event_source(Manager *m) { return 0; } +static int manager_find_credentials_dirs(Manager *m) { + const char *e; + int r; + + assert(m); + + r = get_credentials_dir(&e); + if (r < 0) { + if (r != -ENXIO) + log_debug_errno(r, "Failed to determine credentials directory, ignoring: %m"); + } else { + m->received_credentials_directory = strdup(e); + if (!m->received_credentials_directory) + return -ENOMEM; + } + + r = get_encrypted_credentials_dir(&e); + if (r < 0) { + if (r != -ENXIO) + log_debug_errno(r, "Failed to determine encrypted credentials directory, ignoring: %m"); + } else { + m->received_encrypted_credentials_directory = strdup(e); + if (!m->received_encrypted_credentials_directory) + return -ENOMEM; + } + + return 0; +} + int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) { _cleanup_(manager_freep) Manager *m = NULL; - const char *e; int r; assert(_m); @@ -883,12 +911,9 @@ int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager * if (r < 0) return r; - r = get_credentials_dir(&e); - if (r >= 0) { - m->received_credentials = strdup(e); - if (!m->received_credentials) - return -ENOMEM; - } + r = manager_find_credentials_dirs(m); + if (r < 0) + return r; r = sd_event_default(&m->event); if (r < 0) @@ -1533,7 +1558,8 @@ Manager* manager_free(Manager *m) { for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) m->prefix[dt] = mfree(m->prefix[dt]); - free(m->received_credentials); + free(m->received_credentials_directory); + free(m->received_encrypted_credentials_directory); free(m->watchdog_pretimeout_governor); free(m->watchdog_pretimeout_governor_overridden); diff --git a/src/core/manager.h b/src/core/manager.h index 6f4bbb36ab1..fd5da52b7f9 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -438,7 +438,8 @@ struct Manager { /* Prefixes of e.g. RuntimeDirectory= */ char *prefix[_EXEC_DIRECTORY_TYPE_MAX]; - char *received_credentials; + char *received_credentials_directory; + char *received_encrypted_credentials_directory; /* Used in the SIGCHLD and sd_notify() message invocation logic to avoid that we dispatch the same event * multiple times on the same unit. */ diff --git a/src/core/unit.c b/src/core/unit.c index 5ab7601ed86..ff1288dcac0 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -5032,7 +5032,8 @@ int unit_set_exec_params(Unit *u, ExecParameters *p) { p->cgroup_path = u->cgroup_path; SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, unit_cgroup_delegate(u)); - p->received_credentials = u->manager->received_credentials; + p->received_credentials_directory = u->manager->received_credentials_directory; + p->received_encrypted_credentials_directory = u->manager->received_encrypted_credentials_directory; return 0; }