1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 xcfg = config.services.xserver;
8 dmcfg = xcfg.displayManager;
9 cfg = dmcfg.sddm;
10 xEnv = config.systemd.services."display-manager".environment;
11
12 inherit (pkgs) sddm;
13
14 xserverWrapper = pkgs.writeScript "xserver-wrapper" ''
15 #!/bin/sh
16 ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
17 exec systemd-cat ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} "$@"
18 '';
19
20 Xsetup = pkgs.writeScript "Xsetup" ''
21 #!/bin/sh
22 ${cfg.setupScript}
23 '';
24
25 Xstop = pkgs.writeScript "Xstop" ''
26 #!/bin/sh
27 ${cfg.stopScript}
28 '';
29
30 cfgFile = pkgs.writeText "sddm.conf" ''
31 [General]
32 HaltCommand=${pkgs.systemd}/bin/systemctl poweroff
33 RebootCommand=${pkgs.systemd}/bin/systemctl reboot
34 ${optionalString cfg.autoNumlock ''
35 Numlock=on
36 ''}
37
38 [Theme]
39 Current=${cfg.theme}
40 ThemeDir=/run/current-system/sw/share/sddm/themes
41 FacesDir=/run/current-system/sw/share/sddm/faces
42
43 [Users]
44 MaximumUid=${toString config.ids.uids.nixbld}
45 HideUsers=${concatStringsSep "," dmcfg.hiddenUsers}
46 HideShells=/run/current-system/sw/bin/nologin
47
48 [X11]
49 MinimumVT=${toString (if xcfg.tty != null then xcfg.tty else 7)}
50 ServerPath=${xserverWrapper}
51 XephyrPath=${pkgs.xorg.xorgserver.out}/bin/Xephyr
52 SessionCommand=${dmcfg.session.script}
53 SessionDir=${dmcfg.session.desktops}
54 XauthPath=${pkgs.xorg.xauth}/bin/xauth
55 DisplayCommand=${Xsetup}
56 DisplayStopCommand=${Xstop}
57
58 ${optionalString cfg.autoLogin.enable ''
59 [Autologin]
60 User=${cfg.autoLogin.user}
61 Session=${defaultSessionName}.desktop
62 Relogin=${boolToString cfg.autoLogin.relogin}
63 ''}
64
65 ${cfg.extraConfig}
66 '';
67
68 defaultSessionName =
69 let
70 dm = xcfg.desktopManager.default;
71 wm = xcfg.windowManager.default;
72 in dm + optionalString (wm != "none") ("+" + wm);
73
74in
75{
76 options = {
77
78 services.xserver.displayManager.sddm = {
79 enable = mkOption {
80 type = types.bool;
81 default = false;
82 description = ''
83 Whether to enable sddm as the display manager.
84 '';
85 };
86
87 extraConfig = mkOption {
88 type = types.lines;
89 default = "";
90 example = ''
91 [Autologin]
92 User=john
93 Session=plasma.desktop
94 '';
95 description = ''
96 Extra lines appended to the configuration of SDDM.
97 '';
98 };
99
100 theme = mkOption {
101 type = types.str;
102 default = "";
103 description = ''
104 Greeter theme to use.
105 '';
106 };
107
108 autoNumlock = mkOption {
109 type = types.bool;
110 default = false;
111 description = ''
112 Enable numlock at login.
113 '';
114 };
115
116 setupScript = mkOption {
117 type = types.str;
118 default = "";
119 example = ''
120 # workaround for using NVIDIA Optimus without Bumblebee
121 xrandr --setprovideroutputsource modesetting NVIDIA-0
122 xrandr --auto
123 '';
124 description = ''
125 A script to execute when starting the display server.
126 '';
127 };
128
129 stopScript = mkOption {
130 type = types.str;
131 default = "";
132 description = ''
133 A script to execute when stopping the display server.
134 '';
135 };
136
137 autoLogin = mkOption {
138 default = {};
139 description = ''
140 Configuration for automatic login.
141 '';
142
143 type = types.submodule {
144 options = {
145 enable = mkOption {
146 type = types.bool;
147 default = false;
148 description = ''
149 Automatically log in as <option>autoLogin.user</option>.
150 '';
151 };
152
153 user = mkOption {
154 type = types.nullOr types.str;
155 default = null;
156 description = ''
157 User to be used for the automatic login.
158 '';
159 };
160
161 relogin = mkOption {
162 type = types.bool;
163 default = false;
164 description = ''
165 If true automatic login will kick in again on session exit (logout), otherwise it
166 will only log in automatically when the display-manager is started.
167 '';
168 };
169 };
170 };
171 };
172
173 };
174
175 };
176
177 config = mkIf cfg.enable {
178
179 assertions = [
180 { assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null;
181 message = ''
182 SDDM auto-login requires services.xserver.displayManager.sddm.autoLogin.user to be set
183 '';
184 }
185 { assertion = cfg.autoLogin.enable -> elem defaultSessionName dmcfg.session.names;
186 message = ''
187 SDDM auto-login requires that services.xserver.desktopManager.default and
188 services.xserver.windowMananger.default are set to valid values. The current
189 default session: ${defaultSessionName} is not valid.
190 '';
191 }
192 ];
193
194 services.xserver.displayManager.slim.enable = false;
195
196 services.xserver.displayManager.job = {
197 logsXsession = true;
198
199 environment = {
200 # Load themes from system environment
201 QT_PLUGIN_PATH = "/run/current-system/sw/" + pkgs.qt5.qtbase.qtPluginPrefix;
202 QML2_IMPORT_PATH = "/run/current-system/sw/" + pkgs.qt5.qtbase.qtQmlPrefix;
203
204 XDG_DATA_DIRS = "/run/current-system/sw/share";
205 };
206
207 execCmd = "exec /run/current-system/sw/bin/sddm";
208 };
209
210 security.pam.services = {
211 sddm = {
212 allowNullPassword = true;
213 startSession = true;
214 };
215
216 sddm-greeter.text = ''
217 auth required pam_succeed_if.so audit quiet_success user = sddm
218 auth optional pam_permit.so
219
220 account required pam_succeed_if.so audit quiet_success user = sddm
221 account sufficient pam_unix.so
222
223 password required pam_deny.so
224
225 session required pam_succeed_if.so audit quiet_success user = sddm
226 session required pam_env.so envfile=${config.system.build.pamEnvironment}
227 session optional ${pkgs.systemd}/lib/security/pam_systemd.so
228 session optional pam_keyinit.so force revoke
229 session optional pam_permit.so
230 '';
231
232 sddm-autologin.text = ''
233 auth requisite pam_nologin.so
234 auth required pam_succeed_if.so uid >= 1000 quiet
235 auth required pam_permit.so
236
237 account include sddm
238
239 password include sddm
240
241 session include sddm
242 '';
243 };
244
245 users.extraUsers.sddm = {
246 createHome = true;
247 home = "/var/lib/sddm";
248 group = "sddm";
249 uid = config.ids.uids.sddm;
250 };
251
252 environment.etc."sddm.conf".source = cfgFile;
253
254 users.extraGroups.sddm.gid = config.ids.gids.sddm;
255
256 environment.systemPackages = [ sddm ];
257 services.dbus.packages = [ sddm ];
258
259 # To enable user switching, allow sddm to allocate TTYs/displays dynamically.
260 services.xserver.tty = null;
261 services.xserver.display = null;
262 };
263}