Thread (6 messages) flat view 6 messages, 3 authors, 2016-06-15

Re: [PATCH][v2] http authentication via prompts (with correct line lengths)

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:46:21
Subsystem: the rest · Maintainer: Linus Torvalds

Possibly related (same subject, not in this thread)

Mike Gaffney [off-list ref] writes:
quoted
quoted
+static const char *curl_http_username = NULL;
+static const char *curl_http_password = NULL;
+
Please do not introduce new initializations of static variables to 0 or
NULL.  As a clean-up, before your patch, you can send in a patch to fix
existing such initializations.
...
Or do you mean that I can send in a patch to fix other static variables
(not mine) which are being initialized to NULL?
Yeah, a preparatory patch to clean things up, like the one I sent out
earlier this evening, was what I meant.
2) Being that I'm not a big C guy, I'm not sure the best way to go about 
parsing the username out of the URL to pull it into a variable to pass
to CURLOPT_USERPASS. Any advice from the community would be greatly
appreciated.
I am sort of a C guy, but I am by no means a libcurl person.  A quick and
dirty patch is attached, which is partly based on yours, but is stripped
of version dependency and also I suspect it handles only the http-walker
side.  It is on top of the two clean-up patch I sent this evening.

It hasn't seen any test, but I just ran this once:

    $ git clone http://junio@my.private.machine/test-repo.git/

from a repository that requires authentication but I have no .netrc and no
http.password configuration; I was asked for the password once, of course.
3) From my experience with curl, many of the options do
not work the same across versions or platforms. For example, the new
CURLOPT_USERNAME/PASSWORD options worked fine in 7.19.4 on cygwin but not
on FC9, which is why I used the older USERPWD. Also, my curl never prompted
me for the password when I supplied a username in the URL which is what 
prompted me to do this patch in the first place. As such, I think it is
better to pull the username & password prompting logic into git make this 
stable and fix the bug. 
Heh, 7.19.4 was only released on a few days ago if I am reading its
download page correctly.

The version of libcurl on my box is 7.18.something, and it does not seem
to ask for password when the URL has only username but not colon-password.
I also expected it to ask for password when $HOME/.netrc has login but not
password for a given machine, but that does not seem to happen either.
Perhaps the version is too old.
4) I'm not really impressed that file permissions actually make the .netrc
file a secure option. However, it's already in there and would break
backwards compatibility to take it out. I also realize that there is a need
for automated builds to be able to pull the source. So I would like to add a nice 
warning section to the http docs explaining the repercussions of using it.
I agree with the first two sentences and am not happy with http.password
because of it.


---
 http.c |   60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/http.c b/http.c
index f4f0bf6..3d5caa6 100644
--- a/http.c
+++ b/http.c
@@ -25,6 +25,7 @@ static long curl_low_speed_limit = -1;
 static long curl_low_speed_time = -1;
 static int curl_ftp_no_epsv;
 static const char *curl_http_proxy;
+static char *user_name, *user_pass;
 
 static struct curl_slist *pragma_header;
 
@@ -135,6 +136,20 @@ static int http_options(const char *var, const char *value, void *cb)
 	return git_default_config(var, value, cb);
 }
 
+static void init_curl_http_auth(CURL *result)
+{
+	if (!user_name)
+		curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
+	else {
+		struct strbuf up = STRBUF_INIT;
+		if (!user_pass)
+			user_pass = xstrdup(getpass("Password: "));
+		strbuf_addf(&up, "%s:%s", user_name, user_pass);
+		curl_easy_setopt(result, CURLOPT_USERPWD,
+				 strbuf_detach(&up, NULL));
+	}
+}
+
 static CURL *get_curl_handle(void)
 {
 	CURL *result = curl_easy_init();
@@ -153,6 +168,8 @@ static CURL *get_curl_handle(void)
 	curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
 #endif
 
+	init_curl_http_auth(result);
+
 	if (ssl_cert != NULL)
 		curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
 #if LIBCURL_VERSION_NUM >= 0x070902
@@ -190,6 +207,46 @@ static CURL *get_curl_handle(void)
 	return result;
 }
 
+static void http_auth_init(const char *url)
+{
+	char *at, *colon, *cp, *slash;
+	int len;
+
+	cp = strstr(url, "://");
+	if (!cp)
+		return;
+
+	/*
+	 * Ok, the URL looks like "proto://something".  Which one?
+	 * "proto://<user>:<pass>@<host>/...",
+	 * "proto://<user>@<host>/...", or just
+	 * "proto://<host>/..."?
+	 */
+	cp += 3;
+	at = strchr(cp, '@');
+	colon = strchr(cp, ':');
+	slash = strchrnul(cp, '/');
+	if (!at || slash <= at)
+		return; /* No credentials */
+	if (!colon || at <= colon) {
+		/* Only username */
+		len = at - cp;
+		user_name = xmalloc(len + 1);
+		memcpy(user_name, cp, len);
+		user_name[len] = '\0';
+		user_pass = NULL;
+	} else {
+		len = colon - cp;
+		user_name = xmalloc(len + 1);
+		memcpy(user_name, cp, len);
+		user_name[len] = '\0';
+		len = at - (colon + 1);
+		user_pass = xmalloc(len + 1);
+		memcpy(user_pass, colon + 1, len);
+		user_pass[len] = '\0';
+	}
+}
+
 void http_init(struct remote *remote)
 {
 	char *low_speed_limit;
@@ -252,6 +309,9 @@ void http_init(struct remote *remote)
 	if (getenv("GIT_CURL_FTP_NO_EPSV"))
 		curl_ftp_no_epsv = 1;
 
+	if (remote && remote->url && remote->url[0])
+		http_auth_init(remote->url[0]);
+
 #ifndef NO_CURL_EASY_DUPHANDLE
 	curl_default = get_curl_handle();
 #endif
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help