diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml index 491ca6e9bf..8c9ea80f15 100644 --- a/man/systemd-firstboot.xml +++ b/man/systemd-firstboot.xml @@ -164,9 +164,10 @@ - Sets the password of the system's root user. This creates a + Sets the password of the system's root user. This creates/modifies the + passwd5 and shadow5 - file. This setting exists in three forms: accepts the password to + files. This setting exists in three forms: accepts the password to set directly on the command line, reads it from a file and accepts an already hashed password on the command line. See shadow5 diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 5c9ee779ca..61565145dd 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -606,6 +606,8 @@ static int write_root_passwd(const char *passwd_path, const char *password) { _cleanup_(unlink_and_freep) char *passwd_tmp = NULL; int r; + assert(password); + r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp); if (r < 0) return r; @@ -669,6 +671,8 @@ static int write_root_shadow(const char *shadow_path, const char *hashed_passwor _cleanup_(unlink_and_freep) char *shadow_tmp = NULL; int r; + assert(hashed_password); + r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp); if (r < 0) return r; @@ -734,70 +738,53 @@ static int write_root_shadow(const char *shadow_path, const char *hashed_passwor static int process_root_password(void) { _cleanup_close_ int lock = -1; struct crypt_data cd = {}; - const char *hashed_password; - const char *etc_shadow; + const char *password, *hashed_password; + const char *etc_passwd, *etc_shadow; int r; + etc_passwd = prefix_roota(arg_root, "/etc/passwd"); etc_shadow = prefix_roota(arg_root, "/etc/shadow"); - if (laccess(etc_shadow, F_OK) >= 0 && !arg_force) + + /* We only mess with passwd and shadow if both do not exist or --force is specified. These files are + * tightly coupled and hence we make sure we have permission from the user to create/modify both + * files. */ + if ((laccess(etc_passwd, F_OK) >= 0 || laccess(etc_shadow, F_OK) >= 0) && !arg_force) return 0; - (void) mkdir_parents(etc_shadow, 0755); + (void) mkdir_parents(etc_passwd, 0755); lock = take_etc_passwd_lock(arg_root); if (lock < 0) - return log_error_errno(lock, "Failed to take a lock: %m"); - - if (arg_delete_root_password) { - const char *etc_passwd; - - /* Mixing alloca() and other stuff that touches the stack in one expression is not portable. */ - etc_passwd = prefix_roota(arg_root, "/etc/passwd"); - - r = write_root_passwd(etc_passwd, ""); - if (r < 0) - return log_error_errno(r, "Failed to write %s: %m", etc_passwd); - - log_info("%s written", etc_passwd); - - return 0; - } + return log_error_errno(lock, "Failed to take a lock on %s: %m", etc_passwd); if (arg_copy_root_password && arg_root) { struct spwd *p; errno = 0; p = getspnam("root"); - if (p || errno != ENOENT) { - if (!p) { - if (!errno) - errno = EIO; + if (!p) + return log_error_errno(errno_or_else(EIO), "Failed to find shadow entry for root: %m"); - return log_error_errno(errno, "Failed to find shadow entry for root: %m"); - } + r = free_and_strdup(&arg_root_password, p->sp_pwdp); + if (r < 0) + return log_oom(); - r = write_root_shadow(etc_shadow, p->sp_pwdp); - if (r < 0) - return log_error_errno(r, "Failed to write %s: %m", etc_shadow); - - log_info("%s copied.", etc_shadow); - return 0; - } + arg_root_password_is_hashed = true; } r = prompt_root_password(); if (r < 0) return r; - if (!arg_root_password) - return 0; - - if (arg_root_password_is_hashed) + if (arg_root_password && arg_root_password_is_hashed) { + password = "x"; hashed_password = arg_root_password; - else { + } else if (arg_root_password) { _cleanup_free_ char *salt = NULL; /* hashed_password points inside cd after crypt_r returns so cd has function scope. */ + password = "x"; + r = make_salt(&salt); if (r < 0) return log_error_errno(r, "Failed to get salt: %m"); @@ -807,7 +794,16 @@ static int process_root_password(void) { if (!hashed_password) return log_error_errno(errno == 0 ? SYNTHETIC_ERRNO(EINVAL) : errno, "Failed to encrypt password: %m"); - } + } else if (arg_delete_root_password) + password = hashed_password = ""; + else + password = hashed_password = "!"; + + r = write_root_passwd(etc_passwd, password); + if (r < 0) + return log_error_errno(r, "Failed to write %s: %m", etc_passwd); + + log_info("%s written", etc_passwd); r = write_root_shadow(etc_shadow, hashed_password); if (r < 0)