chiark / gitweb /
firstboot: follow lock protocol when changing /etc/shadow
authorLennart Poettering <lennart@poettering.net>
Mon, 7 Jul 2014 16:57:09 +0000 (18:57 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 7 Jul 2014 16:57:09 +0000 (18:57 +0200)
src/firstboot/firstboot.c
src/shared/util.c
src/shared/util.h
src/sysusers/sysusers.c

index 57173a5..6abffc5 100644 (file)
@@ -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;
 
index bef8730..88511b6 100644 (file)
@@ -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;
+}
index 7c9842b..fb852d6 100644 (file)
@@ -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);
index c0af693..1765f31 100644 (file)
@@ -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;