quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

libssh.c (94448B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Red Hat, Inc.
      9  *
     10  * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
     11  *          Robert Kolcun, Andreas Schneider
     12  *
     13  * This software is licensed as described in the file COPYING, which
     14  * you should have received as part of this distribution. The terms
     15  * are also available at https://curl.se/docs/copyright.html.
     16  *
     17  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     18  * copies of the Software, and permit persons to whom the Software is
     19  * furnished to do so, under the terms of the COPYING file.
     20  *
     21  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     22  * KIND, either express or implied.
     23  *
     24  * SPDX-License-Identifier: curl
     25  *
     26  ***************************************************************************/
     27 
     28 #include "../curl_setup.h"
     29 
     30 #ifdef USE_LIBSSH
     31 
     32 #include <limits.h>
     33 
     34 #ifdef HAVE_NETINET_IN_H
     35 #include <netinet/in.h>
     36 #endif
     37 #ifdef HAVE_ARPA_INET_H
     38 #include <arpa/inet.h>
     39 #endif
     40 #ifdef HAVE_NETDB_H
     41 #include <netdb.h>
     42 #endif
     43 #ifdef __VMS
     44 #include <in.h>
     45 #include <inet.h>
     46 #endif
     47 
     48 #include <curl/curl.h>
     49 #include "../urldata.h"
     50 #include "../sendf.h"
     51 #include "../hostip.h"
     52 #include "../progress.h"
     53 #include "../transfer.h"
     54 #include "../escape.h"
     55 #include "../http.h"               /* for HTTP proxy tunnel stuff */
     56 #include "ssh.h"
     57 #include "../url.h"
     58 #include "../speedcheck.h"
     59 #include "../getinfo.h"
     60 #include "../strdup.h"
     61 #include "../vtls/vtls.h"
     62 #include "../cfilters.h"
     63 #include "../connect.h"
     64 #include "../parsedate.h"          /* for the week day and month names */
     65 #include "../sockaddr.h"           /* required for Curl_sockaddr_storage */
     66 #include "../curlx/strparse.h"
     67 #include "../multiif.h"
     68 #include "../select.h"
     69 #include "../curlx/warnless.h"
     70 #include "curl_path.h"
     71 
     72 #ifdef HAVE_UNISTD_H
     73 #include <unistd.h>
     74 #endif
     75 #ifdef HAVE_FCNTL_H
     76 #include <fcntl.h>
     77 #endif
     78 
     79 /* The last 3 #include files should be in this order */
     80 #include "../curl_printf.h"
     81 #include "../curl_memory.h"
     82 #include "../memdebug.h"
     83 
     84 /* A recent macro provided by libssh. Or make our own. */
     85 #ifndef SSH_STRING_FREE_CHAR
     86 #define SSH_STRING_FREE_CHAR(x)                 \
     87   do {                                          \
     88     if(x) {                                     \
     89       ssh_string_free_char(x);                  \
     90       x = NULL;                                 \
     91     }                                           \
     92   } while(0)
     93 #endif
     94 
     95 /* These stat values may not be the same as the user's S_IFMT / S_IFLNK */
     96 #ifndef SSH_S_IFMT
     97 #define SSH_S_IFMT   00170000
     98 #endif
     99 #ifndef SSH_S_IFLNK
    100 #define SSH_S_IFLNK  0120000
    101 #endif
    102 
    103 /* Local functions: */
    104 static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
    105 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
    106                                       bool *done);
    107 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
    108 
    109 static CURLcode scp_done(struct Curl_easy *data,
    110                          CURLcode, bool premature);
    111 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
    112 static CURLcode scp_disconnect(struct Curl_easy *data,
    113                                struct connectdata *conn,
    114                                bool dead_connection);
    115 
    116 static CURLcode sftp_done(struct Curl_easy *data,
    117                           CURLcode, bool premature);
    118 static CURLcode sftp_doing(struct Curl_easy *data,
    119                            bool *dophase_done);
    120 static CURLcode sftp_disconnect(struct Curl_easy *data,
    121                                 struct connectdata *conn,
    122                                 bool dead);
    123 static
    124 CURLcode sftp_perform(struct Curl_easy *data,
    125                       bool *connected,
    126                       bool *dophase_done);
    127 
    128 static int myssh_getsock(struct Curl_easy *data,
    129                          struct connectdata *conn, curl_socket_t *sock);
    130 static void myssh_block2waitfor(struct connectdata *conn,
    131                                 struct ssh_conn *sshc,
    132                                 bool block);
    133 
    134 static CURLcode myssh_setup_connection(struct Curl_easy *data,
    135                                        struct connectdata *conn);
    136 static void sshc_cleanup(struct ssh_conn *sshc);
    137 
    138 /*
    139  * SCP protocol handler.
    140  */
    141 
    142 const struct Curl_handler Curl_handler_scp = {
    143   "SCP",                        /* scheme */
    144   myssh_setup_connection,       /* setup_connection */
    145   myssh_do_it,                  /* do_it */
    146   scp_done,                     /* done */
    147   ZERO_NULL,                    /* do_more */
    148   myssh_connect,                /* connect_it */
    149   myssh_multi_statemach,        /* connecting */
    150   scp_doing,                    /* doing */
    151   myssh_getsock,                /* proto_getsock */
    152   myssh_getsock,                /* doing_getsock */
    153   ZERO_NULL,                    /* domore_getsock */
    154   myssh_getsock,                /* perform_getsock */
    155   scp_disconnect,               /* disconnect */
    156   ZERO_NULL,                    /* write_resp */
    157   ZERO_NULL,                    /* write_resp_hd */
    158   ZERO_NULL,                    /* connection_check */
    159   ZERO_NULL,                    /* attach connection */
    160   ZERO_NULL,                    /* follow */
    161   PORT_SSH,                     /* defport */
    162   CURLPROTO_SCP,                /* protocol */
    163   CURLPROTO_SCP,                /* family */
    164   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY    /* flags */
    165 };
    166 
    167 /*
    168  * SFTP protocol handler.
    169  */
    170 
    171 const struct Curl_handler Curl_handler_sftp = {
    172   "SFTP",                               /* scheme */
    173   myssh_setup_connection,               /* setup_connection */
    174   myssh_do_it,                          /* do_it */
    175   sftp_done,                            /* done */
    176   ZERO_NULL,                            /* do_more */
    177   myssh_connect,                        /* connect_it */
    178   myssh_multi_statemach,                /* connecting */
    179   sftp_doing,                           /* doing */
    180   myssh_getsock,                        /* proto_getsock */
    181   myssh_getsock,                        /* doing_getsock */
    182   ZERO_NULL,                            /* domore_getsock */
    183   myssh_getsock,                        /* perform_getsock */
    184   sftp_disconnect,                      /* disconnect */
    185   ZERO_NULL,                            /* write_resp */
    186   ZERO_NULL,                            /* write_resp_hd */
    187   ZERO_NULL,                            /* connection_check */
    188   ZERO_NULL,                            /* attach connection */
    189   ZERO_NULL,                            /* follow */
    190   PORT_SSH,                             /* defport */
    191   CURLPROTO_SFTP,                       /* protocol */
    192   CURLPROTO_SFTP,                       /* family */
    193   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
    194   | PROTOPT_NOURLQUERY                  /* flags */
    195 };
    196 
    197 static CURLcode sftp_error_to_CURLE(int err)
    198 {
    199   switch(err) {
    200     case SSH_FX_OK:
    201       return CURLE_OK;
    202 
    203     case SSH_FX_NO_SUCH_FILE:
    204     case SSH_FX_NO_SUCH_PATH:
    205       return CURLE_REMOTE_FILE_NOT_FOUND;
    206 
    207     case SSH_FX_PERMISSION_DENIED:
    208     case SSH_FX_WRITE_PROTECT:
    209       return CURLE_REMOTE_ACCESS_DENIED;
    210 
    211     case SSH_FX_FILE_ALREADY_EXISTS:
    212       return CURLE_REMOTE_FILE_EXISTS;
    213 
    214     default:
    215       break;
    216   }
    217 
    218   return CURLE_SSH;
    219 }
    220 
    221 #ifndef DEBUGBUILD
    222 #define myssh_to(x,y,z) myssh_set_state(x,y,z)
    223 #else
    224 #define myssh_to(x,y,z) myssh_set_state(x,y,z, __LINE__)
    225 #endif
    226 
    227 /*
    228  * SSH State machine related code
    229  */
    230 /* This is the ONLY way to change SSH state! */
    231 static void myssh_set_state(struct Curl_easy *data,
    232                             struct ssh_conn *sshc,
    233                             sshstate nowstate
    234 #ifdef DEBUGBUILD
    235                           , int lineno
    236 #endif
    237   )
    238 {
    239 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
    240   /* for debug purposes */
    241   static const char *const names[] = {
    242     "SSH_STOP",
    243     "SSH_INIT",
    244     "SSH_S_STARTUP",
    245     "SSH_HOSTKEY",
    246     "SSH_AUTHLIST",
    247     "SSH_AUTH_PKEY_INIT",
    248     "SSH_AUTH_PKEY",
    249     "SSH_AUTH_PASS_INIT",
    250     "SSH_AUTH_PASS",
    251     "SSH_AUTH_AGENT_INIT",
    252     "SSH_AUTH_AGENT_LIST",
    253     "SSH_AUTH_AGENT",
    254     "SSH_AUTH_HOST_INIT",
    255     "SSH_AUTH_HOST",
    256     "SSH_AUTH_KEY_INIT",
    257     "SSH_AUTH_KEY",
    258     "SSH_AUTH_GSSAPI",
    259     "SSH_AUTH_DONE",
    260     "SSH_SFTP_INIT",
    261     "SSH_SFTP_REALPATH",
    262     "SSH_SFTP_QUOTE_INIT",
    263     "SSH_SFTP_POSTQUOTE_INIT",
    264     "SSH_SFTP_QUOTE",
    265     "SSH_SFTP_NEXT_QUOTE",
    266     "SSH_SFTP_QUOTE_STAT",
    267     "SSH_SFTP_QUOTE_SETSTAT",
    268     "SSH_SFTP_QUOTE_SYMLINK",
    269     "SSH_SFTP_QUOTE_MKDIR",
    270     "SSH_SFTP_QUOTE_RENAME",
    271     "SSH_SFTP_QUOTE_RMDIR",
    272     "SSH_SFTP_QUOTE_UNLINK",
    273     "SSH_SFTP_QUOTE_STATVFS",
    274     "SSH_SFTP_GETINFO",
    275     "SSH_SFTP_FILETIME",
    276     "SSH_SFTP_TRANS_INIT",
    277     "SSH_SFTP_UPLOAD_INIT",
    278     "SSH_SFTP_CREATE_DIRS_INIT",
    279     "SSH_SFTP_CREATE_DIRS",
    280     "SSH_SFTP_CREATE_DIRS_MKDIR",
    281     "SSH_SFTP_READDIR_INIT",
    282     "SSH_SFTP_READDIR",
    283     "SSH_SFTP_READDIR_LINK",
    284     "SSH_SFTP_READDIR_BOTTOM",
    285     "SSH_SFTP_READDIR_DONE",
    286     "SSH_SFTP_DOWNLOAD_INIT",
    287     "SSH_SFTP_DOWNLOAD_STAT",
    288     "SSH_SFTP_CLOSE",
    289     "SSH_SFTP_SHUTDOWN",
    290     "SSH_SCP_TRANS_INIT",
    291     "SSH_SCP_UPLOAD_INIT",
    292     "SSH_SCP_DOWNLOAD_INIT",
    293     "SSH_SCP_DOWNLOAD",
    294     "SSH_SCP_DONE",
    295     "SSH_SCP_SEND_EOF",
    296     "SSH_SCP_WAIT_EOF",
    297     "SSH_SCP_WAIT_CLOSE",
    298     "SSH_SCP_CHANNEL_FREE",
    299     "SSH_SESSION_DISCONNECT",
    300     "SSH_SESSION_FREE",
    301     "QUIT"
    302   };
    303 
    304 
    305   if(sshc->state != nowstate) {
    306     infof(data, "SSH %p state change from %s to %s (line %d)",
    307           (void *) sshc, names[sshc->state], names[nowstate],
    308           lineno);
    309   }
    310 #endif
    311   (void)data;
    312   sshc->state = nowstate;
    313 }
    314 
    315 /* Multiple options:
    316  * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
    317  *    hash (90s style auth, not sure we should have it here)
    318  * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
    319  *    use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
    320  *    is returned by it.
    321  * 3. none of the above. We only accept if it is present on known hosts.
    322  *
    323  * Returns SSH_OK or SSH_ERROR.
    324  */
    325 static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc)
    326 {
    327   int rc;
    328   ssh_key pubkey;
    329   size_t hlen;
    330   unsigned char *hash = NULL;
    331   char *found_base64 = NULL;
    332   char *known_base64 = NULL;
    333   int vstate;
    334   enum curl_khmatch keymatch;
    335   struct curl_khkey foundkey;
    336   struct curl_khkey *knownkeyp = NULL;
    337   curl_sshkeycallback func =
    338     data->set.ssh_keyfunc;
    339   struct ssh_knownhosts_entry *knownhostsentry = NULL;
    340   struct curl_khkey knownkey;
    341 
    342   rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
    343 
    344   if(rc != SSH_OK)
    345     return rc;
    346 
    347   if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
    348     int i;
    349     char md5buffer[33];
    350     const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
    351 
    352     rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
    353                                 &hash, &hlen);
    354     if(rc != SSH_OK || hlen != 16) {
    355       failf(data,
    356             "Denied establishing ssh session: md5 fingerprint not available");
    357       goto cleanup;
    358     }
    359 
    360     for(i = 0; i < 16; i++)
    361       msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
    362 
    363     infof(data, "SSH MD5 fingerprint: %s", md5buffer);
    364 
    365     if(!curl_strequal(md5buffer, pubkey_md5)) {
    366       failf(data,
    367             "Denied establishing ssh session: mismatch md5 fingerprint. "
    368             "Remote %s is not equal to %s", md5buffer, pubkey_md5);
    369       rc = SSH_ERROR;
    370       goto cleanup;
    371     }
    372 
    373     rc = SSH_OK;
    374     goto cleanup;
    375   }
    376 
    377   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
    378 
    379     /* Get the known_key from the known hosts file */
    380     vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
    381                                                &knownhostsentry);
    382 
    383     /* Case an entry was found in a known hosts file */
    384     if(knownhostsentry) {
    385       if(knownhostsentry->publickey) {
    386         rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
    387                                           &known_base64);
    388         if(rc != SSH_OK) {
    389           goto cleanup;
    390         }
    391         knownkey.key = known_base64;
    392         knownkey.len = strlen(known_base64);
    393 
    394         switch(ssh_key_type(knownhostsentry->publickey)) {
    395         case SSH_KEYTYPE_RSA:
    396           knownkey.keytype = CURLKHTYPE_RSA;
    397           break;
    398         case SSH_KEYTYPE_RSA1:
    399           knownkey.keytype = CURLKHTYPE_RSA1;
    400           break;
    401         case SSH_KEYTYPE_ECDSA:
    402         case SSH_KEYTYPE_ECDSA_P256:
    403         case SSH_KEYTYPE_ECDSA_P384:
    404         case SSH_KEYTYPE_ECDSA_P521:
    405           knownkey.keytype = CURLKHTYPE_ECDSA;
    406           break;
    407         case SSH_KEYTYPE_ED25519:
    408           knownkey.keytype = CURLKHTYPE_ED25519;
    409           break;
    410         case SSH_KEYTYPE_DSS:
    411           knownkey.keytype = CURLKHTYPE_DSS;
    412           break;
    413         default:
    414           rc = SSH_ERROR;
    415           goto cleanup;
    416         }
    417         knownkeyp = &knownkey;
    418       }
    419     }
    420 
    421     switch(vstate) {
    422     case SSH_KNOWN_HOSTS_OK:
    423       keymatch = CURLKHMATCH_OK;
    424       break;
    425     case SSH_KNOWN_HOSTS_OTHER:
    426     case SSH_KNOWN_HOSTS_NOT_FOUND:
    427     case SSH_KNOWN_HOSTS_UNKNOWN:
    428     case SSH_KNOWN_HOSTS_ERROR:
    429       keymatch = CURLKHMATCH_MISSING;
    430       break;
    431     default:
    432       keymatch = CURLKHMATCH_MISMATCH;
    433       break;
    434     }
    435 
    436     if(func) { /* use callback to determine action */
    437       rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
    438       if(rc != SSH_OK)
    439         goto cleanup;
    440 
    441       foundkey.key = found_base64;
    442       foundkey.len = strlen(found_base64);
    443 
    444       switch(ssh_key_type(pubkey)) {
    445       case SSH_KEYTYPE_RSA:
    446         foundkey.keytype = CURLKHTYPE_RSA;
    447         break;
    448       case SSH_KEYTYPE_RSA1:
    449         foundkey.keytype = CURLKHTYPE_RSA1;
    450         break;
    451       case SSH_KEYTYPE_ECDSA:
    452       case SSH_KEYTYPE_ECDSA_P256:
    453       case SSH_KEYTYPE_ECDSA_P384:
    454       case SSH_KEYTYPE_ECDSA_P521:
    455         foundkey.keytype = CURLKHTYPE_ECDSA;
    456         break;
    457       case SSH_KEYTYPE_ED25519:
    458         foundkey.keytype = CURLKHTYPE_ED25519;
    459         break;
    460       case SSH_KEYTYPE_DSS:
    461         foundkey.keytype = CURLKHTYPE_DSS;
    462         break;
    463       default:
    464         rc = SSH_ERROR;
    465         goto cleanup;
    466       }
    467 
    468       Curl_set_in_callback(data, TRUE);
    469       rc = func(data, knownkeyp, /* from the knownhosts file */
    470                 &foundkey, /* from the remote host */
    471                 keymatch, data->set.ssh_keyfunc_userp);
    472       Curl_set_in_callback(data, FALSE);
    473 
    474       switch(rc) {
    475       case CURLKHSTAT_FINE_ADD_TO_FILE:
    476         rc = ssh_session_update_known_hosts(sshc->ssh_session);
    477         if(rc != SSH_OK) {
    478           goto cleanup;
    479         }
    480         break;
    481       case CURLKHSTAT_FINE:
    482         break;
    483       default: /* REJECT/DEFER */
    484         rc = SSH_ERROR;
    485         goto cleanup;
    486       }
    487     }
    488     else {
    489       if(keymatch != CURLKHMATCH_OK) {
    490         rc = SSH_ERROR;
    491         goto cleanup;
    492       }
    493     }
    494   }
    495   rc = SSH_OK;
    496 
    497 cleanup:
    498   if(found_base64) {
    499     (free)(found_base64);
    500   }
    501   if(known_base64) {
    502     (free)(known_base64);
    503   }
    504   if(hash)
    505     ssh_clean_pubkey_hash(&hash);
    506   ssh_key_free(pubkey);
    507   if(knownhostsentry) {
    508     ssh_knownhosts_entry_free(knownhostsentry);
    509   }
    510   return rc;
    511 }
    512 
    513 static int myssh_to_ERROR(struct Curl_easy *data,
    514                           struct ssh_conn *sshc,
    515                           CURLcode result)
    516 {
    517   myssh_to(data, sshc, SSH_SESSION_DISCONNECT);
    518   sshc->actualcode = result;
    519   return SSH_ERROR;
    520 }
    521 
    522 static int myssh_to_SFTP_CLOSE(struct Curl_easy *data,
    523                                struct ssh_conn *sshc)
    524 {
    525   myssh_to(data, sshc, SSH_SFTP_CLOSE);
    526   sshc->actualcode =
    527     sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session));
    528   return SSH_ERROR;
    529 }
    530 
    531 static int myssh_to_PASSWD_AUTH(struct Curl_easy *data,
    532                                 struct ssh_conn *sshc)
    533 {
    534   if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
    535     myssh_to(data, sshc, SSH_AUTH_PASS_INIT);
    536     return SSH_OK;
    537   }
    538   return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
    539 }
    540 
    541 static int myssh_to_KEY_AUTH(struct Curl_easy *data,
    542                              struct ssh_conn *sshc)
    543 {
    544   if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
    545     myssh_to(data, sshc, SSH_AUTH_KEY_INIT);
    546     return SSH_OK;
    547   }
    548   return myssh_to_PASSWD_AUTH(data, sshc);
    549 }
    550 
    551 static int myssh_to_GSSAPI_AUTH(struct Curl_easy *data,
    552                                 struct ssh_conn *sshc)
    553 {
    554   if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
    555     myssh_to(data, sshc, SSH_AUTH_GSSAPI);
    556     return SSH_OK;
    557   }
    558   return myssh_to_KEY_AUTH(data, sshc);
    559 }
    560 
    561 static int myssh_in_SFTP_READDIR_INIT(struct Curl_easy *data,
    562                                       struct ssh_conn *sshc,
    563                                       struct SSHPROTO *sshp)
    564 {
    565   Curl_pgrsSetDownloadSize(data, -1);
    566   if(data->req.no_body) {
    567     myssh_to(data, sshc, SSH_STOP);
    568     return SSH_NO_ERROR;
    569   }
    570 
    571   /*
    572    * This is a directory that we are trying to get, so produce a directory
    573    * listing
    574    */
    575   sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
    576                                 sshp->path);
    577   if(!sshc->sftp_dir) {
    578     failf(data, "Could not open directory for reading: %s",
    579           ssh_get_error(sshc->ssh_session));
    580     return myssh_to_SFTP_CLOSE(data, sshc);
    581   }
    582   myssh_to(data, sshc, SSH_SFTP_READDIR);
    583   return SSH_NO_ERROR;
    584 }
    585 
    586 static int myssh_in_SFTP_READDIR(struct Curl_easy *data,
    587                                  struct ssh_conn *sshc,
    588                                  struct SSHPROTO *sshp)
    589 {
    590   CURLcode result = CURLE_OK;
    591 
    592   curlx_dyn_reset(&sshc->readdir_buf);
    593   if(sshc->readdir_attrs)
    594     sftp_attributes_free(sshc->readdir_attrs);
    595 
    596   sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
    597   if(sshc->readdir_attrs) {
    598     sshc->readdir_filename = sshc->readdir_attrs->name;
    599     sshc->readdir_longentry = sshc->readdir_attrs->longname;
    600     sshc->readdir_len = strlen(sshc->readdir_filename);
    601 
    602     if(data->set.list_only) {
    603       char *tmpLine;
    604 
    605       tmpLine = aprintf("%s\n", sshc->readdir_filename);
    606       if(!tmpLine) {
    607         myssh_to(data, sshc, SSH_SFTP_CLOSE);
    608         sshc->actualcode = CURLE_OUT_OF_MEMORY;
    609         return SSH_ERROR;
    610       }
    611       result = Curl_client_write(data, CLIENTWRITE_BODY,
    612                                  tmpLine, sshc->readdir_len + 1);
    613       free(tmpLine);
    614 
    615       if(result) {
    616         myssh_to(data, sshc, SSH_STOP);
    617         return SSH_NO_ERROR;
    618       }
    619 
    620     }
    621     else {
    622       if(curlx_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
    623         sshc->actualcode = CURLE_OUT_OF_MEMORY;
    624         myssh_to(data, sshc, SSH_STOP);
    625         return SSH_ERROR;
    626       }
    627 
    628       if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
    629          ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
    630           SSH_S_IFLNK)) {
    631         sshc->readdir_linkPath = aprintf("%s%s", sshp->path,
    632                                          sshc->readdir_filename);
    633 
    634         if(!sshc->readdir_linkPath) {
    635           myssh_to(data, sshc, SSH_SFTP_CLOSE);
    636           sshc->actualcode = CURLE_OUT_OF_MEMORY;
    637           return SSH_ERROR;
    638         }
    639 
    640         myssh_to(data, sshc, SSH_SFTP_READDIR_LINK);
    641         return SSH_NO_ERROR;
    642       }
    643       myssh_to(data, sshc, SSH_SFTP_READDIR_BOTTOM);
    644       return SSH_NO_ERROR;
    645     }
    646   }
    647   else if(sftp_dir_eof(sshc->sftp_dir)) {
    648     myssh_to(data, sshc, SSH_SFTP_READDIR_DONE);
    649   }
    650   else {
    651     failf(data, "Could not open remote directory for reading: %s",
    652           ssh_get_error(sshc->ssh_session));
    653     return myssh_to_SFTP_CLOSE(data, sshc);
    654   }
    655   return SSH_NO_ERROR;
    656 }
    657 
    658 static int myssh_in_SFTP_READDIR_LINK(struct Curl_easy *data,
    659                                       struct ssh_conn *sshc)
    660 {
    661   if(sshc->readdir_link_attrs)
    662     sftp_attributes_free(sshc->readdir_link_attrs);
    663 
    664   sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
    665                                         sshc->readdir_linkPath);
    666   if(!sshc->readdir_link_attrs) {
    667     failf(data, "Could not read symlink for reading: %s",
    668           ssh_get_error(sshc->ssh_session));
    669     return myssh_to_SFTP_CLOSE(data, sshc);
    670   }
    671 
    672   if(!sshc->readdir_link_attrs->name) {
    673     sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
    674                                       sshc->readdir_linkPath);
    675     if(!sshc->readdir_tmp)
    676       sshc->readdir_len = 0;
    677     else
    678       sshc->readdir_len = strlen(sshc->readdir_tmp);
    679     sshc->readdir_longentry = NULL;
    680     sshc->readdir_filename = sshc->readdir_tmp;
    681   }
    682   else {
    683     sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
    684     sshc->readdir_filename = sshc->readdir_link_attrs->name;
    685     sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
    686   }
    687 
    688   Curl_safefree(sshc->readdir_linkPath);
    689 
    690   if(curlx_dyn_addf(&sshc->readdir_buf, " -> %s",
    691                     sshc->readdir_filename)) {
    692     /* Not using:
    693      * return myssh_to_SFTP_CLOSE(data, sshc);
    694      *
    695      * as that assumes an sftp related error while
    696      * assigning sshc->actualcode whereas the current
    697      * error is curlx_dyn_addf() related.
    698      */
    699     myssh_to(data, sshc, SSH_SFTP_CLOSE);
    700     sshc->actualcode = CURLE_OUT_OF_MEMORY;
    701     return SSH_ERROR;
    702   }
    703 
    704   sftp_attributes_free(sshc->readdir_link_attrs);
    705   sshc->readdir_link_attrs = NULL;
    706   sshc->readdir_filename = NULL;
    707   sshc->readdir_longentry = NULL;
    708 
    709   myssh_to(data, sshc, SSH_SFTP_READDIR_BOTTOM);
    710   return SSH_NO_ERROR;
    711 }
    712 
    713 static int myssh_in_SFTP_READDIR_BOTTOM(struct Curl_easy *data,
    714                                         struct ssh_conn *sshc)
    715 {
    716   CURLcode result;
    717 
    718   if(curlx_dyn_addn(&sshc->readdir_buf, "\n", 1))
    719     result = CURLE_OUT_OF_MEMORY;
    720   else
    721     result = Curl_client_write(data, CLIENTWRITE_BODY,
    722                                curlx_dyn_ptr(&sshc->readdir_buf),
    723                                curlx_dyn_len(&sshc->readdir_buf));
    724 
    725   ssh_string_free_char(sshc->readdir_tmp);
    726   sshc->readdir_tmp = NULL;
    727 
    728   if(result)
    729     myssh_to(data, sshc, SSH_STOP);
    730   else
    731     myssh_to(data, sshc, SSH_SFTP_READDIR);
    732   return SSH_NO_ERROR;
    733 }
    734 
    735 static int myssh_in_SFTP_READDIR_DONE(struct Curl_easy *data,
    736                                       struct ssh_conn *sshc)
    737 {
    738   sftp_closedir(sshc->sftp_dir);
    739   sshc->sftp_dir = NULL;
    740 
    741   /* no data to transfer */
    742   Curl_xfer_setup_nop(data);
    743   myssh_to(data, sshc, SSH_STOP);
    744   return SSH_NO_ERROR;
    745 }
    746 
    747 static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data,
    748                                        struct ssh_conn *sshc)
    749 {
    750   sftp_statvfs_t statvfs;
    751 
    752   statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
    753   if(!statvfs && !sshc->acceptfail) {
    754     Curl_safefree(sshc->quote_path1);
    755     failf(data, "statvfs command failed: %s",
    756           ssh_get_error(sshc->ssh_session));
    757     myssh_to(data, sshc, SSH_SFTP_CLOSE);
    758     sshc->nextstate = SSH_NO_STATE;
    759     sshc->actualcode = CURLE_QUOTE_ERROR;
    760     return SSH_OK;
    761   }
    762   else if(statvfs) {
    763     #ifdef _MSC_VER
    764     #define CURL_LIBSSH_VFS_SIZE_MASK "I64u"
    765     #else
    766     #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64
    767     #endif
    768     CURLcode result;
    769     char *tmp = aprintf("statvfs:\n"
    770                         "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    771                         "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    772                         "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    773                         "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    774                         "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    775                         "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    776                         "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    777                         "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    778                         "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    779                         "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
    780                         "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n",
    781                         statvfs->f_bsize, statvfs->f_frsize,
    782                         statvfs->f_blocks, statvfs->f_bfree,
    783                         statvfs->f_bavail, statvfs->f_files,
    784                         statvfs->f_ffree, statvfs->f_favail,
    785                         statvfs->f_fsid, statvfs->f_flag,
    786                         statvfs->f_namemax);
    787     sftp_statvfs_free(statvfs);
    788 
    789     if(!tmp) {
    790       myssh_to(data, sshc, SSH_SFTP_CLOSE);
    791       sshc->nextstate = SSH_NO_STATE;
    792       return SSH_OK;
    793     }
    794 
    795     result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
    796     free(tmp);
    797     if(result) {
    798       myssh_to(data, sshc, SSH_SFTP_CLOSE);
    799       sshc->nextstate = SSH_NO_STATE;
    800       sshc->actualcode = result;
    801     }
    802   }
    803   myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
    804   return SSH_OK;
    805 }
    806 
    807 static int myssh_auth_interactive(struct connectdata *conn,
    808                                   struct ssh_conn *sshc)
    809 {
    810   int rc;
    811   int nprompts;
    812 
    813 restart:
    814   switch(sshc->kbd_state) {
    815     case 0:
    816       rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
    817       if(rc == SSH_AUTH_AGAIN)
    818         return SSH_AGAIN;
    819 
    820       if(rc != SSH_AUTH_INFO)
    821         return SSH_ERROR;
    822 
    823       nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
    824       if(nprompts != 1)
    825         return SSH_ERROR;
    826 
    827       rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
    828       if(rc < 0)
    829         return SSH_ERROR;
    830 
    831       FALLTHROUGH();
    832     case 1:
    833       sshc->kbd_state = 1;
    834 
    835       rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
    836       if(rc == SSH_AUTH_AGAIN)
    837         return SSH_AGAIN;
    838       else if(rc == SSH_AUTH_SUCCESS)
    839         rc = SSH_OK;
    840       else if(rc == SSH_AUTH_INFO) {
    841         nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
    842         if(nprompts)
    843           return SSH_ERROR;
    844 
    845         sshc->kbd_state = 2;
    846         goto restart;
    847       }
    848       else
    849         rc = SSH_ERROR;
    850       break;
    851     case 2:
    852       sshc->kbd_state = 2;
    853 
    854       rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
    855       if(rc == SSH_AUTH_AGAIN)
    856         return SSH_AGAIN;
    857       else if(rc == SSH_AUTH_SUCCESS)
    858         rc = SSH_OK;
    859       else
    860         rc = SSH_ERROR;
    861 
    862       break;
    863     default:
    864       return SSH_ERROR;
    865   }
    866 
    867   sshc->kbd_state = 0;
    868   return rc;
    869 }
    870 
    871 static void myssh_state_init(struct Curl_easy *data,
    872                              struct ssh_conn *sshc)
    873 {
    874   sshc->secondCreateDirs = 0;
    875   sshc->nextstate = SSH_NO_STATE;
    876   sshc->actualcode = CURLE_OK;
    877 
    878 #if 0
    879   ssh_set_log_level(SSH_LOG_PROTOCOL);
    880 #endif
    881 
    882   /* Set libssh to non-blocking, since everything internally is
    883      non-blocking */
    884   ssh_set_blocking(sshc->ssh_session, 0);
    885 
    886   myssh_to(data, sshc, SSH_S_STARTUP);
    887 }
    888 
    889 static int myssh_in_S_STARTUP(struct Curl_easy *data,
    890                               struct ssh_conn *sshc)
    891 {
    892   struct connectdata *conn = data->conn;
    893   int rc = ssh_connect(sshc->ssh_session);
    894 
    895   myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN));
    896   if(rc == SSH_AGAIN) {
    897     DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
    898   }
    899   else if(rc != SSH_OK) {
    900     failf(data, "Failure establishing ssh session");
    901     rc = myssh_to_ERROR(data, sshc, CURLE_FAILED_INIT);
    902   }
    903   else
    904     myssh_to(data, sshc, SSH_HOSTKEY);
    905 
    906   return rc;
    907 }
    908 
    909 static int myssh_in_AUTHLIST(struct Curl_easy *data,
    910                              struct ssh_conn *sshc)
    911 {
    912   int rc;
    913   sshc->authed = FALSE;
    914 
    915   rc = ssh_userauth_none(sshc->ssh_session, NULL);
    916   if(rc == SSH_AUTH_AGAIN)
    917     return SSH_AGAIN;
    918 
    919   if(rc == SSH_AUTH_SUCCESS) {
    920     sshc->authed = TRUE;
    921     infof(data, "Authenticated with none");
    922     myssh_to(data, sshc, SSH_AUTH_DONE);
    923     return rc;
    924   }
    925   else if(rc == SSH_AUTH_ERROR) {
    926     rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
    927     return rc;
    928   }
    929 
    930   sshc->auth_methods =
    931     (unsigned int)ssh_userauth_list(sshc->ssh_session, NULL);
    932   if(sshc->auth_methods)
    933     infof(data, "SSH authentication methods available: %s%s%s%s",
    934           sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
    935           "public key, ": "",
    936           sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
    937           "GSSAPI, " : "",
    938           sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?
    939           "keyboard-interactive, " : "",
    940           sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
    941           "password": "");
    942   if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
    943     myssh_to(data, sshc, SSH_AUTH_PKEY_INIT);
    944     infof(data, "Authentication using SSH public key file");
    945   }
    946   else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
    947     myssh_to(data, sshc, SSH_AUTH_GSSAPI);
    948   }
    949   else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
    950     myssh_to(data, sshc, SSH_AUTH_KEY_INIT);
    951   }
    952   else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
    953     myssh_to(data, sshc, SSH_AUTH_PASS_INIT);
    954   }
    955   else {                  /* unsupported authentication method */
    956     rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
    957   }
    958   return rc;
    959 }
    960 
    961 static int myssh_in_AUTH_PKEY_INIT(struct Curl_easy *data,
    962                                    struct ssh_conn *sshc)
    963 {
    964   int rc;
    965   if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
    966     rc = myssh_to_GSSAPI_AUTH(data, sshc);
    967     return rc;
    968   }
    969 
    970   /* Two choices, (1) private key was given on CMD,
    971    * (2) use the "default" keys. */
    972   if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
    973     if(sshc->pubkey && !data->set.ssl.key_passwd) {
    974       rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
    975                                       sshc->pubkey);
    976       if(rc == SSH_AUTH_AGAIN)
    977         return SSH_AGAIN;
    978 
    979       if(rc != SSH_OK) {
    980         rc = myssh_to_GSSAPI_AUTH(data, sshc);
    981         return rc;
    982       }
    983     }
    984 
    985     rc = ssh_pki_import_privkey_file(data->
    986                                      set.str[STRING_SSH_PRIVATE_KEY],
    987                                      data->set.ssl.key_passwd, NULL,
    988                                      NULL, &sshc->privkey);
    989     if(rc != SSH_OK) {
    990       failf(data, "Could not load private key file %s",
    991             data->set.str[STRING_SSH_PRIVATE_KEY]);
    992       rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
    993       return rc;
    994     }
    995 
    996     myssh_to(data, sshc, SSH_AUTH_PKEY);
    997   }
    998   else {
    999     rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
   1000                                          data->set.ssl.key_passwd);
   1001     if(rc == SSH_AUTH_AGAIN)
   1002       return SSH_AGAIN;
   1003 
   1004     if(rc == SSH_AUTH_SUCCESS) {
   1005       rc = SSH_OK;
   1006       sshc->authed = TRUE;
   1007       infof(data, "Completed public key authentication");
   1008       myssh_to(data, sshc, SSH_AUTH_DONE);
   1009       return rc;
   1010     }
   1011 
   1012     rc = myssh_to_GSSAPI_AUTH(data, sshc);
   1013   }
   1014   return rc;
   1015 }
   1016 
   1017 static int myssh_in_AUTH_PKEY(struct Curl_easy *data,
   1018                               struct ssh_conn *sshc)
   1019 {
   1020   int rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
   1021   if(rc == SSH_AUTH_AGAIN)
   1022     return SSH_AGAIN;
   1023   else if(rc == SSH_AUTH_SUCCESS) {
   1024     sshc->authed = TRUE;
   1025     infof(data, "Completed public key authentication");
   1026     myssh_to(data, sshc, SSH_AUTH_DONE);
   1027     return SSH_OK;
   1028   }
   1029   else {
   1030     infof(data, "Failed public key authentication (rc: %d)", rc);
   1031     return myssh_to_GSSAPI_AUTH(data, sshc);
   1032   }
   1033 }
   1034 
   1035 static int myssh_in_AUTH_GSSAPI(struct Curl_easy *data,
   1036                                 struct ssh_conn *sshc)
   1037 {
   1038   int rc;
   1039   if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI))
   1040     return myssh_to_KEY_AUTH(data, sshc);
   1041 
   1042   rc = ssh_userauth_gssapi(sshc->ssh_session);
   1043   if(rc == SSH_AUTH_AGAIN)
   1044     return SSH_AGAIN;
   1045 
   1046   if(rc == SSH_AUTH_SUCCESS) {
   1047     sshc->authed = TRUE;
   1048     infof(data, "Completed gssapi authentication");
   1049     myssh_to(data, sshc, SSH_AUTH_DONE);
   1050     return SSH_OK;
   1051   }
   1052 
   1053   return myssh_to_KEY_AUTH(data, sshc);
   1054 }
   1055 
   1056 static int myssh_in_AUTH_KEY_INIT(struct Curl_easy *data,
   1057                                   struct ssh_conn *sshc)
   1058 {
   1059   if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
   1060     myssh_to(data, sshc, SSH_AUTH_KEY);
   1061     return SSH_NO_ERROR;
   1062   }
   1063   return myssh_to_PASSWD_AUTH(data, sshc);
   1064 }
   1065 
   1066 static int myssh_in_AUTH_KEY(struct Curl_easy *data,
   1067                              struct ssh_conn *sshc)
   1068 {
   1069   /* keyboard-interactive authentication */
   1070   int rc = myssh_auth_interactive(data->conn, sshc);
   1071   if(rc == SSH_AGAIN)
   1072     return rc;
   1073   else if(rc == SSH_OK) {
   1074     sshc->authed = TRUE;
   1075     infof(data, "completed keyboard interactive authentication");
   1076     myssh_to(data, sshc, SSH_AUTH_DONE);
   1077     return SSH_NO_ERROR;
   1078   }
   1079   else
   1080     return myssh_to_PASSWD_AUTH(data, sshc);
   1081 }
   1082 
   1083 static int myssh_in_AUTH_PASS_INIT(struct Curl_easy *data,
   1084                                    struct ssh_conn *sshc)
   1085 {
   1086   if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD))
   1087     return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
   1088   myssh_to(data, sshc, SSH_AUTH_PASS);
   1089   return SSH_NO_ERROR;
   1090 }
   1091 
   1092 static int myssh_in_AUTH_PASS(struct Curl_easy *data,
   1093                               struct ssh_conn *sshc)
   1094 {
   1095   int rc = ssh_userauth_password(sshc->ssh_session, NULL, data->conn->passwd);
   1096   if(rc == SSH_AUTH_AGAIN)
   1097     return SSH_AGAIN;
   1098   else if(rc == SSH_AUTH_SUCCESS) {
   1099     sshc->authed = TRUE;
   1100     infof(data, "Completed password authentication");
   1101     myssh_to(data, sshc, SSH_AUTH_DONE);
   1102     return SSH_NO_ERROR;
   1103   }
   1104   return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
   1105 }
   1106 
   1107 static int myssh_in_AUTH_DONE(struct Curl_easy *data,
   1108                               struct ssh_conn *sshc)
   1109 {
   1110   if(!sshc->authed) {
   1111     failf(data, "Authentication failure");
   1112     return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
   1113   }
   1114 
   1115   /* At this point we have an authenticated ssh session. */
   1116   infof(data, "Authentication complete");
   1117   Curl_pgrsTime(data, TIMER_APPCONNECT);      /* SSH is connected */
   1118   data->conn->sockfd = data->conn->sock[FIRSTSOCKET];
   1119   data->conn->writesockfd = CURL_SOCKET_BAD;
   1120 
   1121   if(data->conn->handler->protocol == CURLPROTO_SFTP) {
   1122     myssh_to(data, sshc, SSH_SFTP_INIT);
   1123     return SSH_NO_ERROR;
   1124   }
   1125   infof(data, "SSH CONNECT phase done");
   1126   myssh_to(data, sshc, SSH_STOP);
   1127   return SSH_NO_ERROR;
   1128 }
   1129 
   1130 static int myssh_in_UPLOAD_INIT(struct Curl_easy *data,
   1131                                 struct ssh_conn *sshc,
   1132                                 struct SSHPROTO *sshp)
   1133 {
   1134   int flags;
   1135   int rc = 0;
   1136 
   1137   if(data->state.resume_from) {
   1138     sftp_attributes attrs;
   1139 
   1140     if(data->state.resume_from < 0) {
   1141       attrs = sftp_stat(sshc->sftp_session, sshp->path);
   1142       if(attrs) {
   1143         curl_off_t size = attrs->size;
   1144         if(size < 0) {
   1145           failf(data, "Bad file size (%" FMT_OFF_T ")", size);
   1146           rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
   1147           return rc;
   1148         }
   1149         data->state.resume_from = attrs->size;
   1150 
   1151         sftp_attributes_free(attrs);
   1152       }
   1153       else {
   1154         data->state.resume_from = 0;
   1155       }
   1156     }
   1157   }
   1158 
   1159   if(data->set.remote_append)
   1160     /* Try to open for append, but create if nonexisting */
   1161     flags = O_WRONLY|O_CREAT|O_APPEND;
   1162   else if(data->state.resume_from > 0)
   1163     /* If we have restart position then open for append */
   1164     flags = O_WRONLY|O_APPEND;
   1165   else
   1166     /* Clear file before writing (normal behavior) */
   1167     flags = O_WRONLY|O_CREAT|O_TRUNC;
   1168 
   1169   if(sshc->sftp_file)
   1170     sftp_close(sshc->sftp_file);
   1171   sshc->sftp_file =
   1172     sftp_open(sshc->sftp_session, sshp->path,
   1173               flags, (mode_t)data->set.new_file_perms);
   1174   if(!sshc->sftp_file) {
   1175     int err = sftp_get_error(sshc->sftp_session);
   1176 
   1177     if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
   1178          err == SSH_FX_NO_SUCH_PATH)) &&
   1179        (data->set.ftp_create_missing_dirs &&
   1180         (strlen(sshp->path) > 1))) {
   1181       /* try to create the path remotely */
   1182       rc = 0;
   1183       sshc->secondCreateDirs = 1;
   1184       myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS_INIT);
   1185       return rc;
   1186     }
   1187     else {
   1188       rc = myssh_to_SFTP_CLOSE(data, sshc);
   1189       return rc;
   1190     }
   1191   }
   1192 
   1193   /* If we have a restart point then we need to seek to the correct
   1194      position. */
   1195   if(data->state.resume_from > 0) {
   1196     int seekerr = CURL_SEEKFUNC_OK;
   1197     /* Let's read off the proper amount of bytes from the input. */
   1198     if(data->set.seek_func) {
   1199       Curl_set_in_callback(data, TRUE);
   1200       seekerr = data->set.seek_func(data->set.seek_client,
   1201                                     data->state.resume_from, SEEK_SET);
   1202       Curl_set_in_callback(data, FALSE);
   1203     }
   1204 
   1205     if(seekerr != CURL_SEEKFUNC_OK) {
   1206       curl_off_t passed = 0;
   1207 
   1208       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
   1209         failf(data, "Could not seek stream");
   1210         rc = myssh_to_ERROR(data, sshc, CURLE_FTP_COULDNT_USE_REST);
   1211         return rc;
   1212       }
   1213       /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
   1214       do {
   1215         char scratch[4*1024];
   1216         size_t readthisamountnow =
   1217           (data->state.resume_from - passed >
   1218            (curl_off_t)sizeof(scratch)) ?
   1219           sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
   1220 
   1221         size_t actuallyread =
   1222           data->state.fread_func(scratch, 1,
   1223                                  readthisamountnow, data->state.in);
   1224 
   1225         passed += actuallyread;
   1226         if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
   1227           /* this checks for greater-than only to make sure that the
   1228              CURL_READFUNC_ABORT return code still aborts */
   1229           failf(data, "Failed to read data");
   1230           rc = myssh_to_ERROR(data, sshc, CURLE_FTP_COULDNT_USE_REST);
   1231           return rc;
   1232         }
   1233       } while(passed < data->state.resume_from);
   1234     }
   1235 
   1236     /* now, decrease the size of the read */
   1237     if(data->state.infilesize > 0) {
   1238       data->state.infilesize -= data->state.resume_from;
   1239       data->req.size = data->state.infilesize;
   1240       Curl_pgrsSetUploadSize(data, data->state.infilesize);
   1241     }
   1242 
   1243     rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
   1244     if(rc) {
   1245       rc = myssh_to_SFTP_CLOSE(data, sshc);
   1246       return rc;
   1247     }
   1248   }
   1249   if(data->state.infilesize > 0) {
   1250     data->req.size = data->state.infilesize;
   1251     Curl_pgrsSetUploadSize(data, data->state.infilesize);
   1252   }
   1253   /* upload data */
   1254   Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
   1255 
   1256   /* not set by Curl_xfer_setup to preserve keepon bits */
   1257   data->conn->sockfd = data->conn->writesockfd;
   1258 
   1259   /* store this original bitmask setup to use later on if we cannot
   1260      figure out a "real" bitmask */
   1261   sshc->orig_waitfor = data->req.keepon;
   1262 
   1263   /* since we do not really wait for anything at this point, we want the
   1264      state machine to move on as soon as possible so we mark this as dirty */
   1265   Curl_multi_mark_dirty(data);
   1266 #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
   1267   sshc->sftp_send_state = 0;
   1268 #endif
   1269   myssh_to(data, sshc, SSH_STOP);
   1270   return rc;
   1271 }
   1272 
   1273 static int myssh_in_SFTP_DOWNLOAD_INIT(struct Curl_easy *data,
   1274                                        struct ssh_conn *sshc,
   1275                                        struct SSHPROTO *sshp)
   1276 {
   1277   /* Work on getting the specified file */
   1278   if(sshc->sftp_file)
   1279     sftp_close(sshc->sftp_file);
   1280 
   1281   sshc->sftp_file = sftp_open(sshc->sftp_session, sshp->path,
   1282                               O_RDONLY, (mode_t)data->set.new_file_perms);
   1283   if(!sshc->sftp_file) {
   1284     failf(data, "Could not open remote file for reading: %s",
   1285           ssh_get_error(sshc->ssh_session));
   1286 
   1287     return myssh_to_SFTP_CLOSE(data, sshc);
   1288   }
   1289   sftp_file_set_nonblocking(sshc->sftp_file);
   1290   myssh_to(data, sshc, SSH_SFTP_DOWNLOAD_STAT);
   1291   return SSH_NO_ERROR;
   1292 }
   1293 
   1294 static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data,
   1295                                        struct ssh_conn *sshc)
   1296 {
   1297   curl_off_t size;
   1298   int rc = 0;
   1299   sftp_attributes attrs = sftp_fstat(sshc->sftp_file);
   1300   if(!attrs ||
   1301      !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
   1302      (attrs->size == 0)) {
   1303     /*
   1304      * sftp_fstat did not return an error, so maybe the server
   1305      * just does not support stat()
   1306      * OR the server does not return a file size with a stat()
   1307      * OR file size is 0
   1308      */
   1309     data->req.size = -1;
   1310     data->req.maxdownload = -1;
   1311     Curl_pgrsSetDownloadSize(data, -1);
   1312     size = 0;
   1313     if(attrs)
   1314       sftp_attributes_free(attrs);
   1315   }
   1316   else {
   1317     size = attrs->size;
   1318 
   1319     sftp_attributes_free(attrs);
   1320 
   1321     if(size < 0) {
   1322       failf(data, "Bad file size (%" FMT_OFF_T ")", size);
   1323       rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
   1324       return rc;
   1325     }
   1326     if(data->state.use_range) {
   1327       curl_off_t from, to;
   1328       const char *p = data->state.range;
   1329       int from_t, to_t;
   1330 
   1331       from_t = curlx_str_number(&p, &from, CURL_OFF_T_MAX);
   1332       if(from_t == STRE_OVERFLOW) {
   1333         rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR);
   1334         return rc;
   1335       }
   1336       curlx_str_passblanks(&p);
   1337       (void)curlx_str_single(&p, '-');
   1338 
   1339       to_t = curlx_str_numblanks(&p, &to);
   1340       if(to_t == STRE_OVERFLOW)
   1341         return CURLE_RANGE_ERROR;
   1342 
   1343       if((to_t == STRE_NO_NUM) || (to >= size)) {
   1344         to = size - 1;
   1345         to_t = STRE_OK;
   1346       }
   1347 
   1348       if(from_t == STRE_NO_NUM) {
   1349         /* from is relative to end of file */
   1350         from = size - to;
   1351         to = size - 1;
   1352         from_t = STRE_OK;
   1353       }
   1354       if(from > size) {
   1355         failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
   1356               FMT_OFF_T ")", from, size);
   1357         rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
   1358         return rc;
   1359       }
   1360       if(from > to) {
   1361         from = to;
   1362         size = 0;
   1363       }
   1364       else {
   1365         if((to - from) == CURL_OFF_T_MAX) {
   1366           rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR);
   1367           return rc;
   1368         }
   1369         size = to - from + 1;
   1370       }
   1371 
   1372       rc = sftp_seek64(sshc->sftp_file, from);
   1373       if(rc) {
   1374         rc = myssh_to_SFTP_CLOSE(data, sshc);
   1375         return rc;
   1376       }
   1377     }
   1378     data->req.size = size;
   1379     data->req.maxdownload = size;
   1380     Curl_pgrsSetDownloadSize(data, size);
   1381   }
   1382 
   1383   /* We can resume if we can seek to the resume position */
   1384   if(data->state.resume_from) {
   1385     if(data->state.resume_from < 0) {
   1386       /* We are supposed to download the last abs(from) bytes */
   1387       if((curl_off_t)size < -data->state.resume_from) {
   1388         failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
   1389               FMT_OFF_T ")", data->state.resume_from, size);
   1390         rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
   1391         return rc;
   1392       }
   1393       /* download from where? */
   1394       data->state.resume_from += size;
   1395     }
   1396     else {
   1397       if((curl_off_t)size < data->state.resume_from) {
   1398         failf(data, "Offset (%" FMT_OFF_T
   1399               ") was beyond file size (%" FMT_OFF_T ")",
   1400               data->state.resume_from, size);
   1401         rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
   1402         return rc;
   1403       }
   1404     }
   1405     /* Now store the number of bytes we are expected to download */
   1406     data->req.size = size - data->state.resume_from;
   1407     data->req.maxdownload = size - data->state.resume_from;
   1408     Curl_pgrsSetDownloadSize(data,
   1409                              size - data->state.resume_from);
   1410 
   1411     rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
   1412     if(rc) {
   1413       rc = myssh_to_SFTP_CLOSE(data, sshc);
   1414       return rc;
   1415     }
   1416   }
   1417 
   1418   /* Setup the actual download */
   1419   if(data->req.size == 0) {
   1420     /* no data to transfer */
   1421     Curl_xfer_setup_nop(data);
   1422     infof(data, "File already completely downloaded");
   1423     myssh_to(data, sshc, SSH_STOP);
   1424     return rc;
   1425   }
   1426   Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
   1427 
   1428   /* not set by Curl_xfer_setup to preserve keepon bits */
   1429   data->conn->writesockfd = data->conn->sockfd;
   1430 
   1431   sshc->sftp_recv_state = 0;
   1432   myssh_to(data, sshc, SSH_STOP);
   1433 
   1434   return rc;
   1435 }
   1436 
   1437 static int myssh_in_SFTP_CLOSE(struct Curl_easy *data,
   1438                                struct ssh_conn *sshc,
   1439                                struct SSHPROTO *sshp)
   1440 {
   1441   if(sshc->sftp_file) {
   1442     sftp_close(sshc->sftp_file);
   1443     sshc->sftp_file = NULL;
   1444   }
   1445   Curl_safefree(sshp->path);
   1446 
   1447   DEBUGF(infof(data, "SFTP DONE done"));
   1448 
   1449   /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
   1450      After nextstate is executed, the control should come back to
   1451      SSH_SFTP_CLOSE to pass the correct result back  */
   1452   if(sshc->nextstate != SSH_NO_STATE &&
   1453      sshc->nextstate != SSH_SFTP_CLOSE) {
   1454     myssh_to(data, sshc, sshc->nextstate);
   1455     sshc->nextstate = SSH_SFTP_CLOSE;
   1456   }
   1457   else {
   1458     myssh_to(data, sshc, SSH_STOP);
   1459   }
   1460   return SSH_NO_ERROR;
   1461 }
   1462 
   1463 static int myssh_in_SFTP_SHUTDOWN(struct Curl_easy *data,
   1464                                   struct ssh_conn *sshc)
   1465 {
   1466   /* during times we get here due to a broken transfer and then the
   1467      sftp_handle might not have been taken down so make sure that is done
   1468      before we proceed */
   1469   ssh_set_blocking(sshc->ssh_session, 0);
   1470 #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
   1471   if(sshc->sftp_aio) {
   1472     sftp_aio_free(sshc->sftp_aio);
   1473     sshc->sftp_aio = NULL;
   1474   }
   1475 #endif
   1476 
   1477   if(sshc->sftp_file) {
   1478     sftp_close(sshc->sftp_file);
   1479     sshc->sftp_file = NULL;
   1480   }
   1481 
   1482   if(sshc->sftp_session) {
   1483     sftp_free(sshc->sftp_session);
   1484     sshc->sftp_session = NULL;
   1485   }
   1486 
   1487   SSH_STRING_FREE_CHAR(sshc->homedir);
   1488 
   1489   myssh_to(data, sshc, SSH_SESSION_DISCONNECT);
   1490   return SSH_NO_ERROR;
   1491 }
   1492 
   1493 static int myssh_in_SFTP_INIT(struct Curl_easy *data,
   1494                               struct ssh_conn *sshc)
   1495 {
   1496   int rc;
   1497   ssh_set_blocking(sshc->ssh_session, 1);
   1498 
   1499   sshc->sftp_session = sftp_new(sshc->ssh_session);
   1500   if(!sshc->sftp_session) {
   1501     failf(data, "Failure initializing sftp session: %s",
   1502           ssh_get_error(sshc->ssh_session));
   1503     return myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT);
   1504   }
   1505 
   1506   rc = sftp_init(sshc->sftp_session);
   1507   if(rc != SSH_OK) {
   1508     failf(data, "Failure initializing sftp session: %s",
   1509           ssh_get_error(sshc->ssh_session));
   1510     return myssh_to_ERROR(data, sshc, sftp_error_to_CURLE(SSH_FX_FAILURE));
   1511   }
   1512   myssh_to(data, sshc, SSH_SFTP_REALPATH);
   1513   return SSH_NO_ERROR;
   1514 }
   1515 
   1516 static int myssh_in_SFTP_REALPATH(struct Curl_easy *data,
   1517                                   struct ssh_conn *sshc)
   1518 {
   1519   /* Get the "home" directory */
   1520   sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
   1521   if(!sshc->homedir)
   1522     return myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT);
   1523 
   1524   free(data->state.most_recent_ftp_entrypath);
   1525   data->state.most_recent_ftp_entrypath = strdup(sshc->homedir);
   1526   if(!data->state.most_recent_ftp_entrypath)
   1527     return myssh_to_ERROR(data, sshc, CURLE_OUT_OF_MEMORY);
   1528 
   1529   /* This is the last step in the SFTP connect phase. Do note that while
   1530      we get the homedir here, we get the "workingpath" in the DO action
   1531      since the homedir will remain the same between request but the
   1532      working path will not. */
   1533   DEBUGF(infof(data, "SSH CONNECT phase done"));
   1534   myssh_to(data, sshc, SSH_STOP);
   1535   return SSH_NO_ERROR;
   1536 }
   1537 
   1538 static int myssh_in_SFTP_QUOTE_INIT(struct Curl_easy *data,
   1539                                     struct ssh_conn *sshc,
   1540                                     struct SSHPROTO *sshp)
   1541 {
   1542   CURLcode result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
   1543   if(result) {
   1544     sshc->actualcode = result;
   1545     myssh_to(data, sshc, SSH_STOP);
   1546   }
   1547   else if(data->set.quote) {
   1548     infof(data, "Sending quote commands");
   1549     sshc->quote_item = data->set.quote;
   1550     myssh_to(data, sshc, SSH_SFTP_QUOTE);
   1551   }
   1552   else
   1553     myssh_to(data, sshc, SSH_SFTP_GETINFO);
   1554   return SSH_NO_ERROR;
   1555 }
   1556 
   1557 static int myssh_in_SFTP_POSTQUOTE_INIT(struct Curl_easy *data,
   1558                                         struct ssh_conn *sshc)
   1559 {
   1560   if(data->set.postquote) {
   1561     infof(data, "Sending quote commands");
   1562     sshc->quote_item = data->set.postquote;
   1563     myssh_to(data, sshc, SSH_SFTP_QUOTE);
   1564   }
   1565   else {
   1566     myssh_to(data, sshc, SSH_STOP);
   1567   }
   1568   return SSH_NO_ERROR;
   1569 }
   1570 
   1571 static int myssh_in_SFTP_QUOTE(struct Curl_easy *data,
   1572                                struct ssh_conn *sshc,
   1573                                struct SSHPROTO *sshp)
   1574 {
   1575   const char *cp;
   1576   CURLcode result;
   1577 
   1578   /*
   1579    * Support some of the "FTP" commands
   1580    */
   1581   char *cmd = sshc->quote_item->data;
   1582   sshc->acceptfail = FALSE;
   1583 
   1584   /* if a command starts with an asterisk, which a legal SFTP command never
   1585      can, the command will be allowed to fail without it causing any
   1586      aborts or cancels etc. It will cause libcurl to act as if the command
   1587      is successful, whatever the server responds. */
   1588 
   1589   if(cmd[0] == '*') {
   1590     cmd++;
   1591     sshc->acceptfail = TRUE;
   1592   }
   1593 
   1594   if(curl_strequal("pwd", cmd)) {
   1595     /* output debug output if that is requested */
   1596     char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path);
   1597     if(!tmp) {
   1598       sshc->actualcode = CURLE_OUT_OF_MEMORY;
   1599       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1600       sshc->nextstate = SSH_NO_STATE;
   1601       return SSH_NO_ERROR;
   1602     }
   1603     Curl_debug(data, CURLINFO_HEADER_OUT, "PWD\n", 4);
   1604     Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
   1605 
   1606     /* this sends an FTP-like "header" to the header callback so that the
   1607        current directory can be read very similar to how it is read when
   1608        using ordinary FTP. */
   1609     result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
   1610     free(tmp);
   1611     if(result) {
   1612       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1613       sshc->nextstate = SSH_NO_STATE;
   1614       sshc->actualcode = result;
   1615     }
   1616     else
   1617       myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
   1618     return SSH_NO_ERROR;
   1619   }
   1620 
   1621   /*
   1622    * the arguments following the command must be separated from the
   1623    * command with a space so we can check for it unconditionally
   1624    */
   1625   cp = strchr(cmd, ' ');
   1626   if(!cp) {
   1627     failf(data, "Syntax error in SFTP command. Supply parameter(s)");
   1628     myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1629     sshc->nextstate = SSH_NO_STATE;
   1630     sshc->actualcode = CURLE_QUOTE_ERROR;
   1631     return SSH_NO_ERROR;
   1632   }
   1633 
   1634   /*
   1635    * also, every command takes at least one argument so we get that
   1636    * first argument right now
   1637    */
   1638   result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
   1639   if(result) {
   1640     if(result == CURLE_OUT_OF_MEMORY)
   1641       failf(data, "Out of memory");
   1642     else
   1643       failf(data, "Syntax error: Bad first parameter");
   1644     myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1645     sshc->nextstate = SSH_NO_STATE;
   1646     sshc->actualcode = result;
   1647     return SSH_NO_ERROR;
   1648   }
   1649 
   1650   /*
   1651    * SFTP is a binary protocol, so we do not send text commands
   1652    * to the server. Instead, we scan for commands used by
   1653    * OpenSSH's sftp program and call the appropriate libssh
   1654    * functions.
   1655    */
   1656   if(!strncmp(cmd, "chgrp ", 6) ||
   1657      !strncmp(cmd, "chmod ", 6) ||
   1658      !strncmp(cmd, "chown ", 6) ||
   1659      !strncmp(cmd, "atime ", 6) ||
   1660      !strncmp(cmd, "mtime ", 6)) {
   1661     /* attribute change */
   1662 
   1663     /* sshc->quote_path1 contains the mode to set */
   1664     /* get the destination */
   1665     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
   1666     if(result) {
   1667       if(result == CURLE_OUT_OF_MEMORY)
   1668         failf(data, "Out of memory");
   1669       else
   1670         failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
   1671               "Bad second parameter");
   1672       Curl_safefree(sshc->quote_path1);
   1673       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1674       sshc->nextstate = SSH_NO_STATE;
   1675       sshc->actualcode = result;
   1676       return SSH_NO_ERROR;
   1677     }
   1678     sshc->quote_attrs = NULL;
   1679     myssh_to(data, sshc, SSH_SFTP_QUOTE_STAT);
   1680     return SSH_NO_ERROR;
   1681   }
   1682   if(!strncmp(cmd, "ln ", 3) ||
   1683      !strncmp(cmd, "symlink ", 8)) {
   1684     /* symbolic linking */
   1685     /* sshc->quote_path1 is the source */
   1686     /* get the destination */
   1687     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
   1688     if(result) {
   1689       if(result == CURLE_OUT_OF_MEMORY)
   1690         failf(data, "Out of memory");
   1691       else
   1692         failf(data, "Syntax error in ln/symlink: Bad second parameter");
   1693       Curl_safefree(sshc->quote_path1);
   1694       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1695       sshc->nextstate = SSH_NO_STATE;
   1696       sshc->actualcode = result;
   1697       return SSH_NO_ERROR;
   1698     }
   1699     myssh_to(data, sshc, SSH_SFTP_QUOTE_SYMLINK);
   1700     return SSH_NO_ERROR;
   1701   }
   1702   else if(!strncmp(cmd, "mkdir ", 6)) {
   1703     /* create dir */
   1704     myssh_to(data, sshc, SSH_SFTP_QUOTE_MKDIR);
   1705     return SSH_NO_ERROR;
   1706   }
   1707   else if(!strncmp(cmd, "rename ", 7)) {
   1708     /* rename file */
   1709     /* first param is the source path */
   1710     /* second param is the dest. path */
   1711     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
   1712     if(result) {
   1713       if(result == CURLE_OUT_OF_MEMORY)
   1714         failf(data, "Out of memory");
   1715       else
   1716         failf(data, "Syntax error in rename: Bad second parameter");
   1717       Curl_safefree(sshc->quote_path1);
   1718       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1719       sshc->nextstate = SSH_NO_STATE;
   1720       sshc->actualcode = result;
   1721       return SSH_NO_ERROR;
   1722     }
   1723     myssh_to(data, sshc, SSH_SFTP_QUOTE_RENAME);
   1724     return SSH_NO_ERROR;
   1725   }
   1726   else if(!strncmp(cmd, "rmdir ", 6)) {
   1727     /* delete dir */
   1728     myssh_to(data, sshc, SSH_SFTP_QUOTE_RMDIR);
   1729     return SSH_NO_ERROR;
   1730   }
   1731   else if(!strncmp(cmd, "rm ", 3)) {
   1732     myssh_to(data, sshc, SSH_SFTP_QUOTE_UNLINK);
   1733     return SSH_NO_ERROR;
   1734   }
   1735 #ifdef HAS_STATVFS_SUPPORT
   1736   else if(!strncmp(cmd, "statvfs ", 8)) {
   1737     myssh_to(data, sshc, SSH_SFTP_QUOTE_STATVFS);
   1738     return SSH_NO_ERROR;
   1739   }
   1740 #endif
   1741 
   1742   failf(data, "Unknown SFTP command");
   1743   Curl_safefree(sshc->quote_path1);
   1744   Curl_safefree(sshc->quote_path2);
   1745   myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1746   sshc->nextstate = SSH_NO_STATE;
   1747   sshc->actualcode = CURLE_QUOTE_ERROR;
   1748   return SSH_NO_ERROR;
   1749 }
   1750 
   1751 static int myssh_in_SFTP_NEXT_QUOTE(struct Curl_easy *data,
   1752                                     struct ssh_conn *sshc)
   1753 {
   1754   Curl_safefree(sshc->quote_path1);
   1755   Curl_safefree(sshc->quote_path2);
   1756 
   1757   sshc->quote_item = sshc->quote_item->next;
   1758 
   1759   if(sshc->quote_item) {
   1760     myssh_to(data, sshc, SSH_SFTP_QUOTE);
   1761   }
   1762   else {
   1763     if(sshc->nextstate != SSH_NO_STATE) {
   1764       myssh_to(data, sshc, sshc->nextstate);
   1765       sshc->nextstate = SSH_NO_STATE;
   1766     }
   1767     else {
   1768       myssh_to(data, sshc, SSH_SFTP_GETINFO);
   1769     }
   1770   }
   1771   return SSH_NO_ERROR;
   1772 }
   1773 
   1774 static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data,
   1775                                     struct ssh_conn *sshc)
   1776 {
   1777   char *cmd = sshc->quote_item->data;
   1778   sshc->acceptfail = FALSE;
   1779 
   1780   /* if a command starts with an asterisk, which a legal SFTP command never
   1781      can, the command will be allowed to fail without it causing any
   1782      aborts or cancels etc. It will cause libcurl to act as if the command
   1783      is successful, whatever the server responds. */
   1784 
   1785   if(cmd[0] == '*') {
   1786     cmd++;
   1787     sshc->acceptfail = TRUE;
   1788   }
   1789 
   1790   /* We read the file attributes, store them in sshc->quote_attrs
   1791    * and modify them accordingly to command. Then we switch to
   1792    * QUOTE_SETSTAT state to write new ones.
   1793    */
   1794 
   1795   if(sshc->quote_attrs)
   1796     sftp_attributes_free(sshc->quote_attrs);
   1797   sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
   1798   if(!sshc->quote_attrs) {
   1799     Curl_safefree(sshc->quote_path1);
   1800     Curl_safefree(sshc->quote_path2);
   1801     failf(data, "Attempt to get SFTP stats failed: %d",
   1802           sftp_get_error(sshc->sftp_session));
   1803     myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1804     sshc->nextstate = SSH_NO_STATE;
   1805     sshc->actualcode = CURLE_QUOTE_ERROR;
   1806     return SSH_NO_ERROR;
   1807   }
   1808 
   1809   /* Now set the new attributes... */
   1810   if(!strncmp(cmd, "chgrp", 5)) {
   1811     const char *p = sshc->quote_path1;
   1812     curl_off_t gid;
   1813     (void)curlx_str_number(&p, &gid, UINT_MAX);
   1814     sshc->quote_attrs->gid = (uint32_t)gid;
   1815     if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
   1816        !sshc->acceptfail) {
   1817       Curl_safefree(sshc->quote_path1);
   1818       Curl_safefree(sshc->quote_path2);
   1819       failf(data, "Syntax error: chgrp gid not a number");
   1820       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1821       sshc->nextstate = SSH_NO_STATE;
   1822       sshc->actualcode = CURLE_QUOTE_ERROR;
   1823       return SSH_NO_ERROR;
   1824     }
   1825     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
   1826   }
   1827   else if(!strncmp(cmd, "chmod", 5)) {
   1828     curl_off_t perms;
   1829     const char *p = sshc->quote_path1;
   1830     if(curlx_str_octal(&p, &perms, 07777)) {
   1831       Curl_safefree(sshc->quote_path1);
   1832       Curl_safefree(sshc->quote_path2);
   1833       failf(data, "Syntax error: chmod permissions not a number");
   1834       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1835       sshc->nextstate = SSH_NO_STATE;
   1836       sshc->actualcode = CURLE_QUOTE_ERROR;
   1837       return SSH_NO_ERROR;
   1838     }
   1839     sshc->quote_attrs->permissions = (mode_t)perms;
   1840     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
   1841   }
   1842   else if(!strncmp(cmd, "chown", 5)) {
   1843     const char *p = sshc->quote_path1;
   1844     curl_off_t uid;
   1845     (void)curlx_str_number(&p, &uid, UINT_MAX);
   1846     if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
   1847        !sshc->acceptfail) {
   1848       Curl_safefree(sshc->quote_path1);
   1849       Curl_safefree(sshc->quote_path2);
   1850       failf(data, "Syntax error: chown uid not a number");
   1851       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1852       sshc->nextstate = SSH_NO_STATE;
   1853       sshc->actualcode = CURLE_QUOTE_ERROR;
   1854       return SSH_NO_ERROR;
   1855     }
   1856     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
   1857   }
   1858   else if(!strncmp(cmd, "atime", 5) ||
   1859           !strncmp(cmd, "mtime", 5)) {
   1860     time_t date = Curl_getdate_capped(sshc->quote_path1);
   1861     bool fail = FALSE;
   1862     if(date == -1) {
   1863       failf(data, "incorrect date format for %.*s", 5, cmd);
   1864       fail = TRUE;
   1865     }
   1866 #if SIZEOF_TIME_T > 4
   1867     else if(date > 0xffffffff) {
   1868       failf(data, "date overflow");
   1869       fail = TRUE; /* avoid setting a capped time */
   1870     }
   1871 #endif
   1872     if(fail) {
   1873       Curl_safefree(sshc->quote_path1);
   1874       Curl_safefree(sshc->quote_path2);
   1875       myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1876       sshc->nextstate = SSH_NO_STATE;
   1877       sshc->actualcode = CURLE_QUOTE_ERROR;
   1878       return SSH_NO_ERROR;
   1879     }
   1880     if(!strncmp(cmd, "atime", 5))
   1881       sshc->quote_attrs->atime = (uint32_t)date;
   1882     else /* mtime */
   1883       sshc->quote_attrs->mtime = (uint32_t)date;
   1884 
   1885     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
   1886   }
   1887 
   1888   /* Now send the completed structure... */
   1889   myssh_to(data, sshc, SSH_SFTP_QUOTE_SETSTAT);
   1890   return SSH_NO_ERROR;
   1891 }
   1892 
   1893 /*
   1894  * ssh_statemach_act() runs the SSH state machine as far as it can without
   1895  * blocking and without reaching the end. The data the pointer 'block' points
   1896  * to will be set to TRUE if the libssh function returns SSH_AGAIN
   1897  * meaning it wants to be called again when the socket is ready
   1898  */
   1899 static CURLcode myssh_statemach_act(struct Curl_easy *data,
   1900                                     struct ssh_conn *sshc,
   1901                                     struct SSHPROTO *sshp,
   1902                                     bool *block)
   1903 {
   1904   CURLcode result = CURLE_OK;
   1905   struct connectdata *conn = data->conn;
   1906   int rc = SSH_NO_ERROR, err;
   1907   const char *err_msg;
   1908 
   1909   *block = FALSE;                   /* we are not blocking by default */
   1910   do {
   1911 
   1912     switch(sshc->state) {
   1913     case SSH_INIT:
   1914       myssh_state_init(data, sshc);
   1915       FALLTHROUGH();
   1916     case SSH_S_STARTUP:
   1917       rc = myssh_in_S_STARTUP(data, sshc);
   1918       if(rc)
   1919         break;
   1920       FALLTHROUGH();
   1921     case SSH_HOSTKEY:
   1922       rc = myssh_is_known(data, sshc);
   1923       if(rc != SSH_OK) {
   1924         rc = myssh_to_ERROR(data, sshc, CURLE_PEER_FAILED_VERIFICATION);
   1925         break;
   1926       }
   1927       myssh_to(data, sshc, SSH_AUTHLIST);
   1928       FALLTHROUGH();
   1929     case SSH_AUTHLIST:
   1930       rc = myssh_in_AUTHLIST(data, sshc);
   1931       break;
   1932     case SSH_AUTH_PKEY_INIT:
   1933       rc = myssh_in_AUTH_PKEY_INIT(data, sshc);
   1934       break;
   1935     case SSH_AUTH_PKEY:
   1936       rc = myssh_in_AUTH_PKEY(data, sshc);
   1937       break;
   1938     case SSH_AUTH_GSSAPI:
   1939       rc = myssh_in_AUTH_GSSAPI(data, sshc);
   1940       break;
   1941     case SSH_AUTH_KEY_INIT:
   1942       rc = myssh_in_AUTH_KEY_INIT(data, sshc);
   1943       break;
   1944     case SSH_AUTH_KEY:
   1945       rc = myssh_in_AUTH_KEY(data, sshc);
   1946       break;
   1947     case SSH_AUTH_PASS_INIT:
   1948       rc = myssh_in_AUTH_PASS_INIT(data, sshc);
   1949       break;
   1950     case SSH_AUTH_PASS:
   1951       rc = myssh_in_AUTH_PASS(data, sshc);
   1952       break;
   1953     case SSH_AUTH_DONE:
   1954       rc = myssh_in_AUTH_DONE(data, sshc);
   1955       break;
   1956     case SSH_SFTP_INIT:
   1957       rc = myssh_in_SFTP_INIT(data, sshc);
   1958       break;
   1959     case SSH_SFTP_REALPATH:
   1960       rc = myssh_in_SFTP_REALPATH(data, sshc);
   1961       break;
   1962     case SSH_SFTP_QUOTE_INIT:
   1963       rc = myssh_in_SFTP_QUOTE_INIT(data, sshc, sshp);
   1964       break;
   1965     case SSH_SFTP_POSTQUOTE_INIT:
   1966       rc = myssh_in_SFTP_POSTQUOTE_INIT(data, sshc);
   1967       break;
   1968     case SSH_SFTP_QUOTE:
   1969       rc = myssh_in_SFTP_QUOTE(data, sshc, sshp);
   1970       break;
   1971     case SSH_SFTP_NEXT_QUOTE:
   1972       rc = myssh_in_SFTP_NEXT_QUOTE(data, sshc);
   1973       break;
   1974     case SSH_SFTP_QUOTE_STAT:
   1975       rc = myssh_in_SFTP_QUOTE_STAT(data, sshc);
   1976       break;
   1977 
   1978     case SSH_SFTP_QUOTE_SETSTAT:
   1979       rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
   1980                         sshc->quote_attrs);
   1981       if(rc && !sshc->acceptfail) {
   1982         Curl_safefree(sshc->quote_path1);
   1983         Curl_safefree(sshc->quote_path2);
   1984         failf(data, "Attempt to set SFTP stats failed: %s",
   1985               ssh_get_error(sshc->ssh_session));
   1986         myssh_to(data, sshc, SSH_SFTP_CLOSE);
   1987         sshc->nextstate = SSH_NO_STATE;
   1988         sshc->actualcode = CURLE_QUOTE_ERROR;
   1989         /* sshc->actualcode = sftp_error_to_CURLE(err);
   1990          * we do not send the actual error; we return
   1991          * the error the libssh2 backend is returning */
   1992         break;
   1993       }
   1994       myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
   1995       break;
   1996 
   1997     case SSH_SFTP_QUOTE_SYMLINK:
   1998       rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
   1999                         sshc->quote_path1);
   2000       if(rc && !sshc->acceptfail) {
   2001         Curl_safefree(sshc->quote_path1);
   2002         Curl_safefree(sshc->quote_path2);
   2003         failf(data, "symlink command failed: %s",
   2004               ssh_get_error(sshc->ssh_session));
   2005         myssh_to(data, sshc, SSH_SFTP_CLOSE);
   2006         sshc->nextstate = SSH_NO_STATE;
   2007         sshc->actualcode = CURLE_QUOTE_ERROR;
   2008         break;
   2009       }
   2010       myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
   2011       break;
   2012 
   2013     case SSH_SFTP_QUOTE_MKDIR:
   2014       rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
   2015                       (mode_t)data->set.new_directory_perms);
   2016       if(rc && !sshc->acceptfail) {
   2017         Curl_safefree(sshc->quote_path1);
   2018         failf(data, "mkdir command failed: %s",
   2019               ssh_get_error(sshc->ssh_session));
   2020         myssh_to(data, sshc, SSH_SFTP_CLOSE);
   2021         sshc->nextstate = SSH_NO_STATE;
   2022         sshc->actualcode = CURLE_QUOTE_ERROR;
   2023         break;
   2024       }
   2025       myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
   2026       break;
   2027 
   2028     case SSH_SFTP_QUOTE_RENAME:
   2029       rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
   2030                        sshc->quote_path2);
   2031       if(rc && !sshc->acceptfail) {
   2032         Curl_safefree(sshc->quote_path1);
   2033         Curl_safefree(sshc->quote_path2);
   2034         failf(data, "rename command failed: %s",
   2035               ssh_get_error(sshc->ssh_session));
   2036         myssh_to(data, sshc, SSH_SFTP_CLOSE);
   2037         sshc->nextstate = SSH_NO_STATE;
   2038         sshc->actualcode = CURLE_QUOTE_ERROR;
   2039         break;
   2040       }
   2041       myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
   2042       break;
   2043 
   2044     case SSH_SFTP_QUOTE_RMDIR:
   2045       rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
   2046       if(rc && !sshc->acceptfail) {
   2047         Curl_safefree(sshc->quote_path1);
   2048         failf(data, "rmdir command failed: %s",
   2049               ssh_get_error(sshc->ssh_session));
   2050         myssh_to(data, sshc, SSH_SFTP_CLOSE);
   2051         sshc->nextstate = SSH_NO_STATE;
   2052         sshc->actualcode = CURLE_QUOTE_ERROR;
   2053         break;
   2054       }
   2055       myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
   2056       break;
   2057 
   2058     case SSH_SFTP_QUOTE_UNLINK:
   2059       rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
   2060       if(rc && !sshc->acceptfail) {
   2061         Curl_safefree(sshc->quote_path1);
   2062         failf(data, "rm command failed: %s",
   2063               ssh_get_error(sshc->ssh_session));
   2064         myssh_to(data, sshc, SSH_SFTP_CLOSE);
   2065         sshc->nextstate = SSH_NO_STATE;
   2066         sshc->actualcode = CURLE_QUOTE_ERROR;
   2067         break;
   2068       }
   2069       myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
   2070       break;
   2071 
   2072     case SSH_SFTP_QUOTE_STATVFS:
   2073       rc = myssh_in_SFTP_QUOTE_STATVFS(data, sshc);
   2074       break;
   2075 
   2076     case SSH_SFTP_GETINFO:
   2077       if(data->set.get_filetime) {
   2078         myssh_to(data, sshc, SSH_SFTP_FILETIME);
   2079       }
   2080       else {
   2081         myssh_to(data, sshc, SSH_SFTP_TRANS_INIT);
   2082       }
   2083       break;
   2084 
   2085     case SSH_SFTP_FILETIME: {
   2086       sftp_attributes attrs;
   2087 
   2088       attrs = sftp_stat(sshc->sftp_session, sshp->path);
   2089       if(attrs) {
   2090         data->info.filetime = attrs->mtime;
   2091         sftp_attributes_free(attrs);
   2092       }
   2093 
   2094       myssh_to(data, sshc, SSH_SFTP_TRANS_INIT);
   2095       break;
   2096     }
   2097 
   2098     case SSH_SFTP_TRANS_INIT:
   2099       if(data->state.upload)
   2100         myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT);
   2101       else {
   2102         if(sshp->path[strlen(sshp->path)-1] == '/')
   2103           myssh_to(data, sshc, SSH_SFTP_READDIR_INIT);
   2104         else
   2105           myssh_to(data, sshc, SSH_SFTP_DOWNLOAD_INIT);
   2106       }
   2107       break;
   2108 
   2109     case SSH_SFTP_UPLOAD_INIT:
   2110       rc = myssh_in_UPLOAD_INIT(data, sshc, sshp);
   2111       break;
   2112 
   2113     case SSH_SFTP_CREATE_DIRS_INIT:
   2114       if(strlen(sshp->path) > 1) {
   2115         sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
   2116         myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS);
   2117       }
   2118       else {
   2119         myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT);
   2120       }
   2121       break;
   2122 
   2123     case SSH_SFTP_CREATE_DIRS:
   2124       sshc->slash_pos = strchr(sshc->slash_pos, '/');
   2125       if(sshc->slash_pos) {
   2126         *sshc->slash_pos = 0;
   2127 
   2128         infof(data, "Creating directory '%s'", sshp->path);
   2129         myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR);
   2130         break;
   2131       }
   2132       myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT);
   2133       break;
   2134 
   2135     case SSH_SFTP_CREATE_DIRS_MKDIR:
   2136       /* 'mode' - parameter is preliminary - default to 0644 */
   2137       rc = sftp_mkdir(sshc->sftp_session, sshp->path,
   2138                       (mode_t)data->set.new_directory_perms);
   2139       *sshc->slash_pos = '/';
   2140       ++sshc->slash_pos;
   2141       if(rc < 0) {
   2142         /*
   2143          * Abort if failure was not that the dir already exists or the
   2144          * permission was denied (creation might succeed further down the
   2145          * path) - retry on unspecific FAILURE also
   2146          */
   2147         err = sftp_get_error(sshc->sftp_session);
   2148         if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
   2149            (err != SSH_FX_FAILURE) &&
   2150            (err != SSH_FX_PERMISSION_DENIED)) {
   2151           rc = myssh_to_SFTP_CLOSE(data, sshc);
   2152           break;
   2153         }
   2154         rc = 0; /* clear rc and continue */
   2155       }
   2156       myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS);
   2157       break;
   2158 
   2159     case SSH_SFTP_READDIR_INIT:
   2160       rc = myssh_in_SFTP_READDIR_INIT(data, sshc, sshp);
   2161       break;
   2162     case SSH_SFTP_READDIR:
   2163       rc = myssh_in_SFTP_READDIR(data, sshc, sshp);
   2164       break;
   2165     case SSH_SFTP_READDIR_LINK:
   2166       rc = myssh_in_SFTP_READDIR_LINK(data, sshc);
   2167       break;
   2168     case SSH_SFTP_READDIR_BOTTOM:
   2169       rc = myssh_in_SFTP_READDIR_BOTTOM(data, sshc);
   2170       break;
   2171     case SSH_SFTP_READDIR_DONE:
   2172       rc = myssh_in_SFTP_READDIR_DONE(data, sshc);
   2173       break;
   2174     case SSH_SFTP_DOWNLOAD_INIT:
   2175       rc = myssh_in_SFTP_DOWNLOAD_INIT(data, sshc, sshp);
   2176       break;
   2177     case SSH_SFTP_DOWNLOAD_STAT:
   2178       rc = myssh_in_SFTP_DOWNLOAD_STAT(data, sshc);
   2179       break;
   2180     case SSH_SFTP_CLOSE:
   2181       rc = myssh_in_SFTP_CLOSE(data, sshc, sshp);
   2182       break;
   2183     case SSH_SFTP_SHUTDOWN:
   2184       rc = myssh_in_SFTP_SHUTDOWN(data, sshc);
   2185       break;
   2186 
   2187     case SSH_SCP_TRANS_INIT:
   2188       result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
   2189       if(result) {
   2190         sshc->actualcode = result;
   2191         myssh_to(data, sshc, SSH_STOP);
   2192         break;
   2193       }
   2194 
   2195       /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
   2196       ssh_set_blocking(sshc->ssh_session, 1);
   2197 
   2198       if(data->state.upload) {
   2199         if(data->state.infilesize < 0) {
   2200           failf(data, "SCP requires a known file size for upload");
   2201           sshc->actualcode = CURLE_UPLOAD_FAILED;
   2202           rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
   2203           break;
   2204         }
   2205 
   2206         sshc->scp_session =
   2207           ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, sshp->path);
   2208         myssh_to(data, sshc, SSH_SCP_UPLOAD_INIT);
   2209       }
   2210       else {
   2211         sshc->scp_session =
   2212           ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, sshp->path);
   2213         myssh_to(data, sshc, SSH_SCP_DOWNLOAD_INIT);
   2214       }
   2215 
   2216       if(!sshc->scp_session) {
   2217         err_msg = ssh_get_error(sshc->ssh_session);
   2218         failf(data, "%s", err_msg);
   2219         rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
   2220       }
   2221       break;
   2222 
   2223     case SSH_SCP_UPLOAD_INIT:
   2224 
   2225       rc = ssh_scp_init(sshc->scp_session);
   2226       if(rc != SSH_OK) {
   2227         err_msg = ssh_get_error(sshc->ssh_session);
   2228         failf(data, "%s", err_msg);
   2229         rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
   2230         break;
   2231       }
   2232 
   2233       rc = ssh_scp_push_file64(sshc->scp_session, sshp->path,
   2234                                (uint64_t)data->state.infilesize,
   2235                                (int)data->set.new_file_perms);
   2236 
   2237       if(rc != SSH_OK) {
   2238         err_msg = ssh_get_error(sshc->ssh_session);
   2239         failf(data, "%s", err_msg);
   2240         rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
   2241         break;
   2242       }
   2243 
   2244       /* upload data */
   2245       Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
   2246 
   2247       /* not set by Curl_xfer_setup to preserve keepon bits */
   2248       conn->sockfd = conn->writesockfd;
   2249 
   2250       /* store this original bitmask setup to use later on if we cannot
   2251          figure out a "real" bitmask */
   2252       sshc->orig_waitfor = data->req.keepon;
   2253 
   2254       myssh_to(data, sshc, SSH_STOP);
   2255 
   2256       break;
   2257 
   2258     case SSH_SCP_DOWNLOAD_INIT:
   2259 
   2260       rc = ssh_scp_init(sshc->scp_session);
   2261       if(rc != SSH_OK) {
   2262         err_msg = ssh_get_error(sshc->ssh_session);
   2263         failf(data, "%s", err_msg);
   2264         rc = myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT);
   2265         break;
   2266       }
   2267       myssh_to(data, sshc, SSH_SCP_DOWNLOAD);
   2268       FALLTHROUGH();
   2269 
   2270     case SSH_SCP_DOWNLOAD: {
   2271         curl_off_t bytecount;
   2272 
   2273         rc = ssh_scp_pull_request(sshc->scp_session);
   2274         if(rc != SSH_SCP_REQUEST_NEWFILE) {
   2275           err_msg = ssh_get_error(sshc->ssh_session);
   2276           failf(data, "%s", err_msg);
   2277           rc = myssh_to_ERROR(data, sshc, CURLE_REMOTE_FILE_NOT_FOUND);
   2278           break;
   2279         }
   2280 
   2281         /* download data */
   2282         bytecount = ssh_scp_request_get_size(sshc->scp_session);
   2283         data->req.maxdownload = (curl_off_t) bytecount;
   2284         Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);
   2285 
   2286         /* not set by Curl_xfer_setup to preserve keepon bits */
   2287         conn->writesockfd = conn->sockfd;
   2288 
   2289         myssh_to(data, sshc, SSH_STOP);
   2290         break;
   2291     }
   2292     case SSH_SCP_DONE:
   2293       if(data->state.upload)
   2294         myssh_to(data, sshc, SSH_SCP_SEND_EOF);
   2295       else
   2296         myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE);
   2297       break;
   2298 
   2299     case SSH_SCP_SEND_EOF:
   2300       if(sshc->scp_session) {
   2301         rc = ssh_scp_close(sshc->scp_session);
   2302         if(rc == SSH_AGAIN) {
   2303           /* Currently the ssh_scp_close handles waiting for EOF in
   2304            * blocking way.
   2305            */
   2306           break;
   2307         }
   2308         if(rc != SSH_OK) {
   2309           infof(data, "Failed to close libssh scp channel: %s",
   2310                 ssh_get_error(sshc->ssh_session));
   2311         }
   2312       }
   2313 
   2314       myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE);
   2315       break;
   2316 
   2317     case SSH_SCP_CHANNEL_FREE:
   2318       if(sshc->scp_session) {
   2319         ssh_scp_free(sshc->scp_session);
   2320         sshc->scp_session = NULL;
   2321       }
   2322       DEBUGF(infof(data, "SCP DONE phase complete"));
   2323 
   2324       ssh_set_blocking(sshc->ssh_session, 0);
   2325 
   2326       myssh_to(data, sshc, SSH_SESSION_DISCONNECT);
   2327       FALLTHROUGH();
   2328 
   2329     case SSH_SESSION_DISCONNECT:
   2330       /* during weird times when we have been prematurely aborted, the channel
   2331          is still alive when we reach this state and we MUST kill the channel
   2332          properly first */
   2333       if(sshc->scp_session) {
   2334         ssh_scp_free(sshc->scp_session);
   2335         sshc->scp_session = NULL;
   2336       }
   2337 
   2338       if(sshc->sftp_file) {
   2339         sftp_close(sshc->sftp_file);
   2340         sshc->sftp_file = NULL;
   2341       }
   2342       if(sshc->sftp_session) {
   2343         sftp_free(sshc->sftp_session);
   2344         sshc->sftp_session = NULL;
   2345       }
   2346 
   2347       ssh_disconnect(sshc->ssh_session);
   2348       if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
   2349         /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
   2350            tell the connection to forget about it. This libssh
   2351            bug is fixed in 0.10.0. */
   2352         Curl_conn_forget_socket(data, FIRSTSOCKET);
   2353       }
   2354 
   2355       SSH_STRING_FREE_CHAR(sshc->homedir);
   2356 
   2357       myssh_to(data, sshc, SSH_SESSION_FREE);
   2358       FALLTHROUGH();
   2359     case SSH_SESSION_FREE:
   2360       sshc_cleanup(sshc);
   2361       /* the code we are about to return */
   2362       result = sshc->actualcode;
   2363       memset(sshc, 0, sizeof(struct ssh_conn));
   2364       connclose(conn, "SSH session free");
   2365       sshc->state = SSH_SESSION_FREE;   /* current */
   2366       sshc->nextstate = SSH_NO_STATE;
   2367       myssh_to(data, sshc, SSH_STOP);
   2368       break;
   2369 
   2370     case SSH_QUIT:
   2371     default:
   2372       /* internal error */
   2373       sshc->nextstate = SSH_NO_STATE;
   2374       myssh_to(data, sshc, SSH_STOP);
   2375       break;
   2376 
   2377     }
   2378   } while(!rc && (sshc->state != SSH_STOP));
   2379 
   2380 
   2381   if(rc == SSH_AGAIN) {
   2382     /* we would block, we need to wait for the socket to be ready (in the
   2383        right direction too)! */
   2384     *block = TRUE;
   2385   }
   2386   if(!result && (sshc->state == SSH_STOP))
   2387     result = sshc->actualcode;
   2388   DEBUGF(infof(data, "SSH: myssh_statemach_act -> %d", result));
   2389   return result;
   2390 }
   2391 
   2392 
   2393 /* called by the multi interface to figure out what socket(s) to wait for and
   2394    for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
   2395 static int myssh_getsock(struct Curl_easy *data,
   2396                          struct connectdata *conn,
   2397                          curl_socket_t *sock)
   2398 {
   2399   int bitmap = GETSOCK_BLANK;
   2400   (void)data;
   2401   sock[0] = conn->sock[FIRSTSOCKET];
   2402 
   2403   if(conn->waitfor & KEEP_RECV)
   2404     bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
   2405 
   2406   if(conn->waitfor & KEEP_SEND)
   2407     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
   2408 
   2409   if(!conn->waitfor)
   2410     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
   2411 
   2412   DEBUGF(infof(data, "ssh_getsock -> %x", bitmap));
   2413   return bitmap;
   2414 }
   2415 
   2416 static void myssh_block2waitfor(struct connectdata *conn,
   2417                                 struct ssh_conn *sshc,
   2418                                 bool block)
   2419 {
   2420   /* If it did not block, or nothing was returned by ssh_get_poll_flags
   2421    * have the original set */
   2422   conn->waitfor = sshc->orig_waitfor;
   2423 
   2424   if(block) {
   2425     int dir = ssh_get_poll_flags(sshc->ssh_session);
   2426     conn->waitfor = 0;
   2427     /* translate the libssh define bits into our own bit defines */
   2428     if(dir & SSH_READ_PENDING)
   2429       conn->waitfor |= KEEP_RECV;
   2430     if(dir & SSH_WRITE_PENDING)
   2431       conn->waitfor |= KEEP_SEND;
   2432   }
   2433 }
   2434 
   2435 /* called repeatedly until done from multi.c */
   2436 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
   2437                                       bool *done)
   2438 {
   2439   struct connectdata *conn = data->conn;
   2440   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   2441   struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
   2442   bool block;    /* we store the status and use that to provide a ssh_getsock()
   2443                     implementation */
   2444   CURLcode result;
   2445 
   2446   if(!sshc || !sshp)
   2447     return CURLE_FAILED_INIT;
   2448   result = myssh_statemach_act(data, sshc, sshp, &block);
   2449   *done = (sshc->state == SSH_STOP);
   2450   myssh_block2waitfor(conn, sshc, block);
   2451 
   2452   return result;
   2453 }
   2454 
   2455 static CURLcode myssh_block_statemach(struct Curl_easy *data,
   2456                                       struct ssh_conn *sshc,
   2457                                       struct SSHPROTO *sshp,
   2458                                       bool disconnect)
   2459 {
   2460   struct connectdata *conn = data->conn;
   2461   CURLcode result = CURLE_OK;
   2462 
   2463   while((sshc->state != SSH_STOP) && !result) {
   2464     bool block;
   2465     timediff_t left = 1000;
   2466     struct curltime now = curlx_now();
   2467 
   2468     result = myssh_statemach_act(data, sshc, sshp, &block);
   2469     if(result)
   2470       break;
   2471 
   2472     if(!disconnect) {
   2473       if(Curl_pgrsUpdate(data))
   2474         return CURLE_ABORTED_BY_CALLBACK;
   2475 
   2476       result = Curl_speedcheck(data, now);
   2477       if(result)
   2478         break;
   2479 
   2480       left = Curl_timeleft(data, NULL, FALSE);
   2481       if(left < 0) {
   2482         failf(data, "Operation timed out");
   2483         return CURLE_OPERATION_TIMEDOUT;
   2484       }
   2485     }
   2486 
   2487     if(block) {
   2488       curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
   2489       /* wait for the socket to become ready */
   2490       (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
   2491                                CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
   2492     }
   2493 
   2494   }
   2495 
   2496   return result;
   2497 }
   2498 
   2499 static void myssh_easy_dtor(void *key, size_t klen, void *entry)
   2500 {
   2501   struct SSHPROTO *sshp = entry;
   2502   (void)key;
   2503   (void)klen;
   2504   Curl_safefree(sshp->path);
   2505   free(sshp);
   2506 }
   2507 
   2508 static void myssh_conn_dtor(void *key, size_t klen, void *entry)
   2509 {
   2510   struct ssh_conn *sshc = entry;
   2511   (void)key;
   2512   (void)klen;
   2513   sshc_cleanup(sshc);
   2514   free(sshc);
   2515 }
   2516 
   2517 /*
   2518  * SSH setup connection
   2519  */
   2520 static CURLcode myssh_setup_connection(struct Curl_easy *data,
   2521                                        struct connectdata *conn)
   2522 {
   2523   struct SSHPROTO *sshp;
   2524   struct ssh_conn *sshc;
   2525 
   2526   sshc = calloc(1, sizeof(*sshc));
   2527   if(!sshc)
   2528     return CURLE_OUT_OF_MEMORY;
   2529 
   2530   curlx_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
   2531   sshc->initialised = TRUE;
   2532   if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, myssh_conn_dtor))
   2533     return CURLE_OUT_OF_MEMORY;
   2534 
   2535   sshp = calloc(1, sizeof(*sshp));
   2536   if(!sshp ||
   2537      Curl_meta_set(data, CURL_META_SSH_EASY, sshp, myssh_easy_dtor))
   2538     return CURLE_OUT_OF_MEMORY;
   2539 
   2540   return CURLE_OK;
   2541 }
   2542 
   2543 static Curl_recv scp_recv, sftp_recv;
   2544 static Curl_send scp_send, sftp_send;
   2545 
   2546 /*
   2547  * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
   2548  * do protocol-specific actions at connect-time.
   2549  */
   2550 static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
   2551 {
   2552   CURLcode result;
   2553   struct connectdata *conn = data->conn;
   2554   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   2555   struct SSHPROTO *ssh = Curl_meta_get(data, CURL_META_SSH_EASY);
   2556   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   2557   int rc;
   2558 
   2559   if(!sshc || !ssh)
   2560     return CURLE_FAILED_INIT;
   2561 
   2562   /* We default to persistent connections. We set this already in this connect
   2563      function to make the reuse checks properly be able to check this bit. */
   2564   connkeep(conn, "SSH default");
   2565 
   2566   if(conn->handler->protocol & CURLPROTO_SCP) {
   2567     conn->recv[FIRSTSOCKET] = scp_recv;
   2568     conn->send[FIRSTSOCKET] = scp_send;
   2569   }
   2570   else {
   2571     conn->recv[FIRSTSOCKET] = sftp_recv;
   2572     conn->send[FIRSTSOCKET] = sftp_send;
   2573   }
   2574 
   2575   sshc->ssh_session = ssh_new();
   2576   if(!sshc->ssh_session) {
   2577     failf(data, "Failure initialising ssh session");
   2578     return CURLE_FAILED_INIT;
   2579   }
   2580 
   2581   if(conn->bits.ipv6_ip) {
   2582     char ipv6[MAX_IPADR_LEN];
   2583     msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name);
   2584     rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, ipv6);
   2585   }
   2586   else
   2587     rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
   2588 
   2589   if(rc != SSH_OK) {
   2590     failf(data, "Could not set remote host");
   2591     return CURLE_FAILED_INIT;
   2592   }
   2593 
   2594   rc = ssh_options_parse_config(sshc->ssh_session, NULL);
   2595   if(rc != SSH_OK) {
   2596     infof(data, "Could not parse SSH configuration files");
   2597     /* ignore */
   2598   }
   2599 
   2600   rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_FD, &sock);
   2601   if(rc != SSH_OK) {
   2602     failf(data, "Could not set socket");
   2603     return CURLE_FAILED_INIT;
   2604   }
   2605 
   2606   if(conn->user && conn->user[0] != '\0') {
   2607     infof(data, "User: %s", conn->user);
   2608     rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_USER, conn->user);
   2609     if(rc != SSH_OK) {
   2610       failf(data, "Could not set user");
   2611       return CURLE_FAILED_INIT;
   2612     }
   2613   }
   2614 
   2615   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
   2616     infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
   2617     rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
   2618                          data->set.str[STRING_SSH_KNOWNHOSTS]);
   2619     if(rc != SSH_OK) {
   2620       failf(data, "Could not set known hosts file path");
   2621       return CURLE_FAILED_INIT;
   2622     }
   2623   }
   2624 
   2625   if(conn->remote_port) {
   2626     rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_PORT,
   2627                          &conn->remote_port);
   2628     if(rc != SSH_OK) {
   2629       failf(data, "Could not set remote port");
   2630       return CURLE_FAILED_INIT;
   2631     }
   2632   }
   2633 
   2634   if(data->set.ssh_compression) {
   2635     rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_COMPRESSION,
   2636                          "zlib,zlib@openssh.com,none");
   2637     if(rc != SSH_OK) {
   2638       failf(data, "Could not set compression");
   2639       return CURLE_FAILED_INIT;
   2640     }
   2641   }
   2642 
   2643   sshc->privkey = NULL;
   2644   sshc->pubkey = NULL;
   2645 
   2646   if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
   2647     rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
   2648                                     &sshc->pubkey);
   2649     if(rc != SSH_OK) {
   2650       failf(data, "Could not load public key file");
   2651       return CURLE_FAILED_INIT;
   2652     }
   2653   }
   2654 
   2655   /* we do not verify here, we do it at the state machine,
   2656    * after connection */
   2657 
   2658   myssh_to(data, sshc, SSH_INIT);
   2659 
   2660   result = myssh_multi_statemach(data, done);
   2661 
   2662   return result;
   2663 }
   2664 
   2665 /* called from multi.c while DOing */
   2666 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
   2667 {
   2668   CURLcode result;
   2669 
   2670   result = myssh_multi_statemach(data, dophase_done);
   2671 
   2672   if(*dophase_done) {
   2673     DEBUGF(infof(data, "DO phase is complete"));
   2674   }
   2675   return result;
   2676 }
   2677 
   2678 /*
   2679  ***********************************************************************
   2680  *
   2681  * scp_perform()
   2682  *
   2683  * This is the actual DO function for SCP. Get a file according to
   2684  * the options previously setup.
   2685  */
   2686 
   2687 static
   2688 CURLcode scp_perform(struct Curl_easy *data,
   2689                      bool *connected, bool *dophase_done)
   2690 {
   2691   CURLcode result = CURLE_OK;
   2692   struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
   2693 
   2694   DEBUGF(infof(data, "DO phase starts"));
   2695 
   2696   *dophase_done = FALSE;        /* not done yet */
   2697   if(!sshc)
   2698     return CURLE_FAILED_INIT;
   2699 
   2700   /* start the first command in the DO phase */
   2701   myssh_to(data, sshc, SSH_SCP_TRANS_INIT);
   2702 
   2703   result = myssh_multi_statemach(data, dophase_done);
   2704 
   2705   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
   2706 
   2707   if(*dophase_done) {
   2708     DEBUGF(infof(data, "DO phase is complete"));
   2709   }
   2710 
   2711   return result;
   2712 }
   2713 
   2714 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
   2715 {
   2716   CURLcode result;
   2717   bool connected = FALSE;
   2718   struct connectdata *conn = data->conn;
   2719   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   2720 
   2721   *done = FALSE;                /* default to false */
   2722   if(!sshc)
   2723     return CURLE_FAILED_INIT;
   2724 
   2725   data->req.size = -1;          /* make sure this is unknown at this point */
   2726 
   2727   sshc->actualcode = CURLE_OK;  /* reset error code */
   2728   sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
   2729                                    variable */
   2730 
   2731   Curl_pgrsSetUploadCounter(data, 0);
   2732   Curl_pgrsSetDownloadCounter(data, 0);
   2733   Curl_pgrsSetUploadSize(data, -1);
   2734   Curl_pgrsSetDownloadSize(data, -1);
   2735 
   2736   if(conn->handler->protocol & CURLPROTO_SCP)
   2737     result = scp_perform(data, &connected, done);
   2738   else
   2739     result = sftp_perform(data, &connected, done);
   2740 
   2741   return result;
   2742 }
   2743 
   2744 static void sshc_cleanup(struct ssh_conn *sshc)
   2745 {
   2746   if(sshc->initialised) {
   2747     if(sshc->sftp_file) {
   2748       sftp_close(sshc->sftp_file);
   2749       sshc->sftp_file = NULL;
   2750     }
   2751     if(sshc->sftp_session) {
   2752       sftp_free(sshc->sftp_session);
   2753       sshc->sftp_session = NULL;
   2754     }
   2755     if(sshc->ssh_session) {
   2756       ssh_free(sshc->ssh_session);
   2757       sshc->ssh_session = NULL;
   2758     }
   2759 
   2760     /* worst-case scenario cleanup */
   2761     DEBUGASSERT(sshc->ssh_session == NULL);
   2762     DEBUGASSERT(sshc->scp_session == NULL);
   2763 
   2764     if(sshc->readdir_tmp) {
   2765       ssh_string_free_char(sshc->readdir_tmp);
   2766       sshc->readdir_tmp = NULL;
   2767     }
   2768     if(sshc->quote_attrs) {
   2769       sftp_attributes_free(sshc->quote_attrs);
   2770       sshc->quote_attrs = NULL;
   2771     }
   2772     if(sshc->readdir_attrs) {
   2773       sftp_attributes_free(sshc->readdir_attrs);
   2774       sshc->readdir_attrs = NULL;
   2775     }
   2776     if(sshc->readdir_link_attrs) {
   2777       sftp_attributes_free(sshc->readdir_link_attrs);
   2778       sshc->readdir_link_attrs = NULL;
   2779     }
   2780     if(sshc->privkey) {
   2781       ssh_key_free(sshc->privkey);
   2782       sshc->privkey = NULL;
   2783     }
   2784     if(sshc->pubkey) {
   2785       ssh_key_free(sshc->pubkey);
   2786       sshc->pubkey = NULL;
   2787     }
   2788 
   2789     Curl_safefree(sshc->rsa_pub);
   2790     Curl_safefree(sshc->rsa);
   2791     Curl_safefree(sshc->quote_path1);
   2792     Curl_safefree(sshc->quote_path2);
   2793     curlx_dyn_free(&sshc->readdir_buf);
   2794     Curl_safefree(sshc->readdir_linkPath);
   2795     SSH_STRING_FREE_CHAR(sshc->homedir);
   2796     sshc->initialised = FALSE;
   2797   }
   2798 }
   2799 
   2800 /* BLOCKING, but the function is using the state machine so the only reason
   2801    this is still blocking is that the multi interface code has no support for
   2802    disconnecting operations that takes a while */
   2803 static CURLcode scp_disconnect(struct Curl_easy *data,
   2804                                struct connectdata *conn,
   2805                                bool dead_connection)
   2806 {
   2807   CURLcode result = CURLE_OK;
   2808   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   2809   struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
   2810   (void) dead_connection;
   2811 
   2812   if(sshc && sshc->ssh_session && sshp) {
   2813     /* only if there is a session still around to use! */
   2814 
   2815     myssh_to(data, sshc, SSH_SESSION_DISCONNECT);
   2816 
   2817     result = myssh_block_statemach(data, sshc, sshp, TRUE);
   2818   }
   2819 
   2820   return result;
   2821 }
   2822 
   2823 /* generic done function for both SCP and SFTP called from their specific
   2824    done functions */
   2825 static CURLcode myssh_done(struct Curl_easy *data,
   2826                            struct ssh_conn *sshc,
   2827                            CURLcode status)
   2828 {
   2829   CURLcode result = CURLE_OK;
   2830   struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
   2831 
   2832   if(!status && sshp) {
   2833     /* run the state-machine */
   2834     result = myssh_block_statemach(data, sshc, sshp, FALSE);
   2835   }
   2836   else
   2837     result = status;
   2838 
   2839   if(Curl_pgrsDone(data))
   2840     return CURLE_ABORTED_BY_CALLBACK;
   2841 
   2842   data->req.keepon = 0;   /* clear all bits */
   2843   return result;
   2844 }
   2845 
   2846 
   2847 static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
   2848                          bool premature)
   2849 {
   2850   struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
   2851   (void) premature;             /* not used */
   2852 
   2853   if(!sshc)
   2854     return CURLE_FAILED_INIT;
   2855   if(!status)
   2856     myssh_to(data, sshc, SSH_SCP_DONE);
   2857 
   2858   return myssh_done(data, sshc, status);
   2859 }
   2860 
   2861 static CURLcode scp_send(struct Curl_easy *data, int sockindex,
   2862                          const void *mem, size_t len, bool eos,
   2863                          size_t *pnwritten)
   2864 {
   2865   int rc;
   2866   struct connectdata *conn = data->conn;
   2867   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   2868 
   2869   (void) sockindex; /* we only support SCP on the fixed known primary socket */
   2870   (void)eos;
   2871   *pnwritten = 0;
   2872 
   2873   if(!sshc)
   2874     return CURLE_FAILED_INIT;
   2875 
   2876   rc = ssh_scp_write(sshc->scp_session, mem, len);
   2877 
   2878 #if 0
   2879   /* The following code is misleading, mostly added as wishful thinking
   2880    * that libssh at some point will implement non-blocking ssh_scp_write/read.
   2881    * Currently rc can only be number of bytes read or SSH_ERROR. */
   2882   myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN));
   2883 
   2884   if(rc == SSH_AGAIN)
   2885     return CURLE_AGAIN;
   2886   else
   2887 #endif
   2888   if(rc != SSH_OK)
   2889     return CURLE_SSH;
   2890 
   2891   *pnwritten = len;
   2892   return CURLE_OK;
   2893 }
   2894 
   2895 static CURLcode scp_recv(struct Curl_easy *data, int sockindex,
   2896                          char *mem, size_t len, size_t *pnread)
   2897 {
   2898   struct connectdata *conn = data->conn;
   2899   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   2900   ssize_t nread;
   2901 
   2902   (void) sockindex; /* we only support SCP on the fixed known primary socket */
   2903   *pnread = 0;
   2904 
   2905   if(!sshc)
   2906     return CURLE_FAILED_INIT;
   2907 
   2908   /* libssh returns int */
   2909   nread = ssh_scp_read(sshc->scp_session, mem, len);
   2910 
   2911 #if 0
   2912   /* The following code is misleading, mostly added as wishful thinking
   2913    * that libssh at some point will implement non-blocking ssh_scp_write/read.
   2914    * Currently rc can only be SSH_OK or SSH_ERROR. */
   2915 
   2916   myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN));
   2917   if(nread == SSH_AGAIN)
   2918     return CURLE_AGAIN;
   2919 #endif
   2920   *pnread = (size_t)nread;
   2921   return CURLE_OK;
   2922 }
   2923 
   2924 /*
   2925  * =============== SFTP ===============
   2926  */
   2927 
   2928 /*
   2929  ***********************************************************************
   2930  *
   2931  * sftp_perform()
   2932  *
   2933  * This is the actual DO function for SFTP. Get a file/directory according to
   2934  * the options previously setup.
   2935  */
   2936 
   2937 static
   2938 CURLcode sftp_perform(struct Curl_easy *data,
   2939                       bool *connected,
   2940                       bool *dophase_done)
   2941 {
   2942   struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
   2943   CURLcode result = CURLE_OK;
   2944 
   2945   DEBUGF(infof(data, "DO phase starts"));
   2946 
   2947   *dophase_done = FALSE; /* not done yet */
   2948   if(!sshc)
   2949     return CURLE_FAILED_INIT;
   2950 
   2951   /* start the first command in the DO phase */
   2952   myssh_to(data, sshc, SSH_SFTP_QUOTE_INIT);
   2953 
   2954   /* run the state-machine */
   2955   result = myssh_multi_statemach(data, dophase_done);
   2956 
   2957   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
   2958 
   2959   if(*dophase_done) {
   2960     DEBUGF(infof(data, "DO phase is complete"));
   2961   }
   2962 
   2963   return result;
   2964 }
   2965 
   2966 /* called from multi.c while DOing */
   2967 static CURLcode sftp_doing(struct Curl_easy *data,
   2968                            bool *dophase_done)
   2969 {
   2970   CURLcode result = myssh_multi_statemach(data, dophase_done);
   2971   if(*dophase_done) {
   2972     DEBUGF(infof(data, "DO phase is complete"));
   2973   }
   2974   return result;
   2975 }
   2976 
   2977 /* BLOCKING, but the function is using the state machine so the only reason
   2978    this is still blocking is that the multi interface code has no support for
   2979    disconnecting operations that takes a while */
   2980 static CURLcode sftp_disconnect(struct Curl_easy *data,
   2981                                 struct connectdata *conn,
   2982                                 bool dead_connection)
   2983 {
   2984   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   2985   struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
   2986   CURLcode result = CURLE_OK;
   2987   (void) dead_connection;
   2988 
   2989   DEBUGF(infof(data, "SSH DISCONNECT starts now"));
   2990 
   2991   if(sshc && sshc->ssh_session && sshp) {
   2992     /* only if there is a session still around to use! */
   2993     myssh_to(data, sshc, SSH_SFTP_SHUTDOWN);
   2994     result = myssh_block_statemach(data, sshc, sshp, TRUE);
   2995   }
   2996 
   2997   DEBUGF(infof(data, "SSH DISCONNECT is done"));
   2998   return result;
   2999 }
   3000 
   3001 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
   3002                           bool premature)
   3003 {
   3004   struct connectdata *conn = data->conn;
   3005   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   3006 
   3007   if(!sshc)
   3008     return CURLE_FAILED_INIT;
   3009   if(!status) {
   3010     /* Post quote commands are executed after the SFTP_CLOSE state to avoid
   3011        errors that could happen due to open file handles during POSTQUOTE
   3012        operation */
   3013     if(!premature && data->set.postquote && !conn->bits.retry)
   3014       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
   3015     myssh_to(data, sshc, SSH_SFTP_CLOSE);
   3016   }
   3017   return myssh_done(data, sshc, status);
   3018 }
   3019 
   3020 /* return number of sent bytes */
   3021 static CURLcode sftp_send(struct Curl_easy *data, int sockindex,
   3022                           const void *mem, size_t len, bool eos,
   3023                           size_t *pnwritten)
   3024 {
   3025   struct connectdata *conn = data->conn;
   3026   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   3027   ssize_t nwrite;
   3028 
   3029   (void)sockindex;
   3030   (void)eos;
   3031   *pnwritten = 0;
   3032 
   3033   if(!sshc)
   3034     return CURLE_FAILED_INIT;
   3035 
   3036   /* limit the writes to the maximum specified in Section 3 of
   3037    * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
   3038    */
   3039   if(len > 32768)
   3040     len = 32768;
   3041 #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
   3042   switch(sshc->sftp_send_state) {
   3043     case 0:
   3044       sftp_file_set_nonblocking(sshc->sftp_file);
   3045       if(sftp_aio_begin_write(sshc->sftp_file, mem, len,
   3046                               &sshc->sftp_aio) == SSH_ERROR) {
   3047         return CURLE_SEND_ERROR;
   3048       }
   3049       sshc->sftp_send_state = 1;
   3050       FALLTHROUGH();
   3051     case 1:
   3052       nwrite = sftp_aio_wait_write(&sshc->sftp_aio);
   3053       myssh_block2waitfor(conn, sshc, (nwrite == SSH_AGAIN) ? TRUE : FALSE);
   3054       if(nwrite == SSH_AGAIN)
   3055         return CURLE_AGAIN;
   3056       else if(nwrite < 0)
   3057         return CURLE_SEND_ERROR;
   3058       if(sshc->sftp_aio) {
   3059         sftp_aio_free(sshc->sftp_aio);
   3060         sshc->sftp_aio = NULL;
   3061       }
   3062       sshc->sftp_send_state = 0;
   3063       *pnwritten = (size_t)nwrite;
   3064       return CURLE_OK;
   3065     default:
   3066       /* we never reach here */
   3067       return CURLE_SEND_ERROR;
   3068   }
   3069 #else
   3070   nwrite = sftp_write(sshc->sftp_file, mem, len);
   3071 
   3072   myssh_block2waitfor(conn, sshc, FALSE);
   3073 
   3074 #if 0 /* not returned by libssh on write */
   3075   if(nwrite == SSH_AGAIN) {
   3076     *err = CURLE_AGAIN;
   3077     nwrite = 0;
   3078   }
   3079   else
   3080 #endif
   3081   if(nwrite < 0)
   3082     return CURLE_SSH;
   3083 
   3084   *pnwritten = (size_t)nwrite;
   3085   return CURLE_OK;
   3086 #endif
   3087 }
   3088 
   3089 /*
   3090  * Return number of received (decrypted) bytes
   3091  * or <0 on error
   3092  */
   3093 static CURLcode sftp_recv(struct Curl_easy *data, int sockindex,
   3094                           char *mem, size_t len, size_t *pnread)
   3095 {
   3096   struct connectdata *conn = data->conn;
   3097   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
   3098   ssize_t nread;
   3099 
   3100   (void)sockindex;
   3101   *pnread = 0;
   3102 
   3103   DEBUGASSERT(len < CURL_MAX_READ_SIZE);
   3104   if(!sshc)
   3105     return CURLE_FAILED_INIT;
   3106 
   3107   switch(sshc->sftp_recv_state) {
   3108     case 0:
   3109       sshc->sftp_file_index =
   3110         sftp_async_read_begin(sshc->sftp_file, (uint32_t)len);
   3111       if(sshc->sftp_file_index < 0)
   3112         return CURLE_RECV_ERROR;
   3113 
   3114       FALLTHROUGH();
   3115     case 1:
   3116       sshc->sftp_recv_state = 1;
   3117       nread = sftp_async_read(sshc->sftp_file, mem, (uint32_t)len,
   3118                               (uint32_t)sshc->sftp_file_index);
   3119 
   3120       myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN));
   3121 
   3122       if(nread == SSH_AGAIN)
   3123         return CURLE_AGAIN;
   3124       else if(nread < 0)
   3125         return CURLE_RECV_ERROR;
   3126 
   3127       sshc->sftp_recv_state = 0;
   3128       *pnread = (size_t)nread;
   3129       return CURLE_OK;
   3130 
   3131     default:
   3132       /* we never reach here */
   3133       return CURLE_RECV_ERROR;
   3134   }
   3135 }
   3136 
   3137 
   3138 CURLcode Curl_ssh_init(void)
   3139 {
   3140   if(ssh_init()) {
   3141     DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
   3142     return CURLE_FAILED_INIT;
   3143   }
   3144   return CURLE_OK;
   3145 }
   3146 
   3147 void Curl_ssh_cleanup(void)
   3148 {
   3149   (void)ssh_finalize();
   3150 }
   3151 
   3152 void Curl_ssh_version(char *buffer, size_t buflen)
   3153 {
   3154   (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
   3155 }
   3156 
   3157 #endif                          /* USE_LIBSSH */