summaryrefslogtreecommitdiff
path: root/src/transports
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2015-05-07 12:57:56 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2016-04-19 13:54:19 +0200
commit07bd3e57d9a9930727695be690c8757f79117d45 (patch)
tree487cd3795e1f0ae208d53889c9a90bbed9924d03 /src/transports
parenta7bece2014ec043cfe58418dc13e982f79dcfcba (diff)
downloadlibgit2-07bd3e57d9a9930727695be690c8757f79117d45.tar.gz
proxy: ask the user for credentials if necessary
Diffstat (limited to 'src/transports')
-rw-r--r--src/transports/local.c5
-rw-r--r--src/transports/smart.c5
-rw-r--r--src/transports/smart.h1
-rw-r--r--src/transports/winhttp.c128
4 files changed, 127 insertions, 12 deletions
diff --git a/src/transports/local.c b/src/transports/local.c
index 1c6e5f01e..4eae9dead 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -25,6 +25,7 @@
#include "odb.h"
#include "push.h"
#include "remote.h"
+#include "proxy.h"
typedef struct {
git_transport parent;
@@ -199,6 +200,7 @@ static int local_connect(
const char *url,
git_cred_acquire_cb cred_acquire_cb,
void *cred_acquire_payload,
+ const git_proxy_options *proxy,
int direction, int flags)
{
git_repository *repo;
@@ -209,6 +211,7 @@ static int local_connect(
GIT_UNUSED(cred_acquire_cb);
GIT_UNUSED(cred_acquire_payload);
+ GIT_UNUSED(proxy);
if (t->connected)
return 0;
@@ -439,7 +442,7 @@ static int local_push(
if (!url || t->parent.close(&t->parent) < 0 ||
t->parent.connect(&t->parent, url,
- NULL, NULL, GIT_DIRECTION_PUSH, flags))
+ NULL, NULL, NULL, GIT_DIRECTION_PUSH, flags))
goto on_error;
}
diff --git a/src/transports/smart.c b/src/transports/smart.c
index b0611c35e..a78b57218 100644
--- a/src/transports/smart.c
+++ b/src/transports/smart.c
@@ -8,6 +8,7 @@
#include "smart.h"
#include "refs.h"
#include "refspec.h"
+#include "proxy.h"
static int git_smart__recv_cb(gitno_buffer *buf)
{
@@ -199,6 +200,7 @@ static int git_smart__connect(
const char *url,
git_cred_acquire_cb cred_acquire_cb,
void *cred_acquire_payload,
+ const git_proxy_options *proxy,
int direction,
int flags)
{
@@ -216,6 +218,9 @@ static int git_smart__connect(
t->url = git__strdup(url);
GITERR_CHECK_ALLOC(t->url);
+ if (git_proxy_options_dup(&t->proxy, proxy) < 0)
+ return -1;
+
t->direction = direction;
t->flags = flags;
t->cred_acquire_cb = cred_acquire_cb;
diff --git a/src/transports/smart.h b/src/transports/smart.h
index 800466adf..0a0c3fc1b 100644
--- a/src/transports/smart.h
+++ b/src/transports/smart.h
@@ -133,6 +133,7 @@ typedef struct {
char *url;
git_cred_acquire_cb cred_acquire_cb;
void *cred_acquire_payload;
+ git_proxy_options proxy;
int direction;
int flags;
git_transport_message_cb progress_cb;
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index 32b838084..22be39c6c 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -91,13 +91,39 @@ typedef struct {
git_smart_subtransport parent;
transport_smart *owner;
gitno_connection_data connection_data;
+ gitno_connection_data proxy_connection_data;
git_cred *cred;
git_cred *url_cred;
+ git_cred *proxy_cred;
int auth_mechanism;
HINTERNET session;
HINTERNET connection;
} winhttp_subtransport;
+static int apply_basic_credential_proxy(HINTERNET request, git_cred *cred)
+{
+ git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
+ wchar_t *user, *pass;
+ int error;
+
+ if ((error = git__utf8_to_16_alloc(&user, c->username)) < 0)
+ return error;
+
+ if ((error = git__utf8_to_16_alloc(&pass, c->password)) < 0)
+ return error;
+
+ if (!WinHttpSetCredentials(request, WINHTTP_AUTH_TARGET_PROXY, WINHTTP_AUTH_SCHEME_BASIC,
+ user, pass, NULL)) {
+ giterr_set(GITERR_OS, "failed to set proxy auth");
+ error = -1;
+ }
+
+ git__free(user);
+ git__free(pass);
+
+ return error;
+}
+
static int apply_basic_credential(HINTERNET request, git_cred *cred)
{
git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
@@ -271,6 +297,34 @@ static void winhttp_stream_close(winhttp_stream *s)
s->sent_request = 0;
}
+/**
+ * Extract the url and password from a URL. The outputs are pointers
+ * into the input.
+ */
+static int userpass_from_url(wchar_t **user, int *user_len,
+ wchar_t **pass, int *pass_len,
+ const wchar_t *url, int url_len)
+{
+ URL_COMPONENTS components = { 0 };
+
+ components.dwStructSize = sizeof(components);
+ /* These tell WinHttpCrackUrl that we're interested in the fields */
+ components.dwUserNameLength = 1;
+ components.dwPasswordLength = 1;
+
+ if (!WinHttpCrackUrl(url, url_len, 0, &components)) {
+ giterr_set(GITERR_OS, "failed to extract user/pass from url");
+ return -1;
+ }
+
+ *user = components.lpszUserName;
+ *user_len = components.dwUserNameLength;
+ *pass = components.lpszPassword;
+ *pass_len = components.dwPasswordLength;
+
+ return 0;
+}
+
static int winhttp_stream_connect(winhttp_stream *s)
{
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
@@ -284,6 +338,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
int default_timeout = TIMEOUT_INFINITE;
int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
size_t i;
+ const git_proxy_options *proxy_opts;
/* Prepare URL */
git_buf_printf(&buf, "%s%s", t->connection_data.path, s->service_url);
@@ -317,26 +372,49 @@ static int winhttp_stream_connect(winhttp_stream *s)
goto on_error;
}
- /* Set proxy if necessary */
- if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0)
- goto on_error;
+ proxy_opts = &t->owner->proxy;
+ if (proxy_opts->type == GIT_PROXY_AUTO) {
+ /* Set proxy if necessary */
+ if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0)
+ goto on_error;
+ }
+ else if (proxy_opts->type == GIT_PROXY_HTTP) {
+ proxy_url = git__strdup(proxy_opts->url);
+ GITERR_CHECK_ALLOC(proxy_url);
+ }
if (proxy_url) {
+ git_buf processed_url = GIT_BUF_INIT;
WINHTTP_PROXY_INFO proxy_info;
wchar_t *proxy_wide;
- /* Convert URL to wide characters */
- int proxy_wide_len = git__utf8_to_16_alloc(&proxy_wide, proxy_url);
+ if ((error = gitno_connection_data_from_url(&t->proxy_connection_data, proxy_url, NULL)) < 0)
+ goto on_error;
- if (proxy_wide_len < 0) {
- giterr_set(GITERR_OS, "Failed to convert string to wide form");
+ if (t->proxy_connection_data.user && t->proxy_connection_data.pass) {
+ if ((error = git_cred_userpass_plaintext_new(&t->proxy_cred, t->proxy_connection_data.user, t->proxy_connection_data.pass)) < 0)
+ goto on_error;
+ }
+
+ if (t->proxy_connection_data.use_ssl)
+ git_buf_puts(&processed_url, "https://");
+ else
+ git_buf_puts(&processed_url, "http://");
+
+ git_buf_puts(&processed_url, t->proxy_connection_data.host);
+ if (t->proxy_connection_data.port)
+ git_buf_printf(&processed_url, ":%s", t->proxy_connection_data.port);
+
+ if (git_buf_oom(&processed_url)) {
+ giterr_set_oom();
+ error = -1;
goto on_error;
}
- /* Strip any trailing forward slash on the proxy URL;
- * WinHTTP doesn't like it if one is present */
- if (proxy_wide_len > 1 && L'/' == proxy_wide[proxy_wide_len - 2])
- proxy_wide[proxy_wide_len - 2] = L'\0';
+ /* Convert URL to wide characters */
+ if ((error = git__utf8_to_16_alloc(&proxy_wide, processed_url.ptr)) < 0)
+ goto on_error;
+
proxy_info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
proxy_info.lpszProxy = proxy_wide;
@@ -352,6 +430,14 @@ static int winhttp_stream_connect(winhttp_stream *s)
}
git__free(proxy_wide);
+
+ if (t->proxy_cred) {
+ if (t->proxy_cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT) {
+ if ((error = apply_basic_credential_proxy(s->request, t->proxy_cred)) < 0)
+ goto on_error;
+ }
+ }
+
}
/* Disable WinHTTP redirects so we can handle them manually. Why, you ask?
@@ -919,6 +1005,26 @@ replay:
goto replay;
}
+ /* Handle proxy authentication failures */
+ if (status_code == HTTP_STATUS_PROXY_AUTH_REQ) {
+ int allowed_types;
+
+ if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0)
+ return -1;
+
+ /* TODO: extract the username from the url, no payload? */
+ if (t->owner->proxy.credentials) {
+ int cred_error = 1;
+ cred_error = t->owner->proxy.credentials(&t->proxy_cred, t->owner->proxy.url, NULL, allowed_types, NULL);
+
+ if (cred_error < 0)
+ return cred_error;
+ }
+
+ winhttp_stream_close(s);
+ goto replay;
+ }
+
/* Handle authentication failures */
if (HTTP_STATUS_DENIED == status_code && get_verb == s->verb) {
int allowed_types;