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