summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-04-19 15:52:58 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-04-22 14:34:26 +0200
commitbc0a61986745b89258a98773f88bd98c44ef88d5 (patch)
treee86cff8daec29c4eb82c214ca01baac4f9a43533
parent2efd7df6b11e8c646d05870965bb4588d6b6d425 (diff)
downloadlibgit2-bc0a61986745b89258a98773f88bd98c44ef88d5.tar.gz
transports: allow the creds callback to say it doesn't exist
Allow the credentials callback to return GIT_PASSTHROUGH to make the transports code behave as though none was set. This should make it easier for bindings to behave closer to the C code when there is no credentials callback set at their level.
-rw-r--r--include/git2/remote.h3
-rw-r--r--src/transports/http.c55
-rw-r--r--src/transports/ssh.c32
3 files changed, 58 insertions, 32 deletions
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 578fcf51b..ddde3e85e 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -468,6 +468,9 @@ struct git_remote_callbacks {
/**
* This will be called if the remote host requires
* authentication in order to connect to it.
+ *
+ * Returning GIT_PASSTHROUGH will make libgit2 behave as
+ * though this field isn't set.
*/
int (*credentials)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data);
diff --git a/src/transports/http.c b/src/transports/http.c
index c6aaeb9cf..a7eff7365 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -248,6 +248,7 @@ static int on_headers_complete(http_parser *parser)
http_subtransport *t = ctx->t;
http_stream *s = ctx->s;
git_buf buf = GIT_BUF_INIT;
+ int error = 0, no_callback = 0;
/* Both parse_header_name and parse_header_value are populated
* and ready for consumption. */
@@ -256,29 +257,43 @@ static int on_headers_complete(http_parser *parser)
return t->parse_error = PARSE_ERROR_GENERIC;
/* Check for an authentication failure. */
+
if (parser->status_code == 401 &&
- get_verb == s->verb &&
- t->owner->cred_acquire_cb) {
- int allowed_types = 0;
+ get_verb == s->verb) {
+ if (!t->owner->cred_acquire_payload) {
+ no_callback = 1;
+ } else {
+ int allowed_types = 0;
+
+ if (parse_unauthorized_response(&t->www_authenticate,
+ &allowed_types, &t->auth_mechanism) < 0)
+ return t->parse_error = PARSE_ERROR_GENERIC;
+
+ if (allowed_types &&
+ (!t->cred || 0 == (t->cred->credtype & allowed_types))) {
+
+ error = t->owner->cred_acquire_cb(&t->cred,
+ t->owner->url,
+ t->connection_data.user,
+ allowed_types,
+ t->owner->cred_acquire_payload);
+
+ if (error == GIT_PASSTHROUGH) {
+ no_callback = 1;
+ } else if (error < 0) {
+ return PARSE_ERROR_GENERIC;
+ } else {
+ assert(t->cred);
+
+ /* Successfully acquired a credential. */
+ return t->parse_error = PARSE_ERROR_REPLAY;
+ }
+ }
+ }
- if (parse_unauthorized_response(&t->www_authenticate,
- &allowed_types, &t->auth_mechanism) < 0)
+ if (no_callback) {
+ giterr_set(GITERR_NET, "authentication required but no callback set");
return t->parse_error = PARSE_ERROR_GENERIC;
-
- if (allowed_types &&
- (!t->cred || 0 == (t->cred->credtype & allowed_types))) {
-
- if (t->owner->cred_acquire_cb(&t->cred,
- t->owner->url,
- t->connection_data.user,
- allowed_types,
- t->owner->cred_acquire_payload) < 0)
- return PARSE_ERROR_GENERIC;
-
- assert(t->cred);
-
- /* Successfully acquired a credential. */
- return t->parse_error = PARSE_ERROR_REPLAY;
}
}
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index dea990275..b403727c9 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -387,6 +387,7 @@ static int _git_ssh_setup_conn(
{
char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL;
const char *default_port="22";
+ int no_callback = 0;
ssh_stream *s;
LIBSSH2_SESSION* session=NULL;
LIBSSH2_CHANNEL* channel=NULL;
@@ -413,24 +414,31 @@ static int _git_ssh_setup_conn(
if (user && pass) {
if (git_cred_userpass_plaintext_new(&t->cred, user, pass) < 0)
goto on_error;
- } else if (t->owner->cred_acquire_cb) {
- if (t->owner->cred_acquire_cb(
- &t->cred, t->owner->url, user,
- GIT_CREDTYPE_USERPASS_PLAINTEXT |
- GIT_CREDTYPE_SSH_KEY |
- GIT_CREDTYPE_SSH_INTERACTIVE |
- GIT_CREDTYPE_SSH_CUSTOM,
- t->owner->cred_acquire_payload) < 0)
+ } else if (!t->owner->cred_acquire_cb) {
+ no_callback = 1;
+ } else {
+ int error;
+ error = t->owner->cred_acquire_cb(&t->cred, t->owner->url, user,
+ GIT_CREDTYPE_USERPASS_PLAINTEXT |
+ GIT_CREDTYPE_SSH_KEY | GIT_CREDTYPE_SSH_CUSTOM |
+ GIT_CREDTYPE_SSH_INTERACTIVE,
+ t->owner->cred_acquire_payload);
+
+ if (error == GIT_PASSTHROUGH)
+ no_callback = 1;
+ else if (error < 0)
goto on_error;
-
- if (!t->cred) {
+ else if (!t->cred) {
giterr_set(GITERR_SSH, "Callback failed to initialize SSH credentials");
goto on_error;
}
- } else {
- giterr_set(GITERR_SSH, "Cannot set up SSH connection without credentials");
+ }
+
+ if (no_callback) {
+ giterr_set(GITERR_SSH, "authentication required but no callback set");
goto on_error;
}
+
assert(t->cred);
if (_git_ssh_session_create(&session, s->socket) < 0)