diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2000-06-20 22:10:38 +0000 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2000-06-20 22:10:38 +0000 |
commit | ea488580c42e8918445a945484de3c8a5addc761 (patch) | |
tree | c992f3ba699caafedfadc16af38e6359c3c24698 /doc/pam_modules.sgml | |
download | pam-ea488580c42e8918445a945484de3c8a5addc761.tar.gz pam-ea488580c42e8918445a945484de3c8a5addc761.tar.bz2 pam-ea488580c42e8918445a945484de3c8a5addc761.zip |
Initial revision
Diffstat (limited to 'doc/pam_modules.sgml')
-rw-r--r-- | doc/pam_modules.sgml | 1476 |
1 files changed, 1476 insertions, 0 deletions
diff --git a/doc/pam_modules.sgml b/doc/pam_modules.sgml new file mode 100644 index 00000000..e76e3d7a --- /dev/null +++ b/doc/pam_modules.sgml @@ -0,0 +1,1476 @@ +<!doctype linuxdoc system> + +<!-- + + $Id$ + + Copyright (c) Andrew G. Morgan 1996-9. All rights reserved. + + ** some sections, in this document, were contributed by other + ** authors. They carry individual copyrights. + +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, 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 +DAMAGE. + + --> + +<article> + +<title>The Linux-PAM Module Writers' Guide +<author>Andrew G. Morgan, <tt>morgan@linux.kernel.org</tt> +<date>DRAFT v0.71 1999/11/8 +<abstract> +This manual documents what a programmer needs to know in order to +write a module that conforms to the <bf/Linux-PAM/ standard. It also +discusses some security issues from the point of view of the module +programmer. +</abstract> + +<toc> + +<sect>Introduction + +<sect1> Synopsis +<p> +<tscreen> +<verb> +#include <security/pam_modules.h> + +gcc -fPIC -c pam_module-name.c +ld -x --shared -o pam_module-name.so pam_module-name.o -lpam +</verb> +</tscreen> + +<sect1> Description + +<p> +<bf/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 +<bf/Linux-PAM/ library see the <bf/Linux-PAM/ System Administrators' +Guide. + +<p> +A <bf/Linux-PAM/ module is a single executable binary file that can be +loaded by the <bf/Linux-PAM/ interface library. This PAM library is +configured locally with a system file, <tt>/etc/pam.conf</tt>, to +authenticate a user request via the locally available authentication +modules. The modules themselves will usually be located in the +directory <tt>/usr/lib/security</tt> and take the form of dynamically +loadable object files (see dlopen(3)). Alternatively, the modules can +be statically linked into the <bf/Linux-PAM/ library; this is mostly to +allow <bf/Linux-PAM/ to be used on platforms without dynamic linking +available, but the two forms can be used together. It is the +<bf/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 <bf/Linux-PAM/-module. + +<p> +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. + +<sect>What can be expected by the module + +<p> +Here we list the interface that the conventions that all +<bf/Linux-PAM/ modules must adhere to. + +<sect1>Getting and setting <tt/PAM_ITEM/s and <em/data/ + +<p> +First, we cover what the module should expect from the <bf/Linux-PAM/ +library and a <bf/Linux-PAM/ <em/aware/ application. Essesntially this +is the <tt/libpam.*/ library. + +<sect2> +Setting data + +<p> +Synopsis: +<tscreen> +<verb> +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) ); +</verb> +</tscreen> + +<p> +The modules may be dynamically loadable objects. In general such files +should not contain <tt/static/ variables. This and the subsequent +function provide a mechanism for a module to associate some data with +the handle <tt/pamh/. Typically a module will call the +<tt/pam_set_data()/ function to register some data under a (hopefully) +unique <tt/module_data_name/. The data is available for use by other +modules too but <em/not/ by an application. + +<p> +The function <tt/cleanup()/ is associated with the <tt/data/ and, if +non-<tt/NULL/, it is called when this data is over-written or +following a call to <tt/pam_end()/ (see the Linux-PAM Application +Developers' Guide). + +<p> +The <tt/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 +<tt/pam_end()/ is called by the module, the <tt/error_status/ +carries the return value of the <tt/pam_authenticate()/ or other +<tt/libpam/ function as appropriate. Based on this value the Kerberos +module may choose to delete the ticket file (<em/authentication +failure/) or leave it in place. + +<p> +The <tt/error_status/ may have been logically OR'd with either of the +following two values: + +<p> +<descrip> +<tag><tt/PAM_DATA_REPLACE/</tag> + When a data item is being replaced (through a second call to +<tt/pam_set_data()/) this mask is used. Otherwise, the call is assumed +to be from <tt/pam_end()/. + +<tag><tt/PAM_DATA_SILENT/</tag> + Which indicates that the process would prefer to perform the +<tt/cleanup()/ quietly. That is, discourages logging/messages to the +user. + +</descrip> + + +<sect2> +Getting data + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_get_data(const pam_handle_t *pamh, + const char *module_data_name, + const void **data); +</verb> +</tscreen> + +<p> +This function together with the previous one provides a method of +associating module-specific data with the handle <tt/pamh/. A +successful call to <tt/pam_get_data/ will result in <tt/*data/ +pointing to the data associated with the <tt/module_data_name/. Note, +this data is <em/not/ a copy and should be treated as <em/constant/ +by the module. + +<p> +Note, if there is an entry but it has the value <tt/NULL/, then this +call returns <tt/PAM_NO_MODULE_DATA/. + +<sect2> +Setting items + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_set_item(pam_handle_t *pamh + , int item_type + , const void *item + ); +</verb> +</tscreen> + +<p> +This function is used to (re)set the value of one of the +<tt/item_type/s. The reader is urged to read the entry for this +function in the <bf/Linux-PAM/ application developers' manual. + +<p> +In addition to the <tt/item/s listed there, the module can set the +following two <tt/item_type/s: + +<p> +<descrip> +<tag><tt/PAM_AUTHTOK/</tag> + +The authentication token (password). This token should be ignored by +all module functions besides <tt/pam_sm_authenticate()/ and +<tt/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. + +<tag><tt/PAM_OLDAUTHTOK/</tag> + +The old authentication token. This token should be ignored by all +module functions except <tt/pam_sm_chauthtok()/. + +</descrip> + +<p> +Both of these items are reset before returning to the application. +When resetting these items, the <bf/Linux-PAM/ library first writes +<tt/0/'s to the current tokens and then <tt/free()/'s the associated +memory. + +<p> +The return values for this function are listed in the +<bf>Linux-PAM</bf> Application Developers' Guide. + +<sect2> +Getting items + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_get_item(const pam_handle_t *pamh + , int item_type + , const void **item + ); +</verb> +</tscreen> + +<p> +This function is used to obtain the value of the specified +<tt/item_type/. It is better documented in the <bf/Linux-PAM/ +Application Developers' Guide. However, there are three things worth +stressing here: +<itemize> + +<item> +Generally, if the module wishes to obtain the name of the user, it +should not use this function, but instead perform a call to +<tt/pam_get_user()/ (see section <ref id="pam-get-user" +name="below">). + +<item> +The module is additionally privileged to read the authentication +tokens, <tt/PAM_AUTHTOK/ and <tt/PAM_OLDAUTHTOK/ (see the section +above on <tt/pam_set_data()/). + +<item> +The module should <em/not/ <tt/free()/ or alter the data pointed to by +<tt/*item/ after a successful return from <tt/pam_get_item()/. This +pointer points directly at the data contained within the <tt/*pamh/ +structure. Should a module require that a change is made to the this +<tt/ITEM/ it should make the appropriate call to <tt/pam_set_item()/. +</itemize> + +<sect2>The <em/conversation/ mechanism + +<p> +Following the call <tt>pam_get_item(pamh,PAM_CONV,&item)</tt>, the +pointer <tt/item/ points to a <em/conversation/-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. + +<p> +The reader is strongly urged to read the more complete description of +the <tt/pam_conv/ structure, written from the perspective of the +application developer, in the <bf/Linux-PAM/ Application Developers' +Guide. + +<p> +The <tt/pam_response/ structure returned after a call to the +<tt/pam_conv/ function must be <tt/free()/'d by the module. Since the +call to the conversation function originates from the module, it is +clear that either this <tt/pam_response/ structure could be either +statically or dynamically (using <tt/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 <tt/malloc()/ family of commands and <em/must/ be +<tt/free()/'d by the module. + +<p> +If the <tt/pam_conv/ mechanism is used to enter authentication tokens, +the module should either pass the result to the <tt/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 <tt/0/'s, and +then <tt/free()/'d. + +<p> +The return values for this function are listed in the +<bf>Linux-PAM</bf> Application Developers' Guide. + +<sect2>Getting the name of a user<label id="pam-get-user"> + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_get_user(pam_handle_t *pamh, + const char **user, + const char *prompt); +</verb> +</tscreen> + +<p> +This is a <bf/Linux-PAM/ library function that returns the +(prospective) name of the user. To determine the username it does the +following things, in this order: +<itemize> + +<item> checks what <tt/pam_get_item(pamh, PAM_USER, ... );/ would have +returned. If this is not <tt/NULL/ this is what it returns. Otherwise, + +<item> obtains a username from the application via the <tt/pam_conv/ +mechanism, it prompts the user with the first non-<tt/NULL/ string in +the following list: +<itemize> + +<item> The <tt/prompt/ argument passed to the function +<item> What is returned by <tt/pam_get_item(pamh,PAM_USER_PROMPT, ... );/ +<item> The default prompt: ``Please enter username: '' + +</itemize> +</itemize> + +<p> +By whatever means the username is obtained, a pointer to it is +returned as the contents of <tt/*user/. Note, this memory should +<em/not/ be <tt/free()/'d by the module. Instead, it will be liberated +on the next call to <tt/pam_get_user()/, or by <tt/pam_end()/ when the +application ends its interaction with <bf/Linux-PAM/. + +<p> +Also, in addition, it should be noted that this function sets the +<tt/PAM_USER/ item that is associated with the <tt/pam_[gs]et_item()/ +function. + +<p> +The return value of this function is one of the following: +<itemize> + +<item> <tt/PAM_SUCCESS/ - username obtained. + +<item> <tt/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 <tt/pam_get_user()/ that obtains this return code, +should return <tt/PAM_INCOMPLETE/ and be prepared (when invoked the +next time) to recall <tt/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. + +<item> <tt/PAM_CONV_ERR/ - the conversation method supplied by the +application failed to obtain the username. + +</itemize> + +<sect2>Setting a Linux-PAM environment variable + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_putenv(pam_handle_t *pamh, const char *name_value); +</verb> +</tscreen> + +<p> +<bf/Linux-PAM/ (0.54+) comes equipped with a series of functions for +maintaining a set of <em/environment/ variables. The environment is +initialized by the call to <tt/pam_start()/ and is <bf/erased/ with a +call to <tt/pam_end()/. This <em/environment/ is associated with the +<tt/pam_handle_t/ pointer returned by the former call. + +<p> +The default environment is all but empty. It contains a single +<tt/NULL/ pointer, which is always required to terminate the +variable-list. The <tt/pam_putenv()/ function can be used to add a +new environment variable, replace an existing one, or delete an old +one. + +<p> +<itemize> +<item>Adding/replacing a variable<newline> + +To add or overwrite a <bf/Linux-PAM/ environment variable the value of +the argument <tt/name_value/, should be of the following form: +<tscreen> +<verb> +name_value="VARIABLE=VALUE OF VARIABLE" +</verb> +</tscreen> +Here, <tt/VARIABLE/ is the environment variable's name and what +follows the `<tt/=/' is its (new) value. (Note, that <tt/"VARIABLE="/ +is a valid value for <tt/name_value/, indicating that the variable is +set to <tt/""/.) + +<item> Deleting a variable<newline> + +To delete a <bf/Linux-PAM/ environment variable the value of +the argument <tt/name_value/, should be of the following form: +<tscreen> +<verb> +name_value="VARIABLE" +</verb> +</tscreen> +Here, <tt/VARIABLE/ is the environment variable's name and the absence +of an `<tt/=/' indicates that the variable should be removed. + +</itemize> + +<p> +In all cases <tt/PAM_SUCCESS/ indicates success. + +<sect2>Getting a Linux-PAM environment variable + +<p> +Synopsis: +<tscreen> +<verb> +extern const char *pam_getenv(pam_handle_t *pamh, const char *name); +</verb> +</tscreen> + +<p> +This function can be used to return the value of the given +variable. If the returned value is <tt/NULL/, the variable is not +known. + +<sect2>Listing the Linux-PAM environment + +<p> +Synopsis: +<tscreen> +<verb> +extern char * const *pam_getenvlist(pam_handle_t *pamh); +</verb> +</tscreen> + +<p> +This function returns a pointer to the entire <bf/Linux-PAM/ +environment array. At first sight the <em/type/ of the returned data +may appear a little confusing. It is basically a <em/read-only/ array +of character pointers, that lists the <tt/NULL/ terminated list of +environment variables set so far. + +<p> +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 <tt/pam_end()/ otherwise all the variable information +will be lost. (There are functions in <tt/libpam_misc/ for this +purpose: <tt/pam_misc_copy_env()/ and <tt/pam_misc_drop_env()/.) + +<sect1>Other functions provided by <tt/libpam/ + +<sect2>Understanding errors + +<p> +<itemize> + +<item> +<tt>extern const char *pam_strerror(pam_handle_t *pamh, int errnum);</tt> + +<p> +This function returns some text describing the <bf/Linux-PAM/ error +associated with the argument <tt/errnum/. If the error is not +recognized <tt/``Unknown Linux-PAM error''/ is returned. + +</itemize> + +<sect2>Planning for delays + +<p> +<itemize> + +<item> +<tt>extern int pam_fail_delay(pam_handle_t *pamh, unsigned int +micro_sec)</tt> + +<p> +This function is offered by <bf/Linux-PAM/ to facilitate time delays +following a failed call to <tt/pam_authenticate()/ and before control +is returned to the application. When using this function the module +programmer should check if it is available with, +<tscreen> +<verb> +#ifdef HAVE_PAM_FAIL_DELAY + .... +#endif /* HAVE_PAM_FAIL_DELAY */ +</verb> +</tscreen> + +<p> +Generally, an application requests that a user is authenticated by +<bf/Linux-PAM/ through a call to <tt/pam_authenticate()/ or +<tt/pam_chauthtok()/. These functions call each of the <em/stacked/ +authentication modules listed in the <bf/Linux-PAM/ configuration +file. As directed by this file, one of more of the modules may fail +causing the <tt/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 <em/brute force/ dictionary attacks primarily, but also +helps hinder <em/timed/ (cf. covert channel) attacks. + +<p> +The <tt/pam_fail_delay()/ function provides the mechanism by which an +application or module can suggest a minimum delay (of <tt/micro_sec/ +<em/micro-seconds/). <bf/Linux-PAM/ keeps a record of the longest time +requested with this function. Should <tt/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. + +<p> +Independent of success, the delay time is reset to its zero default +value when <bf/Linux-PAM/ returns control to the application. + +</itemize> + +<sect>What is expected of a module + +<p> +The module must supply a sub-set of the six functions listed +below. Together they define the function of a <bf/Linux-PAM +module/. Module developers are strongly urged to read the comments on +security that follow this list. + +<sect1> Overview + +<p> +The six module functions are grouped into four independent management +groups. These groups are as follows: <em/authentication/, +<em/account/, <em/session/ and <em/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 +<em/all/ four groups. + +<sect2> Functional independence + +<p> +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. + +<p> +As an informative example, consider the possibility that an +application applies to change a user's authentication token, without +having first requested that <bf/Linux-PAM/ authenticate the user. In +some cases this may be deemed appropriate: when <tt/root/ wants to +change the authentication token of some lesser user. In other cases it +may not be appropriate: when <tt/joe/ maliciously wants to reset +<tt/alice/'s password; or when anyone other than the user themself +wishes to reset their <em/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. + +<sect2> Minimizing administration problems + +<p> +To avoid system administration problems and the poor construction of a +<tt>/etc/pam.conf</tt> file, the module developer may define all +six of the following functions. For those functions that would not be +called, the module should return <tt/PAM_SERVICE_ERR/ and write an +appropriate message to the system log. When this action is deemed +inappropriate, the function would simply return <tt/PAM_IGNORE/. + +<sect2> Arguments supplied to the module + +<p> +The <tt/flags/ argument of each of the following functions can be +logically OR'd with <tt/PAM_SILENT/, which is used to inform the +module to not pass any <em/text/ (errors or warnings) to the +application. + +<p> +The <tt/argc/ and <tt/argv/ arguments are taken from the line +appropriate to this module---that is, with the <em/service_name/ +matching that of the application---in the configuration file (see the +<bf/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 +<tt/main()/. Note, however, that the first argument (<tt/argv[0]/) is +a true argument and <bf/not/ the name of the module. + +<sect1> Authentication management + +<p> +To be correctly initialized, <tt/PAM_SM_AUTH/ must be <tt/#define/'d +prior to including <tt><security/pam_modules.h></tt>. This will +ensure that the prototypes for static modules are properly declared. + +<p> +<itemize> + +<item> +<tt>PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, +int argc, const char **argv);</tt> + +<p> +This function performs the task of authenticating the user. + +<p> +The <tt/flags/ argument can be a logically OR'd with <tt/PAM_SILENT/ +and optionally take the following value: + +<p><descrip> +<tag><tt/PAM_DISALLOW_NULL_AUTHTOK/</tag> + return <tt/PAM_AUTH_ERR/ if the database of authentication +tokens for this authentication mechanism has a <tt/NULL/ entry for the +user. Without this flag, such a <tt/NULL/ token will lead to a success +without the user being prompted. +</descrip> + +<p> +Besides <tt/PAM_SUCCESS/ return values that can be sent by this +function are one of the following: + +<descrip> + +<tag><tt/PAM_AUTH_ERR/</tag> + The user was not authenticated +<tag><tt/PAM_CRED_INSUFFICIENT/</tag> + For some reason the application does not have sufficient +credentials to authenticate the user. +<tag><tt/PAM_AUTHINFO_UNAVAIL/</tag> + The modules were not able to access the authentication +information. This might be due to a network or hardware failure etc. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The supplied username is not known to the authentication +service +<tag><tt/PAM_MAXTRIES/</tag> + One or more of the authentication modules has reached its +limit of tries authenticating the user. Do not try again. + +</descrip> + +<item> +<tt>PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +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 <em/after/ the user has been +authenticated and after a session has been established. + +<p> +Permitted flags, one of which, may be logically OR'd with +<tt/PAM_SILENT/ are, + +<p><descrip> +<tag><tt/PAM_ESTABLISH_CRED/</tag> + Set the credentials for the authentication service, +<tag><tt/PAM_DELETE_CRED/</tag> + Delete the credentials associated with the authentication service, +<tag><tt/PAM_REINITIALIZE_CRED/</tag> + Reinitialize the user credentials, and +<tag><tt/PAM_REFRESH_CRED/</tag> + Extend the lifetime of the user credentials. +</descrip> + +<p> +Generally, the module should attempt to return the same error code as +<tt/pam_sm_authenticate/ did. This will preserve the logic followed +by libpam as it executes the stack of <em/authentication/ modules, +when the application calls <tt/pam_authenticate()/ and +<tt/pam_setcred()/. Failing to do this, will lead to much confudion +on the part of the System administrator. + +<p> +<bf>The following text is depreciated. Some thought needs to be given to +how the credential setting modules are supposed to be stacked...</bf> + +<p> +Besides <tt/PAM_SUCCESS/, the module may return one of the following +errors: + +<p><descrip> +<tag><tt/PAM_CRED_UNAVAIL/</tag> + This module cannot retrieve the user's credentials. +<tag><tt/PAM_CRED_EXPIRED/</tag> + The user's credentials have expired. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to this authentication module. +<tag><tt/PAM_CRED_ERR/</tag> + This module was unable to set the credentials of the user. +</descrip> + +</itemize> + +<sect1> Account management + +<p> +To be correctly initialized, <tt/PAM_SM_ACCOUNT/ must be +<tt/#define/'d prior to including <tt><security/pam_modules.h></tt>. +This will ensure that the prototype for a static module is properly +declared. + +<p> +<itemize> + +<item> +<tt>PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +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. . + +<p> +This function may also determine things like the expiration on +passwords, and respond that the user change it before continuing. + +<p> +Valid flags, which may be logically OR'd with <tt/PAM_SILENT/, are the +same as those applicable to the <tt/flags/ argument of +<tt/pam_sm_authenticate/. + +<p> +This function may return one of the following errors, + +<descrip> + +<tag><tt/PAM_ACCT_EXPIRED/</tag> + The user is no longer permitted access to the system. +<tag><tt/PAM_AUTH_ERR/</tag> + There was an authentication error. +<tag><tt/PAM_AUTHTOKEN_REQD/</tag> + 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 <tt/pam_sm_chauthtok()/. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to the module's account management +component. + +</descrip> + +</itemize> + +<sect1> Session management + +<p> +To be correctly initialized, <tt/PAM_SM_SESSION/ must be +<tt/#define/'d prior to including +<tt><security/pam_modules.h></tt>. This will ensure that the +prototypes for static modules are properly declared. + +<p> +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. + +<p> +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 <tt/pam_get_item()/, or that information +regarding the session is stored in some way by the operating system +(in a file for example). + +<p> +<itemize> + +<item> +<tt>PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +This function is called to commence a session. The only valid, but +optional, flag is <tt/PAM_SILENT/. + +<p> +As a return value, <tt/PAM_SUCCESS/ signals success and +<tt/PAM_SESSION_ERR/ failure. + +<item> +<tt>PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +This function is called to terminate a session. The only valid, but +optional, flag is <tt/PAM_SILENT/. + +<p> +As a return value, <tt/PAM_SUCCESS/ signals success and +<tt/PAM_SESSION_ERR/ failure. + +</itemize> + +<sect1> Password management + +<p> +To be correctly initialized, <tt/PAM_SM_PASSWORD/ must be +<tt/#define/'d prior to including <tt><security/pam_modules.h></tt>. +This will ensure that the prototype for a static module is properly +declared. + +<p> +<itemize> + +<item> +<tt>PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +This function is used to (re-)set the authentication token of the +user. A valid flag, which may be logically OR'd with <tt/PAM_SILENT/, +can be built from the following list, + +<descrip> +<tag><tt/PAM_CHANGE_EXPIRED_AUTHTOK/</tag> + 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 <em/must/ be combined with one of +the following two flags. Note, however, the following two options are +<em/mutually exclusive/. + +<tag><tt/PAM_PRELIM_CHECK/</tag> + 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 <tt/PAM_TRY_AGAIN/, this +information will be passed back to the application. + +<tag><tt/PAM_UPDATE_AUTHTOK/</tag> + This informs the module that this is the call it should change +the authorization tokens. If the flag is logically OR'd with +<tt/PAM_CHANGE_EXPIRED_AUTHTOK/, the token is only changed if it has +actually expired. + +</descrip> + +<p> +Note, the <bf/Linux-PAM/ library calls this function twice in +succession. The first time with <tt/PAM_PRELIM_CHECK/ and then, if the +module does not return <tt/PAM_TRY_AGAIN/, subsequently with +<tt/PAM_UPDATE_AUTHTOK/. It is only on the second call that the +authorization token is (possibly) changed. + +<p> +<tt/PAM_SUCCESS/ is the only successful return value, valid +error-returns are: + +<descrip> +<tag><tt/PAM_AUTHTOK_ERR/</tag> + The module was unable to obtain the new authentication token. + +<tag><tt/PAM_AUTHTOK_RECOVERY_ERR/</tag> + The module was unable to obtain the old authentication token. + +<tag><tt/PAM_AUTHTOK_LOCK_BUSY/</tag> + Cannot change the authentication token since it is currently +locked. + +<tag><tt/PAM_AUTHTOK_DISABLE_AGING/</tag> + Authentication token aging has been disabled. + +<tag><tt/PAM_PERM_DENIED/</tag> + Permission denied. + +<tag><tt/PAM_TRY_AGAIN/</tag> + Preliminary check was unsuccessful. Signals an immediate return +to the application is desired. + +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to the authentication token changing +service. + +</descrip> + +</itemize> + +<sect>Generic optional arguments + +<p> +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. + +<p> +<descrip> +<tag><tt/debug/</tag> + +Use the <tt/syslog(3)/ call to log debugging information to the system +log files. + +<tag><tt/no_warn/</tag> + +Instruct module to not give warning messages to the application. + +<tag><tt/use_first_pass/</tag> + +The module should not prompt the user for a password. Instead, it +should obtain the previously typed password (by a call to +<tt/pam_get_item()/ for the <tt/PAM_AUTHTOK/ item), and use that. If +that doesn't work, then the user will not be authenticated. (This +option is intended for <tt/auth/ and <tt/passwd/ modules only). + +<tag><tt/try_first_pass/</tag> + +The module should attempt authentication with the previously typed +password (by a call to <tt/pam_get_item()/ for the <tt/PAM_AUTHTOK/ +item). If that doesn't work, then the user is prompted for a +password. (This option is intended for <tt/auth/ modules only). + +<tag><tt/use_mapped_pass/</tag> + +<bf/WARNING:/ coding this functionality may cause the module writer to +break <em/local/ 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 <bf/Linux-PAM/. + +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 <tt/PAM_AUTHTOK/ item (established by a previously +executed module). Then, with logical-exclusive-or, use the result as a +<em/key/ to safely store/retrieve the authentication token for this +module in/from a local file <em/etc/. . + +<tag><tt/expose_account/</tag> + +<p> +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 <tt/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. + +</descrip> + +<sect>Programming notes + +<p> +Here we collect some pointers for the module writer to bear in mind +when writing/developing a <bf/Linux-PAM/ compatible module. + +<sect1>Security issues for module creation + +<sect2>Sufficient resources + +<p> +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 <tt/setrlimit(2)/ family of commands +should be taken into consideration. + +<sect2>Who's who? + +<p> +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 <tt/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. + +<p> +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 <em/su/ program: user <tt/joe/ executes +<em/su/ to become the user <em/jane/. In this situation X=<tt/joe/, +Y=<tt/root/ and Z=<tt/jane/. Clearly, it is important that the module +does not confuse these different users and grant an inappropriate +level of privilege. + +<p> +The following is the convention to be adhered to when juggling +user-identities. + +<p> +<itemize> +<item>X, the identity of the user invoking the service request. +This is the user identifier; returned by the function <tt/getuid(2)/. + +<item>Y, the privileged identity of the application used to grant the +requested service. This is the <em/effective/ user identifier; +returned by the function <tt/geteuid(2)/. + +<item>Z, the user under whose identity the service will be granted. +This is the username returned by <tt/pam_get_user(2)/ and also stored +in the <bf/Linux-PAM/ item, <tt/PAM_USER/. + +<item><bf/Linux-PAM/ has a place for an additional user identity that +a module may care to make use of. This is the <tt/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. + +</itemize> + +<p> +Note, if a module wishes to modify the identity of either the <tt/uid/ +or <tt/euid/ of the running process, it should take care to restore +the original values prior to returning control to the <bf/Linux-PAM/ +library. + +<sect2>Using the conversation function +<p> +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! + +<p> +The module should be prepared for a failure from the conversation. The +generic error would be <tt/PAM_CONV_ERR/, but anything other than +<tt/PAM_SUCCESS/ should be treated as indicating failure. + +<sect2>Authentication tokens + +<p> +To ensure that the authentication tokens are not left lying around the +items, <tt/PAM_AUTHTOK/ and <tt/PAM_OLDAUTHTOK/, are not available to +the application: they are defined in +<tt><security/pam_modules.h></tt>. 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 <tt/free()/'ing them. The <bf/Linux-PAM/ library is +required to do this when either of these authentication token items +are (re)set. + +<p> +Not to dwell too little on this concern; should the module store the +authentication tokens either as (automatic) function variables or +using <tt/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 <tt/cleanup()/ function +should explicitly overwrite the <tt/*data/ before <tt/free()/'ing it: +for example, + +<tscreen> +<verb> +/* + * 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; +} +</verb> +</tscreen> + +<sect1>Use of <tt/syslog(3)/ + +<p> +Only rarely should error information be directed to the user. Usually, +this is to be limited to ``<em/sorry you cannot login now/'' type +messages. Information concerning errors in the configuration file, +<tt>/etc/pam.conf</tt>, or due to some system failure encountered by +the module, should be written to <tt/syslog(3)/ with +<em/facility-type/ <tt/LOG_AUTHPRIV/. + +<p> +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: + +<p> +<itemize> + +<item> +As a general rule, errors encountered by a module should be logged at +the <tt/LOG_ERR/ level. However, information regarding an unrecognized +argument, passed to a module from an entry in the +<tt>/etc/pam.conf</tt> file, is <bf/required/ to be logged at the +<tt/LOG_ERR/ level. + +<item> +Debugging information, as activated by the <tt/debug/ argument to the +module in <tt>/etc/pam.conf</tt>, should be logged at the +<tt/LOG_DEBUG/ level. + +<item> +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, <tt/LOG_ALERT/. + +<item> +Shortages of system resources, such as a failure to manipulate a file +or <tt/malloc()/ failures should be logged at level <tt/LOG_CRIT/. + +<item> +Authentication failures, associated with an incorrectly typed password +should be logged at level, <tt/LOG_NOTICE/. + +</itemize> + +<sect1> Modules that require system libraries + +<p> +Writing a module is much like writing an application. You have to +provide the "conventional hooks" for it to work correctly, like +<tt>pam_sm_authenticate()</tt> etc., which would correspond to the +<tt/main()/ function in a normal function. + +<p> +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 <tt>-l</tt><em>XXX</em> arguments +for the desired libraries when you create the shared module object. To +make sure a module is linked to the <tt>lib<em>whatever</em>.so</tt> +library when it is <tt>dlopen()</tt>ed, try: +<tscreen> +<verb> +% gcc -shared -Xlinker -x -o pam_module.so pam_module.o -lwhatever +</verb> +</tscreen> + +<sect1> Added requirements for <em/statically/ loaded modules. + +<!-- + Copyright (C) Michael K. Johnson 1996. + Last modified: AGM 1996/5/31. + --> + +<p> +Modules may be statically linked into libpam. This should be true of +all the modules distributed with the basic <bf/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 <tt/#ifdef PAM_STATIC/ and <tt/#endif/. The static code should do +the following: +<itemize> +<item> Define a single structure, <tt/struct pam_module/, called +<tt>_pam_<it>modname</it>_modstruct</tt>, where +<tt><it>modname</it></tt> is the name of the module <bf/as used in the +filesystem/ but without the leading directory name (generally +<tt>/usr/lib/security/</tt> or the suffix (generally <tt/.so/). + +</itemize> + +<p> +As a simple example, consider the following module code which defines +a module that can be compiled to be <em/static/ or <em/dynamic/: + +<p> +<tscreen> +<verb> +#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 */ +</verb> +</tscreen> + +<p> +To be linked with <em/libpam/, staticly-linked modules must be built +from within the <tt>Linux-PAM-X.YY/modules/</tt> subdirectory of the +<bf/Linux-PAM/ source directory as part of a normal build of the +<bf/Linux-PAM/ system. + +The <em/Makefile/, for the module in question, must execute the +<tt/register_static/ shell script that is located in the +<tt>Linux-PAM-X.YY/modules/</tt> subdirectory. This is to ensure that +the module is properly registered with <em/libpam/. + +The <bf/two/ manditory arguments to <tt/register_static/ are the +title, and the pathname of the object file containing the module's +code. The pathname is specified relative to the +<tt>Linux-PAM-X.YY/modules</tt> directory. The pathname may be an +empty string---this is for the case that a single object file needs to +register more than one <tt/struct pam_module/. In such a case, exactly +one call to <tt/register_static/ must indicate the object file. + +<p> +Here is an example; a line in the <em/Makefile/ might look like this: +<tscreen> +<verb> +register: +ifdef STATIC + (cd ..; ./register_static pam_modname pam_modname/pam_modname.o) +endif +</verb> +</tscreen> + +For some further examples, see the <tt>modules</tt> subdirectory of +the current <bf/Linux-PAM/ distribution. + +<p> +<sect>An example module file + +<p> +<em> +perhaps this should point to a place in the file structure!? +</em> + +<sect>Files + +<p><descrip> + +<tag><tt>/usr/lib/libpam.so.*</tt></tag> + +the shared library providing applications with access to +<bf/Linux-PAM/. + +<tag><tt>/etc/pam.conf</tt></tag> + +the <bf/Linux-PAM/ configuration file. + +<tag><tt>/usr/lib/security/pam_*.so</tt></tag> + +the primary location for <bf/Linux-PAM/ dynamically loadable object +files; the modules. + +</descrip> + +<sect>See also + +<p><itemize> +<item>The <bf/Linux-PAM/ System Administrators' Guide. +<item>The <bf/Linux-PAM/ Application Writers' Guide. +<item> +V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH PLUGGABLE +AUTHENTICATION MODULES'', Open Software Foundation Request For +Comments 86.0, October 1995. +</itemize> + +<sect>Notes + +<p> +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! :) + +<p> +<itemize> +<item> +Perhaps we should keep a registry of data-names as used by +<tt/pam_[gs]et_data()/ so there are no unintentional problems due to +conflicts? + +<item> +<tt/pam_strerror()/ should be internationalized.... + +<item> +There has been some debate about whether <tt/initgroups()/ should be +in an application or in a module. It was settled by Sun who stated +that initgroups is an action of the <em/application/. The modules are +permitted to add additional groups, however. + +<item> +Refinements/futher suggestions to <tt/syslog(3)/ usage by modules are +needed. + +</itemize> + +<sect>Author/acknowledgments + +<p> +This document was written by Andrew G. Morgan +(<tt/morgan@transmeta.com/) with many contributions from +<!-- insert credits here --> +<!-- + an sgml list of people to credit for their contributions to Linux-PAM + $Id$ + --> +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. + +<p> +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 +<bf/Linux-PAM/, Sun graciously made the documentation for their +implementation of PAM available. This act greatly accelerated the +development of <bf/Linux-PAM/. + +<sect>Bugs/omissions + +<p> +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. + +<sect>Copyright information for this document + +<p> +Copyright (c) Andrew G. Morgan 1996, 1997. All rights reserved. +<newline> +Email: <tt><morgan@transmeta.com></tt> + +<p> +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +<p> +<itemize> + +<item> +1. Redistributions of source code must retain the above copyright + notice, and the entire permission notice in its entirety, + including the disclaimer of warranties. + +<item> +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. + +<item> +3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +</itemize> + +<p> +<bf/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 <bf/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.) + +<p> +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. + +<p> +<tt>$Id$</tt> + +</article> |