2014-04-02 17:21:00 +01:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
|
|
cfg = config.services.xserver.displayManager;
|
2017-09-24 12:15:50 +01:00
|
|
|
gdm = pkgs.gnome3.gdm;
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2018-06-30 08:33:45 +01:00
|
|
|
xSessionWrapper = if (cfg.setupCommands == "") then null else
|
|
|
|
pkgs.writeScript "gdm-x-session-wrapper" ''
|
|
|
|
#!${pkgs.bash}/bin/bash
|
|
|
|
${cfg.setupCommands}
|
|
|
|
exec "$@"
|
|
|
|
'';
|
|
|
|
|
2019-05-09 17:04:34 +01:00
|
|
|
# Solves problems like:
|
|
|
|
# https://wiki.archlinux.org/index.php/Talk:Bluetooth_headset#GDMs_pulseaudio_instance_captures_bluetooth_headset
|
|
|
|
# Instead of blacklisting plugins, we use Fedora's PulseAudio configuration for GDM:
|
|
|
|
# https://src.fedoraproject.org/rpms/gdm/blob/master/f/default.pa-for-gdm
|
|
|
|
pulseConfig = pkgs.writeText "default.pa" ''
|
|
|
|
load-module module-device-restore
|
|
|
|
load-module module-card-restore
|
|
|
|
load-module module-udev-detect
|
|
|
|
load-module module-native-protocol-unix
|
|
|
|
load-module module-default-device-restore
|
|
|
|
load-module module-rescue-streams
|
|
|
|
load-module module-always-sink
|
|
|
|
load-module module-intended-roles
|
|
|
|
load-module module-suspend-on-idle
|
|
|
|
load-module module-position-event-sounds
|
|
|
|
'';
|
|
|
|
|
2014-04-02 17:21:00 +01:00
|
|
|
in
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
###### interface
|
|
|
|
|
|
|
|
options = {
|
|
|
|
|
|
|
|
services.xserver.displayManager.gdm = {
|
|
|
|
|
2015-08-27 17:11:09 +01:00
|
|
|
enable = mkEnableOption ''
|
2019-09-27 22:42:39 +01:00
|
|
|
GDM, the GNOME Display Manager
|
2015-08-27 17:11:09 +01:00
|
|
|
'';
|
|
|
|
|
2015-09-14 09:33:44 +01:00
|
|
|
debug = mkEnableOption ''
|
|
|
|
debugging messages in GDM
|
|
|
|
'';
|
|
|
|
|
2015-08-27 17:11:09 +01:00
|
|
|
autoLogin = mkOption {
|
|
|
|
default = {};
|
2015-08-28 04:55:56 +01:00
|
|
|
description = ''
|
|
|
|
Auto login configuration attrset.
|
|
|
|
'';
|
2015-08-27 17:11:09 +01:00
|
|
|
|
|
|
|
type = types.submodule {
|
|
|
|
options = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
2015-09-03 21:11:25 +01:00
|
|
|
Automatically log in as the sepecified <option>autoLogin.user</option>.
|
2015-08-27 17:11:09 +01:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
user = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
User to be used for the autologin.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
delay = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 0;
|
|
|
|
description = ''
|
|
|
|
Seconds of inactivity after which the autologin will be performed.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
2014-04-02 17:21:00 +01:00
|
|
|
};
|
|
|
|
|
2017-05-07 21:27:02 +01:00
|
|
|
wayland = mkOption {
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
Allow GDM run on Wayland instead of Xserver
|
|
|
|
'';
|
|
|
|
type = types.bool;
|
|
|
|
};
|
|
|
|
|
2019-06-25 22:58:20 +01:00
|
|
|
autoSuspend = mkOption {
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
Suspend the machine after inactivity.
|
|
|
|
'';
|
|
|
|
type = types.bool;
|
|
|
|
};
|
|
|
|
|
2014-04-02 17:21:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
###### implementation
|
|
|
|
|
|
|
|
config = mkIf cfg.gdm.enable {
|
|
|
|
|
2015-09-03 21:22:00 +01:00
|
|
|
assertions = [
|
2015-09-05 09:21:43 +01:00
|
|
|
{ assertion = cfg.gdm.autoLogin.enable -> cfg.gdm.autoLogin.user != null;
|
2015-09-03 21:22:00 +01:00
|
|
|
message = "GDM auto-login requires services.xserver.displayManager.gdm.autoLogin.user to be set";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2018-08-20 13:25:25 +01:00
|
|
|
services.xserver.displayManager.lightdm.enable = false;
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2018-06-30 00:58:35 +01:00
|
|
|
users.users.gdm =
|
2014-04-02 17:21:00 +01:00
|
|
|
{ name = "gdm";
|
|
|
|
uid = config.ids.uids.gdm;
|
|
|
|
group = "gdm";
|
|
|
|
home = "/run/gdm";
|
|
|
|
description = "GDM user";
|
|
|
|
};
|
|
|
|
|
2018-06-30 00:58:35 +01:00
|
|
|
users.groups.gdm.gid = config.ids.gids.gdm;
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2016-12-04 13:48:47 +00:00
|
|
|
# GDM needs different xserverArgs, presumable because using wayland by default.
|
|
|
|
services.xserver.tty = null;
|
|
|
|
services.xserver.display = null;
|
2017-05-07 22:01:20 +01:00
|
|
|
services.xserver.verbose = null;
|
2016-12-04 13:48:47 +00:00
|
|
|
|
2014-04-02 17:21:00 +01:00
|
|
|
services.xserver.displayManager.job =
|
2015-08-28 04:55:56 +01:00
|
|
|
{
|
2014-04-02 17:21:00 +01:00
|
|
|
environment = {
|
2016-12-04 13:48:47 +00:00
|
|
|
GDM_X_SERVER_EXTRA_ARGS = toString
|
|
|
|
(filter (arg: arg != "-terminate") cfg.xserverArgs);
|
2018-09-08 06:58:17 +01:00
|
|
|
XDG_DATA_DIRS = "${cfg.session.desktops}/share/";
|
2018-06-30 08:33:45 +01:00
|
|
|
} // optionalAttrs (xSessionWrapper != null) {
|
|
|
|
# Make GDM use this wrapper before running the session, which runs the
|
|
|
|
# configured setupCommands. This relies on a patched GDM which supports
|
|
|
|
# this environment variable.
|
|
|
|
GDM_X_SESSION_WRAPPER = "${xSessionWrapper}";
|
2014-04-02 17:21:00 +01:00
|
|
|
};
|
2015-04-10 16:02:57 +01:00
|
|
|
execCmd = "exec ${gdm}/bin/gdm";
|
2019-05-09 17:04:34 +01:00
|
|
|
preStart = optionalString config.hardware.pulseaudio.enable ''
|
|
|
|
mkdir -p /run/gdm/.config/pulse
|
|
|
|
ln -sf ${pulseConfig} /run/gdm/.config/pulse/default.pa
|
|
|
|
chown -R gdm:gdm /run/gdm/.config
|
|
|
|
'';
|
2014-04-02 17:21:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
# Because sd_login_monitor_new requires /run/systemd/machines
|
|
|
|
systemd.services.display-manager.wants = [ "systemd-machined.service" ];
|
2017-06-25 17:59:23 +01:00
|
|
|
systemd.services.display-manager.after = [
|
|
|
|
"rc-local.service"
|
|
|
|
"systemd-machined.service"
|
|
|
|
"systemd-user-sessions.service"
|
2019-09-15 12:30:04 +01:00
|
|
|
"getty@tty1.service"
|
|
|
|
];
|
|
|
|
systemd.services.display-manager.conflicts = [
|
|
|
|
"getty@tty1.service"
|
2017-06-25 17:59:23 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
systemd.services.display-manager.serviceConfig = {
|
2017-08-28 15:56:04 +01:00
|
|
|
# Restart = "always"; - already defined in xserver.nix
|
|
|
|
KillMode = "mixed";
|
|
|
|
IgnoreSIGPIPE = "no";
|
|
|
|
BusName = "org.gnome.DisplayManager";
|
|
|
|
StandardOutput = "syslog";
|
|
|
|
StandardError = "inherit";
|
2017-06-25 17:59:23 +01:00
|
|
|
};
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2018-02-25 02:23:58 +00:00
|
|
|
systemd.services.display-manager.path = [ pkgs.gnome3.gnome-session ];
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2018-04-30 17:15:28 +01:00
|
|
|
# Allow choosing an user account
|
|
|
|
services.accounts-daemon.enable = true;
|
|
|
|
|
2014-04-02 17:21:00 +01:00
|
|
|
services.dbus.packages = [ gdm ];
|
2016-10-03 16:11:24 +01:00
|
|
|
|
|
|
|
systemd.user.services.dbus.wantedBy = [ "default.target" ];
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2019-06-25 22:58:20 +01:00
|
|
|
programs.dconf.profiles.gdm =
|
|
|
|
let
|
|
|
|
customDconf = pkgs.writeTextFile {
|
|
|
|
name = "gdm-dconf";
|
|
|
|
destination = "/dconf/gdm-custom";
|
|
|
|
text = ''
|
|
|
|
${optionalString (!cfg.gdm.autoSuspend) ''
|
|
|
|
[org/gnome/settings-daemon/plugins/power]
|
|
|
|
sleep-inactive-ac-type='nothing'
|
|
|
|
sleep-inactive-battery-type='nothing'
|
|
|
|
sleep-inactive-ac-timeout=0
|
|
|
|
sleep-inactive-battery-timeout=0
|
|
|
|
''}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
customDconfDb = pkgs.stdenv.mkDerivation {
|
|
|
|
name = "gdm-dconf-db";
|
|
|
|
buildCommand = ''
|
|
|
|
${pkgs.gnome3.dconf}/bin/dconf compile $out ${customDconf}/dconf
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
in pkgs.stdenv.mkDerivation {
|
|
|
|
name = "dconf-gdm-profile";
|
|
|
|
buildCommand = ''
|
|
|
|
# Check that the GDM profile starts with what we expect.
|
|
|
|
if [ $(head -n 1 ${gdm}/share/dconf/profile/gdm) != "user-db:user" ]; then
|
|
|
|
echo "GDM dconf profile changed, please update gdm.nix"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
# Insert our custom DB behind it.
|
|
|
|
sed '2ifile-db:${customDconfDb}' ${gdm}/share/dconf/profile/gdm > $out
|
|
|
|
'';
|
|
|
|
};
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2015-09-14 09:48:00 +01:00
|
|
|
# Use AutomaticLogin if delay is zero, because it's immediate.
|
|
|
|
# Otherwise with TimedLogin with zero seconds the prompt is still
|
|
|
|
# presented and there's a little delay.
|
2015-08-27 17:11:09 +01:00
|
|
|
environment.etc."gdm/custom.conf".text = ''
|
|
|
|
[daemon]
|
2017-05-07 21:27:02 +01:00
|
|
|
WaylandEnable=${if cfg.gdm.wayland then "true" else "false"}
|
2015-09-14 09:48:00 +01:00
|
|
|
${optionalString cfg.gdm.autoLogin.enable (
|
|
|
|
if cfg.gdm.autoLogin.delay > 0 then ''
|
|
|
|
TimedLoginEnable=true
|
|
|
|
TimedLogin=${cfg.gdm.autoLogin.user}
|
|
|
|
TimedLoginDelay=${toString cfg.gdm.autoLogin.delay}
|
|
|
|
'' else ''
|
|
|
|
AutomaticLoginEnable=true
|
|
|
|
AutomaticLogin=${cfg.gdm.autoLogin.user}
|
|
|
|
'')
|
|
|
|
}
|
2015-08-27 17:11:09 +01:00
|
|
|
|
|
|
|
[security]
|
|
|
|
|
|
|
|
[xdmcp]
|
|
|
|
|
|
|
|
[greeter]
|
|
|
|
|
|
|
|
[chooser]
|
|
|
|
|
|
|
|
[debug]
|
2015-09-14 09:33:44 +01:00
|
|
|
${optionalString cfg.gdm.debug "Enable=true"}
|
2015-08-27 17:11:09 +01:00
|
|
|
'';
|
|
|
|
|
2018-07-24 15:52:49 +01:00
|
|
|
environment.etc."gdm/Xsession".source = config.services.xserver.displayManager.session.wrapper;
|
2018-07-23 00:34:53 +01:00
|
|
|
|
2014-04-02 17:21:00 +01:00
|
|
|
# GDM LFS PAM modules, adapted somehow to NixOS
|
|
|
|
security.pam.services = {
|
|
|
|
gdm-launch-environment.text = ''
|
|
|
|
auth required pam_succeed_if.so audit quiet_success user = gdm
|
|
|
|
auth optional pam_permit.so
|
|
|
|
|
|
|
|
account required pam_succeed_if.so audit quiet_success user = gdm
|
|
|
|
account sufficient pam_unix.so
|
|
|
|
|
|
|
|
password required pam_deny.so
|
|
|
|
|
|
|
|
session required pam_succeed_if.so audit quiet_success user = gdm
|
2019-08-19 15:05:10 +01:00
|
|
|
session required pam_env.so conffile=${config.system.build.pamEnvironment} readenv=0
|
2014-04-02 17:21:00 +01:00
|
|
|
session optional ${pkgs.systemd}/lib/security/pam_systemd.so
|
|
|
|
session optional pam_keyinit.so force revoke
|
|
|
|
session optional pam_permit.so
|
|
|
|
'';
|
|
|
|
|
|
|
|
gdm-password.text = ''
|
2017-01-13 16:16:55 +00:00
|
|
|
auth substack login
|
|
|
|
account include login
|
|
|
|
password substack login
|
|
|
|
session include login
|
2014-04-02 17:21:00 +01:00
|
|
|
'';
|
|
|
|
|
|
|
|
gdm-autologin.text = ''
|
2017-01-13 16:16:55 +00:00
|
|
|
auth requisite pam_nologin.so
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2017-01-13 16:16:55 +00:00
|
|
|
auth required pam_succeed_if.so uid >= 1000 quiet
|
|
|
|
auth required pam_permit.so
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2017-01-13 16:16:55 +00:00
|
|
|
account sufficient pam_unix.so
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2017-01-13 16:16:55 +00:00
|
|
|
password requisite pam_unix.so nullok sha512
|
2014-04-02 17:21:00 +01:00
|
|
|
|
2017-01-13 16:16:55 +00:00
|
|
|
session optional pam_keyinit.so revoke
|
|
|
|
session include login
|
2014-04-02 17:21:00 +01:00
|
|
|
'';
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|