From 7a87973b4ced86e1ba94ee84449979d6afebc9ea Mon Sep 17 00:00:00 2001 From: Symphorien Gibol Date: Sun, 7 Mar 2021 14:54:00 +0100 Subject: [PATCH] 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 --- .../manual/development/settings-options.xml | 2 +- nixos/doc/manual/release-notes/rl-2105.xml | 7 ++++ nixos/modules/config/pulseaudio.nix | 1 + nixos/modules/config/users-groups.nix | 34 ++++++++++++++----- nixos/modules/services/backup/borgbackup.nix | 1 + nixos/modules/services/databases/pgmanage.nix | 1 + nixos/modules/services/misc/bazarr.nix | 1 + nixos/modules/services/misc/nix-daemon.nix | 1 + nixos/modules/services/monitoring/tuptime.nix | 5 ++- nixos/modules/services/networking/bird.nix | 1 + nixos/modules/services/networking/ncdns.nix | 6 ++-- .../modules/services/networking/pixiecore.nix | 1 + nixos/modules/services/networking/pleroma.nix | 1 + .../modules/services/security/privacyidea.nix | 2 ++ nixos/modules/services/web-apps/nextcloud.nix | 1 + .../mysql/mariadb-galera-mariabackup.nix | 6 ++-- nixos/tests/mysql/mariadb-galera-rsync.nix | 6 ++-- nixos/tests/mysql/mysql.nix | 12 +++---- nixos/tests/redis.nix | 3 +- nixos/tests/rspamd.nix | 5 ++- nixos/tests/shadow.nix | 3 ++ nixos/tests/systemd-confinement.nix | 1 + nixos/tests/unbound.nix | 11 +++--- 23 files changed, 80 insertions(+), 32 deletions(-) diff --git a/nixos/doc/manual/development/settings-options.xml b/nixos/doc/manual/development/settings-options.xml index c99c3af92f89..7795d7c80445 100644 --- a/nixos/doc/manual/development/settings-options.xml +++ b/nixos/doc/manual/development/settings-options.xml @@ -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; }; # ... }; diff --git a/nixos/doc/manual/release-notes/rl-2105.xml b/nixos/doc/manual/release-notes/rl-2105.xml index cf9e06097237..723f928ec353 100644 --- a/nixos/doc/manual/release-notes/rl-2105.xml +++ b/nixos/doc/manual/release-notes/rl-2105.xml @@ -839,6 +839,13 @@ environment.systemPackages = [ The option's description was incorrect regarding ownership management and has been simplified greatly. + + + When defining a new user, one of and 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 has no effect for those. + + The GNOME desktop manager once again installs gnome3.epiphany by default. diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index c0e90a8c26e6..0266bbfb121d 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -306,6 +306,7 @@ in { description = "PulseAudio system service user"; home = stateDir; createHome = true; + isSystemUser = true; }; users.groups.pulse.gid = gid; diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 4a2647339c59..2b6a61e9a80e 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -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 isNormalUser and + isSystemUser must be true. ''; }; @@ -107,6 +109,8 @@ let to true, and to false. + Exactly one of isNormalUser and + isSystemUser 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) ( diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix index be661b201f0d..18fb29fd72a5 100644 --- a/nixos/modules/services/backup/borgbackup.nix +++ b/nixos/modules/services/backup/borgbackup.nix @@ -169,6 +169,7 @@ let (map (mkAuthorizedKey cfg false) cfg.authorizedKeys ++ map (mkAuthorizedKey cfg true) cfg.authorizedKeysAppendOnly); useDefaultShell = true; + isSystemUser = true; }; groups.${cfg.group} = { }; }; diff --git a/nixos/modules/services/databases/pgmanage.nix b/nixos/modules/services/databases/pgmanage.nix index 0f8634dab319..8508e76b5cd6 100644 --- a/nixos/modules/services/databases/pgmanage.nix +++ b/nixos/modules/services/databases/pgmanage.nix @@ -197,6 +197,7 @@ in { group = pgmanage; home = cfg.sqlRoot; createHome = true; + isSystemUser = true; }; groups.${pgmanage} = { name = pgmanage; diff --git a/nixos/modules/services/misc/bazarr.nix b/nixos/modules/services/misc/bazarr.nix index d3fd5b08cc84..99343a146a7a 100644 --- a/nixos/modules/services/misc/bazarr.nix +++ b/nixos/modules/services/misc/bazarr.nix @@ -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}"; }; diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index 64bdbf159d51..133e96da0ec8 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -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" ]; }; diff --git a/nixos/modules/services/monitoring/tuptime.nix b/nixos/modules/services/monitoring/tuptime.nix index 8f79d9165990..17c5c1f56eaf 100644 --- a/nixos/modules/services/monitoring/tuptime.nix +++ b/nixos/modules/services/monitoring/tuptime.nix @@ -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 = { diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix index 6d7e7760d94e..1923afdf83f2 100644 --- a/nixos/modules/services/networking/bird.nix +++ b/nixos/modules/services/networking/bird.nix @@ -73,6 +73,7 @@ let users.${variant} = { description = "BIRD Internet Routing Daemon user"; group = variant; + isSystemUser = true; }; groups.${variant} = {}; }; diff --git a/nixos/modules/services/networking/ncdns.nix b/nixos/modules/services/networking/ncdns.nix index c1832ad17520..d30fe0f6f6d1 100644 --- a/nixos/modules/services/networking/ncdns.nix +++ b/nixos/modules/services/networking/ncdns.nix @@ -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"; diff --git a/nixos/modules/services/networking/pixiecore.nix b/nixos/modules/services/networking/pixiecore.nix index 85aa40784af8..d2642c82c2d3 100644 --- a/nixos/modules/services/networking/pixiecore.nix +++ b/nixos/modules/services/networking/pixiecore.nix @@ -93,6 +93,7 @@ in users.users.pixiecore = { description = "Pixiecore daemon user"; group = "pixiecore"; + isSystemUser = true; }; networking.firewall = mkIf cfg.openFirewall { diff --git a/nixos/modules/services/networking/pleroma.nix b/nixos/modules/services/networking/pleroma.nix index 9b2bf9f61244..2687230a158d 100644 --- a/nixos/modules/services/networking/pleroma.nix +++ b/nixos/modules/services/networking/pleroma.nix @@ -75,6 +75,7 @@ in { description = "Pleroma user"; home = cfg.stateDir; extraGroups = [ cfg.group ]; + isSystemUser = true; }; groups."${cfg.group}" = {}; }; diff --git a/nixos/modules/services/security/privacyidea.nix b/nixos/modules/services/security/privacyidea.nix index f7b40089a932..2696dca4c767 100644 --- a/nixos/modules/services/security/privacyidea.nix +++ b/nixos/modules/services/security/privacyidea.nix @@ -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") {}; diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index 9a541aba6e43..58e8e5a0a8b1 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -607,6 +607,7 @@ in { home = "${cfg.home}"; group = "nextcloud"; createHome = true; + isSystemUser = true; }; users.groups.nextcloud.members = [ "nextcloud" config.services.nginx.user ]; diff --git a/nixos/tests/mysql/mariadb-galera-mariabackup.nix b/nixos/tests/mysql/mariadb-galera-mariabackup.nix index 0a40c010a471..1c73bc854a57 100644 --- a/nixos/tests/mysql/mariadb-galera-mariabackup.nix +++ b/nixos/tests/mysql/mariadb-galera-mariabackup.nix @@ -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 ]; }; diff --git a/nixos/tests/mysql/mariadb-galera-rsync.nix b/nixos/tests/mysql/mariadb-galera-rsync.nix index 6fb3cfef8d73..709a8b5085cb 100644 --- a/nixos/tests/mysql/mariadb-galera-rsync.nix +++ b/nixos/tests/mysql/mariadb-galera-rsync.nix @@ -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 ]; }; diff --git a/nixos/tests/mysql/mysql.nix b/nixos/tests/mysql/mysql.nix index 50ad5c68aef1..c21136416d47 100644 --- a/nixos/tests/mysql/mysql.nix +++ b/nixos/tests/mysql/mysql.nix @@ -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; diff --git a/nixos/tests/redis.nix b/nixos/tests/redis.nix index 79a7847414a9..28b6058c2c02 100644 --- a/nixos/tests/redis.nix +++ b/nixos/tests/redis.nix @@ -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"; }; }; }; diff --git a/nixos/tests/rspamd.nix b/nixos/tests/rspamd.nix index 7f41e1a79566..f0ccfe7ea0e6 100644 --- a/nixos/tests/rspamd.nix +++ b/nixos/tests/rspamd.nix @@ -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"]; diff --git a/nixos/tests/shadow.nix b/nixos/tests/shadow.nix index e5755e8e0878..c51961e1fc68 100644 --- a/nixos/tests/shadow.nix +++ b/nixos/tests/shadow.nix @@ -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; }; diff --git a/nixos/tests/systemd-confinement.nix b/nixos/tests/systemd-confinement.nix index ebf6d218fd68..d04e4a3f867c 100644 --- a/nixos/tests/systemd-confinement.nix +++ b/nixos/tests/systemd-confinement.nix @@ -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"; }; diff --git a/nixos/tests/unbound.nix b/nixos/tests/unbound.nix index d4b8bb15ced6..ca9718ac633e 100644 --- a/nixos/tests/unbound.nix +++ b/nixos/tests/unbound.nix @@ -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 = {