grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / programs / shadow.nix
blobef5bad69e934e5215724113d66d941f932f732ed
1 # Configuration for the pwdutils suite of tools: passwd, useradd, etc.
2 { config, lib, utils, pkgs, ... }:
3 let
4   cfg = config.security.loginDefs;
5 in
7   options = {
9     security.shadow.enable = lib.mkEnableOption "" // {
10       default = true;
11       description = ''
12         Enable the shadow authentication suite, which provides critical programs such as su, login, passwd.
14         Note: This is currently experimental. Only disable this if you're
15         confident that you can recover your system if it breaks.
16       '';
17     };
19     security.loginDefs = {
20       package = lib.mkPackageOption pkgs "shadow" { };
22       chfnRestrict = lib.mkOption {
23         description = ''
24           Use chfn SUID to allow non-root users to change their account GECOS information.
25         '';
26         type = lib.types.nullOr lib.types.str;
27         default = null;
28       };
30       settings = lib.mkOption {
31         description = ''
32           Config options for the /etc/login.defs file, that defines
33           the site-specific configuration for the shadow password suite.
34           See login.defs(5) man page for available options.
35         '';
36         type = lib.types.submodule {
37           freeformType = (pkgs.formats.keyValue { }).type;
38           /* There are three different sources for user/group id ranges, each of which gets
39              used by different programs:
40              - The login.defs file, used by the useradd, groupadd and newusers commands
41              - The update-users-groups.pl file, used by NixOS in the activation phase to
42                decide on which ids to use for declaratively defined users without a static
43                id
44              - Systemd compile time options -Dsystem-uid-max= and -Dsystem-gid-max=, used
45                by systemd for features like ConditionUser=@system and systemd-sysusers
46               */
47           options = {
48             DEFAULT_HOME = lib.mkOption {
49               description = "Indicate if login is allowed if we can't cd to the home directory.";
50               default = "yes";
51               type = lib.types.enum [ "yes" "no" ];
52             };
54             ENCRYPT_METHOD = lib.mkOption {
55               description = "This defines the system default encryption algorithm for encrypting passwords.";
56               # The default crypt() method, keep in sync with the PAM default
57               default = "YESCRYPT";
58               type = lib.types.enum [ "YESCRYPT" "SHA512" "SHA256" "MD5" "DES"];
59             };
61             SYS_UID_MIN = lib.mkOption {
62               description = "Range of user IDs used for the creation of system users by useradd or newusers.";
63               default = 400;
64               type = lib.types.int;
65             };
67             SYS_UID_MAX = lib.mkOption {
68               description = "Range of user IDs used for the creation of system users by useradd or newusers.";
69               default = 999;
70               type = lib.types.int;
71             };
73             UID_MIN = lib.mkOption {
74               description = "Range of user IDs used for the creation of regular users by useradd or newusers.";
75               default = 1000;
76               type = lib.types.int;
77             };
79             UID_MAX = lib.mkOption {
80               description = "Range of user IDs used for the creation of regular users by useradd or newusers.";
81               default = 29999;
82               type = lib.types.int;
83             };
85             SYS_GID_MIN = lib.mkOption {
86               description = "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers";
87               default = 400;
88               type = lib.types.int;
89             };
91             SYS_GID_MAX = lib.mkOption {
92               description = "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers";
93               default = 999;
94               type = lib.types.int;
95             };
97             GID_MIN = lib.mkOption {
98               description = "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers.";
99               default = 1000;
100               type = lib.types.int;
101             };
103             GID_MAX = lib.mkOption {
104               description = "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers.";
105               default = 29999;
106               type = lib.types.int;
107             };
109             TTYGROUP = lib.mkOption {
110               description = ''
111                 The terminal permissions: the login tty will be owned by the TTYGROUP group,
112                 and the permissions will be set to TTYPERM'';
113               default = "tty";
114               type = lib.types.str;
115             };
117             TTYPERM = lib.mkOption {
118               description = ''
119                 The terminal permissions: the login tty will be owned by the TTYGROUP group,
120                 and the permissions will be set to TTYPERM'';
121               default = "0620";
122               type = lib.types.str;
123             };
125             # Ensure privacy for newly created home directories.
126             UMASK = lib.mkOption {
127               description = "The file mode creation mask is initialized to this value.";
128               default = "077";
129               type = lib.types.str;
130             };
131           };
132         };
133         default = { };
134       };
135     };
137     users.defaultUserShell = lib.mkOption {
138       description = ''
139         This option defines the default shell assigned to user
140         accounts. This can be either a full system path or a shell package.
142         This must not be a store path, since the path is
143         used outside the store (in particular in /etc/passwd).
144       '';
145       example = lib.literalExpression "pkgs.zsh";
146       type = lib.types.either lib.types.path lib.types.shellPackage;
147     };
148   };
150   ###### implementation
152   config = lib.mkMerge [
153     {
154       assertions = [
155         {
156           assertion = config.security.shadow.enable || config.services.greetd.enable;
157           message = "You must enable at least one VT login method, either security.shadow.enable or services.greetd.enable";
158         }
159       ];
160     }
161     (lib.mkIf config.security.shadow.enable {
162       assertions = [
163         {
164           assertion = cfg.settings.SYS_UID_MIN <= cfg.settings.SYS_UID_MAX;
165           message = "SYS_UID_MIN must be less than or equal to SYS_UID_MAX";
166         }
167         {
168           assertion = cfg.settings.UID_MIN <= cfg.settings.UID_MAX;
169           message = "UID_MIN must be less than or equal to UID_MAX";
170         }
171         {
172           assertion = cfg.settings.SYS_GID_MIN <= cfg.settings.SYS_GID_MAX;
173           message = "SYS_GID_MIN must be less than or equal to SYS_GID_MAX";
174         }
175         {
176           assertion = cfg.settings.GID_MIN <= cfg.settings.GID_MAX;
177           message = "GID_MIN must be less than or equal to GID_MAX";
178         }
179       ];
181       security.loginDefs.settings.CHFN_RESTRICT = lib.mkIf (cfg.chfnRestrict != null) cfg.chfnRestrict;
183       environment.systemPackages = lib.optional config.users.mutableUsers cfg.package
184         ++ lib.optional (lib.types.shellPackage.check config.users.defaultUserShell) config.users.defaultUserShell
185         ++ lib.optional (cfg.chfnRestrict != null) pkgs.util-linux;
187       environment.etc =
188         # Create custom toKeyValue generator
189         # see https://man7.org/linux/man-pages/man5/login.defs.5.html for config specification
190         let
191           toKeyValue = lib.generators.toKeyValue {
192             mkKeyValue = lib.generators.mkKeyValueDefault { } " ";
193           };
194         in {
195           # /etc/login.defs: global configuration for pwdutils.
196           # You cannot login without it!
197           "login.defs".source = pkgs.writeText "login.defs" (toKeyValue cfg.settings);
199           # /etc/default/useradd: configuration for useradd.
200           "default/useradd".source = pkgs.writeText "useradd" ''
201             GROUP=100
202             HOME=/home
203             SHELL=${utils.toShellPath config.users.defaultUserShell}
204           '';
205         };
207       security.pam.services = {
208         chsh.rootOK = true;
209         chfn.rootOK = true;
210         su = {
211           rootOK = true;
212           forwardXAuth = true;
213           logFailures = true;
214         };
215         passwd = { };
216         # Note: useradd, groupadd etc. aren't setuid root, so it
217         # doesn't really matter what the PAM config says as long as it
218         # lets root in.
219         useradd.rootOK = true;
220         usermod.rootOK = true;
221         userdel.rootOK = true;
222         groupadd.rootOK = true;
223         groupmod.rootOK = true;
224         groupmems.rootOK = true;
225         groupdel.rootOK = true;
226         login = {
227           startSession = true;
228           allowNullPassword = true;
229           showMotd = true;
230           updateWtmp = true;
231         };
232         chpasswd.rootOK = true;
233       };
235       security.wrappers =
236         let
237           mkSetuidRoot = source: {
238             setuid = true;
239             owner = "root";
240             group = "root";
241             inherit source;
242           };
243         in
244           {
245             su = mkSetuidRoot "${cfg.package.su}/bin/su";
246             sg = mkSetuidRoot "${cfg.package.out}/bin/sg";
247             newgrp = mkSetuidRoot "${cfg.package.out}/bin/newgrp";
248             newuidmap = mkSetuidRoot "${cfg.package.out}/bin/newuidmap";
249             newgidmap = mkSetuidRoot "${cfg.package.out}/bin/newgidmap";
250           }
251           // lib.optionalAttrs config.users.mutableUsers {
252             chsh = mkSetuidRoot "${cfg.package.out}/bin/chsh";
253             passwd = mkSetuidRoot "${cfg.package.out}/bin/passwd";
254           };
255     })
256   ];