The Pluggable Authentication Modules system allows an administrator to fully control how authentication is done on a system, and releaves a developer from implementing all kinds of authentication mechanisms.
The "old" way of doing authentication is through /etc/passwd, which contained the username, uid and password. As long as everybody used /etc/passwd there was nog problem, but when different schemes came into play, like NIS, Kerberos, LDAP, and even the shadow system, it meant that developers needed to support all these different ways in their product, which created a enormous amount of duplicated code and a lot of overhead for the developers. To overcome this issue PAM was created. PAM provides a single interface for the developer to talk to. It just tells an application if a user is allowed or not. Meaning that the developer only has to support PAM.
By means of modules the administrator can on the fly change the e.g. the login policy for a certain system from /etc/passwd to kerberos without the users or applications noticing the change. And as long as all programs on a certain system, responsible for user authentication, work with PAM all should be fine.
|PAM library||PAM configuration|
|account checks||authentication||session management||password management|
As said PAM is a modular system, hence the name. The configuration of PAM can be done in two different ways. You could have one long configuration file, or you could have a /etc/pam.d directory which contains several files for the configuration. This document will only discuss the /etc/pam.d variant.
Within the /etc/pam.d directory there are files for every program that needs authentication. In each file there are rules for that specific service. Of course there would be a lot of duplication if your created rules specific for every service, since most services will use the same way of authentication. To solve this issue there is an include statement that you can use in the configuration files.
auth include filewhich includes the auth sections from the mentioned file.
On Red Hat based systems the included file is often system-auth, while for Debian based system you have a common-* file per "type" in the configuration file.
The "type" mentioned is the first colomn in the configuration file. The complete syntax for the file is:
type control module-path module-argumentsThe type can be:
|account||pam_acct_mgmt||Tests if the user is allowed to access the service, meaning if the password is not expired, if the user is allowed during this time of day, if the load is not too high, etc.|
|auth||pam_authenticate||This is the actual authentication. In the good old fashioned way it means that the password is checked to see if the user is who he or she claims to be.|
|pam_setcred||Sets UID, GID and limits|
|session||pam_open_session||Things that should be done when the user is authenticated, and thus logs in.|
|pam_close_session||Things that should be done when the user logs off.|
|password||pam_chauthtok||Used when the user wants to change the authentication credentials (password). Check password length, strength, etc.|
Per type you can have multiple lines. So you can have "stacked" modules that describe what should be done, or to what rules the username and credentials should comply, before a user is authenticated to the system.
The second column in our configuration file is the "control" column. The field tells PAM what it should do when the module reports a failure. This field can be:
PAM started with some predefined actions, which are described below. The use of [...] in the control field is a later addition that gives you full control of PAMs actions. The list below is split in two parts, those that are relevant for system administrators and those that are needed for debugging modules. Within the remainder of this document we are only concerned about the administrators part.
For system administrators:
The action part can be any of:
The third field in the configuration is the "module-path". This tells PAM the modules to use and most the times the path to find the module. According to the LFS, the modules should be located in /lib/security. However the PAM default is /usr/lib/security. For a complete overview of the different modules and their options see: http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-module-reference.html
The last field is the "module-arguments" which varies per module.
The examples below are a mix of Debian, Red Hat and CentOS system configurations mixed with additional features.
The following examples are tested with login and with sshd. Do know if you should replace system-auth (RHEL) or common-* (Debian) files with it.
To act as a normal unix machine using /etc/passwd, /etc/shadow and /etc/group we use the pam_unix.so. We need this anyway to support the system accounts of our system like root.
# Per default the pam_unix.so module treats empty password fields as # disabled accounts. The "nullok" option overrides this behaviour. # To disable an account according to CERT policies, change the # password field to * and set the login shell to /bin/false. # # The "md5" option enables MD5 passwords. Without this option, the # default is Unix crypt. auth sufficient pam_unix.so nullok auth required pam_deny.so account required pam_unix.so account required pam_permit.so session required pam_unix.so # NOT tested password sufficient pam_unix.so shadow nullok md5 password required pam_deny.so
Especially for the login functionality, there are a couple of "native" files that give a system administrator control of who is allowed to do what from where with which restrictions. The first ones that you will probably know are the hosts.allow and hosts.deny files. But also /etc/securetty, /etc/login.defs, and a couple more. If we want to control everything through pam we have to adjust our stack a little bit.
Let's start with the auth section:
# Load the /etc/security/pam_env.conf file. Just to be sure auth required pam_env.so # Enforce a minimal delay in case of failure (in microseconds). # (Replaces the `FAIL_DELAY' setting from login.defs) # Note that other modules may require another minimal delay. (for example, # to disable any delay, you should add the nodelay option to pam_unix) auth optional pam_faildelay.so delay=3000000 # Disallows other than root logins when /etc/nologin exists # (Replaces the `NOLOGINS_FILE' option from login.defs) auth requisite pam_nologin.so # Disallows root logins except on tty's listed in /etc/securetty # (Replaces the `CONSOLE' setting from login.defs) auth [success=ok ignore=ignore user_unknown=ignore default=die] pam_securetty.so # Check if the users shell exists # (Uses /etc/shells) auth required pam_shells.so # Outputs an issue file prior to each login prompt # (Replaces the ISSUE_FILE option from login.defs). auth optional pam_issue.so issue=/etc/issue # This allows certain extra groups to be granted to a user # based on things like time of day, tty, service, and user. # Please edit /etc/security/group.conf to fit your needs # (Replaces the `CONSOLE_GROUPS' option in login.defs) auth optional pam_group.so auth sufficient pam_unix.so nullok auth required pam_deny.so
Next we adjust the account section:
# Edit /etc/security/time.conf if you need to set time # restrainst on logins. # (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs # as well as /etc/porttime) account requisite pam_time.so # Edit /etc/security/access.conf if you need to set # access limits. # (Replaces /etc/login.access file) account required pam_access.so account required pam_unix.so account required pam_permit.so
Then the session section:
# This module parses environment configuration file(s) # and also allows you to use an extended config # file /etc/security/pam_env.conf. # Backwards compatibility for /etc/environment session required pam_env.so readenv=1 envfile=/etc/environment # Setting the locale or i18n settings # Debian: locale variables are also kept into /etc/default/locale in etch # reading this file *in addition to /etc/environment* does not hurt # RHEL: locale variables are kept in /etc/sysconfig/i18n # # Debian: session required pam_env.so readenv=1 envfile=/etc/default/locale # RHEL: session required pam_env.so readenv=1 envfile=/etc/sysconfig/i18n # Sets up user limits according to /etc/security/limits.conf # (Replaces the use of /etc/limits in old login) session required pam_limits.so # Sets the umask # (Replaces UMASK setting in login.defs) # Does not seem to have any influence on the umask... # needs more testing session optional pam_umask.so umask=0077 # The following two options report some additional # information when a user logs in. sshd also reports # this information, so to prevent duplicate messages # set in sshd_config: # PrintLastLog no # PrintMotd no # (Replaces the `LASTLOG_ENAB' and `MOTD_FILE' options # from login.defs) session optional pam_lastlog.so session optional pam_motd.so # Prints the status of the user's mailbox upon succesful login # (Replaces the `MAIL_CHECK_ENAB' option from login.defs). # # This also defines the MAIL environment variable # However, userdel also needs MAIL_DIR and MAIL_FILE variables # in /etc/login.defs to make sure that removing a user # also removes the user's mail spool file. # See comments in /etc/login.defs session optional pam_mail.so standard # Create home dir if it does not exist on login session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 # SELinux needs to intervene at login time to ensure that the process # starts in the proper default security context. # Uncomment the following line to enable SELinux # session required pam_selinux.so select_context # Did NOT test this: # session required pam_unix.so session required pam_unix.so
And last the password section:
# Alternate strength checking for password. Note that this # requires the libpam-cracklib package to be installed. # You will need to comment out the password line above and # uncomment the next two in order to use this. # (Replaces the `OBSCURE_CHECKS_ENAB', `CRACKLIB_DICTPATH') # # This is NOT tested password required pam_cracklib.so retry=3 minlen=6 difok=3 password required pam_unix.so use_authtok nullok md5 password required pam_deny.so
This section builds on the previous one, but adds LDAP support. We assume that users having a UID above 500 are in LDAP and all others are in the default files (passwd, shadow, group). The password for the users in LDAP is also placed in LDAP.
One extra feature supported is the fact that we need to be able to login to our servers with a normal unix account (root) when there is trouble with LDAP.
Let's start with the auth section:
auth required pam_env.so auth optional pam_faildelay.so delay=3000000 auth requisite pam_nologin.so auth [success=ok ignore=ignore user_unknown=ignore default=die] pam_securetty.so auth required pam_shells.so auth optional pam_issue.so issue=/etc/issue auth optional pam_group.so # We assume that UIDs above 500 are in LDAP # If LDAP fails we want to still be able to login through local accounts auth sufficient pam_unix.so nullok auth requisite pam_succeed_if.so uid >= 500 quiet auth sufficient pam_ldap.so use_first_pass auth required pam_deny.so
Next we adjust the account section:
account requisite pam_time.so account required pam_access.so # If the user id is below 500 end the account section, if LDAP failes # we can still login with a local account account required pam_unix.so account sufficient pam_succeed_if.so uid < 500 quit account [default=bad success=ok user_unknown=ignore] pam_ldap.so account required pam_permit.so
Then the session section:
session required pam_env.so readenv=1 envfile=/etc/environment session required pam_env.so readenv=1 envfile=/etc/sysconfig/i18n session required pam_limits.so session optional pam_umask.so umask=0077 session optional pam_lastlog.so session optional pam_motd.so session optional pam_mail.so standard session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 session required pam_unix.so
And last the password section:
# This is NOT tested # We need pam_ldap.so to set the password in LDAP # Additional rules we might need: # password sufficient pam_unix.so md5 obscure min=4 max=8 nullok try_first_pass # password sufficient pam_ldap.so password required pam_cracklib.so retry=3 minlen=6 difok=3 password sufficient pam_unix.so use_authtok md5 password required pam_ldap.so use_authtok password required pam_deny.so
Only tested with LDAP, kerberos still needs testing.
This example expands the above one, with kerberos. The users above UID 500 are still in LDAP, but their password is stored in kerberos.
NOTE: Debian supplies: http://www.eyrie.org/~eagle/software/pam-krb5/
RHEL supplies: http://people.redhat.com/nalin/pam_krb5/
auth required pam_env.so auth optional pam_faildelay.so delay=3000000 auth requisite pam_nologin.so auth [success=ok ignore=ignore user_unknown=ignore default=die] pam_securetty.so auth required pam_shells.so auth optional pam_issue.so issue=/etc/issue auth optional pam_group.so # pam_ldap.so is in here for migration purposes, when all your # users are kerberized you can remove the pam_ldap.so line auth sufficient pam_unix.so nullok try_first_pass auth requisite pam_succeed_if.so uid >= 500 quiet auth sufficient pam_ldap.so use_first_pass auth sufficient pam_krb5.so use_first_pass auth required pam_deny.so account requisite pam_time.so account required pam_access.so account sufficient pam_unix.so broken_shadow account sufficient pam_succeed_if.so uid < 500 quiet account required pam_ldap.so account [default=bad success=ok user_unknown=ignore] pam_krb5.so account required pam_permit.so session required pam_env.so readenv=1 envfile=/etc/environment session required pam_env.so readenv=1 envfile=/etc/sysconfig/i18n session required pam_limits.so session optional pam_umask.so umask=0077 session optional pam_lastlog.so session optional pam_motd.so session optional pam_mail.so standard session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 # pam_ldap.so for session? session optional pam_keyinit.so revoke session required pam_unix.so session optional pam_krb5.so minimum_uid=500 # Set password in krb database password requisite pam_cracklib.so try_first_pass retry=3 password sufficient pam_unix.so md5 shadow nullok use_authtok password required pam_krb5.so use_authtok clear_on_fail password required pam_deny.so