firstboot: follow lock protocol when changing /etc/shadow
This commit is contained in:
parent
30f10abf42
commit
45035609fc
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue