From 315d28801cad6f0de64f60d0875b068c0165a975 Mon Sep 17 00:00:00 2001
From: Jeff King <peff@peff.net>
Date: Sat, 18 Apr 2020 20:48:05 -0700
Subject: credential: parse URL without host as empty host, not unset

We may feed a URL like "cert:///path/to/cert.pem" into the credential
machinery to get the key for a client-side certificate. That
credential has no hostname field, which is about to be disallowed (to
avoid confusion with protocols where a helper _would_ expect a
hostname).

This means as of the next patch, credential helpers won't work for
unlocking certs. Let's fix that by doing two things:

  - when we parse a url with an empty host, set the host field to the
    empty string (asking only to match stored entries with an empty
    host) rather than NULL (asking to match _any_ host).

  - when we build a cert:// credential by hand, similarly assign an
    empty string

It's the latter that is more likely to impact real users in practice,
since it's what's used for http connections. But we don't have good
infrastructure to test it.

The url-parsing version will help anybody using git-credential in a
script, and is easy to test.

Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
(cherry picked from commit 24036686c4af84c9e84e486ef3debab6e6d8e6b5)
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 credential.c           |  3 +--
 http.c                 |  1 +
 t/t0300-credentials.sh | 17 +++++++++++++++++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/credential.c b/credential.c
index 24823829f66..f2413cec145 100644
--- a/credential.c
+++ b/credential.c
@@ -376,8 +376,7 @@ int credential_from_url_gently(struct credential *c, const char *url,
 
 	if (proto_end - url > 0)
 		c->protocol = xmemdupz(url, proto_end - url);
-	if (slash - host > 0)
-		c->host = url_decode_mem(host, slash - host);
+	c->host = url_decode_mem(host, slash - host);
 	/* Trim leading and trailing slashes from path */
 	while (*slash == '/')
 		slash++;
diff --git a/http.c b/http.c
index eacc2a75ef2..4abe11c1253 100644
--- a/http.c
+++ b/http.c
@@ -554,6 +554,7 @@ static int has_cert_password(void)
 		return 0;
 	if (!cert_auth.password) {
 		cert_auth.protocol = xstrdup("cert");
+		cert_auth.host = xstrdup("");
 		cert_auth.username = xstrdup("");
 		cert_auth.path = xstrdup(ssl_cert);
 		credential_fill(&cert_auth);
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index fb63ab85834..771fe6b8ccb 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -413,4 +413,21 @@ test_expect_success 'url parser ignores embedded newlines' '
 	EOF
 '
 
+test_expect_success 'host-less URLs are parsed as empty host' '
+	check fill "verbatim foo bar" <<-\EOF
+	url=cert:///path/to/cert.pem
+	--
+	protocol=cert
+	host=
+	path=path/to/cert.pem
+	username=foo
+	password=bar
+	--
+	verbatim: get
+	verbatim: protocol=cert
+	verbatim: host=
+	verbatim: path=path/to/cert.pem
+	EOF
+'
+
 test_done
-- 
2.26.1.301.g55bc3eb7cb9

