summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2021-12-18 10:13:18 -0500
committerEdward Thomson <ethomson@edwardthomson.com>2022-01-13 09:36:21 -0500
commit342e55ac9104346d925154b5d472cf5f58668f0d (patch)
tree0acdf3162393b6fd901c98bd634cf3700387a29e
parentc104a56536fa7bac0c1d0702623ebbc769babd03 (diff)
downloadlibgit2-342e55ac9104346d925154b5d472cf5f58668f0d.tar.gz
url: optionally allow off-site redirects
In redirect application logic, (optionally) allow off-site redirects.
-rw-r--r--src/net.c6
-rw-r--r--src/net.h1
-rw-r--r--src/transports/http.c2
-rw-r--r--src/transports/winhttp.c2
-rw-r--r--tests/network/url/redirect.c62
5 files changed, 47 insertions, 26 deletions
diff --git a/src/net.c b/src/net.c
index a91e7460e..79c3fcd28 100644
--- a/src/net.c
+++ b/src/net.c
@@ -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);
diff --git a/src/net.h b/src/net.h
index 728add3d0..c74397409 100644
--- a/src/net.h
+++ b/src/net.h
@@ -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");
}