summaryrefslogtreecommitdiff
path: root/doc/pam_modules.sgml
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2000-06-20 22:10:38 +0000
committerAndrew G. Morgan <morgan@kernel.org>2000-06-20 22:10:38 +0000
commitea488580c42e8918445a945484de3c8a5addc761 (patch)
treec992f3ba699caafedfadc16af38e6359c3c24698 /doc/pam_modules.sgml
Initial revision
Diffstat (limited to 'doc/pam_modules.sgml')
-rw-r--r--doc/pam_modules.sgml1476
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,&amp;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>&lt;security/pam_modules.h&gt;</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>&lt;security/pam_modules.h&gt;</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>&lt;security/pam_modules.h&gt;</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>&lt;security/pam_modules.h&gt;</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>&lt;security/pam_modules.h&gt;</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>&lt;morgan@transmeta.com&gt;</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>