From def1e23be848848400d1d097d4f044e3c401f9dd Mon Sep 17 00:00:00 2001 From: Weijia Wang <9713184+wegank@users.noreply.github.com> Date: Sun, 14 Apr 2024 23:02:32 +0200 Subject: treewide: remove lib.mdDoc --- modules/users/default.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 25cc97e..cd0986d 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -39,7 +39,7 @@ in users.knownGroups = mkOption { type = types.listOf types.str; default = []; - description = lib.mdDoc '' + description = '' List of groups owned and managed by nix-darwin. Used to indicate what users are safe to create/delete based on the configuration. Don't add system groups to this. @@ -49,7 +49,7 @@ in users.knownUsers = mkOption { type = types.listOf types.str; default = []; - description = lib.mdDoc '' + description = '' List of users owned and managed by nix-darwin. Used to indicate what users are safe to create/delete based on the configuration. Don't add the admin user or other system users to this. @@ -59,13 +59,13 @@ in users.groups = mkOption { type = types.attrsOf (types.submodule group); default = {}; - description = lib.mdDoc "Configuration for groups."; + description = "Configuration for groups."; }; users.users = mkOption { type = types.attrsOf (types.submodule user); default = {}; - description = lib.mdDoc "Configuration for users."; + description = "Configuration for users."; }; users.gids = mkOption { @@ -84,7 +84,7 @@ in internal = true; type = types.bool; default = false; - description = lib.mdDoc "Remove and recreate existing groups/users."; + description = "Remove and recreate existing groups/users."; }; }; -- cgit v1.2.3 From 2788e4fa981566e34fa40938705cd7f595f05e74 Mon Sep 17 00:00:00 2001 From: Andrew Lubawy Date: Mon, 17 Jun 2024 11:56:58 -0700 Subject: Use `sysadminctl` instead of `dscl` Co-authored-by: Michael Hoang --- modules/users/default.nix | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index cd0986d..ead996c 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -147,28 +147,28 @@ in ${concatMapStringsSep "\n" (v: '' ${optionalString cfg.forceRecreate '' - u=$(dscl . -read '/Users/${v.name}' UniqueID 2> /dev/null) || true - u=''${u#UniqueID: } + u=$(id -u '${v.name}' 2> /dev/null) || true if [[ "$u" -eq ${toString v.uid} ]]; then echo "deleting user ${v.name}..." >&2 - dscl . -delete '/Users/${v.name}' 2> /dev/null + sysadminctl -deleteUser '${v.name}' 2> /dev/null else echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 fi ''} - u=$(dscl . -read '/Users/${v.name}' UniqueID 2> /dev/null) || true - u=''${u#UniqueID: } + u=$(id -u '${v.name}' 2> /dev/null) || true if [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 else if [ -z "$u" ]; then echo "creating user ${v.name}..." >&2 - dscl . -create '/Users/${v.name}' UniqueID ${toString v.uid} - dscl . -create '/Users/${v.name}' PrimaryGroupID ${toString v.gid} + sysadminctl -addUser '${v.name}' \ + -UID ${toString v.uid} \ + -GID ${toString v.gid} \ + -fullName '${v.description}' \ + -home '${v.home}' \ + -shell ${lib.escapeShellArg (shellPath v.shell)} dscl . -create '/Users/${v.name}' IsHidden ${if v.isHidden then "1" else "0"} - dscl . -create '/Users/${v.name}' RealName '${v.description}' - dscl . -create '/Users/${v.name}' NFSHomeDirectory '${v.home}' ${optionalString v.createHome "createhomedir -cu '${v.name}'"} fi # Always set the shell path, in case it was updated @@ -177,12 +177,11 @@ in '') createdUsers} ${concatMapStringsSep "\n" (name: '' - u=$(dscl . -read '/Users/${name}' UniqueID 2> /dev/null) || true - u=''${u#UniqueID: } + u=$(id -u '${name}' 2> /dev/null) || true if [ -n "$u" ]; then if [ "$u" -gt 501 ]; then echo "deleting user ${name}..." >&2 - dscl . -delete '/Users/${name}' 2> /dev/null + sysadminctl -deleteUser '${name}' 2> /dev/null else echo "warning: existing user '${name}' has unexpected uid $u, skipping..." >&2 fi -- cgit v1.2.3 From 9a6b12b9ef35cf4ac4970f94791b3dd734c0da96 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 06:58:23 +1100 Subject: users: use `lib.escapeShellArg` for `id -u` --- modules/users/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index ead996c..ffceb9b 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -147,7 +147,7 @@ in ${concatMapStringsSep "\n" (v: '' ${optionalString cfg.forceRecreate '' - u=$(id -u '${v.name}' 2> /dev/null) || true + u=$(id -u ${lib.escapeShellArg v.name} 2> /dev/null) || true if [[ "$u" -eq ${toString v.uid} ]]; then echo "deleting user ${v.name}..." >&2 sysadminctl -deleteUser '${v.name}' 2> /dev/null @@ -156,7 +156,7 @@ in fi ''} - u=$(id -u '${v.name}' 2> /dev/null) || true + u=$(id -u ${lib.escapeShellArg v.name} 2> /dev/null) || true if [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 else @@ -177,7 +177,7 @@ in '') createdUsers} ${concatMapStringsSep "\n" (name: '' - u=$(id -u '${name}' 2> /dev/null) || true + u=$(id -u ${lib.escapeShellArg name} 2> /dev/null) || true if [ -n "$u" ]; then if [ "$u" -gt 501 ]; then echo "deleting user ${name}..." >&2 -- cgit v1.2.3 From cb2e5fa6c5d99c581f9669e66e61ac1585ab56ad Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 07:05:10 +1100 Subject: users: use `lib.escapeShellArg` for `sysadminctl -deleteUser` --- modules/users/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index ffceb9b..83a6084 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -150,7 +150,7 @@ in u=$(id -u ${lib.escapeShellArg v.name} 2> /dev/null) || true if [[ "$u" -eq ${toString v.uid} ]]; then echo "deleting user ${v.name}..." >&2 - sysadminctl -deleteUser '${v.name}' 2> /dev/null + sysadminctl -deleteUser ${lib.escapeShellArg v.name} 2> /dev/null else echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 fi @@ -181,7 +181,7 @@ in if [ -n "$u" ]; then if [ "$u" -gt 501 ]; then echo "deleting user ${name}..." >&2 - sysadminctl -deleteUser '${name}' 2> /dev/null + sysadminctl -deleteUser ${lib.escapeShellArg name} 2> /dev/null else echo "warning: existing user '${name}' has unexpected uid $u, skipping..." >&2 fi -- cgit v1.2.3 From 26f7e45fb117171c9e8b27a34cfccb91ef50f068 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 09:29:56 +1100 Subject: users: use `lib.escapeShellArgs` for `sysadminctl -addUser` --- modules/users/default.nix | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 83a6084..f43b139 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -162,12 +162,7 @@ in else if [ -z "$u" ]; then echo "creating user ${v.name}..." >&2 - sysadminctl -addUser '${v.name}' \ - -UID ${toString v.uid} \ - -GID ${toString v.gid} \ - -fullName '${v.description}' \ - -home '${v.home}' \ - -shell ${lib.escapeShellArg (shellPath v.shell)} + sysadminctl -addUser ${lib.escapeShellArgs [ v.name "-UID" v.uid "-GID" v.gid "-fullName" v.description "-home" v.home "-shell" (shellPath v.shell) ]} dscl . -create '/Users/${v.name}' IsHidden ${if v.isHidden then "1" else "0"} ${optionalString v.createHome "createhomedir -cu '${v.name}'"} fi -- cgit v1.2.3 From 7bb6366f40dd4ef6efe3223e6dffb3dd7f8dea66 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 09:43:19 +1100 Subject: users: use `lib.escapeShellArgs` instead of custom version --- modules/users/default.nix | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index f43b139..90e5534 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -8,7 +8,6 @@ let group = import ./group.nix; user = import ./user.nix; - toArguments = concatMapStringsSep " " (v: "'${v}'"); toGID = v: { "${toString v.gid}" = v.name; }; toUID = v: { "${toString v.uid}" = v.name; }; @@ -121,7 +120,7 @@ in g=$(dscl . -read '/Groups/${v.name}' GroupMembership 2> /dev/null) || true if [ "$g" != 'GroupMembership: ${concatStringsSep " " v.members}' ]; then echo "updating group members ${v.name}..." >&2 - dscl . -create '/Groups/${v.name}' GroupMembership ${toArguments v.members} + dscl . -create '/Groups/${v.name}' GroupMembership ${lib.escapeShellArgs v.members} fi else echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2 -- cgit v1.2.3 From 8451125cf8eab07056da090a4616ce46a1952ff9 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 10:08:41 +1100 Subject: users: use `lib.escapeShellArg` for `dscl` paths --- modules/users/default.nix | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 90e5534..f57dfa5 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -95,45 +95,49 @@ in system.activationScripts.groups.text = mkIf (cfg.knownGroups != []) '' echo "setting up groups..." >&2 - ${concatMapStringsSep "\n" (v: '' + ${concatMapStringsSep "\n" (v: let + dsclGroup = lib.escapeShellArg "/Groups/${v.name}"; + in '' ${optionalString cfg.forceRecreate '' - g=$(dscl . -read '/Groups/${v.name}' PrimaryGroupID 2> /dev/null) || true + g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true g=''${g#PrimaryGroupID: } if [[ "$g" -eq ${toString v.gid} ]]; then echo "deleting group ${v.name}..." >&2 - dscl . -delete '/Groups/${v.name}' 2> /dev/null + dscl . -delete ${dsclGroup} 2> /dev/null else echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2 fi ''} - g=$(dscl . -read '/Groups/${v.name}' PrimaryGroupID 2> /dev/null) || true + g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true g=''${g#PrimaryGroupID: } if [ -z "$g" ]; then echo "creating group ${v.name}..." >&2 - dscl . -create '/Groups/${v.name}' PrimaryGroupID ${toString v.gid} - dscl . -create '/Groups/${v.name}' RealName '${v.description}' + dscl . -create ${dsclGroup} PrimaryGroupID ${toString v.gid} + dscl . -create ${dsclGroup} RealName '${v.description}' g=${toString v.gid} fi if [ "$g" -eq ${toString v.gid} ]; then - g=$(dscl . -read '/Groups/${v.name}' GroupMembership 2> /dev/null) || true + g=$(dscl . -read ${dsclGroup} GroupMembership 2> /dev/null) || true if [ "$g" != 'GroupMembership: ${concatStringsSep " " v.members}' ]; then echo "updating group members ${v.name}..." >&2 - dscl . -create '/Groups/${v.name}' GroupMembership ${lib.escapeShellArgs v.members} + dscl . -create ${dsclGroup} GroupMembership ${lib.escapeShellArgs v.members} fi else echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2 fi '') createdGroups} - ${concatMapStringsSep "\n" (name: '' - g=$(dscl . -read '/Groups/${name}' PrimaryGroupID 2> /dev/null) || true + ${concatMapStringsSep "\n" (name: let + dsclGroup = lib.escapeShellArg "/Groups/${name}"; + in '' + g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true g=''${g#PrimaryGroupID: } if [ -n "$g" ]; then if [ "$g" -gt 501 ]; then echo "deleting group ${name}..." >&2 - dscl . -delete '/Groups/${name}' 2> /dev/null + dscl . -delete ${dsclGroup} 2> /dev/null else echo "warning: existing group '${name}' has unexpected gid $g, skipping..." >&2 fi @@ -144,7 +148,9 @@ in system.activationScripts.users.text = mkIf (cfg.knownUsers != []) '' echo "setting up users..." >&2 - ${concatMapStringsSep "\n" (v: '' + ${concatMapStringsSep "\n" (v: let + dsclUser = lib.escapeShellArg "/Users/${v.name}"; + in '' ${optionalString cfg.forceRecreate '' u=$(id -u ${lib.escapeShellArg v.name} 2> /dev/null) || true if [[ "$u" -eq ${toString v.uid} ]]; then @@ -162,11 +168,11 @@ in if [ -z "$u" ]; then echo "creating user ${v.name}..." >&2 sysadminctl -addUser ${lib.escapeShellArgs [ v.name "-UID" v.uid "-GID" v.gid "-fullName" v.description "-home" v.home "-shell" (shellPath v.shell) ]} - dscl . -create '/Users/${v.name}' IsHidden ${if v.isHidden then "1" else "0"} + dscl . -create ${dsclUser} IsHidden ${if v.isHidden then "1" else "0"} ${optionalString v.createHome "createhomedir -cu '${v.name}'"} fi # Always set the shell path, in case it was updated - dscl . -create '/Users/${v.name}' UserShell ${lib.escapeShellArg (shellPath v.shell)} + dscl . -create ${dsclUser} UserShell ${lib.escapeShellArg (shellPath v.shell)} fi '') createdUsers} -- cgit v1.2.3 From ea7e178ad4113c2134c5b734e3198ebbc591af0b Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 10:20:43 +1100 Subject: users: use `lib.escapeShellArg` for `createhomedir` --- modules/users/default.nix | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index f57dfa5..08785be 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -149,19 +149,20 @@ in echo "setting up users..." >&2 ${concatMapStringsSep "\n" (v: let + name = lib.escapeShellArg v.name; dsclUser = lib.escapeShellArg "/Users/${v.name}"; in '' ${optionalString cfg.forceRecreate '' - u=$(id -u ${lib.escapeShellArg v.name} 2> /dev/null) || true + u=$(id -u ${name} 2> /dev/null) || true if [[ "$u" -eq ${toString v.uid} ]]; then echo "deleting user ${v.name}..." >&2 - sysadminctl -deleteUser ${lib.escapeShellArg v.name} 2> /dev/null + sysadminctl -deleteUser ${name} 2> /dev/null else echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 fi ''} - u=$(id -u ${lib.escapeShellArg v.name} 2> /dev/null) || true + u=$(id -u ${name} 2> /dev/null) || true if [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 else @@ -169,7 +170,7 @@ in echo "creating user ${v.name}..." >&2 sysadminctl -addUser ${lib.escapeShellArgs [ v.name "-UID" v.uid "-GID" v.gid "-fullName" v.description "-home" v.home "-shell" (shellPath v.shell) ]} dscl . -create ${dsclUser} IsHidden ${if v.isHidden then "1" else "0"} - ${optionalString v.createHome "createhomedir -cu '${v.name}'"} + ${optionalString v.createHome "createhomedir -cu ${name}"} fi # Always set the shell path, in case it was updated dscl . -create ${dsclUser} UserShell ${lib.escapeShellArg (shellPath v.shell)} -- cgit v1.2.3 From ac7932f9de36b8126abcb9d4966d5d95fcadd807 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 10:24:06 +1100 Subject: users: use `lib.escapeShellArg` for group description --- modules/users/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 08785be..9f906b3 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -114,7 +114,7 @@ in if [ -z "$g" ]; then echo "creating group ${v.name}..." >&2 dscl . -create ${dsclGroup} PrimaryGroupID ${toString v.gid} - dscl . -create ${dsclGroup} RealName '${v.description}' + dscl . -create ${dsclGroup} RealName ${lib.escapeShellArg v.description} g=${toString v.gid} fi -- cgit v1.2.3 From 11c777c7198f4cfcd55fe81646e503c58ceb9f4a Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 10:24:06 +1100 Subject: users: change default `description` to `null` --- modules/users/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 9f906b3..e9e3ac4 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -168,7 +168,7 @@ in else if [ -z "$u" ]; then echo "creating user ${v.name}..." >&2 - sysadminctl -addUser ${lib.escapeShellArgs [ v.name "-UID" v.uid "-GID" v.gid "-fullName" v.description "-home" v.home "-shell" (shellPath v.shell) ]} + sysadminctl -addUser ${lib.escapeShellArgs ([ v.name "-UID" v.uid "-GID" v.gid ] ++ (lib.optionals (v.description != null) [ "-fullName" v.description ]) ++ [ "-home" v.home "-shell" (shellPath v.shell) ])} dscl . -create ${dsclUser} IsHidden ${if v.isHidden then "1" else "0"} ${optionalString v.createHome "createhomedir -cu ${name}"} fi -- cgit v1.2.3 From 8c02940d702170feea7947f768aa807c11b65a41 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 22 Oct 2024 22:38:17 +1100 Subject: users: ensure Full Disk Access is granted before trying to delete users --- modules/users/default.nix | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index e9e3ac4..ce77d4d 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -148,6 +148,42 @@ in system.activationScripts.users.text = mkIf (cfg.knownUsers != []) '' echo "setting up users..." >&2 + deleteUser() { + fullDiskAccess=false + + if cat /Library/Preferences/com.apple.TimeMachine.plist > /dev/null 2>&1; then + fullDiskAccess=true + fi + + if [[ "$fullDiskAccess" != true ]]; then + printf >&2 '\e[1;31merror: users cannot be deleted without Full Disk Access, aborting activation\e[0m\n' + printf >&2 'The user %s could not be deleted as `darwin-rebuild` was not executed with Full Disk Access.' "$1" + + printf >&2 'Opening "Privacy & Security" > "Full Disk Access" in System Settings\n' + printf >&2 '\n' + # This command will fail if run as root and System Settings is already running + # even if System Settings was launched by root. + sudo -u $SUDO_USER open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles" + + if [[ -n "$SSH_CONNECTION" ]]; then + printf >&2 'Please enable Full Disk Access for programs over SSH by flipping\n' + printf >&2 'the switch for `sshd-keygen-wrapper`.\n' + else + printf >&2 'Please enable Full Disk Access for your terminal emulator by flipping\n' + printf >&2 'the switch in System Settings.\n' + fi + + exit 1 + fi + + sysadminctl -deleteUser "$1" 2> /dev/null + + if id -u "$1" > /dev/null 2>&1; then + printf >&2 '\e[1;31merror: failed to delete user %s, aborting activation\e[0m\n', "$1" + exit 1 + fi + } + ${concatMapStringsSep "\n" (v: let name = lib.escapeShellArg v.name; dsclUser = lib.escapeShellArg "/Users/${v.name}"; @@ -156,7 +192,7 @@ in u=$(id -u ${name} 2> /dev/null) || true if [[ "$u" -eq ${toString v.uid} ]]; then echo "deleting user ${v.name}..." >&2 - sysadminctl -deleteUser ${name} 2> /dev/null + deleteUser ${name} else echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 fi @@ -182,7 +218,7 @@ in if [ -n "$u" ]; then if [ "$u" -gt 501 ]; then echo "deleting user ${name}..." >&2 - sysadminctl -deleteUser ${lib.escapeShellArg name} 2> /dev/null + deleteUser ${lib.escapeShellArg name} else echo "warning: existing user '${name}' has unexpected uid $u, skipping..." >&2 fi -- cgit v1.2.3 From bbe1917238b3ea22890e5aa3fe51ed6910ee9429 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Thu, 24 Oct 2024 14:14:15 +1100 Subject: users: ensure users' shells are installed --- modules/users/default.nix | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index ce77d4d..e4be46a 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -31,6 +31,12 @@ let then "/run/current-system/sw${v.shellPath}" else v; + systemShells = + let + shells = mapAttrsToList (_: u: u.shell) cfg.users; + in + filter types.shellPackage.check shells; + in { @@ -226,6 +232,9 @@ in '') deletedUsers} ''; + # Install all the user shells + environment.systemPackages = systemShells; + environment.etc = mapAttrs' (name: { packages, ... }: { name = "profiles/per-user/${name}"; value.source = pkgs.buildEnv { -- cgit v1.2.3 From 467a0d3d0c27ed7e688c040281aced98d37120d2 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Thu, 24 Oct 2024 02:00:15 +1100 Subject: users: prevent deleting the user calling `darwin-rebuild` `sysadminctl -deleteUser` will only prevent you from deleting the current user if it's not the last admin and not the last secure token user, otherwise it will happily oblige. --- modules/users/default.nix | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index ce77d4d..e8a030b 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -149,6 +149,15 @@ in echo "setting up users..." >&2 deleteUser() { + # TODO: add `darwin.primaryUser` as well + if [[ "$1" == "$SUDO_USER" ]]; then + printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', "$1" + exit 1 + elif [[ "$1" == "root" ]]; then + printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n', "$1" + exit 1 + fi + fullDiskAccess=false if cat /Library/Preferences/com.apple.TimeMachine.plist > /dev/null 2>&1; then @@ -191,8 +200,15 @@ in ${optionalString cfg.forceRecreate '' u=$(id -u ${name} 2> /dev/null) || true if [[ "$u" -eq ${toString v.uid} ]]; then - echo "deleting user ${v.name}..." >&2 - deleteUser ${name} + # TODO: add `darwin.primaryUser` as well + if [[ ${name} == "$SUDO_USER" ]]; then + printf >&2 'warning: not going to recreate the user calling `darwin-rebuild` (%s), skipping...\n' "$SUDO_USER" + elif [[ ${name} == "root" ]]; then + printf >&2 'warning: not going to recreate root, skipping...\n' + else + printf >&2 'deleting user ${v.name}...\n' + deleteUser ${name} + fi else echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 fi -- cgit v1.2.3 From 2be05de06ed8e634c839ad58ffb895d5bed98c0a Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Thu, 24 Oct 2024 12:44:45 +1100 Subject: users: add missing newlines for FDA prompt --- modules/users/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index e8a030b..1d7127a 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -166,8 +166,8 @@ in if [[ "$fullDiskAccess" != true ]]; then printf >&2 '\e[1;31merror: users cannot be deleted without Full Disk Access, aborting activation\e[0m\n' - printf >&2 'The user %s could not be deleted as `darwin-rebuild` was not executed with Full Disk Access.' "$1" - + printf >&2 'The user %s could not be deleted as `darwin-rebuild` was not executed with Full Disk Access.\n' "$1" + printf >&2 '\n' printf >&2 'Opening "Privacy & Security" > "Full Disk Access" in System Settings\n' printf >&2 '\n' # This command will fail if run as root and System Settings is already running -- cgit v1.2.3 From b702750226a86abb029440641bfa994ff650cf99 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Thu, 24 Oct 2024 13:13:52 +1100 Subject: users: ensure Full Disk Access is granted before trying to create users --- modules/users/default.nix | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 1d7127a..9227080 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -148,16 +148,7 @@ in system.activationScripts.users.text = mkIf (cfg.knownUsers != []) '' echo "setting up users..." >&2 - deleteUser() { - # TODO: add `darwin.primaryUser` as well - if [[ "$1" == "$SUDO_USER" ]]; then - printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', "$1" - exit 1 - elif [[ "$1" == "root" ]]; then - printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n', "$1" - exit 1 - fi - + requireFDA() { fullDiskAccess=false if cat /Library/Preferences/com.apple.TimeMachine.plist > /dev/null 2>&1; then @@ -165,8 +156,8 @@ in fi if [[ "$fullDiskAccess" != true ]]; then - printf >&2 '\e[1;31merror: users cannot be deleted without Full Disk Access, aborting activation\e[0m\n' - printf >&2 'The user %s could not be deleted as `darwin-rebuild` was not executed with Full Disk Access.\n' "$1" + printf >&2 '\e[1;31merror: users cannot be %s without Full Disk Access, aborting activation\e[0m\n' "$2" + printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access.\n' "$1" "$2" printf >&2 '\n' printf >&2 'Opening "Privacy & Security" > "Full Disk Access" in System Settings\n' printf >&2 '\n' @@ -184,10 +175,24 @@ in exit 1 fi + } + + deleteUser() { + # FIXME: add `darwin.primaryUser` as well + if [[ "$1" == "$SUDO_USER" ]]; then + printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', "$1" + exit 1 + elif [[ "$1" == "root" ]]; then + printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n', "$1" + exit 1 + fi + + requireFDA "$1" deleted sysadminctl -deleteUser "$1" 2> /dev/null - if id -u "$1" > /dev/null 2>&1; then + # We need to check as `sysadminctl -deleteUser` still exits with exit code 0 when there's an error + if id "$1" &> /dev/null; then printf >&2 '\e[1;31merror: failed to delete user %s, aborting activation\e[0m\n', "$1" exit 1 fi @@ -220,7 +225,17 @@ in else if [ -z "$u" ]; then echo "creating user ${v.name}..." >&2 - sysadminctl -addUser ${lib.escapeShellArgs ([ v.name "-UID" v.uid "-GID" v.gid ] ++ (lib.optionals (v.description != null) [ "-fullName" v.description ]) ++ [ "-home" v.home "-shell" (shellPath v.shell) ])} + + requireFDA ${name} "created" + + sysadminctl -addUser ${lib.escapeShellArgs ([ v.name "-UID" v.uid "-GID" v.gid ] ++ (lib.optionals (v.description != null) [ "-fullName" v.description ]) ++ [ "-home" v.home "-shell" (shellPath v.shell) ])} 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 + printf >&2 '\e[1;31merror: failed to create user %s, aborting activation\e[0m\n' ${name} + exit 1 + fi + dscl . -create ${dsclUser} IsHidden ${if v.isHidden then "1" else "0"} ${optionalString v.createHome "createhomedir -cu ${name}"} fi -- cgit v1.2.3 From b089e7e7266403ddda9f96bfd8c5adf9a0f0f6b5 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Thu, 24 Oct 2024 18:30:55 +1100 Subject: users: switch back to using `dscl` for deleting users The previous default behaviour when nix-darwin deletes users is that their home directories are left intact, however as the `-keepHome` flag for `sysadminctl -deleteUser` is broken, we'll need to switch back for now. --- modules/users/default.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 9227080..0cb4350 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -189,8 +189,10 @@ in requireFDA "$1" deleted - sysadminctl -deleteUser "$1" 2> /dev/null + dscl . -delete "/Users/$1" 2> /dev/null + # `dscl . -delete` should exit with a non-zero exit code when there's an error, but we'll leave + # this code here just in case and for when we switch to `sysadminctl -deleteUser` # We need to check as `sysadminctl -deleteUser` still exits with exit code 0 when there's an error if id "$1" &> /dev/null; then printf >&2 '\e[1;31merror: failed to delete user %s, aborting activation\e[0m\n', "$1" -- cgit v1.2.3 From c9af5c2d1394d1bc34f4722998bcd51714ccd68c Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Thu, 24 Oct 2024 22:58:35 +1100 Subject: users: update properties on known users --- modules/users/default.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index b636d6f..f293f77 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -247,7 +247,10 @@ in dscl . -create ${dsclUser} IsHidden ${if v.isHidden then "1" else "0"} ${optionalString v.createHome "createhomedir -cu ${name}"} fi - # Always set the shell path, in case it was updated + + # 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)} fi '') createdUsers} -- cgit v1.2.3 From bd161d61d6f322e1c16543b67b1dbd13934e763c Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Thu, 24 Oct 2024 23:19:27 +1100 Subject: users: allow `home` to be managed by macOS --- modules/users/default.nix | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index f293f77..0b2ffd9 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -236,7 +236,13 @@ in requireFDA ${name} "created" - sysadminctl -addUser ${lib.escapeShellArgs ([ v.name "-UID" v.uid "-GID" v.gid ] ++ (lib.optionals (v.description != null) [ "-fullName" v.description ]) ++ [ "-home" v.home "-shell" (shellPath v.shell) ])} 2> /dev/null + sysadminctl -addUser ${lib.escapeShellArgs ([ + v.name + "-UID" v.uid + "-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 # We need to check as `sysadminctl -addUser` still exits with exit code 0 when there's an error if ! id ${name} &> /dev/null; then @@ -245,7 +251,10 @@ in fi dscl . -create ${dsclUser} IsHidden ${if v.isHidden then "1" else "0"} - ${optionalString v.createHome "createhomedir -cu ${name}"} + + # `sysadminctl -addUser` won't create the home directory if we use the `-home` + # flag so we need to do it ourselves + ${optionalString (v.home != null && v.createHome) "createhomedir -cu ${name} > /dev/null"} fi # Update properties on known users to keep them inline with configuration -- cgit v1.2.3 From dc6f754fe5d3b0d1ee6b033495c87ec3199a7f68 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Fri, 25 Oct 2024 01:16:19 +1100 Subject: users: allow `shell` to be managed by macOS --- modules/users/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 0b2ffd9..aee8fec 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} -- cgit v1.2.3 From 55be3e1a5f9c816f30baf0d9de8ba77c954847dd Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Sat, 26 Oct 2024 12:31:53 +1100 Subject: users: move checks to `system.checks` --- modules/users/default.nix | 120 ++++++++++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 42 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index aee8fec..a618792 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -98,6 +98,84 @@ in users.gids = mkMerge gids; users.uids = mkMerge uids; + # NOTE: We put this in `system.checks` as we want this to run first to avoid partial activations + # however currently that runs at user level activation as that runs before system level activation + # TODO: replace `$USER` with `$SUDO_USER` when system.checks runs from system level + system.checks.text = lib.mkAfter '' + requireFDA() { + fullDiskAccess=false + + if cat /Library/Preferences/com.apple.TimeMachine.plist > /dev/null 2>&1; then + fullDiskAccess=true + fi + + if [[ "$fullDiskAccess" != true ]]; then + printf >&2 '\e[1;31merror: users cannot be %s without Full Disk Access, aborting activation\e[0m\n' "$2" + printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access.\n' "$1" "$2" + printf >&2 '\n' + printf >&2 'Opening "Privacy & Security" > "Full Disk Access" in System Settings\n' + printf >&2 '\n' + # This command will fail if run as root and System Settings is already running + # even if System Settings was launched by root. + open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles" + + if [[ -n "$SSH_CONNECTION" ]]; then + printf >&2 'Please enable Full Disk Access for programs over SSH by flipping\n' + printf >&2 'the switch for `sshd-keygen-wrapper`.\n' + else + printf >&2 'Please enable Full Disk Access for your terminal emulator by flipping\n' + printf >&2 'the switch in System Settings.\n' + fi + + exit 1 + fi + } + + ensureDeletable() { + # TODO: add `darwin.primaryUser` as well + if [[ "$1" == "$USER" ]]; then + printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', "$1" + exit 1 + elif [[ "$1" == "root" ]]; then + printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n' + exit 1 + fi + + requireFDA "$1" deleted + } + + ${concatMapStringsSep "\n" (v: let + name = lib.escapeShellArg v.name; + dsclUser = lib.escapeShellArg "/Users/${v.name}"; + in '' + ${optionalString cfg.forceRecreate '' + u=$(id -u ${name} 2> /dev/null) || true + if [[ "$u" -eq ${toString v.uid} ]]; then + # TODO: add `darwin.primaryUser` as well + if [[ ${name} != "$USER" && ${name} != "root" ]]; then + ensureDeletable ${name} + fi + fi + ''} + + u=$(id -u ${name} 2> /dev/null) || true + if ! [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then + if [ -z "$u" ]; then + requireFDA ${name} created + fi + fi + '') createdUsers} + + ${concatMapStringsSep "\n" (name: '' + u=$(id -u ${lib.escapeShellArg name} 2> /dev/null) || true + if [ -n "$u" ]; then + if [ "$u" -gt 501 ]; then + ensureDeletable ${lib.escapeShellArg name} + fi + fi + '') deletedUsers} + ''; + system.activationScripts.groups.text = mkIf (cfg.knownGroups != []) '' echo "setting up groups..." >&2 @@ -154,47 +232,7 @@ in system.activationScripts.users.text = mkIf (cfg.knownUsers != []) '' echo "setting up users..." >&2 - requireFDA() { - fullDiskAccess=false - - if cat /Library/Preferences/com.apple.TimeMachine.plist > /dev/null 2>&1; then - fullDiskAccess=true - fi - - if [[ "$fullDiskAccess" != true ]]; then - printf >&2 '\e[1;31merror: users cannot be %s without Full Disk Access, aborting activation\e[0m\n' "$2" - printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access.\n' "$1" "$2" - printf >&2 '\n' - printf >&2 'Opening "Privacy & Security" > "Full Disk Access" in System Settings\n' - printf >&2 '\n' - # This command will fail if run as root and System Settings is already running - # even if System Settings was launched by root. - sudo -u $SUDO_USER open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles" - - if [[ -n "$SSH_CONNECTION" ]]; then - printf >&2 'Please enable Full Disk Access for programs over SSH by flipping\n' - printf >&2 'the switch for `sshd-keygen-wrapper`.\n' - else - printf >&2 'Please enable Full Disk Access for your terminal emulator by flipping\n' - printf >&2 'the switch in System Settings.\n' - fi - - exit 1 - fi - } - deleteUser() { - # FIXME: add `darwin.primaryUser` as well - if [[ "$1" == "$SUDO_USER" ]]; then - printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', "$1" - exit 1 - elif [[ "$1" == "root" ]]; then - printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n', "$1" - exit 1 - fi - - requireFDA "$1" deleted - dscl . -delete "/Users/$1" 2> /dev/null # `dscl . -delete` should exit with a non-zero exit code when there's an error, but we'll leave @@ -234,8 +272,6 @@ in if [ -z "$u" ]; then echo "creating user ${v.name}..." >&2 - requireFDA ${name} "created" - sysadminctl -addUser ${lib.escapeShellArgs ([ v.name "-UID" v.uid -- cgit v1.2.3 From 9cd3976486fd0d189cbb3ad3e71c345502a3b1f5 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Sat, 26 Oct 2024 12:31:53 +1100 Subject: users: ensure all users' home directories in the config are correct --- modules/users/default.nix | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index a618792..3f614c6 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -94,6 +94,14 @@ in }; config = { + assertions = [ + { + # We don't check `root` like the rest of the users as on some systems `root`'s + # home directory is set to `/var/root /private/var/root` + assertion = cfg.users ? root -> (cfg.users.root.home == null || cfg.users.root.home == "/var/root"); + message = "`users.users.root.home` must be set to either `null` or `/var/root`."; + } + ]; users.gids = mkMerge gids; users.uids = mkMerge uids; @@ -163,6 +171,22 @@ in if [ -z "$u" ]; then requireFDA ${name} created fi + + ${optionalString (v.home != null && v.name != "root") '' + homeDirectory=$(dscl . -read ${dsclUser} NFSHomeDirectory) + homeDirectory=''${homeDirectory#NFSHomeDirectory: } + if [[ ${lib.escapeShellArg v.home} != "$homeDirectory" ]]; then + printf >&2 '\e[1;31merror: config contains the wrong home directory for %s, aborting activation\e[0m\n' ${name} + printf >&2 'nix-darwin does not support changing the home directory of existing users. + printf >&2 '\n' + printf >&2 'Please set:\n' + printf >&2 '\n' + printf >&2 ' users.users.%s.home = "%s";\n' ${name} "$homeDirectory" + printf >&2 '\n' + printf >&2 'or remove it from your configuration.\n' + exit 1 + fi + ''} fi '') createdUsers} -- cgit v1.2.3 From 32f0cf2140af6a852f8c8b6c8f15e4855d461b87 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 28 Oct 2024 00:37:55 +1100 Subject: users: replace FDA check with more fine grained permissions check --- modules/users/default.nix | 78 +++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 39 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 3f614c6..c6c66f3 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -110,32 +110,44 @@ in # however currently that runs at user level activation as that runs before system level activation # TODO: replace `$USER` with `$SUDO_USER` when system.checks runs from system level system.checks.text = lib.mkAfter '' - requireFDA() { - fullDiskAccess=false - - if cat /Library/Preferences/com.apple.TimeMachine.plist > /dev/null 2>&1; then - fullDiskAccess=true - fi - - if [[ "$fullDiskAccess" != true ]]; then - printf >&2 '\e[1;31merror: users cannot be %s without Full Disk Access, aborting activation\e[0m\n' "$2" - printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access.\n' "$1" "$2" - printf >&2 '\n' - printf >&2 'Opening "Privacy & Security" > "Full Disk Access" in System Settings\n' - printf >&2 '\n' - # This command will fail if run as root and System Settings is already running - # even if System Settings was launched by root. - open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles" + ensurePerms() { + homeDirectory=$(dscl . -read /Users/nobody NFSHomeDirectory) + homeDirectory=''${homeDirectory#NFSHomeDirectory: } + if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then if [[ -n "$SSH_CONNECTION" ]]; then - printf >&2 'Please enable Full Disk Access for programs over SSH by flipping\n' - printf >&2 'the switch for `sshd-keygen-wrapper`.\n' + printf >&2 '\e[1;31merror: users cannot be %s over SSH without Full Disk Access, aborting activation\e[0m\n' "$2" + printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access over SSH.\n' "$1" "$2" + printf >&2 'You can either:\n' + printf >&2 '\n' + printf >&2 ' grant Full Disk Access to all programs run over SSH\n' + printf >&2 '\n' + printf >&2 'or\n' + printf >&2 '\n' + printf >&2 ' run `darwin-rebuild` in a graphical session.\n' + printf >&2 '\n' + printf >&2 'The option "Allow full disk access for remote users" can be found by\n' + printf >&2 'navigating to System Settings > General > Sharing > Remote Login\n' + printf >&2 'and then pressing on the i icon next to the switch.\n' + exit 1 else - printf >&2 'Please enable Full Disk Access for your terminal emulator by flipping\n' - printf >&2 'the switch in System Settings.\n' + # The TCC service required to change home directories is `kTCCServiceSystemPolicySysAdminFiles` + # and we can reset it to ensure the user gets another prompt + tccutil reset SystemPolicySysAdminFiles > /dev/null + + if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then + printf >&2 '\e[1;31merror: permission denied when trying to %s user %s, aborting activation\e[0m\n' "$2" "$1" + printf >&2 '`darwin-rebuild` requires permissions to administrate your computer,\n' "$1" "$2" + printf >&2 'please accept the dialog that pops up.\n' + printf >&2 '\n' + printf >&2 'If you do not wish to be prompted every time `darwin-rebuild updates your users,\n' + printf >&2 'you can grant Full Disk Access to your terminal emulator in System Settings.\n' + printf >&2 '\n' + printf >&2 'This can be found in System Settings > Privacy & Security > Full Disk Access.\n' + exit 1 + fi fi - exit 1 fi } @@ -149,7 +161,7 @@ in exit 1 fi - requireFDA "$1" deleted + ensurePerms "$1" delete } ${concatMapStringsSep "\n" (v: let @@ -169,7 +181,7 @@ in u=$(id -u ${name} 2> /dev/null) || true if ! [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then if [ -z "$u" ]; then - requireFDA ${name} created + ensurePerms ${name} create fi ${optionalString (v.home != null && v.name != "root") '' @@ -211,7 +223,7 @@ in g=''${g#PrimaryGroupID: } if [[ "$g" -eq ${toString v.gid} ]]; then echo "deleting group ${v.name}..." >&2 - dscl . -delete ${dsclGroup} 2> /dev/null + dscl . -delete ${dsclGroup} else echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2 fi @@ -245,7 +257,7 @@ in if [ -n "$g" ]; then if [ "$g" -gt 501 ]; then echo "deleting group ${name}..." >&2 - dscl . -delete ${dsclGroup} 2> /dev/null + dscl . -delete ${dsclGroup} else echo "warning: existing group '${name}' has unexpected gid $g, skipping..." >&2 fi @@ -256,18 +268,6 @@ in system.activationScripts.users.text = mkIf (cfg.knownUsers != []) '' echo "setting up users..." >&2 - deleteUser() { - dscl . -delete "/Users/$1" 2> /dev/null - - # `dscl . -delete` should exit with a non-zero exit code when there's an error, but we'll leave - # this code here just in case and for when we switch to `sysadminctl -deleteUser` - # We need to check as `sysadminctl -deleteUser` still exits with exit code 0 when there's an error - if id "$1" &> /dev/null; then - printf >&2 '\e[1;31merror: failed to delete user %s, aborting activation\e[0m\n', "$1" - exit 1 - fi - } - ${concatMapStringsSep "\n" (v: let name = lib.escapeShellArg v.name; dsclUser = lib.escapeShellArg "/Users/${v.name}"; @@ -282,7 +282,7 @@ in printf >&2 'warning: not going to recreate root, skipping...\n' else printf >&2 'deleting user ${v.name}...\n' - deleteUser ${name} + dscl . -delete ${dsclUser} fi else echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 @@ -329,7 +329,7 @@ in if [ -n "$u" ]; then if [ "$u" -gt 501 ]; then echo "deleting user ${name}..." >&2 - deleteUser ${lib.escapeShellArg name} + dscl . -delete ${lib.escapeShellArg "/Users/${name}"} else echo "warning: existing user '${name}' has unexpected uid $u, skipping..." >&2 fi -- cgit v1.2.3 From febc3b3f514d1e3d46182975430737d0232e6af0 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Sat, 26 Oct 2024 16:13:23 +1100 Subject: users: remove `with lib;` --- modules/users/default.nix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index c6c66f3..a23251d 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -1,8 +1,9 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) concatStringsSep concatMapStringsSep elem filter filterAttrs + mapAttrs' mapAttrsToList mkIf mkMerge mkOption mkOrder optionalString types; + cfg = config.users; group = import ./group.nix; -- cgit v1.2.3 From a15a3d9f1f9fadd455b38b3833e1ee6db6b59186 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 28 Oct 2024 10:47:15 +1100 Subject: users: fix unclosed string --- modules/users/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index a23251d..92c0cd8 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -190,7 +190,7 @@ in homeDirectory=''${homeDirectory#NFSHomeDirectory: } if [[ ${lib.escapeShellArg v.home} != "$homeDirectory" ]]; then printf >&2 '\e[1;31merror: config contains the wrong home directory for %s, aborting activation\e[0m\n' ${name} - printf >&2 'nix-darwin does not support changing the home directory of existing users. + printf >&2 'nix-darwin does not support changing the home directory of existing users.\n' printf >&2 '\n' printf >&2 'Please set:\n' printf >&2 '\n' -- cgit v1.2.3 From c908607e8a8ac1aaa0db60955800be4b02e500cc Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 28 Oct 2024 01:05:16 +1100 Subject: users: remove `users.forceRecreate` option --- modules/users/default.nix | 78 +++++++++++------------------------------------ 1 file changed, 18 insertions(+), 60 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 92c0cd8..58156d2 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -41,6 +41,10 @@ let in { + imports = [ + (lib.mkRemovedOptionModule [ "users" "forceRecreate" ] "") + ]; + options = { users.knownGroups = mkOption { type = types.listOf types.str; @@ -85,13 +89,6 @@ in type = types.attrsOf types.str; default = {}; }; - - users.forceRecreate = mkOption { - internal = true; - type = types.bool; - default = false; - description = "Remove and recreate existing groups/users."; - }; }; config = { @@ -152,33 +149,11 @@ in fi } - ensureDeletable() { - # TODO: add `darwin.primaryUser` as well - if [[ "$1" == "$USER" ]]; then - printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', "$1" - exit 1 - elif [[ "$1" == "root" ]]; then - printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n' - exit 1 - fi - - ensurePerms "$1" delete - } ${concatMapStringsSep "\n" (v: let name = lib.escapeShellArg v.name; dsclUser = lib.escapeShellArg "/Users/${v.name}"; in '' - ${optionalString cfg.forceRecreate '' - u=$(id -u ${name} 2> /dev/null) || true - if [[ "$u" -eq ${toString v.uid} ]]; then - # TODO: add `darwin.primaryUser` as well - if [[ ${name} != "$USER" && ${name} != "root" ]]; then - ensureDeletable ${name} - fi - fi - ''} - u=$(id -u ${name} 2> /dev/null) || true if ! [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then if [ -z "$u" ]; then @@ -203,11 +178,22 @@ in fi '') createdUsers} - ${concatMapStringsSep "\n" (name: '' - u=$(id -u ${lib.escapeShellArg name} 2> /dev/null) || true + ${concatMapStringsSep "\n" (v: let + name = lib.escapeShellArg v; + in '' + u=$(id -u ${name} 2> /dev/null) || true if [ -n "$u" ]; then if [ "$u" -gt 501 ]; then - ensureDeletable ${lib.escapeShellArg name} + # TODO: add `darwin.primaryUser` as well + if [[ ${name} == "$USER" ]]; then + printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', ${name} + exit 1 + elif [[ ${name} == "root" ]]; then + printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n' + exit 1 + fi + + ensurePerms ${name} delete fi fi '') deletedUsers} @@ -219,17 +205,6 @@ in ${concatMapStringsSep "\n" (v: let dsclGroup = lib.escapeShellArg "/Groups/${v.name}"; in '' - ${optionalString cfg.forceRecreate '' - g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true - g=''${g#PrimaryGroupID: } - if [[ "$g" -eq ${toString v.gid} ]]; then - echo "deleting group ${v.name}..." >&2 - dscl . -delete ${dsclGroup} - else - echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2 - fi - ''} - g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true g=''${g#PrimaryGroupID: } if [ -z "$g" ]; then @@ -273,23 +248,6 @@ in name = lib.escapeShellArg v.name; dsclUser = lib.escapeShellArg "/Users/${v.name}"; in '' - ${optionalString cfg.forceRecreate '' - u=$(id -u ${name} 2> /dev/null) || true - if [[ "$u" -eq ${toString v.uid} ]]; then - # TODO: add `darwin.primaryUser` as well - if [[ ${name} == "$SUDO_USER" ]]; then - printf >&2 'warning: not going to recreate the user calling `darwin-rebuild` (%s), skipping...\n' "$SUDO_USER" - elif [[ ${name} == "root" ]]; then - printf >&2 'warning: not going to recreate root, skipping...\n' - else - printf >&2 'deleting user ${v.name}...\n' - dscl . -delete ${dsclUser} - fi - else - echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 - fi - ''} - u=$(id -u ${name} 2> /dev/null) || true if [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 -- cgit v1.2.3 From f380194f3dac82e63dc72db160490dcb58208534 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 28 Oct 2024 10:30:02 +1100 Subject: users: create users with home directory `/var/empty` by default --- modules/users/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 58156d2..a945fb4 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -260,7 +260,7 @@ in "-UID" v.uid "-GID" v.gid ] ++ (lib.optionals (v.description != null) [ "-fullName" v.description ]) - ++ (lib.optionals (v.home != null) [ "-home" v.home ]) + ++ [ "-home" (if v.home != null then v.home else "/var/empty") ] ++ [ "-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 -- cgit v1.2.3 From 318df382e61e6116034017454ae596f3980c4613 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Sat, 2 Nov 2024 10:31:40 +1100 Subject: users: don't check home directory is correct before creating user --- modules/users/default.nix | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index a945fb4..6a1cd2e 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -158,23 +158,24 @@ in if ! [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then if [ -z "$u" ]; then ensurePerms ${name} create - fi - ${optionalString (v.home != null && v.name != "root") '' - homeDirectory=$(dscl . -read ${dsclUser} NFSHomeDirectory) - homeDirectory=''${homeDirectory#NFSHomeDirectory: } - if [[ ${lib.escapeShellArg v.home} != "$homeDirectory" ]]; then - printf >&2 '\e[1;31merror: config contains the wrong home directory for %s, aborting activation\e[0m\n' ${name} - printf >&2 'nix-darwin does not support changing the home directory of existing users.\n' - printf >&2 '\n' - printf >&2 'Please set:\n' - printf >&2 '\n' - printf >&2 ' users.users.%s.home = "%s";\n' ${name} "$homeDirectory" - printf >&2 '\n' - printf >&2 'or remove it from your configuration.\n' - exit 1 - fi - ''} + ${optionalString (v.home != null && v.name != "root") '' + else + homeDirectory=$(dscl . -read ${dsclUser} NFSHomeDirectory) + homeDirectory=''${homeDirectory#NFSHomeDirectory: } + if [[ ${lib.escapeShellArg v.home} != "$homeDirectory" ]]; then + printf >&2 '\e[1;31merror: config contains the wrong home directory for %s, aborting activation\e[0m\n' ${name} + printf >&2 'nix-darwin does not support changing the home directory of existing users.\n' + printf >&2 '\n' + printf >&2 'Please set:\n' + printf >&2 '\n' + printf >&2 ' users.users.%s.home = "%s";\n' ${name} "$homeDirectory" + printf >&2 '\n' + printf >&2 'or remove it from your configuration.\n' + exit 1 + fi + ''} + fi fi '') createdUsers} -- cgit v1.2.3 From 041996803af5497fb000e3f79621fa5bb6995057 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 29 Oct 2024 00:09:37 +1100 Subject: treewide: fix shellcheck warnings and errors --- modules/users/default.nix | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 6a1cd2e..d15deac 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -115,6 +115,7 @@ in if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then if [[ -n "$SSH_CONNECTION" ]]; then printf >&2 '\e[1;31merror: users cannot be %s over SSH without Full Disk Access, aborting activation\e[0m\n' "$2" + # shellcheck disable=SC2016 printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access over SSH.\n' "$1" "$2" printf >&2 'You can either:\n' printf >&2 '\n' @@ -122,6 +123,7 @@ in printf >&2 '\n' printf >&2 'or\n' printf >&2 '\n' + # shellcheck disable=SC2016 printf >&2 ' run `darwin-rebuild` in a graphical session.\n' printf >&2 '\n' printf >&2 'The option "Allow full disk access for remote users" can be found by\n' @@ -135,9 +137,11 @@ in if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then printf >&2 '\e[1;31merror: permission denied when trying to %s user %s, aborting activation\e[0m\n' "$2" "$1" - printf >&2 '`darwin-rebuild` requires permissions to administrate your computer,\n' "$1" "$2" + # shellcheck disable=SC2016 + printf >&2 '`darwin-rebuild` requires permissions to administrate your computer,\n' printf >&2 'please accept the dialog that pops up.\n' printf >&2 '\n' + # shellcheck disable=SC2016 printf >&2 'If you do not wish to be prompted every time `darwin-rebuild updates your users,\n' printf >&2 'you can grant Full Disk Access to your terminal emulator in System Settings.\n' printf >&2 '\n' @@ -187,6 +191,7 @@ in if [ "$u" -gt 501 ]; then # TODO: add `darwin.primaryUser` as well if [[ ${name} == "$USER" ]]; then + # shellcheck disable=SC2016 printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', ${name} exit 1 elif [[ ${name} == "root" ]]; then -- cgit v1.2.3 From 32814a6eb1de3b564ff43e5b6453637b1eb25721 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Fri, 1 Nov 2024 00:38:47 +1100 Subject: users: replace runtime check to prevent deleting `root` with assertion This fixes SC2050 as `${name} == "root"` will be generated as a constant expression. --- modules/users/default.nix | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index d15deac..4044732 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -99,6 +99,10 @@ in assertion = cfg.users ? root -> (cfg.users.root.home == null || cfg.users.root.home == "/var/root"); message = "`users.users.root.home` must be set to either `null` or `/var/root`."; } + { + assertion = !builtins.elem "root" deletedUsers; + message = "Remove `root` from `users.knownUsers` if you no longer want nix-darwin to manage it."; + } ]; users.gids = mkMerge gids; @@ -194,9 +198,6 @@ in # shellcheck disable=SC2016 printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', ${name} exit 1 - elif [[ ${name} == "root" ]]; then - printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n' - exit 1 fi ensurePerms ${name} delete -- cgit v1.2.3 From cf130aa9579fc1708ff4a265d2108eefa535e9b2 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Sun, 3 Nov 2024 19:53:20 +1100 Subject: users: don't generate `ensurePerms` when no users to manage --- modules/users/default.nix | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 4044732..434b1da 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -111,7 +111,7 @@ in # NOTE: We put this in `system.checks` as we want this to run first to avoid partial activations # however currently that runs at user level activation as that runs before system level activation # TODO: replace `$USER` with `$SUDO_USER` when system.checks runs from system level - system.checks.text = lib.mkAfter '' + system.checks.text = lib.mkIf (builtins.length (createdUsers ++ deletedUsers) > 0) (lib.mkAfter '' ensurePerms() { homeDirectory=$(dscl . -read /Users/nobody NFSHomeDirectory) homeDirectory=''${homeDirectory#NFSHomeDirectory: } @@ -157,7 +157,6 @@ in fi } - ${concatMapStringsSep "\n" (v: let name = lib.escapeShellArg v.name; dsclUser = lib.escapeShellArg "/Users/${v.name}"; @@ -204,7 +203,7 @@ in fi fi '') deletedUsers} - ''; + ''); system.activationScripts.groups.text = mkIf (cfg.knownGroups != []) '' echo "setting up groups..." >&2 -- cgit v1.2.3 From c2c88ae983c236839c24f547a0047310f8c69647 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 11 Nov 2024 00:21:42 +1100 Subject: users: remove `lib.` --- modules/users/default.nix | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 434b1da..2adf813 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -1,8 +1,10 @@ { config, lib, pkgs, ... }: let - inherit (lib) concatStringsSep concatMapStringsSep elem filter filterAttrs - mapAttrs' mapAttrsToList mkIf mkMerge mkOption mkOrder optionalString types; + inherit (lib) concatStringsSep concatMapStringsSep elem escapeShellArg + escapeShellArgs filter filterAttrs mapAttrs' mapAttrsToList mkAfter + mkIf mkMerge mkOption mkOrder mkRemovedOptionModule optionals + optionalString types; cfg = config.users; @@ -42,7 +44,7 @@ in { imports = [ - (lib.mkRemovedOptionModule [ "users" "forceRecreate" ] "") + (mkRemovedOptionModule [ "users" "forceRecreate" ] "") ]; options = { @@ -111,7 +113,7 @@ in # NOTE: We put this in `system.checks` as we want this to run first to avoid partial activations # however currently that runs at user level activation as that runs before system level activation # TODO: replace `$USER` with `$SUDO_USER` when system.checks runs from system level - system.checks.text = lib.mkIf (builtins.length (createdUsers ++ deletedUsers) > 0) (lib.mkAfter '' + system.checks.text = mkIf (builtins.length (createdUsers ++ deletedUsers) > 0) (mkAfter '' ensurePerms() { homeDirectory=$(dscl . -read /Users/nobody NFSHomeDirectory) homeDirectory=''${homeDirectory#NFSHomeDirectory: } @@ -158,8 +160,8 @@ in } ${concatMapStringsSep "\n" (v: let - name = lib.escapeShellArg v.name; - dsclUser = lib.escapeShellArg "/Users/${v.name}"; + name = escapeShellArg v.name; + dsclUser = escapeShellArg "/Users/${v.name}"; in '' u=$(id -u ${name} 2> /dev/null) || true if ! [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then @@ -170,7 +172,7 @@ in else homeDirectory=$(dscl . -read ${dsclUser} NFSHomeDirectory) homeDirectory=''${homeDirectory#NFSHomeDirectory: } - if [[ ${lib.escapeShellArg v.home} != "$homeDirectory" ]]; then + if [[ ${escapeShellArg v.home} != "$homeDirectory" ]]; then printf >&2 '\e[1;31merror: config contains the wrong home directory for %s, aborting activation\e[0m\n' ${name} printf >&2 'nix-darwin does not support changing the home directory of existing users.\n' printf >&2 '\n' @@ -187,7 +189,7 @@ in '') createdUsers} ${concatMapStringsSep "\n" (v: let - name = lib.escapeShellArg v; + name = escapeShellArg v; in '' u=$(id -u ${name} 2> /dev/null) || true if [ -n "$u" ]; then @@ -209,14 +211,14 @@ in echo "setting up groups..." >&2 ${concatMapStringsSep "\n" (v: let - dsclGroup = lib.escapeShellArg "/Groups/${v.name}"; + dsclGroup = escapeShellArg "/Groups/${v.name}"; in '' g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true g=''${g#PrimaryGroupID: } if [ -z "$g" ]; then echo "creating group ${v.name}..." >&2 dscl . -create ${dsclGroup} PrimaryGroupID ${toString v.gid} - dscl . -create ${dsclGroup} RealName ${lib.escapeShellArg v.description} + dscl . -create ${dsclGroup} RealName ${escapeShellArg v.description} g=${toString v.gid} fi @@ -224,7 +226,7 @@ in g=$(dscl . -read ${dsclGroup} GroupMembership 2> /dev/null) || true if [ "$g" != 'GroupMembership: ${concatStringsSep " " v.members}' ]; then echo "updating group members ${v.name}..." >&2 - dscl . -create ${dsclGroup} GroupMembership ${lib.escapeShellArgs v.members} + dscl . -create ${dsclGroup} GroupMembership ${escapeShellArgs v.members} fi else echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2 @@ -232,7 +234,7 @@ in '') createdGroups} ${concatMapStringsSep "\n" (name: let - dsclGroup = lib.escapeShellArg "/Groups/${name}"; + dsclGroup = escapeShellArg "/Groups/${name}"; in '' g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true g=''${g#PrimaryGroupID: } @@ -251,8 +253,8 @@ in echo "setting up users..." >&2 ${concatMapStringsSep "\n" (v: let - name = lib.escapeShellArg v.name; - dsclUser = lib.escapeShellArg "/Users/${v.name}"; + name = escapeShellArg v.name; + dsclUser = escapeShellArg "/Users/${v.name}"; in '' u=$(id -u ${name} 2> /dev/null) || true if [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then @@ -261,11 +263,11 @@ in if [ -z "$u" ]; then echo "creating user ${v.name}..." >&2 - sysadminctl -addUser ${lib.escapeShellArgs ([ + sysadminctl -addUser ${escapeShellArgs ([ v.name "-UID" v.uid "-GID" v.gid ] - ++ (lib.optionals (v.description != null) [ "-fullName" v.description ]) + ++ (optionals (v.description != null) [ "-fullName" v.description ]) ++ [ "-home" (if v.home != null then v.home else "/var/empty") ] ++ [ "-shell" (if v.shell != null then shellPath v.shell else "/usr/bin/false") ])} 2> /dev/null @@ -284,17 +286,17 @@ 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}"} - ${optionalString (v.shell != null) "dscl . -create ${dsclUser} UserShell ${lib.escapeShellArg (shellPath v.shell)}"} + ${optionalString (v.description != null) "dscl . -create ${dsclUser} RealName ${escapeShellArg v.description}"} + ${optionalString (v.shell != null) "dscl . -create ${dsclUser} UserShell ${escapeShellArg (shellPath v.shell)}"} fi '') createdUsers} ${concatMapStringsSep "\n" (name: '' - u=$(id -u ${lib.escapeShellArg name} 2> /dev/null) || true + u=$(id -u ${escapeShellArg name} 2> /dev/null) || true if [ -n "$u" ]; then if [ "$u" -gt 501 ]; then echo "deleting user ${name}..." >&2 - dscl . -delete ${lib.escapeShellArg "/Users/${name}"} + dscl . -delete ${escapeShellArg "/Users/${name}"} else echo "warning: existing user '${name}' has unexpected uid $u, skipping..." >&2 fi -- cgit v1.2.3 From 5eb88645f74396d4b80fdf736ddd63afbe8320d5 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 11 Nov 2024 00:08:42 +1100 Subject: users: assert that `programs..enable = true;` for users' shells Backport of https://github.com/NixOS/nixpkgs/pull/211603 and https://github.com/NixOS/nixpkgs/commit/093f354a1777e462bd80398c4fc624c4d383dc68 --- modules/users/default.nix | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index 2adf813..ade4ffb 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -2,8 +2,8 @@ let inherit (lib) concatStringsSep concatMapStringsSep elem escapeShellArg - escapeShellArgs filter filterAttrs mapAttrs' mapAttrsToList mkAfter - mkIf mkMerge mkOption mkOrder mkRemovedOptionModule optionals + escapeShellArgs filter filterAttrs flatten flip mapAttrs' mapAttrsToList + mkAfter mkIf mkMerge mkOption mkOrder mkRemovedOptionModule optionals optionalString types; cfg = config.users; @@ -105,7 +105,29 @@ in assertion = !builtins.elem "root" deletedUsers; message = "Remove `root` from `users.knownUsers` if you no longer want nix-darwin to manage it."; } - ]; + ] ++ flatten (flip mapAttrsToList cfg.users (name: user: + map (shell: { + assertion = let + s = user.shell.pname or null; + in + !user.ignoreShellProgramCheck -> (s == shell || (shell == "bash" && s == "bash-interactive")) -> (config.programs.${shell}.enable == true); + message = '' + users.users.${user.name}.shell is set to ${shell}, but + programs.${shell}.enable is not true. This will cause the ${shell} + shell to lack the basic Nix directories in its PATH and might make + logging in as that user impossible. You can fix it with: + programs.${shell}.enable = true; + + If you know what you're doing and you are fine with the behavior, + set users.users.${user.name}.ignoreShellProgramCheck = true; + instead. + ''; + }) [ + "bash" + "fish" + "zsh" + ] + )); users.gids = mkMerge gids; users.uids = mkMerge uids; -- cgit v1.2.3 From 8b27551e094666e6beb273c484392fa205bb0c97 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 11 Nov 2024 00:08:42 +1100 Subject: users: warn users to use `pkgs.bashInteractive` instead of `pkgs.bash` --- modules/users/default.nix | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'modules/users/default.nix') diff --git a/modules/users/default.nix b/modules/users/default.nix index ade4ffb..574f5a4 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -129,6 +129,12 @@ in ] )); + warnings = flatten (flip mapAttrsToList cfg.users (name: user: + mkIf + (user.shell.pname or null == "bash") + "Set `users.users.${name}.shell = pkgs.bashInteractive;` instead of `pkgs.bash` as it does not include `readline`." + )); + users.gids = mkMerge gids; users.uids = mkMerge uids; -- cgit v1.2.3