Changeset 6797
- Timestamp:
- Sep 25, 2008, 5:03:39 AM (13 years ago)
- Location:
- trunk
- Files:
-
- 29 deleted
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/cli/Makefile.am
r6302 r6797 10 10 transmissioncli_LDADD = \ 11 11 $(top_builddir)/libtransmission/libtransmission.a \ 12 $(top_builddir)/third-party/libevent/libevent _core.la \12 $(top_builddir)/third-party/libevent/libevent.la \ 13 13 $(top_builddir)/third-party/libnatpmp/libnatpmp.a \ 14 14 $(top_builddir)/third-party/miniupnp/libminiupnp.a \ 15 $(top_builddir)/third-party/shttpd/libshttpd.a \16 15 $(INTLLIBS) \ 17 16 $(OPENSSL_LIBS) \ -
trunk/configure.ac
r6775 r6797 326 326 third-party/miniupnp/Makefile 327 327 third-party/libnatpmp/Makefile 328 third-party/shttpd/Makefile329 328 macosx/Makefile 330 329 wx/Makefile -
trunk/daemon/Makefile.am
r6297 r6797 12 12 LDADD = \ 13 13 $(top_builddir)/libtransmission/libtransmission.a \ 14 $(top_builddir)/third-party/shttpd/libshttpd.a \15 14 $(top_builddir)/third-party/miniupnp/libminiupnp.a \ 16 15 $(top_builddir)/third-party/libnatpmp/libnatpmp.a \ 17 $(top_builddir)/third-party/libevent/libevent _core.la \16 $(top_builddir)/third-party/libevent/libevent.la \ 18 17 $(INTLLIBS) \ 19 18 $(OPENSSL_LIBS) \ -
trunk/gtk/Makefile.am
r6727 r6797 83 83 transmission_LDADD = \ 84 84 $(top_builddir)/libtransmission/libtransmission.a \ 85 $(top_builddir)/third-party/libevent/libevent _core.la \85 $(top_builddir)/third-party/libevent/libevent.la \ 86 86 $(top_builddir)/third-party/miniupnp/libminiupnp.a \ 87 87 $(top_builddir)/third-party/libnatpmp/libnatpmp.a \ 88 $(top_builddir)/third-party/shttpd/libshttpd.a \89 88 $(GTK_LIBS) \ 90 89 $(GIO_LIBS) \ -
trunk/libtransmission/Makefile.am
r6703 r6797 110 110 APPS_LDADD = \ 111 111 ./libtransmission.a \ 112 $(top_builddir)/third-party/shttpd/libshttpd.a \113 112 $(top_builddir)/third-party/miniupnp/libminiupnp.a \ 114 113 $(top_builddir)/third-party/libnatpmp/libnatpmp.a \ -
trunk/libtransmission/rpc-server.c
r6795 r6797 16 16 #include <stdlib.h> /* strtol */ 17 17 #include <string.h> 18 #include <limits.h> /* INT_MAX */ 19 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <fcntl.h> /* open */ 18 23 19 24 #include <unistd.h> /* unlink */ 20 25 21 26 #include <libevent/event.h> 22 #include <shttpd/defs.h> /* edit_passwords */ 23 #include <shttpd/shttpd.h> 27 #include <libevent/evhttp.h> 24 28 25 29 #include "transmission.h" … … 37 41 #define INACTIVE_INTERVAL_MSEC 200 38 42 43 #define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( *ary ) ) 44 45 struct acl_addr 46 { 47 char flag; 48 char parts[4][20]; 49 }; 50 39 51 struct tr_rpc_server 40 52 { … … 43 55 int port; 44 56 time_t lastRequestTime; 45 struct shttpd_ctx * ctx;57 struct evhttp * httpd; 46 58 tr_handle * session; 47 struct event timer;48 59 char * username; 49 60 char * password; 50 char * acl ;51 tr_list * connections;61 char * acl_str; 62 tr_list * acl_list; /* struct acl_addr */ 52 63 }; 53 64 … … 72 83 } 73 84 85 86 /**** 87 ***** ACL UTILITIES 88 ****/ 89 90 static int 91 parseAddress( const char * addr, struct acl_addr * setme, const char ** end ) 92 { 93 const char * pch; 94 95 memset( setme, 0, sizeof( struct acl_addr ) ); 96 97 if( !addr ) return 0; 98 99 if(!((pch = strchr( addr, '.' )))) return 0; 100 if( pch-addr > 20 ) return 0; 101 memcpy( setme->parts[0], addr, pch-addr ); 102 addr = pch + 1; 103 104 if(!((pch = strchr( addr, '.' )))) return 0; 105 if( pch-addr > 20 ) return 0; 106 memcpy( setme->parts[1], addr, pch-addr ); 107 addr = pch + 1; 108 109 if(!((pch = strchr( addr, '.' )))) return 0; 110 if( pch-addr > 20 ) return 0; 111 memcpy( setme->parts[2], addr, pch-addr ); 112 addr = pch + 1; 113 114 while( *pch && *pch!=',' ) ++pch; 115 if( pch-addr > 20 ) return 0; 116 memcpy( setme->parts[3], addr, pch-addr ); 117 118 *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 135 return 1; 136 } 137 138 static int 139 isAddressAllowed( const tr_rpc_server * server, 140 const char * address ) 141 { 142 struct acl_addr tmp; 143 const char * end; 144 const int parsed = parseAddress( address, &tmp, &end ); 145 tr_list * l; 146 147 if( !parsed ) 148 return 0; 149 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 } 155 } 156 157 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 } 185 } 186 74 187 /** 75 188 *** 76 189 **/ 77 190 78 struct ConnBuf79 {80 char * key;81 time_t lastActivity;82 struct evbuffer * in;83 struct evbuffer * out;84 };85 86 static char*87 buildKey( struct shttpd_arg * arg )88 {89 return tr_strdup_printf( "%s %s",90 shttpd_get_env( arg, "REMOTE_ADDR" ),91 shttpd_get_env( arg, "REQUEST_URI" ) );92 }93 94 static struct ConnBuf*95 getBuffer(96 tr_rpc_server * server,97 struct shttpd_arg * arg )98 {99 tr_list * l;100 char * key = buildKey( arg );101 struct ConnBuf * found = NULL;102 103 for( l = server->connections; l && !found; l = l->next )104 {105 struct ConnBuf * buf = l->data;106 if( !strcmp( key, buf->key ) )107 found = buf;108 }109 110 if( found == NULL )111 {112 found = tr_new0( struct ConnBuf, 1 );113 found->lastActivity = time( NULL );114 found->key = tr_strdup( key );115 found->in = evbuffer_new( );116 found->out = evbuffer_new( );117 tr_list_append( &server->connections, found );118 }119 120 tr_free( key );121 return found;122 }123 124 191 static void 125 pruneBuf( tr_rpc_server * server, 126 struct ConnBuf * buf ) 127 { 128 tr_list_remove_data( &server->connections, buf ); 129 130 evbuffer_free( buf->in ); 131 evbuffer_free( buf->out ); 132 tr_free( buf->key ); 133 tr_free( buf ); 134 } 135 136 /** 137 *** 138 **/ 139 140 static void 141 handle_upload( struct shttpd_arg * arg ) 142 { 143 struct tr_rpc_server * s; 144 struct ConnBuf * cbuf; 145 146 s = arg->user_data; 147 s->lastRequestTime = time( NULL ); 148 cbuf = getBuffer( s, arg ); 149 150 /* if we haven't parsed the POST, do that now */ 151 if( !EVBUFFER_LENGTH( cbuf->out ) ) 152 { 153 const char * query_string; 154 const char * content_type; 155 const char * delim; 156 const char * in; 157 size_t inlen; 158 char * boundary; 159 size_t boundary_len; 160 char buf[64]; 161 int paused; 162 163 /* if we haven't finished reading the POST, read more now */ 164 evbuffer_add( cbuf->in, arg->in.buf, arg->in.len ); 165 arg->in.num_bytes = arg->in.len; 166 if( arg->flags & SHTTPD_MORE_POST_DATA ) 167 return; 168 169 query_string = shttpd_get_env( arg, "QUERY_STRING" ); 170 content_type = shttpd_get_header( arg, "Content-Type" ); 171 in = (const char *) EVBUFFER_DATA( cbuf->in ); 172 inlen = EVBUFFER_LENGTH( cbuf->in ); 173 boundary = 192 handle_upload( struct evhttp_request * req, struct tr_rpc_server * server ) 193 { 194 if( req->type != EVHTTP_REQ_POST ) 195 { 196 evhttp_send_reply( req, HTTP_BADREQUEST, "Bad Request", NULL ); 197 } 198 else 199 { 200 201 const char * content_type = evhttp_find_header( req->input_headers, "Content-Type" ); 202 203 const char * query = strchr( req->uri, '?' ); 204 const int paused = query && strstr( query+1, "paused=true" ); 205 206 const char * in = (const char *) EVBUFFER_DATA( req->input_buffer ); 207 size_t inlen = EVBUFFER_LENGTH( req->input_buffer ); 208 209 char * boundary = 174 210 tr_strdup_printf( "--%s", strstr( content_type, 175 211 "boundary=" ) + 176 212 strlen( "boundary=" ) ); 177 boundary_len = strlen( boundary ); 178 paused = ( query_string != NULL ) 179 && ( shttpd_get_var( "paused", query_string, 180 strlen( query_string ), buf, 181 sizeof( buf ) ) == 4 ) 182 && ( !strcmp( buf, "true" ) ); 183 184 delim = tr_memmem( in, inlen, boundary, boundary_len ); 213 const size_t boundary_len = strlen( boundary ); 214 215 const char * delim = tr_memmem( in, inlen, boundary, boundary_len ); 185 216 if( delim ) do 186 217 { … … 220 251 json = tr_bencSaveAsJSON( &top, &json_len ); 221 252 freeme = 222 tr_rpc_request_exec_json( s ->session, json,223 json _len,253 tr_rpc_request_exec_json( server->session, 254 json, json_len, 224 255 NULL ); 225 256 … … 235 266 while( delim ); 236 267 237 evbuffer_drain( cbuf->in, EVBUFFER_LENGTH( cbuf->in ) );238 268 tr_free( boundary ); 239 269 240 { 241 /* use xml here because json responses to file uploads is trouble. 242 * see http://www.malsup.com/jquery/form/#sample7 for details */ 243 const char * response = "<result>success</result>"; 244 const int len = strlen( response ); 245 evbuffer_add_printf( 246 cbuf->out, "HTTP/1.1 200 OK\r\n" 247 "Content-Type: text/xml; charset=UTF-8\r\n" 248 "Content-Length: %d\r\n" 249 "\r\n" 250 "%s\r\n", len, response ); 251 } 252 } 253 254 if( EVBUFFER_LENGTH( cbuf->out ) ) 255 { 256 const int n = MIN( ( int )EVBUFFER_LENGTH( 257 cbuf->out ), arg->out.len ); 258 memcpy( arg->out.buf, EVBUFFER_DATA( cbuf->out ), n ); 259 evbuffer_drain( cbuf->out, n ); 260 arg->out.num_bytes = n; 261 } 262 263 if( !EVBUFFER_LENGTH( cbuf->out ) ) 264 { 265 arg->flags |= SHTTPD_END_OF_OUTPUT; 266 pruneBuf( s, cbuf ); 267 } 270 /* use xml here because json responses to file uploads is trouble. 271 * see http://www.malsup.com/jquery/form/#sample7 for details */ 272 evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=UTF-8" ); 273 evhttp_send_reply( req, HTTP_OK, "Success", NULL ); 274 } 275 } 276 277 static const char* 278 mimetype_guess( const char * path ) 279 { 280 unsigned int i; 281 const struct { 282 const char * suffix; 283 const char * mime_type; 284 } types[] = { 285 /* these are just the ones we need for serving clutch... */ 286 { "css", "text/css" }, 287 { "gif", "image/gif" }, 288 { "html", "text/html" }, 289 { "ico", "image/vnd.microsoft.icon" }, 290 { "js", "application/javascript" }, 291 { "png", "image/png" } 292 }; 293 const char * dot = strrchr( path, '.' ); 294 295 for( i=0; dot && i<TR_N_ELEMENTS(types); ++i ) 296 if( !strcmp( dot+1, types[i].suffix ) ) 297 return types[i].mime_type; 298 299 return "application/octet-stream"; 268 300 } 269 301 270 302 static void 271 handle_root( struct shttpd_arg * arg ) 272 { 273 const char * redirect = "HTTP/1.1 200 OK" "\r\n" 274 "Content-Type: text/html; charset=UTF-8" 275 "\r\n" 276 "\r\n" 277 "<html><head>" 278 "\r\n" 279 " <meta http-equiv=\"Refresh\" content=\"2; url=/transmission/web/\">" 280 "\r\n" 281 "</head><body>" 282 "\r\n" 283 " <p>redirecting to <a href=\"/transmission/web\">/transmission/web/</a></p>" 284 "\r\n" 285 "</body></html>" 286 "\r\n"; 287 const size_t n = strlen( redirect ); 288 289 memcpy( arg->out.buf, redirect, n ); 290 arg->in.num_bytes = arg->in.len; 291 arg->out.num_bytes = n; 292 arg->flags |= SHTTPD_END_OF_OUTPUT; 303 serve_file( struct evhttp_request * req, const char * path ) 304 { 305 if( req->type != EVHTTP_REQ_GET ) 306 { 307 evhttp_add_header(req->output_headers, "Allow", "GET"); 308 evhttp_send_reply(req, 405, "Method Not Allowed", NULL); 309 } 310 else 311 { 312 const int fd = open( path, O_RDONLY, 0 ); 313 if( fd != -1 ) 314 { 315 char size[12]; 316 struct evbuffer * buf = evbuffer_new(); 317 318 evbuffer_read(buf, fd, INT_MAX ); 319 evhttp_add_header(req->output_headers, "Content-Type", mimetype_guess( path ) ); 320 snprintf(size, sizeof(size), "%zu", EVBUFFER_LENGTH( buf ) ); 321 evhttp_add_header(req->output_headers, "Content-Length", size ); 322 evhttp_send_reply(req, HTTP_OK, "OK", buf); 323 324 evbuffer_free(buf); 325 close( fd ); 326 } 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 } 334 } 293 335 } 294 336 295 337 static void 296 handle_rpc( struct shttpd_arg * arg ) 297 { 298 struct tr_rpc_server * s; 299 struct ConnBuf * cbuf; 300 301 s = arg->user_data; 302 s->lastRequestTime = time( NULL ); 303 cbuf = getBuffer( s, arg ); 304 305 if( !EVBUFFER_LENGTH( cbuf->out ) ) 306 { 307 int len = 0; 308 char * response = NULL; 309 const char * request_method = shttpd_get_env( arg, "REQUEST_METHOD" ); 310 const char * query_string = shttpd_get_env( arg, "QUERY_STRING" ); 311 312 if( query_string && *query_string ) 313 response = tr_rpc_request_exec_uri( s->session, 314 query_string, 315 strlen( query_string ), 338 handle_clutch( struct evhttp_request * req, struct tr_rpc_server * server ) 339 { 340 const char * uri; 341 struct evbuffer * buf = evbuffer_new( ); 342 343 assert( !strncmp( req->uri, "/transmission/web/", 18 ) ); 344 345 evbuffer_add_printf( buf, "%s%s", tr_getClutchDir( server->session ), TR_PATH_DELIMITER_STR ); 346 uri = req->uri + 18; 347 if( !*uri || (*uri=='?') ) 348 evbuffer_add_printf( buf, "index.html" ); 349 else { 350 const char * pch; 351 if(( pch = strchr( uri, '?' ))) 352 evbuffer_add_printf( buf, "%*.*s", (int)(pch-uri), (int)(pch-uri), uri ); 353 else 354 evbuffer_add_printf( buf, "%s", uri ); 355 } 356 357 if( strstr( (const char *)EVBUFFER_DATA( buf ), ".." ) ) 358 serve_file( req, "/dev/null" ); 359 else 360 serve_file( req, (const char *)EVBUFFER_DATA( buf ) ); 361 362 evbuffer_free( buf ); 363 } 364 365 static void 366 handle_rpc( struct evhttp_request * req, struct tr_rpc_server * server ) 367 { 368 int len = 0; 369 char * response; 370 struct evbuffer * buf; 371 372 if( req->type == EVHTTP_REQ_GET ) 373 { 374 const char * q; 375 if(( q = strchr( req->uri, '?' ))) 376 response = tr_rpc_request_exec_uri( server->session, 377 q + 1, 378 strlen( q + 1 ), 316 379 &len ); 317 else if( !strcmp( request_method, "POST" ) ) 318 { 319 evbuffer_add( cbuf->in, arg->in.buf, arg->in.len ); 320 arg->in.num_bytes = arg->in.len; 321 if( arg->flags & SHTTPD_MORE_POST_DATA ) 322 return; 323 response = tr_rpc_request_exec_json( s->session, 324 EVBUFFER_DATA( cbuf->in ), 325 EVBUFFER_LENGTH( cbuf->in ), 326 &len ); 327 evbuffer_drain( cbuf->in, EVBUFFER_LENGTH( cbuf->in ) ); 328 } 329 330 evbuffer_add_printf( 331 cbuf->out, "HTTP/1.1 200 OK\r\n" 332 "Content-Type: application/json; charset=UTF-8\r\n" 333 "Content-Length: %d\r\n" 334 "\r\n" 335 "%*.*s", len, len, len, response ); 336 tr_free( response ); 337 } 338 339 if( EVBUFFER_LENGTH( cbuf->out ) ) 340 { 341 const int n = MIN( ( int )EVBUFFER_LENGTH( 342 cbuf->out ), arg->out.len ); 343 memcpy( arg->out.buf, EVBUFFER_DATA( cbuf->out ), n ); 344 evbuffer_drain( cbuf->out, n ); 345 arg->out.num_bytes = n; 346 } 347 348 if( !EVBUFFER_LENGTH( cbuf->out ) ) 349 { 350 arg->flags |= SHTTPD_END_OF_OUTPUT; 351 pruneBuf( s, cbuf ); 352 } 380 } 381 else if( req->type == EVHTTP_REQ_POST ) 382 { 383 response = tr_rpc_request_exec_json( server->session, 384 EVBUFFER_DATA( req->input_buffer ), 385 EVBUFFER_LENGTH( req->input_buffer ), 386 &len ); 387 } 388 389 buf = evbuffer_new( ); 390 evbuffer_add( buf, response, len ); 391 evhttp_add_header( req->output_headers, "Content-Type", "application/json; charset=UTF-8" ); 392 evhttp_send_reply( req, HTTP_OK, "OK", buf ); 393 evbuffer_free( buf ); 353 394 } 354 395 355 396 static void 356 rpcPulse( int socket UNUSED, 357 short action UNUSED, 358 void * vserver ) 359 { 360 int interval; 361 struct timeval tv; 362 tr_rpc_server * server = vserver; 363 const time_t now = time( NULL ); 364 365 assert( server ); 366 367 if( server->ctx ) 368 shttpd_poll( server->ctx, 1 ); 369 370 /* set a timer for the next pulse */ 371 if( now - server->lastRequestTime < 300 ) 372 interval = ACTIVE_INTERVAL_MSEC; 373 else 374 interval = INACTIVE_INTERVAL_MSEC; 375 tv = tr_timevalMsec( interval ); 376 evtimer_add( &server->timer, &tv ); 377 } 378 379 static void 380 getPasswordFile( tr_rpc_server * server, 381 char * buf, 382 int buflen ) 383 { 384 tr_buildPath( buf, buflen, tr_sessionGetConfigDir( server->session ), 385 "htpasswd", 386 NULL ); 397 handle_request( struct evhttp_request * req, void * arg ) 398 { 399 struct tr_rpc_server * server = arg; 400 401 if (req && req->evcon ) 402 { 403 const char * auth; 404 char * user = NULL; 405 char * pass = NULL; 406 407 evhttp_add_header( req->output_headers, "Server", "Transmission" ); 408 409 auth = evhttp_find_header( req->input_headers, "Authorization" ); 410 411 if( auth && !strncasecmp( auth, "basic ", 6 ) ) 412 { 413 int plen; 414 char * p = tr_base64_decode( auth + 6, 0, &plen ); 415 if( p && plen && (( pass = strchr( p, ':' )))) { 416 user = p; 417 *pass++ = '\0'; 418 } 419 } 420 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 ); 426 } 427 else if( server->isPasswordEnabled && ( !pass 428 || !user 429 || strcmp( server->username, user ) 430 || strcmp( server->password, pass ) ) ) 431 { 432 struct evbuffer * buf = evbuffer_new(); 433 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); 437 } 438 else if( !strcmp( req->uri, "/transmission/web" ) || 439 !strcmp( req->uri, "/transmission/clutch" ) || 440 !strcmp( req->uri, "/" ) ) 441 { 442 evhttp_add_header( req->output_headers, "Location", "/transmission/web/" ); 443 evhttp_send_reply(req, HTTP_MOVEPERM, "Moved Permanently", NULL ); 444 } 445 else if( !strncmp( req->uri, "/transmission/web/", 18 ) ) 446 { 447 handle_clutch( req, server ); 448 } 449 else if( !strncmp( req->uri, "/transmission/rpc", 17 ) ) 450 { 451 handle_rpc( req, server ); 452 } 453 else if( !strncmp( req->uri, "/transmission/upload", 20 ) ) 454 { 455 handle_upload( req, server ); 456 } 457 else 458 { 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); 462 } 463 464 tr_free( user ); 465 } 387 466 } 388 467 … … 390 469 startServer( tr_rpc_server * server ) 391 470 { 392 dbgmsg( "in startServer; current context is %p", server->ctx ); 393 394 if( !server->ctx ) 395 { 396 int i; 397 int argc = 0; 398 char * argv[100]; 399 char passwd[MAX_PATH_LENGTH]; 400 const char * clutchDir = tr_getClutchDir( server->session ); 401 struct timeval tv = tr_timevalMsec( INACTIVE_INTERVAL_MSEC ); 402 403 getPasswordFile( server, passwd, sizeof( passwd ) ); 404 if( !server->isPasswordEnabled ) 405 unlink( passwd ); 406 else 407 shttpd_edit_passwords( passwd, MY_REALM, server->username, 408 server->password ); 409 410 argv[argc++] = tr_strdup( "appname-unused" ); 411 412 argv[argc++] = tr_strdup( "-ports" ); 413 argv[argc++] = tr_strdup_printf( "%d", server->port ); 414 415 argv[argc++] = tr_strdup( "-dir_list" ); 416 argv[argc++] = tr_strdup( "0" ); 417 418 argv[argc++] = tr_strdup( "-auth_realm" ); 419 argv[argc++] = tr_strdup( MY_REALM ); 420 421 argv[argc++] = tr_strdup( "-root" ); 422 argv[argc++] = tr_strdup( "/dev/null" ); 423 424 if( server->acl ) 425 { 426 argv[argc++] = tr_strdup( "-acl" ); 427 argv[argc++] = tr_strdup( server->acl ); 428 } 429 if( server->isPasswordEnabled ) 430 { 431 argv[argc++] = tr_strdup( "-protect" ); 432 argv[argc++] = tr_strdup_printf( "/transmission=%s", passwd ); 433 } 434 if( clutchDir && *clutchDir ) 435 { 436 tr_inf( _( 437 "Serving the web interface files from \"%s\"" ), 438 clutchDir ); 439 argv[argc++] = tr_strdup( "-aliases" ); 440 argv[argc++] = tr_strdup_printf( "%s=%s,%s=%s", 441 "/transmission/clutch", 442 clutchDir, 443 "/transmission/web", 444 clutchDir ); 445 } 446 447 argv[argc] = NULL; /* shttpd_init() wants it null-terminated */ 448 449 if( ( server->ctx = shttpd_init( argc, argv ) ) ) 450 { 451 shttpd_register_uri( server->ctx, "/transmission/rpc", 452 handle_rpc, 453 server ); 454 shttpd_register_uri( server->ctx, "/transmission/upload", 455 handle_upload, 456 server ); 457 shttpd_register_uri( server->ctx, "/", handle_root, server ); 458 459 evtimer_set( &server->timer, rpcPulse, server ); 460 evtimer_add( &server->timer, &tv ); 461 } 462 463 for( i = 0; i < argc; ++i ) 464 tr_free( argv[i] ); 465 } 471 dbgmsg( "in startServer; current context is %p", server->httpd ); 472 473 if( !server->httpd ) 474 if( ( server->httpd = evhttp_start( "0.0.0.0", server->port ) ) ) 475 evhttp_set_gencb( server->httpd, handle_request, server ); 466 476 } 467 477 … … 469 479 stopServer( tr_rpc_server * server ) 470 480 { 471 if( server->ctx ) 472 { 473 char passwd[MAX_PATH_LENGTH]; 474 getPasswordFile( server, passwd, sizeof( passwd ) ); 475 unlink( passwd ); 476 477 evtimer_del( &server->timer ); 478 shttpd_fini( server->ctx ); 479 server->ctx = NULL; 481 if( server->httpd ) 482 { 483 evhttp_free( server->httpd ); 484 server->httpd = NULL; 480 485 } 481 486 } … … 496 501 tr_rpcIsEnabled( const tr_rpc_server * server ) 497 502 { 498 return server-> ctx!= NULL;503 return server->httpd != NULL; 499 504 } 500 505 … … 519 524 { 520 525 return server->port; 521 }522 523 /****524 ***** ACL525 ****/526 527 /*528 * FOR_EACH_WORD_IN_LIST, isbyte, and testACL are from, or modified from,529 * shttpd, written by Sergey Lyubka under this license:530 * "THE BEER-WARE LICENSE" (Revision 42):531 * Sergey Lyubka wrote this file. As long as you retain this notice you532 * can do whatever you want with this stuff. If we meet some day, and you think533 * this stuff is worth it, you can buy me a beer in return.534 */535 536 #define FOR_EACH_WORD_IN_LIST( s, len ) \537 for( ; s != NULL && ( len = strcspn( s, DELIM_CHARS ) ) != 0; \538 s += len, s += strspn( s, DELIM_CHARS ) )539 540 static int541 isbyte( int n ) { return n >= 0 && n <= 255; }542 543 static char*544 testACL( const char * s )545 {546 int len;547 548 FOR_EACH_WORD_IN_LIST( s, len )549 {550 char flag;551 int a, b, c, d, n, mask;552 553 if( sscanf( s, "%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n ) != 5 )554 return tr_strdup_printf( _(555 "[%s]: subnet must be [+|-]x.x.x.x[/x]" ),556 s );557 if( flag != '+' && flag != '-' )558 return tr_strdup_printf( _( "[%s]: flag must be + or -" ), s );559 if( !isbyte( a ) || !isbyte( b ) || !isbyte( c ) || !isbyte( d ) )560 return tr_strdup_printf( _( "[%s]: bad ip address" ), s );561 if( sscanf( s + n, "/%d", &mask ) == 1 && ( mask < 0 || mask > 32 ) )562 return tr_strdup_printf( _( "[%s]: bad subnet mask %d" ), s, n );563 }564 565 return NULL;566 }567 568 /* 192.*.*.* --> 192.0.0.0/8569 192.64.*.* --> 192.64.0.0/16570 192.64.1.* --> 192.64.1.0/24571 192.64.1.2 --> 192.64.1.2/32 */572 static void573 cidrizeOne( const char * in,574 int len,575 struct evbuffer * out )576 {577 int stars = 0;578 const char * pch;579 const char * end;580 char zero = '0';581 char huh = '?';582 583 for( pch = in, end = pch + len; pch != end; ++pch )584 {585 if( stars && isdigit( *pch ) )586 evbuffer_add( out, &huh, 1 );587 else if( *pch != '*' )588 evbuffer_add( out, pch, 1 );589 else590 {591 evbuffer_add( out, &zero, 1 );592 ++stars;593 }594 }595 596 evbuffer_add_printf( out, "/%d", ( 32 - ( stars * 8 ) ) );597 }598 599 char*600 cidrize( const char * acl )601 {602 int len;603 const char * walk = acl;604 char * ret;605 struct evbuffer * out = evbuffer_new( );606 607 FOR_EACH_WORD_IN_LIST( walk, len )608 {609 cidrizeOne( walk, len, out );610 evbuffer_add_printf( out, "," );611 }612 613 /* the -1 is to eat the final ", " */614 ret = tr_strndup( EVBUFFER_DATA( out ), EVBUFFER_LENGTH( out ) - 1 );615 evbuffer_free( out );616 return ret;617 526 } 618 527 … … 622 531 char ** setme_errmsg ) 623 532 { 624 int err = 0; 625 char * cidr = cidrize( acl ); 626 char * errmsg = testACL( cidr ); 627 628 if( errmsg ) 629 { 630 if( setme_errmsg ) 631 *setme_errmsg = errmsg; 632 else 633 tr_free( errmsg ); 634 err = -1; 635 } 636 tr_free( cidr ); 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 ); 637 538 return err; 638 539 } … … 640 541 int 641 542 tr_rpcSetACL( tr_rpc_server * server, 642 const char * acl ,543 const char * acl_str, 643 544 char ** setme_errmsg ) 644 545 { 645 char * cidr = cidrize( acl ); 646 const int err = tr_rpcTestACL( server, cidr, setme_errmsg ); 647 648 if( !err ) 649 { 650 const int isEnabled = server->isEnabled; 651 652 if( isEnabled ) 653 stopServer( server ); 654 655 tr_free( server->acl ); 656 server->acl = tr_strdup( cidr ); 657 dbgmsg( "setting our ACL to [%s]", server->acl ); 658 659 if( isEnabled ) 660 startServer( server ); 661 } 662 tr_free( cidr ); 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 } 663 560 664 561 return err; … … 668 565 tr_rpcGetACL( const tr_rpc_server * server ) 669 566 { 670 return tr_strdup( server->acl ? server->acl: "" );567 return tr_strdup( server->acl_str ? server->acl_str : "" ); 671 568 } 672 569 … … 679 576 const char * username ) 680 577 { 681 const int isEnabled = server->isEnabled;682 683 if( isEnabled )684 stopServer( server );685 686 578 tr_free( server->username ); 687 579 server->username = tr_strdup( username ); 688 580 dbgmsg( "setting our Username to [%s]", server->username ); 689 690 if( isEnabled )691 startServer( server );692 581 } 693 582 … … 702 591 const char * password ) 703 592 { 704 const int isEnabled = server->isEnabled;705 706 if( isEnabled )707 stopServer( server );708 709 593 tr_free( server->password ); 710 594 server->password = tr_strdup( password ); 711 595 dbgmsg( "setting our Password to [%s]", server->password ); 712 713 if( isEnabled )714 startServer( server );715 596 } 716 597 … … 725 606 int isEnabled ) 726 607 { 727 const int wasEnabled = server->isEnabled;728 729 if( wasEnabled )730 stopServer( server );731 732 608 server->isPasswordEnabled = isEnabled; 733 609 dbgmsg( "setting 'password enabled' to %d", isEnabled ); 734 735 if( isEnabled )736 startServer( server );737 610 } 738 611 … … 755 628 756 629 stopServer( s ); 630 tr_list_free( &s->acl_list, tr_free ); 631 tr_free( s->acl_str ); 757 632 tr_free( s->username ); 758 633 tr_free( s->password ); 759 tr_free( s->acl );760 634 tr_free( s ); 761 635 } … … 765 639 int isEnabled, 766 640 int port, 767 const char * acl ,641 const char * acl_str, 768 642 int isPasswordEnabled, 769 643 const char * username, 770 644 const char * password ) 771 645 { 772 char * errmsg;773 646 tr_rpc_server * s; 774 775 if( ( errmsg = testACL ( acl ) ) )776 { 777 tr_nerr( MY_NAME, errmsg );778 tr_free( errmsg );779 acl = TR_DEFAULT_RPC_ACL;780 tr_nerr( MY_NAME, "using fallback ACL \"%s\"", acl);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 ); 781 654 } 782 655 … … 784 657 s->session = session; 785 658 s->port = port; 786 s->acl = tr_strdup( acl ); 659 s->acl_str = tr_strdup( acl_str ); 660 s->acl_list = list; 787 661 s->username = tr_strdup( username ); 788 662 s->password = tr_strdup( password ); … … 794 668 return s; 795 669 } 796 -
trunk/libtransmission/rpc-test.c
r6795 r6797 25 25 } 26 26 27 #if 0 27 28 extern char* cidrize( const char * in ); 28 29 … … 43 44 return ok; 44 45 } 46 #endif 45 47 46 48 static int 47 49 test_acl( void ) 48 50 { 51 #if 0 49 52 int err; 50 53 char * errmsg = NULL; … … 68 71 check( !err ); 69 72 check( !errmsg ); 73 #endif 70 74 71 75 return 0; -
trunk/third-party/Makefile.am
r5822 r6797 2 2 libevent \ 3 3 libnatpmp \ 4 miniupnp \ 5 shttpd 4 miniupnp 6 5 7 6 EXTRA_DIST = \ -
trunk/wx/Makefile.am
r6792 r6797 23 23 xmission_LDADD = \ 24 24 $(top_builddir)/libtransmission/libtransmission.a \ 25 $(top_builddir)/third-party/libevent/libevent _core.la \25 $(top_builddir)/third-party/libevent/libevent.la \ 26 26 $(top_builddir)/third-party/miniupnp/libminiupnp.a \ 27 27 $(top_builddir)/third-party/libnatpmp/libnatpmp.a \ 28 $(top_builddir)/third-party/shttpd/libshttpd.a \29 28 $(WX_LIBS) \ 30 29 $(OPENSSL_LIBS) \
Note: See TracChangeset
for help on using the changeset viewer.