PAM

Debian Packages

libpam-runtime
libpam0g
libpam-doc


References

PAM web site 
http://www.kernel.org/pub/linux/libs/pam/
System Administrator's Guide 
http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/Linux-PAM_SAG.html
Local documentation 1 
/usr/share/doc/libpam-doc/Linux-PAM_SAG.txt.gz
Local documentation 2 
each PAM has its own man page (e.g. man pam_unix)
Wikipedia 
http://en.wikipedia.org/wiki/Pluggable_Authentication_Modules


Glossary

PAM 
Pluggable Authentication Modules. The name of the library/framework. Can also be used to refer to the modules themselves ("the PAM" (singular), or "the PAMs" (plural))
Conversation function 
A callback function that clients must supply PAM with; PAM modules can use the conversation function to acquire information from the client.
Authentication token 
Typically a password.


Overview: What is PAM

PAM is a framework that applications (services) can use to authenticate users and perform other authentication-related tasks. PAM decouples applications (services) from the concrete method of authentication that the application (service) should use.

A rough overview of how an authentication session might look when PAM is involved:

  • the user provides his credentials (usually a user name and a password) to some piece of application software
  • the application uses the API of the PAM system library to delegate checking whether the credentials are valid
  • the application identifies itself to PAM with a "service name"
  • PAM maps the service name to a configuration file in /etc/pam.d; for instance, a service named "imap" requires /etc/pam.d/imap to be present
  • PAM evaluates the configuration file to determine which authentication mechanism it should use to perform the check
  • the result of the check is reported back to the application


PAM service types

The PAM library provides different service types to its clients, each type deals with a separate type of management task. Some modules (e.g. pam_unix) can be used for all service types, while others provide only one or two service types (e.g. pam_env).

auth 
This service type provides authentication management. A module that provides this service type provides two aspects of authenticating the user: Firstly, it establishes that the user is who they claim to be, by instructing the application to prompt the user for a password or other means of identification. Secondly, the module can grant group membership or other privileges through its credential granting properties.
account 
This service type provides non-authentication based account management. A module that provides this service type is typically used to restrict/permit access to a service based on the time of day, currently available system resources (maximum number of users) or perhaps the location of the applicant user -- 'root' login only on the console.
password 
This service type provides password management. A module that provides this service type is required for updating the authentication token (e.g. a password) associated with the user. Typically, there is one module for each 'challenge/response' based authentication (auth) type.
session 
This service type provides session management. A module that provides this service type is associated with doing things that need to be done for the user before/after they can be given service. Such things include the logging of information concerning the opening/closing of some data exchange with a user, mounting directories, etc.


The configuration file

Overview

A service's PAM configuration file lists the modules that will do the authentication tasks required by the service, and the appropriate behavior of the PAM-API in the event that individual modules fail.

The filename of a PAM configuration file must be in lower case. It represents the name of a service, usually a familiar application name such as login, sshd, samba or imap. A configuration file with the service name other is reserved for providing defaults.

Each line in the configuration file is a rule. A number of rules may be stacked to combine the services of a number of PAMs for a given authentication task. The format of each rule is this:

<service-type> <control> <module-path> <module-arguments>


service-type field

The service-type field refers to the service type (see chapter above) that the rule corresponds to. Possible values are:

  • account
  • auth
  • password
  • session


control field

The control field indicates the behavior of the PAM-API should the module fail to succeed in its authentication task. There are two types of syntax for this control field: the simple one has a single simple keyword; the more complicated one - which is not further explored on this page - involves a square-bracketed selection of value=action pairs. Possible keywords for control are:

  • required : failure of such a PAM will ultimately lead to the PAM-API returning failure but only after the remaining stacked modules (for this service and type) have been invoked
  • requisite : like required, however, in the case that such a module returns a failure, control is directly returned to the application. The return value is that associated with the first required or requisite module to fail. Note, this flag can be used to protect against the possibility of a user getting the opportunity to enter a password over an unsafe medium. It is conceivable that such behavior might inform an attacker of valid accounts on a system. This possibility should be weighed against the not insignificant concerns of exposing a sensitive password in a hostile environment.
  • sufficient : success of such a module is enough to satisfy the authentication requirements of the stack of modules (if a prior required module has failed the success of this one is ignored). A failure of this module is not deemed as fatal to satisfying the application that this type has succeeded. If the module succeeds the PAM framework returns success to the application immediately without trying any other modules.
  • optional : the success or failure of this module is only important if it is the only module in the stack associated with this type.
  • include : include all lines of given type from the configuration file specified as an argument to this control.
  • substack : include all lines of given type from the configuration file specified as an argument to this control. This differs from include in that evaluation of the done and die actions in a substack does not cause skipping the rest of the complete module stack, but only of the substack. Jumps in a substack also can not make evaluation jump out of it, and the whole substack is counted as one module when the jump is done in a parent stack. The reset action will reset the state of a module stack to the state it was in as of beginning of the substack evaluation.


