From ab17f553c4609a3c6625c135a67dd76595677ed4 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 5 Jun 2008 16:23:03 +0000 Subject: [PATCH] get RPC password protections working in libT and the gtk+ client. mac, daemon, and cli need to be synced. --- gtk/main.c | 15 +++- gtk/tr-prefs.c | 65 ++++++++--------- gtk/tr-prefs.h | 1 + libtransmission/JSON_parser.c | 2 +- libtransmission/completion.c | 6 +- libtransmission/rpc-server.c | 124 ++++++++++++++++++++++++++++++++- libtransmission/rpc-server.h | 60 ++++++++++------ libtransmission/session.c | 51 ++++++++++++-- libtransmission/tracker.c | 1 - libtransmission/transmission.h | 30 +++++++- 10 files changed, 285 insertions(+), 70 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index 229660fc9..d3deba692 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -428,7 +428,10 @@ main( int argc, char ** argv ) pref_int_get( PREF_KEY_PEER_SOCKET_TOS ), pref_flag_get( PREF_KEY_RPC_ENABLED ), pref_int_get( PREF_KEY_RPC_PORT ), - pref_string_get( PREF_KEY_RPC_ACL ) ); + pref_string_get( PREF_KEY_RPC_ACL ), + pref_flag_get( PREF_KEY_RPC_PASSWORD_ENABLED ), + pref_string_get( PREF_KEY_RPC_USERNAME ), + pref_string_get( PREF_KEY_RPC_PASSWORD ) ); cbdata->core = tr_core_new( h ); /* create main window now to be a parent to any error dialogs */ @@ -948,16 +951,22 @@ prefschanged( TrCore * core UNUSED, const char * key, gpointer data ) tr_sessionSetRPCACL( tr, s, &err ); g_free( s ); } + else if( !strcmp( key, PREF_KEY_RPC_USERNAME ) ) + { + char * s = pref_string_get( key ); + tr_sessionSetRPCUsername( tr, s ); + g_free( s ); + } else if( !strcmp( key, PREF_KEY_RPC_PASSWORD ) ) { char * s = pref_string_get( key ); - /*FIXMEtr_sessionSetRPCACL( tr, s );*/ + tr_sessionSetRPCPassword( tr, s ); g_free( s ); } else if( !strcmp( key, PREF_KEY_RPC_PASSWORD_ENABLED ) ) { const gboolean enabled = pref_flag_get( key ); - /*FIXME tr_sessionSetRPCEnabled( tr, enabled );*/ + tr_sessionSetRPCPasswordEnabled( tr, enabled ); } } diff --git a/gtk/tr-prefs.c b/gtk/tr-prefs.c index e93660074..b7003634e 100644 --- a/gtk/tr-prefs.c +++ b/gtk/tr-prefs.c @@ -35,8 +35,11 @@ void tr_prefs_init_global( void ) { int i; - char pw[12]; + char pw[32]; const char * str; + const char * pool = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "1234567890"; cf_check_older_configs( ); @@ -101,13 +104,13 @@ tr_prefs_init_global( void ) pref_int_set_default ( PREF_KEY_RPC_PORT, TR_DEFAULT_RPC_PORT ); pref_string_set_default ( PREF_KEY_RPC_ACL, TR_DEFAULT_RPC_ACL ); - for( i=0; i<8; ++i ) - pw[i] = 'a' + tr_rand(26); - pw[8] = '\0'; + for( i=0; i<16; ++i ) + pw[i] = pool[ tr_rand( strlen( pool ) ) ]; + pw[16] = '\0'; + pref_string_set_default( PREF_KEY_RPC_USERNAME, "transmission" ); pref_string_set_default( PREF_KEY_RPC_PASSWORD, pw ); pref_flag_set_default ( PREF_KEY_RPC_PASSWORD_ENABLED, FALSE ); - pref_save( NULL ); } @@ -615,10 +618,10 @@ struct remote_page GtkTreeView * view; GtkListStore * store; GtkWidget * remove_button; - GtkWidget * pw_entry; GSList * widgets; + GSList * auth_widgets; GtkToggleButton * rpc_tb; - GtkToggleButton * pw_tb; + GtkToggleButton * auth_tb; }; static void @@ -727,7 +730,7 @@ refreshRPCSensitivity( struct remote_page * page ) { GSList * l; const int rpc_active = gtk_toggle_button_get_active( page->rpc_tb ); - const int pw_active = gtk_toggle_button_get_active( page->pw_tb ); + const int auth_active = gtk_toggle_button_get_active( page->auth_tb ); GtkTreeSelection * sel = gtk_tree_view_get_selection( page->view ); const int have_addr = gtk_tree_selection_get_selected( sel, NULL, NULL ); const int n_rules = gtk_tree_model_iter_n_children( @@ -736,7 +739,8 @@ refreshRPCSensitivity( struct remote_page * page ) for( l=page->widgets; l!=NULL; l=l->next ) gtk_widget_set_sensitive( GTK_WIDGET( l->data ), rpc_active ); - gtk_widget_set_sensitive( page->pw_entry, rpc_active && pw_active ); + for( l=page->auth_widgets; l!=NULL; l=l->next ) + gtk_widget_set_sensitive( GTK_WIDGET( l->data ), rpc_active && auth_active); gtk_widget_set_sensitive( page->remove_button, rpc_active && have_addr && n_rules>1 ); @@ -748,11 +752,6 @@ onRPCToggled( GtkToggleButton * tb UNUSED, gpointer page ) refreshRPCSensitivity( page ); } static void -onRPCPassToggled( GtkToggleButton * tb UNUSED, gpointer page ) -{ - refreshRPCSensitivity( page ); -} -static void onACLSelectionChanged( GtkTreeSelection * sel UNUSED, gpointer page ) { refreshRPCSensitivity( page ); @@ -765,8 +764,6 @@ remotePage( GObject * core ) int row = 0; GtkWidget * t; GtkWidget * w; - GtkWidget * w2; - GtkWidget * enabled_toggle; struct remote_page * page = g_new0( struct remote_page, 1 ); page->core = TR_CORE( core ); @@ -780,29 +777,37 @@ remotePage( GObject * core ) s = _( "A_llow requests from transmission-remote, Clutch, etc." ); w = new_check_button( s, PREF_KEY_RPC_ENABLED, core ); hig_workarea_add_wide_control( t, &row, w ); - enabled_toggle = w; page->rpc_tb = GTK_TOGGLE_BUTTON( w ); g_signal_connect( w, "clicked", G_CALLBACK(onRPCToggled), page ); - /* password protection */ - s = _( "Require _password:" ); + /* require authentication */ + s = _( "Require _authentication" ); w = new_check_button( s, PREF_KEY_RPC_PASSWORD_ENABLED, core ); - g_signal_connect( w, "clicked", G_CALLBACK(onRPCPassToggled), page ); - page->pw_tb = GTK_TOGGLE_BUTTON( w ); + hig_workarea_add_wide_control( t, &row, w ); + page->auth_tb = GTK_TOGGLE_BUTTON( w ); page->widgets = g_slist_append( page->widgets, w ); - //toggles_set_sensitivity( w, enabled_toggle, NULL ); - w2 = page->pw_entry = new_entry( PREF_KEY_RPC_PASSWORD, core ); - //toggles_set_sensitivity( w2, enabled_toggle, w, NULL ); - gtk_entry_set_visibility( GTK_ENTRY( w2 ), FALSE ); - hig_workarea_add_row_w( t, &row, w, w2, NULL ); + g_signal_connect( w, "clicked", G_CALLBACK(onRPCToggled), page ); + + /* username */ + s = _( "_Username:" ); + w = new_entry( PREF_KEY_RPC_USERNAME, core ); + page->auth_widgets = g_slist_append( page->auth_widgets, w ); + w = hig_workarea_add_row( t, &row, s, w, NULL ); + page->auth_widgets = g_slist_append( page->auth_widgets, w ); + + /* password */ + s = _( "_Password:" ); + w = new_entry( PREF_KEY_RPC_PASSWORD, core ); + gtk_entry_set_visibility( GTK_ENTRY( w ), FALSE ); + page->auth_widgets = g_slist_append( page->auth_widgets, w ); + w = hig_workarea_add_row( t, &row, s, w, NULL ); + page->auth_widgets = g_slist_append( page->auth_widgets, w ); /* port */ w = new_spin_button( PREF_KEY_RPC_PORT, core, 0, 65535, 1 ); page->widgets = g_slist_append( page->widgets, w ); - //toggles_set_sensitivity( w, enabled_toggle, NULL ); w = hig_workarea_add_row( t, &row, _( "Listening _port:" ), w, NULL ); page->widgets = g_slist_append( page->widgets, w ); - //toggles_set_sensitivity( w, enabled_toggle, NULL ); /* access control list */ { @@ -821,7 +826,6 @@ remotePage( GObject * core ) w = gtk_tree_view_new_with_model( m ); page->widgets = g_slist_append( page->widgets, w ); - //toggles_set_sensitivity( w, enabled_toggle, NULL ); v = page->view = GTK_TREE_VIEW( w ); gtk_tooltips_set_tip( tips, w, _( "IP addresses may use wildcards, such as 192.168.*.*" ), @@ -849,7 +853,6 @@ remotePage( GObject * core ) w = hig_workarea_add_row( t, &row, s, w, NULL ); gtk_misc_set_alignment( GTK_MISC( w ), 0.0f, 0.1f ); page->widgets = g_slist_append( page->widgets, w ); - //toggles_set_sensitivity( w, enabled_toggle, NULL ); g_free( val ); /* permission column */ @@ -875,7 +878,6 @@ remotePage( GObject * core ) gtk_box_pack_start_defaults( GTK_BOX( h ), w ); w = gtk_button_new_from_stock( GTK_STOCK_ADD ); page->widgets = g_slist_append( page->widgets, w ); - //toggles_set_sensitivity( w, enabled_toggle, NULL ); g_signal_connect( w, "clicked", G_CALLBACK(onAddACLClicked), page ); gtk_box_pack_start_defaults( GTK_BOX( h ), w ); w = gtk_hbox_new( FALSE, 0 ); @@ -884,6 +886,7 @@ remotePage( GObject * core ) hig_workarea_add_wide_control( t, &row, w ); } + refreshRPCSensitivity( page ); hig_workarea_finish( t, &row ); return t; } diff --git a/gtk/tr-prefs.h b/gtk/tr-prefs.h index d4b517d16..ed5b175bb 100644 --- a/gtk/tr-prefs.h +++ b/gtk/tr-prefs.h @@ -59,6 +59,7 @@ GtkWidget * tr_prefs_dialog_new( GObject * core, GtkWindow * parent ); #define PREF_KEY_RPC_ACL "rpc-access-control-list" #define PREF_KEY_RPC_PASSWORD_ENABLED "rpc-password-required" #define PREF_KEY_RPC_PASSWORD "rpc-password" +#define PREF_KEY_RPC_USERNAME "rpc-username" void tr_prefs_init_global( void ); diff --git a/libtransmission/JSON_parser.c b/libtransmission/JSON_parser.c index 634b60791..99f0a4af5 100644 --- a/libtransmission/JSON_parser.c +++ b/libtransmission/JSON_parser.c @@ -57,7 +57,7 @@ SOFTWARE. #include "ConvertUTF.h" #if _MSC_VER >= 1400 /* Visual Studio 2005 and up */ -# pragma warning(disable:4996) // unsecure sscanf +# pragma warning(disable:4996) /* unsecure sscanf */ #endif diff --git a/libtransmission/completion.c b/libtransmission/completion.c index 1a346500d..1f7aecc67 100644 --- a/libtransmission/completion.c +++ b/libtransmission/completion.c @@ -105,13 +105,13 @@ tr_cpSizeWhenDone( const tr_completion * ccp ) for( i=0; ipieceCount; ++i ) { if( !info->pieces[i].dnd ) { - // we want the piece... + /* we want the piece... */ size += tr_torPieceCountBytes( tor, i ); } else if( tr_cpPieceIsComplete( cp, i ) ) { - // we have the piece... + /* we have the piece... */ size += tr_torPieceCountBytes( tor, i ); } else if( cp->completeBlocks[i] ) { - // we have part of the piece... + /* we have part of the piece... */ const tr_block_index_t b = tr_torPieceFirstBlock( tor, i ); const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, i ); tr_block_index_t j; diff --git a/libtransmission/rpc-server.c b/libtransmission/rpc-server.c index 8f7004e5a..0dc88504e 100644 --- a/libtransmission/rpc-server.c +++ b/libtransmission/rpc-server.c @@ -16,7 +16,10 @@ #include /* strtol */ #include +#include /* unlink */ + #include +#include /* edit_passwords */ #include #include "transmission.h" @@ -25,6 +28,7 @@ #include "utils.h" #define MY_NAME "RPC Server" +#define MY_REALM "Transmission RPC Server" #define BUSY_INTERVAL_MSEC 30 #define IDLE_INTERVAL_MSEC 100 @@ -39,6 +43,9 @@ struct tr_rpc_server struct evbuffer * in; struct evbuffer * out; struct event timer; + int isPasswordEnabled; + char * username; + char * password; char * acl; }; @@ -119,6 +126,14 @@ rpcPulse( int socket UNUSED, short action UNUSED, void * vserver ) evtimer_add( &server->timer, &tv ); } +static void +getPasswordFile( tr_rpc_server * server, char * buf, int buflen ) +{ + tr_buildPath( buf, buflen, tr_sessionGetConfigDir( server->session ), + "htpasswd", + NULL ); +} + static void startServer( tr_rpc_server * server ) { @@ -127,18 +142,31 @@ startServer( tr_rpc_server * server ) if( !server->ctx ) { char ports[128]; + char passwd[MAX_PATH_LENGTH]; struct timeval tv = tr_timevalMsec( UNUSED_INTERVAL_MSEC ); + getPasswordFile( server, passwd, sizeof( passwd ) ); + if( !server->isPasswordEnabled ) + unlink( passwd ); + else + edit_passwords( passwd, MY_REALM, "user", "pass" ); + server->ctx = shttpd_init( ); snprintf( ports, sizeof( ports ), "%d", server->port ); shttpd_register_uri( server->ctx, "/transmission", handle_rpc, server ); shttpd_set_option( server->ctx, "ports", ports ); shttpd_set_option( server->ctx, "dir_list", "0" ); shttpd_set_option( server->ctx, "root", "/dev/null" ); + shttpd_set_option( server->ctx, "auth_realm", MY_REALM ); if( server->acl ) { dbgmsg( "setting acl [%s]", server->acl ); shttpd_set_option( server->ctx, "acl", server->acl ); } + if( server->isPasswordEnabled ) { + char * buf = tr_strdup_printf( "/transmission=%s", passwd ); + shttpd_set_option( server->ctx, "protect", buf ); + tr_free( buf ); + } evtimer_set( &server->timer, rpcPulse, server ); evtimer_add( &server->timer, &tv ); @@ -150,6 +178,10 @@ stopServer( tr_rpc_server * server ) { if( server->ctx ) { + char passwd[MAX_PATH_LENGTH]; + getPasswordFile( server, passwd, sizeof( passwd ) ); + unlink( passwd ); + evtimer_del( &server->timer ); shttpd_fini( server->ctx ); server->ctx = NULL; @@ -193,6 +225,10 @@ tr_rpcGetPort( const tr_rpc_server * server ) return server->port; } +/**** +***** ACL +****/ + /* * DELIM_CHARS, FOR_EACH_WORD_IN_LIST, isbyte, and testACL are from, or modified from, * shttpd, written by Sergey Lyubka under this license: @@ -327,12 +363,88 @@ tr_rpcSetACL( tr_rpc_server * server, return err; } -const char* +char* tr_rpcGetACL( const tr_rpc_server * server ) { - return server->acl ? server->acl : ""; + return tr_strdup( server->acl ? server->acl : "" ); } +/**** +***** PASSWORD +****/ + +void +tr_rpcSetUsername( tr_rpc_server * server, + const char * username ) +{ + const int isRunning = server->ctx != NULL; + + if( isRunning ) + stopServer( server ); + + tr_free( server->username ); + server->username = tr_strdup( username ); + dbgmsg( "setting our Username to [%s]", server->username ); + + if( isRunning ) + startServer( server ); +} + +char* +tr_rpcGetUsername( const tr_rpc_server * server ) +{ + return tr_strdup( server->username ? server->username : "" ); +} + +void +tr_rpcSetPassword( tr_rpc_server * server, + const char * password ) +{ + const int isRunning = server->ctx != NULL; + + if( isRunning ) + stopServer( server ); + + tr_free( server->password ); + server->password = tr_strdup( password ); + dbgmsg( "setting our Password to [%s]", server->password ); + + if( isRunning ) + startServer( server ); +} + +char* +tr_rpcGetPassword( const tr_rpc_server * server ) +{ + return tr_strdup( server->password ? server->password : "" ); +} + +void +tr_rpcSetPasswordEnabled( tr_rpc_server * server, + int isEnabled ) +{ + const int isRunning = server->ctx != NULL; + + if( isRunning ) + stopServer( server ); + + server->isPasswordEnabled = isEnabled; + dbgmsg( "setting 'password enabled' to %d", isEnabled ); + + if( isRunning ) + startServer( server ); +} + +int +tr_rpcIsPasswordEnabled( const tr_rpc_server * server ) +{ + return server->isPasswordEnabled; +} + +/**** +***** LIFE CYCLE +****/ + void tr_rpcClose( tr_rpc_server ** ps ) { @@ -350,7 +462,10 @@ tr_rpc_server * tr_rpcInit( tr_handle * session, int isEnabled, int port, - const char * acl ) + const char * acl, + int isPasswordEnabled, + const char * username, + const char * password ) { char * errmsg; tr_rpc_server * s; @@ -369,6 +484,9 @@ tr_rpcInit( tr_handle * session, s->in = evbuffer_new( ); s->out = evbuffer_new( ); s->acl = tr_strdup( acl ); + s->username = tr_strdup( username ); + s->password = tr_strdup( password ); + s->isPasswordEnabled = isPasswordEnabled; if( isEnabled ) startServer( s ); diff --git a/libtransmission/rpc-server.h b/libtransmission/rpc-server.h index 12a16ec9d..b4a7b6593 100644 --- a/libtransmission/rpc-server.h +++ b/libtransmission/rpc-server.h @@ -15,35 +15,53 @@ typedef struct tr_rpc_server tr_rpc_server; -tr_rpc_server * tr_rpcInit ( struct tr_handle * session, - int isEnabled, - int port, - const char * acl ); +tr_rpc_server * tr_rpcInit ( struct tr_handle * session, + int isEnabled, + int port, + const char * acl, + int isPasswordEnabled, + const char * username, + const char * password ); -void tr_rpcClose ( tr_rpc_server ** freeme ); +void tr_rpcClose ( tr_rpc_server ** freeme ); -void tr_rpcSetEnabled( tr_rpc_server * server, - int isEnabled ); +void tr_rpcSetEnabled ( tr_rpc_server * server, + int isEnabled ); -int tr_rpcIsEnabled ( const tr_rpc_server * server ); +int tr_rpcIsEnabled ( const tr_rpc_server * server ); -void tr_rpcSetPort ( tr_rpc_server * server, - int port ); +void tr_rpcSetPort ( tr_rpc_server * server, + int port ); -int tr_rpcGetPort ( const tr_rpc_server * server ); +int tr_rpcGetPort ( const tr_rpc_server * server ); -int tr_rpcSetTest ( const tr_rpc_server * server, - const char * acl, - char ** allocme_errmsg ); +int tr_rpcSetTest ( const tr_rpc_server * server, + const char * acl, + char ** allocme_errmsg ); -int tr_rpcTestACL ( const tr_rpc_server * server, - const char * acl, - char ** allocme_errmsg ); +int tr_rpcTestACL ( const tr_rpc_server * server, + const char * acl, + char ** allocme_errmsg ); -int tr_rpcSetACL ( tr_rpc_server * server, - const char * acl, - char ** allocme_errmsg ); +int tr_rpcSetACL ( tr_rpc_server * server, + const char * acl, + char ** allocme_errmsg ); -const char* tr_rpcGetACL ( const tr_rpc_server * server ); +char* tr_rpcGetACL ( const tr_rpc_server * server ); + +void tr_rpcSetPassword ( tr_rpc_server * server, + const char * password ); + +char* tr_rpcGetPassword ( const tr_rpc_server * server ); + +void tr_rpcSetUsername ( tr_rpc_server * server, + const char * username ); + +char* tr_rpcGetUsername ( const tr_rpc_server * server ); + +void tr_rpcSetPasswordEnabled ( tr_rpc_server * server, + int isEnabled ); + +int tr_rpcIsPasswordEnabled ( const tr_rpc_server * session ); #endif diff --git a/libtransmission/session.c b/libtransmission/session.c index a850b09bc..ccd525afb 100644 --- a/libtransmission/session.c +++ b/libtransmission/session.c @@ -137,7 +137,10 @@ tr_sessionInitFull( const char * configDir, int peerSocketTOS, int rpcIsEnabled, int rpcPort, - const char * rpcACL ) + const char * rpcACL, + int rpcPasswordIsEnabled, + const char * rpcUsername, + const char * rpcPassword ) { tr_handle * h; char filename[MAX_PATH_LENGTH]; @@ -199,7 +202,8 @@ tr_sessionInitFull( const char * configDir, tr_statsInit( h ); h->web = tr_webInit( h ); - h->rpcServer = tr_rpcInit( h, rpcIsEnabled, rpcPort, rpcACL ); + h->rpcServer = tr_rpcInit( h, rpcIsEnabled, rpcPort, rpcACL, + rpcPasswordIsEnabled, rpcUsername, rpcPassword ); metainfoLookupRescan( h ); @@ -229,7 +233,10 @@ tr_sessionInit( const char * configDir, TR_DEFAULT_PEER_SOCKET_TOS, TR_DEFAULT_RPC_ENABLED, TR_DEFAULT_RPC_PORT, - TR_DEFAULT_RPC_ACL ); + TR_DEFAULT_RPC_ACL, + FALSE, + "fnord", + "potzrebie" ); } /*** @@ -791,8 +798,44 @@ tr_sessionSetRPCACL( tr_handle * session, return tr_rpcSetACL( session->rpcServer, acl, allocme_errmsg ); } -const char* +char* tr_sessionGetRPCACL( const tr_session * session ) { return tr_rpcGetACL( session->rpcServer ); } + +void +tr_sessionSetRPCPassword( tr_handle * session, const char * password ) +{ + tr_rpcSetPassword( session->rpcServer, password ); +} + +char* +tr_sessionGetRPCPassword( const tr_handle * session ) +{ + return tr_rpcGetPassword( session->rpcServer ); +} + +void +tr_sessionSetRPCUsername( tr_handle * session, const char * username ) +{ + tr_rpcSetUsername( session->rpcServer, username ); +} + +char* +tr_sessionGetRPCUsername( const tr_handle * session ) +{ + return tr_rpcGetUsername( session->rpcServer ); +} + +void +tr_sessionSetRPCPasswordEnabled( tr_handle * session, int isEnabled ) +{ + tr_rpcSetPasswordEnabled( session->rpcServer, isEnabled ); +} + +int +tr_sessionIsRPCPasswordEnabled( const tr_handle * session ) +{ + return tr_rpcIsPasswordEnabled( session->rpcServer ); +} diff --git a/libtransmission/tracker.c b/libtransmission/tracker.c index 1ef965699..a70da7c2c 100644 --- a/libtransmission/tracker.c +++ b/libtransmission/tracker.c @@ -327,7 +327,6 @@ onTrackerResponse( tr_session * session, success = TRUE; if(( tr_bencDictFindStr( &benc, "failure reason", &str ))) { - // publishErrorMessageAndStop( t, str ); publishMessage( t, str, TR_TRACKER_ERROR ); success = FALSE; } diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 0d88cd039..ec1448fe8 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -229,7 +229,10 @@ tr_handle * tr_sessionInitFull( const char * configDir, int peerSocketTOS, int rpcIsEnabled, int rpcPort, - const char * rpcAccessControlList ); + const char * rpcAccessControlList, + int rpcPasswordIsEnabled, + const char * rpcUsername, + const char * rpcPassword ); /** @brief Shorter form of tr_sessionInitFull() @deprecated Use tr_sessionInitFull() instead. */ @@ -338,10 +341,31 @@ int tr_sessionSetRPCACL( tr_handle * session, const char * acl, char ** allocme_errmsg ); -/** Returns the Access Control List for allowing/denying RPC requests. +/** @brief get the Access Control List for allowing/denying RPC requests. + @return a comma-separated string of ACL rules. tr_free() when done. @see tr_sessionInitFull @see tr_sessionSetRPCACL */ -const char* tr_sessionGetRPCACL( const tr_handle * ); +char* tr_sessionGetRPCACL( const tr_handle * ); + +void tr_sessionSetRPCPassword( tr_handle * session, + const char * password ); + +void tr_sessionSetRPCUsername( tr_handle * session, + const char * username ); + +/** @brief get the password used to restrict RPC requests. + @return the password string. tr_free() when done. + @see tr_sessionInitFull() + @see tr_sessionSetRPCPassword() */ +char* tr_sessionGetRPCPassword( const tr_handle * session ); + +char* tr_sessionGetRPCUsername( const tr_handle * session ); + +void tr_sessionSetRPCPasswordEnabled( tr_handle * session, + int isEnabled ); + +int tr_sessionIsRPCPasswordEnabled( const tr_handle * session ); + typedef enum {