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