1 of 3

PAM and Account PolicyLesson 1 of 3

How PAM decides, and authselect

Read a PAM stack line by line, understand control flags, and change it the supported way with authselect.

  • authselect
  • authselect current
  • authselect list
  • authselect select
  • authselect enable-feature
  • authselect apply-changes
  • authselect check
  • /etc/pam.d
  • /etc/authselect
  • man pam.d
  • ls -l /etc/pam.d/system-auth

50 min3 exercises

After this lesson you can

  • Name the four PAM management groups and explain required, requisite, sufficient and optional.
  • Read /etc/pam.d/sshd and system-auth and say which modules run in which order.
  • Switch profile or enable a feature with authselect, and recover a damaged PAM configuration.

The idea

PAM (Pluggable Authentication Modules) is how programs ask “may this user do this?” without knowing how the answer is produced. sshd, login, sudo, su, cockpit and crond do not read /etc/shadow themselves; they call PAM, and PAM runs a configured list of small modules that each check one thing: the password, whether the account has expired, whether /etc/nologin exists, how many failed attempts there have been.

Each service has a file in /etc/pam.d/ named after it. The file is a list of lines; PAM runs the lines for the kind of check that is needed.

The four groups

GroupQuestionExamples
authWho are you? Prove itPassword, key, token, pam_faillock counting failures
accountAre you allowed in now?Expired account, locked, /etc/nologin, pam_access
passwordChanging credentialspam_pwquality (strength), pam_unix (store)
sessionSet up and tear down the sessionpam_limits, pam_systemd, pam_selinux, pam_lastlog

A login runs auth, then account, then session. Changing a password runs password. A failure in the wrong group gives a different symptom: a wrong password fails in auth; a correct password for an expired account fails in account.

One line

auth        required      pam_faillock.so preauth silent deny=3 unlock_time=600
type        control       module          arguments

The control flag decides what the module’s answer means for the whole stack:

FlagOn successOn failure
requiredContinueRemember the failure, keep running the rest of the group, then fail
requisiteContinueStop immediately with failure
sufficientStop with success (if no earlier required failed)Ignore and continue
optionalIgnored unless it is the only moduleIgnored
include / substackRun the lines of another file; substack has its own result scope
[success=1 default=ignore]Advanced form: jump over the next line(s)man pam.conf

Running on after a required failure is deliberate: an attacker should not learn which check failed by how fast the answer came back.

Where the files come from on RHEL

You will see include system-auth or substack password-auth in many service files. On RHEL those two files, and a few others, are not edited by hand. They are generated by authselect from a profile:

ls -l /etc/pam.d/system-auth
lrwxrwxrwx. 1 root root 28 Nov  4 10:12 /etc/pam.d/system-auth -> /etc/authselect/system-auth

The symlinks point into /etc/authselect/, where authselect writes the result of the selected profile plus optional features. The profile and features are chosen with authselect:

authselect list                         # available profiles: local ("minimal"), sssd, winbind
authselect current                      # the profile in use and its enabled features
authselect select sssd with-mkhomedir   # choose a profile and features
authselect list-features sssd           # features available for a profile
authselect enable-feature with-faillock # add a feature to the current profile
authselect apply-changes                # regenerate files from the current selection
authselect check                        # verify that files match what authselect would write

The safety rule

A mistake in PAM can lock everyone out, including root at the console, with no way to log in and fix it. So:

  1. Keep a root shell open (a second terminal, or the console already logged in) before you change anything.
  2. Test with a new login (a second ssh session) before closing the working one.
  3. Prefer authselect, which writes consistent files, to hand edits.
  4. If you are locked out, boot with rd.break (or rescue media), mount the system, and run authselect select/apply-changes from the chroot.

Try it

What is selected

authselect current
Profile ID: sssd
Enabled features:
- with-mkhomedir
- with-sudo

Read sshd

cat /etc/pam.d/sshd
#%PAM-1.0
auth       substack     password-auth
auth       include      postlogin
account    required     pam_sepermit.so
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
session    required     pam_selinux.so open env_params
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      password-auth
session    include      postlogin

Read it as a script. For auth, run the auth lines of password-auth (as a substack: its success or failure is judged on its own, then summed up), then postlogin. For account, check SELinux’s sepermit, then pam_nologin: if /etc/nologin exists, ordinary users are refused. Then the account checks of password-auth, which include pam_unix (expired? locked?). For session, set the SELinux context, record the login id, apply namespace and keyring setup, and include more from password-auth.

The auth stack of system-auth

grep '^auth' /etc/pam.d/system-auth
auth        required                                     pam_env.so
auth        required                                     pam_faildelay.so delay=2000000
auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular
auth        [default=1 ignore=ignore success=ok]         pam_localuser.so
auth        sufficient                                   pam_unix.so nullok
auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular
auth        sufficient                                   pam_sss.so forward_pass
auth        required                                     pam_deny.so

