Listing 1. Skeleton of Login Application

#include <stdio.h>
/* PAM definitions for applications  */
#include <security/pam_appl.h>

/* Linux-PAM specific application
   helper library contains sample
   text based conversation function. */
#include <security/pam_misc.h>

/*
 * static data for application
 */
/* PAM handle for continuity with library */
static pam_handle_t *pamh=NULL;
static struct pam_conv login_conversation = {
    /* example conversation function in
     * libpam_misc */
    misc_conv,
    /* trivial application specific data */
    NULL
};

/* this function is used to terminate the
 * application. */

static void Failed(int pam_error)
{
    /* textual error */
    fprintf(stderr,"Sorry: %s\n",
   pam_strerror(pam_error));
    if (NULL != pamh)
        /* shutdown PAM */
        pam_end(pamh, pam_error);
    /* exit with error */
    exit(1);
}

/*
 * login-type application
 */

void main()
{
    /* keep track of PAM errors */
    int retval;
    /* to refer to user's name */
    const char *username=NULL;
    /* PAM environment variable list */
    const char * const *environment=NULL;
    /* login function to initialize terminal etc
    */
    Login_Initialize();

    /*
     * Initialize libpam; library silently
     * consults /etc/pam.conf and loads
     * the appropriate authentication modules
     */

    retval = pam_start("login", username,
   &login_conversation, &pamh);
    if (NULL == pamh || PAM_SUCCESS != retval)
        /* something went wrong */
   Failed(retval);
    /* default prompt */
    pam_set_item(pamh, PAM_USER_PROMPT,
   "login: ");

    /*
     * attempt authentication until the modules
     * become exhausted or we succeed
     */

    do {
        /* delay for failures */
   pam_fail_delay(pamh, 1000000 /* usec */);
        /* require entered username */
   pam_set_item(pamh, PAM_USER, NULL);
        /* attempt to authenticate user */
   retval = pam_authenticate(pamh, 0);
   if (PAM_MAXTRIES == retval)
            /* the modules do not want login to
             * retry */
       Failed(retval);

    } while (PAM_SUCCESS != retval);

    /*
     * The user has been authenticated. Check if
     * they are allowed to login at this time with
     * the account management..
     */

    retval = pam_acct_mgmt(pamh, 0);
    switch (retval) {
    /* user's password(s) need renewing */
    case PAM_AUTHTOKEN_REQD:
   retval = pam_chauthtok(pamh,
      PAM_CHANGE_EXPIRED_AUTHTOK);
   if (PAM_SUCCESS == retval)
            /* password safely updated */
       break;
    default:
   Failed(retval);
    }

    /*
     * open a PAM session for the user
     */

    retval = pam_open_session(pamh, 0);

    /*
     * Establish the user's credentials
     */
    /* build the user's environment */
    pam_putenv(pamh, "SYSTEM=Linux");
    /* obtain username from PAM */
    pam_get_item(pamh, PAM_USER, &username);
    /* set login specific user identity
       (initgroups etc..) */
    Initialize_User(username);
    /* PAM specific credentials */
    pam_setcred(pamh, PAM_CRED_ESTABLISH);

    /*
     * invoke user shell and wait for it to
     * terminate */
    /* get environment from PAM */
    environment = pam_getenvlist(pamh);
    /* run interactive user shell */
    Do_User_Session(username, environment);

    /*
     * The user has finished interacting with the
     * system. Tidy up.
     */
    /* drop user credentials */
    pam_setcred(pamh, PAM_CRED_DELETE);
    /* close PAM session */
    pam_close_session(pamh, 0);
    /* close the library */
    pam_end(pamh, PAM_SUCCESS);
    /* to avoid potential confusion */
    pamh = NULL;
    /* exit successfully */
    exit(0);
}