Linux DevCenter    
 Published on Linux DevCenter (http://www.linuxdevcenter.com/)
 See this if you're having trouble printing code examples


Writing PAM Modules, Part Three

by Jennifer Vesperman
05/30/2002

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.

Required Functions

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.

Account

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:

Authentication

User Validation

The 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:

Credential Setting

The 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_CRED
Delete the credentials associated with this authentication system.

PAM_ESTABLISH_CRED
Set the credentials associated with this authentication system.

PAM_REFRESH_CRED
Extend the credentials' life.

PAM_REINITIALIZE_CRED
Reinitialize the credentials for this authentication system.

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

Related Reading

Learning the Korn Shell
By Bill Rosenblatt, Arnold Robbins

If the module succeeds, it should return PAM_SUCCESS. Other valid responses are:

Password

This 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_AUTHTOK
User's authentication token should only be changed if it has expired.

PAM_PRELIM_CHECK
This verifies that the module is being asked for a readiness status, to ensure that the module is currently capable of updating the user's authentication token. If not, the module should return PAM_TRY_AGAIN.

PAM_UPDATE_AUTHTOK
The module should actually change the authentication token.

PAM_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:

Session

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.

Other Functions

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)

Response Codes

Applications need modules to return meaningful response codes.

Successes

PAM_SUCCESS
Everything went well, the module succeeded in its function, and (if appropriate) the user is who they say they are.

Failures

PAM_ABORT
Usually means the PAM handle has been corrupted.

PAM_ACCT_EXPIRED
The user's account is out of date and they may not access the system.

PAM_AUTH_ERR
Authentication error.

PAM_AUTHINFO_UNAVAIL
The module could not access the authentication information, perhaps due to hardware failure.

PAM_AUTHTOK_DISABLE_AGING
The module has had token aging disabled.

PAM_AUTHTOK_ERR
The module could not read the new authentication token.

PAM_AUTHTOK_LOCK_BUSY
The authentication token could not be changed because of a lock.

PAM_AUTHTOK_RECOVERY_ERR
The old authentication token could not be retrieved.

PAM_BAD_ITEM
A variable could not be set/deleted because it was undefined, inaccessible, or not currently set.

PAM_BUF_ERR
Memory allocation failure.

PAM_CRED_ERR
The module could not set the user's credentials.

PAM_CRED_EXPIRED
The user's credentials have expired.

PAM_CRED_INSUFFICIENT
The application is not permitted to authenticate the user, due to insufficient credentials.

PAM_CRED_UNAVAIL
The module cannot read the user's credentials.

PAM_IGNORE
The results of this module should be ignored.

PAM_MAXTRIES
The module has reached its maximum number of retries. Do not continue to attempt to authenticate this user.

PAM_NEW_AUTHTOK_REQD
The authentication token has expired, and should be renewed.

PAM_PERM_DENIED
Permission denied, or a required parameter was a NULL pointer.

PAM_SERVICE_ERR
This module cannot fulfil this type of request.

PAM_SYSTEM_ERR
Usually means an invalid PAM handle.

PAM_TRY_AGAIN
The module could not update the authentication token, therefore none of the tokens were updated.

PAM_USER_UNKNOWN
The module does not recognize the user.

Related Articles:

Writing PAM Modules, Part Two

Writing PAM Modules, Part One

Security Issues

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.

Final Words

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?

Further Reading

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.