Modern Linux systems use Pluggable Authentication Modules (PAMs) to provide flexible authentication for services and applications. Here are the gory details you'll need in order to use PAMs to quickly and flexibly secure your systems.
Many Linux applications require authentication of one type or another. In days gone by, each authentication-aware application was compiled with hardwired information about the authentication mechanism used by the system on which it was running. Changing or enhancing a system's authentication mechanism therefore required all such applications to be updated and recompiled, which is tedious even when you have the source code for all of the relevant applications on your system.
Enter PAMs, which provide a flexible and dynamic mechanism for authenticating any application or service that uses them. Applications or services compiled with the Linux-PAM library use text-format configuration files to identify their authentication requirements. Using PAMs on your system lets you modify authentication requirements or integrate new authentication mechanisms by simply adding entries to the PAM configuration file that is used by a specific application or service.
Though the information contained here may seem like overkill at first glance, knowing about PAMs and how PAM configuration files work is necessary background for the next four hacks, which explain how to integrate specific types of modern authentication into your Linux system without rewriting or recompiling the wheel. Read on, sysadmins!
PAMs are shared library modules that are automatically loaded by applications that were compiled with the primary Linux-PAM authentication library. Applications that use PAMs (or PAM modules, are they're sometimes called) are typically referred to as PAM-aware applications.
PAMs satisfy different parts of the authentication requirements for PAM-aware applications, much like reusable code and libraries do for applications in general. For example, a PAM-aware version of the login program can invoke a variety of PAMs that check things such as whether the user logging in as root is on a terminal listed as a secure terminal, whether users are allowed to log in on the system at the moment, and other similar authentication requirements. Because PAMs are shared library modules, a PAM-aware version of the rsh program can reuse the same "are users allowed to log in on the system now?" PAM as the PAM-aware version of login, but then apply other rules that are more relevant to rsh than to login. PAM modules themselves are now typically stored in the directory /lib/security, though some older Linux distributions stored PAMs in /usr/lib/security.
The PAMs used by different PAM-aware applications are defined in one of two ways. In modern PAM implementations, they are controlled by application-specific configuration files found in the directory /etc/pam.d. In older PAM implementations, all PAM modules used by the applications on a system were defined in a single central configuration file, /etc/pam.conf. The older approach is still supported, but it's deprecated—to maintain backward compatibility while encouraging the modern approach, the contents of the directory /etc/pam.d are used instead of the /etc/pam.conf file if both exist on your system. This hack focuses on PAM configuration files in /etc/pam.d, since that's the way PAMs are used on most modern systems.
Each PAM configuration file in /etc/pam.d has the same name as the PAM-aware application or service it is associated with and contains the PAM rules used during its authentication process. The name of the configuration file to use is derived from the first parameter passed to the Linux-PAM library's pam_start()
function, which is the name of the service that is being authenticated (often the same as the name of the application, for convenience's sake). These files can also contain comments—any characters on a line that follow the traditional hash mark (#) are interpreted as a comment.
Each non-comment line in one of the files in /etc/pam.d defines how a single PAM module is used as part of the authentication process for the associated application or service. Each of these files can contain four fields separated by whitespace, the first three of which are mandatory. These fields have the following meaning and content:
-
module-type
The type of PAM module defined on the line. A PAM module's type defines how it is used during the authentication process. Valid values are:
-
auth
Identifies an authentication check to verify the user's identity or that system requirements have been met. Common system requirements are that a service can be started at the current time (for example, that /etc/nologin does not exist when a user is trying to log in), that an acceptable device is being used (i.e., the device is listed in /etc/securetty), whether the user is already the root user, and so on.
-
account
Verifies whether the user can authenticate based on system requirements such as whether the user has a valid account, the maximum number of users on the system, the device being used to access the system, whether the user has access to the requested application or service, and so on.
-
password
Verifies a user's ability to update authentication mechanisms. There is usually one module of type
password
for eachauth
entry that is tied to an authentication mechanism that can be updated.-
session
Identifies modules associated with tasks that must be done before the associated service or application is activated, or just before the termination of that service or application. Modules of this type typically perform system functions such as mounting directories, logging audit trail information, or guaranteeing that system resources are available.
-
-
control-flag
The implications of the return value from the specified PAM module. Valid values are:
-
required
Indicates that success of the PAM module is mandatory for the specified module type. The failure of any PAM marked as required for a specific module-type (such as all labeled as
auth
) is reported to the associated application or service only after allrequired
PAMs for that module type have been executed.-
requisite
Indicates that failure of the PAM module will immediately be reported to the associated application or service.
-
sufficient
Indicates that success of the PAM module satisfies the authentication requirements of this module type. If no previous
required
PAM has failed, no other PAMs for the associated module type are executed. Failure of a PAM identified assufficient
is ignored as long as subsequentrequired
modules for that module type return success. If a previousrequired
PAM has failed, the success of a PAM marked assufficient
is ignored.-
optional
Indicates that success of the PAM module is not critical to the application or service unless it is the only PAM for a specified module type. If it is, its success or failure determines the success or failure of the specified module type.
-
-
module-path
The name of the PAM module associated with this entry. By default, PAM modules are located in /lib/security, but this field can also identify modules located in other directories by specifying the absolute path and filename of a PAM module.
-
arguments
Optional, module-specific arguments.
Well, that was mind-numbing but necessary reference information. To see all this in action, let's look at an example.
The configuration file for the PAMs used by the login program is the file /etc/pam.d/login. On a Red Hat system of recent vintage, this file contains the following entries:
#%PAM-1.0 auth required pam_securetty.so auth required pam_stack.so service=system-auth auth required pam_nologin.so account required pam_stack.so service=system-auth password required pam_stack.so service=system-auth session required pam_stack.so service=system-auth session optional pam_console.so
The first line is a comment that identifies this PAM as conforming to the PAM 1.0 specification.
The second, third, and fourth lines define the auth
(authentication) requirements for system logins, all of which must succeed because they are identified as required
. The second line invokes the PAM module pam_securetty.so to check whether the user is logged in on a secure terminal, as defined in the file /etc/securetty. The third line invokes the pam_stack.so PAM module, a clever module used primarily on Red Hat–inspired systems that enables you to call the entire set of PAM requirements defined for a different service or application (and thus described in a separate file by that name in /etc/pam.d). In this case it calls the set (stack) of requirements defined for the system-auth service. We'll look at that later—for now, it's sufficient to know that the authentication requirements specified in that file must be satisfied. Finally, to wrap up the auth
module-type entries for the login program, the fourth line invokes the pam_nologin.so PAM module to check whether logins are allowed on the system at the current time.
The fifth line in this file identifies the requirements for the account
module-type, which in this case uses the pam_stack.so PAM module to verify that the set of requirements for the system-auth service have been satisfied.
Similarly, the sixth line in this file identifies the requirements for the password
module-type, which also uses the pam_stack.so PAM module to verify that the set of requirements for the system-auth service have been satisfied.
Finally, the seventh and eighth lines in this file identify session
requirements for the login program. The seventh line uses the familiar pam_stack.so PAM module to verify that the set of requirements for the system-auth service were satisfied. The eighth line in this file defines an optional
requirement that the user be running on the console. If this module succeeds, the user is granted any additional privileges associated with this PAM module. If this module fails, authentication succeeds as long as the previous required
modules have completed successfully, but the user doesn't get the bonus privileges.
Now let's look at the /etc/pam.d/system-auth file on the same system, which contains the following:
#%PAM-1.0 # This file is auto-generated. # User changes will be destroyed the next time authconfig is run. auth required /lib/security/pam_env.so auth sufficient /lib/security/pam_unix.so likeauth nullok auth required /lib/security/pam_deny.so account required /lib/security/pam_unix.so password required /lib/security/pam_cracklib.so retry=3 type= password sufficient /lib/security/pam_unix.so nullok use_authtok md5 shadow password required /lib/security/pam_deny.so session required /lib/security/pam_limits.so session required /lib/security/pam_unix.so
Now that you grok PAM configuration files, you can see that the auth
module-type first requires that the pam_env.so module succeed, then tries the pam_unix.so module, which is a generic module that can perform auth, account, password
, and session
functions (depending on how it is called). When called for the auth
module-type, it verifies a user's identity, sets credentials if successful, and so on. If this module succeeds, the following required
entry for the pam_deny.so module isn't executed. If the pam_unix.so module fails, pam_deny.so executes, which returns a failure code to ensure that the specified module-type will fail. In our login example, where another auth
request (for pam_nologin.so) follows the invocation of the contents of the system-auth PAM stack, that auth
request is executed, but its value isn't important because pam_deny.so is required and has already indicated failure.
Next, the account
module-type requires that the pam_unix.so module succeed—in this case, pam_unix.so provides default account checks.
Following the account
check, the first password module-type line specifies that pam_cracklib.so be used when setting passwords to select a password that isn't easily cracked, based on the contents of a database of easily cracked passwords (/usr/lib/cracklib_dict.pwd on Red Hat systems). Arguments to this module give the user three chances to select a password (by passing the argument retry=3
) and specify that this password isn't for any specific type of authentication, such as LDAP or NIS (by passing a null name using the type=
argument). If this module succeeds, the second password
module-type line invokes the standard pam_unix.so module, with arguments specifying that null passwords are acceptable but can't be set by users (nullok
), not to prompt for a password but to use any password that succeeded in a previous PAM of module-type password (use_authtok)
, that passwords use md5 hashing by default (md5
), and that the system uses the /etc/shadow file to hold passwords (shadow
). If this module fails, the user is denied access to the application or service that invoked the system-auth service through the next line, which invokes the pam_deny.so module to ensure failure of the password
auth-type.
Finally, the session
checks set system limits using the pam_limits.so module, which provides functions to initiate and terminate sessions.
If you need to take a few aspirin after parsing each entry in these files, join the club. But even though it's a pain, security is one of any sysadmin's most important responsibilities. If it's any consolation, think how complex the code to implement all of this would have been without the flexibility that PAMs provide!
The text-format files in /etc/pam.d control the PAMs associated with each authentication-aware application or service. Some of these PAMs themselves use optional configuration files to further refine their behavior. The configuration files for individual PAMs are located in the directory /etc/security. Though these files must exist, they do not need to contain any useful information—they are there in case you want to take advantage of the advanced configuration options that they provide. Here is a list of the files in this directory that are found on a variety of Linux systems:
- access.conf
Provides fine-grained access control for logins. Used by the pam_access.so module.
- console.apps
A directory that contains a file for each privileged application that a user can use from the console. The name of each file is the same as the base-name of the application with which it is associated. These files must exist but can be empty. When they have contents, these files typically contain environment variables associated with the applications that match their names. Used by the pam_console.so module on Red Hat–inspired Linux systems.
- console.perms
Defines the device permissions granted to privileged users when logged in on the console, and the permissions to which those devices revert when the user logs out. Used by the pam_console.so module on Red Hat–inspired Linux systems.
- group.conf
Provides per-session group membership control. Used by the pam_group.so module.
- limits.conf
Provides a per-user mechanism for setting system resource limits. Used by the pam_limits.so module.
- pam_env.conf
Provides a mechanism for setting environment variables to specific values. Used by the pam_env.so module.
- pam_pwcheck.conf
Provides options for identifying the mechanism used when evaluating password strength. Used by the pam_pwcheck.so module on SUSE-inspired Linux systems.
- pam_unix2.conf
Provides options for advanced configuration of traditional password checking. Used by the pam_unix2.so module on SUSE-inspired systems.
- time.conf
Provides a mechanism for imposing general or user-specific time restrictions for system services and applications. Used by the pam_time.so module.
Applications that use PAMs are very powerful, and correct configuration is very important. However, the Linux-PAM library does provide a default configuration file for any applications and services that do not have their own configuration files. This is the file /etc/pam.d/other. Since a missing configuration file generally indicates a misconfigured system (or that someone has imported a PAM-aware binary without thinking things through), the /etc/pam.d/other file implements extremely paranoid security, as in the following example:
#%PAM-1.0 auth required pam_deny.so account required pam_deny.so password required pam_deny.so session required pam_deny.so
In this example, any request for any module-type that falls through to this PAM configuration file will return a failure code. A slightly more useful version of this file is the following:
#%PAM-1.0 auth required pam_deny.so auth required pam_warn.so account required pam_deny.so account required pam_warn.so password required pam_deny.so password required pam_warn.so session required pam_deny.so session required pam_warn.so
Because subsequent required
entries for a given module-type are still executed, each module-type entry first executes the pam_deny.so PAM, which denies access to the requested service, and then also executes the pam_warn.so PAM, which logs a warning message to the system log.
man
pam
(wherepam
is the name of a PAM module without the .so extension)
Get Linux Server Hacks, Volume Two now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.