+Index: libtransmission/native-auth.c
+===================================================================
+--- libtransmission/native-auth.c (revision 0)
++++ libtransmission/native-auth.c (revision 0)
+@@ -0,0 +1,158 @@
++/******************************************************************************
++ * $Id:$
++ *
++ * Copyright (c) Transmission authors and contributors
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ *****************************************************************************/
++
++#include "native-auth.h"
++
++
++#if defined(HAVE_NATIVE_AUTH_ENABLED) && defined(linux)
++ #define NATIVE_AUTH_ENABLED 1
++
++ #include "transmission.h"
++ #include "utils.h"
++
++ #include <assert.h>
++ #include <string.h>
++
++ #include <security/pam_appl.h>
++#endif
++
++#if defined(NATIVE_AUTH_ENABLED)
++static struct pam_response *
++makePAMResponse( const char * data )
++{
++ struct pam_response * response = ( struct pam_response * )tr_malloc( sizeof( struct pam_response ) );
++ if ( !response )
++ {
++ tr_err( _("Cannot allocate memory for PAM response") );
++ return NULL;
++ }
++
++ response->resp_retcode = PAM_SUCCESS;
++ response->resp = strdup( data );
++
++ return response;
++}
++
++static int
++pamAuthConversation( int numMsg,
++ const struct pam_message ** messages,
++ struct pam_response ** responses,
++ void * data )
++{
++ int msgIndex;
++ bool errorOccurred = false;
++
++ assert( data );
++
++ *responses = (struct pam_response *)tr_malloc0( numMsg*sizeof( struct pam_response ) );
++ if ( !*responses )
++ {
++ return PAM_CONV_ERR;
++ }
++
++ for( msgIndex = 0; msgIndex < numMsg && !errorOccurred; ++msgIndex )
++ {
++ const struct pam_message * msg = *messages++;
++ switch( msg->msg_style )
++ {
++ case PAM_PROMPT_ECHO_OFF:
++ case PAM_PROMPT_ECHO_ON:
++ {
++ const char * password = (char *)data;
++ struct pam_response * response = makePAMResponse( password );
++
++ if ( !response )
++ errorOccurred = true;
++ else
++ responses[msgIndex] = response;
++
++ break;
++ }
++
++ case PAM_TEXT_INFO:
++ break;
++
++ default:
++ errorOccurred = true;
++ tr_err( _("Error while PAM conversation occurred") );
++ }
++ }
++
++ if( errorOccurred )
++ {
++ tr_free( *responses );
++ return PAM_CONV_ERR;
++ }
++
++ return PAM_SUCCESS;
++}
++
++static void
++performPAMAuthentication( const char * user, const char * password, bool * isSuccess )
++{
++ const char * PAM_AUTH_MODULE = "auth";
++ struct pam_conv pamConversation = { pamAuthConversation, (void *) password };
++ int pamError = 0;
++ pam_handle_t * pamHandle = NULL;
++
++ *isSuccess = false;
++
++ pamError = pam_start( PAM_AUTH_MODULE, user, &pamConversation, &pamHandle );
++ if ( PAM_SUCCESS != pamError )
++ {
++ tr_err( _( "Failed to start PAM session: %s" ), pam_strerror( pamHandle, pamError ) );
++ return;
++ }
++
++ pamError = pam_authenticate( pamHandle, PAM_SILENT );
++ if ( PAM_SUCCESS == pamError )
++ *isSuccess = true;
++ else
++ pamError = pam_end( pamHandle, /* last status */ 0 );
++
++ if ( PAM_SUCCESS != pamError )
++ {
++ tr_err( _( "Failed to close PAM session: %s" ), pam_strerror( pamHandle, pamError ) );
++ }
++}
++#endif
++
++void
++tr_performNativeAuthentication( const char * user, const char * password, tr_rpcNativeAuthenticationResult * result )
++{
++ bool isSuccessAuth = false;
++
++#ifdef HAVE_NATIVE_AUTH_ENABLED
++
++#if defined(linux)
++ performPAMAuthentication( user, password, &isSuccessAuth );
++#else
++ #warning Native user authentication for this platform is not supported yet.
++#endif
++
++#endif /* HAVE_NATIVE_AUTH_ENABLED */
++
++ *result = ( isSuccessAuth ) ? NATIVE_AUTHENTICATON_SUCCESS : NATIVE_AUTHENTICATON_FAIL;
++}
++