�ɲɾ�����ӯ�����һ��ˣ��������С���˴��ͣ�������P���ҹ��ñ˽��ά�Բ��������˸߸ԣ�������ơ��ҹ��ñ�����ά�Բ���ˡ���˳^�ӣ������ӡ� ���ͯj�ӣ��ƺ���ӣ� ? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!PK/.1]F b?Linux-PAM_ADG.txtnu[ The Linux-PAM Application Developers' Guide Andrew G. Morgan Thorsten Kukuk Version 1.1.2, 31. August 2010 Abstract This manual documents what an application developer needs to know about the Linux-PAM library. It describes how an application might use the Linux-PAM library to authenticate users. In addition it contains a description of the functions to be found in libpam_misc library, that can be used in general applications. Finally, it contains some comments on PAM related security issues for the application developer. -------------------------------------------------------------------------- 1. Introduction 1.1. Description 1.2. Synopsis 2. Overview 3. The public interface to Linux-PAM 3.1. What can be expected by the application 3.1.1. Initialization of PAM transaction 3.1.2. Termination of PAM transaction 3.1.3. Setting PAM items 3.1.4. Getting PAM items 3.1.5. Strings describing PAM error codes 3.1.6. Request a delay on failure 3.1.7. Authenticating the user 3.1.8. Setting user credentials 3.1.9. Account validation management 3.1.10. Updating authentication tokens 3.1.11. Start PAM session management 3.1.12. terminating PAM session management 3.1.13. Set or change PAM environment variable 3.1.14. Get a PAM environment variable 3.1.15. Getting the PAM environment 3.2. What is expected of an application 3.2.1. The conversation function 3.3. Programming notes 4. Security issues of Linux-PAM 4.1. Care about standard library calls 4.2. Choice of a service name 4.3. The conversation function 4.4. The identity of the user 4.5. Sufficient resources 5. A library of miscellaneous helper functions 5.1. Functions supplied 5.1.1. Text based conversation function 5.1.2. Transcribing an environment to that of PAM 5.1.3. Liberating a locally saved environment 5.1.4. BSD like PAM environment variable setting 6. Porting legacy applications 7. Glossary of PAM related terms 8. An example application 9. Files 10. See also 11. Author/acknowledgments 12. Copyright information for this document Chapter 1. Introduction 1.1. Description 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 Linux-PAM library see the Linux-PAM System Administrators' Guide. It is the purpose of the Linux-PAM project to liberate the development of privilege granting software from the development of secure and appropriate authentication schemes. This is accomplished by providing a documented library of functions that an application may use for all forms of user authentication management. This library dynamically loads locally configured authentication modules that actually perform the authentication tasks. From the perspective of an application developer the information contained in the local configuration of the PAM library should not be important. Indeed it is intended that an application treat the functions documented here as a 'black box' that will deal with all aspects of user authentication. 'All aspects' includes user verification, account management, session initialization/termination and also the resetting of passwords (authentication tokens). 1.2. Synopsis For general applications that wish to use the services provided by Linux-PAM the following is a summary of the relevant linking information: #include cc -o application .... -lpam In addition to libpam, there is a library of miscellaneous functions that make the job of writing PAM-aware applications easier (this library is not covered in the DCE-RFC for PAM and is specific to the Linux-PAM distribution): #include #include cc -o application .... -lpam -lpam_misc Chapter 2. Overview Most service-giving applications are restricted. In other words, their service is not available to all and every prospective client. Instead, the applying client must jump through a number of hoops to convince the serving application that they are authorized to obtain service. The process of authenticating a client is what PAM is designed to manage. In addition to authentication, PAM provides account management, credential management, session management and authentication-token (password changing) management services. It is important to realize when writing a PAM based application that these services are provided in a manner that is transparent to the application. That is to say, when the application is written, no assumptions can be made about how the client will be authenticated. The process of authentication is performed by the PAM library via a call to pam_authenticate(). The return value of this function will indicate whether a named client (the user) has been authenticated. If the PAM library needs to prompt the user for any information, such as their name or a password then it will do so. If the PAM library is configured to authenticate the user using some silent protocol, it will do this too. (This latter case might be via some hardware interface for example.) It is important to note that the application must leave all decisions about when to prompt the user at the discretion of the PAM library. The PAM library, however, must work equally well for different styles of application. Some applications, like the familiar login and passwd are terminal based applications, exchanges of information with the client in these cases is as plain text messages. Graphically based applications, however, have a more sophisticated interface. They generally interact with the user via specially constructed dialogue boxes. Additionally, network based services require that text messages exchanged with the client are specially formatted for automated processing: one such example is ftpd which prefixes each exchanged message with a numeric identifier. The presentation of simple requests to a client is thus something very dependent on the protocol that the serving application will use. In spite of the fact that PAM demands that it drives the whole authentication process, it is not possible to leave such protocol subtleties up to the PAM library. To overcome this potential problem, the application provides the PAM library with a conversation function. This function is called from within the PAM library and enables the PAM to directly interact with the client. The sorts of things that this conversation function must be able to do are prompt the user with text and/or obtain textual input from the user for processing by the PAM library. The details of this function are provided in a later section. For example, the conversation function may be called by the PAM library with a request to prompt the user for a password. Its job is to reformat the prompt request into a form that the client will understand. In the case of ftpd, this might involve prefixing the string with the number 331 and sending the request over the network to a connected client. The conversation function will then obtain any reply and, after extracting the typed password, will return this string of text to the PAM library. Similar concerns need to be addressed in the case of an X-based graphical server. There are a number of issues that need to be addressed when one is porting an existing application to become PAM compliant. A section below has been devoted to this: Porting legacy applications. Besides authentication, PAM provides other forms of management. Session management is provided with calls to pam_open_session() and pam_close_session(). What these functions actually do is up to the local administrator. But typically, they could be used to log entry and exit from the system or for mounting and unmounting the user's home directory. If an application provides continuous service for a period of time, it should probably call these functions, first open after the user is authenticated and then close when the service is terminated. Account management is another area that an application developer should include with a call to pam_acct_mgmt(). This call will perform checks on the good health of the user's account (has it expired etc.). One of the things this function may check is whether the user's authentication token has expired - in such a case the application may choose to attempt to update it with a call to pam_chauthtok(), although some applications are not suited to this task (ftp for example) and in this case the application should deny access to the user. PAM is also capable of setting and deleting the user's credentials with the call pam_setcred(). This function should always be called after the user is authenticated and before service is offered to the user. By convention, this should be the last call to the PAM library before the PAM session is opened. What exactly a credential is, is not well defined. However, some examples are given in the glossary below. Chapter 3. The public interface to Linux-PAM Firstly, the relevant include file for the Linux-PAM library is . It contains the definitions for a number of functions. After listing these functions, we collect some guiding remarks for programmers. 3.1. What can be expected by the application 3.1.1. Initialization of PAM transaction #include int pam_start( service_name, user, pam_conversation, pamh); const char *service_name; const char *user; const struct pam_conv *pam_conversation; pam_handle_t **pamh; 3.1.1.1. DESCRIPTION The pam_start function creates the PAM context and initiates the PAM transaction. It is the first of the PAM functions that needs to be called by an application. The transaction state is contained entirely within the structure identified by this handle, so it is possible to have multiple transactions in parallel. But it is not possible to use the same handle for different transactions, a new one is needed for every new context. The service_name argument specifies the name of the service to apply and will be stored as PAM_SERVICE item in the new context. The policy for the service will be read from the file /etc/pam.d/service_name or, if that file does not exist, from /etc/pam.conf. The user argument can specify the name of the target user and will be stored as PAM_USER item. If the argument is NULL, the module has to ask for this item if necessary. The pam_conversation argument points to a struct pam_conv describing the conversation function to use. An application must provide this for direct communication between a loaded module and the application. Following a successful return (PAM_SUCCESS) the contents of pamh is a handle that contains the PAM context for successive calls to the PAM functions. In an error case is the content of pamh undefined. The pam_handle_t is a blind structure and the application should not attempt to probe it directly for information. Instead the PAM library provides the functions pam_set_item(3) and pam_get_item(3). The PAM handle cannot be used for mulitiple authentications at the same time as long as pam_end was not called on it before. 3.1.1.2. RETURN VALUES PAM_ABORT General failure. PAM_BUF_ERR Memory buffer error. PAM_SUCCESS Transaction was successful created. PAM_SYSTEM_ERR System error, for example a NULL pointer was submitted instead of a pointer to data. 3.1.2. Termination of PAM transaction #include int pam_end( pamh, pam_status); pam_handle_t *pamh; int pam_status; 3.1.2.1. DESCRIPTION The pam_end function terminates the PAM transaction and is the last function an application should call in the PAM context. Upon return the handle pamh is no longer valid and all memory associated with it will be invalid. The pam_status argument should be set to the value returned to the application by the last PAM library call. The value taken by pam_status is used as an argument to the module specific callback function, cleanup() (See pam_set_data(3) and pam_get_data(3)). In this way the module can be given notification of the pass/fail nature of the tear-down process, and perform any last minute tasks that are appropriate to the module before it is unlinked. This argument can be logically OR'd with PAM_DATA_SILENT to indicate to indicate that the module should not treat the call too seriously. It is generally used to indicate that the current closing of the library is in a fork(2)ed process, and that the parent will take care of cleaning up things that exist outside of the current process space (files etc.). This function free's all memory for items associated with the pam_set_item(3) and pam_get_item(3) functions. Pointers associated with such objects are not valid anymore after pam_end was called. 3.1.2.2. RETURN VALUES PAM_SUCCESS Transaction was successful terminated. PAM_SYSTEM_ERR System error, for example a NULL pointer was submitted as PAM handle or the function was called by a module. 3.1.3. Setting PAM items #include int pam_set_item( pamh, item_type, item); pam_handle_t *pamh; int item_type; const void *item; 3.1.3.1. DESCRIPTION The pam_set_item function allows applications and PAM service modules to access and to update PAM informations of item_type. For this a copy of the object pointed to by the item argument is created. The following item_types are supported: PAM_SERVICE The service name (which identifies that PAM stack that the PAM functions will use to authenticate the program). PAM_USER The username of the entity under whose identity service will be given. That is, following authentication, PAM_USER identifies the local entity that gets to use the service. Note, this value can be mapped from something (eg., "anonymous") to something else (eg. "guest119") by any module in the PAM stack. As such an application should consult the value of PAM_USER after each call to a PAM function. PAM_USER_PROMPT The string used when prompting for a user's name. The default value for this string is a localized version of "login: ". PAM_TTY The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based, applications the value for this item should be the $DISPLAY variable. PAM_RUSER The requesting user name: local name for a locally requesting user or a remote user name for a remote requesting user. Generally an application or module will attempt to supply the value that is most strongly authenticated (a local account before a remote one. The level of trust in this value is embodied in the actual authentication stack associated with the application, so it is ultimately at the discretion of the system administrator. PAM_RUSER@PAM_RHOST should always identify the requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear who the requesting entity is. PAM_RHOST The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is requesting service). That is PAM_RUSER@PAM_RHOST does identify the requesting user. In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the authentication request is originating from. PAM_AUTHTOK The authentication token (often a password). This token should be ignored by all module functions besides pam_sm_authenticate(3) and pam_sm_chauthtok(3). In the former function it is used to pass the most recent authentication token from one stacked module to another. In the latter function the token is used for another purpose. It contains the currently active authentication token. PAM_OLDAUTHTOK The old authentication token. This token should be ignored by all module functions except pam_sm_chauthtok(3). PAM_CONV The pam_conv structure. See pam_conv(3). The following additional items are specific to Linux-PAM and should not be used in portable applications: PAM_FAIL_DELAY A function pointer to redirect centrally managed failure delays. See pam_fail_delay(3). PAM_XDISPLAY The name of the X display. For graphical, X-based applications the value for this item should be the $DISPLAY variable. This value may be used independently of PAM_TTY for passing the name of the display. PAM_XAUTHDATA A pointer to a structure containing the X authentication data required to make a connection to the display specified by PAM_XDISPLAY, if such information is necessary. See pam_xauth_data(3). PAM_AUTHTOK_TYPE The default action is for the module to use the following prompts when requesting passwords: "New UNIX password: " and "Retype UNIX password: ". The example word UNIX can be replaced with this item, by default it is empty. This item is used by pam_get_authtok(3). For all item_types, other than PAM_CONV and PAM_FAIL_DELAY, item is a pointer to a terminated character string. In the case of PAM_CONV, item points to an initialized pam_conv structure. In the case of PAM_FAIL_DELAY, item is a function pointer: void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr) Both, PAM_AUTHTOK and PAM_OLDAUTHTOK, will be reseted before returning to the application. Which means an application is not able to access the authentication tokens. 3.1.3.2. RETURN VALUES PAM_BAD_ITEM The application attempted to set an undefined or inaccessible item. PAM_BUF_ERR Memory buffer error. PAM_SUCCESS Data was successful updated. PAM_SYSTEM_ERR The pam_handle_t passed as first argument was invalid. 3.1.4. Getting PAM items #include int pam_get_item( pamh, item_type, item); const pam_handle_t *pamh; int item_type; const void **item; 3.1.4.1. DESCRIPTION The pam_get_item function allows applications and PAM service modules to access and retrieve PAM informations of item_type. Upon successful return, item contains a pointer to the value of the corresponding item. Note, this is a pointer to the actual data and should not be free()'ed or over-written! The following values are supported for item_type: PAM_SERVICE The service name (which identifies that PAM stack that the PAM functions will use to authenticate the program). PAM_USER The username of the entity under whose identity service will be given. That is, following authentication, PAM_USER identifies the local entity that gets to use the service. Note, this value can be mapped from something (eg., "anonymous") to something else (eg. "guest119") by any module in the PAM stack. As such an application should consult the value of PAM_USER after each call to a PAM function. PAM_USER_PROMPT The string used when prompting for a user's name. The default value for this string is a localized version of "login: ". PAM_TTY The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based, applications the value for this item should be the $DISPLAY variable. PAM_RUSER The requesting user name: local name for a locally requesting user or a remote user name for a remote requesting user. Generally an application or module will attempt to supply the value that is most strongly authenticated (a local account before a remote one. The level of trust in this value is embodied in the actual authentication stack associated with the application, so it is ultimately at the discretion of the system administrator. PAM_RUSER@PAM_RHOST should always identify the requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear who the requesting entity is. PAM_RHOST The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is requesting service). That is PAM_RUSER@PAM_RHOST does identify the requesting user. In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the authentication request is originating from. PAM_AUTHTOK The authentication token (often a password). This token should be ignored by all module functions besides pam_sm_authenticate(3) and pam_sm_chauthtok(3). In the former function it is used to pass the most recent authentication token from one stacked module to another. In the latter function the token is used for another purpose. It contains the currently active authentication token. PAM_OLDAUTHTOK The old authentication token. This token should be ignored by all module functions except pam_sm_chauthtok(3). PAM_CONV The pam_conv structure. See pam_conv(3). The following additional items are specific to Linux-PAM and should not be used in portable applications: PAM_FAIL_DELAY A function pointer to redirect centrally managed failure delays. See pam_fail_delay(3). PAM_XDISPLAY The name of the X display. For graphical, X-based applications the value for this item should be the $DISPLAY variable. This value may be used independently of PAM_TTY for passing the name of the display. PAM_XAUTHDATA A pointer to a structure containing the X authentication data required to make a connection to the display specified by PAM_XDISPLAY, if such information is necessary. See pam_xauth_data(3). PAM_AUTHTOK_TYPE The default action is for the module to use the following prompts when requesting passwords: "New UNIX password: " and "Retype UNIX password: ". The example word UNIX can be replaced with this item, by default it is empty. This item is used by pam_get_authtok(3). If a service module wishes to obtain the name of the user, it should not use this function, but instead perform a call to pam_get_user(3). Only a service module is privileged to read the authentication tokens, PAM_AUTHTOK and PAM_OLDAUTHTOK. 3.1.4.2. RETURN VALUES PAM_BAD_ITEM The application attempted to set an undefined or inaccessible item. PAM_BUF_ERR Memory buffer error. PAM_PERM_DENIED The value of item was NULL. PAM_SUCCESS Data was successful updated. PAM_SYSTEM_ERR The pam_handle_t passed as first argument was invalid. 3.1.5. Strings describing PAM error codes #include const char *pam_strerror( pamh, errnum); pam_handle_t *pamh; int errnum; 3.1.5.1. DESCRIPTION The pam_strerror function returns a pointer to a string describing the error code passed in the argument errnum, possibly using the LC_MESSAGES part of the current locale to select the appropriate language. This string must not be modified by the application. No library function will modify this string. 3.1.5.2. RETURN VALUES This function returns always a pointer to a string. 3.1.6. Request a delay on failure #include int pam_fail_delay( pamh, usec); pam_handle_t *pamh; unsigned int usec; 3.1.6.1. DESCRIPTION The pam_fail_delay function provides a mechanism by which an application or module can suggest a minimum delay of usec micro-seconds. The function keeps a record of the longest time requested with this function. Should pam_authenticate(3) fail, the failing return to the application is delayed by an amount of time randomly distributed (by up to 50%) about this longest value. Independent of success, the delay time is reset to its zero default value when the PAM service module returns control to the application. The delay occurs after all authentication modules have been called, but before control is returned to the service application. When using this function the programmer should check if it is available with: #ifdef HAVE_PAM_FAIL_DELAY .... #endif /* HAVE_PAM_FAIL_DELAY */ For applications written with a single thread that are event driven in nature, generating this delay may be undesirable. Instead, the application may want to register the delay in some other way. For example, in a single threaded server that serves multiple authentication requests from a single event loop, the application might want to simply mark a given connection as blocked until an application timer expires. For this reason the delay function can be changed with the PAM_FAIL_DELAY item. It can be queried and set with pam_get_item(3) and pam_set_item (3) respectively. The value used to set it should be a function pointer of the following prototype: void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr); The arguments being the retval return code of the module stack, the usec_delay micro-second delay that libpam is requesting and the appdata_ptr that the application has associated with the current pamh. This last value was set by the application when it called pam_start(3) or explicitly with pam_set_item(3). Note, if PAM_FAIL_DELAY item is unset (or set to NULL), then no delay will be performed. 3.1.6.2. RETURN VALUES PAM_SUCCESS Delay was successful adjusted. PAM_SYSTEM_ERR A NULL pointer was submitted as PAM handle. 3.1.7. Authenticating the user #include int pam_authenticate( pamh, flags); pam_handle_t *pamh; int flags; 3.1.7.1. DESCRIPTION The pam_authenticate function is used to authenticate the user. The user is required to provide an authentication token depending upon the authentication service, usually this is a password, but could also be a finger print. The PAM service module may request that the user enter their username via the conversation mechanism (see pam_start(3) and pam_conv(3)). The name of the authenticated user will be present in the PAM item PAM_USER. This item may be recovered with a call to pam_get_item(3). The pamh argument is an authentication handle obtained by a prior call to pam_start(). The flags argument is the binary or of zero or more of the following values: PAM_SILENT Do not emit any messages. PAM_DISALLOW_NULL_AUTHTOK The PAM module service should return PAM_AUTH_ERR if the user does not have a registered authentication token. 3.1.7.2. RETURN VALUES PAM_ABORT The application should exit immediately after calling pam_end(3) first. PAM_AUTH_ERR The user was not authenticated. PAM_CRED_INSUFFICIENT For some reason the application does not have sufficient credentials to authenticate the user. PAM_AUTHINFO_UNAVAIL The modules were not able to access the authentication information. This might be due to a network or hardware failure etc. PAM_MAXTRIES One or more of the authentication modules has reached its limit of tries authenticating the user. Do not try again. PAM_SUCCESS The user was successfully authenticated. PAM_USER_UNKNOWN User unknown to authentication service. 3.1.8. Setting user credentials #include int pam_setcred( pamh, flags); pam_handle_t *pamh; int flags; 3.1.8.1. DESCRIPTION The pam_setcred function is used to establish, maintain and delete the credentials of a user. It should be called to set the credentials after a user has been authenticated and before a session is opened for the user (with pam_open_session(3)). The credentials should be deleted after the session has been closed (with pam_close_session(3)). A credential is something that the user possesses. It is some property, such as a Kerberos ticket, or a supplementary group membership that make up the uniqueness of a given user. On a Linux system the user's UID and GID's are credentials too. However, it has been decided that these properties (along with the default supplementary groups of which the user is a member) are credentials that should be set directly by the application and not by PAM. Such credentials should be established, by the application, prior to a call to this function. For example, initgroups(2) (or equivalent) should have been performed. Valid flags, any one of which, may be logically OR'd with PAM_SILENT, are: PAM_ESTABLISH_CRED Initialize the credentials for the user. PAM_DELETE_CRED Delete the user's credentials. PAM_REINITIALIZE_CRED Fully reinitialize the user's credentials. PAM_REFRESH_CRED Extend the lifetime of the existing credentials. 3.1.8.2. RETURN VALUES PAM_BUF_ERR Memory buffer error. PAM_CRED_ERR Failed to set user credentials. PAM_CRED_EXPIRED User credentials are expired. PAM_CRED_UNAVAIL Failed to retrieve user credentials. PAM_SUCCESS Data was successful stored. PAM_SYSTEM_ERR A NULL pointer was submitted as PAM handle, the function was called by a module or another system error occured. PAM_USER_UNKNOWN User is not known to an authentication module. 3.1.9. Account validation management #include int pam_acct_mgmt( pamh, flags); pam_handle_t *pamh; int flags; 3.1.9.1. DESCRIPTION The pam_acct_mgmt function is used to determine if the user's account is valid. It checks for authentication token and account expiration and verifies access restrictions. It is typically called after the user has been authenticated. The pamh argument is an authentication handle obtained by a prior call to pam_start(). The flags argument is the binary or of zero or more of the following values: PAM_SILENT Do not emit any messages. PAM_DISALLOW_NULL_AUTHTOK The PAM module service should return PAM_NEW_AUTHTOK_REQD if the user has a null authentication token. 3.1.9.2. RETURN VALUES PAM_ACCT_EXPIRED User account has expired. PAM_AUTH_ERR Authentication failure. PAM_NEW_AUTHTOK_REQD The user account is valid but their authentication token is expired. The correct response to this return-value is to require that the user satisfies the pam_chauthtok() function before obtaining service. It may not be possible for some applications to do this. In such cases, the user should be denied access until such time as they can update their password. PAM_PERM_DENIED Permission denied. PAM_SUCCESS The authentication token was successfully updated. PAM_USER_UNKNOWN User unknown to password service. 3.1.10. Updating authentication tokens #include int pam_chauthtok( pamh, flags); pam_handle_t *pamh; int flags; 3.1.10.1. DESCRIPTION The pam_chauthtok function is used to change the authentication token for a given user (as indicated by the state associated with the handle pamh). The pamh argument is an authentication handle obtained by a prior call to pam_start(). The flags argument is the binary or of zero or more of the following values: PAM_SILENT Do not emit any messages. PAM_CHANGE_EXPIRED_AUTHTOK This argument indicates to the modules that the user's authentication token (password) should only be changed if it has expired. If this argument is not passed, the application requires that all authentication tokens are to be changed. 3.1.10.2. RETURN VALUES PAM_AUTHTOK_ERR A module was unable to obtain the new authentication token. PAM_AUTHTOK_RECOVERY_ERR A module was unable to obtain the old authentication token. PAM_AUTHTOK_LOCK_BUSY One or more of the modules was unable to change the authentication token since it is currently locked. PAM_AUTHTOK_DISABLE_AGING Authentication token aging has been disabled for at least one of the modules. PAM_PERM_DENIED Permission denied. PAM_SUCCESS The authentication token was successfully updated. PAM_TRY_AGAIN Not all of the modules were in a position to update the authentication token(s). In such a case none of the user's authentication tokens are updated. PAM_USER_UNKNOWN User unknown to password service. 3.1.11. Start PAM session management #include int pam_open_session( pamh, flags); pam_handle_t *pamh; int flags; 3.1.11.1. DESCRIPTION The pam_open_session function sets up a user session for a previously successful authenticated user. The session should later be terminated with a call to pam_close_session(3). It should be noted that the effective uid, geteuid(2). of the application should be of sufficient privilege to perform such tasks as creating or mounting the user's home directory for example. The flags argument is the binary or of zero or more of the following values: PAM_SILENT Do not emit any messages. 3.1.11.2. RETURN VALUES PAM_ABORT General failure. PAM_BUF_ERR Memory buffer error. PAM_SESSION_ERR Session failure. PAM_SUCCESS Session was successful created. 3.1.12. terminating PAM session management #include int pam_close_session( pamh, flags); pam_handle_t *pamh; int flags; 3.1.12.1. DESCRIPTION The pam_close_session function is used to indicate that an authenticated session has ended. The session should have been created with a call to pam_open_session(3). It should be noted that the effective uid, geteuid(2). of the application should be of sufficient privilege to perform such tasks as unmounting the user's home directory for example. The flags argument is the binary or of zero or more of the following values: PAM_SILENT Do not emit any messages. 3.1.12.2. RETURN VALUES PAM_ABORT General failure. PAM_BUF_ERR Memory buffer error. PAM_SESSION_ERR Session failure. PAM_SUCCESS Session was successful terminated. 3.1.13. Set or change PAM environment variable #include int pam_putenv( pamh, name_value); pam_handle_t *pamh; const char *name_value; 3.1.13.1. DESCRIPTION The pam_putenv function is used to add or change the value of PAM environment variables as associated with the pamh handle. The pamh argument is an authentication handle obtained by a prior call to pam_start(). The name_value argument is a single NUL terminated string of one of the following forms: NAME=value of variable In this case the environment variable of the given NAME is set to the indicated value: value of variable. If this variable is already known, it is overwritten. Otherwise it is added to the PAM environment. NAME= This function sets the variable to an empty value. It is listed separately to indicate that this is the correct way to achieve such a setting. NAME Without an '=' the pam_putenv() function will delete the corresponding variable from the PAM environment. pam_putenv() operates on a copy of name_value, which means in contrast to putenv(3), the application is responsible to free the data. 3.1.13.2. RETURN VALUES PAM_PERM_DENIED Argument name_value given is a NULL pointer. PAM_BAD_ITEM Variable requested (for deletion) is not currently set. PAM_ABORT The pamh handle is corrupt. PAM_BUF_ERR Memory buffer error. PAM_SUCCESS The environment variable was successfully updated. 3.1.14. Get a PAM environment variable #include const char *pam_getenv( pamh, name); pam_handle_t *pamh; const char *name; 3.1.14.1. DESCRIPTION The pam_getenv function searches the PAM environment list as associated with the handle pamh for an item that matches the string pointed to by name and returns a pointer to the value of the environment variable. The application is not allowed to free the data. 3.1.14.2. RETURN VALUES The pam_getenv function returns NULL on failure. 3.1.15. Getting the PAM environment #include char **pam_getenvlist( pamh); pam_handle_t *pamh; 3.1.15.1. DESCRIPTION The pam_getenvlist function returns a complete copy of the PAM environment as associated with the handle pamh. The PAM environment variables represent the contents of the regular environment variables of the authenticated user when service is granted. The format of the memory is a malloc()'d array of char pointers, the last element of which is set to NULL. Each of the non-NULL entries in this array point to a NUL terminated and malloc()'d char string of the form: "name=value". It should be noted that this memory will never be free()'d by libpam. Once obtained by a call to pam_getenvlist, it is the responsibility of the calling application to free() this memory. It is by design, and not a coincidence, that the format and contents of the returned array matches that required for the third argument of the execle(3) function call. 3.1.15.2. RETURN VALUES The pam_getenvlist function returns NULL on failure. 3.2. What is expected of an application 3.2.1. The conversation function #include struct pam_message { int msg_style; const char *msg; }; struct pam_response { char *resp; int resp_retcode; }; struct pam_conv { int (*conv)(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); void *appdata_ptr; }; 3.2.1.1. DESCRIPTION The PAM library uses an application-defined callback to allow a direct communication between a loaded module and the application. This callback is specified by the struct pam_conv passed to pam_start(3) at the start of the transaction. When a module calls the referenced conv() function, the argument appdata_ptr is set to the second element of this structure. The other arguments of a call to conv() concern the information exchanged by module and application. That is to say, num_msg holds the length of the array of pointers, msg. After a successful return, the pointer resp points to an array of pam_response structures, holding the application supplied text. The resp_retcode member of this struct is unused and should be set to zero. It is the caller's responsibility to release both, this array and the responses themselves, using free(3). Note, *resp is a struct pam_response array and not an array of pointers. The number of responses is always equal to the num_msg conversation function argument. This does require that the response array is free(3)'d after every call to the conversation function. The index of the responses corresponds directly to the prompt index in the pam_message array. On failure, the conversation function should release any resources it has allocated, and return one of the predefined PAM error codes. Each message can have one of four types, specified by the msg_style member of struct pam_message: PAM_PROMPT_ECHO_OFF Obtain a string without echoing any text. PAM_PROMPT_ECHO_ON Obtain a string whilst echoing text. PAM_ERROR_MSG Display an error message. PAM_TEXT_INFO Display some text. The point of having an array of messages is that it becomes possible to pass a number of things to the application in a single call from the module. It can also be convenient for the application that related things come at once: a windows based application can then present a single form with many messages/prompts on at once. In passing, it is worth noting that there is a descrepency between the way Linux-PAM handles the const struct pam_message **msg conversation function argument from the way that Solaris' PAM (and derivitives, known to include HP/UX, are there others?) does. Linux-PAM interprets the msg argument as entirely equivalent to the following prototype const struct pam_message *msg[] (which, in spirit, is consistent with the commonly used prototypes for argv argument to the familiar main() function: char **argv; and char *argv[]). Said another way Linux-PAM interprets the msg argument as a pointer to an array of num_msg read only 'struct pam_message' pointers. Solaris' PAM implementation interprets this argument as a pointer to a pointer to an array of num_msg pam_message structures. Fortunately, perhaps, for most module/application developers when num_msg has a value of one these two definitions are entirely equivalent. Unfortunately, casually raising this number to two has led to unanticipated compatibility problems. For what its worth the two known module writer work-arounds for trying to maintain source level compatibility with both PAM implementations are: * never call the conversation function with num_msg greater than one. * set up msg as doubly referenced so both types of conversation function can find the messages. That is, make msg[n] = & (( *msg )[n]) 3.2.1.2. RETURN VALUES PAM_BUF_ERR Memory buffer error. PAM_CONV_ERR Conversation failure. The application should not set *resp. PAM_SUCCESS Success. 3.3. Programming notes Note, all of the authentication service function calls accept the token PAM_SILENT, which instructs the modules to not send messages to the application. This token can be logically OR'd with any one of the permitted tokens specific to the individual function calls. PAM_SILENT does not override the prompting of the user for passwords etc., it only stops informative messages from being generated. Chapter 4. Security issues of Linux-PAM PAM, from the perspective of an application, is a convenient API for authenticating users. PAM modules generally have no increased privilege over that possessed by the application that is making use of it. For this reason, the application must take ultimate responsibility for protecting the environment in which PAM operates. A poorly (or maliciously) written application can defeat any Linux-PAM module's authentication mechanisms by simply ignoring it's return values. It is the applications task and responsibility to grant privileges and access to services. The Linux-PAM library simply assumes the responsibility of authenticating the user; ascertaining that the user is who they say they are. Care should be taken to anticipate all of the documented behavior of the Linux-PAM library functions. A failure to do this will most certainly lead to a future security breach. 4.1. Care about standard library calls In general, writers of authorization-granting applications should assume that each module is likely to call any or all 'libc' functions. For 'libc' functions that return pointers to static/dynamically allocated structures (ie. the library allocates the memory and the user is not expected to 'free()' it) any module call to this function is likely to corrupt a pointer previously obtained by the application. The application programmer should either re-call such a 'libc' function after a call to the Linux-PAM library, or copy the structure contents to some safe area of memory before passing control to the Linux-PAM library. Two important function classes that fall into this category are getpwnam(3) and syslog(3). 4.2. Choice of a service name When picking the service-name that corresponds to the first entry in the Linux-PAM configuration file, the application programmer should avoid the temptation of choosing something related to argv[0]. It is a trivial matter for any user to invoke any application on a system under a different name and this should not be permitted to cause a security breach. In general, this is always the right advice if the program is setuid, or otherwise more privileged than the user that invokes it. In some cases, avoiding this advice is convenient, but as an author of such an application, you should consider well the ways in which your program will be installed and used. (Its often the case that programs are not intended to be setuid, but end up being installed that way for convenience. If your program falls into this category, don't fall into the trap of making this mistake.) To invoke some target application by another name, the user may symbolically link the target application with the desired name. To be precise all the user need do is, ln -s /target/application ./preferred_name and then run ./preferred_name. By studying the Linux-PAM configuration file(s), an attacker can choose the preferred_name to be that of a service enjoying minimal protection; for example a game which uses Linux-PAM to restrict access to certain hours of the day. If the service-name were to be linked to the filename under which the service was invoked, it is clear that the user is effectively in the position of dictating which authentication scheme the service uses. Needless to say, this is not a secure situation. The conclusion is that the application developer should carefully define the service-name of an application. The safest thing is to make it a single hard-wired name. 4.3. The conversation function Care should be taken to ensure that the conv() function is robust. Such a function is provided in the library libpam_misc (see below). 4.4. The identity of the user The Linux-PAM modules will need to determine the identity of the user who requests a service, and the identity of the user who grants the service. These two users will seldom be the same. Indeed there is generally a third user identity to be considered, the new (assumed) identity of the user once the service is granted. The need for keeping tabs on these identities is clearly an issue of security. One convention that is actively used by some modules is that the identity of the user requesting a service should be the current UID (user ID) of the running process; the identity of the privilege granting user is the EUID (effective user ID) of the running process; the identity of the user, under whose name the service will be executed, is given by the contents of the PAM_USER pam_get_item(3). Note, modules can change the values of PAM_USER and PAM_RUSER during any of the pam_*() library calls. For this reason, the application should take care to use the pam_get_item() every time it wishes to establish who the authenticated user is (or will currently be). For network-serving databases and other applications that provide their own security model (independent of the OS kernel) the above scheme is insufficient to identify the requesting user. A more portable solution to storing the identity of the requesting user is to use the PAM_RUSER pam_get_item(3). The application should supply this value before attempting to authenticate the user with pam_authenticate(). How well this name can be trusted will ultimately be at the discretion of the local administrator (who configures PAM for your application) and a selected module may attempt to override the value where it can obtain more reliable data. If an application is unable to determine the identity of the requesting entity/user, it should not call pam_set_item(3) to set PAM_RUSER. In addition to the PAM_RUSER item, the application should supply the PAM_RHOST (requesting host) item. As a general rule, the following convention for its value can be assumed: NULL = unknown; localhost = invoked directly from the local system; other.place.xyz = some component of the user's connection originates from this remote/requesting host. At present, PAM has no established convention for indicating whether the application supports a trusted path to communication from this host. 4.5. Sufficient resources Care should be taken to ensure that the proper execution of an application is not compromised by a lack of system resources. If an application is unable to open sufficient files to perform its service, it should fail gracefully, or request additional resources. Specifically, the quantities manipulated by the setrlimit(2) family of commands should be taken into consideration. This is also true of conversation prompts. The application should not accept prompts of arbitrary length with out checking for resource allocation failure and dealing with such extreme conditions gracefully and in a manner that preserves the PAM API. Such tolerance may be especially important when attempting to track a malicious adversary. Chapter 5. A library of miscellaneous helper functions To aid the work of the application developer a library of miscellaneous functions is provided. It is called libpam_misc, and contains a text based conversation function, and routines for enhancing the standard PAM-environment variable support. The functions, structures and macros, made available by this library can be defined by including . It should be noted that this library is specific to Linux-PAM and is not referred to in the defining DCE-RFC (see See also) below. 5.1. Functions supplied 5.1.1. Text based conversation function #include int misc_conv( num_msg, msgm, response, appdata_ptr); int num_msg; const struct pam_message **msgm; struct pam_response **response; void *appdata_ptr; 5.1.1.1. DESCRIPTION The misc_conv function is part of libpam_misc and not of the standard libpam library. This function will prompt the user with the appropriate comments and obtain the appropriate inputs as directed by authentication modules. In addition to simply slotting into the appropriate pam_conv(3), this function provides some time-out facilities. The function exports five variables that can be used by an application programmer to limit the amount of time this conversation function will spend waiting for the user to type something. The five variabls are as follows: time_t pam_misc_conv_warn_time; This variable contains the time (as returned by time(2)) that the user should be first warned that the clock is ticking. By default it has the value 0, which indicates that no such warning will be given. The application may set its value to sometime in the future, but this should be done prior to passing control to the Linux-PAM library. const char *pam_misc_conv_warn_line; Used in conjuction with pam_misc_conv_warn_time, this variable is a pointer to the string that will be displayed when it becomes time to warn the user that the timeout is approaching. Its default value is a translated version of "...Time is running out...", but this can be changed by the application prior to passing control to Linux-PAM. time_t pam_misc_conv_die_time; This variable contains the time (as returned by time(2)) that the will time out. By default it has the value 0, which indicates that the conversation function will not timeout. The application may set its value to sometime in the future, but this should be done prior to passing control to the Linux-PAM library. const char *pam_misc_conv_die_line; Used in conjuction with pam_misc_conv_die_time, this variable is a pointer to the string that will be displayed when the conversation times out. Its default value is a translated version of "...Sorry, your time is up!", but this can be changed by the application prior to passing control to Linux-PAM. int pam_misc_conv_died; Following a return from the Linux-PAM libraray, the value of this variable indicates whether the conversation has timed out. A value of 1 indicates the time-out occurred. The following two function pointers are available for supporting binary prompts in the conversation function. They are optimized for the current incarnation of the libpamc library and are subject to change. int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p); This function pointer is initialized to NULL but can be filled with a function that provides machine-machine (hidden) message exchange. It is intended for use with hidden authentication protocols such as RSA or Diffie-Hellman key exchanges. (This is still under development.) int (*pam_binary_handler_free)(void *appdata, pamc_bp_t *delete_me); This function pointer is initialized to PAM_BP_RENEW(delete_me, 0, 0), but can be redefined as desired by the application. 5.1.2. Transcribing an environment to that of PAM #include int pam_misc_paste_env( pamh, user); pam_handle_t *pamh; const char * const *user; 5.1.2.1. DESCRIPTION This function takes the supplied list of environment pointers and uploads its contents to the PAM environment. Success is indicated by PAM_SUCCESS. 5.1.3. Liberating a locally saved environment #include int pam_misc_drop_env( env); char **env; 5.1.3.1. DESCRIPTION This function is defined to complement the pam_getenvlist(3) function. It liberates the memory associated with env, overwriting with 0 all memory before free()ing it. 5.1.4. BSD like PAM environment variable setting #include int pam_misc_setenv( pamh, name, value, readonly); pam_handle_t *pamh; const char *name; const char *value; int readonly; 5.1.4.1. DESCRIPTION This function performs a task equivalent to pam_putenv(3), its syntax is, however, more like the BSD style function; setenv(). The name and value are concatenated with an '=' to form a name=value and passed to pam_putenv(). If, however, the PAM variable is already set, the replacement will only be applied if the last argument, readonly, is zero. Chapter 6. Porting legacy applications The point of PAM is that the application is not supposed to have any idea how the attached authentication modules will choose to authenticate the user. So all they can do is provide a conversation function that will talk directly to the user(client) on the modules' behalf. Consider the case that you plug a retinal scanner into the login program. In this situation the user would be prompted: "please look into the scanner". No username or password would be needed - all this information could be deduced from the scan and a database lookup. The point is that the retinal scanner is an ideal task for a "module". While it is true that a pop-daemon program is designed with the POP protocol in mind and no-one ever considered attaching a retinal scanner to it, it is also the case that the "clean" PAM'ification of such a daemon would allow for the possibility of a scanner module being be attached to it. The point being that the "standard" pop-authentication protocol(s) [which will be needed to satisfy inflexible/legacy clients] would be supported by inserting an appropriate pam_qpopper module(s). However, having rewritten popd once in this way any new protocols can be implemented in-situ. One simple test of a ported application would be to insert the pam_permit module and see if the application demands you type a password... In such a case, xlock would fail to lock the terminal - or would at best be a screen-saver, ftp would give password free access to all etc.. Neither of these is a very secure thing to do, but they do illustrate how much flexibility PAM puts in the hands of the local admin. The key issue, in doing things correctly, is identifying what is part of the authentication procedure (how many passwords etc..) the exchange protocol (prefixes to prompts etc., numbers like 331 in the case of ftpd) and what is part of the service that the application delivers. PAM really needs to have total control in the authentication "procedure", the conversation function should only deal with reformatting user prompts and extracting responses from raw input. Chapter 7. Glossary of PAM related terms The following are a list of terms used within this document. Authentication token Generally, this is a password. However, a user can authenticate him/herself in a variety of ways. Updating the user's authentication token thus corresponds to refreshing the object they use to authenticate themself with the system. The word password is avoided to keep open the possibility that the authentication involves a retinal scan or other non-textual mode of challenge/response. Credentials Having successfully authenticated the user, PAM is able to establish certain characteristics/attributes of the user. These are termed credentials. Examples of which are group memberships to perform privileged tasks with, and tickets in the form of environment variables etc. . Some user-credentials, such as the user's UID and GID (plus default group memberships) are not deemed to be PAM-credentials. It is the responsibility of the application to grant these directly. Chapter 8. An example application To get a flavor of the way a Linux-PAM application is written we include the following example. It prompts the user for their password and indicates whether their account is valid on the standard output, its return code also indicates the success (0 for success; 1 for failure). /* This program was contributed by Shane Watts [modifications by AGM and kukuk] You need to add the following (or equivalent) to the /etc/pam.d/check_user file: # check authorization auth required pam_unix.so account required pam_unix.so */ #include #include #include static struct pam_conv conv = { misc_conv, NULL }; int main(int argc, char *argv[]) { pam_handle_t *pamh=NULL; int retval; const char *user="nobody"; if(argc == 2) { user = argv[1]; } if(argc > 2) { fprintf(stderr, "Usage: check_user [username]\n"); exit(1); } retval = pam_start("check_user", user, &conv, &pamh); if (retval == PAM_SUCCESS) retval = pam_authenticate(pamh, 0); /* is user really user? */ if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ /* This is where we have been authorized or not. */ if (retval == PAM_SUCCESS) { fprintf(stdout, "Authenticated\n"); } else { fprintf(stdout, "Not Authenticated\n"); } if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ pamh = NULL; fprintf(stderr, "check_user: failed to release authenticator\n"); exit(1); } return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ } Chapter 9. Files /usr/include/security/pam_appl.h Header file with interfaces for Linux-PAM applications. /usr/include/security/pam_misc.h Header file for useful library functions for making applications easier to write. Chapter 10. See also * The Linux-PAM System Administrators' Guide. * The Linux-PAM Module Writers' Guide. * The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request For Comments 86.0, October 1995. Chapter 11. Author/acknowledgments This document was written by Andrew G. Morgan (morgan@kernel.org) with many contributions from Chris Adams, Peter Allgeyer, Tim Baverstock, Tim Berger, Craig S. Bell, Derrick J. Brashear, Ben Buxton, Seth Chaiklin, Oliver Crow, Chris Dent, Marc Ewing, Cristian Gafton, Emmanuel Galanos, Brad M. Garcia, Eric Hester, Roger Hu, Eric Jacksch, Michael K. Johnson, David Kinchlea, Olaf Kirch, Marcin Korzonek, Thorsten Kukuk, Stephen Langasek, Nicolai Langfeldt, Elliot Lee, Luke Kenneth Casson Leighton, Al Longyear, Ingo Luetkebohle, Marek Michalkiewicz, Robert Milkowski, Aleph One, Martin Pool, Sean Reifschneider, Jan Rekorajski, Erik Troan, Theodore Ts'o, Jeff Uphoff, Myles Uyema, Savochkin Andrey Vladimirovich, Ronald Wahl, David Wood, John Wilmes, Joseph S. D. Yao and Alex O. Yuriev. Thanks are also due to Sun Microsystems, especially to Vipin Samar and Charlie Lai for their advice. At an early stage in the development of Linux-PAM, Sun graciously made the documentation for their implementation of PAM available. This act greatly accelerated the development of Linux-PAM. Chapter 12. Copyright information for this document Copyright (c) 2006 Thorsten Kukuk Copyright (c) 1996-2002 Andrew G. Morgan 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 (GPL), 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 PK/.1]7Linux-PAM_MWG.txtnu[ The Linux-PAM Module Writers' Guide Andrew G. Morgan Thorsten Kukuk Version 1.1.2, 31. August 2010 Abstract This manual documents what a programmer needs to know in order to write a module that conforms to the Linux-PAM standard.It also discusses some security issues from the point of view of the module programmer. -------------------------------------------------------------------------- 1. Introduction 1.1. Description 1.2. Synopsis 2. What can be expected by the module 2.1. Getting and setting PAM_ITEMs and data 2.1.1. Set module internal data 2.1.2. Get module internal data 2.1.3. Setting PAM items 2.1.4. Getting PAM items 2.1.5. Get user name 2.1.6. The conversation function 2.1.7. Set or change PAM environment variable 2.1.8. Get a PAM environment variable 2.1.9. Getting the PAM environment 2.2. Other functions provided by libpam 2.2.1. Strings describing PAM error codes 2.2.2. Request a delay on failure 3. What is expected of a module 3.1. Overview 3.1.1. Functional independence 3.1.2. Minimizing administration problems 3.1.3. Arguments supplied to the module 3.2. Authentication management 3.2.1. Service function for user authentication 3.2.2. Service function to alter credentials 3.3. Account management 3.3.1. Service function for account management 3.4. Session management 3.4.1. Service function to start session management 3.4.2. Service function to terminate session management 3.5. Authentication token management 3.5.1. Service function to alter authentication token 4. Generic optional arguments 5. Programming notes 5.1. Security issues for module creation 5.1.1. Sufficient resources 5.1.2. Who's who? 5.1.3. Using the conversation function 5.1.4. Authentication tokens 5.2. Use of syslog(3) 5.3. Modules that require system libraries 6. An example module 7. See also 8. Author/acknowledgments 9. Copyright information for this document Chapter 1. Introduction 1.1. Description 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 Linux-PAM library see the Linux-PAM System Administrators' Guide. A Linux-PAM module is a single executable binary file that can be loaded by the Linux-PAM interface library. This PAM library is configured locally with a system file, /etc/pam.conf, to authenticate a user request via the locally available authentication modules. The modules themselves will usually be located in the directory /lib/security (or /lib64/security, depending on the architecture) and take the form of dynamically loadable object files (see dlopen(3). Alternatively, the modules can be statically linked into the Linux-PAM library; this is mostly to allow Linux-PAM to be used on platforms without dynamic linking available, but this is a deprecated functionality. It is the 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 Linux-PAM-module. Except for the immediate purpose of interacting with the user (entering a password etc..) the module should never call the application directly. This exception requires a "conversation mechanism" which is documented below. 1.2. Synopsis #include gcc -fPIC -c pam_module.c gcc -shared -o pam_module.so pam_module.o -lpam Chapter 2. What can be expected by the module Here we list the interface that the conventions that all Linux-PAM modules must adhere to. 2.1. Getting and setting PAM_ITEMs and data First, we cover what the module should expect from the Linux-PAM library and a Linux-PAM aware application. Essentially this is the libpam.* library. 2.1.1. Set module internal data #include int pam_set_data( pamh, module_data_name, data, (*cleanup)(pam_handle_t *pamh, void *data, int error_status)); pam_handle_t *pamh; const char *module_data_name; void *data; void (*cleanup)(pam_handle_t *pamh, void *data, int error_status); 2.1.1.1. DESCRIPTION The pam_set_data function associates a pointer to an object with the (hopefully) unique string module_data_name in the PAM context specified by the pamh argument. PAM modules may be dynamically loadable objects. In general such files should not contain static variables. This function and its counterpart pam_get_data(3), provide a mechanism for a module to associate some data with the handle pamh. Typically a module will call the pam_set_data function to register some data under a (hopefully) unique module_data_name. The data is available for use by other modules too but not by an application. Since this functions stores only a pointer to the data, the module should not modify or free the content of it. The function cleanup() is associated with the data and, if non-NULL, it is called when this data is over-written or following a call to pam_end(3). The error_status argument is used to indicate to the module the sort of action it is to take in cleaning this data item. As an example, Kerberos creates a ticket file during the authentication phase, this file might be associated with a data item. When pam_end(3) is called by the module, the error_status carries the return value of the pam_authenticate(3) or other libpam function as appropriate. Based on this value the Kerberos module may choose to delete the ticket file (authentication failure) or leave it in place. The error_status may have been logically OR'd with either of the following two values: PAM_DATA_REPLACE When a data item is being replaced (through a second call to pam_set_data) this mask is used. Otherwise, the call is assumed to be from pam_end(3). PAM_DATA_SILENT Which indicates that the process would prefer to perform the cleanup() quietly. That is, discourages logging/messages to the user. 2.1.1.2. RETURN VALUES PAM_BUF_ERR Memory buffer error. PAM_SUCCESS Data was successful stored. PAM_SYSTEM_ERR A NULL pointer was submitted as PAM handle or the function was called by an application. 2.1.2. Get module internal data #include int pam_get_data( pamh, module_data_name, data); const pam_handle_t *pamh; const char *module_data_name; const void **data; 2.1.2.1. DESCRIPTION This function together with the pam_set_data(3) function is useful to manage module-specific data meaningful only to the calling PAM module. The pam_get_data function looks up the object associated with the (hopefully) unique string module_data_name in the PAM context specified by the pamh argument. A successful call to pam_get_data will result in data pointing to the object. Note, this data is not a copy and should be treated as constant by the module. 2.1.2.2. RETURN VALUES PAM_SUCCESS Data was successful retrieved. PAM_SYSTEM_ERR A NULL pointer was submitted as PAM handle or the function was called by an application. PAM_NO_MODULE_DATA Module data not found or there is an entry, but it has the value NULL. 2.1.3. Setting PAM items #include int pam_set_item( pamh, item_type, item); pam_handle_t *pamh; int item_type; const void *item; 2.1.3.1. DESCRIPTION The pam_set_item function allows applications and PAM service modules to access and to update PAM informations of item_type. For this a copy of the object pointed to by the item argument is created. The following item_types are supported: PAM_SERVICE The service name (which identifies that PAM stack that the PAM functions will use to authenticate the program). PAM_USER The username of the entity under whose identity service will be given. That is, following authentication, PAM_USER identifies the local entity that gets to use the service. Note, this value can be mapped from something (eg., "anonymous") to something else (eg. "guest119") by any module in the PAM stack. As such an application should consult the value of PAM_USER after each call to a PAM function. PAM_USER_PROMPT The string used when prompting for a user's name. The default value for this string is a localized version of "login: ". PAM_TTY The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based, applications the value for this item should be the $DISPLAY variable. PAM_RUSER The requesting user name: local name for a locally requesting user or a remote user name for a remote requesting user. Generally an application or module will attempt to supply the value that is most strongly authenticated (a local account before a remote one. The level of trust in this value is embodied in the actual authentication stack associated with the application, so it is ultimately at the discretion of the system administrator. PAM_RUSER@PAM_RHOST should always identify the requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear who the requesting entity is. PAM_RHOST The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is requesting service). That is PAM_RUSER@PAM_RHOST does identify the requesting user. In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the authentication request is originating from. PAM_AUTHTOK The authentication token (often a password). This token should be ignored by all module functions besides pam_sm_authenticate(3) and pam_sm_chauthtok(3). In the former function it is used to pass the most recent authentication token from one stacked module to another. In the latter function the token is used for another purpose. It contains the currently active authentication token. PAM_OLDAUTHTOK The old authentication token. This token should be ignored by all module functions except pam_sm_chauthtok(3). PAM_CONV The pam_conv structure. See pam_conv(3). The following additional items are specific to Linux-PAM and should not be used in portable applications: PAM_FAIL_DELAY A function pointer to redirect centrally managed failure delays. See pam_fail_delay(3). PAM_XDISPLAY The name of the X display. For graphical, X-based applications the value for this item should be the $DISPLAY variable. This value may be used independently of PAM_TTY for passing the name of the display. PAM_XAUTHDATA A pointer to a structure containing the X authentication data required to make a connection to the display specified by PAM_XDISPLAY, if such information is necessary. See pam_xauth_data(3). PAM_AUTHTOK_TYPE The default action is for the module to use the following prompts when requesting passwords: "New UNIX password: " and "Retype UNIX password: ". The example word UNIX can be replaced with this item, by default it is empty. This item is used by pam_get_authtok(3). For all item_types, other than PAM_CONV and PAM_FAIL_DELAY, item is a pointer to a terminated character string. In the case of PAM_CONV, item points to an initialized pam_conv structure. In the case of PAM_FAIL_DELAY, item is a function pointer: void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr) Both, PAM_AUTHTOK and PAM_OLDAUTHTOK, will be reseted before returning to the application. Which means an application is not able to access the authentication tokens. 2.1.3.2. RETURN VALUES PAM_BAD_ITEM The application attempted to set an undefined or inaccessible item. PAM_BUF_ERR Memory buffer error. PAM_SUCCESS Data was successful updated. PAM_SYSTEM_ERR The pam_handle_t passed as first argument was invalid. 2.1.4. Getting PAM items #include int pam_get_item( pamh, item_type, item); const pam_handle_t *pamh; int item_type; const void **item; 2.1.4.1. DESCRIPTION The pam_get_item function allows applications and PAM service modules to access and retrieve PAM informations of item_type. Upon successful return, item contains a pointer to the value of the corresponding item. Note, this is a pointer to the actual data and should not be free()'ed or over-written! The following values are supported for item_type: PAM_SERVICE The service name (which identifies that PAM stack that the PAM functions will use to authenticate the program). PAM_USER The username of the entity under whose identity service will be given. That is, following authentication, PAM_USER identifies the local entity that gets to use the service. Note, this value can be mapped from something (eg., "anonymous") to something else (eg. "guest119") by any module in the PAM stack. As such an application should consult the value of PAM_USER after each call to a PAM function. PAM_USER_PROMPT The string used when prompting for a user's name. The default value for this string is a localized version of "login: ". PAM_TTY The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based, applications the value for this item should be the $DISPLAY variable. PAM_RUSER The requesting user name: local name for a locally requesting user or a remote user name for a remote requesting user. Generally an application or module will attempt to supply the value that is most strongly authenticated (a local account before a remote one. The level of trust in this value is embodied in the actual authentication stack associated with the application, so it is ultimately at the discretion of the system administrator. PAM_RUSER@PAM_RHOST should always identify the requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear who the requesting entity is. PAM_RHOST The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is requesting service). That is PAM_RUSER@PAM_RHOST does identify the requesting user. In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the authentication request is originating from. PAM_AUTHTOK The authentication token (often a password). This token should be ignored by all module functions besides pam_sm_authenticate(3) and pam_sm_chauthtok(3). In the former function it is used to pass the most recent authentication token from one stacked module to another. In the latter function the token is used for another purpose. It contains the currently active authentication token. PAM_OLDAUTHTOK The old authentication token. This token should be ignored by all module functions except pam_sm_chauthtok(3). PAM_CONV The pam_conv structure. See pam_conv(3). The following additional items are specific to Linux-PAM and should not be used in portable applications: PAM_FAIL_DELAY A function pointer to redirect centrally managed failure delays. See pam_fail_delay(3). PAM_XDISPLAY The name of the X display. For graphical, X-based applications the value for this item should be the $DISPLAY variable. This value may be used independently of PAM_TTY for passing the name of the display. PAM_XAUTHDATA A pointer to a structure containing the X authentication data required to make a connection to the display specified by PAM_XDISPLAY, if such information is necessary. See pam_xauth_data(3). PAM_AUTHTOK_TYPE The default action is for the module to use the following prompts when requesting passwords: "New UNIX password: " and "Retype UNIX password: ". The example word UNIX can be replaced with this item, by default it is empty. This item is used by pam_get_authtok(3). If a service module wishes to obtain the name of the user, it should not use this function, but instead perform a call to pam_get_user(3). Only a service module is privileged to read the authentication tokens, PAM_AUTHTOK and PAM_OLDAUTHTOK. 2.1.4.2. RETURN VALUES PAM_BAD_ITEM The application attempted to set an undefined or inaccessible item. PAM_BUF_ERR Memory buffer error. PAM_PERM_DENIED The value of item was NULL. PAM_SUCCESS Data was successful updated. PAM_SYSTEM_ERR The pam_handle_t passed as first argument was invalid. 2.1.5. Get user name #include int pam_get_user( pamh, user, prompt); const pam_handle_t *pamh; const char **user; const char *prompt; 2.1.5.1. DESCRIPTION The pam_get_user function returns the name of the user specified by pam_start(3). If no user was specified it returns what pam_get_item (pamh, PAM_USER, ... ); would have returned. If this is NULL it obtains the username via the pam_conv(3) mechanism, it prompts the user with the first non-NULL string in the following list: * The prompt argument passed to the function. * What is returned by pam_get_item (pamh, PAM_USER_PROMPT, ... ); * The default prompt: "login: " By whatever means the username is obtained, a pointer to it is returned as the contents of *user. Note, this memory should not be free()'d or modified by the module. This function sets the PAM_USER item associated with the pam_set_item(3) and pam_get_item(3) functions. 2.1.5.2. RETURN VALUES PAM_SUCCESS User name was successful retrieved. PAM_SYSTEM_ERR A NULL pointer was submitted. PAM_CONV_ERR The conversation method supplied by the application failed to obtain the username. 2.1.6. The conversation function #include struct pam_message { int msg_style; const char *msg; }; struct pam_response { char *resp; int resp_retcode; }; struct pam_conv { int (*conv)(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); void *appdata_ptr; }; 2.1.6.1. DESCRIPTION The PAM library uses an application-defined callback to allow a direct communication between a loaded module and the application. This callback is specified by the struct pam_conv passed to pam_start(3) at the start of the transaction. When a module calls the referenced conv() function, the argument appdata_ptr is set to the second element of this structure. The other arguments of a call to conv() concern the information exchanged by module and application. That is to say, num_msg holds the length of the array of pointers, msg. After a successful return, the pointer resp points to an array of pam_response structures, holding the application supplied text. The resp_retcode member of this struct is unused and should be set to zero. It is the caller's responsibility to release both, this array and the responses themselves, using free(3). Note, *resp is a struct pam_response array and not an array of pointers. The number of responses is always equal to the num_msg conversation function argument. This does require that the response array is free(3)'d after every call to the conversation function. The index of the responses corresponds directly to the prompt index in the pam_message array. On failure, the conversation function should release any resources it has allocated, and return one of the predefined PAM error codes. Each message can have one of four types, specified by the msg_style member of struct pam_message: PAM_PROMPT_ECHO_OFF Obtain a string without echoing any text. PAM_PROMPT_ECHO_ON Obtain a string whilst echoing text. PAM_ERROR_MSG Display an error message. PAM_TEXT_INFO Display some text. The point of having an array of messages is that it becomes possible to pass a number of things to the application in a single call from the module. It can also be convenient for the application that related things come at once: a windows based application can then present a single form with many messages/prompts on at once. In passing, it is worth noting that there is a descrepency between the way Linux-PAM handles the const struct pam_message **msg conversation function argument from the way that Solaris' PAM (and derivitives, known to include HP/UX, are there others?) does. Linux-PAM interprets the msg argument as entirely equivalent to the following prototype const struct pam_message *msg[] (which, in spirit, is consistent with the commonly used prototypes for argv argument to the familiar main() function: char **argv; and char *argv[]). Said another way Linux-PAM interprets the msg argument as a pointer to an array of num_msg read only 'struct pam_message' pointers. Solaris' PAM implementation interprets this argument as a pointer to a pointer to an array of num_msg pam_message structures. Fortunately, perhaps, for most module/application developers when num_msg has a value of one these two definitions are entirely equivalent. Unfortunately, casually raising this number to two has led to unanticipated compatibility problems. For what its worth the two known module writer work-arounds for trying to maintain source level compatibility with both PAM implementations are: * never call the conversation function with num_msg greater than one. * set up msg as doubly referenced so both types of conversation function can find the messages. That is, make msg[n] = & (( *msg )[n]) 2.1.6.2. RETURN VALUES PAM_BUF_ERR Memory buffer error. PAM_CONV_ERR Conversation failure. The application should not set *resp. PAM_SUCCESS Success. 2.1.7. Set or change PAM environment variable #include int pam_putenv( pamh, name_value); pam_handle_t *pamh; const char *name_value; 2.1.7.1. DESCRIPTION The pam_putenv function is used to add or change the value of PAM environment variables as associated with the pamh handle. The pamh argument is an authentication handle obtained by a prior call to pam_start(). The name_value argument is a single NUL terminated string of one of the following forms: NAME=value of variable In this case the environment variable of the given NAME is set to the indicated value: value of variable. If this variable is already known, it is overwritten. Otherwise it is added to the PAM environment. NAME= This function sets the variable to an empty value. It is listed separately to indicate that this is the correct way to achieve such a setting. NAME Without an '=' the pam_putenv() function will delete the corresponding variable from the PAM environment. pam_putenv() operates on a copy of name_value, which means in contrast to putenv(3), the application is responsible to free the data. 2.1.7.2. RETURN VALUES PAM_PERM_DENIED Argument name_value given is a NULL pointer. PAM_BAD_ITEM Variable requested (for deletion) is not currently set. PAM_ABORT The pamh handle is corrupt. PAM_BUF_ERR Memory buffer error. PAM_SUCCESS The environment variable was successfully updated. 2.1.8. Get a PAM environment variable #include const char *pam_getenv( pamh, name); pam_handle_t *pamh; const char *name; 2.1.8.1. DESCRIPTION The pam_getenv function searches the PAM environment list as associated with the handle pamh for an item that matches the string pointed to by name and returns a pointer to the value of the environment variable. The application is not allowed to free the data. 2.1.8.2. RETURN VALUES The pam_getenv function returns NULL on failure. 2.1.9. Getting the PAM environment #include char **pam_getenvlist( pamh); pam_handle_t *pamh; 2.1.9.1. DESCRIPTION The pam_getenvlist function returns a complete copy of the PAM environment as associated with the handle pamh. The PAM environment variables represent the contents of the regular environment variables of the authenticated user when service is granted. The format of the memory is a malloc()'d array of char pointers, the last element of which is set to NULL. Each of the non-NULL entries in this array point to a NUL terminated and malloc()'d char string of the form: "name=value". It should be noted that this memory will never be free()'d by libpam. Once obtained by a call to pam_getenvlist, it is the responsibility of the calling application to free() this memory. It is by design, and not a coincidence, that the format and contents of the returned array matches that required for the third argument of the execle(3) function call. 2.1.9.2. RETURN VALUES The pam_getenvlist function returns NULL on failure. 2.2. Other functions provided by libpam 2.2.1. Strings describing PAM error codes #include const char *pam_strerror( pamh, errnum); pam_handle_t *pamh; int errnum; 2.2.1.1. DESCRIPTION The pam_strerror function returns a pointer to a string describing the error code passed in the argument errnum, possibly using the LC_MESSAGES part of the current locale to select the appropriate language. This string must not be modified by the application. No library function will modify this string. 2.2.1.2. RETURN VALUES This function returns always a pointer to a string. 2.2.2. Request a delay on failure #include int pam_fail_delay( pamh, usec); pam_handle_t *pamh; unsigned int usec; 2.2.2.1. DESCRIPTION The pam_fail_delay function provides a mechanism by which an application or module can suggest a minimum delay of usec micro-seconds. The function keeps a record of the longest time requested with this function. Should pam_authenticate(3) fail, the failing return to the application is delayed by an amount of time randomly distributed (by up to 50%) about this longest value. Independent of success, the delay time is reset to its zero default value when the PAM service module returns control to the application. The delay occurs after all authentication modules have been called, but before control is returned to the service application. When using this function the programmer should check if it is available with: #ifdef HAVE_PAM_FAIL_DELAY .... #endif /* HAVE_PAM_FAIL_DELAY */ For applications written with a single thread that are event driven in nature, generating this delay may be undesirable. Instead, the application may want to register the delay in some other way. For example, in a single threaded server that serves multiple authentication requests from a single event loop, the application might want to simply mark a given connection as blocked until an application timer expires. For this reason the delay function can be changed with the PAM_FAIL_DELAY item. It can be queried and set with pam_get_item(3) and pam_set_item (3) respectively. The value used to set it should be a function pointer of the following prototype: void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr); The arguments being the retval return code of the module stack, the usec_delay micro-second delay that libpam is requesting and the appdata_ptr that the application has associated with the current pamh. This last value was set by the application when it called pam_start(3) or explicitly with pam_set_item(3). Note, if PAM_FAIL_DELAY item is unset (or set to NULL), then no delay will be performed. 2.2.2.2. RETURN VALUES PAM_SUCCESS Delay was successful adjusted. PAM_SYSTEM_ERR A NULL pointer was submitted as PAM handle. Chapter 3. What is expected of a module The module must supply a sub-set of the six functions listed below. Together they define the function of a Linux-PAM module. Module developers are strongly urged to read the comments on security that follow this list. 3.1. Overview The six module functions are grouped into four independent management groups. These groups are as follows: authentication, account, session and 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 all four groups. 3.1.1. Functional independence The independence of the four groups of service a module can offer means that the module should allow for the possibility that any one of these four services may legitimately be called in any order. Thus, the module writer should consider the appropriateness of performing a service without the prior success of some other part of the module. As an informative example, consider the possibility that an application applies to change a user's authentication token, without having first requested that Linux-PAM authenticate the user. In some cases this may be deemed appropriate: when root wants to change the authentication token of some lesser user. In other cases it may not be appropriate: when joe maliciously wants to reset alice's password; or when anyone other than the user themself wishes to reset their 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. 3.1.2. Minimizing administration problems To avoid system administration problems and the poor construction of a /etc/pam.conf file, the module developer may define all six of the following functions. For those functions that would not be called, the module should return PAM_SERVICE_ERR and write an appropriate message to the system log. When this action is deemed inappropriate, the function would simply return PAM_IGNORE. 3.1.3. Arguments supplied to the module The flags argument of each of the following functions can be logically OR'd with PAM_SILENT, which is used to inform the module to not pass any text (errors or warnings) application. The argc and argv arguments are taken from the line appropriate to this module---that is, with the service_name matching that of the application---in the configuration file (see the 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 main(). Note, however, that the first argument (argv[0]) is a true argument and not the name of the module. 3.2. Authentication management To be correctly initialized, PAM_SM_AUTH must be #define'd prior to including . This will ensure that the prototypes for static modules are properly declared. 3.2.1. Service function for user authentication #define PAM_SM_AUTH #include int pam_sm_authenticate( pamh, flags, argc, argv); pam_handle_t *pamh; int flags; int argc; const char **argv; 3.2.1.1. DESCRIPTION The pam_sm_authenticate function is the service module's implementation of the pam_authenticate(3) interface. This function performs the task of authenticating the user. Valid flags, which may be logically OR'd with PAM_SILENT, are: PAM_SILENT Do not emit any messages. PAM_DISALLOW_NULL_AUTHTOK Return PAM_AUTH_ERR if the database of authentication tokens for this authentication mechanism has a NULL entry for the user. Without this flag, such a NULL token will lead to a success without the user being prompted. 3.2.1.2. RETURN VALUES PAM_AUTH_ERR Authentication failure. PAM_CRED_INSUFFICIENT For some reason the application does not have sufficient credentials to authenticate the user. PAM_AUTHINFO_UNAVAIL The modules were not able to access the authentication information. This might be due to a network or hardware failure etc. PAM_SUCCESS The authentication token was successfully updated. PAM_USER_UNKNOWN The supplied username is not known to the authentication service. PAM_MAXTRIES One or more of the authentication modules has reached its limit of tries authenticating the user. Do not try again. 3.2.2. Service function to alter credentials #define PAM_SM_AUTH #include int pam_sm_setcred( pamh, flags, argc, argv); pam_handle_t *pamh; int flags; int argc; const char **argv; 3.2.2.1. DESCRIPTION The pam_sm_setcred function is the service module's implementation of the pam_setcred(3) interface. 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 after the user has been authenticated but before a session has been established. Valid flags, which may be logically OR'd with PAM_SILENT, are: PAM_SILENT Do not emit any messages. PAM_ESTABLISH_CRED Initialize the credentials for the user. PAM_DELETE_CRED Delete the credentials associated with the authentication service. PAM_REINITIALIZE_CRED Reinitialize the user credentials. PAM_REFRESH_CRED Extend the lifetime of the user credentials. The way the auth stack is navigated in order to evaluate the pam_setcred() function call, independent of the pam_sm_setcred() return codes, is exactly the same way that it was navigated when evaluating the pam_authenticate() library call. Typically, if a stack entry was ignored in evaluating pam_authenticate(), it will be ignored when libpam evaluates the pam_setcred() function call. Otherwise, the return codes from each module specific pam_sm_setcred() call are treated as required. 3.2.2.2. RETURN VALUES PAM_CRED_UNAVAIL This module cannot retrieve the user's credentials. PAM_CRED_EXPIRED The user's credentials have expired. PAM_CRED_ERR This module was unable to set the credentials of the user. PAM_SUCCESS The user credential was successfully set. PAM_USER_UNKNOWN The user is not known to this authentication module. These, non-PAM_SUCCESS, return values will typically lead to the credential stack failing. The first such error will dominate in the return value of pam_setcred(). 3.3. Account management To be correctly initialized, PAM_SM_ACCOUNT must be #define'd prior to including . This will ensure that the prototypes for static modules are properly declared. 3.3.1. Service function for account management #define PAM_SM_ACCOUNT #include int pam_sm_acct_mgmt( pamh, flags, argc, argv); pam_handle_t *pamh; int flags; int argc; const char **argv; 3.3.1.1. DESCRIPTION The pam_sm_acct_mgmt function is the service module's implementation of the pam_acct_mgmt(3) interface. This function performs the task of establishing whether the user is permitted to gain access at this time. It should be understood that the user has previously been validated by an authentication module. This function checks for other things. Such things might be: the time of day or the date, the terminal line, remote hostname, etc. This function may also determine things like the expiration on passwords, and respond that the user change it before continuing. Valid flags, which may be logically OR'd with PAM_SILENT, are: PAM_SILENT Do not emit any messages. PAM_DISALLOW_NULL_AUTHTOK Return PAM_AUTH_ERR if the database of authentication tokens for this authentication mechanism has a NULL entry for the user. 3.3.1.2. RETURN VALUES PAM_ACCT_EXPIRED User account has expired. PAM_AUTH_ERR Authentication failure. PAM_NEW_AUTHTOK_REQD The user's authentication token has expired. Before calling this function again the application will arrange for a new one to be given. This will likely result in a call to pam_sm_chauthtok(). PAM_PERM_DENIED Permission denied. PAM_SUCCESS The authentication token was successfully updated. PAM_USER_UNKNOWN User unknown to password service. 3.4. Session management To be correctly initialized, PAM_SM_SESSION must be #define'd prior to including . This will ensure that the prototypes for static modules are properly declared. 3.4.1. Service function to start session management #define PAM_SM_SESSION #include int pam_sm_open_session( pamh, flags, argc, argv); pam_handle_t *pamh; int flags; int argc; const char **argv; 3.4.1.1. DESCRIPTION The pam_sm_open_session function is the service module's implementation of the pam_open_session(3) interface. This function is called to commence a session. The only valid value for flags is zero or: PAM_SILENT Do not emit any messages. 3.4.1.2. RETURN VALUES PAM_SESSION_ERR Cannot make/remove an entry for the specified session. PAM_SUCCESS The session was successfully started. 3.4.2. Service function to terminate session management #define PAM_SM_SESSION #include int pam_sm_close_session( pamh, flags, argc, argv); pam_handle_t *pamh; int flags; int argc; const char **argv; 3.4.2.1. DESCRIPTION The pam_sm_close_session function is the service module's implementation of the pam_close_session(3) interface. This function is called to terminate a session. The only valid value for flags is zero or: PAM_SILENT Do not emit any messages. 3.4.2.2. RETURN VALUES PAM_SESSION_ERR Cannot make/remove an entry for the specified session. PAM_SUCCESS The session was successfully terminated. 3.5. Authentication token management To be correctly initialized, PAM_SM_PASSWORD must be #define'd prior to including . This will ensure that the prototypes for static modules are properly declared. 3.5.1. Service function to alter authentication token #define PAM_SM_PASSWORD #include int pam_sm_chauthtok( pamh, flags, argc, argv); pam_handle_t *pamh; int flags; int argc; const char **argv; 3.5.1.1. DESCRIPTION The pam_sm_chauthtok function is the service module's implementation of the pam_chauthtok(3) interface. This function is used to (re-)set the authentication token of the user. Valid flags, which may be logically OR'd with PAM_SILENT, are: PAM_SILENT Do not emit any messages. PAM_CHANGE_EXPIRED_AUTHTOK This argument indicates to the module that the user's authentication token (password) should only be changed if it has expired. This flag is optional and must be combined with one of the following two flags. Note, however, the following two options are mutually exclusive. PAM_PRELIM_CHECK This indicates that the modules are being probed as to their ready status for altering the user's authentication token. If the module requires access to another system over some network it should attempt to verify it can connect to this system on receiving this flag. If a module cannot establish it is ready to update the user's authentication token it should return PAM_TRY_AGAIN, this information will be passed back to the application. If the control value sufficient is used in the password stack, the PAM_PRELIM_CHECK section of the modules following that control value is not always executed. PAM_UPDATE_AUTHTOK This informs the module that this is the call it should change the authorization tokens. If the flag is logically OR'd with PAM_CHANGE_EXPIRED_AUTHTOK, the token is only changed if it has actually expired. The PAM library calls this function twice in succession. The first time with PAM_PRELIM_CHECK and then, if the module does not return PAM_TRY_AGAIN, subsequently with PAM_UPDATE_AUTHTOK. It is only on the second call that the authorization token is (possibly) changed. 3.5.1.2. RETURN VALUES PAM_AUTHTOK_ERR The module was unable to obtain the new authentication token. PAM_AUTHTOK_RECOVERY_ERR The module was unable to obtain the old authentication token. PAM_AUTHTOK_LOCK_BUSY Cannot change the authentication token since it is currently locked. PAM_AUTHTOK_DISABLE_AGING Authentication token aging has been disabled. PAM_PERM_DENIED Permission denied. PAM_TRY_AGAIN Preliminary check was unsuccessful. Signals an immediate return to the application is desired. PAM_SUCCESS The authentication token was successfully updated. PAM_USER_UNKNOWN User unknown to password service. Chapter 4. Generic optional arguments Here we list the generic arguments that all modules can expect to be passed. They are not mandatory, and their absence should be accepted without comment by the module. debug Use the pam_syslog(3) call to log debugging information to the system log files. use_first_pass The module should not prompt the user for a password. Instead, it should obtain the previously typed password (by a call to pam_get_item() for the PAM_AUTHTOK item), and use that. If that doesn't work, then the user will not be authenticated. (This option is intended for auth and passwd modules only). Chapter 5. Programming notes Here we collect some pointers for the module writer to bear in mind when writing/developing a Linux-PAM compatible module. 5.1. Security issues for module creation 5.1.1. Sufficient resources Care should be taken to ensure that the proper execution of a module is not compromised by a lack of system resources. If a module is unable to open sufficient files to perform its task, it should fail gracefully, or request additional resources. Specifically, the quantities manipulated by the setrlimit(2) family of commands should be taken into consideration. 5.1.2. Who's who? Generally, the module may wish to establish the identity of the user requesting a service. This may not be the same as the username returned by pam_get_user(). Indeed, that is only going to be the name of the user under whose identity the service will be given. This is not necessarily the user that requests the service. In other words, user X runs a program that is setuid-Y, it grants the user to have the permissions of Z. A specific example of this sort of service request is the su program: user joe executes su to become the user jane. In this situation X=joe, Y=root and Z=jane. Clearly, it is important that the module does not confuse these different users and grant an inappropriate level of privilege. The following is the convention to be adhered to when juggling user-identities. * X, the identity of the user invoking the service request. This is the user identifier; returned by the function getuid(2). * Y, the privileged identity of the application used to grant the requested service. This is the effective user identifier; returned by the function geteuid(2). * Z, the user under whose identity the service will be granted. This is the username returned by pam_get_user() and also stored in the Linux-PAM item, PAM_USER. * Linux-PAM has a place for an additional user identity that a module may care to make use of. This is the PAM_RUSER item. Generally, network sensitive modules/applications may wish to set/read this item to establish the identity of the user requesting a service from a remote location. Note, if a module wishes to modify the identity of either the uid or euid of the running process, it should take care to restore the original values prior to returning control to the Linux-PAM library. 5.1.3. Using the conversation function Prior to calling the conversation function, the module should reset the contents of the pointer that will return the applications response. This is a good idea since the application may fail to fill the pointer and the module should be in a position to notice! The module should be prepared for a failure from the conversation. The generic error would be PAM_CONV_ERR, but anything other than PAM_SUCCESS should be treated as indicating failure. 5.1.4. Authentication tokens To ensure that the authentication tokens are not left lying around the items, PAM_AUTHTOK and PAM_OLDAUTHTOK, are not available to the application: they are defined in . This is ostensibly for security reasons, but a maliciously programmed application will always have access to all memory of the process, so it is only superficially enforced. As a general rule the module should overwrite authentication tokens as soon as they are no longer needed. Especially before free()'ing them. The Linux-PAM library is required to do this when either of these authentication token items are (re)set. Not to dwell too little on this concern; should the module store the authentication tokens either as (automatic) function variables or using pam_[gs]et_data() the associated memory should be over-written explicitly before it is released. In the case of the latter storage mechanism, the associated cleanup() function should explicitly overwrite the *data before free()'ing it: for example, /* * An example cleanup() function for releasing memory that was used to * store a password. */ int cleanup(pam_handle_t *pamh, void *data, int error_status) { char *xx; if ((xx = data)) { while (*xx) *xx++ = '\0'; free(data); } return PAM_SUCCESS; } 5.2. Use of syslog(3) Only rarely should error information be directed to the user. Usually, this is to be limited to "sorry you cannot login now" type messages. Information concerning errors in the configuration file, /etc/pam.conf, or due to some system failure encountered by the module, should be written to syslog(3) with facility-type LOG_AUTHPRIV. With a few exceptions, the level of logging is, at the discretion of the module developer. Here is the recommended usage of different logging levels: * As a general rule, errors encountered by a module should be logged at the LOG_ERR level. However, information regarding an unrecognized argument, passed to a module from an entry in the /etc/pam.conf file, is required to be logged at the LOG_ERR level. * Debugging information, as activated by the debug argument to the module in /etc/pam.conf, should be logged at the LOG_DEBUG level. * If a module discovers that its personal configuration file or some system file it uses for information is corrupted or somehow unusable, it should indicate this by logging messages at level, LOG_ALERT. * Shortages of system resources, such as a failure to manipulate a file or malloc() failures should be logged at level LOG_CRIT. * Authentication failures, associated with an incorrectly typed password should be logged at level, LOG_NOTICE. 5.3. Modules that require system libraries Writing a module is much like writing an application. You have to provide the "conventional hooks" for it to work correctly, like pam_sm_authenticate() etc., which would correspond to the main() function in a normal function. Typically, the author may want to link against some standard system libraries. As when one compiles a normal program, this can be done for modules too: you simply append the -lXXX arguments for the desired libraries when you create the shared module object. To make sure a module is linked to the libwhatever.so library when it is dlopen()ed, try: % gcc -shared -o pam_module.so pam_module.o -lwhatever Chapter 6. An example module At some point, we may include a fully commented example of a module in this document. For now, please look at the modules directory of the Linux-PAM sources. Chapter 7. See also * The Linux-PAM System Administrators' Guide. * The Linux-PAM Application Developers' Guide. * The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request For Comments 86.0, October 1995. Chapter 8. Author/acknowledgments This document was written by Andrew G. Morgan (morgan@kernel.org) with many contributions from Chris Adams, Peter Allgeyer, Tim Baverstock, Tim Berger, Craig S. Bell, Derrick J. Brashear, Ben Buxton, Seth Chaiklin, Oliver Crow, Chris Dent, Marc Ewing, Cristian Gafton, Emmanuel Galanos, Brad M. Garcia, Eric Hester, Roger Hu, Eric Jacksch, Michael K. Johnson, David Kinchlea, Olaf Kirch, Marcin Korzonek, Thorsten Kukuk, Stephen Langasek, Nicolai Langfeldt, Elliot Lee, Luke Kenneth Casson Leighton, Al Longyear, Ingo Luetkebohle, Marek Michalkiewicz, Robert Milkowski, Aleph One, Martin Pool, Sean Reifschneider, Jan Rekorajski, Erik Troan, Theodore Ts'o, Jeff Uphoff, Myles Uyema, Savochkin Andrey Vladimirovich, Ronald Wahl, David Wood, John Wilmes, Joseph S. D. Yao and Alex O. Yuriev. Thanks are also due to Sun Microsystems, especially to Vipin Samar and Charlie Lai for their advice. At an early stage in the development of Linux-PAM, Sun graciously made the documentation for their implementation of PAM available. This act greatly accelerated the development of Linux-PAM. Chapter 9. Copyright information for this document Copyright (c) 2006 Thorsten Kukuk Copyright (c) 1996-2002 Andrew G. Morgan 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 (GPL), 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 PK/.1](W W html/adg-security-resources.htmlnu[4.5. Sufficient resources

4.5. Sufficient resources

Care should be taken to ensure that the proper execution of an application is not compromised by a lack of system resources. If an application is unable to open sufficient files to perform its service, it should fail gracefully, or request additional resources. Specifically, the quantities manipulated by the setrlimit(2) family of commands should be taken into consideration.

This is also true of conversation prompts. The application should not accept prompts of arbitrary length with out checking for resource allocation failure and dealing with such extreme conditions gracefully and in a manner that preserves the PAM API. Such tolerance may be especially important when attempting to track a malicious adversary.

PK/.1]$html/mwg-see-programming-syslog.htmlnu[5.2. Use of syslog(3)

5.2. Use of syslog(3)

Only rarely should error information be directed to the user. Usually, this is to be limited to sorry you cannot login now type messages. Information concerning errors in the configuration file, /etc/pam.conf, or due to some system failure encountered by the module, should be written to syslog(3) with facility-type LOG_AUTHPRIV.

With a few exceptions, the level of logging is, at the discretion of the module developer. Here is the recommended usage of different logging levels:

  • As a general rule, errors encountered by a module should be logged at the LOG_ERR level. However, information regarding an unrecognized argument, passed to a module from an entry in the /etc/pam.conf file, is required to be logged at the LOG_ERR level.

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

  • If a module discovers that its personal configuration file or some system file it uses for information is corrupted or somehow unusable, it should indicate this by logging messages at level, LOG_ALERT.

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

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

PK/.1]ZMhtml/adg-interface.htmlnu[Chapter 3.  The public interface to Linux-PAM PK/.1]~  html/mwg-author.htmlnu[Chapter 8. Author/acknowledgments

Chapter 8. Author/acknowledgments

This document was written by Andrew G. Morgan (morgan@kernel.org) with many contributions from Chris Adams, Peter Allgeyer, Tim Baverstock, Tim Berger, Craig S. Bell, Derrick J. Brashear, Ben Buxton, Seth Chaiklin, Oliver Crow, Chris Dent, Marc Ewing, Cristian Gafton, Emmanuel Galanos, Brad M. Garcia, Eric Hester, Roger Hu, Eric Jacksch, Michael K. Johnson, David Kinchlea, Olaf Kirch, Marcin Korzonek, Thorsten Kukuk, Stephen Langasek, Nicolai Langfeldt, Elliot Lee, Luke Kenneth Casson Leighton, Al Longyear, Ingo Luetkebohle, Marek Michalkiewicz, Robert Milkowski, Aleph One, Martin Pool, Sean Reifschneider, Jan Rekorajski, Erik Troan, Theodore Ts'o, Jeff Uphoff, Myles Uyema, Savochkin Andrey Vladimirovich, Ronald Wahl, David Wood, John Wilmes, Joseph S. D. Yao and Alex O. Yuriev.

Thanks are also due to Sun Microsystems, especially to Vipin Samar and Charlie Lai for their advice. At an early stage in the development of Linux-PAM, Sun graciously made the documentation for their implementation of PAM available. This act greatly accelerated the development of Linux-PAM.

PK/.1]|Όc"c"html/Linux-PAM_MWG.htmlnu[The Linux-PAM Module Writers' Guide

The Linux-PAM Module Writers' Guide

Andrew G. Morgan

Thorsten Kukuk

Version 1.1.2, 31. August 2010

Abstract

This manual documents what a programmer needs to know in order to write a module that conforms to the Linux-PAM standard.It also discusses some security issues from the point of view of the module programmer.


PK/.1] E  html/adg-author.htmlnu[Chapter 11. Author/acknowledgments

Chapter 11. Author/acknowledgments

This document was written by Andrew G. Morgan (morgan@kernel.org) with many contributions from Chris Adams, Peter Allgeyer, Tim Baverstock, Tim Berger, Craig S. Bell, Derrick J. Brashear, Ben Buxton, Seth Chaiklin, Oliver Crow, Chris Dent, Marc Ewing, Cristian Gafton, Emmanuel Galanos, Brad M. Garcia, Eric Hester, Roger Hu, Eric Jacksch, Michael K. Johnson, David Kinchlea, Olaf Kirch, Marcin Korzonek, Thorsten Kukuk, Stephen Langasek, Nicolai Langfeldt, Elliot Lee, Luke Kenneth Casson Leighton, Al Longyear, Ingo Luetkebohle, Marek Michalkiewicz, Robert Milkowski, Aleph One, Martin Pool, Sean Reifschneider, Jan Rekorajski, Erik Troan, Theodore Ts'o, Jeff Uphoff, Myles Uyema, Savochkin Andrey Vladimirovich, Ronald Wahl, David Wood, John Wilmes, Joseph S. D. Yao and Alex O. Yuriev.

Thanks are also due to Sun Microsystems, especially to Vipin Samar and Charlie Lai for their advice. At an early stage in the development of Linux-PAM, Sun graciously made the documentation for their implementation of PAM available. This act greatly accelerated the development of Linux-PAM.

PK/.1]~˺\\html/adg-example.htmlnu[Chapter 8. An example application

Chapter 8. An example application

To get a flavor of the way a Linux-PAM application is written we include the following example. It prompts the user for their password and indicates whether their account is valid on the standard output, its return code also indicates the success (0 for success; 1 for failure).

/*
  This program was contributed by Shane Watts
  [modifications by AGM and kukuk]

  You need to add the following (or equivalent) to the
  /etc/pam.d/check_user file:
  # check authorization
  auth       required     pam_unix.so
  account    required     pam_unix.so
 */

#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>

static struct pam_conv conv = {
    misc_conv,
    NULL
};

int main(int argc, char *argv[])
{
    pam_handle_t *pamh=NULL;
    int retval;
    const char *user="nobody";

    if(argc == 2) {
        user = argv[1];
    }

    if(argc > 2) {
        fprintf(stderr, "Usage: check_user [username]\n");
        exit(1);
    }

    retval = pam_start("check_user", user, &conv, &pamh);

    if (retval == PAM_SUCCESS)
        retval = pam_authenticate(pamh, 0);    /* is user really user? */

    if (retval == PAM_SUCCESS)
        retval = pam_acct_mgmt(pamh, 0);       /* permitted access? */

    /* This is where we have been authorized or not. */

    if (retval == PAM_SUCCESS) {
        fprintf(stdout, "Authenticated\n");
    } else {
        fprintf(stdout, "Not Authenticated\n");
    }

    if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
        pamh = NULL;
        fprintf(stderr, "check_user: failed to release authenticator\n");
        exit(1);
    }

    return ( retval == PAM_SUCCESS ? 0:1 );       /* indicate success */
}

    
PK/.1]G9html/adg-files.htmlnu[Chapter 9. Files

Chapter 9. Files

/usr/include/security/pam_appl.h

Header file with interfaces for Linux-PAM applications.

/usr/include/security/pam_misc.h

Header file for useful library functions for making applications easier to write.

PK/.1]޿%(html/mwg-expected-of-module-session.htmlnu[3.4. Session management

3.4. Session management

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

3.4.1. Service function to start session management

#define PAM_SM_SESSION
#include <security/pam_modules.h>
int pam_sm_open_session(pamh,  
 flags,  
 argc,  
 argv); 
pam_handle_t *pamh;
int flags;
int argc;
const char **argv;
 

3.4.1.1. DESCRIPTION

The pam_sm_open_session function is the service module's implementation of the pam_open_session(3) interface.

This function is called to commence a session. The only valid value for flags is zero or:

PAM_SILENT

Do not emit any messages.

3.4.1.2. RETURN VALUES

PAM_SESSION_ERR

Cannot make/remove an entry for the specified session.

PAM_SUCCESS

The session was successfully started.

3.4.2. Service function to terminate session management

#define PAM_SM_SESSION
#include <security/pam_modules.h>
int pam_sm_close_session(pamh,  
 flags,  
 argc,  
 argv); 
pam_handle_t *pamh;
int flags;
int argc;
const char **argv;
 

3.4.2.1. DESCRIPTION

The pam_sm_close_session function is the service module's implementation of the pam_close_session(3) interface.

This function is called to terminate a session. The only valid value for flags is zero or:

PAM_SILENT

Do not emit any messages.

3.4.2.2. RETURN VALUES

PAM_SESSION_ERR

Cannot make/remove an entry for the specified session.

PAM_SUCCESS

The session was successfully terminated.

PK/.1]^Thtml/adg-porting.htmlnu[Chapter 6. Porting legacy applications

Chapter 6. Porting legacy applications

The point of PAM is that the application is not supposed to have any idea how the attached authentication modules will choose to authenticate the user. So all they can do is provide a conversation function that will talk directly to the user(client) on the modules' behalf.

Consider the case that you plug a retinal scanner into the login program. In this situation the user would be prompted: "please look into the scanner". No username or password would be needed - all this information could be deduced from the scan and a database lookup. The point is that the retinal scanner is an ideal task for a "module".

While it is true that a pop-daemon program is designed with the POP protocol in mind and no-one ever considered attaching a retinal scanner to it, it is also the case that the "clean" PAM'ification of such a daemon would allow for the possibility of a scanner module being be attached to it. The point being that the "standard" pop-authentication protocol(s) [which will be needed to satisfy inflexible/legacy clients] would be supported by inserting an appropriate pam_qpopper module(s). However, having rewritten popd once in this way any new protocols can be implemented in-situ.

One simple test of a ported application would be to insert the pam_permit module and see if the application demands you type a password... In such a case, xlock would fail to lock the terminal - or would at best be a screen-saver, ftp would give password free access to all etc.. Neither of these is a very secure thing to do, but they do illustrate how much flexibility PAM puts in the hands of the local admin.

The key issue, in doing things correctly, is identifying what is part of the authentication procedure (how many passwords etc..) the exchange protocol (prefixes to prompts etc., numbers like 331 in the case of ftpd) and what is part of the service that the application delivers. PAM really needs to have total control in the authentication "procedure", the conversation function should only deal with reformatting user prompts and extracting responses from raw input.

PK/.1]Lhtml/mwg-copyright.htmlnu[Chapter 9. Copyright information for this document

Chapter 9. Copyright information for this document

Copyright (c) 2006 Thorsten Kukuk <kukuk@thkukuk.de>
Copyright (c) 1996-2002 Andrew G. Morgan <morgan@kernel.org>
    

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 (GPL), 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
    
PK/.1]_Š &html/mwg-expected-by-module-other.htmlnu[2.2.  Other functions provided by libpam

2.2.  Other functions provided by libpam

2.2.1. Strings describing PAM error codes

#include <security/pam_appl.h>
const char *pam_strerror(pamh,  
 errnum); 
pam_handle_t *pamh;
int errnum;
 

2.2.1.1. DESCRIPTION

The pam_strerror function returns a pointer to a string describing the error code passed in the argument errnum, possibly using the LC_MESSAGES part of the current locale to select the appropriate language. This string must not be modified by the application. No library function will modify this string.

2.2.1.2. RETURN VALUES

This function returns always a pointer to a string.

2.2.2. Request a delay on failure

#include <security/pam_appl.h>
int pam_fail_delay(pamh,  
 usec); 
pam_handle_t *pamh;
unsigned int usec;
 

2.2.2.1. DESCRIPTION

The pam_fail_delay function provides a mechanism by which an application or module can suggest a minimum delay of usec micro-seconds. The function keeps a record of the longest time requested with this function. Should pam_authenticate(3) fail, the failing return to the application is delayed by an amount of time randomly distributed (by up to 50%) about this longest value.

Independent of success, the delay time is reset to its zero default value when the PAM service module returns control to the application. The delay occurs after all authentication modules have been called, but before control is returned to the service application.

When using this function the programmer should check if it is available with:

#ifdef HAVE_PAM_FAIL_DELAY
    ....
#endif /* HAVE_PAM_FAIL_DELAY */
      

For applications written with a single thread that are event driven in nature, generating this delay may be undesirable. Instead, the application may want to register the delay in some other way. For example, in a single threaded server that serves multiple authentication requests from a single event loop, the application might want to simply mark a given connection as blocked until an application timer expires. For this reason the delay function can be changed with the PAM_FAIL_DELAY item. It can be queried and set with pam_get_item(3) and pam_set_item (3) respectively. The value used to set it should be a function pointer of the following prototype:

void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr);
      

The arguments being the retval return code of the module stack, the usec_delay micro-second delay that libpam is requesting and the appdata_ptr that the application has associated with the current pamh. This last value was set by the application when it called pam_start(3) or explicitly with pam_set_item(3). Note, if PAM_FAIL_DELAY item is unset (or set to NULL), then no delay will be performed.

2.2.2.2. RETURN VALUES

PAM_SUCCESS

Delay was successful adjusted.

PAM_SYSTEM_ERR

A NULL pointer was submitted as PAM handle.

PK/.1]A4f html/mwg-expected-of-module.htmlnu[Chapter 3. What is expected of a module PK/.1]%%)html/mwg-expected-of-module-overview.htmlnu[3.1. Overview

3.1. Overview

The six module functions are grouped into four independent management groups. These groups are as follows: authentication, account, session and 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 all four groups.

3.1.1. Functional independence

The independence of the four groups of service a module can offer means that the module should allow for the possibility that any one of these four services may legitimately be called in any order. Thus, the module writer should consider the appropriateness of performing a service without the prior success of some other part of the module.

As an informative example, consider the possibility that an application applies to change a user's authentication token, without having first requested that Linux-PAM authenticate the user. In some cases this may be deemed appropriate: when root wants to change the authentication token of some lesser user. In other cases it may not be appropriate: when joe maliciously wants to reset alice's password; or when anyone other than the user themself wishes to reset their 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.

3.1.2. Minimizing administration problems

To avoid system administration problems and the poor construction of a /etc/pam.conf file, the module developer may define all six of the following functions. For those functions that would not be called, the module should return PAM_SERVICE_ERR and write an appropriate message to the system log. When this action is deemed inappropriate, the function would simply return PAM_IGNORE.

3.1.3. Arguments supplied to the module

The flags argument of each of the following functions can be logically OR'd with PAM_SILENT, which is used to inform the module to not pass any text (errors or warnings) application.

The argc and argv arguments are taken from the line appropriate to this module---that is, with the service_name matching that of the application---in the configuration file (see the 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 main(). Note, however, that the first argument (argv[0]) is a true argument and not the name of the module.

PK/.1]c*$html/adg-security-user-identity.htmlnu[4.4. The identity of the user

4.4. The identity of the user

The Linux-PAM modules will need to determine the identity of the user who requests a service, and the identity of the user who grants the service. These two users will seldom be the same. Indeed there is generally a third user identity to be considered, the new (assumed) identity of the user once the service is granted.

The need for keeping tabs on these identities is clearly an issue of security. One convention that is actively used by some modules is that the identity of the user requesting a service should be the current UID (user ID) of the running process; the identity of the privilege granting user is the EUID (effective user ID) of the running process; the identity of the user, under whose name the service will be executed, is given by the contents of the PAM_USER pam_get_item(3). Note, modules can change the values of PAM_USER and PAM_RUSER during any of the pam_*() library calls. For this reason, the application should take care to use the pam_get_item() every time it wishes to establish who the authenticated user is (or will currently be).

For network-serving databases and other applications that provide their own security model (independent of the OS kernel) the above scheme is insufficient to identify the requesting user.

A more portable solution to storing the identity of the requesting user is to use the PAM_RUSER pam_get_item(3). The application should supply this value before attempting to authenticate the user with pam_authenticate(). How well this name can be trusted will ultimately be at the discretion of the local administrator (who configures PAM for your application) and a selected module may attempt to override the value where it can obtain more reliable data. If an application is unable to determine the identity of the requesting entity/user, it should not call pam_set_item(3) to set PAM_RUSER.

In addition to the PAM_RUSER item, the application should supply the PAM_RHOST (requesting host) item. As a general rule, the following convention for its value can be assumed: NULL = unknown; localhost = invoked directly from the local system; other.place.xyz = some component of the user's connection originates from this remote/requesting host. At present, PAM has no established convention for indicating whether the application supports a trusted path to communication from this host.

PK/.1]тA##!html/mwg-see-programming-sec.htmlnu[5.1. Security issues for module creation

5.1. Security issues for module creation

5.1.1. Sufficient resources

Care should be taken to ensure that the proper execution of a module is not compromised by a lack of system resources. If a module is unable to open sufficient files to perform its task, it should fail gracefully, or request additional resources. Specifically, the quantities manipulated by the setrlimit(2) family of commands should be taken into consideration.

5.1.2. Who´s who?

Generally, the module may wish to establish the identity of the user requesting a service. This may not be the same as the username returned by pam_get_user(). Indeed, that is only going to be the name of the user under whose identity the service will be given. This is not necessarily the user that requests the service.

In other words, user X runs a program that is setuid-Y, it grants the user to have the permissions of Z. A specific example of this sort of service request is the su program: user joe executes su to become the user jane. In this situation X=joe, Y=root and Z=jane. Clearly, it is important that the module does not confuse these different users and grant an inappropriate level of privilege.

The following is the convention to be adhered to when juggling user-identities.

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

  • Y, the privileged identity of the application used to grant the requested service. This is the effective user identifier; returned by the function geteuid(2).

  • Z, the user under whose identity the service will be granted. This is the username returned by pam_get_user() and also stored in the Linux-PAM item, PAM_USER.

  • Linux-PAM has a place for an additional user identity that a module may care to make use of. This is the PAM_RUSER item. Generally, network sensitive modules/applications may wish to set/read this item to establish the identity of the user requesting a service from a remote location.

Note, if a module wishes to modify the identity of either the uid or euid of the running process, it should take care to restore the original values prior to returning control to the Linux-PAM library.

5.1.3. Using the conversation function

Prior to calling the conversation function, the module should reset the contents of the pointer that will return the applications response. This is a good idea since the application may fail to fill the pointer and the module should be in a position to notice!

The module should be prepared for a failure from the conversation. The generic error would be PAM_CONV_ERR, but anything other than PAM_SUCCESS should be treated as indicating failure.

5.1.4. Authentication tokens

To ensure that the authentication tokens are not left lying around the items, PAM_AUTHTOK and PAM_OLDAUTHTOK, are not available to the application: they are defined in <security/pam_modules.h>. This is ostensibly for security reasons, but a maliciously programmed application will always have access to all memory of the process, so it is only superficially enforced. As a general rule the module should overwrite authentication tokens as soon as they are no longer needed. Especially before free()'ing them. The Linux-PAM library is required to do this when either of these authentication token items are (re)set.

Not to dwell too little on this concern; should the module store the authentication tokens either as (automatic) function variables or using pam_[gs]et_data() the associated memory should be over-written explicitly before it is released. In the case of the latter storage mechanism, the associated cleanup() function should explicitly overwrite the *data before free()'ing it: for example,

/*
 * An example cleanup() function for releasing memory that was used to
 * store a password.
 */

int cleanup(pam_handle_t *pamh, void *data, int error_status)
{
    char *xx;

    if ((xx = data)) {
        while (*xx)
            *xx++ = '\0';
        free(data);
    }
    return PAM_SUCCESS;
}
          

PK/.1]S#html/adg-security-service-name.htmlnu[4.2. Choice of a service name

4.2. Choice of a service name

When picking the service-name that corresponds to the first entry in the Linux-PAM configuration file, the application programmer should avoid the temptation of choosing something related to argv[0]. It is a trivial matter for any user to invoke any application on a system under a different name and this should not be permitted to cause a security breach.

In general, this is always the right advice if the program is setuid, or otherwise more privileged than the user that invokes it. In some cases, avoiding this advice is convenient, but as an author of such an application, you should consider well the ways in which your program will be installed and used. (Its often the case that programs are not intended to be setuid, but end up being installed that way for convenience. If your program falls into this category, don't fall into the trap of making this mistake.)

To invoke some target application by another name, the user may symbolically link the target application with the desired name. To be precise all the user need do is, ln -s /target/application ./preferred_name and then run ./preferred_name.

By studying the Linux-PAM configuration file(s), an attacker can choose the preferred_name to be that of a service enjoying minimal protection; for example a game which uses Linux-PAM to restrict access to certain hours of the day. If the service-name were to be linked to the filename under which the service was invoked, it is clear that the user is effectively in the position of dictating which authentication scheme the service uses. Needless to say, this is not a secure situation.

The conclusion is that the application developer should carefully define the service-name of an application. The safest thing is to make it a single hard-wired name.

PK/.1](A++%html/mwg-expected-of-module-acct.htmlnu[3.3. Account management

3.3. Account management

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

3.3.1. Service function for account management

#define PAM_SM_ACCOUNT
#include <security/pam_modules.h>
int pam_sm_acct_mgmt(pamh,  
 flags,  
 argc,  
 argv); 
pam_handle_t *pamh;
int flags;
int argc;
const char **argv;
 

3.3.1.1. DESCRIPTION

The pam_sm_acct_mgmt function is the service module's implementation of the pam_acct_mgmt(3) interface.

This function performs the task of establishing whether the user is permitted to gain access at this time. It should be understood that the user has previously been validated by an authentication module. This function checks for other things. Such things might be: the time of day or the date, the terminal line, remote hostname, etc. This function may also determine things like the expiration on passwords, and respond that the user change it before continuing.

Valid flags, which may be logically OR'd with PAM_SILENT, are:

PAM_SILENT

Do not emit any messages.

PAM_DISALLOW_NULL_AUTHTOK

Return PAM_AUTH_ERR if the database of authentication tokens for this authentication mechanism has a NULL entry for the user.

3.3.1.2. RETURN VALUES

PAM_ACCT_EXPIRED

User account has expired.

PAM_AUTH_ERR

Authentication failure.

PAM_NEW_AUTHTOK_REQD

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

PAM_PERM_DENIED

Permission denied.

PAM_SUCCESS

The authentication token was successfully updated.

PAM_USER_UNKNOWN

User unknown to password service.

PK/.1]- - &html/adg-introduction-description.htmlnu[1.1. Description

1.1. Description

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 Linux-PAM library see the Linux-PAM System Administrators' Guide.

It is the purpose of the Linux-PAM project to liberate the development of privilege granting software from the development of secure and appropriate authentication schemes. This is accomplished by providing a documented library of functions that an application may use for all forms of user authentication management. This library dynamically loads locally configured authentication modules that actually perform the authentication tasks.

From the perspective of an application developer the information contained in the local configuration of the PAM library should not be important. Indeed it is intended that an application treat the functions documented here as a 'black box' that will deal with all aspects of user authentication. 'All aspects' includes user verification, account management, session initialization/termination and also the resetting of passwords (authentication tokens).

PK/.1]ԣ**%html/mwg-expected-of-module-auth.htmlnu[3.2. Authentication management

3.2. Authentication management

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

3.2.1. Service function for user authentication

#define PAM_SM_AUTH
#include <security/pam_modules.h>
int pam_sm_authenticate(pamh,  
 flags,  
 argc,  
 argv); 
pam_handle_t *pamh;
int flags;
int argc;
const char **argv;
 

3.2.1.1. DESCRIPTION

The pam_sm_authenticate function is the service module's implementation of the pam_authenticate(3) interface.

This function performs the task of authenticating the user.

Valid flags, which may be logically OR'd with PAM_SILENT, are:

PAM_SILENT

Do not emit any messages.

PAM_DISALLOW_NULL_AUTHTOK

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

3.2.1.2. RETURN VALUES

PAM_AUTH_ERR

Authentication failure.

PAM_CRED_INSUFFICIENT

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

PAM_AUTHINFO_UNAVAIL

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

PAM_SUCCESS

The authentication token was successfully updated.

PAM_USER_UNKNOWN

The supplied username is not known to the authentication service.

PAM_MAXTRIES

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

3.2.2. Service function to alter credentials

#define PAM_SM_AUTH
#include <security/pam_modules.h>
int pam_sm_setcred(pamh,  
 flags,  
 argc,  
 argv); 
pam_handle_t *pamh;
int flags;
int argc;
const char **argv;
 

3.2.2.1. DESCRIPTION

The pam_sm_setcred function is the service module's implementation of the pam_setcred(3) interface.

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 after the user has been authenticated but before a session has been established.

Valid flags, which may be logically OR'd with PAM_SILENT, are:

PAM_SILENT

Do not emit any messages.

PAM_ESTABLISH_CRED

Initialize the credentials for the user.

PAM_DELETE_CRED

Delete the credentials associated with the authentication service.

PAM_REINITIALIZE_CRED

Reinitialize the user credentials.

PAM_REFRESH_CRED

Extend the lifetime of the user credentials.

The way the auth stack is navigated in order to evaluate the pam_setcred() function call, independent of the pam_sm_setcred() return codes, is exactly the same way that it was navigated when evaluating the pam_authenticate() library call. Typically, if a stack entry was ignored in evaluating pam_authenticate(), it will be ignored when libpam evaluates the pam_setcred() function call. Otherwise, the return codes from each module specific pam_sm_setcred() call are treated as required.

3.2.2.2. RETURN VALUES

PAM_CRED_UNAVAIL

This module cannot retrieve the user's credentials.

PAM_CRED_EXPIRED

The user's credentials have expired.

PAM_CRED_ERR

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

PAM_SUCCESS

The user credential was successfully set.

PAM_USER_UNKNOWN

The user is not known to this authentication module.

These, non-PAM_SUCCESS, return values will typically lead to the credential stack failing. The first such error will dominate in the return value of pam_setcred().

PK/.1] html/adg-overview.htmlnu[Chapter 2. Overview

Chapter 2. Overview

Most service-giving applications are restricted. In other words, their service is not available to all and every prospective client. Instead, the applying client must jump through a number of hoops to convince the serving application that they are authorized to obtain service.

The process of authenticating a client is what PAM is designed to manage. In addition to authentication, PAM provides account management, credential management, session management and authentication-token (password changing) management services. It is important to realize when writing a PAM based application that these services are provided in a manner that is transparent to the application. That is to say, when the application is written, no assumptions can be made about how the client will be authenticated.

The process of authentication is performed by the PAM library via a call to pam_authenticate(). The return value of this function will indicate whether a named client (the user) has been authenticated. If the PAM library needs to prompt the user for any information, such as their name or a password then it will do so. If the PAM library is configured to authenticate the user using some silent protocol, it will do this too. (This latter case might be via some hardware interface for example.)

It is important to note that the application must leave all decisions about when to prompt the user at the discretion of the PAM library.

The PAM library, however, must work equally well for different styles of application. Some applications, like the familiar login and passwd are terminal based applications, exchanges of information with the client in these cases is as plain text messages. Graphically based applications, however, have a more sophisticated interface. They generally interact with the user via specially constructed dialogue boxes. Additionally, network based services require that text messages exchanged with the client are specially formatted for automated processing: one such example is ftpd which prefixes each exchanged message with a numeric identifier.

The presentation of simple requests to a client is thus something very dependent on the protocol that the serving application will use. In spite of the fact that PAM demands that it drives the whole authentication process, it is not possible to leave such protocol subtleties up to the PAM library. To overcome this potential problem, the application provides the PAM library with a conversation function. This function is called from within the PAM library and enables the PAM to directly interact with the client. The sorts of things that this conversation function must be able to do are prompt the user with text and/or obtain textual input from the user for processing by the PAM library. The details of this function are provided in a later section.

For example, the conversation function may be called by the PAM library with a request to prompt the user for a password. Its job is to reformat the prompt request into a form that the client will understand. In the case of ftpd, this might involve prefixing the string with the number 331 and sending the request over the network to a connected client. The conversation function will then obtain any reply and, after extracting the typed password, will return this string of text to the PAM library. Similar concerns need to be addressed in the case of an X-based graphical server.

There are a number of issues that need to be addressed when one is porting an existing application to become PAM compliant. A section below has been devoted to this: Porting legacy applications.

Besides authentication, PAM provides other forms of management. Session management is provided with calls to pam_open_session() and pam_close_session(). What these functions actually do is up to the local administrator. But typically, they could be used to log entry and exit from the system or for mounting and unmounting the user's home directory. If an application provides continuous service for a period of time, it should probably call these functions, first open after the user is authenticated and then close when the service is terminated.

Account management is another area that an application developer should include with a call to pam_acct_mgmt(). This call will perform checks on the good health of the user's account (has it expired etc.). One of the things this function may check is whether the user's authentication token has expired - in such a case the application may choose to attempt to update it with a call to pam_chauthtok(), although some applications are not suited to this task (ftp for example) and in this case the application should deny access to the user.

PAM is also capable of setting and deleting the user's credentials with the call pam_setcred(). This function should always be called after the user is authenticated and before service is offered to the user. By convention, this should be the last call to the PAM library before the PAM session is opened. What exactly a credential is, is not well defined. However, some examples are given in the glossary below.

PK/.1]/(* * $html/adg-security-conv-function.htmlnu[4.3. The conversation function

4.3. The conversation function

Care should be taken to ensure that the conv() function is robust. Such a function is provided in the library libpam_misc (see below).

PK/.1]m  html/mwg-see-programming.htmlnu[Chapter 5. Programming notes

Chapter 5. Programming notes

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

PK/.1]6#v6 6 )html/adg-interface-programming-notes.htmlnu[3.3. Programming notes

3.3. Programming notes

Note, all of the authentication service function calls accept the token PAM_SILENT, which instructs the modules to not send messages to the application. This token can be logically OR'd with any one of the permitted tokens specific to the individual function calls. PAM_SILENT does not override the prompting of the user for passwords etc., it only stops informative messages from being generated.

PK/.1]5G2html/mwg-example.htmlnu[Chapter 6. An example module

Chapter 6. An example module

At some point, we may include a fully commented example of a module in this document. For now, please look at the modules directory of the Linux-PAM sources.

PK/.1]d ^ ! !'html/adg-interface-of-app-expected.htmlnu[3.2. What is expected of an application

3.2. What is expected of an application

3.2.1. The conversation function

#include <security/pam_appl.h>
struct pam_message {
    int msg_style;
    const char *msg;
};

struct pam_response {
    char *resp;
    int resp_retcode;
};

struct pam_conv {
    int (*conv)(int num_msg, const struct pam_message **msg,
                struct pam_response **resp, void *appdata_ptr);
    void *appdata_ptr;
};
  

3.2.1.1. DESCRIPTION

The PAM library uses an application-defined callback to allow a direct communication between a loaded module and the application. This callback is specified by the struct pam_conv passed to pam_start(3) at the start of the transaction.

When a module calls the referenced conv() function, the argument appdata_ptr is set to the second element of this structure.

The other arguments of a call to conv() concern the information exchanged by module and application. That is to say, num_msg holds the length of the array of pointers, msg. After a successful return, the pointer resp points to an array of pam_response structures, holding the application supplied text. The resp_retcode member of this struct is unused and should be set to zero. It is the caller's responsibility to release both, this array and the responses themselves, using free(3). Note, *resp is a struct pam_response array and not an array of pointers.

The number of responses is always equal to the num_msg conversation function argument. This does require that the response array is free(3)'d after every call to the conversation function. The index of the responses corresponds directly to the prompt index in the pam_message array.

On failure, the conversation function should release any resources it has allocated, and return one of the predefined PAM error codes.

Each message can have one of four types, specified by the msg_style member of struct pam_message:

PAM_PROMPT_ECHO_OFF

Obtain a string without echoing any text.

PAM_PROMPT_ECHO_ON

Obtain a string whilst echoing text.

PAM_ERROR_MSG

Display an error message.

PAM_TEXT_INFO

Display some text.

The point of having an array of messages is that it becomes possible to pass a number of things to the application in a single call from the module. It can also be convenient for the application that related things come at once: a windows based application can then present a single form with many messages/prompts on at once.

In passing, it is worth noting that there is a descrepency between the way Linux-PAM handles the const struct pam_message **msg conversation function argument from the way that Solaris' PAM (and derivitives, known to include HP/UX, are there others?) does. Linux-PAM interprets the msg argument as entirely equivalent to the following prototype const struct pam_message *msg[] (which, in spirit, is consistent with the commonly used prototypes for argv argument to the familiar main() function: char **argv; and char *argv[]). Said another way Linux-PAM interprets the msg argument as a pointer to an array of num_msg read only 'struct pam_message' pointers. Solaris' PAM implementation interprets this argument as a pointer to a pointer to an array of num_msg pam_message structures. Fortunately, perhaps, for most module/application developers when num_msg has a value of one these two definitions are entirely equivalent. Unfortunately, casually raising this number to two has led to unanticipated compatibility problems.

For what its worth the two known module writer work-arounds for trying to maintain source level compatibility with both PAM implementations are:

  • never call the conversation function with num_msg greater than one.

  • set up msg as doubly referenced so both types of conversation function can find the messages. That is, make

           msg[n] = & (( *msg )[n])
           

3.2.1.2. RETURN VALUES

PAM_BUF_ERR

Memory buffer error.

PAM_CONV_ERR

Conversation failure. The application should not set *resp.

PAM_SUCCESS

Success.

PK/.1]v "html/mwg-see-programming-libs.htmlnu[5.3. Modules that require system libraries

5.3. Modules that require system libraries

Writing a module is much like writing an application. You have to provide the "conventional hooks" for it to work correctly, like pam_sm_authenticate() etc., which would correspond to the main() function in a normal function.

Typically, the author may want to link against some standard system libraries. As when one compiles a normal program, this can be done for modules too: you simply append the -lXXX arguments for the desired libraries when you create the shared module object. To make sure a module is linked to the libwhatever.so library when it is dlopen()ed, try:

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

PK/.1]-|] ] html/adg-libpam_misc.htmlnu[Chapter 5. A library of miscellaneous helper functions

Chapter 5. A library of miscellaneous helper functions

To aid the work of the application developer a library of miscellaneous functions is provided. It is called libpam_misc, and contains a text based conversation function, and routines for enhancing the standard PAM-environment variable support.

The functions, structures and macros, made available by this library can be defined by including <security/pam_misc.h>. It should be noted that this library is specific to Linux-PAM and is not referred to in the defining DCE-RFC (see See also) below.

PK/.1]I^X))*html/mwg-expected-of-module-chauthtok.htmlnu[3.5. Authentication token management

3.5. Authentication token management

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

3.5.1. Service function to alter authentication token

#define PAM_SM_PASSWORD
#include <security/pam_modules.h>
int pam_sm_chauthtok(pamh,  
 flags,  
 argc,  
 argv); 
pam_handle_t *pamh;
int flags;
int argc;
const char **argv;
 

3.5.1.1. DESCRIPTION

The pam_sm_chauthtok function is the service module's implementation of the pam_chauthtok(3) interface.

This function is used to (re-)set the authentication token of the user.

Valid flags, which may be logically OR'd with PAM_SILENT, are:

PAM_SILENT

Do not emit any messages.

PAM_CHANGE_EXPIRED_AUTHTOK

This argument indicates to the module that the user's authentication token (password) should only be changed if it has expired. This flag is optional and must be combined with one of the following two flags. Note, however, the following two options are mutually exclusive.

PAM_PRELIM_CHECK

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

If the control value sufficient is used in the password stack, the PAM_PRELIM_CHECK section of the modules following that control value is not always executed.

PAM_UPDATE_AUTHTOK

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

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

3.5.1.2. RETURN VALUES

PAM_AUTHTOK_ERR

The module was unable to obtain the new authentication token.

PAM_AUTHTOK_RECOVERY_ERR

The module was unable to obtain the old authentication token.

PAM_AUTHTOK_LOCK_BUSY

Cannot change the authentication token since it is currently locked.

PAM_AUTHTOK_DISABLE_AGING

Authentication token aging has been disabled.

PAM_PERM_DENIED

Permission denied.

PAM_TRY_AGAIN

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

PAM_SUCCESS

The authentication token was successfully updated.

PAM_USER_UNKNOWN

User unknown to password service.

PK/.1]&html/mwg-introduction-description.htmlnu[1.1. Description

1.1. Description

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 Linux-PAM library see the Linux-PAM System Administrators' Guide.

A Linux-PAM module is a single executable binary file that can be loaded by the Linux-PAM interface library. This PAM library is configured locally with a system file, /etc/pam.conf, to authenticate a user request via the locally available authentication modules. The modules themselves will usually be located in the directory /lib/security (or /lib64/security, depending on the architecture) and take the form of dynamically loadable object files (see dlopen(3). Alternatively, the modules can be statically linked into the Linux-PAM library; this is mostly to allow Linux-PAM to be used on platforms without dynamic linking available, but this is a deprecated functionality. It is the 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 Linux-PAM-module.

Except for the immediate purpose of interacting with the user (entering a password etc..) the module should never call the application directly. This exception requires a "conversation mechanism" which is documented below.

PK/.1]℃ $html/adg-security-library-calls.htmlnu[4.1. Care about standard library calls

4.1. Care about standard library calls

In general, writers of authorization-granting applications should assume that each module is likely to call any or all 'libc' functions. For 'libc' functions that return pointers to static/dynamically allocated structures (ie. the library allocates the memory and the user is not expected to 'free()' it) any module call to this function is likely to corrupt a pointer previously obtained by the application. The application programmer should either re-call such a 'libc' function after a call to the Linux-PAM library, or copy the structure contents to some safe area of memory before passing control to the Linux-PAM library.

Two important function classes that fall into this category are getpwnam(3) and syslog(3).

PK/.1]Ӓqhtml/mwg-see-also.htmlnu[Chapter 7. See also

Chapter 7. See also

  • The Linux-PAM System Administrators' Guide.

  • The Linux-PAM Application Developers' Guide.

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

PK/.1] px,44html/adg-libpam-functions.htmlnu[5.1. Functions supplied

5.1. Functions supplied

5.1.1. Text based conversation function

#include <security/pam_misc.h>
int misc_conv(num_msg,  
 msgm,  
 response,  
 appdata_ptr); 
int num_msg;
const struct pam_message **msgm;
struct pam_response **response;
void *appdata_ptr;
 

5.1.1.1. DESCRIPTION

The misc_conv function is part of libpam_misc and not of the standard libpam library. This function will prompt the user with the appropriate comments and obtain the appropriate inputs as directed by authentication modules.

In addition to simply slotting into the appropriate pam_conv(3), this function provides some time-out facilities. The function exports five variables that can be used by an application programmer to limit the amount of time this conversation function will spend waiting for the user to type something. The five variabls are as follows:

time_t pam_misc_conv_warn_time;

This variable contains the time (as returned by time(2)) that the user should be first warned that the clock is ticking. By default it has the value 0, which indicates that no such warning will be given. The application may set its value to sometime in the future, but this should be done prior to passing control to the Linux-PAM library.

const char *pam_misc_conv_warn_line;

Used in conjuction with pam_misc_conv_warn_time, this variable is a pointer to the string that will be displayed when it becomes time to warn the user that the timeout is approaching. Its default value is a translated version of ...Time is running out..., but this can be changed by the application prior to passing control to Linux-PAM.

time_t pam_misc_conv_die_time;

This variable contains the time (as returned by time(2)) that the will time out. By default it has the value 0, which indicates that the conversation function will not timeout. The application may set its value to sometime in the future, but this should be done prior to passing control to the Linux-PAM library.

const char *pam_misc_conv_die_line;

Used in conjuction with pam_misc_conv_die_time, this variable is a pointer to the string that will be displayed when the conversation times out. Its default value is a translated version of ...Sorry, your time is up!, but this can be changed by the application prior to passing control to Linux-PAM.

int pam_misc_conv_died;

Following a return from the Linux-PAM libraray, the value of this variable indicates whether the conversation has timed out. A value of 1 indicates the time-out occurred.

The following two function pointers are available for supporting binary prompts in the conversation function. They are optimized for the current incarnation of the libpamc library and are subject to change.

int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p);

This function pointer is initialized to NULL but can be filled with a function that provides machine-machine (hidden) message exchange. It is intended for use with hidden authentication protocols such as RSA or Diffie-Hellman key exchanges. (This is still under development.)

int (*pam_binary_handler_free)(void *appdata, pamc_bp_t *delete_me);

This function pointer is initialized to PAM_BP_RENEW(delete_me, 0, 0), but can be redefined as desired by the application.

5.1.2. Transcribing an environment to that of PAM

#include <security/pam_misc.h>
int pam_misc_paste_env(pamh,  
 user); 
pam_handle_t *pamh;
const char * const *user;
 

5.1.2.1. DESCRIPTION

This function takes the supplied list of environment pointers and uploads its contents to the PAM environment. Success is indicated by PAM_SUCCESS.

5.1.3. Liberating a locally saved environment

#include <security/pam_misc.h>
int pam_misc_drop_env(env); 
char **env;
 

5.1.3.1. DESCRIPTION

This function is defined to complement the pam_getenvlist(3) function. It liberates the memory associated with env, overwriting with 0 all memory before free()ing it.

5.1.4. BSD like PAM environment variable setting

#include <security/pam_misc.h>
int pam_misc_setenv(pamh,  
 name,  
 value,  
 readonly); 
pam_handle_t *pamh;
const char *name;
const char *value;
int readonly;
 

5.1.4.1. DESCRIPTION

This function performs a task equivalent to pam_putenv(3), its syntax is, however, more like the BSD style function; setenv(). The name and value are concatenated with an '=' to form a name=value and passed to pam_putenv(). If, however, the PAM variable is already set, the replacement will only be applied if the last argument, readonly, is zero.

PK/.1]cW0 html/mwg-expected-by-module.htmlnu[Chapter 2. What can be expected by the module PK/.1]bS html/adg-glossary.htmlnu[Chapter 7. Glossary of PAM related terms

Chapter 7. Glossary of PAM related terms

The following are a list of terms used within this document.

Authentication token

Generally, this is a password. However, a user can authenticate him/herself in a variety of ways. Updating the user's authentication token thus corresponds to refreshing the object they use to authenticate themself with the system. The word password is avoided to keep open the possibility that the authentication involves a retinal scan or other non-textual mode of challenge/response.

Credentials

Having successfully authenticated the user, PAM is able to establish certain characteristics/attributes of the user. These are termed credentials. Examples of which are group memberships to perform privileged tasks with, and tickets in the form of environment variables etc. . Some user-credentials, such as the user's UID and GID (plus default group memberships) are not deemed to be PAM-credentials. It is the responsibility of the application to grant these directly.

PK/.1]>?zhtml/adg-security.htmlnu[Chapter 4.  Security issues of Linux-PAM

Chapter 4.  Security issues of Linux-PAM

PAM, from the perspective of an application, is a convenient API for authenticating users. PAM modules generally have no increased privilege over that possessed by the application that is making use of it. For this reason, the application must take ultimate responsibility for protecting the environment in which PAM operates.

A poorly (or maliciously) written application can defeat any Linux-PAM module's authentication mechanisms by simply ignoring it's return values. It is the applications task and responsibility to grant privileges and access to services. The Linux-PAM library simply assumes the responsibility of authenticating the user; ascertaining that the user is who they say they are. Care should be taken to anticipate all of the documented behavior of the Linux-PAM library functions. A failure to do this will most certainly lead to a future security breach.

PK/.1]gΥ!!html/Linux-PAM_ADG.htmlnu[The Linux-PAM Application Developers' Guide

The Linux-PAM Application Developers' Guide

Andrew G. Morgan

Thorsten Kukuk

Version 1.1.2, 31. August 2010

Abstract

This manual documents what an application developer needs to know about the Linux-PAM library. It describes how an application might use the Linux-PAM library to authenticate users. In addition it contains a description of the functions to be found in libpam_misc library, that can be used in general applications. Finally, it contains some comments on PAM related security issues for the application developer.


PK/.1]z1'html/adg-interface-by-app-expected.htmlnu[3.1. What can be expected by the application

