1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.xserver.displayManager;
8 gnome3 = config.environment.gnome3.packageSet;
9 gdm = gnome3.gdm;
10
11in
12
13{
14
15 ###### interface
16
17 options = {
18
19 services.xserver.displayManager.gdm = {
20
21 enable = mkEnableOption ''
22 GDM as the display manager.
23 <emphasis>GDM in NixOS is not well-tested with desktops other
24 than GNOME, so use with caution, as it could render the
25 system unusable.</emphasis>
26 '';
27
28 debug = mkEnableOption ''
29 debugging messages in GDM
30 '';
31
32 autoLogin = mkOption {
33 default = {};
34 description = ''
35 Auto login configuration attrset.
36 '';
37
38 type = types.submodule {
39 options = {
40 enable = mkOption {
41 type = types.bool;
42 default = false;
43 description = ''
44 Automatically log in as the sepecified <option>autoLogin.user</option>.
45 '';
46 };
47
48 user = mkOption {
49 type = types.nullOr types.str;
50 default = null;
51 description = ''
52 User to be used for the autologin.
53 '';
54 };
55
56 delay = mkOption {
57 type = types.int;
58 default = 0;
59 description = ''
60 Seconds of inactivity after which the autologin will be performed.
61 '';
62 };
63
64 };
65 };
66 };
67
68 };
69
70 };
71
72
73 ###### implementation
74
75 config = mkIf cfg.gdm.enable {
76
77 assertions = [
78 { assertion = cfg.gdm.autoLogin.enable -> cfg.gdm.autoLogin.user != null;
79 message = "GDM auto-login requires services.xserver.displayManager.gdm.autoLogin.user to be set";
80 }
81 ];
82
83 services.xserver.displayManager.slim.enable = false;
84
85 users.extraUsers.gdm =
86 { name = "gdm";
87 uid = config.ids.uids.gdm;
88 group = "gdm";
89 home = "/run/gdm";
90 description = "GDM user";
91 };
92
93 users.extraGroups.gdm.gid = config.ids.gids.gdm;
94
95 # GDM needs different xserverArgs, presumable because using wayland by default.
96 services.xserver.tty = null;
97 services.xserver.display = null;
98
99 services.xserver.displayManager.job =
100 {
101 environment = {
102 GDM_X_SERVER_EXTRA_ARGS = toString
103 (filter (arg: arg != "-terminate") cfg.xserverArgs);
104 GDM_SESSIONS_DIR = "${cfg.session.desktops}";
105 # Find the mouse
106 XCURSOR_PATH = "~/.icons:${gnome3.adwaita-icon-theme}/share/icons";
107 };
108 execCmd = "exec ${gdm}/bin/gdm";
109 };
110
111 # Because sd_login_monitor_new requires /run/systemd/machines
112 systemd.services.display-manager.wants = [ "systemd-machined.service" ];
113 systemd.services.display-manager.after = [
114 "rc-local.service"
115 "systemd-machined.service"
116 "systemd-user-sessions.service"
117 "getty@tty1.service"
118 ];
119
120 systemd.services.display-manager.conflicts = [ "getty@tty1.service" ];
121 systemd.services.display-manager.serviceConfig = {
122 # Restart = "always"; - already defined in xserver.nix
123 KillMode = "mixed";
124 IgnoreSIGPIPE = "no";
125 BusName = "org.gnome.DisplayManager";
126 StandardOutput = "syslog";
127 StandardError = "inherit";
128 };
129
130 systemd.services.display-manager.path = [ gnome3.gnome_session ];
131
132 services.dbus.packages = [ gdm ];
133
134 systemd.user.services.dbus.wantedBy = [ "default.target" ];
135
136 programs.dconf.profiles.gdm = "${gdm}/share/dconf/profile/gdm";
137
138 # Use AutomaticLogin if delay is zero, because it's immediate.
139 # Otherwise with TimedLogin with zero seconds the prompt is still
140 # presented and there's a little delay.
141 environment.etc."gdm/custom.conf".text = ''
142 [daemon]
143 ${optionalString cfg.gdm.autoLogin.enable (
144 if cfg.gdm.autoLogin.delay > 0 then ''
145 TimedLoginEnable=true
146 TimedLogin=${cfg.gdm.autoLogin.user}
147 TimedLoginDelay=${toString cfg.gdm.autoLogin.delay}
148 '' else ''
149 AutomaticLoginEnable=true
150 AutomaticLogin=${cfg.gdm.autoLogin.user}
151 '')
152 }
153
154 [security]
155
156 [xdmcp]
157
158 [greeter]
159
160 [chooser]
161
162 [debug]
163 ${optionalString cfg.gdm.debug "Enable=true"}
164 '';
165
166 # GDM LFS PAM modules, adapted somehow to NixOS
167 security.pam.services = {
168 gdm-launch-environment.text = ''
169 auth required pam_succeed_if.so audit quiet_success user = gdm
170 auth optional pam_permit.so
171
172 account required pam_succeed_if.so audit quiet_success user = gdm
173 account sufficient pam_unix.so
174
175 password required pam_deny.so
176
177 session required pam_succeed_if.so audit quiet_success user = gdm
178 session required pam_env.so envfile=${config.system.build.pamEnvironment}
179 session optional ${pkgs.systemd}/lib/security/pam_systemd.so
180 session optional pam_keyinit.so force revoke
181 session optional pam_permit.so
182 '';
183
184 gdm.text = ''
185 auth requisite pam_nologin.so
186 auth required pam_env.so envfile=${config.system.build.pamEnvironment}
187
188 auth required pam_succeed_if.so uid >= 1000 quiet
189 auth optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so
190 auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth
191 ${optionalString config.security.pam.enableEcryptfs
192 "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"}
193
194 ${optionalString (! config.security.pam.enableEcryptfs)
195 "auth required pam_deny.so"}
196
197 account sufficient pam_unix.so
198
199 password requisite pam_unix.so nullok sha512
200 ${optionalString config.security.pam.enableEcryptfs
201 "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
202
203 session required pam_env.so envfile=${config.system.build.pamEnvironment}
204 session required pam_unix.so
205 ${optionalString config.security.pam.enableEcryptfs
206 "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
207 session required pam_loginuid.so
208 session optional ${pkgs.systemd}/lib/security/pam_systemd.so
209 session optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start
210 '';
211
212 gdm-password.text = ''
213 auth requisite pam_nologin.so
214 auth required pam_env.so envfile=${config.system.build.pamEnvironment}
215
216 auth required pam_succeed_if.so uid >= 1000 quiet
217 auth optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so
218 auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth
219 ${optionalString config.security.pam.enableEcryptfs
220 "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"}
221 ${optionalString (! config.security.pam.enableEcryptfs)
222 "auth required pam_deny.so"}
223
224 account sufficient pam_unix.so
225
226 password requisite pam_unix.so nullok sha512
227 ${optionalString config.security.pam.enableEcryptfs
228 "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
229
230 session required pam_env.so envfile=${config.system.build.pamEnvironment}
231 session required pam_unix.so
232 ${optionalString config.security.pam.enableEcryptfs
233 "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
234 session required pam_loginuid.so
235 session optional ${pkgs.systemd}/lib/security/pam_systemd.so
236 session optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start
237 '';
238
239 gdm-autologin.text = ''
240 auth requisite pam_nologin.so
241
242 auth required pam_succeed_if.so uid >= 1000 quiet
243 auth required pam_permit.so
244
245 account sufficient pam_unix.so
246
247 password requisite pam_unix.so nullok sha512
248
249 session optional pam_keyinit.so revoke
250 session required pam_env.so envfile=${config.system.build.pamEnvironment}
251 session required pam_unix.so
252 session required pam_loginuid.so
253 session optional ${pkgs.systemd}/lib/security/pam_systemd.so
254 '';
255
256 };
257
258 };
259
260}