typioca: 2.7.0 -> 2.8.0
[NixPkgs.git] / nixos / modules / programs / shadow.nix
blob00895db03fc32e3d8eb4a3c1454d0b0a8302f0b1
1 # Configuration for the pwdutils suite of tools: passwd, useradd, etc.
2 { config, lib, utils, pkgs, ... }:
3 with lib;
4 let
5   cfg = config.security.loginDefs;
6 in
8   options = with types; {
9     security.loginDefs = {
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.
15         '';
16         type = nullOr str;
17         default = null;
18       };
20       settings = mkOption {
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.
25         '';
26         type = submodule {
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
33                id
34              - Systemd compile time options -Dsystem-uid-max= and -Dsystem-gid-max=, used
35                by systemd for features like ConditionUser=@system and systemd-sysusers
36               */
37           options = {
38             DEFAULT_HOME = mkOption {
39               description = mdDoc "Indicate if login is allowed if we can't cd to the home directory.";
40               default = "yes";
41               type = enum [ "yes" "no" ];
42             };
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
47               default = "YESCRYPT";
48               type = enum [ "YESCRYPT" "SHA512" "SHA256" "MD5" "DES"];
49             };
51             SYS_UID_MIN = mkOption {
52               description = mdDoc "Range of user IDs used for the creation of system users by useradd or newusers.";
53               default = 400;
54               type = int;
55             };
57             SYS_UID_MAX = mkOption {
58               description = mdDoc "Range of user IDs used for the creation of system users by useradd or newusers.";
59               default = 999;
60               type = int;
61             };
63             UID_MIN = mkOption {
64               description = mdDoc "Range of user IDs used for the creation of regular users by useradd or newusers.";
65               default = 1000;
66               type = int;
67             };
69             UID_MAX = mkOption {
70               description = mdDoc "Range of user IDs used for the creation of regular users by useradd or newusers.";
71               default = 29999;
72               type = int;
73             };
75             SYS_GID_MIN = mkOption {
76               description = mdDoc "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers";
77               default = 400;
78               type = int;
79             };
81             SYS_GID_MAX = mkOption {
82               description = mdDoc "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers";
83               default = 999;
84               type = int;
85             };
87             GID_MIN = mkOption {
88               description = mdDoc "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers.";
89               default = 1000;
90               type = int;
91             };
93             GID_MAX = mkOption {
94               description = mdDoc "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers.";
95               default = 29999;
96               type = int;
97             };
99             TTYGROUP = mkOption {
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'';
103               default = "tty";
104               type = str;
105             };
107             TTYPERM = mkOption {
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'';
111               default = "0620";
112               type = str;
113             };
115             # Ensure privacy for newly created home directories.
116             UMASK = mkOption {
117               description = mdDoc "The file mode creation mask is initialized to this value.";
118               default = "077";
119               type = str;
120             };
121           };
122         };
123         default = { };
124       };
125     };
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).
134       '';
135       example = literalExpression "pkgs.zsh";
136       type = either path shellPackage;
137     };
138   };
140   ###### implementation
142   config = {
143     assertions = [
144       {
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";
147       }
148       {
149         assertion = cfg.settings.UID_MIN <= cfg.settings.UID_MAX;
150         message = "UID_MIN must be less than or equal to UID_MAX";
151       }
152       {
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";
155       }
156       {
157         assertion = cfg.settings.GID_MIN <= cfg.settings.GID_MAX;
158         message = "GID_MIN must be less than or equal to GID_MAX";
159       }
160     ];
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;
169     environment.etc =
170       # Create custom toKeyValue generator
171       # see https://man7.org/linux/man-pages/man5/login.defs.5.html for config specification
172       let
173         toKeyValue = generators.toKeyValue {
174           mkKeyValue = generators.mkKeyValueDefault { } " ";
175         };
176       in
177       {
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" ''
184           GROUP=100
185           HOME=/home
186           SHELL=${utils.toShellPath config.users.defaultUserShell}
187         '';
188       };
190     security.pam.services = {
191       chsh = { rootOK = true; };
192       chfn = { rootOK = true; };
193       su = {
194         rootOK = true;
195         forwardXAuth = true;
196         logFailures = true;
197       };
198       passwd = { };
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
201       # lets root in.
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;
209       login = {
210         startSession = true;
211         allowNullPassword = true;
212         showMotd = true;
213         updateWtmp = true;
214       };
215       chpasswd = { rootOK = true; };
216     };
218     security.wrappers =
219       let
220         mkSetuidRoot = source: {
221           setuid = true;
222           owner = "root";
223           group = "root";
224           inherit source;
225         };
226       in
227       {
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";
233       }
234       // optionalAttrs config.users.mutableUsers {
235         chsh = mkSetuidRoot "${cfg.package.out}/bin/chsh";
236         passwd = mkSetuidRoot "${cfg.package.out}/bin/passwd";
237       };
238   };