Home / Alt manpages / pam_pwhistory(8)

  • pam_pwhistory(8)
  • Admin command
  • linux

Add Local Password History with pam_pwhistory

Someone changes their password, then immediately changes it back, and your password policy is worthless. pam_pwhistory closes that loop by remembering recent passwords and rejecting a reuse.

The examples target Ubuntu's libpam-modules package, version 1.5.3-5ubuntu5.7 on the machine used for this guide. Allow about 15 minutes, including a test and a recovery check.

Warning

This is a security-sensitive change to the password stack. Keep an existing root shell or console session open before editing PAM, and make a dated backup first. A malformed PAM file can prevent authentication, even though an already logged-in shell keeps working.

1. Check the installed module and current stack

Run these read-only checks as an ordinary user:

$ dpkg-query -W -f='${Package} ${Version}\n' libpam-modules:amd64
libpam-modules:amd64 1.5.3-5ubuntu5.7
$ ls -l /lib/x86_64-linux-gnu/security/pam_pwhistory.so
$ grep -n '^[[:space:]]*password' /etc/pam.d/common-password

The module is a PAM password module, not a command you run directly. On this Ubuntu installation, common-password holds the shared password stack and currently uses pam_unix. Your service may use a different stack, so inspect whichever file actually handles the password change before editing it.

Checkpoint

Identify the existing pam_unix.so password line. The history line belongs immediately before it, so pam_pwhistory can grab the new token and pam_unix can reuse it.

2. Choose the history policy

The preferred configuration file is /etc/security/pwhistory.conf. It uses one option per line in name = value form; comments start with #, and whitespace around the equals sign is ignored. The installed defaults remember 10 passwords, prompt once, and store the history in /etc/security/opasswd.

For a five-password history, edit the file as root:

$ sudoedit /etc/security/pwhistory.conf

Set or uncomment these values, keeping the other comments if they help future maintenance:

remember = 5
retry = 1
file = /etc/security/opasswd
  • Do not add debug as a routine setting. It sends module diagnostics to syslog and can expose more operational detail than a normal password policy needs.
  • Add enforce_for_root only deliberately. Without it, the history check is not enforced for root; add it once you have decided root password changes must obey the same history.

Checkpoint

Verify the file as root without printing the password history itself:

$ sudo sed -n '1,160p' /etc/security/pwhistory.conf
$ sudo stat -c '%U:%G %a %n' /etc/security/opasswd

Warning

The history file contains password-history data and should stay protected. Do not copy it into a ticket, paste it into a chat, or use a temporary path such as /tmp/opasswd for a production policy.

3. Add the module before pam_unix

Back up the PAM file, then open it with elevated privileges:

$ sudo cp --preserve=all /etc/pam.d/common-password /etc/pam.d/common-password.$(date +%Y%m%d-%H%M%S).bak
$ sudoedit /etc/pam.d/common-password

Add this line immediately before the existing pam_unix.so password line:

password    required    pam_pwhistory.so    use_authtok

For the stack installed here, the result should look like this around the password modules:

password    required                         pam_pwhistory.so use_authtok
password    [success=1 default=ignore]        pam_unix.so obscure yescrypt
password    requisite                        pam_deny.so
password    required                         pam_permit.so

use_authtok tells the module to use the new password supplied by an earlier password module. If your stack already runs a password-quality module before pam_pwhistory, follow the local stack's own ordering and do not copy an example from another distribution wholesale. The module provides only the password type.

  • No earlier module supplies a token? Do not put use_authtok on the history line.
  • Keep use_authtok on the pam_unix line. Remove it from the documented two-module arrangement and the stack can ask for the new password twice.

4. Test a real password change safely

First check that the edited lines are present and the history file is still protected:

$ grep -n -A2 -B1 'pam_pwhistory' /etc/pam.d/common-password
$ sudo stat -c '%U:%G %a %n' /etc/security/opasswd
root:root 600 /etc/security/opasswd

Use a disposable non-root test account if your system policy permits it. The following changes state and requires elevated privileges:

$ sudo useradd --create-home pam-history-test
$ sudo passwd pam-history-test

Give the test account an initial password, then run sudo passwd pam-history-test again and try that same password as the new value. The second change should be rejected as a reuse. Choose a fresh test password to confirm a permitted change still succeeds.

Warning

Do not use a real user's password in a test transcript. Remove the disposable account after testing, only if you created it for this purpose:

$ sudo userdel --remove pam-history-test

This deletion removes the test account and its home directory. It does not remove the shared history entries for other accounts. If the account was not disposable, stop and do not run that command.

5. Recover if authentication behaves unexpectedly

If a password change fails unexpectedly, record the exact PAM error and inspect the system log through your normal log-management process.

  • PAM_MAXTRIES means the password was rejected too often.
  • PAM_AUTHTOK_ERR means no usable new password was set.
  • PAM_USER_UNKNOWN means the account was not known to PAM.
  • PAM_IGNORE indicates disabled history.

If the edited stack causes broader authentication trouble, use the root shell or console you kept open. Restore the backup, then check the file before closing that recovery session:

$ sudo cp --preserve=all /etc/pam.d/common-password.YYYYMMDD-HHMMSS.bak /etc/pam.d/common-password
$ sudo grep -n '^[[:space:]]*password' /etc/pam.d/common-password

Replace YYYYMMDD-HHMMSS with the actual backup suffix; do not guess if several backups exist. List them first with ls -1t /etc/pam.d/common-password.*.bak. The same restore approach applies to pwhistory.conf if a policy edit needs undoing, provided you backed it up before changing it.

Done means

  • pam_pwhistory.so is installed and the relevant PAM stack has been identified.
  • pwhistory.conf sets an intentional history count and a protected history path.
  • The history module sits before pam_unix, with token handling that matches the surrounding stack.
  • A disposable account rejected a recently used password and accepted a new one, where testing was permitted.
  • A dated PAM backup remains available, and the recovery shell has not been closed until the change is trusted.