Skip to content

Commit 6828e59

Browse files
dschogitster
authored andcommitted
credential: optionally allow partial URLs in credential_from_url_gently()
Prior to the fixes for CVE-2020-11008, we were _very_ lenient in what we required from a URL in order to parse it into a `struct credential`. That led to serious vulnerabilities. There was one call site, though, that really needed that leniency: when parsing config settings a la `credential.dev.azure.com.useHTTPPath`. Settings like this might be desired when users want to use, say, a given user name on a given host, regardless of the protocol to be used. In preparation for fixing that bug, let's refactor the code to optionally allow for partial URLs. For the moment, this functionality is only exposed via the now-renamed function `credential_from_url_1()`, but it is not used. The intention is to make it easier to verify that this commit does not change the existing behavior unless explicitly allowing for partial URLs. Please note that this patch does more than just reinstating a way to imitate the behavior before those CVE-2020-11008 fixes: Before that, we would simply ignore URLs without a protocol. In other words, misleadingly, the following setting would be applied to _all_ URLs: [credential "example.com"] username = that-me The obvious intention is to match the host name only. With this patch, we allow precisely that: when parsing the URL with non-zero `allow_partial_url`, we do not simply return success if there was no protocol, but we simply leave the protocol unset and continue parsing the URL. Signed-off-by: Johannes Schindelin <[email protected]> Reviewed-by: Carlo Marcelo Arenas Belón <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 21920cb commit 6828e59

File tree

1 file changed

+36
-6
lines changed

1 file changed

+36
-6
lines changed

credential.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,31 @@ static int check_url_component(const char *url, int quiet,
343343
return -1;
344344
}
345345

346-
int credential_from_url_gently(struct credential *c, const char *url,
347-
int quiet)
346+
/*
347+
* Potentially-partial URLs can, but do not have to, contain
348+
*
349+
* - a protocol (or scheme) of the form "<protocol>://"
350+
*
351+
* - a host name (the part after the protocol and before the first slash after
352+
* that, if any)
353+
*
354+
* - a user name and potentially a password (as "<user>[:<password>]@" part of
355+
* the host name)
356+
*
357+
* - a path (the part after the host name, if any, starting with the slash)
358+
*
359+
* Missing parts will be left unset in `struct credential`. Thus, `https://`
360+
* will have only the `protocol` set, `example.com` only the host name, and
361+
* `/git` only the path.
362+
*
363+
* Note that an empty host name in an otherwise fully-qualified URL (e.g.
364+
* `cert:///path/to/cert.pem`) will be treated as unset if we expect the URL to
365+
* be potentially partial, and only then (otherwise, the empty string is used).
366+
*
367+
* The credential_from_url() function does not allow partial URLs.
368+
*/
369+
static int credential_from_url_1(struct credential *c, const char *url,
370+
int allow_partial_url, int quiet)
348371
{
349372
const char *at, *colon, *cp, *slash, *host, *proto_end;
350373

@@ -357,12 +380,12 @@ int credential_from_url_gently(struct credential *c, const char *url,
357380
* (3) proto://<user>:<pass>@<host>/...
358381
*/
359382
proto_end = strstr(url, "://");
360-
if (!proto_end || proto_end == url) {
383+
if (!allow_partial_url && (!proto_end || proto_end == url)) {
361384
if (!quiet)
362385
warning(_("url has no scheme: %s"), url);
363386
return -1;
364387
}
365-
cp = proto_end + 3;
388+
cp = proto_end ? proto_end + 3 : url;
366389
at = strchr(cp, '@');
367390
colon = strchr(cp, ':');
368391
slash = strchrnul(cp, '/');
@@ -382,8 +405,10 @@ int credential_from_url_gently(struct credential *c, const char *url,
382405
host = at + 1;
383406
}
384407

385-
c->protocol = xmemdupz(url, proto_end - url);
386-
c->host = url_decode_mem(host, slash - host);
408+
if (proto_end && proto_end - url > 0)
409+
c->protocol = xmemdupz(url, proto_end - url);
410+
if (!allow_partial_url || slash - host > 0)
411+
c->host = url_decode_mem(host, slash - host);
387412
/* Trim leading and trailing slashes from path */
388413
while (*slash == '/')
389414
slash++;
@@ -405,6 +430,11 @@ int credential_from_url_gently(struct credential *c, const char *url,
405430
return 0;
406431
}
407432

433+
int credential_from_url_gently(struct credential *c, const char *url, int quiet)
434+
{
435+
return credential_from_url_1(c, url, 0, quiet);
436+
}
437+
408438
void credential_from_url(struct credential *c, const char *url)
409439
{
410440
if (credential_from_url_gently(c, url, 0) < 0)

0 commit comments

Comments
 (0)