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