]> granicus.if.org Git - transmission/commitdiff
RPC ACL: (1) add a new call for testing ACLs (2) add wildcard notation support (3...
authorCharles Kerr <charles@transmissionbt.com>
Wed, 4 Jun 2008 17:14:58 +0000 (17:14 +0000)
committerCharles Kerr <charles@transmissionbt.com>
Wed, 4 Jun 2008 17:14:58 +0000 (17:14 +0000)
libtransmission/Makefile.am
libtransmission/rpc-server.c
libtransmission/rpc-server.h
libtransmission/rpc-test.c [new file with mode: 0644]
libtransmission/session.c
libtransmission/transmission.h

index 59dc503630af8f6d63cc59cdb48ef6e900c2e601..3f00d572d7a9aa847b3a7a2d631f2d0daa85d073 100644 (file)
@@ -91,6 +91,7 @@ TESTS = \
     bencode-test \
     clients-test \
     json-test \
+    rpc-test \
     test-fastset \
     test-peer-id \
     utils-test
@@ -117,6 +118,8 @@ clients_test_SOURCES = clients-test.c
 clients_test_LDADD = $(APPS_LDADD)
 json_test_SOURCES = json-test.c
 json_test_LDADD = $(APPS_LDADD)
+rpc_test_SOURCES = rpc-test.c
+rpc_test_LDADD = $(APPS_LDADD)
 test_fastset_SOURCES = test-fastset.c
 test_fastset_LDADD = $(APPS_LDADD)
 test_peer_id_SOURCES = test-peer-id.c
index 7d1450f84fb11a9b747f7ced59aac08c178b0335..558284ec30d47a5f536d7588a2d1deb5154b0d94 100644 (file)
@@ -11,6 +11,9 @@
  */
 
 #include <assert.h>
+#include <ctype.h> /* isdigit */
+#include <errno.h>
+#include <stdlib.h> /* strtol */
 #include <string.h>
 
 #include <libevent/event.h>
@@ -218,13 +221,61 @@ testACL( const char * s )
     return NULL;
 }
 
+/* 192.*.*.* --> 192.0.0.0/8
+   192.64.*.* --> 192.64.0.0/16
+   192.64.1.* --> 192.64.1.0/24
+   192.64.1.2 --> 192.64.1.2/32 */
+static void
+cidrizeOne( const char * in, int len, struct evbuffer * out )
+{
+    int stars = 0;
+    const char * pch;
+    const char * end;
+    char zero = '0';
+    char huh = '?';
+
+    for( pch=in, end=pch+len; pch!=end; ++pch ) {
+        if( stars && isdigit(*pch) )
+            evbuffer_add( out, &huh, 1 ); 
+        else if( *pch!='*' )
+            evbuffer_add( out, pch, 1 );
+        else {
+            evbuffer_add( out, &zero, 1 );
+            ++stars;
+        }
+    }
+
+    evbuffer_add_printf( out, "/%d", (32-(stars*8)));
+}
+
+char*
+cidrize( const char * acl )
+{
+    int len;
+    const char * walk = acl;
+    char * ret;
+    struct evbuffer * out = evbuffer_new( );
+
+    FOR_EACH_WORD_IN_LIST( walk, len )
+    {
+        cidrizeOne( walk, len, out );
+        evbuffer_add_printf( out, ", " );
+    }
+
+    /* the -2 is to eat the final ", " */
+    ret = tr_strndup( (char*) EVBUFFER_DATA(out), EVBUFFER_LENGTH(out)-2 );
+    evbuffer_free( out );
+    return ret;
+}
+
 int
