PAM stands for Pluggable Authentication Modules and is a system for providing application independence for authentication. A PAM-enabled application calls a stack of PAM modules to run authentication, open and close sessions, and check account validity.
This is part three of a three-part series on writing PAM modules. Part one discussed the background information needed to write modules. Part two covered supporting code, including the conversation structure.
PAM modules are grouped into four module types, though there are six critical functions. Applications call each of the functions as they need them, but system administrators can only choose functions by their module type.
An application needs to completely fulfil the requirements for at least one of the module types. It should, but is not required to, respond to a request for the other module types with PAM_SERVICE_ERR or PAM_IGNORE.
The four types are: account, authentication, password, and session.
All of these functions have a flag parameter. The PAM_SILENT flag is valid for any function, and tells the module not to pass any text errors or warnings to the application. Flags may be logically ORed together.
This module type establishes whether the user can gain access at this time. The module should assume that the user has previously been authenticated. The module may verify whether or not a password has expired, and may return PAM_NEW_AUTHTOK_REQD if it has.
The flag PAM_DISALLOW_NULL_AUTHTOK tells the module to check whether or not there is a NULL authentication token in the token database. If so, return PAM_AUTH_ERR.
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv);
If the module succeeds, it should return PAM_SUCCESS. Other valid responses are:
PAM_ACCT_EXPIREDPAM_AUTH_ERRPAM_NEW_AUTHTOK_REQDPAM_USER_UNKNOWNThe first part of an authentication module is the actual user validation.
The flag PAM_DISALLOW_NULL_AUTHTOK tells the module to check whether or not there is a NULL authentication token in the token database. If so, return PAM_AUTH_ERR. Without this flag, the module can return PAM_SUCCESS in these cases without prompting the user for a token.
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv);
If the module succeeds, it should return PAM_SUCCESS. Other valid responses are:
PAM_AUTH_ERRPAM_AUTHINFO_UNAVAILPAM_CRED_INSUFFICIENTPAM_MAXTRIESPAM_USER_UNKNOWNThe second part of authentication is setting the user's credentials. Such credentials may be a Kerberos ticket, or Unix group membership. Only set credentials that are appropriate to the module you're writing.
Valid flags:
PAM_DELETE_CREDPAM_ESTABLISH_CREDPAM_REFRESH_CREDPAM_REINITIALIZE_CREDPAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv);
|
Related Reading
Learning the Korn Shell |
If the module succeeds, it should return PAM_SUCCESS. Other valid responses are:
PAM_CRED_ERRPAM_CRED_EXPIREDPAM_CRED_UNAVAILPAM_USER_UNKNOWNThis module type sets or resets the authentication token. Linux-PAM calls the module twice, once to verify that everything is ready and once to change the token itself.
Valid flags:
PAM_CHANGE_EXPIRED_AUTHTOKPAM_PRELIM_CHECKPAM_TRY_AGAIN.PAM_UPDATE_AUTHTOKPAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv);
If the module succeeds, it should return PAM_SUCCESS. Other valid responses are:
PAM_AUTHTOK_DISABLE_AGINGPAM_AUTHTOK_ERRPAM_AUTHTOK_LOCK_BUSYPAM_AUTHTOK_RECOVERY_ERRPAM_PERM_DENIEDPAM_TRY_AGAINPAM_USER_UNKNOWN
|
Initialise or terminate the session. This may entail tasks like writing log entries or cleaning up stored authentication tickets.
The close session function may be called by a different application than the one that opened the session, so data should be stored within the PAM system or in some non-volatile way.
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv);
PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv);
If the module succeeds, it should return PAM_SUCCESS. If it fails, it should return PAM_SESSION_ERR.
The pam_strerror function returns a human-readable string of text describing the error given in the parameter.
The pam_fail_delay function is used to suggest a delay time after a failed authentication attempt. Should pam_authenticate() fail, PAM delays returning control to the application by a randomized amount of time based on the longest delay time suggested in this PAM session. The application may also recommend a delay time.
extern const char *pam_strerror(pam_handle_t *pamh, int errnum);
extern int pam_fail_delay(pam_handle_t *pamh, unsigned int micro_sec)
Applications need modules to return meaningful response codes.
Successes
PAM_SUCCESSFailures
PAM_ABORTPAM_ACCT_EXPIREDPAM_AUTH_ERRPAM_AUTHINFO_UNAVAILPAM_AUTHTOK_DISABLE_AGINGPAM_AUTHTOK_ERRPAM_AUTHTOK_LOCK_BUSYPAM_AUTHTOK_RECOVERY_ERRPAM_BUF_ERRPAM_CRED_ERRPAM_CRED_EXPIREDPAM_CRED_INSUFFICIENTPAM_CRED_UNAVAILPAM_IGNOREPAM_MAXTRIESPAM_NEW_AUTHTOK_REQDPAM_PERM_DENIEDNULL pointer.PAM_SERVICE_ERRPAM_SYSTEM_ERRPAM_TRY_AGAINPAM_USER_UNKNOWN|
Related Articles: |
Authentication systems need to be securely coded. There are a few concerns mentioned here, and others in the Linux-PAM Module Developer's Guide. Read both of these, and also be careful to have someone who knows secure programming check your code before you release it to production use.
Be careful to authenticate the correct user. The username returned by pam_get_user() is the person who will be receiving the service. This is not necessarily the same as the getuid or geteuid user.
When receiving an authentication token, be sure to zero the data space once you no longer need it, and certainly before you free it.
Ensure that the conversation response is zeroed, or otherwise has predictable content that you can test to be sure the application has returned an actual response and you're not reading junk data.
Use syslog rather than user messages for most errors.
Ensure that your module tries to fail gracefully if it runs out of system resources.
Be aware of the programming issues for statically-linked programs. Many modules will be statically loaded in practice.
This is part three of a three part series on writing PAM modules. Start by writing small, useful modules that do one thing well. What do you wish your application would do when you start it?
Jennifer Vesperman is the author of Essential CVS. She writes for the O'Reilly Network, the Linux Documentation Project, and occasionally Linux.Com.
Return to the Linux DevCenter.
Copyright © 2009 O'Reilly Media, Inc.