module-path field

module-path is either the full filename of the PAM (it begins with a '/'), or a relative pathname from the default module location (/lib/security on my Debian machine)


module-arguments field

module-arguments are a space separated list of tokens that can be used to modify the specific behavior of the given PAM. Such arguments are documented for each individual module. To include spaces in an argument it must be surrounded with square brackets.


Include files

Configuration files may include other files. For instance, /etc/pam.d/other has the following content:

@include common-auth
@include common-account
@include common-password
@include common-session


A module overview

Module Services provided Description Links Comments
pam_access.so all logdaemon style login access control based on login names, host or domain names, internet addresses or network numbers kernel.org
pam_cracklib.so all Checks the password against dictionary words kernel.org
pam_debug.so all Debug the PAM stack kernel.org
pam_deny.so all Locking-out PAM module kernel.org
pam_echo.so all Print text messages kernel.org
pam_env.so auth, session Set/unset environment variables kernel.org
pam_exec.so all Call an external command kernel.org
pam_faildelay.so auth Change the delay on failure per-application kernel.org
pam_filter.so all Filter module kernel.org
pam_ftp.so auth Module for anonymous access kernel.org
pam_group.so auth Module to modify group access kernel.org
pam_issue.so auth Add issue file to user prompt kernel.org
pam_keyinit.so session Display the keyinit file kernel.org
pam_lastlog.so session Display date of last login kernel.org
pam_limits.so session Limit resources kernel.org
pam_listfile.so all Deny or allow services based on an arbitrary file kernel.org
pam_localuser.so all Require users to be listed in /etc/passwd kernel.org
pam_loginuid.so session Record user's login uid to the process attribute kernel.org
pam_mail.so auth, account Inform about available mail kernel.org
pam_mkhomedir.so session Create users home directory kernel.org
pam_motd.so session Display the motd file kernel.org
pam_namespace.so session Setup a private namespace kernel.org
pam_nologin.so auth, acct Prevent non-root users from login kernel.org
pam_permit.so all The promiscuous module kernel.org
pam_rhosts.so auth Grant access using .rhosts file kernel.org
pam_rootok.so auth Gain only root access kernel.org
pam_securetty.so auth Limit root login to special devices kernel.org
pam_selinux.so session Set the default security context kernel.org
pam_shells.so auth, account Check for valid login shell kernel.org
pam_succeed_if.so all Test account characteristics kernel.org
pam_tally.so auth, account Login counter (tallying) module kernel.org
pam_time.so account Time controled access kernel.org
pam_umask.so session Set the file mode creation mask kernel.org
pam_unix.so all Traditional password authentication kernel.org
pam_userdb.so auth, account Authenticate against a db database kernel.org
pam_warn.so all Logs all PAM items kernel.org
pam_wheel.so auth, account Only permit root access to members of group wheel kernel.org
pam_xauth.so session Forward xauth keys between users kernel.org
pam_ldap.so all Authenticate against LDAP directories, and to change their passwords in the directory padl.com


Notes on specific module arguments

Overview

In the following sections, specific module arguments are discussed. The semantics of each argument is usually determined by quoting from the documentation of the pam_unix module. Hopefully, other modules retain these semantics.

Note: Usually PAMs have their own man page.


use_first_pass

pam_unix documents the semantics of this argument like this:

The argument use_first_pass forces the module to use a previous stacked modules password and will never prompt the user - if no password is available or the password is not appropriate, the user will be denied access.

Some modules that support this argument:

  • pam_unix
  • pam_ldap


try_first_pass

pam_unix documents the semantics of this argument like this:

Before prompting the user for their password, the module first tries the previous stacked module's password in case that satisfies this module as well.

Some modules that support this argument:

  • pam_unix
  • pam_ldap


use_authtok

pam_unix documents the semantics of this argument like this:

