diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/shared/creds-util.c | 50 | ||||
-rw-r--r-- | src/shared/creds-util.h | 5 | ||||
-rw-r--r-- | src/test/meson.build | 2 | ||||
-rw-r--r-- | src/test/test-creds.c | 74 | ||||
-rw-r--r-- | src/vconsole/vconsole-setup.c | 18 |
5 files changed, 146 insertions, 3 deletions
diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index 9f4d0832ab..a68837b70b 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -86,6 +86,56 @@ int read_credential(const char *name, void **ret, size_t *ret_size) { (char**) ret, ret_size); } +int read_credential_strings_many_internal( + const char *first_name, char **first_value, + ...) { + + _cleanup_free_ void *b = NULL; + int r, ret = 0; + + /* Reads a bunch of credentials into the specified buffers. If the specified buffers are already + * non-NULL frees them if a credential is found. Only supports string-based credentials + * (i.e. refuses embedded NUL bytes) */ + + if (!first_name) + return 0; + + r = read_credential(first_name, &b, NULL); + if (r == -ENXIO) /* no creds passed at all? propagate this */ + return r; + if (r < 0) + ret = r; + else + free_and_replace(*first_value, b); + + va_list ap; + va_start(ap, first_value); + + for (;;) { + _cleanup_free_ void *bb = NULL; + const char *name; + char **value; + + name = va_arg(ap, const char *); + if (!name) + break; + + value = va_arg(ap, char **); + if (*value) + continue; + + r = read_credential(name, &bb, NULL); + if (r < 0) { + if (ret >= 0) + ret = r; + } else + free_and_replace(*value, bb); + } + + va_end(ap); + return ret; +} + int get_credential_user_password(const char *username, char **ret_password, bool *ret_is_hashed) { _cleanup_(erase_and_freep) char *creds_password = NULL; _cleanup_free_ char *cn = NULL; diff --git a/src/shared/creds-util.h b/src/shared/creds-util.h index cf3d6c7dc6..05d8b74634 100644 --- a/src/shared/creds-util.h +++ b/src/shared/creds-util.h @@ -36,6 +36,11 @@ int get_encrypted_credentials_dir(const char **ret); int read_credential(const char *name, void **ret, size_t *ret_size); +int read_credential_strings_many_internal(const char *first_name, char **first_value, ...); + +#define read_credential_strings_many(first_name, first_value, ...) \ + read_credential_strings_many_internal(first_name, first_value, __VA_ARGS__, NULL) + typedef enum CredentialSecretFlags { CREDENTIAL_SECRET_GENERATE = 1 << 0, CREDENTIAL_SECRET_WARN_NOT_ENCRYPTED = 1 << 1, diff --git a/src/test/meson.build b/src/test/meson.build index 0b7ba3fb02..f9ee919019 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -260,6 +260,8 @@ tests += [ [files('test-umask-util.c')], + [files('test-creds.c')], + [files('test-proc-cmdline.c')], [files('test-fd-util.c'), diff --git a/src/test/test-creds.c b/src/test/test-creds.c new file mode 100644 index 0000000000..44022e7324 --- /dev/null +++ b/src/test/test-creds.c @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "creds-util.h" +#include "fileio.h" +#include "path-util.h" +#include "rm-rf.h" +#include "tests.h" +#include "tmpfile-util.h" + +TEST(read_credential_strings) { + _cleanup_free_ char *x = NULL, *y = NULL, *saved = NULL, *p = NULL; + _cleanup_(rm_rf_physical_and_freep) char *tmp = NULL; + _cleanup_fclose_ FILE *f = NULL; + + const char *e = getenv("CREDENTIALS_DIRECTORY"); + if (e) + assert_se(saved = strdup(e)); + + assert_se(read_credential_strings_many("foo", &x, "bar", &y) == -ENXIO); + assert_se(x == NULL); + assert_se(y == NULL); + + assert_se(mkdtemp_malloc(NULL, &tmp) >= 0); + + assert_se(setenv("CREDENTIALS_DIRECTORY", tmp, /* override= */ true) >= 0); + + assert_se(read_credential_strings_many("foo", &x, "bar", &y) == -ENOENT); + assert_se(x == NULL); + assert_se(y == NULL); + + assert_se(p = path_join(tmp, "bar")); + assert_se(write_string_file(p, "piff", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_AVOID_NEWLINE) >= 0); + + assert_se(read_credential_strings_many("foo", &x, "bar", &y) == -ENOENT); + assert_se(x == NULL); + assert_se(streq(y, "piff")); + + assert_se(write_string_file(p, "paff", WRITE_STRING_FILE_TRUNCATE|WRITE_STRING_FILE_AVOID_NEWLINE) >= 0); + + assert_se(read_credential_strings_many("foo", &x, "bar", &y) == -ENOENT); + assert_se(x == NULL); + assert_se(streq(y, "piff")); + + p = mfree(p); + assert_se(p = path_join(tmp, "foo")); + assert_se(write_string_file(p, "knurz", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_AVOID_NEWLINE) >= 0); + + assert_se(read_credential_strings_many("foo", &x, "bar", &y) >= 0); + assert_se(streq(x, "knurz")); + assert_se(streq(y, "piff")); + + y = mfree(y); + + assert_se(read_credential_strings_many("foo", &x, "bar", &y) >= 0); + assert_se(streq(x, "knurz")); + assert_se(streq(y, "paff")); + + p = mfree(p); + assert_se(p = path_join(tmp, "bazz")); + assert_se(f = fopen(p, "w")); + assert_se(fwrite("x\0y", 1, 3, f) == 3); /* embedded NUL byte should result in EBADMSG when reading back with read_credential_strings_many() */ + f = safe_fclose(f); + + assert_se(read_credential_strings_many("bazz", &x, "foo", &y) == -EBADMSG); + assert_se(streq(x, "knurz")); + assert_se(streq(y, "paff")); + + if (saved) + assert_se(setenv("CREDENTIALS_DIRECTORY", saved, /* override= */ 1) >= 0); + else + assert_se(unsetenv("CREDENTIALS_DIRECTORY") >= 0); +} + +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index ecc859a2c3..7d3e9db73f 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -19,6 +19,7 @@ #include <unistd.h> #include "alloc-util.h" +#include "creds-util.h" #include "env-file.h" #include "errno-util.h" #include "fd-util.h" @@ -434,6 +435,17 @@ int main(int argc, char **argv) { utf8 = is_locale_utf8(); + /* Load data from credentials (lowest priority) */ + r = read_credential_strings_many( + "vconsole.keymap", &vc_keymap, + "vconsole.keymap_toggle", &vc_keymap_toggle, + "vconsole.font", &vc_font, + "vconsole.font_map", &vc_font_map, + "vconsole.font_unimap", &vc_font_unimap); + if (r < 0 && r != -ENXIO) + log_warning_errno(r, "Failed to import credentials, ignoring: %m"); + + /* Load data from configuration file (middle priority) */ r = parse_env_file(NULL, "/etc/vconsole.conf", "KEYMAP", &vc_keymap, "KEYMAP_TOGGLE", &vc_keymap_toggle, @@ -441,9 +453,9 @@ int main(int argc, char **argv) { "FONT_MAP", &vc_font_map, "FONT_UNIMAP", &vc_font_unimap); if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to read /etc/vconsole.conf: %m"); + log_warning_errno(r, "Failed to read /etc/vconsole.conf, ignoring: %m"); - /* Let the kernel command line override /etc/vconsole.conf */ + /* Let the kernel command line override /etc/vconsole.conf (highest priority) */ r = proc_cmdline_get_key_many( PROC_CMDLINE_STRIP_RD_PREFIX, "vconsole.keymap", &vc_keymap, @@ -456,7 +468,7 @@ int main(int argc, char **argv) { "vconsole.font.map", &vc_font_map, "vconsole.font.unimap", &vc_font_unimap); if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to read /proc/cmdline: %m"); + log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m"); (void) toggle_utf8_sysfs(utf8); (void) toggle_utf8_vc(vc, fd, utf8); |