The Linux-PAM Module Writers' Guide
Andrew G.
Morgan
morgan@kernel.org
Thorsten
Kukuk
kukuk@thkukuk.de
Version 1.1.2, 31. August 2010
This manual documents what a programmer needs to know in order
to write a module that conforms to the
Linux-PAM standard.It also
discusses some security issues from the point of view of the
module programmer.
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.
A Linux-PAM module is a single
executable binary file that can be loaded by the
Linux-PAM interface library.
This PAM library is configured locally with a system file,
/etc/pam.conf, to authenticate a user
request via the locally available authentication modules. The
modules themselves will usually be located in the directory
/lib/security (or
/lib64/security, depending on the architecture)
and take the form of dynamically loadable object files (see
dlopen3
. Alternatively, the modules can be statically
linked into the Linux-PAM library;
this is mostly to allow Linux-PAM to
be used on platforms without dynamic linking available, but this is
a deprecated functionality. It is the
Linux-PAM interface that is called
by an application and it is the responsibility of the library to
locate, load and call the appropriate functions in a
Linux-PAM-module.
Except for the immediate purpose of interacting with the user
(entering a password etc..) the module should never call the
application directly. This exception requires a "conversation
mechanism" which is documented below.
Synopsis
#include <security/pam_modules.h>
gcc -fPIC -c pam_module.c
gcc -shared -o pam_module.so pam_module.o -lpam
What can be expected by the module
Here we list the interface that the conventions that all
Linux-PAM modules must adhere to.
Getting and setting PAM_ITEMs and
data
First, we cover what the module should expect from the
Linux-PAM library and a
Linux-PAM aware application.
Essentially this is the libpam.* library.
Other functions provided by libpam
What is expected of a module
The module must supply a sub-set of the six functions listed
below. Together they define the function of a
Linux-PAM module. Module developers
are strongly urged to read the comments on security that follow
this list.
Overview
The six module functions are grouped into four independent
management groups. These groups are as follows:
authentication, account,
session and password.
To be properly defined, a module must define all functions within
at least one of these groups. A single module may contain the
necessary functions for all four groups.
Functional independence
The independence of the four groups of service a module can
offer means that the module should allow for the possibility
that any one of these four services may legitimately be called
in any order. Thus, the module writer should consider the
appropriateness of performing a service without the prior
success of some other part of the module.
As an informative example, consider the possibility that an
application applies to change a user's authentication token,
without having first requested that
Linux-PAM authenticate the
user. In some cases this may be deemed appropriate: when
root wants to change the authentication
token of some lesser user. In other cases it may not be
appropriate: when joe maliciously wants
to reset alice's password; or when anyone
other than the user themself wishes to reset their
KERBEROS authentication token. A policy
for this action should be defined by any reasonable
authentication scheme, the module writer should consider
this when implementing a given module.
Minimizing administration problems
To avoid system administration problems and the poor
construction of a /etc/pam.conf file,
the module developer may define all six of the following
functions. For those functions that would not be called,
the module should return PAM_SERVICE_ERR
and write an appropriate message to the system log. When
this action is deemed inappropriate, the function would
simply return PAM_IGNORE.
Arguments supplied to the module
The flags argument of each of
the following functions can be logically OR'd with
PAM_SILENT, which is used to inform the
module to not pass any text (errors or
warnings) application.
The argc and argv
arguments are taken from the line appropriate to this
module---that is, with the service_name
matching that of the application---in the configuration file
(see the Linux-PAM
System Administrators' Guide). Together these two parameters
provide the number of arguments and an array of pointers to
the individual argument tokens. This will be familiar to C
programmers as the ubiquitous method of passing command arguments
to the function main(). Note, however, that
the first argument (argv[0]) is a true
argument and not the name of the module.
Authentication management
Authentication token management
Generic optional arguments
Here we list the generic arguments that all modules can expect to
be passed. They are not mandatory, and their absence should be
accepted without comment by the module.
debug
Use the
pam_syslog3
call to log debugging information to the system
log files.
use_first_pass
The module should not prompt the user for a password.
Instead, it should obtain the previously typed password
(by a call to pam_get_item() for the
PAM_AUTHTOK item), and use that. If
that doesn't work, then the user will not be authenticated.
(This option is intended for auth and
passwd modules only).
Programming notes
Here we collect some pointers for the module writer to bear in mind
when writing/developing a Linux-PAM
compatible module.
Security issues for module creation
Sufficient resources
Care should be taken to ensure that the proper execution
of a module is not compromised by a lack of system resources.
If a module is unable to open sufficient files to perform its
task, it should fail gracefully, or request additional resources.
Specifically, the quantities manipulated by the
setrlimit2
family of commands should be taken into
consideration.
Who´s who?
Generally, the module may wish to establish the identity of
the user requesting a service. This may not be the same as
the username returned by pam_get_user().
Indeed, that is only going to be the name of the user under
whose identity the service will be given. This is not
necessarily the user that requests the service.
In other words, user X runs a program that is setuid-Y, it
grants the user to have the permissions of Z. A specific example
of this sort of service request is the su
program: user joe executes
su to become the user jane.
In this situation X=joe, Y=root
and Z=jane. Clearly, it is important that
the module does not confuse these different users and grant an
inappropriate level of privilege.
The following is the convention to be adhered to when juggling
user-identities.
X, the identity of the user invoking the service request.
This is the user identifier; returned by the function
getuid2
.
Y, the privileged identity of the application used to
grant the requested service. This is the
effective user identifier;
returned by the function
geteuid2
.
Z, the user under whose identity the service will be granted.
This is the username returned by
pam_get_user() and also stored in the
Linux-PAM item,
PAM_USER.
Linux-PAM has a place for
an additional user identity that a module may care to make
use of. This is the PAM_RUSER item.
Generally, network sensitive modules/applications may wish
to set/read this item to establish the identity of the user
requesting a service from a remote location.
Note, if a module wishes to modify the identity of either the
uid or euid of the
running process, it should take care to restore the original
values prior to returning control to the
Linux-PAM library.
Using the conversation function
Prior to calling the conversation function, the module should
reset the contents of the pointer that will return the applications
response. This is a good idea since the application may fail
to fill the pointer and the module should be in a position to
notice!
The module should be prepared for a failure from the
conversation. The generic error would be
PAM_CONV_ERR, but anything other than
PAM_SUCCESS should be treated as
indicating failure.
Authentication tokens
To ensure that the authentication tokens are not left lying
around the items, PAM_AUTHTOK and
PAM_OLDAUTHTOK, are not available to
the application: they are defined in
<security/pam_modules.h>. This
is ostensibly for security reasons, but a maliciously
programmed application will always have access to all memory
of the process, so it is only superficially enforced. As a
general rule the module should overwrite authentication tokens
as soon as they are no longer needed. Especially before
free()'ing them. The
Linux-PAM library is
required to do this when either of these authentication
token items are (re)set.
Not to dwell too little on this concern; should the module
store the authentication tokens either as (automatic) function
variables or using pam_[gs]et_data() the
associated memory should be over-written explicitly before it
is released. In the case of the latter storage mechanism, the
associated cleanup() function should
explicitly overwrite the *data before
free()'ing it: for example,
/*
* An example cleanup() function for releasing memory that was used to
* store a password.
*/
int cleanup(pam_handle_t *pamh, void *data, int error_status)
{
char *xx;
if ((xx = data)) {
while (*xx)
*xx++ = '\0';
free(data);
}
return PAM_SUCCESS;
}
Use of
syslog3
Only rarely should error information be directed to the user.
Usually, this is to be limited to
sorry you cannot login now
type messages. Information concerning errors in the configuration
file, /etc/pam.conf, or due to some system
failure encountered by the module, should be written to
syslog3
with facility-type
LOG_AUTHPRIV.
With a few exceptions, the level of logging is, at the discretion
of the module developer. Here is the recommended usage of different
logging levels:
As a general rule, errors encountered by a module should be
logged at the LOG_ERR level. However,
information regarding an unrecognized argument, passed to a
module from an entry in the /etc/pam.conf
file, is required to be logged at the
LOG_ERR level.
Debugging information, as activated by the
debug argument to the module in
/etc/pam.conf, should be logged
at the LOG_DEBUG level.
If a module discovers that its personal configuration
file or some system file it uses for information is
corrupted or somehow unusable, it should indicate this
by logging messages at level, LOG_ALERT.
Shortages of system resources, such as a failure to
manipulate a file or malloc() failures
should be logged at level LOG_CRIT.
Authentication failures, associated with an incorrectly
typed password should be logged at level,
LOG_NOTICE.
Modules that require system libraries
Writing a module is much like writing an application. You
have to provide the "conventional hooks" for it to work
correctly, like pam_sm_authenticate()
etc., which would correspond to the main()
function in a normal function.
Typically, the author may want to link against some standard system
libraries. As when one compiles a normal program, this can be
done for modules too: you simply append the
-lXXX arguments
for the desired libraries when you create the shared module object.
To make sure a module is linked to the
libwhatever.so library
when it is dlopen()ed, try:
% gcc -shared -o pam_module.so pam_module.o -lwhatever
An example module
At some point, we may include a fully commented example of a module in
this document. For now, please look at the modules directory of the
Linux-PAM sources.
See also
The Linux-PAM System Administrators' Guide.
The Linux-PAM Application Developers' 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