at master 86 kB view raw
1# This module provides configuration for the PAM (Pluggable 2# Authentication Modules) system. 3{ 4 config, 5 lib, 6 pkgs, 7 ... 8}: 9let 10 11 moduleSettingsType = 12 with lib.types; 13 attrsOf ( 14 nullOr (oneOf [ 15 bool 16 str 17 int 18 pathInStore 19 ]) 20 ); 21 moduleSettingsDescription = '' 22 Boolean values render just the key if true, and nothing if false. 23 Null values are ignored. 24 All other values are rendered as key-value pairs. 25 ''; 26 27 mkRulesTypeOption = 28 type: 29 lib.mkOption { 30 # These options are experimental and subject to breaking changes without notice. 31 description = '' 32 PAM `${type}` rules for this service. 33 34 Attribute keys are the name of each rule. 35 ''; 36 type = lib.types.attrsOf ( 37 lib.types.submodule ( 38 { name, config, ... }: 39 { 40 options = { 41 name = lib.mkOption { 42 type = lib.types.str; 43 description = '' 44 Name of this rule. 45 ''; 46 internal = true; 47 readOnly = true; 48 }; 49 enable = lib.mkOption { 50 type = lib.types.bool; 51 default = true; 52 description = '' 53 Whether this rule is added to the PAM service config file. 54 ''; 55 }; 56 order = lib.mkOption { 57 type = lib.types.int; 58 description = '' 59 Order of this rule in the service file. Rules are arranged in ascending order of this value. 60 61 ::: {.warning} 62 The `order` values for the built-in rules are subject to change. If you assign a constant value to this option, a system update could silently reorder your rule. You could be locked out of your system, or your system could be left wide open. When using this option, set it to a relative offset from another rule's `order` value: 63 64 ```nix 65 { 66 security.pam.services.login.rules.auth.foo.order = 67 config.security.pam.services.login.rules.auth.unix.order + 10; 68 } 69 ``` 70 ::: 71 ''; 72 }; 73 control = lib.mkOption { 74 type = lib.types.str; 75 description = '' 76 Indicates the behavior of the PAM-API should the module fail to succeed in its authentication task. See `control` in {manpage}`pam.conf(5)` for details. 77 ''; 78 }; 79 modulePath = lib.mkOption { 80 type = lib.types.str; 81 description = '' 82 Either the full filename of the PAM to be used by the application (it begins with a '/'), or a relative pathname from the default module location. See `module-path` in {manpage}`pam.conf(5)` for details. 83 ''; 84 }; 85 args = lib.mkOption { 86 type = lib.types.listOf lib.types.str; 87 description = '' 88 Tokens that can be used to modify the specific behavior of the given PAM. Such arguments will be documented for each individual module. See `module-arguments` in {manpage}`pam.conf(5)` for details. 89 90 Escaping rules for spaces and square brackets are automatically applied. 91 92 {option}`settings` are automatically added as {option}`args`. It's recommended to use the {option}`settings` option whenever possible so that arguments can be overridden. 93 ''; 94 }; 95 settings = lib.mkOption { 96 type = moduleSettingsType; 97 default = { }; 98 description = '' 99 Settings to add as `module-arguments`. 100 101 ${moduleSettingsDescription} 102 ''; 103 }; 104 }; 105 config = { 106 inherit name; 107 # Formats an attrset of settings as args for use as `module-arguments`. 108 args = lib.concatLists ( 109 lib.flip lib.mapAttrsToList config.settings ( 110 name: value: 111 if lib.isBool value then 112 lib.optional value name 113 else 114 lib.optional (value != null) "${name}=${toString value}" 115 ) 116 ); 117 }; 118 } 119 ) 120 ); 121 }; 122 123 package = config.security.pam.package; 124 parentConfig = config; 125 126 pamOpts = 127 { config, name, ... }: 128 let 129 cfg = config; 130 in 131 let 132 config = parentConfig; 133 in 134 { 135 136 imports = [ 137 (lib.mkRenamedOptionModule [ "enableKwallet" ] [ "kwallet" "enable" ]) 138 ]; 139 140 options = { 141 142 name = lib.mkOption { 143 example = "sshd"; 144 type = lib.types.str; 145 description = "Name of the PAM service."; 146 }; 147 148 enable = lib.mkEnableOption "this PAM service" // { 149 default = true; 150 example = false; 151 }; 152 153 rules = lib.mkOption { 154 # This option is experimental and subject to breaking changes without notice. 155 visible = false; 156 157 description = '' 158 PAM rules for this service. 159 160 ::: {.warning} 161 This option and its suboptions are experimental and subject to breaking changes without notice. 162 163 If you use this option in your system configuration, you will need to manually monitor this module for any changes. Otherwise, failure to adjust your configuration properly could lead to you being locked out of your system, or worse, your system could be left wide open to attackers. 164 165 If you share configuration examples that use this option, you MUST include this warning so that users are informed. 166 167 You may freely use this option within `nixpkgs`, and future changes will account for those use sites. 168 ::: 169 ''; 170 type = lib.types.submodule { 171 options = lib.genAttrs [ "account" "auth" "password" "session" ] mkRulesTypeOption; 172 }; 173 }; 174 175 unixAuth = lib.mkOption { 176 default = true; 177 type = lib.types.bool; 178 description = '' 179 Whether users can log in with passwords defined in 180 {file}`/etc/shadow`. 181 ''; 182 }; 183 184 rootOK = lib.mkOption { 185 default = false; 186 type = lib.types.bool; 187 description = '' 188 If set, root doesn't need to authenticate (e.g. for the 189 {command}`useradd` service). 190 ''; 191 }; 192 193 p11Auth = lib.mkOption { 194 default = config.security.pam.p11.enable; 195 defaultText = lib.literalExpression "config.security.pam.p11.enable"; 196 type = lib.types.bool; 197 description = '' 198 If set, keys listed in 199 {file}`~/.ssh/authorized_keys` and 200 {file}`~/.eid/authorized_certificates` 201 can be used to log in with the associated PKCS#11 tokens. 202 ''; 203 }; 204 205 u2fAuth = lib.mkOption { 206 default = config.security.pam.u2f.enable; 207 defaultText = lib.literalExpression "config.security.pam.u2f.enable"; 208 type = lib.types.bool; 209 description = '' 210 If set, users listed in 211 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or 212 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is 213 not set) are able to log in with the associated U2F key. Path can be 214 changed using {option}`security.pam.u2f.authFile` option. 215 ''; 216 }; 217 218 usshAuth = lib.mkOption { 219 default = false; 220 type = lib.types.bool; 221 description = '' 222 If set, users with an SSH certificate containing an authorized principal 223 in their SSH agent are able to log in. Specific options are controlled 224 using the {option}`security.pam.ussh` options. 225 226 Note that the {option}`security.pam.ussh.enable` must also be 227 set for this option to take effect. 228 ''; 229 }; 230 231 yubicoAuth = lib.mkOption { 232 default = config.security.pam.yubico.enable; 233 defaultText = lib.literalExpression "config.security.pam.yubico.enable"; 234 type = lib.types.bool; 235 description = '' 236 If set, users listed in 237 {file}`~/.yubico/authorized_yubikeys` 238 are able to log in with the associated Yubikey tokens. 239 ''; 240 }; 241 242 googleAuthenticator = { 243 enable = lib.mkOption { 244 default = false; 245 type = lib.types.bool; 246 description = '' 247 If set, users with enabled Google Authenticator (created 248 {file}`~/.google_authenticator`) will be required 249 to provide Google Authenticator token to log in. 250 ''; 251 }; 252 allowNullOTP = lib.mkOption { 253 type = lib.types.bool; 254 default = false; 255 description = '' 256 Whether to allow login for accounts that have no OTP set 257 (i.e., accounts with no OTP configured or no existing 258 {file}`~/.google_authenticator`). 259 ''; 260 }; 261 forwardPass = lib.mkOption { 262 type = lib.types.bool; 263 default = false; 264 description = '' 265 The authentication provides a single field requiring 266 the user's password followed by the one-time password (OTP). 267 ''; 268 }; 269 }; 270 271 otpwAuth = lib.mkOption { 272 default = config.security.pam.enableOTPW; 273 defaultText = lib.literalExpression "config.security.pam.enableOTPW"; 274 type = lib.types.bool; 275 description = '' 276 If set, the OTPW system will be used (if 277 {file}`~/.otpw` exists). 278 ''; 279 }; 280 281 googleOsLoginAccountVerification = lib.mkOption { 282 default = false; 283 type = lib.types.bool; 284 description = '' 285 If set, will use the Google OS Login PAM modules 286 (`pam_oslogin_login`, 287 `pam_oslogin_admin`) to verify possible OS Login 288 users and set sudoers configuration accordingly. 289 This only makes sense to enable for the `sshd` PAM 290 service. 291 ''; 292 }; 293 294 googleOsLoginAuthentication = lib.mkOption { 295 default = false; 296 type = lib.types.bool; 297 description = '' 298 If set, will use the `pam_oslogin_login`'s user 299 authentication methods to authenticate users using 2FA. 300 This only makes sense to enable for the `sshd` PAM 301 service. 302 ''; 303 }; 304 305 mysqlAuth = lib.mkOption { 306 default = config.users.mysql.enable; 307 defaultText = lib.literalExpression "config.users.mysql.enable"; 308 type = lib.types.bool; 309 description = '' 310 If set, the `pam_mysql` module will be used to 311 authenticate users against a MySQL/MariaDB database. 312 ''; 313 }; 314 315 fprintAuth = lib.mkOption { 316 default = config.services.fprintd.enable; 317 defaultText = lib.literalExpression "config.services.fprintd.enable"; 318 type = lib.types.bool; 319 description = '' 320 If set, fingerprint reader will be used (if exists and 321 your fingerprints are enrolled). 322 ''; 323 }; 324 325 oathAuth = lib.mkOption { 326 default = config.security.pam.oath.enable; 327 defaultText = lib.literalExpression "config.security.pam.oath.enable"; 328 type = lib.types.bool; 329 description = '' 330 If set, the OATH Toolkit will be used. 331 ''; 332 }; 333 334 sshAgentAuth = lib.mkOption { 335 default = false; 336 type = lib.types.bool; 337 description = '' 338 If set, the calling user's SSH agent is used to authenticate 339 against the keys in the calling user's 340 {file}`~/.ssh/authorized_keys`. This is useful 341 for {command}`sudo` on password-less remote systems. 342 ''; 343 }; 344 345 rssh = lib.mkOption { 346 default = false; 347 type = lib.types.bool; 348 description = '' 349 If set, the calling user's SSH agent is used to authenticate 350 against the configured keys. This module works in a manner 351 similar to pam_ssh_agent_auth, but supports a wider range 352 of SSH key types, including those protected by security 353 keys (FIDO2). 354 ''; 355 }; 356 357 duoSecurity = { 358 enable = lib.mkOption { 359 default = false; 360 type = lib.types.bool; 361 description = '' 362 If set, use the Duo Security pam module 363 `pam_duo` for authentication. Requires 364 configuration of {option}`security.duosec` options. 365 ''; 366 }; 367 }; 368 369 startSession = lib.mkOption { 370 default = false; 371 type = lib.types.bool; 372 description = '' 373 If set, the service will register a new session with 374 systemd's login manager. For local sessions, this will give 375 the user access to audio devices, CD-ROM drives. In the 376 default PolicyKit configuration, it also allows the user to 377 reboot the system. 378 ''; 379 }; 380 381 setEnvironment = lib.mkOption { 382 type = lib.types.bool; 383 default = true; 384 description = '' 385 Whether the service should set the environment variables 386 listed in {option}`environment.sessionVariables` 387 using `pam_env.so`. 388 ''; 389 }; 390 391 setLoginUid = lib.mkOption { 392 type = lib.types.bool; 393 description = '' 394 Set the login uid of the process 395 ({file}`/proc/self/loginuid`) for auditing 396 purposes. The login uid is only set by entry points like 397 {command}`login` and {command}`sshd`, not by 398 commands like {command}`sudo`. 399 ''; 400 }; 401 402 ttyAudit = { 403 enable = lib.mkOption { 404 type = lib.types.bool; 405 default = false; 406 description = '' 407 Enable or disable TTY auditing for specified users 408 ''; 409 }; 410 411 enablePattern = lib.mkOption { 412 type = lib.types.nullOr lib.types.str; 413 default = null; 414 description = '' 415 For each user matching one of comma-separated 416 glob patterns, enable TTY auditing 417 ''; 418 }; 419 420 disablePattern = lib.mkOption { 421 type = lib.types.nullOr lib.types.str; 422 default = null; 423 description = '' 424 For each user matching one of comma-separated 425 glob patterns, disable TTY auditing 426 ''; 427 }; 428 429 openOnly = lib.mkOption { 430 type = lib.types.bool; 431 default = false; 432 description = '' 433 Set the TTY audit flag when opening the session, 434 but do not restore it when closing the session. 435 Using this option is necessary for some services 436 that don't fork() to run the authenticated session, 437 such as sudo. 438 ''; 439 }; 440 }; 441 442 forwardXAuth = lib.mkOption { 443 default = false; 444 type = lib.types.bool; 445 description = '' 446 Whether X authentication keys should be passed from the 447 calling user to the target user (e.g. for 448 {command}`su`) 449 ''; 450 }; 451 452 pamMount = lib.mkOption { 453 default = config.security.pam.mount.enable; 454 defaultText = lib.literalExpression "config.security.pam.mount.enable"; 455 type = lib.types.bool; 456 description = '' 457 Enable PAM mount (pam_mount) system to mount filesystems on user login. 458 ''; 459 }; 460 461 allowNullPassword = lib.mkOption { 462 default = false; 463 type = lib.types.bool; 464 description = '' 465 Whether to allow logging into accounts that have no password 466 set (i.e., have an empty password field in 467 {file}`/etc/passwd` or 468 {file}`/etc/group`). This does not enable 469 logging into disabled accounts (i.e., that have the password 470 field set to `!`). Note that regardless of 471 what the pam_unix documentation says, accounts with hashed 472 empty passwords are always allowed to log in. 473 ''; 474 }; 475 476 nodelay = lib.mkOption { 477 default = false; 478 type = lib.types.bool; 479 description = '' 480 Whether the delay after typing a wrong password should be disabled. 481 ''; 482 }; 483 484 requireWheel = lib.mkOption { 485 default = false; 486 type = lib.types.bool; 487 description = '' 488 Whether to permit root access only to members of group wheel. 489 ''; 490 }; 491 492 limits = lib.mkOption { 493 default = [ ]; 494 type = limitsType; 495 description = '' 496 Attribute set describing resource limits. Defaults to the 497 value of {option}`security.pam.loginLimits`. 498 The meaning of the values is explained in {manpage}`limits.conf(5)`. 499 ''; 500 }; 501 502 showMotd = lib.mkOption { 503 default = false; 504 type = lib.types.bool; 505 description = "Whether to show the message of the day."; 506 }; 507 508 makeHomeDir = lib.mkOption { 509 default = false; 510 type = lib.types.bool; 511 description = '' 512 Whether to try to create home directories for users 513 with `$HOME`s pointing to nonexistent 514 locations on session login. 515 ''; 516 }; 517 518 updateWtmp = lib.mkOption { 519 default = false; 520 type = lib.types.bool; 521 description = "Whether to update {file}`/var/log/wtmp`."; 522 }; 523 524 logFailures = lib.mkOption { 525 default = false; 526 type = lib.types.bool; 527 description = "Whether to log authentication failures in {file}`/var/log/faillog`."; 528 }; 529 530 enableAppArmor = lib.mkOption { 531 default = false; 532 type = lib.types.bool; 533 description = '' 534 Enable support for attaching AppArmor profiles at the 535 user/group level, e.g., as part of a role based access 536 control scheme. 537 ''; 538 }; 539 540 kwallet = { 541 enable = lib.mkOption { 542 default = false; 543 type = lib.types.bool; 544 description = '' 545 If enabled, pam_wallet will attempt to automatically unlock the 546 user's default KDE wallet upon login. If the user has no wallet named 547 "kdewallet", or the login password does not match their wallet 548 password, KDE will prompt separately after login. 549 ''; 550 }; 551 552 package = lib.mkPackageOption pkgs.kdePackages "kwallet-pam" { 553 pkgsText = "pkgs.kdePackages"; 554 }; 555 556 forceRun = lib.mkEnableOption null // { 557 description = '' 558 The `force_run` option is used to tell the PAM module for KWallet 559 to forcefully run even if no graphical session (such as a GUI 560 display manager) is detected. This is useful for when you are 561 starting an X Session or a Wayland Session from a TTY. If you 562 intend to log-in from a TTY, it is recommended that you enable 563 this option **and** ensure that `plasma-kwallet-pam.service` is 564 started by `graphical-session.target`. 565 ''; 566 }; 567 }; 568 569 sssdStrictAccess = lib.mkOption { 570 default = false; 571 type = lib.types.bool; 572 description = "enforce sssd access control"; 573 }; 574 575 enableGnomeKeyring = lib.mkOption { 576 default = false; 577 type = lib.types.bool; 578 description = '' 579 If enabled, pam_gnome_keyring will attempt to automatically unlock the 580 user's default Gnome keyring upon login. If the user login password does 581 not match their keyring password, Gnome Keyring will prompt separately 582 after login. 583 ''; 584 }; 585 586 failDelay = { 587 enable = lib.mkOption { 588 type = lib.types.bool; 589 default = false; 590 description = '' 591 If enabled, this will replace the `FAIL_DELAY` setting from `login.defs`. 592 Change the delay on failure per-application. 593 ''; 594 }; 595 596 delay = lib.mkOption { 597 default = 3000000; 598 type = lib.types.int; 599 example = 1000000; 600 description = "The delay time (in microseconds) on failure."; 601 }; 602 }; 603 604 gnupg = { 605 enable = lib.mkOption { 606 type = lib.types.bool; 607 default = false; 608 description = '' 609 If enabled, pam_gnupg will attempt to automatically unlock the 610 user's GPG keys with the login password via 611 {command}`gpg-agent`. The keygrips of all keys to be 612 unlocked should be written to {file}`~/.pam-gnupg`, 613 and can be queried with {command}`gpg -K --with-keygrip`. 614 Presetting passphrases must be enabled by adding 615 `allow-preset-passphrase` in 616 {file}`~/.gnupg/gpg-agent.conf`. 617 ''; 618 }; 619 620 noAutostart = lib.mkOption { 621 type = lib.types.bool; 622 default = false; 623 description = '' 624 Don't start {command}`gpg-agent` if it is not running. 625 Useful in conjunction with starting {command}`gpg-agent` as 626 a systemd user service. 627 ''; 628 }; 629 630 storeOnly = lib.mkOption { 631 type = lib.types.bool; 632 default = false; 633 description = '' 634 Don't send the password immediately after login, but store for PAM 635 `session`. 636 ''; 637 }; 638 }; 639 640 zfs = lib.mkOption { 641 default = config.security.pam.zfs.enable; 642 defaultText = lib.literalExpression "config.security.pam.zfs.enable"; 643 type = lib.types.bool; 644 description = '' 645 Enable unlocking and mounting of encrypted ZFS home dataset at login. 646 ''; 647 }; 648 649 text = lib.mkOption { 650 type = lib.types.nullOr lib.types.lines; 651 description = "Contents of the PAM service file."; 652 }; 653 654 }; 655 656 # The resulting /etc/pam.d/* file contents are verified in 657 # nixos/tests/pam/pam-file-contents.nix. Please update tests there when 658 # changing the derivation. 659 config = { 660 name = lib.mkDefault name; 661 setLoginUid = lib.mkDefault cfg.startSession; 662 limits = lib.mkDefault config.security.pam.loginLimits; 663 664 text = 665 let 666 ensureUniqueOrder = 667 type: rules: 668 let 669 checkPair = 670 a: b: 671 assert lib.assertMsg (a.order != b.order) 672 "security.pam.services.${name}.rules.${type}: rules '${a.name}' and '${b.name}' cannot have the same order value (${toString a.order})"; 673 b; 674 checked = lib.zipListsWith checkPair rules (lib.drop 1 rules); 675 in 676 lib.take 1 rules ++ checked; 677 # Formats a string for use in `module-arguments`. See `man pam.conf`. 678 formatModuleArgument = 679 token: if lib.hasInfix " " token then "[${lib.replaceStrings [ "]" ] [ "\\]" ] token}]" else token; 680 formatRules = 681 type: 682 lib.pipe cfg.rules.${type} [ 683 lib.attrValues 684 (lib.filter (rule: rule.enable)) 685 (lib.sort (a: b: a.order < b.order)) 686 (ensureUniqueOrder type) 687 (map ( 688 rule: 689 lib.concatStringsSep " " ( 690 [ 691 type 692 rule.control 693 rule.modulePath 694 ] 695 ++ map formatModuleArgument rule.args 696 ++ [ "# ${rule.name} (order ${toString rule.order})" ] 697 ) 698 )) 699 (lib.concatStringsSep "\n") 700 ]; 701 in 702 lib.mkDefault '' 703 # Account management. 704 ${formatRules "account"} 705 706 # Authentication management. 707 ${formatRules "auth"} 708 709 # Password management. 710 ${formatRules "password"} 711 712 # Session management. 713 ${formatRules "session"} 714 ''; 715 716 # !!! TODO: move the LDAP stuff to the LDAP module, and the 717 # Samba stuff to the Samba module. This requires that the PAM 718 # module provides the right hooks. 719 rules = 720 let 721 autoOrderRules = lib.flip lib.pipe [ 722 (lib.imap1 (index: rule: rule // { order = lib.mkDefault (10000 + index * 100); })) 723 (map (rule: lib.nameValuePair rule.name (removeAttrs rule [ "name" ]))) 724 lib.listToAttrs 725 ]; 726 in 727 { 728 account = autoOrderRules [ 729 { 730 name = "ldap"; 731 enable = use_ldap; 732 control = "sufficient"; 733 modulePath = "${pam_ldap}/lib/security/pam_ldap.so"; 734 } 735 { 736 name = "mysql"; 737 enable = cfg.mysqlAuth; 738 control = "sufficient"; 739 modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; 740 settings = { 741 config_file = "/etc/security/pam_mysql.conf"; 742 }; 743 } 744 { 745 name = "kanidm"; 746 enable = config.services.kanidm.enablePam; 747 control = "sufficient"; 748 modulePath = "${config.services.kanidm.package}/lib/pam_kanidm.so"; 749 settings = { 750 ignore_unknown_user = true; 751 }; 752 } 753 { 754 name = "sss"; 755 enable = config.services.sssd.enable; 756 control = 757 if cfg.sssdStrictAccess then "[default=bad success=ok user_unknown=ignore]" else "sufficient"; 758 modulePath = "${pkgs.sssd}/lib/security/pam_sss.so"; 759 } 760 { 761 name = "krb5"; 762 enable = config.security.pam.krb5.enable; 763 control = "sufficient"; 764 modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; 765 } 766 { 767 name = "oslogin_login"; 768 enable = cfg.googleOsLoginAccountVerification; 769 control = "[success=ok ignore=ignore default=die]"; 770 modulePath = "${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so"; 771 } 772 { 773 name = "oslogin_admin"; 774 enable = cfg.googleOsLoginAccountVerification; 775 control = "[success=ok default=ignore]"; 776 modulePath = "${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so"; 777 } 778 { 779 name = "systemd_home"; 780 enable = config.services.homed.enable; 781 control = "sufficient"; 782 modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; 783 } 784 # The required pam_unix.so module has to come after all the sufficient modules 785 # because otherwise, the account lookup will fail if the user does not exist 786 # locally, for example with MySQL- or LDAP-auth. 787 { 788 name = "unix"; 789 control = "required"; 790 modulePath = "${package}/lib/security/pam_unix.so"; 791 } 792 ]; 793 794 auth = autoOrderRules ( 795 [ 796 { 797 name = "oslogin_login"; 798 enable = cfg.googleOsLoginAuthentication; 799 control = "[success=done perm_denied=die default=ignore]"; 800 modulePath = "${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so"; 801 } 802 { 803 name = "rootok"; 804 enable = cfg.rootOK; 805 control = "sufficient"; 806 modulePath = "${package}/lib/security/pam_rootok.so"; 807 } 808 { 809 name = "wheel"; 810 enable = cfg.requireWheel; 811 control = "required"; 812 modulePath = "${package}/lib/security/pam_wheel.so"; 813 settings = { 814 use_uid = true; 815 }; 816 } 817 { 818 name = "faillock"; 819 enable = cfg.logFailures; 820 control = "required"; 821 modulePath = "${package}/lib/security/pam_faillock.so"; 822 } 823 { 824 name = "mysql"; 825 enable = cfg.mysqlAuth; 826 control = "sufficient"; 827 modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; 828 settings = { 829 config_file = "/etc/security/pam_mysql.conf"; 830 }; 831 } 832 { 833 name = "ssh_agent_auth"; 834 enable = config.security.pam.sshAgentAuth.enable && cfg.sshAgentAuth; 835 control = "sufficient"; 836 modulePath = "${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so"; 837 settings = { 838 file = lib.concatStringsSep ":" config.security.pam.sshAgentAuth.authorizedKeysFiles; 839 }; 840 } 841 ( 842 let 843 inherit (config.security.pam) rssh; 844 in 845 { 846 name = "rssh"; 847 enable = rssh.enable && cfg.rssh; 848 control = "sufficient"; 849 modulePath = "${pkgs.pam_rssh}/lib/libpam_rssh.so"; 850 inherit (rssh) settings; 851 } 852 ) 853 ( 854 let 855 p11 = config.security.pam.p11; 856 in 857 { 858 name = "p11"; 859 enable = cfg.p11Auth; 860 control = p11.control; 861 modulePath = "${pkgs.pam_p11}/lib/security/pam_p11.so"; 862 args = [ 863 "${pkgs.opensc}/lib/opensc-pkcs11.so" 864 ]; 865 } 866 ) 867 ( 868 let 869 u2f = config.security.pam.u2f; 870 in 871 { 872 name = "u2f"; 873 enable = cfg.u2fAuth; 874 control = u2f.control; 875 modulePath = "${pkgs.pam_u2f}/lib/security/pam_u2f.so"; 876 inherit (u2f) settings; 877 } 878 ) 879 ( 880 let 881 ussh = config.security.pam.ussh; 882 in 883 { 884 name = "ussh"; 885 enable = config.security.pam.ussh.enable && cfg.usshAuth; 886 control = ussh.control; 887 modulePath = "${pkgs.pam_ussh}/lib/security/pam_ussh.so"; 888 settings = { 889 ca_file = ussh.caFile; 890 authorized_principals = ussh.authorizedPrincipals; 891 authorized_principals_file = ussh.authorizedPrincipalsFile; 892 inherit (ussh) group; 893 }; 894 } 895 ) 896 ( 897 let 898 oath = config.security.pam.oath; 899 in 900 { 901 name = "oath"; 902 enable = cfg.oathAuth; 903 control = "requisite"; 904 modulePath = "${pkgs.oath-toolkit}/lib/security/pam_oath.so"; 905 settings = { 906 inherit (oath) window digits; 907 usersfile = oath.usersFile; 908 }; 909 } 910 ) 911 ( 912 let 913 yubi = config.security.pam.yubico; 914 in 915 { 916 name = "yubico"; 917 enable = cfg.yubicoAuth; 918 control = yubi.control; 919 modulePath = "${pkgs.yubico-pam}/lib/security/pam_yubico.so"; 920 settings = { 921 inherit (yubi) mode debug; 922 chalresp_path = yubi.challengeResponsePath; 923 id = lib.mkIf (yubi.mode == "client") yubi.id; 924 }; 925 } 926 ) 927 ( 928 let 929 dp9ik = config.security.pam.dp9ik; 930 in 931 { 932 name = "p9"; 933 enable = dp9ik.enable; 934 control = dp9ik.control; 935 modulePath = "${pkgs.pam_dp9ik}/lib/security/pam_p9.so"; 936 args = [ 937 dp9ik.authserver 938 ]; 939 } 940 ) 941 { 942 name = "fprintd"; 943 enable = cfg.fprintAuth; 944 control = "sufficient"; 945 modulePath = "${config.services.fprintd.package}/lib/security/pam_fprintd.so"; 946 } 947 ] 948 ++ 949 # Modules in this block require having the password set in PAM_AUTHTOK. 950 # pam_unix is marked as 'sufficient' on NixOS which means nothing will run 951 # after it succeeds. Certain modules need to run after pam_unix 952 # prompts the user for password so we run it once with 'optional' at an 953 # earlier point and it will run again with 'sufficient' further down. 954 # We use try_first_pass the second time to avoid prompting password twice. 955 # 956 # The same principle applies to systemd-homed 957 (lib.optionals 958 ( 959 (cfg.unixAuth || config.services.homed.enable) 960 && ( 961 config.security.pam.enableEcryptfs 962 || config.security.pam.enableFscrypt 963 || cfg.pamMount 964 || cfg.kwallet.enable 965 || cfg.enableGnomeKeyring 966 || config.services.intune.enable 967 || cfg.googleAuthenticator.enable 968 || cfg.gnupg.enable 969 || cfg.failDelay.enable 970 || cfg.duoSecurity.enable 971 || cfg.zfs 972 ) 973 ) 974 [ 975 { 976 name = "systemd_home-early"; 977 enable = config.services.homed.enable; 978 control = "optional"; 979 modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; 980 } 981 { 982 name = "unix-early"; 983 enable = cfg.unixAuth; 984 control = "optional"; 985 modulePath = "${package}/lib/security/pam_unix.so"; 986 settings = { 987 nullok = cfg.allowNullPassword; 988 inherit (cfg) nodelay; 989 likeauth = true; 990 }; 991 } 992 { 993 name = "ecryptfs"; 994 enable = config.security.pam.enableEcryptfs; 995 control = "optional"; 996 modulePath = "${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"; 997 settings = { 998 unwrap = true; 999 }; 1000 } 1001 { 1002 name = "fscrypt"; 1003 enable = config.security.pam.enableFscrypt; 1004 control = "optional"; 1005 modulePath = "${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so"; 1006 } 1007 { 1008 name = "zfs_key"; 1009 enable = cfg.zfs; 1010 control = "optional"; 1011 modulePath = "${config.boot.zfs.package}/lib/security/pam_zfs_key.so"; 1012 settings = { 1013 inherit (config.security.pam.zfs) homes; 1014 }; 1015 } 1016 { 1017 name = "mount"; 1018 enable = cfg.pamMount; 1019 control = "optional"; 1020 modulePath = "${pkgs.pam_mount}/lib/security/pam_mount.so"; 1021 settings = { 1022 disable_interactive = true; 1023 }; 1024 } 1025 { 1026 name = "kwallet"; 1027 enable = cfg.kwallet.enable; 1028 control = "optional"; 1029 modulePath = "${cfg.kwallet.package}/lib/security/pam_kwallet5.so"; 1030 } 1031 { 1032 name = "gnome_keyring"; 1033 enable = cfg.enableGnomeKeyring; 1034 control = "optional"; 1035 modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; 1036 } 1037 { 1038 name = "intune"; 1039 enable = config.services.intune.enable; 1040 control = "optional"; 1041 modulePath = "${pkgs.intune-portal}/lib/security/pam_intune.so"; 1042 } 1043 { 1044 name = "gnupg"; 1045 enable = cfg.gnupg.enable; 1046 control = "optional"; 1047 modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; 1048 settings = { 1049 store-only = cfg.gnupg.storeOnly; 1050 }; 1051 } 1052 { 1053 name = "faildelay"; 1054 enable = cfg.failDelay.enable; 1055 control = "optional"; 1056 modulePath = "${package}/lib/security/pam_faildelay.so"; 1057 settings = { 1058 inherit (cfg.failDelay) delay; 1059 }; 1060 } 1061 { 1062 name = "google_authenticator"; 1063 enable = cfg.googleAuthenticator.enable; 1064 control = "required"; 1065 modulePath = "${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so"; 1066 settings = { 1067 no_increment_hotp = true; 1068 forward_pass = cfg.googleAuthenticator.forwardPass; 1069 nullok = cfg.googleAuthenticator.allowNullOTP; 1070 }; 1071 } 1072 { 1073 name = "duo"; 1074 enable = cfg.duoSecurity.enable; 1075 control = "required"; 1076 modulePath = "${pkgs.duo-unix}/lib/security/pam_duo.so"; 1077 } 1078 ] 1079 ) 1080 ++ [ 1081 { 1082 name = "systemd_home"; 1083 enable = config.services.homed.enable; 1084 control = "sufficient"; 1085 modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; 1086 } 1087 { 1088 name = "unix"; 1089 enable = cfg.unixAuth; 1090 control = "sufficient"; 1091 modulePath = "${package}/lib/security/pam_unix.so"; 1092 settings = { 1093 nullok = cfg.allowNullPassword; 1094 inherit (cfg) nodelay; 1095 likeauth = true; 1096 try_first_pass = true; 1097 }; 1098 } 1099 { 1100 name = "otpw"; 1101 enable = cfg.otpwAuth; 1102 control = "sufficient"; 1103 modulePath = "${pkgs.otpw}/lib/security/pam_otpw.so"; 1104 } 1105 { 1106 name = "ldap"; 1107 enable = use_ldap; 1108 control = "sufficient"; 1109 modulePath = "${pam_ldap}/lib/security/pam_ldap.so"; 1110 settings = { 1111 use_first_pass = true; 1112 }; 1113 } 1114 { 1115 name = "kanidm"; 1116 enable = config.services.kanidm.enablePam; 1117 control = "sufficient"; 1118 modulePath = "${config.services.kanidm.package}/lib/pam_kanidm.so"; 1119 settings = { 1120 ignore_unknown_user = true; 1121 use_first_pass = true; 1122 }; 1123 } 1124 { 1125 name = "sss"; 1126 enable = config.services.sssd.enable; 1127 control = "sufficient"; 1128 modulePath = "${pkgs.sssd}/lib/security/pam_sss.so"; 1129 settings = { 1130 use_first_pass = true; 1131 }; 1132 } 1133 { 1134 name = "krb5"; 1135 enable = config.security.pam.krb5.enable; 1136 control = "[default=ignore success=1 service_err=reset]"; 1137 modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; 1138 settings = { 1139 use_first_pass = true; 1140 }; 1141 } 1142 { 1143 name = "ccreds-validate"; 1144 enable = config.security.pam.krb5.enable; 1145 control = "[default=die success=done]"; 1146 modulePath = "${pam_ccreds}/lib/security/pam_ccreds.so"; 1147 settings = { 1148 action = "validate"; 1149 use_first_pass = true; 1150 }; 1151 } 1152 { 1153 name = "ccreds-store"; 1154 enable = config.security.pam.krb5.enable; 1155 control = "sufficient"; 1156 modulePath = "${pam_ccreds}/lib/security/pam_ccreds.so"; 1157 settings = { 1158 action = "store"; 1159 use_first_pass = true; 1160 }; 1161 } 1162 { 1163 name = "deny"; 1164 control = "required"; 1165 modulePath = "${package}/lib/security/pam_deny.so"; 1166 } 1167 ] 1168 ); 1169 1170 password = autoOrderRules [ 1171 { 1172 name = "systemd_home"; 1173 enable = config.services.homed.enable; 1174 control = "sufficient"; 1175 modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; 1176 } 1177 { 1178 name = "unix"; 1179 control = "sufficient"; 1180 modulePath = "${package}/lib/security/pam_unix.so"; 1181 settings = { 1182 nullok = true; 1183 yescrypt = true; 1184 }; 1185 } 1186 { 1187 name = "ecryptfs"; 1188 enable = config.security.pam.enableEcryptfs; 1189 control = "optional"; 1190 modulePath = "${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"; 1191 } 1192 { 1193 name = "fscrypt"; 1194 enable = config.security.pam.enableFscrypt; 1195 control = "optional"; 1196 modulePath = "${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so"; 1197 } 1198 { 1199 name = "zfs_key"; 1200 enable = cfg.zfs; 1201 control = "optional"; 1202 modulePath = "${config.boot.zfs.package}/lib/security/pam_zfs_key.so"; 1203 settings = { 1204 inherit (config.security.pam.zfs) homes; 1205 }; 1206 } 1207 { 1208 name = "mount"; 1209 enable = cfg.pamMount; 1210 control = "optional"; 1211 modulePath = "${pkgs.pam_mount}/lib/security/pam_mount.so"; 1212 } 1213 { 1214 name = "ldap"; 1215 enable = use_ldap; 1216 control = "sufficient"; 1217 modulePath = "${pam_ldap}/lib/security/pam_ldap.so"; 1218 } 1219 { 1220 name = "mysql"; 1221 enable = cfg.mysqlAuth; 1222 control = "sufficient"; 1223 modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; 1224 settings = { 1225 config_file = "/etc/security/pam_mysql.conf"; 1226 }; 1227 } 1228 { 1229 name = "kanidm"; 1230 enable = config.services.kanidm.enablePam; 1231 control = "sufficient"; 1232 modulePath = "${config.services.kanidm.package}/lib/pam_kanidm.so"; 1233 } 1234 { 1235 name = "sss"; 1236 enable = config.services.sssd.enable; 1237 control = "sufficient"; 1238 modulePath = "${pkgs.sssd}/lib/security/pam_sss.so"; 1239 } 1240 { 1241 name = "krb5"; 1242 enable = config.security.pam.krb5.enable; 1243 control = "sufficient"; 1244 modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; 1245 settings = { 1246 use_first_pass = true; 1247 }; 1248 } 1249 { 1250 name = "gnome_keyring"; 1251 enable = cfg.enableGnomeKeyring; 1252 control = "optional"; 1253 modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; 1254 settings = { 1255 use_authtok = true; 1256 }; 1257 } 1258 ]; 1259 1260 session = autoOrderRules [ 1261 { 1262 name = "env"; 1263 enable = cfg.setEnvironment; 1264 control = "required"; 1265 modulePath = "${package}/lib/security/pam_env.so"; 1266 settings = { 1267 conffile = "/etc/pam/environment"; 1268 readenv = 0; 1269 }; 1270 } 1271 { 1272 name = "unix"; 1273 control = "required"; 1274 modulePath = "${package}/lib/security/pam_unix.so"; 1275 } 1276 { 1277 name = "loginuid"; 1278 enable = cfg.setLoginUid; 1279 control = if config.boot.isContainer then "optional" else "required"; 1280 modulePath = "${package}/lib/security/pam_loginuid.so"; 1281 } 1282 { 1283 name = "tty_audit"; 1284 enable = cfg.ttyAudit.enable; 1285 control = "required"; 1286 modulePath = "${package}/lib/security/pam_tty_audit.so"; 1287 settings = { 1288 open_only = cfg.ttyAudit.openOnly; 1289 enable = cfg.ttyAudit.enablePattern; 1290 disable = cfg.ttyAudit.disablePattern; 1291 }; 1292 } 1293 { 1294 name = "systemd_home"; 1295 enable = config.services.homed.enable; 1296 control = "required"; 1297 modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; 1298 } 1299 { 1300 name = "mkhomedir"; 1301 enable = cfg.makeHomeDir; 1302 control = "required"; 1303 modulePath = "${package}/lib/security/pam_mkhomedir.so"; 1304 settings = { 1305 silent = true; 1306 skel = config.security.pam.makeHomeDir.skelDirectory; 1307 inherit (config.security.pam.makeHomeDir) umask; 1308 }; 1309 } 1310 { 1311 name = "lastlog"; 1312 enable = cfg.updateWtmp; 1313 control = "required"; 1314 modulePath = "${pkgs.util-linux.lastlog}/lib/security/pam_lastlog2.so"; 1315 settings = { 1316 silent = true; 1317 }; 1318 } 1319 { 1320 name = "ecryptfs"; 1321 enable = config.security.pam.enableEcryptfs; 1322 control = "optional"; 1323 modulePath = "${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"; 1324 } 1325 # Work around https://github.com/systemd/systemd/issues/8598 1326 # Skips the pam_fscrypt module for systemd-user sessions which do not have a password 1327 # anyways. 1328 # See also https://github.com/google/fscrypt/issues/95 1329 { 1330 name = "fscrypt-skip-systemd"; 1331 enable = config.security.pam.enableFscrypt; 1332 control = "[success=1 default=ignore]"; 1333 modulePath = "${package}/lib/security/pam_succeed_if.so"; 1334 args = [ 1335 "service" 1336 "=" 1337 "systemd-user" 1338 ]; 1339 } 1340 { 1341 name = "fscrypt"; 1342 enable = config.security.pam.enableFscrypt; 1343 control = "optional"; 1344 modulePath = "${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so"; 1345 } 1346 { 1347 name = "zfs_key-skip-systemd"; 1348 enable = cfg.zfs; 1349 control = "[success=1 default=ignore]"; 1350 modulePath = "${package}/lib/security/pam_succeed_if.so"; 1351 args = [ 1352 "service" 1353 "=" 1354 "systemd-user" 1355 ]; 1356 } 1357 { 1358 name = "zfs_key"; 1359 enable = cfg.zfs; 1360 control = "optional"; 1361 modulePath = "${config.boot.zfs.package}/lib/security/pam_zfs_key.so"; 1362 settings = { 1363 inherit (config.security.pam.zfs) homes; 1364 nounmount = config.security.pam.zfs.noUnmount; 1365 }; 1366 } 1367 { 1368 name = "mount"; 1369 enable = cfg.pamMount; 1370 control = "optional"; 1371 modulePath = "${pkgs.pam_mount}/lib/security/pam_mount.so"; 1372 settings = { 1373 disable_interactive = true; 1374 }; 1375 } 1376 { 1377 name = "ldap"; 1378 enable = use_ldap; 1379 control = "optional"; 1380 modulePath = "${pam_ldap}/lib/security/pam_ldap.so"; 1381 } 1382 { 1383 name = "mysql"; 1384 enable = cfg.mysqlAuth; 1385 control = "optional"; 1386 modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; 1387 settings = { 1388 config_file = "/etc/security/pam_mysql.conf"; 1389 }; 1390 } 1391 { 1392 name = "kanidm"; 1393 enable = config.services.kanidm.enablePam; 1394 control = "optional"; 1395 modulePath = "${config.services.kanidm.package}/lib/pam_kanidm.so"; 1396 } 1397 { 1398 name = "sss"; 1399 enable = config.services.sssd.enable; 1400 control = "optional"; 1401 modulePath = "${pkgs.sssd}/lib/security/pam_sss.so"; 1402 } 1403 { 1404 name = "krb5"; 1405 enable = config.security.pam.krb5.enable; 1406 control = "optional"; 1407 modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; 1408 } 1409 { 1410 name = "otpw"; 1411 enable = cfg.otpwAuth; 1412 control = "optional"; 1413 modulePath = "${pkgs.otpw}/lib/security/pam_otpw.so"; 1414 } 1415 { 1416 name = "systemd"; 1417 enable = cfg.startSession; 1418 control = "optional"; 1419 modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; 1420 } 1421 { 1422 name = "xauth"; 1423 enable = cfg.forwardXAuth; 1424 control = "optional"; 1425 modulePath = "${package}/lib/security/pam_xauth.so"; 1426 settings = { 1427 xauthpath = "${pkgs.xorg.xauth}/bin/xauth"; 1428 systemuser = 99; 1429 }; 1430 } 1431 { 1432 name = "limits"; 1433 enable = cfg.limits != [ ]; 1434 control = "required"; 1435 modulePath = "${package}/lib/security/pam_limits.so"; 1436 settings = { 1437 conf = "${makeLimitsConf cfg.limits}"; 1438 }; 1439 } 1440 { 1441 name = "motd"; 1442 enable = cfg.showMotd && (config.users.motd != "" || config.users.motdFile != null); 1443 control = "optional"; 1444 modulePath = "${package}/lib/security/pam_motd.so"; 1445 settings = { 1446 inherit motd; 1447 }; 1448 } 1449 { 1450 name = "apparmor"; 1451 enable = cfg.enableAppArmor && config.security.apparmor.enable; 1452 control = "optional"; 1453 modulePath = "${pkgs.apparmor-pam}/lib/security/pam_apparmor.so"; 1454 settings = { 1455 order = "user,group,default"; 1456 debug = true; 1457 }; 1458 } 1459 { 1460 name = "kwallet"; 1461 enable = cfg.kwallet.enable; 1462 control = "optional"; 1463 modulePath = "${cfg.kwallet.package}/lib/security/pam_kwallet5.so"; 1464 settings = lib.mkIf cfg.kwallet.forceRun { force_run = true; }; 1465 } 1466 { 1467 name = "gnome_keyring"; 1468 enable = cfg.enableGnomeKeyring; 1469 control = "optional"; 1470 modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; 1471 settings = { 1472 auto_start = true; 1473 }; 1474 } 1475 { 1476 name = "gnupg"; 1477 enable = cfg.gnupg.enable; 1478 control = "optional"; 1479 modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; 1480 settings = { 1481 no-autostart = cfg.gnupg.noAutostart; 1482 }; 1483 } 1484 { 1485 name = "intune"; 1486 enable = config.services.intune.enable; 1487 control = "optional"; 1488 modulePath = "${pkgs.intune-portal}/lib/security/pam_intune.so"; 1489 } 1490 ]; 1491 }; 1492 }; 1493 1494 }; 1495 1496 inherit (pkgs) pam_krb5 pam_ccreds; 1497 1498 use_ldap = (config.users.ldap.enable && config.users.ldap.loginPam); 1499 pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap; 1500 1501 # Create a limits.conf(5) file. 1502 makeLimitsConf = 1503 limits: 1504 pkgs.writeText "limits.conf" ( 1505 lib.concatMapStrings ( 1506 { 1507 domain, 1508 type, 1509 item, 1510 value, 1511 }: 1512 "${domain} ${type} ${item} ${toString value}\n" 1513 ) limits 1514 ); 1515 1516 limitsType = 1517 with lib.types; 1518 listOf ( 1519 submodule ( 1520 { ... }: 1521 { 1522 options = { 1523 domain = lib.mkOption { 1524 description = "Username, groupname, or wildcard this limit applies to"; 1525 example = "@wheel"; 1526 type = str; 1527 }; 1528 1529 type = lib.mkOption { 1530 description = "Type of this limit"; 1531 type = enum [ 1532 "-" 1533 "hard" 1534 "soft" 1535 ]; 1536 default = "-"; 1537 }; 1538 1539 item = lib.mkOption { 1540 description = "Item this limit applies to"; 1541 type = enum [ 1542 "core" 1543 "data" 1544 "fsize" 1545 "memlock" 1546 "nofile" 1547 "rss" 1548 "stack" 1549 "cpu" 1550 "nproc" 1551 "as" 1552 "maxlogins" 1553 "maxsyslogins" 1554 "priority" 1555 "locks" 1556 "sigpending" 1557 "msgqueue" 1558 "nice" 1559 "rtprio" 1560 ]; 1561 }; 1562 1563 value = lib.mkOption { 1564 description = "Value of this limit"; 1565 type = oneOf [ 1566 str 1567 int 1568 ]; 1569 }; 1570 }; 1571 } 1572 ) 1573 ); 1574 1575 motd = 1576 if config.users.motdFile == null then 1577 pkgs.writeText "motd" config.users.motd 1578 else 1579 config.users.motdFile; 1580 1581 makePAMService = name: service: { 1582 name = "pam.d/${name}"; 1583 value.source = pkgs.writeText "${name}.pam" service.text; 1584 }; 1585 1586 optionalSudoConfigForSSHAgentAuth = 1587 lib.optionalString (config.security.pam.sshAgentAuth.enable || config.security.pam.rssh.enable) 1588 '' 1589 # Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so and libpam_rssh.so can do their magic. 1590 Defaults env_keep+=SSH_AUTH_SOCK 1591 ''; 1592 1593 enabledServices = lib.filterAttrs (name: svc: svc.enable) config.security.pam.services; 1594 1595in 1596 1597{ 1598 1599 meta.maintainers = [ lib.maintainers.majiir ]; 1600 1601 imports = [ 1602 (lib.mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ]) 1603 (lib.mkRenamedOptionModule 1604 [ "security" "pam" "enableSSHAgentAuth" ] 1605 [ "security" "pam" "sshAgentAuth" "enable" ] 1606 ) 1607 (lib.mkRenamedOptionModule 1608 [ "security" "pam" "u2f" "authFile" ] 1609 [ "security" "pam" "u2f" "settings" "authfile" ] 1610 ) 1611 (lib.mkRenamedOptionModule 1612 [ "security" "pam" "u2f" "appId" ] 1613 [ "security" "pam" "u2f" "settings" "appid" ] 1614 ) 1615 (lib.mkRenamedOptionModule 1616 [ "security" "pam" "u2f" "origin" ] 1617 [ "security" "pam" "u2f" "settings" "origin" ] 1618 ) 1619 (lib.mkRenamedOptionModule 1620 [ "security" "pam" "u2f" "debug" ] 1621 [ "security" "pam" "u2f" "settings" "debug" ] 1622 ) 1623 (lib.mkRenamedOptionModule 1624 [ "security" "pam" "u2f" "interactive" ] 1625 [ "security" "pam" "u2f" "settings" "interactive" ] 1626 ) 1627 (lib.mkRenamedOptionModule 1628 [ "security" "pam" "u2f" "cue" ] 1629 [ "security" "pam" "u2f" "settings" "cue" ] 1630 ) 1631 ]; 1632 1633 ###### interface 1634 1635 options = { 1636 1637 security.pam.package = lib.mkPackageOption pkgs "pam" { }; 1638 1639 security.pam.loginLimits = lib.mkOption { 1640 default = [ ]; 1641 type = limitsType; 1642 example = [ 1643 { 1644 domain = "ftp"; 1645 type = "hard"; 1646 item = "nproc"; 1647 value = "0"; 1648 } 1649 { 1650 domain = "@student"; 1651 type = "-"; 1652 item = "maxlogins"; 1653 value = "4"; 1654 } 1655 ]; 1656 1657 description = '' 1658 Define resource limits that should apply to users or groups. 1659 Each item in the list should be an attribute set with a 1660 {var}`domain`, {var}`type`, 1661 {var}`item`, and {var}`value` 1662 attribute. The syntax and semantics of these attributes 1663 must be that described in {manpage}`limits.conf(5)`. 1664 1665 Note that these limits do not apply to systemd services, 1666 whose limits can be changed via {option}`systemd.settings.Manager` 1667 instead. 1668 ''; 1669 }; 1670 1671 security.pam.services = lib.mkOption { 1672 default = { }; 1673 type = with lib.types; attrsOf (submodule pamOpts); 1674 description = '' 1675 This option defines the PAM services. A service typically 1676 corresponds to a program that uses PAM, 1677 e.g. {command}`login` or {command}`passwd`. 1678 Each attribute of this set defines a PAM service, with the attribute name 1679 defining the name of the service. 1680 ''; 1681 }; 1682 1683 security.pam.makeHomeDir.skelDirectory = lib.mkOption { 1684 type = lib.types.str; 1685 default = "/var/empty"; 1686 example = "/etc/skel"; 1687 description = '' 1688 Path to skeleton directory whose contents are copied to home 1689 directories newly created by `pam_mkhomedir`. 1690 ''; 1691 }; 1692 1693 security.pam.makeHomeDir.umask = lib.mkOption { 1694 type = lib.types.str; 1695 default = "0077"; 1696 example = "0022"; 1697 description = '' 1698 The user file mode creation mask to use on home directories 1699 newly created by `pam_mkhomedir`. 1700 ''; 1701 }; 1702 1703 security.pam.sshAgentAuth = { 1704 enable = lib.mkEnableOption '' 1705 authenticating using a signature performed by the ssh-agent. 1706 This allows using SSH keys exclusively, instead of passwords, for instance on remote machines 1707 ''; 1708 1709 authorizedKeysFiles = lib.mkOption { 1710 type = with lib.types; listOf str; 1711 description = '' 1712 A list of paths to files in OpenSSH's `authorized_keys` format, containing 1713 the keys that will be trusted by the `pam_ssh_agent_auth` module. 1714 1715 The following patterns are expanded when interpreting the path: 1716 - `%f` and `%H` respectively expand to the fully-qualified and short hostname ; 1717 - `%u` expands to the username ; 1718 - `~` or `%h` expands to the user's home directory. 1719 1720 ::: {.note} 1721 Specifying user-writeable files here result in an insecure configuration: a malicious process 1722 can then edit such an authorized_keys file and bypass the ssh-agent-based authentication. 1723 1724 See [issue #31611](https://github.com/NixOS/nixpkgs/issues/31611) 1725 ::: 1726 ''; 1727 default = [ "/etc/ssh/authorized_keys.d/%u" ]; 1728 }; 1729 }; 1730 1731 security.pam.rssh = { 1732 enable = lib.mkEnableOption "authenticating using a signature performed by the ssh-agent"; 1733 1734 settings = lib.mkOption { 1735 type = lib.types.submodule { 1736 freeformType = moduleSettingsType; 1737 options = { 1738 auth_key_file = lib.mkOption { 1739 type = with lib.types; nullOr nonEmptyStr; 1740 description = '' 1741 Path to file with trusted public keys in OpenSSH's `authorized_keys` format. The following 1742 variables are expanded to the respective PAM items: 1743 1744 - `service`: `PAM_SERVICE`, the service name, 1745 - `user`: `PAM_USER`, the username of the entity under whose identity service will be given, 1746 - `tty`: `PAM_TTY`, the terminal name, 1747 - `rhost`: `PAM_RHOST`, the requesting hostname, and 1748 - `ruser`: `PAM_RUSER`, the requesting entity. 1749 1750 These PAM items are explained in {manpage}`pam_get_item(3)`. 1751 1752 Variables may be specified as `$var`, `''${var}` or `''${var:defaultValue}`. 1753 1754 ::: {.note} 1755 Specifying user-writeable files here results in an insecure configuration: a malicious process 1756 can then edit such an `authorized_keys` file and bypass the ssh-agent-based authentication. 1757 1758 This option is ignored if {option}`security.pam.rssh.settings.authorized_keys_command` is set. 1759 1760 If both this option and {option}`security.pam.rssh.settings.authorized_keys_command` are unset, 1761 the keys will be read from `''${HOME}/.ssh/authorized_keys`, which should be considered 1762 insecure. 1763 ''; 1764 default = "/etc/ssh/authorized_keys.d/$ruser"; 1765 }; 1766 }; 1767 }; 1768 1769 default = { }; 1770 description = '' 1771 Options to pass to the pam_rssh module. Refer to 1772 <https://github.com/z4yx/pam_rssh/blob/main/README.md#optional-arguments> 1773 for supported values. 1774 1775 ${moduleSettingsDescription} 1776 ''; 1777 }; 1778 }; 1779 1780 security.pam.enableOTPW = lib.mkEnableOption "the OTPW (one-time password) PAM module"; 1781 1782 security.pam.dp9ik = { 1783 enable = lib.mkEnableOption '' 1784 the dp9ik pam module provided by tlsclient. 1785 1786 If set, users can be authenticated against the 9front 1787 authentication server given in {option}`security.pam.dp9ik.authserver` 1788 ''; 1789 control = lib.mkOption { 1790 default = "sufficient"; 1791 type = lib.types.str; 1792 description = '' 1793 This option sets the pam "control" used for this module. 1794 ''; 1795 }; 1796 authserver = lib.mkOption { 1797 default = null; 1798 type = with lib.types; nullOr str; 1799 description = '' 1800 This controls the hostname for the 9front authentication server 1801 that users will be authenticated against. 1802 ''; 1803 }; 1804 }; 1805 1806 security.pam.krb5 = { 1807 enable = lib.mkOption { 1808 default = config.security.krb5.enable; 1809 defaultText = lib.literalExpression "config.security.krb5.enable"; 1810 type = lib.types.bool; 1811 description = '' 1812 Enables Kerberos PAM modules (`pam-krb5`, 1813 `pam-ccreds`). 1814 1815 If set, users can authenticate with their Kerberos password. 1816 This requires a valid Kerberos configuration 1817 (`security.krb5.enable` should be set to `true`). 1818 1819 Note that the Kerberos PAM modules are not necessary when using SSS 1820 to handle Kerberos authentication. 1821 ''; 1822 }; 1823 }; 1824 1825 security.pam.p11 = { 1826 enable = lib.mkOption { 1827 default = false; 1828 type = lib.types.bool; 1829 description = '' 1830 Enables P11 PAM (`pam_p11`) module. 1831 1832 If set, users can log in with SSH keys and PKCS#11 tokens. 1833 1834 More information can be found [here](https://github.com/OpenSC/pam_p11). 1835 ''; 1836 }; 1837 1838 control = lib.mkOption { 1839 default = "sufficient"; 1840 type = lib.types.enum [ 1841 "required" 1842 "requisite" 1843 "sufficient" 1844 "optional" 1845 ]; 1846 description = '' 1847 This option sets pam "control". 1848 If you want to have multi factor authentication, use "required". 1849 If you want to use the PKCS#11 device instead of the regular password, 1850 use "sufficient". 1851 1852 Read 1853 {manpage}`pam.conf(5)` 1854 for better understanding of this option. 1855 ''; 1856 }; 1857 }; 1858 1859 security.pam.u2f = { 1860 enable = lib.mkOption { 1861 default = false; 1862 type = lib.types.bool; 1863 description = '' 1864 Enables U2F PAM (`pam-u2f`) module. 1865 1866 If set, users listed in 1867 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or 1868 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is 1869 not set) are able to log in with the associated U2F key. The path can 1870 be changed using {option}`security.pam.u2f.authFile` option. 1871 1872 File format is: 1873 ``` 1874 <username1>:<KeyHandle1>,<UserKey1>,<CoseType1>,<Options1>:<KeyHandle2>,<UserKey2>,<CoseType2>,<Options2>:... 1875 <username2>:<KeyHandle1>,<UserKey1>,<CoseType1>,<Options1>:<KeyHandle2>,<UserKey2>,<CoseType2>,<Options2>:... 1876 ``` 1877 This file can be generated using {command}`pamu2fcfg` command. 1878 1879 More information can be found [here](https://developers.yubico.com/pam-u2f/). 1880 ''; 1881 }; 1882 1883 control = lib.mkOption { 1884 default = "sufficient"; 1885 type = lib.types.enum [ 1886 "required" 1887 "requisite" 1888 "sufficient" 1889 "optional" 1890 ]; 1891 description = '' 1892 This option sets pam "control". 1893 If you want to have multi factor authentication, use "required". 1894 If you want to use U2F device instead of regular password, use "sufficient". 1895 1896 Read 1897 {manpage}`pam.conf(5)` 1898 for better understanding of this option. 1899 ''; 1900 }; 1901 1902 settings = lib.mkOption { 1903 type = lib.types.submodule { 1904 freeformType = moduleSettingsType; 1905 1906 options = { 1907 authfile = lib.mkOption { 1908 default = null; 1909 type = with lib.types; nullOr path; 1910 description = '' 1911 By default `pam-u2f` module reads the keys from 1912 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or 1913 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is 1914 not set). 1915 1916 If you want to change auth file locations or centralize database (for 1917 example use {file}`/etc/u2f-mappings`) you can set this 1918 option. 1919 1920 File format is: 1921 `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key` 1922 This file can be generated using {command}`pamu2fcfg` command. 1923 1924 More information can be found [here](https://developers.yubico.com/pam-u2f/). 1925 ''; 1926 }; 1927 1928 appid = lib.mkOption { 1929 default = null; 1930 type = with lib.types; nullOr str; 1931 description = '' 1932 By default `pam-u2f` module sets the application 1933 ID to `pam://$HOSTNAME`. 1934 1935 When using {command}`pamu2fcfg`, you can specify your 1936 application ID with the `-i` flag. 1937 1938 More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html) 1939 ''; 1940 }; 1941 1942 origin = lib.mkOption { 1943 default = null; 1944 type = with lib.types; nullOr str; 1945 description = '' 1946 By default `pam-u2f` module sets the origin 1947 to `pam://$HOSTNAME`. 1948 Setting origin to an host independent value will allow you to 1949 reuse credentials across machines 1950 1951 When using {command}`pamu2fcfg`, you can specify your 1952 application ID with the `-o` flag. 1953 1954 More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html) 1955 ''; 1956 }; 1957 1958 debug = lib.mkOption { 1959 default = false; 1960 type = lib.types.bool; 1961 description = '' 1962 Debug output to stderr. 1963 ''; 1964 }; 1965 1966 interactive = lib.mkOption { 1967 default = false; 1968 type = lib.types.bool; 1969 description = '' 1970 Set to prompt a message and wait before testing the presence of a U2F device. 1971 Recommended if your device doesnt have a tactile trigger. 1972 ''; 1973 }; 1974 1975 cue = lib.mkOption { 1976 default = false; 1977 type = lib.types.bool; 1978 description = '' 1979 By default `pam-u2f` module does not inform user 1980 that he needs to use the u2f device, it just waits without a prompt. 1981 1982 If you set this option to `true`, 1983 `cue` option is added to `pam-u2f` 1984 module and reminder message will be displayed. 1985 ''; 1986 }; 1987 }; 1988 }; 1989 default = { }; 1990 example = { 1991 authfile = "/etc/u2f_keys"; 1992 authpending_file = ""; 1993 userpresence = 0; 1994 pinverification = 1; 1995 }; 1996 description = '' 1997 Options to pass to the PAM module. 1998 1999 ${moduleSettingsDescription} 2000 ''; 2001 }; 2002 }; 2003 2004 security.pam.ussh = { 2005 enable = lib.mkOption { 2006 default = false; 2007 type = lib.types.bool; 2008 description = '' 2009 Enables Uber's USSH PAM (`pam-ussh`) module. 2010 2011 This is similar to `pam-ssh-agent`, except that 2012 the presence of a CA-signed SSH key with a valid principal is checked 2013 instead. 2014 2015 Note that this module must both be enabled using this option and on a 2016 per-PAM-service level as well (using `usshAuth`). 2017 2018 More information can be found [here](https://github.com/uber/pam-ussh). 2019 ''; 2020 }; 2021 2022 caFile = lib.mkOption { 2023 default = null; 2024 type = with lib.types; nullOr path; 2025 description = '' 2026 By default `pam-ussh` reads the trusted user CA keys 2027 from {file}`/etc/ssh/trusted_user_ca`. 2028 2029 This should be set the same as your `TrustedUserCAKeys` 2030 option for sshd. 2031 ''; 2032 }; 2033 2034 authorizedPrincipals = lib.mkOption { 2035 default = null; 2036 type = with lib.types; nullOr commas; 2037 description = '' 2038 Comma-separated list of authorized principals to permit; if the user 2039 presents a certificate with one of these principals, then they will be 2040 authorized. 2041 2042 Note that `pam-ussh` also requires that the certificate 2043 contain a principal matching the user's username. The principals from 2044 this list are in addition to those principals. 2045 2046 Mutually exclusive with `authorizedPrincipalsFile`. 2047 ''; 2048 }; 2049 2050 authorizedPrincipalsFile = lib.mkOption { 2051 default = null; 2052 type = with lib.types; nullOr path; 2053 description = '' 2054 Path to a list of principals; if the user presents a certificate with 2055 one of these principals, then they will be authorized. 2056 2057 Note that `pam-ussh` also requires that the certificate 2058 contain a principal matching the user's username. The principals from 2059 this file are in addition to those principals. 2060 2061 Mutually exclusive with `authorizedPrincipals`. 2062 ''; 2063 }; 2064 2065 group = lib.mkOption { 2066 default = null; 2067 type = with lib.types; nullOr str; 2068 description = '' 2069 If set, then the authenticating user must be a member of this group 2070 to use this module. 2071 ''; 2072 }; 2073 2074 control = lib.mkOption { 2075 default = "sufficient"; 2076 type = lib.types.enum [ 2077 "required" 2078 "requisite" 2079 "sufficient" 2080 "optional" 2081 ]; 2082 description = '' 2083 This option sets pam "control". 2084 If you want to have multi factor authentication, use "required". 2085 If you want to use the SSH certificate instead of the regular password, 2086 use "sufficient". 2087 2088 Read 2089 {manpage}`pam.conf(5)` 2090 for better understanding of this option. 2091 ''; 2092 }; 2093 }; 2094 2095 security.pam.yubico = { 2096 enable = lib.mkOption { 2097 default = false; 2098 type = lib.types.bool; 2099 description = '' 2100 Enables Yubico PAM (`yubico-pam`) module. 2101 2102 If set, users listed in 2103 {file}`~/.yubico/authorized_yubikeys` 2104 are able to log in with the associated Yubikey tokens. 2105 2106 The file must have only one line: 2107 `username:yubikey_token_id1:yubikey_token_id2` 2108 More information can be found [here](https://developers.yubico.com/yubico-pam/). 2109 ''; 2110 }; 2111 control = lib.mkOption { 2112 default = "sufficient"; 2113 type = lib.types.enum [ 2114 "required" 2115 "requisite" 2116 "sufficient" 2117 "optional" 2118 ]; 2119 description = '' 2120 This option sets pam "control". 2121 If you want to have multi factor authentication, use "required". 2122 If you want to use Yubikey instead of regular password, use "sufficient". 2123 2124 Read 2125 {manpage}`pam.conf(5)` 2126 for better understanding of this option. 2127 ''; 2128 }; 2129 id = lib.mkOption { 2130 example = "42"; 2131 type = lib.types.str; 2132 description = "client id"; 2133 }; 2134 2135 debug = lib.mkOption { 2136 default = false; 2137 type = lib.types.bool; 2138 description = '' 2139 Debug output to stderr. 2140 ''; 2141 }; 2142 mode = lib.mkOption { 2143 default = "client"; 2144 type = lib.types.enum [ 2145 "client" 2146 "challenge-response" 2147 ]; 2148 description = '' 2149 Mode of operation. 2150 2151 Use "client" for online validation with a YubiKey validation service such as 2152 the YubiCloud. 2153 2154 Use "challenge-response" for offline validation using YubiKeys with HMAC-SHA-1 2155 Challenge-Response configurations. See the man-page {manpage}`ykpamcfg(1)` for further 2156 details on how to configure offline Challenge-Response validation. 2157 2158 More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html). 2159 ''; 2160 }; 2161 challengeResponsePath = lib.mkOption { 2162 default = null; 2163 type = lib.types.nullOr lib.types.path; 2164 description = '' 2165 If not null, set the path used by yubico pam module where the challenge expected response is stored. 2166 2167 More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html). 2168 ''; 2169 }; 2170 }; 2171 2172 security.pam.zfs = { 2173 enable = lib.mkOption { 2174 default = false; 2175 type = lib.types.bool; 2176 description = '' 2177 Enable unlocking and mounting of encrypted ZFS home dataset at login. 2178 ''; 2179 }; 2180 2181 homes = lib.mkOption { 2182 example = "rpool/home"; 2183 default = "rpool/home"; 2184 type = lib.types.str; 2185 description = '' 2186 Prefix of home datasets. This value will be concatenated with 2187 `"/" + <username>` in order to determine the home dataset to unlock. 2188 ''; 2189 }; 2190 2191 noUnmount = lib.mkOption { 2192 default = false; 2193 type = lib.types.bool; 2194 description = '' 2195 Do not unmount home dataset on logout. 2196 ''; 2197 }; 2198 }; 2199 2200 security.pam.enableEcryptfs = lib.mkEnableOption "eCryptfs PAM module (mounting ecryptfs home directory on login)"; 2201 security.pam.enableFscrypt = lib.mkEnableOption '' 2202 fscrypt, to automatically unlock directories with the user's login password. 2203 2204 This also enables a service at security.pam.services.fscrypt which is used by 2205 fscrypt to verify the user's password when setting up a new protector. If you 2206 use something other than pam_unix to verify user passwords, please remember to 2207 adjust this PAM service 2208 ''; 2209 2210 users.motd = lib.mkOption { 2211 default = ""; 2212 example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178."; 2213 type = lib.types.lines; 2214 description = "Message of the day shown to users when they log in."; 2215 }; 2216 2217 users.motdFile = lib.mkOption { 2218 default = null; 2219 example = "/etc/motd"; 2220 type = lib.types.nullOr lib.types.path; 2221 description = "A file containing the message of the day shown to users when they log in."; 2222 }; 2223 }; 2224 2225 ###### implementation 2226 2227 config = { 2228 assertions = [ 2229 { 2230 assertion = config.users.motd == "" || config.users.motdFile == null; 2231 message = '' 2232 Only one of users.motd and users.motdFile can be set. 2233 ''; 2234 } 2235 { 2236 assertion = config.security.pam.zfs.enable -> config.boot.zfs.enabled; 2237 message = '' 2238 `security.pam.zfs.enable` requires enabling ZFS (`boot.zfs.enabled`). 2239 ''; 2240 } 2241 { 2242 assertion = with config.security.pam.sshAgentAuth; enable -> authorizedKeysFiles != [ ]; 2243 message = '' 2244 `security.pam.enableSSHAgentAuth` requires `services.openssh.authorizedKeysFiles` to be a non-empty list. 2245 Did you forget to set `services.openssh.enable` ? 2246 ''; 2247 } 2248 { 2249 assertion = 2250 with config.security.pam.rssh; 2251 enable 2252 -> (settings.auth_key_file or null != null || settings.authorized_keys_command or null != null); 2253 message = '' 2254 security.pam.rssh.enable requires either security.pam.rssh.settings.auth_key_file or 2255 security.pam.rssh.settings.authorized_keys_command to be set. 2256 ''; 2257 } 2258 ]; 2259 2260 warnings = 2261 lib.optional 2262 ( 2263 with config.security.pam.sshAgentAuth; 2264 enable && lib.any (s: lib.hasPrefix "%h" s || lib.hasPrefix "~" s) authorizedKeysFiles 2265 ) 2266 '' 2267 security.pam.sshAgentAuth.authorizedKeysFiles contains files in the user's home directory. 2268 2269 Specifying user-writeable files there result in an insecure configuration: 2270 a malicious process can then edit such an authorized_keys file and bypass the ssh-agent-based authentication. 2271 See https://github.com/NixOS/nixpkgs/issues/31611 2272 '' 2273 ++ 2274 lib.optional 2275 ( 2276 with config.security.pam.rssh; 2277 enable && settings.auth_key_file or null != null && settings.authorized_keys_command or null != null 2278 ) 2279 '' 2280 security.pam.rssh.settings.auth_key_file will be ignored as 2281 security.pam.rssh.settings.authorized_keys_command has been specified. 2282 Explictly set the former to null to silence this warning. 2283 ''; 2284 2285 environment.systemPackages = 2286 # Include the PAM modules in the system path mostly for the manpages. 2287 [ package ] 2288 ++ lib.optional config.users.ldap.enable pam_ldap 2289 ++ lib.optional config.services.kanidm.enablePam config.services.kanidm.package 2290 ++ lib.optional config.services.sssd.enable pkgs.sssd 2291 ++ lib.optionals config.security.pam.krb5.enable [ 2292 pam_krb5 2293 pam_ccreds 2294 ] 2295 ++ lib.optionals config.security.pam.enableOTPW [ pkgs.otpw ] 2296 ++ lib.optionals config.security.pam.oath.enable [ pkgs.oath-toolkit ] 2297 ++ lib.optionals config.security.pam.p11.enable [ pkgs.pam_p11 ] 2298 ++ lib.optionals config.security.pam.enableFscrypt [ pkgs.fscrypt-experimental ] 2299 ++ lib.optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ]; 2300 2301 boot.supportedFilesystems = lib.optionals config.security.pam.enableEcryptfs [ "ecryptfs" ]; 2302 2303 security.wrappers = { 2304 unix_chkpwd = { 2305 setuid = true; 2306 owner = "root"; 2307 group = "root"; 2308 source = "${package}/bin/unix_chkpwd"; 2309 }; 2310 }; 2311 2312 environment.etc = lib.mapAttrs' makePAMService enabledServices; 2313 2314 systemd = 2315 lib.optionalAttrs 2316 (lib.any (service: service.updateWtmp) (lib.attrValues config.security.pam.services)) 2317 { 2318 tmpfiles.packages = [ pkgs.util-linux.lastlog ]; # /lib/tmpfiles.d/lastlog2-tmpfiles.conf 2319 services.lastlog2-import = { 2320 enable = true; 2321 wantedBy = [ "default.target" ]; 2322 after = [ 2323 "local-fs.target" 2324 "systemd-tmpfiles-setup.service" 2325 ]; 2326 # TODO: ${pkgs.util-linux.lastlog}/lib/systemd/system/lastlog2-import.service 2327 # uses unpatched /usr/bin/mv, needs to be fixed on staging 2328 # in the meantime, use a service drop-in here 2329 serviceConfig.ExecStartPost = [ 2330 "" 2331 "${lib.getExe' pkgs.coreutils "mv"} /var/log/lastlog /var/log/lastlog.migrated" 2332 ]; 2333 }; 2334 packages = [ pkgs.util-linux.lastlog ]; # lib/systemd/system/lastlog2-import.service 2335 }; 2336 2337 security.pam.services = { 2338 other.text = '' 2339 auth required pam_warn.so 2340 auth required pam_deny.so 2341 account required pam_warn.so 2342 account required pam_deny.so 2343 password required pam_warn.so 2344 password required pam_deny.so 2345 session required pam_warn.so 2346 session required pam_deny.so 2347 ''; 2348 2349 # Most of these should be moved to specific modules. 2350 i3lock.enable = lib.mkDefault config.programs.i3lock.enable; 2351 i3lock-color.enable = lib.mkDefault config.programs.i3lock.enable; 2352 vlock.enable = lib.mkDefault config.console.enable; 2353 xlock.enable = lib.mkDefault config.services.xserver.enable; 2354 xscreensaver.enable = lib.mkDefault config.services.xscreensaver.enable; 2355 2356 runuser = { 2357 rootOK = true; 2358 unixAuth = false; 2359 setEnvironment = false; 2360 }; 2361 2362 /* 2363 FIXME: should runuser -l start a systemd session? Currently 2364 it complains "Cannot create session: Already running in a 2365 session". 2366 */ 2367 runuser-l = { 2368 rootOK = true; 2369 unixAuth = false; 2370 }; 2371 } 2372 // lib.optionalAttrs (config.security.pam.enableFscrypt) { 2373 # Allow fscrypt to verify login passphrase 2374 fscrypt = { }; 2375 }; 2376 2377 security.apparmor.includes."abstractions/pam" = 2378 lib.concatMapStrings (name: "r ${config.environment.etc."pam.d/${name}".source},\n") ( 2379 lib.attrNames enabledServices 2380 ) 2381 + ( 2382 with lib; 2383 pipe enabledServices [ 2384 lib.attrValues 2385 (catAttrs "rules") 2386 (lib.concatMap lib.attrValues) 2387 (lib.concatMap lib.attrValues) 2388 (lib.filter (rule: rule.enable)) 2389 (lib.catAttrs "modulePath") 2390 (map ( 2391 modulePath: 2392 lib.throwIfNot (lib.hasPrefix "/" modulePath) 2393 ''non-absolute PAM modulePath "${modulePath}" is unsupported by apparmor'' 2394 modulePath 2395 )) 2396 lib.unique 2397 (map (module: "mr ${module},")) 2398 concatLines 2399 ] 2400 ); 2401 2402 security.sudo.extraConfig = optionalSudoConfigForSSHAgentAuth; 2403 security.sudo-rs.extraConfig = optionalSudoConfigForSSHAgentAuth; 2404 }; 2405}