1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.xserver.displayManager; 8 gdm = pkgs.gnome3.gdm; 9 10in 11 12{ 13 14 ###### interface 15 16 options = { 17 18 services.xserver.displayManager.gdm = { 19 20 enable = mkEnableOption '' 21 GDM as the display manager. 22 <emphasis>GDM in NixOS is not well-tested with desktops other 23 than GNOME, so use with caution, as it could render the 24 system unusable.</emphasis> 25 ''; 26 27 debug = mkEnableOption '' 28 debugging messages in GDM 29 ''; 30 31 autoLogin = mkOption { 32 default = {}; 33 description = '' 34 Auto login configuration attrset. 35 ''; 36 37 type = types.submodule { 38 options = { 39 enable = mkOption { 40 type = types.bool; 41 default = false; 42 description = '' 43 Automatically log in as the sepecified <option>autoLogin.user</option>. 44 ''; 45 }; 46 47 user = mkOption { 48 type = types.nullOr types.str; 49 default = null; 50 description = '' 51 User to be used for the autologin. 52 ''; 53 }; 54 55 delay = mkOption { 56 type = types.int; 57 default = 0; 58 description = '' 59 Seconds of inactivity after which the autologin will be performed. 60 ''; 61 }; 62 63 }; 64 }; 65 }; 66 67 wayland = mkOption { 68 default = true; 69 description = '' 70 Allow GDM run on Wayland instead of Xserver 71 ''; 72 type = types.bool; 73 }; 74 75 }; 76 77 }; 78 79 80 ###### implementation 81 82 config = mkIf cfg.gdm.enable { 83 84 assertions = [ 85 { assertion = cfg.gdm.autoLogin.enable -> cfg.gdm.autoLogin.user != null; 86 message = "GDM auto-login requires services.xserver.displayManager.gdm.autoLogin.user to be set"; 87 } 88 ]; 89 90 services.xserver.displayManager.lightdm.enable = false; 91 92 users.users.gdm = 93 { name = "gdm"; 94 uid = config.ids.uids.gdm; 95 group = "gdm"; 96 home = "/run/gdm"; 97 description = "GDM user"; 98 }; 99 100 users.groups.gdm.gid = config.ids.gids.gdm; 101 102 # GDM needs different xserverArgs, presumable because using wayland by default. 103 services.xserver.tty = null; 104 services.xserver.display = null; 105 services.xserver.verbose = null; 106 107 services.xserver.displayManager.job = 108 { 109 environment = { 110 GDM_X_SERVER_EXTRA_ARGS = toString 111 (filter (arg: arg != "-terminate") cfg.xserverArgs); 112 GDM_SESSIONS_DIR = "${cfg.session.desktops}/share/xsessions"; 113 # Find the mouse 114 XCURSOR_PATH = "~/.icons:${pkgs.gnome3.adwaita-icon-theme}/share/icons"; 115 }; 116 execCmd = "exec ${gdm}/bin/gdm"; 117 }; 118 119 # Because sd_login_monitor_new requires /run/systemd/machines 120 systemd.services.display-manager.wants = [ "systemd-machined.service" ]; 121 systemd.services.display-manager.after = [ 122 "rc-local.service" 123 "systemd-machined.service" 124 "systemd-user-sessions.service" 125 ]; 126 127 systemd.services.display-manager.serviceConfig = { 128 # Restart = "always"; - already defined in xserver.nix 129 KillMode = "mixed"; 130 IgnoreSIGPIPE = "no"; 131 BusName = "org.gnome.DisplayManager"; 132 StandardOutput = "syslog"; 133 StandardError = "inherit"; 134 }; 135 136 systemd.services.display-manager.path = [ pkgs.gnome3.gnome-session ]; 137 138 # Allow choosing an user account 139 services.accounts-daemon.enable = true; 140 141 services.dbus.packages = [ gdm ]; 142 143 systemd.user.services.dbus.wantedBy = [ "default.target" ]; 144 145 programs.dconf.profiles.gdm = "${gdm}/share/dconf/profile/gdm"; 146 147 # Use AutomaticLogin if delay is zero, because it's immediate. 148 # Otherwise with TimedLogin with zero seconds the prompt is still 149 # presented and there's a little delay. 150 environment.etc."gdm/custom.conf".text = '' 151 [daemon] 152 WaylandEnable=${if cfg.gdm.wayland then "true" else "false"} 153 ${optionalString cfg.gdm.autoLogin.enable ( 154 if cfg.gdm.autoLogin.delay > 0 then '' 155 TimedLoginEnable=true 156 TimedLogin=${cfg.gdm.autoLogin.user} 157 TimedLoginDelay=${toString cfg.gdm.autoLogin.delay} 158 '' else '' 159 AutomaticLoginEnable=true 160 AutomaticLogin=${cfg.gdm.autoLogin.user} 161 '') 162 } 163 164 [security] 165 166 [xdmcp] 167 168 [greeter] 169 170 [chooser] 171 172 [debug] 173 ${optionalString cfg.gdm.debug "Enable=true"} 174 ''; 175 176 environment.etc."gdm/Xsession".source = config.services.xserver.displayManager.session.wrapper; 177 178 # GDM LFS PAM modules, adapted somehow to NixOS 179 security.pam.services = { 180 gdm-launch-environment.text = '' 181 auth required pam_succeed_if.so audit quiet_success user = gdm 182 auth optional pam_permit.so 183 184 account required pam_succeed_if.so audit quiet_success user = gdm 185 account sufficient pam_unix.so 186 187 password required pam_deny.so 188 189 session required pam_succeed_if.so audit quiet_success user = gdm 190 session required pam_env.so envfile=${config.system.build.pamEnvironment} 191 session optional ${pkgs.systemd}/lib/security/pam_systemd.so 192 session optional pam_keyinit.so force revoke 193 session optional pam_permit.so 194 ''; 195 196 gdm.text = '' 197 auth requisite pam_nologin.so 198 auth required pam_env.so envfile=${config.system.build.pamEnvironment} 199 200 auth required pam_succeed_if.so uid >= 1000 quiet 201 auth optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so 202 auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth 203 ${optionalString config.security.pam.enableEcryptfs 204 "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} 205 206 ${optionalString (! config.security.pam.enableEcryptfs) 207 "auth required pam_deny.so"} 208 209 account sufficient pam_unix.so 210 211 password requisite pam_unix.so nullok sha512 212 ${optionalString config.security.pam.enableEcryptfs 213 "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} 214 215 session required pam_env.so envfile=${config.system.build.pamEnvironment} 216 session required pam_unix.so 217 ${optionalString config.security.pam.enableEcryptfs 218 "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} 219 session required pam_loginuid.so 220 session optional ${pkgs.systemd}/lib/security/pam_systemd.so 221 session optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start 222 ''; 223 224 gdm-password.text = '' 225 auth requisite pam_nologin.so 226 auth required pam_env.so envfile=${config.system.build.pamEnvironment} 227 228 auth required pam_succeed_if.so uid >= 1000 quiet 229 auth optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so 230 auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth 231 ${optionalString config.security.pam.enableEcryptfs 232 "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} 233 ${optionalString (! config.security.pam.enableEcryptfs) 234 "auth required pam_deny.so"} 235 236 account sufficient pam_unix.so 237 238 password requisite pam_unix.so nullok sha512 239 ${optionalString config.security.pam.enableEcryptfs 240 "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} 241 242 session required pam_env.so envfile=${config.system.build.pamEnvironment} 243 session required pam_unix.so 244 ${optionalString config.security.pam.enableEcryptfs 245 "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} 246 session required pam_loginuid.so 247 session optional ${pkgs.systemd}/lib/security/pam_systemd.so 248 session optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start 249 ''; 250 251 gdm-autologin.text = '' 252 auth requisite pam_nologin.so 253 254 auth required pam_succeed_if.so uid >= 1000 quiet 255 auth required pam_permit.so 256 257 account sufficient pam_unix.so 258 259 password requisite pam_unix.so nullok sha512 260 261 session optional pam_keyinit.so revoke 262 session required pam_env.so envfile=${config.system.build.pamEnvironment} 263 session required pam_unix.so 264 session required pam_loginuid.so 265 session optional ${pkgs.systemd}/lib/security/pam_systemd.so 266 ''; 267 268 }; 269 270 }; 271 272}