mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-13 23:05:27 +00:00
Merge pull request #2273 from jacquesg/ssh-interactive
Add support for SSH keyboard-interactive authentication
This commit is contained in:
commit
bfc50f83f8
@ -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 {
|
|||||||
|
|
||||||
#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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,6 +80,16 @@ typedef struct git_cred_ssh_key {
|
|||||||
char *passphrase;
|
char *passphrase;
|
||||||
} 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
|
||||||
*/
|
*/
|
||||||
@ -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 */
|
||||||
@ -130,6 +145,21 @@ GIT_EXTERN(int) git_cred_ssh_key_new(
|
|||||||
const char *privatekey,
|
const char *privatekey,
|
||||||
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(
|
|||||||
* @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(
|
|||||||
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)
|
|||||||
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)
|
|||||||
(git_cred_ssh_key *)cred;
|
(git_cred_ssh_key *)cred;
|
||||||
|
|
||||||
git__free(c->username);
|
git__free(c->username);
|
||||||
git__free(c->publickey);
|
|
||||||
git__free(c->privatekey);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
git__free(c->publickey);
|
|
||||||
|
|
||||||
git__memzero(c, sizeof(*c));
|
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);
|
git__free(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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(
|
|||||||
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(
|
|||||||
|
|
||||||
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(
|
|||||||
|
|
||||||
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(
|
|||||||
&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;
|
||||||
|
Loading…
Reference in New Issue
Block a user