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,                    /* connection_check */
166   ZERO_NULL,                    /* attach connection */
167   PORT_SSH,                     /* defport */
168   CURLPROTO_SCP,                /* protocol */
169   CURLPROTO_SCP,                /* family */
170   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY    /* flags */
171 };
172 
173 /*
174  * SFTP protocol handler.
175  */
176 
177 const struct Curl_handler Curl_handler_sftp = {
178   "SFTP",                               /* scheme */
179   myssh_setup_connection,               /* setup_connection */
180   myssh_do_it,                          /* do_it */
181   sftp_done,                            /* done */
182   ZERO_NULL,                            /* do_more */
183   myssh_connect,                        /* connect_it */
184   myssh_multi_statemach,                /* connecting */
185   sftp_doing,                           /* doing */
186   myssh_getsock,                        /* proto_getsock */
187   myssh_getsock,                        /* doing_getsock */
188   ZERO_NULL,                            /* domore_getsock */
189   myssh_getsock,                        /* perform_getsock */
190   sftp_disconnect,                      /* disconnect */
191   ZERO_NULL,                            /* write_resp */
192   ZERO_NULL,                            /* connection_check */
193   ZERO_NULL,                            /* attach connection */
194   PORT_SSH,                             /* defport */
195   CURLPROTO_SFTP,                       /* protocol */
196   CURLPROTO_SFTP,                       /* family */
197   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
198   | PROTOPT_NOURLQUERY                  /* flags */
199 };
200 
sftp_error_to_CURLE(int err)201 static CURLcode sftp_error_to_CURLE(int err)
202 {
203   switch(err) {
204     case SSH_FX_OK:
205       return CURLE_OK;
206 
207     case SSH_FX_NO_SUCH_FILE:
208     case SSH_FX_NO_SUCH_PATH:
209       return CURLE_REMOTE_FILE_NOT_FOUND;
210 
211     case SSH_FX_PERMISSION_DENIED:
212     case SSH_FX_WRITE_PROTECT:
213       return CURLE_REMOTE_ACCESS_DENIED;
214 
215     case SSH_FX_FILE_ALREADY_EXISTS:
216       return CURLE_REMOTE_FILE_EXISTS;
217 
218     default:
219       break;
220   }
221 
222   return CURLE_SSH;
223 }
224 
225 #ifndef DEBUGBUILD
226 #define state(x,y) mystate(x,y)
227 #else
228 #define state(x,y) mystate(x,y, __LINE__)
229 #endif
230 
231 /*
232  * SSH State machine related code
233  */
234 /* This is the ONLY way to change SSH state! */
mystate(struct Curl_easy *data, sshstate nowstate , int lineno )235 static void mystate(struct Curl_easy *data, sshstate nowstate
236 #ifdef DEBUGBUILD
237                     , int lineno
238 #endif
239   )
240 {
241   struct connectdata *conn = data->conn;
242   struct ssh_conn *sshc = &conn->proto.sshc;
243 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
244   /* for debug purposes */
245   static const char *const names[] = {
246     "SSH_STOP",
247     "SSH_INIT",
248     "SSH_S_STARTUP",
249     "SSH_HOSTKEY",
250     "SSH_AUTHLIST",
251     "SSH_AUTH_PKEY_INIT",
252     "SSH_AUTH_PKEY",
253     "SSH_AUTH_PASS_INIT",
254     "SSH_AUTH_PASS",
255     "SSH_AUTH_AGENT_INIT",
256     "SSH_AUTH_AGENT_LIST",
257     "SSH_AUTH_AGENT",
258     "SSH_AUTH_HOST_INIT",
259     "SSH_AUTH_HOST",
260     "SSH_AUTH_KEY_INIT",
261     "SSH_AUTH_KEY",
262     "SSH_AUTH_GSSAPI",
263     "SSH_AUTH_DONE",
264     "SSH_SFTP_INIT",
265     "SSH_SFTP_REALPATH",
266     "SSH_SFTP_QUOTE_INIT",
267     "SSH_SFTP_POSTQUOTE_INIT",
268     "SSH_SFTP_QUOTE",
269     "SSH_SFTP_NEXT_QUOTE",
270     "SSH_SFTP_QUOTE_STAT",
271     "SSH_SFTP_QUOTE_SETSTAT",
272     "SSH_SFTP_QUOTE_SYMLINK",
273     "SSH_SFTP_QUOTE_MKDIR",
274     "SSH_SFTP_QUOTE_RENAME",
275     "SSH_SFTP_QUOTE_RMDIR",
276     "SSH_SFTP_QUOTE_UNLINK",
277     "SSH_SFTP_QUOTE_STATVFS",
278     "SSH_SFTP_GETINFO",
279     "SSH_SFTP_FILETIME",
280     "SSH_SFTP_TRANS_INIT",
281     "SSH_SFTP_UPLOAD_INIT",
282     "SSH_SFTP_CREATE_DIRS_INIT",
283     "SSH_SFTP_CREATE_DIRS",
284     "SSH_SFTP_CREATE_DIRS_MKDIR",
285     "SSH_SFTP_READDIR_INIT",
286     "SSH_SFTP_READDIR",
287     "SSH_SFTP_READDIR_LINK",
288     "SSH_SFTP_READDIR_BOTTOM",
289     "SSH_SFTP_READDIR_DONE",
290     "SSH_SFTP_DOWNLOAD_INIT",
291     "SSH_SFTP_DOWNLOAD_STAT",
292     "SSH_SFTP_CLOSE",
293     "SSH_SFTP_SHUTDOWN",
294     "SSH_SCP_TRANS_INIT",
295     "SSH_SCP_UPLOAD_INIT",
296     "SSH_SCP_DOWNLOAD_INIT",
297     "SSH_SCP_DOWNLOAD",
298     "SSH_SCP_DONE",
299     "SSH_SCP_SEND_EOF",
300     "SSH_SCP_WAIT_EOF",
301     "SSH_SCP_WAIT_CLOSE",
302     "SSH_SCP_CHANNEL_FREE",
303     "SSH_SESSION_DISCONNECT",
304     "SSH_SESSION_FREE",
305     "QUIT"
306   };
307 
308 
309   if(sshc->state != nowstate) {
310     infof(data, "SSH %p state change from %s to %s (line %d)",
311           (void *) sshc, names[sshc->state], names[nowstate],
312           lineno);
313   }
314 #endif
315 
316   sshc->state = nowstate;
317 }
318 
319 /* Multiple options:
320  * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
321  *    hash (90s style auth, not sure we should have it here)
322  * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
323  *    use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
324  *    is returned by it.
325  * 3. none of the above. We only accept if it is present on known hosts.
326  *
327  * Returns SSH_OK or SSH_ERROR.
328  */
myssh_is_known(struct Curl_easy *data)329 static int myssh_is_known(struct Curl_easy *data)
330 {
331   int rc;
332   struct connectdata *conn = data->conn;
333   struct ssh_conn *sshc = &conn->proto.sshc;
334   ssh_key pubkey;
335   size_t hlen;
336   unsigned char *hash = NULL;
337   char *found_base64 = NULL;
338   char *known_base64 = NULL;
339   int vstate;
340   enum curl_khmatch keymatch;
341   struct curl_khkey foundkey;
342   struct curl_khkey *knownkeyp = NULL;
343   curl_sshkeycallback func =
344     data->set.ssh_keyfunc;
345 
346 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
347   struct ssh_knownhosts_entry *knownhostsentry = NULL;
348   struct curl_khkey knownkey;
349 #endif
350 
351 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
352   rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
353 #else
354   rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
355 #endif
356   if(rc != SSH_OK)
357     return rc;
358 
359   if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
360     int i;
361     char md5buffer[33];
362     const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
363 
364     rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
365                                 &hash, &hlen);
366     if(rc != SSH_OK || hlen != 16) {
367       failf(data,
368             "Denied establishing ssh session: md5 fingerprint not available");
369       goto cleanup;
370     }
371 
372     for(i = 0; i < 16; i++)
373       msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
374 
375     infof(data, "SSH MD5 fingerprint: %s", md5buffer);
376 
377     if(!strcasecompare(md5buffer, pubkey_md5)) {
378       failf(data,
379             "Denied establishing ssh session: mismatch md5 fingerprint. "
380             "Remote %s is not equal to %s", md5buffer, pubkey_md5);
381       rc = SSH_ERROR;
382       goto cleanup;
383     }
384 
385     rc = SSH_OK;
386     goto cleanup;
387   }
388 
389   if(data->set.ssl.primary.verifyhost != TRUE) {
390     rc = SSH_OK;
391     goto cleanup;
392   }
393 
394 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
395   /* Get the known_key from the known hosts file */
396   vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
397                                              &knownhostsentry);
398 
399   /* Case an entry was found in a known hosts file */
400   if(knownhostsentry) {
401     if(knownhostsentry->publickey) {
402       rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
403                                         &known_base64);
404       if(rc != SSH_OK) {
405         goto cleanup;
406       }
407       knownkey.key = known_base64;
408       knownkey.len = strlen(known_base64);
409 
410       switch(ssh_key_type(knownhostsentry->publickey)) {
411         case SSH_KEYTYPE_RSA:
412           knownkey.keytype = CURLKHTYPE_RSA;
413           break;
414         case SSH_KEYTYPE_RSA1:
415           knownkey.keytype = CURLKHTYPE_RSA1;
416           break;
417         case SSH_KEYTYPE_ECDSA:
418         case SSH_KEYTYPE_ECDSA_P256:
419         case SSH_KEYTYPE_ECDSA_P384:
420         case SSH_KEYTYPE_ECDSA_P521:
421           knownkey.keytype = CURLKHTYPE_ECDSA;
422           break;
423         case SSH_KEYTYPE_ED25519:
424           knownkey.keytype = CURLKHTYPE_ED25519;
425           break;
426         case SSH_KEYTYPE_DSS:
427           knownkey.keytype = CURLKHTYPE_DSS;
428           break;
429         default:
430           rc = SSH_ERROR;
431           goto cleanup;
432       }
433       knownkeyp = &knownkey;
434     }
435   }
436 
437   switch(vstate) {
438     case SSH_KNOWN_HOSTS_OK:
439       keymatch = CURLKHMATCH_OK;
440       break;
441     case SSH_KNOWN_HOSTS_OTHER:
442     case SSH_KNOWN_HOSTS_NOT_FOUND:
443     case SSH_KNOWN_HOSTS_UNKNOWN:
444     case SSH_KNOWN_HOSTS_ERROR:
445       keymatch = CURLKHMATCH_MISSING;
446       break;
447   default:
448       keymatch = CURLKHMATCH_MISMATCH;
449       break;
450   }
451 
452 #else
453   vstate = ssh_is_server_known(sshc->ssh_session);
454   switch(vstate) {
455     case SSH_SERVER_KNOWN_OK:
456       keymatch = CURLKHMATCH_OK;
457       break;
458     case SSH_SERVER_FILE_NOT_FOUND:
459     case SSH_SERVER_NOT_KNOWN:
460       keymatch = CURLKHMATCH_MISSING;
461       break;
462   default:
463       keymatch = CURLKHMATCH_MISMATCH;
464       break;
465   }
466 #endif
467 
468   if(func) { /* use callback to determine action */
469     rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
470     if(rc != SSH_OK)
471       goto cleanup;
472 
473     foundkey.key = found_base64;
474     foundkey.len = strlen(found_base64);
475 
476     switch(ssh_key_type(pubkey)) {
477       case SSH_KEYTYPE_RSA:
478         foundkey.keytype = CURLKHTYPE_RSA;
479         break;
480       case SSH_KEYTYPE_RSA1:
481         foundkey.keytype = CURLKHTYPE_RSA1;
482         break;
483       case SSH_KEYTYPE_ECDSA:
484 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
485       case SSH_KEYTYPE_ECDSA_P256:
486       case SSH_KEYTYPE_ECDSA_P384:
487       case SSH_KEYTYPE_ECDSA_P521:
488 #endif
489         foundkey.keytype = CURLKHTYPE_ECDSA;
490         break;
491 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
492       case SSH_KEYTYPE_ED25519:
493         foundkey.keytype = CURLKHTYPE_ED25519;
494         break;
495 #endif
496       case SSH_KEYTYPE_DSS:
497         foundkey.keytype = CURLKHTYPE_DSS;
498         break;
499       default:
500         rc = SSH_ERROR;
501         goto cleanup;
502     }
503 
504     Curl_set_in_callback(data, true);
505     rc = func(data, knownkeyp, /* from the knownhosts file */
506               &foundkey, /* from the remote host */
507               keymatch, data->set.ssh_keyfunc_userp);
508     Curl_set_in_callback(data, false);
509 
510     switch(rc) {
511       case CURLKHSTAT_FINE_ADD_TO_FILE:
512 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
513         rc = ssh_session_update_known_hosts(sshc->ssh_session);
514 #else
515         rc = ssh_write_knownhost(sshc->ssh_session);
516 #endif
517         if(rc != SSH_OK) {
518           goto cleanup;
519         }
520         break;
521       case CURLKHSTAT_FINE:
522         break;
523       default: /* REJECT/DEFER */
524         rc = SSH_ERROR;
525         goto cleanup;
526     }
527   }
528   else {
529     if(keymatch != CURLKHMATCH_OK) {
530       rc = SSH_ERROR;
531       goto cleanup;
532     }
533   }
534   rc = SSH_OK;
535 
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(conn->seek_func) {
1296           Curl_set_in_callback(data, true);
1297           seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1298                                     SEEK_SET);
1299           Curl_set_in_callback(data, false);
1300         }
1301 
1302         if(seekerr != CURL_SEEKFUNC_OK) {
1303           curl_off_t passed = 0;
1304 
1305           if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1306             failf(data, "Could not seek stream");
1307             return CURLE_FTP_COULDNT_USE_REST;
1308           }
1309           /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1310           do {
1311             char scratch[4*1024];
1312             size_t readthisamountnow =
1313               (data->state.resume_from - passed >
1314                 (curl_off_t)sizeof(scratch)) ?
1315               sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
1316 
1317             size_t actuallyread =
1318               data->state.fread_func(scratch, 1,
1319                                      readthisamountnow, data->state.in);
1320 
1321             passed += actuallyread;
1322             if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1323               /* this checks for greater-than only to make sure that the
1324                  CURL_READFUNC_ABORT return code still aborts */
1325               failf(data, "Failed to read data");
1326               MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
1327               break;
1328             }
1329           } while(passed < data->state.resume_from);
1330           if(rc)
1331             break;
1332         }
1333 
1334         /* now, decrease the size of the read */
1335         if(data->state.infilesize > 0) {
1336           data->state.infilesize -= data->state.resume_from;
1337           data->req.size = data->state.infilesize;
1338           Curl_pgrsSetUploadSize(data, data->state.infilesize);
1339         }
1340 
1341         rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1342         if(rc) {
1343           MOVE_TO_SFTP_CLOSE_STATE();
1344           break;
1345         }
1346       }
1347       if(data->state.infilesize > 0) {
1348         data->req.size = data->state.infilesize;
1349         Curl_pgrsSetUploadSize(data, data->state.infilesize);
1350       }
1351       /* upload data */
1352       Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
1353 
1354       /* not set by Curl_setup_transfer to preserve keepon bits */
1355       conn->sockfd = conn->writesockfd;
1356 
1357       /* store this original bitmask setup to use later on if we can't
1358          figure out a "real" bitmask */
1359       sshc->orig_waitfor = data->req.keepon;
1360 
1361       /* we want to use the _sending_ function even when the socket turns
1362          out readable as the underlying libssh sftp send function will deal
1363          with both accordingly */
1364       data->state.select_bits = CURL_CSELECT_OUT;
1365 
1366       /* since we don't really wait for anything at this point, we want the
1367          state machine to move on as soon as possible so we set a very short
1368          timeout here */
1369       Curl_expire(data, 0, EXPIRE_RUN_NOW);
1370 
1371       state(data, SSH_STOP);
1372       break;
1373     }
1374 
1375     case SSH_SFTP_CREATE_DIRS_INIT:
1376       if(strlen(protop->path) > 1) {
1377         sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1378         state(data, SSH_SFTP_CREATE_DIRS);
1379       }
1380       else {
1381         state(data, SSH_SFTP_UPLOAD_INIT);
1382       }
1383       break;
1384 
1385     case SSH_SFTP_CREATE_DIRS:
1386       sshc->slash_pos = strchr(sshc->slash_pos, '/');
1387       if(sshc->slash_pos) {
1388         *sshc->slash_pos = 0;
1389 
1390         infof(data, "Creating directory '%s'", protop->path);
1391         state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
1392         break;
1393       }
1394       state(data, SSH_SFTP_UPLOAD_INIT);
1395       break;
1396 
1397     case SSH_SFTP_CREATE_DIRS_MKDIR:
1398       /* 'mode' - parameter is preliminary - default to 0644 */
1399       rc = sftp_mkdir(sshc->sftp_session, protop->path,
1400                       (mode_t)data->set.new_directory_perms);
1401       *sshc->slash_pos = '/';
1402       ++sshc->slash_pos;
1403       if(rc < 0) {
1404         /*
1405          * Abort if failure wasn't that the dir already exists or the
1406          * permission was denied (creation might succeed further down the
1407          * path) - retry on unspecific FAILURE also
1408          */
1409         err = sftp_get_error(sshc->sftp_session);
1410         if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1411            (err != SSH_FX_FAILURE) &&
1412            (err != SSH_FX_PERMISSION_DENIED)) {
1413           MOVE_TO_SFTP_CLOSE_STATE();
1414           break;
1415         }
1416         rc = 0; /* clear rc and continue */
1417       }
1418       state(data, SSH_SFTP_CREATE_DIRS);
1419       break;
1420 
1421     case SSH_SFTP_READDIR_INIT:
1422       Curl_pgrsSetDownloadSize(data, -1);
1423       if(data->req.no_body) {
1424         state(data, SSH_STOP);
1425         break;
1426       }
1427 
1428       /*
1429        * This is a directory that we are trying to get, so produce a directory
1430        * listing
1431        */
1432       sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1433                                     protop->path);
1434       if(!sshc->sftp_dir) {
1435         failf(data, "Could not open directory for reading: %s",
1436               ssh_get_error(sshc->ssh_session));
1437         MOVE_TO_SFTP_CLOSE_STATE();
1438         break;
1439       }
1440       state(data, SSH_SFTP_READDIR);
1441       break;
1442 
1443     case SSH_SFTP_READDIR:
1444       Curl_dyn_reset(&sshc->readdir_buf);
1445       if(sshc->readdir_attrs)
1446         sftp_attributes_free(sshc->readdir_attrs);
1447 
1448       sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1449       if(sshc->readdir_attrs) {
1450         sshc->readdir_filename = sshc->readdir_attrs->name;
1451         sshc->readdir_longentry = sshc->readdir_attrs->longname;
1452         sshc->readdir_len = strlen(sshc->readdir_filename);
1453 
1454         if(data->set.list_only) {
1455           char *tmpLine;
1456 
1457           tmpLine = aprintf("%s\n", sshc->readdir_filename);
1458           if(!tmpLine) {
1459             state(data, SSH_SFTP_CLOSE);
1460             sshc->actualcode = CURLE_OUT_OF_MEMORY;
1461             break;
1462           }
1463           result = Curl_client_write(data, CLIENTWRITE_BODY,
1464                                      tmpLine, sshc->readdir_len + 1);
1465           free(tmpLine);
1466 
1467           if(result) {
1468             state(data, SSH_STOP);
1469             break;
1470           }
1471 
1472         }
1473         else {
1474           if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
1475             sshc->actualcode = CURLE_OUT_OF_MEMORY;
1476             state(data, SSH_STOP);
1477             break;
1478           }
1479 
1480           if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1481              ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
1482               SSH_S_IFLNK)) {
1483             sshc->readdir_linkPath = aprintf("%s%s", protop->path,
1484                                              sshc->readdir_filename);
1485 
1486             if(!sshc->readdir_linkPath) {
1487               state(data, SSH_SFTP_CLOSE);
1488               sshc->actualcode = CURLE_OUT_OF_MEMORY;
1489               break;
1490             }
1491 
1492             state(data, SSH_SFTP_READDIR_LINK);
1493             break;
1494           }
1495           state(data, SSH_SFTP_READDIR_BOTTOM);
1496           break;
1497         }
1498       }
1499       else if(sftp_dir_eof(sshc->sftp_dir)) {
1500         state(data, SSH_SFTP_READDIR_DONE);
1501         break;
1502       }
1503       else {
1504         failf(data, "Could not open remote file for reading: %s",
1505               ssh_get_error(sshc->ssh_session));
1506         MOVE_TO_SFTP_CLOSE_STATE();
1507         break;
1508       }
1509       break;
1510 
1511     case SSH_SFTP_READDIR_LINK:
1512       if(sshc->readdir_link_attrs)
1513         sftp_attributes_free(sshc->readdir_link_attrs);
1514 
1515       sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1516                                             sshc->readdir_linkPath);
1517       if(sshc->readdir_link_attrs == 0) {
1518         failf(data, "Could not read symlink for reading: %s",
1519               ssh_get_error(sshc->ssh_session));
1520         MOVE_TO_SFTP_CLOSE_STATE();
1521         break;
1522       }
1523 
1524       if(!sshc->readdir_link_attrs->name) {
1525         sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1526                                           sshc->readdir_linkPath);
1527         if(!sshc->readdir_filename)
1528           sshc->readdir_len = 0;
1529         else
1530           sshc->readdir_len = strlen(sshc->readdir_tmp);
1531         sshc->readdir_longentry = NULL;
1532         sshc->readdir_filename = sshc->readdir_tmp;
1533       }
1534       else {
1535         sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
1536         sshc->readdir_filename = sshc->readdir_link_attrs->name;
1537         sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1538       }
1539 
1540       Curl_safefree(sshc->readdir_linkPath);
1541 
1542       if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
1543                        sshc->readdir_filename)) {
1544         sshc->actualcode = CURLE_OUT_OF_MEMORY;
1545         break;
1546       }
1547 
1548       sftp_attributes_free(sshc->readdir_link_attrs);
1549       sshc->readdir_link_attrs = NULL;
1550       sshc->readdir_filename = NULL;
1551       sshc->readdir_longentry = NULL;
1552 
1553       state(data, SSH_SFTP_READDIR_BOTTOM);
1554       FALLTHROUGH();
1555     case SSH_SFTP_READDIR_BOTTOM:
1556       if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
1557         result = CURLE_OUT_OF_MEMORY;
1558       else
1559         result = Curl_client_write(data, CLIENTWRITE_BODY,
1560                                    Curl_dyn_ptr(&sshc->readdir_buf),
1561                                    Curl_dyn_len(&sshc->readdir_buf));
1562 
1563       ssh_string_free_char(sshc->readdir_tmp);
1564       sshc->readdir_tmp = NULL;
1565 
1566       if(result) {
1567         state(data, SSH_STOP);
1568       }
1569       else
1570         state(data, SSH_SFTP_READDIR);
1571       break;
1572 
1573     case SSH_SFTP_READDIR_DONE:
1574       sftp_closedir(sshc->sftp_dir);
1575       sshc->sftp_dir = NULL;
1576 
1577       /* no data to transfer */
1578       Curl_setup_transfer(data, -1, -1, FALSE, -1);
1579       state(data, SSH_STOP);
1580       break;
1581 
1582     case SSH_SFTP_DOWNLOAD_INIT:
1583       /*
1584        * Work on getting the specified file
1585        */
1586       if(sshc->sftp_file)
1587         sftp_close(sshc->sftp_file);
1588 
1589       sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1590                                   O_RDONLY, (mode_t)data->set.new_file_perms);
1591       if(!sshc->sftp_file) {
1592         failf(data, "Could not open remote file for reading: %s",
1593               ssh_get_error(sshc->ssh_session));
1594 
1595         MOVE_TO_SFTP_CLOSE_STATE();
1596         break;
1597       }
1598       sftp_file_set_nonblocking(sshc->sftp_file);
1599       state(data, SSH_SFTP_DOWNLOAD_STAT);
1600       break;
1601 
1602     case SSH_SFTP_DOWNLOAD_STAT:
1603     {
1604       sftp_attributes attrs;
1605       curl_off_t size;
1606 
1607       attrs = sftp_fstat(sshc->sftp_file);
1608       if(!attrs ||
1609               !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1610               (attrs->size == 0)) {
1611         /*
1612          * sftp_fstat didn't return an error, so maybe the server
1613          * just doesn't support stat()
1614          * OR the server doesn't return a file size with a stat()
1615          * OR file size is 0
1616          */
1617         data->req.size = -1;
1618         data->req.maxdownload = -1;
1619         Curl_pgrsSetDownloadSize(data, -1);
1620         size = 0;
1621       }
1622       else {
1623         size = attrs->size;
1624 
1625         sftp_attributes_free(attrs);
1626 
1627         if(size < 0) {
1628           failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1629           return CURLE_BAD_DOWNLOAD_RESUME;
1630         }
1631         if(data->state.use_range) {
1632           curl_off_t from, to;
1633           char *ptr;
1634           char *ptr2;
1635           CURLofft to_t;
1636           CURLofft from_t;
1637 
1638           from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
1639           if(from_t == CURL_OFFT_FLOW) {
1640             return CURLE_RANGE_ERROR;
1641           }
1642           while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
1643             ptr++;
1644           to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
1645           if(to_t == CURL_OFFT_FLOW) {
1646             return CURLE_RANGE_ERROR;
1647           }
1648           if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1649              || (to >= size)) {
1650             to = size - 1;
1651           }
1652           if(from_t) {
1653             /* from is relative to end of file */
1654             from = size - to;
1655             to = size - 1;
1656           }
1657           if(from > size) {
1658             failf(data, "Offset (%"
1659                   CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1660                   CURL_FORMAT_CURL_OFF_T ")", from, size);
1661             return CURLE_BAD_DOWNLOAD_RESUME;
1662           }
1663           if(from > to) {
1664             from = to;
1665             size = 0;
1666           }
1667           else {
1668             size = to - from + 1;
1669           }
1670 
1671           rc = sftp_seek64(sshc->sftp_file, from);
1672           if(rc) {
1673             MOVE_TO_SFTP_CLOSE_STATE();
1674             break;
1675           }
1676         }
1677         data->req.size = size;
1678         data->req.maxdownload = size;
1679         Curl_pgrsSetDownloadSize(data, size);
1680       }
1681 
1682       /* We can resume if we can seek to the resume position */
1683       if(data->state.resume_from) {
1684         if(data->state.resume_from < 0) {
1685           /* We're supposed to download the last abs(from) bytes */
1686           if((curl_off_t)size < -data->state.resume_from) {
1687             failf(data, "Offset (%"
1688                   CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1689                   CURL_FORMAT_CURL_OFF_T ")",
1690                   data->state.resume_from, size);
1691             return CURLE_BAD_DOWNLOAD_RESUME;
1692           }
1693           /* download from where? */
1694           data->state.resume_from += size;
1695         }
1696         else {
1697           if((curl_off_t)size < data->state.resume_from) {
1698             failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
1699                   ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
1700                   data->state.resume_from, size);
1701             return CURLE_BAD_DOWNLOAD_RESUME;
1702           }
1703         }
1704         /* Now store the number of bytes we are expected to download */
1705         data->req.size = size - data->state.resume_from;
1706         data->req.maxdownload = size - data->state.resume_from;
1707         Curl_pgrsSetDownloadSize(data,
1708                                  size - data->state.resume_from);
1709 
1710         rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1711         if(rc) {
1712           MOVE_TO_SFTP_CLOSE_STATE();
1713           break;
1714         }
1715       }
1716     }
1717 
1718     /* Setup the actual download */
1719     if(data->req.size == 0) {
1720       /* no data to transfer */
1721       Curl_setup_transfer(data, -1, -1, FALSE, -1);
1722       infof(data, "File already completely downloaded");
1723       state(data, SSH_STOP);
1724       break;
1725     }
1726     Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
1727 
1728     /* not set by Curl_setup_transfer to preserve keepon bits */
1729     conn->writesockfd = conn->sockfd;
1730 
1731     /* we want to use the _receiving_ function even when the socket turns
1732        out writableable as the underlying libssh recv function will deal
1733        with both accordingly */
1734     data->state.select_bits = CURL_CSELECT_IN;
1735 
1736     if(result) {
1737       /* this should never occur; the close state should be entered
1738          at the time the error occurs */
1739       state(data, SSH_SFTP_CLOSE);
1740       sshc->actualcode = result;
1741     }
1742     else {
1743       sshc->sftp_recv_state = 0;
1744       state(data, SSH_STOP);
1745     }
1746     break;
1747 
1748     case SSH_SFTP_CLOSE:
1749       if(sshc->sftp_file) {
1750         sftp_close(sshc->sftp_file);
1751         sshc->sftp_file = NULL;
1752       }
1753       Curl_safefree(protop->path);
1754 
1755       DEBUGF(infof(data, "SFTP DONE done"));
1756 
1757       /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
1758          After nextstate is executed, the control should come back to
1759          SSH_SFTP_CLOSE to pass the correct result back  */
1760       if(sshc->nextstate != SSH_NO_STATE &&
1761          sshc->nextstate != SSH_SFTP_CLOSE) {
1762         state(data, sshc->nextstate);
1763         sshc->nextstate = SSH_SFTP_CLOSE;
1764       }
1765       else {
1766         state(data, SSH_STOP);
1767         result = sshc->actualcode;
1768       }
1769       break;
1770 
1771     case SSH_SFTP_SHUTDOWN:
1772       /* during times we get here due to a broken transfer and then the
1773          sftp_handle might not have been taken down so make sure that is done
1774          before we proceed */
1775 
1776       if(sshc->sftp_file) {
1777         sftp_close(sshc->sftp_file);
1778         sshc->sftp_file = NULL;
1779       }
1780 
1781       if(sshc->sftp_session) {
1782         sftp_free(sshc->sftp_session);
1783         sshc->sftp_session = NULL;
1784       }
1785 
1786       SSH_STRING_FREE_CHAR(sshc->homedir);
1787       data->state.most_recent_ftp_entrypath = NULL;
1788 
1789       state(data, SSH_SESSION_DISCONNECT);
1790       break;
1791 
1792     case SSH_SCP_TRANS_INIT:
1793       result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
1794       if(result) {
1795         sshc->actualcode = result;
1796         state(data, SSH_STOP);
1797         break;
1798       }
1799 
1800       /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
1801       ssh_set_blocking(sshc->ssh_session, 1);
1802 
1803       if(data->state.upload) {
1804         if(data->state.infilesize < 0) {
1805           failf(data, "SCP requires a known file size for upload");
1806           sshc->actualcode = CURLE_UPLOAD_FAILED;
1807           MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1808           break;
1809         }
1810 
1811         sshc->scp_session =
1812           ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
1813         state(data, SSH_SCP_UPLOAD_INIT);
1814       }
1815       else {
1816         sshc->scp_session =
1817           ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
1818         state(data, SSH_SCP_DOWNLOAD_INIT);
1819       }
1820 
1821       if(!sshc->scp_session) {
1822         err_msg = ssh_get_error(sshc->ssh_session);
1823         failf(data, "%s", err_msg);
1824         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1825       }
1826 
1827       break;
1828 
1829     case SSH_SCP_UPLOAD_INIT:
1830 
1831       rc = ssh_scp_init(sshc->scp_session);
1832       if(rc != SSH_OK) {
1833         err_msg = ssh_get_error(sshc->ssh_session);
1834         failf(data, "%s", err_msg);
1835         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1836         break;
1837       }
1838 
1839       rc = ssh_scp_push_file(sshc->scp_session, protop->path,
1840                              data->state.infilesize,
1841                              (int)data->set.new_file_perms);
1842       if(rc != SSH_OK) {
1843         err_msg = ssh_get_error(sshc->ssh_session);
1844         failf(data, "%s", err_msg);
1845         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1846         break;
1847       }
1848 
1849       /* upload data */
1850       Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
1851 
1852       /* not set by Curl_setup_transfer to preserve keepon bits */
1853       conn->sockfd = conn->writesockfd;
1854 
1855       /* store this original bitmask setup to use later on if we can't
1856          figure out a "real" bitmask */
1857       sshc->orig_waitfor = data->req.keepon;
1858 
1859       /* we want to use the _sending_ function even when the socket turns
1860          out readable as the underlying libssh scp send function will deal
1861          with both accordingly */
1862       data->state.select_bits = CURL_CSELECT_OUT;
1863 
1864       state(data, SSH_STOP);
1865 
1866       break;
1867 
1868     case SSH_SCP_DOWNLOAD_INIT:
1869 
1870       rc = ssh_scp_init(sshc->scp_session);
1871       if(rc != SSH_OK) {
1872         err_msg = ssh_get_error(sshc->ssh_session);
1873         failf(data, "%s", err_msg);
1874         MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
1875         break;
1876       }
1877       state(data, SSH_SCP_DOWNLOAD);
1878       FALLTHROUGH();
1879 
1880     case SSH_SCP_DOWNLOAD:{
1881         curl_off_t bytecount;
1882 
1883         rc = ssh_scp_pull_request(sshc->scp_session);
1884         if(rc != SSH_SCP_REQUEST_NEWFILE) {
1885           err_msg = ssh_get_error(sshc->ssh_session);
1886           failf(data, "%s", err_msg);
1887           MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
1888           break;
1889         }
1890 
1891         /* download data */
1892         bytecount = ssh_scp_request_get_size(sshc->scp_session);
1893         data->req.maxdownload = (curl_off_t) bytecount;
1894         Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
1895 
1896         /* not set by Curl_setup_transfer to preserve keepon bits */
1897         conn->writesockfd = conn->sockfd;
1898 
1899         /* we want to use the _receiving_ function even when the socket turns
1900            out writableable as the underlying libssh recv function will deal
1901            with both accordingly */
1902         data->state.select_bits = CURL_CSELECT_IN;
1903 
1904         state(data, SSH_STOP);
1905         break;
1906       }
1907     case SSH_SCP_DONE:
1908       if(data->state.upload)
1909         state(data, SSH_SCP_SEND_EOF);
1910       else
1911         state(data, SSH_SCP_CHANNEL_FREE);
1912       break;
1913 
1914     case SSH_SCP_SEND_EOF:
1915       if(sshc->scp_session) {
1916         rc = ssh_scp_close(sshc->scp_session);
1917         if(rc == SSH_AGAIN) {
1918           /* Currently the ssh_scp_close handles waiting for EOF in
1919            * blocking way.
1920            */
1921           break;
1922         }
1923         if(rc != SSH_OK) {
1924           infof(data, "Failed to close libssh scp channel: %s",
1925                 ssh_get_error(sshc->ssh_session));
1926         }
1927       }
1928 
1929       state(data, SSH_SCP_CHANNEL_FREE);
1930       break;
1931 
1932     case SSH_SCP_CHANNEL_FREE:
1933       if(sshc->scp_session) {
1934         ssh_scp_free(sshc->scp_session);
1935         sshc->scp_session = NULL;
1936       }
1937       DEBUGF(infof(data, "SCP DONE phase complete"));
1938 
1939       ssh_set_blocking(sshc->ssh_session, 0);
1940 
1941       state(data, SSH_SESSION_DISCONNECT);
1942       FALLTHROUGH();
1943 
1944     case SSH_SESSION_DISCONNECT:
1945       /* during weird times when we've been prematurely aborted, the channel
1946          is still alive when we reach this state and we MUST kill the channel
1947          properly first */
1948       if(sshc->scp_session) {
1949         ssh_scp_free(sshc->scp_session);
1950         sshc->scp_session = NULL;
1951       }
1952 
1953       ssh_disconnect(sshc->ssh_session);
1954       if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
1955         /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
1956            tell the connection to forget about it. This libssh
1957            bug is fixed in 0.10.0. */
1958         Curl_conn_forget_socket(data, FIRSTSOCKET);
1959       }
1960 
1961       SSH_STRING_FREE_CHAR(sshc->homedir);
1962       data->state.most_recent_ftp_entrypath = NULL;
1963 
1964       state(data, SSH_SESSION_FREE);
1965       FALLTHROUGH();
1966     case SSH_SESSION_FREE:
1967       if(sshc->ssh_session) {
1968         ssh_free(sshc->ssh_session);
1969         sshc->ssh_session = NULL;
1970       }
1971 
1972       /* worst-case scenario cleanup */
1973 
1974       DEBUGASSERT(sshc->ssh_session == NULL);
1975       DEBUGASSERT(sshc->scp_session == NULL);
1976 
1977       if(sshc->readdir_tmp) {
1978         ssh_string_free_char(sshc->readdir_tmp);
1979         sshc->readdir_tmp = NULL;
1980       }
1981 
1982       if(sshc->quote_attrs)
1983         sftp_attributes_free(sshc->quote_attrs);
1984 
1985       if(sshc->readdir_attrs)
1986         sftp_attributes_free(sshc->readdir_attrs);
1987 
1988       if(sshc->readdir_link_attrs)
1989         sftp_attributes_free(sshc->readdir_link_attrs);
1990 
1991       if(sshc->privkey)
1992         ssh_key_free(sshc->privkey);
1993       if(sshc->pubkey)
1994         ssh_key_free(sshc->pubkey);
1995 
1996       Curl_safefree(sshc->rsa_pub);
1997       Curl_safefree(sshc->rsa);
1998       Curl_safefree(sshc->quote_path1);
1999       Curl_safefree(sshc->quote_path2);
2000       Curl_dyn_free(&sshc->readdir_buf);
2001       Curl_safefree(sshc->readdir_linkPath);
2002       SSH_STRING_FREE_CHAR(sshc->homedir);
2003 
2004       /* the code we are about to return */
2005       result = sshc->actualcode;
2006 
2007       memset(sshc, 0, sizeof(struct ssh_conn));
2008 
2009       connclose(conn, "SSH session free");
2010       sshc->state = SSH_SESSION_FREE;   /* current */
2011       sshc->nextstate = SSH_NO_STATE;
2012       state(data, SSH_STOP);
2013       break;
2014 
2015     case SSH_QUIT:
2016     default:
2017       /* internal error */
2018       sshc->nextstate = SSH_NO_STATE;
2019       state(data, SSH_STOP);
2020       break;
2021 
2022     }
2023   } while(!rc && (sshc->state != SSH_STOP));
2024 
2025 
2026   if(rc == SSH_AGAIN) {
2027     /* we would block, we need to wait for the socket to be ready (in the
2028        right direction too)! */
2029     *block = TRUE;
2030   }
2031 
2032   return result;
2033 }
2034 
2035 
2036 /* called by the multi interface to figure out what socket(s) to wait for and
2037    for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
myssh_getsock(struct Curl_easy *data, struct connectdata *conn, curl_socket_t *sock)2038 static int myssh_getsock(struct Curl_easy *data,
2039                          struct connectdata *conn,
2040                          curl_socket_t *sock)
2041 {
2042   int bitmap = GETSOCK_BLANK;
2043   (void)data;
2044   sock[0] = conn->sock[FIRSTSOCKET];
2045 
2046   if(conn->waitfor & KEEP_RECV)
2047     bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
2048 
2049   if(conn->waitfor & KEEP_SEND)
2050     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2051 
2052   if(!conn->waitfor)
2053     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2054 
2055   return bitmap;
2056 }
2057 
myssh_block2waitfor(struct connectdata *conn, bool block)2058 static void myssh_block2waitfor(struct connectdata *conn, bool block)
2059 {
2060   struct ssh_conn *sshc = &conn->proto.sshc;
2061 
2062   /* If it didn't block, or nothing was returned by ssh_get_poll_flags
2063    * have the original set */
2064   conn->waitfor = sshc->orig_waitfor;
2065 
2066   if(block) {
2067     int dir = ssh_get_poll_flags(sshc->ssh_session);
2068     if(dir & SSH_READ_PENDING) {
2069       /* translate the libssh define bits into our own bit defines */
2070       conn->waitfor = KEEP_RECV;
2071     }
2072     else if(dir & SSH_WRITE_PENDING) {
2073       conn->waitfor = KEEP_SEND;
2074     }
2075   }
2076 }
2077 
2078 /* called repeatedly until done from multi.c */
myssh_multi_statemach(struct Curl_easy *data, bool *done)2079 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
2080                                       bool *done)
2081 {
2082   struct connectdata *conn = data->conn;
2083   struct ssh_conn *sshc = &conn->proto.sshc;
2084   bool block;    /* we store the status and use that to provide a ssh_getsock()
2085                     implementation */
2086   CURLcode result = myssh_statemach_act(data, &block);
2087 
2088   *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
2089   myssh_block2waitfor(conn, block);
2090 
2091   return result;
2092 }
2093 
myssh_block_statemach(struct Curl_easy *data, bool disconnect)2094 static CURLcode myssh_block_statemach(struct Curl_easy *data,
2095                                       bool disconnect)
2096 {
2097   struct connectdata *conn = data->conn;
2098   struct ssh_conn *sshc = &conn->proto.sshc;
2099   CURLcode result = CURLE_OK;
2100 
2101   while((sshc->state != SSH_STOP) && !result) {
2102     bool block;
2103     timediff_t left = 1000;
2104     struct curltime now = Curl_now();
2105 
2106     result = myssh_statemach_act(data, &block);
2107     if(result)
2108       break;
2109 
2110     if(!disconnect) {
2111       if(Curl_pgrsUpdate(data))
2112         return CURLE_ABORTED_BY_CALLBACK;
2113 
2114       result = Curl_speedcheck(data, now);
2115       if(result)
2116         break;
2117 
2118       left = Curl_timeleft(data, NULL, FALSE);
2119       if(left < 0) {
2120         failf(data, "Operation timed out");
2121         return CURLE_OPERATION_TIMEDOUT;
2122       }
2123     }
2124 
2125     if(block) {
2126       curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
2127       /* wait for the socket to become ready */
2128       (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2129                                CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2130     }
2131 
2132   }
2133 
2134   return result;
2135 }
2136 
2137 /*
2138  * SSH setup connection
2139  */
myssh_setup_connection(struct Curl_easy *data, struct connectdata *conn)2140 static CURLcode myssh_setup_connection(struct Curl_easy *data,
2141                                        struct connectdata *conn)
2142 {
2143   struct SSHPROTO *ssh;
2144   struct ssh_conn *sshc = &conn->proto.sshc;
2145 
2146   data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
2147   if(!ssh)
2148     return CURLE_OUT_OF_MEMORY;
2149   Curl_dyn_init(&sshc->readdir_buf, PATH_MAX * 2);
2150 
2151   return CURLE_OK;
2152 }
2153 
2154 static Curl_recv scp_recv, sftp_recv;
2155 static Curl_send scp_send, sftp_send;
2156 
2157 /*
2158  * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2159  * do protocol-specific actions at connect-time.
2160  */
myssh_connect(struct Curl_easy *data, bool *done)2161 static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
2162 {
2163   struct ssh_conn *ssh;
2164   CURLcode result;
2165   struct connectdata *conn = data->conn;
2166   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2167   int rc;
2168 
2169   /* initialize per-handle data if not already */
2170   if(!data->req.p.ssh)
2171     myssh_setup_connection(data, conn);
2172 
2173   /* We default to persistent connections. We set this already in this connect
2174      function to make the reuse checks properly be able to check this bit. */
2175   connkeep(conn, "SSH default");
2176 
2177   if(conn->handler->protocol & CURLPROTO_SCP) {
2178     conn->recv[FIRSTSOCKET] = scp_recv;
2179     conn->send[FIRSTSOCKET] = scp_send;
2180   }
2181   else {
2182     conn->recv[FIRSTSOCKET] = sftp_recv;
2183     conn->send[FIRSTSOCKET] = sftp_send;
2184   }
2185 
2186   ssh = &conn->proto.sshc;
2187 
2188   ssh->ssh_session = ssh_new();
2189   if(!ssh->ssh_session) {
2190     failf(data, "Failure initialising ssh session");
2191     return CURLE_FAILED_INIT;
2192   }
2193 
2194   rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2195   if(rc != SSH_OK) {
2196     failf(data, "Could not set remote host");
2197     return CURLE_FAILED_INIT;
2198   }
2199 
2200   rc = ssh_options_parse_config(ssh->ssh_session, NULL);
2201   if(rc != SSH_OK) {
2202     infof(data, "Could not parse SSH configuration files");
2203     /* ignore */
2204   }
2205 
2206   rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2207   if(rc != SSH_OK) {
2208     failf(data, "Could not set socket");
2209     return CURLE_FAILED_INIT;
2210   }
2211 
2212   if(conn->user && conn->user[0] != '\0') {
2213     infof(data, "User: %s", conn->user);
2214     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2215     if(rc != SSH_OK) {
2216       failf(data, "Could not set user");
2217       return CURLE_FAILED_INIT;
2218     }
2219   }
2220 
2221   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2222     infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
2223     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2224                          data->set.str[STRING_SSH_KNOWNHOSTS]);
2225     if(rc != SSH_OK) {
2226       failf(data, "Could not set known hosts file path");
2227       return CURLE_FAILED_INIT;
2228     }
2229   }
2230 
2231   if(conn->remote_port) {
2232     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2233                          &conn->remote_port);
2234     if(rc != SSH_OK) {
2235       failf(data, "Could not set remote port");
2236       return CURLE_FAILED_INIT;
2237     }
2238   }
2239 
2240   if(data->set.ssh_compression) {
2241     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2242                          "zlib,zlib@openssh.com,none");
2243     if(rc != SSH_OK) {
2244       failf(data, "Could not set compression");
2245       return CURLE_FAILED_INIT;
2246     }
2247   }
2248 
2249   ssh->privkey = NULL;
2250   ssh->pubkey = NULL;
2251 
2252   if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2253     rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2254                                     &ssh->pubkey);
2255     if(rc != SSH_OK) {
2256       failf(data, "Could not load public key file");
2257       return CURLE_FAILED_INIT;
2258     }
2259   }
2260 
2261   /* we do not verify here, we do it at the state machine,
2262    * after connection */
2263 
2264   state(data, SSH_INIT);
2265 
2266   result = myssh_multi_statemach(data, done);
2267 
2268   return result;
2269 }
2270 
2271 /* called from multi.c while DOing */
scp_doing(struct Curl_easy *data, bool *dophase_done)2272 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
2273 {
2274   CURLcode result;
2275 
2276   result = myssh_multi_statemach(data, dophase_done);
2277 
2278   if(*dophase_done) {
2279     DEBUGF(infof(data, "DO phase is complete"));
2280   }
2281   return result;
2282 }
2283 
2284 /*
2285  ***********************************************************************
2286  *
2287  * scp_perform()
2288  *
2289  * This is the actual DO function for SCP. Get a file according to
2290  * the options previously setup.
2291  */
2292 
2293 static
scp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done)2294 CURLcode scp_perform(struct Curl_easy *data,
2295                      bool *connected, bool *dophase_done)
2296 {
2297   CURLcode result = CURLE_OK;
2298 
2299   DEBUGF(infof(data, "DO phase starts"));
2300 
2301   *dophase_done = FALSE;        /* not done yet */
2302 
2303   /* start the first command in the DO phase */
2304   state(data, SSH_SCP_TRANS_INIT);
2305 
2306   result = myssh_multi_statemach(data, dophase_done);
2307 
2308   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2309 
2310   if(*dophase_done) {
2311     DEBUGF(infof(data, "DO phase is complete"));
2312   }
2313 
2314   return result;
2315 }
2316 
myssh_do_it(struct Curl_easy *data, bool *done)2317 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
2318 {
2319   CURLcode result;
2320   bool connected = 0;
2321   struct connectdata *conn = data->conn;
2322   struct ssh_conn *sshc = &conn->proto.sshc;
2323 
2324   *done = FALSE;                /* default to false */
2325 
2326   data->req.size = -1;          /* make sure this is unknown at this point */
2327 
2328   sshc->actualcode = CURLE_OK;  /* reset error code */
2329   sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
2330                                    variable */
2331 
2332   Curl_pgrsSetUploadCounter(data, 0);
2333   Curl_pgrsSetDownloadCounter(data, 0);
2334   Curl_pgrsSetUploadSize(data, -1);
2335   Curl_pgrsSetDownloadSize(data, -1);
2336 
2337   if(conn->handler->protocol & CURLPROTO_SCP)
2338     result = scp_perform(data, &connected, done);
2339   else
2340     result = sftp_perform(data, &connected, done);
2341 
2342   return result;
2343 }
2344 
2345 /* BLOCKING, but the function is using the state machine so the only reason
2346    this is still blocking is that the multi interface code has no support for
2347    disconnecting operations that takes a while */
scp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection)2348 static CURLcode scp_disconnect(struct Curl_easy *data,
2349                                struct connectdata *conn,
2350                                bool dead_connection)
2351 {
2352   CURLcode result = CURLE_OK;
2353   struct ssh_conn *ssh = &conn->proto.sshc;
2354   (void) dead_connection;
2355 
2356   if(ssh->ssh_session) {
2357     /* only if there's a session still around to use! */
2358 
2359     state(data, SSH_SESSION_DISCONNECT);
2360 
2361     result = myssh_block_statemach(data, TRUE);
2362   }
2363 
2364   return result;
2365 }
2366 
2367 /* generic done function for both SCP and SFTP called from their specific
2368    done functions */
myssh_done(struct Curl_easy *data, CURLcode status)2369 static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
2370 {
2371   CURLcode result = CURLE_OK;
2372   struct SSHPROTO *protop = data->req.p.ssh;
2373 
2374   if(!status) {
2375     /* run the state-machine */
2376     result = myssh_block_statemach(data, FALSE);
2377   }
2378   else
2379     result = status;
2380 
2381   if(protop)
2382     Curl_safefree(protop->path);
2383   if(Curl_pgrsDone(data))
2384     return CURLE_ABORTED_BY_CALLBACK;
2385 
2386   data->req.keepon = 0;   /* clear all bits */
2387   return result;
2388 }
2389 
2390 
scp_done(struct Curl_easy *data, CURLcode status, bool premature)2391 static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
2392                          bool premature)
2393 {
2394   (void) premature;             /* not used */
2395 
2396   if(!status)
2397     state(data, SSH_SCP_DONE);
2398 
2399   return myssh_done(data, status);
2400 
2401 }
2402 
scp_send(struct Curl_easy *data, int sockindex, const void *mem, size_t len, CURLcode *err)2403 static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2404                         const void *mem, size_t len, CURLcode *err)
2405 {
2406   int rc;
2407   struct connectdata *conn = data->conn;
2408   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2409   (void) err;
2410 
2411   rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2412 
2413 #if 0
2414   /* The following code is misleading, mostly added as wishful thinking
2415    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2416    * Currently rc can only be number of bytes read or SSH_ERROR. */
2417   myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
2418 
2419   if(rc == SSH_AGAIN) {
2420     *err = CURLE_AGAIN;
2421     return 0;
2422   }
2423   else
2424 #endif
2425   if(rc != SSH_OK) {
2426     *err = CURLE_SSH;
2427     return -1;
2428   }
2429 
2430   return len;
2431 }
2432 
scp_recv(struct Curl_easy *data, int sockindex, char *mem, size_t len, CURLcode *err)2433 static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2434                         char *mem, size_t len, CURLcode *err)
2435 {
2436   ssize_t nread;
2437   struct connectdata *conn = data->conn;
2438   (void) err;
2439   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2440 
2441   /* libssh returns int */
2442   nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2443 
2444 #if 0
2445   /* The following code is misleading, mostly added as wishful thinking
2446    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2447    * Currently rc can only be SSH_OK or SSH_ERROR. */
2448 
2449   myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
2450   if(nread == SSH_AGAIN) {
2451     *err = CURLE_AGAIN;
2452     nread = -1;
2453   }
2454 #endif
2455 
2456   return nread;
2457 }
2458 
2459 /*
2460  * =============== SFTP ===============
2461  */
2462 
2463 /*
2464  ***********************************************************************
2465  *
2466  * sftp_perform()
2467  *
2468  * This is the actual DO function for SFTP. Get a file/directory according to
2469  * the options previously setup.
2470  */
2471 
2472 static
sftp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done)2473 CURLcode sftp_perform(struct Curl_easy *data,
2474                       bool *connected,
2475                       bool *dophase_done)
2476 {
2477   CURLcode result = CURLE_OK;
2478 
2479   DEBUGF(infof(data, "DO phase starts"));
2480 
2481   *dophase_done = FALSE; /* not done yet */
2482 
2483   /* start the first command in the DO phase */
2484   state(data, SSH_SFTP_QUOTE_INIT);
2485 
2486   /* run the state-machine */
2487   result = myssh_multi_statemach(data, dophase_done);
2488 
2489   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2490 
2491   if(*dophase_done) {
2492     DEBUGF(infof(data, "DO phase is complete"));
2493   }
2494 
2495   return result;
2496 }
2497 
2498 /* called from multi.c while DOing */
sftp_doing(struct Curl_easy *data, bool *dophase_done)2499 static CURLcode sftp_doing(struct Curl_easy *data,
2500                            bool *dophase_done)
2501 {
2502   CURLcode result = myssh_multi_statemach(data, dophase_done);
2503   if(*dophase_done) {
2504     DEBUGF(infof(data, "DO phase is complete"));
2505   }
2506   return result;
2507 }
2508 
2509 /* BLOCKING, but the function is using the state machine so the only reason
2510    this is still blocking is that the multi interface code has no support for
2511    disconnecting operations that takes a while */
sftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection)2512 static CURLcode sftp_disconnect(struct Curl_easy *data,
2513                                 struct connectdata *conn,
2514                                 bool dead_connection)
2515 {
2516   CURLcode result = CURLE_OK;
2517   (void) dead_connection;
2518 
2519   DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2520 
2521   if(conn->proto.sshc.ssh_session) {
2522     /* only if there's a session still around to use! */
2523     state(data, SSH_SFTP_SHUTDOWN);
2524     result = myssh_block_statemach(data, TRUE);
2525   }
2526 
2527   DEBUGF(infof(data, "SSH DISCONNECT is done"));
2528 
2529   return result;
2530 
2531 }
2532 
sftp_done(struct Curl_easy *data, CURLcode status, bool premature)2533 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2534                           bool premature)
2535 {
2536   struct connectdata *conn = data->conn;
2537   struct ssh_conn *sshc = &conn->proto.sshc;
2538 
2539   if(!status) {
2540     /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2541        errors that could happen due to open file handles during POSTQUOTE
2542        operation */
2543     if(!premature && data->set.postquote && !conn->bits.retry)
2544       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2545     state(data, SSH_SFTP_CLOSE);
2546   }
2547   return myssh_done(data, status);
2548 }
2549 
2550 /* return number of sent bytes */
sftp_send(struct Curl_easy *data, int sockindex, const void *mem, size_t len, CURLcode *err)2551 static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2552                          const void *mem, size_t len, CURLcode *err)
2553 {
2554   ssize_t nwrite;
2555   struct connectdata *conn = data->conn;
2556   (void)sockindex;
2557 
2558   /* limit the writes to the maximum specified in Section 3 of
2559    * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
2560    */
2561   if(len > 32768)
2562     len = 32768;
2563 
2564   nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2565 
2566   myssh_block2waitfor(conn, FALSE);
2567 
2568 #if 0 /* not returned by libssh on write */
2569   if(nwrite == SSH_AGAIN) {
2570     *err = CURLE_AGAIN;
2571     nwrite = 0;
2572   }
2573   else
2574 #endif
2575   if(nwrite < 0) {
2576     *err = CURLE_SSH;
2577     nwrite = -1;
2578   }
2579 
2580   return nwrite;
2581 }
2582 
2583 /*
2584  * Return number of received (decrypted) bytes
2585  * or <0 on error
2586  */
sftp_recv(struct Curl_easy *data, int sockindex, char *mem, size_t len, CURLcode *err)2587 static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2588                          char *mem, size_t len, CURLcode *err)
2589 {
2590   ssize_t nread;
2591   struct connectdata *conn = data->conn;
2592   (void)sockindex;
2593 
2594   DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2595 
2596   switch(conn->proto.sshc.sftp_recv_state) {
2597     case 0:
2598       conn->proto.sshc.sftp_file_index =
2599         sftp_async_read_begin(conn->proto.sshc.sftp_file,
2600                               (uint32_t)len);
2601       if(conn->proto.sshc.sftp_file_index < 0) {
2602         *err = CURLE_RECV_ERROR;
2603         return -1;
2604       }
2605 
2606       FALLTHROUGH();
2607     case 1:
2608       conn->proto.sshc.sftp_recv_state = 1;
2609 
2610       nread = sftp_async_read(conn->proto.sshc.sftp_file,
2611                               mem, (uint32_t)len,
2612                               conn->proto.sshc.sftp_file_index);
2613 
2614       myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
2615 
2616       if(nread == SSH_AGAIN) {
2617         *err = CURLE_AGAIN;
2618         return -1;
2619       }
2620       else if(nread < 0) {
2621         *err = CURLE_RECV_ERROR;
2622         return -1;
2623       }
2624 
2625       conn->proto.sshc.sftp_recv_state = 0;
2626       return nread;
2627 
2628     default:
2629       /* we never reach here */
2630       return -1;
2631   }
2632 }
2633 
sftp_quote(struct Curl_easy *data)2634 static void sftp_quote(struct Curl_easy *data)
2635 {
2636   const char *cp;
2637   struct connectdata *conn = data->conn;
2638   struct SSHPROTO *protop = data->req.p.ssh;
2639   struct ssh_conn *sshc = &conn->proto.sshc;
2640   CURLcode result;
2641 
2642   /*
2643    * Support some of the "FTP" commands
2644    */
2645   char *cmd = sshc->quote_item->data;
2646   sshc->acceptfail = FALSE;
2647 
2648   /* if a command starts with an asterisk, which a legal SFTP command never
2649      can, the command will be allowed to fail without it causing any
2650      aborts or cancels etc. It will cause libcurl to act as if the command
2651      is successful, whatever the server responds. */
2652 
2653   if(cmd[0] == '*') {
2654     cmd++;
2655     sshc->acceptfail = TRUE;
2656   }
2657 
2658   if(strcasecompare("pwd", cmd)) {
2659     /* output debug output if that is requested */
2660     char *tmp = aprintf("257 \"%s\" is current directory.\n",
2661                         protop->path);
2662     if(!tmp) {
2663       sshc->actualcode = CURLE_OUT_OF_MEMORY;
2664       state(data, SSH_SFTP_CLOSE);
2665       sshc->nextstate = SSH_NO_STATE;
2666       return;
2667     }
2668     Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2669     Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2670 
2671     /* this sends an FTP-like "header" to the header callback so that the
2672        current directory can be read very similar to how it is read when
2673        using ordinary FTP. */
2674     result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2675     free(tmp);
2676     if(result) {
2677       state(data, SSH_SFTP_CLOSE);
2678       sshc->nextstate = SSH_NO_STATE;
2679       sshc->actualcode = result;
2680     }
2681     else
2682       state(data, SSH_SFTP_NEXT_QUOTE);
2683     return;
2684   }
2685 
2686   /*
2687    * the arguments following the command must be separated from the
2688    * command with a space so we can check for it unconditionally
2689    */
2690   cp = strchr(cmd, ' ');
2691   if(!cp) {
2692     failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2693     state(data, SSH_SFTP_CLOSE);
2694     sshc->nextstate = SSH_NO_STATE;
2695     sshc->actualcode = CURLE_QUOTE_ERROR;
2696     return;
2697   }
2698 
2699   /*
2700    * also, every command takes at least one argument so we get that
2701    * first argument right now
2702    */
2703   result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2704   if(result) {
2705     if(result == CURLE_OUT_OF_MEMORY)
2706       failf(data, "Out of memory");
2707     else
2708       failf(data, "Syntax error: Bad first parameter");
2709     state(data, SSH_SFTP_CLOSE);
2710     sshc->nextstate = SSH_NO_STATE;
2711     sshc->actualcode = result;
2712     return;
2713   }
2714 
2715   /*
2716    * SFTP is a binary protocol, so we don't send text commands
2717    * to the server. Instead, we scan for commands used by
2718    * OpenSSH's sftp program and call the appropriate libssh
2719    * functions.
2720    */
2721   if(strncasecompare(cmd, "chgrp ", 6) ||
2722      strncasecompare(cmd, "chmod ", 6) ||
2723      strncasecompare(cmd, "chown ", 6) ||
2724      strncasecompare(cmd, "atime ", 6) ||
2725      strncasecompare(cmd, "mtime ", 6)) {
2726     /* attribute change */
2727 
2728     /* sshc->quote_path1 contains the mode to set */
2729     /* get the destination */
2730     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2731     if(result) {
2732       if(result == CURLE_OUT_OF_MEMORY)
2733         failf(data, "Out of memory");
2734       else
2735         failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2736               "Bad second parameter");
2737       Curl_safefree(sshc->quote_path1);
2738       state(data, SSH_SFTP_CLOSE);
2739       sshc->nextstate = SSH_NO_STATE;
2740       sshc->actualcode = result;
2741       return;
2742     }
2743     sshc->quote_attrs = NULL;
2744     state(data, SSH_SFTP_QUOTE_STAT);
2745     return;
2746   }
2747   if(strncasecompare(cmd, "ln ", 3) ||
2748      strncasecompare(cmd, "symlink ", 8)) {
2749     /* symbolic linking */
2750     /* sshc->quote_path1 is the source */
2751     /* get the destination */
2752     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2753     if(result) {
2754       if(result == CURLE_OUT_OF_MEMORY)
2755         failf(data, "Out of memory");
2756       else
2757         failf(data, "Syntax error in ln/symlink: Bad second parameter");
2758       Curl_safefree(sshc->quote_path1);
2759       state(data, SSH_SFTP_CLOSE);
2760       sshc->nextstate = SSH_NO_STATE;
2761       sshc->actualcode = result;
2762       return;
2763     }
2764     state(data, SSH_SFTP_QUOTE_SYMLINK);
2765     return;
2766   }
2767   else if(strncasecompare(cmd, "mkdir ", 6)) {
2768     /* create dir */
2769     state(data, SSH_SFTP_QUOTE_MKDIR);
2770     return;
2771   }
2772   else if(strncasecompare(cmd, "rename ", 7)) {
2773     /* rename file */
2774     /* first param is the source path */
2775     /* second param is the dest. path */
2776     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2777     if(result) {
2778       if(result == CURLE_OUT_OF_MEMORY)
2779         failf(data, "Out of memory");
2780       else
2781         failf(data, "Syntax error in rename: Bad second parameter");
2782       Curl_safefree(sshc->quote_path1);
2783       state(data, SSH_SFTP_CLOSE);
2784       sshc->nextstate = SSH_NO_STATE;
2785       sshc->actualcode = result;
2786       return;
2787     }
2788     state(data, SSH_SFTP_QUOTE_RENAME);
2789     return;
2790   }
2791   else if(strncasecompare(cmd, "rmdir ", 6)) {
2792     /* delete dir */
2793     state(data, SSH_SFTP_QUOTE_RMDIR);
2794     return;
2795   }
2796   else if(strncasecompare(cmd, "rm ", 3)) {
2797     state(data, SSH_SFTP_QUOTE_UNLINK);
2798     return;
2799   }
2800 #ifdef HAS_STATVFS_SUPPORT
2801   else if(strncasecompare(cmd, "statvfs ", 8)) {
2802     state(data, SSH_SFTP_QUOTE_STATVFS);
2803     return;
2804   }
2805 #endif
2806 
2807   failf(data, "Unknown SFTP command");
2808   Curl_safefree(sshc->quote_path1);
2809   Curl_safefree(sshc->quote_path2);
2810   state(data, SSH_SFTP_CLOSE);
2811   sshc->nextstate = SSH_NO_STATE;
2812   sshc->actualcode = CURLE_QUOTE_ERROR;
2813 }
2814 
sftp_quote_stat(struct Curl_easy *data)2815 static void sftp_quote_stat(struct Curl_easy *data)
2816 {
2817   struct connectdata *conn = data->conn;
2818   struct ssh_conn *sshc = &conn->proto.sshc;
2819   char *cmd = sshc->quote_item->data;
2820   sshc->acceptfail = FALSE;
2821 
2822   /* if a command starts with an asterisk, which a legal SFTP command never
2823      can, the command will be allowed to fail without it causing any
2824      aborts or cancels etc. It will cause libcurl to act as if the command
2825      is successful, whatever the server responds. */
2826 
2827   if(cmd[0] == '*') {
2828     cmd++;
2829     sshc->acceptfail = TRUE;
2830   }
2831 
2832   /* We read the file attributes, store them in sshc->quote_attrs
2833    * and modify them accordingly to command. Then we switch to
2834    * QUOTE_SETSTAT state to write new ones.
2835    */
2836 
2837   if(sshc->quote_attrs)
2838     sftp_attributes_free(sshc->quote_attrs);
2839   sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2840   if(!sshc->quote_attrs) {
2841     Curl_safefree(sshc->quote_path1);
2842     Curl_safefree(sshc->quote_path2);
2843     failf(data, "Attempt to get SFTP stats failed: %d",
2844           sftp_get_error(sshc->sftp_session));
2845     state(data, SSH_SFTP_CLOSE);
2846     sshc->nextstate = SSH_NO_STATE;
2847     sshc->actualcode = CURLE_QUOTE_ERROR;
2848     return;
2849   }
2850 
2851   /* Now set the new attributes... */
2852   if(strncasecompare(cmd, "chgrp", 5)) {
2853     sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2854     if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2855         !sshc->acceptfail) {
2856       Curl_safefree(sshc->quote_path1);
2857       Curl_safefree(sshc->quote_path2);
2858       failf(data, "Syntax error: chgrp gid not a number");
2859       state(data, SSH_SFTP_CLOSE);
2860       sshc->nextstate = SSH_NO_STATE;
2861       sshc->actualcode = CURLE_QUOTE_ERROR;
2862       return;
2863     }
2864     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2865   }
2866   else if(strncasecompare(cmd, "chmod", 5)) {
2867     mode_t perms;
2868     perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2869     /* permissions are octal */
2870     if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2871       Curl_safefree(sshc->quote_path1);
2872       Curl_safefree(sshc->quote_path2);
2873       failf(data, "Syntax error: chmod permissions not a number");
2874       state(data, SSH_SFTP_CLOSE);
2875       sshc->nextstate = SSH_NO_STATE;
2876       sshc->actualcode = CURLE_QUOTE_ERROR;
2877       return;
2878     }
2879     sshc->quote_attrs->permissions = perms;
2880     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2881   }
2882   else if(strncasecompare(cmd, "chown", 5)) {
2883     sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2884     if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2885         !sshc->acceptfail) {
2886       Curl_safefree(sshc->quote_path1);
2887       Curl_safefree(sshc->quote_path2);
2888       failf(data, "Syntax error: chown uid not a number");
2889       state(data, SSH_SFTP_CLOSE);
2890       sshc->nextstate = SSH_NO_STATE;
2891       sshc->actualcode = CURLE_QUOTE_ERROR;
2892       return;
2893     }
2894     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2895   }
2896   else if(strncasecompare(cmd, "atime", 5) ||
2897           strncasecompare(cmd, "mtime", 5)) {
2898     time_t date = Curl_getdate_capped(sshc->quote_path1);
2899     bool fail = FALSE;
2900     if(date == -1) {
2901       failf(data, "incorrect date format for %.*s", 5, cmd);
2902       fail = TRUE;
2903     }
2904 #if SIZEOF_TIME_T > 4
2905     else if(date > 0xffffffff) {
2906       failf(data, "date overflow");
2907       fail = TRUE; /* avoid setting a capped time */
2908     }
2909 #endif
2910     if(fail) {
2911       Curl_safefree(sshc->quote_path1);
2912       Curl_safefree(sshc->quote_path2);
2913       state(data, SSH_SFTP_CLOSE);
2914       sshc->nextstate = SSH_NO_STATE;
2915       sshc->actualcode = CURLE_QUOTE_ERROR;
2916       return;
2917     }
2918     if(strncasecompare(cmd, "atime", 5))
2919       sshc->quote_attrs->atime = (uint32_t)date;
2920     else /* mtime */
2921       sshc->quote_attrs->mtime = (uint32_t)date;
2922 
2923     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2924   }
2925 
2926   /* Now send the completed structure... */
2927   state(data, SSH_SFTP_QUOTE_SETSTAT);
2928   return;
2929 }
2930 
Curl_ssh_init(void)2931 CURLcode Curl_ssh_init(void)
2932 {
2933   if(ssh_init()) {
2934     DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2935     return CURLE_FAILED_INIT;
2936   }
2937   return CURLE_OK;
2938 }
2939 
Curl_ssh_cleanup(void)2940 void Curl_ssh_cleanup(void)
2941 {
2942   (void)ssh_finalize();
2943 }
2944 
Curl_ssh_version(char *buffer, size_t buflen)2945 void Curl_ssh_version(char *buffer, size_t buflen)
2946 {
2947   (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
2948 }
2949 
2950 #endif                          /* USE_LIBSSH */
2951