summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Germishuys <jacquesg@striata.com>2014-04-17 23:03:44 +0200
committerJacques Germishuys <jacquesg@striata.com>2014-04-18 17:58:25 +0200
commit478408c01006f39ab916675bc84b8a7340bae086 (patch)
tree48bc3acd3a69ad8b4144d31b7c8ea1efd5472e5a
parent3c69bebc1c18444e9358c33f56c7cfefea4d1a8f (diff)
downloadlibgit2-478408c01006f39ab916675bc84b8a7340bae086.tar.gz
Introduce git_cred_ssh_interactive_new()
This allows for keyboard-interactive based SSH authentication
-rw-r--r--include/git2/transport.h30
-rw-r--r--src/transports/cred.c36
-rw-r--r--src/transports/ssh.c22
3 files changed, 88 insertions, 0 deletions
diff --git a/include/git2/transport.h b/include/git2/transport.h
index 1f4d03eea..eba08cd27 100644
--- a/include/git2/transport.h
+++ b/include/git2/transport.h
@@ -41,6 +41,9 @@ typedef enum {
/* git_cred_default */
GIT_CREDTYPE_DEFAULT = (1u << 3),
+
+ /* git_cred_ssh_interactive */
+ GIT_CREDTYPE_SSH_INTERACTIVE = (1u << 4),
} git_credtype_t;
/* The base structure for all credential types */
@@ -60,8 +63,10 @@ typedef struct {
#ifdef GIT_SSH
typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback));
+typedef LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*git_cred_ssh_interactive_callback));
#else
typedef int (*git_cred_sign_callback)(void *, ...);
+typedef int (*git_cred_ssh_interactive_callback)(void *, ...);
#endif
/**
@@ -76,6 +81,16 @@ typedef struct git_cred_ssh_key {
} git_cred_ssh_key;
/**
+ * Keyboard-interactive based ssh authentication
+ */
+typedef struct git_cred_ssh_interactive {
+ git_cred parent;
+ char *username;
+ void *prompt_callback;
+ void *payload;
+} git_cred_ssh_interactive;
+
+/**
* A key with a custom signature function
*/
typedef struct git_cred_ssh_custom {
@@ -131,6 +146,21 @@ GIT_EXTERN(int) git_cred_ssh_key_new(
const char *passphrase);
/**
+ * Create a new ssh keyboard-interactive based credential object.
+ * The supplied credential parameter will be internally duplicated.
+ *
+ * @param username Username to use to authenticate.
+ * @param prompt_callback The callback method used for prompts.
+ * @param payload Additional data to pass to the callback.
+ * @return 0 for success or an error code for failure.
+ */
+GIT_EXTERN(int) git_cred_ssh_interactive_new(
+ git_cred **out,
+ const char *username,
+ git_cred_ssh_interactive_callback prompt_callback,
+ void *payload);
+
+/**
* Create a new ssh key credential object used for querying an ssh-agent.
* The supplied credential parameter will be internally duplicated.
*
diff --git a/src/transports/cred.c b/src/transports/cred.c
index 460ed04a2..528d6af73 100644
--- a/src/transports/cred.c
+++ b/src/transports/cred.c
@@ -87,6 +87,16 @@ static void ssh_key_free(struct git_cred *cred)
git__free(c);
}
+static void ssh_interactive_free(struct git_cred *cred)
+{
+ git_cred_ssh_interactive *c = (git_cred_ssh_interactive *)cred;
+
+ git__free(c->username);
+
+ git__memzero(c, sizeof(*c));
+ git__free(c);
+}
+
static void ssh_custom_free(struct git_cred *cred)
{
git_cred_ssh_custom *c = (git_cred_ssh_custom *)cred;
@@ -142,6 +152,32 @@ int git_cred_ssh_key_new(
return 0;
}
+int git_cred_ssh_interactive_new(
+ git_cred **out,
+ const char *username,
+ git_cred_ssh_interactive_callback prompt_callback,
+ void *payload)
+{
+ git_cred_ssh_interactive *c;
+
+ assert(out && username && prompt_callback);
+
+ c = git__calloc(1, sizeof(git_cred_ssh_interactive));
+ GITERR_CHECK_ALLOC(c);
+
+ c->parent.credtype = GIT_CREDTYPE_SSH_INTERACTIVE;
+ c->parent.free = ssh_interactive_free;
+
+ c->username = git__strdup(username);
+ GITERR_CHECK_ALLOC(c->username);
+
+ c->prompt_callback = prompt_callback;
+ c->payload = payload;
+
+ *out = &c->parent;
+ return 0;
+}
+
int git_cred_ssh_key_from_agent(git_cred **cred, const char *username) {
git_cred_ssh_key *c;
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index 879af9059..48e51f2ae 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -313,6 +313,27 @@ static int _git_ssh_authenticate_session(
c->publickey_len, c->sign_callback, &c->sign_data);
break;
}
+ case GIT_CREDTYPE_SSH_INTERACTIVE: {
+ void **abstract = libssh2_session_abstract(session);
+ git_cred_ssh_interactive *c = (git_cred_ssh_interactive *)cred;
+
+ /* ideally, we should be able to set this by calling
+ * libssh2_session_init_ex() instead of libssh2_session_init().
+ * libssh2's API is inconsistent here i.e. libssh2_userauth_publickey()
+ * allows you to pass the `abstract` as part of the call, whereas
+ * libssh2_userauth_keyboard_interactive() does not!
+ *
+ * The only way to set the `abstract` pointer is by calling
+ * libssh2_session_abstract(), which will replace the existing
+ * pointer as is done below. This is safe for now (at time of writing),
+ * but may not be valid in future.
+ */
+ *abstract = c->payload;
+
+ rc = libssh2_userauth_keyboard_interactive(
+ session, c->username, c->prompt_callback);
+ break;
+ }
default:
rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED;
}
@@ -397,6 +418,7 @@ static int _git_ssh_setup_conn(
&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)
goto on_error;