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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 578fcf5..ddde3e8 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 c6aaeb9..a7eff73 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 dea9902..b403727 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)