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