3.1. What can be expected by the application

3.1.1. Initialization of PAM transaction

#include <security/pam_appl.h>
int pam_start(service_name,  
 user,  
 pam_conversation,  
 pamh); 
const char *service_name;
const char *user;
const struct pam_conv *pam_conversation;
pam_handle_t **pamh;
 

3.1.1.1. DESCRIPTION

The pam_start function creates the PAM context and initiates the PAM transaction. It is the first of the PAM functions that needs to be called by an application. The transaction state is contained entirely within the structure identified by this handle, so it is possible to have multiple transactions in parallel. But it is not possible to use the same handle for different transactions, a new one is needed for every new context.

The service_name argument specifies the name of the service to apply and will be stored as PAM_SERVICE item in the new context. The policy for the service will be read from the file /etc/pam.d/service_name or, if that file does not exist, from /etc/pam.conf.

The user argument can specify the name of the target user and will be stored as PAM_USER item. If the argument is NULL, the module has to ask for this item if necessary.

The pam_conversation argument points to a struct pam_conv describing the conversation function to use. An application must provide this for direct communication between a loaded module and the application.

Following a successful return (PAM_SUCCESS) the contents of pamh is a handle that contains the PAM context for successive calls to the PAM functions. In an error case is the content of pamh undefined.

The pam_handle_t is a blind structure and the application should not attempt to probe it directly for information. Instead the PAM library provides the functions pam_set_item(3) and pam_get_item(3). The PAM handle cannot be used for mulitiple authentications at the same time as long as pam_end was not called on it before.

