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