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