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