The PAM API offers six different authentication primitives grouped in four facilities, which are described below.
Authentication. This facility concerns itself with authenticating the applicant and establishing the account credentials. It provides two primitives:
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:
pam_acct_mgmt(3) verifies that the requested account is available.
Session management. This facility handles tasks associated with session set-up and tear-down, such as login accounting. It provides two primitives:
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.
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.
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.
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're not truly versioned, because the number is a part of the module name and must be included in the configuration.
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:
Success is required, but the chain continues no matter what this module returns, so that later modules can override it.
A negative result from this module will immediately terminate the chain and deny the request.
A positive result from this module will immediately terminate the chain and grant the request. On failure, the chain continues.
A negative result from this module will be ignored.
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 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.
The lifecycle of a typical PAM transaction is described below. Note that if this 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_authenticate(3) to authenticate the applicant.
The server calls pam_acct_mgmt(3) 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.
Once the server is done serving the client, it calls pam_close_session(3) to tear down the session.
Finally, the server calls pam_end(3) to notify the PAM library that it is done and that it can release whatever resources it has allocated in the course of the transaction.
This, and other documents, can be downloaded from ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
For questions about FreeBSD, read the
before contacting <questions@FreeBSD.org>.
For questions about this documentation, e-mail <doc@FreeBSD.org>.