Ignore:
Timestamp:
Sep 25, 2008, 6:48:09 PM (13 years ago)
Author:
charles
Message:

rpc-server cleanups. add true wildmat control. break the Mac build a little harder.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/rpc-server.c

    r6797 r6798  
    1212
    1313#include <assert.h>
    14 #include <ctype.h> /* isdigit */
    15 #include <errno.h>
    16 #include <stdlib.h> /* strtol */
    17 #include <string.h>
     14#include <string.h> /* memcpy */
    1815#include <limits.h> /* INT_MAX */
    1916
     
    2118#include <sys/stat.h>
    2219#include <fcntl.h> /* open */
    23 
    24 #include <unistd.h> /* unlink */
     20#include <unistd.h> /* close */
    2521
    2622#include <libevent/event.h>
     
    3430#include "rpc-server.h"
    3531#include "utils.h"
     32#include "web.h"
    3633
    3734#define MY_NAME "RPC Server"
    3835#define MY_REALM "Transmission"
    39 
    40 #define ACTIVE_INTERVAL_MSEC 40
    41 #define INACTIVE_INTERVAL_MSEC 200
    42 
     36#define MAX_TOKEN_LEN 16
    4337#define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( *ary ) )
    4438
    4539struct acl_addr
    4640{
    47     char flag;
    48     char parts[4][20];
     41    char flag; /* '+' to allow, '-' to deny */
     42    char quads[4][MAX_TOKEN_LEN];
    4943};
    5044
     
    5953    char *               username;
    6054    char *               password;
    61     char *               acl_str;
    62     tr_list *            acl_list; /* struct acl_addr */
     55    char *               acl;
    6356};
    6457
     
    9891
    9992    if(!((pch = strchr( addr, '.' )))) return 0;
    100     if( pch-addr > 20 ) return 0;
    101     memcpy( setme->parts[0], addr, pch-addr );
     93    if( pch-addr > MAX_TOKEN_LEN ) return 0;
     94    memcpy( setme->quads[0], addr, pch-addr );
    10295    addr = pch + 1;
    10396
    10497    if(!((pch = strchr( addr, '.' )))) return 0;
    105     if( pch-addr > 20 ) return 0;
    106     memcpy( setme->parts[1], addr, pch-addr );
     98    if( pch-addr > MAX_TOKEN_LEN ) return 0;
     99    memcpy( setme->quads[1], addr, pch-addr );
    107100    addr = pch + 1;
    108101
    109102    if(!((pch = strchr( addr, '.' )))) return 0;
    110     if( pch-addr > 20 ) return 0;
    111     memcpy( setme->parts[2], addr, pch-addr );
     103    if( pch-addr > MAX_TOKEN_LEN ) return 0;
     104    memcpy( setme->quads[2], addr, pch-addr );
    112105    addr = pch + 1;
    113106
    114107    while( *pch && *pch!=',' ) ++pch;
    115     if( pch-addr > 20 ) return 0;
    116     memcpy( setme->parts[3], addr, pch-addr );
     108    if( pch-addr > MAX_TOKEN_LEN ) return 0;
     109    memcpy( setme->quads[3], addr, pch-addr );
    117110
    118111    *end = pch;
    119     return 1;
    120 }
    121 
    122 static int
    123 testAddress( const struct acl_addr * ref,
    124              const struct acl_addr * testme )
    125 {
    126     int i;
    127 
    128     for( i=0; i<4; ++i )
    129     {
    130         const char * a = ref->parts[i];
    131         const char * b = testme->parts[i];
    132         if( strcmp( a, "*" ) && strcmp( a, b ) ) return 0;
    133     }
    134 
    135112    return 1;
    136113}
     
    140117                  const char * address )
    141118{
     119    const char * acl;
    142120    struct acl_addr tmp;
    143121    const char * end;
    144122    const int parsed = parseAddress( address, &tmp, &end );
    145     tr_list * l;
    146123
    147124    if( !parsed )
    148125        return 0;
    149126
    150     for( l=server->acl_list; l; l=l->next ) {
    151         const struct acl_addr * a = l->data;
    152         if( testAddress( a, &tmp ) ) {
    153             return a->flag == '+';
    154         }
     127    for( acl=server->acl; acl && *acl; )
     128    {
     129        const char * delimiter = strchr( acl, ',' );
     130        const int len = delimiter ? delimiter-acl : (int)strlen( acl );
     131        char * token = tr_strndup( acl, len );
     132        const int match = tr_wildmat( address, token+1 );
     133        tr_free( token );
     134        if( match )
     135            return *acl == '+';
     136        if( !delimiter )
     137            break;
     138        acl = delimiter + 1;
    155139    }
    156140
    157141    return 0;
    158 }
    159 
    160 static tr_list*
    161 parseACL( const char * acl, int * err )
    162 {
    163     tr_list * list = NULL;
    164 
    165     *err = 0;
    166 
    167     for( ;; )
    168     {
    169         const char flag = *acl++;
    170         struct acl_addr tmp;
    171 
    172         if( ( flag!='+' && flag!='-' ) || !parseAddress( acl, &tmp, &acl ) )
    173         {
    174             *err = 1;
    175             tr_list_free( &list, tr_free );
    176             return NULL;
    177         }
    178 
    179         tmp.flag = flag;
    180         tr_list_append( &list, tr_memdup( &tmp, sizeof( struct acl_addr ) ) );
    181         if( !*acl )
    182             return list;
    183         ++acl;
    184     }
    185142}
    186143
     
    190147
    191148static void
     149send_simple_response( struct evhttp_request * req, int code, const char * text )
     150{
     151    const char * code_text = tr_webGetResponseStr( code );
     152    struct evbuffer * body = evbuffer_new( );
     153    evbuffer_add_printf( body, "<h1>%s</h1>", text ? text : code_text );
     154    evhttp_send_reply( req, code, code_text, body );
     155    evbuffer_free( body );
     156}
     157
     158static void
    192159handle_upload( struct evhttp_request * req, struct tr_rpc_server * server )
    193160{
    194161    if( req->type != EVHTTP_REQ_POST )
    195162    {
    196         evhttp_send_reply( req, HTTP_BADREQUEST, "Bad Request", NULL );
     163        send_simple_response( req, HTTP_BADREQUEST, NULL );
    197164    }
    198165    else
     
    214181
    215182        const char * delim = tr_memmem( in, inlen, boundary, boundary_len );
    216         if( delim ) do
     183        while( delim )
    217184            {
    218185                size_t       part_len;
     
    264231                }
    265232            }
    266             while( delim );
    267233
    268234        tr_free( boundary );
     
    271237           * see http://www.malsup.com/jquery/form/#sample7 for details */
    272238        evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=UTF-8" );
    273         evhttp_send_reply( req, HTTP_OK, "Success", NULL );
     239        send_simple_response( req, HTTP_OK, NULL );
    274240    }
    275241}
     
    306272    {
    307273        evhttp_add_header(req->output_headers, "Allow", "GET");
    308         evhttp_send_reply(req, 405, "Method Not Allowed", NULL);
     274        send_simple_response( req, 405, NULL );
    309275    }
    310276    else
    311277    {
    312278        const int fd = open( path, O_RDONLY, 0 );
    313         if( fd != -1 )
     279        if( fd == -1 )
     280        {
     281            send_simple_response( req, HTTP_NOTFOUND, NULL );
     282        }
     283        else
    314284        {
    315285            char size[12];
     
    320290            snprintf(size, sizeof(size), "%zu", EVBUFFER_LENGTH( buf ) );
    321291            evhttp_add_header(req->output_headers, "Content-Length", size );
    322             evhttp_send_reply(req, HTTP_OK, "OK", buf);
     292            evhttp_send_reply( req, HTTP_OK, "OK", buf );
    323293
    324294            evbuffer_free(buf);
    325295            close( fd );
    326296        }
    327         else
    328         {
    329             struct evbuffer * buf = evbuffer_new();
    330             evbuffer_add_printf(buf, "<h1>Not Found</h1>");
    331             evhttp_send_reply(req, HTTP_NOTFOUND, "Not Found", buf);
    332             evbuffer_free(buf);
    333         }
    334297    }
    335298}
     
    345308    evbuffer_add_printf( buf, "%s%s", tr_getClutchDir( server->session ), TR_PATH_DELIMITER_STR );
    346309    uri = req->uri + 18;
    347     if( !*uri || (*uri=='?') )
     310    if( (*uri=='?') || (*uri=='\0') )
    348311        evbuffer_add_printf( buf, "index.html" );
    349312    else {
     
    405368        char * pass = NULL;
    406369
    407         evhttp_add_header( req->output_headers, "Server", "Transmission" );
     370        evhttp_add_header( req->output_headers, "Server", MY_REALM );
    408371       
    409372        auth = evhttp_find_header( req->input_headers, "Authorization" );
     
    419382        }
    420383
    421         if( server->acl_list && !isAddressAllowed( server, req->remote_host ) )
    422         {
    423             struct evbuffer * buf = evbuffer_new();
    424             evbuffer_add_printf(buf, "<h1>Unauthorized IP Address</h1>");
    425             evhttp_send_reply(req, 401, "Unauthorized", buf );
     384        if( server->acl && !isAddressAllowed( server, req->remote_host ) )
     385        {
     386            send_simple_response( req, 401, "Unauthorized IP Address" );
    426387        }
    427388        else if( server->isPasswordEnabled && (    !pass
     
    430391                                                || strcmp( server->password, pass ) ) )
    431392        {
    432             struct evbuffer * buf = evbuffer_new();
    433393            evhttp_add_header( req->output_headers,
    434                 "WWW-Authenticate", "Basic realm=\"Transmission\"");
    435             evbuffer_add_printf(buf, "<h1>Unauthorized User</h1>");
    436             evhttp_send_reply(req, 401, "Unauthorized", buf);
     394                "WWW-Authenticate", "Basic realm=\"" MY_REALM "\"" );
     395            send_simple_response( req, 401, "Unauthorized User" );
    437396        }
    438397        else if( !strcmp( req->uri, "/transmission/web" ) ||
     
    441400        {
    442401            evhttp_add_header( req->output_headers, "Location", "/transmission/web/" );
    443             evhttp_send_reply(req, HTTP_MOVEPERM, "Moved Permanently", NULL );
     402            send_simple_response( req, HTTP_MOVEPERM, NULL );
    444403        }
    445404        else if( !strncmp( req->uri, "/transmission/web/", 18 ) )
     
    457416        else
    458417        {
    459             struct evbuffer *buf = evbuffer_new( );
    460             evbuffer_add_printf(buf, "<h1>Not Found</h1>");
    461             evhttp_send_reply(req, HTTP_NOTFOUND, "Not Found", buf);
     418            send_simple_response( req, HTTP_NOTFOUND, NULL );
    462419        }
    463420
     
    501458tr_rpcIsEnabled( const tr_rpc_server * server )
    502459{
    503     return server->httpd != NULL;
     460    return server->isEnabled;
    504461}
    505462
     
    526483}
    527484
    528 int
    529 tr_rpcTestACL( const tr_rpc_server  * server UNUSED,
    530                const char *                  acl,
    531                char **                       setme_errmsg )
    532 {
    533     int err = 0;
    534     tr_list * list = parseACL( acl, &err );
    535     if( err )
    536         *setme_errmsg = tr_strdup( "invalid ACL" );
    537     tr_list_free( &list, tr_free );
    538     return err;
    539 }
    540 
    541 int
     485void
    542486tr_rpcSetACL( tr_rpc_server * server,
    543               const char *    acl_str,
    544               char **         setme_errmsg )
    545 {
    546     int err = 0;
    547     tr_list * list = parseACL( acl_str, &err );
    548 
    549     if( err )
    550     {
    551         *setme_errmsg = tr_strdup( "invalid ACL" );
    552     }
    553     else
    554     {
    555         tr_free( server->acl_str );
    556         tr_list_free( &server->acl_list, tr_free );
    557         server->acl_str = tr_strdup( acl_str );
    558         server->acl_list = list;
    559     }
    560 
    561     return err;
     487              const char *    acl )
     488{
     489    tr_free( server->acl );
     490    server->acl = tr_strdup( acl );
    562491}
    563492
     
    565494tr_rpcGetACL( const tr_rpc_server * server )
    566495{
    567     return tr_strdup( server->acl_str ? server->acl_str : "" );
     496    return tr_strdup( server->acl ? server->acl : "" );
    568497}
    569498
     
    606535                          int             isEnabled )
    607536{
    608     server->isPasswordEnabled = isEnabled;
     537    server->isPasswordEnabled = isEnabled != 0;
    609538    dbgmsg( "setting 'password enabled' to %d", isEnabled );
    610539}
     
    628557
    629558    stopServer( s );
    630     tr_list_free( &s->acl_list, tr_free );
    631     tr_free( s->acl_str );
     559    tr_free( s->acl );
    632560    tr_free( s->username );
    633561    tr_free( s->password );
     
    639567            int          isEnabled,
    640568            int          port,
    641             const char * acl_str,
     569            const char * acl,
    642570            int          isPasswordEnabled,
    643571            const char * username,
     
    645573{
    646574    tr_rpc_server * s;
    647     int err = 0;
    648     tr_list * list = parseACL( acl_str, &err );
    649 
    650     if( err ) {
    651         acl_str = TR_DEFAULT_RPC_ACL;
    652         tr_nerr( MY_NAME, "using fallback ACL \"%s\"", acl_str );
    653         list = parseACL( acl_str, &err );
    654     }
    655575
    656576    s = tr_new0( tr_rpc_server, 1 );
    657577    s->session = session;
    658578    s->port = port;
    659     s->acl_str = tr_strdup( acl_str );
    660     s->acl_list = list;
     579    s->acl = tr_strdup( acl && *acl ? acl : TR_DEFAULT_RPC_ACL );
    661580    s->username = tr_strdup( username );
    662581    s->password = tr_strdup( password );
Note: See TracChangeset for help on using the changeset viewer.