The traditional PAM policy file is /etc/pam.conf. This file contains all the PAM policies for your system. Each line of the file describes one step in a chain, as shown below:
login auth required pam_nologin.so no_warn
The fields are, in order: service name, facility name, control flag, module name, and module arguments. Any additional fields are interpreted as additional module arguments.
A separate chain is constructed for each service / facility pair, so while the order in which lines for the same service and facility appear is significant, the order in which the individual services and facilities are listed is not. The examples in the original PAM paper grouped configuration lines by facility, and the Solaris™ stock pam.conf still does that, but FreeBSD's stock configuration groups configuration lines by service. Either way is fine; either way makes equal sense.
OpenPAM and Linux-PAM support an alternate configuration mechanism, which is the preferred mechanism in FreeBSD. In this scheme, each policy is contained in a separate file bearing the name of the service it applies to. These files are stored in /etc/pam.d/.
These per-service policy files have only four fields instead of pam.conf's five: the service name field is omitted. Thus, instead of the sample pam.conf line from the previous section, one would have the following line in /etc/pam.d/login:
auth required pam_nologin.so no_warn
As a consequence of this simplified syntax, it is possible to use the same policy for multiple services by linking each service name to a same policy file. For instance, to use the same policy for the su and sudo services, one could do as follows:
# cd /etc/pam.d # ln -s su sudo
This works because the service name is determined from the file name rather than specified in the policy file, so the same file can be used for multiple differently-named services.
Since each service's policy is stored in a separate file, the pam.d mechanism also makes it very easy to install additional policies for third-party software packages.
As we have seen above, PAM policies can be found in a number of places. What happens if policies for the same service exist in multiple places?
It is essential to understand that PAM's configuration system is centered on chains.
As explained in the PAM policy files section, each line in /etc/pam.conf consists of four or more fields: the service name, the facility name, the control flag, the module name, and zero or more module arguments.
The service name is generally (though not always) the name of the application the statement applies to. If you are unsure, refer to the individual application's documentation to determine what service name it uses.
Note that if you use /etc/pam.d/ instead of /etc/pam.conf, the service name is specified by the name of the policy file, and omitted from the actual configuration lines, which then start with the facility name.
The facility is one of the four facility keywords described in the Facilities and primitives section.
Likewise, the control flag is one of the four keywords described in the Chains and policies section, describing how to interpret the return code from the module. Linux-PAM supports an alternate syntax that lets you specify the action to associate with each possible return code, but this should be avoided as it is non-standard and closely tied in with the way Linux-PAM dispatches service calls (which differs greatly from the way Solaris and OpenPAM do it.) Unsurprisingly, OpenPAM does not support this syntax.
To configure PAM correctly, it is essential to understand how policies are interpreted.
When an application calls pam_start(3), the PAM library loads the policy for the specified service and constructs four module chains (one for each facility.) If one or more of these chains are empty, the corresponding chains from the policy for the other service are substituted.
When the application later calls one of the six PAM primitives, the PAM library retrieves the chain for the corresponding facility and calls the appropriate service function in each module listed in the chain, in the order in which they were listed in the configuration. After each call to a service function, the module type and the error code returned by the service function are used to determine what happens next. With a few exceptions, which we discuss below, the following table applies:
Table 1. PAM chain execution summary
PAM_SUCCESS | PAM_IGNORE | other | |
---|---|---|---|
binding | if (!fail) break; | - | fail = true; |
required | - | - | fail = true; |
requisite | - | - | fail = true; break; |
sufficient | if (!fail) break; | - | - |
optional | - | - | - |
If fail
is true at the end of a chain, or when a
“break” is reached, the dispatcher returns the error code returned by the
first module that failed. Otherwise, it returns PAM_SUCCESS.
The first exception of note is that the error code PAM_NEW_AUTHTOK_REQD is treated like a success, except that if no module failed, and at least one module returned PAM_NEW_AUTHTOK_REQD, the dispatcher will return PAM_NEW_AUTHTOK_REQD.
The second exception is that pam_setcred(3) treats binding and sufficient modules as if they were required.
The third and final exception is that pam_chauthtok(3) runs the entire chain twice (once for preliminary checks and once to actually set the password), and in the preliminary phase it treats binding and sufficient modules as if they were required.