From dc6f754fe5d3b0d1ee6b033495c87ec3199a7f68 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Fri, 25 Oct 2024 01:16:19 +1100 Subject: [PATCH] users: allow `shell` to be managed by macOS --- modules/system/shells.nix | 12 +++++++++--- modules/users/default.nix | 4 ++-- modules/users/user.nix | 13 ++++++++++--- tests/users-groups.nix | 4 +++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/modules/system/shells.nix b/modules/system/shells.nix index 0b599d98..025936d4 100644 --- a/modules/system/shells.nix +++ b/modules/system/shells.nix @@ -14,9 +14,15 @@ in example = literalExpression "[ pkgs.bashInteractive pkgs.zsh ]"; description = '' A list of permissible login shells for user accounts. - No need to mention `/bin/sh` - and other shells that are available by default on - macOS. + + The default macOS shells will be automatically included: + - /bin/bash + - /bin/csh + - /bin/dash + - /bin/ksh + - /bin/sh + - /bin/tcsh + - /bin/zsh ''; apply = map (v: if types.shellPackage.check v then "/run/current-system/sw${v.shellPath}" else v); }; diff --git a/modules/users/default.nix b/modules/users/default.nix index 0b2ffd91..aee8fecc 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -242,7 +242,7 @@ in "-GID" v.gid ] ++ (lib.optionals (v.description != null) [ "-fullName" v.description ]) ++ (lib.optionals (v.home != null) [ "-home" v.home ]) - ++ [ "-shell" (shellPath v.shell) ])} 2> /dev/null + ++ [ "-shell" (if v.shell != null then shellPath v.shell else "/usr/bin/false") ])} 2> /dev/null # We need to check as `sysadminctl -addUser` still exits with exit code 0 when there's an error if ! id ${name} &> /dev/null; then @@ -260,7 +260,7 @@ in # Update properties on known users to keep them inline with configuration dscl . -create ${dsclUser} PrimaryGroupID ${toString v.gid} ${optionalString (v.description != null) "dscl . -create ${dsclUser} RealName ${lib.escapeShellArg v.description}"} - dscl . -create ${dsclUser} UserShell ${lib.escapeShellArg (shellPath v.shell)} + ${optionalString (v.shell != null) "dscl . -create ${dsclUser} UserShell ${lib.escapeShellArg (shellPath v.shell)}"} fi '') createdUsers} diff --git a/modules/users/user.nix b/modules/users/user.nix index 281b7e65..72ae07b8 100644 --- a/modules/users/user.nix +++ b/modules/users/user.nix @@ -73,10 +73,17 @@ }; shell = mkOption { - type = types.either types.shellPackage types.path; - default = "/usr/bin/false"; + type = types.nullOr (types.either types.shellPackage types.path); + default = null; example = literalExpression "pkgs.bashInteractive"; - description = "The user's shell."; + description = '' + The user's shell. This defaults to `null`. + + When this is set to `null`, if the user has not been created yet, + they will be created with the shell `/usr/bin/false` to prevent + interactive login. If the user already exists, the value is + considered managed by macOS and `nix-darwin` will not change it. + ''; }; packages = mkOption { diff --git a/tests/users-groups.nix b/tests/users-groups.nix index 290b94b5..cf2f0084 100644 --- a/tests/users-groups.nix +++ b/tests/users-groups.nix @@ -21,6 +21,7 @@ users.users."created.user".uid = 42001; users.users."created.user".description = null; users.users."created.user".home = null; + users.users."created.user".shell = null; users.users."unknown.user".uid = 42002; @@ -49,7 +50,7 @@ # checking user creation in /activate grep "sysadminctl -addUser ${lib.escapeShellArgs [ "foo" "-UID" 42000 "-GID" 42000 "-fullName" "Foo user" "-home" "/Users/foo" "-shell" "/run/current-system/sw/bin/bash" ]}" ${config.out}/activate grep "createhomedir -cu ${lib.escapeShellArg "foo"}" ${config.out}/activate - grep "sysadminctl -addUser ${lib.escapeShellArgs [ "created.user" "-UID" 42001 ]} .* ${lib.escapeShellArgs [ "-shell" "/usr/bin/false" ]}" ${config.out}/activate + grep "sysadminctl -addUser ${lib.escapeShellArgs [ "created.user" "-UID" 42001 ]} .* ${lib.escapeShellArgs [ "-shell" "/usr/bin/false" ] }" ${config.out}/activate (! grep "sysadminctl -addUser ${lib.escapeShellArg "created.user"} .* -home" ${config.out}/activate) (! grep "deleteUser ${lib.escapeShellArg "created.user"}" ${config.out}/activate) (! grep "dscl . -delete ${lib.escapeShellArg "/Groups/created.user"}" ${config.out}/activate) @@ -63,6 +64,7 @@ # checking user properties that are null don't get updated in /activate (! grep "dscl . -create ${lib.escapeShellArg "/Users/created.user"} RealName" ${config.out}/activate) + (! grep "dscl . -create ${lib.escapeShellArg "/Users/created.user"} UserShell" ${config.out}/activate) # checking user deletion in /activate grep "deleteUser ${lib.escapeShellArg "deleted.user"}" ${config.out}/activate