Previous Next Table of Contents

5. Programming notes

Here we collect some pointers for the module writer to bear in mind when writing/developing a Linux-PAM compatible module.

5.1 Security issues for module creation

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;
}

5.2 Use of 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:

5.3 Added requirements for statically loaded modules.

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:

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.


Previous Next Table of Contents