/* * (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 * (from the solid-pop3d sources) */ #ifdef HAVE_CONFIG_H # include #endif #ifndef PAM_SERVICE_NAME # define PAM_SERVICE_NAME "pop3lite" #endif /* ! PAM_SERVICE_NAME */ #include #include #include #include #include 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; }