1 { config, lib, pkgs, ... }:
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"
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/^://)
25 then additionalArgs=":0 -logfile /var/log/X.0.log"
26 else additionalArgs="-logfile /var/log/X.$display.log"
29 exec ${xcfg.displayManager.xserverBin} ${toString xcfg.displayManager.xserverArgs} $additionalArgs "$@"
32 usersConf = writeText "users.conf"
36 hidden-users=${concatStringsSep " " dmcfg.hiddenUsers}
37 hidden-shells=/run/current-system/sw/bin/nologin
40 lightdmConf = writeText "lightdm.conf"
43 ${optionalString cfg.greeter.enable ''
44 greeter-user = ${config.users.users.lightdm.name}
45 greeters-directory = ${cfg.greeter.package}
47 sessions-directory = ${dmcfg.sessionData.desktops}/share/xsessions:${dmcfg.sessionData.desktops}/share/wayland-sessions
51 xserver-command = ${xserverWrapper}
52 session-wrapper = ${dmcfg.sessionData.wrapper}
53 ${optionalString cfg.greeter.enable ''
54 greeter-session = ${cfg.greeter.name}
56 ${optionalString dmcfg.autoLogin.enable ''
57 autologin-user = ${dmcfg.autoLogin.user}
58 autologin-user-timeout = ${toString cfg.autoLogin.timeout}
59 autologin-session = ${sessionData.autologinSession}
61 ${optionalString (xcfg.displayManager.setupCommands != "") ''
62 display-setup-script=${pkgs.writeScript "lightdm-display-setup" ''
63 #!${pkgs.bash}/bin/bash
64 ${xcfg.displayManager.setupCommands}
67 ${cfg.extraSeatDefaults}
73 maintainers = with maintainers; [ ] ++ teams.pantheon.members;
76 # Note: the order in which lightdm greeter modules are imported
77 # here determines the default: later modules (if enable) are
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" ] [
94 (mkRenamedOptionModule [ "services" "xserver" "displayManager" "lightdm" "autoLogin" "user" ] [
104 services.xserver.displayManager.lightdm = {
110 Whether to enable lightdm as the display manager.
119 If set to false, run lightdm in greeterless mode. This only works if autologin
120 is enabled and autoLogin.timeout is zero.
124 type = types.package;
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.
134 The name of a .desktop file in the directory specified
135 in the 'package' option.
140 extraConfig = mkOption {
144 user-authority-in-system-dir = true
146 description = "Extra lines to append to LightDM section.";
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";
154 The background image or color to use.
158 extraSeatDefaults = mkOption {
162 greeter-show-manual-login=true
164 description = "Extra lines to append to SeatDefaults section.";
167 # Configuration for automatic login specific to LightDM
168 autoLogin.timeout = mkOption {
172 Show the greeter for this many seconds before automatic login occurs.
179 config = mkIf cfg.enable {
182 { assertion = xcfg.enable;
184 LightDM requires services.xserver.enable to be true
187 { assertion = dmcfg.autoLogin.enable -> sessionData.autologinSession != null;
189 LightDM auto-login requires that services.displayManager.defaultSession is set.
192 { assertion = !cfg.greeter.enable -> (dmcfg.autoLogin.enable && cfg.autoLogin.timeout == 0);
194 LightDM can only run without greeter if automatic login is enabled and the timeout for it
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}
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"
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
224 systemd.services.display-manager.conflicts = [
226 # TODO: Add "plymouth-quit.service" so LightDM can control when plymouth
227 # quits. Currently this breaks switching to configurations with plymouth.
230 # Pull in dependencies of services we replace.
231 systemd.services.display-manager.after = [
233 "systemd-machined.service"
234 "systemd-user-sessions.service"
239 # user.slice needs to be present
240 systemd.services.display-manager.requires = [
244 # lightdm stops plymouth so when it fails make sure plymouth stops.
245 systemd.services.display-manager.onFailure = [
246 "plymouth-quit.service"
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";
256 StandardError = "inherit";
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 = ''
275 account include login
276 password substack login
277 session include login
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
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
310 users.users.lightdm = {
311 home = "/var/lib/lightdm";
313 uid = config.ids.uids.lightdm;
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 -"
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