diff --git a/modules/users/default.nix b/modules/users/default.nix index 90e55344..f57dfa56 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} diff --git a/tests/users-groups.nix b/tests/users-groups.nix index 17b8c0d2..72c6e0c1 100644 --- a/tests/users-groups.nix +++ b/tests/users-groups.nix @@ -25,22 +25,22 @@ set -v # checking group creation in /activate - grep "dscl . -create '/Groups/foo' PrimaryGroupID 42000" ${config.out}/activate - grep "dscl . -create '/Groups/foo' RealName 'Foo group'" ${config.out}/activate - grep "dscl . -create '/Groups/created.group' PrimaryGroupID 42001" ${config.out}/activate - grep -qv "dscl . -delete '/Groups/created.group'" ${config.out}/activate + grep "dscl . -create ${lib.escapeShellArg "/Groups/foo"} PrimaryGroupID 42000" ${config.out}/activate + grep "dscl . -create ${lib.escapeShellArg "/Groups/foo"} RealName 'Foo group'" ${config.out}/activate + grep "dscl . -create ${lib.escapeShellArg "/Groups/created.group"} PrimaryGroupID 42001" ${config.out}/activate + grep -qv "dscl . -delete ${lib.escapeShellArg "/Groups/created.group"}" ${config.out}/activate # checking group deletion in /activate - grep "dscl . -delete '/Groups/deleted.group'" ${config.out}/activate - grep -qv "dscl . -create '/Groups/deleted.group'" ${config.out}/activate + grep "dscl . -delete ${lib.escapeShellArg "/Groups/deleted.group"}" ${config.out}/activate + grep -qv "dscl . -create ${lib.escapeShellArg "/Groups/deleted.group"}" ${config.out}/activate echo "checking group membership in /activate" >&2 - grep "dscl . -create '/Groups/foo' GroupMembership ${lib.escapeShellArgs [ "admin" "foo" ]}" ${config.out}/activate - grep "dscl . -create '/Groups/created.group' GroupMembership" ${config.out}/activate + grep "dscl . -create ${lib.escapeShellArg "/Groups/foo"} GroupMembership ${lib.escapeShellArgs [ "admin" "foo" ]}" ${config.out}/activate + grep "dscl . -create ${lib.escapeShellArg "/Groups/created.group"} GroupMembership" ${config.out}/activate # checking unknown group in /activate - grep -qv "dscl . -create '/Groups/unknown.group'" ${config.out}/activate - grep -qv "dscl . -delete '/Groups/unknown.group'" ${config.out}/activate + grep -qv "dscl . -create ${lib.escapeShellArg "/Groups/unknown.group"}" ${config.out}/activate + grep -qv "dscl . -delete ${lib.escapeShellArg "/Groups/unknown.group"}" ${config.out}/activate # 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 @@ -50,7 +50,7 @@ grep -qv "sysadminctl -deleteUser ${lib.escapeShellArg "created.user"}" ${config.out}/activate # checking user properties always get updated in /activate - grep "dscl . -create '/Users/foo' UserShell ${lib.escapeShellArg "/run/current-system/sw/bin/bash"}" ${config.out}/activate + grep "dscl . -create ${lib.escapeShellArg "/Users/foo"} UserShell ${lib.escapeShellArg "/run/current-system/sw/bin/bash"}" ${config.out}/activate # checking user deletion in /activate grep "sysadminctl -deleteUser ${lib.escapeShellArg "deleted.user"}" ${config.out}/activate