nixos/update-users-groups: add support for account expiry

Introduce a `users.users.<name>.expires` option to allows setting an
expiry date to user accounts.

This is useful when members should gain temporary access and you don't
want to have to roll out another system update to disable them.
This commit is contained in:
zimbatm 2022-11-30 14:54:59 +01:00
parent d40fea9aeb
commit 9da75fdaf1
No known key found for this signature in database
GPG key ID: 71BAF6D40C1D63D7
2 changed files with 39 additions and 9 deletions

View file

@ -4,6 +4,7 @@ use File::Path qw(make_path);
use File::Slurp;
use Getopt::Long;
use JSON;
use DateTime;
# Keep track of deleted uids and gids.
my $uidMapFile = "/var/lib/nixos/uid-map";
@ -22,6 +23,22 @@ sub updateFile {
write_file($path, { atomic => 1, binmode => ':utf8', perms => $perms // 0644 }, $contents) or die;
}
# Converts an ISO date to number of days since 1970-01-01
sub dateToDays {
my ($date) = @_;
my ($year, $month, $day) = split('-', $date, -3);
my $dt = DateTime->new(
year => $year,
month => $month,
day => $day,
hour => 0,
minute => 0,
second => 0,
time_zone => 'UTC',
);
return $dt->epoch / 86400;
}
sub nscdInvalidate {
system("nscd", "--invalidate", $_[0]) unless $is_dry;
}
@ -283,14 +300,16 @@ my %shadowSeen;
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};;
# struct name copied from `man 3 shadow`
my ($sp_namp, $sp_pwdp, $sp_lstch, $sp_min, $sp_max, $sp_warn, $sp_inact, $sp_expire, $sp_flag) = split(':', $line, -9);
my $u = $usersOut{$sp_namp};;
next if !defined $u;
$hashedPassword = "!" if !$spec->{mutableUsers};
$hashedPassword = $u->{hashedPassword} if defined $u->{hashedPassword} && !$spec->{mutableUsers}; # FIXME
chomp $hashedPassword;
push @shadowNew, join(":", $name, $hashedPassword, @rest) . "\n";
$shadowSeen{$name} = 1;
$sp_pwdp = "!" if !$spec->{mutableUsers};
$sp_pwdp = $u->{hashedPassword} if defined $u->{hashedPassword} && !$spec->{mutableUsers}; # FIXME
$sp_expire = dateToDays($u->{expires}) if defined $u->{expires};
chomp $sp_pwdp;
push @shadowNew, join(":", $sp_namp, $sp_pwdp, $sp_lstch, $sp_min, $sp_max, $sp_warn, $sp_inact, $sp_expire, $sp_flag) . "\n";
$shadowSeen{$sp_namp} = 1;
}
foreach my $u (values %usersOut) {

View file

@ -308,6 +308,17 @@ let
'';
};
expires = mkOption {
type = types.nullOr (types.strMatching "[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}");
default = null;
description = lib.mdDoc ''
Set the date on which the user's account will no longer be
accessible. The date is expressed in the format YYYY-MM-DD, or null
to disable the expiry.
A user whose account is locked must contact the system
administrator before being able to use the system again.
'';
};
};
config = mkMerge
@ -433,7 +444,7 @@ let
name uid group description home homeMode createHome isSystemUser
password passwordFile hashedPassword
autoSubUidGidRange subUidRanges subGidRanges
initialPassword initialHashedPassword;
initialPassword initialHashedPassword expires;
shell = utils.toShellPath u.shell;
}) cfg.users;
groups = attrValues cfg.groups;
@ -587,7 +598,7 @@ in {
install -m 0700 -d /root
install -m 0755 -d /home
${pkgs.perl.withPackages (p: [ p.FileSlurp p.JSON ])}/bin/perl \
${pkgs.perl.withPackages (p: [ p.FileSlurp p.JSON p.DateTime ])}/bin/perl \
-w ${./update-users-groups.pl} ${spec}
'';
};