]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ssh: move easy handle/connection protocol structs to meta
authorStefan Eissing <stefan@eissing.org>
Wed, 7 May 2025 11:45:41 +0000 (13:45 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 8 May 2025 09:56:50 +0000 (11:56 +0200)
Closes #17273

lib/request.h
lib/url.c
lib/urldata.h
lib/vssh/libssh.c
lib/vssh/libssh2.c
lib/vssh/ssh.h
lib/vssh/wolfssh.c

index f26ae7f2f77f096a89fa9a4f101787e2375649b6..1ac873099ae3a8ae5c88e514c06de4ad9acbd7fb 100644 (file)
@@ -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;
index 02b386f0551ceafef1c7b5a5bc861f25ca861ae9..aac9c2e84fcd60289ceecb12e2602025c6160de1 100644 (file)
--- 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
 
index 44030fec7c80088b523634edbffa71c862e78233..912abdada2bb8dff1989819914af8bcca273258e 100644 (file)
@@ -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
index 13a6147be6795d78fd1d9260a5390d2a1ecccc75..e288cd2ec589d30e81f09272e03303866251cc0b 100644 (file)
@@ -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;
 }
 
index 19a80f127d7cd5d2cbed9a7ffdf2024b167b6c76..d56d7b32d9d4bd635b3d9241e41bdb0852263643 100644 (file)
@@ -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;
index a43179871954cb5e155fc2da440a2be302d9da6c..db8ad885115f8200cd6475bb802898cd3287f00d 100644 (file)
 
 #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
  ***************************************************************************/
index 1bee2836a86b31c27d6a0fdf7aa678a1fb216546..5097ca02c5158e62eb3fa060ef7cc073c2233901 100644 (file)
@@ -29,6 +29,7 @@
 #include <limits.h>
 
 #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;
 }