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