grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / x11 / display-managers / lightdm.nix
blob25e6c597adcbd38ef2172425901aafa9bafc790c
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   xcfg = config.services.xserver;
8   dmcfg = config.services.displayManager;
9   xEnv = config.systemd.services.display-manager.environment;
10   cfg = xcfg.displayManager.lightdm;
11   sessionData = dmcfg.sessionData;
13   setSessionScript = pkgs.callPackage ./account-service-util.nix { };
15   inherit (pkgs) lightdm writeScript writeText;
17   # lightdm runs with clearenv(), but we need a few things in the environment for X to startup
18   xserverWrapper = writeScript "xserver-wrapper"
19     ''
20       #! ${pkgs.bash}/bin/bash
21       ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
23       display=$(echo "$@" | xargs -n 1 | grep -P ^:\\d\$ | head -n 1 | sed s/^://)
24       if [ -z "$display" ]
25       then additionalArgs=":0 -logfile /var/log/X.0.log"
26       else additionalArgs="-logfile /var/log/X.$display.log"
27       fi
29       exec ${xcfg.displayManager.xserverBin} ${toString xcfg.displayManager.xserverArgs} $additionalArgs "$@"
30     '';
32   usersConf = writeText "users.conf"
33     ''
34       [UserList]
35       minimum-uid=1000
36       hidden-users=${concatStringsSep " " dmcfg.hiddenUsers}
37       hidden-shells=/run/current-system/sw/bin/nologin
38     '';
40   lightdmConf = writeText "lightdm.conf"
41     ''
42       [LightDM]
43       ${optionalString cfg.greeter.enable ''
44         greeter-user = ${config.users.users.lightdm.name}
45         greeters-directory = ${cfg.greeter.package}
46       ''}
47       sessions-directory = ${dmcfg.sessionData.desktops}/share/xsessions:${dmcfg.sessionData.desktops}/share/wayland-sessions
48       ${cfg.extraConfig}
50       [Seat:*]
51       xserver-command = ${xserverWrapper}
52       session-wrapper = ${dmcfg.sessionData.wrapper}
53       ${optionalString cfg.greeter.enable ''
54         greeter-session = ${cfg.greeter.name}
55       ''}
56       ${optionalString dmcfg.autoLogin.enable ''
57         autologin-user = ${dmcfg.autoLogin.user}
58         autologin-user-timeout = ${toString cfg.autoLogin.timeout}
59         autologin-session = ${sessionData.autologinSession}
60       ''}
61       ${optionalString (xcfg.displayManager.setupCommands != "") ''
62         display-setup-script=${pkgs.writeScript "lightdm-display-setup" ''
63           #!${pkgs.bash}/bin/bash
64           ${xcfg.displayManager.setupCommands}
65         ''}
66       ''}
67       ${cfg.extraSeatDefaults}
68     '';
72   meta = with lib; {
73     maintainers = with maintainers; [ ] ++ teams.pantheon.members;
74   };
76   # Note: the order in which lightdm greeter modules are imported
77   # here determines the default: later modules (if enable) are
78   # preferred.
79   imports = [
80     ./lightdm-greeters/gtk.nix
81     ./lightdm-greeters/mini.nix
82     ./lightdm-greeters/enso-os.nix
83     ./lightdm-greeters/pantheon.nix
84     ./lightdm-greeters/lomiri.nix
85     ./lightdm-greeters/tiny.nix
86     ./lightdm-greeters/slick.nix
87     ./lightdm-greeters/mobile.nix
88     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "lightdm" "autoLogin" "enable" ] [
89       "services"
90       "displayManager"
91       "autoLogin"
92       "enable"
93     ])
94     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "lightdm" "autoLogin" "user" ] [
95      "services"
96      "displayManager"
97      "autoLogin"
98      "user"
99     ])
100   ];
102   options = {
104     services.xserver.displayManager.lightdm = {
106       enable = mkOption {
107         type = types.bool;
108         default = false;
109         description = ''
110           Whether to enable lightdm as the display manager.
111         '';
112       };
114       greeter =  {
115         enable = mkOption {
116           type = types.bool;
117           default = true;
118           description = ''
119             If set to false, run lightdm in greeterless mode. This only works if autologin
120             is enabled and autoLogin.timeout is zero.
121           '';
122         };
123         package = mkOption {
124           type = types.package;
125           description = ''
126             The LightDM greeter to login via. The package should be a directory
127             containing a .desktop file matching the name in the 'name' option.
128           '';
130         };
131         name = mkOption {
132           type = types.str;
133           description = ''
134             The name of a .desktop file in the directory specified
135             in the 'package' option.
136           '';
137         };
138       };
140       extraConfig = mkOption {
141         type = types.lines;
142         default = "";
143         example = ''
144           user-authority-in-system-dir = true
145         '';
146         description = "Extra lines to append to LightDM section.";
147       };
149       background = mkOption {
150         type = types.either types.path (types.strMatching "^#[0-9]\{6\}$");
151         # Manual cannot depend on packages, we are actually setting the default in config below.
152         defaultText = literalExpression "pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom.gnomeFilePath";
153         description = ''
154           The background image or color to use.
155         '';
156       };
158       extraSeatDefaults = mkOption {
159         type = types.lines;
160         default = "";
161         example = ''
162           greeter-show-manual-login=true
163         '';
164         description = "Extra lines to append to SeatDefaults section.";
165       };
167       # Configuration for automatic login specific to LightDM
168       autoLogin.timeout = mkOption {
169         type = types.int;
170         default = 0;
171         description = ''
172           Show the greeter for this many seconds before automatic login occurs.
173         '';
174       };
176     };
177   };
179   config = mkIf cfg.enable {
181     assertions = [
182       { assertion = xcfg.enable;
183         message = ''
184           LightDM requires services.xserver.enable to be true
185         '';
186       }
187       { assertion = dmcfg.autoLogin.enable -> sessionData.autologinSession != null;
188         message = ''
189           LightDM auto-login requires that services.displayManager.defaultSession is set.
190         '';
191       }
192       { assertion = !cfg.greeter.enable -> (dmcfg.autoLogin.enable && cfg.autoLogin.timeout == 0);
193         message = ''
194           LightDM can only run without greeter if automatic login is enabled and the timeout for it
195           is set to zero.
196         '';
197       }
198     ];
200     # Keep in sync with the defaultText value from the option definition.
201     services.xserver.displayManager.lightdm.background = mkDefault pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom.gnomeFilePath;
203     # Set default session in session chooser to a specified values – basically ignore session history.
204     # Auto-login is already covered by a config value.
205     services.displayManager.preStart = optionalString (!dmcfg.autoLogin.enable && dmcfg.defaultSession != null) ''
206       ${setSessionScript}/bin/set-session ${dmcfg.defaultSession}
207     '';
209     # setSessionScript needs session-files in XDG_DATA_DIRS
210     services.displayManager.environment.XDG_DATA_DIRS = "${dmcfg.sessionData.desktops}/share/";
212     # setSessionScript wants AccountsService
213     systemd.services.display-manager.wants = [
214       "accounts-daemon.service"
215     ];
217     # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
218     services.displayManager.execCmd = ''
219       export PATH=${lightdm}/sbin:$PATH
220       exec ${lightdm}/sbin/lightdm
221     '';
223     # Replaces getty
224     systemd.services.display-manager.conflicts = [
225       "getty@tty7.service"
226       # TODO: Add "plymouth-quit.service" so LightDM can control when plymouth
227       # quits. Currently this breaks switching to configurations with plymouth.
228      ];
230     # Pull in dependencies of services we replace.
231     systemd.services.display-manager.after = [
232       "rc-local.service"
233       "systemd-machined.service"
234       "systemd-user-sessions.service"
235       "getty@tty7.service"
236       "user.slice"
237     ];
239     # user.slice needs to be present
240     systemd.services.display-manager.requires = [
241       "user.slice"
242     ];
244     # lightdm stops plymouth so when it fails make sure plymouth stops.
245     systemd.services.display-manager.onFailure = [
246       "plymouth-quit.service"
247     ];
249     systemd.services.display-manager.serviceConfig = {
250       BusName = "org.freedesktop.DisplayManager";
251       IgnoreSIGPIPE = "no";
252       # This allows lightdm to pass the LUKS password through to PAM.
253       # login keyring is unlocked automatic when autologin is used.
254       KeyringMode = "shared";
255       KillMode = "mixed";
256       StandardError = "inherit";
257     };
259     environment.etc."lightdm/lightdm.conf".source = lightdmConf;
260     environment.etc."lightdm/users.conf".source = usersConf;
262     services.dbus.enable = true;
263     services.dbus.packages = [ lightdm ];
265     # lightdm uses the accounts daemon to remember language/window-manager per user
266     services.accounts-daemon.enable = true;
268     # Enable the accounts daemon to find lightdm's dbus interface
269     environment.systemPackages = [ lightdm ];
271     security.polkit.enable = true;
273     security.pam.services.lightdm.text = ''
274         auth      substack      login
275         account   include       login
276         password  substack      login
277         session   include       login
278     '';
280     security.pam.services.lightdm-greeter.text = ''
281         auth     required       pam_succeed_if.so audit quiet_success user = lightdm
282         auth     optional       pam_permit.so
284         account  required       pam_succeed_if.so audit quiet_success user = lightdm
285         account  sufficient     pam_unix.so
287         password required       pam_deny.so
289         session  required       pam_succeed_if.so audit quiet_success user = lightdm
290         session  required       pam_env.so conffile=/etc/pam/environment readenv=0
291         session  optional       ${config.systemd.package}/lib/security/pam_systemd.so
292         session  optional       pam_keyinit.so force revoke
293         session  optional       pam_permit.so
294     '';
296     security.pam.services.lightdm-autologin.text = ''
297         auth      requisite     pam_nologin.so
299         auth      required      pam_succeed_if.so uid >= 1000 quiet
300         auth      required      pam_permit.so
302         account   sufficient    pam_unix.so
304         password  requisite     pam_unix.so nullok yescrypt
306         session   optional      pam_keyinit.so revoke
307         session   include       login
308     '';
310     users.users.lightdm = {
311       home = "/var/lib/lightdm";
312       group = "lightdm";
313       uid = config.ids.uids.lightdm;
314     };
316     systemd.tmpfiles.rules = [
317       "d /run/lightdm 0711 lightdm lightdm -"
318       "d /var/cache/lightdm 0711 root lightdm -"
319       "d /var/lib/lightdm 1770 lightdm lightdm -"
320       "d /var/lib/lightdm-data 1775 lightdm lightdm -"
321       "d /var/log/lightdm 0711 root lightdm -"
322     ];
324     users.groups.lightdm.gid = config.ids.gids.lightdm;
325     services.xserver.tty     = null; # We might start multiple X servers so let the tty increment themselves..
326     services.xserver.display = null; # We specify our own display (and logfile) in xserver-wrapper up there
327   };