# The Linux-PAM Application Developers' Guide

## 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 Linux-PAM

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 Linux-PAM

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

getpwnam

3 and

syslog

3 .

### 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_item

3 . 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_item

3 . 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_item

3 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

setrlimit

2 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, users can authenticate themselves in a variety of ways. Updating the user's authentication token thus corresponds to refreshing the object they use to authenticate themselves 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).

    /*
      This program was contributed by Shane Watts
      [modifications by AGM and kukuk]

      You need to add the following (or equivalent) to the
      /etc/pam.d/check_user file:
      # check authorization
      auth       required     pam_unix.so
      account    required     pam_unix.so
     */

    #include <security/pam_appl.h>
    #include <security/pam_misc.h>
    #include <stdio.h>

    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