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