--- /dev/null
+The patches to add PAM authentication support for Transmission torrent daemon.
+(c) Andrew Sichevoi, http://thekondor.net
+
+The patches are distributed in the terms of GNU GPL v3.0+ license.
+
+Applicable for trunk@13057.
+
+Please find more details here: http://blog.thekondor.net/2011/10/pam-authentication-for-transmission.html
+
--- /dev/null
+Index: cli/Makefile.am
+===================================================================
+--- cli/Makefile.am (revision 13057)
++++ cli/Makefile.am (working copy)
+@@ -23,6 +23,7 @@
+ @DHT_LIBS@ \
+ @LIBUTP_LIBS@ \
+ @LIBEVENT_LIBS@ \
++ @LIBPAM_LIBS@ \
+ @LIBCURL_LIBS@ \
+ @OPENSSL_LIBS@ \
+ @INTLLIBS@ \
--- /dev/null
+Index: configure.ac
+===================================================================
+--- configure.ac (revision 13057)
++++ configure.ac (working copy)
+@@ -311,6 +311,27 @@
+
+ dnl ----------------------------------------------------------------------------
+ dnl
++dnl native RPC authentication
++
++AC_ARG_ENABLE([native-rpc-auth],
++ AS_HELP_STRING([--enable-native-rpc-auth],[enable native user authentication for RPC]),
++ [enable_native_rpc_auth=yes])
++
++if test "x$enable_native_rpc_auth" == "xyes"; then
++ AC_CHECK_LIB([pam],[],
++ [AC_MSG_ERROR(PAM library not found!)])
++ AC_CHECK_HEADER([security/pam_appl.h],[],
++ [AC_MSG_ERROR(security/pam_appl.h not found!)])
++ AC_DEFINE([HAVE_NATIVE_AUTH_ENABLED], 1)
++ LIBPAM_CFLAGS=""
++ LIBPAM_LIBS="-lpam"
++fi
++ AC_SUBST(LIBPAM_CFLAGS)
++ AC_SUBST(LIBPAM_LIBS)
++
++
++dnl ----------------------------------------------------------------------------
++dnl
+ dnl detection for the GTK+ client
+
+
--- /dev/null
+Index: daemon/Makefile.am
+===================================================================
+--- daemon/Makefile.am (revision 13057)
++++ daemon/Makefile.am (working copy)
+@@ -25,6 +25,7 @@
+ @DHT_LIBS@ \
+ @LIBUTP_LIBS@ \
+ @LIBEVENT_LIBS@ \
++ @LIBPAM_LIBS@ \
+ @LIBCURL_LIBS@ \
+ @OPENSSL_LIBS@ \
+ @INTLLIBS@ \
--- /dev/null
+Index: gtk/Makefile.am
+===================================================================
+--- gtk/Makefile.am (revision 13057)
++++ gtk/Makefile.am (working copy)
+@@ -91,6 +91,7 @@
+ @GTK_LIBS@ \
+ @LIBAPPINDICATOR_LIBS@ \
+ @LIBEVENT_LIBS@ \
++ @LIBPAM_LIBS@ \
+ @LIBCURL_LIBS@ \
+ @OPENSSL_LIBS@ \
+ @ZLIB_LIBS@ \
--- /dev/null
+Index: libtransmission/Makefile.am
+===================================================================
+--- libtransmission/Makefile.am (revision 13057)
++++ libtransmission/Makefile.am (working copy)
+@@ -40,6 +40,7 @@
+ magnet.c \
+ makemeta.c \
+ metainfo.c \
++ native-auth.c \
+ natpmp.c \
+ net.c \
+ peer-io.c \
+@@ -91,6 +92,7 @@
+ magnet.h \
+ makemeta.h \
+ metainfo.h \
++ native-auth.h \
+ natpmp.h \
+ net.h \
+ peer-common.h \
+@@ -145,6 +147,7 @@
+ @INTLLIBS@ \
+ @DHT_LIBS@ \
+ @LIBUTP_LIBS@ \
++ @LIBPAM_LIBS@ \
+ @LIBCURL_LIBS@ \
+ @LIBEVENT_LIBS@ \
+ @OPENSSL_LIBS@ \
--- /dev/null
+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;
++}
++
--- /dev/null
+Index: libtransmission/native-auth.h
+===================================================================
+--- libtransmission/native-auth.h (revision 0)
++++ libtransmission/native-auth.h (revision 0)
+@@ -0,0 +1,43 @@
++/******************************************************************************
++ * $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.
++ *****************************************************************************/
++
++#ifndef __TRANSMISSION__
++ #error only libtransmission should #include this header.
++#endif
++
++#ifndef TR_NATIVE_AUTH_H
++#define TR_NATIVE_AUTH_H 1
++
++enum _tr_rpcNativeAuthenticationResult
++{
++ NATIVE_AUTHENTICATON_FAIL = 0,
++ NATIVE_AUTHENTICATON_SUCCESS
++};
++
++typedef enum _tr_rpcNativeAuthenticationResult tr_rpcNativeAuthenticationResult;
++
++void tr_performNativeAuthentication( const char * user, const char * password, tr_rpcNativeAuthenticationResult * result );
++
++#endif
++
--- /dev/null
+Index: libtransmission/rpc-server.c
+===================================================================
+--- libtransmission/rpc-server.c (revision 13057)
++++ libtransmission/rpc-server.c (working copy)
+@@ -32,6 +32,7 @@
+ #include "fdlimit.h"
+ #include "list.h"
+ #include "net.h"
++#include "native-auth.h"
+ #include "platform.h" /* tr_getWebClientDir() */
+ #include "ptrarray.h"
+ #include "rpcimpl.h"
+@@ -56,6 +57,7 @@
+ {
+ bool isEnabled;
+ bool isPasswordEnabled;
++ bool isNativeAuthenticationEnabled;
+ bool isWhitelistEnabled;
+ tr_port port;
+ char * url;
+@@ -575,6 +577,35 @@
+ }
+
+ static bool
++isUserAllowed( struct tr_rpc_server* server, const char * user, const char * pass)
++{
++ bool successAuth;
++
++ if( !server->isPasswordEnabled )
++ return true;
++
++ if( !user || !pass )
++ {
++ return false;
++ }
++
++ if( server->isNativeAuthenticationEnabled )
++ {
++ tr_rpcNativeAuthenticationResult authResult;
++ tr_performNativeAuthentication( user, pass, &authResult);
++ successAuth = (NATIVE_AUTHENTICATON_SUCCESS == authResult);
++ }
++ else
++ {
++ successAuth = !strcmp( server->username, user ) &&
++ tr_ssha1_matches( server->password, pass);
++ }
++
++ return successAuth;
++}
++
++
++static bool
+ test_session_id( struct tr_rpc_server * server, struct evhttp_request * req )
+ {
+ const char * ours = get_current_session_id( server );
+@@ -616,10 +647,7 @@
+ "<p>If you're editing settings.json, see the 'rpc-whitelist' and 'rpc-whitelist-enabled' entries.</p>"
+ "<p>If you're still using ACLs, use a whitelist instead. See the transmission-daemon manpage for details.</p>" );
+ }
+- else if( server->isPasswordEnabled
+- && ( !pass || !user || strcmp( server->username, user )
+- || !tr_ssha1_matches( server->password,
+- pass ) ) )
++ else if( !isUserAllowed( server, user, pass ) )
+ {
+ evhttp_add_header( req->output_headers,
+ "WWW-Authenticate",
+@@ -877,6 +905,19 @@
+ return server->isPasswordEnabled;
+ }
+
++void
++tr_rpcSetNativeAuthenticationEnabled( tr_rpc_server * server, bool isEnabled )
++{
++ server->isNativeAuthenticationEnabled = isEnabled;
++ dbgmsg( "setting 'native authenication enabled' to %d", (int)isEnabled );
++}
++
++bool
++tr_rpcIsNativeAuthenticationEnabled( const tr_rpc_server * server )
++{
++ return server->isNativeAuthenticationEnabled;
++}
++
+ const char *
+ tr_rpcGetBindAddress( const tr_rpc_server * server )
+ {
+@@ -961,6 +1002,12 @@
+ else
+ tr_rpcSetPasswordEnabled( s, boolVal );
+
++ key = TR_PREFS_KEY_RPC_NATIVE_AUTH_ENABLED;
++ if ( !tr_bencDictFindBool( settings, key, &boolVal ) )
++ tr_nerr( MY_NAME, _( "Couldn't find settings key \"%s\"" ), key );
++ else
++ tr_rpcSetNativeAuthenticationEnabled( s, boolVal );
++
+ key = TR_PREFS_KEY_RPC_WHITELIST;
+ if( !tr_bencDictFindStr( settings, key, &str ) && str )
+ tr_nerr( MY_NAME, _( "Couldn't find settings key \"%s\"" ), key );
--- /dev/null
+Index: libtransmission/rpc-server.h
+===================================================================
+--- libtransmission/rpc-server.h (revision 13057)
++++ libtransmission/rpc-server.h (working copy)
+@@ -64,6 +64,10 @@
+
+ bool tr_rpcIsPasswordEnabled( const tr_rpc_server * session );
+
++void tr_rpcSetNativeAuthenticationEnabled( tr_rpc_server * server, bool isEnabled );
++
++bool tr_rpcIsNativeAuthenticationEnabled( const tr_rpc_server * server );
++
+ const char* tr_rpcGetBindAddress( const tr_rpc_server * server );
+
+ #endif
--- /dev/null
+Index: libtransmission/session.c
+===================================================================
+--- libtransmission/session.c (revision 13057)
++++ libtransmission/session.c (working copy)
+@@ -342,6 +342,7 @@
+ tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED, false );
+ tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD, "" );
+ tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME, "" );
++ tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_NATIVE_AUTH_ENABLED, false );
+ tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST, TR_DEFAULT_RPC_WHITELIST );
+ tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, true );
+ tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT, atoi( TR_DEFAULT_RPC_PORT_STR ) );
+@@ -415,6 +416,7 @@
+ tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT, tr_sessionGetRPCPort( s ) );
+ tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_URL, tr_sessionGetRPCUrl( s ) );
+ tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME, tr_sessionGetRPCUsername( s ) );
++ tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_NATIVE_AUTH_ENABLED, tr_sessionIsRPCNativeAuthenticationEnabled( s) );
+ tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST, tr_sessionGetRPCWhitelist( s ) );
+ tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, tr_sessionGetRPCWhitelistEnabled( s ) );
+ tr_bencDictAddBool( d, TR_PREFS_KEY_SCRAPE_PAUSED_TORRENTS, s->scrapePausedTorrents );
+@@ -2578,6 +2580,22 @@
+ return tr_rpcIsPasswordEnabled( session->rpcServer );
+ }
+
++void
++tr_sessionSetRPCNativeAuthenticationEnabled( tr_session * session, bool isEnabled )
++{
++ assert( tr_isSession( session ) );
++
++ return tr_rpcSetNativeAuthenticationEnabled( session->rpcServer, isEnabled );
++}
++
++bool
++tr_sessionIsRPCNativeAuthenticationEnabled( const tr_session * session )
++{
++ assert( tr_isSession (session) );
++
++ return tr_rpcIsNativeAuthenticationEnabled( session->rpcServer );
++}
++
+ const char *
+ tr_sessionGetRPCBindAddress( const tr_session * session )
+ {
--- /dev/null
+Index: libtransmission/transmission.h
+===================================================================
+--- libtransmission/transmission.h (revision 13057)
++++ libtransmission/transmission.h (working copy)
+@@ -196,6 +196,7 @@
+ #define TR_PREFS_KEY_RATIO_ENABLED "ratio-limit-enabled"
+ #define TR_PREFS_KEY_RENAME_PARTIAL_FILES "rename-partial-files"
+ #define TR_PREFS_KEY_RPC_AUTH_REQUIRED "rpc-authentication-required"
++#define TR_PREFS_KEY_RPC_NATIVE_AUTH_ENABLED "rpc-native-authentication-enabled"
+ #define TR_PREFS_KEY_RPC_BIND_ADDRESS "rpc-bind-address"
+ #define TR_PREFS_KEY_RPC_ENABLED "rpc-enabled"
+ #define TR_PREFS_KEY_RPC_PASSWORD "rpc-password"
+@@ -504,6 +505,11 @@
+
+ bool tr_sessionIsRPCPasswordEnabled( const tr_session * session );
+
++void tr_sessionSetRPCNativeAuthenticationEnabled( tr_session * session,
++ bool isEnabled );
++
++bool tr_sessionIsRPCNativeAuthenticationEnabled( const tr_session * session );
++
+ const char* tr_sessionGetRPCBindAddress( const tr_session * session );
+
+
--- /dev/null
+Index: qt/qtr.pro
+===================================================================
+--- qt/qtr.pro (revision 13057)
++++ qt/qtr.pro (working copy)
+@@ -27,7 +27,7 @@
+ LIBS += $${TRANSMISSION_TOP}/third-party/miniupnp/libminiupnp.a
+ }
+ LIBS += $${TRANSMISSION_TOP}/third-party/libnatpmp/libnatpmp.a
+-unix: LIBS += -L$${EVENT_TOP}/lib -lz -lrt
++unix: LIBS += -L$${EVENT_TOP}/lib -lz -lrt -lpam
+ win32:DEFINES += QT_DBUS
+ win32:LIBS += -levent-2.0 -lws2_32 -lintl
+ win32:LIBS += -lidn -liconv -lwldap32 -liphlpapi
--- /dev/null
+Index: utils/Makefile.am
+===================================================================
+--- utils/Makefile.am (revision 13057)
++++ utils/Makefile.am (working copy)
+@@ -32,6 +32,7 @@
+ @DHT_LIBS@ \
+ @LIBUTP_LIBS@ \
+ @LIBEVENT_LIBS@ \
++ @LIBPAM_LIBS@ \
+ @LIBCURL_LIBS@ \
+ @OPENSSL_LIBS@ \
+ @ZLIB_LIBS@ \