Commit bfc50f83 by Vicent Marti

Merge pull request #2273 from jacquesg/ssh-interactive

Add support for SSH keyboard-interactive authentication
parents 7b0f8ba9 a622ff17
...@@ -41,6 +41,9 @@ typedef enum { ...@@ -41,6 +41,9 @@ typedef enum {
/* git_cred_default */ /* git_cred_default */
GIT_CREDTYPE_DEFAULT = (1u << 3), GIT_CREDTYPE_DEFAULT = (1u << 3),
/* git_cred_ssh_interactive */
GIT_CREDTYPE_SSH_INTERACTIVE = (1u << 4),
} git_credtype_t; } git_credtype_t;
/* The base structure for all credential types */ /* The base structure for all credential types */
...@@ -60,8 +63,10 @@ typedef struct { ...@@ -60,8 +63,10 @@ typedef struct {
#ifdef GIT_SSH #ifdef GIT_SSH
typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback)); typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback));
typedef LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*git_cred_ssh_interactive_callback));
#else #else
typedef int (*git_cred_sign_callback)(void *, ...); typedef int (*git_cred_sign_callback)(void *, ...);
typedef int (*git_cred_ssh_interactive_callback)(void *, ...);
#endif #endif
/** /**
...@@ -76,6 +81,16 @@ typedef struct git_cred_ssh_key { ...@@ -76,6 +81,16 @@ typedef struct git_cred_ssh_key {
} git_cred_ssh_key; } git_cred_ssh_key;
/** /**
* Keyboard-interactive based ssh authentication
*/
typedef struct git_cred_ssh_interactive {
git_cred parent;
char *username;
git_cred_ssh_interactive_callback prompt_callback;
void *payload;
} git_cred_ssh_interactive;
/**
* A key with a custom signature function * A key with a custom signature function
*/ */
typedef struct git_cred_ssh_custom { typedef struct git_cred_ssh_custom {
...@@ -83,8 +98,8 @@ typedef struct git_cred_ssh_custom { ...@@ -83,8 +98,8 @@ typedef struct git_cred_ssh_custom {
char *username; char *username;
char *publickey; char *publickey;
size_t publickey_len; size_t publickey_len;
void *sign_callback; git_cred_sign_callback sign_callback;
void *sign_data; void *payload;
} git_cred_ssh_custom; } git_cred_ssh_custom;
/** A key for NTLM/Kerberos "default" credentials */ /** A key for NTLM/Kerberos "default" credentials */
...@@ -131,6 +146,21 @@ GIT_EXTERN(int) git_cred_ssh_key_new( ...@@ -131,6 +146,21 @@ GIT_EXTERN(int) git_cred_ssh_key_new(
const char *passphrase); 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. * Create a new ssh key credential object used for querying an ssh-agent.
* The supplied credential parameter will be internally duplicated. * The supplied credential parameter will be internally duplicated.
* *
...@@ -156,8 +186,8 @@ GIT_EXTERN(int) git_cred_ssh_key_from_agent( ...@@ -156,8 +186,8 @@ GIT_EXTERN(int) git_cred_ssh_key_from_agent(
* @param username username to use to authenticate * @param username username to use to authenticate
* @param publickey The bytes of the public key. * @param publickey The bytes of the public key.
* @param publickey_len The length of the public key in bytes. * @param publickey_len The length of the public key in bytes.
* @param sign_fn The callback method to sign the data during the challenge. * @param sign_callback The callback method to sign the data during the challenge.
* @param sign_data The data to pass to the sign function. * @param payload Additional data to pass to the callback.
* @return 0 for success or an error code for failure * @return 0 for success or an error code for failure
*/ */
GIT_EXTERN(int) git_cred_ssh_custom_new( GIT_EXTERN(int) git_cred_ssh_custom_new(
...@@ -165,8 +195,8 @@ GIT_EXTERN(int) git_cred_ssh_custom_new( ...@@ -165,8 +195,8 @@ GIT_EXTERN(int) git_cred_ssh_custom_new(
const char *username, const char *username,
const char *publickey, const char *publickey,
size_t publickey_len, size_t publickey_len,
git_cred_sign_callback sign_fn, git_cred_sign_callback sign_callback,
void *sign_data); void *payload);
/** /**
* Create a "default" credential usable for Negotiate mechanisms like NTLM * Create a "default" credential usable for Negotiate mechanisms like NTLM
......
...@@ -30,7 +30,6 @@ static void plaintext_free(struct git_cred *cred) ...@@ -30,7 +30,6 @@ static void plaintext_free(struct git_cred *cred)
git__free(c->password); git__free(c->password);
} }
git__memzero(c, sizeof(*c));
git__free(c); git__free(c);
} }
...@@ -73,8 +72,13 @@ static void ssh_key_free(struct git_cred *cred) ...@@ -73,8 +72,13 @@ static void ssh_key_free(struct git_cred *cred)
(git_cred_ssh_key *)cred; (git_cred_ssh_key *)cred;
git__free(c->username); git__free(c->username);
git__free(c->publickey);
if (c->privatekey) {
/* Zero the memory which previously held the private key */
size_t key_len = strlen(c->privatekey);
git__memzero(c->privatekey, key_len);
git__free(c->privatekey); git__free(c->privatekey);
}
if (c->passphrase) { if (c->passphrase) {
/* Zero the memory which previously held the passphrase */ /* Zero the memory which previously held the passphrase */
...@@ -83,7 +87,22 @@ static void ssh_key_free(struct git_cred *cred) ...@@ -83,7 +87,22 @@ static void ssh_key_free(struct git_cred *cred)
git__free(c->passphrase); git__free(c->passphrase);
} }
git__memzero(c, sizeof(*c)); if (c->publickey) {
/* Zero the memory which previously held the public key */
size_t key_len = strlen(c->publickey);
git__memzero(c->publickey, key_len);
git__free(c->publickey);
}
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__free(c); git__free(c);
} }
...@@ -92,9 +111,14 @@ static void ssh_custom_free(struct git_cred *cred) ...@@ -92,9 +111,14 @@ static void ssh_custom_free(struct git_cred *cred)
git_cred_ssh_custom *c = (git_cred_ssh_custom *)cred; git_cred_ssh_custom *c = (git_cred_ssh_custom *)cred;
git__free(c->username); git__free(c->username);
if (c->publickey) {
/* Zero the memory which previously held the publickey */
size_t key_len = strlen(c->publickey);
git__memzero(c->publickey, key_len);
git__free(c->publickey); git__free(c->publickey);
}
git__memzero(c, sizeof(*c));
git__free(c); git__free(c);
} }
...@@ -142,6 +166,32 @@ int git_cred_ssh_key_new( ...@@ -142,6 +166,32 @@ int git_cred_ssh_key_new(
return 0; 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) { int git_cred_ssh_key_from_agent(git_cred **cred, const char *username) {
git_cred_ssh_key *c; git_cred_ssh_key *c;
...@@ -168,7 +218,7 @@ int git_cred_ssh_custom_new( ...@@ -168,7 +218,7 @@ int git_cred_ssh_custom_new(
const char *publickey, const char *publickey,
size_t publickey_len, size_t publickey_len,
git_cred_sign_callback sign_callback, git_cred_sign_callback sign_callback,
void *sign_data) void *payload)
{ {
git_cred_ssh_custom *c; git_cred_ssh_custom *c;
...@@ -192,7 +242,7 @@ int git_cred_ssh_custom_new( ...@@ -192,7 +242,7 @@ int git_cred_ssh_custom_new(
c->publickey_len = publickey_len; c->publickey_len = publickey_len;
c->sign_callback = sign_callback; c->sign_callback = sign_callback;
c->sign_data = sign_data; c->payload = payload;
*cred = &c->parent; *cred = &c->parent;
return 0; return 0;
......
...@@ -310,7 +310,28 @@ static int _git_ssh_authenticate_session( ...@@ -310,7 +310,28 @@ static int _git_ssh_authenticate_session(
rc = libssh2_userauth_publickey( rc = libssh2_userauth_publickey(
session, c->username, (const unsigned char *)c->publickey, session, c->username, (const unsigned char *)c->publickey,
c->publickey_len, c->sign_callback, &c->sign_data); c->publickey_len, c->sign_callback, &c->payload);
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; break;
} }
default: default:
...@@ -397,6 +418,7 @@ static int _git_ssh_setup_conn( ...@@ -397,6 +418,7 @@ static int _git_ssh_setup_conn(
&t->cred, t->owner->url, user, &t->cred, t->owner->url, user,
GIT_CREDTYPE_USERPASS_PLAINTEXT | GIT_CREDTYPE_USERPASS_PLAINTEXT |
GIT_CREDTYPE_SSH_KEY | GIT_CREDTYPE_SSH_KEY |
GIT_CREDTYPE_SSH_INTERACTIVE |
GIT_CREDTYPE_SSH_CUSTOM, GIT_CREDTYPE_SSH_CUSTOM,
t->owner->cred_acquire_payload) < 0) t->owner->cred_acquire_payload) < 0)
goto on_error; goto on_error;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment