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