-tr_rpcSetACL( tr_rpc_server * server, const char * acl, char ** setme_errmsg )
+tr_rpcTestACL( const tr_rpc_server  * server UNUSED,
+               const char           * acl,
+               char                ** setme_errmsg )
 {
-    const int isRunning = server->ctx != NULL;
     int ret = 0;
-    char * errmsg = testACL( acl );
-
+    char * cidr = cidrize( acl );
+    char * errmsg = testACL( cidr );
     if( errmsg )
     {
         if( setme_errmsg )
@@ -233,13 +284,27 @@ tr_rpcSetACL( tr_rpc_server * server, const char * acl, char ** setme_errmsg )
             tr_free( errmsg );
         ret = -1;
     }
-    else
+    tr_free( cidr );
+    return ret;
+}
+
+int
+tr_rpcSetACL( tr_rpc_server   * server,
+              const char      * acl,
+              char           ** setme_errmsg )
+{
+    char * cidr = cidrize( acl );
+    const int ret = tr_rpcTestACL( server, cidr, setme_errmsg );
+
+    if( ret )
     {
+        const int isRunning = server->ctx != NULL;
+
         if( isRunning )
             stopServer( server );
 
         tr_free( server->acl );
-        server->acl = tr_strdup( acl );
+        server->acl = tr_strdup( cidr );
 
         if( isRunning )
             startServer( server );
index b452e8377b5b988b634f8514de2da223f3036637..f86d53382c21052f016738101c9deed7888efa26 100644 (file)
@@ -32,6 +32,10 @@ void        tr_rpcSetPort   ( tr_rpc_server          * server,
 
 int         tr_rpcGetPort   ( const tr_rpc_server    * server );
 
+int         tr_rpcSetTest   ( const tr_rpc_server    * server,
+                              const char             * acl,
+                              char                  ** allocme_errmsg );
+
 int         tr_rpcSetACL    ( tr_rpc_server          * server,
                               const char             * acl,
                               char                  ** allocme_errmsg );
diff --git a/libtransmission/rpc-test.c b/libtransmission/rpc-test.c
new file mode 100644 (file)
index 0000000..fabb601
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdio.h> /* fprintf */
+#include <string.h> /* strcmp */
+#include "transmission.h"
+#include "utils.h"
+
+#define VERBOSE 0
+
+int test = 0;
+
+#define check(A) { \
+    ++test; \
+    if (A) { \
+        if( VERBOSE ) \
+            fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
+    } else { \
+        if( VERBOSE ) \
+            fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
+        return test; \
+    } \
+}
+
+extern char* cidrize( const char * in );
+
+extern int tr_rpcTestACL( const void           * unused,
+                          const char           * acl,
+                          char                ** setme_errmsg );
+
+static int
+testWildcard( const char * in, const char * expected )
+{
+    int ok;
+    char * str = cidrize( in );
+/*fprintf( stderr, "in [%s] out [%s] should be [%s]\n", in, str, expected );*/
+    ok = expected ? !strcmp( expected, str ) : !str;
+    tr_free( str );
+    return ok;
+}
+
+static int
+test_acl( void )
+{
+    int err;
+    char * errmsg = NULL;
+
+    check( testWildcard( "192.*.*.*", "192.0.0.0/8" ) );
+    check( testWildcard( "192.64.*.*", "192.64.0.0/16" ) );
+    check( testWildcard( "192.64.0.*", "192.64.0.0/24" ) );
+    check( testWildcard( "192.64.0.1", "192.64.0.1/32" ) );
+    check( testWildcard( "+192.*.*.*, -192.64.*.*", "+192.0.0.0/8, -192.64.0.0/16" ) );
+
+    err = tr_rpcTestACL( NULL, "+192.*.*.*", &errmsg );
+    check( !err );
+    check( !errmsg );
+    err = tr_rpcTestACL( NULL, "+192.*.8.*", &errmsg );
+    check( err );
+    check( errmsg );
+    tr_free( errmsg );
+    errmsg = NULL;
+    err = tr_rpcTestACL( NULL, "+192.*.*.*, -192.168.*.*", &errmsg );
+    check( !err );
+    check( !errmsg );
+
+    return 0;
+}
+
+int
+main( void )
+{
+    int i;
+
+    if(( i = test_acl( )))
+        return i;
+
+    return 0;
+}
index 977efade16cfd5df9c70223305097ccdd2e052ed..a850b09bc53cf869ecaa0d4db7b0d5a6db8109f8 100644 (file)
@@ -775,6 +775,14 @@ tr_sessionSetRPCCallback( tr_handle    * session,
     session->rpc_func_user_data = user_data;
 }
 
+int
+tr_sessionTestRPCACL( const tr_handle  * session,
+                      const char       * acl,
+                      char            ** allocme_errmsg )
+{
+    return tr_rpcTestACL( session->rpcServer, acl, allocme_errmsg );
+}
+
 int
 tr_sessionSetRPCACL( tr_handle    * session,
                      const char   * acl,
index d276d11272622bfb030125b1c696e74d528cfd8b..0d88cd039c180ff090eeaa93ffb877aa25ea1103 100644 (file)
@@ -292,21 +292,45 @@ void tr_sessionSetRPCPort( tr_handle *, int port );
 int tr_sessionGetRPCPort( const tr_handle * );
 
 /**
- * Specify access control list (ACL). ACL is a comma separated list
- * of IP subnets, each subnet is prepended by a '-' or '+' sign.
- * Plus means allow, minus means deny. If the subnet mask is omitted,
- * like * "-1.2.3.4", it means a single IP address. The mask may vary
- * from 0 to 32 inclusive.
- *
- * The default string is "+127.0.0.1"
+ * @brief test an ACL's syntax without modifying the RPC settings.
+ * 
+ * ACL is a comma separated list of IP subnets, each subnet is prepended
+ * by a '+' or '-' sign to denote 'allow' or 'deny'.  If the subnet mask
+ * is omitted, like "-1.2.3.4", it means a single IP address. The mask
+ * may vary from 0 to 32 inclusive.  A simple primer on x.x.x.x/n notation
+ * can be found at <http://25yearsofprogramming.com/blog/20070803.htm>.
  *
- * @param acl the new ACL to use.
+ * Since wildcards are more familiar to most users than netmasks,
+ * libtransmission supports a wildcard notation that it
+ * converts into cidr required by the embedded http server.
+ * So, notation like "+192.168.*.*" is accepted by libtransmission and is
+ * converted to "+192.168.0.0/16" before it reaches the server.
+
+ * @param acl the ACL to test
  * @param allocme_errmsg If the ACL can't be parsed, this is set to a
  *                       newly-allocated error string describing the problem.
  *                       The client should tr_free() this string when done.
- *
  * @return 0 on success, -1 on failure due to an unparseable ACL.
+ */
+int tr_sessionTestRPCACL( const tr_handle  * session,
+                          const char       * acl,
+                          char            ** allocme_errmsg );
+
+/**
+ * @brief Specify access control list (ACL).
+ ACL is a comma separated list
+ * of IP subnets, each subnet is prepended by a '-' or '+' sign.
+ * Plus means allow, minus means deny. If the subnet mask is omitted,
+ * like "-1.2.3.4", it means a single IP address. The mask may vary
+ * from 0 to 32 inclusive.
+ *
+ * http://25yearsofprogramming.com/blog/20070803.htm has a simple
+ * primer on x.x.x.x/n notation for those interested.
+ *
+ * The parameters and return value follow the same behavior as
+ * tr_sessionTestRPCACL().
  *
+ * @see tr_sessionTestRPCACL
  * @see tr_sessionInitFull
  * @see tr_sessionGetRPCACL
  */