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