336 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{ config, lib, pkgs, ... }:
 | 
						||
 | 
						||
with lib;
 | 
						||
 | 
						||
let
 | 
						||
 | 
						||
  xcfg = config.services.xserver;
 | 
						||
  dmcfg = xcfg.displayManager;
 | 
						||
  xEnv = config.systemd.services.display-manager.environment;
 | 
						||
  cfg = dmcfg.lightdm;
 | 
						||
  sessionData = dmcfg.sessionData;
 | 
						||
 | 
						||
  setSessionScript = pkgs.callPackage ./account-service-util.nix { };
 | 
						||
 | 
						||
  inherit (pkgs) lightdm writeScript writeText;
 | 
						||
 | 
						||
  # lightdm runs with clearenv(), but we need a few things in the environment for X to startup
 | 
						||
  xserverWrapper = writeScript "xserver-wrapper"
 | 
						||
    ''
 | 
						||
      #! ${pkgs.bash}/bin/bash
 | 
						||
      ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
 | 
						||
 | 
						||
      display=$(echo "$@" | xargs -n 1 | grep -P ^:\\d\$ | head -n 1 | sed s/^://)
 | 
						||
      if [ -z "$display" ]
 | 
						||
      then additionalArgs=":0 -logfile /var/log/X.0.log"
 | 
						||
      else additionalArgs="-logfile /var/log/X.$display.log"
 | 
						||
      fi
 | 
						||
 | 
						||
      exec ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} $additionalArgs "$@"
 | 
						||
    '';
 | 
						||
 | 
						||
  usersConf = writeText "users.conf"
 | 
						||
    ''
 | 
						||
      [UserList]
 | 
						||
      minimum-uid=500
 | 
						||
      hidden-users=${concatStringsSep " " dmcfg.hiddenUsers}
 | 
						||
      hidden-shells=/run/current-system/sw/bin/nologin
 | 
						||
    '';
 | 
						||
 | 
						||
  lightdmConf = writeText "lightdm.conf"
 | 
						||
    ''
 | 
						||
      [LightDM]
 | 
						||
      ${optionalString cfg.greeter.enable ''
 | 
						||
        greeter-user = ${config.users.users.lightdm.name}
 | 
						||
        greeters-directory = ${cfg.greeter.package}
 | 
						||
      ''}
 | 
						||
      sessions-directory = ${dmcfg.sessionData.desktops}/share/xsessions:${dmcfg.sessionData.desktops}/share/wayland-sessions
 | 
						||
      ${cfg.extraConfig}
 | 
						||
 | 
						||
      [Seat:*]
 | 
						||
      xserver-command = ${xserverWrapper}
 | 
						||
      session-wrapper = ${dmcfg.sessionData.wrapper}
 | 
						||
      ${optionalString cfg.greeter.enable ''
 | 
						||
        greeter-session = ${cfg.greeter.name}
 | 
						||
      ''}
 | 
						||
      ${optionalString cfg.autoLogin.enable ''
 | 
						||
        autologin-user = ${cfg.autoLogin.user}
 | 
						||
        autologin-user-timeout = ${toString cfg.autoLogin.timeout}
 | 
						||
        autologin-session = ${sessionData.autologinSession}
 | 
						||
      ''}
 | 
						||
      ${optionalString (dmcfg.setupCommands != "") ''
 | 
						||
        display-setup-script=${pkgs.writeScript "lightdm-display-setup" ''
 | 
						||
          #!${pkgs.bash}/bin/bash
 | 
						||
          ${dmcfg.setupCommands}
 | 
						||
        ''}
 | 
						||
      ''}
 | 
						||
      ${cfg.extraSeatDefaults}
 | 
						||
    '';
 | 
						||
 | 
						||
