1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-03-02 17:55:22 +00:00

add authentication support to daemon & remote

This commit is contained in:
Charles Kerr 2008-06-05 18:16:59 +00:00
parent c0e5efbc03
commit 486bb768f0
4 changed files with 97 additions and 14 deletions

View file

@ -38,12 +38,18 @@ saveState( tr_handle * h )
{
tr_benc d;
const char * str;
char * username = tr_sessionGetRPCUsername( h );
char * password = tr_sessionGetRPCPassword( h );
char * auth = tr_strdup_printf( "%s:%s", username, password );
tr_bencInitDict( &d, 12 );
tr_bencInitDict( &d, 14 );
tr_bencDictAddStr( &d, "download-dir", tr_sessionGetDownloadDir( h ) );
tr_bencDictAddInt( &d, "peer-limit", tr_sessionGetPeerLimit( h ) );
tr_bencDictAddInt( &d, "pex-allowed", tr_sessionIsPexEnabled( h ) );
tr_bencDictAddInt( &d, "port", tr_sessionGetPeerPort( h ) );
tr_bencDictAddStr( &d, "auth", auth );
tr_bencDictAddInt( &d, "auth-required",
tr_sessionIsRPCPasswordEnabled( h ) );
tr_bencDictAddInt( &d, "port-forwarding-enabled",
tr_sessionIsPortForwardingEnabled( h ) );
tr_bencDictAddStr( &d, "rpc-acl", tr_sessionGetRPCACL( h ) );
@ -67,10 +73,28 @@ saveState( tr_handle * h )
tr_bencSaveFile( myConfigFilename, &d );
tr_bencFree( &d );
tr_free( auth );
tr_free( password );
tr_free( username );
}
static int
parseAuth( const char * auth, char ** username, char ** password )
{
int err = 0;
const char * pch = strchr( auth, ':' );
if( !pch )
err = -1;
else {
*username = tr_strndup( auth, pch-auth );
*password = tr_strdup( pch+1 );
}
return err;
}
static void
session_init( const char * configDir, int rpc_port, const char * rpc_acl )
session_init( const char * configDir, int rpc_port,
const char * acl, const char * auth, int noauth )
{
tr_benc state;
int have_state;
@ -84,10 +108,15 @@ session_init( const char * configDir, int rpc_port, const char * rpc_acl )
int64_t down_limited = FALSE;
int encryption = TR_ENCRYPTION_PREFERRED;
char downloadDir[MAX_PATH_LENGTH] = { '\0' };
const char * rpc_acl_fallback = TR_DEFAULT_RPC_ACL;
const char * acl_fallback = TR_DEFAULT_RPC_ACL;
int64_t rpc_port_fallback = TR_DEFAULT_RPC_PORT;
int64_t auth_required_fallback = 0;
const char * auth_fallback = NULL;
tr_ctor * ctor;
tr_torrent ** torrents;
int auth_required;
char * user = NULL;
char * pass = NULL;
if(( have_state = !tr_bencLoadFile( myConfigFilename, &state )))
{
@ -100,7 +129,9 @@ session_init( const char * configDir, int rpc_port, const char * rpc_acl )
tr_bencDictFindInt( &state, "pex-allowed", &pex_enabled );
tr_bencDictFindInt( &state, "port", &peer_port );
tr_bencDictFindInt( &state, "port-forwarding-enabled", &fwd_enabled );
tr_bencDictFindStr( &state, "rpc-acl", &rpc_acl_fallback );
tr_bencDictFindStr( &state, "rpc-acl", &acl_fallback );
tr_bencDictFindStr( &state, "auth", &auth_fallback );
tr_bencDictFindInt( &state, "auth-required", &auth_required_fallback );
tr_bencDictFindInt( &state, "rpc-port", &rpc_port_fallback );
tr_bencDictFindInt( &state, "speed-limit-down", &down_limit );
tr_bencDictFindInt( &state, "speed-limit-down-enabled", &down_limited );
@ -119,8 +150,23 @@ session_init( const char * configDir, int rpc_port, const char * rpc_acl )
getcwd( downloadDir, sizeof( downloadDir ) );
if( rpc_port < 1 )
rpc_port = rpc_port_fallback;
if( !rpc_acl || !*rpc_acl )
rpc_acl = rpc_acl_fallback;
if( !acl || !*acl )
acl = acl_fallback;
if( !auth || !*auth )
auth = auth_fallback;
if( auth && parseAuth( auth, &user, &pass ) ) {
tr_nerr( MY_NAME, "Unable to parse authentication string \"%s\"", auth );
abort( );
}
if( noauth ) {
/* user has explicitly turned off authentication */
user = NULL;
pass = NULL;
}
auth_required = user || pass;
/* start the session */
mySession = tr_sessionInitFull( configDir, "daemon", downloadDir,
@ -132,7 +178,11 @@ session_init( const char * configDir, int rpc_port, const char * rpc_acl )
TR_MSG_INF, 0,
FALSE, /* is the blocklist enabled? */
TR_DEFAULT_PEER_SOCKET_TOS,
TRUE, rpc_port, rpc_acl );
TRUE, rpc_port, acl,
auth_required, user, pass );
if( auth_required )
tr_ninf( MY_NAME, "requiring authentication" );
/* load the torrents */
ctor = tr_ctorNew( mySession );
@ -156,6 +206,7 @@ daemonUsage( void )
" -f --foreground Run in the foreground and log to stderr\n"
" -g --config-dir <dir> Where to look for torrents and daemon-config.benc\n"
" -h --help Display this message and exit\n"
" -t --auth <user>:<pass> Username and password for authentication\n"
" -p --port n Port to listen to for requests (Default: "TR_DEFAULT_RPC_PORT_STR")\n"
"\n"
MY_NAME" is a headless Transmission session\n"
@ -165,24 +216,31 @@ daemonUsage( void )
static void
readargs( int argc, char ** argv,
int * nofork, int * port, char ** acl,
char ** configDir )
int * nofork, int * port,
char ** configDir,
char ** acl,
char ** auth,
int * noauth )
{
int opt;
char optstr[] = "a:fg:hp:";
char optstr[] = "a:fg:hnp:t:u:w:";
struct option longopts[] = {
{ "acl", required_argument, NULL, 'a' },
{ "foreground", no_argument, NULL, 'f' },
{ "config-dir", required_argument, NULL, 'g' },
{ "help", no_argument, NULL, 'h' },
{ "noauth", no_argument, NULL, 'n' },
{ "port", required_argument, NULL, 'p' },
{ "auth", required_argument, NULL, 't' },
{ NULL, 0, NULL, '\0' }
};
while((( opt = getopt_long( argc, argv, optstr, longopts, NULL ))) != -1 ) {
switch( opt ) {
case 'a': *acl = tr_strdup( optarg ); break;
case 'f': *nofork = 1; break;
case 'n': *noauth = 1; break;
case 'g': *configDir = tr_strdup( optarg ); break;
case 't': *auth = tr_strdup( optarg ); break;
case 'p': *port = atoi( optarg ); break;
default: daemonUsage( ); break;
}
@ -253,9 +311,11 @@ int
main( int argc, char ** argv )
{
int nofork = 0;
int noauth = 0;
int port = TR_DEFAULT_RPC_PORT;
char * configDir = NULL;
char * acl = NULL;
char * auth = NULL;
signal( SIGINT, gotsig );
signal( SIGQUIT, gotsig );
@ -263,7 +323,7 @@ main( int argc, char ** argv )
signal( SIGPIPE, SIG_IGN );
signal( SIGHUP, SIG_IGN );
readargs( argc, argv, &nofork, &port, &acl, &configDir );
readargs( argc, argv, &nofork, &port, &configDir, &acl, &auth, &noauth );
if( configDir == NULL )
configDir = tr_strdup_printf( "%s-daemon", tr_getDefaultConfigDir() );
tr_buildPath( myConfigFilename, sizeof( myConfigFilename ),
@ -276,7 +336,7 @@ main( int argc, char ** argv )
}
}
session_init( configDir, port, acl );
session_init( configDir, port, acl, auth, noauth );
while( !closing )
sleep( 1 );

View file

@ -65,6 +65,7 @@ showUsage( void )
" -s --start all Start all stopped torrents\n"
" -S --stop <int> Stop the torrent with the given ID\n"
" -S --stop all Stop all running torrents\n"
" -t --auth <user>:<pass> Username and password for authentication\n"
" -u --upload-limit <int> Max upload rate in KiB/s\n"
" -U --upload-unlimited No upload rate limit\n"
" -v --verify <id> Verify the torrent's local data\n" );
@ -86,6 +87,7 @@ numarg( const char * arg )
static char * reqs[256]; /* arbitrary max */
static int reqCount = 0;
static int debug = 0;
static char * auth = NULL;
static char*
absolutify( char * buf, size_t len, const char * path )
@ -114,7 +116,7 @@ static void
readargs( int argc, char ** argv )
{
int opt;
char optstr[] = "a:c:d:DeEf:ghlmMp:r:s:S:u:Uv:";
char optstr[] = "a:c:d:DeEf:ghlmMp:r:s:S:t:u:Uv:";
const struct option longopts[] =
{
@ -134,6 +136,7 @@ readargs( int argc, char ** argv )
{ "remove", required_argument, NULL, 'r' },
{ "start", required_argument, NULL, 's' },
{ "stop", required_argument, NULL, 'S' },
{ "auth", required_argument, NULL, 't' },
{ "upload-limit", required_argument, NULL, 'u' },
{ "upload-unlimited", no_argument, NULL, 'U' },
{ "verify", required_argument, NULL, 'v' },
@ -154,6 +157,9 @@ readargs( int argc, char ** argv )
case 'g': debug = 1;
addArg = FALSE;
break;
case 't': auth = tr_strdup( optarg );
addArg = FALSE;
break;
case 'h': showUsage( );
addArg = FALSE;
break;
@ -287,7 +293,7 @@ processResponse( const char * host, int port,
(int)len, (int)len, (const char*) response );
if( tr_jsonParse( response, len, &top, NULL ) )
tr_nerr( MY_NAME, "Unable to parse response" );
tr_nerr( MY_NAME, "Unable to parse response \"%*.*s\"", (int)len, (int)len, (char*)response );
else
{
tr_benc *args, *list;
@ -346,6 +352,10 @@ processRequests( const char * host, int port,
curl_easy_setopt( curl, CURLOPT_WRITEDATA, buf );
curl_easy_setopt( curl, CURLOPT_POST, 1 );
curl_easy_setopt( curl, CURLOPT_URL, url );
if( auth ) {
curl_easy_setopt( curl, CURLOPT_USERPWD, auth );
curl_easy_setopt( curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
}
for( i=0; i<reqCount; ++i )
{

View file

@ -13,6 +13,7 @@
.Op Fl a Ar (+|-)x.x.x.x[/x],...
.Op Fl g Ar directory
.Op Fl p Ar port
.Op Fl t Ar user:pass
.Ek
.Sh DESCRIPTION
@ -38,6 +39,12 @@ Run in the foreground and print errors to stderr instead of forking
and logging errors with syslog.
.It Fl g Fl -config-dir Ar directory
Where to look for .torrent and config files on startup.
.It Fl t Fl -auth Ar user:pass
Requre
.Ar username
and
.Ar password
authentication
.It Fl h Fl -help
Print command-line option descriptions.
.It Fl p Fl -port Ar port

View file

@ -24,6 +24,7 @@ and
.Op Fl m
.Op Fl M
.Op Fl p Ar port
.Op Fl t Ar user:pass
.Op Fl q
.Oo
.Fl r Ar all | Ar id | Ar hash
@ -83,6 +84,11 @@ Disable automatic port mapping.
Attempt to bind to
.Ar port
for use as a listening port to accept incoming peer connections.
.It Fl t Fl -auth Ar user:pass
.Ar Username
and
.Ar password
for authentication
.It Fl r Fl -remove Ar all | id | torrent-hash
Remove all torrents, or the torrent matching the specified