From: Lennart Poettering Date: Tue, 3 Jan 2023 12:05:32 +0000 (+0100) Subject: vconsole: permit configuration of vconsole settings via credentials X-Git-Tag: v253-rc1~186 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ea575e176aac9fa8f430bb30a3e8abd8da767a10;p=thirdparty%2Fsystemd.git vconsole: permit configuration of vconsole settings via credentials --- diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml index 3f01836ddda..cfce8a40ad5 100644 --- a/man/systemd-firstboot.xml +++ b/man/systemd-firstboot.xml @@ -325,7 +325,15 @@ firstboot.keymap This credential specifies the keyboard setting to set during first boot, in place of - prompting the user. + prompting the user. + + Note the relationship to the vconsole.keymap credential understood by + systemd-vconsole-setup.service8: + both ultimately affect the same setting, but firstboot.keymap is written into + /etc/vconsole.conf on first boot (if not already configured), and then read from + there by systemd-vconsole-setup, while vconsole.keymap is read + on every boot, and is not persisted to disk (but any configuration in + vconsole.conf will take precedence if present). diff --git a/man/systemd-vconsole-setup.service.xml b/man/systemd-vconsole-setup.service.xml index 80577edba05..98d9e2ad01b 100644 --- a/man/systemd-vconsole-setup.service.xml +++ b/man/systemd-vconsole-setup.service.xml @@ -49,6 +49,44 @@ information about the configuration files and kernel command line options understood by this program. + + Credentials + + systemd-vconsole-setup supports the service credentials logic as implemented by + LoadCredential=/SetCredential= (see + systemd.exec1 for + details). The following credentials are used when passed in: + + + + vconsole.keymap + vconsole.keymap_toggle + + The keymap (and toggle keymap) to apply. The matching options in + vconsole.conf and on the kernel command line take precedence over these + credentials. + + Note the relationship to the firstboot.keymap credential understood by + systemd-firstboot.service8: + both ultimately affect the same setting, but firstboot.keymap is written into + /etc/vconsole.conf on first boot (if not already configured), and then read from + there by systemd-vconsole-setup, while vconsole.keymap is read + on every boot, and is not persisted to disk (but any configuration in + vconsole.conf will take precedence if present). + + + + vconsole.font + vconsole.font_map + vconsole.font_unimap + + The console font settings to apply. The matching options in + vconsole.conf and on the kernel command line take precedence over these + credentials. + + + + See Also diff --git a/man/systemd.system-credentials.xml b/man/systemd.system-credentials.xml index 3ec7ae8d4f4..3eadf9b9852 100644 --- a/man/systemd.system-credentials.xml +++ b/man/systemd.system-credentials.xml @@ -178,6 +178,18 @@ + + vconsole.keymap + vconsole.keymap_toggle + vconsole.font + vconsole.font_map + vconsole.font_unimap + + Console settings to apply, see + systemd-vconsole-setup.service8 for details. + + + diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index 9f4d0832abf..a68837b70bd 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 cf3d6c7dc6a..05d8b746348 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 0b7ba3fb02e..f9ee9190195 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 00000000000..44022e73248 --- /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 ecc859a2c35..7d3e9db73f8 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -19,6 +19,7 @@ #include #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); diff --git a/units/systemd-vconsole-setup.service.in b/units/systemd-vconsole-setup.service.in index 23f5ac2f50b..c07869feddd 100644 --- a/units/systemd-vconsole-setup.service.in +++ b/units/systemd-vconsole-setup.service.in @@ -18,3 +18,8 @@ ConditionPathExists=/dev/tty0 Type=oneshot RemainAfterExit=yes ExecStart={{ROOTLIBEXECDIR}}/systemd-vconsole-setup +LoadCredential=vconsole.keymap +LoadCredential=vconsole.keymap_toggle +LoadCredential=vconsole.font +LoadCredential=vconsole.font_map +LoadCredential=vconsole.font_unimap