The Linux-PAM Application Developers' Guide Andrew G. Morgan morgan@kernel.org Thorsten Kukuk kukuk@thkukuk.de Version 1.1.2, 31. August 2010 This manual documents what an application developer needs to know about the Linux-PAM library. It describes how an application might use the Linux-PAM library to authenticate users. In addition it contains a description of the functions to be found in libpam_misc library, that can be used in general applications. Finally, it contains some comments on PAM related security issues for the application developer. Introduction
Description Linux-PAM (Pluggable Authentication Modules for Linux) is a library that enables the local system administrator to choose how individual applications authenticate users. For an overview of the Linux-PAM library see the Linux-PAM System Administrators' Guide. It is the purpose of the Linux-PAM project to liberate the development of privilege granting software from the development of secure and appropriate authentication schemes. This is accomplished by providing a documented library of functions that an application may use for all forms of user authentication management. This library dynamically loads locally configured authentication modules that actually perform the authentication tasks. From the perspective of an application developer the information contained in the local configuration of the PAM library should not be important. Indeed it is intended that an application treat the functions documented here as a 'black box' that will deal with all aspects of user authentication. 'All aspects' includes user verification, account management, session initialization/termination and also the resetting of passwords (authentication tokens).
Synopsis For general applications that wish to use the services provided by Linux-PAM the following is a summary of the relevant linking information: #include <security/pam_appl.h> cc -o application .... -lpam In addition to libpam, there is a library of miscellaneous functions that make the job of writing PAM-aware applications easier (this library is not covered in the DCE-RFC for PAM and is specific to the Linux-PAM distribution): #include <security/pam_appl.h> #include <security/pam_misc.h> cc -o application .... -lpam -lpam_misc
Overview Most service-giving applications are restricted. In other words, their service is not available to all and every prospective client. Instead, the applying client must jump through a number of hoops to convince the serving application that they are authorized to obtain service. The process of authenticating a client is what PAM is designed to manage. In addition to authentication, PAM provides account management, credential management, session management and authentication-token (password changing) management services. It is important to realize when writing a PAM based application that these services are provided in a manner that is transparent to the application. That is to say, when the application is written, no assumptions can be made about how the client will be authenticated. The process of authentication is performed by the PAM library via a call to pam_authenticate(). The return value of this function will indicate whether a named client (the user) has been authenticated. If the PAM library needs to prompt the user for any information, such as their name or a password then it will do so. If the PAM library is configured to authenticate the user using some silent protocol, it will do this too. (This latter case might be via some hardware interface for example.) It is important to note that the application must leave all decisions about when to prompt the user at the discretion of the PAM library. The PAM library, however, must work equally well for different styles of application. Some applications, like the familiar login and passwd are terminal based applications, exchanges of information with the client in these cases is as plain text messages. Graphically based applications, however, have a more sophisticated interface. They generally interact with the user via specially constructed dialogue boxes. Additionally, network based services require that text messages exchanged with the client are specially formatted for automated processing: one such example is ftpd which prefixes each exchanged message with a numeric identifier. The presentation of simple requests to a client is thus something very dependent on the protocol that the serving application will use. In spite of the fact that PAM demands that it drives the whole authentication process, it is not possible to leave such protocol subtleties up to the PAM library. To overcome this potential problem, the application provides the PAM library with a conversation function. This function is called from within the PAM library and enables the PAM to directly interact with the client. The sorts of things that this conversation function must be able to do are prompt the user with text and/or obtain textual input from the user for processing by the PAM library. The details of this function are provided in a later section. For example, the conversation function may be called by the PAM library with a request to prompt the user for a password. Its job is to reformat the prompt request into a form that the client will understand. In the case of ftpd, this might involve prefixing the string with the number 331 and sending the request over the network to a connected client. The conversation function will then obtain any reply and, after extracting the typed password, will return this string of text to the PAM library. Similar concerns need to be addressed in the case of an X-based graphical server. There are a number of issues that need to be addressed when one is porting an existing application to become PAM compliant. A section below has been devoted to this: Porting legacy applications. Besides authentication, PAM provides other forms of management. Session management is provided with calls to pam_open_session() and pam_close_session(). What these functions actually do is up to the local administrator. But typically, they could be used to log entry and exit from the system or for mounting and unmounting the user's home directory. If an application provides continuous service for a period of time, it should probably call these functions, first open after the user is authenticated and then close when the service is terminated. Account management is another area that an application developer should include with a call to pam_acct_mgmt(). This call will perform checks on the good health of the user's account (has it expired etc.). One of the things this function may check is whether the user's authentication token has expired - in such a case the application may choose to attempt to update it with a call to pam_chauthtok(), although some applications are not suited to this task (ftp for example) and in this case the application should deny access to the user. PAM is also capable of setting and deleting the user's credentials with the call pam_setcred(). This function should always be called after the user is authenticated and before service is offered to the user. By convention, this should be the last call to the PAM library before the PAM session is opened. What exactly a credential is, is not well defined. However, some examples are given in the glossary below. The public interface to <emphasis remap='B'>Linux-PAM</emphasis> Firstly, the relevant include file for the Linux-PAM library is <security/pam_appl.h>. It contains the definitions for a number of functions. After listing these functions, we collect some guiding remarks for programmers.
What can be expected by the application
What is expected of an application
Programming notes Note, all of the authentication service function calls accept the token PAM_SILENT, which instructs the modules to not send messages to the application. This token can be logically OR'd with any one of the permitted tokens specific to the individual function calls. PAM_SILENT does not override the prompting of the user for passwords etc., it only stops informative messages from being generated.
Security issues of <emphasis remap='B'>Linux-PAM</emphasis> PAM, from the perspective of an application, is a convenient API for authenticating users. PAM modules generally have no increased privilege over that possessed by the application that is making use of it. For this reason, the application must take ultimate responsibility for protecting the environment in which PAM operates. A poorly (or maliciously) written application can defeat any Linux-PAM module's authentication mechanisms by simply ignoring it's return values. It is the applications task and responsibility to grant privileges and access to services. The Linux-PAM library simply assumes the responsibility of authenticating the user; ascertaining that the user is who they say they are. Care should be taken to anticipate all of the documented behavior of the Linux-PAM library functions. A failure to do this will most certainly lead to a future security breach.
Care about standard library calls In general, writers of authorization-granting applications should assume that each module is likely to call any or all 'libc' functions. For 'libc' functions that return pointers to static/dynamically allocated structures (ie. the library allocates the memory and the user is not expected to 'free()' it) any module call to this function is likely to corrupt a pointer previously obtained by the application. The application programmer should either re-call such a 'libc' function after a call to the Linux-PAM library, or copy the structure contents to some safe area of memory before passing control to the Linux-PAM library. Two important function classes that fall into this category are getpwnam3 and syslog3 .
Choice of a service name When picking the service-name that corresponds to the first entry in the Linux-PAM configuration file, the application programmer should avoid the temptation of choosing something related to argv[0]. It is a trivial matter for any user to invoke any application on a system under a different name and this should not be permitted to cause a security breach. In general, this is always the right advice if the program is setuid, or otherwise more privileged than the user that invokes it. In some cases, avoiding this advice is convenient, but as an author of such an application, you should consider well the ways in which your program will be installed and used. (Its often the case that programs are not intended to be setuid, but end up being installed that way for convenience. If your program falls into this category, don't fall into the trap of making this mistake.) To invoke some target application by another name, the user may symbolically link the target application with the desired name. To be precise all the user need do is, ln -s /target/application ./preferred_name and then run ./preferred_name. By studying the Linux-PAM configuration file(s), an attacker can choose the preferred_name to be that of a service enjoying minimal protection; for example a game which uses Linux-PAM to restrict access to certain hours of the day. If the service-name were to be linked to the filename under which the service was invoked, it is clear that the user is effectively in the position of dictating which authentication scheme the service uses. Needless to say, this is not a secure situation. The conclusion is that the application developer should carefully define the service-name of an application. The safest thing is to make it a single hard-wired name.
The conversation function Care should be taken to ensure that the conv() function is robust. Such a function is provided in the library libpam_misc (see below).
The identity of the user The Linux-PAM modules will need to determine the identity of the user who requests a service, and the identity of the user who grants the service. These two users will seldom be the same. Indeed there is generally a third user identity to be considered, the new (assumed) identity of the user once the service is granted. The need for keeping tabs on these identities is clearly an issue of security. One convention that is actively used by some modules is that the identity of the user requesting a service should be the current UID (user ID) of the running process; the identity of the privilege granting user is the EUID (effective user ID) of the running process; the identity of the user, under whose name the service will be executed, is given by the contents of the PAM_USER pam_get_item3 . Note, modules can change the values of PAM_USER and PAM_RUSER during any of the pam_*() library calls. For this reason, the application should take care to use the pam_get_item() every time it wishes to establish who the authenticated user is (or will currently be). For network-serving databases and other applications that provide their own security model (independent of the OS kernel) the above scheme is insufficient to identify the requesting user. A more portable solution to storing the identity of the requesting user is to use the PAM_RUSER pam_get_item3 . The application should supply this value before attempting to authenticate the user with pam_authenticate(). How well this name can be trusted will ultimately be at the discretion of the local administrator (who configures PAM for your application) and a selected module may attempt to override the value where it can obtain more reliable data. If an application is unable to determine the identity of the requesting entity/user, it should not call pam_set_item3 to set PAM_RUSER. In addition to the PAM_RUSER item, the application should supply the PAM_RHOST (requesting host) item. As a general rule, the following convention for its value can be assumed: NULL = unknown; localhost = invoked directly from the local system; other.place.xyz = some component of the user's connection originates from this remote/requesting host. At present, PAM has no established convention for indicating whether the application supports a trusted path to communication from this host.
Sufficient resources Care should be taken to ensure that the proper execution of an application is not compromised by a lack of system resources. If an application is unable to open sufficient files to perform its service, it should fail gracefully, or request additional resources. Specifically, the quantities manipulated by the setrlimit2 family of commands should be taken into consideration. This is also true of conversation prompts. The application should not accept prompts of arbitrary length with out checking for resource allocation failure and dealing with such extreme conditions gracefully and in a manner that preserves the PAM API. Such tolerance may be especially important when attempting to track a malicious adversary.
A library of miscellaneous helper functions To aid the work of the application developer a library of miscellaneous functions is provided. It is called libpam_misc, and contains a text based conversation function, and routines for enhancing the standard PAM-environment variable support. The functions, structures and macros, made available by this library can be defined by including <security/pam_misc.h>. It should be noted that this library is specific to Linux-PAM and is not referred to in the defining DCE-RFC (see See also) below.
Functions supplied
Porting legacy applications The point of PAM is that the application is not supposed to have any idea how the attached authentication modules will choose to authenticate the user. So all they can do is provide a conversation function that will talk directly to the user(client) on the modules' behalf. Consider the case that you plug a retinal scanner into the login program. In this situation the user would be prompted: "please look into the scanner". No username or password would be needed - all this information could be deduced from the scan and a database lookup. The point is that the retinal scanner is an ideal task for a "module". While it is true that a pop-daemon program is designed with the POP protocol in mind and no-one ever considered attaching a retinal scanner to it, it is also the case that the "clean" PAM'ification of such a daemon would allow for the possibility of a scanner module being be attached to it. The point being that the "standard" pop-authentication protocol(s) [which will be needed to satisfy inflexible/legacy clients] would be supported by inserting an appropriate pam_qpopper module(s). However, having rewritten popd once in this way any new protocols can be implemented in-situ. One simple test of a ported application would be to insert the pam_permit module and see if the application demands you type a password... In such a case, xlock would fail to lock the terminal - or would at best be a screen-saver, ftp would give password free access to all etc.. Neither of these is a very secure thing to do, but they do illustrate how much flexibility PAM puts in the hands of the local admin. The key issue, in doing things correctly, is identifying what is part of the authentication procedure (how many passwords etc..) the exchange protocol (prefixes to prompts etc., numbers like 331 in the case of ftpd) and what is part of the service that the application delivers. PAM really needs to have total control in the authentication "procedure", the conversation function should only deal with reformatting user prompts and extracting responses from raw input. Glossary of PAM related terms The following are a list of terms used within this document. Authentication token Generally, this is a password. However, a user can authenticate him/herself in a variety of ways. Updating the user's authentication token thus corresponds to refreshing the object they use to authenticate themself with the system. The word password is avoided to keep open the possibility that the authentication involves a retinal scan or other non-textual mode of challenge/response. Credentials Having successfully authenticated the user, PAM is able to establish certain characteristics/attributes of the user. These are termed credentials. Examples of which are group memberships to perform privileged tasks with, and tickets in the form of environment variables etc. . Some user-credentials, such as the user's UID and GID (plus default group memberships) are not deemed to be PAM-credentials. It is the responsibility of the application to grant these directly. An example application To get a flavor of the way a Linux-PAM application is written we include the following example. It prompts the user for their password and indicates whether their account is valid on the standard output, its return code also indicates the success (0 for success; 1 for failure). #include #include static struct pam_conv conv = { misc_conv, NULL }; int main(int argc, char *argv[]) { pam_handle_t *pamh=NULL; int retval; const char *user="nobody"; if(argc == 2) { user = argv[1]; } if(argc > 2) { fprintf(stderr, "Usage: check_user [username]\n"); exit(1); } retval = pam_start("check_user", user, &conv, &pamh); if (retval == PAM_SUCCESS) retval = pam_authenticate(pamh, 0); /* is user really user? */ if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ /* This is where we have been authorized or not. */ if (retval == PAM_SUCCESS) { fprintf(stdout, "Authenticated\n"); } else { fprintf(stdout, "Not Authenticated\n"); } if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ pamh = NULL; fprintf(stderr, "check_user: failed to release authenticator\n"); exit(1); } return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ } ]]> Files /usr/include/security/pam_appl.h Header file with interfaces for Linux-PAM applications. /usr/include/security/pam_misc.h Header file for useful library functions for making applications easier to write. See also The Linux-PAM System Administrators' Guide. The Linux-PAM Module Writers' Guide. The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request For Comments 86.0, October 1995. Author/acknowledgments This document was written by Andrew G. Morgan (morgan@kernel.org) with many contributions from Chris Adams, Peter Allgeyer, Tim Baverstock, Tim Berger, Craig S. Bell, Derrick J. Brashear, Ben Buxton, Seth Chaiklin, Oliver Crow, Chris Dent, Marc Ewing, Cristian Gafton, Emmanuel Galanos, Brad M. Garcia, Eric Hester, Roger Hu, Eric Jacksch, Michael K. Johnson, David Kinchlea, Olaf Kirch, Marcin Korzonek, Thorsten Kukuk, Stephen Langasek, Nicolai Langfeldt, Elliot Lee, Luke Kenneth Casson Leighton, Al Longyear, Ingo Luetkebohle, Marek Michalkiewicz, Robert Milkowski, Aleph One, Martin Pool, Sean Reifschneider, Jan Rekorajski, Erik Troan, Theodore Ts'o, Jeff Uphoff, Myles Uyema, Savochkin Andrey Vladimirovich, Ronald Wahl, David Wood, John Wilmes, Joseph S. D. Yao and Alex O. Yuriev. Thanks are also due to Sun Microsystems, especially to Vipin Samar and Charlie Lai for their advice. At an early stage in the development of Linux-PAM, Sun graciously made the documentation for their implementation of PAM available. This act greatly accelerated the development of Linux-PAM. Copyright information for this document Copyright (c) 2006 Thorsten Kukuk <kukuk@thkukuk.de> Copyright (c) 1996-2002 Andrew G. Morgan <morgan@kernel.org> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, and the entire permission notice in its entirety, including the disclaimer of warranties. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. Alternatively, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GNU GPL are required instead of the above restrictions. (This clause is necessary due to a potential bad interaction between the GNU GPL and the restrictions contained in a BSD-style copyright.) THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH