From 66c8448543432308e8fce5e3e04076e875410f67 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:48:51 -0400 Subject: url: decode buffers that are not NUL-terminated The url_decode function needs only minor tweaks to handle arbitrary buffers. Let's do those tweaks, which cleans up an unreadable mess of temporary strings in http.c. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- http.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index a1ea3db499..c93716c72f 100644 --- a/http.c +++ b/http.c @@ -307,8 +307,7 @@ static CURL *get_curl_handle(void) static void http_auth_init(const char *url) { - char *at, *colon, *cp, *slash, *decoded; - int len; + char *at, *colon, *cp, *slash; cp = strstr(url, "://"); if (!cp) @@ -328,29 +327,11 @@ static void http_auth_init(const char *url) 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'; - decoded = url_decode(user_name); - free(user_name); - user_name = decoded; + user_name = url_decode_mem(cp, at - cp); user_pass = NULL; } else { - len = colon - cp; - user_name = xmalloc(len + 1); - memcpy(user_name, cp, len); - user_name[len] = '\0'; - decoded = url_decode(user_name); - free(user_name); - user_name = decoded; - len = at - (colon + 1); - user_pass = xmalloc(len + 1); - memcpy(user_pass, colon + 1, len); - user_pass[len] = '\0'; - decoded = url_decode(user_pass); - free(user_pass); - user_pass = decoded; + user_name = url_decode_mem(cp, colon - cp); + user_pass = url_decode_mem(colon + 1, at - (colon + 1)); } } -- cgit v1.2.3 From 8d677edc4fa3fd1fe12b49bf279aaad5be89b81c Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:50:14 -0400 Subject: http: retry authentication failures for all http requests Commit 42653c0 (Prompt for a username when an HTTP request 401s, 2010-04-01) changed http_get_strbuf to prompt for credentials when we receive a 401, but didn't touch http_get_file. The latter is called only for dumb http; while it's usually the case that people don't use authentication on top of dumb http, there is no reason not to allow both types of requests to use this feature. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- http.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index c93716c72f..89e3cf4bd8 100644 --- a/http.c +++ b/http.c @@ -846,13 +846,18 @@ static int http_request(const char *url, void *result, int target, int options) return ret; } +static int http_request_reauth(const char *url, void *result, int target, + int options) +{ + int ret = http_request(url, result, target, options); + if (ret != HTTP_REAUTH) + return ret; + return http_request(url, result, target, options); +} + int http_get_strbuf(const char *url, struct strbuf *result, int options) { - int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options); - if (http_ret == HTTP_REAUTH) { - http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options); - } - return http_ret; + return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options); } /* @@ -875,7 +880,7 @@ static int http_get_file(const char *url, const char *filename, int options) goto cleanup; } - ret = http_request(url, result, HTTP_REQUEST_FILE, options); + ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options); fclose(result); if ((ret == HTTP_OK) && move_temp_to_file(tmpfile.buf, filename)) -- cgit v1.2.3 From 070b4dd5899927cb399b8ae9d75cad1fce537429 Mon Sep 17 00:00:00 2001 From: Michael J Gruber Date: Fri, 14 Oct 2011 09:40:39 +0200 Subject: http: use hostname in credential description Until now, a request for an http password looked like: Username: Password: Now it will look like: Username for 'example.com': Password for 'example.com': Picked-from: Jeff King Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- http.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index 89e3cf4bd8..7ae0c2a320 100644 --- a/http.c +++ b/http.c @@ -42,7 +42,7 @@ static long curl_low_speed_time = -1; static int curl_ftp_no_epsv; static const char *curl_http_proxy; static const char *curl_cookie_file; -static char *user_name, *user_pass; +static char *user_name, *user_pass, *description; static const char *user_agent; #if LIBCURL_VERSION_NUM >= 0x071700 @@ -139,6 +139,27 @@ static void process_curl_messages(void) } #endif +static char *git_getpass_with_description(const char *what, const char *desc) +{ + struct strbuf prompt = STRBUF_INIT; + char *r; + + if (desc) + strbuf_addf(&prompt, "%s for '%s': ", what, desc); + else + strbuf_addf(&prompt, "%s: ", what); + /* + * NEEDSWORK: for usernames, we should do something less magical that + * actually echoes the characters. However, we need to read from + * /dev/tty and not stdio, which is not portable (but getpass will do + * it for us). http.c uses the same workaround. + */ + r = git_getpass(prompt.buf); + + strbuf_release(&prompt); + return xstrdup(r); +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -214,7 +235,7 @@ static void init_curl_http_auth(CURL *result) if (user_name) { struct strbuf up = STRBUF_INIT; if (!user_pass) - user_pass = xstrdup(git_getpass("Password: ")); + user_pass = xstrdup(git_getpass_with_description("Password", description)); strbuf_addf(&up, "%s:%s", user_name, user_pass); curl_easy_setopt(result, CURLOPT_USERPWD, strbuf_detach(&up, NULL)); @@ -229,7 +250,7 @@ static int has_cert_password(void) return 0; /* Only prompt the user once. */ ssl_cert_password_required = -1; - ssl_cert_password = git_getpass("Certificate Password: "); + ssl_cert_password = git_getpass_with_description("Certificate Password", description); if (ssl_cert_password != NULL) { ssl_cert_password = xstrdup(ssl_cert_password); return 1; @@ -307,7 +328,7 @@ static CURL *get_curl_handle(void) static void http_auth_init(const char *url) { - char *at, *colon, *cp, *slash; + const char *at, *colon, *cp, *slash, *host; cp = strstr(url, "://"); if (!cp) @@ -323,16 +344,22 @@ static void http_auth_init(const char *url) at = strchr(cp, '@'); colon = strchr(cp, ':'); slash = strchrnul(cp, '/'); - if (!at || slash <= at) - return; /* No credentials */ - if (!colon || at <= colon) { + if (!at || slash <= at) { + /* No credentials, but we may have to ask for some later */ + host = cp; + } + else if (!colon || at <= colon) { /* Only username */ user_name = url_decode_mem(cp, at - cp); user_pass = NULL; + host = at + 1; } else { user_name = url_decode_mem(cp, colon - cp); user_pass = url_decode_mem(colon + 1, at - (colon + 1)); + host = at + 1; } + + description = url_decode_mem(host, slash - host); } static void set_from_env(const char **var, const char *envname) @@ -828,7 +855,7 @@ static int http_request(const char *url, void *result, int target, int options) * but that is non-portable. Using git_getpass() can at least be stubbed * on other platforms with a different implementation if/when necessary. */ - user_name = xstrdup(git_getpass("Username: ")); + user_name = xstrdup(git_getpass_with_description("Username", description)); init_curl_http_auth(slot->curl); ret = HTTP_REAUTH; } -- cgit v1.2.3 From deba49377b717d1e26c342f65c7f5e75a2db8641 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 14 Oct 2011 09:40:40 +0200 Subject: http_init: accept separate URL parameter The http_init function takes a "struct remote". Part of its initialization procedure is to look at the remote's url and grab some auth-related parameters. However, using the url included in the remote is: - wrong; the remote-curl helper may have a separate, unrelated URL (e.g., from remote.*.pushurl). Looking at the remote's configured url is incorrect. - incomplete; http-fetch doesn't have a remote, so passes NULL. So http_init never gets to see the URL we are actually going to use. - cumbersome; http-push has a similar problem to http-fetch, but actually builds a fake remote just to pass in the URL. Instead, let's just add a separate URL parameter to http_init, and all three callsites can pass in the appropriate information. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- http.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index 7ae0c2a320..00a8553fcc 100644 --- a/http.c +++ b/http.c @@ -369,7 +369,7 @@ static void set_from_env(const char **var, const char *envname) *var = val; } -void http_init(struct remote *remote) +void http_init(struct remote *remote, const char *url) { char *low_speed_limit; char *low_speed_time; @@ -433,11 +433,11 @@ 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]); + if (url) { + http_auth_init(url); if (!ssl_cert_password_required && getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") && - !prefixcmp(remote->url[0], "https://")) + !prefixcmp(url, "https://")) ssl_cert_password_required = 1; } -- cgit v1.2.3