From 09fed294601cdc8c48f268ee980c7f0df0ff3adc Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 7 May 2025 13:45:41 +0200 Subject: [PATCH] ssh: move easy handle/connection protocol structs to meta Closes #17273 --- lib/request.h | 1 - lib/url.c | 8 +- lib/urldata.h | 7 - lib/vssh/libssh.c | 584 ++++++++++++++++++++++++--------------------- lib/vssh/libssh2.c | 559 +++++++++++++++++++++++++------------------ lib/vssh/ssh.h | 5 + lib/vssh/wolfssh.c | 194 +++++++++------ 7 files changed, 781 insertions(+), 577 deletions(-) diff --git a/lib/request.h b/lib/request.h index f26ae7f2f7..1ac873099a 100644 --- a/lib/request.h +++ b/lib/request.h @@ -103,7 +103,6 @@ struct SingleRequest { points to data it needs. */ union { struct FILEPROTO *file; - struct SSHPROTO *ssh; } p; #ifndef CURL_DISABLE_COOKIES unsigned char setcookies; diff --git a/lib/url.c b/lib/url.c index 02b386f055..aac9c2e84f 100644 --- a/lib/url.c +++ b/lib/url.c @@ -801,8 +801,12 @@ CURLcode Curl_conn_upkeep(struct Curl_easy *data, static bool ssh_config_matches(struct connectdata *one, struct connectdata *two) { - return Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) && - Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub); + struct ssh_conn *sshc1, *sshc2; + + sshc1 = Curl_conn_meta_get(one, CURL_META_SSH_CONN); + sshc2 = Curl_conn_meta_get(two, CURL_META_SSH_CONN); + return (sshc1 && sshc2 && Curl_safecmp(sshc1->rsa, sshc2->rsa) && + Curl_safecmp(sshc1->rsa_pub, sshc2->rsa_pub)); } #endif diff --git a/lib/urldata.h b/lib/urldata.h index 44030fec7c..912abdada2 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -862,13 +862,6 @@ struct connectdata { struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */ #endif - union { -#ifdef USE_SSH - struct ssh_conn sshc; -#endif - unsigned int unused:1; /* avoids empty union */ - } proto; - #ifdef USE_UNIX_SOCKETS char *unix_domain_socket; #endif diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 13a6147be6..e288cd2ec5 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -130,15 +130,19 @@ CURLcode sftp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done); -static void sftp_quote(struct Curl_easy *data); -static void sftp_quote_stat(struct Curl_easy *data); +static void sftp_quote(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp); +static void sftp_quote_stat(struct Curl_easy *data, struct ssh_conn *sshc); static int myssh_getsock(struct Curl_easy *data, struct connectdata *conn, curl_socket_t *sock); -static void myssh_block2waitfor(struct connectdata *conn, bool block); +static void myssh_block2waitfor(struct connectdata *conn, + struct ssh_conn *sshc, + bool block); static CURLcode myssh_setup_connection(struct Curl_easy *data, struct connectdata *conn); -static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data); +static void sshc_cleanup(struct ssh_conn *sshc); /* * SCP protocol handler. @@ -224,23 +228,23 @@ static CURLcode sftp_error_to_CURLE(int err) } #ifndef DEBUGBUILD -#define state(x,y) mystate(x,y) +#define myssh_state(x,y,z) myssh_set_state(x,y,z) #else -#define state(x,y) mystate(x,y, __LINE__) +#define myssh_state(x,y,z) myssh_set_state(x,y,z, __LINE__) #endif /* * SSH State machine related code */ /* This is the ONLY way to change SSH state! */ -static void mystate(struct Curl_easy *data, sshstate nowstate +static void myssh_set_state(struct Curl_easy *data, + struct ssh_conn *sshc, + sshstate nowstate #ifdef DEBUGBUILD - , int lineno + , int lineno #endif ) { - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char *const names[] = { @@ -313,7 +317,7 @@ static void mystate(struct Curl_easy *data, sshstate nowstate lineno); } #endif - + (void)data; sshc->state = nowstate; } @@ -327,11 +331,9 @@ static void mystate(struct Curl_easy *data, sshstate nowstate * * Returns SSH_OK or SSH_ERROR. */ -static int myssh_is_known(struct Curl_easy *data) +static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc) { int rc; - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; ssh_key pubkey; size_t hlen; unsigned char *hash = NULL; @@ -517,14 +519,14 @@ cleanup: return rc; } -#define MOVE_TO_ERROR_STATE(_r) do { \ - state(data, SSH_SESSION_DISCONNECT); \ - sshc->actualcode = _r; \ - rc = SSH_ERROR; \ +#define MOVE_TO_ERROR_STATE(_r) do { \ + myssh_state(data, sshc, SSH_SESSION_DISCONNECT); \ + sshc->actualcode = _r; \ + rc = SSH_ERROR; \ } while(0) #define MOVE_TO_SFTP_CLOSE_STATE() do { \ - state(data, SSH_SFTP_CLOSE); \ + myssh_state(data, sshc, SSH_SFTP_CLOSE); \ sshc->actualcode = \ sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \ rc = SSH_ERROR; \ @@ -533,7 +535,7 @@ cleanup: #define MOVE_TO_PASSWD_AUTH do { \ if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \ rc = SSH_OK; \ - state(data, SSH_AUTH_PASS_INIT); \ + myssh_state(data, sshc, SSH_AUTH_PASS_INIT); \ } \ else { \ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \ @@ -543,7 +545,7 @@ cleanup: #define MOVE_TO_KEY_AUTH do { \ if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \ rc = SSH_OK; \ - state(data, SSH_AUTH_KEY_INIT); \ + myssh_state(data, sshc, SSH_AUTH_KEY_INIT); \ } \ else { \ MOVE_TO_PASSWD_AUTH; \ @@ -553,7 +555,7 @@ cleanup: #define MOVE_TO_GSSAPI_AUTH do { \ if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \ rc = SSH_OK; \ - state(data, SSH_AUTH_GSSAPI); \ + myssh_state(data, sshc, SSH_AUTH_GSSAPI); \ } \ else { \ MOVE_TO_KEY_AUTH; \ @@ -561,10 +563,10 @@ cleanup: } while(0) static -int myssh_auth_interactive(struct connectdata *conn) +int myssh_auth_interactive(struct connectdata *conn, + struct ssh_conn *sshc) { int rc; - struct ssh_conn *sshc = &conn->proto.sshc; int nprompts; restart: @@ -631,12 +633,13 @@ restart: * to will be set to TRUE if the libssh function returns SSH_AGAIN * meaning it wants to be called again when the socket is ready */ -static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) +static CURLcode myssh_statemach_act(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp, + bool *block) { CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; - struct SSHPROTO *protop = data->req.p.ssh; - struct ssh_conn *sshc = &conn->proto.sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc = SSH_NO_ERROR, err; int seekerr = CURL_SEEKFUNC_OK; @@ -659,13 +662,13 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) non-blocking */ ssh_set_blocking(sshc->ssh_session, 0); - state(data, SSH_S_STARTUP); + myssh_state(data, sshc, SSH_S_STARTUP); FALLTHROUGH(); case SSH_S_STARTUP: rc = ssh_connect(sshc->ssh_session); - myssh_block2waitfor(conn, (rc == SSH_AGAIN)); + myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN)); if(rc == SSH_AGAIN) { DEBUGF(infof(data, "ssh_connect -> EAGAIN")); break; @@ -677,18 +680,18 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; } - state(data, SSH_HOSTKEY); + myssh_state(data, sshc, SSH_HOSTKEY); FALLTHROUGH(); case SSH_HOSTKEY: - rc = myssh_is_known(data); + rc = myssh_is_known(data, sshc); if(rc != SSH_OK) { MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION); break; } - state(data, SSH_AUTHLIST); + myssh_state(data, sshc, SSH_AUTHLIST); FALLTHROUGH(); case SSH_AUTHLIST:{ sshc->authed = FALSE; @@ -702,7 +705,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(rc == SSH_AUTH_SUCCESS) { sshc->authed = TRUE; infof(data, "Authenticated with none"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); break; } else if(rc == SSH_AUTH_ERROR) { @@ -723,17 +726,17 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ? "password": ""); if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { - state(data, SSH_AUTH_PKEY_INIT); + myssh_state(data, sshc, SSH_AUTH_PKEY_INIT); infof(data, "Authentication using SSH public key file"); } else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { - state(data, SSH_AUTH_GSSAPI); + myssh_state(data, sshc, SSH_AUTH_GSSAPI); } else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { - state(data, SSH_AUTH_KEY_INIT); + myssh_state(data, sshc, SSH_AUTH_KEY_INIT); } else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { - state(data, SSH_AUTH_PASS_INIT); + myssh_state(data, sshc, SSH_AUTH_PASS_INIT); } else { /* unsupported authentication method */ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); @@ -776,7 +779,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; } - state(data, SSH_AUTH_PKEY); + myssh_state(data, sshc, SSH_AUTH_PKEY); break; } @@ -791,7 +794,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) rc = SSH_OK; sshc->authed = TRUE; infof(data, "Completed public key authentication"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); break; } @@ -808,7 +811,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(rc == SSH_AUTH_SUCCESS) { sshc->authed = TRUE; infof(data, "Completed public key authentication"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); break; } else { @@ -833,7 +836,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) rc = SSH_OK; sshc->authed = TRUE; infof(data, "Completed gssapi authentication"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); break; } @@ -842,7 +845,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) case SSH_AUTH_KEY_INIT: if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) { - state(data, SSH_AUTH_KEY); + myssh_state(data, sshc, SSH_AUTH_KEY); } else { MOVE_TO_PASSWD_AUTH; @@ -851,14 +854,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) case SSH_AUTH_KEY: /* keyboard-interactive authentication */ - rc = myssh_auth_interactive(conn); + rc = myssh_auth_interactive(conn, sshc); if(rc == SSH_AGAIN) { break; } if(rc == SSH_OK) { sshc->authed = TRUE; infof(data, "completed keyboard interactive authentication"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); } else { MOVE_TO_PASSWD_AUTH; @@ -870,7 +873,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); break; } - state(data, SSH_AUTH_PASS); + myssh_state(data, sshc, SSH_AUTH_PASS); FALLTHROUGH(); case SSH_AUTH_PASS: @@ -883,7 +886,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(rc == SSH_AUTH_SUCCESS) { sshc->authed = TRUE; infof(data, "Completed password authentication"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); } else { MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); @@ -908,11 +911,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) conn->writesockfd = CURL_SOCKET_BAD; if(conn->handler->protocol == CURLPROTO_SFTP) { - state(data, SSH_SFTP_INIT); + myssh_state(data, sshc, SSH_SFTP_INIT); break; } infof(data, "SSH CONNECT phase done"); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; case SSH_SFTP_INIT: @@ -933,7 +936,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE)); break; } - state(data, SSH_SFTP_REALPATH); + myssh_state(data, sshc, SSH_SFTP_REALPATH); FALLTHROUGH(); case SSH_SFTP_REALPATH: /* @@ -954,24 +957,24 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) since the homedir will remain the same between request but the working path will not. */ DEBUGF(infof(data, "SSH CONNECT phase done")); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; case SSH_SFTP_QUOTE_INIT: - result = Curl_getworkingpath(data, sshc->homedir, &protop->path); + result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); if(result) { sshc->actualcode = result; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } if(data->set.quote) { infof(data, "Sending quote commands"); sshc->quote_item = data->set.quote; - state(data, SSH_SFTP_QUOTE); + myssh_state(data, sshc, SSH_SFTP_QUOTE); } else { - state(data, SSH_SFTP_GETINFO); + myssh_state(data, sshc, SSH_SFTP_GETINFO); } break; @@ -979,16 +982,16 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(data->set.postquote) { infof(data, "Sending quote commands"); sshc->quote_item = data->set.postquote; - state(data, SSH_SFTP_QUOTE); + myssh_state(data, sshc, SSH_SFTP_QUOTE); } else { - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); } break; case SSH_SFTP_QUOTE: /* Send any quote commands */ - sftp_quote(data); + sftp_quote(data, sshc, sshp); break; case SSH_SFTP_NEXT_QUOTE: @@ -998,21 +1001,21 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) sshc->quote_item = sshc->quote_item->next; if(sshc->quote_item) { - state(data, SSH_SFTP_QUOTE); + myssh_state(data, sshc, SSH_SFTP_QUOTE); } else { if(sshc->nextstate != SSH_NO_STATE) { - state(data, sshc->nextstate); + myssh_state(data, sshc, sshc->nextstate); sshc->nextstate = SSH_NO_STATE; } else { - state(data, SSH_SFTP_GETINFO); + myssh_state(data, sshc, SSH_SFTP_GETINFO); } } break; case SSH_SFTP_QUOTE_STAT: - sftp_quote_stat(data); + sftp_quote_stat(data, sshc); break; case SSH_SFTP_QUOTE_SETSTAT: @@ -1023,7 +1026,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path2); failf(data, "Attempt to set SFTP stats failed: %s", ssh_get_error(sshc->ssh_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; /* sshc->actualcode = sftp_error_to_CURLE(err); @@ -1031,7 +1034,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) * the error the libssh2 backend is returning */ break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_SYMLINK: @@ -1042,12 +1045,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path2); failf(data, "symlink command failed: %s", ssh_get_error(sshc->ssh_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_MKDIR: @@ -1057,12 +1060,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path1); failf(data, "mkdir command failed: %s", ssh_get_error(sshc->ssh_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RENAME: @@ -1073,12 +1076,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path2); failf(data, "rename command failed: %s", ssh_get_error(sshc->ssh_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RMDIR: @@ -1087,12 +1090,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path1); failf(data, "rmdir command failed: %s", ssh_get_error(sshc->ssh_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_UNLINK: @@ -1101,12 +1104,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path1); failf(data, "rm command failed: %s", ssh_get_error(sshc->ssh_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_STATVFS: @@ -1118,7 +1121,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path1); failf(data, "statvfs command failed: %s", ssh_get_error(sshc->ssh_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; @@ -1151,7 +1154,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(!tmp) { result = CURLE_OUT_OF_MEMORY; - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; break; } @@ -1159,21 +1162,21 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); free(tmp); if(result) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; } case SSH_SFTP_GETINFO: if(data->set.get_filetime) { - state(data, SSH_SFTP_FILETIME); + myssh_state(data, sshc, SSH_SFTP_FILETIME); } else { - state(data, SSH_SFTP_TRANS_INIT); + myssh_state(data, sshc, SSH_SFTP_TRANS_INIT); } break; @@ -1181,24 +1184,24 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) { sftp_attributes attrs; - attrs = sftp_stat(sshc->sftp_session, protop->path); + attrs = sftp_stat(sshc->sftp_session, sshp->path); if(attrs) { data->info.filetime = attrs->mtime; sftp_attributes_free(attrs); } - state(data, SSH_SFTP_TRANS_INIT); + myssh_state(data, sshc, SSH_SFTP_TRANS_INIT); break; } case SSH_SFTP_TRANS_INIT: if(data->state.upload) - state(data, SSH_SFTP_UPLOAD_INIT); + myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); else { - if(protop->path[strlen(protop->path)-1] == '/') - state(data, SSH_SFTP_READDIR_INIT); + if(sshp->path[strlen(sshp->path)-1] == '/') + myssh_state(data, sshc, SSH_SFTP_READDIR_INIT); else - state(data, SSH_SFTP_DOWNLOAD_INIT); + myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT); } break; @@ -1210,7 +1213,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) sftp_attributes attrs; if(data->state.resume_from < 0) { - attrs = sftp_stat(sshc->sftp_session, protop->path); + attrs = sftp_stat(sshc->sftp_session, sshp->path); if(attrs) { curl_off_t size = attrs->size; if(size < 0) { @@ -1241,7 +1244,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(sshc->sftp_file) sftp_close(sshc->sftp_file); sshc->sftp_file = - sftp_open(sshc->sftp_session, protop->path, + sftp_open(sshc->sftp_session, sshp->path, flags, (mode_t)data->set.new_file_perms); if(!sshc->sftp_file) { err = sftp_get_error(sshc->sftp_session); @@ -1249,11 +1252,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE || err == SSH_FX_NO_SUCH_PATH)) && (data->set.ftp_create_missing_dirs && - (strlen(protop->path) > 1))) { + (strlen(sshp->path) > 1))) { /* try to create the path remotely */ rc = 0; sshc->secondCreateDirs = 1; - state(data, SSH_SFTP_CREATE_DIRS_INIT); + myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_INIT); break; } else { @@ -1344,17 +1347,17 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) sshc->sftp_send_state = 0; #endif - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } case SSH_SFTP_CREATE_DIRS_INIT: - if(strlen(protop->path) > 1) { - sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */ - state(data, SSH_SFTP_CREATE_DIRS); + if(strlen(sshp->path) > 1) { + sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */ + myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS); } else { - state(data, SSH_SFTP_UPLOAD_INIT); + myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); } break; @@ -1363,16 +1366,16 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(sshc->slash_pos) { *sshc->slash_pos = 0; - infof(data, "Creating directory '%s'", protop->path); - state(data, SSH_SFTP_CREATE_DIRS_MKDIR); + infof(data, "Creating directory '%s'", sshp->path); + myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR); break; } - state(data, SSH_SFTP_UPLOAD_INIT); + myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); break; case SSH_SFTP_CREATE_DIRS_MKDIR: /* 'mode' - parameter is preliminary - default to 0644 */ - rc = sftp_mkdir(sshc->sftp_session, protop->path, + rc = sftp_mkdir(sshc->sftp_session, sshp->path, (mode_t)data->set.new_directory_perms); *sshc->slash_pos = '/'; ++sshc->slash_pos; @@ -1391,13 +1394,13 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) } rc = 0; /* clear rc and continue */ } - state(data, SSH_SFTP_CREATE_DIRS); + myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS); break; case SSH_SFTP_READDIR_INIT: Curl_pgrsSetDownloadSize(data, -1); if(data->req.no_body) { - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } @@ -1406,14 +1409,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) * listing */ sshc->sftp_dir = sftp_opendir(sshc->sftp_session, - protop->path); + sshp->path); if(!sshc->sftp_dir) { failf(data, "Could not open directory for reading: %s", ssh_get_error(sshc->ssh_session)); MOVE_TO_SFTP_CLOSE_STATE(); break; } - state(data, SSH_SFTP_READDIR); + myssh_state(data, sshc, SSH_SFTP_READDIR); break; case SSH_SFTP_READDIR: @@ -1432,7 +1435,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) tmpLine = aprintf("%s\n", sshc->readdir_filename); if(!tmpLine) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } @@ -1441,7 +1444,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) free(tmpLine); if(result) { - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } @@ -1449,31 +1452,31 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) else { if(curlx_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) { sshc->actualcode = CURLE_OUT_OF_MEMORY; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) && ((sshc->readdir_attrs->permissions & SSH_S_IFMT) == SSH_S_IFLNK)) { - sshc->readdir_linkPath = aprintf("%s%s", protop->path, + sshc->readdir_linkPath = aprintf("%s%s", sshp->path, sshc->readdir_filename); if(!sshc->readdir_linkPath) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } - state(data, SSH_SFTP_READDIR_LINK); + myssh_state(data, sshc, SSH_SFTP_READDIR_LINK); break; } - state(data, SSH_SFTP_READDIR_BOTTOM); + myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM); break; } } else if(sftp_dir_eof(sshc->sftp_dir)) { - state(data, SSH_SFTP_READDIR_DONE); + myssh_state(data, sshc, SSH_SFTP_READDIR_DONE); break; } else { @@ -1526,7 +1529,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) sshc->readdir_filename = NULL; sshc->readdir_longentry = NULL; - state(data, SSH_SFTP_READDIR_BOTTOM); + myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM); FALLTHROUGH(); case SSH_SFTP_READDIR_BOTTOM: if(curlx_dyn_addn(&sshc->readdir_buf, "\n", 1)) @@ -1540,10 +1543,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) sshc->readdir_tmp = NULL; if(result) { - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); } else - state(data, SSH_SFTP_READDIR); + myssh_state(data, sshc, SSH_SFTP_READDIR); break; case SSH_SFTP_READDIR_DONE: @@ -1552,7 +1555,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) /* no data to transfer */ Curl_xfer_setup_nop(data); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; case SSH_SFTP_DOWNLOAD_INIT: @@ -1562,7 +1565,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(sshc->sftp_file) sftp_close(sshc->sftp_file); - sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path, + sshc->sftp_file = sftp_open(sshc->sftp_session, sshp->path, O_RDONLY, (mode_t)data->set.new_file_perms); if(!sshc->sftp_file) { failf(data, "Could not open remote file for reading: %s", @@ -1572,7 +1575,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; } sftp_file_set_nonblocking(sshc->sftp_file); - state(data, SSH_SFTP_DOWNLOAD_STAT); + myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); break; case SSH_SFTP_DOWNLOAD_STAT: @@ -1695,7 +1698,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) /* no data to transfer */ Curl_xfer_setup_nop(data); infof(data, "File already completely downloaded"); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); @@ -1711,12 +1714,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(result) { /* this should never occur; the close state should be entered at the time the error occurs */ - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = result; } else { sshc->sftp_recv_state = 0; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); } break; @@ -1725,7 +1728,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) sftp_close(sshc->sftp_file); sshc->sftp_file = NULL; } - Curl_safefree(protop->path); + Curl_safefree(sshp->path); DEBUGF(infof(data, "SFTP DONE done")); @@ -1734,11 +1737,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) SSH_SFTP_CLOSE to pass the correct result back */ if(sshc->nextstate != SSH_NO_STATE && sshc->nextstate != SSH_SFTP_CLOSE) { - state(data, sshc->nextstate); + myssh_state(data, sshc, sshc->nextstate); sshc->nextstate = SSH_SFTP_CLOSE; } else { - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); result = sshc->actualcode; } break; @@ -1767,14 +1770,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) SSH_STRING_FREE_CHAR(sshc->homedir); - state(data, SSH_SESSION_DISCONNECT); + myssh_state(data, sshc, SSH_SESSION_DISCONNECT); break; case SSH_SCP_TRANS_INIT: - result = Curl_getworkingpath(data, sshc->homedir, &protop->path); + result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); if(result) { sshc->actualcode = result; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } @@ -1790,13 +1793,13 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) } sshc->scp_session = - ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path); - state(data, SSH_SCP_UPLOAD_INIT); + ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, sshp->path); + myssh_state(data, sshc, SSH_SCP_UPLOAD_INIT); } else { sshc->scp_session = - ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path); - state(data, SSH_SCP_DOWNLOAD_INIT); + ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, sshp->path); + myssh_state(data, sshc, SSH_SCP_DOWNLOAD_INIT); } if(!sshc->scp_session) { @@ -1817,7 +1820,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; } - rc = ssh_scp_push_file64(sshc->scp_session, protop->path, + rc = ssh_scp_push_file64(sshc->scp_session, sshp->path, (uint64_t)data->state.infilesize, (int)data->set.new_file_perms); @@ -1843,7 +1846,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) with both accordingly */ data->state.select_bits = CURL_CSELECT_OUT; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; @@ -1856,7 +1859,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); break; } - state(data, SSH_SCP_DOWNLOAD); + myssh_state(data, sshc, SSH_SCP_DOWNLOAD); FALLTHROUGH(); case SSH_SCP_DOWNLOAD:{ @@ -1883,14 +1886,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) with both accordingly */ data->state.select_bits = CURL_CSELECT_IN; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } case SSH_SCP_DONE: if(data->state.upload) - state(data, SSH_SCP_SEND_EOF); + myssh_state(data, sshc, SSH_SCP_SEND_EOF); else - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_SEND_EOF: @@ -1908,7 +1911,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) } } - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_CHANNEL_FREE: @@ -1920,7 +1923,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) ssh_set_blocking(sshc->ssh_session, 0); - state(data, SSH_SESSION_DISCONNECT); + myssh_state(data, sshc, SSH_SESSION_DISCONNECT); FALLTHROUGH(); case SSH_SESSION_DISCONNECT: @@ -1942,24 +1945,24 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) SSH_STRING_FREE_CHAR(sshc->homedir); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); FALLTHROUGH(); case SSH_SESSION_FREE: - sshc_cleanup(sshc, data); + sshc_cleanup(sshc); /* the code we are about to return */ result = sshc->actualcode; memset(sshc, 0, sizeof(struct ssh_conn)); connclose(conn, "SSH session free"); sshc->state = SSH_SESSION_FREE; /* current */ sshc->nextstate = SSH_NO_STATE; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; case SSH_QUIT: default: /* internal error */ sshc->nextstate = SSH_NO_STATE; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } @@ -1999,10 +2002,10 @@ static int myssh_getsock(struct Curl_easy *data, return bitmap; } -static void myssh_block2waitfor(struct connectdata *conn, bool block) +static void myssh_block2waitfor(struct connectdata *conn, + struct ssh_conn *sshc, + bool block) { - struct ssh_conn *sshc = &conn->proto.sshc; - /* If it did not block, or nothing was returned by ssh_get_poll_flags * have the original set */ conn->waitfor = sshc->orig_waitfor; @@ -2023,22 +2026,27 @@ static CURLcode myssh_multi_statemach(struct Curl_easy *data, bool *done) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); bool block; /* we store the status and use that to provide a ssh_getsock() implementation */ - CURLcode result = myssh_statemach_act(data, &block); + CURLcode result; + if(!sshc || !sshp) + return CURLE_FAILED_INIT; + result = myssh_statemach_act(data, sshc, sshp, &block); *done = (sshc->state == SSH_STOP); - myssh_block2waitfor(conn, block); + myssh_block2waitfor(conn, sshc, block); return result; } static CURLcode myssh_block_statemach(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp, bool disconnect) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; while((sshc->state != SSH_STOP) && !result) { @@ -2046,7 +2054,7 @@ static CURLcode myssh_block_statemach(struct Curl_easy *data, timediff_t left = 1000; struct curltime now = curlx_now(); - result = myssh_statemach_act(data, &block); + result = myssh_statemach_act(data, sshc, sshp, &block); if(result) break; @@ -2077,22 +2085,45 @@ static CURLcode myssh_block_statemach(struct Curl_easy *data, return result; } +static void myssh_easy_dtor(void *key, size_t klen, void *entry) +{ + struct SSHPROTO *sshp = entry; + (void)key; + (void)klen; + Curl_safefree(sshp->path); + free(sshp); +} + +static void myssh_conn_dtor(void *key, size_t klen, void *entry) +{ + struct ssh_conn *sshc = entry; + (void)key; + (void)klen; + sshc_cleanup(sshc); + free(sshc); +} + /* * SSH setup connection */ static CURLcode myssh_setup_connection(struct Curl_easy *data, struct connectdata *conn) { - struct SSHPROTO *ssh; - struct ssh_conn *sshc = &conn->proto.sshc; + struct SSHPROTO *sshp; + struct ssh_conn *sshc; - if(!sshc->initialised) { - curlx_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2); - sshc->initialised = TRUE; - } + sshc = calloc(1, sizeof(*sshc)); + if(!sshc) + return CURLE_OUT_OF_MEMORY; - data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); - if(!ssh) + curlx_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2); + sshc->initialised = TRUE; + if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, myssh_conn_dtor)) + return CURLE_OUT_OF_MEMORY; + + sshp = calloc(1, sizeof(*sshp)); + if(!sshp || + Curl_meta_set(data, CURL_META_SSH_EASY, sshp, myssh_easy_dtor)) return CURLE_OUT_OF_MEMORY; return CURLE_OK; @@ -2107,15 +2138,15 @@ static Curl_send scp_send, sftp_send; */ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) { - struct ssh_conn *ssh; CURLcode result; struct connectdata *conn = data->conn; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + struct SSHPROTO *ssh = Curl_meta_get(data, CURL_META_SSH_EASY); curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc; - /* initialize per-handle data if not already */ - if(!data->req.p.ssh) - myssh_setup_connection(data, conn); + if(!sshc || !ssh) + return CURLE_FAILED_INIT; /* We default to persistent connections. We set this already in this connect function to make the reuse checks properly be able to check this bit. */ @@ -2130,10 +2161,8 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) conn->send[FIRSTSOCKET] = sftp_send; } - ssh = &conn->proto.sshc; - - ssh->ssh_session = ssh_new(); - if(!ssh->ssh_session) { + sshc->ssh_session = ssh_new(); + if(!sshc->ssh_session) { failf(data, "Failure initialising ssh session"); return CURLE_FAILED_INIT; } @@ -2141,23 +2170,23 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) if(conn->bits.ipv6_ip) { char ipv6[MAX_IPADR_LEN]; msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name); - rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, ipv6); + rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, ipv6); } else - rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name); + rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, conn->host.name); if(rc != SSH_OK) { failf(data, "Could not set remote host"); return CURLE_FAILED_INIT; } - rc = ssh_options_parse_config(ssh->ssh_session, NULL); + rc = ssh_options_parse_config(sshc->ssh_session, NULL); if(rc != SSH_OK) { infof(data, "Could not parse SSH configuration files"); /* ignore */ } - rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock); + rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_FD, &sock); if(rc != SSH_OK) { failf(data, "Could not set socket"); return CURLE_FAILED_INIT; @@ -2165,7 +2194,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) if(conn->user && conn->user[0] != '\0') { infof(data, "User: %s", conn->user); - rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user); + rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_USER, conn->user); if(rc != SSH_OK) { failf(data, "Could not set user"); return CURLE_FAILED_INIT; @@ -2174,7 +2203,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) if(data->set.str[STRING_SSH_KNOWNHOSTS]) { infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]); - rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS, + rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_KNOWNHOSTS, data->set.str[STRING_SSH_KNOWNHOSTS]); if(rc != SSH_OK) { failf(data, "Could not set known hosts file path"); @@ -2183,7 +2212,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) } if(conn->remote_port) { - rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT, + rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_PORT, &conn->remote_port); if(rc != SSH_OK) { failf(data, "Could not set remote port"); @@ -2192,7 +2221,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) } if(data->set.ssh_compression) { - rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION, + rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_COMPRESSION, "zlib,zlib@openssh.com,none"); if(rc != SSH_OK) { failf(data, "Could not set compression"); @@ -2200,12 +2229,12 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) } } - ssh->privkey = NULL; - ssh->pubkey = NULL; + sshc->privkey = NULL; + sshc->pubkey = NULL; if(data->set.str[STRING_SSH_PUBLIC_KEY]) { rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY], - &ssh->pubkey); + &sshc->pubkey); if(rc != SSH_OK) { failf(data, "Could not load public key file"); return CURLE_FAILED_INIT; @@ -2215,7 +2244,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) /* we do not verify here, we do it at the state machine, * after connection */ - state(data, SSH_INIT); + myssh_state(data, sshc, SSH_INIT); result = myssh_multi_statemach(data, done); @@ -2249,13 +2278,16 @@ CURLcode scp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done) { CURLcode result = CURLE_OK; + struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); DEBUGF(infof(data, "DO phase starts")); *dophase_done = FALSE; /* not done yet */ + if(!sshc) + return CURLE_FAILED_INIT; /* start the first command in the DO phase */ - state(data, SSH_SCP_TRANS_INIT); + myssh_state(data, sshc, SSH_SCP_TRANS_INIT); result = myssh_multi_statemach(data, dophase_done); @@ -2273,9 +2305,11 @@ static CURLcode myssh_do_it(struct Curl_easy *data, bool *done) CURLcode result; bool connected = FALSE; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); *done = FALSE; /* default to false */ + if(!sshc) + return CURLE_FAILED_INIT; data->req.size = -1; /* make sure this is unknown at this point */ @@ -2296,9 +2330,8 @@ static CURLcode myssh_do_it(struct Curl_easy *data, bool *done) return result; } -static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data) +static void sshc_cleanup(struct ssh_conn *sshc) { - (void)data; if(sshc->initialised) { if(sshc->ssh_session) { ssh_free(sshc->ssh_session); @@ -2353,37 +2386,37 @@ static CURLcode scp_disconnect(struct Curl_easy *data, bool dead_connection) { CURLcode result = CURLE_OK; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); (void) dead_connection; - if(sshc->ssh_session) { + if(sshc && sshc->ssh_session && sshp) { /* only if there is a session still around to use! */ - state(data, SSH_SESSION_DISCONNECT); + myssh_state(data, sshc, SSH_SESSION_DISCONNECT); - result = myssh_block_statemach(data, TRUE); + result = myssh_block_statemach(data, sshc, sshp, TRUE); } - sshc_cleanup(sshc, data); return result; } /* generic done function for both SCP and SFTP called from their specific done functions */ -static CURLcode myssh_done(struct Curl_easy *data, CURLcode status) +static CURLcode myssh_done(struct Curl_easy *data, + struct ssh_conn *sshc, + CURLcode status) { CURLcode result = CURLE_OK; - struct SSHPROTO *protop = data->req.p.ssh; + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); if(!status) { /* run the state-machine */ - result = myssh_block_statemach(data, FALSE); + result = myssh_block_statemach(data, sshc, sshp, FALSE); } else result = status; - if(protop) - Curl_safefree(protop->path); if(Curl_pgrsDone(data)) return CURLE_ABORTED_BY_CALLBACK; @@ -2395,13 +2428,15 @@ static CURLcode myssh_done(struct Curl_easy *data, CURLcode status) static CURLcode scp_done(struct Curl_easy *data, CURLcode status, bool premature) { + struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); (void) premature; /* not used */ + if(!sshc) + return CURLE_FAILED_INIT; if(!status) - state(data, SSH_SCP_DONE); - - return myssh_done(data, status); + myssh_state(data, sshc, SSH_SCP_DONE); + return myssh_done(data, sshc, status); } static ssize_t scp_send(struct Curl_easy *data, int sockindex, @@ -2409,17 +2444,22 @@ static ssize_t scp_send(struct Curl_easy *data, int sockindex, { int rc; struct connectdata *conn = data->conn; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); (void) sockindex; /* we only support SCP on the fixed known primary socket */ - (void) err; (void)eos; - rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len); + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } + + rc = ssh_scp_write(sshc->scp_session, mem, len); #if 0 /* The following code is misleading, mostly added as wishful thinking * that libssh at some point will implement non-blocking ssh_scp_write/read. * Currently rc can only be number of bytes read or SSH_ERROR. */ - myssh_block2waitfor(conn, (rc == SSH_AGAIN)); + myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN)); if(rc == SSH_AGAIN) { *err = CURLE_AGAIN; @@ -2440,18 +2480,22 @@ static ssize_t scp_recv(struct Curl_easy *data, int sockindex, { ssize_t nread; struct connectdata *conn = data->conn; - (void) err; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); (void) sockindex; /* we only support SCP on the fixed known primary socket */ + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } /* libssh returns int */ - nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len); + nread = ssh_scp_read(sshc->scp_session, mem, len); #if 0 /* The following code is misleading, mostly added as wishful thinking * that libssh at some point will implement non-blocking ssh_scp_write/read. * Currently rc can only be SSH_OK or SSH_ERROR. */ - myssh_block2waitfor(conn, (nread == SSH_AGAIN)); + myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN)); if(nread == SSH_AGAIN) { *err = CURLE_AGAIN; nread = -1; @@ -2479,14 +2523,17 @@ CURLcode sftp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done) { + struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); CURLcode result = CURLE_OK; DEBUGF(infof(data, "DO phase starts")); *dophase_done = FALSE; /* not done yet */ + if(!sshc) + return CURLE_FAILED_INIT; /* start the first command in the DO phase */ - state(data, SSH_SFTP_QUOTE_INIT); + myssh_state(data, sshc, SSH_SFTP_QUOTE_INIT); /* run the state-machine */ result = myssh_multi_statemach(data, dophase_done); @@ -2518,21 +2565,20 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection) { - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); CURLcode result = CURLE_OK; (void) dead_connection; DEBUGF(infof(data, "SSH DISCONNECT starts now")); - if(conn->proto.sshc.ssh_session) { + if(sshc && sshc->ssh_session && sshp) { /* only if there is a session still around to use! */ - state(data, SSH_SFTP_SHUTDOWN); - result = myssh_block_statemach(data, TRUE); + myssh_state(data, sshc, SSH_SFTP_SHUTDOWN); + result = myssh_block_statemach(data, sshc, sshp, TRUE); } DEBUGF(infof(data, "SSH DISCONNECT is done")); - sshc_cleanup(sshc, data); - return result; } @@ -2540,17 +2586,19 @@ static CURLcode sftp_done(struct Curl_easy *data, CURLcode status, bool premature) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + if(!sshc) + return CURLE_FAILED_INIT; if(!status) { /* Post quote commands are executed after the SFTP_CLOSE state to avoid errors that could happen due to open file handles during POSTQUOTE operation */ if(!premature && data->set.postquote && !conn->bits.retry) sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); } - return myssh_done(data, status); + return myssh_done(data, sshc, status); } /* return number of sent bytes */ @@ -2560,28 +2608,33 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex, { ssize_t nwrite; struct connectdata *conn = data->conn; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); (void)sockindex; (void)eos; + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } /* limit the writes to the maximum specified in Section 3 of * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02 */ if(len > 32768) len = 32768; #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) - switch(conn->proto.sshc.sftp_send_state) { + switch(sshc->sftp_send_state) { case 0: - sftp_file_set_nonblocking(conn->proto.sshc.sftp_file); - if(sftp_aio_begin_write(conn->proto.sshc.sftp_file, mem, len, - &conn->proto.sshc.sftp_aio) == SSH_ERROR) { + sftp_file_set_nonblocking(sshc->sftp_file); + if(sftp_aio_begin_write(sshc->sftp_file, mem, len, + &sshc->sftp_aio) == SSH_ERROR) { *err = CURLE_SEND_ERROR; return -1; } - conn->proto.sshc.sftp_send_state = 1; + sshc->sftp_send_state = 1; FALLTHROUGH(); case 1: - nwrite = sftp_aio_wait_write(&conn->proto.sshc.sftp_aio); - myssh_block2waitfor(conn, (nwrite == SSH_AGAIN) ? TRUE : FALSE); + nwrite = sftp_aio_wait_write(&sshc->sftp_aio); + myssh_block2waitfor(conn, sshc, (nwrite == SSH_AGAIN) ? TRUE : FALSE); if(nwrite == SSH_AGAIN) { *err = CURLE_AGAIN; return 0; @@ -2590,20 +2643,20 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex, *err = CURLE_SEND_ERROR; return -1; } - if(conn->proto.sshc.sftp_aio) { - sftp_aio_free(conn->proto.sshc.sftp_aio); - conn->proto.sshc.sftp_aio = NULL; + if(sshc->sftp_aio) { + sftp_aio_free(sshc->sftp_aio); + sshc->sftp_aio = NULL; } - conn->proto.sshc.sftp_send_state = 0; + sshc->sftp_send_state = 0; return nwrite; default: /* we never reach here */ return -1; } #else - nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len); + nwrite = sftp_write(sshc->sftp_file, mem, len); - myssh_block2waitfor(conn, FALSE); + myssh_block2waitfor(conn, sshc, FALSE); #if 0 /* not returned by libssh on write */ if(nwrite == SSH_AGAIN) { @@ -2630,29 +2683,31 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, { ssize_t nread; struct connectdata *conn = data->conn; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); (void)sockindex; DEBUGASSERT(len < CURL_MAX_READ_SIZE); + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } - switch(conn->proto.sshc.sftp_recv_state) { + switch(sshc->sftp_recv_state) { case 0: - conn->proto.sshc.sftp_file_index = - sftp_async_read_begin(conn->proto.sshc.sftp_file, - (uint32_t)len); - if(conn->proto.sshc.sftp_file_index < 0) { + sshc->sftp_file_index = + sftp_async_read_begin(sshc->sftp_file, (uint32_t)len); + if(sshc->sftp_file_index < 0) { *err = CURLE_RECV_ERROR; return -1; } FALLTHROUGH(); case 1: - conn->proto.sshc.sftp_recv_state = 1; - - nread = sftp_async_read(conn->proto.sshc.sftp_file, - mem, (uint32_t)len, - (uint32_t)conn->proto.sshc.sftp_file_index); + sshc->sftp_recv_state = 1; + nread = sftp_async_read(sshc->sftp_file, mem, (uint32_t)len, + (uint32_t)sshc->sftp_file_index); - myssh_block2waitfor(conn, (nread == SSH_AGAIN)); + myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN)); if(nread == SSH_AGAIN) { *err = CURLE_AGAIN; @@ -2663,7 +2718,7 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, return -1; } - conn->proto.sshc.sftp_recv_state = 0; + sshc->sftp_recv_state = 0; return nread; default: @@ -2672,12 +2727,11 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, } } -static void sftp_quote(struct Curl_easy *data) +static void sftp_quote(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) { const char *cp; - struct connectdata *conn = data->conn; - struct SSHPROTO *protop = data->req.p.ssh; - struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result; /* @@ -2698,11 +2752,10 @@ static void sftp_quote(struct Curl_easy *data) if(strcasecompare("pwd", cmd)) { /* output debug output if that is requested */ - char *tmp = aprintf("257 \"%s\" is current directory.\n", - protop->path); + char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path); if(!tmp) { sshc->actualcode = CURLE_OUT_OF_MEMORY; - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; return; } @@ -2715,12 +2768,12 @@ static void sftp_quote(struct Curl_easy *data) result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); free(tmp); if(result) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } else - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); return; } @@ -2731,7 +2784,7 @@ static void sftp_quote(struct Curl_easy *data) cp = strchr(cmd, ' '); if(!cp) { failf(data, "Syntax error in SFTP command. Supply parameter(s)"); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; @@ -2747,7 +2800,7 @@ static void sftp_quote(struct Curl_easy *data) failf(data, "Out of memory"); else failf(data, "Syntax error: Bad first parameter"); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; return; @@ -2776,13 +2829,13 @@ static void sftp_quote(struct Curl_easy *data) failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: " "Bad second parameter"); Curl_safefree(sshc->quote_path1); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; return; } sshc->quote_attrs = NULL; - state(data, SSH_SFTP_QUOTE_STAT); + myssh_state(data, sshc, SSH_SFTP_QUOTE_STAT); return; } if(!strncmp(cmd, "ln ", 3) || @@ -2797,17 +2850,17 @@ static void sftp_quote(struct Curl_easy *data) else failf(data, "Syntax error in ln/symlink: Bad second parameter"); Curl_safefree(sshc->quote_path1); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; return; } - state(data, SSH_SFTP_QUOTE_SYMLINK); + myssh_state(data, sshc, SSH_SFTP_QUOTE_SYMLINK); return; } else if(!strncmp(cmd, "mkdir ", 6)) { /* create dir */ - state(data, SSH_SFTP_QUOTE_MKDIR); + myssh_state(data, sshc, SSH_SFTP_QUOTE_MKDIR); return; } else if(!strncmp(cmd, "rename ", 7)) { @@ -2821,26 +2874,26 @@ static void sftp_quote(struct Curl_easy *data) else failf(data, "Syntax error in rename: Bad second parameter"); Curl_safefree(sshc->quote_path1); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; return; } - state(data, SSH_SFTP_QUOTE_RENAME); + myssh_state(data, sshc, SSH_SFTP_QUOTE_RENAME); return; } else if(!strncmp(cmd, "rmdir ", 6)) { /* delete dir */ - state(data, SSH_SFTP_QUOTE_RMDIR); + myssh_state(data, sshc, SSH_SFTP_QUOTE_RMDIR); return; } else if(!strncmp(cmd, "rm ", 3)) { - state(data, SSH_SFTP_QUOTE_UNLINK); + myssh_state(data, sshc, SSH_SFTP_QUOTE_UNLINK); return; } #ifdef HAS_STATVFS_SUPPORT else if(!strncmp(cmd, "statvfs ", 8)) { - state(data, SSH_SFTP_QUOTE_STATVFS); + myssh_state(data, sshc, SSH_SFTP_QUOTE_STATVFS); return; } #endif @@ -2848,15 +2901,14 @@ static void sftp_quote(struct Curl_easy *data) failf(data, "Unknown SFTP command"); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; } -static void sftp_quote_stat(struct Curl_easy *data) +static void sftp_quote_stat(struct Curl_easy *data, + struct ssh_conn *sshc) { - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; char *cmd = sshc->quote_item->data; sshc->acceptfail = FALSE; @@ -2883,7 +2935,7 @@ static void sftp_quote_stat(struct Curl_easy *data) Curl_safefree(sshc->quote_path2); failf(data, "Attempt to get SFTP stats failed: %d", sftp_get_error(sshc->sftp_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; @@ -2900,7 +2952,7 @@ static void sftp_quote_stat(struct Curl_easy *data) Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chgrp gid not a number"); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; @@ -2914,7 +2966,7 @@ static void sftp_quote_stat(struct Curl_easy *data) Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chmod permissions not a number"); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; @@ -2931,7 +2983,7 @@ static void sftp_quote_stat(struct Curl_easy *data) Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chown uid not a number"); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; @@ -2955,7 +3007,7 @@ static void sftp_quote_stat(struct Curl_easy *data) if(fail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; @@ -2969,7 +3021,7 @@ static void sftp_quote_stat(struct Curl_easy *data) } /* Now send the completed structure... */ - state(data, SSH_SFTP_QUOTE_SETSTAT); + myssh_state(data, sshc, SSH_SFTP_QUOTE_SETSTAT); return; } diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 19a80f127d..d56d7b32d9 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -86,7 +86,8 @@ static const char *sftp_libssh2_strerror(unsigned long err); static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); static LIBSSH2_FREE_FUNC(my_libssh2_free); -static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data); +static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, + struct ssh_conn *sshc); static CURLcode ssh_connect(struct Curl_easy *data, bool *done); static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done); static CURLcode ssh_do(struct Curl_easy *data, bool *done); @@ -298,10 +299,10 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free) * SSH State machine related code */ /* This is the ONLY way to change SSH state! */ -static void state(struct Curl_easy *data, sshstate nowstate) +static void myssh_state(struct Curl_easy *data, + struct ssh_conn *sshc, + sshstate nowstate) { - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[] = { @@ -375,7 +376,7 @@ static void state(struct Curl_easy *data, sshstate nowstate) (void *)sshc, names[sshc->state], names[nowstate]); } #endif - + (void)data; sshc->state = nowstate; } @@ -428,7 +429,8 @@ static enum curl_khtype convert_ssh2_keytype(int sshkeytype) return keytype; } -static CURLcode ssh_knownhost(struct Curl_easy *data) +static CURLcode ssh_knownhost(struct Curl_easy *data, + struct ssh_conn *sshc) { int sshkeytype = 0; size_t keylen = 0; @@ -438,7 +440,6 @@ static CURLcode ssh_knownhost(struct Curl_easy *data) if(data->set.str[STRING_SSH_KNOWNHOSTS]) { /* we are asked to verify the host against a file */ struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; struct libssh2_knownhost *host = NULL; const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, &keylen, &sshkeytype); @@ -543,7 +544,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data) switch(rc) { default: /* unknown return codes will equal reject */ case CURLKHSTAT_REJECT: - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); FALLTHROUGH(); case CURLKHSTAT_DEFER: /* DEFER means bail out but keep the SSH_HOSTKEY state */ @@ -589,10 +590,9 @@ static CURLcode ssh_knownhost(struct Curl_easy *data) return result; } -static CURLcode ssh_check_fingerprint(struct Curl_easy *data) +static CURLcode ssh_check_fingerprint(struct Curl_easy *data, + struct ssh_conn *sshc) { - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256]; @@ -628,7 +628,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) failf(data, "Denied establishing ssh session: sha256 fingerprint " "not available"); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } @@ -637,14 +637,14 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) * See libssh2_hostkey_hash documentation. */ if(curlx_base64_encode(fingerprint, 32, &fingerprint_b64, &fingerprint_b64_len) != CURLE_OK) { - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } if(!fingerprint_b64) { failf(data, "sha256 fingerprint could not be encoded"); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } @@ -671,7 +671,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) "Denied establishing ssh session: mismatch sha256 fingerprint. " "Remote %s is not equal to %s", fingerprint_b64, pubkey_sha256); free(fingerprint_b64); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } @@ -711,7 +711,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) "Denied establishing ssh session: md5 fingerprint " "not available"); } - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } @@ -733,20 +733,20 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) (int)keytype, remotekey, keylen); Curl_set_in_callback(data, FALSE); if(rc!= CURLKHMATCH_OK) { - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } } else { - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } return CURLE_OK; } else { - return ssh_knownhost(data); + return ssh_knownhost(data, sshc); } } else { @@ -759,7 +759,8 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) * ssh_force_knownhost_key_type() will check the known hosts file and try to * force a specific public key type from the server if an entry is found. */ -static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data) +static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, + struct ssh_conn *sshc) { CURLcode result = CURLE_OK; @@ -788,7 +789,6 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data) const char *hostkey_method = NULL; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; struct libssh2_knownhost* store = NULL; const char *kh_name_end = NULL; size_t kh_name_size = 0; @@ -941,7 +941,7 @@ static CURLcode sftp_quote(struct Curl_easy *data, result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); free(tmp); if(!result) - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); return result; } @@ -988,7 +988,7 @@ static CURLcode sftp_quote(struct Curl_easy *data, return result; } memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); - state(data, SSH_SFTP_QUOTE_STAT); + myssh_state(data, sshc, SSH_SFTP_QUOTE_STAT); return result; } if(!strncmp(cmd, "ln ", 3) || @@ -1003,12 +1003,12 @@ static CURLcode sftp_quote(struct Curl_easy *data, Curl_safefree(sshc->quote_path1); return result; } - state(data, SSH_SFTP_QUOTE_SYMLINK); + myssh_state(data, sshc, SSH_SFTP_QUOTE_SYMLINK); return result; } else if(!strncmp(cmd, "mkdir ", 6)) { /* create dir */ - state(data, SSH_SFTP_QUOTE_MKDIR); + myssh_state(data, sshc, SSH_SFTP_QUOTE_MKDIR); return result; } else if(!strncmp(cmd, "rename ", 7)) { @@ -1022,20 +1022,20 @@ static CURLcode sftp_quote(struct Curl_easy *data, Curl_safefree(sshc->quote_path1); return result; } - state(data, SSH_SFTP_QUOTE_RENAME); + myssh_state(data, sshc, SSH_SFTP_QUOTE_RENAME); return result; } else if(!strncmp(cmd, "rmdir ", 6)) { /* delete dir */ - state(data, SSH_SFTP_QUOTE_RMDIR); + myssh_state(data, sshc, SSH_SFTP_QUOTE_RMDIR); return result; } else if(!strncmp(cmd, "rm ", 3)) { - state(data, SSH_SFTP_QUOTE_UNLINK); + myssh_state(data, sshc, SSH_SFTP_QUOTE_UNLINK); return result; } else if(!strncmp(cmd, "statvfs ", 8)) { - state(data, SSH_SFTP_QUOTE_STATVFS); + myssh_state(data, sshc, SSH_SFTP_QUOTE_STATVFS); return result; } @@ -1117,7 +1117,7 @@ sftp_upload_init(struct Curl_easy *data, sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */ if(sshc->secondCreateDirs) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = sftperr != LIBSSH2_FX_OK ? sftp_libssh2_error_to_CURLE(sftperr) : CURLE_SSH; failf(data, "Creating the dir/file failed: %s", @@ -1131,10 +1131,10 @@ sftp_upload_init(struct Curl_easy *data, (strlen(sshp->path) > 1))) { /* try to create the path remotely */ sshc->secondCreateDirs = 1; - state(data, SSH_SFTP_CREATE_DIRS_INIT); + myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_INIT); return CURLE_OK; } - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = sftperr != LIBSSH2_FX_OK ? sftp_libssh2_error_to_CURLE(sftperr) : CURLE_SSH; if(!sshc->actualcode) { @@ -1229,7 +1229,7 @@ sftp_upload_init(struct Curl_easy *data, timeout here */ Curl_expire(data, 0, EXPIRE_RUN_NOW); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); return CURLE_OK; } @@ -1306,7 +1306,7 @@ sftp_pkey_init(struct Curl_easy *data, if(out_of_memory || !sshc->rsa) { Curl_safefree(sshc->rsa); Curl_safefree(sshc->rsa_pub); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY; } @@ -1319,10 +1319,10 @@ sftp_pkey_init(struct Curl_easy *data, infof(data, "Using SSH public key file '%s'", sshc->rsa_pub); infof(data, "Using SSH private key file '%s'", sshc->rsa); - state(data, SSH_AUTH_PKEY); + myssh_state(data, sshc, SSH_AUTH_PKEY); } else { - state(data, SSH_AUTH_PASS_INIT); + myssh_state(data, sshc, SSH_AUTH_PASS_INIT); } return CURLE_OK; } @@ -1431,7 +1431,7 @@ sftp_quote_stat(struct Curl_easy *data, } /* Now send the completed structure... */ - state(data, SSH_SFTP_QUOTE_SETSTAT); + myssh_state(data, sshc, SSH_SFTP_QUOTE_SETSTAT); return CURLE_OK; fail: Curl_safefree(sshc->quote_path1); @@ -1553,7 +1553,7 @@ sftp_download_stat(struct Curl_easy *data, /* no data to transfer */ Curl_xfer_setup_nop(data); infof(data, "File already completely downloaded"); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); return CURLE_OK; } Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); @@ -1565,7 +1565,7 @@ sftp_download_stat(struct Curl_easy *data, out writableable as the underlying libssh2 recv function will deal with both accordingly */ data->state.select_bits = CURL_CSELECT_IN; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); return CURLE_OK; } @@ -1606,17 +1606,17 @@ static CURLcode sftp_readdir(struct Curl_easy *data, LIBSSH2_SFTP_S_IFLNK)) { result = curlx_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path, sshp->readdir_filename); - state(data, SSH_SFTP_READDIR_LINK); + myssh_state(data, sshc, SSH_SFTP_READDIR_LINK); } else { - state(data, SSH_SFTP_READDIR_BOTTOM); + myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM); } } return result; } } else if(!rc) { - state(data, SSH_SFTP_READDIR_DONE); + myssh_state(data, sshc, SSH_SFTP_READDIR_DONE); } else { unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session); @@ -1625,7 +1625,7 @@ static CURLcode sftp_readdir(struct Curl_easy *data, failf(data, "Could not open remote file for reading: %s :: %d", sftp_libssh2_strerror(sftperr), libssh2_session_last_errno(sshc->ssh_session)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); } return result; } @@ -1636,12 +1636,13 @@ static CURLcode sftp_readdir(struct Curl_easy *data, * meaning it wants to be called again when the socket is ready */ -static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) +static CURLcode ssh_statemachine(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp, + bool *block) { CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; - struct SSHPROTO *sshp = data->req.p.ssh; - struct ssh_conn *sshc = &conn->proto.sshc; int rc = LIBSSH2_ERROR_NONE; *block = 0; /* we are not blocking by default */ @@ -1657,14 +1658,14 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) non-blocking */ libssh2_session_set_blocking(sshc->ssh_session, 0); - result = ssh_force_knownhost_key_type(data); + result = ssh_force_knownhost_key_type(data, sshc); if(result) { - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = result; break; } - state(data, SSH_S_STARTUP); + myssh_state(data, sshc, SSH_S_STARTUP); FALLTHROUGH(); case SSH_S_STARTUP: @@ -1678,12 +1679,12 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_FAILED_INIT; break; } - state(data, SSH_HOSTKEY); + myssh_state(data, sshc, SSH_HOSTKEY); FALLTHROUGH(); case SSH_HOSTKEY: @@ -1692,9 +1693,9 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) * against our known hosts. How that is handled (reading from file, * whatever) is up to us. */ - result = ssh_check_fingerprint(data); + result = ssh_check_fingerprint(data, sshc); if(!result) - state(data, SSH_AUTHLIST); + myssh_state(data, sshc, SSH_AUTHLIST); /* ssh_check_fingerprint sets state appropriately on error */ break; @@ -1717,14 +1718,14 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) if(libssh2_userauth_authenticated(sshc->ssh_session)) { sshc->authed = TRUE; infof(data, "SSH user accepted with no authentication"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); break; } rc = libssh2_session_last_errno(sshc->ssh_session); if(rc == LIBSSH2_ERROR_EAGAIN) rc = LIBSSH2_ERROR_EAGAIN; else { - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = libssh2_session_error_to_CURLE(rc); } break; @@ -1732,7 +1733,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) infof(data, "SSH authentication methods available: %s", sshc->authlist); - state(data, SSH_AUTH_PKEY_INIT); + myssh_state(data, sshc, SSH_AUTH_PKEY_INIT); break; case SSH_AUTH_PKEY_INIT: @@ -1758,7 +1759,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) if(rc == 0) { sshc->authed = TRUE; infof(data, "Initialized SSH public key authentication"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); } else { char *err_msg = NULL; @@ -1773,7 +1774,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) &err_msg, NULL, 0); } infof(data, "SSH public key authentication failed: %s", err_msg); - state(data, SSH_AUTH_PASS_INIT); + myssh_state(data, sshc, SSH_AUTH_PASS_INIT); rc = 0; /* clear rc and continue */ } break; @@ -1781,10 +1782,10 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) case SSH_AUTH_PASS_INIT: if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) && (strstr(sshc->authlist, "password") != NULL)) { - state(data, SSH_AUTH_PASS); + myssh_state(data, sshc, SSH_AUTH_PASS); } else { - state(data, SSH_AUTH_HOST_INIT); + myssh_state(data, sshc, SSH_AUTH_HOST_INIT); rc = 0; /* clear rc and continue */ } break; @@ -1801,10 +1802,10 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) if(rc == 0) { sshc->authed = TRUE; infof(data, "Initialized password authentication"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); } else { - state(data, SSH_AUTH_HOST_INIT); + myssh_state(data, sshc, SSH_AUTH_HOST_INIT); rc = 0; /* clear rc and continue */ } break; @@ -1812,15 +1813,15 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) case SSH_AUTH_HOST_INIT: if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) && (strstr(sshc->authlist, "hostbased") != NULL)) { - state(data, SSH_AUTH_HOST); + myssh_state(data, sshc, SSH_AUTH_HOST); } else { - state(data, SSH_AUTH_AGENT_INIT); + myssh_state(data, sshc, SSH_AUTH_AGENT_INIT); } break; case SSH_AUTH_HOST: - state(data, SSH_AUTH_AGENT_INIT); + myssh_state(data, sshc, SSH_AUTH_AGENT_INIT); break; case SSH_AUTH_AGENT_INIT: @@ -1835,7 +1836,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) if(!sshc->ssh_agent) { infof(data, "Could not create agent object"); - state(data, SSH_AUTH_KEY_INIT); + myssh_state(data, sshc, SSH_AUTH_KEY_INIT); break; } } @@ -1845,15 +1846,15 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) break; if(rc < 0) { infof(data, "Failure connecting to agent"); - state(data, SSH_AUTH_KEY_INIT); + myssh_state(data, sshc, SSH_AUTH_KEY_INIT); rc = 0; /* clear rc and continue */ } else { - state(data, SSH_AUTH_AGENT_LIST); + myssh_state(data, sshc, SSH_AUTH_AGENT_LIST); } } else - state(data, SSH_AUTH_KEY_INIT); + myssh_state(data, sshc, SSH_AUTH_KEY_INIT); break; case SSH_AUTH_AGENT_LIST: @@ -1863,11 +1864,11 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) break; if(rc < 0) { infof(data, "Failure requesting identities to agent"); - state(data, SSH_AUTH_KEY_INIT); + myssh_state(data, sshc, SSH_AUTH_KEY_INIT); rc = 0; /* clear rc and continue */ } else { - state(data, SSH_AUTH_AGENT); + myssh_state(data, sshc, SSH_AUTH_AGENT); sshc->sshagent_prev_identity = NULL; } break; @@ -1903,10 +1904,10 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) if(rc == LIBSSH2_ERROR_NONE) { sshc->authed = TRUE; infof(data, "Agent based authentication successful"); - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); } else { - state(data, SSH_AUTH_KEY_INIT); + myssh_state(data, sshc, SSH_AUTH_KEY_INIT); rc = 0; /* clear rc and continue */ } break; @@ -1914,10 +1915,10 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) case SSH_AUTH_KEY_INIT: if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) { - state(data, SSH_AUTH_KEY); + myssh_state(data, sshc, SSH_AUTH_KEY); } else { - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); } break; @@ -1935,13 +1936,13 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) sshc->authed = TRUE; infof(data, "Initialized keyboard interactive authentication"); } - state(data, SSH_AUTH_DONE); + myssh_state(data, sshc, SSH_AUTH_DONE); break; case SSH_AUTH_DONE: if(!sshc->authed) { failf(data, "Authentication failure"); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_LOGIN_DENIED; break; } @@ -1957,11 +1958,11 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) conn->writesockfd = CURL_SOCKET_BAD; if(conn->handler->protocol == CURLPROTO_SFTP) { - state(data, SSH_SFTP_INIT); + myssh_state(data, sshc, SSH_SFTP_INIT); break; } infof(data, "SSH CONNECT phase done"); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; case SSH_SFTP_INIT: @@ -1980,11 +1981,11 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); failf(data, "Failure initializing sftp session: %s", err_msg); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); sshc->actualcode = CURLE_FAILED_INIT; break; } - state(data, SSH_SFTP_REALPATH); + myssh_state(data, sshc, SSH_SFTP_REALPATH); break; case SSH_SFTP_REALPATH: @@ -2004,7 +2005,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) free(sshc->homedir); sshc->homedir = strdup(sshp->readdir_filename); if(!sshc->homedir) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } @@ -2025,7 +2026,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) sshc->actualcode = result; DEBUGF(infof(data, "error = %lu makes libcurl = %d", sftperr, (int)result)); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } @@ -2034,7 +2035,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) since the homedir will remain the same between request but the working path will not. */ DEBUGF(infof(data, "SSH CONNECT phase done")); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; case SSH_SFTP_QUOTE_INIT: @@ -2042,17 +2043,17 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); if(result) { sshc->actualcode = result; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } if(data->set.quote) { infof(data, "Sending quote commands"); sshc->quote_item = data->set.quote; - state(data, SSH_SFTP_QUOTE); + myssh_state(data, sshc, SSH_SFTP_QUOTE); } else { - state(data, SSH_SFTP_GETINFO); + myssh_state(data, sshc, SSH_SFTP_GETINFO); } break; @@ -2060,10 +2061,10 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) if(data->set.postquote) { infof(data, "Sending quote commands"); sshc->quote_item = data->set.postquote; - state(data, SSH_SFTP_QUOTE); + myssh_state(data, sshc, SSH_SFTP_QUOTE); } else { - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); } break; @@ -2071,7 +2072,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) /* Send quote commands */ result = sftp_quote(data, sshc, sshp); if(result) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } @@ -2084,15 +2085,15 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) sshc->quote_item = sshc->quote_item->next; if(sshc->quote_item) { - state(data, SSH_SFTP_QUOTE); + myssh_state(data, sshc, SSH_SFTP_QUOTE); } else { if(sshc->nextstate != SSH_NO_STATE) { - state(data, sshc->nextstate); + myssh_state(data, sshc, sshc->nextstate); sshc->nextstate = SSH_NO_STATE; } else { - state(data, SSH_SFTP_GETINFO); + myssh_state(data, sshc, SSH_SFTP_GETINFO); } } break; @@ -2100,7 +2101,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) case SSH_SFTP_QUOTE_STAT: result = sftp_quote_stat(data, sshc, sshp, block); if(result) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } @@ -2120,12 +2121,12 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path2); failf(data, "Attempt to set SFTP stats failed: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_SYMLINK: @@ -2143,12 +2144,12 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path2); failf(data, "symlink command failed: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_MKDIR: @@ -2163,12 +2164,12 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path1); failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RENAME: @@ -2189,12 +2190,12 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path2); failf(data, "rename command failed: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RMDIR: @@ -2208,12 +2209,12 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path1); failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_UNLINK: @@ -2226,12 +2227,12 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_STATVFS: @@ -2249,7 +2250,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) Curl_safefree(sshc->quote_path1); failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; @@ -2280,7 +2281,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) statvfs.f_namemax); if(!tmp) { result = CURLE_OUT_OF_MEMORY; - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; break; } @@ -2288,21 +2289,21 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); free(tmp); if(result) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } } - state(data, SSH_SFTP_NEXT_QUOTE); + myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); break; } case SSH_SFTP_GETINFO: if(data->set.get_filetime) { - state(data, SSH_SFTP_FILETIME); + myssh_state(data, sshc, SSH_SFTP_FILETIME); } else { - state(data, SSH_SFTP_TRANS_INIT); + myssh_state(data, sshc, SSH_SFTP_TRANS_INIT); } break; @@ -2320,25 +2321,25 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) data->info.filetime = (time_t)attrs.mtime; } - state(data, SSH_SFTP_TRANS_INIT); + myssh_state(data, sshc, SSH_SFTP_TRANS_INIT); break; } case SSH_SFTP_TRANS_INIT: if(data->state.upload) - state(data, SSH_SFTP_UPLOAD_INIT); + myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); else { if(sshp->path[strlen(sshp->path)-1] == '/') - state(data, SSH_SFTP_READDIR_INIT); + myssh_state(data, sshc, SSH_SFTP_READDIR_INIT); else - state(data, SSH_SFTP_DOWNLOAD_INIT); + myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT); } break; case SSH_SFTP_UPLOAD_INIT: result = sftp_upload_init(data, sshc, sshp, block); if(result) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } @@ -2347,10 +2348,10 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) case SSH_SFTP_CREATE_DIRS_INIT: if(strlen(sshp->path) > 1) { sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */ - state(data, SSH_SFTP_CREATE_DIRS); + myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS); } else { - state(data, SSH_SFTP_UPLOAD_INIT); + myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); } break; @@ -2360,10 +2361,10 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) *sshc->slash_pos = 0; infof(data, "Creating directory '%s'", sshp->path); - state(data, SSH_SFTP_CREATE_DIRS_MKDIR); + myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR); break; } - state(data, SSH_SFTP_UPLOAD_INIT); + myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); break; case SSH_SFTP_CREATE_DIRS_MKDIR: @@ -2387,19 +2388,19 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) (sftperr != LIBSSH2_FX_FAILURE) && (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) { result = sftp_libssh2_error_to_CURLE(sftperr); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = result ? result : CURLE_SSH; break; } rc = 0; /* clear rc and continue */ } - state(data, SSH_SFTP_CREATE_DIRS); + myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS); break; case SSH_SFTP_READDIR_INIT: Curl_pgrsSetDownloadSize(data, -1); if(data->req.no_body) { - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } @@ -2421,19 +2422,19 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) sftperr = libssh2_sftp_last_error(sshc->sftp_session); failf(data, "Could not open directory for reading: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); result = sftp_libssh2_error_to_CURLE(sftperr); sshc->actualcode = result ? result : CURLE_SSH; break; } - state(data, SSH_SFTP_READDIR); + myssh_state(data, sshc, SSH_SFTP_READDIR); break; case SSH_SFTP_READDIR: result = sftp_readdir(data, sshc, sshp, block); if(result) { sshc->actualcode = result; - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); } break; @@ -2455,12 +2456,12 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) sshp->readdir_filename); if(result) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = result; break; } - state(data, SSH_SFTP_READDIR_BOTTOM); + myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM); break; case SSH_SFTP_READDIR_BOTTOM: @@ -2472,11 +2473,11 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) if(result) { curlx_dyn_free(&sshp->readdir); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); } else { curlx_dyn_reset(&sshp->readdir); - state(data, SSH_SFTP_READDIR); + myssh_state(data, sshc, SSH_SFTP_READDIR); } break; @@ -2490,7 +2491,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) /* no data to transfer */ Curl_xfer_setup_nop(data); - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; case SSH_SFTP_DOWNLOAD_INIT: @@ -2512,18 +2513,18 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) sftperr = libssh2_sftp_last_error(sshc->sftp_session); failf(data, "Could not open remote file for reading: %s", sftp_libssh2_strerror(sftperr)); - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); result = sftp_libssh2_error_to_CURLE(sftperr); sshc->actualcode = result ? result : CURLE_SSH; break; } - state(data, SSH_SFTP_DOWNLOAD_STAT); + myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); break; case SSH_SFTP_DOWNLOAD_STAT: result = sftp_download_stat(data, sshc, sshp, block); if(result) { - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } @@ -2553,11 +2554,11 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) SSH_SFTP_CLOSE to pass the correct result back */ if(sshc->nextstate != SSH_NO_STATE && sshc->nextstate != SSH_SFTP_CLOSE) { - state(data, sshc->nextstate); + myssh_state(data, sshc, sshc->nextstate); sshc->nextstate = SSH_SFTP_CLOSE; } else { - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); result = sshc->actualcode; } break; @@ -2593,14 +2594,14 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) Curl_safefree(sshc->homedir); - state(data, SSH_SESSION_DISCONNECT); + myssh_state(data, sshc, SSH_SESSION_DISCONNECT); break; case SSH_SCP_TRANS_INIT: result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); if(result) { sshc->actualcode = result; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } @@ -2608,13 +2609,13 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) if(data->state.infilesize < 0) { failf(data, "SCP requires a known file size for upload"); sshc->actualcode = CURLE_UPLOAD_FAILED; - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); break; } - state(data, SSH_SCP_UPLOAD_INIT); + myssh_state(data, sshc, SSH_SCP_UPLOAD_INIT); } else { - state(data, SSH_SCP_DOWNLOAD_INIT); + myssh_state(data, sshc, SSH_SCP_DOWNLOAD_INIT); } break; @@ -2642,7 +2643,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0)); failf(data, "%s", err_msg); - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); /* Map generic errors to upload failed */ if(sshc->actualcode == CURLE_SSH || @@ -2660,7 +2661,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) conn->sockfd = conn->writesockfd; if(result) { - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); sshc->actualcode = result; } else { @@ -2673,7 +2674,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) with both accordingly */ data->state.select_bits = CURL_CSELECT_OUT; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); } break; @@ -2717,7 +2718,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0)); failf(data, "%s", err_msg); - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); break; } @@ -2736,19 +2737,19 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) data->state.select_bits = CURL_CSELECT_IN; if(result) { - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); sshc->actualcode = result; } else - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); } break; case SSH_SCP_DONE: if(data->state.upload) - state(data, SSH_SCP_SEND_EOF); + myssh_state(data, sshc, SSH_SCP_SEND_EOF); else - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_SEND_EOF: @@ -2765,7 +2766,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) rc, err_msg); } } - state(data, SSH_SCP_WAIT_EOF); + myssh_state(data, sshc, SSH_SCP_WAIT_EOF); break; case SSH_SCP_WAIT_EOF: @@ -2781,7 +2782,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) infof(data, "Failed to get channel EOF: %d %s", rc, err_msg); } } - state(data, SSH_SCP_WAIT_CLOSE); + myssh_state(data, sshc, SSH_SCP_WAIT_CLOSE); break; case SSH_SCP_WAIT_CLOSE: @@ -2797,7 +2798,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) infof(data, "Channel failed to close: %d %s", rc, err_msg); } } - state(data, SSH_SCP_CHANNEL_FREE); + myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_CHANNEL_FREE: @@ -2817,9 +2818,9 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) } DEBUGF(infof(data, "SCP DONE phase complete")); #if 0 /* PREV */ - state(data, SSH_SESSION_DISCONNECT); + myssh_state(data, sshc, SSH_SESSION_DISCONNECT); #endif - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); result = sshc->actualcode; break; @@ -2858,7 +2859,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) Curl_safefree(sshc->homedir); - state(data, SSH_SESSION_FREE); + myssh_state(data, sshc, SSH_SESSION_FREE); break; case SSH_SESSION_FREE: @@ -2871,14 +2872,14 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) connclose(conn, "SSH session free"); sshc->state = SSH_SESSION_FREE; /* current */ sshc->nextstate = SSH_NO_STATE; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; case SSH_QUIT: default: /* internal error */ sshc->nextstate = SSH_NO_STATE; - state(data, SSH_STOP); + myssh_state(data, sshc, SSH_STOP); break; } @@ -2920,10 +2921,11 @@ static int ssh_getsock(struct Curl_easy *data, * function in all cases so that when it _does not_ return EAGAIN we can * restore the default wait bits. */ -static void ssh_block2waitfor(struct Curl_easy *data, bool block) +static void ssh_block2waitfor(struct Curl_easy *data, + struct ssh_conn *sshc, + bool block) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; int dir = 0; if(block) { dir = libssh2_session_block_directions(sshc->ssh_session); @@ -2943,26 +2945,30 @@ static void ssh_block2waitfor(struct Curl_easy *data, bool block) static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); CURLcode result = CURLE_OK; bool block; /* we store the status and use that to provide a ssh_getsock() implementation */ + if(!sshc || !sshp) + return CURLE_FAILED_INIT; + do { - result = ssh_statemachine(data, &block); + result = ssh_statemachine(data, sshc, sshp, &block); *done = (sshc->state == SSH_STOP); /* if there is no error, it is not done and it did not EWOULDBLOCK, then try again */ } while(!result && !*done && !block); - ssh_block2waitfor(data, block); + ssh_block2waitfor(data, sshc, block); return result; } static CURLcode ssh_block_statemach(struct Curl_easy *data, - struct connectdata *conn, + struct ssh_conn *sshc, + struct SSHPROTO *sshp, bool disconnect) { - struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; struct curltime dis = curlx_now(); @@ -2971,7 +2977,7 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data, timediff_t left = 1000; struct curltime now = curlx_now(); - result = ssh_statemachine(data, &block); + result = ssh_statemachine(data, sshc, sshp, &block); if(result) break; @@ -2998,7 +3004,7 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data, if(block) { int dir = libssh2_session_block_directions(sshc->ssh_session); - curl_socket_t sock = conn->sock[FIRSTSOCKET]; + curl_socket_t sock = data->conn->sock[FIRSTSOCKET]; curl_socket_t fd_read = CURL_SOCKET_BAD; curl_socket_t fd_write = CURL_SOCKET_BAD; if(LIBSSH2_SESSION_BLOCK_INBOUND & dir) @@ -3014,28 +3020,52 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data, return result; } +static void myssh_easy_dtor(void *key, size_t klen, void *entry) +{ + struct SSHPROTO *sshp = entry; + (void)key; + (void)klen; + Curl_safefree(sshp->path); + curlx_dyn_free(&sshp->readdir); + curlx_dyn_free(&sshp->readdir_link); + free(sshp); +} + +static void myssh_conn_dtor(void *key, size_t klen, void *entry) +{ + struct ssh_conn *sshc = entry; + (void)key; + (void)klen; + sshc_cleanup(sshc, NULL, TRUE); + free(sshc); +} + /* * SSH setup and connection */ static CURLcode ssh_setup_connection(struct Curl_easy *data, struct connectdata *conn) { - struct ssh_conn *sshc = &conn->proto.sshc; - struct SSHPROTO *ssh; + struct ssh_conn *sshc; + struct SSHPROTO *sshp; (void)conn; - if(!sshc->initialised) { - /* other ssh implementations do something here, let's keep - * the initialised flag correct even if this implementation does not. */ - sshc->initialised = TRUE; - } + sshc = calloc(1, sizeof(*sshc)); + if(!sshc) + return CURLE_OUT_OF_MEMORY; + + sshc->initialised = TRUE; + if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, myssh_conn_dtor)) + return CURLE_OUT_OF_MEMORY; - data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); - if(!ssh) + sshp = calloc(1, sizeof(*sshp)); + if(!sshp) return CURLE_OUT_OF_MEMORY; - curlx_dyn_init(&ssh->readdir, CURL_PATH_MAX * 2); - curlx_dyn_init(&ssh->readdir_link, CURL_PATH_MAX); + curlx_dyn_init(&sshp->readdir, CURL_PATH_MAX * 2); + curlx_dyn_init(&sshp->readdir_link, CURL_PATH_MAX); + if(Curl_meta_set(data, CURL_META_SSH_EASY, sshp, myssh_easy_dtor)) + return CURLE_OUT_OF_MEMORY; return CURLE_OK; } @@ -3052,13 +3082,16 @@ static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer, CURLcode result; struct connectdata *conn = data->conn; Curl_recv *backup = conn->recv[0]; - struct ssh_conn *ssh = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); int socknum = Curl_conn_sockindex(data, sock); (void)flags; + if(!sshc) + return -1; + /* swap in the TLS reader function for this call only, and then swap back the SSH one again */ - conn->recv[0] = ssh->tls_recv; + conn->recv[0] = sshc->tls_recv; result = Curl_conn_recv(data, socknum, buffer, length, &nread); conn->recv[0] = backup; if(result == CURLE_AGAIN) @@ -3077,13 +3110,16 @@ static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer, CURLcode result; struct connectdata *conn = data->conn; Curl_send *backup = conn->send[0]; - struct ssh_conn *ssh = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); int socknum = Curl_conn_sockindex(data, sock); (void)flags; + if(!sshc) + return -1; + /* swap in the TLS writer function for this call only, and then swap back the SSH one again */ - conn->send[0] = ssh->tls_send; + conn->send[0] = sshc->tls_send; result = Curl_conn_send(data, socknum, buffer, length, FALSE, &nwrite); conn->send[0] = backup; if(result == CURLE_AGAIN) @@ -3104,9 +3140,9 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) #ifdef CURL_LIBSSH2_DEBUG curl_socket_t sock; #endif - struct ssh_conn *sshc; - CURLcode result; struct connectdata *conn = data->conn; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + CURLcode result; #if LIBSSH2_VERSION_NUM >= 0x010b00 { @@ -3136,19 +3172,13 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) } #endif - /* initialize per-handle data if not already */ - if(!data->req.p.ssh) { - result = ssh_setup_connection(data, conn); - if(result) - return result; - } + if(!sshc) + return CURLE_FAILED_INIT; /* We default to persistent connections. We set this already in this connect function to make the reuse checks properly be able to check this bit. */ connkeep(conn, "SSH default"); - sshc = &conn->proto.sshc; - if(conn->user) infof(data, "User: '%s'", conn->user); else @@ -3272,7 +3302,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) infof(data, "SSH socket: %d", (int)sock); #endif /* CURL_LIBSSH2_DEBUG */ - state(data, SSH_INIT); + myssh_state(data, sshc, SSH_INIT); result = ssh_multi_statemach(data, done); @@ -3293,14 +3323,17 @@ CURLcode scp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done) { + struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); CURLcode result = CURLE_OK; DEBUGF(infof(data, "DO phase starts")); *dophase_done = FALSE; /* not done yet */ + if(!sshc) + return CURLE_FAILED_INIT; /* start the first command in the DO phase */ - state(data, SSH_SCP_TRANS_INIT); + myssh_state(data, sshc, SSH_SCP_TRANS_INIT); /* run the state-machine */ result = ssh_multi_statemach(data, dophase_done); @@ -3337,9 +3370,11 @@ static CURLcode ssh_do(struct Curl_easy *data, bool *done) CURLcode result; bool connected = FALSE; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); *done = FALSE; /* default to false */ + if(!sshc) + return CURLE_FAILED_INIT; data->req.size = -1; /* make sure this is unknown at this point */ @@ -3376,7 +3411,7 @@ static int sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data, if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { return rc; } - if(rc < 0) { + if((rc < 0) && data) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); @@ -3392,12 +3427,51 @@ static int sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data, sshc->sshagent_prev_identity = NULL; } + if(sshc->sftp_handle) { + rc = libssh2_sftp_close(sshc->sftp_handle); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { + return rc; + } + if((rc < 0) && data) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, + NULL, 0); + infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg); + } + sshc->sftp_handle = NULL; + } + + if(sshc->ssh_channel) { + rc = libssh2_channel_free(sshc->ssh_channel); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { + return rc; + } + if((rc < 0) && data) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to free libssh2 scp subsystem: %d %s", + rc, err_msg); + } + sshc->ssh_channel = NULL; + } + + if(sshc->sftp_session) { + rc = libssh2_sftp_shutdown(sshc->sftp_session); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { + return rc; + } + if((rc < 0) && data) + infof(data, "Failed to stop libssh2 sftp subsystem"); + sshc->sftp_session = NULL; + } + if(sshc->ssh_session) { rc = libssh2_session_free(sshc->ssh_session); if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { return rc; } - if(rc < 0) { + if((rc < 0) && data) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); @@ -3433,16 +3507,18 @@ static CURLcode scp_disconnect(struct Curl_easy *data, bool dead_connection) { CURLcode result = CURLE_OK; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); (void) dead_connection; - if(sshc->ssh_session) { + if(sshc && sshc->ssh_session && sshp) { /* only if there is a session still around to use! */ - state(data, SSH_SESSION_DISCONNECT); - result = ssh_block_statemach(data, conn, TRUE); + myssh_state(data, sshc, SSH_SESSION_DISCONNECT); + result = ssh_block_statemach(data, sshc, sshp, TRUE); } - sshc_cleanup(sshc, data, TRUE); + if(sshc) + sshc_cleanup(sshc, data, TRUE); return result; } @@ -3450,20 +3526,19 @@ static CURLcode scp_disconnect(struct Curl_easy *data, done functions */ static CURLcode ssh_done(struct Curl_easy *data, CURLcode status) { + struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); CURLcode result = CURLE_OK; - struct SSHPROTO *sshp = data->req.p.ssh; - struct connectdata *conn = data->conn; + + if(!sshc || !sshp) + return CURLE_FAILED_INIT; if(!status) /* run the state-machine */ - result = ssh_block_statemach(data, conn, FALSE); + result = ssh_block_statemach(data, sshc, sshp, FALSE); else result = status; - Curl_safefree(sshp->path); - curlx_dyn_free(&sshp->readdir); - curlx_dyn_free(&sshp->readdir_link); - if(Curl_pgrsDone(data)) return CURLE_ABORTED_BY_CALLBACK; @@ -3475,13 +3550,13 @@ static CURLcode ssh_done(struct Curl_easy *data, CURLcode status) static CURLcode scp_done(struct Curl_easy *data, CURLcode status, bool premature) { + struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); (void)premature; /* not used */ - if(!status) - state(data, SSH_SCP_DONE); + if(sshc && !status) + myssh_state(data, sshc, SSH_SCP_DONE); return ssh_done(data, status); - } static ssize_t scp_send(struct Curl_easy *data, int sockindex, @@ -3489,14 +3564,18 @@ static ssize_t scp_send(struct Curl_easy *data, int sockindex, { ssize_t nwrite; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); (void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)eos; + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } /* libssh2_channel_write() returns int! */ nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len); - ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)); + ssh_block2waitfor(data, sshc, (nwrite == LIBSSH2_ERROR_EAGAIN)); if(nwrite == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; @@ -3515,13 +3594,17 @@ static ssize_t scp_recv(struct Curl_easy *data, int sockindex, { ssize_t nread; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); (void)sockindex; /* we only support SCP on the fixed known primary socket */ + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } /* libssh2_channel_read() returns int */ nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len); - ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)); + ssh_block2waitfor(data, sshc, (nread == LIBSSH2_ERROR_EAGAIN)); if(nread == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; nread = -1; @@ -3548,14 +3631,17 @@ CURLcode sftp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done) { + struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); CURLcode result = CURLE_OK; DEBUGF(infof(data, "DO phase starts")); *dophase_done = FALSE; /* not done yet */ + if(!sshc) + return CURLE_FAILED_INIT; /* start the first command in the DO phase */ - state(data, SSH_SFTP_QUOTE_INIT); + myssh_state(data, sshc, SSH_SFTP_QUOTE_INIT); /* run the state-machine */ result = ssh_multi_statemach(data, dophase_done); @@ -3588,19 +3674,21 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection) { CURLcode result = CURLE_OK; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); (void) dead_connection; DEBUGF(infof(data, "SSH DISCONNECT starts now")); - if(sshc->ssh_session) { + if(sshc && sshc->ssh_session && sshp) { /* only if there is a session still around to use! */ - state(data, SSH_SFTP_SHUTDOWN); - result = ssh_block_statemach(data, conn, TRUE); + myssh_state(data, sshc, SSH_SFTP_SHUTDOWN); + result = ssh_block_statemach(data, sshc, sshp, TRUE); } DEBUGF(infof(data, "SSH DISCONNECT is done")); - sshc_cleanup(sshc, data, TRUE); + if(sshc) + sshc_cleanup(sshc, data, TRUE); return result; @@ -3610,7 +3698,10 @@ static CURLcode sftp_done(struct Curl_easy *data, CURLcode status, bool premature) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + + if(!sshc) + return CURLE_FAILED_INIT; if(!status) { /* Post quote commands are executed after the SFTP_CLOSE state to avoid @@ -3618,7 +3709,7 @@ static CURLcode sftp_done(struct Curl_easy *data, CURLcode status, operation */ if(!premature && data->set.postquote && !conn->bits.retry) sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; - state(data, SSH_SFTP_CLOSE); + myssh_state(data, sshc, SSH_SFTP_CLOSE); } return ssh_done(data, status); } @@ -3629,13 +3720,17 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex, { ssize_t nwrite; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); (void)sockindex; (void)eos; + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len); - ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)); + ssh_block2waitfor(data, sshc, (nwrite == LIBSSH2_ERROR_EAGAIN)); if(nwrite == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; @@ -3658,12 +3753,16 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, { ssize_t nread; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); (void)sockindex; + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } nread = libssh2_sftp_read(sshc->sftp_handle, mem, len); - ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)); + ssh_block2waitfor(data, sshc, (nread == LIBSSH2_ERROR_EAGAIN)); if(nread == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; @@ -3770,8 +3869,8 @@ static void ssh_attach(struct Curl_easy *data, struct connectdata *conn) DEBUGASSERT(data); DEBUGASSERT(conn); if(conn->handler->protocol & PROTO_FAMILY_SSH) { - struct ssh_conn *sshc = &conn->proto.sshc; - if(sshc->ssh_session) { + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + if(sshc && sshc->ssh_session) { /* only re-attach if the session already exists */ void **abstract = libssh2_session_abstract(sshc->ssh_session); *abstract = data; diff --git a/lib/vssh/ssh.h b/lib/vssh/ssh.h index a431798719..db8ad88511 100644 --- a/lib/vssh/ssh.h +++ b/lib/vssh/ssh.h @@ -41,6 +41,11 @@ #include "curl_path.h" +/* meta key for storing protocol meta at easy handle */ +#define CURL_META_SSH_EASY "meta:proto:ssh:easy" +/* meta key for storing protocol meta at connection */ +#define CURL_META_SSH_CONN "meta:proto:ssh:conn" + /**************************************************************************** * SSH unique setup ***************************************************************************/ diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c index 1bee2836a8..5097ca02c5 100644 --- a/lib/vssh/wolfssh.c +++ b/lib/vssh/wolfssh.c @@ -29,6 +29,7 @@ #include #include "../urldata.h" +#include "../url.h" #include "../cfilters.h" #include "../connect.h" #include "../sendf.h" @@ -70,7 +71,7 @@ static int wssh_getsock(struct Curl_easy *data, curl_socket_t *sock); static CURLcode wssh_setup_connection(struct Curl_easy *data, struct connectdata *conn); -static void wssh_sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data); +static void wssh_sshc_cleanup(struct ssh_conn *sshc); #if 0 /* @@ -138,10 +139,10 @@ const struct Curl_handler Curl_handler_sftp = { * SSH State machine related code */ /* This is the ONLY way to change SSH state! */ -static void state(struct Curl_easy *data, sshstate nowstate) +static void wssh_state(struct Curl_easy *data, + struct ssh_conn *sshc, + sshstate nowstate) { - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[] = { @@ -215,7 +216,7 @@ static void state(struct Curl_easy *data, sshstate nowstate) (void *)sshc, names[sshc->state], names[nowstate]); } #endif - + (void)data; sshc->state = nowstate; } @@ -252,12 +253,16 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex, const void *mem, size_t len, bool eos, CURLcode *err) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); word32 offset[2]; int rc; (void)sockindex; (void)eos; + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } offset[0] = (word32)sshc->offset & 0xFFFFFFFF; offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF; @@ -298,10 +303,14 @@ static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex, { int rc; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); word32 offset[2]; (void)sockindex; + if(!sshc) { + *err = CURLE_FAILED_INIT; + return -1; + } offset[0] = (word32)sshc->offset & 0xFFFFFFFF; offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF; @@ -333,17 +342,45 @@ static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex, return (ssize_t)rc; } +static void wssh_easy_dtor(void *key, size_t klen, void *entry) +{ + struct SSHPROTO *sshp = entry; + (void)key; + (void)klen; + Curl_safefree(sshp->path); + free(sshp); +} + +static void wssh_conn_dtor(void *key, size_t klen, void *entry) +{ + struct ssh_conn *sshc = entry; + (void)key; + (void)klen; + wssh_sshc_cleanup(sshc); + free(sshc); +} + /* * SSH setup and connection */ static CURLcode wssh_setup_connection(struct Curl_easy *data, struct connectdata *conn) { - struct SSHPROTO *ssh; + struct ssh_conn *sshc; + struct SSHPROTO *sshp; (void)conn; - data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); - if(!ssh) + sshc = calloc(1, sizeof(*sshc)); + if(!sshc) + return CURLE_OUT_OF_MEMORY; + + sshc->initialised = TRUE; + if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, wssh_conn_dtor)) + return CURLE_OUT_OF_MEMORY; + + sshp = calloc(1, sizeof(*sshp)); + if(!sshp || + Curl_meta_set(data, CURL_META_SSH_EASY, sshp, wssh_easy_dtor)) return CURLE_OUT_OF_MEMORY; return CURLE_OK; @@ -368,13 +405,13 @@ static int userauth(byte authtype, static CURLcode wssh_connect(struct Curl_easy *data, bool *done) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc; - /* initialize per-handle data if not already */ - if(!data->req.p.ssh) - wssh_setup_connection(data, conn); + if(!sshc || !sshp) + return CURLE_FAILED_INIT; /* We default to persistent connections. We set this already in this connect function to make the reuse checks properly be able to check this bit. */ @@ -422,13 +459,13 @@ static CURLcode wssh_connect(struct Curl_easy *data, bool *done) *done = TRUE; if(conn->handler->protocol & CURLPROTO_SCP) - state(data, SSH_INIT); + wssh_state(data, sshc, SSH_INIT); else - state(data, SSH_SFTP_INIT); + wssh_state(data, sshc, SSH_SFTP_INIT); return wssh_multi_statemach(data, done); error: - wssh_sshc_cleanup(sshc, data); + wssh_sshc_cleanup(sshc); return CURLE_FAILED_INIT; } @@ -439,20 +476,24 @@ error: * wants to be called again when the socket is ready */ -static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) +static CURLcode wssh_statemach_act(struct Curl_easy *data, + struct ssh_conn *sshc, + bool *block) { CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; - struct SSHPROTO *sftp_scp = data->req.p.ssh; + struct SSHPROTO *sftp_scp = Curl_meta_get(data, CURL_META_SSH_EASY); WS_SFTPNAME *name; int rc = 0; *block = FALSE; /* we are not blocking by default */ + if(!sftp_scp) + return CURLE_FAILED_INIT; + do { switch(sshc->state) { case SSH_INIT: - state(data, SSH_S_STARTUP); + wssh_state(data, sshc, SSH_S_STARTUP); break; case SSH_S_STARTUP: @@ -470,11 +511,11 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) return CURLE_OK; } else if(rc != WS_SUCCESS) { - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); return CURLE_SSH; } infof(data, "wolfssh connected"); - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); break; case SSH_STOP: break; @@ -495,7 +536,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) } else if(rc == WS_SUCCESS) { infof(data, "wolfssh SFTP connected"); - state(data, SSH_SFTP_REALPATH); + wssh_state(data, sshc, SSH_SFTP_REALPATH); } else { failf(data, "wolfssh SFTP connect error %d", rc); @@ -521,7 +562,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) if(!sshc->homedir) sshc->actualcode = CURLE_OUT_OF_MEMORY; wolfSSH_SFTPNAME_list_free(name); - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); return CURLE_OK; } failf(data, "wolfssh SFTP realpath %d", rc); @@ -531,35 +572,35 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path); if(result) { sshc->actualcode = result; - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); break; } if(data->set.quote) { infof(data, "Sending quote commands"); sshc->quote_item = data->set.quote; - state(data, SSH_SFTP_QUOTE); + wssh_state(data, sshc, SSH_SFTP_QUOTE); } else { - state(data, SSH_SFTP_GETINFO); + wssh_state(data, sshc, SSH_SFTP_GETINFO); } break; case SSH_SFTP_GETINFO: if(data->set.get_filetime) { - state(data, SSH_SFTP_FILETIME); + wssh_state(data, sshc, SSH_SFTP_FILETIME); } else { - state(data, SSH_SFTP_TRANS_INIT); + wssh_state(data, sshc, SSH_SFTP_TRANS_INIT); } break; case SSH_SFTP_TRANS_INIT: if(data->state.upload) - state(data, SSH_SFTP_UPLOAD_INIT); + wssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); else { if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') - state(data, SSH_SFTP_READDIR_INIT); + wssh_state(data, sshc, SSH_SFTP_READDIR_INIT); else - state(data, SSH_SFTP_DOWNLOAD_INIT); + wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT); } break; case SSH_SFTP_UPLOAD_INIT: { @@ -622,7 +663,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) failf(data, "wolfssh SFTP upload open failed: %d", rc); return CURLE_SSH; } - state(data, SSH_SFTP_DOWNLOAD_STAT); + wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); /* If we have a restart point then we need to seek to the correct position. */ @@ -688,7 +729,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) conn->sockfd = conn->writesockfd; if(result) { - state(data, SSH_SFTP_CLOSE); + wssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = result; } else { @@ -706,7 +747,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) timeout here */ Curl_expire(data, 0, EXPIRE_RUN_NOW); - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); } break; } @@ -729,7 +770,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) } else if(rc == WS_SUCCESS) { infof(data, "wolfssh SFTP open succeeded"); - state(data, SSH_SFTP_DOWNLOAD_STAT); + wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); return CURLE_OK; } @@ -784,7 +825,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) /* no data to transfer */ Curl_xfer_setup_nop(data); infof(data, "File already completely downloaded"); - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); break; } Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); @@ -800,11 +841,11 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) if(result) { /* this should never occur; the close state should be entered at the time the error occurs */ - state(data, SSH_SFTP_CLOSE); + wssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = result; } else { - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); } break; } @@ -829,7 +870,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) return CURLE_OK; } else if(rc == WS_SUCCESS) { - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); return CURLE_OK; } @@ -839,10 +880,10 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) case SSH_SFTP_READDIR_INIT: Curl_pgrsSetDownloadSize(data, -1); if(data->req.no_body) { - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); break; } - state(data, SSH_SFTP_READDIR); + wssh_state(data, sshc, SSH_SFTP_READDIR); break; case SSH_SFTP_READDIR: @@ -870,7 +911,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) data->set.list_only ? name->fName : name->lName); if(!line) { - state(data, SSH_SFTP_CLOSE); + wssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } @@ -884,15 +925,15 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) name = name->next; } wolfSSH_SFTPNAME_list_free(origname); - state(data, SSH_STOP); + wssh_state(data, sshc, SSH_STOP); return result; } failf(data, "wolfssh SFTP ls failed: %d", rc); return CURLE_SSH; case SSH_SFTP_SHUTDOWN: - wssh_sshc_cleanup(sshc, data); - state(data, SSH_STOP); + wssh_sshc_cleanup(sshc); + wssh_state(data, sshc, SSH_STOP); return CURLE_OK; default: break; @@ -905,12 +946,15 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); CURLcode result = CURLE_OK; bool block; /* we store the status and use that to provide a ssh_getsock() implementation */ + if(!sshc) + return CURLE_FAILED_INIT; + do { - result = wssh_statemach_act(data, &block); + result = wssh_statemach_act(data, sshc, &block); *done = (sshc->state == SSH_STOP); /* if there is no error, it is not done and it did not EWOULDBLOCK, then try again */ @@ -935,6 +979,7 @@ CURLcode wscp_perform(struct Curl_easy *data, static CURLcode wsftp_perform(struct Curl_easy *data, + struct ssh_conn *sshc, bool *connected, bool *dophase_done) { @@ -945,7 +990,7 @@ CURLcode wsftp_perform(struct Curl_easy *data, *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ - state(data, SSH_SFTP_QUOTE_INIT); + wssh_state(data, sshc, SSH_SFTP_QUOTE_INIT); /* run the state-machine */ result = wssh_multi_statemach(data, dophase_done); @@ -967,9 +1012,12 @@ static CURLcode wssh_do(struct Curl_easy *data, bool *done) CURLcode result; bool connected = FALSE; struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); *done = FALSE; /* default to false */ + if(!sshc) + return CURLE_FAILED_INIT; + data->req.size = -1; /* make sure this is unknown at this point */ sshc->actualcode = CURLE_OK; /* reset error code */ sshc->secondCreateDirs = 0; /* reset the create dir attempt state @@ -983,16 +1031,16 @@ static CURLcode wssh_do(struct Curl_easy *data, bool *done) if(conn->handler->protocol & CURLPROTO_SCP) result = wscp_perform(data, &connected, done); else - result = wsftp_perform(data, &connected, done); + result = wsftp_perform(data, sshc, &connected, done); return result; } static CURLcode wssh_block_statemach(struct Curl_easy *data, - bool disconnect) + struct ssh_conn *sshc, + bool disconnect) { struct connectdata *conn = data->conn; - struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; while((sshc->state != SSH_STOP) && !result) { @@ -1000,7 +1048,7 @@ static CURLcode wssh_block_statemach(struct Curl_easy *data, timediff_t left = 1000; struct curltime now = curlx_now(); - result = wssh_statemach_act(data, &block); + result = wssh_statemach_act(data, sshc, &block); if(result) break; @@ -1040,20 +1088,19 @@ static CURLcode wssh_block_statemach(struct Curl_easy *data, /* generic done function for both SCP and SFTP called from their specific done functions */ -static CURLcode wssh_done(struct Curl_easy *data, CURLcode status) +static CURLcode wssh_done(struct Curl_easy *data, + struct ssh_conn *sshc, + CURLcode status) { CURLcode result = CURLE_OK; - struct SSHPROTO *sftp_scp = data->req.p.ssh; if(!status) { /* run the state-machine */ - result = wssh_block_statemach(data, FALSE); + result = wssh_block_statemach(data, sshc, FALSE); } else result = status; - if(sftp_scp) - Curl_safefree(sftp_scp->path); if(Curl_pgrsDone(data)) return CURLE_ABORTED_BY_CALLBACK; @@ -1061,9 +1108,8 @@ static CURLcode wssh_done(struct Curl_easy *data, CURLcode status) return result; } -static void wssh_sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data) +static void wssh_sshc_cleanup(struct ssh_conn *sshc) { - (void)data; if(sshc->ssh_session) { wolfSSH_free(sshc->ssh_session); sshc->ssh_session = NULL; @@ -1100,10 +1146,11 @@ static CURLcode wscp_doing(struct Curl_easy *data, static CURLcode wscp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection) { - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); CURLcode result = CURLE_OK; (void)dead_connection; - wssh_sshc_cleanup(sshc, data); + if(sshc) + wssh_sshc_cleanup(sshc); return result; } #endif @@ -1111,10 +1158,14 @@ static CURLcode wscp_disconnect(struct Curl_easy *data, static CURLcode wsftp_done(struct Curl_easy *data, CURLcode code, bool premature) { + struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); (void)premature; - state(data, SSH_SFTP_CLOSE); + if(!sshc) + return CURLE_FAILED_INIT; + + wssh_state(data, sshc, SSH_SFTP_CLOSE); - return wssh_done(data, code); + return wssh_done(data, sshc, code); } static CURLcode wsftp_doing(struct Curl_easy *data, @@ -1132,19 +1183,20 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead) { - struct ssh_conn *sshc = &conn->proto.sshc; + struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); CURLcode result = CURLE_OK; (void)dead; DEBUGF(infof(data, "SSH DISCONNECT starts now")); - if(conn->proto.sshc.ssh_session) { + if(sshc && sshc->ssh_session) { /* only if there is a session still around to use! */ - state(data, SSH_SFTP_SHUTDOWN); - result = wssh_block_statemach(data, TRUE); + wssh_state(data, sshc, SSH_SFTP_SHUTDOWN); + result = wssh_block_statemach(data, sshc, TRUE); } - wssh_sshc_cleanup(sshc, data); + if(sshc) + wssh_sshc_cleanup(sshc); DEBUGF(infof(data, "SSH DISCONNECT is done")); return result; } -- 2.47.3