1# This module provides configuration for the PAM (Pluggable
2# Authentication Modules) system.
3
4{ config, lib, pkgs, ... }:
5
6with lib;
7
8let
9 parentConfig = config;
10
11 pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in {
12
13 options = {
14
15 name = mkOption {
16 example = "sshd";
17 type = types.str;
18 description = lib.mdDoc "Name of the PAM service.";
19 };
20
21 unixAuth = mkOption {
22 default = true;
23 type = types.bool;
24 description = lib.mdDoc ''
25 Whether users can log in with passwords defined in
26 {file}`/etc/shadow`.
27 '';
28 };
29
30 rootOK = mkOption {
31 default = false;
32 type = types.bool;
33 description = lib.mdDoc ''
34 If set, root doesn't need to authenticate (e.g. for the
35 {command}`useradd` service).
36 '';
37 };
38
39 p11Auth = mkOption {
40 default = config.security.pam.p11.enable;
41 defaultText = literalExpression "config.security.pam.p11.enable";
42 type = types.bool;
43 description = lib.mdDoc ''
44 If set, keys listed in
45 {file}`~/.ssh/authorized_keys` and
46 {file}`~/.eid/authorized_certificates`
47 can be used to log in with the associated PKCS#11 tokens.
48 '';
49 };
50
51 u2fAuth = mkOption {
52 default = config.security.pam.u2f.enable;
53 defaultText = literalExpression "config.security.pam.u2f.enable";
54 type = types.bool;
55 description = lib.mdDoc ''
56 If set, users listed in
57 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
58 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
59 not set) are able to log in with the associated U2F key. Path can be
60 changed using {option}`security.pam.u2f.authFile` option.
61 '';
62 };
63
64 usshAuth = mkOption {
65 default = false;
66 type = types.bool;
67 description = lib.mdDoc ''
68 If set, users with an SSH certificate containing an authorized principal
69 in their SSH agent are able to log in. Specific options are controlled
70 using the {option}`security.pam.ussh` options.
71
72 Note that the {option}`security.pam.ussh.enable` must also be
73 set for this option to take effect.
74 '';
75 };
76
77 yubicoAuth = mkOption {
78 default = config.security.pam.yubico.enable;
79 defaultText = literalExpression "config.security.pam.yubico.enable";
80 type = types.bool;
81 description = lib.mdDoc ''
82 If set, users listed in
83 {file}`~/.yubico/authorized_yubikeys`
84 are able to log in with the associated Yubikey tokens.
85 '';
86 };
87
88 googleAuthenticator = {
89 enable = mkOption {
90 default = false;
91 type = types.bool;
92 description = lib.mdDoc ''
93 If set, users with enabled Google Authenticator (created
94 {file}`~/.google_authenticator`) will be required
95 to provide Google Authenticator token to log in.
96 '';
97 };
98 };
99
100 usbAuth = mkOption {
101 default = config.security.pam.usb.enable;
102 defaultText = literalExpression "config.security.pam.usb.enable";
103 type = types.bool;
104 description = lib.mdDoc ''
105 If set, users listed in
106 {file}`/etc/pamusb.conf` are able to log in
107 with the associated USB key.
108 '';
109 };
110
111 otpwAuth = mkOption {
112 default = config.security.pam.enableOTPW;
113 defaultText = literalExpression "config.security.pam.enableOTPW";
114 type = types.bool;
115 description = lib.mdDoc ''
116 If set, the OTPW system will be used (if
117 {file}`~/.otpw` exists).
118 '';
119 };
120
121 googleOsLoginAccountVerification = mkOption {
122 default = false;
123 type = types.bool;
124 description = lib.mdDoc ''
125 If set, will use the Google OS Login PAM modules
126 (`pam_oslogin_login`,
127 `pam_oslogin_admin`) to verify possible OS Login
128 users and set sudoers configuration accordingly.
129 This only makes sense to enable for the `sshd` PAM
130 service.
131 '';
132 };
133
134 googleOsLoginAuthentication = mkOption {
135 default = false;
136 type = types.bool;
137 description = lib.mdDoc ''
138 If set, will use the `pam_oslogin_login`'s user
139 authentication methods to authenticate users using 2FA.
140 This only makes sense to enable for the `sshd` PAM
141 service.
142 '';
143 };
144
145 mysqlAuth = mkOption {
146 default = config.users.mysql.enable;
147 defaultText = literalExpression "config.users.mysql.enable";
148 type = types.bool;
149 description = lib.mdDoc ''
150 If set, the `pam_mysql` module will be used to
151 authenticate users against a MySQL/MariaDB database.
152 '';
153 };
154
155 fprintAuth = mkOption {
156 default = config.services.fprintd.enable;
157 defaultText = literalExpression "config.services.fprintd.enable";
158 type = types.bool;
159 description = lib.mdDoc ''
160 If set, fingerprint reader will be used (if exists and
161 your fingerprints are enrolled).
162 '';
163 };
164
165 oathAuth = mkOption {
166 default = config.security.pam.oath.enable;
167 defaultText = literalExpression "config.security.pam.oath.enable";
168 type = types.bool;
169 description = lib.mdDoc ''
170 If set, the OATH Toolkit will be used.
171 '';
172 };
173
174 sshAgentAuth = mkOption {
175 default = false;
176 type = types.bool;
177 description = lib.mdDoc ''
178 If set, the calling user's SSH agent is used to authenticate
179 against the keys in the calling user's
180 {file}`~/.ssh/authorized_keys`. This is useful
181 for {command}`sudo` on password-less remote systems.
182 '';
183 };
184
185 duoSecurity = {
186 enable = mkOption {
187 default = false;
188 type = types.bool;
189 description = lib.mdDoc ''
190 If set, use the Duo Security pam module
191 `pam_duo` for authentication. Requires
192 configuration of {option}`security.duosec` options.
193 '';
194 };
195 };
196
197 startSession = mkOption {
198 default = false;
199 type = types.bool;
200 description = lib.mdDoc ''
201 If set, the service will register a new session with
202 systemd's login manager. For local sessions, this will give
203 the user access to audio devices, CD-ROM drives. In the
204 default PolicyKit configuration, it also allows the user to
205 reboot the system.
206 '';
207 };
208
209 setEnvironment = mkOption {
210 type = types.bool;
211 default = true;
212 description = lib.mdDoc ''
213 Whether the service should set the environment variables
214 listed in {option}`environment.sessionVariables`
215 using `pam_env.so`.
216 '';
217 };
218
219 setLoginUid = mkOption {
220 type = types.bool;
221 description = lib.mdDoc ''
222 Set the login uid of the process
223 ({file}`/proc/self/loginuid`) for auditing
224 purposes. The login uid is only set by ‘entry points’ like
225 {command}`login` and {command}`sshd`, not by
226 commands like {command}`sudo`.
227 '';
228 };
229
230 ttyAudit = {
231 enable = mkOption {
232 type = types.bool;
233 default = false;
234 description = lib.mdDoc ''
235 Enable or disable TTY auditing for specified users
236 '';
237 };
238
239 enablePattern = mkOption {
240 type = types.nullOr types.str;
241 default = null;
242 description = lib.mdDoc ''
243 For each user matching one of comma-separated
244 glob patterns, enable TTY auditing
245 '';
246 };
247
248 disablePattern = mkOption {
249 type = types.nullOr types.str;
250 default = null;
251 description = lib.mdDoc ''
252 For each user matching one of comma-separated
253 glob patterns, disable TTY auditing
254 '';
255 };
256
257 openOnly = mkOption {
258 type = types.bool;
259 default = false;
260 description = lib.mdDoc ''
261 Set the TTY audit flag when opening the session,
262 but do not restore it when closing the session.
263 Using this option is necessary for some services
264 that don't fork() to run the authenticated session,
265 such as sudo.
266 '';
267 };
268 };
269
270 forwardXAuth = mkOption {
271 default = false;
272 type = types.bool;
273 description = lib.mdDoc ''
274 Whether X authentication keys should be passed from the
275 calling user to the target user (e.g. for
276 {command}`su`)
277 '';
278 };
279
280 pamMount = mkOption {
281 default = config.security.pam.mount.enable;
282 defaultText = literalExpression "config.security.pam.mount.enable";
283 type = types.bool;
284 description = lib.mdDoc ''
285 Enable PAM mount (pam_mount) system to mount fileystems on user login.
286 '';
287 };
288
289 allowNullPassword = mkOption {
290 default = false;
291 type = types.bool;
292 description = lib.mdDoc ''
293 Whether to allow logging into accounts that have no password
294 set (i.e., have an empty password field in
295 {file}`/etc/passwd` or
296 {file}`/etc/group`). This does not enable
297 logging into disabled accounts (i.e., that have the password
298 field set to `!`). Note that regardless of
299 what the pam_unix documentation says, accounts with hashed
300 empty passwords are always allowed to log in.
301 '';
302 };
303
304 nodelay = mkOption {
305 default = false;
306 type = types.bool;
307 description = lib.mdDoc ''
308 Wheather the delay after typing a wrong password should be disabled.
309 '';
310 };
311
312 requireWheel = mkOption {
313 default = false;
314 type = types.bool;
315 description = lib.mdDoc ''
316 Whether to permit root access only to members of group wheel.
317 '';
318 };
319
320 limits = mkOption {
321 default = [];
322 type = limitsType;
323 description = lib.mdDoc ''
324 Attribute set describing resource limits. Defaults to the
325 value of {option}`security.pam.loginLimits`.
326 The meaning of the values is explained in {manpage}`limits.conf(5)`.
327 '';
328 };
329
330 showMotd = mkOption {
331 default = false;
332 type = types.bool;
333 description = lib.mdDoc "Whether to show the message of the day.";
334 };
335
336 makeHomeDir = mkOption {
337 default = false;
338 type = types.bool;
339 description = lib.mdDoc ''
340 Whether to try to create home directories for users
341 with `$HOME`s pointing to nonexistent
342 locations on session login.
343 '';
344 };
345
346 updateWtmp = mkOption {
347 default = false;
348 type = types.bool;
349 description = lib.mdDoc "Whether to update {file}`/var/log/wtmp`.";
350 };
351
352 logFailures = mkOption {
353 default = false;
354 type = types.bool;
355 description = lib.mdDoc "Whether to log authentication failures in {file}`/var/log/faillog`.";
356 };
357
358 enableAppArmor = mkOption {
359 default = false;
360 type = types.bool;
361 description = lib.mdDoc ''
362 Enable support for attaching AppArmor profiles at the
363 user/group level, e.g., as part of a role based access
364 control scheme.
365 '';
366 };
367
368 enableKwallet = mkOption {
369 default = false;
370 type = types.bool;
371 description = lib.mdDoc ''
372 If enabled, pam_wallet will attempt to automatically unlock the
373 user's default KDE wallet upon login. If the user has no wallet named
374 "kdewallet", or the login password does not match their wallet
375 password, KDE will prompt separately after login.
376 '';
377 };
378 sssdStrictAccess = mkOption {
379 default = false;
380 type = types.bool;
381 description = lib.mdDoc "enforce sssd access control";
382 };
383
384 enableGnomeKeyring = mkOption {
385 default = false;
386 type = types.bool;
387 description = lib.mdDoc ''
388 If enabled, pam_gnome_keyring will attempt to automatically unlock the
389 user's default Gnome keyring upon login. If the user login password does
390 not match their keyring password, Gnome Keyring will prompt separately
391 after login.
392 '';
393 };
394
395 failDelay = {
396 enable = mkOption {
397 type = types.bool;
398 default = false;
399 description = lib.mdDoc ''
400 If enabled, this will replace the `FAIL_DELAY` setting from `login.defs`.
401 Change the delay on failure per-application.
402 '';
403 };
404
405 delay = mkOption {
406 default = 3000000;
407 type = types.int;
408 example = 1000000;
409 description = lib.mdDoc "The delay time (in microseconds) on failure.";
410 };
411 };
412
413 gnupg = {
414 enable = mkOption {
415 type = types.bool;
416 default = false;
417 description = lib.mdDoc ''
418 If enabled, pam_gnupg will attempt to automatically unlock the
419 user's GPG keys with the login password via
420 {command}`gpg-agent`. The keygrips of all keys to be
421 unlocked should be written to {file}`~/.pam-gnupg`,
422 and can be queried with {command}`gpg -K --with-keygrip`.
423 Presetting passphrases must be enabled by adding
424 `allow-preset-passphrase` in
425 {file}`~/.gnupg/gpg-agent.conf`.
426 '';
427 };
428
429 noAutostart = mkOption {
430 type = types.bool;
431 default = false;
432 description = lib.mdDoc ''
433 Don't start {command}`gpg-agent` if it is not running.
434 Useful in conjunction with starting {command}`gpg-agent` as
435 a systemd user service.
436 '';
437 };
438
439 storeOnly = mkOption {
440 type = types.bool;
441 default = false;
442 description = lib.mdDoc ''
443 Don't send the password immediately after login, but store for PAM
444 `session`.
445 '';
446 };
447 };
448
449 text = mkOption {
450 type = types.nullOr types.lines;
451 description = lib.mdDoc "Contents of the PAM service file.";
452 };
453
454 };
455
456 # The resulting /etc/pam.d/* file contents are verified in
457 # nixos/tests/pam/pam-file-contents.nix. Please update tests there when
458 # changing the derivation.
459 config = {
460 name = mkDefault name;
461 setLoginUid = mkDefault cfg.startSession;
462 limits = mkDefault config.security.pam.loginLimits;
463
464 # !!! TODO: move the LDAP stuff to the LDAP module, and the
465 # Samba stuff to the Samba module. This requires that the PAM
466 # module provides the right hooks.
467 text = mkDefault
468 (
469 ''
470 # Account management.
471 '' +
472 optionalString use_ldap ''
473 account sufficient ${pam_ldap}/lib/security/pam_ldap.so
474 '' +
475 optionalString cfg.mysqlAuth ''
476 account sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
477 '' +
478 optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false) ''
479 account sufficient ${pkgs.sssd}/lib/security/pam_sss.so
480 '' +
481 optionalString (config.services.sssd.enable && cfg.sssdStrictAccess) ''
482 account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so
483 '' +
484 optionalString config.security.pam.krb5.enable ''
485 account sufficient ${pam_krb5}/lib/security/pam_krb5.so
486 '' +
487 optionalString cfg.googleOsLoginAccountVerification ''
488 account [success=ok ignore=ignore default=die] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
489 account [success=ok default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so
490 '' +
491 # The required pam_unix.so module has to come after all the sufficient modules
492 # because otherwise, the account lookup will fail if the user does not exist
493 # locally, for example with MySQL- or LDAP-auth.
494 ''
495 account required pam_unix.so
496
497 # Authentication management.
498 '' +
499 optionalString cfg.googleOsLoginAuthentication ''
500 auth [success=done perm_denied=die default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
501 '' +
502 optionalString cfg.rootOK ''
503 auth sufficient pam_rootok.so
504 '' +
505 optionalString cfg.requireWheel ''
506 auth required pam_wheel.so use_uid
507 '' +
508 optionalString cfg.logFailures ''
509 auth required pam_faillock.so
510 '' +
511 optionalString cfg.mysqlAuth ''
512 auth sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
513 '' +
514 optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) ''
515 auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}
516 '' +
517 (let p11 = config.security.pam.p11; in optionalString cfg.p11Auth ''
518 auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so
519 '') +
520 (let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth (''
521 auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ''
522 + ''${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"} ${optionalString (u2f.origin != null) "origin=${u2f.origin}"}
523 '')) +
524 optionalString cfg.usbAuth ''
525 auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so
526 '' +
527 (let ussh = config.security.pam.ussh; in optionalString (config.security.pam.ussh.enable && cfg.usshAuth) ''
528 auth ${ussh.control} ${pkgs.pam_ussh}/lib/security/pam_ussh.so ${optionalString (ussh.caFile != null) "ca_file=${ussh.caFile}"} ${optionalString (ussh.authorizedPrincipals != null) "authorized_principals=${ussh.authorizedPrincipals}"} ${optionalString (ussh.authorizedPrincipalsFile != null) "authorized_principals_file=${ussh.authorizedPrincipalsFile}"} ${optionalString (ussh.group != null) "group=${ussh.group}"}
529 '') +
530 (let oath = config.security.pam.oath; in optionalString cfg.oathAuth ''
531 auth requisite ${pkgs.oath-toolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}
532 '') +
533 (let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth ''
534 auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.challengeResponsePath != null) "chalresp_path=${yubi.challengeResponsePath}"} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"}
535 '') +
536 optionalString cfg.fprintAuth ''
537 auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so
538 '' +
539 # Modules in this block require having the password set in PAM_AUTHTOK.
540 # pam_unix is marked as 'sufficient' on NixOS which means nothing will run
541 # after it succeeds. Certain modules need to run after pam_unix
542 # prompts the user for password so we run it once with 'optional' at an
543 # earlier point and it will run again with 'sufficient' further down.
544 # We use try_first_pass the second time to avoid prompting password twice
545 (optionalString (cfg.unixAuth &&
546 (config.security.pam.enableEcryptfs
547 || config.security.pam.enableFscrypt
548 || cfg.pamMount
549 || cfg.enableKwallet
550 || cfg.enableGnomeKeyring
551 || cfg.googleAuthenticator.enable
552 || cfg.gnupg.enable
553 || cfg.failDelay.enable
554 || cfg.duoSecurity.enable))
555 (
556 ''
557 auth optional pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
558 '' +
559 optionalString config.security.pam.enableEcryptfs ''
560 auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap
561 '' +
562 optionalString config.security.pam.enableFscrypt ''
563 auth optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
564 '' +
565 optionalString cfg.pamMount ''
566 auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
567 '' +
568 optionalString cfg.enableKwallet ''
569 auth optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
570 '' +
571 optionalString cfg.enableGnomeKeyring ''
572 auth optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so
573 '' +
574 optionalString cfg.gnupg.enable ''
575 auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"}
576 '' +
577 optionalString cfg.failDelay.enable ''
578 auth optional ${pkgs.pam}/lib/security/pam_faildelay.so delay=${toString cfg.failDelay.delay}
579 '' +
580 optionalString cfg.googleAuthenticator.enable ''
581 auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
582 '' +
583 optionalString cfg.duoSecurity.enable ''
584 auth required ${pkgs.duo-unix}/lib/security/pam_duo.so
585 ''
586 )) +
587 optionalString cfg.unixAuth ''
588 auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass
589 '' +
590 optionalString cfg.otpwAuth ''
591 auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so
592 '' +
593 optionalString use_ldap ''
594 auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass
595 '' +
596 optionalString config.services.sssd.enable ''
597 auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass
598 '' +
599 optionalString config.security.pam.krb5.enable ''
600 auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
601 auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
602 auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
603 '' +
604 ''
605 auth required pam_deny.so
606
607 # Password management.
608 password sufficient pam_unix.so nullok sha512
609 '' +
610 optionalString config.security.pam.enableEcryptfs ''
611 password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
612 '' +
613 optionalString config.security.pam.enableFscrypt ''
614 password optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
615 '' +
616 optionalString cfg.pamMount ''
617 password optional ${pkgs.pam_mount}/lib/security/pam_mount.so
618 '' +
619 optionalString use_ldap ''
620 password sufficient ${pam_ldap}/lib/security/pam_ldap.so
621 '' +
622 optionalString cfg.mysqlAuth ''
623 password sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
624 '' +
625 optionalString config.services.sssd.enable ''
626 password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok
627 '' +
628 optionalString config.security.pam.krb5.enable ''
629 password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
630 '' +
631 optionalString cfg.enableGnomeKeyring ''
632 password optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok
633 '' +
634 ''
635
636 # Session management.
637 '' +
638 optionalString cfg.setEnvironment ''
639 session required pam_env.so conffile=/etc/pam/environment readenv=0
640 '' +
641 ''
642 session required pam_unix.so
643 '' +
644 optionalString cfg.setLoginUid ''
645 session ${if config.boot.isContainer then "optional" else "required"} pam_loginuid.so
646 '' +
647 optionalString cfg.ttyAudit.enable (concatStringsSep " \\\n " ([
648 "session required ${pkgs.pam}/lib/security/pam_tty_audit.so"
649 ] ++ optional cfg.ttyAudit.openOnly "open_only"
650 ++ optional (cfg.ttyAudit.enablePattern != null) "enable=${cfg.ttyAudit.enablePattern}"
651 ++ optional (cfg.ttyAudit.disablePattern != null) "disable=${cfg.ttyAudit.disablePattern}"
652 )) +
653 optionalString cfg.makeHomeDir ''
654 session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=0077
655 '' +
656 optionalString cfg.updateWtmp ''
657 session required ${pkgs.pam}/lib/security/pam_lastlog.so silent
658 '' +
659 optionalString config.security.pam.enableEcryptfs ''
660 session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
661 '' +
662 optionalString config.security.pam.enableFscrypt ''
663 # Work around https://github.com/systemd/systemd/issues/8598
664 # Skips the pam_fscrypt module for systemd-user sessions which do not have a password
665 # anyways.
666 # See also https://github.com/google/fscrypt/issues/95
667 session [success=1 default=ignore] pam_succeed_if.so service = systemd-user
668 session optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
669 '' +
670 optionalString cfg.pamMount ''
671 session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
672 '' +
673 optionalString use_ldap ''
674 session optional ${pam_ldap}/lib/security/pam_ldap.so
675 '' +
676 optionalString cfg.mysqlAuth ''
677 session optional ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
678 '' +
679 optionalString config.services.sssd.enable ''
680 session optional ${pkgs.sssd}/lib/security/pam_sss.so
681 '' +
682 optionalString config.security.pam.krb5.enable ''
683 session optional ${pam_krb5}/lib/security/pam_krb5.so
684 '' +
685 optionalString cfg.otpwAuth ''
686 session optional ${pkgs.otpw}/lib/security/pam_otpw.so
687 '' +
688 optionalString cfg.startSession ''
689 session optional ${config.systemd.package}/lib/security/pam_systemd.so
690 '' +
691 optionalString cfg.forwardXAuth ''
692 session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99
693 '' +
694 optionalString (cfg.limits != []) ''
695 session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}
696 '' +
697 optionalString (cfg.showMotd && config.users.motd != null) ''
698 session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}
699 '' +
700 optionalString (cfg.enableAppArmor && config.security.apparmor.enable) ''
701 session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug
702 '' +
703 optionalString (cfg.enableKwallet) ''
704 session optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
705 '' +
706 optionalString (cfg.enableGnomeKeyring) ''
707 session optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start
708 '' +
709 optionalString cfg.gnupg.enable ''
710 session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.noAutostart " no-autostart"}
711 '' +
712 optionalString (config.virtualisation.lxc.lxcfs.enable) ''
713 session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all
714 ''
715 );
716 };
717
718 };
719
720
721 inherit (pkgs) pam_krb5 pam_ccreds;
722
723 use_ldap = (config.users.ldap.enable && config.users.ldap.loginPam);
724 pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap;
725
726 # Create a limits.conf(5) file.
727 makeLimitsConf = limits:
728 pkgs.writeText "limits.conf"
729 (concatMapStrings ({ domain, type, item, value }:
730 "${domain} ${type} ${item} ${toString value}\n")
731 limits);
732
733 limitsType = with lib.types; listOf (submodule ({ ... }: {
734 options = {
735 domain = mkOption {
736 description = lib.mdDoc "Username, groupname, or wildcard this limit applies to";
737 example = "@wheel";
738 type = str;
739 };
740
741 type = mkOption {
742 description = lib.mdDoc "Type of this limit";
743 type = enum [ "-" "hard" "soft" ];
744 default = "-";
745 };
746
747 item = mkOption {
748 description = lib.mdDoc "Item this limit applies to";
749 type = enum [
750 "core"
751 "data"
752 "fsize"
753 "memlock"
754 "nofile"
755 "rss"
756 "stack"
757 "cpu"
758 "nproc"
759 "as"
760 "maxlogins"
761 "maxsyslogins"
762 "priority"
763 "locks"
764 "sigpending"
765 "msgqueue"
766 "nice"
767 "rtprio"
768 ];
769 };
770
771 value = mkOption {
772 description = lib.mdDoc "Value of this limit";
773 type = oneOf [ str int ];
774 };
775 };
776 }));
777
778 motd = pkgs.writeText "motd" config.users.motd;
779
780 makePAMService = name: service:
781 { name = "pam.d/${name}";
782 value.source = pkgs.writeText "${name}.pam" service.text;
783 };
784
785in
786
787{
788
789 imports = [
790 (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ])
791 ];
792
793 ###### interface
794
795 options = {
796
797 security.pam.loginLimits = mkOption {
798 default = [];
799 type = limitsType;
800 example =
801 [ { domain = "ftp";
802 type = "hard";
803 item = "nproc";
804 value = "0";
805 }
806 { domain = "@student";
807 type = "-";
808 item = "maxlogins";
809 value = "4";
810 }
811 ];
812
813 description = lib.mdDoc ''
814 Define resource limits that should apply to users or groups.
815 Each item in the list should be an attribute set with a
816 {var}`domain`, {var}`type`,
817 {var}`item`, and {var}`value`
818 attribute. The syntax and semantics of these attributes
819 must be that described in {manpage}`limits.conf(5)`.
820
821 Note that these limits do not apply to systemd services,
822 whose limits can be changed via {option}`systemd.extraConfig`
823 instead.
824 '';
825 };
826
827 security.pam.services = mkOption {
828 default = {};
829 type = with types; attrsOf (submodule pamOpts);
830 description =
831 lib.mdDoc ''
832 This option defines the PAM services. A service typically
833 corresponds to a program that uses PAM,
834 e.g. {command}`login` or {command}`passwd`.
835 Each attribute of this set defines a PAM service, with the attribute name
836 defining the name of the service.
837 '';
838 };
839
840 security.pam.makeHomeDir.skelDirectory = mkOption {
841 type = types.str;
842 default = "/var/empty";
843 example = "/etc/skel";
844 description = lib.mdDoc ''
845 Path to skeleton directory whose contents are copied to home
846 directories newly created by `pam_mkhomedir`.
847 '';
848 };
849
850 security.pam.enableSSHAgentAuth = mkOption {
851 type = types.bool;
852 default = false;
853 description =
854 lib.mdDoc ''
855 Enable sudo logins if the user's SSH agent provides a key
856 present in {file}`~/.ssh/authorized_keys`.
857 This allows machines to exclusively use SSH keys instead of
858 passwords.
859 '';
860 };
861
862 security.pam.enableOTPW = mkEnableOption (lib.mdDoc "the OTPW (one-time password) PAM module");
863
864 security.pam.krb5 = {
865 enable = mkOption {
866 default = config.krb5.enable;
867 defaultText = literalExpression "config.krb5.enable";
868 type = types.bool;
869 description = lib.mdDoc ''
870 Enables Kerberos PAM modules (`pam-krb5`,
871 `pam-ccreds`).
872
873 If set, users can authenticate with their Kerberos password.
874 This requires a valid Kerberos configuration
875 (`config.krb5.enable` should be set to
876 `true`).
877
878 Note that the Kerberos PAM modules are not necessary when using SSS
879 to handle Kerberos authentication.
880 '';
881 };
882 };
883
884 security.pam.p11 = {
885 enable = mkOption {
886 default = false;
887 type = types.bool;
888 description = lib.mdDoc ''
889 Enables P11 PAM (`pam_p11`) module.
890
891 If set, users can log in with SSH keys and PKCS#11 tokens.
892
893 More information can be found [here](https://github.com/OpenSC/pam_p11).
894 '';
895 };
896
897 control = mkOption {
898 default = "sufficient";
899 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
900 description = lib.mdDoc ''
901 This option sets pam "control".
902 If you want to have multi factor authentication, use "required".
903 If you want to use the PKCS#11 device instead of the regular password,
904 use "sufficient".
905
906 Read
907 {manpage}`pam.conf(5)`
908 for better understanding of this option.
909 '';
910 };
911 };
912
913 security.pam.u2f = {
914 enable = mkOption {
915 default = false;
916 type = types.bool;
917 description = lib.mdDoc ''
918 Enables U2F PAM (`pam-u2f`) module.
919
920 If set, users listed in
921 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
922 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
923 not set) are able to log in with the associated U2F key. The path can
924 be changed using {option}`security.pam.u2f.authFile` option.
925
926 File format is:
927 `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
928 This file can be generated using {command}`pamu2fcfg` command.
929
930 More information can be found [here](https://developers.yubico.com/pam-u2f/).
931 '';
932 };
933
934 authFile = mkOption {
935 default = null;
936 type = with types; nullOr path;
937 description = lib.mdDoc ''
938 By default `pam-u2f` module reads the keys from
939 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
940 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
941 not set).
942
943 If you want to change auth file locations or centralize database (for
944 example use {file}`/etc/u2f-mappings`) you can set this
945 option.
946
947 File format is:
948 `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
949 This file can be generated using {command}`pamu2fcfg` command.
950
951 More information can be found [here](https://developers.yubico.com/pam-u2f/).
952 '';
953 };
954
955 appId = mkOption {
956 default = null;
957 type = with types; nullOr str;
958 description = lib.mdDoc ''
959 By default `pam-u2f` module sets the application
960 ID to `pam://$HOSTNAME`.
961
962 When using {command}`pamu2fcfg`, you can specify your
963 application ID with the `-i` flag.
964
965 More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
966 '';
967 };
968
969 origin = mkOption {
970 default = null;
971 type = with types; nullOr str;
972 description = lib.mdDoc ''
973 By default `pam-u2f` module sets the origin
974 to `pam://$HOSTNAME`.
975 Setting origin to an host independent value will allow you to
976 reuse credentials across machines
977
978 When using {command}`pamu2fcfg`, you can specify your
979 application ID with the `-o` flag.
980
981 More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
982 '';
983 };
984
985 control = mkOption {
986 default = "sufficient";
987 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
988 description = lib.mdDoc ''
989 This option sets pam "control".
990 If you want to have multi factor authentication, use "required".
991 If you want to use U2F device instead of regular password, use "sufficient".
992
993 Read
994 {manpage}`pam.conf(5)`
995 for better understanding of this option.
996 '';
997 };
998
999 debug = mkOption {
1000 default = false;
1001 type = types.bool;
1002 description = lib.mdDoc ''
1003 Debug output to stderr.
1004 '';
1005 };
1006
1007 interactive = mkOption {
1008 default = false;
1009 type = types.bool;
1010 description = lib.mdDoc ''
1011 Set to prompt a message and wait before testing the presence of a U2F device.
1012 Recommended if your device doesn’t have a tactile trigger.
1013 '';
1014 };
1015
1016 cue = mkOption {
1017 default = false;
1018 type = types.bool;
1019 description = lib.mdDoc ''
1020 By default `pam-u2f` module does not inform user
1021 that he needs to use the u2f device, it just waits without a prompt.
1022
1023 If you set this option to `true`,
1024 `cue` option is added to `pam-u2f`
1025 module and reminder message will be displayed.
1026 '';
1027 };
1028 };
1029
1030 security.pam.ussh = {
1031 enable = mkOption {
1032 default = false;
1033 type = types.bool;
1034 description = lib.mdDoc ''
1035 Enables Uber's USSH PAM (`pam-ussh`) module.
1036
1037 This is similar to `pam-ssh-agent`, except that
1038 the presence of a CA-signed SSH key with a valid principal is checked
1039 instead.
1040
1041 Note that this module must both be enabled using this option and on a
1042 per-PAM-service level as well (using `usshAuth`).
1043
1044 More information can be found [here](https://github.com/uber/pam-ussh).
1045 '';
1046 };
1047
1048 caFile = mkOption {
1049 default = null;
1050 type = with types; nullOr path;
1051 description = lib.mdDoc ''
1052 By default `pam-ussh` reads the trusted user CA keys
1053 from {file}`/etc/ssh/trusted_user_ca`.
1054
1055 This should be set the same as your `TrustedUserCAKeys`
1056 option for sshd.
1057 '';
1058 };
1059
1060 authorizedPrincipals = mkOption {
1061 default = null;
1062 type = with types; nullOr commas;
1063 description = lib.mdDoc ''
1064 Comma-separated list of authorized principals to permit; if the user
1065 presents a certificate with one of these principals, then they will be
1066 authorized.
1067
1068 Note that `pam-ussh` also requires that the certificate
1069 contain a principal matching the user's username. The principals from
1070 this list are in addition to those principals.
1071
1072 Mutually exclusive with `authorizedPrincipalsFile`.
1073 '';
1074 };
1075
1076 authorizedPrincipalsFile = mkOption {
1077 default = null;
1078 type = with types; nullOr path;
1079 description = lib.mdDoc ''
1080 Path to a list of principals; if the user presents a certificate with
1081 one of these principals, then they will be authorized.
1082
1083 Note that `pam-ussh` also requires that the certificate
1084 contain a principal matching the user's username. The principals from
1085 this file are in addition to those principals.
1086
1087 Mutually exclusive with `authorizedPrincipals`.
1088 '';
1089 };
1090
1091 group = mkOption {
1092 default = null;
1093 type = with types; nullOr str;
1094 description = lib.mdDoc ''
1095 If set, then the authenticating user must be a member of this group
1096 to use this module.
1097 '';
1098 };
1099
1100 control = mkOption {
1101 default = "sufficient";
1102 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1103 description = lib.mdDoc ''
1104 This option sets pam "control".
1105 If you want to have multi factor authentication, use "required".
1106 If you want to use the SSH certificate instead of the regular password,
1107 use "sufficient".
1108
1109 Read
1110 {manpage}`pam.conf(5)`
1111 for better understanding of this option.
1112 '';
1113 };
1114 };
1115
1116 security.pam.yubico = {
1117 enable = mkOption {
1118 default = false;
1119 type = types.bool;
1120 description = lib.mdDoc ''
1121 Enables Yubico PAM (`yubico-pam`) module.
1122
1123 If set, users listed in
1124 {file}`~/.yubico/authorized_yubikeys`
1125 are able to log in with the associated Yubikey tokens.
1126
1127 The file must have only one line:
1128 `username:yubikey_token_id1:yubikey_token_id2`
1129 More information can be found [here](https://developers.yubico.com/yubico-pam/).
1130 '';
1131 };
1132 control = mkOption {
1133 default = "sufficient";
1134 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1135 description = lib.mdDoc ''
1136 This option sets pam "control".
1137 If you want to have multi factor authentication, use "required".
1138 If you want to use Yubikey instead of regular password, use "sufficient".
1139
1140 Read
1141 {manpage}`pam.conf(5)`
1142 for better understanding of this option.
1143 '';
1144 };
1145 id = mkOption {
1146 example = "42";
1147 type = types.str;
1148 description = lib.mdDoc "client id";
1149 };
1150
1151 debug = mkOption {
1152 default = false;
1153 type = types.bool;
1154 description = lib.mdDoc ''
1155 Debug output to stderr.
1156 '';
1157 };
1158 mode = mkOption {
1159 default = "client";
1160 type = types.enum [ "client" "challenge-response" ];
1161 description = lib.mdDoc ''
1162 Mode of operation.
1163
1164 Use "client" for online validation with a YubiKey validation service such as
1165 the YubiCloud.
1166
1167 Use "challenge-response" for offline validation using YubiKeys with HMAC-SHA-1
1168 Challenge-Response configurations. See the man-page ykpamcfg(1) for further
1169 details on how to configure offline Challenge-Response validation.
1170
1171 More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
1172 '';
1173 };
1174 challengeResponsePath = mkOption {
1175 default = null;
1176 type = types.nullOr types.path;
1177 description = lib.mdDoc ''
1178 If not null, set the path used by yubico pam module where the challenge expected response is stored.
1179
1180 More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
1181 '';
1182 };
1183 };
1184
1185 security.pam.enableEcryptfs = mkEnableOption (lib.mdDoc "eCryptfs PAM module (mounting ecryptfs home directory on login)");
1186 security.pam.enableFscrypt = mkEnableOption (lib.mdDoc ''
1187 Enables fscrypt to automatically unlock directories with the user's login password.
1188
1189 This also enables a service at security.pam.services.fscrypt which is used by
1190 fscrypt to verify the user's password when setting up a new protector. If you
1191 use something other than pam_unix to verify user passwords, please remember to
1192 adjust this PAM service.
1193 '');
1194
1195 users.motd = mkOption {
1196 default = null;
1197 example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
1198 type = types.nullOr types.lines;
1199 description = lib.mdDoc "Message of the day shown to users when they log in.";
1200 };
1201
1202 };
1203
1204
1205 ###### implementation
1206
1207 config = {
1208
1209 environment.systemPackages =
1210 # Include the PAM modules in the system path mostly for the manpages.
1211 [ pkgs.pam ]
1212 ++ optional config.users.ldap.enable pam_ldap
1213 ++ optional config.services.sssd.enable pkgs.sssd
1214 ++ optionals config.security.pam.krb5.enable [pam_krb5 pam_ccreds]
1215 ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
1216 ++ optionals config.security.pam.oath.enable [ pkgs.oath-toolkit ]
1217 ++ optionals config.security.pam.p11.enable [ pkgs.pam_p11 ]
1218 ++ optionals config.security.pam.enableFscrypt [ pkgs.fscrypt-experimental ]
1219 ++ optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ];
1220
1221 boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ];
1222
1223 security.wrappers = {
1224 unix_chkpwd = {
1225 setuid = true;
1226 owner = "root";
1227 group = "root";
1228 source = "${pkgs.pam}/bin/unix_chkpwd";
1229 };
1230 };
1231
1232 environment.etc = mapAttrs' makePAMService config.security.pam.services;
1233
1234 security.pam.services =
1235 { other.text =
1236 ''
1237 auth required pam_warn.so
1238 auth required pam_deny.so
1239 account required pam_warn.so
1240 account required pam_deny.so
1241 password required pam_warn.so
1242 password required pam_deny.so
1243 session required pam_warn.so
1244 session required pam_deny.so
1245 '';
1246
1247 # Most of these should be moved to specific modules.
1248 i3lock = {};
1249 i3lock-color = {};
1250 vlock = {};
1251 xlock = {};
1252 xscreensaver = {};
1253
1254 runuser = { rootOK = true; unixAuth = false; setEnvironment = false; };
1255
1256 /* FIXME: should runuser -l start a systemd session? Currently
1257 it complains "Cannot create session: Already running in a
1258 session". */
1259 runuser-l = { rootOK = true; unixAuth = false; };
1260 } // optionalAttrs (config.security.pam.enableFscrypt) {
1261 # Allow fscrypt to verify login passphrase
1262 fscrypt = {};
1263 };
1264
1265 security.apparmor.includes."abstractions/pam" = let
1266 isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
1267 in
1268 lib.concatMapStrings
1269 (name: "r ${config.environment.etc."pam.d/${name}".source},\n")
1270 (attrNames config.security.pam.services) +
1271 ''
1272 mr ${getLib pkgs.pam}/lib/security/pam_filter/*,
1273 mr ${getLib pkgs.pam}/lib/security/pam_*.so,
1274 r ${getLib pkgs.pam}/lib/security/,
1275 '' +
1276 optionalString use_ldap ''
1277 mr ${pam_ldap}/lib/security/pam_ldap.so,
1278 '' +
1279 optionalString config.services.sssd.enable ''
1280 mr ${pkgs.sssd}/lib/security/pam_sss.so,
1281 '' +
1282 optionalString config.security.pam.krb5.enable ''
1283 mr ${pam_krb5}/lib/security/pam_krb5.so,
1284 mr ${pam_ccreds}/lib/security/pam_ccreds.so,
1285 '' +
1286 optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
1287 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
1288 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so,
1289 '' +
1290 optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication)) ''
1291 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
1292 '' +
1293 optionalString (config.security.pam.enableSSHAgentAuth
1294 && isEnabled (cfg: cfg.sshAgentAuth)) ''
1295 mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,
1296 '' +
1297 optionalString (isEnabled (cfg: cfg.fprintAuth)) ''
1298 mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,
1299 '' +
1300 optionalString (isEnabled (cfg: cfg.u2fAuth)) ''
1301 mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,
1302 '' +
1303 optionalString (isEnabled (cfg: cfg.usbAuth)) ''
1304 mr ${pkgs.pam_usb}/lib/security/pam_usb.so,
1305 '' +
1306 optionalString (isEnabled (cfg: cfg.usshAuth)) ''
1307 mr ${pkgs.pam_ussh}/lib/security/pam_ussh.so,
1308 '' +
1309 optionalString (isEnabled (cfg: cfg.oathAuth)) ''
1310 "mr ${pkgs.oath-toolkit}/lib/security/pam_oath.so,
1311 '' +
1312 optionalString (isEnabled (cfg: cfg.mysqlAuth)) ''
1313 mr ${pkgs.pam_mysql}/lib/security/pam_mysql.so,
1314 '' +
1315 optionalString (isEnabled (cfg: cfg.yubicoAuth)) ''
1316 mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,
1317 '' +
1318 optionalString (isEnabled (cfg: cfg.duoSecurity.enable)) ''
1319 mr ${pkgs.duo-unix}/lib/security/pam_duo.so,
1320 '' +
1321 optionalString (isEnabled (cfg: cfg.otpwAuth)) ''
1322 mr ${pkgs.otpw}/lib/security/pam_otpw.so,
1323 '' +
1324 optionalString config.security.pam.enableEcryptfs ''
1325 mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,
1326 '' +
1327 optionalString config.security.pam.enableFscrypt ''
1328 mr ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so,
1329 '' +
1330 optionalString (isEnabled (cfg: cfg.pamMount)) ''
1331 mr ${pkgs.pam_mount}/lib/security/pam_mount.so,
1332 '' +
1333 optionalString (isEnabled (cfg: cfg.enableGnomeKeyring)) ''
1334 mr ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so,
1335 '' +
1336 optionalString (isEnabled (cfg: cfg.startSession)) ''
1337 mr ${config.systemd.package}/lib/security/pam_systemd.so,
1338 '' +
1339 optionalString (isEnabled (cfg: cfg.enableAppArmor)
1340 && config.security.apparmor.enable) ''
1341 mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,
1342 '' +
1343 optionalString (isEnabled (cfg: cfg.enableKwallet)) ''
1344 mr ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so,
1345 '' +
1346 optionalString config.virtualisation.lxc.lxcfs.enable ''
1347 mr ${pkgs.lxc}/lib/security/pam_cgfs.so
1348 '';
1349 };
1350
1351}