oreilly.comSafari Books Online.Conferences.


Writing PAM-Capable Applications, Part Two
Pages: 1, 2

Setting Credentials

After the user is authenticated and the account is verified as currently usable, many authentication methods require the authenticator to set credentials. Credentials might be group membership in a Unix system, or a Kerberos ticket.

The application should call this function before the session is started.

extern int pam_setcred(pam_handle_t *pamh, int flags);


These functions open and close authenticated sessions. The close session function can be called from a different application, provided the application has the PAM handle.

extern int pam_open_session(pam_handle_t *pamh, int flags);
extern int pam_close_session(pam_handle_t *pamh, int flags);


pam_chauthtok changes authentication tokens, using the conversation function to interact with the user.

Calling this function with the flag PAM_CHANGE_EXPIRED_AUTHTOK will instruct it to only change the token if the token has actually expired. I recommend doing this if the call is triggered by the account module returning PAM_NEW_AUTHTOK_REQD.

This module type is usually called after the session is started, but it can be called immediately following account management, to refresh expired authentication tokens.

extern int pam_chauthtok(pam_handle_t *pamh, const int flags);


This function closes the PAM application. Call it when you no longer need the PAM handle, to allow the modules to be called and perform their cleanups -- freeing memory, wiping data structures clean, and disabling tokens.

The pam_status parameter indicates whether PAM was successful or not, which helps modules determine what cleanup has to be done. It can be useful to use one variable to receive the return value of all PAM calls, and bracket most PAM calls with if (retval == PAM_SUCCESS). You can then call pam_end with the return value as the pam_status argument.

extern int pam_end(pam_handle_t *pamh, int pam_status);

Failure Codes

All PAM functions return either PAM_SUCCESS or one of the following failure codes. It is worth noting that I have had PAM functions return failure codes not listed in the documentation.

The PAM function pam_strerror() displays the text string associated with each failure code.

extern const char *pam_strerror(pam_handle_t *pamh, int errnum);

Listed failure codes are:

Usually means the PAM handle has been corrupted.

The user's account is out-of-date and he or she may not access the system.

Authentication error.

One or more modules could not access the authentication information, perhaps due to hardware failure.

One or more modules has had token-aging disabled.

One or more modules could not read the new authentication token.

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

The old authentication token could not be retrieved.

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

Memory allocation failure.

One or more modules could not set the user's credentials.

The user's credentials have expired.

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

One or more modules cannot read the user's credentials.

One or more authentication modules has reached its maximum number of retries. Do not continue to attempt to authenticate this user.

The authentication token has expired and should be renewed.

This usually means permission denied, but sometimes means that a required parameter was a NULL pointer.

Usually means an invalid PAM handle.

One or more modules could not update the authentication token, therefore none of the tokens were updated.

The user is not known to one or more modules (of this type).

Additional Functions

This function is in <security/pam_misc.h>. Linux-PAM provides a function to securely duplicate strings. A copy of the parameter is returned. If there isn't enough memory to duplicate the string, a NULL is returned.

extern char *x_strdup(const char *s)

Default Configuration

In your application's installation script, check for a file with your service name in /etc/pam.d. If it doesn't exist, create one with an appropriate default PAM-authentication sequence for your program. You can find an acceptable default PAM configuration, with explanations, in /etc/pam.d/login in the default installation of many Linux systems. Another alternative is:

auth       requisite
auth       required
account    required
session    required
password   required retry=3 minlen=6 difok=3
password   required use_authtok nullok md5

If a file with your service name exists, you may have a service-name clash with another application, or the file may have been installed by a previous version of your application.

Caveats and Gotchas

  • DO read the Linux-PAM Application Developer's Guide.
  • DO code securely.
  • xstrdup in the documentation is x_strdup in the code (confirmed with Andrew Morgan).
  • PAM_AUTHTOKEN_REQD in the documentation seems to be PAM_NEW_AUTHTOK_REQD in the code.

Final Words

This article has touched on the most critical aspects of writing PAM-capable applications. For additional details, please do see the Application Developer's Guide.

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.

Linux Online Certification

Linux/Unix System Administration Certificate Series
Linux/Unix System Administration Certificate Series — This course series targets both beginning and intermediate Linux/Unix users who want to acquire advanced system administration skills, and to back those skills up with a Certificate from the University of Illinois Office of Continuing Education.

Enroll today!

Linux Resources
  • Linux Online
  • The Linux FAQ
  • Linux Kernel Archives
  • Kernel Traffic

  • Sponsored by: