From 1dd23b5d74525ec5a093d43f73535a94aa5a9c86 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 Nov 2024 11:28:32 +0300 Subject: [PATCH 1/4] nixos/user-groups: add a toggle for user account creation Microscopic change that allows users to toggle user accounts, per user, conditionally. --- nixos/doc/manual/release-notes/rl-2505.section.md | 3 +++ nixos/modules/config/users-groups.nix | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 3cc413fcac5e..7fda749b13ab 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -462,8 +462,11 @@ - `gerbera` now has wavpack support. +- A toggle has been added under `users.users..enable` to allow toggling individual users conditionally. If set to false, the user account will not be created. + - `ddclient` was updated from 3.11.2 to 4.0.0 [Release notes](https://github.com/ddclient/ddclient/releases/tag/v4.0.0) + ```{=include=} sections diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index eb3c6c1bef7c..86d0ad9b41b7 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -124,6 +124,16 @@ let options = { + enable = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + If set to false, the user account will not be created. This is useful for when you wish to conditionally + disable user accounts. + ''; + }; + name = mkOption { type = types.passwdEntry types.str; apply = x: assert (stringLength x < 32 || abort "Username '${x}' is longer than 31 characters which is not allowed!"); x; @@ -557,7 +567,7 @@ let autoSubUidGidRange subUidRanges subGidRanges initialPassword initialHashedPassword expires; shell = utils.toShellPath u.shell; - }) cfg.users; + }) (filterAttrs (_: u: u.enable) cfg.users); groups = attrValues cfg.groups; }); From d36a3641485ae31f7e773323030bc4a04dc5e8a0 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Tue, 26 Nov 2024 16:31:02 +0300 Subject: [PATCH 2/4] nixos/tests: add user-enable-option Specifically for checking if a user exist when `users.users..enable` is set to `true`. --- nixos/tests/all-tests.nix | 1 + nixos/tests/user-enable-option.nix | 82 ++++++++++++++++++++++++++++++ nixos/tests/userborn.nix | 9 ++++ 3 files changed, 92 insertions(+) create mode 100644 nixos/tests/user-enable-option.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 2255c2f5eacc..8d88d577a41b 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1145,6 +1145,7 @@ in { userborn-mutable-etc = runTest ./userborn-mutable-etc.nix; userborn-immutable-etc = runTest ./userborn-immutable-etc.nix; user-activation-scripts = handleTest ./user-activation-scripts.nix {}; + user-enable-option = runTest ./user-enable-option.nix; user-expiry = runTest ./user-expiry.nix; user-home-mode = handleTest ./user-home-mode.nix {}; ustreamer = handleTest ./ustreamer.nix {}; diff --git a/nixos/tests/user-enable-option.nix b/nixos/tests/user-enable-option.nix new file mode 100644 index 000000000000..304777fd6a55 --- /dev/null +++ b/nixos/tests/user-enable-option.nix @@ -0,0 +1,82 @@ +let + normal-enabled = "username-normal-enabled"; + normal-disabled = "username-normal-disabled"; + system-enabled = "username-system-enabled"; + system-disabled = "username-system-disabled"; + passwd = "enableOptionPasswd"; +in +{ + name = "user-enable-option"; + + nodes.machine = { + users = { + groups.test-group = { }; + users = { + # User is enabled (default behaviour). + ${normal-enabled} = { + enable = true; + isNormalUser = true; + initialPassword = passwd; + }; + + # User is disabled. + ${normal-disabled} = { + enable = false; + isNormalUser = true; + initialPassword = passwd; + }; + + # User is a system user, and is enabled. + ${system-enabled} = { + enable = true; + isSystemUser = true; + initialPassword = passwd; + group = "test-group"; + }; + + # User is a system user, and is disabled. + ${system-disabled} = { + enable = false; + isSystemUser = true; + initialPassword = passwd; + group = "test-group"; + }; + }; + }; + }; + + testScript = '' + def switch_to_tty(tty_number): + machine.fail(f"pgrep -f 'agetty.*tty{tty_number}'") + machine.send_key(f"alt-f{tty_number}") + machine.wait_until_succeeds(f"[ $(fgconsole) = {tty_number} ]") + machine.wait_for_unit(f"getty@tty{tty_number}.service") + machine.wait_until_succeeds(f"pgrep -f 'agetty.*tty{tty_number}'") + + machine.wait_for_unit("multi-user.target") + machine.wait_for_unit("getty@tty1.service") + + with subtest("${normal-enabled} exists"): + check_fn = f"id ${normal-enabled}" + machine.succeed(check_fn) + machine.wait_until_tty_matches("1", "login: ") + machine.send_chars("${normal-enabled}\n") + machine.wait_until_tty_matches("1", "Password: ") + machine.send_chars("${passwd}\n") + + with subtest("${normal-disabled} does not exist"): + switch_to_tty(2) + check_fn = f"id ${normal-disabled}" + machine.fail(check_fn) + + with subtest("${system-enabled} exists"): + switch_to_tty(3) + check_fn = f"id ${system-enabled}" + machine.succeed(check_fn) + + with subtest("${system-disabled} does not exist"): + switch_to_tty(4) + check_fn = f"id ${system-disabled}" + machine.fail(check_fn) + ''; +} diff --git a/nixos/tests/userborn.nix b/nixos/tests/userborn.nix index 2c4f44b93ca5..7932a73b7c9b 100644 --- a/nixos/tests/userborn.nix +++ b/nixos/tests/userborn.nix @@ -66,6 +66,10 @@ in isNormalUser = true; hashedPassword = newNormaloHashedPassword; }; + normalo-disabled = { + enable = false; + isNormalUser = true; + }; }; groups = { new-group = { }; @@ -96,6 +100,11 @@ in assert 1000 > int(machine.succeed("id --user sysuser")), "sysuser user doesn't have a system UID" assert "${sysuserInitialHashedPassword}" in machine.succeed("getent shadow sysuser"), "system user password is not correct" + with subtest("normalo-disabled is NOT created"): + machine.fail("id normalo-disabled") + # Check if user's home has been created + machine.fail("[ -d '/home/normalo-disabled' ]") + with subtest("sysusers group is created"): print(machine.succeed("getent group sysusers")) From 813244ed0ff412ebc702dbe8b815f37b3144dda9 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Tue, 26 Nov 2024 19:35:44 +0300 Subject: [PATCH 3/4] nixos/userborn: filter enabled users --- nixos/modules/services/system/userborn.nix | 29 ++++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/nixos/modules/services/system/userborn.nix b/nixos/modules/services/system/userborn.nix index 4d72229573ee..96c0e6f65ae7 100644 --- a/nixos/modules/services/system/userborn.nix +++ b/nixos/modules/services/system/userborn.nix @@ -31,7 +31,7 @@ let ; isNormal = opts.isNormalUser; shell = utils.toShellPath opts.shell; - }) config.users.users; + }) (lib.filterAttrs (_: u: u.enable) config.users.users); }; userbornConfigJson = pkgs.writeText "userborn.json" (builtins.toJSON userbornConfig); @@ -95,16 +95,23 @@ in # Create home directories, do not create /var/empty even if that's a user's # home. - tmpfiles.settings.home-directories = lib.mapAttrs' ( - username: opts: - lib.nameValuePair (toString opts.home) { - d = { - mode = opts.homeMode; - user = opts.name; - inherit (opts) group; - }; - } - ) (lib.filterAttrs (_username: opts: opts.createHome && opts.home != "/var/empty") userCfg.users); + tmpfiles.settings.home-directories = + lib.mapAttrs' + ( + username: opts: + lib.nameValuePair (toString opts.home) { + d = { + mode = opts.homeMode; + user = opts.name; + inherit (opts) group; + }; + } + ) + ( + lib.filterAttrs ( + _username: opts: opts.enable && opts.createHome && opts.home != "/var/empty" + ) userCfg.users + ); services.userborn = { wantedBy = [ "sysinit.target" ]; From 75f83b13f6087f78a5b0706ef42057f7473128c9 Mon Sep 17 00:00:00 2001 From: Sandro Date: Thu, 27 Feb 2025 23:36:41 +0100 Subject: [PATCH 4/4] release-notes/25.05: drop extra added new line --- nixos/doc/manual/release-notes/rl-2505.section.md | 1 - 1 file changed, 1 deletion(-) diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 7fda749b13ab..57dfe0507c23 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -466,7 +466,6 @@ - `ddclient` was updated from 3.11.2 to 4.0.0 [Release notes](https://github.com/ddclient/ddclient/releases/tag/v4.0.0) - ```{=include=} sections