xref: /curl/lib/vssh/libssh.c (revision 4157ccb8)
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 = ssh_userauth_list(sshc->ssh_session, NULL);
744         if(sshc->auth_methods)
745           infof(data, "SSH authentication methods available: %s%s%s%s",
746                 sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
747                 "public key, ": "",
748                 sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
749                 "GSSAPI, " : "",
750                 sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?
751                 "keyboard-interactive, " : "",
752                 sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
753                 "password": "");
754         if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
755           state(data, SSH_AUTH_PKEY_INIT);
756           infof(data, "Authentication using SSH public key file");
757         }
758         else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
759           state(data, SSH_AUTH_GSSAPI);
760         }
761         else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
762           state(data, SSH_AUTH_KEY_INIT);
763         }
764         else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
765           state(data, SSH_AUTH_PASS_INIT);
766         }
767         else {                  /* unsupported authentication method */
768           MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
769           break;
770         }
771 
772         break;
773       }
774     case SSH_AUTH_PKEY_INIT:
775       if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
776         MOVE_TO_GSSAPI_AUTH;
777         break;
778       }
779 
780       /* Two choices, (1) private key was given on CMD,
781        * (2) use the "default" keys. */
782       if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
783         if(sshc->pubkey && !data->set.ssl.key_passwd) {
784           rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
785                                           sshc->pubkey);
786           if(rc == SSH_AUTH_AGAIN) {
787             rc = SSH_AGAIN;
788             break;
789           }
790 
791           if(rc != SSH_OK) {
792             MOVE_TO_GSSAPI_AUTH;
793             break;
794           }
795         }
796 
797         rc = ssh_pki_import_privkey_file(data->
798                                          set.str[STRING_SSH_PRIVATE_KEY],
799                                          data->set.ssl.key_passwd, NULL,
800                                          NULL, &sshc->privkey);
801         if(rc != SSH_OK) {
802           failf(data, "Could not load private key file %s",
803                 data->set.str[STRING_SSH_PRIVATE_KEY]);
804           MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
805           break;
806         }
807 
808         state(data, SSH_AUTH_PKEY);
809         break;
810 
811       }
812       else {
813         rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
814                                          data->set.ssl.key_passwd);
815         if(rc == SSH_AUTH_AGAIN) {
816           rc = SSH_AGAIN;
817           break;
818         }
819         if(rc == SSH_AUTH_SUCCESS) {
820           rc = SSH_OK;
821           sshc->authed = TRUE;
822           infof(data, "Completed public key authentication");
823           state(data, SSH_AUTH_DONE);
824           break;
825         }
826 
827         MOVE_TO_GSSAPI_AUTH;
828       }
829       break;
830     case SSH_AUTH_PKEY:
831       rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
832       if(rc == SSH_AUTH_AGAIN) {
833         rc = SSH_AGAIN;
834         break;
835       }
836 
837       if(rc == SSH_AUTH_SUCCESS) {
838         sshc->authed = TRUE;
839         infof(data, "Completed public key authentication");
840         state(data, SSH_AUTH_DONE);
841         break;
842       }
843       else {
844         infof(data, "Failed public key authentication (rc: %d)", rc);
845         MOVE_TO_GSSAPI_AUTH;
846       }
847       break;
848 
849     case SSH_AUTH_GSSAPI:
850       if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
851         MOVE_TO_KEY_AUTH;
852         break;
853       }
854 
855       rc = ssh_userauth_gssapi(sshc->ssh_session);
856       if(rc == SSH_AUTH_AGAIN) {
857         rc = SSH_AGAIN;
858         break;
859       }
860 
861       if(rc == SSH_AUTH_SUCCESS) {
862         rc = SSH_OK;
863         sshc->authed = TRUE;
864         infof(data, "Completed gssapi authentication");
865         state(data, SSH_AUTH_DONE);
866         break;
867       }
868 
869       MOVE_TO_KEY_AUTH;
870       break;
871 
872     case SSH_AUTH_KEY_INIT:
873       if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
874         state(data, SSH_AUTH_KEY);
875       }
876       else {
877         MOVE_TO_PASSWD_AUTH;
878       }
879       break;
880 
881     case SSH_AUTH_KEY:
882       /* keyboard-interactive authentication */
883       rc = myssh_auth_interactive(conn);
884       if(rc == SSH_AGAIN) {
885         break;
886       }
887       if(rc == SSH_OK) {
888         sshc->authed = TRUE;
889         infof(data, "completed keyboard interactive authentication");
890         state(data, SSH_AUTH_DONE);
891       }
892       else {
893         MOVE_TO_PASSWD_AUTH;
894       }
895       break;
896 
897     case SSH_AUTH_PASS_INIT:
898       if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
899         MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
900         break;
901       }
902       state(data, SSH_AUTH_PASS);
903       FALLTHROUGH();
904 
905     case SSH_AUTH_PASS:
906       rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
907       if(rc == SSH_AUTH_AGAIN) {
908         rc = SSH_AGAIN;
909         break;
910       }
911 
912       if(rc == SSH_AUTH_SUCCESS) {
913         sshc->authed = TRUE;
914         infof(data, "Completed password authentication");
915         state(data, SSH_AUTH_DONE);
916       }
917       else {
918         MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
919       }
920       break;
921 
922     case SSH_AUTH_DONE:
923       if(!sshc->authed) {
924         failf(data, "Authentication failure");
925         MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
926         break;
927       }
928 
929       /*
930        * At this point we have an authenticated ssh session.
931        */
932       infof(data, "Authentication complete");
933 
934       Curl_pgrsTime(data, TIMER_APPCONNECT);      /* SSH is connected */
935 
936       conn->sockfd = sock;
937       conn->writesockfd = CURL_SOCKET_BAD;
938 
939       if(conn->handler->protocol == CURLPROTO_SFTP) {
940         state(data, SSH_SFTP_INIT);
941         break;
942       }
943       infof(data, "SSH CONNECT phase done");
944       state(data, SSH_STOP);
945       break;
946 
947     case SSH_SFTP_INIT:
948       ssh_set_blocking(sshc->ssh_session, 1);
949 
950       sshc->sftp_session = sftp_new(sshc->ssh_session);
951       if(!sshc->sftp_session) {
952         failf(data, "Failure initializing sftp session: %s",
953               ssh_get_error(sshc->ssh_session));
954         MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
955         break;
956       }
957 
958       rc = sftp_init(sshc->sftp_session);
959       if(rc != SSH_OK) {
960         failf(data, "Failure initializing sftp session: %s",
961               ssh_get_error(sshc->ssh_session));
962         MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE));
963         break;
964       }
965       state(data, SSH_SFTP_REALPATH);
966       FALLTHROUGH();
967     case SSH_SFTP_REALPATH:
968       /*
969        * Get the "home" directory
970        */
971       sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
972       if(!sshc->homedir) {
973         MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
974         break;
975       }
976       data->state.most_recent_ftp_entrypath = sshc->homedir;
977 
978       /* This is the last step in the SFTP connect phase. Do note that while
979          we get the homedir here, we get the "workingpath" in the DO action
980          since the homedir will remain the same between request but the
981          working path will not. */
982       DEBUGF(infof(data, "SSH CONNECT phase done"));
983       state(data, SSH_STOP);
984       break;
985 
986     case SSH_SFTP_QUOTE_INIT:
987       result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
988       if(result) {
989         sshc->actualcode = result;
990         state(data, SSH_STOP);
991         break;
992       }
993 
994       if(data->set.quote) {
995         infof(data, "Sending quote commands");
996         sshc->quote_item = data->set.quote;
997         state(data, SSH_SFTP_QUOTE);
998       }
999       else {
1000         state(data, SSH_SFTP_GETINFO);
1001       }
1002       break;
1003 
1004     case SSH_SFTP_POSTQUOTE_INIT:
1005       if(data->set.postquote) {
1006         infof(data, "Sending quote commands");
1007         sshc->quote_item = data->set.postquote;
1008         state(data, SSH_SFTP_QUOTE);
1009       }
1010       else {
1011         state(data, SSH_STOP);
1012       }
1013       break;
1014 
1015     case SSH_SFTP_QUOTE:
1016       /* Send any quote commands */
1017       sftp_quote(data);
1018       break;
1019 
1020     case SSH_SFTP_NEXT_QUOTE:
1021       Curl_safefree(sshc->quote_path1);
1022       Curl_safefree(sshc->quote_path2);
1023 
1024       sshc->quote_item = sshc->quote_item->next;
1025 
1026       if(sshc->quote_item) {
1027         state(data, SSH_SFTP_QUOTE);
1028       }
1029       else {
1030         if(sshc->nextstate != SSH_NO_STATE) {
1031           state(data, sshc->nextstate);
1032           sshc->nextstate = SSH_NO_STATE;
1033         }
1034         else {
1035           state(data, SSH_SFTP_GETINFO);
1036         }
1037       }
1038       break;
1039 
1040     case SSH_SFTP_QUOTE_STAT:
1041       sftp_quote_stat(data);
1042       break;
1043 
1044     case SSH_SFTP_QUOTE_SETSTAT:
1045       rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
1046                         sshc->quote_attrs);
1047       if(rc && !sshc->acceptfail) {
1048         Curl_safefree(sshc->quote_path1);
1049         Curl_safefree(sshc->quote_path2);
1050         failf(data, "Attempt to set SFTP stats failed: %s",
1051               ssh_get_error(sshc->ssh_session));
1052         state(data, SSH_SFTP_CLOSE);
1053         sshc->nextstate = SSH_NO_STATE;
1054         sshc->actualcode = CURLE_QUOTE_ERROR;
1055         /* sshc->actualcode = sftp_error_to_CURLE(err);
1056          * we do not send the actual error; we return
1057          * the error the libssh2 backend is returning */
1058         break;
1059       }
1060       state(data, SSH_SFTP_NEXT_QUOTE);
1061       break;
1062 
1063     case SSH_SFTP_QUOTE_SYMLINK:
1064       rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
1065                         sshc->quote_path1);
1066       if(rc && !sshc->acceptfail) {
1067         Curl_safefree(sshc->quote_path1);
1068         Curl_safefree(sshc->quote_path2);
1069         failf(data, "symlink command failed: %s",
1070               ssh_get_error(sshc->ssh_session));
1071         state(data, SSH_SFTP_CLOSE);
1072         sshc->nextstate = SSH_NO_STATE;
1073         sshc->actualcode = CURLE_QUOTE_ERROR;
1074         break;
1075       }
1076       state(data, SSH_SFTP_NEXT_QUOTE);
1077       break;
1078 
1079     case SSH_SFTP_QUOTE_MKDIR:
1080       rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
1081                       (mode_t)data->set.new_directory_perms);
1082       if(rc && !sshc->acceptfail) {
1083         Curl_safefree(sshc->quote_path1);
1084         failf(data, "mkdir command failed: %s",
1085               ssh_get_error(sshc->ssh_session));
1086         state(data, SSH_SFTP_CLOSE);
1087         sshc->nextstate = SSH_NO_STATE;
1088         sshc->actualcode = CURLE_QUOTE_ERROR;
1089         break;
1090       }
1091       state(data, SSH_SFTP_NEXT_QUOTE);
1092       break;
1093 
1094     case SSH_SFTP_QUOTE_RENAME:
1095       rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
1096                        sshc->quote_path2);
1097       if(rc && !sshc->acceptfail) {
1098         Curl_safefree(sshc->quote_path1);
1099         Curl_safefree(sshc->quote_path2);
1100         failf(data, "rename command failed: %s",
1101               ssh_get_error(sshc->ssh_session));
1102         state(data, SSH_SFTP_CLOSE);
1103         sshc->nextstate = SSH_NO_STATE;
1104         sshc->actualcode = CURLE_QUOTE_ERROR;
1105         break;
1106       }
1107       state(data, SSH_SFTP_NEXT_QUOTE);
1108       break;
1109 
1110     case SSH_SFTP_QUOTE_RMDIR:
1111       rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
1112       if(rc && !sshc->acceptfail) {
1113         Curl_safefree(sshc->quote_path1);
1114         failf(data, "rmdir command failed: %s",
1115               ssh_get_error(sshc->ssh_session));
1116         state(data, SSH_SFTP_CLOSE);
1117         sshc->nextstate = SSH_NO_STATE;
1118         sshc->actualcode = CURLE_QUOTE_ERROR;
1119         break;
1120       }
1121       state(data, SSH_SFTP_NEXT_QUOTE);
1122       break;
1123 
1124     case SSH_SFTP_QUOTE_UNLINK:
1125       rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
1126       if(rc && !sshc->acceptfail) {
1127         Curl_safefree(sshc->quote_path1);
1128         failf(data, "rm command failed: %s",
1129               ssh_get_error(sshc->ssh_session));
1130         state(data, SSH_SFTP_CLOSE);
1131         sshc->nextstate = SSH_NO_STATE;
1132         sshc->actualcode = CURLE_QUOTE_ERROR;
1133         break;
1134       }
1135       state(data, SSH_SFTP_NEXT_QUOTE);
1136       break;
1137 
1138     case SSH_SFTP_QUOTE_STATVFS:
1139     {
1140       sftp_statvfs_t statvfs;
1141 
1142       statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
1143       if(!statvfs && !sshc->acceptfail) {
1144         Curl_safefree(sshc->quote_path1);
1145         failf(data, "statvfs command failed: %s",
1146               ssh_get_error(sshc->ssh_session));
1147         state(data, SSH_SFTP_CLOSE);
1148         sshc->nextstate = SSH_NO_STATE;
1149         sshc->actualcode = CURLE_QUOTE_ERROR;
1150         break;
1151       }
1152       else if(statvfs) {
1153         #ifdef _MSC_VER
1154         #define CURL_LIBSSH_VFS_SIZE_MASK "I64u"
1155         #else
1156         #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64
1157         #endif
1158         char *tmp = aprintf("statvfs:\n"
1159                             "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1160                             "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1161                             "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1162                             "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1163                             "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1164                             "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1165                             "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1166                             "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1167                             "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1168                             "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1169                             "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n",
1170                             statvfs->f_bsize, statvfs->f_frsize,
1171                             statvfs->f_blocks, statvfs->f_bfree,
1172                             statvfs->f_bavail, statvfs->f_files,
1173                             statvfs->f_ffree, statvfs->f_favail,
1174                             statvfs->f_fsid, statvfs->f_flag,
1175                             statvfs->f_namemax);
1176         sftp_statvfs_free(statvfs);
1177 
1178         if(!tmp) {
1179           result = CURLE_OUT_OF_MEMORY;
1180           state(data, SSH_SFTP_CLOSE);
1181           sshc->nextstate = SSH_NO_STATE;
1182           break;
1183         }
1184 
1185         result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1186         free(tmp);
1187         if(result) {
1188           state(data, SSH_SFTP_CLOSE);
1189           sshc->nextstate = SSH_NO_STATE;
1190           sshc->actualcode = result;
1191         }
1192       }
1193       state(data, SSH_SFTP_NEXT_QUOTE);
1194       break;
1195     }
1196 
1197     case SSH_SFTP_GETINFO:
1198       if(data->set.get_filetime) {
1199         state(data, SSH_SFTP_FILETIME);
1200       }
1201       else {
1202         state(data, SSH_SFTP_TRANS_INIT);
1203       }
1204       break;
1205 
1206     case SSH_SFTP_FILETIME:
1207     {
1208       sftp_attributes attrs;
1209 
1210       attrs = sftp_stat(sshc->sftp_session, protop->path);
1211       if(attrs) {
1212         data->info.filetime = attrs->mtime;
1213         sftp_attributes_free(attrs);
1214       }
1215 
1216       state(data, SSH_SFTP_TRANS_INIT);
1217       break;
1218     }
1219 
1220     case SSH_SFTP_TRANS_INIT:
1221       if(data->state.upload)
1222         state(data, SSH_SFTP_UPLOAD_INIT);
1223       else {
1224         if(protop->path[strlen(protop->path)-1] == '/')
1225           state(data, SSH_SFTP_READDIR_INIT);
1226         else
1227           state(data, SSH_SFTP_DOWNLOAD_INIT);
1228       }
1229       break;
1230 
1231     case SSH_SFTP_UPLOAD_INIT:
1232     {
1233       int flags;
1234 
1235       if(data->state.resume_from) {
1236         sftp_attributes attrs;
1237 
1238         if(data->state.resume_from < 0) {
1239           attrs = sftp_stat(sshc->sftp_session, protop->path);
1240           if(attrs) {
1241             curl_off_t size = attrs->size;
1242             if(size < 0) {
1243               failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1244               MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
1245               break;
1246             }
1247             data->state.resume_from = attrs->size;
1248 
1249             sftp_attributes_free(attrs);
1250           }
1251           else {
1252             data->state.resume_from = 0;
1253           }
1254         }
1255       }
1256 
1257       if(data->set.remote_append)
1258         /* Try to open for append, but create if nonexisting */
1259         flags = O_WRONLY|O_CREAT|O_APPEND;
1260       else if(data->state.resume_from > 0)
1261         /* If we have restart position then open for append */
1262         flags = O_WRONLY|O_APPEND;
1263       else
1264         /* Clear file before writing (normal behavior) */
1265         flags = O_WRONLY|O_CREAT|O_TRUNC;
1266 
1267       if(sshc->sftp_file)
1268         sftp_close(sshc->sftp_file);
1269       sshc->sftp_file =
1270         sftp_open(sshc->sftp_session, protop->path,
1271                   flags, (mode_t)data->set.new_file_perms);
1272       if(!sshc->sftp_file) {
1273         err = sftp_get_error(sshc->sftp_session);
1274 
1275         if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
1276              err == SSH_FX_NO_SUCH_PATH)) &&
1277              (data->set.ftp_create_missing_dirs &&
1278              (strlen(protop->path) > 1))) {
1279                /* try to create the path remotely */
1280                rc = 0;
1281                sshc->secondCreateDirs = 1;
1282                state(data, SSH_SFTP_CREATE_DIRS_INIT);
1283                break;
1284         }
1285         else {
1286           MOVE_TO_SFTP_CLOSE_STATE();
1287           break;
1288         }
1289       }
1290 
1291       /* If we have a restart point then we need to seek to the correct
1292          position. */
1293       if(data->state.resume_from > 0) {
1294         /* Let's read off the proper amount of bytes from the input. */
1295         if(data->set.seek_func) {
1296           Curl_set_in_callback(data, true);
1297           seekerr = data->set.seek_func(data->set.seek_client,
1298                                         data->state.resume_from, SEEK_SET);
1299           Curl_set_in_callback(data, false);
1300         }
1301 
1302         if(seekerr != CURL_SEEKFUNC_OK) {
1303           curl_off_t passed = 0;
1304 
1305           if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1306             failf(data, "Could not seek stream");
1307             return CURLE_FTP_COULDNT_USE_REST;
1308           }
1309           /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1310           do {
1311             char scratch[4*1024];
1312             size_t readthisamountnow =
1313               (data->state.resume_from - passed >
1314                 (curl_off_t)sizeof(scratch)) ?
1315               sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
1316 
1317             size_t actuallyread =
1318               data->state.fread_func(scratch, 1,
1319                                      readthisamountnow, data->state.in);
1320 
1321             passed += actuallyread;
1322             if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1323               /* this checks for greater-than only to make sure that the
1324                  CURL_READFUNC_ABORT return code still aborts */
1325               failf(data, "Failed to read data");
1326               MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
1327               break;
1328             }
1329           } while(passed < data->state.resume_from);
1330           if(rc)
1331             break;
1332         }
1333 
1334         /* now, decrease the size of the read */
1335         if(data->state.infilesize > 0) {
1336           data->state.infilesize -= data->state.resume_from;
1337           data->req.size = data->state.infilesize;
1338           Curl_pgrsSetUploadSize(data, data->state.infilesize);
1339         }
1340 
1341         rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1342         if(rc) {
1343           MOVE_TO_SFTP_CLOSE_STATE();
1344           break;
1345         }
1346       }
1347       if(data->state.infilesize > 0) {
1348         data->req.size = data->state.infilesize;
1349         Curl_pgrsSetUploadSize(data, data->state.infilesize);
1350       }
1351       /* upload data */
1352       Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
1353 
1354       /* not set by Curl_xfer_setup to preserve keepon bits */
1355       conn->sockfd = conn->writesockfd;
1356 
1357       /* store this original bitmask setup to use later on if we can't
1358          figure out a "real" bitmask */
1359       sshc->orig_waitfor = data->req.keepon;
1360 
1361       /* we want to use the _sending_ function even when the socket turns
1362          out readable as the underlying libssh sftp send function will deal
1363          with both accordingly */
1364       data->state.select_bits = CURL_CSELECT_OUT;
1365 
1366       /* since we don't really wait for anything at this point, we want the
1367          state machine to move on as soon as possible so we set a very short
1368          timeout here */
1369       Curl_expire(data, 0, EXPIRE_RUN_NOW);
1370 
1371       state(data, SSH_STOP);
1372       break;
1373     }
1374 
1375     case SSH_SFTP_CREATE_DIRS_INIT:
1376       if(strlen(protop->path) > 1) {
1377         sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1378         state(data, SSH_SFTP_CREATE_DIRS);
1379       }
1380       else {
1381         state(data, SSH_SFTP_UPLOAD_INIT);
1382       }
1383       break;
1384 
1385     case SSH_SFTP_CREATE_DIRS:
1386       sshc->slash_pos = strchr(sshc->slash_pos, '/');
1387       if(sshc->slash_pos) {
1388         *sshc->slash_pos = 0;
1389 
1390         infof(data, "Creating directory '%s'", protop->path);
1391         state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
1392         break;
1393       }
1394       state(data, SSH_SFTP_UPLOAD_INIT);
1395       break;
1396 
1397     case SSH_SFTP_CREATE_DIRS_MKDIR:
1398       /* 'mode' - parameter is preliminary - default to 0644 */
1399       rc = sftp_mkdir(sshc->sftp_session, protop->path,
1400                       (mode_t)data->set.new_directory_perms);
1401       *sshc->slash_pos = '/';
1402       ++sshc->slash_pos;
1403       if(rc < 0) {
1404         /*
1405          * Abort if failure wasn't that the dir already exists or the
1406          * permission was denied (creation might succeed further down the
1407          * path) - retry on unspecific FAILURE also
1408          */
1409         err = sftp_get_error(sshc->sftp_session);
1410         if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1411            (err != SSH_FX_FAILURE) &&
1412            (err != SSH_FX_PERMISSION_DENIED)) {
1413           MOVE_TO_SFTP_CLOSE_STATE();
1414           break;
1415         }
1416         rc = 0; /* clear rc and continue */
1417       }
1418       state(data, SSH_SFTP_CREATE_DIRS);
1419       break;
1420 
1421     case SSH_SFTP_READDIR_INIT:
1422       Curl_pgrsSetDownloadSize(data, -1);
1423       if(data->req.no_body) {
1424         state(data, SSH_STOP);
1425         break;
1426       }
1427 
1428       /*
1429        * This is a directory that we are trying to get, so produce a directory
1430        * listing
1431        */
1432       sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1433                                     protop->path);
1434       if(!sshc->sftp_dir) {
1435         failf(data, "Could not open directory for reading: %s",
1436               ssh_get_error(sshc->ssh_session));
1437         MOVE_TO_SFTP_CLOSE_STATE();
1438         break;
1439       }
1440       state(data, SSH_SFTP_READDIR);
1441       break;
1442 
1443     case SSH_SFTP_READDIR:
1444       Curl_dyn_reset(&sshc->readdir_buf);
1445       if(sshc->readdir_attrs)
1446         sftp_attributes_free(sshc->readdir_attrs);
1447 
1448       sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1449       if(sshc->readdir_attrs) {
1450         sshc->readdir_filename = sshc->readdir_attrs->name;
1451         sshc->readdir_longentry = sshc->readdir_attrs->longname;
1452         sshc->readdir_len = strlen(sshc->readdir_filename);
1453 
1454         if(data->set.list_only) {
1455           char *tmpLine;
1456 
1457           tmpLine = aprintf("%s\n", sshc->readdir_filename);
1458           if(!tmpLine) {
1459             state(data, SSH_SFTP_CLOSE);
1460             sshc->actualcode = CURLE_OUT_OF_MEMORY;
1461             break;
1462           }
1463           result = Curl_client_write(data, CLIENTWRITE_BODY,
1464                                      tmpLine, sshc->readdir_len + 1);
1465           free(tmpLine);
1466 
1467           if(result) {
1468             state(data, SSH_STOP);
1469             break;
1470           }
1471 
1472         }
1473         else {
1474           if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
1475             sshc->actualcode = CURLE_OUT_OF_MEMORY;
1476             state(data, SSH_STOP);
1477             break;
1478           }
1479 
1480           if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1481              ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
1482               SSH_S_IFLNK)) {
1483             sshc->readdir_linkPath = aprintf("%s%s", protop->path,
1484                                              sshc->readdir_filename);
1485 
1486             if(!sshc->readdir_linkPath) {
1487               state(data, SSH_SFTP_CLOSE);
1488               sshc->actualcode = CURLE_OUT_OF_MEMORY;
1489               break;
1490             }
1491 
1492             state(data, SSH_SFTP_READDIR_LINK);
1493             break;
1494           }
1495           state(data, SSH_SFTP_READDIR_BOTTOM);
1496           break;
1497         }
1498       }
1499       else if(sftp_dir_eof(sshc->sftp_dir)) {
1500         state(data, SSH_SFTP_READDIR_DONE);
1501         break;
1502       }
1503       else {
1504         failf(data, "Could not open remote file for reading: %s",
1505               ssh_get_error(sshc->ssh_session));
1506         MOVE_TO_SFTP_CLOSE_STATE();
1507         break;
1508       }
1509       break;
1510 
1511     case SSH_SFTP_READDIR_LINK:
1512       if(sshc->readdir_link_attrs)
1513         sftp_attributes_free(sshc->readdir_link_attrs);
1514 
1515       sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1516                                             sshc->readdir_linkPath);
1517       if(sshc->readdir_link_attrs == 0) {
1518         failf(data, "Could not read symlink for reading: %s",
1519               ssh_get_error(sshc->ssh_session));
1520         MOVE_TO_SFTP_CLOSE_STATE();
1521         break;
1522       }
1523 
1524       if(!sshc->readdir_link_attrs->name) {
1525         sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1526                                           sshc->readdir_linkPath);
1527         if(!sshc->readdir_filename)
1528           sshc->readdir_len = 0;
1529         else
1530           sshc->readdir_len = strlen(sshc->readdir_tmp);
1531         sshc->readdir_longentry = NULL;
1532         sshc->readdir_filename = sshc->readdir_tmp;
1533       }
1534       else {
1535         sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
1536         sshc->readdir_filename = sshc->readdir_link_attrs->name;
1537         sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1538       }
1539 
1540       Curl_safefree(sshc->readdir_linkPath);
1541 
1542       if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
1543                        sshc->readdir_filename)) {
1544         sshc->actualcode = CURLE_OUT_OF_MEMORY;
1545         break;
1546       }
1547 
1548       sftp_attributes_free(sshc->readdir_link_attrs);
1549       sshc->readdir_link_attrs = NULL;
1550       sshc->readdir_filename = NULL;
1551       sshc->readdir_longentry = NULL;
1552 
1553       state(data, SSH_SFTP_READDIR_BOTTOM);
1554       FALLTHROUGH();
1555     case SSH_SFTP_READDIR_BOTTOM:
1556       if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
1557         result = CURLE_OUT_OF_MEMORY;
1558       else
1559         result = Curl_client_write(data, CLIENTWRITE_BODY,
1560                                    Curl_dyn_ptr(&sshc->readdir_buf),
1561                                    Curl_dyn_len(&sshc->readdir_buf));
1562 
1563       ssh_string_free_char(sshc->readdir_tmp);
1564       sshc->readdir_tmp = NULL;
1565 
1566       if(result) {
1567         state(data, SSH_STOP);
1568       }
1569       else
1570         state(data, SSH_SFTP_READDIR);
1571       break;
1572 
1573     case SSH_SFTP_READDIR_DONE:
1574       sftp_closedir(sshc->sftp_dir);
1575       sshc->sftp_dir = NULL;
1576 
1577       /* no data to transfer */
1578       Curl_xfer_setup(data, -1, -1, FALSE, -1);
1579       state(data, SSH_STOP);
1580       break;
1581 
1582     case SSH_SFTP_DOWNLOAD_INIT:
1583       /*
1584        * Work on getting the specified file
1585        */
1586       if(sshc->sftp_file)
1587         sftp_close(sshc->sftp_file);
1588 
1589       sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1590                                   O_RDONLY, (mode_t)data->set.new_file_perms);
1591       if(!sshc->sftp_file) {
1592         failf(data, "Could not open remote file for reading: %s",
1593               ssh_get_error(sshc->ssh_session));
1594 
1595         MOVE_TO_SFTP_CLOSE_STATE();
1596         break;
1597       }
1598       sftp_file_set_nonblocking(sshc->sftp_file);
1599       state(data, SSH_SFTP_DOWNLOAD_STAT);
1600       break;
1601 
1602     case SSH_SFTP_DOWNLOAD_STAT:
1603     {
1604       sftp_attributes attrs;
1605       curl_off_t size;
1606 
1607       attrs = sftp_fstat(sshc->sftp_file);
1608       if(!attrs ||
1609               !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1610               (attrs->size == 0)) {
1611         /*
1612          * sftp_fstat didn't return an error, so maybe the server
1613          * just doesn't support stat()
1614          * OR the server doesn't return a file size with a stat()
1615          * OR file size is 0
1616          */
1617         data->req.size = -1;
1618         data->req.maxdownload = -1;
1619         Curl_pgrsSetDownloadSize(data, -1);
1620         size = 0;
1621       }
1622       else {
1623         size = attrs->size;
1624 
1625         sftp_attributes_free(attrs);
1626 
1627         if(size < 0) {
1628           failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1629           return CURLE_BAD_DOWNLOAD_RESUME;
1630         }
1631         if(data->state.use_range) {
1632           curl_off_t from, to;
1633           char *ptr;
1634           char *ptr2;
1635           CURLofft to_t;
1636           CURLofft from_t;
1637 
1638           from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
1639           if(from_t == CURL_OFFT_FLOW) {
1640             return CURLE_RANGE_ERROR;
1641           }
1642           while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
1643             ptr++;
1644           to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
1645           if(to_t == CURL_OFFT_FLOW) {
1646             return CURLE_RANGE_ERROR;
1647           }
1648           if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1649              || (to >= size)) {
1650             to = size - 1;
1651           }
1652           if(from_t) {
1653             /* from is relative to end of file */
1654             from = size - to;
1655             to = size - 1;
1656           }
1657           if(from > size) {
1658             failf(data, "Offset (%"
1659                   CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1660                   CURL_FORMAT_CURL_OFF_T ")", from, size);
1661             return CURLE_BAD_DOWNLOAD_RESUME;
1662           }
1663           if(from > to) {
1664             from = to;
1665             size = 0;
1666           }
1667           else {
1668             if((to - from) == CURL_OFF_T_MAX)
1669               return CURLE_RANGE_ERROR;
1670             size = to - from + 1;
1671           }
1672 
1673           rc = sftp_seek64(sshc->sftp_file, from);
1674           if(rc) {
1675             MOVE_TO_SFTP_CLOSE_STATE();
1676             break;
1677           }
1678         }
1679         data->req.size = size;
1680         data->req.maxdownload = size;
1681         Curl_pgrsSetDownloadSize(data, size);
1682       }
1683 
1684       /* We can resume if we can seek to the resume position */
1685       if(data->state.resume_from) {
1686         if(data->state.resume_from < 0) {
1687           /* We're supposed to download the last abs(from) bytes */
1688           if((curl_off_t)size < -data->state.resume_from) {
1689             failf(data, "Offset (%"
1690                   CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1691                   CURL_FORMAT_CURL_OFF_T ")",
1692                   data->state.resume_from, size);
1693             return CURLE_BAD_DOWNLOAD_RESUME;
1694           }
1695           /* download from where? */
1696           data->state.resume_from += size;
1697         }
1698         else {
1699           if((curl_off_t)size < data->state.resume_from) {
1700             failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
1701                   ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
1702                   data->state.resume_from, size);
1703             return CURLE_BAD_DOWNLOAD_RESUME;
1704           }
1705         }
1706         /* Now store the number of bytes we are expected to download */
1707         data->req.size = size - data->state.resume_from;
1708         data->req.maxdownload = size - data->state.resume_from;
1709         Curl_pgrsSetDownloadSize(data,
1710                                  size - data->state.resume_from);
1711 
1712         rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1713         if(rc) {
1714           MOVE_TO_SFTP_CLOSE_STATE();
1715           break;
1716         }
1717       }
1718     }
1719 
1720     /* Setup the actual download */
1721     if(data->req.size == 0) {
1722       /* no data to transfer */
1723       Curl_xfer_setup(data, -1, -1, FALSE, -1);
1724       infof(data, "File already completely downloaded");
1725       state(data, SSH_STOP);
1726       break;
1727     }
1728     Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
1729 
1730     /* not set by Curl_xfer_setup to preserve keepon bits */
1731     conn->writesockfd = conn->sockfd;
1732 
1733     /* we want to use the _receiving_ function even when the socket turns
1734        out writableable as the underlying libssh recv function will deal
1735        with both accordingly */
1736     data->state.select_bits = CURL_CSELECT_IN;
1737 
1738     if(result) {
1739       /* this should never occur; the close state should be entered
1740          at the time the error occurs */
1741       state(data, SSH_SFTP_CLOSE);
1742       sshc->actualcode = result;
1743     }
1744     else {
1745       sshc->sftp_recv_state = 0;
1746       state(data, SSH_STOP);
1747     }
1748     break;
1749 
1750     case SSH_SFTP_CLOSE:
1751       if(sshc->sftp_file) {
1752         sftp_close(sshc->sftp_file);
1753         sshc->sftp_file = NULL;
1754       }
1755       Curl_safefree(protop->path);
1756 
1757       DEBUGF(infof(data, "SFTP DONE done"));
1758 
1759       /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
1760          After nextstate is executed, the control should come back to
1761          SSH_SFTP_CLOSE to pass the correct result back  */
1762       if(sshc->nextstate != SSH_NO_STATE &&
1763          sshc->nextstate != SSH_SFTP_CLOSE) {
1764         state(data, sshc->nextstate);
1765         sshc->nextstate = SSH_SFTP_CLOSE;
1766       }
1767       else {
1768         state(data, SSH_STOP);
1769         result = sshc->actualcode;
1770       }
1771       break;
1772 
1773     case SSH_SFTP_SHUTDOWN:
1774       /* during times we get here due to a broken transfer and then the
1775          sftp_handle might not have been taken down so make sure that is done
1776          before we proceed */
1777 
1778       if(sshc->sftp_file) {
1779         sftp_close(sshc->sftp_file);
1780         sshc->sftp_file = NULL;
1781       }
1782 
1783       if(sshc->sftp_session) {
1784         sftp_free(sshc->sftp_session);
1785         sshc->sftp_session = NULL;
1786       }
1787 
1788       SSH_STRING_FREE_CHAR(sshc->homedir);
1789       data->state.most_recent_ftp_entrypath = NULL;
1790 
1791       state(data, SSH_SESSION_DISCONNECT);
1792       break;
1793 
1794     case SSH_SCP_TRANS_INIT:
1795       result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
1796       if(result) {
1797         sshc->actualcode = result;
1798         state(data, SSH_STOP);
1799         break;
1800       }
1801 
1802       /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
1803       ssh_set_blocking(sshc->ssh_session, 1);
1804 
1805       if(data->state.upload) {
1806         if(data->state.infilesize < 0) {
1807           failf(data, "SCP requires a known file size for upload");
1808           sshc->actualcode = CURLE_UPLOAD_FAILED;
1809           MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1810           break;
1811         }
1812 
1813         sshc->scp_session =
1814           ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
1815         state(data, SSH_SCP_UPLOAD_INIT);
1816       }
1817       else {
1818         sshc->scp_session =
1819           ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
1820         state(data, SSH_SCP_DOWNLOAD_INIT);
1821       }
1822 
1823       if(!sshc->scp_session) {
1824         err_msg = ssh_get_error(sshc->ssh_session);
1825         failf(data, "%s", err_msg);
1826         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1827       }
1828 
1829       break;
1830 
1831     case SSH_SCP_UPLOAD_INIT:
1832 
1833       rc = ssh_scp_init(sshc->scp_session);
1834       if(rc != SSH_OK) {
1835         err_msg = ssh_get_error(sshc->ssh_session);
1836         failf(data, "%s", err_msg);
1837         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1838         break;
1839       }
1840 
1841       rc = ssh_scp_push_file(sshc->scp_session, protop->path,
1842                              data->state.infilesize,
1843                              (int)data->set.new_file_perms);
1844       if(rc != SSH_OK) {
1845         err_msg = ssh_get_error(sshc->ssh_session);
1846         failf(data, "%s", err_msg);
1847         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1848         break;
1849       }
1850 
1851       /* upload data */
1852       Curl_xfer_setup(data, -1, data->req.size, FALSE, FIRSTSOCKET);
1853 
1854       /* not set by Curl_xfer_setup to preserve keepon bits */
1855       conn->sockfd = conn->writesockfd;
1856 
1857       /* store this original bitmask setup to use later on if we can't
1858          figure out a "real" bitmask */
1859       sshc->orig_waitfor = data->req.keepon;
1860 
1861       /* we want to use the _sending_ function even when the socket turns
1862          out readable as the underlying libssh scp send function will deal
1863          with both accordingly */
1864       data->state.select_bits = CURL_CSELECT_OUT;
1865 
1866       state(data, SSH_STOP);
1867 
1868       break;
1869 
1870     case SSH_SCP_DOWNLOAD_INIT:
1871 
1872       rc = ssh_scp_init(sshc->scp_session);
1873       if(rc != SSH_OK) {
1874         err_msg = ssh_get_error(sshc->ssh_session);
1875         failf(data, "%s", err_msg);
1876         MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
1877         break;
1878       }
1879       state(data, SSH_SCP_DOWNLOAD);
1880       FALLTHROUGH();
1881 
1882     case SSH_SCP_DOWNLOAD:{
1883         curl_off_t bytecount;
1884 
1885         rc = ssh_scp_pull_request(sshc->scp_session);
1886         if(rc != SSH_SCP_REQUEST_NEWFILE) {
1887           err_msg = ssh_get_error(sshc->ssh_session);
1888           failf(data, "%s", err_msg);
1889           MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
1890           break;
1891         }
1892 
1893         /* download data */
1894         bytecount = ssh_scp_request_get_size(sshc->scp_session);
1895         data->req.maxdownload = (curl_off_t) bytecount;
1896         Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);
1897 
1898         /* not set by Curl_xfer_setup to preserve keepon bits */
1899         conn->writesockfd = conn->sockfd;
1900 
1901         /* we want to use the _receiving_ function even when the socket turns
1902            out writableable as the underlying libssh recv function will deal
1903            with both accordingly */
1904         data->state.select_bits = CURL_CSELECT_IN;
1905 
1906         state(data, SSH_STOP);
1907         break;
1908       }
1909     case SSH_SCP_DONE:
1910       if(data->state.upload)
1911         state(data, SSH_SCP_SEND_EOF);
1912       else
1913         state(data, SSH_SCP_CHANNEL_FREE);
1914       break;
1915 
1916     case SSH_SCP_SEND_EOF:
1917       if(sshc->scp_session) {
1918         rc = ssh_scp_close(sshc->scp_session);
1919         if(rc == SSH_AGAIN) {
1920           /* Currently the ssh_scp_close handles waiting for EOF in
1921            * blocking way.
1922            */
1923           break;
1924         }
1925         if(rc != SSH_OK) {
1926           infof(data, "Failed to close libssh scp channel: %s",
1927                 ssh_get_error(sshc->ssh_session));
1928         }
1929       }
1930 
1931       state(data, SSH_SCP_CHANNEL_FREE);
1932       break;
1933 
1934     case SSH_SCP_CHANNEL_FREE:
1935       if(sshc->scp_session) {
1936         ssh_scp_free(sshc->scp_session);
1937         sshc->scp_session = NULL;
1938       }
1939       DEBUGF(infof(data, "SCP DONE phase complete"));
1940 
1941       ssh_set_blocking(sshc->ssh_session, 0);
1942 
1943       state(data, SSH_SESSION_DISCONNECT);
1944       FALLTHROUGH();
1945 
1946     case SSH_SESSION_DISCONNECT:
1947       /* during weird times when we've been prematurely aborted, the channel
1948          is still alive when we reach this state and we MUST kill the channel
1949          properly first */
1950       if(sshc->scp_session) {
1951         ssh_scp_free(sshc->scp_session);
1952         sshc->scp_session = NULL;
1953       }
1954 
1955       ssh_disconnect(sshc->ssh_session);
1956       if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
1957         /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
1958            tell the connection to forget about it. This libssh
1959            bug is fixed in 0.10.0. */
1960         Curl_conn_forget_socket(data, FIRSTSOCKET);
1961       }
1962 
1963       SSH_STRING_FREE_CHAR(sshc->homedir);
1964       data->state.most_recent_ftp_entrypath = NULL;
1965 
1966       state(data, SSH_SESSION_FREE);
1967       FALLTHROUGH();
1968     case SSH_SESSION_FREE:
1969       if(sshc->ssh_session) {
1970         ssh_free(sshc->ssh_session);
1971         sshc->ssh_session = NULL;
1972       }
1973 
1974       /* worst-case scenario cleanup */
1975 
1976       DEBUGASSERT(sshc->ssh_session == NULL);
1977       DEBUGASSERT(sshc->scp_session == NULL);
1978 
1979       if(sshc->readdir_tmp) {
1980         ssh_string_free_char(sshc->readdir_tmp);
1981         sshc->readdir_tmp = NULL;
1982       }
1983 
1984       if(sshc->quote_attrs)
1985         sftp_attributes_free(sshc->quote_attrs);
1986 
1987       if(sshc->readdir_attrs)
1988         sftp_attributes_free(sshc->readdir_attrs);
1989 
1990       if(sshc->readdir_link_attrs)
1991         sftp_attributes_free(sshc->readdir_link_attrs);
1992 
1993       if(sshc->privkey)
1994         ssh_key_free(sshc->privkey);
1995       if(sshc->pubkey)
1996         ssh_key_free(sshc->pubkey);
1997 
1998       Curl_safefree(sshc->rsa_pub);
1999       Curl_safefree(sshc->rsa);
2000       Curl_safefree(sshc->quote_path1);
2001       Curl_safefree(sshc->quote_path2);
2002       Curl_dyn_free(&sshc->readdir_buf);
2003       Curl_safefree(sshc->readdir_linkPath);
2004       SSH_STRING_FREE_CHAR(sshc->homedir);
2005 
2006       /* the code we are about to return */
2007       result = sshc->actualcode;
2008 
2009       memset(sshc, 0, sizeof(struct ssh_conn));
2010 
2011       connclose(conn, "SSH session free");
2012       sshc->state = SSH_SESSION_FREE;   /* current */
2013       sshc->nextstate = SSH_NO_STATE;
2014       state(data, SSH_STOP);
2015       break;
2016 
2017     case SSH_QUIT:
2018     default:
2019       /* internal error */
2020       sshc->nextstate = SSH_NO_STATE;
2021       state(data, SSH_STOP);
2022       break;
2023 
2024     }
2025   } while(!rc && (sshc->state != SSH_STOP));
2026 
2027 
2028   if(rc == SSH_AGAIN) {
2029     /* we would block, we need to wait for the socket to be ready (in the
2030        right direction too)! */
2031     *block = TRUE;
2032   }
2033 
2034   return result;
2035 }
2036 
2037 
2038 /* called by the multi interface to figure out what socket(s) to wait for and
2039    for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
myssh_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * sock)2040 static int myssh_getsock(struct Curl_easy *data,
2041                          struct connectdata *conn,
2042                          curl_socket_t *sock)
2043 {
2044   int bitmap = GETSOCK_BLANK;
2045   (void)data;
2046   sock[0] = conn->sock[FIRSTSOCKET];
2047 
2048   if(conn->waitfor & KEEP_RECV)
2049     bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
2050 
2051   if(conn->waitfor & KEEP_SEND)
2052     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2053 
2054   if(!conn->waitfor)
2055     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2056 
2057   return bitmap;
2058 }
2059 
myssh_block2waitfor(struct connectdata * conn,bool block)2060 static void myssh_block2waitfor(struct connectdata *conn, bool block)
2061 {
2062   struct ssh_conn *sshc = &conn->proto.sshc;
2063 
2064   /* If it didn't block, or nothing was returned by ssh_get_poll_flags
2065    * have the original set */
2066   conn->waitfor = sshc->orig_waitfor;
2067 
2068   if(block) {
2069     int dir = ssh_get_poll_flags(sshc->ssh_session);
2070     if(dir & SSH_READ_PENDING) {
2071       /* translate the libssh define bits into our own bit defines */
2072       conn->waitfor = KEEP_RECV;
2073     }
2074     else if(dir & SSH_WRITE_PENDING) {
2075       conn->waitfor = KEEP_SEND;
2076     }
2077   }
2078 }
2079 
2080 /* called repeatedly until done from multi.c */
myssh_multi_statemach(struct Curl_easy * data,bool * done)2081 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
2082                                       bool *done)
2083 {
2084   struct connectdata *conn = data->conn;
2085   struct ssh_conn *sshc = &conn->proto.sshc;
2086   bool block;    /* we store the status and use that to provide a ssh_getsock()
2087                     implementation */
2088   CURLcode result = myssh_statemach_act(data, &block);
2089 
2090   *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
2091   myssh_block2waitfor(conn, block);
2092 
2093   return result;
2094 }
2095 
myssh_block_statemach(struct Curl_easy * data,bool disconnect)2096 static CURLcode myssh_block_statemach(struct Curl_easy *data,
2097                                       bool disconnect)
2098 {
2099   struct connectdata *conn = data->conn;
2100   struct ssh_conn *sshc = &conn->proto.sshc;
2101   CURLcode result = CURLE_OK;
2102 
2103   while((sshc->state != SSH_STOP) && !result) {
2104     bool block;
2105     timediff_t left = 1000;
2106     struct curltime now = Curl_now();
2107 
2108     result = myssh_statemach_act(data, &block);
2109     if(result)
2110       break;
2111 
2112     if(!disconnect) {
2113       if(Curl_pgrsUpdate(data))
2114         return CURLE_ABORTED_BY_CALLBACK;
2115 
2116       result = Curl_speedcheck(data, now);
2117       if(result)
2118         break;
2119 
2120       left = Curl_timeleft(data, NULL, FALSE);
2121       if(left < 0) {
2122         failf(data, "Operation timed out");
2123         return CURLE_OPERATION_TIMEDOUT;
2124       }
2125     }
2126 
2127     if(block) {
2128       curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
2129       /* wait for the socket to become ready */
2130       (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2131                                CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2132     }
2133 
2134   }
2135 
2136   return result;
2137 }
2138 
2139 /*
2140  * SSH setup connection
2141  */
myssh_setup_connection(struct Curl_easy * data,struct connectdata * conn)2142 static CURLcode myssh_setup_connection(struct Curl_easy *data,
2143                                        struct connectdata *conn)
2144 {
2145   struct SSHPROTO *ssh;
2146   struct ssh_conn *sshc = &conn->proto.sshc;
2147 
2148   data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
2149   if(!ssh)
2150     return CURLE_OUT_OF_MEMORY;
2151   Curl_dyn_init(&sshc->readdir_buf, PATH_MAX * 2);
2152 
2153   return CURLE_OK;
2154 }
2155 
2156 static Curl_recv scp_recv, sftp_recv;
2157 static Curl_send scp_send, sftp_send;
2158 
2159 /*
2160  * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2161  * do protocol-specific actions at connect-time.
2162  */
myssh_connect(struct Curl_easy * data,bool * done)2163 static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
2164 {
2165   struct ssh_conn *ssh;
2166   CURLcode result;
2167   struct connectdata *conn = data->conn;
2168   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2169   int rc;
2170 
2171   /* initialize per-handle data if not already */
2172   if(!data->req.p.ssh)
2173     myssh_setup_connection(data, conn);
2174 
2175   /* We default to persistent connections. We set this already in this connect
2176      function to make the reuse checks properly be able to check this bit. */
2177   connkeep(conn, "SSH default");
2178 
2179   if(conn->handler->protocol & CURLPROTO_SCP) {
2180     conn->recv[FIRSTSOCKET] = scp_recv;
2181     conn->send[FIRSTSOCKET] = scp_send;
2182   }
2183   else {
2184     conn->recv[FIRSTSOCKET] = sftp_recv;
2185     conn->send[FIRSTSOCKET] = sftp_send;
2186   }
2187 
2188   ssh = &conn->proto.sshc;
2189 
2190   ssh->ssh_session = ssh_new();
2191   if(!ssh->ssh_session) {
2192     failf(data, "Failure initialising ssh session");
2193     return CURLE_FAILED_INIT;
2194   }
2195 
2196   rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2197   if(rc != SSH_OK) {
2198     failf(data, "Could not set remote host");
2199     return CURLE_FAILED_INIT;
2200   }
2201 
2202   rc = ssh_options_parse_config(ssh->ssh_session, NULL);
2203   if(rc != SSH_OK) {
2204     infof(data, "Could not parse SSH configuration files");
2205     /* ignore */
2206   }
2207 
2208   rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2209   if(rc != SSH_OK) {
2210     failf(data, "Could not set socket");
2211     return CURLE_FAILED_INIT;
2212   }
2213 
2214   if(conn->user && conn->user[0] != '\0') {
2215     infof(data, "User: %s", conn->user);
2216     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2217     if(rc != SSH_OK) {
2218       failf(data, "Could not set user");
2219       return CURLE_FAILED_INIT;
2220     }
2221   }
2222 
2223   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2224     infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
2225     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2226                          data->set.str[STRING_SSH_KNOWNHOSTS]);
2227     if(rc != SSH_OK) {
2228       failf(data, "Could not set known hosts file path");
2229       return CURLE_FAILED_INIT;
2230     }
2231   }
2232 
2233   if(conn->remote_port) {
2234     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2235                          &conn->remote_port);
2236     if(rc != SSH_OK) {
2237       failf(data, "Could not set remote port");
2238       return CURLE_FAILED_INIT;
2239     }
2240   }
2241 
2242   if(data->set.ssh_compression) {
2243     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2244                          "zlib,zlib@openssh.com,none");
2245     if(rc != SSH_OK) {
2246       failf(data, "Could not set compression");
2247       return CURLE_FAILED_INIT;
2248     }
2249   }
2250 
2251   ssh->privkey = NULL;
2252   ssh->pubkey = NULL;
2253 
2254   if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2255     rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2256                                     &ssh->pubkey);
2257     if(rc != SSH_OK) {
2258       failf(data, "Could not load public key file");
2259       return CURLE_FAILED_INIT;
2260     }
2261   }
2262 
2263   /* we do not verify here, we do it at the state machine,
2264    * after connection */
2265 
2266   state(data, SSH_INIT);
2267 
2268   result = myssh_multi_statemach(data, done);
2269 
2270   return result;
2271 }
2272 
2273 /* called from multi.c while DOing */
scp_doing(struct Curl_easy * data,bool * dophase_done)2274 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
2275 {
2276   CURLcode result;
2277 
2278   result = myssh_multi_statemach(data, dophase_done);
2279 
2280   if(*dophase_done) {
2281     DEBUGF(infof(data, "DO phase is complete"));
2282   }
2283   return result;
2284 }
2285 
2286 /*
2287  ***********************************************************************
2288  *
2289  * scp_perform()
2290  *
2291  * This is the actual DO function for SCP. Get a file according to
2292  * the options previously setup.
2293  */
2294 
2295 static
scp_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)2296 CURLcode scp_perform(struct Curl_easy *data,
2297                      bool *connected, bool *dophase_done)
2298 {
2299   CURLcode result = CURLE_OK;
2300 
2301   DEBUGF(infof(data, "DO phase starts"));
2302 
2303   *dophase_done = FALSE;        /* not done yet */
2304 
2305   /* start the first command in the DO phase */
2306   state(data, SSH_SCP_TRANS_INIT);
2307 
2308   result = myssh_multi_statemach(data, dophase_done);
2309 
2310   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2311 
2312   if(*dophase_done) {
2313     DEBUGF(infof(data, "DO phase is complete"));
2314   }
2315 
2316   return result;
2317 }
2318 
myssh_do_it(struct Curl_easy * data,bool * done)2319 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
2320 {
2321   CURLcode result;
2322   bool connected = 0;
2323   struct connectdata *conn = data->conn;
2324   struct ssh_conn *sshc = &conn->proto.sshc;
2325 
2326   *done = FALSE;                /* default to false */
2327 
2328   data->req.size = -1;          /* make sure this is unknown at this point */
2329 
2330   sshc->actualcode = CURLE_OK;  /* reset error code */
2331   sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
2332                                    variable */
2333 
2334   Curl_pgrsSetUploadCounter(data, 0);
2335   Curl_pgrsSetDownloadCounter(data, 0);
2336   Curl_pgrsSetUploadSize(data, -1);
2337   Curl_pgrsSetDownloadSize(data, -1);
2338 
2339   if(conn->handler->protocol & CURLPROTO_SCP)
2340     result = scp_perform(data, &connected, done);
2341   else
2342     result = sftp_perform(data, &connected, done);
2343 
2344   return result;
2345 }
2346 
2347 /* BLOCKING, but the function is using the state machine so the only reason
2348    this is still blocking is that the multi interface code has no support for
2349    disconnecting operations that takes a while */
scp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)2350 static CURLcode scp_disconnect(struct Curl_easy *data,
2351                                struct connectdata *conn,
2352                                bool dead_connection)
2353 {
2354   CURLcode result = CURLE_OK;
2355   struct ssh_conn *ssh = &conn->proto.sshc;
2356   (void) dead_connection;
2357 
2358   if(ssh->ssh_session) {
2359     /* only if there's a session still around to use! */
2360 
2361     state(data, SSH_SESSION_DISCONNECT);
2362 
2363     result = myssh_block_statemach(data, TRUE);
2364   }
2365 
2366   return result;
2367 }
2368 
2369 /* generic done function for both SCP and SFTP called from their specific
2370    done functions */
myssh_done(struct Curl_easy * data,CURLcode status)2371 static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
2372 {
2373   CURLcode result = CURLE_OK;
2374   struct SSHPROTO *protop = data->req.p.ssh;
2375 
2376   if(!status) {
2377     /* run the state-machine */
2378     result = myssh_block_statemach(data, FALSE);
2379   }
2380   else
2381     result = status;
2382 
2383   if(protop)
2384     Curl_safefree(protop->path);
2385   if(Curl_pgrsDone(data))
2386     return CURLE_ABORTED_BY_CALLBACK;
2387 
2388   data->req.keepon = 0;   /* clear all bits */
2389   return result;
2390 }
2391 
2392 
scp_done(struct Curl_easy * data,CURLcode status,bool premature)2393 static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
2394                          bool premature)
2395 {
2396   (void) premature;             /* not used */
2397 
2398   if(!status)
2399     state(data, SSH_SCP_DONE);
2400 
2401   return myssh_done(data, status);
2402 
2403 }
2404 
scp_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,CURLcode * err)2405 static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2406                         const void *mem, size_t len, CURLcode *err)
2407 {
2408   int rc;
2409   struct connectdata *conn = data->conn;
2410   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2411   (void) err;
2412 
2413   rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2414 
2415 #if 0
2416   /* The following code is misleading, mostly added as wishful thinking
2417    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2418    * Currently rc can only be number of bytes read or SSH_ERROR. */
2419   myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
2420 
2421   if(rc == SSH_AGAIN) {
2422     *err = CURLE_AGAIN;
2423     return 0;
2424   }
2425   else
2426 #endif
2427   if(rc != SSH_OK) {
2428     *err = CURLE_SSH;
2429     return -1;
2430   }
2431 
2432   return len;
2433 }
2434 
scp_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)2435 static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2436                         char *mem, size_t len, CURLcode *err)
2437 {
2438   ssize_t nread;
2439   struct connectdata *conn = data->conn;
2440   (void) err;
2441   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2442 
2443   /* libssh returns int */
2444   nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2445 
2446 #if 0
2447   /* The following code is misleading, mostly added as wishful thinking
2448    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2449    * Currently rc can only be SSH_OK or SSH_ERROR. */
2450 
2451   myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
2452   if(nread == SSH_AGAIN) {
2453     *err = CURLE_AGAIN;
2454     nread = -1;
2455   }
2456 #endif
2457 
2458   return nread;
2459 }
2460 
2461 /*
2462  * =============== SFTP ===============
2463  */
2464 
2465 /*
2466  ***********************************************************************
2467  *
2468  * sftp_perform()
2469  *
2470  * This is the actual DO function for SFTP. Get a file/directory according to
2471  * the options previously setup.
2472  */
2473 
2474 static
sftp_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)2475 CURLcode sftp_perform(struct Curl_easy *data,
2476                       bool *connected,
2477                       bool *dophase_done)
2478 {
2479   CURLcode result = CURLE_OK;
2480 
2481   DEBUGF(infof(data, "DO phase starts"));
2482 
2483   *dophase_done = FALSE; /* not done yet */
2484 
2485   /* start the first command in the DO phase */
2486   state(data, SSH_SFTP_QUOTE_INIT);
2487 
2488   /* run the state-machine */
2489   result = myssh_multi_statemach(data, dophase_done);
2490 
2491   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2492 
2493   if(*dophase_done) {
2494     DEBUGF(infof(data, "DO phase is complete"));
2495   }
2496 
2497   return result;
2498 }
2499 
2500 /* called from multi.c while DOing */
sftp_doing(struct Curl_easy * data,bool * dophase_done)2501 static CURLcode sftp_doing(struct Curl_easy *data,
2502                            bool *dophase_done)
2503 {
2504   CURLcode result = myssh_multi_statemach(data, dophase_done);
2505   if(*dophase_done) {
2506     DEBUGF(infof(data, "DO phase is complete"));
2507   }
2508   return result;
2509 }
2510 
2511 /* BLOCKING, but the function is using the state machine so the only reason
2512    this is still blocking is that the multi interface code has no support for
2513    disconnecting operations that takes a while */
sftp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)2514 static CURLcode sftp_disconnect(struct Curl_easy *data,
2515                                 struct connectdata *conn,
2516                                 bool dead_connection)
2517 {
2518   CURLcode result = CURLE_OK;
2519   (void) dead_connection;
2520 
2521   DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2522 
2523   if(conn->proto.sshc.ssh_session) {
2524     /* only if there's a session still around to use! */
2525     state(data, SSH_SFTP_SHUTDOWN);
2526     result = myssh_block_statemach(data, TRUE);
2527   }
2528 
2529   DEBUGF(infof(data, "SSH DISCONNECT is done"));
2530 
2531   return result;
2532 
2533 }
2534 
sftp_done(struct Curl_easy * data,CURLcode status,bool premature)2535 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2536                           bool premature)
2537 {
2538   struct connectdata *conn = data->conn;
2539   struct ssh_conn *sshc = &conn->proto.sshc;
2540 
2541   if(!status) {
2542     /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2543        errors that could happen due to open file handles during POSTQUOTE
2544        operation */
2545     if(!premature && data->set.postquote && !conn->bits.retry)
2546       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2547     state(data, SSH_SFTP_CLOSE);
2548   }
2549   return myssh_done(data, status);
2550 }
2551 
2552 /* return number of sent bytes */
sftp_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,CURLcode * err)2553 static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2554                          const void *mem, size_t len, CURLcode *err)
2555 {
2556   ssize_t nwrite;
2557   struct connectdata *conn = data->conn;
2558   (void)sockindex;
2559 
2560   /* limit the writes to the maximum specified in Section 3 of
2561    * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
2562    */
2563   if(len > 32768)
2564     len = 32768;
2565 
2566   nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2567 
2568   myssh_block2waitfor(conn, FALSE);
2569 
2570 #if 0 /* not returned by libssh on write */
2571   if(nwrite == SSH_AGAIN) {
2572     *err = CURLE_AGAIN;
2573     nwrite = 0;
2574   }
2575   else
2576 #endif
2577   if(nwrite < 0) {
2578     *err = CURLE_SSH;
2579     nwrite = -1;
2580   }
2581 
2582   return nwrite;
2583 }
2584 
2585 /*
2586  * Return number of received (decrypted) bytes
2587  * or <0 on error
2588  */
sftp_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)2589 static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2590                          char *mem, size_t len, CURLcode *err)
2591 {
2592   ssize_t nread;
2593   struct connectdata *conn = data->conn;
2594   (void)sockindex;
2595 
2596   DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2597 
2598   switch(conn->proto.sshc.sftp_recv_state) {
2599     case 0:
2600       conn->proto.sshc.sftp_file_index =
2601         sftp_async_read_begin(conn->proto.sshc.sftp_file,
2602                               (uint32_t)len);
2603       if(conn->proto.sshc.sftp_file_index < 0) {
2604         *err = CURLE_RECV_ERROR;
2605         return -1;
2606       }
2607 
2608       FALLTHROUGH();
2609     case 1:
2610       conn->proto.sshc.sftp_recv_state = 1;
2611 
2612       nread = sftp_async_read(conn->proto.sshc.sftp_file,
2613                               mem, (uint32_t)len,
2614                               conn->proto.sshc.sftp_file_index);
2615 
2616       myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
2617 
2618       if(nread == SSH_AGAIN) {
2619         *err = CURLE_AGAIN;
2620         return -1;
2621       }
2622       else if(nread < 0) {
2623         *err = CURLE_RECV_ERROR;
2624         return -1;
2625       }
2626 
2627       conn->proto.sshc.sftp_recv_state = 0;
2628       return nread;
2629 
2630     default:
2631       /* we never reach here */
2632       return -1;
2633   }
2634 }
2635 
sftp_quote(struct Curl_easy * data)2636 static void sftp_quote(struct Curl_easy *data)
2637 {
2638   const char *cp;
2639   struct connectdata *conn = data->conn;
2640   struct SSHPROTO *protop = data->req.p.ssh;
2641   struct ssh_conn *sshc = &conn->proto.sshc;
2642   CURLcode result;
2643 
2644   /*
2645    * Support some of the "FTP" commands
2646    */
2647   char *cmd = sshc->quote_item->data;
2648   sshc->acceptfail = FALSE;
2649 
2650   /* if a command starts with an asterisk, which a legal SFTP command never
2651      can, the command will be allowed to fail without it causing any
2652      aborts or cancels etc. It will cause libcurl to act as if the command
2653      is successful, whatever the server responds. */
2654 
2655   if(cmd[0] == '*') {
2656     cmd++;
2657     sshc->acceptfail = TRUE;
2658   }
2659 
2660   if(strcasecompare("pwd", cmd)) {
2661     /* output debug output if that is requested */
2662     char *tmp = aprintf("257 \"%s\" is current directory.\n",
2663                         protop->path);
2664     if(!tmp) {
2665       sshc->actualcode = CURLE_OUT_OF_MEMORY;
2666       state(data, SSH_SFTP_CLOSE);
2667       sshc->nextstate = SSH_NO_STATE;
2668       return;
2669     }
2670     Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2671     Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2672 
2673     /* this sends an FTP-like "header" to the header callback so that the
2674        current directory can be read very similar to how it is read when
2675        using ordinary FTP. */
2676     result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2677     free(tmp);
2678     if(result) {
2679       state(data, SSH_SFTP_CLOSE);
2680       sshc->nextstate = SSH_NO_STATE;
2681       sshc->actualcode = result;
2682     }
2683     else
2684       state(data, SSH_SFTP_NEXT_QUOTE);
2685     return;
2686   }
2687 
2688   /*
2689    * the arguments following the command must be separated from the
2690    * command with a space so we can check for it unconditionally
2691    */
2692   cp = strchr(cmd, ' ');
2693   if(!cp) {
2694     failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2695     state(data, SSH_SFTP_CLOSE);
2696     sshc->nextstate = SSH_NO_STATE;
2697     sshc->actualcode = CURLE_QUOTE_ERROR;
2698     return;
2699   }
2700 
2701   /*
2702    * also, every command takes at least one argument so we get that
2703    * first argument right now
2704    */
2705   result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2706   if(result) {
2707     if(result == CURLE_OUT_OF_MEMORY)
2708       failf(data, "Out of memory");
2709     else
2710       failf(data, "Syntax error: Bad first parameter");
2711     state(data, SSH_SFTP_CLOSE);
2712     sshc->nextstate = SSH_NO_STATE;
2713     sshc->actualcode = result;
2714     return;
2715   }
2716 
2717   /*
2718    * SFTP is a binary protocol, so we don't send text commands
2719    * to the server. Instead, we scan for commands used by
2720    * OpenSSH's sftp program and call the appropriate libssh
2721    * functions.
2722    */
2723   if(strncasecompare(cmd, "chgrp ", 6) ||
2724      strncasecompare(cmd, "chmod ", 6) ||
2725      strncasecompare(cmd, "chown ", 6) ||
2726      strncasecompare(cmd, "atime ", 6) ||
2727      strncasecompare(cmd, "mtime ", 6)) {
2728     /* attribute change */
2729 
2730     /* sshc->quote_path1 contains the mode to set */
2731     /* get the destination */
2732     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2733     if(result) {
2734       if(result == CURLE_OUT_OF_MEMORY)
2735         failf(data, "Out of memory");
2736       else
2737         failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2738               "Bad second parameter");
2739       Curl_safefree(sshc->quote_path1);
2740       state(data, SSH_SFTP_CLOSE);
2741       sshc->nextstate = SSH_NO_STATE;
2742       sshc->actualcode = result;
2743       return;
2744     }
2745     sshc->quote_attrs = NULL;
2746     state(data, SSH_SFTP_QUOTE_STAT);
2747     return;
2748   }
2749   if(strncasecompare(cmd, "ln ", 3) ||
2750      strncasecompare(cmd, "symlink ", 8)) {
2751     /* symbolic linking */
2752     /* sshc->quote_path1 is the source */
2753     /* get the destination */
2754     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2755     if(result) {
2756       if(result == CURLE_OUT_OF_MEMORY)
2757         failf(data, "Out of memory");
2758       else
2759         failf(data, "Syntax error in ln/symlink: Bad second parameter");
2760       Curl_safefree(sshc->quote_path1);
2761       state(data, SSH_SFTP_CLOSE);
2762       sshc->nextstate = SSH_NO_STATE;
2763       sshc->actualcode = result;
2764       return;
2765     }
2766     state(data, SSH_SFTP_QUOTE_SYMLINK);
2767     return;
2768   }
2769   else if(strncasecompare(cmd, "mkdir ", 6)) {
2770     /* create dir */
2771     state(data, SSH_SFTP_QUOTE_MKDIR);
2772     return;
2773   }
2774   else if(strncasecompare(cmd, "rename ", 7)) {
2775     /* rename file */
2776     /* first param is the source path */
2777     /* second param is the dest. path */
2778     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2779     if(result) {
2780       if(result == CURLE_OUT_OF_MEMORY)
2781         failf(data, "Out of memory");
2782       else
2783         failf(data, "Syntax error in rename: Bad second parameter");
2784       Curl_safefree(sshc->quote_path1);
2785       state(data, SSH_SFTP_CLOSE);
2786       sshc->nextstate = SSH_NO_STATE;
2787       sshc->actualcode = result;
2788       return;
2789     }
2790     state(data, SSH_SFTP_QUOTE_RENAME);
2791     return;
2792   }
2793   else if(strncasecompare(cmd, "rmdir ", 6)) {
2794     /* delete dir */
2795     state(data, SSH_SFTP_QUOTE_RMDIR);
2796     return;
2797   }
2798   else if(strncasecompare(cmd, "rm ", 3)) {
2799     state(data, SSH_SFTP_QUOTE_UNLINK);
2800     return;
2801   }
2802 #ifdef HAS_STATVFS_SUPPORT
2803   else if(strncasecompare(cmd, "statvfs ", 8)) {
2804     state(data, SSH_SFTP_QUOTE_STATVFS);
2805     return;
2806   }
2807 #endif
2808 
2809   failf(data, "Unknown SFTP command");
2810   Curl_safefree(sshc->quote_path1);
2811   Curl_safefree(sshc->quote_path2);
2812   state(data, SSH_SFTP_CLOSE);
2813   sshc->nextstate = SSH_NO_STATE;
2814   sshc->actualcode = CURLE_QUOTE_ERROR;
2815 }
2816 
sftp_quote_stat(struct Curl_easy * data)2817 static void sftp_quote_stat(struct Curl_easy *data)
2818 {
2819   struct connectdata *conn = data->conn;
2820   struct ssh_conn *sshc = &conn->proto.sshc;
2821   char *cmd = sshc->quote_item->data;
2822   sshc->acceptfail = FALSE;
2823 
2824   /* if a command starts with an asterisk, which a legal SFTP command never
2825      can, the command will be allowed to fail without it causing any
2826      aborts or cancels etc. It will cause libcurl to act as if the command
2827      is successful, whatever the server responds. */
2828 
2829   if(cmd[0] == '*') {
2830     cmd++;
2831     sshc->acceptfail = TRUE;
2832   }
2833 
2834   /* We read the file attributes, store them in sshc->quote_attrs
2835    * and modify them accordingly to command. Then we switch to
2836    * QUOTE_SETSTAT state to write new ones.
2837    */
2838 
2839   if(sshc->quote_attrs)
2840     sftp_attributes_free(sshc->quote_attrs);
2841   sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2842   if(!sshc->quote_attrs) {
2843     Curl_safefree(sshc->quote_path1);
2844     Curl_safefree(sshc->quote_path2);
2845     failf(data, "Attempt to get SFTP stats failed: %d",
2846           sftp_get_error(sshc->sftp_session));
2847     state(data, SSH_SFTP_CLOSE);
2848     sshc->nextstate = SSH_NO_STATE;
2849     sshc->actualcode = CURLE_QUOTE_ERROR;
2850     return;
2851   }
2852 
2853   /* Now set the new attributes... */
2854   if(strncasecompare(cmd, "chgrp", 5)) {
2855     sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2856     if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2857         !sshc->acceptfail) {
2858       Curl_safefree(sshc->quote_path1);
2859       Curl_safefree(sshc->quote_path2);
2860       failf(data, "Syntax error: chgrp gid not a number");
2861       state(data, SSH_SFTP_CLOSE);
2862       sshc->nextstate = SSH_NO_STATE;
2863       sshc->actualcode = CURLE_QUOTE_ERROR;
2864       return;
2865     }
2866     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2867   }
2868   else if(strncasecompare(cmd, "chmod", 5)) {
2869     mode_t perms;
2870     perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2871     /* permissions are octal */
2872     if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2873       Curl_safefree(sshc->quote_path1);
2874       Curl_safefree(sshc->quote_path2);
2875       failf(data, "Syntax error: chmod permissions not a number");
2876       state(data, SSH_SFTP_CLOSE);
2877       sshc->nextstate = SSH_NO_STATE;
2878       sshc->actualcode = CURLE_QUOTE_ERROR;
2879       return;
2880     }
2881     sshc->quote_attrs->permissions = perms;
2882     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2883   }
2884   else if(strncasecompare(cmd, "chown", 5)) {
2885     sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2886     if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2887         !sshc->acceptfail) {
2888       Curl_safefree(sshc->quote_path1);
2889       Curl_safefree(sshc->quote_path2);
2890       failf(data, "Syntax error: chown uid not a number");
2891       state(data, SSH_SFTP_CLOSE);
2892       sshc->nextstate = SSH_NO_STATE;
2893       sshc->actualcode = CURLE_QUOTE_ERROR;
2894       return;
2895     }
2896     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2897   }
2898   else if(strncasecompare(cmd, "atime", 5) ||
2899           strncasecompare(cmd, "mtime", 5)) {
2900     time_t date = Curl_getdate_capped(sshc->quote_path1);
2901     bool fail = FALSE;
2902     if(date == -1) {
2903       failf(data, "incorrect date format for %.*s", 5, cmd);
2904       fail = TRUE;
2905     }
2906 #if SIZEOF_TIME_T > 4
2907     else if(date > 0xffffffff) {
2908       failf(data, "date overflow");
2909       fail = TRUE; /* avoid setting a capped time */
2910     }
2911 #endif
2912     if(fail) {
2913       Curl_safefree(sshc->quote_path1);
2914       Curl_safefree(sshc->quote_path2);
2915       state(data, SSH_SFTP_CLOSE);
2916       sshc->nextstate = SSH_NO_STATE;
2917       sshc->actualcode = CURLE_QUOTE_ERROR;
2918       return;
2919     }
2920     if(strncasecompare(cmd, "atime", 5))
2921       sshc->quote_attrs->atime = (uint32_t)date;
2922     else /* mtime */
2923       sshc->quote_attrs->mtime = (uint32_t)date;
2924 
2925     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2926   }
2927 
2928   /* Now send the completed structure... */
2929   state(data, SSH_SFTP_QUOTE_SETSTAT);
2930   return;
2931 }
2932 
Curl_ssh_init(void)2933 CURLcode Curl_ssh_init(void)
2934 {
2935   if(ssh_init()) {
2936     DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2937     return CURLE_FAILED_INIT;
2938   }
2939   return CURLE_OK;
2940 }
2941 
Curl_ssh_cleanup(void)2942 void Curl_ssh_cleanup(void)
2943 {
2944   (void)ssh_finalize();
2945 }
2946 
Curl_ssh_version(char * buffer,size_t buflen)2947 void Curl_ssh_version(char *buffer, size_t buflen)
2948 {
2949   (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
2950 }
2951 
2952 #endif                          /* USE_LIBSSH */
2953