A Linux user types the correct password and is still refused at login, with no message about a wrong password. Explain how PAM structures the login path and which stage rejects an otherwise-valid password.
answer
- four stacks, four different questions
- auth is only the first of them
- correct password, wrong stage
- control flag decides how it folds
- vagueness is deliberate, read the log
basics
~20 sPAM splits authentication into four independent stacks: auth (are you who you say), account (are you allowed right now), password (changing the secret) and session (setting the session up). A correct password that still fails is almost always rejected by the account or session stack.
solid answer
~50 sPAM is the pluggable layer that programs like `login`, `sshd` and `sudo` call instead of checking passwords themselves. Each program has a file in `/etc/pam.d/` naming four stacks of modules. The **auth** stack verifies the credential — that is the part the password satisfies. The **account** stack then asks a separate question: is this account permitted to log in *now*? It is where expiry from `/etc/shadow`, `pam_nologin` blocking non-root logins, `pam_access` restricting origin, `pam_time` restricting hours, and `pam_faillock` lockouts all live. The **session** stack runs afterwards to set up the environment, limits and home directory, and can fail too. Each line carries a control flag — `required`, `requisite`, `sufficient`, `optional` — that decides how its result folds into the stack's verdict. So diagnose by stage: `chage -l user` for expiry, check for `/etc/nologin`, check lockout state, and read the service's own PAM file rather than assuming the generic one applies.
code
bash · 10 lines# Which stack does this service actually use?
cat /etc/pam.d/sshd
# Account-stage suspects, in order
sudo chage -l alice # expiry and ageing fields
ls -l /etc/nologin # blocks every non-root login while present
sudo faillock --user alice # lockout tally (RHEL-family)
# The modules name themselves in the log even when the user is told nothing
sudo journalctl -u sshd -n 50go deeper
Know that PAM is the shared layer programs call to authenticate users, and that its configuration lives in per-service files under /etc/pam.d/.
Explain the four stacks and what each decides, and describe how the control flags — required, requisite, sufficient, optional — combine module results into one verdict.
Diagnose by stage: separate a credential failure from account expiry, a nologin file, a faillock lockout or a failing session module, and keep a second root session open before touching the stack.
Own authentication policy across the fleet — where identity is backed, how second factors and lockout thresholds are standardised, and what console-level recovery exists when a PAM change locks everyone out.
## What PAM is for Before PAM, every program that authenticated a user contained its own password-checking code. Pluggable Authentication Modules invert that: `login`, `sshd`, `su`, `sudo`, display managers and cron all hand the decision to a shared library, and the administrator composes the policy from modules. Adding two-factor authentication or a directory backend becomes an edit to a text file rather than a patch to every program. ## Four stacks, four questions Each service's file in `/etc/pam.d/` (named after the service — `/etc/pam.d/sshd`, `/etc/pam.d/sudo`) contains lines of the form: ``` <type> <control> <module> [arguments] ``` The four types are independent stacks answering different questions: - **auth** — *are you who you claim?* Verifies the credential: `pam_unix.so` against `/etc/shadow`, `pam_sss.so` against a directory, a second-factor module, and so on. - **account** — *is this account allowed to proceed, right now?* Nothing here re-checks the password. It checks validity: expiry, allowed hours, allowed origins, lockout state. - **password** — *changing the secret.* Only runs when a password is being set, and hosts quality rules such as `pam_pwquality.so`. - **session** — *set up and tear down the session.* Resource limits (`pam_limits.so`), environment (`pam_env.so`), creating a home directory (`pam_mkhomedir.so`), registering with the login manager (`pam_systemd.so`). A correct password satisfies **auth** only. A login that fails after a correct password was almost always rejected by **account** or **session** — which is exactly why the message is often vague rather than "wrong password". ## Control flags The control field decides how one module's result folds into the stack's verdict: - **required** — must succeed; failure fails the stack, but the remaining modules still run, so the user cannot tell *which* one objected. - **requisite** — must succeed, and failure returns immediately. - **sufficient** — success ends the stack successfully, provided no earlier `required` module failed. - **optional** — result ignored unless it is the only module in the stack. - **[value=action …]** — the modern, explicit form, for example `[success=1 default=ignore]`, which is what distributions actually generate when they need to skip a line. The deliberate vagueness of `required` is a security property: revealing which check failed leaks whether an account exists, is locked, or is merely out of hours. ## Where the files live Debian-family systems factor shared policy into `common-auth`, `common-account`, `common-password`, `common-session`, pulled in with `@include`. RHEL-family uses `system-auth` and `password-auth`, pulled in with `substack`, and on RHEL 8+ those files are generated by `authselect` — hand-editing them gets overwritten. Either way, always read the *service's* file, because `sshd` and `sudo` do not necessarily share a stack. ## The usual culprits for "correct password, still refused" - **Account expiry.** The eighth field of `/etc/shadow` is an absolute expiry date; `chage -l alice` prints it. Past that date, `pam_unix` fails the account stack. - **Password expired past the inactivity grace.** An expired password normally forces a change; once the inactive period lapses, the account is refused outright. - **`/etc/nologin` exists.** `pam_nologin.so` refuses every non-root login while that file is present and prints its contents. A maintenance script that failed to remove it locks everybody out. - **Lockout after failed attempts.** `pam_faillock.so` counts failures and denies for a window; `faillock --user alice` shows the tally and `faillock --user alice --reset` clears it (RHEL-family ships this by default). - **Origin or time restrictions.** `pam_access.so` (`/etc/security/access.conf`) and `pam_time.so` deny by source or by hour, with no reference to the password. - **Shell is nologin.** Not PAM at all — authentication succeeded and the session started, but `/usr/sbin/nologin` refused an interactive shell. The symptom is an immediate disconnect. - **Session stack failure.** A home directory on an unmounted network filesystem, or a `pam_limits` rule the session cannot satisfy, can end a session that authenticated perfectly. ## How to work the problem Read the service's log first — `journalctl -u sshd` or the authentication log — because PAM modules say which module denied even when the user is told nothing. Then walk the stages in order: does `chage -l` show expiry; does `/etc/nologin` exist; does `faillock` show a lockout; does the service's `/etc/pam.d/` file include a restriction the generic stack does not. Keep a second root session open while you test, since a broken PAM file can lock every account out of the machine and force console recovery.
- What is the difference between the `required` and `requisite` control flags?Both must succeed for the stack to succeed. `required` keeps running the remaining modules after a failure and reports at the end, which hides *which* check objected and avoids leaking whether the account exists. `requisite` aborts immediately on failure. Distributions favour `required` for that concealment, at the cost of a less specific error for the administrator — who is expected to read the log instead.
- Every account on a host is suddenly refused at login except root on the console. What do you check first?Whether `/etc/nologin` exists — `pam_nologin.so` refuses all non-root logins while it does and prints the file's contents as the message. It is typically left behind by a maintenance script or an interrupted shutdown. If the file is absent, look next for a broken edit to the shared PAM stack, which produces the same fleet-wide symptom and needs console recovery.
- Does `sudo` go through PAM as well, and why does that matter?Yes — sudo has its own file in `/etc/pam.d/sudo`, so the password prompt, any second factor, and the account checks apply there too. It matters because sudo can fail for reasons that have nothing to do with sudoers: an expired account or a faillock lockout denies at the PAM layer before the policy is even consulted. When `sudo -l` shows a valid rule but the command is refused, check PAM before rereading the sudoers file.
saying these in an interview costs you the question
- Thinking PAM only checks passwords
- Assuming a refused login means a wrong password
- Editing a shared PAM file with no second root session open
- Believing every service shares one PAM configuration
- Hand-editing authselect-generated files on RHEL 8+