1 # Configuration for the pwdutils suite of tools: passwd, useradd, etc.
2 { config, lib, utils, pkgs, ... }:
5 cfg = config.security.loginDefs;
8 options = with types; {
10 package = mkPackageOptionMD pkgs "shadow" { };
12 chfnRestrict = mkOption {
13 description = mdDoc ''
14 Use chfn SUID to allow non-root users to change their account GECOS information.
21 description = mdDoc ''
22 Config options for the /etc/login.defs file, that defines
23 the site-specific configuration for the shadow password suite.
24 See login.defs(5) man page for available options.
27 freeformType = (pkgs.formats.keyValue { }).type;
28 /* There are three different sources for user/group id ranges, each of which gets
29 used by different programs:
30 - The login.defs file, used by the useradd, groupadd and newusers commands
31 - The update-users-groups.pl file, used by NixOS in the activation phase to
32 decide on which ids to use for declaratively defined users without a static
34 - Systemd compile time options -Dsystem-uid-max= and -Dsystem-gid-max=, used
35 by systemd for features like ConditionUser=@system and systemd-sysusers
38 DEFAULT_HOME = mkOption {
39 description = mdDoc "Indicate if login is allowed if we can't cd to the home directory.";
41 type = enum [ "yes" "no" ];
44 ENCRYPT_METHOD = mkOption {
45 description = mdDoc "This defines the system default encryption algorithm for encrypting passwords.";
46 # The default crypt() method, keep in sync with the PAM default
48 type = enum [ "YESCRYPT" "SHA512" "SHA256" "MD5" "DES"];
51 SYS_UID_MIN = mkOption {
52 description = mdDoc "Range of user IDs used for the creation of system users by useradd or newusers.";
57 SYS_UID_MAX = mkOption {
58 description = mdDoc "Range of user IDs used for the creation of system users by useradd or newusers.";
64 description = mdDoc "Range of user IDs used for the creation of regular users by useradd or newusers.";
70 description = mdDoc "Range of user IDs used for the creation of regular users by useradd or newusers.";
75 SYS_GID_MIN = mkOption {
76 description = mdDoc "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers";
81 SYS_GID_MAX = mkOption {
82 description = mdDoc "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers";
88 description = mdDoc "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers.";
94 description = mdDoc "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers.";
100 description = mdDoc ''
101 The terminal permissions: the login tty will be owned by the TTYGROUP group,
102 and the permissions will be set to TTYPERM'';
108 description = mdDoc ''
109 The terminal permissions: the login tty will be owned by the TTYGROUP group,
110 and the permissions will be set to TTYPERM'';
115 # Ensure privacy for newly created home directories.
117 description = mdDoc "The file mode creation mask is initialized to this value.";
127 users.defaultUserShell = mkOption {
128 description = mdDoc ''
129 This option defines the default shell assigned to user
130 accounts. This can be either a full system path or a shell package.
132 This must not be a store path, since the path is
133 used outside the store (in particular in /etc/passwd).
135 example = literalExpression "pkgs.zsh";
136 type = either path shellPackage;
140 ###### implementation
145 assertion = cfg.settings.SYS_UID_MIN <= cfg.settings.SYS_UID_MAX;
146 message = "SYS_UID_MIN must be less than or equal to SYS_UID_MAX";
149 assertion = cfg.settings.UID_MIN <= cfg.settings.UID_MAX;
150 message = "UID_MIN must be less than or equal to UID_MAX";
153 assertion = cfg.settings.SYS_GID_MIN <= cfg.settings.SYS_GID_MAX;
154 message = "SYS_GID_MIN must be less than or equal to SYS_GID_MAX";
157 assertion = cfg.settings.GID_MIN <= cfg.settings.GID_MAX;
158 message = "GID_MIN must be less than or equal to GID_MAX";
162 security.loginDefs.settings.CHFN_RESTRICT =
163 mkIf (cfg.chfnRestrict != null) cfg.chfnRestrict;
165 environment.systemPackages = optional config.users.mutableUsers cfg.package
166 ++ optional (types.shellPackage.check config.users.defaultUserShell) config.users.defaultUserShell
167 ++ optional (cfg.chfnRestrict != null) pkgs.util-linux;
170 # Create custom toKeyValue generator
171 # see https://man7.org/linux/man-pages/man5/login.defs.5.html for config specification
173 toKeyValue = generators.toKeyValue {
174 mkKeyValue = generators.mkKeyValueDefault { } " ";
178 # /etc/login.defs: global configuration for pwdutils.
179 # You cannot login without it!
180 "login.defs".source = pkgs.writeText "login.defs" (toKeyValue cfg.settings);
182 # /etc/default/useradd: configuration for useradd.
183 "default/useradd".source = pkgs.writeText "useradd" ''
186 SHELL=${utils.toShellPath config.users.defaultUserShell}
190 security.pam.services = {
191 chsh = { rootOK = true; };
192 chfn = { rootOK = true; };
199 # Note: useradd, groupadd etc. aren't setuid root, so it
200 # doesn't really matter what the PAM config says as long as it
202 useradd.rootOK = true;
203 usermod.rootOK = true;
204 userdel.rootOK = true;
205 groupadd.rootOK = true;
206 groupmod.rootOK = true;
207 groupmems.rootOK = true;
208 groupdel.rootOK = true;
211 allowNullPassword = true;
215 chpasswd = { rootOK = true; };
220 mkSetuidRoot = source: {
228 su = mkSetuidRoot "${cfg.package.su}/bin/su";
229 sg = mkSetuidRoot "${cfg.package.out}/bin/sg";
230 newgrp = mkSetuidRoot "${cfg.package.out}/bin/newgrp";
231 newuidmap = mkSetuidRoot "${cfg.package.out}/bin/newuidmap";
232 newgidmap = mkSetuidRoot "${cfg.package.out}/bin/newgidmap";
234 // optionalAttrs config.users.mutableUsers {
235 chsh = mkSetuidRoot "${cfg.package.out}/bin/chsh";
236 passwd = mkSetuidRoot "${cfg.package.out}/bin/passwd";