PAM&mdash;Securing Linux Boxes Everywhere

If you are into British detective fiction and names like Sherlock Holmes,
Sexton Blake, Mr. J. G. Reeder, Miss Marple, Hercule Poirot, Father Brown,
Dr. John Evelyn Thorndyke and Lord Peter Wimsey mean anything to you,
you also probably will recognize E. W. Hornung's (brother-in-law to
Sir Arthur Conan Doyle, the creator of Sherlock Holmes) character: the
white-glove thief, Raffles. In the “A Jubilee Present” short story,
the thief is fascinated with an antique gold cup, displayed at the
British Museum. Upon finding only one guard, Raffles questions him on
the perceived lack of security and gets the confident answer, “You see,
sir, it's early as yet; in a few minutes these here rooms will fill up;
and there's safety in numbers, as they say.” With Linux, rather
than security by
numbers (which eventually is no good for the poor guard; see
Resources for a link to the complete story), security is managed by
Pluggable Authentication Modules (PAM). In this article, we
study PAM's features, configuration and usage.

Let's start at the beginning and consider how an application
authenticates a user. Without a common, basic
mechanism, each application would need to be programmed with particular
authentication logic, such as checking the /etc/passwd for a valid user
and password. But, what if you have several different applications
that need authentication? Do you include the same specific logic in all
of them? And, what if your security requirements vary? Would you
then have to modify and recompile all those applications? This wouldn't
be a practical method and surely would become a vulnerability. How
would you be sure that all applications were duly updated and correctly
implemented your new specifications?

The PAM Project provides a solution by adding an extra layer. Programs
that need authentication use a standard library or API (Application
Programming Interface), and system administrators can configure
what checks will be done by that library separately. (Checks are implemented via
independent modules; you even can program your own modules.) This way,
you can change your security checks dynamically, and all utilities
will follow your new rules automatically. In other words, you can modify the
authentication mechanism used by any PAM-aware application, without ever
touching the application itself. For programmers, this also is a good
thing, because they need not be concerned with the mechanisms that will be
used.
Simply by using the PAM libraries, whenever the application is run,
the appropriate checks will be made (Figure 1).

The PAM library breaks down authentication in four areas or groups (Table
1). Note that all applications won't always require the four
previous actions. For example, the passwd command will require
only the last group. (Quick tip: how can you learn whether an application uses
PAM? Use ldd to print the shared libraries required by the program,
and check for libpam.so; see Listing 1 for an example.)

Figure 1. Whenever an application does an authentication request, the
PAM library executes whatever modules are specified in the configuration
file and decides whether to approve (success) or reject (failure)
the request.

Listing 1. To learn whether a program uses PAM, use ldd and look for the
libpam.so library. You need to provide the full path to the
program; use whereis if you don't know it.

Table 1. PAM has four groups of checks, organized as stacks.
The groups that will be used depend on what the user requires.

auth

Related to user identification, such as when a user needs
to enter a password. This is usually the first set of checks.

account

Has to do with user account management, including
checking whether a password has expired or whether there are time-access
restrictions. Once users have been identified
by the authentication modules, the account modules
will determine whether they can be granted access.

session

Deals with connection management, with actions such
as logging entries or activities, or doing some cleanup
actions after the session ends.

password

Includes functions such as updating users' passwords.

Table 2. For each stack, modules are executed in sequence, depending
on their control flags. You
must specify whether the corresponding check is mandatory, optional and so
on.

required

This module must end successfully. If it doesn't, the overall result
will be failure. If all modules are labeled as required,
any single failure will deny authentication, although the other
modules in the stack will be tried anyway.

requisite

Works like required, but in case of failure, returns immediately,
without going through the rest of the stack.

sufficient

If this module ends successfully, other modules will be skipped,
and the overall result will be successful.

optional

If this module fails, the overall result will depend upon the other
modules. If there are no required or sufficient modules, at
least one optional module should end successfully to
allow authentication.