nixos/users: require one of users.users.name.{isSystemUser,isNormalUser}

As the only consequence of isSystemUser is that if the uid is null then
it's allocated below 500, if a user has uid = something below 500 then
we don't require isSystemUser to be set.

Motivation: https://github.com/NixOS/nixpkgs/issues/112647
This commit is contained in:
Symphorien Gibol 2021-03-07 14:54:00 +01:00
parent 311ceed827
commit 7a87973b4c
23 changed files with 80 additions and 32 deletions

View File

@ -167,7 +167,7 @@ in {
# We know that the `user` attribute exists because we set a default value
# for it above, allowing us to use it without worries here
users.users.${cfg.settings.user} = {};
users.users.${cfg.settings.user} = { isSystemUser = true; };
# ...
};

View File

@ -839,6 +839,13 @@ environment.systemPackages = [
The option's description was incorrect regarding ownership management and has been simplified greatly.
</para>
</listitem>
<listitem>
<para>
When defining a new user, one of <xref linkend="opt-users.users._name_.isNormalUser" /> and <xref linkend="opt-users.users._name_.isSystemUser" /> is now required.
This is to prevent accidentally giving a UID above 1000 to system users, which could have unexpected consequences, like running user activation scripts for system users.
Note that users defined with an explicit UID below 500 are exempted from this check, as <xref linkend="opt-users.users._name_.isSystemUser" /> has no effect for those.
</para>
</listitem>
<listitem>
<para>
The GNOME desktop manager once again installs <package>gnome3.epiphany</package> by default.

View File

@ -306,6 +306,7 @@ in {
description = "PulseAudio system service user";
home = stateDir;
createHome = true;
isSystemUser = true;
};
users.groups.pulse.gid = gid;

View File

@ -92,6 +92,8 @@ let
the user's UID is allocated in the range for system users
(below 500) or in the range for normal users (starting at
1000).
Exactly one of <literal>isNormalUser</literal> and
<literal>isSystemUser</literal> must be true.
'';
};
@ -107,6 +109,8 @@ let
<option>useDefaultShell</option> to <literal>true</literal>,
and <option>isSystemUser</option> to
<literal>false</literal>.
Exactly one of <literal>isNormalUser</literal> and
<literal>isSystemUser</literal> must be true.
'';
};
@ -521,6 +525,7 @@ in {
};
nobody = {
uid = ids.uids.nobody;
isSystemUser = true;
description = "Unprivileged account (don't use!)";
group = "nogroup";
};
@ -608,17 +613,28 @@ in {
Neither the root account nor any wheel user has a password or SSH authorized key.
You must set one to prevent being locked out of your system.'';
}
] ++ flip mapAttrsToList cfg.users (name: user:
{
] ++ flatten (flip mapAttrsToList cfg.users (name: user:
[
{
assertion = (user.hashedPassword != null)
-> (builtins.match ".*:.*" user.hashedPassword == null);
-> (builtins.match ".*:.*" user.hashedPassword == null);
message = ''
The password hash of user "${user.name}" contains a ":" character.
This is invalid and would break the login system because the fields
of /etc/shadow (file where hashes are stored) are colon-separated.
Please check the value of option `users.users."${user.name}".hashedPassword`.'';
}
);
The password hash of user "${user.name}" contains a ":" character.
This is invalid and would break the login system because the fields
of /etc/shadow (file where hashes are stored) are colon-separated.
Please check the value of option `users.users."${user.name}".hashedPassword`.'';
}
{
assertion = let
xor = a: b: a && !b || b && !a;
isEffectivelySystemUser = user.isSystemUser || (user.uid != null && user.uid < 500);
in xor isEffectivelySystemUser user.isNormalUser;
message = ''
Exactly one of users.users.${user.name}.isSystemUser and users.users.${user.name}.isNormalUser must be set.
'';
}
]
));
warnings =
builtins.filter (x: x != null) (

View File

@ -169,6 +169,7 @@ let
(map (mkAuthorizedKey cfg false) cfg.authorizedKeys
++ map (mkAuthorizedKey cfg true) cfg.authorizedKeysAppendOnly);
useDefaultShell = true;
isSystemUser = true;
};
groups.${cfg.group} = { };
};

