diff options
-rw-r--r-- | include/git2/types.h | 3 | ||||
-rw-r--r-- | src/transports/http.c | 13 | ||||
-rw-r--r-- | src/transports/ssh.c | 12 | ||||
-rw-r--r-- | src/transports/winhttp.c | 7 |
4 files changed, 29 insertions, 6 deletions
diff --git a/include/git2/types.h b/include/git2/types.h index 8d9a94710..8183b6c4e 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -330,6 +330,9 @@ typedef struct { * this certificate is valid * @param host Hostname of the host libgit2 connected to * @param payload Payload provided by the caller + * @return 0 to proceed with the connection, < 0 to fail the connection + * or > 0 to indicate that the callback refused to act and that + * the existing validity determination should be honored */ typedef int (*git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload); diff --git a/src/transports/http.c b/src/transports/http.c index 22b8bb864..14bd38b8d 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -367,11 +367,15 @@ static int on_headers_complete(http_parser *parser) allowed_auth_types, t->owner->cred_acquire_payload); - if (error == GIT_PASSTHROUGH) { - no_callback = 1; - } else if (error < 0) { + /* treat GIT_PASSTHROUGH as if callback isn't set */ + if (error == GIT_PASSTHROUGH) + error = 1; + + if (error < 0) { t->error = error; return t->parse_error = PARSE_ERROR_EXT; + } else if (error > 0) { + no_callback = 1; } else { assert(t->cred); @@ -634,6 +638,9 @@ static int http_connect(http_subtransport *t) giterr_clear(); error = t->owner->certificate_check_cb(cert, is_valid, t->connection_data.host, t->owner->message_cb_payload); + if (error > 0) + error = is_valid ? 0 : GIT_ECERTIFICATE; + if (error < 0) { if (!giterr_last()) giterr_set(GITERR_NET, "user cancelled certificate check"); diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 23c643346..614514337 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -448,9 +448,12 @@ static int request_creds(git_cred **out, ssh_subtransport *t, const char *user, t->owner->cred_acquire_payload); if (error == GIT_PASSTHROUGH) - no_callback = 1; - else if (error < 0) + error = 1; + + if (error < 0) return error; + else if (error > 0) + no_callback = 1; else if (!cred) { giterr_set(GITERR_SSH, "callback failed to initialize SSH credentials"); return -1; @@ -584,6 +587,11 @@ post_extract: cert_ptr = &cert; error = t->owner->certificate_check_cb((git_cert *) cert_ptr, 0, host, t->owner->message_cb_payload); + + /* If the callback chose not to act, fail this hostkey */ + if (error > 0) + error = GIT_ECERTIFICATE; + if (error < 0) { if (!giterr_last()) giterr_set(GITERR_NET, "user cancelled hostkey check"); diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index c3c18a80a..56e25b43c 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -226,7 +226,9 @@ static int fallback_cred_acquire_cb( return -1; } - if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) { + hCoInitResult = CoInitializeEx(NULL, COINIT_MULTITHREADED); + + if (SUCCEEDED(hCoInitResult) || hCoInitResult == RPC_E_CHANGED_MODE) { IInternetSecurityManager* pISM; /* And if the target URI is in the My Computer, Intranet, or Trusted zones */ @@ -290,6 +292,9 @@ static int certificate_check(winhttp_stream *s, int valid) error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->connection_data.host, t->owner->message_cb_payload); CertFreeCertificateContext(cert_ctx); + if (error > 0) + error = valid ? 0 : GIT_ECERTIFICATE; + if (error < 0 && !giterr_last()) giterr_set(GITERR_NET, "user cancelled certificate check"); |