Home / Alt manpages / pam_deny(8)

  • pam_deny(8)
  • Admin command
  • linux

Use pam_deny to Make Unmatched PAM Services Fail Safely

You will finish with a PAM fallback that rejects authentication, account, password and session requests when no service-specific rule exists. The example uses pam_deny from Ubuntu's libpam-modules package, version 1.5.3-5ubuntu5.7 on the system used for this guide. Allow about fifteen minutes, plus a separate maintenance window if you are changing a live login path.

This is a security-sensitive configuration change. A bad PAM edit can deny legitimate access, including administrative access. Keep an existing root shell or console session open while testing, and do not test by closing your only working session.

1. Check the installed module

First confirm that the package and shared object are present. These are ordinary, read-only commands and do not need elevated privileges:

$ dpkg-query -W -f='${Package} ${Version}\n' libpam-modules:amd64
libpam-modules 1.5.3-5ubuntu5.7
$ dpkg-query -L libpam-modules:amd64 | grep '/pam_deny\.so$'
/usr/lib/x86_64-linux-gnu/security/pam_deny.so

Your package revision may differ. The important check is that the module belongs to the installed PAM package and that the file is in the security-module directory. The module has no command-line interface and no standalone test mode.

2. Understand what the module does

pam_deny always reports failure through PAM. It supplies all four PAM management types: auth, account, password and session. It accepts no module options.

The result depends on the management type. The installed manual documents PAM_AUTH_ERR for account and authentication calls, PAM_CRED_ERR for credential-setting calls, PAM_AUTHTOK_ERR for password changes, and PAM_SESSION_ERR for session calls. Those are PAM return values, not shell exit statuses you should expect from running a file directly.

That makes the module useful as a deliberate default policy. It is not a password checker, account lockout counter or recovery mechanism. If you put it in a stack that handles a real service, a required failure can make that service reject users.

3. Choose the fallback file

Linux-PAM prefers individual files in /etc/pam.d/ when that directory exists. In those files the service name is the filename, so a file named sshd configures the sshd service. The reserved service name other provides default rules for a service with no matching service-specific entries.

Inspect the current fallback before changing it:

$ sudo sed -n '1,160p' /etc/pam.d/other

sudo is required because /etc/pam.d/other is system configuration. Read the whole file rather than appending a second policy blindly. If a named service already has its own file, changing other will not replace that service's rules.

Checkpoint: identify one service that does not have a dedicated file and one safe way to observe its failure. Do not use your only graphical login, SSH access or privilege-escalation path for the first test.

4. Back up the current fallback

Make a dated copy before editing. This changes no PAM behaviour and gives you a direct recovery path:

$ backup="/etc/pam.d/other.before-pam-deny.$(date +%Y%m%d%H%M%S)"
$ sudo cp --preserve=mode,ownership,timestamps /etc/pam.d/other "$backup"
$ sudo ls -l "$backup"

Keep the backup until the new policy has been tested. The command uses the shell variable only for the current session. Record the printed filename somewhere accessible from the root shell or console you kept open.

5. Add deny rules carefully

Use a root editor to add the fallback lines. The following is the pattern documented by pam_deny(8); pam_warn is optional and logs the attempted operation before the denial. Do not copy these lines into a service that must remain usable without first reviewing its stack.

#%PAM-1.0
# Default policy for services without their own entries.
other auth     required       pam_warn.so
other auth     required       pam_deny.so
other account  required       pam_warn.so
other account  required       pam_deny.so
other password required       pam_warn.so
other password required       pam_deny.so
other session  required       pam_warn.so
other session  required       pam_deny.so

In /etc/pam.d/other, omit the leading other field because the filename already supplies the service name:

#%PAM-1.0
auth     required       pam_warn.so
auth     required       pam_deny.so
account  required       pam_warn.so
account  required       pam_deny.so
password required       pam_warn.so
password required       pam_deny.so
session  required       pam_warn.so
session  required       pam_deny.so

Do not add arbitrary options after pam_deny.so; this module recognises none. The required control means the stack records failure and ultimately returns failure, while later entries may still run. A requisite control would stop the stack immediately, which is a different policy and is not the documented example.

6. Validate the file without starting a login

Check the file as root, then inspect its final contents:

$ sudo sed -n '1,160p' /etc/pam.d/other
$ sudo test -s /etc/pam.d/other && echo 'PAM fallback is non-empty'
PAM fallback is non-empty

These checks confirm that the file exists and contains text. PAM configuration is consumed by PAM-aware applications, so a successful sed or test command does not prove that every service will behave as intended. Check the system journal after a controlled test, and review the service's own documentation for its PAM stack.

7. Test and recover

Use a deliberately non-critical service or a test environment first. Watch the relevant logs in your retained administrative session, then perform exactly one controlled request. Expect the request to fail because pam_deny returns failure by design. Do not retry a production login repeatedly; repeated failures can trigger separate lockout controls.

$ sudo journalctl -b --no-pager | grep -E 'pam_(deny|warn)'

If a service that should work is denied, restore the backup from the retained root shell or console. Replace /etc/pam.d/other.before-pam-deny.TIMESTAMP with the exact filename you recorded:

$ sudo cp --preserve=mode,ownership,timestamps /etc/pam.d/other.before-pam-deny.TIMESTAMP /etc/pam.d/other

Then repeat the controlled test. Some applications cache PAM state only for the lifetime of a process, while others need a new request or service restart before you see the restored result. Restarting a service can disrupt users, so follow that service's normal change procedure rather than issuing a blind restart.

Done means

  • pam_deny.so is present in the installed libpam-modules package.
  • You understand that the module rejects all four PAM management types and takes no options.
  • The fallback file was inspected and backed up before editing.
  • Rules use the correct syntax for either /etc/pam.conf or /etc/pam.d/other.
  • A controlled test produced the expected denial without sacrificing the only administrative session.
  • The dated backup remains available until the policy has been observed in normal operation.