nixpkgs/modules/config/users-groups.nix

242 lines
6.5 KiB
Nix
Raw Normal View History

{pkgs, config, ...}:
###### interface
let
inherit (pkgs.lib) mkOption;
options = {
users = {
extraUsers = mkOption {
default = [];
example = [
{ name = "alice";
uid = 1234;
description = "Alice";
home = "/home/alice";
createHome = true;
group = "users";
extraGroups = ["wheel"];
shell = "/bin/sh";
}
];
description = "
Additional user accounts to be created automatically by the system.
";
};
extraGroups = mkOption {
default = [];
example = [
{ name = "students";
gid = 1001;
}
];
description = "
Additional groups to be created automatically by the system.
";
};
};
};
in
###### implementation
let
ids = config.ids;
# User accounts to be created/updated by NixOS.
users =
let
defaultUsers =
[
{ name = "root";
uid = ids.uids.root;
description = "System administrator";
home = "/root";
shell = config.users.defaultUserShell;
group = "root";
}
{ name = "nobody";
uid = ids.uids.nobody;
description = "Unprivileged account (don't use!)";
}
];
makeNixBuildUser = nr:
{ name = "nixbld${toString nr}";
description = "Nix build user ${toString nr}";
uid = builtins.add ids.uids.nixbld nr;
extraGroups = ["nixbld"];
};
nixBuildUsers = map makeNixBuildUser (pkgs.lib.range 1 10);
addAttrs =
{ name
, description
, uid ? ""
, group ? "nogroup"
, extraGroups ? []
, home ? "/var/empty"
, shell ? (if useDefaultShell then config.users.defaultUserShell else "/noshell")
, createHome ? false
, useDefaultShell ? false
}:
{ inherit name description uid group extraGroups home shell createHome; };
in map addAttrs (defaultUsers ++ nixBuildUsers ++ config.users.extraUsers);
# Groups to be created/updated by NixOS.
groups =
let
defaultGroups =
[
{ name = "root";
gid = ids.gids.root;
}
{ name = "wheel";
gid = ids.gids.wheel;
}
{ name = "disk";
gid = ids.gids.disk;
}
{ name = "kmem";
gid = ids.gids.kmem;
}
{ name = "tty";
gid = ids.gids.tty;
}
{ name = "floppy";
gid = ids.gids.floppy;
}
{ name = "uucp";
gid = ids.gids.uucp;
}
{ name = "lp";
gid = ids.gids.lp;
}
{ name = "cdrom";
gid = ids.gids.cdrom;
}
{ name = "tape";
gid = ids.gids.tape;
}
{ name = "video";
gid = ids.gids.video;
}
{ name = "dialout";
gid = ids.gids.dialout;
}
{ name = "nogroup";
gid = ids.gids.nogroup;
}
{ name = "users";
gid = ids.gids.users;
}
{ name = "nixbld";
gid = ids.gids.nixbld;
}
];
addAttrs =
{ name, gid ? "" }:
{ inherit name gid; };
in map addAttrs (defaultGroups ++ config.users.extraGroups);
inherit (pkgs.lib) concatStringsSep;
serializedUser = u: "${u.name}\n${u.description}\n${toString u.uid}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}";
serializedGroup = g: "${g.name}\n${toString g.gid}";
in
let
inherit (pkgs.stringsWithDeps) fullDepEntry;
# keep this extra file so that cat can be used to pass special chars such as "`" which is used in the avahi daemon
usersFile = pkgs.writeText "users" (concatStringsSep "\n" (map serializedUser users));
in
{
require = [
options
# config.system.activationScripts
# ../system/activate-configuration.nix
];
system = {
activationScripts = {
users = fullDepEntry ''
cat ${usersFile} | while true; do
read name || break
read description
read uid
read group
read extraGroups
read home
read shell
read createHome
if ! curEnt=$(getent passwd "$name"); then
echo "creating user $name..."
useradd --system \
"$name" \
--comment "$description" \
''${uid:+--uid $uid} \
--gid "$group" \
--groups "$extraGroups" \
--home "$home" \
--shell "$shell" \
''${createHome:+--create-home}
else
#echo "updating user $name..."
oldIFS="$IFS"; IFS=:; set -- $curEnt; IFS="$oldIFS"
prevUid=$3
prevHome=$6
# Don't change the UID if it's the same, otherwise usermod
# will complain.
if test "$prevUid" = "$uid"; then unset uid; fi
# Don't change the home directory if it's the same to prevent
# unnecessary warnings about logged in users.
if test "$prevHome" = "$home"; then unset home; fi
usermod \
"$name" \
--comment "$description" \
''${uid:+--uid $uid} \
--gid "$group" \
--groups "$extraGroups" \
''${home:+--home "$home"} \
--shell "$shell"
fi
done
'' [ "groups" ];
groups = fullDepEntry ''
while true; do
read name || break
read gid
if ! curEnt=$(getent group "$name"); then
echo "creating group $name..."
groupadd --system \
"$name" \
''${gid:+--gid $gid}
else
#echo "updating group $name..."
oldIFS="$IFS"; IFS=:; set -- $curEnt; IFS="$oldIFS"
prevGid=$3
if test -n "$gid" -a "$prevGid" != "$gid"; then
groupmod "$name" --gid $gid
fi
fi
done <<EndOfGroupList
${concatStringsSep "\n" (map serializedGroup groups)}
EndOfGroupList
'' [ "rootPasswd" "binsh" "etc" "var" ];
};
};
}