diff options
| author | Patrick Steinhardt <ps@pks.im> | 2020-01-31 08:49:34 +0100 |
|---|---|---|
| committer | Patrick Steinhardt <ps@pks.im> | 2020-01-31 15:25:47 +0100 |
| commit | 93a9044ff663684da278d4d0fc5111a293e6555b (patch) | |
| tree | 679f958f06811c1ae0d8e5188ef65f6d334d090b /src | |
| parent | a1bff63bf1097e08c9ee1843650279054ddd2ea9 (diff) | |
| download | libgit2-93a9044ff663684da278d4d0fc5111a293e6555b.tar.gz | |
fetchhead: strip credentials from remote URL
If fetching from an anonymous remote via its URL, then the URL gets
written into the FETCH_HEAD reference. This is mainly done to give
valuable context to some commands, like for example git-merge(1), which
will put the URL into the generated MERGE_MSG. As a result, what gets
written into FETCH_HEAD may become public in some cases. This is
especially important considering that URLs may contain credentials, e.g.
when cloning 'https://foo:bar@example.com/repo' we persist the complete
URL into FETCH_HEAD and put it without any kind of sanitization into the
MERGE_MSG. This is obviously bad, as your login data has now just leaked
as soon as you do git-push(1).
When writing the URL into FETCH_HEAD, upstream git does strip
credentials first. Let's do the same by trying to parse the remote URL
as a "real" URL, removing any credentials and then re-formatting the
URL. In case this fails, e.g. when it's a file path or not a valid URL,
we just fall back to using the URL as-is without any sanitization. Add
tests to verify our behaviour.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fetchhead.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/src/fetchhead.c b/src/fetchhead.c index a3f6fbc7a..ea610f39a 100644 --- a/src/fetchhead.c +++ b/src/fetchhead.c @@ -14,6 +14,7 @@ #include "futils.h" #include "filebuf.h" #include "refs.h" +#include "net.h" #include "repository.h" int git_fetchhead_ref_cmp(const void *a, const void *b) @@ -36,6 +37,33 @@ int git_fetchhead_ref_cmp(const void *a, const void *b) return 0; } +static char *sanitized_remote_url(const char *remote_url) +{ + git_net_url url = GIT_NET_URL_INIT; + char *sanitized = NULL; + int error; + + if (git_net_url_parse(&url, remote_url) == 0) { + git_buf buf = GIT_BUF_INIT; + + git__free(url.username); + git__free(url.password); + url.username = url.password = NULL; + + if ((error = git_net_url_fmt(&buf, &url)) < 0) + goto fallback; + + sanitized = git_buf_detach(&buf); + } + +fallback: + if (!sanitized) + sanitized = git__strdup(remote_url); + + git_net_url_dispose(&url); + return sanitized; +} + int git_fetchhead_ref_create( git_fetchhead_ref **out, git_oid *oid, @@ -57,11 +85,15 @@ int git_fetchhead_ref_create( git_oid_cpy(&fetchhead_ref->oid, oid); fetchhead_ref->is_merge = is_merge; - if (ref_name) + if (ref_name) { fetchhead_ref->ref_name = git__strdup(ref_name); + GIT_ERROR_CHECK_ALLOC(fetchhead_ref->ref_name); + } - if (remote_url) - fetchhead_ref->remote_url = git__strdup(remote_url); + if (remote_url) { + fetchhead_ref->remote_url = sanitized_remote_url(remote_url); + GIT_ERROR_CHECK_ALLOC(fetchhead_ref->remote_url); + } *out = fetchhead_ref; |
