From 28900a1bfe919fbb10bd3b7b248b54c7aff96c2e Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 21 Jul 2020 22:35:21 +0100 Subject: [PATCH] firstboot: Add --root-shell option --- man/systemd-firstboot.xml | 16 ++++++- src/firstboot/firstboot.c | 99 +++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 10 deletions(-) diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml index 8c9ea80f15..0976394b66 100644 --- a/man/systemd-firstboot.xml +++ b/man/systemd-firstboot.xml @@ -177,6 +177,14 @@ + + + + Sets the shell of the system's root user. This creates/modifies the + passwd5 + file. + + @@ -192,6 +200,7 @@ + Prompt the user interactively for a specific basic setting. Note that any explicit configuration settings @@ -208,7 +217,8 @@ , , , - in combination. + , + in combination. @@ -217,6 +227,7 @@ + Copy a specific basic setting from the host. This only works in combination with @@ -231,7 +242,8 @@ , , , - in combination. + , + in combination. diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 61565145dd..82cd4040f9 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -49,16 +49,19 @@ static char *arg_timezone = NULL; static char *arg_hostname = NULL; static sd_id128_t arg_machine_id = {}; static char *arg_root_password = NULL; +static char *arg_root_shell = NULL; static char *arg_kernel_cmdline = NULL; static bool arg_prompt_locale = false; static bool arg_prompt_keymap = false; static bool arg_prompt_timezone = false; static bool arg_prompt_hostname = false; static bool arg_prompt_root_password = false; +static bool arg_prompt_root_shell = false; static bool arg_copy_locale = false; static bool arg_copy_keymap = false; static bool arg_copy_timezone = false; static bool arg_copy_root_password = false; +static bool arg_copy_root_shell = false; static bool arg_force = false; static bool arg_delete_root_password = false; static bool arg_root_password_is_hashed = false; @@ -601,7 +604,40 @@ static int prompt_root_password(void) { return 0; } -static int write_root_passwd(const char *passwd_path, const char *password) { +static int prompt_root_shell(void) { + int r; + + if (arg_root_shell || !arg_prompt_root_shell) + return 0; + + print_welcome(); + putchar('\n'); + + for (;;) { + _cleanup_free_ char *s = NULL; + + r = ask_string(&s, "%s Please enter root shell for new system (empty to skip): ", special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET)); + if (r < 0) + return log_error_errno(r, "Failed to query root shell: %m"); + + if (isempty(s)) { + log_warning("No shell entered, skipping."); + break; + } + + if (!valid_shell(s)) { + log_error("Specified shell invalid."); + continue; + } + + arg_root_shell = TAKE_PTR(s); + break; + } + + return 0; +} + +static int write_root_passwd(const char *passwd_path, const char *password, const char *shell) { _cleanup_fclose_ FILE *original = NULL, *passwd = NULL; _cleanup_(unlink_and_freep) char *passwd_tmp = NULL; int r; @@ -622,8 +658,11 @@ static int write_root_passwd(const char *passwd_path, const char *password) { while ((r = fgetpwent_sane(original, &i)) > 0) { - if (streq(i->pw_name, "root")) + if (streq(i->pw_name, "root")) { i->pw_passwd = (char *) password; + if (shell) + i->pw_shell = (char *) shell; + } r = putpwent_sane(i, passwd); if (r < 0) @@ -640,7 +679,7 @@ static int write_root_passwd(const char *passwd_path, const char *password) { .pw_gid = 0, .pw_gecos = (char *) "Super User", .pw_dir = (char *) "/root", - .pw_shell = (char *) "/bin/sh", + .pw_shell = (char *) (shell ?: "/bin/sh"), }; if (errno != ENOENT) @@ -735,7 +774,7 @@ static int write_root_shadow(const char *shadow_path, const char *hashed_passwor return 0; } -static int process_root_password(void) { +static int process_root_args(void) { _cleanup_close_ int lock = -1; struct crypt_data cd = {}; const char *password, *hashed_password; @@ -757,6 +796,23 @@ static int process_root_password(void) { if (lock < 0) return log_error_errno(lock, "Failed to take a lock on %s: %m", etc_passwd); + if (arg_copy_root_shell && arg_root) { + struct passwd *p; + + errno = 0; + p = getpwnam("root"); + if (!p) + return log_error_errno(errno_or_else(EIO), "Failed to find passwd entry for root: %m"); + + r = free_and_strdup(&arg_root_shell, p->pw_shell); + if (r < 0) + return log_oom(); + } + + r = prompt_root_shell(); + if (r < 0) + return r; + if (arg_copy_root_password && arg_root) { struct spwd *p; @@ -799,7 +855,7 @@ static int process_root_password(void) { else password = hashed_password = "!"; - r = write_root_passwd(etc_passwd, password); + r = write_root_passwd(etc_passwd, password, arg_root_shell); if (r < 0) return log_error_errno(r, "Failed to write %s: %m", etc_passwd); @@ -964,6 +1020,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_ROOT_PASSWORD, ARG_ROOT_PASSWORD_FILE, ARG_ROOT_PASSWORD_HASHED, + ARG_ROOT_SHELL, ARG_KERNEL_COMMAND_LINE, ARG_PROMPT, ARG_PROMPT_LOCALE, @@ -971,11 +1028,13 @@ static int parse_argv(int argc, char *argv[]) { ARG_PROMPT_TIMEZONE, ARG_PROMPT_HOSTNAME, ARG_PROMPT_ROOT_PASSWORD, + ARG_PROMPT_ROOT_SHELL, ARG_COPY, ARG_COPY_LOCALE, ARG_COPY_KEYMAP, ARG_COPY_TIMEZONE, ARG_COPY_ROOT_PASSWORD, + ARG_COPY_ROOT_SHELL, ARG_SETUP_MACHINE_ID, ARG_FORCE, ARG_DELETE_ROOT_PASSWORD, @@ -996,6 +1055,7 @@ static int parse_argv(int argc, char *argv[]) { { "root-password", required_argument, NULL, ARG_ROOT_PASSWORD }, { "root-password-file", required_argument, NULL, ARG_ROOT_PASSWORD_FILE }, { "root-password-hashed", required_argument, NULL, ARG_ROOT_PASSWORD_HASHED }, + { "root-shell", required_argument, NULL, ARG_ROOT_SHELL }, { "kernel-command-line", required_argument, NULL, ARG_KERNEL_COMMAND_LINE }, { "prompt", no_argument, NULL, ARG_PROMPT }, { "prompt-locale", no_argument, NULL, ARG_PROMPT_LOCALE }, @@ -1003,11 +1063,13 @@ static int parse_argv(int argc, char *argv[]) { { "prompt-timezone", no_argument, NULL, ARG_PROMPT_TIMEZONE }, { "prompt-hostname", no_argument, NULL, ARG_PROMPT_HOSTNAME }, { "prompt-root-password", no_argument, NULL, ARG_PROMPT_ROOT_PASSWORD }, + { "prompt-root-shell", no_argument, NULL, ARG_PROMPT_ROOT_SHELL }, { "copy", no_argument, NULL, ARG_COPY }, { "copy-locale", no_argument, NULL, ARG_COPY_LOCALE }, { "copy-keymap", no_argument, NULL, ARG_COPY_KEYMAP }, { "copy-timezone", no_argument, NULL, ARG_COPY_TIMEZONE }, { "copy-root-password", no_argument, NULL, ARG_COPY_ROOT_PASSWORD }, + { "copy-root-shell", no_argument, NULL, ARG_COPY_ROOT_SHELL }, { "setup-machine-id", no_argument, NULL, ARG_SETUP_MACHINE_ID }, { "force", no_argument, NULL, ARG_FORCE }, { "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD }, @@ -1104,6 +1166,17 @@ static int parse_argv(int argc, char *argv[]) { arg_root_password_is_hashed = true; break; + case ARG_ROOT_SHELL: + if (!valid_shell(optarg)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "%s is not a valid shell path", optarg); + + r = free_and_strdup(&arg_root_shell, optarg); + if (r < 0) + return log_oom(); + + break; + case ARG_HOSTNAME: if (!hostname_is_valid(optarg, true)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -1131,7 +1204,8 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_PROMPT: - arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = true; + arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname = + arg_prompt_root_password = arg_prompt_root_shell = true; break; case ARG_PROMPT_LOCALE: @@ -1154,8 +1228,13 @@ static int parse_argv(int argc, char *argv[]) { arg_prompt_root_password = true; break; + case ARG_PROMPT_ROOT_SHELL: + arg_prompt_root_shell = true; + break; + case ARG_COPY: - arg_copy_locale = arg_copy_keymap = arg_copy_timezone = arg_copy_root_password = true; + arg_copy_locale = arg_copy_keymap = arg_copy_timezone = arg_copy_root_password = + arg_copy_root_shell = true; break; case ARG_COPY_LOCALE: @@ -1174,6 +1253,10 @@ static int parse_argv(int argc, char *argv[]) { arg_copy_root_password = true; break; + case ARG_COPY_ROOT_SHELL: + arg_copy_root_shell = true; + break; + case ARG_SETUP_MACHINE_ID: r = sd_id128_randomize(&arg_machine_id); if (r < 0) @@ -1274,7 +1357,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; - r = process_root_password(); + r = process_root_args(); if (r < 0) return r;