in
 | 
						||
{
 | 
						||
  # Note: the order in which lightdm greeter modules are imported
 | 
						||
  # here determines the default: later modules (if enable) are
 | 
						||
  # preferred.
 | 
						||
  imports = [
 | 
						||
    ./lightdm-greeters/gtk.nix
 | 
						||
    ./lightdm-greeters/mini.nix
 | 
						||
    ./lightdm-greeters/enso-os.nix
 | 
						||
    ./lightdm-greeters/pantheon.nix
 | 
						||
    ./lightdm-greeters/tiny.nix
 | 
						||
  ];
 | 
						||
 | 
						||
  options = {
 | 
						||
 | 
						||
    services.xserver.displayManager.lightdm = {
 | 
						||
 | 
						||
      enable = mkOption {
 | 
						||
        type = types.bool;
 | 
						||
        default = false;
 | 
						||
        description = ''
 | 
						||
          Whether to enable lightdm as the display manager.
 | 
						||
        '';
 | 
						||
      };
 | 
						||
 | 
						||
      greeter =  {
 | 
						||
        enable = mkOption {
 | 
						||
          type = types.bool;
 | 
						||
          default = true;
 | 
						||
          description = ''
 | 
						||
            If set to false, run lightdm in greeterless mode. This only works if autologin
 | 
						||
            is enabled and autoLogin.timeout is zero.
 | 
						||
          '';
 | 
						||
        };
 | 
						||
        package = mkOption {
 | 
						||
          type = types.package;
 | 
						||
          description = ''
 | 
						||
            The LightDM greeter to login via. The package should be a directory
 | 
						||
            containing a .desktop file matching the name in the 'name' option.
 | 
						||
          '';
 | 
						||
 | 
						||
        };
 | 
						||
        name = mkOption {
 | 
						||
          type = types.str;
 | 
						||
          description = ''
 | 
						||
            The name of a .desktop file in the directory specified
 | 
						||
            in the 'package' option.
 | 
						||
          '';
 | 
						||
        };
 | 
						||
      };
 | 
						||
 | 
						||
      extraConfig = mkOption {
 | 
						||
        type = types.lines;
 | 
						||
        default = "";
 | 
						||
        example = ''
 | 
						||
          user-authority-in-system-dir = true
 | 
						||
        '';
 | 
						||
        description = "Extra lines to append to LightDM section.";
 | 
						||
      };
 | 
						||
 | 
						||
      background = mkOption {
 | 
						||
        type = types.str;
 | 
						||
        default = "${pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom}/share/artwork/gnome/nix-wallpaper-simple-dark-gray_bottom.png";
 | 
						||
        description = ''
 | 
						||
          The background image or color to use.
 | 
						||
        '';
 | 
						||
      };
 | 
						||
 | 
						||
      extraSeatDefaults = mkOption {
 | 
						||
        type = types.lines;
 | 
						||
        default = "";
 | 
						||
        example = ''
 | 
						||
          greeter-show-manual-login=true
 | 
						||
        '';
 | 
						||
        description = "Extra lines to append to SeatDefaults section.";
 | 
						||
      };
 | 
						||
 | 
						||
      autoLogin = mkOption {
 | 
						||
        default = {};
 | 
						||
        description = ''
 | 
						||
          Configuration for automatic login.
 | 
						||
        '';
 | 
						||
 | 
						||
        type = types.submodule {
 | 
						||
          options = {
 | 
						||
            enable = mkOption {
 | 
						||
              type = types.bool;
 | 
						||
              default = false;
 | 
						||
              description = ''
 | 
						||
                Automatically log in as the specified <option>autoLogin.user</option>.
 | 
						||
              '';
 | 
						||
            };
 | 
						||
 | 
						||
            user = mkOption {
 | 
						||
              type = types.nullOr types.str;
 | 
						||
              default = null;
 | 
						||
              description = ''
 | 
						||
                User to be used for the automatic login.
 | 
						||
              '';
 | 
						||
            };
 | 
						||
 | 
						||
            timeout = mkOption {
 | 
						||
              type = types.int;
 | 
						||
              default = 0;
 | 
						||
              description = ''
 | 
						||
                Show the greeter for this many seconds before automatic login occurs.
 | 
						||
              '';
 | 
						||
            };
 | 
						||
          };
 | 
						||
        };
 | 
						||
      };
 | 
						||
 | 
						||
    };
 | 
						||
  };
 | 
						||
 | 
						||
  config = mkIf cfg.enable {
 | 
						||
 | 
						||
    assertions = [
 | 
						||
      { assertion = xcfg.enable;
 | 
						||
        message = ''
 | 
						||
          LightDM requires services.xserver.enable to be true
 | 
						||
        '';
 | 
						||
      }
 | 
						||
      { assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null;
 | 
						||
        message = ''
 | 
						||
          LightDM auto-login requires services.xserver.displayManager.lightdm.autoLogin.user to be set
 | 
						||
        '';
 | 
						||
      }
 | 
						||
      { assertion = cfg.autoLogin.enable -> sessionData.autologinSession != null;
 | 
						||
        message = ''
 | 
						||
          LightDM auto-login requires that services.xserver.displayManager.defaultSession is set.
 | 
						||
        '';
 | 
						||
      }
 | 
						||
      { assertion = !cfg.greeter.enable -> (cfg.autoLogin.enable && cfg.autoLogin.timeout == 0);
 | 
						||
        message = ''
 | 
						||
          LightDM can only run without greeter if automatic login is enabled and the timeout for it
 | 
						||
          is set to zero.
 | 
						||
        '';
 | 
						||
      }
 | 
						||
    ];
 | 
						||
 | 
						||
    # Set default session in session chooser to a specified values – basically ignore session history.
 | 
						||
    # Auto-login is already covered by a config value.
 | 
						||
    services.xserver.displayManager.job.preStart = optionalString (!cfg.autoLogin.enable && dmcfg.defaultSession != null) ''
 | 
						||
      ${setSessionScript}/bin/set-session ${dmcfg.defaultSession}
 | 
						||
    '';
 | 
						||
 | 
						||
    # setSessionScript needs session-files in XDG_DATA_DIRS
 | 
						||
    services.xserver.displayManager.job.environment.XDG_DATA_DIRS = "${dmcfg.sessionData.desktops}/share/";
 | 
						||
 | 
						||
    # setSessionScript wants AccountsService
 | 
						||
    systemd.services.display-manager.wants = [
 | 
						||
      "accounts-daemon.service"
 | 
						||
    ];
 | 
						||
 | 
						||
    # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
 | 
						||
    services.xserver.displayManager.job.execCmd = ''
 | 
						||
      export PATH=${lightdm}/sbin:$PATH
 | 
						||
      exec ${lightdm}/sbin/lightdm
 | 
						||
    '';
 | 
						||
 | 
						||
    # Replaces getty
 | 
						||
    systemd.services.display-manager.conflicts = [
 | 
						||
      "getty@tty7.service"
 | 
						||
      # TODO: Add "plymouth-quit.service" so LightDM can control when plymouth
 | 
						||
      # quits. Currently this breaks switching to configurations with plymouth.
 | 
						||
     ];
 | 
						||
 | 
						||
    # Pull in dependencies of services we replace.
 | 
						||
    systemd.services.display-manager.after = [
 | 
						||
      "rc-local.service"
 | 
						||
      "systemd-machined.service"
 | 
						||
      "systemd-user-sessions.service"
 | 
						||
      "getty@tty7.service"
 | 
						||
      "user.slice"
 | 
						||
    ];
 | 
						||
 | 
						||
    # user.slice needs to be present
 | 
						||
    systemd.services.display-manager.requires = [
 | 
						||
      "user.slice"
 | 
						||
    ];
 | 
						||
 | 
						||
    # lightdm stops plymouth so when it fails make sure plymouth stops.
 | 
						||
    systemd.services.display-manager.onFailure = [
 | 
						||
      "plymouth-quit.service"
 | 
						||
    ];
 | 
						||
 | 
						||
    systemd.services.display-manager.serviceConfig = {
 | 
						||
      BusName = "org.freedesktop.DisplayManager";
 | 
						||
      IgnoreSIGPIPE = "no";
 | 
						||
      # This allows lightdm to pass the LUKS password through to PAM.
 | 
						||
      # login keyring is unlocked automatic when autologin is used.
 | 
						||
      KeyringMode = "shared";
 | 
						||
      KillMode = "mixed";
 | 
						||
      StandardError = "inherit";
 | 
						||
      StandardOutput = "syslog";
 | 
						||
    };
 | 
						||
 | 
						||
    environment.etc."lightdm/lightdm.conf".source = lightdmConf;
 | 
						||
    environment.etc."lightdm/users.conf".source = usersConf;
 | 
						||
 | 
						||
    services.dbus.enable = true;
 | 
						||
    services.dbus.packages = [ lightdm ];
 | 
						||
 | 
						||
    # lightdm uses the accounts daemon to remember language/window-manager per user
 | 
						||
    services.accounts-daemon.enable = true;
 | 
						||
 | 
						||
    # Enable the accounts daemon to find lightdm's dbus interface
 | 
						||
    environment.systemPackages = [ lightdm ];
 | 
						||
 | 
						||
    security.pam.services.lightdm.text = ''
 | 
						||
        auth      substack      login
 | 
						||
        account   include       login
 | 
						||
        password  substack      login
 | 
						||
        session   include       login
 | 
						||
    '';
 | 
						||
 | 
						||
    security.pam.services.lightdm-greeter.text = ''
 | 
						||
        auth     required       pam_succeed_if.so audit quiet_success user = lightdm
 | 
						||
        auth     optional       pam_permit.so
 | 
						||
 | 
						||
        account  required       pam_succeed_if.so audit quiet_success user = lightdm
 | 
						||
        account  sufficient     pam_unix.so
 | 
						||
 | 
						||
        password required       pam_deny.so
 | 
						||
 | 
						||
        session  required       pam_succeed_if.so audit quiet_success user = lightdm
 | 
						||
        session  required       pam_env.so conffile=${config.system.build.pamEnvironment} readenv=0
 | 
						||
        session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
 | 
						||
        session  optional       pam_keyinit.so force revoke
 | 
						||
        session  optional       pam_permit.so
 | 
						||
    '';
 | 
						||
 | 
						||
    security.pam.services.lightdm-autologin.text = ''
 | 
						||
        auth      requisite     pam_nologin.so
 | 
						||
 | 
						||
        auth      required      pam_succeed_if.so uid >= 1000 quiet
 | 
						||
        auth      required      pam_permit.so
 | 
						||
 | 
						||
        account   sufficient    pam_unix.so
 | 
						||
 | 
						||
        password  requisite     pam_unix.so nullok sha512
 | 
						||
 | 
						||
        session   optional      pam_keyinit.so revoke
 | 
						||
        session   include       login
 | 
						||
    '';
 | 
						||
 | 
						||
    users.users.lightdm = {
 | 
						||
      home = "/var/lib/lightdm";
 | 
						||
      group = "lightdm";
 | 
						||
      uid = config.ids.uids.lightdm;
 | 
						||
    };
 | 
						||
 | 
						||
    systemd.tmpfiles.rules = [
 | 
						||
      "d /run/lightdm 0711 lightdm lightdm 0"
 | 
						||
      "d /var/cache/lightdm 0711 root lightdm -"
 | 
						||
      "d /var/lib/lightdm 1770 lightdm lightdm -"
 | 
						||
      "d /var/lib/lightdm-data 1775 lightdm lightdm -"
 | 
						||
      "d /var/log/lightdm 0711 root lightdm -"
 | 
						||
    ];
 | 
						||
 | 
						||
    users.groups.lightdm.gid = config.ids.gids.lightdm;
 | 
						||
    services.xserver.tty     = null; # We might start multiple X servers so let the tty increment themselves..
 | 
						||
    services.xserver.display = null; # We specify our own display (and logfile) in xserver-wrapper up there
 | 
						||
  };
 | 
						||
}
 |