diff options
-rw-r--r-- | src/mod_secdownload.c | 38 | ||||
-rw-r--r-- | tests/lighttpd.conf | 1 | ||||
-rwxr-xr-x | tests/mod-secdownload.t | 16 |
3 files changed, 54 insertions, 1 deletions
diff --git a/src/mod_secdownload.c b/src/mod_secdownload.c index f7848391..4a00c933 100644 --- a/src/mod_secdownload.c +++ b/src/mod_secdownload.c @@ -96,6 +96,8 @@ typedef struct { secdl_algorithm algorithm; unsigned int timeout; + unsigned short path_segments; + unsigned short hash_querystr; } plugin_config; typedef struct { @@ -282,6 +284,8 @@ SETDEFAULTS_FUNC(mod_secdownload_set_defaults) { { "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "secdownload.timeout", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ { "secdownload.algorithm", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */ + { "secdownload.path-segments", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */ + { "secdownload.hash-querystr", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 6 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -299,12 +303,16 @@ SETDEFAULTS_FUNC(mod_secdownload_set_defaults) { s->doc_root = buffer_init(); s->uri_prefix = buffer_init(); s->timeout = 60; + s->path_segments = 0; + s->hash_querystr = 0; cv[0].destination = s->secret; cv[1].destination = s->doc_root; cv[2].destination = s->uri_prefix; cv[3].destination = &(s->timeout); cv[4].destination = algorithm; + cv[5].destination = &(s->path_segments); + cv[6].destination = &(s->hash_querystr); p->config_storage[i] = s; @@ -402,6 +410,8 @@ static int mod_secdownload_patch_connection(server *srv, connection *con, plugin PATCH(uri_prefix); PATCH(timeout); PATCH(algorithm); + PATCH(path_segments); + PATCH(hash_querystr); /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { @@ -425,6 +435,10 @@ static int mod_secdownload_patch_connection(server *srv, connection *con, plugin PATCH(timeout); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.algorithm"))) { PATCH(algorithm); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.path-segments"))) { + PATCH(path_segments); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.hash-querystr"))) { + PATCH(hash_querystr); } } } @@ -499,6 +513,30 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) { rel_uri = ts_str + 8; + if (p->conf.path_segments) { + const char *rel_uri_end = rel_uri; + unsigned int count = p->conf.path_segments; + do { + rel_uri_end = strchr(rel_uri_end+1, '/'); + } while (rel_uri_end && --count); + if (rel_uri_end) { + buffer_copy_string_len(srv->tmp_buf, protected_path, + rel_uri_end - protected_path); + protected_path = srv->tmp_buf->ptr; + } + } + + if (p->conf.hash_querystr && !buffer_is_empty(con->uri.query)) { + buffer *b = srv->tmp_buf; + if (protected_path != b->ptr) { + buffer_copy_string(b, protected_path); + } + buffer_append_string_len(b, CONST_STR_LEN("?")); + buffer_append_string_buffer(b, con->uri.query); + /* assign last in case b->ptr is reallocated */ + protected_path = b->ptr; + } + if (!secdl_verify_mac(srv, &p->conf, protected_path, mac_str, mac_len)) { con->http_status = 403; diff --git a/tests/lighttpd.conf b/tests/lighttpd.conf index 3fd8b0da..c2fae77d 100644 --- a/tests/lighttpd.conf +++ b/tests/lighttpd.conf @@ -199,6 +199,7 @@ $HTTP["host"] == "vvv-sha256.example.org" { secdownload.uri-prefix = "/sec/" secdownload.timeout = 120 secdownload.algorithm = "hmac-sha256" + secdownload.hash-querystr = "enable" } $HTTP["host"] == "zzz.example.org" { diff --git a/tests/mod-secdownload.t b/tests/mod-secdownload.t index 96baf9d7..8881df68 100755 --- a/tests/mod-secdownload.t +++ b/tests/mod-secdownload.t @@ -8,7 +8,7 @@ BEGIN { use strict; use IO::Socket; -use Test::More tests => 15; +use Test::More tests => 16; use LightyTest; use Digest::MD5 qw(md5_hex); use Digest::SHA qw(hmac_sha1 hmac_sha256); @@ -142,6 +142,20 @@ $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'secdownload (hmac-sha256)'); +## HMAC-SHA256 +$f = "/index.html?qs=1"; +$thex = sprintf("%08x", time); +$m = encode_base64url(hmac_sha256("/$thex$f", $secret)); + +$t->{REQUEST} = ( <<EOF +GET /sec/$m/$thex$f HTTP/1.0 +Host: vvv-sha256.example.org +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; + +ok($tf->handle_http($t) == 0, 'secdownload (hmac-sha256) with hash-querystr'); + $thex = sprintf("%08x", time - 1800); $m = encode_base64url(hmac_sha256("/$thex$f", $secret)); |