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