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);
}