curl-library
Re: Re: Adding SSH agent / pageant integration?
Date: Sun, 11 Mar 2012 18:55:27 +0100
>On Fri, 9 Mar 2012, Elli? Computing Open Source Program wrote:
>
>> here is what I ended up for agent based authentication, I could test it
>> on
>> my windows box and a linux vm against a WinSCP server.
>
>Thanks!
>
>The patch is unfortunately broken and can't be applied, presumably your
>mail
>client messed it up. Try attaching the patch file instead.
unfortunately all the attachments that I send to the list are removed by the
list management system :(
>Additionally, we need this new feature documented so that users will know
>how
>to use it!
I'll add the doc soon, but this can be two patches no need to put the code
and the doc in a single patch.
>(Also please jsut note that this won't be merged until after the next
>release
>has shipped.)
no problem.
ps: I send you the mail directly with the attachment as well, at least this
one will work!
let's try again:
From: Armel Asselin <armelasselin_at_hotmail.com>
Date: Fri, 9 Mar 2012 17:24:42 +0100
Subject: [PATCH] added agent based authentication
---
include/curl/curl.h | 1 +
lib/ssh.c | 116
++++++++++++++++++++++++++++++++++++++++++++++++++-
lib/ssh.h | 9 ++++
3 files changed, 125 insertions(+), 1 deletions(-)
diff --git a/include/curl/curl.h b/include/curl/curl.h
index f2501cd..db17e42 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -617,6 +617,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 20e9848..3296f0b 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -318,6 +318,7 @@ static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc)
static LIBSSH2_FREE_FUNC(my_libssh2_free)
{
(void)abstract; /* arg not used */
+ if(ptr) /* ssh2 agent sometimes call free with null ptr */
free(ptr);
}
@@ -339,6 +340,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",
@@ -889,12 +893,103 @@ 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_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 lons 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:
@@ -2403,6 +2498,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.9.msysgit.0
Received on 2012-03-11