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 filesystems 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 Whether 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 zfs = mkOption {
450 default = config.security.pam.zfs.enable;
451 defaultText = literalExpression "config.security.pam.zfs.enable";
452 type = types.bool;
453 description = lib.mdDoc ''
454 Enable unlocking and mounting of encrypted ZFS home dataset at login.
455 '';
456 };
457
458 text = mkOption {
459 type = types.nullOr types.lines;
460 description = lib.mdDoc "Contents of the PAM service file.";
461 };
462
463 };
464
465 # The resulting /etc/pam.d/* file contents are verified in
466 # nixos/tests/pam/pam-file-contents.nix. Please update tests there when
467 # changing the derivation.
468 config = {
469 name = mkDefault name;
470 setLoginUid = mkDefault cfg.startSession;
471 limits = mkDefault config.security.pam.loginLimits;
472
473 # !!! TODO: move the LDAP stuff to the LDAP module, and the
474 # Samba stuff to the Samba module. This requires that the PAM
475 # module provides the right hooks.
476 text = mkDefault
477 (
478 ''
479 # Account management.
480 '' +
481 optionalString use_ldap ''
482 account sufficient ${pam_ldap}/lib/security/pam_ldap.so
483 '' +
484 optionalString cfg.mysqlAuth ''
485 account sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
486 '' +
487 optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false) ''
488 account sufficient ${pkgs.sssd}/lib/security/pam_sss.so
489 '' +
490 optionalString (config.services.sssd.enable && cfg.sssdStrictAccess) ''
491 account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so
492 '' +
493 optionalString config.security.pam.krb5.enable ''
494 account sufficient ${pam_krb5}/lib/security/pam_krb5.so
495 '' +
496 optionalString cfg.googleOsLoginAccountVerification ''
497 account [success=ok ignore=ignore default=die] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
498 account [success=ok default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so
499 '' +
500 optionalString config.services.homed.enable ''
501 account sufficient ${config.systemd.package}/lib/security/pam_systemd_home.so
502 '' +
503 # The required pam_unix.so module has to come after all the sufficient modules
504 # because otherwise, the account lookup will fail if the user does not exist
505 # locally, for example with MySQL- or LDAP-auth.
506 ''
507 account required pam_unix.so
508
509 # Authentication management.
510 '' +
511 optionalString cfg.googleOsLoginAuthentication ''
512 auth [success=done perm_denied=die default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
513 '' +
514 optionalString cfg.rootOK ''
515 auth sufficient pam_rootok.so
516 '' +
517 optionalString cfg.requireWheel ''
518 auth required pam_wheel.so use_uid
519 '' +
520 optionalString cfg.logFailures ''
521 auth required pam_faillock.so
522 '' +
523 optionalString cfg.mysqlAuth ''
524 auth sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
525 '' +
526 optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) ''
527 auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}
528 '' +
529 (let p11 = config.security.pam.p11; in optionalString cfg.p11Auth ''
530 auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so
531 '') +
532 (let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth (''
533 auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ''
534 + ''${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"} ${optionalString (u2f.origin != null) "origin=${u2f.origin}"}
535 '')) +
536 optionalString cfg.usbAuth ''
537 auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so
538 '' +
539 (let ussh = config.security.pam.ussh; in optionalString (config.security.pam.ussh.enable && cfg.usshAuth) ''
540 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}"}
541 '') +
542 (let oath = config.security.pam.oath; in optionalString cfg.oathAuth ''
543 auth requisite ${pkgs.oath-toolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}
544 '') +
545 (let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth ''
546 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"}
547 '') +
548 optionalString cfg.fprintAuth ''
549 auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so
550 '' +
551 # Modules in this block require having the password set in PAM_AUTHTOK.
552 # pam_unix is marked as 'sufficient' on NixOS which means nothing will run
553 # after it succeeds. Certain modules need to run after pam_unix
554 # prompts the user for password so we run it once with 'optional' at an
555 # earlier point and it will run again with 'sufficient' further down.
556 # We use try_first_pass the second time to avoid prompting password twice.
557 #
558 # The same principle applies to systemd-homed
559 (optionalString ((cfg.unixAuth || config.services.homed.enable) &&
560 (config.security.pam.enableEcryptfs
561 || config.security.pam.enableFscrypt
562 || cfg.pamMount
563 || cfg.enableKwallet
564 || cfg.enableGnomeKeyring
565 || cfg.googleAuthenticator.enable
566 || cfg.gnupg.enable
567 || cfg.failDelay.enable
568 || cfg.duoSecurity.enable
569 || cfg.zfs))
570 (
571 optionalString config.services.homed.enable ''
572 auth optional ${config.systemd.package}/lib/security/pam_systemd_home.so
573 '' +
574 optionalString cfg.unixAuth ''
575 auth optional pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
576 '' +
577 optionalString config.security.pam.enableEcryptfs ''
578 auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap
579 '' +
580 optionalString config.security.pam.enableFscrypt ''
581 auth optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
582 '' +
583 optionalString cfg.zfs ''
584 auth optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes}
585 '' +
586 optionalString cfg.pamMount ''
587 auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
588 '' +
589 optionalString cfg.enableKwallet ''
590 auth optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
591 '' +
592 optionalString cfg.enableGnomeKeyring ''
593 auth optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so
594 '' +
595 optionalString cfg.gnupg.enable ''
596 auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"}
597 '' +
598 optionalString cfg.failDelay.enable ''
599 auth optional ${pkgs.pam}/lib/security/pam_faildelay.so delay=${toString cfg.failDelay.delay}
600 '' +
601 optionalString cfg.googleAuthenticator.enable ''
602 auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
603 '' +
604 optionalString cfg.duoSecurity.enable ''
605 auth required ${pkgs.duo-unix}/lib/security/pam_duo.so
606 ''
607 )) +
608 optionalString config.services.homed.enable ''
609 auth sufficient ${config.systemd.package}/lib/security/pam_systemd_home.so
610 '' +
611 optionalString cfg.unixAuth ''
612 auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass
613 '' +
614 optionalString cfg.otpwAuth ''
615 auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so
616 '' +
617 optionalString use_ldap ''
618 auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass
619 '' +
620 optionalString config.services.sssd.enable ''
621 auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass
622 '' +
623 optionalString config.security.pam.krb5.enable ''
624 auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
625 auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
626 auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
627 '' +
628 ''
629 auth required pam_deny.so
630
631 # Password management.
632 '' +
633 optionalString config.services.homed.enable ''
634 password sufficient ${config.systemd.package}/lib/security/pam_systemd_home.so
635 '' + ''
636 password sufficient pam_unix.so nullok yescrypt
637 '' +
638 optionalString config.security.pam.enableEcryptfs ''
639 password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
640 '' +
641 optionalString config.security.pam.enableFscrypt ''
642 password optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
643 '' +
644 optionalString cfg.zfs ''
645 password optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes}
646 '' +
647 optionalString cfg.pamMount ''
648 password optional ${pkgs.pam_mount}/lib/security/pam_mount.so
649 '' +
650 optionalString use_ldap ''
651 password sufficient ${pam_ldap}/lib/security/pam_ldap.so
652 '' +
653 optionalString cfg.mysqlAuth ''
654 password sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
655 '' +
656 optionalString config.services.sssd.enable ''
657 password sufficient ${pkgs.sssd}/lib/security/pam_sss.so
658 '' +
659 optionalString config.security.pam.krb5.enable ''
660 password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
661 '' +
662 optionalString cfg.enableGnomeKeyring ''
663 password optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok
664 '' +
665 ''
666
667 # Session management.
668 '' +
669 optionalString cfg.setEnvironment ''
670 session required pam_env.so conffile=/etc/pam/environment readenv=0
671 '' +
672 ''
673 session required pam_unix.so
674 '' +
675 optionalString cfg.setLoginUid ''
676 session ${if config.boot.isContainer then "optional" else "required"} pam_loginuid.so
677 '' +
678 optionalString cfg.ttyAudit.enable (concatStringsSep " \\\n " ([
679 "session required ${pkgs.pam}/lib/security/pam_tty_audit.so"
680 ] ++ optional cfg.ttyAudit.openOnly "open_only"
681 ++ optional (cfg.ttyAudit.enablePattern != null) "enable=${cfg.ttyAudit.enablePattern}"
682 ++ optional (cfg.ttyAudit.disablePattern != null) "disable=${cfg.ttyAudit.disablePattern}"
683 )) +
684 optionalString config.services.homed.enable ''
685 session required ${config.systemd.package}/lib/security/pam_systemd_home.so
686 '' +
687 optionalString cfg.makeHomeDir ''
688 session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=0077
689 '' +
690 optionalString cfg.updateWtmp ''
691 session required ${pkgs.pam}/lib/security/pam_lastlog.so silent
692 '' +
693 optionalString config.security.pam.enableEcryptfs ''
694 session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
695 '' +
696 optionalString config.security.pam.enableFscrypt ''
697 # Work around https://github.com/systemd/systemd/issues/8598
698 # Skips the pam_fscrypt module for systemd-user sessions which do not have a password
699 # anyways.
700 # See also https://github.com/google/fscrypt/issues/95
701 session [success=1 default=ignore] pam_succeed_if.so service = systemd-user
702 session optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
703 '' +
704 optionalString cfg.zfs ''
705 session [success=1 default=ignore] pam_succeed_if.so service = systemd-user
706 session optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes} ${optionalString config.security.pam.zfs.noUnmount "nounmount"}
707 '' +
708 optionalString cfg.pamMount ''
709 session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
710 '' +
711 optionalString use_ldap ''
712 session optional ${pam_ldap}/lib/security/pam_ldap.so
713 '' +
714 optionalString cfg.mysqlAuth ''
715 session optional ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
716 '' +
717 optionalString config.services.sssd.enable ''
718 session optional ${pkgs.sssd}/lib/security/pam_sss.so
719 '' +
720 optionalString config.security.pam.krb5.enable ''
721 session optional ${pam_krb5}/lib/security/pam_krb5.so
722 '' +
723 optionalString cfg.otpwAuth ''
724 session optional ${pkgs.otpw}/lib/security/pam_otpw.so
725 '' +
726 optionalString cfg.startSession ''
727 session optional ${config.systemd.package}/lib/security/pam_systemd.so
728 '' +
729 optionalString cfg.forwardXAuth ''
730 session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99
731 '' +
732 optionalString (cfg.limits != []) ''
733 session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}
734 '' +
735 optionalString (cfg.showMotd && (config.users.motd != null || config.users.motdFile != null)) ''
736 session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}
737 '' +
738 optionalString (cfg.enableAppArmor && config.security.apparmor.enable) ''
739 session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug
740 '' +
741 optionalString (cfg.enableKwallet) ''
742 session optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
743 '' +
744 optionalString (cfg.enableGnomeKeyring) ''
745 session optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start
746 '' +
747 optionalString cfg.gnupg.enable ''
748 session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.noAutostart " no-autostart"}
749 '' +
750 optionalString (config.virtualisation.lxc.lxcfs.enable) ''
751 session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all
752 ''
753 );
754 };
755
756 };
757
758
759 inherit (pkgs) pam_krb5 pam_ccreds;
760
761 use_ldap = (config.users.ldap.enable && config.users.ldap.loginPam);
762 pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap;
763
764 # Create a limits.conf(5) file.
765 makeLimitsConf = limits:
766 pkgs.writeText "limits.conf"
767 (concatMapStrings ({ domain, type, item, value }:
768 "${domain} ${type} ${item} ${toString value}\n")
769 limits);
770
771 limitsType = with lib.types; listOf (submodule ({ ... }: {
772 options = {
773 domain = mkOption {
774 description = lib.mdDoc "Username, groupname, or wildcard this limit applies to";
775 example = "@wheel";
776 type = str;
777 };
778
779 type = mkOption {
780 description = lib.mdDoc "Type of this limit";
781 type = enum [ "-" "hard" "soft" ];
782 default = "-";
783 };
784
785 item = mkOption {
786 description = lib.mdDoc "Item this limit applies to";
787 type = enum [
788 "core"
789 "data"
790 "fsize"
791 "memlock"
792 "nofile"
793 "rss"
794 "stack"
795 "cpu"
796 "nproc"
797 "as"
798 "maxlogins"
799 "maxsyslogins"
800 "priority"
801 "locks"
802 "sigpending"
803 "msgqueue"
804 "nice"
805 "rtprio"
806 ];
807 };
808
809 value = mkOption {
810 description = lib.mdDoc "Value of this limit";
811 type = oneOf [ str int ];
812 };
813 };
814 }));
815
816 motd = if config.users.motdFile == null
817 then pkgs.writeText "motd" config.users.motd
818 else config.users.motdFile;
819
820 makePAMService = name: service:
821 { name = "pam.d/${name}";
822 value.source = pkgs.writeText "${name}.pam" service.text;
823 };
824
825in
826
827{
828
829 imports = [
830 (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ])
831 ];
832
833 ###### interface
834
835 options = {
836
837 security.pam.loginLimits = mkOption {
838 default = [];
839 type = limitsType;
840 example =
841 [ { domain = "ftp";
842 type = "hard";
843 item = "nproc";
844 value = "0";
845 }
846 { domain = "@student";
847 type = "-";
848 item = "maxlogins";
849 value = "4";
850 }
851 ];
852
853 description = lib.mdDoc ''
854 Define resource limits that should apply to users or groups.
855 Each item in the list should be an attribute set with a
856 {var}`domain`, {var}`type`,
857 {var}`item`, and {var}`value`
858 attribute. The syntax and semantics of these attributes
859 must be that described in {manpage}`limits.conf(5)`.
860
861 Note that these limits do not apply to systemd services,
862 whose limits can be changed via {option}`systemd.extraConfig`
863 instead.
864 '';
865 };
866
867 security.pam.services = mkOption {
868 default = {};
869 type = with types; attrsOf (submodule pamOpts);
870 description =
871 lib.mdDoc ''
872 This option defines the PAM services. A service typically
873 corresponds to a program that uses PAM,
874 e.g. {command}`login` or {command}`passwd`.
875 Each attribute of this set defines a PAM service, with the attribute name
876 defining the name of the service.
877 '';
878 };
879
880 security.pam.makeHomeDir.skelDirectory = mkOption {
881 type = types.str;
882 default = "/var/empty";
883 example = "/etc/skel";
884 description = lib.mdDoc ''
885 Path to skeleton directory whose contents are copied to home
886 directories newly created by `pam_mkhomedir`.
887 '';
888 };
889
890 security.pam.enableSSHAgentAuth = mkOption {
891 type = types.bool;
892 default = false;
893 description =
894 lib.mdDoc ''
895 Enable sudo logins if the user's SSH agent provides a key
896 present in {file}`~/.ssh/authorized_keys`.
897 This allows machines to exclusively use SSH keys instead of
898 passwords.
899 '';
900 };
901
902 security.pam.enableOTPW = mkEnableOption (lib.mdDoc "the OTPW (one-time password) PAM module");
903
904 security.pam.krb5 = {
905 enable = mkOption {
906 default = config.krb5.enable;
907 defaultText = literalExpression "config.krb5.enable";
908 type = types.bool;
909 description = lib.mdDoc ''
910 Enables Kerberos PAM modules (`pam-krb5`,
911 `pam-ccreds`).
912
913 If set, users can authenticate with their Kerberos password.
914 This requires a valid Kerberos configuration
915 (`config.krb5.enable` should be set to
916 `true`).
917
918 Note that the Kerberos PAM modules are not necessary when using SSS
919 to handle Kerberos authentication.
920 '';
921 };
922 };
923
924 security.pam.p11 = {
925 enable = mkOption {
926 default = false;
927 type = types.bool;
928 description = lib.mdDoc ''
929 Enables P11 PAM (`pam_p11`) module.
930
931 If set, users can log in with SSH keys and PKCS#11 tokens.
932
933 More information can be found [here](https://github.com/OpenSC/pam_p11).
934 '';
935 };
936
937 control = mkOption {
938 default = "sufficient";
939 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
940 description = lib.mdDoc ''
941 This option sets pam "control".
942 If you want to have multi factor authentication, use "required".
943 If you want to use the PKCS#11 device instead of the regular password,
944 use "sufficient".
945
946 Read
947 {manpage}`pam.conf(5)`
948 for better understanding of this option.
949 '';
950 };
951 };
952
953 security.pam.u2f = {
954 enable = mkOption {
955 default = false;
956 type = types.bool;
957 description = lib.mdDoc ''
958 Enables U2F PAM (`pam-u2f`) module.
959
960 If set, users listed in
961 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
962 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
963 not set) are able to log in with the associated U2F key. The path can
964 be changed using {option}`security.pam.u2f.authFile` option.
965
966 File format is:
967 `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
968 This file can be generated using {command}`pamu2fcfg` command.
969
970 More information can be found [here](https://developers.yubico.com/pam-u2f/).
971 '';
972 };
973
974 authFile = mkOption {
975 default = null;
976 type = with types; nullOr path;
977 description = lib.mdDoc ''
978 By default `pam-u2f` module reads the keys from
979 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
980 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
981 not set).
982
983 If you want to change auth file locations or centralize database (for
984 example use {file}`/etc/u2f-mappings`) you can set this
985 option.
986
987 File format is:
988 `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
989 This file can be generated using {command}`pamu2fcfg` command.
990
991 More information can be found [here](https://developers.yubico.com/pam-u2f/).
992 '';
993 };
994
995 appId = mkOption {
996 default = null;
997 type = with types; nullOr str;
998 description = lib.mdDoc ''
999 By default `pam-u2f` module sets the application
1000 ID to `pam://$HOSTNAME`.
1001
1002 When using {command}`pamu2fcfg`, you can specify your
1003 application ID with the `-i` flag.
1004
1005 More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
1006 '';
1007 };
1008
1009 origin = mkOption {
1010 default = null;
1011 type = with types; nullOr str;
1012 description = lib.mdDoc ''
1013 By default `pam-u2f` module sets the origin
1014 to `pam://$HOSTNAME`.
1015 Setting origin to an host independent value will allow you to
1016 reuse credentials across machines
1017
1018 When using {command}`pamu2fcfg`, you can specify your
1019 application ID with the `-o` flag.
1020
1021 More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
1022 '';
1023 };
1024
1025 control = mkOption {
1026 default = "sufficient";
1027 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1028 description = lib.mdDoc ''
1029 This option sets pam "control".
1030 If you want to have multi factor authentication, use "required".
1031 If you want to use U2F device instead of regular password, use "sufficient".
1032
1033 Read
1034 {manpage}`pam.conf(5)`
1035 for better understanding of this option.
1036 '';
1037 };
1038
1039 debug = mkOption {
1040 default = false;
1041 type = types.bool;
1042 description = lib.mdDoc ''
1043 Debug output to stderr.
1044 '';
1045 };
1046
1047 interactive = mkOption {
1048 default = false;
1049 type = types.bool;
1050 description = lib.mdDoc ''
1051 Set to prompt a message and wait before testing the presence of a U2F device.
1052 Recommended if your device doesn’t have a tactile trigger.
1053 '';
1054 };
1055
1056 cue = mkOption {
1057 default = false;
1058 type = types.bool;
1059 description = lib.mdDoc ''
1060 By default `pam-u2f` module does not inform user
1061 that he needs to use the u2f device, it just waits without a prompt.
1062
1063 If you set this option to `true`,
1064 `cue` option is added to `pam-u2f`
1065 module and reminder message will be displayed.
1066 '';
1067 };
1068 };
1069
1070 security.pam.ussh = {
1071 enable = mkOption {
1072 default = false;
1073 type = types.bool;
1074 description = lib.mdDoc ''
1075 Enables Uber's USSH PAM (`pam-ussh`) module.
1076
1077 This is similar to `pam-ssh-agent`, except that
1078 the presence of a CA-signed SSH key with a valid principal is checked
1079 instead.
1080
1081 Note that this module must both be enabled using this option and on a
1082 per-PAM-service level as well (using `usshAuth`).
1083
1084 More information can be found [here](https://github.com/uber/pam-ussh).
1085 '';
1086 };
1087
1088 caFile = mkOption {
1089 default = null;
1090 type = with types; nullOr path;
1091 description = lib.mdDoc ''
1092 By default `pam-ussh` reads the trusted user CA keys
1093 from {file}`/etc/ssh/trusted_user_ca`.
1094
1095 This should be set the same as your `TrustedUserCAKeys`
1096 option for sshd.
1097 '';
1098 };
1099
1100 authorizedPrincipals = mkOption {
1101 default = null;
1102 type = with types; nullOr commas;
1103 description = lib.mdDoc ''
1104 Comma-separated list of authorized principals to permit; if the user
1105 presents a certificate with one of these principals, then they will be
1106 authorized.
1107
1108 Note that `pam-ussh` also requires that the certificate
1109 contain a principal matching the user's username. The principals from
1110 this list are in addition to those principals.
1111
1112 Mutually exclusive with `authorizedPrincipalsFile`.
1113 '';
1114 };
1115
1116 authorizedPrincipalsFile = mkOption {
1117 default = null;
1118 type = with types; nullOr path;
1119 description = lib.mdDoc ''
1120 Path to a list of principals; if the user presents a certificate with
1121 one of these principals, then they will be authorized.
1122
1123 Note that `pam-ussh` also requires that the certificate
1124 contain a principal matching the user's username. The principals from
1125 this file are in addition to those principals.
1126
1127 Mutually exclusive with `authorizedPrincipals`.
1128 '';
1129 };
1130
1131 group = mkOption {
1132 default = null;
1133 type = with types; nullOr str;
1134 description = lib.mdDoc ''
1135 If set, then the authenticating user must be a member of this group
1136 to use this module.
1137 '';
1138 };
1139
1140 control = mkOption {
1141 default = "sufficient";
1142 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1143 description = lib.mdDoc ''
1144 This option sets pam "control".
1145 If you want to have multi factor authentication, use "required".
1146 If you want to use the SSH certificate instead of the regular password,
1147 use "sufficient".
1148
1149 Read
1150 {manpage}`pam.conf(5)`
1151 for better understanding of this option.
1152 '';
1153 };
1154 };
1155
1156 security.pam.yubico = {
1157 enable = mkOption {
1158 default = false;
1159 type = types.bool;
1160 description = lib.mdDoc ''
1161 Enables Yubico PAM (`yubico-pam`) module.
1162
1163 If set, users listed in
1164 {file}`~/.yubico/authorized_yubikeys`
1165 are able to log in with the associated Yubikey tokens.
1166
1167 The file must have only one line:
1168 `username:yubikey_token_id1:yubikey_token_id2`
1169 More information can be found [here](https://developers.yubico.com/yubico-pam/).
1170 '';
1171 };
1172 control = mkOption {
1173 default = "sufficient";
1174 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1175 description = lib.mdDoc ''
1176 This option sets pam "control".
1177 If you want to have multi factor authentication, use "required".
1178 If you want to use Yubikey instead of regular password, use "sufficient".
1179
1180 Read
1181 {manpage}`pam.conf(5)`
1182 for better understanding of this option.
1183 '';
1184 };
1185 id = mkOption {
1186 example = "42";
1187 type = types.str;
1188 description = lib.mdDoc "client id";
1189 };
1190
1191 debug = mkOption {
1192 default = false;
1193 type = types.bool;
1194 description = lib.mdDoc ''
1195 Debug output to stderr.
1196 '';
1197 };
1198 mode = mkOption {
1199 default = "client";
1200 type = types.enum [ "client" "challenge-response" ];
1201 description = lib.mdDoc ''
1202 Mode of operation.
1203
1204 Use "client" for online validation with a YubiKey validation service such as
1205 the YubiCloud.
1206
1207 Use "challenge-response" for offline validation using YubiKeys with HMAC-SHA-1
1208 Challenge-Response configurations. See the man-page ykpamcfg(1) for further
1209 details on how to configure offline Challenge-Response validation.
1210
1211 More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
1212 '';
1213 };
1214 challengeResponsePath = mkOption {
1215 default = null;
1216 type = types.nullOr types.path;
1217 description = lib.mdDoc ''
1218 If not null, set the path used by yubico pam module where the challenge expected response is stored.
1219
1220 More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
1221 '';
1222 };
1223 };
1224
1225 security.pam.zfs = {
1226 enable = mkOption {
1227 default = false;
1228 type = types.bool;
1229 description = lib.mdDoc ''
1230 Enable unlocking and mounting of encrypted ZFS home dataset at login.
1231 '';
1232 };
1233
1234 homes = mkOption {
1235 example = "rpool/home";
1236 default = "rpool/home";
1237 type = types.str;
1238 description = lib.mdDoc ''
1239 Prefix of home datasets. This value will be concatenated with
1240 `"/" + <username>` in order to determine the home dataset to unlock.
1241 '';
1242 };
1243
1244 noUnmount = mkOption {
1245 default = false;
1246 type = types.bool;
1247 description = lib.mdDoc ''
1248 Do not unmount home dataset on logout.
1249 '';
1250 };
1251 };
1252
1253 security.pam.enableEcryptfs = mkEnableOption (lib.mdDoc "eCryptfs PAM module (mounting ecryptfs home directory on login)");
1254 security.pam.enableFscrypt = mkEnableOption (lib.mdDoc ''
1255 Enables fscrypt to automatically unlock directories with the user's login password.
1256
1257 This also enables a service at security.pam.services.fscrypt which is used by
1258 fscrypt to verify the user's password when setting up a new protector. If you
1259 use something other than pam_unix to verify user passwords, please remember to
1260 adjust this PAM service.
1261 '');
1262
1263 users.motd = mkOption {
1264 default = null;
1265 example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
1266 type = types.nullOr types.lines;
1267 description = lib.mdDoc "Message of the day shown to users when they log in.";
1268 };
1269
1270 users.motdFile = mkOption {
1271 default = null;
1272 example = "/etc/motd";
1273 type = types.nullOr types.path;
1274 description = lib.mdDoc "A file containing the message of the day shown to users when they log in.";
1275 };
1276 };
1277
1278
1279 ###### implementation
1280
1281 config = {
1282 assertions = [
1283 {
1284 assertion = config.users.motd == null || config.users.motdFile == null;
1285 message = ''
1286 Only one of users.motd and users.motdFile can be set.
1287 '';
1288 }
1289 {
1290 assertion = config.security.pam.zfs.enable -> (config.boot.zfs.enabled || config.boot.zfs.enableUnstable);
1291 message = ''
1292 `security.pam.zfs.enable` requires enabling ZFS (`boot.zfs.enabled` or `boot.zfs.enableUnstable`).
1293 '';
1294 }
1295 ];
1296
1297 environment.systemPackages =
1298 # Include the PAM modules in the system path mostly for the manpages.
1299 [ pkgs.pam ]
1300 ++ optional config.users.ldap.enable pam_ldap
1301 ++ optional config.services.sssd.enable pkgs.sssd
1302 ++ optionals config.security.pam.krb5.enable [pam_krb5 pam_ccreds]
1303 ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
1304 ++ optionals config.security.pam.oath.enable [ pkgs.oath-toolkit ]
1305 ++ optionals config.security.pam.p11.enable [ pkgs.pam_p11 ]
1306 ++ optionals config.security.pam.enableFscrypt [ pkgs.fscrypt-experimental ]
1307 ++ optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ];
1308
1309 boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ];
1310
1311 security.wrappers = {
1312 unix_chkpwd = {
1313 setuid = true;
1314 owner = "root";
1315 group = "root";
1316 source = "${pkgs.pam}/bin/unix_chkpwd";
1317 };
1318 };
1319
1320 environment.etc = mapAttrs' makePAMService config.security.pam.services;
1321
1322 security.pam.services =
1323 { other.text =
1324 ''
1325 auth required pam_warn.so
1326 auth required pam_deny.so
1327 account required pam_warn.so
1328 account required pam_deny.so
1329 password required pam_warn.so
1330 password required pam_deny.so
1331 session required pam_warn.so
1332 session required pam_deny.so
1333 '';
1334
1335 # Most of these should be moved to specific modules.
1336 i3lock = {};
1337 i3lock-color = {};
1338 vlock = {};
1339 xlock = {};
1340 xscreensaver = {};
1341
1342 runuser = { rootOK = true; unixAuth = false; setEnvironment = false; };
1343
1344 /* FIXME: should runuser -l start a systemd session? Currently
1345 it complains "Cannot create session: Already running in a
1346 session". */
1347 runuser-l = { rootOK = true; unixAuth = false; };
1348 } // optionalAttrs (config.security.pam.enableFscrypt) {
1349 # Allow fscrypt to verify login passphrase
1350 fscrypt = {};
1351 };
1352
1353 security.apparmor.includes."abstractions/pam" = let
1354 isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
1355 in
1356 lib.concatMapStrings
1357 (name: "r ${config.environment.etc."pam.d/${name}".source},\n")
1358 (attrNames config.security.pam.services) +
1359 ''
1360 mr ${getLib pkgs.pam}/lib/security/pam_filter/*,
1361 mr ${getLib pkgs.pam}/lib/security/pam_*.so,
1362 r ${getLib pkgs.pam}/lib/security/,
1363 '' +
1364 optionalString use_ldap ''
1365 mr ${pam_ldap}/lib/security/pam_ldap.so,
1366 '' +
1367 optionalString config.services.sssd.enable ''
1368 mr ${pkgs.sssd}/lib/security/pam_sss.so,
1369 '' +
1370 optionalString config.security.pam.krb5.enable ''
1371 mr ${pam_krb5}/lib/security/pam_krb5.so,
1372 mr ${pam_ccreds}/lib/security/pam_ccreds.so,
1373 '' +
1374 optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
1375 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
1376 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so,
1377 '' +
1378 optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication)) ''
1379 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
1380 '' +
1381 optionalString (config.security.pam.enableSSHAgentAuth
1382 && isEnabled (cfg: cfg.sshAgentAuth)) ''
1383 mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,
1384 '' +
1385 optionalString (isEnabled (cfg: cfg.fprintAuth)) ''
1386 mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,
1387 '' +
1388 optionalString (isEnabled (cfg: cfg.u2fAuth)) ''
1389 mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,
1390 '' +
1391 optionalString (isEnabled (cfg: cfg.usbAuth)) ''
1392 mr ${pkgs.pam_usb}/lib/security/pam_usb.so,
1393 '' +
1394 optionalString (isEnabled (cfg: cfg.usshAuth)) ''
1395 mr ${pkgs.pam_ussh}/lib/security/pam_ussh.so,
1396 '' +
1397 optionalString (isEnabled (cfg: cfg.oathAuth)) ''
1398 "mr ${pkgs.oath-toolkit}/lib/security/pam_oath.so,
1399 '' +
1400 optionalString (isEnabled (cfg: cfg.mysqlAuth)) ''
1401 mr ${pkgs.pam_mysql}/lib/security/pam_mysql.so,
1402 '' +
1403 optionalString (isEnabled (cfg: cfg.yubicoAuth)) ''
1404 mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,
1405 '' +
1406 optionalString (isEnabled (cfg: cfg.duoSecurity.enable)) ''
1407 mr ${pkgs.duo-unix}/lib/security/pam_duo.so,
1408 '' +
1409 optionalString (isEnabled (cfg: cfg.otpwAuth)) ''
1410 mr ${pkgs.otpw}/lib/security/pam_otpw.so,
1411 '' +
1412 optionalString config.security.pam.enableEcryptfs ''
1413 mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,
1414 '' +
1415 optionalString config.security.pam.enableFscrypt ''
1416 mr ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so,
1417 '' +
1418 optionalString (isEnabled (cfg: cfg.pamMount)) ''
1419 mr ${pkgs.pam_mount}/lib/security/pam_mount.so,
1420 '' +
1421 optionalString (isEnabled (cfg: cfg.enableGnomeKeyring)) ''
1422 mr ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so,
1423 '' +
1424 optionalString (isEnabled (cfg: cfg.startSession)) ''
1425 mr ${config.systemd.package}/lib/security/pam_systemd.so,
1426 '' +
1427 optionalString (isEnabled (cfg: cfg.enableAppArmor)
1428 && config.security.apparmor.enable) ''
1429 mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,
1430 '' +
1431 optionalString (isEnabled (cfg: cfg.enableKwallet)) ''
1432 mr ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so,
1433 '' +
1434 optionalString config.virtualisation.lxc.lxcfs.enable ''
1435 mr ${pkgs.lxc}/lib/security/pam_cgfs.so,
1436 '' +
1437 optionalString (isEnabled (cfg: cfg.zfs)) ''
1438 mr ${config.boot.zfs.package}/lib/security/pam_zfs_key.so,
1439 '' +
1440 optionalString config.services.homed.enable ''
1441 mr ${config.systemd.package}/lib/security/pam_systemd_home.so
1442 '';
1443 };
1444
1445}