Securing Applications on Linux with PAM

The basic concepts of PAM (Pluggable Authentication Module), developing a PAM-enabled application, a PAM authentication module and writing the PAM configuration file.
Provide the Conversation Function

The implementation of a basic conversation function is shown in Listing 1.

Listing 1. A Basic Conversion Function

The arguments of a call to the conversation function concern the information exchanged by the module and the application. That is, num_msg holds the length of the array of the pointer, msg. After a successful return, the pointer *resp points to an array of pam_response structures, holding the application-supplied text.

The message-passing structure (from the module to the application) is defined by security/pam_appl.h as:

struct pam_message {
    int msg_style;
    const char *msg;
};

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. Valid choices for msg_style are:

  • PAM_PROMPT_ECHO_OFF: obtains a string without echoing any text (e.g., password).

  • PAM_PROMPT_ECHO_ON: obtains a string while echoing text (e.g., user name).

  • PAM_ERROR_MSG: displays an error.

  • PAM_TEXT_INFO: displays some text.

The response-passing structure (from the application to the module) is defined by including security/pam_appl.h as:

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

Currently, there are no definitions for resp_retcode values; the normal value is 0.

Compiling and Linking

Compile the application using the following command:

gcc -o azapp azapp.c -lpam -L/usr/azlibs

The folder /usr/azlibs should be the one that typically contains the Linux-PAM library modules, which are libpam.so. This library file contains the definitions for the functions that were declared in pam_appl.h.

Developing the Pluggable Authentication Module (PAM)

When faced with the task of developing a module, we first need to be clear about the type of module we want to implement.

Modules may be grouped into four independent management types: authentication, account, session and password. To be properly defined, a module must define all functions within at least one of those four management groups.

Use the function pam_sm_authenticate() to implement an authentication module, which does the actual authentication. Then use pam_sm_setcred(). Generally, an authentication module may have access to more information about a user than their authentication token. This second 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.

For account management model implementation, pam_sm_acct_mgmt() is the function that performs the task of establishing whether the user is permitted to gain access at this time. The user needs to be previously validated by an authentication module before this step.

The session management module commences a session with a call to pam_sm_open_session().

When a session needs to be terminated, the pam_sm_close_session() function is called. It should be possible for sessions to be opened by one application and closed by another. This either requires that the module uses only information obtained from pam_get_item() or that information regarding the session is stored in some way by the operating system (in a file for example).

Finally, pam_sm_chauthtok() implements the password management module and is the function used to (re-)set the authentication token of the user (change the user password). The Linux-PAM library calls this function twice in succession. The authentication token is changed only in the second call, after it verifies that it matches the one previously entered.

In addition to these module functions, the PAM API also provides the following functions, which the module can invoke:

  • pam_set_item(): writes state information for the PAM session.

  • pam_get_item(): retrieves state information for the PAM session.

  • pam_strerror(): returns an error string.

The PAM API functions needed for module development are made available to the module via the security/pam_modules.h interface.

Putting Them Together

Now, let's develop a module that performs authentication management. For this we need to implement the functions in the authentication management group. Start by including the necessary headers. The header file security/pam_modules.h is the interface to the Linux-PAM library.

Next, authenticate the user; Listing 2 shows a basic implementation of the pam_sm_authenticate(). The purpose of this function is to prompt the application for a user name and password and then authenticate the user against the password encryption scheme.

Listin2. A Basic Implementation of pam_sm_authenticate()

Obtaining the user name is achieved via a call to pam_get_user(), if the application hasn't already supplied the password during a call to start_pam().

Once we get the user name, we need to prompt the user for his authentication token (in this case the password) by calling _read_password(). This method reads the user's password by interacting with the application-provided conversation function.

In _read_password() we first set the appropriate data in the pam_message struct array to be able to interact with the conversation function:

struct pam_message msg[3], *pmsg[3];
struct pam_response *resp;
int i, replies;
/* prepare to converse by setting appropriate */
/* data in the pam_message struct array */
pmsg[i] = &msg[i];
msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
msg[i++].msg = prompt1;
replies = 1;

Now call the conversation function expecting i responses from the conversation function:

retval = converse(pamh, ctrl, i, pmsg, &resp);
The converse() function basically is a front end for the module to the application-supplied conversation function.

Finally, a call to _verify_password(). The _verify_password() method essentially verifies the user's credentials according to the appropriate cryptographic scheme.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

getPassword function is incorrect

prashanth's picture

Hi
your getPassword function is incorrect

while((i = getch()) != '\n')
buf[i++] = i;
is incorrect

Very crisp and to the point.

Sunil's picture

Very crisp and to the point. Great work !

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState