Here we collect some pointers for the module writer to bear in mind when writing/developing a Linux-PAM compatible module.
Regarding the use of 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!
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;
}
syslog(3)
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 some system failure encountered by the
module should be written to syslog(3)
with facility-type
LOG_AUTHPRIV
.
With a few exceptions, the level of logging is, at the discression of the module developer. Here is the recommended usage of different logging levels:
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.
debug
argument to the
module in /etc/pam.conf
, should be logged at the
LOG_DEBUG
level.
LOG_ALERT
.
malloc()
failures should be logged at level LOG_CRIT
.
LOG_NOTICE
.
Modules may be statically linked into libpam. This should be true of all the modules distributed with the basic Linux-PAM distribution. To be statically linked, a module needs to export information about the functions it contains in a manner that does not clash with other modules.
The extra code necessary to build a static module should be delimited
with #ifdef PAM_STATIC
and #endif
. The static code should do
the following:
struct pam_module
, called
_pam_modname_modstruct
, where
modname
is the name of the module as used in the
filesystem but without the leading directory name (generally
/usr/lib/security/
or the suffix (generally .so
).
As a simple example, consider the following module code which defines a module that can be compiled to be static or dynamic:
#include <stdio.h> /* for NULL define */
#define PAM_SM_PASSWORD /* the only pam_sm_... function declared */
#include <security/pam_modules.h>
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
return PAM_SUCCESS;
}
#ifdef PAM_STATIC /* for the case that this module is static */
struct pam_module _pam_modname_modstruct = { /* static module data */
"pam_modname",
NULL,
NULL,
NULL,
NULL,
NULL,
pam_sm_chauthtok,
};
#endif /* end PAM_STATIC */
To be linked with libpam, staticly-linked modules must be built
from within the Linux-PAM-X.YY/modules/
subdirectory of the
Linux-PAM source directory as part of a normal build of the
Linux-PAM system.
The Makefile, for the module in question, must execute the
register_static
shell script that is located in the
Linux-PAM-X.YY/modules/
subdirectory. This is to ensure that
the module is properly registered with libpam.
The two manditory arguments to register_static
are the
title, and the pathname of the object file containing the module's
code. The pathname is specified relative to the
Linux-PAM-X.YY/modules
directory. The pathname may be an
empty string---this is for the case that a single object file needs to
register more than one struct pam_module
. In such a case, exactly
one call to register_static
must indicate the object file.
Here is an example; a line in the Makefile might look like this:
register:
ifdef STATIC
(cd ..; ./register_static pam_modname pam_modname/pam_modname.o)
endif
For some further examples, see the modules
subdirectory of
the current Linux-PAM distribution.