Pluggable Authentication Modules for Linux
Have you ever wondered how much work it would be to modify login to work the way you want it to? Perhaps you want it to refer to shadowed passwords or you don't want to let users log in during certain times of the day. Perhaps your policy is to ensure that root cannot log in anywhere other than at the console; maybe, root should never log in when the system is connected to the network. You might implement MD5-secured passwords, or passwords secured with RIPEMD-160 or SHA? Perhaps you have decided passwords are insufficiently secure for your needs, and instead you would like a user to insert their identity card in a slot to log in. Further, you would like to integrate your system into a network security environment like Kerberos; the primary login of a user would need to activate their identity with respect to the Kerberos server. The variations and combinations are endless. There is no perfect solution. There never will be.
Given sufficient incentive to implement a new user-authentication scheme, the traditional solution has been to amend, or rewrite, all of the system-access applications (login, su, passwd, ftp, xdm, ... )--this takes time and resources. An annoying by-product of such an upgrade is that modifying one application requires you to simultaneously upgrade other applications to maintain a consistent entry policy for your system. Unless you write the applications yourself, it is not easy to simply insert the code and be sure you have filled all the holes.
The revision of a system's security policy also suffers from the following potential weakness: people who write appealing user interfaces are not always paranoid enough to write secure software. This point relates to both access-oriented (login, etc.) and information-security (e-mail encryption, etc.) software.
Current thinking on computer-related security is to separate the security policy from the service offered by an application. This allows the author of a security-dependant application to use an application programming interface (API) to take care of the security-related issues and concentrate their efforts on writing a good (robust but user friendly) application.
An API is typically defined by a document describing a set of functions that an application programmer can rely on. For example, libc is an implementation of a number of APIs. Collaborative organizations, such as ANSI, POSIX or X/Open, produce a document defining the API and then vendors (or enthusiasts in the case of Linux) implement it. Security-related APIs exist for tasks like user authentication and data encryption.
Prompted by a comment on the linux-security e-mail list, Ted Ts'o asked the following question: “Has anyone thought of implementing PAM?”, and thus, he launched the Linux-PAM project. Marc Ewing (of Red Hat Software) quickly coded a framework for most of the library in January 1996. Since then I have been maintaining the Linux-PAM distribution. Thanks to the combined efforts of a number of people (I've included a “mostly” complete list at the end of this article), I'm proud to say Linux-PAM is now a reality. Better still, people are using it.
The document defining PAM is a request-for-comments paper (RFC) that was written by Vipin Samar and Roland J. Schemers III of SunSoft, Inc. Specifically, it is OSF-RFC 86.0, October 1995, “Unified Login with Pluggable Authentication Modules (PAM)”. The Linux-PAM URL at the end of this article contains a pointer to this document.
The PAM-API breaks the business of authentication into four independent management groups. These four groups are:
Authentication token (password) updating
Typically, a login application would need to use each of these groups when granting a candidate user access to a system. Applications like passwd only require access to the last of these groups.
The novelty and power of the PAM-API resides in the leading “P” for pluggability. It may surprise the reader to note that this is the part of PAM that is irrelevant from the point of the login- application writer. Instead, it introduces a role for the system administrator in the process of choosing an authentication scheme for login.
Veteran Linux users will remember all the hype that surrounded the move to ELF from the older a.out system binary. A desirable feature of this transition was the introduction of a library function, dlopen(3). This function call provides a reliable method for a running program to dynamically load some code for the purpose of execution. Its sibling function, dlclose(3), is used to unload, or discard, such code when it is no longer required. Implementations of PAM utilize these functions to dynamically bind an application program to locally specified authentication modules. That is, the pluggability of PAM is dynamic and thus at the discretion of the local system administrator.
With a PAM-based login application, the system administrator can completely change the authentication scheme the application uses without modifying or recompiling it. In principle, this can even be done without rebooting the computer. However, before a new authentication scheme is fully deployed, the best approach is to isolate a computer from any network and test it under controlled conditions to ensure the new arrangement is robust.