PAM

PAM (Pluggable Authentication Modules)

PAM is a system for configuring authentication (login) on Linux systems as well as several others.

It includes many modules to configure the system to authenticate against various databases, including the passwd file, kerberos, and many others.

Sections
PAM authentication consists of four basic parts:

Authentication (auth)
This examines whether the user's password is correct.

Account (account)
This examines whether the user's account is valid, including expiration and time restrictions

Password changing (password)
This controls how users change their passwords.

Session (session)
This does setup for a user session, such as announcing last login, checking if any mail is available, and/or creating a home directory.

Any particular service may check all of these parts or just a subset (or none at all, but that's out side the scope of this document)

Example
Here is an attempt to set up PAM to use every module possible, in the "best" (hah!) way. Successful authentication by any method should allow login. Example is based on Debian/Ubuntu, but should be applicable to any distribution

/etc/pam.d/login:
auth required pam_issue.so auth requisite pam_securetty.so auth requisite pam_nologin.so @include common-auth auth optional pam_group.so
 * 1) display the file /etc/issue before login
 * 1) only allow root login from ttys listed in /etc/securetty
 * 1) only allow root login if /etc/nologin exists
 * 1) include other auth methods common to all services
 * 1) grant additional group access beyond /etc/group

account requisite pam_time.so account required pam_access.so @include common-account
 * 1) only allow logins during time configured in /etc/security/time.conf
 * 1) only allow logins to certain users from certain hosts or ttys
 * 1) include other account methods common to all services

session required pam_limits.so session optional pam_lastlog.so session optional pam_motd.so session optional pam_mail.so standard session required pam_selinux.so multiple @include common-session
 * 1) set limits on system resource usage (memory, files, CPU time)
 * 1) display the last login time
 * 1) display the message of the day (/etc/motd
 * 1) display a message if mail is waiting
 * 1) set the selinux security context
 * 1) include other session methods common to all services

@include common-password
 * 1) include password-change methods common to all services

/etc/pam.d/common-account
account sufficient pam_krb5.so account required pam_unix.so

/etc/pam.d/common-auth
auth required pam_tally.so deny=10 unlock_time=30 lock_time=30 auth [success=ok new_authtok_reqd=ok ignore=ignore default=1] pam_krb5.so try_first_pass auth [default=done] pam_openafs_session.so auth sufficient pam_poldi.so quiet auth sufficient pam_unix.so nullok_secure try_first_pass md5 shadow auth required pam_deny.so
 * 1) lock non-root users out for a time if they fail to log in 10 times. Lock them out for 30 seconds.  Might be a potential DoS vector, especially if you use it with a remotely-accessible service.
 * 1) try to authenticate against kerberos.  If that fails, skip openafs because it requires a kerberos ticket to work.  try_first_pass is not really necessary.
 * 1) try to get openafs token.  Even if we can't get it, if we got here we're done because krb5 must have worked.
 * 1) Try to use the OpenPGP smartcard.  Too bad it doesn't allow try_first_pass.
 * 1) Try to authenticate against /etc/passwd.
 * 1) Else we fail.  This is not really necessary, but if it's not here the last module above needs to be "required" instead of "sufficient"

/etc/pam.d/common-password
password requisite pam_cracklib.so password requisite pam_passwdqc.so password [default=reset] pam_krb5.so use_authtok try_first_pass password required pam_unix.so try_first_pass use_authtok nullok obscure min=4 max=8 md5
 * 1) Password quality checker
 * 1) or another one
 * 1) Try to change kerberos password, but don't sweat it if we can't because user might have entered their UNIX password.  If it does work though, just change it to the one that pam_passwdqc gave us.
 * 1) Try to change smartcard PIN.  Doesn't work because poldi doesn't implement this [yet]
 * 2) password required pam_poldi.so
 * 3) Try to change UNIX password to the one that pam_passwdqc gave us.

Note: this part doesn't work well. It's virtually impossible to get PAM to change passwords properly if you have more than one authentication service.

What should happen: PAM asks for a password for kerberos. If it's correct, use some other module such as pam_passwdqc or pam_cracklib to prompt for a new password. Update the kerberos password with the one accepted by the quality checker. Try the same old password against the next module. If it fails, ask for the old password for this module. If that one succeeds, use it to update that service's password with the qc-accepted password. Continue through the password stack. At the end, report which modules succeeded and which failed.

What shouldn't happen: PAM asks for a password. Fail because a module doesn't support password changing.

What else shouldn't happen: PAM asks for a password. If it's correct for the second module, prompt for a new password for the first module. Fail because the old password for the second module is not correct for the first module.

Another thing that shouldn't happen: PAM looks at the auth stack when running through the password stack.

/etc/pam.d/common-session
session required pam_unix.so session optional pam_foreground.so

Supplied with stock PAM

 * pam_access
 * pam_cracklib
 * pam_debug
 * pam_deny
 * pam_echo
 * pam_env
 * pam_exec
 * pam_faildelay
 * pam_filter
 * pam_ftp
 * pam_group
 * pam_issue
 * pam_keyinit
 * pam_lastlog
 * pam_limits
 * pam_listfile
 * pam_localuser
 * pam_loginuid
 * pam_mail
 * pam_mkhomedir
 * pam_motd
 * pam_namespace
 * pam_nologin
 * pam_permit
 * pam_rhosts
 * pam_rootok
 * pam_securetty
 * pam_selinux
 * pam_shells
 * pam_succeed_if
 * pam_tally
 * pam_time
 * pam_umask
 * pam_unix
 * pam_userdb
 * pam_warn
 * pam_wheel
 * pam_xauth

Other modules

 * pam_ccreds
 * pam_chroot
 * pam_devparm
 * pam_dotfile
 * pam_encfs
 * pam_foreground
 * pam_heimdal
 * pam_http
 * pam_ldap
 * pam_krb5
 * pam_mount
 * pam_musclecard
 * pam_mysql
 * pam_ncp
 * pam_nufw
 * pam_openafs_kaserver
 * pam_openafs_session
 * pam_opie
 * pam_p11
 * pam_passwdqc
 * pam_pgsql
 * pam_poldi
 * pam_pwdfile
 * pam_pwgen
 * pam_radius_auth
 * pam_shishi
 * pam_smbpass
 * pam_ssh
 * pam_tmpdir
 * pam_umask
 * pam_unix2