From 45035609fcfc3fe09324988c4929a3c147171c23 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Jul 2014 18:57:09 +0200 Subject: [PATCH] firstboot: follow lock protocol when changing /etc/shadow --- src/firstboot/firstboot.c | 9 ++++++++- src/shared/util.c | 40 +++++++++++++++++++++++++++++++++++++++ src/shared/util.h | 2 ++ src/sysusers/sysusers.c | 38 +------------------------------------ 4 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 57173a566..6abffc528 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -530,7 +530,6 @@ static int write_root_shadow(const char *path, const struct spwd *p) { assert(path); assert(p); - mkdir_parents(path, 0755); RUN_WITH_UMASK(0777) f = fopen(path, "wex"); if (!f) @@ -560,6 +559,8 @@ static int process_root_password(void) { .sp_expire = -1, .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ }; + + _cleanup_close_ int lock = -1; char salt[3+16+1+1]; uint8_t raw[16]; unsigned i; @@ -572,6 +573,12 @@ static int process_root_password(void) { if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) return 0; + mkdir_parents(etc_shadow, 0755); + + lock = take_password_lock(arg_root); + if (lock < 0) + return lock; + if (arg_copy_root_password && arg_root) { struct spwd *p; diff --git a/src/shared/util.c b/src/shared/util.c index bef87304e..88511b69c 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -6823,3 +6823,43 @@ bool is_localhost(const char *hostname) { endswith(hostname, ".localdomain") || endswith(hostname, ".localdomain."); } + +int take_password_lock(const char *root) { + + struct flock flock = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0, + }; + + const char *path; + int fd, r; + + /* This is roughly the same as lckpwdf(), but not as awful. We + * don't want to use alarm() and signals, hence we implement + * our own trivial version of this. + * + * Note that shadow-utils also takes per-database locks in + * addition to lckpwdf(). However, we don't given that they + * are redundant as they they invoke lckpwdf() first and keep + * it during everything they do. The per-database locks are + * awfully racy, and thus we just won't do them. */ + + if (root) + path = strappenda(root, "/etc/.pwd.lock"); + else + path = "/etc/.pwd.lock"; + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600); + if (fd < 0) + return -errno; + + r = fcntl(fd, F_SETLKW, &flock); + if (r < 0) { + safe_close(fd); + return -errno; + } + + return fd; +} diff --git a/src/shared/util.h b/src/shared/util.h index 7c9842b3e..fb852d697 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -964,3 +964,5 @@ char *tempfn_xxxxxx(const char *p); char *tempfn_random(const char *p); bool is_localhost(const char *hostname); + +int take_password_lock(const char *root); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index c0af69300..1765f31a3 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1379,42 +1379,6 @@ static int read_config_file(const char *fn, bool ignore_enoent) { return r; } -static int take_lock(void) { - - struct flock flock = { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0, - }; - - const char *path; - int fd, r; - - /* This is roughly the same as lckpwdf(), but not as awful. We - * don't want to use alarm() and signals, hence we implement - * our own trivial version of this. - * - * Note that shadow-utils also takes per-database locks in - * addition to lckpwdf(). However, we don't given that they - * are redundant as they they invoke lckpwdf() first and keep - * it during everything they do. The per-database locks are - * awfully racy, and thus we just won't do them. */ - - path = fix_root("/etc/.pwd.lock"); - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600); - if (fd < 0) - return -errno; - - r = fcntl(fd, F_SETLKW, &flock); - if (r < 0) { - safe_close(fd); - return -errno; - } - - return fd; -} - static void free_database(Hashmap *by_name, Hashmap *by_id) { char *name; @@ -1548,7 +1512,7 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - lock = take_lock(); + lock = take_password_lock(arg_root); if (lock < 0) { log_error("Failed to take lock: %s", strerror(-lock)); goto finish; -- 2.30.2