1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 xcfg = config.services.xserver;
8 dmcfg = xcfg.displayManager;
9 xEnv = config.systemd.services."display-manager".environment;
10 cfg = dmcfg.lightdm;
11
12 inherit (pkgs) stdenv lightdm writeScript writeText;
13
14 # lightdm runs with clearenv(), but we need a few things in the enviornment for X to startup
15 xserverWrapper = writeScript "xserver-wrapper"
16 ''
17 #! ${pkgs.bash}/bin/bash
18 ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
19
20 display=$(echo "$@" | xargs -n 1 | grep -P ^:\\d\$ | head -n 1 | sed s/^://)
21 if [ -z "$display" ]
22 then additionalArgs=":0 -logfile /var/log/X.0.log"
23 else additionalArgs="-logfile /var/log/X.$display.log"
24 fi
25
26 exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} $additionalArgs "$@"
27 '';
28
29 usersConf = writeText "users.conf"
30 ''
31 [UserList]
32 minimum-uid=500
33 hidden-users=${concatStringsSep " " dmcfg.hiddenUsers}
34 hidden-shells=/run/current-system/sw/bin/nologin
35 '';
36
37 lightdmConf = writeText "lightdm.conf"
38 ''
39 [LightDM]
40 ${optionalString cfg.greeter.enable ''
41 greeter-user = ${config.users.extraUsers.lightdm.name}
42 greeters-directory = ${cfg.greeter.package}
43 ''}
44 sessions-directory = ${dmcfg.session.desktops}
45
46 [Seat:*]
47 xserver-command = ${xserverWrapper}
48 session-wrapper = ${dmcfg.session.script}
49 ${optionalString cfg.greeter.enable ''
50 greeter-session = ${cfg.greeter.name}
51 ''}
52 ${optionalString cfg.autoLogin.enable ''
53 autologin-user = ${cfg.autoLogin.user}
54 autologin-user-timeout = ${toString cfg.autoLogin.timeout}
55 autologin-session = ${defaultSessionName}
56 ''}
57 ${cfg.extraSeatDefaults}
58 '';
59
60 defaultSessionName =
61 let
62 dm = xcfg.desktopManager.default;
63 wm = xcfg.windowManager.default;
64 in dm + optionalString (wm != "none") (" + " + wm);
65in
66{
67 # Note: the order in which lightdm greeter modules are imported
68 # here determines the default: later modules (if enable) are
69 # preferred.
70 imports = [
71 ./lightdm-greeters/gtk.nix
72 ];
73
74 options = {
75
76 services.xserver.displayManager.lightdm = {
77
78 enable = mkOption {
79 type = types.bool;
80 default = false;
81 description = ''
82 Whether to enable lightdm as the display manager.
83 '';
84 };
85
86 greeter = {
87 enable = mkOption {
88 type = types.bool;
89 default = true;
90 description = ''
91 If set to false, run lightdm in greeterless mode. This only works if autologin
92 is enabled and autoLogin.timeout is zero.
93 '';
94 };
95 package = mkOption {
96 type = types.package;
97 description = ''
98 The LightDM greeter to login via. The package should be a directory
99 containing a .desktop file matching the name in the 'name' option.
100 '';
101
102 };
103 name = mkOption {
104 type = types.string;
105 description = ''
106 The name of a .desktop file in the directory specified
107 in the 'package' option.
108 '';
109 };
110 };
111
112 background = mkOption {
113 type = types.str;
114 default = "${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png";
115 description = ''
116 The background image or color to use.
117 '';
118 };
119
120 extraSeatDefaults = mkOption {
121 type = types.lines;
122 default = "";
123 example = ''
124 greeter-show-manual-login=true
125 '';
126 description = "Extra lines to append to SeatDefaults section.";
127 };
128
129 autoLogin = mkOption {
130 default = {};
131 description = ''
132 Configuration for automatic login.
133 '';
134
135 type = types.submodule {
136 options = {
137 enable = mkOption {
138 type = types.bool;
139 default = false;
140 description = ''
141 Automatically log in as the specified <option>autoLogin.user</option>.
142 '';
143 };
144
145 user = mkOption {
146 type = types.nullOr types.str;
147 default = null;
148 description = ''
149 User to be used for the automatic login.
150 '';
151 };
152
153 timeout = mkOption {
154 type = types.int;
155 default = 0;
156 description = ''
157 Show the greeter for this many seconds before automatic login occurs.
158 '';
159 };
160 };
161 };
162 };
163
164 };
165 };
166
167 config = mkIf cfg.enable {
168
169 assertions = [
170 { assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null;
171 message = ''
172 LightDM auto-login requires services.xserver.displayManager.lightdm.autoLogin.user to be set
173 '';
174 }
175 { assertion = cfg.autoLogin.enable -> elem defaultSessionName dmcfg.session.names;
176 message = ''
177 LightDM auto-login requires that services.xserver.desktopManager.default and
178 services.xserver.windowMananger.default are set to valid values. The current
179 default session: ${defaultSessionName} is not valid.
180 '';
181 }
182 { assertion = !cfg.greeter.enable -> (cfg.autoLogin.enable && cfg.autoLogin.timeout == 0);
183 message = ''
184 LightDM can only run without greeter if automatic login is enabled and the timeout for it
185 is set to zero.
186 '';
187 }
188 ];
189
190 services.xserver.displayManager.slim.enable = false;
191
192 services.xserver.displayManager.job = {
193 logsXsession = true;
194
195 # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
196 execCmd = ''
197 export PATH=${lightdm}/sbin:$PATH
198 exec ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run
199 '';
200 };
201
202 environment.etc."lightdm/lightdm.conf".source = lightdmConf;
203 environment.etc."lightdm/users.conf".source = usersConf;
204
205 services.dbus.enable = true;
206 services.dbus.packages = [ lightdm ];
207
208 security.pam.services.lightdm = {
209 allowNullPassword = true;
210 startSession = true;
211 };
212 security.pam.services.lightdm-greeter = {
213 allowNullPassword = true;
214 startSession = true;
215 text = ''
216 auth required pam_env.so envfile=${config.system.build.pamEnvironment}
217 auth required pam_permit.so
218
219 account required pam_permit.so
220
221 password required pam_deny.so
222
223 session required pam_env.so envfile=${config.system.build.pamEnvironment}
224 session required pam_unix.so
225 session optional ${pkgs.systemd}/lib/security/pam_systemd.so
226 '';
227 };
228 security.pam.services.lightdm-autologin.text = ''
229 auth requisite pam_nologin.so
230 auth required pam_succeed_if.so uid >= 1000 quiet
231 auth required pam_permit.so
232
233 account include lightdm
234
235 password include lightdm
236
237 session include lightdm
238 '';
239
240 users.extraUsers.lightdm = {
241 createHome = true;
242 home = "/var/lib/lightdm-data";
243 group = "lightdm";
244 uid = config.ids.uids.lightdm;
245 };
246
247 users.extraGroups.lightdm.gid = config.ids.gids.lightdm;
248 services.xserver.tty = null; # We might start multiple X servers so let the tty increment themselves..
249 services.xserver.display = null; # We specify our own display (and logfile) in xserver-wrapper up there
250 };
251}