Set Up Password History with pam_pwhistory, Not pwhistory_helper
If you went looking for a pwhistory_helper command to run by hand, stop: it is an internal binary, not something you invoke yourself. This guide configures and verifies local password history through pam_pwhistory instead, while keeping the helper firmly in its own lane. The helper moves password hashes between the module and the opasswd history file, and checks a new password against that history when the module asks it to.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes, plus a few more to line up a recovery session. This assumes Ubuntu or Debian package management, an account with sudo, and a test user whose password you can freely change. The package checked here is libpam-modules-bin 1.5.3-5ubuntu5.7; your revision may differ even on the same upstream Linux-PAM release.
Safety boundary
PAM mistakes lock people out. Keep an existing root shell or console session open the whole time you test. Do not close your only administrative session until a separate login or password change has actually succeeded. Never put a real password in a shell command, script, terminal recording or article example.
1. Confirm the helper and module are present
Check packages and paths before touching anything:
$ dpkg-query -W -f='${Package} ${Version}\n' libpam-modules-bin libpam-modules
libpam-modules-bin 1.5.3-5ubuntu5.7
libpam-modules 1.5.3-5ubuntu5.7
$ command -v pwhistory_helper
/usr/sbin/pwhistory_helper
Versions and paths vary by system. The pwhistory_helper(8) manual is explicit: the interface is internal to pam_pwhistory, and applications should not call it directly. In practice that means there is no supported set of flags to build a script around.
Checkpoint
If the command is missing, stop and repair the normal PAM package through your distribution's usual process. Do not download a replacement helper or copy one over from another host.
2. Read the current PAM password stack before you touch it
Common services each get their own file under /etc/pam.d; which one you care about depends on which login or password-changing path you want to protect:
$ sudo grep -R -n --include='*' -E 'pam_(pwhistory|unix|passwdqc)' /etc/pam.d /etc/pam.conf 2>/dev/null
This reads configuration as root because some files are not world-readable. It changes nothing. Look for an existing pam_pwhistory.so line before adding another: two history modules stacked together produce confusing prompts and unpredictable policy results.
The module only supplies the password type, and it normally sits before pam_unix.so use_authtok so the history check sees the new token first and Unix writes it afterwards:
password required pam_pwhistory.so
password required pam_unix.so use_authtok
Do not paste this into every service file you can find. Edit the one that owns the password change you are actually testing, and keep any distribution-managed comments and surrounding rules intact. If another password module in the stack already obtains a token, its ordering and its use of use_authtok need to stay coherent with what you add.
3. Pick the history file and the count
- Default location.
/etc/security/opasswd. - Default count. Ten remembered passwords.
- remember=N. Overrides the count;
remember=0leaves existingopasswdcontents untouched. - file=/path/filename. Points the module at a different history file.
- conf=/path/to/config-file. Points at a separate configuration file.
For an explicit, small policy, put the count directly on the module line. This example remembers the last five passwords:
password required pam_pwhistory.so remember=5
password required pam_unix.so use_authtok
Options on the PAM line override /etc/security/pwhistory.conf. Keep one source of truth: a value on the PAM line can otherwise silently hide a config-file setting someone reviewed carefully.
Security warning
opasswd holds password-hash history. Treat it as sensitive authentication data: never print it, paste it into a ticket, or leave it world-readable. Check only its ownership and mode:
$ sudo stat -c '%A %U:%G %n' /etc/security/opasswd
-rw------- root:root /etc/security/opasswd
That mode is an example of what a properly restricted file looks like, not a guarantee for your install. If permissions are unexpectedly broad, stop and check the package's intended ownership and your local security policy before touching it. Do not hand-edit its contents.
4. Make one deliberate PAM change
Back up the single service file you are about to edit, then open it with your normal privileged editor:
$ sudo cp --preserve=mode,ownership,timestamps /etc/pam.d/SERVICE /etc/pam.d/SERVICE.before-pwhistory
$ sudoedit /etc/pam.d/SERVICE
Replace SERVICE with the real file, such as whatever your password-changing command uses. Add or adjust the password stack deliberately, save, then check exactly what landed:
$ sudo sed -n '/^password[[:space:]]/p' /etc/pam.d/SERVICE
password required pam_pwhistory.so remember=5
password required pam_unix.so use_authtok
There is no syntax checker that makes an arbitrary PAM stack safe. A single typo can break the next password change or login attempt on that service. Do not test this by closing your only privileged session.
5. Prove it works on a disposable account
Use a test account that owns nothing important. Creating one is a real state change and needs root:
$ sudo useradd --create-home pam-history-test
$ sudo passwd pam-history-test
Set a temporary password interactively, change it once more to a different temporary value, then try to reuse the first one. With remember=5 the reuse should be rejected once it is in the history. Exact wording depends on the rest of your PAM stack.
Check the status after each change rather than trusting the prompt alone:
$ sudo passwd pam-history-test
New password:
Retype new password:
passwd: password updated successfully
$ printf 'status: %s\n' "$?"
status: 0
A successful change here proves this one path accepted the password, not that every PAM service shares the same file or stack. If a reuse gets accepted when it should not, check the service file, the effective remember value, and the history file path before you change anything else.
6. Recover from a failed test
If a password change breaks unexpectedly, keep the recovery session open and restore only the backup you made earlier:
$ sudo cp --preserve=mode,ownership,timestamps /etc/pam.d/SERVICE.before-pwhistory /etc/pam.d/SERVICE
$ sudo sed -n '/^password[[:space:]]/p' /etc/pam.d/SERVICE
This puts the service file back, but it does not clear password history already written to opasswd. Do not delete or edit that file as your first move. Fix the stack, test again, and keep the history unless your documented security procedure says otherwise.
Once you trust the change, remove the disposable account, but only if you are certain nothing needs it:
$ sudo userdel --remove pam-history-test
That command deletes the test account's home directory and cannot be undone without a backup. It has nothing to do with making PAM work; it is just cleanup.
Done means
- Left the helper alone.
pwhistory_helperis installed but never called directly. - One coherent rule. The intended PAM service has a single, working
pam_pwhistorypassword line. - Count and path understood. You know the effective history count and the
opasswdlocation. - History file stayed protected. Its permissions remain restricted and its contents were never exposed.
- Verified with a real test. A new password worked and an old one was rejected on a disposable account.
- Kept a way back. A recovery session and a tested backup stayed available until you trusted the change.