xref: /aosp_15_r20/external/curl/lib/vssh/libssh.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Red Hat, Inc.
9  *
10  * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
11  *          Robert Kolcun, Andreas Schneider
12  *
13  * This software is licensed as described in the file COPYING, which
14  * you should have received as part of this distribution. The terms
15  * are also available at https://curl.se/docs/copyright.html.
16  *
17  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
18  * copies of the Software, and permit persons to whom the Software is
19  * furnished to do so, under the terms of the COPYING file.
20  *
21  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22  * KIND, either express or implied.
23  *
24  * SPDX-License-Identifier: curl
25  *
26  ***************************************************************************/
27 
28 #include "curl_setup.h"
29 
30 #ifdef USE_LIBSSH
31 
32 #include <limits.h>
33 
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
37 #ifdef HAVE_ARPA_INET_H
38 #include <arpa/inet.h>
39 #endif
40 #ifdef HAVE_NETDB_H
41 #include <netdb.h>
42 #endif
43 #ifdef __VMS
44 #include <in.h>
45 #include <inet.h>
46 #endif
47 
48 #include <curl/curl.h>
49 #include "urldata.h"
50 #include "sendf.h"
51 #include "hostip.h"
52 #include "progress.h"
53 #include "transfer.h"
54 #include "escape.h"
55 #include "http.h"               /* for HTTP proxy tunnel stuff */
56 #include "ssh.h"
57 #include "url.h"
58 #include "speedcheck.h"
59 #include "getinfo.h"
60 #include "strdup.h"
61 #include "strcase.h"
62 #include "vtls/vtls.h"
63 #include "cfilters.h"
64 #include "connect.h"
65 #include "inet_ntop.h"
66 #include "parsedate.h"          /* for the week day and month names */
67 #include "sockaddr.h"           /* required for Curl_sockaddr_storage */
68 #include "strtoofft.h"
69 #include "multiif.h"
70 #include "select.h"
71 #include "warnless.h"
72 #include "curl_path.h"
73 
74 #ifdef HAVE_SYS_STAT_H
75 #include <sys/stat.h>
76 #endif
77 #ifdef HAVE_UNISTD_H
78 #include <unistd.h>
79 #endif
80 #ifdef HAVE_FCNTL_H
81 #include <fcntl.h>
82 #endif
83 
84 /* The last 3 #include files should be in this order */
85 #include "curl_printf.h"
86 #include "curl_memory.h"
87 #include "memdebug.h"
88 
89 /* A recent macro provided by libssh. Or make our own. */
90 #ifndef SSH_STRING_FREE_CHAR
91 #define SSH_STRING_FREE_CHAR(x)                 \
92   do {                                          \
93     if(x) {                                     \
94       ssh_string_free_char(x);                  \
95       x = NULL;                                 \
96     }                                           \
97   } while(0)
98 #endif
99 
100 /* These stat values may not be the same as the user's S_IFMT / S_IFLNK */
101 #ifndef SSH_S_IFMT
102 #define SSH_S_IFMT   00170000
103 #endif
104 #ifndef SSH_S_IFLNK
105 #define SSH_S_IFLNK  0120000
106 #endif
107 
108 /* Local functions: */
109 static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
110 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
111                                       bool *done);
112 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
113 
114 static CURLcode scp_done(struct Curl_easy *data,
115                          CURLcode, bool premature);
116 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
117 static CURLcode scp_disconnect(struct Curl_easy *data,
118                                struct connectdata *conn,
119                                bool dead_connection);
120 
121 static CURLcode sftp_done(struct Curl_easy *data,
122                           CURLcode, bool premature);
123 static CURLcode sftp_doing(struct Curl_easy *data,
124                            bool *dophase_done);
125 static CURLcode sftp_disconnect(struct Curl_easy *data,
126                                 struct connectdata *conn,
127                                 bool dead);
128 static
129 CURLcode sftp_perform(struct Curl_easy *data,
130                       bool *connected,
131                       bool *dophase_done);
132 
133 static void sftp_quote(struct Curl_easy *data);
134 static void sftp_quote_stat(struct Curl_easy *data);
135 static int myssh_getsock(struct Curl_easy *data,
136                          struct connectdata *conn, curl_socket_t *sock);
137 static void myssh_block2waitfor(struct connectdata *conn, bool block);
138 
139 static CURLcode myssh_setup_connection(struct Curl_easy *data,
140                                        struct connectdata *conn);
141 
142 /*
143  * SCP protocol handler.
144  */
145 
146 const struct Curl_handler Curl_handler_scp = {
147   "SCP",                        /* scheme */
148   myssh_setup_connection,       /* setup_connection */
149   myssh_do_it,                  /* do_it */
150   scp_done,                     /* done */
151   ZERO_NULL,                    /* do_more */
152   myssh_connect,                /* connect_it */
153   myssh_multi_statemach,        /* connecting */
154   scp_doing,                    /* doing */
155   myssh_getsock,                /* proto_getsock */
156   myssh_getsock,                /* doing_getsock */
157   ZERO_NULL,                    /* domore_getsock */
158   myssh_getsock,                /* perform_getsock */
159   scp_disconnect,               /* disconnect */
160   ZERO_NULL,                    /* write_resp */
161   ZERO_NULL,                    /* write_resp_hd */
162   ZERO_NULL,                    /* connection_check */
163   ZERO_NULL,                    /* attach connection */
164   PORT_SSH,                     /* defport */
165   CURLPROTO_SCP,                /* protocol */
166   CURLPROTO_SCP,                /* family */
167   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY    /* flags */
168 };
169 
170 /*
171  * SFTP protocol handler.
172  */
173 
174 const struct Curl_handler Curl_handler_sftp = {
175   "SFTP",                               /* scheme */
176   myssh_setup_connection,               /* setup_connection */
177   myssh_do_it,                          /* do_it */
178   sftp_done,                            /* done */
179   ZERO_NULL,                            /* do_more */
180   myssh_connect,                        /* connect_it */
181   myssh_multi_statemach,                /* connecting */
182   sftp_doing,                           /* doing */
183   myssh_getsock,                        /* proto_getsock */
184   myssh_getsock,                        /* doing_getsock */
185   ZERO_NULL,                            /* domore_getsock */
186   myssh_getsock,                        /* perform_getsock */
187   sftp_disconnect,                      /* disconnect */
188   ZERO_NULL,                            /* write_resp */
189   ZERO_NULL,                            /* write_resp_hd */
190   ZERO_NULL,                            /* connection_check */
191   ZERO_NULL,                            /* attach connection */
192   PORT_SSH,                             /* defport */
193   CURLPROTO_SFTP,                       /* protocol */
194   CURLPROTO_SFTP,                       /* family */
195   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
196   | PROTOPT_NOURLQUERY                  /* flags */
197 };
198 
sftp_error_to_CURLE(int err)199 static CURLcode sftp_error_to_CURLE(int err)
200 {
201   switch(err) {
202     case SSH_FX_OK:
203       return CURLE_OK;
204 
205     case SSH_FX_NO_SUCH_FILE:
206     case SSH_FX_NO_SUCH_PATH:
207       return CURLE_REMOTE_FILE_NOT_FOUND;
208 
209     case SSH_FX_PERMISSION_DENIED:
210     case SSH_FX_WRITE_PROTECT:
211       return CURLE_REMOTE_ACCESS_DENIED;
212 
213     case SSH_FX_FILE_ALREADY_EXISTS:
214       return CURLE_REMOTE_FILE_EXISTS;
215 
216     default:
217       break;
218   }
219 
220   return CURLE_SSH;
221 }
222 
223 #ifndef DEBUGBUILD
224 #define state(x,y) mystate(x,y)
225 #else
226 #define state(x,y) mystate(x,y, __LINE__)
227 #endif
228 
229 /*
230  * SSH State machine related code
231  */
232 /* This is the ONLY way to change SSH state! */
mystate(struct Curl_easy * data,sshstate nowstate,int lineno)233 static void mystate(struct Curl_easy *data, sshstate nowstate
234 #ifdef DEBUGBUILD
235                     , int lineno
236 #endif
237   )
238 {
239   struct connectdata *conn = data->conn;
240   struct ssh_conn *sshc = &conn->proto.sshc;
241 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
242   /* for debug purposes */
243   static const char *const names[] = {
244     "SSH_STOP",
245     "SSH_INIT",
246     "SSH_S_STARTUP",
247     "SSH_HOSTKEY",
248     "SSH_AUTHLIST",
249     "SSH_AUTH_PKEY_INIT",
250     "SSH_AUTH_PKEY",
251     "SSH_AUTH_PASS_INIT",
252     "SSH_AUTH_PASS",
253     "SSH_AUTH_AGENT_INIT",
254     "SSH_AUTH_AGENT_LIST",
255     "SSH_AUTH_AGENT",
256     "SSH_AUTH_HOST_INIT",
257     "SSH_AUTH_HOST",
258     "SSH_AUTH_KEY_INIT",
259     "SSH_AUTH_KEY",
260     "SSH_AUTH_GSSAPI",
261     "SSH_AUTH_DONE",
262     "SSH_SFTP_INIT",
263     "SSH_SFTP_REALPATH",
264     "SSH_SFTP_QUOTE_INIT",
265     "SSH_SFTP_POSTQUOTE_INIT",
266     "SSH_SFTP_QUOTE",
267     "SSH_SFTP_NEXT_QUOTE",
268     "SSH_SFTP_QUOTE_STAT",
269     "SSH_SFTP_QUOTE_SETSTAT",
270     "SSH_SFTP_QUOTE_SYMLINK",
271     "SSH_SFTP_QUOTE_MKDIR",
272     "SSH_SFTP_QUOTE_RENAME",
273     "SSH_SFTP_QUOTE_RMDIR",
274     "SSH_SFTP_QUOTE_UNLINK",
275     "SSH_SFTP_QUOTE_STATVFS",
276     "SSH_SFTP_GETINFO",
277     "SSH_SFTP_FILETIME",
278     "SSH_SFTP_TRANS_INIT",
279     "SSH_SFTP_UPLOAD_INIT",
280     "SSH_SFTP_CREATE_DIRS_INIT",
281     "SSH_SFTP_CREATE_DIRS",
282     "SSH_SFTP_CREATE_DIRS_MKDIR",
283     "SSH_SFTP_READDIR_INIT",
284     "SSH_SFTP_READDIR",
285     "SSH_SFTP_READDIR_LINK",
286     "SSH_SFTP_READDIR_BOTTOM",
287     "SSH_SFTP_READDIR_DONE",
288     "SSH_SFTP_DOWNLOAD_INIT",
289     "SSH_SFTP_DOWNLOAD_STAT",
290     "SSH_SFTP_CLOSE",
291     "SSH_SFTP_SHUTDOWN",
292     "SSH_SCP_TRANS_INIT",
293     "SSH_SCP_UPLOAD_INIT",
294     "SSH_SCP_DOWNLOAD_INIT",
295     "SSH_SCP_DOWNLOAD",
296     "SSH_SCP_DONE",
297     "SSH_SCP_SEND_EOF",
298     "SSH_SCP_WAIT_EOF",
299     "SSH_SCP_WAIT_CLOSE",
300     "SSH_SCP_CHANNEL_FREE",
301     "SSH_SESSION_DISCONNECT",
302     "SSH_SESSION_FREE",
303     "QUIT"
304   };
305 
306 
307   if(sshc->state != nowstate) {
308     infof(data, "SSH %p state change from %s to %s (line %d)",
309           (void *) sshc, names[sshc->state], names[nowstate],
310           lineno);
311   }
312 #endif
313 
314   sshc->state = nowstate;
315 }
316 
317 /* Multiple options:
318  * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
319  *    hash (90s style auth, not sure we should have it here)
320  * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
321  *    use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
322  *    is returned by it.
323  * 3. none of the above. We only accept if it is present on known hosts.
324  *
325  * Returns SSH_OK or SSH_ERROR.
326  */
myssh_is_known(struct Curl_easy * data)327 static int myssh_is_known(struct Curl_easy *data)
328 {
329   int rc;
330   struct connectdata *conn = data->conn;
331   struct ssh_conn *sshc = &conn->proto.sshc;
332   ssh_key pubkey;
333   size_t hlen;
334   unsigned char *hash = NULL;
335   char *found_base64 = NULL;
336   char *known_base64 = NULL;
337   int vstate;
338   enum curl_khmatch keymatch;
339   struct curl_khkey foundkey;
340   struct curl_khkey *knownkeyp = NULL;
341   curl_sshkeycallback func =
342     data->set.ssh_keyfunc;
343 
344 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
345   struct ssh_knownhosts_entry *knownhostsentry = NULL;
346   struct curl_khkey knownkey;
347 #endif
348 
349 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
350   rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
351 #else
352   rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
353 #endif
354   if(rc != SSH_OK)
355     return rc;
356 
357   if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
358     int i;
359     char md5buffer[33];
360     const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
361 
362     rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
363                                 &hash, &hlen);
364     if(rc != SSH_OK || hlen != 16) {
365       failf(data,
366             "Denied establishing ssh session: md5 fingerprint not available");
367       goto cleanup;
368     }
369 
370     for(i = 0; i < 16; i++)
371       msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
372 
373     infof(data, "SSH MD5 fingerprint: %s", md5buffer);
374 
375     if(!strcasecompare(md5buffer, pubkey_md5)) {
376       failf(data,
377             "Denied establishing ssh session: mismatch md5 fingerprint. "
378             "Remote %s is not equal to %s", md5buffer, pubkey_md5);
379       rc = SSH_ERROR;
380       goto cleanup;
381     }
382 
383     rc = SSH_OK;
384     goto cleanup;
385   }
386 
387   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
388 
389 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
390     /* Get the known_key from the known hosts file */
391     vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
392                                                &knownhostsentry);
393 
394     /* Case an entry was found in a known hosts file */
395     if(knownhostsentry) {
396       if(knownhostsentry->publickey) {
397         rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
398                                           &known_base64);
399         if(rc != SSH_OK) {
400           goto cleanup;
401         }
402         knownkey.key = known_base64;
403         knownkey.len = strlen(known_base64);
404 
405         switch(ssh_key_type(knownhostsentry->publickey)) {
406         case SSH_KEYTYPE_RSA:
407           knownkey.keytype = CURLKHTYPE_RSA;
408           break;
409         case SSH_KEYTYPE_RSA1:
410           knownkey.keytype = CURLKHTYPE_RSA1;
411           break;
412         case SSH_KEYTYPE_ECDSA:
413         case SSH_KEYTYPE_ECDSA_P256:
414         case SSH_KEYTYPE_ECDSA_P384:
415         case SSH_KEYTYPE_ECDSA_P521:
416           knownkey.keytype = CURLKHTYPE_ECDSA;
417           break;
418         case SSH_KEYTYPE_ED25519:
419           knownkey.keytype = CURLKHTYPE_ED25519;
420           break;
421         case SSH_KEYTYPE_DSS:
422           knownkey.keytype = CURLKHTYPE_DSS;
423           break;
424         default:
425           rc = SSH_ERROR;
426           goto cleanup;
427         }
428         knownkeyp = &knownkey;
429       }
430     }
431 
432     switch(vstate) {
433     case SSH_KNOWN_HOSTS_OK:
434       keymatch = CURLKHMATCH_OK;
435       break;
436     case SSH_KNOWN_HOSTS_OTHER:
437     case SSH_KNOWN_HOSTS_NOT_FOUND:
438     case SSH_KNOWN_HOSTS_UNKNOWN:
439     case SSH_KNOWN_HOSTS_ERROR:
440       keymatch = CURLKHMATCH_MISSING;
441       break;
442     default:
443       keymatch = CURLKHMATCH_MISMATCH;
444       break;
445     }
446 
447 #else
448     vstate = ssh_is_server_known(sshc->ssh_session);
449     switch(vstate) {
450     case SSH_SERVER_KNOWN_OK:
451       keymatch = CURLKHMATCH_OK;
452       break;
453     case SSH_SERVER_FILE_NOT_FOUND:
454     case SSH_SERVER_NOT_KNOWN:
455       keymatch = CURLKHMATCH_MISSING;
456       break;
457     default:
458       keymatch = CURLKHMATCH_MISMATCH;
459       break;
460     }
461 #endif
462 
463     if(func) { /* use callback to determine action */
464       rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
465       if(rc != SSH_OK)
466         goto cleanup;
467 
468       foundkey.key = found_base64;
469       foundkey.len = strlen(found_base64);
470 
471       switch(ssh_key_type(pubkey)) {
472       case SSH_KEYTYPE_RSA:
473         foundkey.keytype = CURLKHTYPE_RSA;
474         break;
475       case SSH_KEYTYPE_RSA1:
476         foundkey.keytype = CURLKHTYPE_RSA1;
477         break;
478       case SSH_KEYTYPE_ECDSA:
479 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
480       case SSH_KEYTYPE_ECDSA_P256:
481       case SSH_KEYTYPE_ECDSA_P384:
482       case SSH_KEYTYPE_ECDSA_P521:
483 #endif
484         foundkey.keytype = CURLKHTYPE_ECDSA;
485         break;
486 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
487       case SSH_KEYTYPE_ED25519:
488         foundkey.keytype = CURLKHTYPE_ED25519;
489         break;
490 #endif
491       case SSH_KEYTYPE_DSS:
492         foundkey.keytype = CURLKHTYPE_DSS;
493         break;
494       default:
495         rc = SSH_ERROR;
496         goto cleanup;
497       }
498 
499       Curl_set_in_callback(data, TRUE);
500       rc = func(data, knownkeyp, /* from the knownhosts file */
501                 &foundkey, /* from the remote host */
502                 keymatch, data->set.ssh_keyfunc_userp);
503       Curl_set_in_callback(data, FALSE);
504 
505       switch(rc) {
506       case CURLKHSTAT_FINE_ADD_TO_FILE:
507 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
508         rc = ssh_session_update_known_hosts(sshc->ssh_session);
509 #else
510         rc = ssh_write_knownhost(sshc->ssh_session);
511 #endif
512         if(rc != SSH_OK) {
513           goto cleanup;
514         }
515         break;
516       case CURLKHSTAT_FINE:
517         break;
518       default: /* REJECT/DEFER */
519         rc = SSH_ERROR;
520         goto cleanup;
521       }
522     }
523     else {
524       if(keymatch != CURLKHMATCH_OK) {
525         rc = SSH_ERROR;
526         goto cleanup;
527       }
528     }
529   }
530   rc = SSH_OK;
531 
532 cleanup:
533   if(found_base64) {
534     (free)(found_base64);
535   }
536   if(known_base64) {
537     (free)(known_base64);
538   }
539   if(hash)
540     ssh_clean_pubkey_hash(&hash);
541   ssh_key_free(pubkey);
542 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
543   if(knownhostsentry) {
544     ssh_knownhosts_entry_free(knownhostsentry);
545   }
546 #endif
547   return rc;
548 }
549 
550 #define MOVE_TO_ERROR_STATE(_r) do {            \
551     state(data, SSH_SESSION_DISCONNECT);        \
552     sshc->actualcode = _r;                      \
553     rc = SSH_ERROR;                             \
554   } while(0)
555 
556 #define MOVE_TO_SFTP_CLOSE_STATE() do {                         \
557     state(data, SSH_SFTP_CLOSE);                                \
558     sshc->actualcode =                                          \
559       sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session));  \
560     rc = SSH_ERROR;                                             \
561   } while(0)
562 
563 #define MOVE_TO_PASSWD_AUTH do {                        \
564     if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
565       rc = SSH_OK;                                      \
566       state(data, SSH_AUTH_PASS_INIT);                  \
567     }                                                   \
568     else {                                              \
569       MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);          \
570     }                                                   \
571   } while(0)
572 
573 #define MOVE_TO_KEY_AUTH do {                                   \
574     if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {      \
575       rc = SSH_OK;                                              \
576       state(data, SSH_AUTH_KEY_INIT);                           \
577     }                                                           \
578     else {                                                      \
579       MOVE_TO_PASSWD_AUTH;                                      \
580     }                                                           \
581   } while(0)
582 
583 #define MOVE_TO_GSSAPI_AUTH do {                                \
584     if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {       \
585       rc = SSH_OK;                                              \
586       state(data, SSH_AUTH_GSSAPI);                             \
587     }                                                           \
588     else {                                                      \
589       MOVE_TO_KEY_AUTH;                                         \
590     }                                                           \
591   } while(0)
592 
593 static
myssh_auth_interactive(struct connectdata * conn)594 int myssh_auth_interactive(struct connectdata *conn)
595 {
596   int rc;
597   struct ssh_conn *sshc = &conn->proto.sshc;
598   int nprompts;
599 
600 restart:
601   switch(sshc->kbd_state) {
602     case 0:
603       rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
604       if(rc == SSH_AUTH_AGAIN)
605         return SSH_AGAIN;
606 
607       if(rc != SSH_AUTH_INFO)
608         return SSH_ERROR;
609 
610       nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
611       if(nprompts != 1)
612         return SSH_ERROR;
613 
614       rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
615       if(rc < 0)
616         return SSH_ERROR;
617 
618       FALLTHROUGH();
619     case 1:
620       sshc->kbd_state = 1;
621 
622       rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
623       if(rc == SSH_AUTH_AGAIN)
624         return SSH_AGAIN;
625       else if(rc == SSH_AUTH_SUCCESS)
626         rc = SSH_OK;
627       else if(rc == SSH_AUTH_INFO) {
628         nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
629         if(nprompts)
630           return SSH_ERROR;
631 
632         sshc->kbd_state = 2;
633         goto restart;
634       }
635       else
636         rc = SSH_ERROR;
637       break;
638     case 2:
639       sshc->kbd_state = 2;
640 
641       rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
642       if(rc == SSH_AUTH_AGAIN)
643         return SSH_AGAIN;
644       else if(rc == SSH_AUTH_SUCCESS)
645         rc = SSH_OK;
646       else
647         rc = SSH_ERROR;
648 
649       break;
650     default:
651       return SSH_ERROR;
652   }
653 
654   sshc->kbd_state = 0;
655   return rc;
656 }
657 
658 /*
659  * ssh_statemach_act() runs the SSH state machine as far as it can without
660  * blocking and without reaching the end. The data the pointer 'block' points
661  * to will be set to TRUE if the libssh function returns SSH_AGAIN
662  * meaning it wants to be called again when the socket is ready
663  */
myssh_statemach_act(struct Curl_easy * data,bool * block)664 static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
665 {
666   CURLcode result = CURLE_OK;
667   struct connectdata *conn = data->conn;
668   struct SSHPROTO *protop = data->req.p.ssh;
669   struct ssh_conn *sshc = &conn->proto.sshc;
670   curl_socket_t sock = conn->sock[FIRSTSOCKET];
671   int rc = SSH_NO_ERROR, err;
672   int seekerr = CURL_SEEKFUNC_OK;
673   const char *err_msg;
674   *block = 0;                   /* we are not blocking by default */
675 
676   do {
677 
678     switch(sshc->state) {
679     case SSH_INIT:
680       sshc->secondCreateDirs = 0;
681       sshc->nextstate = SSH_NO_STATE;
682       sshc->actualcode = CURLE_OK;
683 
684 #if 0
685       ssh_set_log_level(SSH_LOG_PROTOCOL);
686 #endif
687 
688       /* Set libssh to non-blocking, since everything internally is
689          non-blocking */
690       ssh_set_blocking(sshc->ssh_session, 0);
691 
692       state(data, SSH_S_STARTUP);
693       FALLTHROUGH();
694 
695     case SSH_S_STARTUP:
696       rc = ssh_connect(sshc->ssh_session);
697 
698       myssh_block2waitfor(conn, (rc == SSH_AGAIN));
699       if(rc == SSH_AGAIN) {
700         DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
701         break;
702       }
703 
704       if(rc != SSH_OK) {
705         failf(data, "Failure establishing ssh session");
706         MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
707         break;
708       }
709 
710       state(data, SSH_HOSTKEY);
711 
712       FALLTHROUGH();
713     case SSH_HOSTKEY:
714 
715       rc = myssh_is_known(data);
716       if(rc != SSH_OK) {
717         MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
718         break;
719       }
720 
721       state(data, SSH_AUTHLIST);
722       FALLTHROUGH();
723     case SSH_AUTHLIST:{
724         sshc->authed = FALSE;
725 
726         rc = ssh_userauth_none(sshc->ssh_session, NULL);
727         if(rc == SSH_AUTH_AGAIN) {
728           rc = SSH_AGAIN;
729           break;
730         }
731 
732         if(rc == SSH_AUTH_SUCCESS) {
733           sshc->authed = TRUE;
734           infof(data, "Authenticated with none");
735           state(data, SSH_AUTH_DONE);
736           break;
737         }
738         else if(rc == SSH_AUTH_ERROR) {
739           MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
740           break;
741         }
742 
743         sshc->auth_methods =
744           (unsigned int)ssh_userauth_list(sshc->ssh_session, NULL);
745         if(sshc->auth_methods)
746           infof(data, "SSH authentication methods available: %s%s%s%s",
747                 sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
748                 "public key, ": "",
749                 sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
750                 "GSSAPI, " : "",
751                 sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?
752                 "keyboard-interactive, " : "",
753                 sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
754                 "password": "");
755         if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
756           state(data, SSH_AUTH_PKEY_INIT);
757           infof(data, "Authentication using SSH public key file");
758         }
759         else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
760           state(data, SSH_AUTH_GSSAPI);
761         }
762         else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
763           state(data, SSH_AUTH_KEY_INIT);
764         }
765         else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
766           state(data, SSH_AUTH_PASS_INIT);
767         }
768         else {                  /* unsupported authentication method */
769           MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
770           break;
771         }
772 
773         break;
774       }
775     case SSH_AUTH_PKEY_INIT:
776       if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
777         MOVE_TO_GSSAPI_AUTH;
778         break;
779       }
780 
781       /* Two choices, (1) private key was given on CMD,
782        * (2) use the "default" keys. */
783       if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
784         if(sshc->pubkey && !data->set.ssl.key_passwd) {
785           rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
786                                           sshc->pubkey);
787           if(rc == SSH_AUTH_AGAIN) {
788             rc = SSH_AGAIN;
789             break;
790           }
791 
792           if(rc != SSH_OK) {
793             MOVE_TO_GSSAPI_AUTH;
794             break;
795           }
796         }
797 
798         rc = ssh_pki_import_privkey_file(data->
799                                          set.str[STRING_SSH_PRIVATE_KEY],
800                                          data->set.ssl.key_passwd, NULL,
801                                          NULL, &sshc->privkey);
802         if(rc != SSH_OK) {
803           failf(data, "Could not load private key file %s",
804                 data->set.str[STRING_SSH_PRIVATE_KEY]);
805           MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
806           break;
807         }
808 
809         state(data, SSH_AUTH_PKEY);
810         break;
811 
812       }
813       else {
814         rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
815                                          data->set.ssl.key_passwd);
816         if(rc == SSH_AUTH_AGAIN) {
817           rc = SSH_AGAIN;
818           break;
819         }
820         if(rc == SSH_AUTH_SUCCESS) {
821           rc = SSH_OK;
822           sshc->authed = TRUE;
823           infof(data, "Completed public key authentication");
824           state(data, SSH_AUTH_DONE);
825           break;
826         }
827 
828         MOVE_TO_GSSAPI_AUTH;
829       }
830       break;
831     case SSH_AUTH_PKEY:
832       rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
833       if(rc == SSH_AUTH_AGAIN) {
834         rc = SSH_AGAIN;
835         break;
836       }
837 
838       if(rc == SSH_AUTH_SUCCESS) {
839         sshc->authed = TRUE;
840         infof(data, "Completed public key authentication");
841         state(data, SSH_AUTH_DONE);
842         break;
843       }
844       else {
845         infof(data, "Failed public key authentication (rc: %d)", rc);
846         MOVE_TO_GSSAPI_AUTH;
847       }
848       break;
849 
850     case SSH_AUTH_GSSAPI:
851       if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
852         MOVE_TO_KEY_AUTH;
853         break;
854       }
855 
856       rc = ssh_userauth_gssapi(sshc->ssh_session);
857       if(rc == SSH_AUTH_AGAIN) {
858         rc = SSH_AGAIN;
859         break;
860       }
861 
862       if(rc == SSH_AUTH_SUCCESS) {
863         rc = SSH_OK;
864         sshc->authed = TRUE;
865         infof(data, "Completed gssapi authentication");
866         state(data, SSH_AUTH_DONE);
867         break;
868       }
869 
870       MOVE_TO_KEY_AUTH;
871       break;
872 
873     case SSH_AUTH_KEY_INIT:
874       if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
875         state(data, SSH_AUTH_KEY);
876       }
877       else {
878         MOVE_TO_PASSWD_AUTH;
879       }
880       break;
881 
882     case SSH_AUTH_KEY:
883       /* keyboard-interactive authentication */
884       rc = myssh_auth_interactive(conn);
885       if(rc == SSH_AGAIN) {
886         break;
887       }
888       if(rc == SSH_OK) {
889         sshc->authed = TRUE;
890         infof(data, "completed keyboard interactive authentication");
891         state(data, SSH_AUTH_DONE);
892       }
893       else {
894         MOVE_TO_PASSWD_AUTH;
895       }
896       break;
897 
898     case SSH_AUTH_PASS_INIT:
899       if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
900         MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
901         break;
902       }
903       state(data, SSH_AUTH_PASS);
904       FALLTHROUGH();
905 
906     case SSH_AUTH_PASS:
907       rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
908       if(rc == SSH_AUTH_AGAIN) {
909         rc = SSH_AGAIN;
910         break;
911       }
912 
913       if(rc == SSH_AUTH_SUCCESS) {
914         sshc->authed = TRUE;
915         infof(data, "Completed password authentication");
916         state(data, SSH_AUTH_DONE);
917       }
918       else {
919         MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
920       }
921       break;
922 
923     case SSH_AUTH_DONE:
924       if(!sshc->authed) {
925         failf(data, "Authentication failure");
926         MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
927         break;
928       }
929 
930       /*
931        * At this point we have an authenticated ssh session.
932        */
933       infof(data, "Authentication complete");
934 
935       Curl_pgrsTime(data, TIMER_APPCONNECT);      /* SSH is connected */
936 
937       conn->sockfd = sock;
938       conn->writesockfd = CURL_SOCKET_BAD;
939 
940       if(conn->handler->protocol == CURLPROTO_SFTP) {
941         state(data, SSH_SFTP_INIT);
942         break;
943       }
944       infof(data, "SSH CONNECT phase done");
945       state(data, SSH_STOP);
946       break;
947 
948     case SSH_SFTP_INIT:
949       ssh_set_blocking(sshc->ssh_session, 1);
950 
951       sshc->sftp_session = sftp_new(sshc->ssh_session);
952       if(!sshc->sftp_session) {
953         failf(data, "Failure initializing sftp session: %s",
954               ssh_get_error(sshc->ssh_session));
955         MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
956         break;
957       }
958 
959       rc = sftp_init(sshc->sftp_session);
960       if(rc != SSH_OK) {
961         failf(data, "Failure initializing sftp session: %s",
962               ssh_get_error(sshc->ssh_session));
963         MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE));
964         break;
965       }
966       state(data, SSH_SFTP_REALPATH);
967       FALLTHROUGH();
968     case SSH_SFTP_REALPATH:
969       /*
970        * Get the "home" directory
971        */
972       sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
973       if(!sshc->homedir) {
974         MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
975         break;
976       }
977       data->state.most_recent_ftp_entrypath = sshc->homedir;
978 
979       /* This is the last step in the SFTP connect phase. Do note that while
980          we get the homedir here, we get the "workingpath" in the DO action
981          since the homedir will remain the same between request but the
982          working path will not. */
983       DEBUGF(infof(data, "SSH CONNECT phase done"));
984       state(data, SSH_STOP);
985       break;
986 
987     case SSH_SFTP_QUOTE_INIT:
988       result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
989       if(result) {
990         sshc->actualcode = result;
991         state(data, SSH_STOP);
992         break;
993       }
994 
995       if(data->set.quote) {
996         infof(data, "Sending quote commands");
997         sshc->quote_item = data->set.quote;
998         state(data, SSH_SFTP_QUOTE);
999       }
1000       else {
1001         state(data, SSH_SFTP_GETINFO);
1002       }
1003       break;
1004 
1005     case SSH_SFTP_POSTQUOTE_INIT:
1006       if(data->set.postquote) {
1007         infof(data, "Sending quote commands");
1008         sshc->quote_item = data->set.postquote;
1009         state(data, SSH_SFTP_QUOTE);
1010       }
1011       else {
1012         state(data, SSH_STOP);
1013       }
1014       break;
1015 
1016     case SSH_SFTP_QUOTE:
1017       /* Send any quote commands */
1018       sftp_quote(data);
1019       break;
1020 
1021     case SSH_SFTP_NEXT_QUOTE:
1022       Curl_safefree(sshc->quote_path1);
1023       Curl_safefree(sshc->quote_path2);
1024 
1025       sshc->quote_item = sshc->quote_item->next;
1026 
1027       if(sshc->quote_item) {
1028         state(data, SSH_SFTP_QUOTE);
1029       }
1030       else {
1031         if(sshc->nextstate != SSH_NO_STATE) {
1032           state(data, sshc->nextstate);
1033           sshc->nextstate = SSH_NO_STATE;
1034         }
1035         else {
1036           state(data, SSH_SFTP_GETINFO);
1037         }
1038       }
1039       break;
1040 
1041     case SSH_SFTP_QUOTE_STAT:
1042       sftp_quote_stat(data);
1043       break;
1044 
1045     case SSH_SFTP_QUOTE_SETSTAT:
1046       rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
1047                         sshc->quote_attrs);
1048       if(rc && !sshc->acceptfail) {
1049         Curl_safefree(sshc->quote_path1);
1050         Curl_safefree(sshc->quote_path2);
1051         failf(data, "Attempt to set SFTP stats failed: %s",
1052               ssh_get_error(sshc->ssh_session));
1053         state(data, SSH_SFTP_CLOSE);
1054         sshc->nextstate = SSH_NO_STATE;
1055         sshc->actualcode = CURLE_QUOTE_ERROR;
1056         /* sshc->actualcode = sftp_error_to_CURLE(err);
1057          * we do not send the actual error; we return
1058          * the error the libssh2 backend is returning */
1059         break;
1060       }
1061       state(data, SSH_SFTP_NEXT_QUOTE);
1062       break;
1063 
1064     case SSH_SFTP_QUOTE_SYMLINK:
1065       rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
1066                         sshc->quote_path1);
1067       if(rc && !sshc->acceptfail) {
1068         Curl_safefree(sshc->quote_path1);
1069         Curl_safefree(sshc->quote_path2);
1070         failf(data, "symlink command failed: %s",
1071               ssh_get_error(sshc->ssh_session));
1072         state(data, SSH_SFTP_CLOSE);
1073         sshc->nextstate = SSH_NO_STATE;
1074         sshc->actualcode = CURLE_QUOTE_ERROR;
1075         break;
1076       }
1077       state(data, SSH_SFTP_NEXT_QUOTE);
1078       break;
1079 
1080     case SSH_SFTP_QUOTE_MKDIR:
1081       rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
1082                       (mode_t)data->set.new_directory_perms);
1083       if(rc && !sshc->acceptfail) {
1084         Curl_safefree(sshc->quote_path1);
1085         failf(data, "mkdir command failed: %s",
1086               ssh_get_error(sshc->ssh_session));
1087         state(data, SSH_SFTP_CLOSE);
1088         sshc->nextstate = SSH_NO_STATE;
1089         sshc->actualcode = CURLE_QUOTE_ERROR;
1090         break;
1091       }
1092       state(data, SSH_SFTP_NEXT_QUOTE);
1093       break;
1094 
1095     case SSH_SFTP_QUOTE_RENAME:
1096       rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
1097                        sshc->quote_path2);
1098       if(rc && !sshc->acceptfail) {
1099         Curl_safefree(sshc->quote_path1);
1100         Curl_safefree(sshc->quote_path2);
1101         failf(data, "rename command failed: %s",
1102               ssh_get_error(sshc->ssh_session));
1103         state(data, SSH_SFTP_CLOSE);
1104         sshc->nextstate = SSH_NO_STATE;
1105         sshc->actualcode = CURLE_QUOTE_ERROR;
1106         break;
1107       }
1108       state(data, SSH_SFTP_NEXT_QUOTE);
1109       break;
1110 
1111     case SSH_SFTP_QUOTE_RMDIR:
1112       rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
1113       if(rc && !sshc->acceptfail) {
1114         Curl_safefree(sshc->quote_path1);
1115         failf(data, "rmdir command failed: %s",
1116               ssh_get_error(sshc->ssh_session));
1117         state(data, SSH_SFTP_CLOSE);
1118         sshc->nextstate = SSH_NO_STATE;
1119         sshc->actualcode = CURLE_QUOTE_ERROR;
1120         break;
1121       }
1122       state(data, SSH_SFTP_NEXT_QUOTE);
1123       break;
1124 
1125     case SSH_SFTP_QUOTE_UNLINK:
1126       rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
1127       if(rc && !sshc->acceptfail) {
1128         Curl_safefree(sshc->quote_path1);
1129         failf(data, "rm command failed: %s",
1130               ssh_get_error(sshc->ssh_session));
1131         state(data, SSH_SFTP_CLOSE);
1132         sshc->nextstate = SSH_NO_STATE;
1133         sshc->actualcode = CURLE_QUOTE_ERROR;
1134         break;
1135       }
1136       state(data, SSH_SFTP_NEXT_QUOTE);
1137       break;
1138 
1139     case SSH_SFTP_QUOTE_STATVFS:
1140     {
1141       sftp_statvfs_t statvfs;
1142 
1143       statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
1144       if(!statvfs && !sshc->acceptfail) {
1145         Curl_safefree(sshc->quote_path1);
1146         failf(data, "statvfs command failed: %s",
1147               ssh_get_error(sshc->ssh_session));
1148         state(data, SSH_SFTP_CLOSE);
1149         sshc->nextstate = SSH_NO_STATE;
1150         sshc->actualcode = CURLE_QUOTE_ERROR;
1151         break;
1152       }
1153       else if(statvfs) {
1154         #ifdef _MSC_VER
1155         #define CURL_LIBSSH_VFS_SIZE_MASK "I64u"
1156         #else
1157         #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64
1158         #endif
1159         char *tmp = aprintf("statvfs:\n"
1160                             "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1161                             "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1162                             "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1163                             "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1164                             "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1165                             "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1166                             "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1167                             "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1168                             "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1169                             "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1170                             "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n",
1171                             statvfs->f_bsize, statvfs->f_frsize,
1172                             statvfs->f_blocks, statvfs->f_bfree,
1173                             statvfs->f_bavail, statvfs->f_files,
1174                             statvfs->f_ffree, statvfs->f_favail,
1175                             statvfs->f_fsid, statvfs->f_flag,
1176                             statvfs->f_namemax);
1177         sftp_statvfs_free(statvfs);
1178 
1179         if(!tmp) {
1180           result = CURLE_OUT_OF_MEMORY;
1181           state(data, SSH_SFTP_CLOSE);
1182           sshc->nextstate = SSH_NO_STATE;
1183           break;
1184         }
1185 
1186         result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1187         free(tmp);
1188         if(result) {
1189           state(data, SSH_SFTP_CLOSE);
1190           sshc->nextstate = SSH_NO_STATE;
1191           sshc->actualcode = result;
1192         }
1193       }
1194       state(data, SSH_SFTP_NEXT_QUOTE);
1195       break;
1196     }
1197 
1198     case SSH_SFTP_GETINFO:
1199       if(data->set.get_filetime) {
1200         state(data, SSH_SFTP_FILETIME);
1201       }
1202       else {
1203         state(data, SSH_SFTP_TRANS_INIT);
1204       }
1205       break;
1206 
1207     case SSH_SFTP_FILETIME:
1208     {
1209       sftp_attributes attrs;
1210 
1211       attrs = sftp_stat(sshc->sftp_session, protop->path);
1212       if(attrs) {
1213         data->info.filetime = attrs->mtime;
1214         sftp_attributes_free(attrs);
1215       }
1216 
1217       state(data, SSH_SFTP_TRANS_INIT);
1218       break;
1219     }
1220 
1221     case SSH_SFTP_TRANS_INIT:
1222       if(data->state.upload)
1223         state(data, SSH_SFTP_UPLOAD_INIT);
1224       else {
1225         if(protop->path[strlen(protop->path)-1] == '/')
1226           state(data, SSH_SFTP_READDIR_INIT);
1227         else
1228           state(data, SSH_SFTP_DOWNLOAD_INIT);
1229       }
1230       break;
1231 
1232     case SSH_SFTP_UPLOAD_INIT:
1233     {
1234       int flags;
1235 
1236       if(data->state.resume_from) {
1237         sftp_attributes attrs;
1238 
1239         if(data->state.resume_from < 0) {
1240           attrs = sftp_stat(sshc->sftp_session, protop->path);
1241           if(attrs) {
1242             curl_off_t size = attrs->size;
1243             if(size < 0) {
1244               failf(data, "Bad file size (%" FMT_OFF_T ")", size);
1245               MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
1246               break;
1247             }
1248             data->state.resume_from = attrs->size;
1249 
1250             sftp_attributes_free(attrs);
1251           }
1252           else {
1253             data->state.resume_from = 0;
1254           }
1255         }
1256       }
1257 
1258       if(data->set.remote_append)
1259         /* Try to open for append, but create if nonexisting */
1260         flags = O_WRONLY|O_CREAT|O_APPEND;
1261       else if(data->state.resume_from > 0)
1262         /* If we have restart position then open for append */
1263         flags = O_WRONLY|O_APPEND;
1264       else
1265         /* Clear file before writing (normal behavior) */
1266         flags = O_WRONLY|O_CREAT|O_TRUNC;
1267 
1268       if(sshc->sftp_file)
1269         sftp_close(sshc->sftp_file);
1270       sshc->sftp_file =
1271         sftp_open(sshc->sftp_session, protop->path,
1272                   flags, (mode_t)data->set.new_file_perms);
1273       if(!sshc->sftp_file) {
1274         err = sftp_get_error(sshc->sftp_session);
1275 
1276         if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
1277              err == SSH_FX_NO_SUCH_PATH)) &&
1278              (data->set.ftp_create_missing_dirs &&
1279              (strlen(protop->path) > 1))) {
1280                /* try to create the path remotely */
1281                rc = 0;
1282                sshc->secondCreateDirs = 1;
1283                state(data, SSH_SFTP_CREATE_DIRS_INIT);
1284                break;
1285         }
1286         else {
1287           MOVE_TO_SFTP_CLOSE_STATE();
1288           break;
1289         }
1290       }
1291 
1292       /* If we have a restart point then we need to seek to the correct
1293          position. */
1294       if(data->state.resume_from > 0) {
1295         /* Let's read off the proper amount of bytes from the input. */
1296         if(data->set.seek_func) {
1297           Curl_set_in_callback(data, TRUE);
1298           seekerr = data->set.seek_func(data->set.seek_client,
1299                                         data->state.resume_from, SEEK_SET);
1300           Curl_set_in_callback(data, FALSE);
1301         }
1302 
1303         if(seekerr != CURL_SEEKFUNC_OK) {
1304           curl_off_t passed = 0;
1305 
1306           if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1307             failf(data, "Could not seek stream");
1308             return CURLE_FTP_COULDNT_USE_REST;
1309           }
1310           /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
1311           do {
1312             char scratch[4*1024];
1313             size_t readthisamountnow =
1314               (data->state.resume_from - passed >
1315                 (curl_off_t)sizeof(scratch)) ?
1316               sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
1317 
1318             size_t actuallyread =
1319               data->state.fread_func(scratch, 1,
1320                                      readthisamountnow, data->state.in);
1321 
1322             passed += actuallyread;
1323             if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1324               /* this checks for greater-than only to make sure that the
1325                  CURL_READFUNC_ABORT return code still aborts */
1326               failf(data, "Failed to read data");
1327               MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
1328               break;
1329             }
1330           } while(passed < data->state.resume_from);
1331           if(rc)
1332             break;
1333         }
1334 
1335         /* now, decrease the size of the read */
1336         if(data->state.infilesize > 0) {
1337           data->state.infilesize -= data->state.resume_from;
1338           data->req.size = data->state.infilesize;
1339           Curl_pgrsSetUploadSize(data, data->state.infilesize);
1340         }
1341 
1342         rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1343         if(rc) {
1344           MOVE_TO_SFTP_CLOSE_STATE();
1345           break;
1346         }
1347       }
1348       if(data->state.infilesize > 0) {
1349         data->req.size = data->state.infilesize;
1350         Curl_pgrsSetUploadSize(data, data->state.infilesize);
1351       }
1352       /* upload data */
1353       Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
1354 
1355       /* not set by Curl_xfer_setup to preserve keepon bits */
1356       conn->sockfd = conn->writesockfd;
1357 
1358       /* store this original bitmask setup to use later on if we cannot
1359          figure out a "real" bitmask */
1360       sshc->orig_waitfor = data->req.keepon;
1361 
1362       /* we want to use the _sending_ function even when the socket turns
1363          out readable as the underlying libssh sftp send function will deal
1364          with both accordingly */
1365       data->state.select_bits = CURL_CSELECT_OUT;
1366 
1367       /* since we do not really wait for anything at this point, we want the
1368          state machine to move on as soon as possible so we set a very short
1369          timeout here */
1370       Curl_expire(data, 0, EXPIRE_RUN_NOW);
1371 
1372       state(data, SSH_STOP);
1373       break;
1374     }
1375 
1376     case SSH_SFTP_CREATE_DIRS_INIT:
1377       if(strlen(protop->path) > 1) {
1378         sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1379         state(data, SSH_SFTP_CREATE_DIRS);
1380       }
1381       else {
1382         state(data, SSH_SFTP_UPLOAD_INIT);
1383       }
1384       break;
1385 
1386     case SSH_SFTP_CREATE_DIRS:
1387       sshc->slash_pos = strchr(sshc->slash_pos, '/');
1388       if(sshc->slash_pos) {
1389         *sshc->slash_pos = 0;
1390 
1391         infof(data, "Creating directory '%s'", protop->path);
1392         state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
1393         break;
1394       }
1395       state(data, SSH_SFTP_UPLOAD_INIT);
1396       break;
1397 
1398     case SSH_SFTP_CREATE_DIRS_MKDIR:
1399       /* 'mode' - parameter is preliminary - default to 0644 */
1400       rc = sftp_mkdir(sshc->sftp_session, protop->path,
1401                       (mode_t)data->set.new_directory_perms);
1402       *sshc->slash_pos = '/';
1403       ++sshc->slash_pos;
1404       if(rc < 0) {
1405         /*
1406          * Abort if failure was not that the dir already exists or the
1407          * permission was denied (creation might succeed further down the
1408          * path) - retry on unspecific FAILURE also
1409          */
1410         err = sftp_get_error(sshc->sftp_session);
1411         if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1412            (err != SSH_FX_FAILURE) &&
1413            (err != SSH_FX_PERMISSION_DENIED)) {
1414           MOVE_TO_SFTP_CLOSE_STATE();
1415           break;
1416         }
1417         rc = 0; /* clear rc and continue */
1418       }
1419       state(data, SSH_SFTP_CREATE_DIRS);
1420       break;
1421 
1422     case SSH_SFTP_READDIR_INIT:
1423       Curl_pgrsSetDownloadSize(data, -1);
1424       if(data->req.no_body) {
1425         state(data, SSH_STOP);
1426         break;
1427       }
1428 
1429       /*
1430        * This is a directory that we are trying to get, so produce a directory
1431        * listing
1432        */
1433       sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1434                                     protop->path);
1435       if(!sshc->sftp_dir) {
1436         failf(data, "Could not open directory for reading: %s",
1437               ssh_get_error(sshc->ssh_session));
1438         MOVE_TO_SFTP_CLOSE_STATE();
1439         break;
1440       }
1441       state(data, SSH_SFTP_READDIR);
1442       break;
1443 
1444     case SSH_SFTP_READDIR:
1445       Curl_dyn_reset(&sshc->readdir_buf);
1446       if(sshc->readdir_attrs)
1447         sftp_attributes_free(sshc->readdir_attrs);
1448 
1449       sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1450       if(sshc->readdir_attrs) {
1451         sshc->readdir_filename = sshc->readdir_attrs->name;
1452         sshc->readdir_longentry = sshc->readdir_attrs->longname;
1453         sshc->readdir_len = strlen(sshc->readdir_filename);
1454 
1455         if(data->set.list_only) {
1456           char *tmpLine;
1457 
1458           tmpLine = aprintf("%s\n", sshc->readdir_filename);
1459           if(!tmpLine) {
1460             state(data, SSH_SFTP_CLOSE);
1461             sshc->actualcode = CURLE_OUT_OF_MEMORY;
1462             break;
1463           }
1464           result = Curl_client_write(data, CLIENTWRITE_BODY,
1465                                      tmpLine, sshc->readdir_len + 1);
1466           free(tmpLine);
1467 
1468           if(result) {
1469             state(data, SSH_STOP);
1470             break;
1471           }
1472 
1473         }
1474         else {
1475           if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
1476             sshc->actualcode = CURLE_OUT_OF_MEMORY;
1477             state(data, SSH_STOP);
1478             break;
1479           }
1480 
1481           if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1482              ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
1483               SSH_S_IFLNK)) {
1484             sshc->readdir_linkPath = aprintf("%s%s", protop->path,
1485                                              sshc->readdir_filename);
1486 
1487             if(!sshc->readdir_linkPath) {
1488               state(data, SSH_SFTP_CLOSE);
1489               sshc->actualcode = CURLE_OUT_OF_MEMORY;
1490               break;
1491             }
1492 
1493             state(data, SSH_SFTP_READDIR_LINK);
1494             break;
1495           }
1496           state(data, SSH_SFTP_READDIR_BOTTOM);
1497           break;
1498         }
1499       }
1500       else if(sftp_dir_eof(sshc->sftp_dir)) {
1501         state(data, SSH_SFTP_READDIR_DONE);
1502         break;
1503       }
1504       else {
1505         failf(data, "Could not open remote file for reading: %s",
1506               ssh_get_error(sshc->ssh_session));
1507         MOVE_TO_SFTP_CLOSE_STATE();
1508         break;
1509       }
1510       break;
1511 
1512     case SSH_SFTP_READDIR_LINK:
1513       if(sshc->readdir_link_attrs)
1514         sftp_attributes_free(sshc->readdir_link_attrs);
1515 
1516       sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1517                                             sshc->readdir_linkPath);
1518       if(sshc->readdir_link_attrs == 0) {
1519         failf(data, "Could not read symlink for reading: %s",
1520               ssh_get_error(sshc->ssh_session));
1521         MOVE_TO_SFTP_CLOSE_STATE();
1522         break;
1523       }
1524 
1525       if(!sshc->readdir_link_attrs->name) {
1526         sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1527                                           sshc->readdir_linkPath);
1528         if(!sshc->readdir_filename)
1529           sshc->readdir_len = 0;
1530         else
1531           sshc->readdir_len = strlen(sshc->readdir_tmp);
1532         sshc->readdir_longentry = NULL;
1533         sshc->readdir_filename = sshc->readdir_tmp;
1534       }
1535       else {
1536         sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
1537         sshc->readdir_filename = sshc->readdir_link_attrs->name;
1538         sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1539       }
1540 
1541       Curl_safefree(sshc->readdir_linkPath);
1542 
1543       if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
1544                        sshc->readdir_filename)) {
1545         sshc->actualcode = CURLE_OUT_OF_MEMORY;
1546         break;
1547       }
1548 
1549       sftp_attributes_free(sshc->readdir_link_attrs);
1550       sshc->readdir_link_attrs = NULL;
1551       sshc->readdir_filename = NULL;
1552       sshc->readdir_longentry = NULL;
1553 
1554       state(data, SSH_SFTP_READDIR_BOTTOM);
1555       FALLTHROUGH();
1556     case SSH_SFTP_READDIR_BOTTOM:
1557       if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
1558         result = CURLE_OUT_OF_MEMORY;
1559       else
1560         result = Curl_client_write(data, CLIENTWRITE_BODY,
1561                                    Curl_dyn_ptr(&sshc->readdir_buf),
1562                                    Curl_dyn_len(&sshc->readdir_buf));
1563 
1564       ssh_string_free_char(sshc->readdir_tmp);
1565       sshc->readdir_tmp = NULL;
1566 
1567       if(result) {
1568         state(data, SSH_STOP);
1569       }
1570       else
1571         state(data, SSH_SFTP_READDIR);
1572       break;
1573 
1574     case SSH_SFTP_READDIR_DONE:
1575       sftp_closedir(sshc->sftp_dir);
1576       sshc->sftp_dir = NULL;
1577 
1578       /* no data to transfer */
1579       Curl_xfer_setup_nop(data);
1580       state(data, SSH_STOP);
1581       break;
1582 
1583     case SSH_SFTP_DOWNLOAD_INIT:
1584       /*
1585        * Work on getting the specified file
1586        */
1587       if(sshc->sftp_file)
1588         sftp_close(sshc->sftp_file);
1589 
1590       sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1591                                   O_RDONLY, (mode_t)data->set.new_file_perms);
1592       if(!sshc->sftp_file) {
1593         failf(data, "Could not open remote file for reading: %s",
1594               ssh_get_error(sshc->ssh_session));
1595 
1596         MOVE_TO_SFTP_CLOSE_STATE();
1597         break;
1598       }
1599       sftp_file_set_nonblocking(sshc->sftp_file);
1600       state(data, SSH_SFTP_DOWNLOAD_STAT);
1601       break;
1602 
1603     case SSH_SFTP_DOWNLOAD_STAT:
1604     {
1605       sftp_attributes attrs;
1606       curl_off_t size;
1607 
1608       attrs = sftp_fstat(sshc->sftp_file);
1609       if(!attrs ||
1610               !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1611               (attrs->size == 0)) {
1612         /*
1613          * sftp_fstat did not return an error, so maybe the server
1614          * just does not support stat()
1615          * OR the server does not return a file size with a stat()
1616          * OR file size is 0
1617          */
1618         data->req.size = -1;
1619         data->req.maxdownload = -1;
1620         Curl_pgrsSetDownloadSize(data, -1);
1621         size = 0;
1622       }
1623       else {
1624         size = attrs->size;
1625 
1626         sftp_attributes_free(attrs);
1627 
1628         if(size < 0) {
1629           failf(data, "Bad file size (%" FMT_OFF_T ")", size);
1630           return CURLE_BAD_DOWNLOAD_RESUME;
1631         }
1632         if(data->state.use_range) {
1633           curl_off_t from, to;
1634           char *ptr;
1635           char *ptr2;
1636           CURLofft to_t;
1637           CURLofft from_t;
1638 
1639           from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
1640           if(from_t == CURL_OFFT_FLOW) {
1641             return CURLE_RANGE_ERROR;
1642           }
1643           while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
1644             ptr++;
1645           to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
1646           if(to_t == CURL_OFFT_FLOW) {
1647             return CURLE_RANGE_ERROR;
1648           }
1649           if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1650              || (to >= size)) {
1651             to = size - 1;
1652           }
1653           if(from_t) {
1654             /* from is relative to end of file */
1655             from = size - to;
1656             to = size - 1;
1657           }
1658           if(from > size) {
1659             failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
1660                   FMT_OFF_T ")", from, size);
1661             return CURLE_BAD_DOWNLOAD_RESUME;
1662           }
1663           if(from > to) {
1664             from = to;
1665             size = 0;
1666           }
1667           else {
1668             if((to - from) == CURL_OFF_T_MAX)
1669               return CURLE_RANGE_ERROR;
1670             size = to - from + 1;
1671           }
1672 
1673           rc = sftp_seek64(sshc->sftp_file, from);
1674           if(rc) {
1675             MOVE_TO_SFTP_CLOSE_STATE();
1676             break;
1677           }
1678         }
1679         data->req.size = size;
1680         data->req.maxdownload = size;
1681         Curl_pgrsSetDownloadSize(data, size);
1682       }
1683 
1684       /* We can resume if we can seek to the resume position */
1685       if(data->state.resume_from) {
1686         if(data->state.resume_from < 0) {
1687           /* We are supposed to download the last abs(from) bytes */
1688           if((curl_off_t)size < -data->state.resume_from) {
1689             failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
1690                   FMT_OFF_T ")", 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 (%" FMT_OFF_T
1699                   ") was beyond file size (%" FMT_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_xfer_setup_nop(data);
1722       infof(data, "File already completely downloaded");
1723       state(data, SSH_STOP);
1724       break;
1725     }
1726     Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
1727 
1728     /* not set by Curl_xfer_setup 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_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
1851 
1852       /* not set by Curl_xfer_setup to preserve keepon bits */
1853       conn->sockfd = conn->writesockfd;
1854 
1855       /* store this original bitmask setup to use later on if we cannot
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_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);
1895 
1896         /* not set by Curl_xfer_setup 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 have 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   DEBUGF(infof(data, "ssh_getsock -> %x", bitmap));
2056   return bitmap;
2057 }
2058 
myssh_block2waitfor(struct connectdata * conn,bool block)2059 static void myssh_block2waitfor(struct connectdata *conn, bool block)
2060 {
2061   struct ssh_conn *sshc = &conn->proto.sshc;
2062 
2063   /* If it did not block, or nothing was returned by ssh_get_poll_flags
2064    * have the original set */
2065   conn->waitfor = sshc->orig_waitfor;
2066 
2067   if(block) {
2068     int dir = ssh_get_poll_flags(sshc->ssh_session);
2069     conn->waitfor = 0;
2070     /* translate the libssh define bits into our own bit defines */
2071     if(dir & SSH_READ_PENDING)
2072       conn->waitfor |= KEEP_RECV;
2073     if(dir & SSH_WRITE_PENDING)
2074       conn->waitfor |= KEEP_SEND;
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);
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, CURL_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,[email protected],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 = FALSE;
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 is 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,bool eos,CURLcode * err)2403 static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2404                         const void *mem, size_t len, bool eos, 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   (void)eos;
2411 
2412   rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2413 
2414 #if 0
2415   /* The following code is misleading, mostly added as wishful thinking
2416    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2417    * Currently rc can only be number of bytes read or SSH_ERROR. */
2418   myssh_block2waitfor(conn, (rc == SSH_AGAIN));
2419 
2420   if(rc == SSH_AGAIN) {
2421     *err = CURLE_AGAIN;
2422     return 0;
2423   }
2424   else
2425 #endif
2426   if(rc != SSH_OK) {
2427     *err = CURLE_SSH;
2428     return -1;
2429   }
2430 
2431   return len;
2432 }
2433 
scp_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)2434 static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2435                         char *mem, size_t len, CURLcode *err)
2436 {
2437   ssize_t nread;
2438   struct connectdata *conn = data->conn;
2439   (void) err;
2440   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2441 
2442   /* libssh returns int */
2443   nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2444 
2445 #if 0
2446   /* The following code is misleading, mostly added as wishful thinking
2447    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2448    * Currently rc can only be SSH_OK or SSH_ERROR. */
2449 
2450   myssh_block2waitfor(conn, (nread == SSH_AGAIN));
2451   if(nread == SSH_AGAIN) {
2452     *err = CURLE_AGAIN;
2453     nread = -1;
2454   }
2455 #endif
2456 
2457   return nread;
2458 }
2459 
2460 /*
2461  * =============== SFTP ===============
2462  */
2463 
2464 /*
2465  ***********************************************************************
2466  *
2467  * sftp_perform()
2468  *
2469  * This is the actual DO function for SFTP. Get a file/directory according to
2470  * the options previously setup.
2471  */
2472 
2473 static
sftp_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)2474 CURLcode sftp_perform(struct Curl_easy *data,
2475                       bool *connected,
2476                       bool *dophase_done)
2477 {
2478   CURLcode result = CURLE_OK;
2479 
2480   DEBUGF(infof(data, "DO phase starts"));
2481 
2482   *dophase_done = FALSE; /* not done yet */
2483 
2484   /* start the first command in the DO phase */
2485   state(data, SSH_SFTP_QUOTE_INIT);
2486 
2487   /* run the state-machine */
2488   result = myssh_multi_statemach(data, dophase_done);
2489 
2490   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2491 
2492   if(*dophase_done) {
2493     DEBUGF(infof(data, "DO phase is complete"));
2494   }
2495 
2496   return result;
2497 }
2498 
2499 /* called from multi.c while DOing */
sftp_doing(struct Curl_easy * data,bool * dophase_done)2500 static CURLcode sftp_doing(struct Curl_easy *data,
2501                            bool *dophase_done)
2502 {
2503   CURLcode result = myssh_multi_statemach(data, dophase_done);
2504   if(*dophase_done) {
2505     DEBUGF(infof(data, "DO phase is complete"));
2506   }
2507   return result;
2508 }
2509 
2510 /* BLOCKING, but the function is using the state machine so the only reason
2511    this is still blocking is that the multi interface code has no support for
2512    disconnecting operations that takes a while */
sftp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)2513 static CURLcode sftp_disconnect(struct Curl_easy *data,
2514                                 struct connectdata *conn,
2515                                 bool dead_connection)
2516 {
2517   CURLcode result = CURLE_OK;
2518   (void) dead_connection;
2519 
2520   DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2521 
2522   if(conn->proto.sshc.ssh_session) {
2523     /* only if there is a session still around to use! */
2524     state(data, SSH_SFTP_SHUTDOWN);
2525     result = myssh_block_statemach(data, TRUE);
2526   }
2527 
2528   DEBUGF(infof(data, "SSH DISCONNECT is done"));
2529 
2530   return result;
2531 
2532 }
2533 
sftp_done(struct Curl_easy * data,CURLcode status,bool premature)2534 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2535                           bool premature)
2536 {
2537   struct connectdata *conn = data->conn;
2538   struct ssh_conn *sshc = &conn->proto.sshc;
2539 
2540   if(!status) {
2541     /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2542        errors that could happen due to open file handles during POSTQUOTE
2543        operation */
2544     if(!premature && data->set.postquote && !conn->bits.retry)
2545       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2546     state(data, SSH_SFTP_CLOSE);
2547   }
2548   return myssh_done(data, status);
2549 }
2550 
2551 /* return number of sent bytes */
sftp_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,bool eos,CURLcode * err)2552 static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2553                          const void *mem, size_t len, bool eos,
2554                          CURLcode *err)
2555 {
2556   ssize_t nwrite;
2557   struct connectdata *conn = data->conn;
2558   (void)sockindex;
2559   (void)eos;
2560 
2561   /* limit the writes to the maximum specified in Section 3 of
2562    * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
2563    */
2564   if(len > 32768)
2565     len = 32768;
2566 
2567   nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2568 
2569   myssh_block2waitfor(conn, FALSE);
2570 
2571 #if 0 /* not returned by libssh on write */
2572   if(nwrite == SSH_AGAIN) {
2573     *err = CURLE_AGAIN;
2574     nwrite = 0;
2575   }
2576   else
2577 #endif
2578   if(nwrite < 0) {
2579     *err = CURLE_SSH;
2580     nwrite = -1;
2581   }
2582 
2583   return nwrite;
2584 }
2585 
2586 /*
2587  * Return number of received (decrypted) bytes
2588  * or <0 on error
2589  */
sftp_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)2590 static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2591                          char *mem, size_t len, CURLcode *err)
2592 {
2593   ssize_t nread;
2594   struct connectdata *conn = data->conn;
2595   (void)sockindex;
2596 
2597   DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2598 
2599   switch(conn->proto.sshc.sftp_recv_state) {
2600     case 0:
2601       conn->proto.sshc.sftp_file_index =
2602         sftp_async_read_begin(conn->proto.sshc.sftp_file,
2603                               (uint32_t)len);
2604       if(conn->proto.sshc.sftp_file_index < 0) {
2605         *err = CURLE_RECV_ERROR;
2606         return -1;
2607       }
2608 
2609       FALLTHROUGH();
2610     case 1:
2611       conn->proto.sshc.sftp_recv_state = 1;
2612 
2613       nread = sftp_async_read(conn->proto.sshc.sftp_file,
2614                               mem, (uint32_t)len,
2615                               (uint32_t)conn->proto.sshc.sftp_file_index);
2616 
2617       myssh_block2waitfor(conn, (nread == SSH_AGAIN));
2618 
2619       if(nread == SSH_AGAIN) {
2620         *err = CURLE_AGAIN;
2621         return -1;
2622       }
2623       else if(nread < 0) {
2624         *err = CURLE_RECV_ERROR;
2625         return -1;
2626       }
2627 
2628       conn->proto.sshc.sftp_recv_state = 0;
2629       return nread;
2630 
2631     default:
2632       /* we never reach here */
2633       return -1;
2634   }
2635 }
2636 
sftp_quote(struct Curl_easy * data)2637 static void sftp_quote(struct Curl_easy *data)
2638 {
2639   const char *cp;
2640   struct connectdata *conn = data->conn;
2641   struct SSHPROTO *protop = data->req.p.ssh;
2642   struct ssh_conn *sshc = &conn->proto.sshc;
2643   CURLcode result;
2644 
2645   /*
2646    * Support some of the "FTP" commands
2647    */
2648   char *cmd = sshc->quote_item->data;
2649   sshc->acceptfail = FALSE;
2650 
2651   /* if a command starts with an asterisk, which a legal SFTP command never
2652      can, the command will be allowed to fail without it causing any
2653      aborts or cancels etc. It will cause libcurl to act as if the command
2654      is successful, whatever the server responds. */
2655 
2656   if(cmd[0] == '*') {
2657     cmd++;
2658     sshc->acceptfail = TRUE;
2659   }
2660 
2661   if(strcasecompare("pwd", cmd)) {
2662     /* output debug output if that is requested */
2663     char *tmp = aprintf("257 \"%s\" is current directory.\n",
2664                         protop->path);
2665     if(!tmp) {
2666       sshc->actualcode = CURLE_OUT_OF_MEMORY;
2667       state(data, SSH_SFTP_CLOSE);
2668       sshc->nextstate = SSH_NO_STATE;
2669       return;
2670     }
2671     Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2672     Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2673 
2674     /* this sends an FTP-like "header" to the header callback so that the
2675        current directory can be read very similar to how it is read when
2676        using ordinary FTP. */
2677     result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2678     free(tmp);
2679     if(result) {
2680       state(data, SSH_SFTP_CLOSE);
2681       sshc->nextstate = SSH_NO_STATE;
2682       sshc->actualcode = result;
2683     }
2684     else
2685       state(data, SSH_SFTP_NEXT_QUOTE);
2686     return;
2687   }
2688 
2689   /*
2690    * the arguments following the command must be separated from the
2691    * command with a space so we can check for it unconditionally
2692    */
2693   cp = strchr(cmd, ' ');
2694   if(!cp) {
2695     failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2696     state(data, SSH_SFTP_CLOSE);
2697     sshc->nextstate = SSH_NO_STATE;
2698     sshc->actualcode = CURLE_QUOTE_ERROR;
2699     return;
2700   }
2701 
2702   /*
2703    * also, every command takes at least one argument so we get that
2704    * first argument right now
2705    */
2706   result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2707   if(result) {
2708     if(result == CURLE_OUT_OF_MEMORY)
2709       failf(data, "Out of memory");
2710     else
2711       failf(data, "Syntax error: Bad first parameter");
2712     state(data, SSH_SFTP_CLOSE);
2713     sshc->nextstate = SSH_NO_STATE;
2714     sshc->actualcode = result;
2715     return;
2716   }
2717 
2718   /*
2719    * SFTP is a binary protocol, so we do not send text commands
2720    * to the server. Instead, we scan for commands used by
2721    * OpenSSH's sftp program and call the appropriate libssh
2722    * functions.
2723    */
2724   if(strncasecompare(cmd, "chgrp ", 6) ||
2725      strncasecompare(cmd, "chmod ", 6) ||
2726      strncasecompare(cmd, "chown ", 6) ||
2727      strncasecompare(cmd, "atime ", 6) ||
2728      strncasecompare(cmd, "mtime ", 6)) {
2729     /* attribute change */
2730 
2731     /* sshc->quote_path1 contains the mode to set */
2732     /* get the destination */
2733     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2734     if(result) {
2735       if(result == CURLE_OUT_OF_MEMORY)
2736         failf(data, "Out of memory");
2737       else
2738         failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2739               "Bad second parameter");
2740       Curl_safefree(sshc->quote_path1);
2741       state(data, SSH_SFTP_CLOSE);
2742       sshc->nextstate = SSH_NO_STATE;
2743       sshc->actualcode = result;
2744       return;
2745     }
2746     sshc->quote_attrs = NULL;
2747     state(data, SSH_SFTP_QUOTE_STAT);
2748     return;
2749   }
2750   if(strncasecompare(cmd, "ln ", 3) ||
2751      strncasecompare(cmd, "symlink ", 8)) {
2752     /* symbolic linking */
2753     /* sshc->quote_path1 is the source */
2754     /* get the destination */
2755     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2756     if(result) {
2757       if(result == CURLE_OUT_OF_MEMORY)
2758         failf(data, "Out of memory");
2759       else
2760         failf(data, "Syntax error in ln/symlink: Bad second parameter");
2761       Curl_safefree(sshc->quote_path1);
2762       state(data, SSH_SFTP_CLOSE);
2763       sshc->nextstate = SSH_NO_STATE;
2764       sshc->actualcode = result;
2765       return;
2766     }
2767     state(data, SSH_SFTP_QUOTE_SYMLINK);
2768     return;
2769   }
2770   else if(strncasecompare(cmd, "mkdir ", 6)) {
2771     /* create dir */
2772     state(data, SSH_SFTP_QUOTE_MKDIR);
2773     return;
2774   }
2775   else if(strncasecompare(cmd, "rename ", 7)) {
2776     /* rename file */
2777     /* first param is the source path */
2778     /* second param is the dest. path */
2779     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2780     if(result) {
2781       if(result == CURLE_OUT_OF_MEMORY)
2782         failf(data, "Out of memory");
2783       else
2784         failf(data, "Syntax error in rename: Bad second parameter");
2785       Curl_safefree(sshc->quote_path1);
2786       state(data, SSH_SFTP_CLOSE);
2787       sshc->nextstate = SSH_NO_STATE;
2788       sshc->actualcode = result;
2789       return;
2790     }
2791     state(data, SSH_SFTP_QUOTE_RENAME);
2792     return;
2793   }
2794   else if(strncasecompare(cmd, "rmdir ", 6)) {
2795     /* delete dir */
2796     state(data, SSH_SFTP_QUOTE_RMDIR);
2797     return;
2798   }
2799   else if(strncasecompare(cmd, "rm ", 3)) {
2800     state(data, SSH_SFTP_QUOTE_UNLINK);
2801     return;
2802   }
2803 #ifdef HAS_STATVFS_SUPPORT
2804   else if(strncasecompare(cmd, "statvfs ", 8)) {
2805     state(data, SSH_SFTP_QUOTE_STATVFS);
2806     return;
2807   }
2808 #endif
2809 
2810   failf(data, "Unknown SFTP command");
2811   Curl_safefree(sshc->quote_path1);
2812   Curl_safefree(sshc->quote_path2);
2813   state(data, SSH_SFTP_CLOSE);
2814   sshc->nextstate = SSH_NO_STATE;
2815   sshc->actualcode = CURLE_QUOTE_ERROR;
2816 }
2817 
sftp_quote_stat(struct Curl_easy * data)2818 static void sftp_quote_stat(struct Curl_easy *data)
2819 {
2820   struct connectdata *conn = data->conn;
2821   struct ssh_conn *sshc = &conn->proto.sshc;
2822   char *cmd = sshc->quote_item->data;
2823   sshc->acceptfail = FALSE;
2824 
2825   /* if a command starts with an asterisk, which a legal SFTP command never
2826      can, the command will be allowed to fail without it causing any
2827      aborts or cancels etc. It will cause libcurl to act as if the command
2828      is successful, whatever the server responds. */
2829 
2830   if(cmd[0] == '*') {
2831     cmd++;
2832     sshc->acceptfail = TRUE;
2833   }
2834 
2835   /* We read the file attributes, store them in sshc->quote_attrs
2836    * and modify them accordingly to command. Then we switch to
2837    * QUOTE_SETSTAT state to write new ones.
2838    */
2839 
2840   if(sshc->quote_attrs)
2841     sftp_attributes_free(sshc->quote_attrs);
2842   sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2843   if(!sshc->quote_attrs) {
2844     Curl_safefree(sshc->quote_path1);
2845     Curl_safefree(sshc->quote_path2);
2846     failf(data, "Attempt to get SFTP stats failed: %d",
2847           sftp_get_error(sshc->sftp_session));
2848     state(data, SSH_SFTP_CLOSE);
2849     sshc->nextstate = SSH_NO_STATE;
2850     sshc->actualcode = CURLE_QUOTE_ERROR;
2851     return;
2852   }
2853 
2854   /* Now set the new attributes... */
2855   if(strncasecompare(cmd, "chgrp", 5)) {
2856     sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2857     if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2858         !sshc->acceptfail) {
2859       Curl_safefree(sshc->quote_path1);
2860       Curl_safefree(sshc->quote_path2);
2861       failf(data, "Syntax error: chgrp gid not a number");
2862       state(data, SSH_SFTP_CLOSE);
2863       sshc->nextstate = SSH_NO_STATE;
2864       sshc->actualcode = CURLE_QUOTE_ERROR;
2865       return;
2866     }
2867     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2868   }
2869   else if(strncasecompare(cmd, "chmod", 5)) {
2870     mode_t perms;
2871     perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2872     /* permissions are octal */
2873     if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2874       Curl_safefree(sshc->quote_path1);
2875       Curl_safefree(sshc->quote_path2);
2876       failf(data, "Syntax error: chmod permissions not a number");
2877       state(data, SSH_SFTP_CLOSE);
2878       sshc->nextstate = SSH_NO_STATE;
2879       sshc->actualcode = CURLE_QUOTE_ERROR;
2880       return;
2881     }
2882     sshc->quote_attrs->permissions = perms;
2883     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2884   }
2885   else if(strncasecompare(cmd, "chown", 5)) {
2886     sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2887     if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2888         !sshc->acceptfail) {
2889       Curl_safefree(sshc->quote_path1);
2890       Curl_safefree(sshc->quote_path2);
2891       failf(data, "Syntax error: chown uid not a number");
2892       state(data, SSH_SFTP_CLOSE);
2893       sshc->nextstate = SSH_NO_STATE;
2894       sshc->actualcode = CURLE_QUOTE_ERROR;
2895       return;
2896     }
2897     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2898   }
2899   else if(strncasecompare(cmd, "atime", 5) ||
2900           strncasecompare(cmd, "mtime", 5)) {
2901     time_t date = Curl_getdate_capped(sshc->quote_path1);
2902     bool fail = FALSE;
2903     if(date == -1) {
2904       failf(data, "incorrect date format for %.*s", 5, cmd);
2905       fail = TRUE;
2906     }
2907 #if SIZEOF_TIME_T > 4
2908     else if(date > 0xffffffff) {
2909       failf(data, "date overflow");
2910       fail = TRUE; /* avoid setting a capped time */
2911     }
2912 #endif
2913     if(fail) {
2914       Curl_safefree(sshc->quote_path1);
2915       Curl_safefree(sshc->quote_path2);
2916       state(data, SSH_SFTP_CLOSE);
2917       sshc->nextstate = SSH_NO_STATE;
2918       sshc->actualcode = CURLE_QUOTE_ERROR;
2919       return;
2920     }
2921     if(strncasecompare(cmd, "atime", 5))
2922       sshc->quote_attrs->atime = (uint32_t)date;
2923     else /* mtime */
2924       sshc->quote_attrs->mtime = (uint32_t)date;
2925 
2926     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2927   }
2928 
2929   /* Now send the completed structure... */
2930   state(data, SSH_SFTP_QUOTE_SETSTAT);
2931   return;
2932 }
2933 
Curl_ssh_init(void)2934 CURLcode Curl_ssh_init(void)
2935 {
2936   if(ssh_init()) {
2937     DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2938     return CURLE_FAILED_INIT;
2939   }
2940   return CURLE_OK;
2941 }
2942 
Curl_ssh_cleanup(void)2943 void Curl_ssh_cleanup(void)
2944 {
2945   (void)ssh_finalize();
2946 }
2947 
Curl_ssh_version(char * buffer,size_t buflen)2948 void Curl_ssh_version(char *buffer, size_t buflen)
2949 {
2950   (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
2951 }
2952 
2953 #endif                          /* USE_LIBSSH */
2954