  The Linux-PAM Module Writers' Guide
  Andrew G. Morgan, morgan@kernel.org
  DRAFT v0.76 2002/05/09

  This manual documents what a programmer needs to know in order to
  write a module that conforms to the [1mLinux-PAM [22mstandard. It also dis-
  cusses some security issues from the point of view of the module pro-
  grammer.
  ______________________________________________________________________

  Table of Contents


  1. Introduction
     1.1 Synopsis
     1.2 Description

  2. What can be expected by the module
     2.1 Getting and setting PAM_ITEMs and data
        2.1.1 Setting data
        2.1.2 Getting data
        2.1.3 Setting items
        2.1.4 Getting items
        2.1.5 The conversation mechanism
        2.1.6 Getting the name of a user
        2.1.7 Setting a Linux-PAM environment variable
        2.1.8 Getting a Linux-PAM environment variable
        2.1.9 Listing the Linux-PAM environment
     2.2 Other functions provided by libpam
        2.2.1 Understanding errors
        2.2.2 Planning for delays

  3. What is expected of a module
     3.1 Overview
        3.1.1 Functional independence
        3.1.2 Minimizing administration problems
        3.1.3 Arguments supplied to the module
     3.2 Authentication management
     3.3 Account management
     3.4 Session management
     3.5 Password management

  4. Generic optional arguments
  5. Programming notes
     5.1 Security issues for module creation
        5.1.1 Sufficient resources
        5.1.2 Who's who?
        5.1.3 Using the conversation function
        5.1.4 Authentication tokens
     5.2 Use of syslog(3)
     5.3 Modules that require system libraries
     5.4 Added requirements for statically loaded modules.

  6. An example module file
  7. Files
  8. See also
  9. Notes
  10. Author/acknowledgments
  11. Bugs/omissions
  12. Copyright information for this document


  ______________________________________________________________________



  [1m1.  Introduction[0m

  [1m1.1.  Synopsis[0m



       #include <security/pam_modules.h>

       gcc -fPIC -c pam_module-name.c
       ld -x --shared -o pam_module-name.so pam_module-name.o



  [1m1.2.  Description[0m

  [1mLinux-PAM [22m(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 [1mLinux-PAM[0m
  library see the [1mLinux-PAM [22mSystem Administrators' Guide.


  A [1mLinux-PAM [22mmodule is a single executable binary file that can be
  loaded by the [1mLinux-PAM [22minterface 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
  /usr/lib/security and take the form of dynamically loadable object
  files (see dlopen(3)). Alternatively, the modules can be statically
  linked into the [1mLinux-PAM [22mlibrary; this is mostly to allow [1mLinux-PAM[0m
  to be used on platforms without dynamic linking available, but the two
  forms can be used together.  It is the [1mLinux-PAM [22minterface that is
  called by an application and it is the responsibility of the library
  to locate, load and call the appropriate functions in a [1mLinux-PAM[22m-
  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.


  [1m2.  What can be expected by the module[0m

  Here we list the interface that the conventions that all [1mLinux-PAM[0m
  modules must adhere to.


  [1m2.1.  Getting and setting PAM_ITEM s and data[0m

  First, we cover what the module should expect from the [1mLinux-PAM[0m
  library and a [1mLinux-PAM [4m[22maware[24m application. Essesntially this is the
  libpam.* library.


  [1m2.1.1.  Setting data[0m

  Synopsis:



  extern int pam_set_data(pam_handle_t *pamh,
                          const char *module_data_name,
                          void *data,
                          void (*cleanup)(pam_handle_t *pamh,
                                          void *data, int error_status) );



  The modules may be dynamically loadable objects. In general such files
  should not contain static variables. This and the subsequent function
  provide a mechanism for a module to associate some data with the
  handle pamh. Typically a module will call the pam_set_data() function
  to register some data under a (hopefully) unique module_data_name. The
  data is available for use by other modules too but [4mnot[24m by an
  application.


  The function cleanup() is associated with the data and, if non-NULL,
  it is called when this data is over-written or following a call to
  pam_end() (see the Linux-PAM Application Developers' Guide).


  The error_status argument is used to indicate to the module the sort
  of action it is to take in cleaning this data item. As an example,
  Kerberos creates a ticket file during the authentication phase, this
  file might be associated with a data item. When pam_end() is called by
  the module, the error_status carries the return value of the
  pam_authenticate() or other libpam function as appropriate. Based on
  this value the Kerberos module may choose to delete the ticket file
  ([4mauthentication[24m [4mfailure[24m) or leave it in place.


  The error_status may have been logically OR'd with either of the
  following two values:



     PAM_DATA_REPLACE
        When a data item is being replaced (through a second call to
        pam_set_data()) this mask is used. Otherwise, the call is
        assumed to be from pam_end().


     PAM_DATA_SILENT
        Which indicates that the process would prefer to perform the
        cleanup() quietly. That is, discourages logging/messages to the
        user.



  [1m2.1.2.  Getting data[0m

  Synopsis:


       extern int pam_get_data(const pam_handle_t *pamh,
                               const char *module_data_name,
                               const void **data);



  This function together with the previous one provides a method of
  associating module-specific data with the handle pamh. A successful
  call to pam_get_data will result in *data pointing to the data
  associated with the module_data_name. Note, this data is [4mnot[24m a copy
  and should be treated as [4mconstant[24m by the module.


  Note, if there is an entry but it has the value NULL, then this call
  returns PAM_NO_MODULE_DATA.


  [1m2.1.3.  Setting items[0m

  Synopsis:


       extern int pam_set_item(pam_handle_t *pamh,
                               int item_type,
                               const void *item);



  This function is used to (re)set the value of one of the item_types.
  The reader is urged to read the entry for this function in the [1mLinux-[0m
  [1mPAM [22mapplication developers' manual.


  In addition to the items listed there, the module can set the
  following two item_types:



     PAM_AUTHTOK
        The authentication token (often a password). This token should
        be ignored by all module functions besides pam_sm_authenticate()
        and pam_sm_chauthtok(). In the former function it is used to
        pass the most recent authentication token from one stacked
        module to another. In the latter function the token is used for
        another purpose. It contains the currently active authentication
        token.


     PAM_OLDAUTHTOK
        The old authentication token. This token should be ignored by
        all module functions except pam_sm_chauthtok().



  Both of these items are reset before returning to the application.
  When resetting these items, the [1mLinux-PAM [22mlibrary first writes 0's to
  the current tokens and then free()'s the associated memory.


  The return values for this function are listed in the [1mLinux-PAM[0m
  Application Developers' Guide.


  [1m2.1.4.  Getting items[0m

  Synopsis:



  extern int pam_get_item(const pam_handle_t *pamh,
                          int item_type,
                          const void **item);



  This function is used to obtain the value of the specified item_type.
  It is better documented in the [1mLinux-PAM [22mApplication Developers'
  Guide. However, there are three things worth stressing here:

  +o  Generally, if the module wishes to obtain the name of the user, it
     should not use this function, but instead perform a call to
     pam_get_user() (see section ``below'').

  +o  The module is additionally privileged to read the authentication
     tokens, PAM_AUTHTOK and PAM_OLDAUTHTOK (see the section above on
     pam_set_data()).

  +o  The module should [4mnot[24m free() or alter the data pointed to by *item
     after a successful return from pam_get_item(). This pointer points
     directly at the data contained within the *pamh structure.  Should
     a module require that a change is made to the this ITEM it should
     make the appropriate call to pam_set_item().


  [1m2.1.5.  The conversation  mechanism[0m

  Following the call pam_get_item(pamh,PAM_CONV,&item), the pointer item
  points to a structure containing an a pointer to a [4mconversation[24m-
  function that provides limited but direct access to the application.
  The purpose of this function is to allow the module to prompt the user
  for their password and pass other information in a manner consistent
  with the application. For example, an X-windows based program might
  pop up a dialog box to report a login failure. Just as the application
  should not be concerned with the method of authentication, so the
  module should not dictate the manner in which input (output) is
  obtained from (presented to) to the user.


  [1mThe reader is strongly urged to read the more complete description of[0m
  [1mthe [22mpam_conv structure, written from the perspective of the
  application developer, in the [1mLinux-PAM [22mApplication Developers' Guide.


  The return values for this function are listed in the [1mLinux-PAM[0m
  Application Developers' Guide.


  The pam_response structure returned after a call to the pam_conv
  function must be free()'d by the module. Since the call to the
  conversation function originates from the module, it is clear that
  this pam_response structure could be either statically or dynamically
  (using malloc() etc.) allocated within the application. Repeated calls
  to the conversation function would likely overwrite static memory, so
  it is required that for a successful return from the conversation
  function the memory for the response structure is dynamically
  allocated by the application with one of the malloc() family of
  commands and [4mmust[24m be free()'d by the module.


  If the pam_conv mechanism is used to enter authentication tokens, the
  module should either pass the result to the pam_set_item() library
  function, or copy it itself. In such a case, once the token has been
  stored (by one of these methods or another one), the memory returned
  by the application should be overwritten with 0's, and then free()'d.

  There is a handy macro _pam_drop_reply() to be found in
  <security/_pam_macros.h> that can be used to conveniently cleanup a
  pam_response structure. (Note, this include file is specific to the
  Linux-PAM sources, and whilst it will work with Sun derived PAM
  implementations, it is not generally distributed by Sun.)


  [1m2.1.6.  Getting the name of a user[0m

  Synopsis:


       extern int pam_get_user(pam_handle_t *pamh,
                               const char **user,
                               const char *prompt);



  This is a [1mLinux-PAM [22mlibrary function that returns the (prospective)
  name of the user. To determine the username it does the following
  things, in this order:

  +o  checks what pam_get_item(pamh, PAM_USER, ... ); would have
     returned. If this is not NULL this is what it returns. Otherwise,

  +o  obtains a username from the application via the pam_conv mechanism,
     it prompts the user with the first non-NULL string in the following
     list:

     +o  The prompt argument passed to the function

     +o  What is returned by pam_get_item(pamh,PAM_USER_PROMPT, ... );

     +o  The default prompt: ``Please enter username: ''


  By whatever means the username is obtained, a pointer to it is
  returned as the contents of *user. Note, this memory should [4mnot[24m be
  free()'d by the module. Instead, it will be liberated on the next call
  to pam_get_user(), or by pam_end() when the application ends its
  interaction with [1mLinux-PAM[22m.


  Also, in addition, it should be noted that this function sets the
  PAM_USER item that is associated with the pam_[gs]et_item() function.


  The return value of this function is one of the following:

  +o  PAM_SUCCESS - username obtained.

  +o  PAM_CONV_AGAIN - converstation did not complete and the caller is
     required to return control to the application, until such time as
     the application has completed the conversation process. A module
     calling pam_get_user() that obtains this return code, should return
     PAM_INCOMPLETE and be prepared (when invoked the next time) to
     recall pam_get_user() to fill in the user's name, and then pick up
     where it left off as if nothing had happened. This procedure is
     needed to support an event-driven application programming model.

  +o  PAM_CONV_ERR - the conversation method supplied by the application
     failed to obtain the username.
  [1m2.1.7.  Setting a Linux-PAM environment variable[0m

  Synopsis:


       extern int pam_putenv(pam_handle_t *pamh, const char *name_value);



  [1mLinux-PAM [22mcomes equipped with a series of functions for maintaining a
  set of [4menvironment[24m variables. The environment is initialized by the
  call to pam_start() and is [1merased [22mwith a call to pam_end().  This
  [4menvironment[24m is associated with the pam_handle_t pointer returned by
  the former call.


  The default environment is all but empty. It contains a single NULL
  pointer, which is always required to terminate the variable-list.  The
  pam_putenv() function can be used to add a new environment variable,
  replace an existing one, or delete an old one.



  +o  Adding/replacing a variable

     To add or overwrite a [1mLinux-PAM [22menvironment variable the value of
     the argument name_value, should be of the following form:


       name_value="VARIABLE=VALUE OF VARIABLE"



  Here, VARIABLE is the environment variable's name and what follows the
  `=' is its (new) value. (Note, that "VARIABLE=" is a valid value for
  name_value, indicating that the variable is set to "".)

  +o  Deleting a variable

     To delete a [1mLinux-PAM [22menvironment variable the value of the
     argument name_value, should be of the following form:


       name_value="VARIABLE"



  Here, VARIABLE is the environment variable's name and the absence of
  an `=' indicates that the variable should be removed.


  In all cases PAM_SUCCESS indicates success.


  [1m2.1.8.  Getting a Linux-PAM environment variable[0m

  Synopsis:


       extern const char *pam_getenv(pam_handle_t *pamh, const char *name);


  This function can be used to return the value of the given variable.
  If the returned value is NULL, the variable is not known.


  [1m2.1.9.  Listing the Linux-PAM environment[0m

  Synopsis:


       extern char * const *pam_getenvlist(pam_handle_t *pamh);



  This function returns a pointer to the entire [1mLinux-PAM [22menvironment
  array.  At first sight the [4mtype[24m of the returned data may appear a
  little confusing.  It is basically a [4mread-only[24m array of character
  pointers, that lists the NULL terminated list of environment variables
  set so far.


  Although, this is not a concern for the module programmer, we mention
  here that an application should be careful to copy this entire array
  before executing pam_end() otherwise all the variable information will
  be lost. (There are functions in libpam_misc for this purpose:
  pam_misc_copy_env() and pam_misc_drop_env().)


  [1m2.2.  Other functions provided by libpam[0m

  [1m2.2.1.  Understanding errors[0m


  +o  extern const char *pam_strerror(pam_handle_t *pamh, int errnum);


     This function returns some text describing the [1mLinux-PAM [22merror
     associated with the argument errnum.  If the error is not
     recognized ``Unknown Linux-PAM error'' is returned.



  [1m2.2.2.  Planning for delays[0m


  +o  extern int pam_fail_delay(pam_handle_t *pamh, unsigned int
     micro_sec)


     This function is offered by [1mLinux-PAM [22mto facilitate time delays
     following a failed call to pam_authenticate() and before control is
     returned to the application. When using this function the module
     programmer should check if it is available with,


       #ifdef PAM_FAIL_DELAY
           ....
       #endif /* PAM_FAIL_DELAY */



  Generally, an application requests that a user is authenticated by
  [1mLinux-PAM [22mthrough a call to pam_authenticate() or pam_chauthtok().
  These functions call each of the [4mstacked[24m authentication modules listed
  in the [1mLinux-PAM [22mconfiguration file.  As directed by this file, one of
  more of the modules may fail causing the pam_...() call to return an
  error.  It is desirable for there to also be a pause before the
  application continues. The principal reason for such a delay is
  security: a delay acts to discourage [4mbrute[24m [4mforce[24m dictionary attacks
  primarily, but also helps hinder [4mtimed[24m (cf. covert channel) attacks.


  The pam_fail_delay() function provides the mechanism by which an
  application or module can suggest a minimum delay (of micro_sec [4mmicro-[0m
  [4mseconds[24m). [1mLinux-PAM [22mkeeps a record of the longest time requested with
  this function. Should pam_authenticate() fail, the failing return to
  the application is delayed by an amount of time randomly distributed
  (by up to 25%) about this longest value.


  Independent of success, the delay time is reset to its zero default
  value when [1mLinux-PAM [22mreturns control to the application.



  [1m3.  What is expected of a module[0m

  The module must supply a sub-set of the six functions listed below.
  Together they define the function of a [1mLinux-PAM module[22m. Module
  developers are strongly urged to read the comments on security that
  follow this list.


  [1m3.1.  Overview[0m

  The six module functions are grouped into four independent management
  groups. These groups are as follows: [4mauthentication[24m, [4maccount[24m, [4msession[0m
  and [4mpassword[24m. 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 [4mall[24m four groups.


  [1m3.1.1.  Functional independence[0m

  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 [1mLinux-PAM [22mauthenticate 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
  [4mKERBEROS[24m 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.


  [1m3.1.2.  Minimizing administration problems[0m

  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.


  [1m3.1.3.  Arguments supplied to the module[0m

  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 [4mtext[24m (errors or warnings) to the application.


  The argc and argv arguments are taken from the line appropriate to
  this module---that is, with the [4mservice_name[24m matching that of the
  application---in the configuration file (see the [1mLinux-PAM [22mSystem
  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 [1mnot [22mthe name of the module.


  [1m3.2.  Authentication management[0m

  To be correctly initialized, PAM_SM_AUTH must be #define'd prior to
  including <security/pam_modules.h>. This will ensure that the
  prototypes for static modules are properly declared.



  +o  PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
     int argc, const char **argv);


     This function performs the task of authenticating the user.


     The flags argument can be a logically OR'd with PAM_SILENT and
     optionally take the following value:



     PAM_DISALLOW_NULL_AUTHTOK
        return PAM_AUTH_ERR if the database of authentication tokens for
        this authentication mechanism has a NULL entry for the user.
        Without this flag, such a NULL token will lead to a success
        without the user being prompted.


     Besides PAM_SUCCESS return values that can be sent by this function
     are one of the following:



     PAM_AUTH_ERR
        The user was not authenticated

     PAM_CRED_INSUFFICIENT
        For some reason the application does not have sufficient
        credentials to authenticate the user.

     PAM_AUTHINFO_UNAVAIL
        The modules were not able to access the authentication
        information. This might be due to a network or hardware failure
        etc.

     PAM_USER_UNKNOWN
        The supplied username is not known to the authentication service

     PAM_MAXTRIES
        One or more of the authentication modules has reached its limit
        of tries authenticating the user. Do not try again.



  +o  PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int
     argc, const char **argv);


     This function performs the task of altering the credentials of the
     user with respect to the corresponding authorization scheme.
     Generally, an authentication module may have access to more
     information about a user than their authentication token. This
     function is used to make such information available to the
     application. It should only be called [4mafter[24m the user has been
     authenticated but before a session has been established.


     Permitted flags, one of which, may be logically OR'd with
     PAM_SILENT are,



     PAM_ESTABLISH_CRED
        Set the credentials for the authentication service,

     PAM_DELETE_CRED
        Delete the credentials associated with the authentication
        service,

     PAM_REINITIALIZE_CRED
        Reinitialize the user credentials, and

     PAM_REFRESH_CRED
        Extend the lifetime of the user credentials.


     Prior to [1mLinux-PAM-0.75[22m, and due to a deficiency with the way the
     auth stack was handled in the case of the setcred stack being
     processed, the module was required to attempt to return the same
     error code as pam_sm_authenticate did.  This was necessary to
     preserve the logic followed by libpam as it executes the stack of
     [4mauthentication[24m modules, when the application called either
     pam_authenticate() or pam_setcred().  Failing to do this, led to
     confusion on the part of the System Administrator.


     For [1mLinux-PAM-0.75 [22mand later, libpam handles the credential stack
     much more sanely. The way the auth stack is navigated in order to
     evaluate the pam_setcred() function call, independent of the
     pam_sm_setcred() return codes, is exactly the same way that it was
     navigated when evaluating the pam_authenticate() library call.
     Typically, if a stack entry was ignored in evaluating
     pam_authenticate(), it will be ignored when libpam evaluates the
     pam_setcred() function call. Otherwise, the return codes from each
     module specific pam_sm_setcred() call are treated as required.


     Besides PAM_SUCCESS, the module may return one of the following
     errors:


     PAM_CRED_UNAVAIL
        This module cannot retrieve the user's credentials.

     PAM_CRED_EXPIRED
        The user's credentials have expired.

     PAM_USER_UNKNOWN
        The user is not known to this authentication module.

     PAM_CRED_ERR
        This module was unable to set the credentials of the user.


     these, non-PAM_SUCCESS, return values will typically lead to the
     credential stack [4mfailing[24m. The first such error will dominate in the
     return value of pam_setcred().



  [1m3.3.  Account management[0m

  To be correctly initialized, PAM_SM_ACCOUNT must be #define'd prior to
  including <security/pam_modules.h>.  This will ensure that the
  prototype for a static module is properly declared.



  +o  PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int
     argc, const char **argv);


     This function performs the task of establishing whether the user is
     permitted to gain access at this time. It should be understood that
     the user has previously been validated by an authentication module.
     This function checks for other things. Such things might be: the
     time of day or the date, the terminal line, remote hostname, etc. .


     This function may also determine things like the expiration on
     passwords, and respond that the user change it before continuing.


     Valid flags, which may be logically OR'd with PAM_SILENT, are the
     same as those applicable to the flags argument of
     pam_sm_authenticate.


     This function may return one of the following errors,



     PAM_ACCT_EXPIRED
        The user is no longer permitted access to the system.

     PAM_AUTH_ERR
        There was an authentication error.

     PAM_AUTHTOKEN_REQD
        The user's authentication token has expired. Before calling this
        function again the application will arrange for a new one to be
        given. This will likely result in a call to pam_sm_chauthtok().

     PAM_USER_UNKNOWN
        The user is not known to the module's account management
        component.

  [1m3.4.  Session management[0m

  To be correctly initialized, PAM_SM_SESSION must be #define'd prior to
  including <security/pam_modules.h>.  This will ensure that the
  prototypes for static modules are properly declared.


  The following two functions are defined to handle the
  initialization/termination of a session. For example, at the beginning
  of a session the module may wish to log a message with the system
  regarding the user. Similarly, at the end of the session the module
  would inform the system that the user's session has ended.


  It should be possible for sessions to be opened by one application and
  closed by another. This either requires that the module uses only
  information obtained from pam_get_item(), or that information
  regarding the session is stored in some way by the operating system
  (in a file for example).



  +o  PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
     int argc, const char **argv);


     This function is called to commence a session. The only valid, but
     optional, flag is PAM_SILENT.


     As a return value, PAM_SUCCESS signals success and PAM_SESSION_ERR
     failure.


  +o  PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags,
     int argc, const char **argv);


     This function is called to terminate a session. The only valid, but
     optional, flag is PAM_SILENT.


     As a return value, PAM_SUCCESS signals success and PAM_SESSION_ERR
     failure.



  [1m3.5.  Password management[0m

  To be correctly initialized, PAM_SM_PASSWORD must be #define'd prior
  to including <security/pam_modules.h>.  This will ensure that the
  prototype for a static module is properly declared.



  +o  PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int
     argc, const char **argv);


     This function is used to (re-)set the authentication token of the
     user. A valid flag, which may be logically OR'd with PAM_SILENT,
     can be built from the following list,


     PAM_CHANGE_EXPIRED_AUTHTOK
        This argument indicates to the module that the users
        authentication token (password) should only be changed if it has
        expired. This flag is optional and [4mmust[24m be combined with one of
        the following two flags. Note, however, the following two
        options are [4mmutually[24m [4mexclusive[24m.


     PAM_PRELIM_CHECK
        This indicates that the modules are being probed as to their
        ready status for altering the user's authentication token. If
        the module requires access to another system over some network
        it should attempt to verify it can connect to this system on
        receiving this flag. If a module cannot establish it is ready to
        update the user's authentication token it should return
        PAM_TRY_AGAIN, this information will be passed back to the
        application.


     PAM_UPDATE_AUTHTOK
        This informs the module that this is the call it should change
        the authorization tokens. If the flag is logically OR'd with
        PAM_CHANGE_EXPIRED_AUTHTOK, the token is only changed if it has
        actually expired.



     Note, the [1mLinux-PAM [22mlibrary calls this function twice in
     succession. The first time with PAM_PRELIM_CHECK and then, if the
     module does not return PAM_TRY_AGAIN, subsequently with
     PAM_UPDATE_AUTHTOK. It is only on the second call that the
     authorization token is (possibly) changed.


     PAM_SUCCESS is the only successful return value, valid error-
     returns are:


     PAM_AUTHTOK_ERR
        The module was unable to obtain the new authentication token.


     PAM_AUTHTOK_RECOVERY_ERR
        The module was unable to obtain the old authentication token.


     PAM_AUTHTOK_LOCK_BUSY
        Cannot change the authentication token since it is currently
        locked.


     PAM_AUTHTOK_DISABLE_AGING
        Authentication token aging has been disabled.


     PAM_PERM_DENIED
        Permission denied.


     PAM_TRY_AGAIN
        Preliminary check was unsuccessful. Signals an immediate return
        to the application is desired.


     PAM_USER_UNKNOWN
        The user is not known to the authentication token changing
        service.

  [1m4.  Generic optional arguments[0m

  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 syslog(3) call to log debugging information to the
        system log files.


     no_warn
        Instruct module to not give warning messages to the application.


     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).


     try_first_pass
        The module should attempt authentication with the previously
        typed password (by a call to pam_get_item() for the PAM_AUTHTOK
        item). If that doesn't work, then the user is prompted for a
        password. (This option is intended for auth modules only).


     use_mapped_pass
        [1mWARNING: [22mcoding this functionality may cause the module writer
        to break [4mlocal[24m encryption laws. For example, in the U.S. there
        are restrictions on the export computer code that is capable of
        strong encryption.  It has not been established whether this
        option is affected by this law, but one might reasonably assume
        that it does until told otherwise.  For this reason, this option
        is not supported by any of the modules distributed with [1mLinux-[0m
        [1mPAM[22m.

        The intended function of this argument, however, is that the
        module should take the existing authentication token from a
        previously invoked module and use it as a key to retrieve the
        authentication token for this module. For example, the module
        might create a strong hash of the PAM_AUTHTOK item (established
        by a previously executed module). Then, with logical-exclusive-
        or, use the result as a [4mkey[24m to safely store/retrieve the
        authentication token for this module in/from a local file [4metc[24m. .


     expose_account

        In general the leakage of some information about user accounts
        is not a secure policy for modules to adopt. Sometimes
        information such as users names or home directories, or
        preferred shell, can be used to attack a user's account. In some
        circumstances, however, this sort of information is not deemed a
        threat: displaying a user's full name when asking them for a
        password in a secured environment could also be called being
        'friendly'. The expose_account argument is a standard module
        argument to encourage a module to be less discrete about account
        information as it is deemed appropriate by the local
        administrator.

  [1m5.  Programming notes[0m

  Here we collect some pointers for the module writer to bear in mind
  when writing/developing a [1mLinux-PAM [22mcompatible module.


  [1m5.1.  Security issues for module creation[0m

  [1m5.1.1.  Sufficient resources[0m

  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 setrlimit(2) family of commands should
  be taken into consideration.


  [1m5.1.2.  Who's who?[0m

  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 [4msu[24m program: user joe executes [4msu[24m to become the
  user [4mjane[24m.  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.



  +o  X, the identity of the user invoking the service request.  This is
     the user identifier; returned by the function getuid(2).

  +o  Y, the privileged identity of the application used to grant the
     requested service.  This is the [4meffective[24m user identifier; returned
     by the function geteuid(2).

  +o  Z, the user under whose identity the service will be granted.  This
     is the username returned by pam_get_user(2) and also stored in the
     [1mLinux-PAM [22mitem, PAM_USER.

  +o  [1mLinux-PAM [22mhas 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 [1mLinux-PAM [22mlibrary.



  [1m5.1.3.  Using the conversation function[0m

  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.


  [1m5.1.4.  Authentication tokens[0m

  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 [1mLinux-PAM [22mlibrary 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;
       }



  [1m5.2.  Use of syslog(3)[0m

  Only rarely should error information be directed to the user. Usually,
  this is to be limited to ``[4msorry[24m [4myou[24m [4mcannot[24m [4mlogin[24m [4mnow[24m'' 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 syslog(3) with [4mfacility-type[0m
  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:



  +o  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 [1mrequired [22mto be logged at the LOG_ERR level.

  +o  Debugging information, as activated by the debug argument to the
     module in /etc/pam.conf, should be logged at the LOG_DEBUG level.

  +o  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.

  +o  Shortages of system resources, such as a failure to manipulate a
     file or malloc() failures should be logged at level LOG_CRIT.

  +o  Authentication failures, associated with an incorrectly typed
     password should be logged at level, LOG_NOTICE.


  [1m5.3.  Modules that require system libraries[0m

  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 -l[4mXXX[24m arguments for the desired
  libraries when you create the shared module object. To make sure a
  module is linked to the lib[4mwhatever[24m.so library when it is dlopen()ed,
  try:


       % gcc -shared -Xlinker -x -o pam_module.so pam_module.o -lwhatever



  [1m5.4.  Added requirements for statically  loaded modules.[0m

  Modules may be statically linked into libpam. This should be true of
  all the modules distributed with the basic [1mLinux-PAM [22mdistribution.  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:

  +o  Define a single structure, struct pam_module, called
     _pam_[4mmodname[24m_modstruct, where [4mmodname[24m is the name of the module [1mas[0m
     [1mused in the filesystem [22mbut 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 [4mstatic[24m or [4mdynamic[24m:



       #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 [4mlibpam[24m, staticly-linked modules must be built from
  within the Linux-PAM-X.YY/modules/ subdirectory of the [1mLinux-PAM[0m
  source directory as part of a normal build of the [1mLinux-PAM [22msystem.

  The [4mMakefile[24m, 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 [4mlibpam[24m.

  The [1mtwo [22mmanditory 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 [4mMakefile[24m 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
  [1mLinux-PAM [22mdistribution.
  [1m6.  An example module file[0m

  At some point, we may include a fully commented example of a module in
  this document. For now, we point the reader to these two locations in
  the public CVS repository:

  +o  A module that always succeeds: http://cvs.sourceforge.net/cgi-
     bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_permit/

  +o  A module that always fails: http://cvs.sourceforge.net/cgi-
     bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_deny/


  [1m7.  Files[0m



     /usr/lib/libpam.so.*
        the shared library providing applications with access to [1mLinux-[0m
        [1mPAM[22m.


     /etc/pam.conf
        the [1mLinux-PAM [22mconfiguration file.


     /usr/lib/security/pam_*.so
        the primary location for [1mLinux-PAM [22mdynamically loadable object
        files; the modules.



  [1m8.  See also[0m


  +o  The [1mLinux-PAM [22mSystem Administrators' Guide.

  +o  The [1mLinux-PAM [22mApplication Writers' Guide.

  +o  V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH PLUGGABLE
     AUTHENTICATION MODULES'', Open Software Foundation Request For
     Comments 86.0, October 1995.


  [1m9.  Notes[0m

  I intend to put development comments here... like ``at the moment this
  isn't actually supported''. At release time what ever is in this
  section will be placed in the Bugs section below! :)



  +o  Perhaps we should keep a registry of data-names as used by
     pam_[gs]et_data() so there are no unintentional problems due to
     conflicts?

  +o  pam_strerror() should be internationalized....

  +o  There has been some debate about whether initgroups() should be in
     an application or in a module. It was settled by Sun who stated
     that initgroups is an action of the [4mapplication[24m. The modules are
     permitted to add additional groups, however.

  +o  Refinements/futher suggestions to syslog(3) usage by modules are
     needed.

  [1m10.  Author/acknowledgments[0m

  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,
  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
  [1mLinux-PAM[22m, Sun graciously made the documentation for their
  implementation of PAM available. This act greatly accelerated the
  development of [1mLinux-PAM[22m.


  [1m11.  Bugs/omissions[0m

  Few PAM modules currently exist. Few PAM-aware applications exist.
  This document is hopelessly unfinished. Only a partial list of people
  is credited for all the good work they have done.


  [1m12.  Copyright information for this document[0m

  Copyright (c) Andrew G. Morgan 1996-2002.  All rights reserved.
  Email: <morgan@kernel.org>


  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:



  +o  1. Redistributions of source code must retain the above copyright
     notice, and the entire permission notice in its entirety, including
     the disclaimer of warranties.

  +o  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.

  +o  3. The name of the author may not be used to endorse or promote
     products derived from this software without specific prior written
     permission.


  [1mAlternatively[22m, 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 [1minstead of [22mthe 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
  DAMAGE.


  $Id: pam_modules.sgml,v 1.9 2002/05/10 06:00:12 agmorgan Exp $



