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