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