Changeset 6798


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.

Location:
trunk
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/gtk/main.c

    r6795 r6798  
    11961196    {
    11971197        const char * s = pref_string_get( key );
    1198         tr_sessionSetRPCACL( tr, s, NULL );
     1198        tr_sessionSetRPCACL( tr, s );
    11991199    }
    12001200    else if( !strcmp( key, PREF_KEY_RPC_USERNAME ) )
  • trunk/gtk/tr-prefs.c

    r6795 r6798  
    684684
    685685    acl = g_strdup_printf( "+%s", new_text );
    686     if( !tr_sessionTestRPCACL( session, acl, NULL ) )
    687         if( gtk_tree_model_get_iter( model, &iter, path ) )
    688             gtk_list_store_set( page->store, &iter, COL_ADDRESS, new_text,
    689                                 -1 );
     686    if( gtk_tree_model_get_iter( model, &iter, path ) )
     687        gtk_list_store_set( page->store, &iter, COL_ADDRESS, new_text, -1 );
    690688
    691689    g_free( acl );
  • trunk/libtransmission/Makefile.am

    r6797 r6798  
    4949    verify.c \
    5050    web.c \
    51     webseed.c
     51    webseed.c \
     52    wildmat.c
    5253
    5354noinst_HEADERS = \
  • 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 );
  • trunk/libtransmission/rpc-server.h

    r6795 r6798  
    4040                               char **               allocme_errmsg );
    4141
    42 int             tr_rpcTestACL( const tr_rpc_server * server,
    43                                const char *          acl,
    44                                char **               allocme_errmsg );
    45 
    46 int             tr_rpcSetACL( tr_rpc_server * server,
    47                               const char *    acl,
    48                               char **         allocme_errmsg );
     42void            tr_rpcSetACL( tr_rpc_server * server,
     43                              const char *    acl );
    4944
    5045char*           tr_rpcGetACL( const tr_rpc_server * server );
  • trunk/libtransmission/session.c

    r6795 r6798  
    10031003}
    10041004
    1005 int
    1006 tr_sessionTestRPCACL( const tr_session * session,
    1007                       const char *       acl,
    1008                       char **            allocme_errmsg )
    1009 {
    1010     return tr_rpcTestACL( session->rpcServer, acl, allocme_errmsg );
    1011 }
    1012 
    1013 int
     1005void
    10141006tr_sessionSetRPCACL( tr_session * session,
    1015                      const char * acl,
    1016                      char **      allocme_errmsg )
    1017 {
    1018     return tr_rpcSetACL( session->rpcServer, acl, allocme_errmsg );
     1007                     const char * acl )
     1008{
     1009    return tr_rpcSetACL( session->rpcServer, acl );
    10191010}
    10201011
  • trunk/libtransmission/transmission.h

    r6795 r6798  
    347347
    348348/**
    349  * @brief test an ACL's syntax without modifying the RPC settings.
    350  *
    351  * ACL is a comma separated list of IP subnets, each subnet is prepended
    352  * by a '+' or '-' sign to denote 'allow' or 'deny'.  If the subnet mask
    353  * is omitted, like "-1.2.3.4", it means a single IP address. The mask
    354  * may vary from 0 to 32 inclusive.  A simple primer on x.x.x.x/n notation
    355  * can be found at <http://25yearsofprogramming.com/blog/20070803.htm>.
    356  *
    357  * Since wildcards are more familiar to most users than netmasks,
    358  * libtransmission supports a wildcard notation that it
    359  * converts into cidr required by the embedded http server.
    360  * So, notation like "+192.168.*.*" is accepted by libtransmission and is
    361  * converted to "+192.168.0.0/16" before it reaches the server.
    362 
    363  * @param acl the ACL to test
    364  * @param allocme_errmsg If the ACL can't be parsed, this is set to a
    365  *                       newly-allocated error string describing the problem.
    366  *                       The client should tr_free() this string when done.
    367  * @return 0 on success, -1 on failure due to an unparseable ACL.
    368  */
    369 int tr_sessionTestRPCACL( const tr_handle * session,
    370                           const char *      acl,
    371                           char **           allocme_errmsg );
    372 
    373 /**
    374349 * @brief Specify access control list (ACL).
    375    ACL is a comma separated list
    376  * of IP subnets, each subnet is prepended by a '-' or '+' sign.
    377  * Plus means allow, minus means deny. If the subnet mask is omitted,
    378  * like "-1.2.3.4", it means a single IP address. The mask may vary
    379  * from 0 to 32 inclusive.
    380  *
    381  * http://25yearsofprogramming.com/blog/20070803.htm has a simple
    382  * primer on x.x.x.x/n notation for those interested.
    383  *
    384  * The parameters and return value follow the same behavior as
    385  * tr_sessionTestRPCACL().
    386  *
    387  * @see tr_sessionTestRPCACL
    388  * @see tr_sessionInitFull
    389  * @see tr_sessionGetRPCACL
    390  */
    391 int   tr_sessionSetRPCACL( tr_session * session,
    392                            const char * acl,
    393                            char **      allocme_errmsg );
     350 *
     351 * ACL is a comma-delimited list of dotted-quad IP addresses, each preceded
     352 * by a '+' or '-' sign to denote 'allow' or 'deny'.  Wildmat notation is
     353 * supported, meaning that '?' is interpreted as a single-character wildcard
     354 * and '*' is interprted as a multi-character wildcard.
     355 */
     356void   tr_sessionSetRPCACL( tr_session * session,
     357                            const char * acl );
    394358
    395359/** @brief get the Access Control List for allowing/denying RPC requests.
  • trunk/libtransmission/utils.h

    r6795 r6798  
    123123#define tr_inf( a... ) tr_msg( __FILE__, __LINE__, TR_MSG_INF, NULL, ## a )
    124124#define tr_dbg( a... ) tr_msg( __FILE__, __LINE__, TR_MSG_DBG, NULL, ## a )
     125
     126int            tr_wildmat( const char * text,
     127                           const char * pattern );
    125128
    126129void           tr_msgInit( void );
Note: See TracChangeset for help on using the changeset viewer.