Change:
# Samba stuff to the Samba module.  This requires that the PAM # module provides the right hooks. text = mkDefault <del> ('' # Account management. account required pam_unix.so ${optionalString use_ldap "account sufficient ${pam_ldap}/lib/security/pam_ldap.so"} ${optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false) "account sufficient ${pkgs.sssd}/lib/security/pam_sss.so"} ${optionalString (config.services.sssd.enable && cfg.sssdStrictAccess) "account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so"} ${optionalString config.krb5.enable "account sufficient ${pam_krb5}/lib/security/pam_krb5.so"} ${optionalString cfg.googleOsLoginAccountVerification '' </del> <ins> ( '' # Account management. account required pam_unix.so '' + optionalString use_ldap '' account sufficient ${pam_ldap}/lib/security/pam_ldap.so '' + optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false) '' account sufficient ${pkgs.sssd}/lib/security/pam_sss.so '' + optionalString (config.services.sssd.enable && cfg.sssdStrictAccess) '' account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so '' + optionalString config.krb5.enable '' account sufficient ${pam_krb5}/lib/security/pam_krb5.so '' + optionalString cfg.googleOsLoginAccountVerification '' </ins> account [success=ok ignore=ignore default=die] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so account [success=ok default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so <del> ''} # Authentication management. ${optionalString cfg.googleOsLoginAuthentication "auth [success=done perm_denied=bad default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so"} ${optionalString cfg.rootOK "auth sufficient pam_rootok.so"} ${optionalString cfg.requireWheel "auth required pam_wheel.so use_uid"} ${optionalString cfg.logFailures "auth required pam_faillock.so"} ${optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}"} ${let p11 = config.security.pam.p11; in optionalString cfg.p11Auth "auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so"} ${let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth "auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"}"} ${optionalString cfg.usbAuth "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"} ${let oath = config.security.pam.oath; in optionalString cfg.oathAuth "auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}"} ${let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth "auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.challengeResponsePath != null) "chalresp_path=${yubi.challengeResponsePath}"} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"}"} ${optionalString cfg.fprintAuth "auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so"} '' + </del> <ins> '' + '' # Authentication management. '' + optionalString cfg.googleOsLoginAuthentication '' auth [success=done perm_denied=bad default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so '' + optionalString cfg.rootOK '' auth sufficient pam_rootok.so '' + optionalString cfg.requireWheel '' auth required pam_wheel.so use_uid '' + optionalString cfg.logFailures '' auth required pam_faillock.so '' + optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) '' auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles} '' + (let p11 = config.security.pam.p11; in optionalString cfg.p11Auth '' auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so '') + (let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth '' auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"} '') + optionalString cfg.usbAuth '' auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so '' + (let oath = config.security.pam.oath; in optionalString cfg.oathAuth '' auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits} '') + (let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth '' auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.challengeResponsePath != null) "chalresp_path=${yubi.challengeResponsePath}"} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"} '') + optionalString cfg.fprintAuth '' auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so '' + </ins> # Modules in this block require having the password set in PAM_AUTHTOK. # pam_unix is marked as 'sufficient' on NixOS which means nothing will run # after it succeeds. Certain modules need to run after pam_unix

Discussion:
Basically redo after it was reverted in . Steps to reproduce the behavior: any file in /etc/pam.d/ The non-empty lines should be separated by at most one empty line. Add any other context about the problem here. Would you be interested? system: host os: multi-user?: sandbox: version: channels(root): channels(victor): nixpkgs: Maintainer information:
I still think it'd be nice to do. I messed up last time and haven't bothered trying again. Happy to se others giving it a try.
Fair enough, I'll give it a try based on what looks like a good pattern at the bottom of the same file. That said, I have a major hole in my understanding of Nix which I'm hoping someone might help with: how do I build and verify the result of a single file like on its own? Is that possible, or do I have to build another package which depends on it just to see whether it works?
This issue has been mentioned on NixOS Discourse. There might be relevant details there: