From 52bdb3eb7bc853873d68187494c2a683ce3084bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 23 Sep 2020 10:44:59 +0200 Subject: [PATCH 1/3] nixos/update-users-group: treat all file as utf-8 Ideally we would treat everything as bytes however our database is already utf-8 encoded so we need to stay compatible. --- nixos/modules/config/update-users-groups.pl | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl index e1c7a46e430..979f6464f08 100644 --- a/nixos/modules/config/update-users-groups.pl +++ b/nixos/modules/config/update-users-groups.pl @@ -98,7 +98,7 @@ sub parseGroup { return ($f[0], { name => $f[0], password => $f[1], gid => $gid, members => $f[3] }); } -my %groupsCur = -f "/etc/group" ? map { parseGroup } read_file("/etc/group") : (); +my %groupsCur = -f "/etc/group" ? map { parseGroup } read_file("/etc/group", { binmode => ":utf8" }) : (); # Read the current /etc/passwd. sub parseUser { @@ -109,20 +109,19 @@ sub parseUser { return ($f[0], { name => $f[0], fakePassword => $f[1], uid => $uid, gid => $f[3], description => $f[4], home => $f[5], shell => $f[6] }); } - -my %usersCur = -f "/etc/passwd" ? map { parseUser } read_file("/etc/passwd") : (); +my %usersCur = -f "/etc/passwd" ? map { parseUser } read_file("/etc/passwd", { binmode => ":utf8" }) : (); # Read the groups that were created declaratively (i.e. not by groups) # in the past. These must be removed if they are no longer in the # current spec. my $declGroupsFile = "/var/lib/nixos/declarative-groups"; my %declGroups; -$declGroups{$_} = 1 foreach split / /, -e $declGroupsFile ? read_file($declGroupsFile) : ""; +$declGroups{$_} = 1 foreach split / /, -e $declGroupsFile ? read_file($declGroupsFile, { binmode => ":utf8" }) : ""; # Idem for the users. my $declUsersFile = "/var/lib/nixos/declarative-users"; my %declUsers; -$declUsers{$_} = 1 foreach split / /, -e $declUsersFile ? read_file($declUsersFile) : ""; +$declUsers{$_} = 1 foreach split / /, -e $declUsersFile ? read_file($declUsersFile, { binmode => ":utf8" }) : ""; # Generate a new /etc/group containing the declared groups. @@ -260,7 +259,7 @@ system("nscd --invalidate passwd"); my @shadowNew; my %shadowSeen; -foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow") : ()) { +foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow", { binmode => ":utf8" }) : ()) { chomp $line; my ($name, $hashedPassword, @rest) = split(':', $line, -9); my $u = $usersOut{$name};; From f072d4dadcee0b616927f14baf3feb18591a1d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 23 Sep 2020 10:46:02 +0200 Subject: [PATCH 2/3] nixos/update-users-groups: fix encoding of json database The issue here is that updateFile expects a unicode string while encode_json returns a binary string unlike to_json. --- nixos/modules/config/update-users-groups.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl index 979f6464f08..ddd7efd82f7 100644 --- a/nixos/modules/config/update-users-groups.pl +++ b/nixos/modules/config/update-users-groups.pl @@ -174,7 +174,7 @@ foreach my $name (keys %groupsCur) { # Rewrite /etc/group. FIXME: acquire lock. my @lines = map { join(":", $_->{name}, $_->{password}, $_->{gid}, $_->{members}) . "\n" } (sort { $a->{gid} <=> $b->{gid} } values(%groupsOut)); -updateFile($gidMapFile, encode_json($gidMap)); +updateFile($gidMapFile, to_json($gidMap)); updateFile("/etc/group", \@lines); system("nscd --invalidate group"); @@ -250,7 +250,7 @@ foreach my $name (keys %usersCur) { # Rewrite /etc/passwd. FIXME: acquire lock. @lines = map { join(":", $_->{name}, $_->{fakePassword}, $_->{uid}, $_->{gid}, $_->{description}, $_->{home}, $_->{shell}) . "\n" } (sort { $a->{uid} <=> $b->{uid} } (values %usersOut)); -updateFile($uidMapFile, encode_json($uidMap)); +updateFile($uidMapFile, to_json($uidMap)); updateFile("/etc/passwd", \@lines); system("nscd --invalidate passwd"); From 99406adaaee52706201c4277051f4226c1160583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 23 Sep 2020 10:47:39 +0200 Subject: [PATCH 3/3] nixos/update-users-groups: write files truly atomic Having the .tmp suffix is broken w.r.t. to multiple writers, as they would overwrite existing files. using the atomic flag will make write_file to create a unique temporary file it gets renamed to its target. --- nixos/modules/config/update-users-groups.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl index ddd7efd82f7..86107abae36 100644 --- a/nixos/modules/config/update-users-groups.pl +++ b/nixos/modules/config/update-users-groups.pl @@ -16,8 +16,7 @@ my $gidMap = -e $gidMapFile ? decode_json(read_file($gidMapFile)) : {}; sub updateFile { my ($path, $contents, $perms) = @_; - write_file("$path.tmp", { binmode => ':utf8', perms => $perms // 0644 }, $contents); - rename("$path.tmp", $path) or die; + write_file($path, { atomic => 1, binmode => ':utf8', perms => $perms // 0644 }, $contents) or die; }