From 7c480ad89695c1309cc2ed5d07c166722476cd8c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 25 Jul 2014 12:48:21 +0200 Subject: [PATCH] setup-etc.pl: Keep track of copied files We now track copied files in /etc/.clean. This is important, because otherwise files that are removed from environment.etc will not actually be removed from the file system. In particular, changing users.extraUsers..openssh.authorizedKeys.keys to an empty list would not cause /etc/ssh/authorized_keys.d/ to be removed, which was a security issue. --- nixos/modules/system/etc/etc.nix | 2 +- nixos/modules/system/etc/setup-etc.pl | 41 ++++++++++++++++++++------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/nixos/modules/system/etc/etc.nix b/nixos/modules/system/etc/etc.nix index 22d55a9e246c..b57b03bcf962 100644 --- a/nixos/modules/system/etc/etc.nix +++ b/nixos/modules/system/etc/etc.nix @@ -132,7 +132,7 @@ in '' # Set up the statically computed bits of /etc. echo "setting up /etc..." - ${pkgs.perl}/bin/perl ${./setup-etc.pl} ${etc}/etc + ${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl ${./setup-etc.pl} ${etc}/etc ''; }; diff --git a/nixos/modules/system/etc/setup-etc.pl b/nixos/modules/system/etc/setup-etc.pl index 8ba9a370b27a..d7e15eccefcd 100644 --- a/nixos/modules/system/etc/setup-etc.pl +++ b/nixos/modules/system/etc/setup-etc.pl @@ -3,6 +3,7 @@ use File::Find; use File::Copy; use File::Path; use File::Basename; +use File::Slurp; my $etc = $ARGV[0] or die; my $static = "/etc/static"; @@ -46,35 +47,55 @@ sub cleanup { find(\&cleanup, "/etc"); +# Use /etc/.clean to keep track of copied files. +my @oldCopied = read_file("/etc/.clean", chomp => 1, err_mode => 'quiet'); +open CLEAN, ">>/etc/.clean"; + + # For every file in the etc tree, create a corresponding symlink in # /etc to /etc/static. The indirection through /etc/static is to make # switching to a new configuration somewhat more atomic. +my %created; +my @copied; + sub link { my $fn = substr $File::Find::name, length($etc) + 1 or next; my $target = "/etc/$fn"; File::Path::make_path(dirname $target); + $created{$fn} = 1; if (-e "$_.mode") { - open MODE, "<$_.mode"; - my $mode = ; chomp $mode; - close MODE; + my $mode = read_file("$_.mode"); chomp $mode; if ($mode eq "direct-symlink") { atomicSymlink readlink("$static/$fn"), $target or warn; } else { - open UID, "<$_.uid"; - my $uid = ; chomp $uid; - close UID; - open GID, "<$_.gid"; - my $gid = ; chomp $gid; - close GID; - + my $uid = read_file("$_.uid"); chomp $uid; + my $gid = read_file("$_.gid"); chomp $gid; copy "$static/$fn", "$target.tmp" or warn; chown int($uid), int($gid), "$target.tmp" or warn; chmod oct($mode), "$target.tmp" or warn; rename "$target.tmp", $target or warn; } + push @copied, $fn; + print CLEAN "$fn\n"; } elsif (-l "$_") { atomicSymlink "$static/$fn", $target or warn; } } find(\&link, $etc); + + +# Delete files that were copied in a previous version but not in the +# current. +foreach my $fn (@oldCopied) { + if (!defined $created{$fn}) { + $fn = "/etc/$fn"; + print STDERR "removing obsolete file ‘$fn’...\n"; + unlink "$fn"; + } +} + + +# Rewrite /etc/.clean. +close CLEAN; +write_file("/etc/.clean", map { "$_\n" } @copied);