mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -05:00
SSH: added agent based authentication
CURLSSH_AUTH_AGENT is a new auth type for SSH
This commit is contained in:
parent
021e89b8c6
commit
e351972bc8
@ -631,6 +631,7 @@ typedef enum {
|
|||||||
#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */
|
#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */
|
||||||
#define CURLSSH_AUTH_HOST (1<<2) /* host key files */
|
#define CURLSSH_AUTH_HOST (1<<2) /* host key files */
|
||||||
#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */
|
#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */
|
||||||
|
#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */
|
||||||
#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
|
#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
|
||||||
|
|
||||||
#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */
|
#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */
|
||||||
|
114
lib/ssh.c
114
lib/ssh.c
@ -324,7 +324,8 @@ static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc)
|
|||||||
static LIBSSH2_FREE_FUNC(my_libssh2_free)
|
static LIBSSH2_FREE_FUNC(my_libssh2_free)
|
||||||
{
|
{
|
||||||
(void)abstract; /* arg not used */
|
(void)abstract; /* arg not used */
|
||||||
free(ptr);
|
if(ptr) /* ssh2 agent sometimes call free with null ptr */
|
||||||
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -345,6 +346,9 @@ static void state(struct connectdata *conn, sshstate nowstate)
|
|||||||
"SSH_AUTH_PKEY",
|
"SSH_AUTH_PKEY",
|
||||||
"SSH_AUTH_PASS_INIT",
|
"SSH_AUTH_PASS_INIT",
|
||||||
"SSH_AUTH_PASS",
|
"SSH_AUTH_PASS",
|
||||||
|
"SSH_AUTH_AGENT_INIT",
|
||||||
|
"SSH_AUTH_AGENT_LIST",
|
||||||
|
"SSH_AUTH_AGENT",
|
||||||
"SSH_AUTH_HOST_INIT",
|
"SSH_AUTH_HOST_INIT",
|
||||||
"SSH_AUTH_HOST",
|
"SSH_AUTH_HOST",
|
||||||
"SSH_AUTH_KEY_INIT",
|
"SSH_AUTH_KEY_INIT",
|
||||||
@ -893,12 +897,97 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
state(conn, SSH_AUTH_HOST);
|
state(conn, SSH_AUTH_HOST);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
state(conn, SSH_AUTH_KEY_INIT);
|
state(conn, SSH_AUTH_AGENT_INIT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_AUTH_HOST:
|
case SSH_AUTH_HOST:
|
||||||
state(conn, SSH_AUTH_KEY_INIT);
|
state(conn, SSH_AUTH_AGENT_INIT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_AUTH_AGENT_INIT:
|
||||||
|
#ifdef HAVE_LIBSSH2_AGENT_API
|
||||||
|
if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT)
|
||||||
|
&& (strstr(sshc->authlist, "publickey") != NULL)) {
|
||||||
|
|
||||||
|
/* Connect to the ssh-agent */
|
||||||
|
/* The agent could be shared by a curl thread i believe
|
||||||
|
but nothing obvious as keys can be added/removed at any time */
|
||||||
|
if(!sshc->ssh_agent) {
|
||||||
|
sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session);
|
||||||
|
if(!sshc->ssh_agent) {
|
||||||
|
infof(data, "Could not create agent object\n");
|
||||||
|
|
||||||
|
state(conn, SSH_AUTH_KEY_INIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = libssh2_agent_connect(sshc->ssh_agent);
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||||
|
break;
|
||||||
|
if(rc < 0) {
|
||||||
|
infof(data, "Failure connecting to agent\n");
|
||||||
|
state(conn, SSH_AUTH_KEY_INIT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state(conn, SSH_AUTH_AGENT_LIST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* HAVE_LIBSSH2_AGENT_API */
|
||||||
|
state(conn, SSH_AUTH_KEY_INIT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_AUTH_AGENT_LIST:
|
||||||
|
rc = libssh2_agent_list_identities(sshc->ssh_agent);
|
||||||
|
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||||
|
break;
|
||||||
|
if(rc < 0) {
|
||||||
|
infof(data, "Failure requesting identities to agent\n");
|
||||||
|
state(conn, SSH_AUTH_KEY_INIT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state(conn, SSH_AUTH_AGENT);
|
||||||
|
sshc->sshagent_prev_identity = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_AUTH_AGENT:
|
||||||
|
/* as prev_identity evolves only after an identity user auth finished we
|
||||||
|
can safely request it again as long as EAGAIN is returned here or by
|
||||||
|
libssh2_agent_userauth */
|
||||||
|
rc = libssh2_agent_get_identity(sshc->ssh_agent,
|
||||||
|
&sshc->sshagent_identity,
|
||||||
|
sshc->sshagent_prev_identity);
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(rc == 0) {
|
||||||
|
rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user,
|
||||||
|
sshc->sshagent_identity);
|
||||||
|
|
||||||
|
if(rc < 0) {
|
||||||
|
if(rc != LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
/* tried and failed? go to next identity */
|
||||||
|
sshc->sshagent_prev_identity = sshc->sshagent_identity;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rc < 0)
|
||||||
|
infof(data, "Failure requesting identities to agent\n");
|
||||||
|
else if(rc == 1)
|
||||||
|
infof(data, "No identity would match\n");
|
||||||
|
|
||||||
|
if(rc == LIBSSH2_ERROR_NONE) {
|
||||||
|
sshc->authed = TRUE;
|
||||||
|
infof(data, "Agent based authentication successful\n");
|
||||||
|
state(conn, SSH_AUTH_DONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
state(conn, SSH_AUTH_KEY_INIT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_AUTH_KEY_INIT:
|
case SSH_AUTH_KEY_INIT:
|
||||||
@ -2357,6 +2446,25 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2_AGENT_API
|
||||||
|
if(sshc->ssh_agent) {
|
||||||
|
rc = libssh2_agent_disconnect(sshc->ssh_agent);
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(rc < 0) {
|
||||||
|
infof(data, "Failed to disconnect from libssh2 agent\n");
|
||||||
|
}
|
||||||
|
libssh2_agent_free (sshc->ssh_agent);
|
||||||
|
sshc->ssh_agent = NULL;
|
||||||
|
|
||||||
|
/* NB: there is no need to free identities, they are part of internal
|
||||||
|
agent stuff */
|
||||||
|
sshc->sshagent_identity = NULL;
|
||||||
|
sshc->sshagent_prev_identity = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(sshc->ssh_session) {
|
if(sshc->ssh_session) {
|
||||||
rc = libssh2_session_free(sshc->ssh_session);
|
rc = libssh2_session_free(sshc->ssh_session);
|
||||||
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
@ -44,6 +44,9 @@ typedef enum {
|
|||||||
SSH_AUTH_PKEY,
|
SSH_AUTH_PKEY,
|
||||||
SSH_AUTH_PASS_INIT,
|
SSH_AUTH_PASS_INIT,
|
||||||
SSH_AUTH_PASS,
|
SSH_AUTH_PASS,
|
||||||
|
SSH_AUTH_AGENT_INIT,/* initialize then wait for connection to agent */
|
||||||
|
SSH_AUTH_AGENT_LIST,/* ask for list then wait for entire list to come */
|
||||||
|
SSH_AUTH_AGENT, /* attempt one key at a time */
|
||||||
SSH_AUTH_HOST_INIT,
|
SSH_AUTH_HOST_INIT,
|
||||||
SSH_AUTH_HOST,
|
SSH_AUTH_HOST,
|
||||||
SSH_AUTH_KEY_INIT,
|
SSH_AUTH_KEY_INIT,
|
||||||
@ -139,6 +142,12 @@ struct ssh_conn {
|
|||||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||||
int orig_waitfor; /* default READ/WRITE bits wait for */
|
int orig_waitfor; /* default READ/WRITE bits wait for */
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2_AGENT_API
|
||||||
|
LIBSSH2_AGENT *ssh_agent; /* proxy to ssh-agent/pageant */
|
||||||
|
struct libssh2_agent_publickey *sshagent_identity,
|
||||||
|
*sshagent_prev_identity;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h
|
/* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h
|
||||||
header */
|
header */
|
||||||
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
|
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
|
||||||
|
Loading…
Reference in New Issue
Block a user