forked from rarias/nixos-riscv
Move other patched scripts to patches/
This commit is contained in:
153
patches/stage-2-init.sh
Executable file
153
patches/stage-2-init.sh
Executable file
@@ -0,0 +1,153 @@
|
||||
#! @shell@
|
||||
|
||||
set -x
|
||||
|
||||
echo "HELLOOOOOOOOOOOO FROM STAGE 2"
|
||||
|
||||
systemConfig=@systemConfig@
|
||||
|
||||
export HOME=/root PATH="@path@"
|
||||
|
||||
|
||||
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
|
||||
# Process the kernel command line.
|
||||
for o in $(</proc/cmdline); do
|
||||
case $o in
|
||||
boot.debugtrace)
|
||||
# Show each command.
|
||||
set -x
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
# Print a greeting.
|
||||
echo
|
||||
echo -e "\e[1;32m<<< @distroName@ Stage 2 >>>\e[0m"
|
||||
echo
|
||||
|
||||
|
||||
# Normally, stage 1 mounts the root filesystem read/writable.
|
||||
# However, in some environments, stage 2 is executed directly, and the
|
||||
# root is read-only. So make it writable here.
|
||||
if [ -z "$container" ]; then
|
||||
mount -n -o remount,rw none /
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
|
||||
# stage 1, we need to do that here.
|
||||
if [ ! -e /proc/1 ]; then
|
||||
specialMount() {
|
||||
local device="$1"
|
||||
local mountPoint="$2"
|
||||
local options="$3"
|
||||
local fsType="$4"
|
||||
|
||||
# We must not overwrite this mount because it's bind-mounted
|
||||
# from stage 1's /run
|
||||
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" = true ] && [ "${mountPoint}" = /run ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
install -m 0755 -d "$mountPoint"
|
||||
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
|
||||
}
|
||||
source @earlyMountScript@
|
||||
fi
|
||||
|
||||
|
||||
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" = true ] || [ ! -c /dev/kmsg ] ; then
|
||||
echo "booting system configuration ${systemConfig}"
|
||||
else
|
||||
echo "booting system configuration $systemConfig" > /dev/kmsg
|
||||
fi
|
||||
|
||||
|
||||
# Make /nix/store a read-only bind mount to enforce immutability of
|
||||
# the Nix store. Note that we can't use "chown root:nixbld" here
|
||||
# because users/groups might not exist yet.
|
||||
# Silence chown/chmod to fail gracefully on a readonly filesystem
|
||||
# like squashfs.
|
||||
chown -f 0:30000 /nix/store
|
||||
chmod -f 1775 /nix/store
|
||||
if [ -n "@readOnlyNixStore@" ]; then
|
||||
if ! [[ "$(findmnt --noheadings --output OPTIONS /nix/store)" =~ ro(,|$) ]]; then
|
||||
if [ -z "$container" ]; then
|
||||
mount --bind /nix/store /nix/store
|
||||
else
|
||||
mount --rbind /nix/store /nix/store
|
||||
fi
|
||||
mount -o remount,ro,bind /nix/store
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
|
||||
# Use /etc/resolv.conf supplied by systemd-nspawn, if applicable.
|
||||
if [ -n "@useHostResolvConf@" ] && [ -e /etc/resolv.conf ]; then
|
||||
resolvconf -m 1000 -a host </etc/resolv.conf
|
||||
fi
|
||||
|
||||
|
||||
# # Log the script output to /dev/kmsg or /run/log/stage-2-init.log.
|
||||
# # Only at this point are all the necessary prerequisites ready for these commands.
|
||||
# exec {logOutFd}>&1 {logErrFd}>&2
|
||||
# if test -w /dev/kmsg; then
|
||||
# exec > >(tee -i /proc/self/fd/"$logOutFd" | while read -r line; do
|
||||
# if test -n "$line"; then
|
||||
# echo "<7>stage-2-init: $line" > /dev/kmsg
|
||||
# fi
|
||||
# done) 2>&1
|
||||
# else
|
||||
# mkdir -p /run/log
|
||||
# exec > >(tee -i /run/log/stage-2-init.log) 2>&1
|
||||
# fi
|
||||
fi
|
||||
|
||||
|
||||
# Required by the activation script
|
||||
install -m 0755 -d /etc
|
||||
if [ ! -h "/etc/nixos" ]; then
|
||||
install -m 0755 -d /etc/nixos
|
||||
fi
|
||||
install -m 01777 -d /tmp
|
||||
|
||||
|
||||
# Run the script that performs all configuration activation that does
|
||||
# not have to be done at boot time.
|
||||
echo "running activation script..."
|
||||
#strace -f $systemConfig/activate
|
||||
$systemConfig/activate
|
||||
|
||||
echo "ACTIVATE WORKED!!!"
|
||||
|
||||
# Record the boot configuration.
|
||||
ln -sfn "$systemConfig" /run/booted-system
|
||||
|
||||
|
||||
# Run any user-specified commands.
|
||||
@shell@ @postBootCommands@
|
||||
|
||||
|
||||
# Ensure systemd doesn't try to populate /etc, by forcing its first-boot
|
||||
# heuristic off. It doesn't matter what's in /etc/machine-id for this purpose,
|
||||
# and systemd will immediately fill in the file when it starts, so just
|
||||
# creating it is enough. This `: >>` pattern avoids forking and avoids changing
|
||||
# the mtime if the file already exists.
|
||||
: >> /etc/machine-id
|
||||
|
||||
|
||||
# No need to restore the stdout/stderr streams we never redirected and
|
||||
# especially no need to start systemd
|
||||
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
|
||||
# Reset the logging file descriptors.
|
||||
#exec 1>&$logOutFd 2>&$logErrFd
|
||||
#exec {logOutFd}>&- {logErrFd}>&-
|
||||
|
||||
|
||||
# Start systemd in a clean environment.
|
||||
echo "starting systemd..."
|
||||
exec @systemdExecutable@ "$@"
|
||||
fi
|
||||
379
patches/update-users-groups.pl
Normal file
379
patches/update-users-groups.pl
Normal file
@@ -0,0 +1,379 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
use File::Path qw(make_path);
|
||||
use File::Slurp;
|
||||
use Getopt::Long;
|
||||
use JSON;
|
||||
use Time::Piece;
|
||||
|
||||
# Keep track of deleted uids and gids.
|
||||
my $uidMapFile = "/var/lib/nixos/uid-map";
|
||||
my $uidMap = -e $uidMapFile ? decode_json(read_file($uidMapFile)) : {};
|
||||
|
||||
my $gidMapFile = "/var/lib/nixos/gid-map";
|
||||
my $gidMap = -e $gidMapFile ? decode_json(read_file($gidMapFile)) : {};
|
||||
|
||||
my $is_dry = ($ENV{'NIXOS_ACTION'} // "") eq "dry-activate";
|
||||
GetOptions("dry-activate" => \$is_dry);
|
||||
make_path("/var/lib/nixos", { mode => 0755 }) unless $is_dry;
|
||||
|
||||
sub updateFile {
|
||||
my ($path, $contents, $perms) = @_;
|
||||
return if $is_dry;
|
||||
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 $time = Time::Piece->strptime($date, "%Y-%m-%d");
|
||||
return $time->epoch / 60 / 60 / 24;
|
||||
}
|
||||
|
||||
sub nscdInvalidate {
|
||||
system("echo", "nscd", "--invalidate", $_[0]) unless $is_dry;
|
||||
}
|
||||
|
||||
sub hashPassword {
|
||||
my ($password) = @_;
|
||||
my $salt = "";
|
||||
my @chars = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
|
||||
$salt .= $chars[rand 64] for (1..8);
|
||||
return crypt($password, '$6$' . $salt . '$');
|
||||
}
|
||||
|
||||
sub dry_print {
|
||||
if ($is_dry) {
|
||||
print STDERR ("$_[1] $_[2]\n")
|
||||
} else {
|
||||
print STDERR ("$_[0] $_[2]\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Functions for allocating free GIDs/UIDs. FIXME: respect ID ranges in
|
||||
# /etc/login.defs.
|
||||
sub allocId {
|
||||
my ($used, $prevUsed, $idMin, $idMax, $up, $getid) = @_;
|
||||
my $id = $up ? $idMin : $idMax;
|
||||
while ($id >= $idMin && $id <= $idMax) {
|
||||
if (!$used->{$id} && !$prevUsed->{$id} && !defined &$getid($id)) {
|
||||
$used->{$id} = 1;
|
||||
return $id;
|
||||
}
|
||||
$used->{$id} = 1;
|
||||
if ($up) { $id++; } else { $id--; }
|
||||
}
|
||||
die "$0: out of free UIDs or GIDs\n";
|
||||
}
|
||||
|
||||
my (%gidsUsed, %uidsUsed, %gidsPrevUsed, %uidsPrevUsed);
|
||||
|
||||
sub allocGid {
|
||||
my ($name) = @_;
|
||||
my $prevGid = $gidMap->{$name};
|
||||
if (defined $prevGid && !defined $gidsUsed{$prevGid}) {
|
||||
dry_print("reviving", "would revive", "group '$name' with GID $prevGid");
|
||||
$gidsUsed{$prevGid} = 1;
|
||||
return $prevGid;
|
||||
}
|
||||
return allocId(\%gidsUsed, \%gidsPrevUsed, 400, 999, 0, sub { my ($gid) = @_; getgrgid($gid) });
|
||||
}
|
||||
|
||||
sub allocUid {
|
||||
my ($name, $isSystemUser) = @_;
|
||||
my ($min, $max, $up) = $isSystemUser ? (400, 999, 0) : (1000, 29999, 1);
|
||||
my $prevUid = $uidMap->{$name};
|
||||
if (defined $prevUid && $prevUid >= $min && $prevUid <= $max && !defined $uidsUsed{$prevUid}) {
|
||||
dry_print("reviving", "would revive", "user '$name' with UID $prevUid");
|
||||
$uidsUsed{$prevUid} = 1;
|
||||
return $prevUid;
|
||||
}
|
||||
return allocId(\%uidsUsed, \%uidsPrevUsed, $min, $max, $up, sub { my ($uid) = @_; getpwuid($uid) });
|
||||
}
|
||||
|
||||
# Read the declared users/groups
|
||||
my $spec = decode_json(read_file($ARGV[0]));
|
||||
|
||||
# Don't allocate UIDs/GIDs that are manually assigned.
|
||||
foreach my $g (@{$spec->{groups}}) {
|
||||
$gidsUsed{$g->{gid}} = 1 if defined $g->{gid};
|
||||
}
|
||||
|
||||
foreach my $u (@{$spec->{users}}) {
|
||||
$uidsUsed{$u->{uid}} = 1 if defined $u->{uid};
|
||||
}
|
||||
|
||||
# Likewise for previously used but deleted UIDs/GIDs.
|
||||
$uidsPrevUsed{$_} = 1 foreach values %{$uidMap};
|
||||
$gidsPrevUsed{$_} = 1 foreach values %{$gidMap};
|
||||
|
||||
|
||||
# Read the current /etc/group.
|
||||
sub parseGroup {
|
||||
chomp;
|
||||
my @f = split(':', $_, -4);
|
||||
my $gid = $f[2] eq "" ? undef : int($f[2]);
|
||||
$gidsUsed{$gid} = 1 if defined $gid;
|
||||
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", { binmode => ":utf8" }) : ();
|
||||
|
||||
# Read the current /etc/passwd.
|
||||
sub parseUser {
|
||||
chomp;
|
||||
my @f = split(':', $_, -7);
|
||||
my $uid = $f[2] eq "" ? undef : int($f[2]);
|
||||
$uidsUsed{$uid} = 1 if defined $uid;
|
||||
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", { 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, { binmode => ":utf8" }) : "";
|
||||
|
||||
# Idem for the users.
|
||||
my $declUsersFile = "/var/lib/nixos/declarative-users";
|
||||
my %declUsers;
|
||||
$declUsers{$_} = 1 foreach split / /, -e $declUsersFile ? read_file($declUsersFile, { binmode => ":utf8" }) : "";
|
||||
|
||||
|
||||
# Generate a new /etc/group containing the declared groups.
|
||||
my %groupsOut;
|
||||
foreach my $g (@{$spec->{groups}}) {
|
||||
my $name = $g->{name};
|
||||
my $existing = $groupsCur{$name};
|
||||
|
||||
my %members = map { ($_, 1) } @{$g->{members}};
|
||||
|
||||
if (defined $existing) {
|
||||
$g->{gid} = $existing->{gid} if !defined $g->{gid};
|
||||
if ($g->{gid} != $existing->{gid}) {
|
||||
dry_print("warning: not applying", "warning: would not apply", "GID change of group ‘$name’ ($existing->{gid} -> $g->{gid}) in /etc/group");
|
||||
$g->{gid} = $existing->{gid};
|
||||
}
|
||||
$g->{password} = $existing->{password}; # do we want this?
|
||||
if ($spec->{mutableUsers}) {
|
||||
# Merge in non-declarative group members.
|
||||
foreach my $uname (split /,/, $existing->{members} // "") {
|
||||
$members{$uname} = 1 if !defined $declUsers{$uname};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$g->{gid} = allocGid($name) if !defined $g->{gid};
|
||||
$g->{password} = "x";
|
||||
}
|
||||
|
||||
$g->{members} = join ",", sort(keys(%members));
|
||||
$groupsOut{$name} = $g;
|
||||
|
||||
$gidMap->{$name} = $g->{gid};
|
||||
}
|
||||
|
||||
# Update the persistent list of declarative groups.
|
||||
updateFile($declGroupsFile, join(" ", sort(keys %groupsOut)));
|
||||
|
||||
# Merge in the existing /etc/group.
|
||||
foreach my $name (keys %groupsCur) {
|
||||
my $g = $groupsCur{$name};
|
||||
next if defined $groupsOut{$name};
|
||||
if (!$spec->{mutableUsers} || defined $declGroups{$name}) {
|
||||
dry_print("removing group", "would remove group", "‘$name’");
|
||||
} else {
|
||||
$groupsOut{$name} = $g;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Rewrite /etc/group. FIXME: acquire lock.
|
||||
my @lines = map { join(":", $_->{name}, $_->{password}, $_->{gid}, $_->{members}) . "\n" }
|
||||
(sort { $a->{gid} <=> $b->{gid} } values(%groupsOut));
|
||||
updateFile($gidMapFile, to_json($gidMap, {canonical => 1}));
|
||||
updateFile("/etc/group", \@lines);
|
||||
nscdInvalidate("group");
|
||||
|
||||
# Generate a new /etc/passwd containing the declared users.
|
||||
my %usersOut;
|
||||
foreach my $u (@{$spec->{users}}) {
|
||||
my $name = $u->{name};
|
||||
|
||||
# Resolve the gid of the user.
|
||||
if ($u->{group} =~ /^[0-9]$/) {
|
||||
$u->{gid} = $u->{group};
|
||||
} elsif (defined $groupsOut{$u->{group}}) {
|
||||
$u->{gid} = $groupsOut{$u->{group}}->{gid} // die;
|
||||
} else {
|
||||
warn "warning: user ‘$name’ has unknown group ‘$u->{group}’\n";
|
||||
$u->{gid} = 65534;
|
||||
}
|
||||
|
||||
my $existing = $usersCur{$name};
|
||||
if (defined $existing) {
|
||||
$u->{uid} = $existing->{uid} if !defined $u->{uid};
|
||||
if ($u->{uid} != $existing->{uid}) {
|
||||
dry_print("warning: not applying", "warning: would not apply", "UID change of user ‘$name’ ($existing->{uid} -> $u->{uid}) in /etc/passwd");
|
||||
$u->{uid} = $existing->{uid};
|
||||
}
|
||||
} else {
|
||||
$u->{uid} = allocUid($name, $u->{isSystemUser}) if !defined $u->{uid};
|
||||
|
||||
if (!defined $u->{hashedPassword}) {
|
||||
if (defined $u->{initialPassword}) {
|
||||
$u->{hashedPassword} = hashPassword($u->{initialPassword});
|
||||
} elsif (defined $u->{initialHashedPassword}) {
|
||||
$u->{hashedPassword} = $u->{initialHashedPassword};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure home directory incl. ownership and permissions.
|
||||
if ($u->{createHome} and !$is_dry) {
|
||||
make_path($u->{home}, { mode => oct($u->{homeMode}) }) if ! -e $u->{home};
|
||||
chown $u->{uid}, $u->{gid}, $u->{home};
|
||||
chmod oct($u->{homeMode}), $u->{home};
|
||||
}
|
||||
|
||||
if (defined $u->{hashedPasswordFile}) {
|
||||
if (-e $u->{hashedPasswordFile}) {
|
||||
$u->{hashedPassword} = read_file($u->{hashedPasswordFile});
|
||||
chomp $u->{hashedPassword};
|
||||
} else {
|
||||
warn "warning: password file ‘$u->{hashedPasswordFile}’ does not exist\n";
|
||||
}
|
||||
} elsif (defined $u->{password}) {
|
||||
$u->{hashedPassword} = hashPassword($u->{password});
|
||||
}
|
||||
|
||||
if (!defined $u->{shell}) {
|
||||
if (defined $existing) {
|
||||
$u->{shell} = $existing->{shell};
|
||||
} else {
|
||||
warn "warning: no declarative or previous shell for ‘$name’, setting shell to nologin\n";
|
||||
$u->{shell} = "/run/current-system/sw/bin/nologin";
|
||||
}
|
||||
}
|
||||
|
||||
$u->{fakePassword} = $existing->{fakePassword} // "x";
|
||||
$usersOut{$name} = $u;
|
||||
|
||||
$uidMap->{$name} = $u->{uid};
|
||||
}
|
||||
|
||||
# Update the persistent list of declarative users.
|
||||
updateFile($declUsersFile, join(" ", sort(keys %usersOut)));
|
||||
|
||||
# Merge in the existing /etc/passwd.
|
||||
foreach my $name (keys %usersCur) {
|
||||
my $u = $usersCur{$name};
|
||||
next if defined $usersOut{$name};
|
||||
if (!$spec->{mutableUsers} || defined $declUsers{$name}) {
|
||||
dry_print("removing user", "would remove user", "‘$name’");
|
||||
} else {
|
||||
$usersOut{$name} = $u;
|
||||
}
|
||||
}
|
||||
|
||||
# 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, to_json($uidMap, {canonical => 1}));
|
||||
updateFile("/etc/passwd", \@lines);
|
||||
nscdInvalidate("passwd");
|
||||
|
||||
|
||||
# Rewrite /etc/shadow to add new accounts or remove dead ones.
|
||||
my @shadowNew;
|
||||
my %shadowSeen;
|
||||
|
||||
foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow", { binmode => ":utf8" }) : ()) {
|
||||
chomp $line;
|
||||
# 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;
|
||||
$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) {
|
||||
next if defined $shadowSeen{$u->{name}};
|
||||
my $hashedPassword = "!";
|
||||
$hashedPassword = $u->{hashedPassword} if defined $u->{hashedPassword};
|
||||
my $expires = "";
|
||||
$expires = dateToDays($u->{expires}) if defined $u->{expires};
|
||||
# FIXME: set correct value for sp_lstchg.
|
||||
push @shadowNew, join(":", $u->{name}, $hashedPassword, "1::::", $expires, "") . "\n";
|
||||
}
|
||||
|
||||
updateFile("/etc/shadow", \@shadowNew, 0640);
|
||||
{
|
||||
my $uid = getpwnam "root";
|
||||
my $gid = getgrnam "shadow";
|
||||
my $path = "/etc/shadow";
|
||||
(chown($uid, $gid, $path) || die "Failed to change ownership of $path: $!") unless $is_dry;
|
||||
}
|
||||
|
||||
# Rewrite /etc/subuid & /etc/subgid to include default container mappings
|
||||
|
||||
my $subUidMapFile = "/var/lib/nixos/auto-subuid-map";
|
||||
my $subUidMap = -e $subUidMapFile ? decode_json(read_file($subUidMapFile)) : {};
|
||||
|
||||
my (%subUidsUsed, %subUidsPrevUsed);
|
||||
|
||||
$subUidsPrevUsed{$_} = 1 foreach values %{$subUidMap};
|
||||
|
||||
sub allocSubUid {
|
||||
my ($name, @rest) = @_;
|
||||
|
||||
# TODO: No upper bounds?
|
||||
my ($min, $max, $up) = (100000, 100000 * 100, 1);
|
||||
my $prevId = $subUidMap->{$name};
|
||||
if (defined $prevId && !defined $subUidsUsed{$prevId}) {
|
||||
$subUidsUsed{$prevId} = 1;
|
||||
return $prevId;
|
||||
}
|
||||
|
||||
my $id = allocId(\%subUidsUsed, \%subUidsPrevUsed, $min, $max, $up, sub { my ($uid) = @_; getpwuid($uid) });
|
||||
my $offset = $id - 100000;
|
||||
my $count = $offset * 65536;
|
||||
my $subordinate = 100000 + $count;
|
||||
return $subordinate;
|
||||
}
|
||||
|
||||
my @subGids;
|
||||
my @subUids;
|
||||
foreach my $u (values %usersOut) {
|
||||
my $name = $u->{name};
|
||||
|
||||
foreach my $range (@{$u->{subUidRanges}}) {
|
||||
my $value = join(":", ($name, $range->{startUid}, $range->{count}));
|
||||
push @subUids, $value;
|
||||
}
|
||||
|
||||
foreach my $range (@{$u->{subGidRanges}}) {
|
||||
my $value = join(":", ($name, $range->{startGid}, $range->{count}));
|
||||
push @subGids, $value;
|
||||
}
|
||||
|
||||
if($u->{autoSubUidGidRange}) {
|
||||
my $subordinate = allocSubUid($name);
|
||||
$subUidMap->{$name} = $subordinate;
|
||||
my $value = join(":", ($name, $subordinate, 65536));
|
||||
push @subUids, $value;
|
||||
push @subGids, $value;
|
||||
}
|
||||
}
|
||||
|
||||
updateFile("/etc/subuid", join("\n", @subUids) . "\n");
|
||||
updateFile("/etc/subgid", join("\n", @subGids) . "\n");
|
||||
updateFile($subUidMapFile, encode_json($subUidMap) . "\n");
|
||||
Reference in New Issue
Block a user