Loading include/curl/curl.h +1 −0 Original line number Diff line number Diff line Loading @@ -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) */ Loading lib/ssh.c +111 −3 Original line number Diff line number Diff line Loading @@ -324,6 +324,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); } Loading @@ -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", Loading Loading @@ -893,11 +897,96 @@ 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 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; Loading Loading @@ -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) { Loading lib/ssh.h +9 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 Loading Loading
include/curl/curl.h +1 −0 Original line number Diff line number Diff line Loading @@ -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) */ Loading
lib/ssh.c +111 −3 Original line number Diff line number Diff line Loading @@ -324,6 +324,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); } Loading @@ -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", Loading Loading @@ -893,11 +897,96 @@ 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 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; Loading Loading @@ -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) { Loading
lib/ssh.h +9 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 Loading