View File

@ -197,6 +197,7 @@ in {
group = pgmanage;
home = cfg.sqlRoot;
createHome = true;
isSystemUser = true;
};
groups.${pgmanage} = {
name = pgmanage;

View File

@ -64,6 +64,7 @@ in
users.users = mkIf (cfg.user == "bazarr") {
bazarr = {
isSystemUser = true;
group = cfg.group;
home = "/var/lib/${config.systemd.services.bazarr.serviceConfig.StateDirectory}";
};

View File

@ -21,6 +21,7 @@ let
calls in `libstore/build.cc', don't add any supplementary group
here except "nixbld". */
uid = builtins.add config.ids.uids.nixbld nr;
isSystemUser = true;
group = "nixbld";
extraGroups = [ "nixbld" ];
};

View File

@ -34,7 +34,10 @@ in {
users = {
groups._tuptime.members = [ "_tuptime" ];
users._tuptime.description = "tuptime database owner";
users._tuptime = {
isSystemUser = true;
description = "tuptime database owner";
};
};
systemd = {

View File

@ -73,6 +73,7 @@ let
users.${variant} = {
description = "BIRD Internet Routing Daemon user";
group = variant;
isSystemUser = true;
};
groups.${variant} = {};
};

View File

@ -243,8 +243,10 @@ in
xlog.journal = true;
};
users.users.ncdns =
{ description = "ncdns daemon user"; };
users.users.ncdns = {
isSystemUser = true;
description = "ncdns daemon user";
};
systemd.services.ncdns = {
description = "ncdns daemon";

View File

@ -93,6 +93,7 @@ in
users.users.pixiecore = {
description = "Pixiecore daemon user";
group = "pixiecore";
isSystemUser = true;
};
networking.firewall = mkIf cfg.openFirewall {

View File

@ -75,6 +75,7 @@ in {
description = "Pleroma user";
home = cfg.stateDir;
extraGroups = [ cfg.group ];
isSystemUser = true;
};
groups."${cfg.group}" = {};
};

View File

@ -264,6 +264,7 @@ in
users.users.privacyidea = mkIf (cfg.user == "privacyidea") {
group = cfg.group;
isSystemUser = true;
};
users.groups.privacyidea = mkIf (cfg.group == "privacyidea") {};
@ -294,6 +295,7 @@ in
users.users.pi-ldap-proxy = mkIf (cfg.ldap-proxy.user == "pi-ldap-proxy") {
group = cfg.ldap-proxy.group;
isSystemUser = true;
};
users.groups.pi-ldap-proxy = mkIf (cfg.ldap-proxy.group == "pi-ldap-proxy") {};

View File

@ -607,6 +607,7 @@ in {
home = "${cfg.home}";
group = "nextcloud";
createHome = true;
isSystemUser = true;
};
users.groups.nextcloud.members = [ "nextcloud" config.services.nginx.user ];

View File

@ -31,7 +31,7 @@ in {
firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
firewall.allowedUDPPorts = [ 4567 ];
};
users.users.testuser = { };
users.users.testuser = { isSystemUser = true; };
systemd.services.mysql = with pkgs; {
path = [ mysqlenv-common mysqlenv-mariabackup ];
};
@ -89,7 +89,7 @@ in {
firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
firewall.allowedUDPPorts = [ 4567 ];
};
users.users.testuser = { };
users.users.testuser = { isSystemUser = true; };
systemd.services.mysql = with pkgs; {
path = [ mysqlenv-common mysqlenv-mariabackup ];
};
@ -136,7 +136,7 @@ in {
firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
firewall.allowedUDPPorts = [ 4567 ];
};
users.users.testuser = { };
users.users.testuser = { isSystemUser = true; };
systemd.services.mysql = with pkgs; {
path = [ mysqlenv-common mysqlenv-mariabackup ];
};

View File

@ -31,7 +31,7 @@ in {
firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
firewall.allowedUDPPorts = [ 4567 ];
};
users.users.testuser = { };
users.users.testuser = { isSystemUser = true; };
systemd.services.mysql = with pkgs; {
path = [ mysqlenv-common mysqlenv-rsync ];
};
@ -84,7 +84,7 @@ in {
firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
firewall.allowedUDPPorts = [ 4567 ];
};
users.users.testuser = { };
users.users.testuser = { isSystemUser = true; };
systemd.services.mysql = with pkgs; {
path = [ mysqlenv-common mysqlenv-rsync ];
};
@ -130,7 +130,7 @@ in {
firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
firewall.allowedUDPPorts = [ 4567 ];
};
users.users.testuser = { };
users.users.testuser = { isSystemUser = true; };
systemd.services.mysql = with pkgs; {
path = [ mysqlenv-common mysqlenv-rsync ];
};

View File

@ -9,8 +9,8 @@ import ./../make-test-python.nix ({ pkgs, ...} : {
{ pkgs, ... }:
{
users.users.testuser = { };
users.users.testuser2 = { };
users.users.testuser = { isSystemUser = true; };
users.users.testuser2 = { isSystemUser = true; };
services.mysql.enable = true;
services.mysql.initialDatabases = [
{ name = "testdb3"; schema = ./testdb.sql; }
@ -44,8 +44,8 @@ import ./../make-test-python.nix ({ pkgs, ...} : {
# Kernel panic - not syncing: Out of memory: compulsory panic_on_oom is enabled
virtualisation.memorySize = 1024;
users.users.testuser = { };
users.users.testuser2 = { };
users.users.testuser = { isSystemUser = true; };
users.users.testuser2 = { isSystemUser = true; };
services.mysql.enable = true;
services.mysql.initialDatabases = [
{ name = "testdb3"; schema = ./testdb.sql; }
@ -75,8 +75,8 @@ import ./../make-test-python.nix ({ pkgs, ...} : {
{ pkgs, ... }:
{
users.users.testuser = { };
users.users.testuser2 = { };
users.users.testuser = { isSystemUser = true; };
users.users.testuser2 = { isSystemUser = true; };
services.mysql.enable = true;
services.mysql.initialScript = pkgs.writeText "mariadb-init.sql" ''
ALTER USER root@localhost IDENTIFIED WITH unix_socket;

View File

@ -22,11 +22,10 @@ in
users.users."member" = {
createHome = false;
description = "A member of the redis group";
isNormalUser = true;
extraGroups = [
"redis"
];
group = "users";
shell = "/bin/sh";
};
};
};

View File

@ -274,7 +274,10 @@ in
I find cows to be evil don't you?
'';
users.users.tester.password = "test";
users.users.tester = {
isNormalUser = true;
password = "test";
};
services.postfix = {
enable = true;
destination = ["example.com"];

View File

@ -13,14 +13,17 @@ in import ./make-test-python.nix ({ pkgs, ... }: {
users = {
mutableUsers = true;
users.emma = {
isNormalUser = true;
password = password1;
shell = pkgs.bash;
};
users.layla = {
isNormalUser = true;
password = password2;
shell = pkgs.shadow;
};
users.ash = {
isNormalUser = true;
password = password4;
shell = pkgs.bash;
};

View File

@ -150,6 +150,7 @@ import ./make-test-python.nix {
config.users.groups.chroot-testgroup = {};
config.users.users.chroot-testuser = {
isSystemUser = true;
description = "Chroot Test User";
group = "chroot-testgroup";
};

View File

@ -132,12 +132,15 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
users.users = {
# user that is permitted to access the unix socket
someuser.extraGroups = [
config.users.users.unbound.group
];
someuser = {
isSystemUser = true;
extraGroups = [
config.users.users.unbound.group
];
};
# user that is not permitted to access the unix socket
unauthorizeduser = {};
unauthorizeduser = { isSystemUser = true; };
};
environment.etc = {