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