Two things stand out. pam_unix.so is sufficient: if the local password is right, authentication succeeds and the rest is skipped. The last line, pam_deny.so, is required: if nothing earlier succeeded, the stack ends in an unconditional failure. That final pam_deny is normal. The fault in the challenge exercise is the same module appearing at the top, where it fails every login.

When the PAM edit goes wrong

SymptomLikely causeFix
Every password login fails after an editA hand edit of system-auth/password-authauthselect check; authselect apply-changes -b
authselect apply-changes refusesFiles modified outside authselect-b to back up and force, after you have read the diff
authselect select removes my changeLocal edit overwritten (as designed)Use features or a custom profile
sssd profile selected but pam_sss.so failssssd not running or no domainsystemctl status sssd, /etc/sssd/sssd.conf mode 600
New user has no home on first loginwith-mkhomedir not enabledauthselect enable-feature with-mkhomedir and oddjobd enabled
Login fails only for some servicesThe service’s own file in /etc/pam.d differsCompare sshd, login, sudo, su
Locked out entirelyBroken stackrd.break, chroot, authselect select ... --force

Going further

Custom profiles. authselect create-profile site -b sssd --symlink-meta copies a profile into /etc/authselect/custom/site/ so you can add your own lines and keep authselect in control. Beyond the exam: pam_wheel restricts su, pam_listfile allows or denies by file, pam_tally2 is gone (replaced by pam_faillock), and pam_debug.so can be added to a stack to log what each module returned.

Practice

0 of 3 done

Do these on your own system. They get harder. Check each result, then tick it off.

  1. Warm-up

    Read a stack

    Print /etc/pam.d/sshd and answer: which file does it include for auth, which module checks /etc/nologin, and which module opens the session. Then print the auth section of /etc/pam.d/system-auth and identify the module that checks the password.

    Check your result
    • auth substack password-auth (or include) appears in sshd.
    • account required pam_nologin.so appears; session lines include pam_systemd.so via password-auth.
    • In the auth section the password check is pam_unix.so (possibly after pam_sss.so if the SSSD profile is active).
    Hint

    A PAM line has four fields: type, control, module, arguments. include/substack pull in another file. Files under /etc/pam.d are named after the service (sshd, login, sudo).

    Solution
    cat /etc/pam.d/sshd
    grep '^auth' /etc/pam.d/system-auth
    ls -l /etc/pam.d/system-auth /etc/pam.d/password-auth
  2. Practice

    Enable a feature the supported way

    Show the current authselect profile and enabled features. Enable with-faillock without editing any file in /etc/pam.d, apply it, and prove that the pam_faillock lines now appear in system-auth and password-auth. Run authselect check. Then disable the feature again and confirm the lines are gone.

    Check your result
    • authselect current prints Profile ID: ... and a feature list.
    • After enabling: grep -c faillock /etc/pam.d/system-auth is greater than 0.
    • authselect check prints Current configuration is valid.
    • After disabling: grep -c faillock /etc/pam.d/system-auth is 0.
    Hint

    authselect enable-feature with-faillock changes the selection and regenerates the files; authselect apply-changes re-applies the current selection. Do not edit system-auth: it is a generated file, and authselect check reports a manual edit.

    Solution
    authselect current
    sudo authselect enable-feature with-faillock
    sudo authselect apply-changes
    grep -c faillock /etc/pam.d/system-auth
    authselect check
    sudo authselect disable-feature with-faillock
    sudo authselect apply-changes
    grep -c faillock /etc/pam.d/system-auth
  3. Challenge

    Someone edited system-auth by hand

    Setup (lab VM, keep a root console open in another terminal before you start):

    sudo cp -a /etc/pam.d/system-auth /root/system-auth.good
    sudo sed -i 's/^auth .*pam_unix.so.*/auth        required      pam_deny.so/' /etc/pam.d/system-auth

    Nobody can log in with a password any more. From your open root shell, prove with authselect check that the file was modified outside authselect, restore a correct configuration without copying the old file back, and confirm a login works. Explain why the supported repair is better than restoring a copy.

    Check your result
    • authselect check reports the files are not what authselect would generate.
    • After sudo authselect apply-changes -b (or authselect select PROFILE --force), grep pam_deny /etc/pam.d/system-auth shows only the normal deny line at the end of a stack, not the first auth line.
    • su - testuser or an ssh login with a password succeeds.
    Hint

    authselect apply-changes fails with an error if files were hand-edited; -b makes a backup and forces the regeneration. A copy would restore this file but not necessarily a consistent state with the selected profile and features.

    Solution
    authselect check
    sudo authselect apply-changes -b
    authselect check
    grep -n '^auth' /etc/pam.d/system-auth
    su - testuser -c id