python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / security / pam.nix
blob412c5a433601d4fb56280f205fd80ea9e4240afd
1 # This module provides configuration for the PAM (Pluggable
2 # Authentication Modules) system.
4 { config, lib, pkgs, ... }:
6 with lib;
8 let
9   parentConfig = config;
11   pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in {
13     options = {
15       name = mkOption {
16         example = "sshd";
17         type = types.str;
18         description = lib.mdDoc "Name of the PAM service.";
19       };
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       };
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       };
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       };
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       };
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.
72           Note that the  {option}`security.pam.ussh.enable` must also be
73           set for this option to take effect.
74         '';
75       };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
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         };
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         };
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         };
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       };
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       };
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       };
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       };
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       };
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       };
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       };
330       showMotd = mkOption {
331         default = false;
332         type = types.bool;
333         description = lib.mdDoc "Whether to show the message of the day.";
334       };
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       };
346       updateWtmp = mkOption {
347         default = false;
348         type = types.bool;
349         description = lib.mdDoc "Whether to update {file}`/var/log/wtmp`.";
350       };
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       };
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       };
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       };
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       };
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         };
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       };
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         };
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         };
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       };
449       text = mkOption {
450         type = types.nullOr types.lines;
451         description = lib.mdDoc "Contents of the PAM service file.";
452       };
454     };
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;
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
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               || cfg.pamMount
548               || cfg.enableKwallet
549               || cfg.enableGnomeKeyring
550               || cfg.googleAuthenticator.enable
551               || cfg.gnupg.enable
552               || cfg.failDelay.enable
553               || cfg.duoSecurity.enable))
554             (
555               ''
556                 auth optional pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
557               '' +
558               optionalString config.security.pam.enableEcryptfs ''
559                 auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap
560               '' +
561               optionalString cfg.pamMount ''
562                 auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
563               '' +
564               optionalString cfg.enableKwallet ''
565                auth optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
566               '' +
567               optionalString cfg.enableGnomeKeyring ''
568                 auth optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so
569               '' +
570               optionalString cfg.gnupg.enable ''
571                 auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"}
572               '' +
573               optionalString cfg.failDelay.enable ''
574                 auth optional ${pkgs.pam}/lib/security/pam_faildelay.so delay=${toString cfg.failDelay.delay}
575               '' +
576               optionalString cfg.googleAuthenticator.enable ''
577                 auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
578               '' +
579               optionalString cfg.duoSecurity.enable ''
580                 auth required ${pkgs.duo-unix}/lib/security/pam_duo.so
581               ''
582             )) +
583           optionalString cfg.unixAuth ''
584             auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass
585           '' +
586           optionalString cfg.otpwAuth ''
587             auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so
588           '' +
589           optionalString use_ldap ''
590             auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass
591           '' +
592           optionalString config.services.sssd.enable ''
593             auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass
594           '' +
595           optionalString config.security.pam.krb5.enable ''
596             auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
597             auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
598             auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
599           '' +
600           ''
601             auth required pam_deny.so
603             # Password management.
604             password sufficient pam_unix.so nullok sha512
605           '' +
606           optionalString config.security.pam.enableEcryptfs ''
607             password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
608           '' +
609           optionalString cfg.pamMount ''
610             password optional ${pkgs.pam_mount}/lib/security/pam_mount.so
611           '' +
612           optionalString use_ldap ''
613             password sufficient ${pam_ldap}/lib/security/pam_ldap.so
614           '' +
615           optionalString cfg.mysqlAuth ''
616             password sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
617           '' +
618           optionalString config.services.sssd.enable ''
619             password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok
620           '' +
621           optionalString config.security.pam.krb5.enable ''
622             password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
623           '' +
624           optionalString cfg.enableGnomeKeyring ''
625             password optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok
626           '' +
627           ''
629             # Session management.
630           '' +
631           optionalString cfg.setEnvironment ''
632             session required pam_env.so conffile=/etc/pam/environment readenv=0
633           '' +
634           ''
635             session required pam_unix.so
636           '' +
637           optionalString cfg.setLoginUid ''
638             session ${if config.boot.isContainer then "optional" else "required"} pam_loginuid.so
639           '' +
640           optionalString cfg.ttyAudit.enable (concatStringsSep " \\\n  " ([
641             "session required ${pkgs.pam}/lib/security/pam_tty_audit.so"
642           ] ++ optional cfg.ttyAudit.openOnly "open_only"
643           ++ optional (cfg.ttyAudit.enablePattern != null) "enable=${cfg.ttyAudit.enablePattern}"
644           ++ optional (cfg.ttyAudit.disablePattern != null) "disable=${cfg.ttyAudit.disablePattern}"
645           )) +
646           optionalString cfg.makeHomeDir ''
647             session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=0077
648           '' +
649           optionalString cfg.updateWtmp ''
650             session required ${pkgs.pam}/lib/security/pam_lastlog.so silent
651           '' +
652           optionalString config.security.pam.enableEcryptfs ''
653             session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
654           '' +
655           optionalString cfg.pamMount ''
656             session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
657           '' +
658           optionalString use_ldap ''
659             session optional ${pam_ldap}/lib/security/pam_ldap.so
660           '' +
661           optionalString cfg.mysqlAuth ''
662             session optional ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
663           '' +
664           optionalString config.services.sssd.enable ''
665             session optional ${pkgs.sssd}/lib/security/pam_sss.so
666           '' +
667           optionalString config.security.pam.krb5.enable ''
668             session optional ${pam_krb5}/lib/security/pam_krb5.so
669           '' +
670           optionalString cfg.otpwAuth ''
671             session optional ${pkgs.otpw}/lib/security/pam_otpw.so
672           '' +
673           optionalString cfg.startSession ''
674             session optional ${config.systemd.package}/lib/security/pam_systemd.so
675           '' +
676           optionalString cfg.forwardXAuth ''
677             session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99
678           '' +
679           optionalString (cfg.limits != []) ''
680             session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}
681           '' +
682           optionalString (cfg.showMotd && config.users.motd != null) ''
683             session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}
684           '' +
685           optionalString (cfg.enableAppArmor && config.security.apparmor.enable) ''
686             session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug
687           '' +
688           optionalString (cfg.enableKwallet) ''
689             session optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
690           '' +
691           optionalString (cfg.enableGnomeKeyring) ''
692             session optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start
693           '' +
694           optionalString cfg.gnupg.enable ''
695             session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.noAutostart " no-autostart"}
696           '' +
697           optionalString (config.virtualisation.lxc.lxcfs.enable) ''
698             session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all
699           ''
700         );
701     };
703   };
706   inherit (pkgs) pam_krb5 pam_ccreds;
708   use_ldap = (config.users.ldap.enable && config.users.ldap.loginPam);
709   pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap;
711   # Create a limits.conf(5) file.
712   makeLimitsConf = limits:
713     pkgs.writeText "limits.conf"
714        (concatMapStrings ({ domain, type, item, value }:
715          "${domain} ${type} ${item} ${toString value}\n")
716          limits);
718   limitsType = with lib.types; listOf (submodule ({ ... }: {
719     options = {
720       domain = mkOption {
721         description = lib.mdDoc "Username, groupname, or wildcard this limit applies to";
722         example = "@wheel";
723         type = str;
724       };
726       type = mkOption {
727         description = lib.mdDoc "Type of this limit";
728         type = enum [ "-" "hard" "soft" ];
729         default = "-";
730       };
732       item = mkOption {
733         description = lib.mdDoc "Item this limit applies to";
734         type = enum [
735           "core"
736           "data"
737           "fsize"
738           "memlock"
739           "nofile"
740           "rss"
741           "stack"
742           "cpu"
743           "nproc"
744           "as"
745           "maxlogins"
746           "maxsyslogins"
747           "priority"
748           "locks"
749           "sigpending"
750           "msgqueue"
751           "nice"
752           "rtprio"
753         ];
754       };
756       value = mkOption {
757         description = lib.mdDoc "Value of this limit";
758         type = oneOf [ str int ];
759       };
760     };
761   }));
763   motd = pkgs.writeText "motd" config.users.motd;
765   makePAMService = name: service:
766     { name = "pam.d/${name}";
767       value.source = pkgs.writeText "${name}.pam" service.text;
768     };
774   imports = [
775     (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ])
776   ];
778   ###### interface
780   options = {
782     security.pam.loginLimits = mkOption {
783       default = [];
784       type = limitsType;
785       example =
786         [ { domain = "ftp";
787             type   = "hard";
788             item   = "nproc";
789             value  = "0";
790           }
791           { domain = "@student";
792             type   = "-";
793             item   = "maxlogins";
794             value  = "4";
795           }
796        ];
798      description = lib.mdDoc ''
799        Define resource limits that should apply to users or groups.
800        Each item in the list should be an attribute set with a
801        {var}`domain`, {var}`type`,
802        {var}`item`, and {var}`value`
803        attribute.  The syntax and semantics of these attributes
804        must be that described in {manpage}`limits.conf(5)`.
806        Note that these limits do not apply to systemd services,
807        whose limits can be changed via {option}`systemd.extraConfig`
808        instead.
809      '';
810     };
812     security.pam.services = mkOption {
813       default = {};
814       type = with types; attrsOf (submodule pamOpts);
815       description =
816         lib.mdDoc ''
817           This option defines the PAM services.  A service typically
818           corresponds to a program that uses PAM,
819           e.g. {command}`login` or {command}`passwd`.
820           Each attribute of this set defines a PAM service, with the attribute name
821           defining the name of the service.
822         '';
823     };
825     security.pam.makeHomeDir.skelDirectory = mkOption {
826       type = types.str;
827       default = "/var/empty";
828       example =  "/etc/skel";
829       description = lib.mdDoc ''
830         Path to skeleton directory whose contents are copied to home
831         directories newly created by `pam_mkhomedir`.
832       '';
833     };
835     security.pam.enableSSHAgentAuth = mkOption {
836       type = types.bool;
837       default = false;
838       description =
839         lib.mdDoc ''
840           Enable sudo logins if the user's SSH agent provides a key
841           present in {file}`~/.ssh/authorized_keys`.
842           This allows machines to exclusively use SSH keys instead of
843           passwords.
844         '';
845     };
847     security.pam.enableOTPW = mkEnableOption (lib.mdDoc "the OTPW (one-time password) PAM module");
849     security.pam.krb5 = {
850       enable = mkOption {
851         default = config.krb5.enable;
852         defaultText = literalExpression "config.krb5.enable";
853         type = types.bool;
854         description = lib.mdDoc ''
855           Enables Kerberos PAM modules (`pam-krb5`,
856           `pam-ccreds`).
858           If set, users can authenticate with their Kerberos password.
859           This requires a valid Kerberos configuration
860           (`config.krb5.enable` should be set to
861           `true`).
863           Note that the Kerberos PAM modules are not necessary when using SSS
864           to handle Kerberos authentication.
865         '';
866       };
867     };
869     security.pam.p11 = {
870       enable = mkOption {
871         default = false;
872         type = types.bool;
873         description = lib.mdDoc ''
874           Enables P11 PAM (`pam_p11`) module.
876           If set, users can log in with SSH keys and PKCS#11 tokens.
878           More information can be found [here](https://github.com/OpenSC/pam_p11).
879         '';
880       };
882       control = mkOption {
883         default = "sufficient";
884         type = types.enum [ "required" "requisite" "sufficient" "optional" ];
885         description = lib.mdDoc ''
886           This option sets pam "control".
887           If you want to have multi factor authentication, use "required".
888           If you want to use the PKCS#11 device instead of the regular password,
889           use "sufficient".
891           Read
892           {manpage}`pam.conf(5)`
893           for better understanding of this option.
894         '';
895       };
896     };
898     security.pam.u2f = {
899       enable = mkOption {
900         default = false;
901         type = types.bool;
902         description = lib.mdDoc ''
903           Enables U2F PAM (`pam-u2f`) module.
905           If set, users listed in
906           {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
907           {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
908           not set) are able to log in with the associated U2F key. The path can
909           be changed using {option}`security.pam.u2f.authFile` option.
911           File format is:
912           `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
913           This file can be generated using {command}`pamu2fcfg` command.
915           More information can be found [here](https://developers.yubico.com/pam-u2f/).
916         '';
917       };
919       authFile = mkOption {
920         default = null;
921         type = with types; nullOr path;
922         description = lib.mdDoc ''
923           By default `pam-u2f` module reads the keys from
924           {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
925           {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
926           not set).
928           If you want to change auth file locations or centralize database (for
929           example use {file}`/etc/u2f-mappings`) you can set this
930           option.
932           File format is:
933           `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
934           This file can be generated using {command}`pamu2fcfg` command.
936           More information can be found [here](https://developers.yubico.com/pam-u2f/).
937         '';
938       };
940       appId = mkOption {
941         default = null;
942         type = with types; nullOr str;
943         description = lib.mdDoc ''
944             By default `pam-u2f` module sets the application
945             ID to `pam://$HOSTNAME`.
947             When using {command}`pamu2fcfg`, you can specify your
948             application ID with the `-i` flag.
950             More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
951         '';
952       };
954       origin = mkOption {
955         default = null;
956         type = with types; nullOr str;
957         description = lib.mdDoc ''
958             By default `pam-u2f` module sets the origin
959             to `pam://$HOSTNAME`.
960             Setting origin to an host independent value will allow you to
961             reuse credentials across machines
963             When using {command}`pamu2fcfg`, you can specify your
964             application ID with the `-o` flag.
966             More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
967         '';
968       };
970       control = mkOption {
971         default = "sufficient";
972         type = types.enum [ "required" "requisite" "sufficient" "optional" ];
973         description = lib.mdDoc ''
974           This option sets pam "control".
975           If you want to have multi factor authentication, use "required".
976           If you want to use U2F device instead of regular password, use "sufficient".
978           Read
979           {manpage}`pam.conf(5)`
980           for better understanding of this option.
981         '';
982       };
984       debug = mkOption {
985         default = false;
986         type = types.bool;
987         description = lib.mdDoc ''
988           Debug output to stderr.
989         '';
990       };
992       interactive = mkOption {
993         default = false;
994         type = types.bool;
995         description = lib.mdDoc ''
996           Set to prompt a message and wait before testing the presence of a U2F device.
997           Recommended if your device doesn’t have a tactile trigger.
998         '';
999       };
1001       cue = mkOption {
1002         default = false;
1003         type = types.bool;
1004         description = lib.mdDoc ''
1005           By default `pam-u2f` module does not inform user
1006           that he needs to use the u2f device, it just waits without a prompt.
1008           If you set this option to `true`,
1009           `cue` option is added to `pam-u2f`
1010           module and reminder message will be displayed.
1011         '';
1012       };
1013     };
1015     security.pam.ussh = {
1016       enable = mkOption {
1017         default = false;
1018         type = types.bool;
1019         description = lib.mdDoc ''
1020           Enables Uber's USSH PAM (`pam-ussh`) module.
1022           This is similar to `pam-ssh-agent`, except that
1023           the presence of a CA-signed SSH key with a valid principal is checked
1024           instead.
1026           Note that this module must both be enabled using this option and on a
1027           per-PAM-service level as well (using `usshAuth`).
1029           More information can be found [here](https://github.com/uber/pam-ussh).
1030         '';
1031       };
1033       caFile = mkOption {
1034         default = null;
1035         type = with types; nullOr path;
1036         description = lib.mdDoc ''
1037           By default `pam-ussh` reads the trusted user CA keys
1038           from {file}`/etc/ssh/trusted_user_ca`.
1040           This should be set the same as your `TrustedUserCAKeys`
1041           option for sshd.
1042         '';
1043       };
1045       authorizedPrincipals = mkOption {
1046         default = null;
1047         type = with types; nullOr commas;
1048         description = lib.mdDoc ''
1049           Comma-separated list of authorized principals to permit; if the user
1050           presents a certificate with one of these principals, then they will be
1051           authorized.
1053           Note that `pam-ussh` also requires that the certificate
1054           contain a principal matching the user's username. The principals from
1055           this list are in addition to those principals.
1057           Mutually exclusive with `authorizedPrincipalsFile`.
1058         '';
1059       };
1061       authorizedPrincipalsFile = mkOption {
1062         default = null;
1063         type = with types; nullOr path;
1064         description = lib.mdDoc ''
1065           Path to a list of principals; if the user presents a certificate with
1066           one of these principals, then they will be authorized.
1068           Note that `pam-ussh` also requires that the certificate
1069           contain a principal matching the user's username. The principals from
1070           this file are in addition to those principals.
1072           Mutually exclusive with `authorizedPrincipals`.
1073         '';
1074       };
1076       group = mkOption {
1077         default = null;
1078         type = with types; nullOr str;
1079         description = lib.mdDoc ''
1080           If set, then the authenticating user must be a member of this group
1081           to use this module.
1082         '';
1083       };
1085       control = mkOption {
1086         default = "sufficient";
1087         type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1088         description = lib.mdDoc ''
1089           This option sets pam "control".
1090           If you want to have multi factor authentication, use "required".
1091           If you want to use the SSH certificate instead of the regular password,
1092           use "sufficient".
1094           Read
1095           {manpage}`pam.conf(5)`
1096           for better understanding of this option.
1097         '';
1098       };
1099     };
1101     security.pam.yubico = {
1102       enable = mkOption {
1103         default = false;
1104         type = types.bool;
1105         description = lib.mdDoc ''
1106           Enables Yubico PAM (`yubico-pam`) module.
1108           If set, users listed in
1109           {file}`~/.yubico/authorized_yubikeys`
1110           are able to log in with the associated Yubikey tokens.
1112           The file must have only one line:
1113           `username:yubikey_token_id1:yubikey_token_id2`
1114           More information can be found [here](https://developers.yubico.com/yubico-pam/).
1115         '';
1116       };
1117       control = mkOption {
1118         default = "sufficient";
1119         type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1120         description = lib.mdDoc ''
1121           This option sets pam "control".
1122           If you want to have multi factor authentication, use "required".
1123           If you want to use Yubikey instead of regular password, use "sufficient".
1125           Read
1126           {manpage}`pam.conf(5)`
1127           for better understanding of this option.
1128         '';
1129       };
1130       id = mkOption {
1131         example = "42";
1132         type = types.str;
1133         description = lib.mdDoc "client id";
1134       };
1136       debug = mkOption {
1137         default = false;
1138         type = types.bool;
1139         description = lib.mdDoc ''
1140           Debug output to stderr.
1141         '';
1142       };
1143       mode = mkOption {
1144         default = "client";
1145         type = types.enum [ "client" "challenge-response" ];
1146         description = lib.mdDoc ''
1147           Mode of operation.
1149           Use "client" for online validation with a YubiKey validation service such as
1150           the YubiCloud.
1152           Use "challenge-response" for offline validation using YubiKeys with HMAC-SHA-1
1153           Challenge-Response configurations. See the man-page ykpamcfg(1) for further
1154           details on how to configure offline Challenge-Response validation.
1156           More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
1157         '';
1158       };
1159       challengeResponsePath = mkOption {
1160         default = null;
1161         type = types.nullOr types.path;
1162         description = lib.mdDoc ''
1163           If not null, set the path used by yubico pam module where the challenge expected response is stored.
1165           More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
1166         '';
1167       };
1168     };
1170     security.pam.enableEcryptfs = mkEnableOption (lib.mdDoc "eCryptfs PAM module (mounting ecryptfs home directory on login)");
1172     users.motd = mkOption {
1173       default = null;
1174       example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
1175       type = types.nullOr types.lines;
1176       description = lib.mdDoc "Message of the day shown to users when they log in.";
1177     };
1179   };
1182   ###### implementation
1184   config = {
1186     environment.systemPackages =
1187       # Include the PAM modules in the system path mostly for the manpages.
1188       [ pkgs.pam ]
1189       ++ optional config.users.ldap.enable pam_ldap
1190       ++ optional config.services.sssd.enable pkgs.sssd
1191       ++ optionals config.security.pam.krb5.enable [pam_krb5 pam_ccreds]
1192       ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
1193       ++ optionals config.security.pam.oath.enable [ pkgs.oath-toolkit ]
1194       ++ optionals config.security.pam.p11.enable [ pkgs.pam_p11 ]
1195       ++ optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ];
1197     boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ];
1199     security.wrappers = {
1200       unix_chkpwd = {
1201         setuid = true;
1202         owner = "root";
1203         group = "root";
1204         source = "${pkgs.pam}/bin/unix_chkpwd";
1205       };
1206     };
1208     environment.etc = mapAttrs' makePAMService config.security.pam.services;
1210     security.pam.services =
1211       { other.text =
1212           ''
1213             auth     required pam_warn.so
1214             auth     required pam_deny.so
1215             account  required pam_warn.so
1216             account  required pam_deny.so
1217             password required pam_warn.so
1218             password required pam_deny.so
1219             session  required pam_warn.so
1220             session  required pam_deny.so
1221           '';
1223         # Most of these should be moved to specific modules.
1224         i3lock = {};
1225         i3lock-color = {};
1226         vlock = {};
1227         xlock = {};
1228         xscreensaver = {};
1230         runuser = { rootOK = true; unixAuth = false; setEnvironment = false; };
1232         /* FIXME: should runuser -l start a systemd session? Currently
1233            it complains "Cannot create session: Already running in a
1234            session". */
1235         runuser-l = { rootOK = true; unixAuth = false; };
1236       };
1238     security.apparmor.includes."abstractions/pam" = let
1239       isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
1240       in
1241       lib.concatMapStrings
1242         (name: "r ${config.environment.etc."pam.d/${name}".source},\n")
1243         (attrNames config.security.pam.services) +
1244       ''
1245       mr ${getLib pkgs.pam}/lib/security/pam_filter/*,
1246       mr ${getLib pkgs.pam}/lib/security/pam_*.so,
1247       r ${getLib pkgs.pam}/lib/security/,
1248       '' +
1249       optionalString use_ldap ''
1250          mr ${pam_ldap}/lib/security/pam_ldap.so,
1251       '' +
1252       optionalString config.services.sssd.enable ''
1253         mr ${pkgs.sssd}/lib/security/pam_sss.so,
1254       '' +
1255       optionalString config.security.pam.krb5.enable ''
1256         mr ${pam_krb5}/lib/security/pam_krb5.so,
1257         mr ${pam_ccreds}/lib/security/pam_ccreds.so,
1258       '' +
1259       optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
1260         mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
1261         mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so,
1262       '' +
1263       optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication)) ''
1264         mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
1265       '' +
1266       optionalString (config.security.pam.enableSSHAgentAuth
1267                      && isEnabled (cfg: cfg.sshAgentAuth)) ''
1268         mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,
1269       '' +
1270       optionalString (isEnabled (cfg: cfg.fprintAuth)) ''
1271         mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,
1272       '' +
1273       optionalString (isEnabled (cfg: cfg.u2fAuth)) ''
1274         mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,
1275       '' +
1276       optionalString (isEnabled (cfg: cfg.usbAuth)) ''
1277         mr ${pkgs.pam_usb}/lib/security/pam_usb.so,
1278       '' +
1279       optionalString (isEnabled (cfg: cfg.usshAuth)) ''
1280         mr ${pkgs.pam_ussh}/lib/security/pam_ussh.so,
1281       '' +
1282       optionalString (isEnabled (cfg: cfg.oathAuth)) ''
1283         "mr ${pkgs.oath-toolkit}/lib/security/pam_oath.so,
1284       '' +
1285       optionalString (isEnabled (cfg: cfg.mysqlAuth)) ''
1286         mr ${pkgs.pam_mysql}/lib/security/pam_mysql.so,
1287       '' +
1288       optionalString (isEnabled (cfg: cfg.yubicoAuth)) ''
1289         mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,
1290       '' +
1291       optionalString (isEnabled (cfg: cfg.duoSecurity.enable)) ''
1292         mr ${pkgs.duo-unix}/lib/security/pam_duo.so,
1293       '' +
1294       optionalString (isEnabled (cfg: cfg.otpwAuth)) ''
1295         mr ${pkgs.otpw}/lib/security/pam_otpw.so,
1296       '' +
1297       optionalString config.security.pam.enableEcryptfs ''
1298         mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,
1299       '' +
1300       optionalString (isEnabled (cfg: cfg.pamMount)) ''
1301         mr ${pkgs.pam_mount}/lib/security/pam_mount.so,
1302       '' +
1303       optionalString (isEnabled (cfg: cfg.enableGnomeKeyring)) ''
1304         mr ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so,
1305       '' +
1306       optionalString (isEnabled (cfg: cfg.startSession)) ''
1307         mr ${config.systemd.package}/lib/security/pam_systemd.so,
1308       '' +
1309       optionalString (isEnabled (cfg: cfg.enableAppArmor)
1310                      && config.security.apparmor.enable) ''
1311         mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,
1312       '' +
1313       optionalString (isEnabled (cfg: cfg.enableKwallet)) ''
1314         mr ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so,
1315       '' +
1316       optionalString config.virtualisation.lxc.lxcfs.enable ''
1317         mr ${pkgs.lxc}/lib/security/pam_cgfs.so
1318       '';
1319   };