/*
* (POP3Lite) pam - 3lite POP3 Daemon (pam authentication module)
* Copyright (C) 2000, 2001 Gergely Nagy <8@free.bsd.hu>
*
* This file is part of POP3Lite.
*
* POP3Lite is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* POP3Lite is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Based on authenticate.c (C) 1999 Jerzy Balamut <jurek@dione.ids.pl>
* (from the solid-pop3d sources)
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifndef PAM_SERVICE_NAME
# define PAM_SERVICE_NAME "pop3lite"
#endif /* ! PAM_SERVICE_NAME */
#include <pop3lite.h>
#include <stdlib.h>
#include <security/pam_appl.h>
#include <glib.h>
#include <syslog.h>
static const char rcsid[]="$Id: pam.c,v 1.6 2001/01/12 15:58:59 algernon Exp $";
static void freeresp ( int numresp, struct pam_response *resp );
static int pconv ( int num_msg, const struct pam_message **msg, struct
pam_response **result, void *appdata_ptr );
static int auth_checkpassword ( GHashTable *data, const char *ausername, const char *apassword );
static AuthResult pam_sys_authenticate ( P3LControl *control,
const char *user,
const char *pass );
int pam_LTX_module_init ( P3LControl *control );
int pam_LTX_module_done ( P3LControl *control );
static P3LSysCon_authenticate B_pam_sys_authenticate;
/**
* freeresp: free PAM response struct
* @numresp: number of responses
* @resp: the response struct
*
* Frees the struct
*
* Returns: nothing.
**/
static void
freeresp ( int numresp, struct pam_response *resp )
{
int respcount;
for ( respcount = 0; respcount < numresp; respcount++ )
if ( resp[respcount].resp != NULL )
g_free ( resp[respcount].resp );
g_free ( resp );
}
/**
* pconv: PAM conversation function
*
* See the PAM docs :)
**/
static int
pconv ( int num_msg, const struct pam_message **msg, struct
pam_response **result, void *appdata_ptr )
{
int account;
struct pam_response *resp;
/*
* Allocate memory
*/
resp = (struct pam_response *) g_malloc ( num_msg * sizeof ( struct pam_response ) );
if ( resp == NULL )
return PAM_CONV_ERR;
/*
* Do the conversation...
*/
for ( account = 0; account < num_msg; account++ )
switch ( msg[account]->msg_style )
{
case PAM_PROMPT_ECHO_OFF:
resp[account].resp =
(char *) g_strdup ( ((char **) appdata_ptr)[1] );
if ( resp[account].resp == NULL )
{
freeresp ( account, resp );
return PAM_CONV_ERR;
}
resp[account].resp_retcode = PAM_SUCCESS;
break;
case PAM_PROMPT_ECHO_ON:
resp[account].resp =
(char *) g_strdup ( ((char **) appdata_ptr)[0] );
if ( resp[account].resp == NULL )
{
freeresp ( account, resp );
return PAM_CONV_ERR;
}
resp[account].resp_retcode = PAM_SUCCESS;
break;
case PAM_TEXT_INFO:
case PAM_ERROR_MSG:
resp[account].resp_retcode = PAM_SUCCESS;
resp[account].resp = NULL;
break;
default:
freeresp ( account, resp );
return PAM_CONV_ERR;
}
*result = resp;
return PAM_SUCCESS;
}
/**
* auth_checkpassword: check the password
* @ausername: user name
* @password:
*
* Checks the validity of the username/password pair.
*
* Returns: PAM_SUCCESS on succes, PAM_* on failure
**/
static int
auth_checkpassword ( GHashTable *data,
const char *ausername,
const char *apassword )
{
pam_handle_t *pamhandle;
char *app_data[2];
struct pam_conv pamconv;
int result;
app_data[0] = g_strdup ( ausername );
app_data[1] = g_strdup ( apassword );
pamconv.conv = &pconv;
pamconv.appdata_ptr = app_data;
/*
* Start conversation...
*/
if ( ( result = pam_start ( SERVICE_NAME, ausername,
&pamconv, &pamhandle ) ) != PAM_SUCCESS )
return result;
g_hash_table_insert ( data, "PAM.HANDLE", (gpointer) pamhandle );
/*
* Do the actual authentication
*/
if ( ( result = pam_authenticate ( pamhandle, 0 ) ) != PAM_SUCCESS )
return result;
/*
* Account management: this checks for expired password
* and the like
*/
if ( ( result = pam_acct_mgmt ( pamhandle, 0 ) ) != PAM_SUCCESS )
return result;
/*
* Set credentials...
*/
if ( ( result = pam_setcred ( pamhandle, PAM_ESTABLISH_CRED ) ) != PAM_SUCCESS )
return result;
/*
* Open session
*/
if ( ( result = pam_open_session ( pamhandle, 0 ) ) != PAM_SUCCESS )
return result;
/*
* Return
*/
return PAM_SUCCESS;
}
/**
* pam_sys_authenticate: do user authentication
* @control: the control struct
* @name: username
* @pass: password
*
* Does the authentication via PAM.
*
* Returns: the result of the conversation
**/
static AuthResult
pam_sys_authenticate ( P3LControl *control,
const char *user,
const char *pass )
{
int result;
pam_handle_t *pamhandle;
#ifdef DEBUG
control->system->log ( control, LOG_DEBUG, "%s:%d: Authenticating user: %s",
__FILE__, __LINE__, user );
#endif
/*
* Do the authentication
*/
result = auth_checkpassword ( control->data, user, pass );
/*
* This is to clean up after PAM
*/
control->system->closelog ( control );
control->system->openlog ( control );
/*
* Check the results. If auth failed:
* (1) Fall back to the previous AUTH handler
* (2) Bail out (default)
*/
if ( result != PAM_SUCCESS )
{
pamhandle = (pam_handle_t *) g_hash_table_lookup ( control->data, "PAM.HANDLE" );
control->system->log ( control, LOG_WARNING, "PAM message: %s",
pam_strerror ( pamhandle, result ) );
g_hash_table_remove ( control->data, "PAM.HANDLE" );
pam_end ( pamhandle, result );
if ( B_pam_sys_authenticate != NULL &&
p3l_is_enabled ( P3L_GET_FIRST_OPTION ("PAM.FALLBACK" ) ) )
return (*B_pam_sys_authenticate) ( control, user, pass );
}
else
return AUTH_RESULT_OK;
return AUTH_RESULT_FAIL;
}
int
pam_LTX_module_init ( P3LControl *control )
{
#ifdef DEBUG
control->system->log ( control, LOG_DEBUG, "%s:%d: init mod-PAM",
__FILE__, __LINE__ );
#endif
B_pam_sys_authenticate = control->system->authenticate;
control->system->authenticate = pam_sys_authenticate;
return 0;
}
int
pam_LTX_module_done ( P3LControl *control )
{
pam_handle_t *pamhandle;
#ifdef DEBUG
control->system->log ( control, LOG_DEBUG, "%s:%d: done mod-PAM",
__FILE__, __LINE__ );
#endif
pamhandle = (pam_handle_t *)
g_hash_table_lookup ( control->data, "PAM.HANDLE" );
if ( pamhandle != NULL )
{
pam_end ( pamhandle, pam_close_session ( pamhandle, 0 ) );
/*
* This is to clean up after PAM
*/
control->system->closelog ( control );
control->system->openlog ( control );
}
control->system->authenticate = B_pam_sys_authenticate;
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1