3.1.1.2. RETURN VALUES

PAM_ABORT

General failure.

PAM_BUF_ERR

Memory buffer error.

PAM_SUCCESS

Transaction was successful created.

PAM_SYSTEM_ERR

System error, for example a NULL pointer was submitted instead of a pointer to data.

3.1.2. Termination of PAM transaction

#include <security/pam_appl.h>
int pam_end(pamh,  
 pam_status); 
pam_handle_t *pamh;
int pam_status;
 

3.1.2.1. DESCRIPTION

The pam_end function terminates the PAM transaction and is the last function an application should call in the PAM context. Upon return the handle pamh is no longer valid and all memory associated with it will be invalid.

The pam_status argument should be set to the value returned to the application by the last PAM library call.

The value taken by pam_status is used as an argument to the module specific callback function, cleanup() (See pam_set_data(3) and pam_get_data(3)). In this way the module can be given notification of the pass/fail nature of the tear-down process, and perform any last minute tasks that are appropriate to the module before it is unlinked. This argument can be logically OR'd with PAM_DATA_SILENT to indicate to indicate that the module should not treat the call too seriously. It is generally used to indicate that the current closing of the library is in a fork(2)ed process, and that the parent will take care of cleaning up things that exist outside of the current process space (files etc.).

This function free's all memory for items associated with the pam_set_item(3) and pam_get_item(3) functions. Pointers associated with such objects are not valid anymore after pam_end was called.

3.1.2.2. RETURN VALUES

PAM_SUCCESS

Transaction was successful terminated.

PAM_SYSTEM_ERR

System error, for example a NULL pointer was submitted as PAM handle or the function was called by a module.

3.1.3. Setting PAM items

#include <security/pam_modules.h>
int pam_set_item(pamh,  
 item_type,  
 item); 
pam_handle_t *pamh;
int item_type;
const void *item;
 

3.1.3.1. DESCRIPTION

The pam_set_item function allows applications and PAM service modules to access and to update PAM informations of item_type. For this a copy of the object pointed to by the item argument is created. The following item_types are supported:

PAM_SERVICE

The service name (which identifies that PAM stack that the PAM functions will use to authenticate the program).

PAM_USER

The username of the entity under whose identity service will be given. That is, following authentication, PAM_USER identifies the local entity that gets to use the service. Note, this value can be mapped from something (eg., "anonymous") to something else (eg. "guest119") by any module in the PAM stack. As such an application should consult the value of PAM_USER after each call to a PAM function.

PAM_USER_PROMPT

The string used when prompting for a user's name. The default value for this string is a localized version of "login: ".

PAM_TTY

The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based, applications the value for this item should be the $DISPLAY variable.

PAM_RUSER

The requesting user name: local name for a locally requesting user or a remote user name for a remote requesting user.

Generally an application or module will attempt to supply the value that is most strongly authenticated (a local account before a remote one. The level of trust in this value is embodied in the actual authentication stack associated with the application, so it is ultimately at the discretion of the system administrator.

PAM_RUSER@PAM_RHOST should always identify the requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear who the requesting entity is.

PAM_RHOST

The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is requesting service). That is PAM_RUSER@PAM_RHOST does identify the requesting user. In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the authentication request is originating from.

PAM_AUTHTOK

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

PAM_OLDAUTHTOK

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

PAM_CONV

The pam_conv structure. See pam_conv(3).

The following additional items are specific to Linux-PAM and should not be used in portable applications:

PAM_FAIL_DELAY

A function pointer to redirect centrally managed failure delays. See pam_fail_delay(3).

PAM_XDISPLAY

The name of the X display. For graphical, X-based applications the value for this item should be the $DISPLAY variable. This value may be used independently of PAM_TTY for passing the name of the display.

PAM_XAUTHDATA

A pointer to a structure containing the X authentication data required to make a connection to the display specified by PAM_XDISPLAY, if such information is necessary. See pam_xauth_data(3).

PAM_AUTHTOK_TYPE

The default action is for the module to use the following prompts when requesting passwords: "New UNIX password: " and "Retype UNIX password: ". The example word UNIX can be replaced with this item, by default it is empty. This item is used by pam_get_authtok(3).

For all item_types, other than PAM_CONV and PAM_FAIL_DELAY, item is a pointer to a <NUL> terminated character string. In the case of PAM_CONV, item points to an initialized pam_conv structure. In the case of PAM_FAIL_DELAY, item is a function pointer: void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr)

Both, PAM_AUTHTOK and PAM_OLDAUTHTOK, will be reseted before returning to the application. Which means an application is not able to access the authentication tokens.

3.1.3.2. RETURN VALUES

PAM_BAD_ITEM

The application attempted to set an undefined or inaccessible item.

PAM_BUF_ERR

Memory buffer error.

PAM_SUCCESS

Data was successful updated.

PAM_SYSTEM_ERR

The pam_handle_t passed as first argument was invalid.

3.1.4. Getting PAM items

#include <security/pam_modules.h>
int pam_get_item(pamh,  
 item_type,  
 item); 
const pam_handle_t *pamh;
int item_type;
const void **item;
 

3.1.4.1. DESCRIPTION

The pam_get_item function allows applications and PAM service modules to access and retrieve PAM informations of item_type. Upon successful return, item contains a pointer to the value of the corresponding item. Note, this is a pointer to the actual data and should not be free()'ed or over-written! The following values are supported for item_type:

PAM_SERVICE

The service name (which identifies that PAM stack that the PAM functions will use to authenticate the program).

PAM_USER

The username of the entity under whose identity service will be given. That is, following authentication, PAM_USER identifies the local entity that gets to use the service. Note, this value can be mapped from something (eg., "anonymous") to something else (eg. "guest119") by any module in the PAM stack. As such an application should consult the value of PAM_USER after each call to a PAM function.

PAM_USER_PROMPT

The string used when prompting for a user's name. The default value for this string is a localized version of "login: ".

PAM_TTY

The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based, applications the value for this item should be the $DISPLAY variable.

PAM_RUSER

The requesting user name: local name for a locally requesting user or a remote user name for a remote requesting user.

Generally an application or module will attempt to supply the value that is most strongly authenticated (a local account before a remote one. The level of trust in this value is embodied in the actual authentication stack associated with the application, so it is ultimately at the discretion of the system administrator.

PAM_RUSER@PAM_RHOST should always identify the requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear who the requesting entity is.

PAM_RHOST

The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is requesting service). That is PAM_RUSER@PAM_RHOST does identify the requesting user. In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the authentication request is originating from.

PAM_AUTHTOK

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

PAM_OLDAUTHTOK

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

PAM_CONV

The pam_conv structure. See pam_conv(3).

The following additional items are specific to Linux-PAM and should not be used in portable applications:

PAM_FAIL_DELAY

A function pointer to redirect centrally managed failure delays. See pam_fail_delay(3).

PAM_XDISPLAY

The name of the X display. For graphical, X-based applications the value for this item should be the $DISPLAY variable. This value may be used independently of PAM_TTY for passing the name of the display.

PAM_XAUTHDATA

A pointer to a structure containing the X authentication data required to make a connection to the display specified by PAM_XDISPLAY, if such information is necessary. See pam_xauth_data(3).

PAM_AUTHTOK_TYPE

The default action is for the module to use the following prompts when requesting passwords: "New UNIX password: " and "Retype UNIX password: ". The example word UNIX can be replaced with this item, by default it is empty. This item is used by pam_get_authtok(3).

If a service module wishes to obtain the name of the user, it should not use this function, but instead perform a call to pam_get_user(3).

Only a service module is privileged to read the authentication tokens, PAM_AUTHTOK and PAM_OLDAUTHTOK.

3.1.4.2. RETURN VALUES

PAM_BAD_ITEM

The application attempted to set an undefined or inaccessible item.

PAM_BUF_ERR

Memory buffer error.

PAM_PERM_DENIED

The value of item was NULL.

PAM_SUCCESS

Data was successful updated.

PAM_SYSTEM_ERR

The pam_handle_t passed as first argument was invalid.

3.1.5. Strings describing PAM error codes

#include <security/pam_appl.h>
const char *pam_strerror(pamh,  
 errnum); 
pam_handle_t *pamh;
int errnum;
 

3.1.5.1. DESCRIPTION

The pam_strerror function returns a pointer to a string describing the error code passed in the argument errnum, possibly using the LC_MESSAGES part of the current locale to select the appropriate language. This string must not be modified by the application. No library function will modify this string.

3.1.5.2. RETURN VALUES

This function returns always a pointer to a string.

3.1.6. Request a delay on failure

#include <security/pam_appl.h>
int pam_fail_delay(pamh,  
 usec); 
pam_handle_t *pamh;
unsigned int usec;
 

3.1.6.1. DESCRIPTION

The pam_fail_delay function provides a mechanism by which an application or module can suggest a minimum delay of usec micro-seconds. The function keeps a record of the longest time requested with this function. Should pam_authenticate(3) fail, the failing return to the application is delayed by an amount of time randomly distributed (by up to 50%) about this longest value.

Independent of success, the delay time is reset to its zero default value when the PAM service module returns control to the application. The delay occurs after all authentication modules have been called, but before control is returned to the service application.

When using this function the programmer should check if it is available with:

#ifdef HAVE_PAM_FAIL_DELAY
    ....
#endif /* HAVE_PAM_FAIL_DELAY */
      

For applications written with a single thread that are event driven in nature, generating this delay may be undesirable. Instead, the application may want to register the delay in some other way. For example, in a single threaded server that serves multiple authentication requests from a single event loop, the application might want to simply mark a given connection as blocked until an application timer expires. For this reason the delay function can be changed with the PAM_FAIL_DELAY item. It can be queried and set with pam_get_item(3) and pam_set_item (3) respectively. The value used to set it should be a function pointer of the following prototype:

void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr);
      

The arguments being the retval return code of the module stack, the usec_delay micro-second delay that libpam is requesting and the appdata_ptr that the application has associated with the current pamh. This last value was set by the application when it called pam_start(3) or explicitly with pam_set_item(3). Note, if PAM_FAIL_DELAY item is unset (or set to NULL), then no delay will be performed.

3.1.6.2. RETURN VALUES

PAM_SUCCESS

Delay was successful adjusted.

PAM_SYSTEM_ERR

A NULL pointer was submitted as PAM handle.

3.1.7. Authenticating the user

#include <security/pam_appl.h>
int pam_authenticate(pamh,  
 flags); 
pam_handle_t *pamh;
int flags;
 

3.1.7.1. DESCRIPTION

The pam_authenticate function is used to authenticate the user. The user is required to provide an authentication token depending upon the authentication service, usually this is a password, but could also be a finger print.

The PAM service module may request that the user enter their username via the conversation mechanism (see pam_start(3) and pam_conv(3)). The name of the authenticated user will be present in the PAM item PAM_USER. This item may be recovered with a call to pam_get_item(3).

The pamh argument is an authentication handle obtained by a prior call to pam_start(). The flags argument is the binary or of zero or more of the following values:

PAM_SILENT

Do not emit any messages.

PAM_DISALLOW_NULL_AUTHTOK

The PAM module service should return PAM_AUTH_ERR if the user does not have a registered authentication token.

3.1.7.2. RETURN VALUES

PAM_ABORT

The application should exit immediately after calling pam_end(3) first.

PAM_AUTH_ERR

The user was not authenticated.

PAM_CRED_INSUFFICIENT

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

PAM_AUTHINFO_UNAVAIL

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

PAM_MAXTRIES

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

PAM_SUCCESS

The user was successfully authenticated.

PAM_USER_UNKNOWN

User unknown to authentication service.

3.1.8. Setting user credentials

#include <security/pam_appl.h>
int pam_setcred(pamh,  
 flags); 
pam_handle_t *pamh;
int flags;
 

3.1.8.1. DESCRIPTION

The pam_setcred function is used to establish, maintain and delete the credentials of a user. It should be called to set the credentials after a user has been authenticated and before a session is opened for the user (with pam_open_session(3)). The credentials should be deleted after the session has been closed (with pam_close_session(3)).

A credential is something that the user possesses. It is some property, such as a Kerberos ticket, or a supplementary group membership that make up the uniqueness of a given user. On a Linux system the user's UID and GID's are credentials too. However, it has been decided that these properties (along with the default supplementary groups of which the user is a member) are credentials that should be set directly by the application and not by PAM. Such credentials should be established, by the application, prior to a call to this function. For example, initgroups(2) (or equivalent) should have been performed.

Valid flags, any one of which, may be logically OR'd with PAM_SILENT, are:

PAM_ESTABLISH_CRED

Initialize the credentials for the user.

PAM_DELETE_CRED

Delete the user's credentials.

PAM_REINITIALIZE_CRED

Fully reinitialize the user's credentials.

PAM_REFRESH_CRED

Extend the lifetime of the existing credentials.

3.1.8.2. RETURN VALUES

PAM_BUF_ERR

Memory buffer error.

PAM_CRED_ERR

Failed to set user credentials.

PAM_CRED_EXPIRED

User credentials are expired.

PAM_CRED_UNAVAIL

Failed to retrieve user credentials.

PAM_SUCCESS

Data was successful stored.

PAM_SYSTEM_ERR

A NULL pointer was submitted as PAM handle, the function was called by a module or another system error occured.

PAM_USER_UNKNOWN

User is not known to an authentication module.

3.1.9. Account validation management

#include <security/pam_appl.h>
int pam_acct_mgmt(pamh,  
 flags); 
pam_handle_t *pamh;
int flags;
 

3.1.9.1. DESCRIPTION

The pam_acct_mgmt function is used to determine if the user's account is valid. It checks for authentication token and account expiration and verifies access restrictions. It is typically called after the user has been authenticated.

The pamh argument is an authentication handle obtained by a prior call to pam_start(). The flags argument is the binary or of zero or more of the following values:

PAM_SILENT

Do not emit any messages.

PAM_DISALLOW_NULL_AUTHTOK

The PAM module service should return PAM_NEW_AUTHTOK_REQD if the user has a null authentication token.

3.1.9.2. RETURN VALUES

PAM_ACCT_EXPIRED

User account has expired.

PAM_AUTH_ERR

Authentication failure.

PAM_NEW_AUTHTOK_REQD

The user account is valid but their authentication token is expired. The correct response to this return-value is to require that the user satisfies the pam_chauthtok() function before obtaining service. It may not be possible for some applications to do this. In such cases, the user should be denied access until such time as they can update their password.

PAM_PERM_DENIED

Permission denied.

PAM_SUCCESS

The authentication token was successfully updated.

PAM_USER_UNKNOWN

User unknown to password service.

3.1.10. Updating authentication tokens

#include <security/pam_appl.h>
int pam_chauthtok(pamh,  
 flags); 
pam_handle_t *pamh;
int flags;
 

3.1.10.1. DESCRIPTION

The pam_chauthtok function is used to change the authentication token for a given user (as indicated by the state associated with the handle pamh).

The pamh argument is an authentication handle obtained by a prior call to pam_start(). The flags argument is the binary or of zero or more of the following values:

PAM_SILENT

Do not emit any messages.

PAM_CHANGE_EXPIRED_AUTHTOK

This argument indicates to the modules that the user's authentication token (password) should only be changed if it has expired. If this argument is not passed, the application requires that all authentication tokens are to be changed.

3.1.10.2. RETURN VALUES

PAM_AUTHTOK_ERR

A module was unable to obtain the new authentication token.

PAM_AUTHTOK_RECOVERY_ERR

A module was unable to obtain the old authentication token.

PAM_AUTHTOK_LOCK_BUSY

One or more of the modules was unable to change the authentication token since it is currently locked.

PAM_AUTHTOK_DISABLE_AGING

Authentication token aging has been disabled for at least one of the modules.

PAM_PERM_DENIED

Permission denied.

PAM_SUCCESS

The authentication token was successfully updated.

PAM_TRY_AGAIN

Not all of the modules were in a position to update the authentication token(s). In such a case none of the user's authentication tokens are updated.

PAM_USER_UNKNOWN

User unknown to password service.

3.1.11. Start PAM session management

#include <security/pam_appl.h>
int pam_open_session(pamh,  
 flags); 
pam_handle_t *pamh;
int flags;
 

3.1.11.1. DESCRIPTION

The pam_open_session function sets up a user session for a previously successful authenticated user. The session should later be terminated with a call to pam_close_session(3).

It should be noted that the effective uid, geteuid(2). of the application should be of sufficient privilege to perform such tasks as creating or mounting the user's home directory for example.

The flags argument is the binary or of zero or more of the following values:

PAM_SILENT

Do not emit any messages.

3.1.11.2. RETURN VALUES

PAM_ABORT

General failure.

PAM_BUF_ERR

Memory buffer error.

PAM_SESSION_ERR

Session failure.

PAM_SUCCESS

Session was successful created.

3.1.12. terminating PAM session management

#include <security/pam_appl.h>
int pam_close_session(pamh,  
 flags); 
pam_handle_t *pamh;
int flags;
 

3.1.12.1. DESCRIPTION

The pam_close_session function is used to indicate that an authenticated session has ended. The session should have been created with a call to pam_open_session(3).

It should be noted that the effective uid, geteuid(2). of the application should be of sufficient privilege to perform such tasks as unmounting the user's home directory for example.

The flags argument is the binary or of zero or more of the following values:

PAM_SILENT

Do not emit any messages.

3.1.12.2. RETURN VALUES

PAM_ABORT

General failure.

PAM_BUF_ERR

Memory buffer error.

PAM_SESSION_ERR

Session failure.

PAM_SUCCESS

Session was successful terminated.

3.1.13. Set or change PAM environment variable

#include <security/pam_appl.h>
int pam_putenv(pamh,  
 name_value); 
pam_handle_t *pamh;
const char *name_value;
 

3.1.13.1. DESCRIPTION

The pam_putenv function is used to add or change the value of PAM environment variables as associated with the pamh handle.

The pamh argument is an authentication handle obtained by a prior call to pam_start(). The name_value argument is a single NUL terminated string of one of the following forms:

NAME=value of variable

In this case the environment variable of the given NAME is set to the indicated value: value of variable. If this variable is already known, it is overwritten. Otherwise it is added to the PAM environment.

NAME=

This function sets the variable to an empty value. It is listed separately to indicate that this is the correct way to achieve such a setting.

NAME

Without an '=' the pam_putenv() function will delete the corresponding variable from the PAM environment.

pam_putenv() operates on a copy of name_value, which means in contrast to putenv(3), the application is responsible to free the data.

3.1.13.2. RETURN VALUES

PAM_PERM_DENIED

Argument name_value given is a NULL pointer.

PAM_BAD_ITEM

Variable requested (for deletion) is not currently set.

PAM_ABORT

The pamh handle is corrupt.

PAM_BUF_ERR

Memory buffer error.

PAM_SUCCESS

The environment variable was successfully updated.

3.1.14. Get a PAM environment variable

#include <security/pam_appl.h>
const char *pam_getenv(pamh,  
 name); 
pam_handle_t *pamh;
const char *name;
 

3.1.14.1. DESCRIPTION

The pam_getenv function searches the PAM environment list as associated with the handle pamh for an item that matches the string pointed to by name and returns a pointer to the value of the environment variable. The application is not allowed to free the data.

3.1.14.2. RETURN VALUES

The pam_getenv function returns NULL on failure.

3.1.15. Getting the PAM environment

#include <security/pam_appl.h>
char **pam_getenvlist(pamh); 
pam_handle_t *pamh;
 

3.1.15.1. DESCRIPTION

The pam_getenvlist function returns a complete copy of the PAM environment as associated with the handle pamh. The PAM environment variables represent the contents of the regular environment variables of the authenticated user when service is granted.

The format of the memory is a malloc()'d array of char pointers, the last element of which is set to NULL. Each of the non-NULL entries in this array point to a NUL terminated and malloc()'d char string of the form: "name=value".

It should be noted that this memory will never be free()'d by libpam. Once obtained by a call to pam_getenvlist, it is the responsibility of the calling application to free() this memory.

It is by design, and not a coincidence, that the format and contents of the returned array matches that required for the third argument of the execle(3) function call.

3.1.15.2. RETURN VALUES

The pam_getenvlist function returns NULL on failure.

PK/.1]S{*((html/adg-copyright.htmlnu[Chapter 12. Copyright information for this document

Chapter 12. Copyright information for this document

Copyright (c) 2006 Thorsten Kukuk <kukuk@thkukuk.de>
Copyright (c) 1996-2002 Andrew G. Morgan <morgan@kernel.org>
    

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 (GPL), 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
    
PK/.1]ghtml/adg-introduction.htmlnu[Chapter 1. Introduction

Chapter 1. Introduction

PK/.1]7html/adg-see-also.htmlnu[Chapter 10. See also

Chapter 10. See also

  • The Linux-PAM System Administrators' Guide.

  • The Linux-PAM Module Writers' Guide.

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

PK/.1]yy%html/mwg-expected-by-module-item.htmlnu[2.1.  Getting and setting PAM_ITEMs and data

2.1.  Getting and setting PAM_ITEMs and data

First, we cover what the module should expect from the Linux-PAM library and a Linux-PAM aware application. Essentially this is the libpam.* library.

2.1.1. Set module internal data

#include <security/pam_modules.h>
int pam_set_data(pamh,  
 module_data_name,  
 data,  
 (*cleanup)(pam_handle_t *pamh, void *data, int error_status)); 
pam_handle_t *pamh;
const char *module_data_name;
void *data;
void (*cleanup)(pam_handle_t *pamh, void *data, int error_status);
 

2.1.1.1. DESCRIPTION

The pam_set_data function associates a pointer to an object with the (hopefully) unique string module_data_name in the PAM context specified by the pamh argument.

PAM modules may be dynamically loadable objects. In general such files should not contain static variables. This function and its counterpart pam_get_data(3), provide a mechanism for a module to associate some data with the handle pamh. Typically a module will call the pam_set_data function to register some data under a (hopefully) unique module_data_name. The data is available for use by other modules too but not by an application. Since this functions stores only a pointer to the data, the module should not modify or free the content of it.

The function cleanup() is associated with the data and, if non-NULL, it is called when this data is over-written or following a call to pam_end(3).

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

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

PAM_DATA_REPLACE

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

PAM_DATA_SILENT

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

2.1.1.2. RETURN VALUES

PAM_BUF_ERR

Memory buffer error.

PAM_SUCCESS

Data was successful stored.

PAM_SYSTEM_ERR

A NULL pointer was submitted as PAM handle or the function was called by an application.

2.1.2. Get module internal data

#include <security/pam_modules.h>
int pam_get_data(pamh,  
 module_data_name,  
 data); 
const pam_handle_t *pamh;
const char *module_data_name;
const void **data;
 

2.1.2.1. DESCRIPTION

This function together with the pam_set_data(3) function is useful to manage module-specific data meaningful only to the calling PAM module.

The pam_get_data function looks up the object associated with the (hopefully) unique string module_data_name in the PAM context specified by the pamh argument. A successful call to pam_get_data will result in data pointing to the object. Note, this data is not a copy and should be treated as constant by the module.

2.1.2.2. RETURN VALUES

PAM_SUCCESS

Data was successful retrieved.

PAM_SYSTEM_ERR

A NULL pointer was submitted as PAM handle or the function was called by an application.

PAM_NO_MODULE_DATA

Module data not found or there is an entry, but it has the value NULL.

2.1.3. Setting PAM items

#include <security/pam_modules.h>
int pam_set_item(pamh,  
 item_type,  
 item); 
pam_handle_t *pamh;
int item_type;
const void *item;
 

2.1.3.1. DESCRIPTION

The pam_set_item function allows applications and PAM service modules to access and to update PAM informations of item_type. For this a copy of the object pointed to by the item argument is created. The following item_types are supported:

PAM_SERVICE

The service name (which identifies that PAM stack that the PAM functions will use to authenticate the program).

PAM_USER

The username of the entity under whose identity service will be given. That is, following authentication, PAM_USER identifies the local entity that gets to use the service. Note, this value can be mapped from something (eg., "anonymous") to something else (eg. "guest119") by any module in the PAM stack. As such an application should consult the value of PAM_USER after each call to a PAM function.

PAM_USER_PROMPT

The string used when prompting for a user's name. The default value for this string is a localized version of "login: ".

PAM_TTY

The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based, applications the value for this item should be the $DISPLAY variable.

PAM_RUSER

The requesting user name: local name for a locally requesting user or a remote user name for a remote requesting user.

Generally an application or module will attempt to supply the value that is most strongly authenticated (a local account before a remote one. The level of trust in this value is embodied in the actual authentication stack associated with the application, so it is ultimately at the discretion of the system administrator.

PAM_RUSER@PAM_RHOST should always identify the requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear who the requesting entity is.

PAM_RHOST

The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is requesting service). That is PAM_RUSER@PAM_RHOST does identify the requesting user. In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the authentication request is originating from.

PAM_AUTHTOK

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

PAM_OLDAUTHTOK

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

PAM_CONV

The pam_conv structure. See pam_conv(3).

The following additional items are specific to Linux-PAM and should not be used in portable applications:

PAM_FAIL_DELAY

A function pointer to redirect centrally managed failure delays. See pam_fail_delay(3).

PAM_XDISPLAY

The name of the X display. For graphical, X-based applications the value for this item should be the $DISPLAY variable. This value may be used independently of PAM_TTY for passing the name of the display.

PAM_XAUTHDATA

A pointer to a structure containing the X authentication data required to make a connection to the display specified by PAM_XDISPLAY, if such information is necessary. See pam_xauth_data(3).

PAM_AUTHTOK_TYPE

The default action is for the module to use the following prompts when requesting passwords: "New UNIX password: " and "Retype UNIX password: ". The example word UNIX can be replaced with this item, by default it is empty. This item is used by pam_get_authtok(3).

For all item_types, other than PAM_CONV and PAM_FAIL_DELAY, item is a pointer to a <NUL> terminated character string. In the case of PAM_CONV, item points to an initialized pam_conv structure. In the case of PAM_FAIL_DELAY, item is a function pointer: void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr)

Both, PAM_AUTHTOK and PAM_OLDAUTHTOK, will be reseted before returning to the application. Which means an application is not able to access the authentication tokens.

2.1.3.2. RETURN VALUES

PAM_BAD_ITEM

The application attempted to set an undefined or inaccessible item.

PAM_BUF_ERR

Memory buffer error.

PAM_SUCCESS

Data was successful updated.

PAM_SYSTEM_ERR

The pam_handle_t passed as first argument was invalid.

2.1.4. Getting PAM items

#include <security/pam_modules.h>
int pam_get_item(pamh,  
 item_type,  
 item); 
const pam_handle_t *pamh;
int item_type;
const void **item;
 

2.1.4.1. DESCRIPTION

The pam_get_item function allows applications and PAM service modules to access and retrieve PAM informations of item_type. Upon successful return, item contains a pointer to the value of the corresponding item. Note, this is a pointer to the actual data and should not be free()'ed or over-written! The following values are supported for item_type:

PAM_SERVICE

The service name (which identifies that PAM stack that the PAM functions will use to authenticate the program).

PAM_USER

The username of the entity under whose identity service will be given. That is, following authentication, PAM_USER identifies the local entity that gets to use the service. Note, this value can be mapped from something (eg., "anonymous") to something else (eg. "guest119") by any module in the PAM stack. As such an application should consult the value of PAM_USER after each call to a PAM function.

PAM_USER_PROMPT

The string used when prompting for a user's name. The default value for this string is a localized version of "login: ".

PAM_TTY

The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based, applications the value for this item should be the $DISPLAY variable.

PAM_RUSER

The requesting user name: local name for a locally requesting user or a remote user name for a remote requesting user.

Generally an application or module will attempt to supply the value that is most strongly authenticated (a local account before a remote one. The level of trust in this value is embodied in the actual authentication stack associated with the application, so it is ultimately at the discretion of the system administrator.

PAM_RUSER@PAM_RHOST should always identify the requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear who the requesting entity is.

PAM_RHOST

The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is requesting service). That is PAM_RUSER@PAM_RHOST does identify the requesting user. In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the authentication request is originating from.

PAM_AUTHTOK

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

PAM_OLDAUTHTOK

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

PAM_CONV

The pam_conv structure. See pam_conv(3).

The following additional items are specific to Linux-PAM and should not be used in portable applications:

PAM_FAIL_DELAY

A function pointer to redirect centrally managed failure delays. See pam_fail_delay(3).

PAM_XDISPLAY

The name of the X display. For graphical, X-based applications the value for this item should be the $DISPLAY variable. This value may be used independently of PAM_TTY for passing the name of the display.

PAM_XAUTHDATA

A pointer to a structure containing the X authentication data required to make a connection to the display specified by PAM_XDISPLAY, if such information is necessary. See pam_xauth_data(3).

PAM_AUTHTOK_TYPE

The default action is for the module to use the following prompts when requesting passwords: "New UNIX password: " and "Retype UNIX password: ". The example word UNIX can be replaced with this item, by default it is empty. This item is used by pam_get_authtok(3).

If a service module wishes to obtain the name of the user, it should not use this function, but instead perform a call to pam_get_user(3).

Only a service module is privileged to read the authentication tokens, PAM_AUTHTOK and PAM_OLDAUTHTOK.

2.1.4.2. RETURN VALUES

PAM_BAD_ITEM

The application attempted to set an undefined or inaccessible item.

PAM_BUF_ERR

Memory buffer error.

PAM_PERM_DENIED

The value of item was NULL.

PAM_SUCCESS

Data was successful updated.

PAM_SYSTEM_ERR

The pam_handle_t passed as first argument was invalid.

2.1.5. Get user name

#include <security/pam_modules.h>
int pam_get_user(pamh,  
 user,  
 prompt); 
const pam_handle_t *pamh;
const char **user;
const char *prompt;
 

2.1.5.1. DESCRIPTION

The pam_get_user function returns the name of the user specified by pam_start(3). If no user was specified it returns what pam_get_item (pamh, PAM_USER, ... ); would have returned. If this is NULL it obtains the username via the pam_conv(3) mechanism, it prompts the user with the first non-NULL string in the following list:

  • The prompt argument passed to the function.

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

  • The default prompt: "login: "

By whatever means the username is obtained, a pointer to it is returned as the contents of *user. Note, this memory should not be free()'d or modified by the module.

This function sets the PAM_USER item associated with the pam_set_item(3) and pam_get_item(3) functions.

2.1.5.2. RETURN VALUES

PAM_SUCCESS

User name was successful retrieved.

PAM_SYSTEM_ERR

A NULL pointer was submitted.

PAM_CONV_ERR

The conversation method supplied by the application failed to obtain the username.

2.1.6. The conversation function

#include <security/pam_appl.h>
struct pam_message {
    int msg_style;
    const char *msg;
};

struct pam_response {
    char *resp;
    int resp_retcode;
};

struct pam_conv {
    int (*conv)(int num_msg, const struct pam_message **msg,
                struct pam_response **resp, void *appdata_ptr);
    void *appdata_ptr;
};
  

2.1.6.1. DESCRIPTION

The PAM library uses an application-defined callback to allow a direct communication between a loaded module and the application. This callback is specified by the struct pam_conv passed to pam_start(3) at the start of the transaction.

When a module calls the referenced conv() function, the argument appdata_ptr is set to the second element of this structure.

The other arguments of a call to conv() concern the information exchanged by module and application. That is to say, num_msg holds the length of the array of pointers, msg. After a successful return, the pointer resp points to an array of pam_response structures, holding the application supplied text. The resp_retcode member of this struct is unused and should be set to zero. It is the caller's responsibility to release both, this array and the responses themselves, using free(3). Note, *resp is a struct pam_response array and not an array of pointers.

The number of responses is always equal to the num_msg conversation function argument. This does require that the response array is free(3)'d after every call to the conversation function. The index of the responses corresponds directly to the prompt index in the pam_message array.

On failure, the conversation function should release any resources it has allocated, and return one of the predefined PAM error codes.

Each message can have one of four types, specified by the msg_style member of struct pam_message:

PAM_PROMPT_ECHO_OFF

Obtain a string without echoing any text.

PAM_PROMPT_ECHO_ON

Obtain a string whilst echoing text.

PAM_ERROR_MSG

Display an error message.

PAM_TEXT_INFO

Display some text.

The point of having an array of messages is that it becomes possible to pass a number of things to the application in a single call from the module. It can also be convenient for the application that related things come at once: a windows based application can then present a single form with many messages/prompts on at once.

In passing, it is worth noting that there is a descrepency between the way Linux-PAM handles the const struct pam_message **msg conversation function argument from the way that Solaris' PAM (and derivitives, known to include HP/UX, are there others?) does. Linux-PAM interprets the msg argument as entirely equivalent to the following prototype const struct pam_message *msg[] (which, in spirit, is consistent with the commonly used prototypes for argv argument to the familiar main() function: char **argv; and char *argv[]). Said another way Linux-PAM interprets the msg argument as a pointer to an array of num_msg read only 'struct pam_message' pointers. Solaris' PAM implementation interprets this argument as a pointer to a pointer to an array of num_msg pam_message structures. Fortunately, perhaps, for most module/application developers when num_msg has a value of one these two definitions are entirely equivalent. Unfortunately, casually raising this number to two has led to unanticipated compatibility problems.

For what its worth the two known module writer work-arounds for trying to maintain source level compatibility with both PAM implementations are:

  • never call the conversation function with num_msg greater than one.

  • set up msg as doubly referenced so both types of conversation function can find the messages. That is, make

           msg[n] = & (( *msg )[n])
           

2.1.6.2. RETURN VALUES

PAM_BUF_ERR

Memory buffer error.

PAM_CONV_ERR

Conversation failure. The application should not set *resp.

PAM_SUCCESS

Success.

2.1.7. Set or change PAM environment variable

#include <security/pam_appl.h>
int pam_putenv(pamh,  
 name_value); 
pam_handle_t *pamh;
const char *name_value;
 

2.1.7.1. DESCRIPTION

The pam_putenv function is used to add or change the value of PAM environment variables as associated with the pamh handle.

The pamh argument is an authentication handle obtained by a prior call to pam_start(). The name_value argument is a single NUL terminated string of one of the following forms:

NAME=value of variable

In this case the environment variable of the given NAME is set to the indicated value: value of variable. If this variable is already known, it is overwritten. Otherwise it is added to the PAM environment.

NAME=

This function sets the variable to an empty value. It is listed separately to indicate that this is the correct way to achieve such a setting.

NAME

Without an '=' the pam_putenv() function will delete the corresponding variable from the PAM environment.

pam_putenv() operates on a copy of name_value, which means in contrast to putenv(3), the application is responsible to free the data.

2.1.7.2. RETURN VALUES

PAM_PERM_DENIED

Argument name_value given is a NULL pointer.

PAM_BAD_ITEM

Variable requested (for deletion) is not currently set.

PAM_ABORT

The pamh handle is corrupt.

PAM_BUF_ERR

Memory buffer error.

PAM_SUCCESS

The environment variable was successfully updated.

2.1.8. Get a PAM environment variable

#include <security/pam_appl.h>
const char *pam_getenv(pamh,  
 name); 
pam_handle_t *pamh;
const char *name;
 

2.1.8.1. DESCRIPTION

The pam_getenv function searches the PAM environment list as associated with the handle pamh for an item that matches the string pointed to by name and returns a pointer to the value of the environment variable. The application is not allowed to free the data.

2.1.8.2. RETURN VALUES

The pam_getenv function returns NULL on failure.

2.1.9. Getting the PAM environment

#include <security/pam_appl.h>
char **pam_getenvlist(pamh); 
pam_handle_t *pamh;
 

2.1.9.1. DESCRIPTION

The pam_getenvlist function returns a complete copy of the PAM environment as associated with the handle pamh. The PAM environment variables represent the contents of the regular environment variables of the authenticated user when service is granted.

The format of the memory is a malloc()'d array of char pointers, the last element of which is set to NULL. Each of the non-NULL entries in this array point to a NUL terminated and malloc()'d char string of the form: "name=value".

It should be noted that this memory will never be free()'d by libpam. Once obtained by a call to pam_getenvlist, it is the responsibility of the calling application to free() this memory.

It is by design, and not a coincidence, that the format and contents of the returned array matches that required for the third argument of the execle(3) function call.

2.1.9.2. RETURN VALUES

The pam_getenvlist function returns NULL on failure.

PK/.1]"DEhtml/mwg-introduction.htmlnu[Chapter 1. Introduction

Chapter 1. Introduction

PK/.1]#ם html/mwg-see-options.htmlnu[Chapter 4. Generic optional arguments

Chapter 4. Generic optional arguments

Here we list the generic arguments that all modules can expect to be passed. They are not mandatory, and their absence should be accepted without comment by the module.

debug

Use the pam_syslog(3) call to log debugging information to the system log files.

use_first_pass

The module should not prompt the user for a password. Instead, it should obtain the previously typed password (by a call to pam_get_item() for the PAM_AUTHTOK item), and use that. If that doesn't work, then the user will not be authenticated. (This option is intended for auth and passwd modules only).

PK/.1]#html/mwg-introduction-synopsis.htmlnu[1.2. Synopsis

1.2. Synopsis

#include <security/pam_modules.h>

gcc -fPIC -c pam_module.c
gcc -shared -o pam_module.so pam_module.o -lpam
      
PK/.1]ha{ { #html/adg-introduction-synopsis.htmlnu[1.2. Synopsis

1.2. Synopsis

For general applications that wish to use the services provided by Linux-PAM the following is a summary of the relevant linking information:

#include <security/pam_appl.h>

cc -o application .... -lpam
        

In addition to libpam, there is a library of miscellaneous functions that make the job of writing PAM-aware applications easier (this library is not covered in the DCE-RFC for PAM and is specific to the Linux-PAM distribution):

#include <security/pam_appl.h>
#include <security/pam_misc.h>

cc -o application .... -lpam -lpam_misc
        

PK/.1]L4_l l  rfc86.0.txtnu[ Open Software Foundation V. Samar (SunSoft) Request For Comments: 86.0 R. Schemers (SunSoft) October 1995 UNIFIED LOGIN WITH PLUGGABLE AUTHENTICATION MODULES (PAM) 1. INTRODUCTION Since low-level authentication mechanisms constantly evolve, it is important to shield the high-level consumers of these mechanisms (system-entry services and users) from such low-level changes. With the Pluggable Authentication Module (PAM) framework, we can provide pluggability for a variety of system-entry services -- not just system authentication _per se_, but also for account, session and password management. PAM's ability to _stack_ authentication modules can be used to integrate `login' with different authentication mechanisms such as RSA, DCE, and Kerberos, and thus unify login mechanisms. The PAM framework can also provide easy integration of smart cards into the system. Modular design and pluggability have become important for users who want ease of use. In the PC hardware arena, no one wants to set the interrupt vector numbers or resolve the addressing conflict between various devices. In the software arena, people also want to be able to replace components easily for easy customization, maintenance, and upgrades. Authentication software deserves special attention because authentication forms a very critical component of any secure computer system. The authentication infrastructure and its components may have to be modified or replaced either because some deficiencies have been found in the current algorithms, or because sites want to enforce a different security policy than what was provided by the system vendor. The replacement and modification should be done in such a way that the user is not affected by these changes. The solution has to address not just how the applications use the new authentication mechanisms in a generic fashion, but also how the user will be authenticated to these mechanisms in a generic way. The former is addressed by GSS-API [Linn 93], while this RFC addresses the later; these two efforts are complementary to each other. Since most system-entry services (for example, `login', `dtlogin', `rlogin', `ftp', `rsh') may want to be independent of the specific authentication mechanisms used by the machine, it is important that there be a framework for _plugging_ in various mechanisms. This requires that the system applications use a standard API to interact Samar, Schemers Page 1 OSF-RFC 86.0 PAM October 1995 with the authentication services. If these system-entry services remain independent of the actual mechanism used on that machine, the system administrator can install suitable authentication modules without requiring changes to these applications. For any security system to be successful, it has to be easy to use. In the case of authentication, the single most important ease-of-use characteristic is that the user should not be required to learn about various ways of authentication and remember multiple passwords. Ideally, there should be one all-encompassing authentication system where there is only one password, but for heterogeneous sites, multiple authentication mechanisms have to co-exist. The problem of integrating multiple authentication mechanisms such as Kerberos [Steiner 88], RSA [Rivest 78], and Diffie-Hellman [Diffie 76, Taylor 88], is also referred to as _integrated login_, or _unified login_ problem. Even if the user has to use multiple authentication mechanisms, the user should not be forced to type multiple passwords. Furthermore, the user should be able to use the new network identity without taking any further actions. The key here is in modular integration of the network authentication technologies with `login' and other system-entry services. In this RFC we discuss the architecture and design of pluggable authentication modules. This design gives the capability to use field-replaceable authentication modules along with unified login capability. It thus provides for both _pluggability_ and _ease-of- use_. The RFC is organized as follows. We first motivate the need for a generic way to authenticate the user by various system-entry services within the operating system. We describe the goals and constraints of the design. This leads to the architecture, description of the interfaces, and _stacking_ of modules to get unified login functionality. We then describe our experience with the design, and end with a description of future work. 2. OVERVIEW OF IDENTIFICATION AND AUTHENTICATION MECHANISMS An identification and authentication ("I&A") mechanism is used to establish a user's identity the system (i.e., to a local machine's operating system) and to other principals on the network. On a typical UNIX system, there are various ports of entry into the system, such as `login', `dtlogin', `rlogin', `ftp', `rsh', `su', and `telnet'. In all cases, the user has to be identified and authenticated before granting appropriate access rights to the user. The user identification and authentication for all these entry points needs to be coordinated to ensure a secure system. In most of the current UNIX systems, the login mechanism is based upon verification of the password using the modified DES algorithm. Samar, Schemers Page 2 OSF-RFC 86.0 PAM October 1995 The security of the implementation assumes that the password cannot be guessed, and that the password does not go over the wire in the clear. These assumptions, however, are not universally valid. Various programs are now available freely on the Internet that can run dictionary attack against the encrypted password. Further, some of the network services (for example, `rlogin', `ftp', `telnet') send the password over in clear, and there are "sniffer" programs freely available to steal these passwords. The classical assumptions may be acceptable on a trusted network, but in an open environment there is a need to use more restrictive and stronger authentication mechanisms. Examples of such mechanisms include Kerberos, RSA, Diffie-Hellman, one-time password [Skey 94], and challenge-response based smart card authentication systems. Since this list will continue to evolve, it is important that the system-entry services do not have hard-coded dependencies on any of these authentication mechanisms. 3. DESIGN GOALS The goals of the PAM framework are as follows: (a) The system administrator should be able to choose the default authentication mechanism for the machine. This can range from a simple password-based mechanism to a biometric or a smart card based system. (b) It should be possible to configure the user authentication mechanism on a per application basis. For example, a site may require S/Key password authentication for `telnet' access, while allowing machine `login' sessions with just UNIX password authentication. (c) The framework should support the display requirements of the applications. For example, for a graphical login session such as `dtlogin', the user name and the password may have to be entered in a new window. For networking system-entry applications such as `ftp' and `telnet', the user name and password has to be transmitted over the network to the client machine. (d) It should be possible to configure multiple authentication protocols for each of those applications. For example, one may want the users to get authenticated by both Kerberos and RSA authentication systems. (e) The system administrator should be able to _stack_ multiple user authentication mechanisms such that the user is authenticated with all authentication protocols without retyping the password. Samar, Schemers Page 3 OSF-RFC 86.0 PAM October 1995 (f) The architecture should allow for multiple passwords if necessary to achieve higher security for users with specific security requirements. (g) The system-entry services should not be required to change when the underlying mechanism changes. This can be very useful for third-party developers because they often do not have the source code for these services. (h) The architecture should provide for a _pluggable_ model for system authentication, as well as for other related tasks such as password, account, and session management. (i) For backward-compatibility reasons, the PAM API should support the authentication requirements of the current system-entry services. There are certain issues that the PAM framework does not specifically address: (a) We focus only on providing a generic scheme through which users use passwords to establish their identities to the machine. Once the identity is established, how the identity is communicated to other interested parties is outside the scope of this design. There are efforts underway at IETF [Linn 93] to develop a Generic Security Services Application Interface (GSSAPI) that can be used by applications for secure and authenticated communication without knowing the underlying mechanism. (b) The _single-signon_ problem of securely transferring the identity of the caller to a remote site is not addressed. For example, the problem of delegating credentials from the `rlogin' client to the other machine without typing the password is not addressed by our work. We also do not address the problem of sending the passwords over the network in the clear. (c) We do not address the source of information obtained from the "`getXbyY()'" family of calls (e.g., `getpwnam()'). Different operating systems address this problem differently. For example, Solaris uses the name service switch (NSS) to determine the source of information for the "`getXbyY()'" calls. It is expected that data which is stored in multiple sources (such as passwd entries in NIS+ and the DCE registry) is kept in sync using the appropriate commands (such as `passwd_export'). Samar, Schemers Page 4 OSF-RFC 86.0 PAM October 1995 4. OVERVIEW OF THE PAM FRAMEWORK We propose that the goals listed above can be met through a framework in which authentication modules can be _plugged_ independently of the application. We call this the _Pluggable Authentication Modules_ (PAM) framework. The core components of the PAM framework are the authentication library API (the front end) and the authentication mechanism-specific modules (the back end), connected through the Service Provider Interface (SPI). Applications write to the PAM API, while the authentication-system providers write to the PAM SPI and supply the back end modules that are independent of the application. ftp telnet login (Applications) | | | | | | +--------+--------+ | +-----+-----+ | PAM API | <-- pam.conf file +-----+-----+ | +--------+--------+ UNIX Kerberos Smart Cards (Mechanisms) Figure 1: The Basic PAM Architecture Figure 1 illustrates the relationship between the application, the PAM library, and the authentication modules. Three applications (`login', `telnet' and `ftp') are shown which use the PAM authentication interfaces. When an application makes a call to the PAM API, it loads the appropriate authentication module as determined by the configuration file, `pam.conf'. The request is forwarded to the underlying authentication module (for example, UNIX password, Kerberos, smart cards) to perform the specified operation. The PAM layer then returns the response from the authentication module to the application. PAM unifies system authentication and access control for the system, and allows plugging of associated authentication modules through well defined interfaces. The plugging can be defined through various means, one of which uses a configuration file, such as the one in Table 1. For each of the system applications, the file specifies the authentication module that should be loaded. In the example below, `login' uses the UNIX password module, while `ftp' and `telnet' use the S/Key module. Samar, Schemers Page 5 OSF-RFC 86.0 PAM October 1995 Table 1: A Simplified View of a Sample PAM Configuration File. service module_path ------- ----------- login pam_unix.so ftp pam_skey.so telnet pam_skey.so Authentication configuration is only one aspect of this interface. Other critical components include account management, session management, and password management. For example, the `login' program may want to verify not only the password but also whether the account has aged or expired. Generic interfaces also need to be provided so that the password can be changed according to the requirements of the module. Furthermore, the application may want to log information about the current session as determined by the module. Not all applications or services may need all of the above components, and not each authentication module may need to provide support for all of the interfaces. For example, while `login' may need access to all four components, `su' may need access to just the authentication component. Some applications may use some specific authentication and password management modules but share the account and session management modules with others. This reasoning leads to a partitioning of the entire set of interfaces into four areas of functionality: (1) authentication, (2) account, (3) session, and (4) password. The concept of PAM was extended to these functional areas by implementing each of them as a separate pluggable module. Breaking the functionality into four modules helps the module providers because they can use the system-provided libraries for the modules that they are not changing. For example, if a supplier wants to provide a better version of Kerberos, they can just provide that new authentication and password module, and reuse the existing ones for account and session. 4.1. Module Description More details on specific API's are described in Appendix A. A brief description of four modules follows: (a) Authentication management: This set includes the `pam_authenticate()' function to authenticate the user, and the `pam_setcred()' interface to set, refresh or destroy the user credentials. (b) Account management: This set includes the `pam_acct_mgmt()' function to check whether the authenticated user should be Samar, Schemers Page 6 OSF-RFC 86.0 PAM October 1995 given access to his/her account. This function can implement account expiration and access hour restrictions. (c) Session management: This set includes the `pam_open_session()' and `pam_close_session()' functions for session management and accounting. For example, the system may want to store the total time for the session. (d) Password management: This set includes a function, `pam_chauthtok()', to change the password. 5. FRAMEWORK INTERFACES The PAM framework further provides a set of administrative interfaces to support the above modules and to provide for application-module communication. There is no corresponding service provider interface (SPI) for such functions. 5.1. Administrative Interfaces Each set of PAM transactions starts with `pam_start()' and ends with the `pam_end()' function. The interfaces `pam_get_item()' and `pam_set_item()' are used to read and write the state information associated with the PAM transaction. If there is any error with any of the PAM interfaces, the error message can be printed with `pam_strerror()'. 5.2. Application-Module Communication During application initialization, certain data such as the user name is saved in the PAM framework layer through `pam_start()' so that it can be used by the underlying modules. The application can also pass opaque data to the module which the modules will pass back while communicating with the user. 5.3. User-Module Communication The `pam_start()' function also passes conversation function that has to be used by the underlying modules to read and write module specific authentication information. For example, these functions can be used to prompt the user for the password in a way determined by the application. PAM can thus be used by graphical, non- graphical, or networked applications. Samar, Schemers Page 7 OSF-RFC 86.0 PAM October 1995 5.4. Inter-Module Communication Though the modules are independent, they can share certain common information about the authentication session such as user name, service name, password, and conversation function through the `pam_get_item()' and `pam_set_item()' interfaces. These API's can also be used by the application to change the state information after having called `pam_start()' once. 5.5. Module State Information The PAM service modules may want to keep certain module-specific state information about the session. The interfaces `pam_get_data()' and `pam_set_data()' can be used by the service modules to access and update module-specific information as needed from the PAM handle. The modules can also attach a cleanup function with the data. The cleanup function is executed when `pam_end()' is called to indicate the end of the current authentication activity. Since the PAM modules are loaded upon demand, there is no direct module initialization support in the PAM framework. If there are certain initialization tasks that the PAM service modules have to do, they should be done upon the first invocation. However, if there are certain clean-up tasks to be done when the authentication session ends, the modules should use `pam_set_data()' to specify the clean-up functions, which would be called when `pam_end()' is called by the application. 6. MODULE CONFIGURATION MANAGEMENT Table 2 shows an example of a configuration file `pam.conf' with support for authentication, session, account, and password management modules. `login' has three entries: one each for authentication processing, session management and account management. Each entry specifies the module name that should be loaded for the given module type. In this example, the `ftp' service uses the authentication and session modules. Note that all services here share the same session management module, while having different authentication modules. Samar, Schemers Page 8 OSF-RFC 86.0 PAM October 1995 Table 2: Configuration File (pam.conf) with Different Modules and Control Flow service module_type control_flag module_path options ------- ----------- ------------ ----------- ------- login auth required pam_unix_auth.so nowarn login session required pam_unix_session.so login account required pam_unix_account.so ftp auth required pam_skey_auth.so debug ftp session required pam_unix_session.so telnet session required pam_unix_session.so login password required pam_unix_passwd.so passwd password required pam_unix_passwd.so OTHER auth required pam_unix_auth.so OTHER session required pam_unix_session.so OTHER account required pam_unix_account.so The first field, _service_, denotes the service (for example, `login', `passwd', `rlogin'). The name `OTHER' indicates the module used by all other applications that have not been specified in this file. This name can also be used if all services have the same requirements. In the example, since all the services use the same session module, we could have replaced those lines with a single `OTHER' line. The second field, _module_type_, indicates the type of the PAM functional module. It can be one of `auth', `account', `session', or `password' modules. The third field, _control_flag_ determines the behavior of stacking multiple modules by specifying whether any particular module is _required_, _sufficient_, or _optional_. The next section describes stacking in more detail. The fourth field, _module_path_, specifies the location of the module. The PAM framework loads this module upon demand to invoke the required function. The fifth field, _options_, is used by the PAM framework layer to pass module specific options to the modules. It is up to the module to parse and interpret the options. This field can be used by the modules to turn on debugging or to pass any module specific parameters such as a timeout value. It is also used to support unified login as described below. The options field can be used by the system administrator to fine-tune the PAM modules. If any of the fields are invalid, or if a module is not found, that line is ignored and the error is logged as a critical error via `syslog(3)'. If no entries are found for the given module type, then the PAM framework returns an error to the application. Samar, Schemers Page 9 OSF-RFC 86.0 PAM October 1995 7. INTEGRATING MULTIPLE AUTHENTICATION SERVICES WITH STACKING In the world of heterogeneous systems, the system administrator often has to deal with the problem of integrating multiple authentication mechanisms. The user is often required to know about the authentication command of the new authentication module (for example, `kinit', `dce_login') after logging into the system. This is not user-friendly because it forces people to remember to type the new command and enter the new password. This functionality should be invisible instead of burdening the user with it. There are two problems to be addressed here: (a) Supporting multiple authentication mechanisms. (b) Providing unified login in the presence of multiple mechanisms. In the previous section, we described how one could replace the default authentication module with any other module of choice. Now we demonstrate how the same model can be extended to provide support for multiple modules. 7.1. Design for Stacked Modules One possibility was to provide hard-coded rules in `login' or other applications requiring authentication services [Adamson 95]. But this becomes very specific to the particular combination of authentication protocols, and also requires the source code of the application. Digital's Security Integration Architecture [SIA 95] addresses this problem by specifying the same list of authentication modules for all applications. Since requirements for various applications can vary, it is essential that the configuration be on a per-application basis. To support multiple authentication mechanisms, the PAM framework was extended to support _stacking_. When any API is called, the back ends for the stacked modules are invoked in the order listed, and the result returned to the caller. In Figure 2, the authentication service of `login' is stacked and the user is authenticated by UNIX, Kerberos, and RSA authentication mechanisms. Note that in this example, there is no stacking for session or account management modules. Samar, Schemers Page 10 OSF-RFC 86.0 PAM October 1995 login | +--------+--------+ | | | session auth account | | | +--+--+ +--+--+ +--+--+ | PAM | | PAM | | PAM | +--+--+ +--+--+ +--+--+ | | | UNIX UNIX UNIX session auth account | Kerberos auth | RSA auth Figure 2: Stacking With the PAM Architecture Stacking is specified through additional entries in the configuration file shown earlier. As shown in Table 2, for each application (such as `login') the configuration file can specify multiple mechanisms that have to be invoked in the specified order. When mechanisms fail, the _control_flag_ decides which error should be returned to the application. Since the user should not know which authentication module failed when a bad password was typed, the PAM framework continues to call other authentication modules on the stack even on failure. The semantics of the control flag are as follows: (a) `required': With this flag, the module failure results in the PAM framework returning the error to the caller _after_ executing all other modules on the stack. For the function to be able to return success to the application all `required' modules have to report success. This flag is normally set when authentication by this module is a _must_. (b) `optional': With this flag, the PAM framework ignores the module failure and continues with the processing of the next module in sequence. This flag is used when the user is allowed to login even if that particular module has failed. (c) `sufficient': With this flag, if the module succeeds the PAM framework returns success to the application immediately without trying any other modules. For failure cases, the _sufficient_ modules are treated as `optional'. Table 3 shows a sample configuration file that stacks the `login' command. Here the user is authenticated by UNIX, Kerberos, and RSA authentication services. The `required' key word for _control_flag_ Samar, Schemers Page 11 OSF-RFC 86.0 PAM October 1995 enforces that the user is allowed to login only if he/she is authenticated by _both_ UNIX and Kerberos services. RSA authentication is optional by virtue of the `optional' key word in the _control_flag_ field. The user can still log in even if RSA authentication fails. Table 3: PAM Configuration File with Support for Stacking service module_type control_flag module_path options ------- ----------- ------------ ----------- ------- login auth required pam_unix.so debug login auth required pam_kerb.so use_mapped_pass login auth optional pam_rsa.so use_first_pass Table 4 illustrates the use of the sufficient flag for the `rlogin' service. The Berkeley `rlogin' protocol specifies that if the remote host is trusted (as specified in the `/etc/hosts.equiv' file or in the `.rhosts' file in the home directory of the user), then the `rlogin' daemon should not require the user to type the password. If this is not the case, then the user is required to type the password. Instead of hard coding this policy in the `rlogin' daemon, this can be expressed with the `pam.conf' file in Table 4. The PAM module `pam_rhosts_auth.so.1' implements the `.rhosts' policy described above. If a site administrator wants to enable remote login with only passwords, then the first line should be deleted. Table 4: PAM Configuration File for the rlogin service service module_type control_flag module_path options ------- ----------- ------------ ----------- ------- rlogin auth sufficient pam_rhosts_auth.so rlogin auth required pam_unix.so 7.2. Password-Mapping Multiple authentication mechanisms on a machine can lead to multiple passwords that users have to remember. One attractive solution from the ease-of-use viewpoint is to use the same password for all mechanisms. This, however, can also weaken the security because if that password were to be compromised in any of the multiple mechanisms, all mechanisms would be compromised at the same time. Furthermore, different authentication mechanisms may have their own distinctive password requirements in regards to its length, allowed characters, time interval between updates, aging, locking, and so forth. These requirements make it problematic to use the same password for multiple authentication mechanisms. The solution we propose, while not precluding use of the same password for every mechanism, allows for a different password for each mechanism through what we call _password-mapping_. This basically means using the user's _primary_ password to encrypt the Samar, Schemers Page 12 OSF-RFC 86.0 PAM October 1995 user's other (_secondary_) passwords, and storing these encrypted passwords in a place where they are available to the user. Once the primary password is verified, the authentication modules would obtain the other passwords for their own mechanisms by decrypting the mechanism-specific encrypted password with the primary password, and passing it to the authentication service. The security of this design for password-mapping assumes that the primary password is the user's strongest password, in terms of its unguessability (length, type and mix of characters used, etc.). If there is any error in password-mapping, or if the mapping does not exist, the user will be prompted for the password by each authentication module. To support password-mapping, the PAM framework saves the primary password and provides it to stacked authentication modules. The password is cleared out before the `pam_authenticate' function returns. How the password is encrypted depends completely on the module implementation. The encrypted secondary password (also called a "mapped password") can be stored in a trusted or untrusted place, such as a smart card, a local file, or a directory service. If the encrypted passwords are stored in an untrusted publicly accessible place, this does provide an intruder with opportunities for potential dictionary attack. Though password-mapping is voluntary, it is recommended that all module providers add support for the following four mapping options: (a) `use_first_pass': Use the same password used by the first mechanism that asked for a password. The module should not ask for the password if the user cannot be authenticated by the first password. This option is normally used when the system administrator wants to enforce the same password across multiple modules. (b) `try_first_pass': This is the same as `use_first_pass', except that if the primary password is not valid, it should prompt the user for the password. (c) `use_mapped_pass': Use the password-mapping scheme to get the actual password for this module. One possible implementation is to get the mapped-password using the XFN API [XFN 94], and decrypt it with the primary password to get the module-specific password. The module should not ask for the password if the user cannot be authenticated by the first password. The XFN API allows user-defined attributes (such as _mapped-password_) to be stored in the _user-context_. Using the XFN API is particularly attractive because support for the XFN may be found on many systems in the future. Samar, Schemers Page 13 OSF-RFC 86.0 PAM October 1995 (d) `try_mapped_pass': This is the same as `use_mapped_pass', except that if the primary password is not valid, it should prompt the user for the password. When passwords get updated, the PAM framework stores both the old as well as the new password to be able to inform other dependent authentication modules about the change. Other modules can use this information to update the encrypted password without forcing the user to type the sequence of passwords again. The PAM framework clears out the passwords before returning to the application. Table 3 illustrates how the same password can be used by `login' for authenticating to the standard UNIX login, Kerberos and RSA services. Once the user has been authenticated to the primary authentication service (UNIX `login' in this example) with the primary password, the option `use_mapped_pass' indicates to the Kerberos module that it should use the primary password to decrypt the stored Kerberos password and then use the Kerberos password to get the ticket for the ticket-granting-service. After that succeeds, the option `use_first_pass' indicates to the RSA module that instead of prompting the user for a password, it should use the primary password typed earlier for authenticating the user. Note that in this scenario, the user has to enter the password just once. Note that if a one-time password scheme (e.g., S/Key) is used, password mapping cannot apply. 7.3. Implications of Stacking on the PAM Design Because of the stacking capability of PAM, we have designed the PAM API's to not return any data to the application, except status. If this were not the case, it would be difficult for the PAM framework to decide which module should return data to the application. When there is any error, the application does not know which of the modules failed. This behavior enables (even requires) the application to be completely independent from the modules. Another design decision we have made is that PAM gives only the user name to all the underlying PAM modules, hence it is the responsibility of the PAM modules to convert the name to their own internal format. For example, the Kerberos module may have to convert the UNIX user name to a Kerberos principal name. Stacking also forces the modules to be designed such that they can occur anywhere in the stack without any side-effects. Since modules such as the authentication and the password module are very closely related, it is important they be configured in the same order and with compatible options. Samar, Schemers Page 14 OSF-RFC 86.0 PAM October 1995 8. INTEGRATION WITH SMART CARDS Many networking authentication protocols require possession of a long key to establish the user identity. For ease-of-use reasons, that long key is normally encrypted with the user's password so that the user is not required to memorize it. However, weak passwords can be compromised through a dictionary attack and thus undermine the stronger network authentication mechanism. Furthermore, the encrypted data is normally stored in a centrally accessible service whose availability depends upon the reliability of the associated service. Solutions have been proposed to use a pass-phrase or one- time-password, but those are much longer than the regular eight character passwords traditionally used with UNIX `login'. This makes the solution user-unfriendly because it requires longer strings to be remembered and typed. For most authentication protocol implementations, the trust boundary is the local machine. This assumption may not be valid in cases where the user is mobile and has to use publicly available networked computers. In such cases, it is required that the clear text of the key or the password never be made available to the machine. Smart cards solve the above problems by reducing password exposure by supporting a _two factor_ authentication mechanism: the first with the possession of the card, and the second with the knowledge of the PIN associated with the card. Not only can the smart cards be a secure repository of multiple passwords, they can also provide the encryption and authentication functions such that the long (private) key is never exposed outside the card. The PAM framework allows for integrating smart cards to the system by providing a smart card specific module for authentication. Furthermore, the unified login problem is simplified because the multiple passwords for various authentication mechanisms can be stored on the smart card itself. This can be enabled by adding a suitable key-word such as `use_smart_card' in the _options_ field. 9. SECURITY ISSUES It is important to understand the impact of PAM on the security of any system so that the site-administrator can make an informed decision. (a) Sharing of passwords with multiple authentication mechanisms. If there are multiple authentication modules, one possibility is to use the same password for all of them. If the password for any of the multiple authentication system is compromised, the user's password in all systems would be compromised. If this is a concern, then multiple passwords might be considered Samar, Schemers Page 15 OSF-RFC 86.0 PAM October 1995 at the cost of ease-of-use. (b) Password-mapping. This technique of encrypting all other passwords with the primary password assumes that it is lot more difficult to crack the primary password and that reasonable steps have been taken to ensure limited availability of the encrypted primary password. If this is not done, an intruder could target the primary password as the first point of dictionary attack. If one of the other modules provide stronger security than the password based security, the site would be negating the strong security by using password-mapping. If this is a concern, then multiple passwords might be considered at the cost of ease-of- use. If smart cards are used, they obviate the need for password-mapping completely. (c) Security of the configuration file. Since the policy file dictates how the user is authenticated, this file should be protected from unauthorized modifications. (d) Stacking various PAM modules. The system administrator should fully understand the implications of stacking various modules that will be installed on the system and their respective orders and interactions. The composition of various authentication modules should be carefully examined. The trusted computing base of the machine now includes the PAM modules. 10. EXPERIENCE WITH PAM The PAM framework was first added in Solaris 2.3 release as a private internal interface. PAM is currently being used by several system entry applications such as `login', `passwd', `su', `dtlogin', `rlogind', `rshd', `telnetd', `ftpd', `in.rexecd', `uucpd', `init', `sac', and `ttymon'. We have found that PAM provides an excellent framework to encapsulate the authentication-related tasks for the entire system. The Solaris 2.3 PAM API's were hence enhanced and simplified to support stacking. PAM modules have been developed for UNIX, DCE, Kerberos, S/Key, remote user authentication, and dialpass authentication. Other PAM modules are under development, and integration with smart cards is being planned. Some third parties have used the PAM interface to extend the security mechanisms offered by the Solaris environment. Samar, Schemers Page 16 OSF-RFC 86.0 PAM October 1995 The PAM API has been accepted by Common Desktop Environment (CDE) vendors as the API to be used for integrating the graphical interface for login, `dtlogin' with multiple authentication mechanisms. 11. FUTURE WORK Amongst the various components of PAM, the password component needs to be carefully examined to see whether the stacking semantics are particularly applicable, and how PAM should deal with partial failures when changing passwords. The _control_flag_ of the configuration file can be extended to include other semantics. For example, if the error is "name service not available", one may want to retry. It is also possible to offer semantics of "return success if any of the modules return success". In an earlier section, we had mentioned integration of smart cards with PAM. Though we feel that integration should be straight forward from the PAM architecture point of view, there may be some issues with implementation because the interfaces to the smart cards have not yet been standardized. One possible extension to PAM is to allow the passing of module- specific data between applications and PAM modules. For example, the `login' program likes to build its new environment from a select list of variables, yet the DCE module needs the `KRB5CCNAME' variable to be exported to the child process. For now we have modified the `login' program to explicitly export the `KRB5CCNAME' variable. Administrative tools are needed to help system administrators modify `pam.conf', and perform sanity checks on it (i.e., a `pam_check' utility). 12. CONCLUSION The PAM framework and the module interfaces provide pluggability for user authentication, as well as for account, session and password management. The PAM architecture can be used by `login' and by all other system-entry services, and thus ensure that all entry points for the system have been secured. This architecture enables replacement and modification of authentication modules in the field to secure the system against the newly found weaknesses without changing any of the system services. The PAM framework can be used to integrate `login' and `dtlogin' with different authentication mechanisms such as RSA and Kerberos. Multiple authentication systems can be accessed with the same password. The PAM framework also provides easy integration of smart cards into the system. Samar, Schemers Page 17 OSF-RFC 86.0 PAM October 1995 PAM provides complementary functionality to GSS-API, in that it provides mechanisms through which the user gets authenticated to any new system-level authentication service on the machine. GSS-API then uses the credentials for authenticated and secure communications with other application-level service entities on the network. 13. ACKNOWLEDGEMENTS PAM development has spanned several release cycles at SunSoft. Shau-Ping Lo, Chuck Hickey, and Alex Choy did the first design and implementation. Bill Shannon and Don Stephenson helped with the PAM architecture. Rocky Wu prototyped stacking of multiple modules. Paul Fronberg, Charlie Lai, and Roland Schemers made very significant enhancements to the PAM interfaces and took the project to completion within a very short time. Kathy Slattery wrote the PAM documentation. John Perry integrated PAM within the CDE framework. APPENDIX A. PAM API'S This appendix gives an informal description of the various interfaces of PAM. Since the goal here is just for the reader to get a working knowledge about the PAM interfaces, not all flags and options have been fully defined and explained. The API's described here are subject to change. The PAM Service Provider Interface is very similar to the PAM API, except for one extra parameter to pass module-specific options to the underlying modules. A.1. Framework Layer API's int pam_start( char *service_name, char *user, struct pam_conv *pam_conversation, pam_handle_t **pamh ); `pam_start()' is called to initiate an authentication transaction. `pam_start()' takes as arguments the name of the service, the name of the user to be authenticated, the address of the conversation structure. `pamh' is later used as a handle for subsequent calls to the PAM library. The PAM modules do not communicate directly with the user; instead they rely on the application to perform all such interaction. The application needs to provide the conversation functions, `conv()', and associated application data pointers through a `pam_conv' Samar, Schemers Page 18 OSF-RFC 86.0 PAM October 1995 structure when it initiates an authentication transaction. The module uses the `conv()' function to prompt the user for data, display error messages, or text information. int pam_end( pam_handle_t *pamh, int pam_status ); `pam_end()' is called to terminate the PAM transaction as specified by `pamh', and to free any storage area allocated by the PAM modules with `pam_set_item()'. int pam_set_item( pam_handle_t *pamh, int item_type, void *item ); int pam_get_item( pam_handle_t *pamh, int item_type, void **item); `pam_get_item()' and `pam_set_item()' allow the parameters specified in the initial call to `pam_start()' to be read and updated. This is useful when a particular parameter is not available when `pam_start()' is called or must be modified after the initial call to `pam_start()'. `pam_set_item()' is passed a pointer to the object, `item', and its type, `item_type'. `pam_get_item()' is passed the address of the pointer, `item', which is assigned the address of the requested object. The `item_type' is one of the following: Table 5: Possible Values for Item_type Item Name Description --------- ----------- PAM_SERVICE The service name PAM_USER The user name PAM_TTY The tty name PAM_RHOST The remote host name PAM_CONV The pam_conv structure PAM_AUTHTOK The authentication token (password) PAM_OLDAUTHTOK The old authentication token PAM_RUSER The remote user name Samar, Schemers Page 19 OSF-RFC 86.0 PAM October 1995 Note that the values of `PAM_AUTHTOK' and `PAM_OLDAUTHTOK' are only available to PAM modules and not to the applications. They are explicitly cleared out by the framework before returning to the application. char * pam_strerror( int errnum ); `pam_strerror()' maps the error number to a PAM error message string, and returns a pointer to that string. int pam_set_data( pam_handle_t *pamh, char *module_data_name, char *data, (*cleanup)(pam_handle_t *pamh, char *data, int error_status) ); The `pam_set_data()' function stores module specific data within the PAM handle. The `module_data_name' uniquely specifies the name to which some data and cleanup callback function can be attached. The cleanup function is called when `pam_end()' is invoked. int pam_get_data( pam_handle_t *pamh, char *module_data_name, void **datap ); The `pam_get_data()' function obtains module-specific data from the PAM handle stored previously by the `pam_get_data()' function. The `module_data_name' uniquely specifies the name for which data has to be obtained. This function is normally used to retrieve module specific state information. A.2. Authentication API's int pam_authenticate( pam_handle_t *pamh, int flags ); The `pam_authenticate()' function is called to verify the identity of the current user. The user is usually required to enter a password or similar authentication token, depending upon the authentication Samar, Schemers Page 20 OSF-RFC 86.0 PAM October 1995 module configured with the system. The user in question is specified by a prior call to `pam_start()', and is referenced by the authentication handle, `pamh'. int pam_setcred( pam_handle_t *pamh, int flags ); The `pam_setcred()' function is called to set the credentials of the current process associated with the authentication handle, `pamh'. The actions that can be denoted through `flags' include credential initialization, refresh, reinitialization and deletion. A.3. Account Management API int pam_acct_mgmt( pam_handle_t *pamh, int flags ); The function `pam_acct_mgmt()' is called to determine whether the current user's account and password are valid. This typically includes checking for password and account expiration, valid login times, etc. The user in question is specified by a prior call to `pam_start()', and is referenced by the authentication handle, `pamh'. A.4. Session Management API's int pam_open_session( pam_handle_t *pamh, int flags ); `pam_open_session()' is called to inform the session modules that a new session has been initialized. All programs which use PAM should invoke `pam_open_session()' when beginning a new session. int pam_close_session( pam_handle_t *pamh, int flags ); Upon termination of this session, the `pam_close_session()' function should be invoked to inform the underlying modules that the session has terminated. Samar, Schemers Page 21 OSF-RFC 86.0 PAM October 1995 A.5. Password Management API's int pam_chauthtok( pam_handle_t *pamh, int flags ); `pam_chauthtok()' is called to change the authentication token associated with the user referenced by the authentication handle `pamh'. After the call, the authentication token of the user will be changed in accordance with the authentication module configured on the system. APPENDIX B. SAMPLE PAM APPLICATION This appendix shows a sample `login' application which uses the PAM API's. It is not meant to be a fully functional login program, as some functionality has been left out in order to emphasize the use of PAM API's. #include static int login_conv(int num_msg, struct pam_message **msg, struct pam_response **response, void *appdata_ptr); static struct pam_conv pam_conv = {login_conv, NULL}; static pam_handle_t *pamh; /* Authentication handle */ void main(int argc, char *argv[], char **renvp) { /* * Call pam_start to initiate a PAM authentication operation */ if ((pam_start("login", user_name, &pam_conv, &pamh)) != PAM_SUCCESS) login_exit(1); pam_set_item(pamh, PAM_TTY, ttyn); pam_set_item(pamh, PAM_RHOST, remote_host); while (!authenticated && retry < MAX_RETRIES) { status = pam_authenticate(pamh, 0); authenticated = (status == PAM_SUCCESS); } Samar, Schemers Page 22 OSF-RFC 86.0 PAM October 1995 if (status != PAM_SUCCESS) { fprintf(stderr,"error: %s\n", pam_strerror(status)); login_exit(1); } /* now check if the authenticated user is allowed to login. */ if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { if (status == PAM_AUTHTOK_EXPIRED) { status = pam_chauthtok(pamh, 0); if (status != PAM_SUCCESS) login_exit(1); } else { login_exit(1); } } /* * call pam_open_session to open the authenticated session * pam_close_session gets called by the process that * cleans up the utmp entry (i.e., init) */ if (status = pam_open_session(pamh, 0) != PAM_SUCCESS) { login_exit(status); } /* set up the process credentials */ setgid(pwd->pw_gid); /* * Initialize the supplementary group access list. * This should be done before pam_setcred because * the PAM modules might add groups during the pam_setcred call */ initgroups(user_name, pwd->pw_gid); status = pam_setcred(pamh, PAM_ESTABLISH_CRED); if (status != PAM_SUCCESS) { login_exit(status); } /* set the real (and effective) UID */ setuid(pwd->pw_uid); pam_end(pamh, PAM_SUCCESS); /* Done using PAM */ /* * Add DCE/Kerberos cred name, if any. * XXX - The module specific stuff should be removed from login * program eventually. This is better placed in DCE module and * will be once PAM has routines for "exporting" environment Samar, Schemers Page 23 OSF-RFC 86.0 PAM October 1995 * variables. */ krb5p = getenv("KRB5CCNAME"); if (krb5p != NULL) { ENVSTRNCAT(krb5ccname, krb5p); envinit[basicenv++] = krb5ccname; } environ = envinit; /* Switch to the new environment. */ exec_the_shell(); /* All done */ } /* * login_exit - Call exit() and terminate. * This function is here for PAM so cleanup can * be done before the process exits. */ static void login_exit(int exit_code) { if (pamh) pam_end(pamh, PAM_ABORT); exit(exit_code); /*NOTREACHED*/ } /* * login_conv(): * This is the conv (conversation) function called from * a PAM authentication module to print error messages * or garner information from the user. */ static int login_conv(int num_msg, struct pam_message **msg, struct pam_response **response, void *appdata_ptr) { while (num_msg--) { switch (m->msg_style) { case PAM_PROMPT_ECHO_OFF: r->resp = strdup(getpass(m->msg)); break; case PAM_PROMPT_ECHO_ON: (void) fputs(m->msg, stdout); r->resp = malloc(PAM_MAX_RESP_SIZE); fgets(r->resp, PAM_MAX_RESP_SIZE, stdin); /* add code here to remove \n from fputs */ Samar, Schemers Page 24 OSF-RFC 86.0 PAM October 1995 break; case PAM_ERROR_MSG: (void) fputs(m->msg, stderr); break; case PAM_TEXT_INFO: (void) fputs(m->msg, stdout); break; default: /* add code here to log error message, etc */ break; } } return (PAM_SUCCESS); } APPENDIX C. DCE MODULE This appendix describes a sample implementation of a DCE PAM module. In order to simplify the description, we do not address the issues raised by password-mapping or stacking. The intent is to show which DCE calls are being made by the DCE module. The `pam_sm_*()' functions implement the PAM SPI functions which are called from the PAM API functions. C.1. DCE Authentication Management The algorithm for authenticating with DCE (not including error checking, prompting for passwords, etc.) is as follows: pam_sm_authenticate() { sec_login_setup_identity(...); pam_set_data(...); sec_login_valid_and_cert_ident(...); } pam_sm_setcred() { pam_get_data(...); sec_login_set_context(...); } The `pam_sm_authenticate()' function for DCE uses the `pam_set_data()' and `pam_get_data()' functions to keep state (like the `sec_login_handle_t' context) between calls. The following cleanup function is also registered and gets called when `pam_end()' Samar, Schemers Page 25 OSF-RFC 86.0 PAM October 1995 is called: dce_cleanup() { if (/* PAM_SUCCESS and sec_login_valid_and_cert_ident success */) { sec_login_release_context(...); } else { sec_login_purge_context(...); } } If everything was successful we release the login context, but leave the credentials file intact. If the status passed to `pam_end()' was not `PAM_SUCCESS' (i.e., a required module failed) we purge the login context which also removes the credentials file. C.2. DCE Account Management The algorithm for DCE account management is as follows: pam_sm_acct_mgmt() { pam_get_data(...); sec_login_inquire_net_info(...); /* check for expired password and account */ sec_login_free_net_info(...); } The `sec_login_inquire_net_info()' function is called to obtain information about when the user's account and/or password are going to expire. A warning message is displayed (using the conversation function) if the user's account or password is going to expire in the near future, or has expired. These warning messages can be disabled using the `nowarn' option in the `pam.conf' file. C.3. DCE Session Management The DCE session management functions are currently empty. They could be modified to optionally remove the DCE credentials file upon logout, etc. C.4. DCE Password Management The algorithm for DCE password management is as follows: Samar, Schemers Page 26 OSF-RFC 86.0 PAM October 1995 pam_sm_chauthtok { sec_rgy_site_open(...); sec_rgy_acct_lookup(...); sec_rgy_acct_passwd(...); sec_rgy_site_close(...); } The `sec_rgy_acct_passwd()' function is called to change the user's password in the DCE registry. REFERENCES [Adamson 95] W. A. Adamson, J. Rees, and P. Honeyman, "Joining Security Realms: A Single Login for Netware and Kerberos", CITI Technical Report 95-1, Center for Information Technology Integration, University of Michigan, Ann Arbor, MI, February 1995. [Diffie 76] W. Diffie and M. E. Hellman, "New Directions in Cryptography", IEEE Transactions on Information Theory, November 1976. [Linn 93] J. Linn, "Generic Security Service Application Programming Interface", Internet RFC 1508, 1509, 1993. [Rivest 78] R. L. Rivest, A. Shamir, and L. Adleman., "A Method for Obtaining Digital Signatures and Pubic-key Cryptosystems", Communications of the ACM, 21(2), 1978. [SIA 95] "Digital UNIX Security", Digital Equipment Corporation, Order Number AA-Q0R2C-TE, July 1995. [Skey 94] N. M. Haller, "The S/Key One-Time Password System", ISOC Symposium on Network and Distributed Security, 1994. [Steiner 88] J.G. Steiner, B. C. Neuman, and J. I. Schiller, "Kerberos, An Authentication Service for Open Network Systems", in Proceedings of the Winter USENIX Conference, Dallas, Jan 1988. [Taylor 88] B. Taylor and D. Goldberg, "Secure Networking in the Sun Environment", Sun Microsystems Technical Paper, 1988. [XFN 94] "Federated Naming: the XFN Specifications", X/Open Preliminary Specification, X/Open Document #P403, ISBN:1-85912-045-8, X/Open Co. Ltd., July 1994. Samar, Schemers Page 27 OSF-RFC 86.0 PAM October 1995 AUTHOR'S ADDRESS Vipin Samar Internet email: vipin@eng.sun.com SunSoft, Inc. Telephone: +1-415-336-1002 2550 Garcia Avenue Mountain View, CA 94043 USA Roland J. Schemers III Internet email: schemers@eng.sun.com SunSoft, Inc. Telephone: +1-415-336-1035 2550 Garcia Avenue Mountain View, CA 94043 USA Samar, Schemers Page 28 PK/.1]F b?Linux-PAM_ADG.txtnu[PK/.1]7Linux-PAM_MWG.txtnu[PK/.1](W W html/adg-security-resources.htmlnu[PK/.1]$html/mwg-see-programming-syslog.htmlnu[PK/.1]ZM^html/adg-interface.htmlnu[PK/.1]~  @html/mwg-author.htmlnu[PK/.1]|Όc"c""html/Linux-PAM_MWG.htmlnu[PK/.1] E  1Ehtml/adg-author.htmlnu[PK/.1]~˺\\Qhtml/adg-example.htmlnu[PK/.1]G90`html/adg-files.htmlnu[PK/.1]޿%(2ihtml/mwg-expected-of-module-session.htmlnu[PK/.1]^T`html/adg-porting.htmlnu[PK/.1]Lwhtml/mwg-copyright.htmlnu[PK/.1]_Š &Ѥhtml/mwg-expected-by-module-other.htmlnu[PK/.1]A4f html/mwg-expected-of-module.htmlnu[PK/.1]%%)-html/mwg-expected-of-module-overview.htmlnu[PK/.1]c*$html/adg-security-user-identity.htmlnu[PK/.1]тA##!html/mwg-see-programming-sec.htmlnu[PK/.1]S#*html/adg-security-service-name.htmlnu[PK/.1](A++%<html/mwg-expected-of-module-acct.htmlnu[PK/.1]- - &Uhtml/adg-introduction-description.htmlnu[PK/.1]ԣ**%bhtml/mwg-expected-of-module-auth.htmlnu[PK/.1] Ǎhtml/adg-overview.htmlnu[PK/.1]/(* * $html/adg-security-conv-function.htmlnu[PK/.1]m  0html/mwg-see-programming.htmlnu[PK/.1]6#v6 6 )html/adg-interface-programming-notes.htmlnu[PK/.1]5G2html/mwg-example.htmlnu[PK/.1]d ^ ! !',html/adg-interface-of-app-expected.htmlnu[PK/.1]v "html/mwg-see-programming-libs.htmlnu[PK/.1]-|] ] html/adg-libpam_misc.htmlnu[PK/.1]I^X))*Khtml/mwg-expected-of-module-chauthtok.htmlnu[PK/.1]&1html/mwg-introduction-description.htmlnu[PK/.1]℃ $Ahtml/adg-security-library-calls.htmlnu[PK/.1]Ӓq~Nhtml/mwg-see-also.htmlnu[PK/.1] px,44{Whtml/adg-libpam-functions.htmlnu[PK/.1]cW0 Rhtml/mwg-expected-by-module.htmlnu[PK/.1]bS html/adg-glossary.htmlnu[PK/.1]>?zөhtml/adg-security.htmlnu[PK/.1]gΥ!! html/Linux-PAM_ADG.htmlnu[PK/.1]z1'html/adg-interface-by-app-expected.htmlnu[PK/.1]S{*((Thtml/adg-copyright.htmlnu[PK/.1]ghtml/adg-introduction.htmlnu[PK/.1]7html/adg-see-also.htmlnu[PK/.1]yy% html/mwg-expected-by-module-item.htmlnu[PK/.1]"DEפhtml/mwg-introduction.htmlnu[PK/.1]#ם html/mwg-see-options.htmlnu[PK/.1]#html/mwg-introduction-synopsis.htmlnu[PK/.1]ha{ { #Mhtml/adg-introduction-synopsis.htmlnu[PK/.1]L4_l l  rfc86.0.txtnu[PK11