3.Â PAM Essentials

3.1.Â Facilities and
primitives

The PAM API offers six different authentication primitives
grouped in four facilities, which are described below.

auth

Authentication. This facility
concerns itself with authenticating the applicant and
establishing the account credentials. It provides two
primitives:

pam_authenticate(3) authenticates the
applicant, usually by requesting an authentication
token and comparing it with a value stored in a
database or obtained from an authentication
server.

pam_setcred(3) establishes account
credentials such as user ID, group membership and
resource limits.

account

Account management. This
facility handles non-authentication-related issues of
account availability, such as access restrictions based
on the time of day or the server's work load. It
provides a single primitive:

Password management. This
facility is used to change the authentication token
associated with an account, either because it has
expired or because the user wishes to change it. It
provides a single primitive:

pam_chauthtok(3) changes the authentication
token, optionally verifying that it is sufficiently
hard to guess, has not been used previously,
etc.

3.2.Â Modules

Modules are a very central concept in PAM; after all,
they are the “M” in “PAM”. A PAM
module is a self-contained piece of program code that
implements the primitives in one or more facilities for one
particular mechanism; possible mechanisms for the
authentication facility, for instance, include the UNIXÂ®
password database, NIS, LDAP and Radius.

3.2.1.Â Module Naming

FreeBSD implements each mechanism in a single module,
named
pam_mechanism.so
(for instance, pam_unix.so for the UNIXÂ®
mechanism.) Other implementations sometimes have separate
modules for separate facilities, and include the facility
name as well as the mechanism name in the module name. To
name one example, Solaris™ has a
pam_dial_auth.so.1 module which is
commonly used to authenticate dialup users.

3.2.2.Â Module Versioning

FreeBSD's original PAM implementation, based on
Linux-PAM, did not use version numbers for PAM modules.
This would commonly cause problems with legacy applications,
which might be linked against older versions of the system
libraries, as there was no way to load a matching version of
the required modules.

OpenPAM, on the other hand, looks for modules that have
the same version number as the PAM library (currently 2),
and only falls back to an unversioned module if no versioned
module could be loaded. Thus legacy modules can be provided
for legacy applications, while allowing new (or newly built)
applications to take advantage of the most recent
modules.

Although Solaris™ PAM modules commonly have a version
number, they are not truly versioned, because the number is a
part of the module name and must be included in the
configuration.

3.3.Â Chains and
policies

When a server initiates a PAM transaction, the PAM library
tries to load a policy for the service specified in the
pam_start(3) call. The policy specifies how
authentication requests should be processed, and is defined in
a configuration file. This is the other central concept in
PAM: the possibility for the admin to tune the system security
policy (in the wider sense of the word) simply by editing a
text file.

A policy consists of four chains, one for each of the four
PAM facilities. Each chain is a sequence of configuration
statements, each specifying a module to invoke, some
(optional) parameters to pass to the module, and a control
flag that describes how to interpret the return code from the
module.

Understanding the control flags is essential to
understanding PAM configuration files. There are four
different control flags:

binding

If the module succeeds and no earlier module in the
chain has failed, the chain is immediately terminated
and the request is granted. If the module fails, the
rest of the chain is executed, but the request is
ultimately denied.

This control flag was introduced by Sun in Solaris™ 9
(SunOS™ 5.9), and is also supported by OpenPAM.

required

If the module succeeds, the rest of the chain is
executed, and the request is granted unless some other
module fails. If the module fails, the rest of the
chain is also executed, but the request is ultimately
denied.

requisite

If the module succeeds, the rest of the chain is
executed, and the request is granted unless some other
module fails. If the module fails, the chain is
immediately terminated and the request is denied.

sufficient

If the module succeeds and no earlier module in the
chain has failed, the chain is immediately terminated
and the request is granted. If the module fails, the
module is ignored and the rest of the chain is
executed.

As the semantics of this flag may be somewhat
confusing, especially when it is used for the last
module in a chain, it is recommended that the
binding control flag be used instead
if the implementation supports it.

optional

The module is executed, but its result is ignored.
If all modules in a chain are marked
optional, all requests will always be
granted.

When a server invokes one of the six PAM primitives, PAM
retrieves the chain for the facility the primitive belongs to,
and invokes each of the modules listed in the chain, in the
order they are listed, until it reaches the end, or determines
that no further processing is necessary (either because a
binding or
sufficient module succeeded, or because a
requisite module failed.) The request is
granted if and only if at least one module was invoked, and
all non-optional modules succeeded.

Note that it is possible, though not very common, to have
the same module listed several times in the same chain. For
instance, a module that looks up user names and passwords in a
directory server could be invoked multiple times with
different parameters specifying different directory servers to
contact. PAM treat different occurrences of the same module
in the same chain as different, unrelated modules.

3.4.Â Transactions

The lifecycle of a typical PAM transaction is described
below. Note that if any of these steps fails, the server
should report a suitable error message to the client and abort
the transaction.

If necessary, the server obtains arbitrator
credentials through a mechanism independent of
PAM—most commonly by virtue of having been started
by root, or of being setuid
root.

The server calls pam_start(3) to initialize the
PAM library and specify its service name and the target
account, and register a suitable conversation
function.

The server obtains various information relating to the
transaction (such as the applicant's user name and the
name of the host the client runs on) and submits it to PAM
using pam_set_item(3).

The server calls pam_acct_mgmt(3) to verify that the
requested account is available and valid. If the password
is correct but has expired, pam_acct_mgmt(3) will
return PAM_NEW_AUTHTOK_REQD instead of
PAM_SUCCESS.

If the previous step returned
PAM_NEW_AUTHTOK_REQD, the server now
calls pam_chauthtok(3) to force the client to change
the authentication token for the requested account.

Now that the applicant has been properly
authenticated, the server calls pam_setcred(3) to
establish the credentials of the requested account. It is
able to do this because it acts on behalf of the
arbitrator, and holds the arbitrator's credentials.

Once the correct credentials have been established,
the server calls pam_open_session(3) to set up the
session.

The server now performs whatever service the client
requested—for instance, provide the applicant with a
shell.