Changeset 8352


Ignore:
Timestamp:
May 8, 2009, 2:38:08 AM (12 years ago)
Author:
charles
Message:

(1.5x) add a session_id cookie to the rpc server

Location:
branches/1.5x
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/1.5x/daemon/remote.c

    r8275 r8352  
    127127static char * auth = NULL;
    128128static char * netrc = NULL;
     129static char * cookies = NULL;
    129130
    130131static char*
     
    12231224}
    12241225
     1226/* very basic handling of cookies: when we get Set-Cookie, throw out all
     1227 * the previous cookies...  T only uses one cookie (session_id) */
     1228static size_t
     1229parseResponseHeader( void *ptr, size_t size, size_t nmemb, void * stream UNUSED )
     1230{
     1231    const char * line = ptr;
     1232    const size_t linelen = size * nmemb;
     1233    const char * lineend = line + linelen;
     1234    const char * key = "Set-Cookie: ";
     1235    const size_t keylen = strlen( key );
     1236    if( ( linelen >= keylen ) && !memcmp( line, key, keylen ) ) {
     1237        const char * begin = line + keylen;
     1238        const char * end = begin;
     1239        while(( end!=lineend ) && !strchr("\r\n",*end))
     1240            ++end;
     1241        tr_free( cookies );
     1242        cookies = tr_strndup( begin, end-begin );
     1243    }
     1244
     1245    return linelen;
     1246}
     1247
     1248static CURL*
     1249tr_curl_easy_init( struct evbuffer * writebuf )
     1250{
     1251    CURL * curl = curl_easy_init( );
     1252    curl_easy_setopt( curl, CURLOPT_USERAGENT, MY_NAME "/" LONG_VERSION_STRING );
     1253    curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, writeFunc );
     1254    curl_easy_setopt( curl, CURLOPT_WRITEDATA, writebuf );
     1255    curl_easy_setopt( curl, CURLOPT_HEADERFUNCTION, parseResponseHeader );
     1256    curl_easy_setopt( curl, CURLOPT_POST, 1 );
     1257    curl_easy_setopt( curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL );
     1258    curl_easy_setopt( curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
     1259    curl_easy_setopt( curl, CURLOPT_TIMEOUT, 60L );
     1260    curl_easy_setopt( curl, CURLOPT_VERBOSE, debug );
     1261#ifdef HAVE_ZLIB
     1262    curl_easy_setopt( curl, CURLOPT_ENCODING, "deflate" );
     1263#endif
     1264    if( cookies )
     1265        curl_easy_setopt( curl, CURLOPT_COOKIE, cookies );
     1266    if( netrc )
     1267        curl_easy_setopt( curl, CURLOPT_NETRC_FILE, netrc );
     1268    if( auth )
     1269        curl_easy_setopt( curl, CURLOPT_USERPWD, auth );
     1270    return curl;
     1271}
     1272
    12251273static void
    12261274processRequests( const char *  host,
     
    12291277                 int           reqCount )
    12301278{
    1231     int               i;
    1232     CURL *            curl;
     1279    int i;
     1280    CURL * curl = NULL;
    12331281    struct evbuffer * buf = evbuffer_new( );
    1234     char *            url = tr_strdup_printf(
    1235         "http://%s:%d/transmission/rpc", host, port );
    1236 
    1237     curl = curl_easy_init( );
    1238     curl_easy_setopt( curl, CURLOPT_VERBOSE, debug );
    1239 #ifdef HAVE_LIBZ
    1240     curl_easy_setopt( curl, CURLOPT_ENCODING, "deflate" );
    1241 #endif
    1242     curl_easy_setopt( curl, CURLOPT_USERAGENT, MY_NAME "/" LONG_VERSION_STRING );
    1243     curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, writeFunc );
    1244     curl_easy_setopt( curl, CURLOPT_WRITEDATA, buf );
    1245     curl_easy_setopt( curl, CURLOPT_POST, 1 );
    1246     curl_easy_setopt( curl, CURLOPT_URL, url );
    1247     curl_easy_setopt( curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL );
    1248     curl_easy_setopt( curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
    1249     curl_easy_setopt( curl, CURLOPT_TIMEOUT, 60L );
    1250     if( netrc )
    1251         curl_easy_setopt( curl, CURLOPT_NETRC_FILE, netrc );
    1252     if( auth )
    1253         curl_easy_setopt( curl, CURLOPT_USERPWD, auth );
    1254 
    1255     for( i = 0; i < reqCount; ++i )
     1282    char * url = tr_strdup_printf( "http://%s:%d/transmission/rpc", host, port );
     1283
     1284    for( i=0; i<reqCount; ++i )
    12561285    {
    12571286        CURLcode res;
     1287        evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
     1288
     1289        if( curl == NULL )
     1290        {
     1291            curl = tr_curl_easy_init( buf );
     1292            curl_easy_setopt( curl, CURLOPT_URL, url );
     1293        }
     1294
    12581295        curl_easy_setopt( curl, CURLOPT_POSTFIELDS, reqs[i] );
     1296
    12591297        if( debug )
    12601298            fprintf( stderr, "posting:\n--------\n%s\n--------\n", reqs[i] );
    12611299        if( ( res = curl_easy_perform( curl ) ) )
    1262             tr_nerr( MY_NAME, "(%s:%d) %s", host, port,
    1263                     curl_easy_strerror( res ) );
    1264         else
    1265             processResponse( host, port, EVBUFFER_DATA(
    1266                                 buf ), EVBUFFER_LENGTH( buf ) );
    1267 
    1268         evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
     1300            tr_nerr( MY_NAME, "(%s:%d) %s", host, port, curl_easy_strerror( res ) );
     1301        else {
     1302            long response;
     1303            curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &response );
     1304            switch( response ) {
     1305                case 200:
     1306                    processResponse( host, port, EVBUFFER_DATA(buf), EVBUFFER_LENGTH(buf) );
     1307                    break;
     1308                case 409:
     1309                    /* session_id cookie expired.  by the time we reach line this our
     1310                     * curl header func has already found the new session_id, so make
     1311                     * a new CURL* and try again... */
     1312                    curl_easy_cleanup( curl );
     1313                    curl = NULL;
     1314                    --i;
     1315                    break;
     1316                default:
     1317                    fprintf( stderr, "Unexpected response: %s\n", (char*)EVBUFFER_DATA(buf) );
     1318                    break;
     1319            }
     1320        }
    12691321    }
    12701322
     
    12721324    tr_free( url );
    12731325    evbuffer_free( buf );
    1274     curl_easy_cleanup( curl );
     1326    if( curl != NULL )
     1327        curl_easy_cleanup( curl );
    12751328}
    12761329
  • branches/1.5x/libtransmission/rpc-server.c

    r8204 r8352  
    3030#include "transmission.h"
    3131#include "bencode.h"
     32#include "crypto.h"
    3233#include "list.h"
    3334#include "platform.h"
     
    5455    struct evhttp *    httpd;
    5556    tr_session *       session;
     57    char *             sessionId;
    5658    char *             username;
    5759    char *             password;
     
    446448}
    447449
    448 static void
    449 handle_request( struct evhttp_request * req,
    450                 void *                  arg )
     450static char*
     451session_id_new( void )
     452{
     453    int i;
     454    const int n = 48;
     455    const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
     456    const size_t pool_size = strlen( pool );
     457    char * buf = tr_new( char, n+1 );
     458    for( i=0; i<n; ++i )
     459        buf[i] = pool[ tr_cryptoRandInt( pool_size ) ];
     460    buf[n] = '\0';
     461    return buf;
     462}
     463
     464static tr_bool
     465test_session_id( struct tr_rpc_server * server, struct evhttp_request * req )
     466{
     467    char * needle = tr_strdup_printf( "session_id=%s", server->sessionId );
     468    const char * haystack = evhttp_find_header( req->input_headers, "Cookie" );
     469    const tr_bool success = (haystack!=NULL) && (strstr(haystack,needle)!=NULL);
     470    tr_free( needle );
     471    return success;
     472}
     473
     474static void
     475handle_request( struct evhttp_request * req, void * arg )
    451476{
    452477    struct tr_rpc_server * server = arg;
     
    455480    {
    456481        const char * auth;
    457         char *       user = NULL;
    458         char *       pass = NULL;
     482        char * user = NULL;
     483        char * pass = NULL;
     484        char * cookie;
    459485
    460486        evhttp_add_header( req->output_headers, "Server", MY_REALM );
     487        cookie = tr_strdup_printf( "session_id=%s;Path=/;Discard", server->sessionId );
     488        evhttp_add_header( req->output_headers, "Set-Cookie", cookie );
     489        tr_free( cookie );
    461490
    462491        auth = evhttp_find_header( req->input_headers, "Authorization" );
    463 
    464492        if( auth && !strncasecmp( auth, "basic ", 6 ) )
    465493        {
     
    475503        if( !isAddressAllowed( server, req->remote_host ) )
    476504        {
    477             send_simple_response( req, 401,
     505            send_simple_response( req, 403,
    478506                "<p>Unauthorized IP Address.</p>"
    479507                "<p>Either disable the IP address whitelist or add your address to it.</p>"
     
    505533        {
    506534            handle_clutch( req, server );
     535        }
     536        else if( !test_session_id( server, req ) )
     537        {
     538            send_simple_response( req, 409, "<p>Invalid session_id cookie.</p>" );
    507539        }
    508540        else if( !strncmp( req->uri, "/transmission/rpc", 17 ) )
     
    742774    s = tr_new0( tr_rpc_server, 1 );
    743775    s->session = session;
     776    s->sessionId = session_id_new( );
    744777
    745778    found = tr_bencDictFindInt( settings, TR_PREFS_KEY_RPC_ENABLED, &i );
Note: See TracChangeset for help on using the changeset viewer.