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