When password changing enforce the module to set the new password to the one provided by a previously stacked password module (this is used in the example of the stacking of the pam_cracklib module documented above).

Some modules that support this argument:

  • pam_unix
  • pam_ldap


nullok

pam_unix documents the semantics of this argument like this:

The default action of this module is to not permit the user access to a service if their official password is blank. The nullok argument overrides this default.

Some modules that support this argument:

  • pam_unix


nullok_secure

This argument results from a Debian-specific patch to pam_unix which has not yet made it into upstream. The semantics of this, as explained by a post of Debian maintainer Steve Langasek, is:

The nullok_secure option was added to support passwordless pam_unix logins only from ttys listed in /etc/securetty. It was added because nullok was not considered an appropriate option to configure for all services, but there was a need to support passwordless root logins on tty2 on newly installed Debian systems when base-config has not yet been run to configure a root password.

Some modules that support this argument:

  • pam_unix


Debian specifics

Debian uses PAM by default. Various packages place their service file into /etc/pam.d. Most of them (including the other pseudo-service) include one or more of the "common" files.

There are 4 "common" include files, one for each of the 4 service types. By default, these files all use the pam_unix module which uses the regular /etc/passwd, /etc/group and /etc/shadow files.

These are the default factory rules (comments stripped away):

account    required   pam_unix.so
auth       required   pam_unix.so nullok_secure
password   required   pam_unix.so nullok obscure min=4 max=8 md5
session    required   pam_unix.so


LDAP authentication

Debian packages

Install the following Debian packages to get LDAP support for PAM:

libpam-ldap
libpam-doc


References

Local documentation 1 
/usr/share/doc/libpam-ldap
Local documentation 2 
man pam_ldap

Of course, the OpenLDAP page in this wiki is also relevant.


Configuration

These are the questions asked by dpkg:

  • LDAP server URI = ldapi:///
  • Distinguished name of the search base = dc=herzbube,dc=ch
  • LDAP version to use = 3
  • Allow LDAP admin account to behave like local root? = No
    • Saying yes here (the default answer) will later ask for the DN of a "root" account
    • This "root" account DN will be used by pam_ldap when it is executed within a process for which geteuid() == 0
    • The idea is that the "root" DN has write access to the LDAP directory, and that pam_ldap can use this "root" DN e.g. when a password change is requested (this would work because /usr/bin/passwd has the setuid bit)
    • This is not necessary, however: the file /usr/share/doc/libpam-ldap/LDAP-Permissions.txt states that pam_ldap uses the user's DN for password changes
    • Because we have a special access rule in /etc/ldap/slapd.conf that allows the change of the userPassword attribute if the entry owning the attribute was used for authentication, the above behaviour of pam_ldap is therefore sufficient for password changes
    • Also see the notes further down for thoughts about saying "yes" to this question
  • Does the LDAP database require login? = Yes
    • We must say "yes" here because we have configured the LDAP server to disable anonymous binding
  • LDAP login user account = cn=readonly-users,ou=users,dc=herzbube,dc=ch
  • Password for LDAP login user = secret
  • Local encryption algorithm to use for passwords = clear
    • We must say "clear" here because the LDAP server stores passwords as SSHA hash
  • PAM profiles to enable
    • I don't know what to answer here, so I choose the default answer
    • The default answer enables the following profiles:
      • Unix authentication
      • LDAP Authentication
    • This DebConf question is called "libpam-runtime/profiles", i.e. the answer to the question is not stored together with the other answers


The answers are stored in

/etc/pam_ldap.conf


Some of the questions/answers are shared with the package libnss-ldap, so if that package has already been installed some questions may not be asked, the answers are simply taken from the DebConf database. To see a complete list of questions and answers that are stored in the DebConf database:

debconf-show libpam-ldap
# The answer to the question "PAM profiles to enable" is not stored
# under "libpam-ldap", so we need a second command to see that answer
debconf-show libpam-runtime


Notes regarding permissions:

  • The file /etc/pam_ldap.conf contains the password for the unprivileged LDAP user "auth". It is owned by root and has mode 644 (i.e. the file is world readable!!!).


