Sunday, April 19, 2009

PAM - Pluggable Authentication Module

As part of my learning, going through this PAM ... I have used it before. But, It is much powerful that I had thought. Here it is ...



An Example :

Listing 1. Skeleton of Login Application

#include 
/* PAM definitions for applications */
#include

/* Linux-PAM specific application
helper library contains sample
text based conversation function. */
#include

/*
* 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);

}




Have you ever wondered how much work it would be to modify login to work the way you want it to? Perhaps you want it to refer to shadowed passwords or you don't want to let users log in during certain times of the day. Perhaps your policy is to ensure that root cannot log in anywhere other than at the console; maybe, root should never log in when the system is connected to the network. You might implement MD5-secured passwords, or passwords secured with RIPEMD-160 or SHA? Perhaps you have decided passwords are insufficiently secure for your needs, and instead you would like a user to insert their identity card in a slot to log in. Further, you would like to integrate your system into a network security environment like Kerberos; the primary login of a user would need to activate their identity with respect to the Kerberos server. The variations and combinations are endless. There is no perfect solution. There never will be.

Given sufficient incentive to implement a new user-authentication scheme, the traditional solution has been to amend, or rewrite, all of the system-access applications (login, su, passwd, ftp, xdm, ... )--this takes time and resources. An annoying by-product of such an upgrade is that modifying one application requires you to simultaneously upgrade other applications to maintain a consistent entry policy for your system. Unless you write the applications yourself, it is not easy to simply insert the code and be sure you have filled all the holes.

The revision of a system's security policy also suffers from the following potential weakness: people who write appealing user interfaces are not always paranoid enough to write secure software. This point relates to both access-oriented (login, etc.) and information-security (e-mail encryption, etc.) software.

Current thinking on computer-related security is to separate the security policy from the service offered by an application. This allows the author of a security-dependant application to use an application programming interface (API) to take care of the security-related issues and concentrate their efforts on writing a good (robust but user friendly) application.

An API is typically defined by a document describing a set of functions that an application programmer can rely on. For example, libc is an implementation of a number of APIs. Collaborative organizations, such as ANSI, POSIX or X/Open, produce a document defining the API and then vendors (or enthusiasts in the case of Linux) implement it. Security-related APIs exist for tasks like user authentication and data encryption.



Reference : http://www.linuxjournal.com/article/2120

No comments: