|< Free Open Study >|| |
This section focuses on configuring PAM to properly support and work with an application. This section has two goals. The first is obviously to explain how to configure and use PAM. The second goal is a bit deeper. The overall goal of this chapter is to demonstrate and discuss a variety of configuration techniques commonly used by programs. PAM uses a certain technique, and so it's a good example to add to the mix. After reading this section, you'll not only understand PAM, but you'll also have seen a distinctive configuration technique that may someday help you figure out a new program on your own.
PAM can use two different configuration file mechanisms. The first is a simple "flat" configuration file in the /etc directory, and the second is the drop-in configuration file directory approach. The format of the file is similar in both cases.
The drop-in configuration file directory approach is discussed extensively in Chapters 3 and 4. The flat file approach is discussed throughout this chapter.
In the first case, all the rules governing PAM's behavior on a particular system are contained in the file /etc/pam.conf. In the second case, files containing PAM rules for a particular service are placed in the /etc/pam.d/ directory. If the /etc/pam.d directory is present, then it overrides the /etc/pam.conf file even if it exists; that is, PAM ignores /etc/pam.conf if the /etc/pam.d directory is present.
In both cases, PAM is configured by rules placed into the files, where each line defines a rule. As is traditional of configuration files, the pound (#) character denotes a comment in the file (meaning that any text after the # symbol is ignored). Each rule is bound to a particular service (such as login for the system login service or ftp for an FTP server).
A program that uses PAM identifies itself by a service name. PAM then goes to its configuration and fetches and executes any rules that are defined for that service. PAM also has a catchall service named "other" that is executed when a program identifies itself as a service that PAM doesn't recognize.
These rules are then executed in order to determine whether the application's use is properly authenticated or to perform other tasks such as account management or session management. The next section discusses how the rules work together and interact to accomplish these tasks; the remainder of this section describes the format of a rule line.
Each rule has the following format:
service type control module arguments
Each element is discussed in the following sections.
The service is the name by which a program will identify itself. This name will be used to locate rules pertinent to the application. If the /etc/pam.conf file is being used, then the service element indicates which service the rule applies to.
If the /etc/pam.d directory is used in lieu of the single /etc/pam.conf file, however, then the rules for a given service are located in a file matching the service's name and the service element is not used. For example, the rules for the login service would be contained in a file named /etc/pam.d/login; since the name of the service is implicit in the file name, the service element can be omitted from the individual rules contained in the file. In contrast, if the /etc/pam.conf file is used, the services' rules are mixed together, and the service element is required to distinguish them.
The type defines the property the rule acts upon. The type element must be one of these values:
auth: The rule affects the authentication of the application's user.
session: The rule affects the application's environment for the duration of the login session.
account: The rule pertains to some permanent aspect of the user's account (other than the password), such as whether the account even exists.
password: The rule pertains to checking, changing, or otherwise interacting with the user's account.
A type of auth is used to determine whether the user is authentic. Typically, auth rules are used to physically validate credentials. This might involve comparing a password to see if it matches the official password, validating a "token" generated by a keychain token system, or authenticating against some external system such as a Kerberos server. An auth rule can also perform other checks; for example, it's common to find auth rules that automatically grant access if the user is already root.
A type of session typically performs ancillary or miscellaneous work required by the functioning of a program. For example, programs that need to use X can have a session rule that configures an xauth entry for a newly authenticated user. A session rule alters the environment of the application.
A type of account indicates that the rule is related to management of the actual user account. Account rules pertain strictly to the account and check things such as whether the account exists, what times of the day or night a user is allowed to log in, and so on. A common use of an account rule is to check to see if the user's account has been disabled and notify the user (and reject access) if that is the case.
A type of password indicates that the rule is related to the management of the user's password in some way, such as expiring a password or checking to see if a password is null (i.e., empty). A common use is to include a password rule that checks whether the account's password has expired and can prompt the user to change the password or eventually reject access entirely.
The control element defines the action to be taken by the rule, such as granting or rejecting access. The control element actually has two forms: a brief (also called historical) form, and a more complicated and powerful form. The longer form is quite a bit more powerful, but it is generally only used where very complicated rules are required. Since this is generally not the case on workstations and even servers, this book will only discuss the short form. Interested readers should consult the man page on PAM for information on the long form.
The short form of the control element must be one of the following four words:
required: Indicates that the PAM must be successful for the stack to succeed.
requisite: Just like required but terminates the PAM stack immediately (PAM stacks are discussed in the next section).
sufficient: Indicates that the success of this single rule is enough for the stack to succeed, and no further rules in the stack need be executed.
optional: Indicates that the success or failure of the rule isn't relevant (unless it's the only rule).
A required rule must be successful, or else the entire PAM stack will fail. A requisite rule is the same, but a failed requisite causes all subsequent rules to be ignored, while a required rule allows them to be executed even though the stack as a whole will fail. (See the next section for more information on PAM stacks.) Typically, it's better to use required than requisite, since the act of terminating a stack early itself can give information to an attacker. For example, if you never prompt for a password because the check to see if the account exists failed, then an attacker immediately knows to stop wasting time on that account.
A sufficient rule is able to "speak for" the entire stack—that is, the success of the rule is "sufficient" to approve the entire stack. An optional rule is always executed, but its success or failure isn't relevant to the stack. (However, if the optional rule is the only rule in the stack, then obviously it's the only rule that can apply, and so it isn't really "optional" and the stack is successful based on whether the single optional rule is successful.)
Generally, most auth rules in a stack will be marked as required in order to make sure that they are successful before granting access. Most session rules will be marked optional since typically they are only doing additional work for the sake of convenience. Rules marked as sufficient are typically auth rules, since they essentially bypass the rest of the stack.
The module is a path to the PAM that is to be used to physically execute the rule. A PAM is actually a standard dynamic shared object that implements the PAM API. The main PAM library (which is called by the application) loads the shared library and then executes its contents. PAMs are usually located in the /lib/security directory. (Note that they are on the root partition rather than the /usr partition, since they are required by the system during the bootup process.)
PAMs can be installed by the system administrator in order to support some desired feature, and each PAM generally has a separate function. For example, there might be one PAM for handling standard Unix username/password authentication and another for handling Kerberos authentication. Additionally, there would also be PAMs handling session and account rules. The module element essentially defines the specific auth, session, or account action to be taken.
It's possible for a given PAM to support multiple stack types; most actually do.
This element is used to pass additional arguments to the PAM specified in the rule. The format and meaning of any argument is specific to the PAM. Each PAM can define its own specific arguments, and the arguments element simply provides a way for PAMs to access their own custom parameters.
When an application attempts to authenticate a user, PAM looks up the rules for the pertinent service and type, and executes them in order. The set of rules that are applied to a given execution are referred to as a stack of PAM rules. This section discusses how PAM stacks are executed and how control flows through them. The next section discusses a sample file in detail.
A PAM stack is simply a list of rules. When all is normal, PAM simply processes each rule in turn, in the order in which it was defined. If each PAM executes successfully, then the stack as a whole is successful, and the application's call to PAM succeeds. However, when all is not normal, a variety of things can occur.
The most obvious case is when a rule marked required fails. For example, the user may enter an incorrect password for the account, which would cause that PAM to fail execution. In that case, any remaining rules will still execute, but the stack itself will fail regardless of whether the later rules succeed. This behavior is useful since you often don't want to override other rules simply because one failed; for example, one rule might be an account rule that must make an entry to a log, regardless of whether the login was successful.
A similar case occurs when a requisite rule fails. This type of rule works exactly like a required rule, but it terminates the stack immediately, and later rules are not executed. This "early return" notion is useful for cases where it's known that a failure of one PAM obviates the rest. For example, if a stack consists of multiple account rules and the first fails because the account doesn't exist, the rest are also guaranteed to fail and there may not be a reason to execute them. (However, in practice this is a bad idea, since the very act of terminating a stack early can give an attacker useful knowledge, as mentioned earlier.)
Rules that are sufficient are similar to requisite rules in that they terminate the stack; however, the meaning of a sufficient rule is precisely opposite of a requisite rule. A sufficient rule alone is enough for an entire stack to succeed, and so there's no reason to bother executing the rest. The most common use of sufficient rules is probably to immediately and unconditionally grant access to the root user (or to another user, such as the personal power user account on a personal workstation). After all, if you're already the most powerful account on the system, there's no reason to check to see if you can become more powerful.
An optional rule is a bit different, however. Most of the time, optional rules have no impact on the operation of a stack. An optional rule can fail and it won't matter to the overall success of the stack. There is, however, an exception to that behavior, which is when the optional rule is the only rule in the stack. In that case, PAM has no other rule to use to determine the success or failure of the stack, and so it has no choice but to use the optional rule.
The key to understanding and using PAM rule stacks is to understand the conditions that can cause them to deviate from the "normal" case. The general idea can be summarized as follows:
PAM groups rules in /etc/pam.conf (or /etc/pam.d/*) into "stacks" by their service and type.
PAM executes the appropriate stack each time an application requests a particular service.
Each rule in the stack is executed, unless a requisite or sufficient rule interrupts the process.
This model used by PAM is actually fairly common, especially in securityrelated systems. For example, the Linux kernel (and in fact most firewall-capable systems) uses a roughly similar paradigm for running its iptables firewall scripts. Another example is the access control list functionality supported by many disk filesystems (such as the AFS network filesystem). This type of configuration can be notoriously subtle and tricky to get right, precisely because it's extremely powerful. The trick to working with this type of configuration is to understand the conditions that can cause a deviation from the norm and to think through all possibilities. Also, the fewer rules, the better, since fewer rules make for simplicity, and simplicity makes for robustness.
Listing 9-1 is a copy of the /etc/pam.d/up2date file from Red Hat Linux 7.3. The up2date program is a system maintenance tool developed by Red Hat and is discussed in Chapter 4. Since up2date is a system maintenance tool, it requires root permissions to run, and so it has security needs that make for a good example of PAM. This file is a typical example of how PAM is used in practice. Each line in the file is described individually. Note, however, that the PAMs themselves are not discussed exhaustively.
Listing 9-1: Sample PAM Configuration File
#%PAM-1.0 auth sufficient /lib/security/pam_rootok.so auth required /lib/security/pam_stack.so service=system-auth session required /lib/security/pam_permit.so session optional /lib/security/pam_xauth.so account required /lib/security/pam_permit.so
The first line is simply a comment, and it includes information on the version of PAM required by the file. The remaining lines define three stacks: an auth stack, a session stack, and an account stack. Note that these lines do not include the service element; this is because Red Hat's distribution uses the /etc/pam.d mechanism. If Red Hat had chosen to use a single /etc/pam.conf instead, then each line would have to be prefixed by "up2date".
The auth stack first checks the pam_rootok.so PAM and then the pam_stack.so PAM. The first PAM checks to see if the user is already root and is immediately successful if so. The second PAM, however, causes a branch to a second stack, namely the "system-auth" service. This is a separate file (in /etc/pam.d/system-auth) that itself contains an entire PAM stack that simply fetches and authenticates a username and password (as well as performs a variety of checks for expired passwords and similar things). This technique allows stacks that are commonly used by many PAM services—such as the very common password verification in this example—to be stored in one single file and reused, rather than having to be copied into every file that needs them.
In this stack for up2date, the normal case is that the user must authenticate via a username and password, which is handled by the system-auth PAM stack, via the pam_stack.so line. However, before this rule can be executed, the first rule (marked sufficient) is given the chance to intercept. This rule simply checks to see if the root user is running the up2date program, in which case the stack succeeds immediately.
The session stack is a bit odd at first. Normally, the pam_permit.so PAM is executed, as well as the optional pam_xauth.so PAM. If the first fails, then the second will still execute, but the overall stack will fail. The optional rule attempts to handle xauth session authentication for X. The pam_permit.so PAM, however, is always successful; it cannot fail. The reason it's there is because the pam_xauth.so PAM can easily fail—for example, if the user is not using X. Since that is an optional rule, if it were the only rule in the stack it would cause the whole stack to fail unnecessarily. Thus, the pam_permit.so rule is there to ensure that the overall stack always succeeds. (Remember that the success or failure of an optional stack is ignored if there are other rules in the stack.)
The third stack is the account stack, which has a single rule. This rule again refers to the pam_permit.so module, which always succeeds. This rule is simply here as a placeholder, to make sure the account stack doesn't fail. (This rule is actually not doing much, since you don't necessarily need an account stack at all, but it's there for good measure.)
This is a pretty simple example of a PAM service configuration file. Other PAM files can get more complicated, but as long as you remember the basics of how PAM operates, they shouldn't be too difficult to figure out. In most cases, you won't have to write your own PAM configuration files, but occasionally you do, and knowledge of PAM is a good thing to have for those cases where you need to read a PAM file.
There is a special service named "other" that PAM defines to be the "default" service. That is, if an application specifies a service name that PAM doesn't recognize, then the other service kicks in. By configuring the other service, you can control the access rights granted to unknown programs.
It's a good idea when dealing with systems like PAM to be conservative and set your default rule to be extremely restrictive. First deny everything, and then approve only specific permissions for specific services; that way, you don't accidentally allow permissions you didn't mean to. (This rule also generally applies to things such as firewall rules and access controls on files.)
In the context of PAM, it's a good idea to make the rules for the other service highly restrictive. For example, the following rules are from Red Hat Linux's definition of the default other service. These rules constitute a reasonable default.
auth required /lib/security/pam_deny.so account required /lib/security/pam_deny.so password required /lib/security/pam_deny.so session required /lib/security/pam_deny.so
Recall that PAM is generally too low level a mechanism to install "after market" on a system, at least without a significant amount of effort to recompile existing programs. Rather than describe how to install PAM, the following sections instead cover a few nuances of the PAM usage on the sample distributions.
PAM comes installed by default on Red Hat Linux 7.3. In keeping with Red Hat's extensive use of the drop-in configuration directory, Red Hat's PAM installation uses the /etc/pam.d approach for configuring the individual services.
Typically, each RPM that installs a service that makes use of PAM installs its own service configuration file into /etc/pam.d. This makes it possible for the rpm tool to install and uninstall additional PAM configuration files. Other programs that you install from source code might include a PAM configuration file for that program; in these cases, you need only to copy the file into /etc/pam.d.
Slackware Linux 8.0 does not include PAM in the stock distribution. It is obviously possible to install PAM after the fact, but that's a tradeoff that can only be left to the administrator. There's a point of diminishing returns, and installing PAM on an existing distrib
|< Free Open Study >|| |