Notes about the "root" DN:

  • If we say yes to the DebConf question "Allow LDAP admin account to behave like local root?", we must also specify a "root" DN
  • Usually I say "no" to the question, but I leave the following comments in this documentation if I re-decide at a later time
  • I would set the "root" DN to something like cn=libpam-ldap,ou=users,dc=herzbube,dc=ch
  • Under no circumstances would I give pam_ldap a "root" DN that actually has total super-user rights on the LDAP directory (e.g. a rootdn configuration in /etc/ldap/slapd.conf)
  • pam_ldap should only have write access to the ou=users subtree of the directory
  • The "root" DN password would be stored in /etc/pam_ldap.secret
  • The file would be owned by root and have mode 600


Directory modifications

After configuring libpam-ldap, modify the LDAP directory as follows:

  • Add an LDAP user cn=readonly-users,ou=users,dc=herzbube,dc=ch to the directory

Configure access rights in /etc/ldap/slapd.conf, then restart the LDAP daemon. The access rights can be derived from reading /usr/share/doc/libpam-ldap/LDAP-Permissions.txt:

  • Read-only access to the ou=users tree for readonly-users

User account LDAP entries must have the following structure so that pam_ldap can use them:

  • Must be located below ou=users,dc=herzbube,dc=ch (we have said so during the dpkg configuration process)
  • Must have an attribute uid whose value matches the user name provided to pam_ldap
  • Must have an attribute userPassword


Modify /etc/pam.d/common-* files

The default configuration provided by the Debian package(s) runs fine, no customization is necessary.


Obsolete PAM configuration to support LDAP

The information in this section is obsolete! The custom configuration described here might still work, but it is no longer necessary. I developed this custom configuration a long time ago when I was starting to work with LDAP. At that time I was still running Debian testing, first on some custom PC hardware and later on a MacMini. When I switched to running Debian stable (jessie) on a Dedicated Server, it turned out that the default configuration provided by the Debian package runs just fine. I'm keeping this section around for historical reasons.


Since most services include the common-* files, it makes sense to change these files to switch the entire system over to LDAP authentication in one go.

However, the matter is not resolved by simply replacing pam_unix.so with pam_ldap.so. This would require that system users (e.g. "root" and others) all need to have an LDAP entry. I don't care to maintain all these users in LDAP - for instance, if I install a Debian package and the installation process creates a new system user I would have to replicate this user in my LDAP directory. In addition, if the LDAP service ever goes down, I am completely locked out of the system because I cannot login anymore even with "root".

For these reasons, I implement the following scheme:

  • in its first attempt, PAM should try to consult the LDAP directory
  • if successful, stop here
  • if not successful (e.g. user was not found, or password did not match, or LDAP is down), fall back to traditional UNIX authentication (i.e. pam_unix.so)

This works for the following situations:

  • if a user exists in LDAP and the password matches, authentication succeeds through LDAP
  • if a user exists in LDAP and the password does not match: PAM will try traditional UNIX authentication, but I expect that the user does not exist in /etc/passwd, so both LDAP and traditional UNIX authentication fail
  • if a user does not exist in LDAP, traditional UNIX authentication rules apply


common-account

osgiliath:/etc/pam.d# cat common-account 
account [success=1 default=ignore] pam_ldap.so
account required pam_unix.so
account required pam_permit.so

common-auth

osgiliath:/etc/pam.d# cat common-auth
# Line 1: Allow LDAP authentication to fail so that traditional UNIX
# authentication can handle system accounts (such as root) which are not
# maintained in LDAP. If LDAP authentication fails because the password did
# not match, it is expected that the user does not exist in /etc/passwd,
# so traditional UNIX authentication will fail, too.
#
# Line 2: use_first_pass lets pam_unix reuse the password that pam_ldap
# acquired from the user. If this option is missing, pam_unix will prompt
# the user for the password a second time.
#
# Line 3: This line is needed, so "success=1" in line 1 can skip over one
# module and still has a module to jump to. Without that, PAM segfaults!
auth [success=1 default=ignore] pam_ldap.so
auth required pam_unix.so nullok_secure use_first_pass
auth required pam_permit.so

common-password

osgiliath:/etc/pam.d# cat common-password
# Line 2: Don't specify use_first_pass or use_authtok! pam_ldap does not
# ask for a password if the user does not exist in LDAP, so pam_unix
# cannot reuse a previously entered password and will therefore always fail.
password [success=1 default=ignore] pam_ldap.so
password required pam_unix.so nullok obscure min=4 max=8 md5
password required pam_permit.so

common-session

osgiliath:/etc/pam.d# cat common-session 
session [success=1 default=ignore] pam_ldap.so
session required pam_unix.so
session required pam_permit.so