diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2021-12-18 10:13:18 -0500 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2022-01-13 09:36:21 -0500 |
commit | 342e55ac9104346d925154b5d472cf5f58668f0d (patch) | |
tree | 0acdf3162393b6fd901c98bd634cf3700387a29e | |
parent | c104a56536fa7bac0c1d0702623ebbc769babd03 (diff) | |
download | libgit2-342e55ac9104346d925154b5d472cf5f58668f0d.tar.gz |
url: optionally allow off-site redirects
In redirect application logic, (optionally) allow off-site redirects.
-rw-r--r-- | src/net.c | 6 | ||||
-rw-r--r-- | src/net.h | 1 | ||||
-rw-r--r-- | src/transports/http.c | 2 | ||||
-rw-r--r-- | src/transports/winhttp.c | 2 | ||||
-rw-r--r-- | tests/network/url/redirect.c | 62 |
5 files changed, 47 insertions, 26 deletions
@@ -315,6 +315,7 @@ static void remove_service_suffix( int git_net_url_apply_redirect( git_net_url *url, const char *redirect_location, + bool allow_offsite, const char *service_suffix) { git_net_url tmp = GIT_NET_URL_INIT; @@ -339,8 +340,8 @@ int git_net_url_apply_redirect( /* Validate that this is a legal redirection */ if (original->scheme && - strcmp(original->scheme, tmp.scheme) != 0 && - strcmp(tmp.scheme, "https") != 0) { + strcmp(original->scheme, tmp.scheme) != 0 && + strcmp(tmp.scheme, "https") != 0) { git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'", original->scheme, tmp.scheme); @@ -349,6 +350,7 @@ int git_net_url_apply_redirect( } if (original->host && + !allow_offsite && git__strcasecmp(original->host, tmp.host) != 0) { git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'", original->host, tmp.host); @@ -46,6 +46,7 @@ extern bool git_net_url_is_ipv6(git_net_url *url); extern int git_net_url_apply_redirect( git_net_url *url, const char *redirect_location, + bool allow_offsite, const char *service_suffix); /** Swaps the contents of one URL for another. */ diff --git a/src/transports/http.c b/src/transports/http.c index fa576ff3e..6a17fa9ab 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -233,7 +233,7 @@ static int handle_response( return -1; } - if (git_net_url_apply_redirect(&transport->server.url, response->location, stream->service->url) < 0) { + if (git_net_url_apply_redirect(&transport->server.url, response->location, false, stream->service->url) < 0) { return -1; } diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 9b5a67d3b..fdc6cf223 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -1190,7 +1190,7 @@ replay: if (!git__prefixcmp_icase(location8, prefix_https)) { /* Upgrade to secure connection; disconnect and start over */ - if (git_net_url_apply_redirect(&t->server.url, location8, s->service_url) < 0) { + if (git_net_url_apply_redirect(&t->server.url, location8, false, s->service_url) < 0) { git__free(location8); return -1; } diff --git a/tests/network/url/redirect.c b/tests/network/url/redirect.c index 2c0b614d9..a94db7daf 100644 --- a/tests/network/url/redirect.c +++ b/tests/network/url/redirect.c @@ -17,9 +17,9 @@ void test_network_url_redirect__cleanup(void) void test_network_url_redirect__redirect_http(void) { cl_git_pass(git_net_url_parse(&conndata, - "http://example.com/foo/bar/baz")); + "http://example.com/foo/bar/baz")); cl_git_pass(git_net_url_apply_redirect(&conndata, - "http://example.com/foo/bar/baz", "bar/baz")); + "http://example.com/foo/bar/baz", false, "bar/baz")); cl_assert_equal_s(conndata.scheme, "http"); cl_assert_equal_s(conndata.host, "example.com"); cl_assert_equal_s(conndata.port, "80"); @@ -31,9 +31,9 @@ void test_network_url_redirect__redirect_http(void) void test_network_url_redirect__redirect_ssl(void) { cl_git_pass(git_net_url_parse(&conndata, - "https://example.com/foo/bar/baz")); + "https://example.com/foo/bar/baz")); cl_git_pass(git_net_url_apply_redirect(&conndata, - "https://example.com/foo/bar/baz", "bar/baz")); + "https://example.com/foo/bar/baz", false, "bar/baz")); cl_assert_equal_s(conndata.scheme, "https"); cl_assert_equal_s(conndata.host, "example.com"); cl_assert_equal_s(conndata.port, "443"); @@ -45,9 +45,9 @@ void test_network_url_redirect__redirect_ssl(void) void test_network_url_redirect__redirect_leaves_root_path(void) { cl_git_pass(git_net_url_parse(&conndata, - "https://example.com/foo/bar/baz")); + "https://example.com/foo/bar/baz")); cl_git_pass(git_net_url_apply_redirect(&conndata, - "https://example.com/foo/bar/baz", "/foo/bar/baz")); + "https://example.com/foo/bar/baz", false, "/foo/bar/baz")); cl_assert_equal_s(conndata.scheme, "https"); cl_assert_equal_s(conndata.host, "example.com"); cl_assert_equal_s(conndata.port, "443"); @@ -59,9 +59,9 @@ void test_network_url_redirect__redirect_leaves_root_path(void) void test_network_url_redirect__redirect_encoded_username_password(void) { cl_git_pass(git_net_url_parse(&conndata, - "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz")); + "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz")); cl_git_pass(git_net_url_apply_redirect(&conndata, - "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", "bar/baz")); + "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", false, "bar/baz")); cl_assert_equal_s(conndata.scheme, "https"); cl_assert_equal_s(conndata.host, "example.com"); cl_assert_equal_s(conndata.port, "443"); @@ -70,27 +70,42 @@ void test_network_url_redirect__redirect_encoded_username_password(void) cl_assert_equal_s(conndata.password, "pass@word%zyx%v"); } +void test_network_url_redirect__redirect_cross_host_allowed(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://bar.com/bar/baz")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "https://foo.com/bar/baz", true, NULL)); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "foo.com"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/bar/baz"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); +} + void test_network_url_redirect__redirect_cross_host_denied(void) { - cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz")); + cl_git_pass(git_net_url_parse(&conndata, + "https://bar.com/bar/baz")); cl_git_fail_with(git_net_url_apply_redirect(&conndata, - "https://foo.com/bar/baz", NULL), - -1); + "https://foo.com/bar/baz", false, NULL), -1); } void test_network_url_redirect__redirect_http_downgrade_denied(void) { - cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz")); + cl_git_pass(git_net_url_parse(&conndata, + "https://foo.com/bar/baz")); cl_git_fail_with(git_net_url_apply_redirect(&conndata, - "http://foo.com/bar/baz", NULL), - -1); + "http://foo.com/bar/baz", true, NULL), -1); } void test_network_url_redirect__redirect_relative(void) { - cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff")); + cl_git_pass(git_net_url_parse(&conndata, + "http://foo.com/bar/baz/biff")); cl_git_pass(git_net_url_apply_redirect(&conndata, - "/zap/baz/biff?bam", NULL)); + "/zap/baz/biff?bam", true, NULL)); cl_assert_equal_s(conndata.scheme, "http"); cl_assert_equal_s(conndata.host, "foo.com"); cl_assert_equal_s(conndata.port, "80"); @@ -101,9 +116,10 @@ void test_network_url_redirect__redirect_relative(void) void test_network_url_redirect__redirect_relative_ssl(void) { - cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff")); + cl_git_pass(git_net_url_parse(&conndata, + "https://foo.com/bar/baz/biff")); cl_git_pass(git_net_url_apply_redirect(&conndata, - "/zap/baz/biff?bam", NULL)); + "/zap/baz/biff?bam", true, NULL)); cl_assert_equal_s(conndata.scheme, "https"); cl_assert_equal_s(conndata.host, "foo.com"); cl_assert_equal_s(conndata.port, "443"); @@ -114,16 +130,18 @@ void test_network_url_redirect__redirect_relative_ssl(void) void test_network_url_redirect__service_query_no_query_params_in_location(void) { - cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack")); + cl_git_pass(git_net_url_parse(&conndata, + "https://foo.com/bar/info/refs?service=git-upload-pack")); cl_git_pass(git_net_url_apply_redirect(&conndata, - "/baz/info/refs", "/info/refs?service=git-upload-pack")); + "/baz/info/refs", true, "/info/refs?service=git-upload-pack")); cl_assert_equal_s(conndata.path, "/baz"); } void test_network_url_redirect__service_query_with_query_params_in_location(void) { - cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack")); + cl_git_pass(git_net_url_parse(&conndata, + "https://foo.com/bar/info/refs?service=git-upload-pack")); cl_git_pass(git_net_url_apply_redirect(&conndata, - "/baz/info/refs?service=git-upload-pack", "/info/refs?service=git-upload-pack")); + "/baz/info/refs?service=git-upload-pack", true, "/info/refs?service=git-upload-pack")); cl_assert_equal_s(conndata.path, "/baz"); } |