xref: /curl/lib/vssh/libssh.c (revision 93c65c00)
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   if(conn->bits.ipv6_ip) {
2195     char ipv6[MAX_IPADR_LEN];
2196     msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name);
2197     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, ipv6);
2198   }
2199   else
2200     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2201 
2202   if(rc != SSH_OK) {
2203     failf(data, "Could not set remote host");
2204     return CURLE_FAILED_INIT;
2205   }
2206 
2207   rc = ssh_options_parse_config(ssh->ssh_session, NULL);
2208   if(rc != SSH_OK) {
2209     infof(data, "Could not parse SSH configuration files");
2210     /* ignore */
2211   }
2212 
2213   rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2214   if(rc != SSH_OK) {
2215     failf(data, "Could not set socket");
2216     return CURLE_FAILED_INIT;
2217   }
2218 
2219   if(conn->user && conn->user[0] != '\0') {
2220     infof(data, "User: %s", conn->user);
2221     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2222     if(rc != SSH_OK) {
2223       failf(data, "Could not set user");
2224       return CURLE_FAILED_INIT;
2225     }
2226   }
2227 
2228   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2229     infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
2230     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2231                          data->set.str[STRING_SSH_KNOWNHOSTS]);
2232     if(rc != SSH_OK) {
2233       failf(data, "Could not set known hosts file path");
2234       return CURLE_FAILED_INIT;
2235     }
2236   }
2237 
2238   if(conn->remote_port) {
2239     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2240                          &conn->remote_port);
2241     if(rc != SSH_OK) {
2242       failf(data, "Could not set remote port");
2243       return CURLE_FAILED_INIT;
2244     }
2245   }
2246 
2247   if(data->set.ssh_compression) {
2248     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2249                          "zlib,zlib@openssh.com,none");
2250     if(rc != SSH_OK) {
2251       failf(data, "Could not set compression");
2252       return CURLE_FAILED_INIT;
2253     }
2254   }
2255 
2256   ssh->privkey = NULL;
2257   ssh->pubkey = NULL;
2258 
2259   if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2260     rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2261                                     &ssh->pubkey);
2262     if(rc != SSH_OK) {
2263       failf(data, "Could not load public key file");
2264       return CURLE_FAILED_INIT;
2265     }
2266   }
2267 
2268   /* we do not verify here, we do it at the state machine,
2269    * after connection */
2270 
2271   state(data, SSH_INIT);
2272 
2273   result = myssh_multi_statemach(data, done);
2274 
2275   return result;
2276 }
2277 
2278 /* called from multi.c while DOing */
scp_doing(struct Curl_easy * data,bool * dophase_done)2279 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
2280 {
2281   CURLcode result;
2282 
2283   result = myssh_multi_statemach(data, dophase_done);
2284 
2285   if(*dophase_done) {
2286     DEBUGF(infof(data, "DO phase is complete"));
2287   }
2288   return result;
2289 }
2290 
2291 /*
2292  ***********************************************************************
2293  *
2294  * scp_perform()
2295  *
2296  * This is the actual DO function for SCP. Get a file according to
2297  * the options previously setup.
2298  */
2299 
2300 static
scp_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)2301 CURLcode scp_perform(struct Curl_easy *data,
2302                      bool *connected, bool *dophase_done)
2303 {
2304   CURLcode result = CURLE_OK;
2305 
2306   DEBUGF(infof(data, "DO phase starts"));
2307 
2308   *dophase_done = FALSE;        /* not done yet */
2309 
2310   /* start the first command in the DO phase */
2311   state(data, SSH_SCP_TRANS_INIT);
2312 
2313   result = myssh_multi_statemach(data, dophase_done);
2314 
2315   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2316 
2317   if(*dophase_done) {
2318     DEBUGF(infof(data, "DO phase is complete"));
2319   }
2320 
2321   return result;
2322 }
2323 
myssh_do_it(struct Curl_easy * data,bool * done)2324 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
2325 {
2326   CURLcode result;
2327   bool connected = FALSE;
2328   struct connectdata *conn = data->conn;
2329   struct ssh_conn *sshc = &conn->proto.sshc;
2330 
2331   *done = FALSE;                /* default to false */
2332 
2333   data->req.size = -1;          /* make sure this is unknown at this point */
2334 
2335   sshc->actualcode = CURLE_OK;  /* reset error code */
2336   sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
2337                                    variable */
2338 
2339   Curl_pgrsSetUploadCounter(data, 0);
2340   Curl_pgrsSetDownloadCounter(data, 0);
2341   Curl_pgrsSetUploadSize(data, -1);
2342   Curl_pgrsSetDownloadSize(data, -1);
2343 
2344   if(conn->handler->protocol & CURLPROTO_SCP)
2345     result = scp_perform(data, &connected, done);
2346   else
2347     result = sftp_perform(data, &connected, done);
2348 
2349   return result;
2350 }
2351 
2352 /* BLOCKING, but the function is using the state machine so the only reason
2353    this is still blocking is that the multi interface code has no support for
2354    disconnecting operations that takes a while */
scp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)2355 static CURLcode scp_disconnect(struct Curl_easy *data,
2356                                struct connectdata *conn,
2357                                bool dead_connection)
2358 {
2359   CURLcode result = CURLE_OK;
2360   struct ssh_conn *ssh = &conn->proto.sshc;
2361   (void) dead_connection;
2362 
2363   if(ssh->ssh_session) {
2364     /* only if there is a session still around to use! */
2365 
2366     state(data, SSH_SESSION_DISCONNECT);
2367 
2368     result = myssh_block_statemach(data, TRUE);
2369   }
2370 
2371   return result;
2372 }
2373 
2374 /* generic done function for both SCP and SFTP called from their specific
2375    done functions */
myssh_done(struct Curl_easy * data,CURLcode status)2376 static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
2377 {
2378   CURLcode result = CURLE_OK;
2379   struct SSHPROTO *protop = data->req.p.ssh;
2380 
2381   if(!status) {
2382     /* run the state-machine */
2383     result = myssh_block_statemach(data, FALSE);
2384   }
2385   else
2386     result = status;
2387 
2388   if(protop)
2389     Curl_safefree(protop->path);
2390   if(Curl_pgrsDone(data))
2391     return CURLE_ABORTED_BY_CALLBACK;
2392 
2393   data->req.keepon = 0;   /* clear all bits */
2394   return result;
2395 }
2396 
2397 
scp_done(struct Curl_easy * data,CURLcode status,bool premature)2398 static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
2399                          bool premature)
2400 {
2401   (void) premature;             /* not used */
2402 
2403   if(!status)
2404     state(data, SSH_SCP_DONE);
2405 
2406   return myssh_done(data, status);
2407 
2408 }
2409 
scp_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,bool eos,CURLcode * err)2410 static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2411                         const void *mem, size_t len, bool eos, CURLcode *err)
2412 {
2413   int rc;
2414   struct connectdata *conn = data->conn;
2415   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2416   (void) err;
2417   (void)eos;
2418 
2419   rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2420 
2421 #if 0
2422   /* The following code is misleading, mostly added as wishful thinking
2423    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2424    * Currently rc can only be number of bytes read or SSH_ERROR. */
2425   myssh_block2waitfor(conn, (rc == SSH_AGAIN));
2426 
2427   if(rc == SSH_AGAIN) {
2428     *err = CURLE_AGAIN;
2429     return 0;
2430   }
2431   else
2432 #endif
2433   if(rc != SSH_OK) {
2434     *err = CURLE_SSH;
2435     return -1;
2436   }
2437 
2438   return len;
2439 }
2440 
scp_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)2441 static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2442                         char *mem, size_t len, CURLcode *err)
2443 {
2444   ssize_t nread;
2445   struct connectdata *conn = data->conn;
2446   (void) err;
2447   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2448 
2449   /* libssh returns int */
2450   nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2451 
2452 #if 0
2453   /* The following code is misleading, mostly added as wishful thinking
2454    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2455    * Currently rc can only be SSH_OK or SSH_ERROR. */
2456 
2457   myssh_block2waitfor(conn, (nread == SSH_AGAIN));
2458   if(nread == SSH_AGAIN) {
2459     *err = CURLE_AGAIN;
2460     nread = -1;
2461   }
2462 #endif
2463 
2464   return nread;
2465 }
2466 
2467 /*
2468  * =============== SFTP ===============
2469  */
2470 
2471 /*
2472  ***********************************************************************
2473  *
2474  * sftp_perform()
2475  *
2476  * This is the actual DO function for SFTP. Get a file/directory according to
2477  * the options previously setup.
2478  */
2479 
2480 static
sftp_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)2481 CURLcode sftp_perform(struct Curl_easy *data,
2482                       bool *connected,
2483                       bool *dophase_done)
2484 {
2485   CURLcode result = CURLE_OK;
2486 
2487   DEBUGF(infof(data, "DO phase starts"));
2488 
2489   *dophase_done = FALSE; /* not done yet */
2490 
2491   /* start the first command in the DO phase */
2492   state(data, SSH_SFTP_QUOTE_INIT);
2493 
2494   /* run the state-machine */
2495   result = myssh_multi_statemach(data, dophase_done);
2496 
2497   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2498 
2499   if(*dophase_done) {
2500     DEBUGF(infof(data, "DO phase is complete"));
2501   }
2502 
2503   return result;
2504 }
2505 
2506 /* called from multi.c while DOing */
sftp_doing(struct Curl_easy * data,bool * dophase_done)2507 static CURLcode sftp_doing(struct Curl_easy *data,
2508                            bool *dophase_done)
2509 {
2510   CURLcode result = myssh_multi_statemach(data, dophase_done);
2511   if(*dophase_done) {
2512     DEBUGF(infof(data, "DO phase is complete"));
2513   }
2514   return result;
2515 }
2516 
2517 /* BLOCKING, but the function is using the state machine so the only reason
2518    this is still blocking is that the multi interface code has no support for
2519    disconnecting operations that takes a while */
sftp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)2520 static CURLcode sftp_disconnect(struct Curl_easy *data,
2521                                 struct connectdata *conn,
2522                                 bool dead_connection)
2523 {
2524   CURLcode result = CURLE_OK;
2525   (void) dead_connection;
2526 
2527   DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2528 
2529   if(conn->proto.sshc.ssh_session) {
2530     /* only if there is a session still around to use! */
2531     state(data, SSH_SFTP_SHUTDOWN);
2532     result = myssh_block_statemach(data, TRUE);
2533   }
2534 
2535   DEBUGF(infof(data, "SSH DISCONNECT is done"));
2536 
2537   return result;
2538 
2539 }
2540 
sftp_done(struct Curl_easy * data,CURLcode status,bool premature)2541 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2542                           bool premature)
2543 {
2544   struct connectdata *conn = data->conn;
2545   struct ssh_conn *sshc = &conn->proto.sshc;
2546 
2547   if(!status) {
2548     /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2549        errors that could happen due to open file handles during POSTQUOTE
2550        operation */
2551     if(!premature && data->set.postquote && !conn->bits.retry)
2552       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2553     state(data, SSH_SFTP_CLOSE);
2554   }
2555   return myssh_done(data, status);
2556 }
2557 
2558 /* return number of sent bytes */
sftp_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,bool eos,CURLcode * err)2559 static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2560                          const void *mem, size_t len, bool eos,
2561                          CURLcode *err)
2562 {
2563   ssize_t nwrite;
2564   struct connectdata *conn = data->conn;
2565   (void)sockindex;
2566   (void)eos;
2567 
2568   /* limit the writes to the maximum specified in Section 3 of
2569    * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
2570    */
2571   if(len > 32768)
2572     len = 32768;
2573 
2574   nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2575 
2576   myssh_block2waitfor(conn, FALSE);
2577 
2578 #if 0 /* not returned by libssh on write */
2579   if(nwrite == SSH_AGAIN) {
2580     *err = CURLE_AGAIN;
2581     nwrite = 0;
2582   }
2583   else
2584 #endif
2585   if(nwrite < 0) {
2586     *err = CURLE_SSH;
2587     nwrite = -1;
2588   }
2589 
2590   return nwrite;
2591 }
2592 
2593 /*
2594  * Return number of received (decrypted) bytes
2595  * or <0 on error
2596  */
sftp_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)2597 static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2598                          char *mem, size_t len, CURLcode *err)
2599 {
2600   ssize_t nread;
2601   struct connectdata *conn = data->conn;
2602   (void)sockindex;
2603 
2604   DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2605 
2606   switch(conn->proto.sshc.sftp_recv_state) {
2607     case 0:
2608       conn->proto.sshc.sftp_file_index =
2609         sftp_async_read_begin(conn->proto.sshc.sftp_file,
2610                               (uint32_t)len);
2611       if(conn->proto.sshc.sftp_file_index < 0) {
2612         *err = CURLE_RECV_ERROR;
2613         return -1;
2614       }
2615 
2616       FALLTHROUGH();
2617     case 1:
2618       conn->proto.sshc.sftp_recv_state = 1;
2619 
2620       nread = sftp_async_read(conn->proto.sshc.sftp_file,
2621                               mem, (uint32_t)len,
2622                               (uint32_t)conn->proto.sshc.sftp_file_index);
2623 
2624       myssh_block2waitfor(conn, (nread == SSH_AGAIN));
2625 
2626       if(nread == SSH_AGAIN) {
2627         *err = CURLE_AGAIN;
2628         return -1;
2629       }
2630       else if(nread < 0) {
2631         *err = CURLE_RECV_ERROR;
2632         return -1;
2633       }
2634 
2635       conn->proto.sshc.sftp_recv_state = 0;
2636       return nread;
2637 
2638     default:
2639       /* we never reach here */
2640       return -1;
2641   }
2642 }
2643 
sftp_quote(struct Curl_easy * data)2644 static void sftp_quote(struct Curl_easy *data)
2645 {
2646   const char *cp;
2647   struct connectdata *conn = data->conn;
2648   struct SSHPROTO *protop = data->req.p.ssh;
2649   struct ssh_conn *sshc = &conn->proto.sshc;
2650   CURLcode result;
2651 
2652   /*
2653    * Support some of the "FTP" commands
2654    */
2655   char *cmd = sshc->quote_item->data;
2656   sshc->acceptfail = FALSE;
2657 
2658   /* if a command starts with an asterisk, which a legal SFTP command never
2659      can, the command will be allowed to fail without it causing any
2660      aborts or cancels etc. It will cause libcurl to act as if the command
2661      is successful, whatever the server responds. */
2662 
2663   if(cmd[0] == '*') {
2664     cmd++;
2665     sshc->acceptfail = TRUE;
2666   }
2667 
2668   if(strcasecompare("pwd", cmd)) {
2669     /* output debug output if that is requested */
2670     char *tmp = aprintf("257 \"%s\" is current directory.\n",
2671                         protop->path);
2672     if(!tmp) {
2673       sshc->actualcode = CURLE_OUT_OF_MEMORY;
2674       state(data, SSH_SFTP_CLOSE);
2675       sshc->nextstate = SSH_NO_STATE;
2676       return;
2677     }
2678     Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2679     Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2680 
2681     /* this sends an FTP-like "header" to the header callback so that the
2682        current directory can be read very similar to how it is read when
2683        using ordinary FTP. */
2684     result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2685     free(tmp);
2686     if(result) {
2687       state(data, SSH_SFTP_CLOSE);
2688       sshc->nextstate = SSH_NO_STATE;
2689       sshc->actualcode = result;
2690     }
2691     else
2692       state(data, SSH_SFTP_NEXT_QUOTE);
2693     return;
2694   }
2695 
2696   /*
2697    * the arguments following the command must be separated from the
2698    * command with a space so we can check for it unconditionally
2699    */
2700   cp = strchr(cmd, ' ');
2701   if(!cp) {
2702     failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2703     state(data, SSH_SFTP_CLOSE);
2704     sshc->nextstate = SSH_NO_STATE;
2705     sshc->actualcode = CURLE_QUOTE_ERROR;
2706     return;
2707   }
2708 
2709   /*
2710    * also, every command takes at least one argument so we get that
2711    * first argument right now
2712    */
2713   result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2714   if(result) {
2715     if(result == CURLE_OUT_OF_MEMORY)
2716       failf(data, "Out of memory");
2717     else
2718       failf(data, "Syntax error: Bad first parameter");
2719     state(data, SSH_SFTP_CLOSE);
2720     sshc->nextstate = SSH_NO_STATE;
2721     sshc->actualcode = result;
2722     return;
2723   }
2724 
2725   /*
2726    * SFTP is a binary protocol, so we do not send text commands
2727    * to the server. Instead, we scan for commands used by
2728    * OpenSSH's sftp program and call the appropriate libssh
2729    * functions.
2730    */
2731   if(strncasecompare(cmd, "chgrp ", 6) ||
2732      strncasecompare(cmd, "chmod ", 6) ||
2733      strncasecompare(cmd, "chown ", 6) ||
2734      strncasecompare(cmd, "atime ", 6) ||
2735      strncasecompare(cmd, "mtime ", 6)) {
2736     /* attribute change */
2737 
2738     /* sshc->quote_path1 contains the mode to set */
2739     /* get the destination */
2740     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2741     if(result) {
2742       if(result == CURLE_OUT_OF_MEMORY)
2743         failf(data, "Out of memory");
2744       else
2745         failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2746               "Bad second parameter");
2747       Curl_safefree(sshc->quote_path1);
2748       state(data, SSH_SFTP_CLOSE);
2749       sshc->nextstate = SSH_NO_STATE;
2750       sshc->actualcode = result;
2751       return;
2752     }
2753     sshc->quote_attrs = NULL;
2754     state(data, SSH_SFTP_QUOTE_STAT);
2755     return;
2756   }
2757   if(strncasecompare(cmd, "ln ", 3) ||
2758      strncasecompare(cmd, "symlink ", 8)) {
2759     /* symbolic linking */
2760     /* sshc->quote_path1 is the source */
2761     /* get the destination */
2762     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2763     if(result) {
2764       if(result == CURLE_OUT_OF_MEMORY)
2765         failf(data, "Out of memory");
2766       else
2767         failf(data, "Syntax error in ln/symlink: Bad second parameter");
2768       Curl_safefree(sshc->quote_path1);
2769       state(data, SSH_SFTP_CLOSE);
2770       sshc->nextstate = SSH_NO_STATE;
2771       sshc->actualcode = result;
2772       return;
2773     }
2774     state(data, SSH_SFTP_QUOTE_SYMLINK);
2775     return;
2776   }
2777   else if(strncasecompare(cmd, "mkdir ", 6)) {
2778     /* create dir */
2779     state(data, SSH_SFTP_QUOTE_MKDIR);
2780     return;
2781   }
2782   else if(strncasecompare(cmd, "rename ", 7)) {
2783     /* rename file */
2784     /* first param is the source path */
2785     /* second param is the dest. path */
2786     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2787     if(result) {
2788       if(result == CURLE_OUT_OF_MEMORY)
2789         failf(data, "Out of memory");
2790       else
2791         failf(data, "Syntax error in rename: Bad second parameter");
2792       Curl_safefree(sshc->quote_path1);
2793       state(data, SSH_SFTP_CLOSE);
2794       sshc->nextstate = SSH_NO_STATE;
2795       sshc->actualcode = result;
2796       return;
2797     }
2798     state(data, SSH_SFTP_QUOTE_RENAME);
2799     return;
2800   }
2801   else if(strncasecompare(cmd, "rmdir ", 6)) {
2802     /* delete dir */
2803     state(data, SSH_SFTP_QUOTE_RMDIR);
2804     return;
2805   }
2806   else if(strncasecompare(cmd, "rm ", 3)) {
2807     state(data, SSH_SFTP_QUOTE_UNLINK);
2808     return;
2809   }
2810 #ifdef HAS_STATVFS_SUPPORT
2811   else if(strncasecompare(cmd, "statvfs ", 8)) {
2812     state(data, SSH_SFTP_QUOTE_STATVFS);
2813     return;
2814   }
2815 #endif
2816 
2817   failf(data, "Unknown SFTP command");
2818   Curl_safefree(sshc->quote_path1);
2819   Curl_safefree(sshc->quote_path2);
2820   state(data, SSH_SFTP_CLOSE);
2821   sshc->nextstate = SSH_NO_STATE;
2822   sshc->actualcode = CURLE_QUOTE_ERROR;
2823 }
2824 
sftp_quote_stat(struct Curl_easy * data)2825 static void sftp_quote_stat(struct Curl_easy *data)
2826 {
2827   struct connectdata *conn = data->conn;
2828   struct ssh_conn *sshc = &conn->proto.sshc;
2829   char *cmd = sshc->quote_item->data;
2830   sshc->acceptfail = FALSE;
2831 
2832   /* if a command starts with an asterisk, which a legal SFTP command never
2833      can, the command will be allowed to fail without it causing any
2834      aborts or cancels etc. It will cause libcurl to act as if the command
2835      is successful, whatever the server responds. */
2836 
2837   if(cmd[0] == '*') {
2838     cmd++;
2839     sshc->acceptfail = TRUE;
2840   }
2841 
2842   /* We read the file attributes, store them in sshc->quote_attrs
2843    * and modify them accordingly to command. Then we switch to
2844    * QUOTE_SETSTAT state to write new ones.
2845    */
2846 
2847   if(sshc->quote_attrs)
2848     sftp_attributes_free(sshc->quote_attrs);
2849   sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2850   if(!sshc->quote_attrs) {
2851     Curl_safefree(sshc->quote_path1);
2852     Curl_safefree(sshc->quote_path2);
2853     failf(data, "Attempt to get SFTP stats failed: %d",
2854           sftp_get_error(sshc->sftp_session));
2855     state(data, SSH_SFTP_CLOSE);
2856     sshc->nextstate = SSH_NO_STATE;
2857     sshc->actualcode = CURLE_QUOTE_ERROR;
2858     return;
2859   }
2860 
2861   /* Now set the new attributes... */
2862   if(strncasecompare(cmd, "chgrp", 5)) {
2863     sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2864     if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2865         !sshc->acceptfail) {
2866       Curl_safefree(sshc->quote_path1);
2867       Curl_safefree(sshc->quote_path2);
2868       failf(data, "Syntax error: chgrp gid not a number");
2869       state(data, SSH_SFTP_CLOSE);
2870       sshc->nextstate = SSH_NO_STATE;
2871       sshc->actualcode = CURLE_QUOTE_ERROR;
2872       return;
2873     }
2874     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2875   }
2876   else if(strncasecompare(cmd, "chmod", 5)) {
2877     mode_t perms;
2878     perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2879     /* permissions are octal */
2880     if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2881       Curl_safefree(sshc->quote_path1);
2882       Curl_safefree(sshc->quote_path2);
2883       failf(data, "Syntax error: chmod permissions not a number");
2884       state(data, SSH_SFTP_CLOSE);
2885       sshc->nextstate = SSH_NO_STATE;
2886       sshc->actualcode = CURLE_QUOTE_ERROR;
2887       return;
2888     }
2889     sshc->quote_attrs->permissions = perms;
2890     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2891   }
2892   else if(strncasecompare(cmd, "chown", 5)) {
2893     sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2894     if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2895         !sshc->acceptfail) {
2896       Curl_safefree(sshc->quote_path1);
2897       Curl_safefree(sshc->quote_path2);
2898       failf(data, "Syntax error: chown uid not a number");
2899       state(data, SSH_SFTP_CLOSE);
2900       sshc->nextstate = SSH_NO_STATE;
2901       sshc->actualcode = CURLE_QUOTE_ERROR;
2902       return;
2903     }
2904     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2905   }
2906   else if(strncasecompare(cmd, "atime", 5) ||
2907           strncasecompare(cmd, "mtime", 5)) {
2908     time_t date = Curl_getdate_capped(sshc->quote_path1);
2909     bool fail = FALSE;
2910     if(date == -1) {
2911       failf(data, "incorrect date format for %.*s", 5, cmd);
2912       fail = TRUE;
2913     }
2914 #if SIZEOF_TIME_T > 4
2915     else if(date > 0xffffffff) {
2916       failf(data, "date overflow");
2917       fail = TRUE; /* avoid setting a capped time */
2918     }
2919 #endif
2920     if(fail) {
2921       Curl_safefree(sshc->quote_path1);
2922       Curl_safefree(sshc->quote_path2);
2923       state(data, SSH_SFTP_CLOSE);
2924       sshc->nextstate = SSH_NO_STATE;
2925       sshc->actualcode = CURLE_QUOTE_ERROR;
2926       return;
2927     }
2928     if(strncasecompare(cmd, "atime", 5))
2929       sshc->quote_attrs->atime = (uint32_t)date;
2930     else /* mtime */
2931       sshc->quote_attrs->mtime = (uint32_t)date;
2932 
2933     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2934   }
2935 
2936   /* Now send the completed structure... */
2937   state(data, SSH_SFTP_QUOTE_SETSTAT);
2938   return;
2939 }
2940 
Curl_ssh_init(void)2941 CURLcode Curl_ssh_init(void)
2942 {
2943   if(ssh_init()) {
2944     DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2945     return CURLE_FAILED_INIT;
2946   }
2947   return CURLE_OK;
2948 }
2949 
Curl_ssh_cleanup(void)2950 void Curl_ssh_cleanup(void)
2951 {
2952   (void)ssh_finalize();
2953 }
2954 
Curl_ssh_version(char * buffer,size_t buflen)2955 void Curl_ssh_version(char *buffer, size_t buflen)
2956 {
2957   (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
2958 }
2959 
2960 #endif                          /* USE_LIBSSH */
2961