Hi Armel,I found this local branch here with these two commits not merged into master. What is the state of them in your opinion?
-- / daniel.haxx.se
From a7d2462e4726c55d6320f2cfc37321f9c229891f Mon Sep 17 00:00:00 2001 From: Armel Asselin <[email protected]> Date: Fri, 9 Mar 2012 17:24:42 +0100 Subject: [PATCH 1/2] SSH: added agent based authentication CURLSSH_AUTH_AGENT is a new auth type for SSH --- include/curl/curl.h | 1 + lib/ssh.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++-- lib/ssh.h | 9 ++++ 3 files changed, 121 insertions(+), 3 deletions(-) diff --git a/include/curl/curl.h b/include/curl/curl.h index 2cad282..46ccf16 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -631,6 +631,7 @@ typedef enum { #define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ #define CURLSSH_AUTH_HOST (1<<2) /* host key files */ #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 CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ diff --git a/lib/ssh.c b/lib/ssh.c index 90c8013..0fd6d5f 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -324,7 +324,8 @@ static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc) static LIBSSH2_FREE_FUNC(my_libssh2_free) { (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_PASS_INIT", "SSH_AUTH_PASS", + "SSH_AUTH_AGENT_INIT", + "SSH_AUTH_AGENT_LIST", + "SSH_AUTH_AGENT", "SSH_AUTH_HOST_INIT", "SSH_AUTH_HOST", "SSH_AUTH_KEY_INIT", @@ -893,12 +897,97 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_AUTH_HOST); } else { - state(conn, SSH_AUTH_KEY_INIT); + state(conn, SSH_AUTH_AGENT_INIT); } break; 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; case SSH_AUTH_KEY_INIT: @@ -2357,6 +2446,25 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } #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) { rc = libssh2_session_free(sshc->ssh_session); if(rc == LIBSSH2_ERROR_EAGAIN) { diff --git a/lib/ssh.h b/lib/ssh.h index dce035b..bf43fdf 100644 --- a/lib/ssh.h +++ b/lib/ssh.h @@ -44,6 +44,9 @@ typedef enum { SSH_AUTH_PKEY, SSH_AUTH_PASS_INIT, 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, SSH_AUTH_KEY_INIT, @@ -139,6 +142,12 @@ struct ssh_conn { LIBSSH2_SFTP_HANDLE *sftp_handle; 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 header */ #ifdef HAVE_LIBSSH2_KNOWNHOST_API -- 1.7.10
From fbe4eafcd67287ab27148853a85426764e4c305e Mon Sep 17 00:00:00 2001 From: Armel Asselin <[email protected]> Date: Fri, 16 Mar 2012 22:40:39 +0100 Subject: [PATCH 2/2] docs: mention CURLSSH_AUTH_AGENT --- docs/libcurl/curl_easy_setopt.3 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index a90ee65..ac0dad1 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -2369,8 +2369,11 @@ GSS_C_DELEG_POLICY_FLAG was available at compile-time. .IP CURLOPT_SSH_AUTH_TYPES Pass a long set to a bitmask consisting of one or more of CURLSSH_AUTH_PUBLICKEY, CURLSSH_AUTH_PASSWORD, CURLSSH_AUTH_HOST, -CURLSSH_AUTH_KEYBOARD. Set CURLSSH_AUTH_ANY to let libcurl pick one. Currently -CURLSSH_AUTH_HOST has no effect. (Added in 7.16.1) +CURLSSH_AUTH_KEYBOARD and CURLSSH_AUTH_AGENT. Set CURLSSH_AUTH_ANY to let +libcurl pick a suitable one. Currently CURLSSH_AUTH_HOST has no effect. (Added +in 7.16.1) If CURLSSH_AUTH_AGENT is used, libcurl attempts to connect to +ssh-agent or pageant and let the agent attempt the authentication. (Added in +7.26.0) .IP CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 Pass a char * pointing to a string containing 32 hexadecimal digits. The string should be the 128 bit MD5 checksum of the remote host's public key, and -- 1.7.10
------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.html
