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 #define SSH_STRING_FREE_CHAR(x)                 \
101   do {                                          \
102     if(x) {                                     \
103       ssh_string_free_char(x);                  \
104       x = NULL;                                 \
105     }                                           \
106   } while(0)
107 #endif
108 
109 /* Local functions: */
110 static CURLcode myssh_connect(struct connectdata *conn, bool *done);
111 static CURLcode myssh_multi_statemach(struct connectdata *conn,
112                                       bool *done);
113 static CURLcode myssh_do_it(struct connectdata *conn, bool *done);
114 
115 static CURLcode scp_done(struct connectdata *conn,
116                          CURLcode, bool premature);
117 static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done);
118 static CURLcode scp_disconnect(struct connectdata *conn,
119                                bool dead_connection);
120 
121 static CURLcode sftp_done(struct connectdata *conn,
122                           CURLcode, bool premature);
123 static CURLcode sftp_doing(struct connectdata *conn,
124                            bool *dophase_done);
125 static CURLcode sftp_disconnect(struct connectdata *conn, bool dead);
126 static
127 CURLcode sftp_perform(struct connectdata *conn,
128                       bool *connected,
129                       bool *dophase_done);
130 
131 static void sftp_quote(struct connectdata *conn);
132 static void sftp_quote_stat(struct connectdata *conn);
133 static int myssh_getsock(struct connectdata *conn, curl_socket_t *sock);
134 static int myssh_perform_getsock(const struct connectdata *conn,
135                                  curl_socket_t *sock);
136 
137 static CURLcode myssh_setup_connection(struct connectdata *conn);
138 
139 /*
140  * SCP protocol handler.
141  */
142 
143 const struct Curl_handler Curl_handler_scp = {
144   "SCP",                        /* scheme */
145   myssh_setup_connection,       /* setup_connection */
146   myssh_do_it,                  /* do_it */
147   scp_done,                     /* done */
148   ZERO_NULL,                    /* do_more */
149   myssh_connect,                /* connect_it */
150   myssh_multi_statemach,        /* connecting */
151   scp_doing,                    /* doing */
152   myssh_getsock,                /* proto_getsock */
153   myssh_getsock,                /* doing_getsock */
154   ZERO_NULL,                    /* domore_getsock */
155   myssh_perform_getsock,        /* perform_getsock */
156   scp_disconnect,               /* disconnect */
157   ZERO_NULL,                    /* readwrite */
158   ZERO_NULL,                    /* connection_check */
159   PORT_SSH,                     /* defport */
160   CURLPROTO_SCP,                /* protocol */
161   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 != 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_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(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)1915 static int myssh_perform_getsock(const struct connectdata *conn,
1916                                  curl_socket_t *sock)
1917 {
1918   int bitmap = GETSOCK_BLANK;
1919   sock[0] = conn->sock[FIRSTSOCKET];
1920 
1921   if(conn->waitfor & KEEP_RECV)
1922     bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
1923 
1924   if(conn->waitfor & KEEP_SEND)
1925     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
1926 
1927   return bitmap;
1928 }
1929 
1930 /* Generic function called by the multi interface to figure out what socket(s)
1931    to wait for and for what actions during the DOING and PROTOCONNECT states*/
myssh_getsock(struct connectdata * conn,curl_socket_t * sock)1932 static int myssh_getsock(struct connectdata *conn,
1933                          curl_socket_t *sock)
1934 {
1935   /* if we know the direction we can use the generic *_getsock() function even
1936      for the protocol_connect and doing states */
1937   return myssh_perform_getsock(conn, sock);
1938 }
1939 
myssh_block2waitfor(struct connectdata * conn,bool block)1940 static void myssh_block2waitfor(struct connectdata *conn, bool block)
1941 {
1942   struct ssh_conn *sshc = &conn->proto.sshc;
1943 
1944   /* If it didn't block, or nothing was returned by ssh_get_poll_flags
1945    * have the original set */
1946   conn->waitfor = sshc->orig_waitfor;
1947 
1948   if(block) {
1949     int dir = ssh_get_poll_flags(sshc->ssh_session);
1950     if(dir & SSH_READ_PENDING) {
1951       /* translate the libssh define bits into our own bit defines */
1952       conn->waitfor = KEEP_RECV;
1953     }
1954     else if(dir & SSH_WRITE_PENDING) {
1955       conn->waitfor = KEEP_SEND;
1956     }
1957   }
1958 }
1959 
1960 /* called repeatedly until done from multi.c */
myssh_multi_statemach(struct connectdata * conn,bool * done)1961 static CURLcode myssh_multi_statemach(struct connectdata *conn,
1962                                       bool *done)
1963 {
1964   struct ssh_conn *sshc = &conn->proto.sshc;
1965   bool block;    /* we store the status and use that to provide a ssh_getsock()
1966                     implementation */
1967   CURLcode result = myssh_statemach_act(conn, &block);
1968 
1969   *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
1970   myssh_block2waitfor(conn, block);
1971 
1972   return result;
1973 }
1974 
myssh_block_statemach(struct connectdata * conn,bool disconnect)1975 static CURLcode myssh_block_statemach(struct connectdata *conn,
1976                                       bool disconnect)
1977 {
1978   struct ssh_conn *sshc = &conn->proto.sshc;
1979   CURLcode result = CURLE_OK;
1980   struct Curl_easy *data = conn->data;
1981 
1982   while((sshc->state != SSH_STOP) && !result) {
1983     bool block;
1984     timediff_t left = 1000;
1985     struct curltime now = Curl_now();
1986 
1987     result = myssh_statemach_act(conn, &block);
1988     if(result)
1989       break;
1990 
1991     if(!disconnect) {
1992       if(Curl_pgrsUpdate(conn))
1993         return CURLE_ABORTED_BY_CALLBACK;
1994 
1995       result = Curl_speedcheck(data, now);
1996       if(result)
1997         break;
1998 
1999       left = Curl_timeleft(data, NULL, FALSE);
2000       if(left < 0) {
2001         failf(data, "Operation timed out");
2002         return CURLE_OPERATION_TIMEDOUT;
2003       }
2004     }
2005 
2006     if(block) {
2007       curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
2008       /* wait for the socket to become ready */
2009       (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2010                                CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2011     }
2012 
2013   }
2014 
2015   return result;
2016 }
2017 
2018 /*
2019  * SSH setup connection
2020  */
myssh_setup_connection(struct connectdata * conn)2021 static CURLcode myssh_setup_connection(struct connectdata *conn)
2022 {
2023   struct SSHPROTO *ssh;
2024 
2025   conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
2026   if(!ssh)
2027     return CURLE_OUT_OF_MEMORY;
2028 
2029   return CURLE_OK;
2030 }
2031 
2032 static Curl_recv scp_recv, sftp_recv;
2033 static Curl_send scp_send, sftp_send;
2034 
2035 /*
2036  * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2037  * do protocol-specific actions at connect-time.
2038  */
myssh_connect(struct connectdata * conn,bool * done)2039 static CURLcode myssh_connect(struct connectdata *conn, bool *done)
2040 {
2041   struct ssh_conn *ssh;
2042   CURLcode result;
2043   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2044   struct Curl_easy *data = conn->data;
2045 
2046   /* initialize per-handle data if not already */
2047   if(!data->req.protop)
2048     myssh_setup_connection(conn);
2049 
2050   /* We default to persistent connections. We set this already in this connect
2051      function to make the re-use checks properly be able to check this bit. */
2052   connkeep(conn, "SSH default");
2053 
2054   if(conn->handler->protocol & CURLPROTO_SCP) {
2055     conn->recv[FIRSTSOCKET] = scp_recv;
2056     conn->send[FIRSTSOCKET] = scp_send;
2057   }
2058   else {
2059     conn->recv[FIRSTSOCKET] = sftp_recv;
2060     conn->send[FIRSTSOCKET] = sftp_send;
2061   }
2062 
2063   ssh = &conn->proto.sshc;
2064 
2065   ssh->ssh_session = ssh_new();
2066   if(ssh->ssh_session == NULL) {
2067     failf(data, "Failure initialising ssh session");
2068     return CURLE_FAILED_INIT;
2069   }
2070 
2071   ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2072 
2073   if(conn->user) {
2074     infof(data, "User: %s\n", conn->user);
2075     ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2076   }
2077 
2078   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2079     infof(data, "Known hosts: %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]);
2080     ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2081                     data->set.str[STRING_SSH_KNOWNHOSTS]);
2082   }
2083 
2084   ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2085   if(conn->remote_port)
2086     ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2087                     &conn->remote_port);
2088 
2089   if(data->set.ssh_compression) {
2090     ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2091                     "zlib,zlib@openssh.com,none");
2092   }
2093 
2094   ssh->privkey = NULL;
2095   ssh->pubkey = NULL;
2096 
2097   if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2098     int rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2099                                         &ssh->pubkey);
2100     if(rc != SSH_OK) {
2101       failf(data, "Could not load public key file");
2102       /* ignore */
2103     }
2104   }
2105 
2106   /* we do not verify here, we do it at the state machine,
2107    * after connection */
2108 
2109   state(conn, SSH_INIT);
2110 
2111   result = myssh_multi_statemach(conn, done);
2112 
2113   return result;
2114 }
2115 
2116 /* called from multi.c while DOing */
scp_doing(struct connectdata * conn,bool * dophase_done)2117 static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done)
2118 {
2119   CURLcode result;
2120 
2121   result = myssh_multi_statemach(conn, dophase_done);
2122 
2123   if(*dophase_done) {
2124     DEBUGF(infof(conn->data, "DO phase is complete\n"));
2125   }
2126   return result;
2127 }
2128 
2129 /*
2130  ***********************************************************************
2131  *
2132  * scp_perform()
2133  *
2134  * This is the actual DO function for SCP. Get a file according to
2135  * the options previously setup.
2136  */
2137 
2138 static
scp_perform(struct connectdata * conn,bool * connected,bool * dophase_done)2139 CURLcode scp_perform(struct connectdata *conn,
2140                      bool *connected, bool *dophase_done)
2141 {
2142   CURLcode result = CURLE_OK;
2143 
2144   DEBUGF(infof(conn->data, "DO phase starts\n"));
2145 
2146   *dophase_done = FALSE;        /* not done yet */
2147 
2148   /* start the first command in the DO phase */
2149   state(conn, SSH_SCP_TRANS_INIT);
2150 
2151   result = myssh_multi_statemach(conn, dophase_done);
2152 
2153   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2154 
2155   if(*dophase_done) {
2156     DEBUGF(infof(conn->data, "DO phase is complete\n"));
2157   }
2158 
2159   return result;
2160 }
2161 
myssh_do_it(struct connectdata * conn,bool * done)2162 static CURLcode myssh_do_it(struct connectdata *conn, bool *done)
2163 {
2164   CURLcode result;
2165   bool connected = 0;
2166   struct Curl_easy *data = conn->data;
2167   struct ssh_conn *sshc = &conn->proto.sshc;
2168 
2169   *done = FALSE;                /* default to false */
2170 
2171   data->req.size = -1;          /* make sure this is unknown at this point */
2172 
2173   sshc->actualcode = CURLE_OK;  /* reset error code */
2174   sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
2175                                    variable */
2176 
2177   Curl_pgrsSetUploadCounter(data, 0);
2178   Curl_pgrsSetDownloadCounter(data, 0);
2179   Curl_pgrsSetUploadSize(data, -1);
2180   Curl_pgrsSetDownloadSize(data, -1);
2181 
2182   if(conn->handler->protocol & CURLPROTO_SCP)
2183     result = scp_perform(conn, &connected, done);
2184   else
2185     result = sftp_perform(conn, &connected, done);
2186 
2187   return result;
2188 }
2189 
2190 /* BLOCKING, but the function is using the state machine so the only reason
2191    this is still blocking is that the multi interface code has no support for
2192    disconnecting operations that takes a while */
scp_disconnect(struct connectdata * conn,bool dead_connection)2193 static CURLcode scp_disconnect(struct connectdata *conn,
2194                                bool dead_connection)
2195 {
2196   CURLcode result = CURLE_OK;
2197   struct ssh_conn *ssh = &conn->proto.sshc;
2198   (void) dead_connection;
2199 
2200   if(ssh->ssh_session) {
2201     /* only if there's a session still around to use! */
2202 
2203     state(conn, SSH_SESSION_DISCONNECT);
2204 
2205     result = myssh_block_statemach(conn, TRUE);
2206   }
2207 
2208   return result;
2209 }
2210 
2211 /* generic done function for both SCP and SFTP called from their specific
2212    done functions */
myssh_done(struct connectdata * conn,CURLcode status)2213 static CURLcode myssh_done(struct connectdata *conn, CURLcode status)
2214 {
2215   CURLcode result = CURLE_OK;
2216   struct SSHPROTO *protop = conn->data->req.protop;
2217 
2218   if(!status) {
2219     /* run the state-machine */
2220     result = myssh_block_statemach(conn, FALSE);
2221   }
2222   else
2223     result = status;
2224 
2225   if(protop)
2226     Curl_safefree(protop->path);
2227   if(Curl_pgrsDone(conn))
2228     return CURLE_ABORTED_BY_CALLBACK;
2229 
2230   conn->data->req.keepon = 0;   /* clear all bits */
2231   return result;
2232 }
2233 
2234 
scp_done(struct connectdata * conn,CURLcode status,bool premature)2235 static CURLcode scp_done(struct connectdata *conn, CURLcode status,
2236                          bool premature)
2237 {
2238   (void) premature;             /* not used */
2239 
2240   if(!status)
2241     state(conn, SSH_SCP_DONE);
2242 
2243   return myssh_done(conn, status);
2244 
2245 }
2246 
scp_send(struct connectdata * conn,int sockindex,const void * mem,size_t len,CURLcode * err)2247 static ssize_t scp_send(struct connectdata *conn, int sockindex,
2248                         const void *mem, size_t len, CURLcode *err)
2249 {
2250   int rc;
2251   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2252   (void) err;
2253 
2254   rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2255 
2256 #if 0
2257   /* The following code is misleading, mostly added as wishful thinking
2258    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2259    * Currently rc can only be number of bytes read or SSH_ERROR. */
2260   myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
2261 
2262   if(rc == SSH_AGAIN) {
2263     *err = CURLE_AGAIN;
2264     return 0;
2265   }
2266   else
2267 #endif
2268   if(rc != SSH_OK) {
2269     *err = CURLE_SSH;
2270     return -1;
2271   }
2272 
2273   return len;
2274 }
2275 
scp_recv(struct connectdata * conn,int sockindex,char * mem,size_t len,CURLcode * err)2276 static ssize_t scp_recv(struct connectdata *conn, int sockindex,
2277                         char *mem, size_t len, CURLcode *err)
2278 {
2279   ssize_t nread;
2280   (void) err;
2281   (void) sockindex; /* we only support SCP on the fixed known primary socket */
2282 
2283   /* libssh returns int */
2284   nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2285 
2286 #if 0
2287   /* The following code is misleading, mostly added as wishful thinking
2288    * that libssh at some point will implement non-blocking ssh_scp_write/read.
2289    * Currently rc can only be SSH_OK or SSH_ERROR. */
2290 
2291   myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
2292   if(nread == SSH_AGAIN) {
2293     *err = CURLE_AGAIN;
2294     nread = -1;
2295   }
2296 #endif
2297 
2298   return nread;
2299 }
2300 
2301 /*
2302  * =============== SFTP ===============
2303  */
2304 
2305 /*
2306  ***********************************************************************
2307  *
2308  * sftp_perform()
2309  *
2310  * This is the actual DO function for SFTP. Get a file/directory according to
2311  * the options previously setup.
2312  */
2313 
2314 static
sftp_perform(struct connectdata * conn,bool * connected,bool * dophase_done)2315 CURLcode sftp_perform(struct connectdata *conn,
2316                       bool *connected,
2317                       bool *dophase_done)
2318 {
2319   CURLcode result = CURLE_OK;
2320 
2321   DEBUGF(infof(conn->data, "DO phase starts\n"));
2322 
2323   *dophase_done = FALSE; /* not done yet */
2324 
2325   /* start the first command in the DO phase */
2326   state(conn, SSH_SFTP_QUOTE_INIT);
2327 
2328   /* run the state-machine */
2329   result = myssh_multi_statemach(conn, dophase_done);
2330 
2331   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2332 
2333   if(*dophase_done) {
2334     DEBUGF(infof(conn->data, "DO phase is complete\n"));
2335   }
2336 
2337   return result;
2338 }
2339 
2340 /* called from multi.c while DOing */
sftp_doing(struct connectdata * conn,bool * dophase_done)2341 static CURLcode sftp_doing(struct connectdata *conn,
2342                            bool *dophase_done)
2343 {
2344   CURLcode result = myssh_multi_statemach(conn, dophase_done);
2345   if(*dophase_done) {
2346     DEBUGF(infof(conn->data, "DO phase is complete\n"));
2347   }
2348   return result;
2349 }
2350 
2351 /* BLOCKING, but the function is using the state machine so the only reason
2352    this is still blocking is that the multi interface code has no support for
2353    disconnecting operations that takes a while */
sftp_disconnect(struct connectdata * conn,bool dead_connection)2354 static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
2355 {
2356   CURLcode result = CURLE_OK;
2357   (void) dead_connection;
2358 
2359   DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
2360 
2361   if(conn->proto.sshc.ssh_session) {
2362     /* only if there's a session still around to use! */
2363     state(conn, SSH_SFTP_SHUTDOWN);
2364     result = myssh_block_statemach(conn, TRUE);
2365   }
2366 
2367   DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
2368 
2369   return result;
2370 
2371 }
2372 
sftp_done(struct connectdata * conn,CURLcode status,bool premature)2373 static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
2374                                bool premature)
2375 {
2376   struct ssh_conn *sshc = &conn->proto.sshc;
2377 
2378   if(!status) {
2379     /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2380        errors that could happen due to open file handles during POSTQUOTE
2381        operation */
2382     if(!premature && conn->data->set.postquote && !conn->bits.retry)
2383       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2384     state(conn, SSH_SFTP_CLOSE);
2385   }
2386   return myssh_done(conn, status);
2387 }
2388 
2389 /* return number of sent bytes */
sftp_send(struct connectdata * conn,int sockindex,const void * mem,size_t len,CURLcode * err)2390 static ssize_t sftp_send(struct connectdata *conn, int sockindex,
2391                          const void *mem, size_t len, CURLcode *err)
2392 {
2393   ssize_t nwrite;
2394   (void)sockindex;
2395 
2396   nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2397 
2398   myssh_block2waitfor(conn, FALSE);
2399 
2400 #if 0 /* not returned by libssh on write */
2401   if(nwrite == SSH_AGAIN) {
2402     *err = CURLE_AGAIN;
2403     nwrite = 0;
2404   }
2405   else
2406 #endif
2407   if(nwrite < 0) {
2408     *err = CURLE_SSH;
2409     nwrite = -1;
2410   }
2411 
2412   return nwrite;
2413 }
2414 
2415 /*
2416  * Return number of received (decrypted) bytes
2417  * or <0 on error
2418  */
sftp_recv(struct connectdata * conn,int sockindex,char * mem,size_t len,CURLcode * err)2419 static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
2420                          char *mem, size_t len, CURLcode *err)
2421 {
2422   ssize_t nread;
2423   (void)sockindex;
2424 
2425   DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2426 
2427   switch(conn->proto.sshc.sftp_recv_state) {
2428     case 0:
2429       conn->proto.sshc.sftp_file_index =
2430             sftp_async_read_begin(conn->proto.sshc.sftp_file,
2431                                   (uint32_t)len);
2432       if(conn->proto.sshc.sftp_file_index < 0) {
2433         *err = CURLE_RECV_ERROR;
2434         return -1;
2435       }
2436 
2437       /* FALLTHROUGH */
2438     case 1:
2439       conn->proto.sshc.sftp_recv_state = 1;
2440 
2441       nread = sftp_async_read(conn->proto.sshc.sftp_file,
2442                               mem, (uint32_t)len,
2443                               conn->proto.sshc.sftp_file_index);
2444 
2445       myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
2446 
2447       if(nread == SSH_AGAIN) {
2448         *err = CURLE_AGAIN;
2449         return -1;
2450       }
2451       else if(nread < 0) {
2452         *err = CURLE_RECV_ERROR;
2453         return -1;
2454       }
2455 
2456       conn->proto.sshc.sftp_recv_state = 0;
2457       return nread;
2458 
2459     default:
2460       /* we never reach here */
2461       return -1;
2462   }
2463 }
2464 
sftp_quote(struct connectdata * conn)2465 static void sftp_quote(struct connectdata *conn)
2466 {
2467   const char *cp;
2468   struct Curl_easy *data = conn->data;
2469   struct SSHPROTO *protop = data->req.protop;
2470   struct ssh_conn *sshc = &conn->proto.sshc;
2471   CURLcode result;
2472 
2473   /*
2474    * Support some of the "FTP" commands
2475    */
2476   char *cmd = sshc->quote_item->data;
2477   sshc->acceptfail = FALSE;
2478 
2479   /* if a command starts with an asterisk, which a legal SFTP command never
2480      can, the command will be allowed to fail without it causing any
2481      aborts or cancels etc. It will cause libcurl to act as if the command
2482      is successful, whatever the server reponds. */
2483 
2484   if(cmd[0] == '*') {
2485     cmd++;
2486     sshc->acceptfail = TRUE;
2487   }
2488 
2489   if(strcasecompare("pwd", cmd)) {
2490     /* output debug output if that is requested */
2491     char *tmp = aprintf("257 \"%s\" is current directory.\n",
2492                         protop->path);
2493     if(!tmp) {
2494       sshc->actualcode = CURLE_OUT_OF_MEMORY;
2495       state(conn, SSH_SFTP_CLOSE);
2496       sshc->nextstate = SSH_NO_STATE;
2497       return;
2498     }
2499     if(data->set.verbose) {
2500       Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2501       Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2502     }
2503     /* this sends an FTP-like "header" to the header callback so that the
2504        current directory can be read very similar to how it is read when
2505        using ordinary FTP. */
2506     result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2507     free(tmp);
2508     if(result) {
2509       state(conn, SSH_SFTP_CLOSE);
2510       sshc->nextstate = SSH_NO_STATE;
2511       sshc->actualcode = result;
2512     }
2513     else
2514       state(conn, SSH_SFTP_NEXT_QUOTE);
2515     return;
2516   }
2517 
2518   /*
2519    * the arguments following the command must be separated from the
2520    * command with a space so we can check for it unconditionally
2521    */
2522   cp = strchr(cmd, ' ');
2523   if(cp == NULL) {
2524     failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
2525     state(conn, SSH_SFTP_CLOSE);
2526     sshc->nextstate = SSH_NO_STATE;
2527     sshc->actualcode = CURLE_QUOTE_ERROR;
2528     return;
2529   }
2530 
2531   /*
2532    * also, every command takes at least one argument so we get that
2533    * first argument right now
2534    */
2535   result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2536   if(result) {
2537     if(result == CURLE_OUT_OF_MEMORY)
2538       failf(data, "Out of memory");
2539     else
2540       failf(data, "Syntax error: Bad first parameter");
2541     state(conn, SSH_SFTP_CLOSE);
2542     sshc->nextstate = SSH_NO_STATE;
2543     sshc->actualcode = result;
2544     return;
2545   }
2546 
2547   /*
2548    * SFTP is a binary protocol, so we don't send text commands
2549    * to the server. Instead, we scan for commands used by
2550    * OpenSSH's sftp program and call the appropriate libssh
2551    * functions.
2552    */
2553   if(strncasecompare(cmd, "chgrp ", 6) ||
2554      strncasecompare(cmd, "chmod ", 6) ||
2555      strncasecompare(cmd, "chown ", 6)) {
2556     /* attribute change */
2557 
2558     /* sshc->quote_path1 contains the mode to set */
2559     /* get the destination */
2560     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2561     if(result) {
2562       if(result == CURLE_OUT_OF_MEMORY)
2563         failf(data, "Out of memory");
2564       else
2565         failf(data, "Syntax error in chgrp/chmod/chown: "
2566               "Bad second parameter");
2567       Curl_safefree(sshc->quote_path1);
2568       state(conn, SSH_SFTP_CLOSE);
2569       sshc->nextstate = SSH_NO_STATE;
2570       sshc->actualcode = result;
2571       return;
2572     }
2573     sshc->quote_attrs = NULL;
2574     state(conn, SSH_SFTP_QUOTE_STAT);
2575     return;
2576   }
2577   if(strncasecompare(cmd, "ln ", 3) ||
2578      strncasecompare(cmd, "symlink ", 8)) {
2579     /* symbolic linking */
2580     /* sshc->quote_path1 is the source */
2581     /* get the destination */
2582     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2583     if(result) {
2584       if(result == CURLE_OUT_OF_MEMORY)
2585         failf(data, "Out of memory");
2586       else
2587         failf(data, "Syntax error in ln/symlink: Bad second parameter");
2588       Curl_safefree(sshc->quote_path1);
2589       state(conn, SSH_SFTP_CLOSE);
2590       sshc->nextstate = SSH_NO_STATE;
2591       sshc->actualcode = result;
2592       return;
2593     }
2594     state(conn, SSH_SFTP_QUOTE_SYMLINK);
2595     return;
2596   }
2597   else if(strncasecompare(cmd, "mkdir ", 6)) {
2598     /* create dir */
2599     state(conn, SSH_SFTP_QUOTE_MKDIR);
2600     return;
2601   }
2602   else if(strncasecompare(cmd, "rename ", 7)) {
2603     /* rename file */
2604     /* first param is the source path */
2605     /* second param is the dest. path */
2606     result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2607     if(result) {
2608       if(result == CURLE_OUT_OF_MEMORY)
2609         failf(data, "Out of memory");
2610       else
2611         failf(data, "Syntax error in rename: Bad second parameter");
2612       Curl_safefree(sshc->quote_path1);
2613       state(conn, SSH_SFTP_CLOSE);
2614       sshc->nextstate = SSH_NO_STATE;
2615       sshc->actualcode = result;
2616       return;
2617     }
2618     state(conn, SSH_SFTP_QUOTE_RENAME);
2619     return;
2620   }
2621   else if(strncasecompare(cmd, "rmdir ", 6)) {
2622     /* delete dir */
2623     state(conn, SSH_SFTP_QUOTE_RMDIR);
2624     return;
2625   }
2626   else if(strncasecompare(cmd, "rm ", 3)) {
2627     state(conn, SSH_SFTP_QUOTE_UNLINK);
2628     return;
2629   }
2630 #ifdef HAS_STATVFS_SUPPORT
2631   else if(strncasecompare(cmd, "statvfs ", 8)) {
2632     state(conn, SSH_SFTP_QUOTE_STATVFS);
2633     return;
2634   }
2635 #endif
2636 
2637   failf(data, "Unknown SFTP command");
2638   Curl_safefree(sshc->quote_path1);
2639   Curl_safefree(sshc->quote_path2);
2640   state(conn, SSH_SFTP_CLOSE);
2641   sshc->nextstate = SSH_NO_STATE;
2642   sshc->actualcode = CURLE_QUOTE_ERROR;
2643 }
2644 
sftp_quote_stat(struct connectdata * conn)2645 static void sftp_quote_stat(struct connectdata *conn)
2646 {
2647   struct Curl_easy *data = conn->data;
2648   struct ssh_conn *sshc = &conn->proto.sshc;
2649   char *cmd = sshc->quote_item->data;
2650   sshc->acceptfail = FALSE;
2651 
2652   /* if a command starts with an asterisk, which a legal SFTP command never
2653      can, the command will be allowed to fail without it causing any
2654      aborts or cancels etc. It will cause libcurl to act as if the command
2655      is successful, whatever the server reponds. */
2656 
2657   if(cmd[0] == '*') {
2658     cmd++;
2659     sshc->acceptfail = TRUE;
2660   }
2661 
2662   /* We read the file attributes, store them in sshc->quote_attrs
2663    * and modify them accordingly to command. Then we switch to
2664    * QUOTE_SETSTAT state to write new ones.
2665    */
2666 
2667   if(sshc->quote_attrs)
2668     sftp_attributes_free(sshc->quote_attrs);
2669   sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2670   if(sshc->quote_attrs == NULL) {
2671     Curl_safefree(sshc->quote_path1);
2672     Curl_safefree(sshc->quote_path2);
2673     failf(data, "Attempt to get SFTP stats failed: %d",
2674           sftp_get_error(sshc->sftp_session));
2675     state(conn, SSH_SFTP_CLOSE);
2676     sshc->nextstate = SSH_NO_STATE;
2677     sshc->actualcode = CURLE_QUOTE_ERROR;
2678     return;
2679   }
2680 
2681   /* Now set the new attributes... */
2682   if(strncasecompare(cmd, "chgrp", 5)) {
2683     sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2684     if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2685         !sshc->acceptfail) {
2686       Curl_safefree(sshc->quote_path1);
2687       Curl_safefree(sshc->quote_path2);
2688       failf(data, "Syntax error: chgrp gid not a number");
2689       state(conn, SSH_SFTP_CLOSE);
2690       sshc->nextstate = SSH_NO_STATE;
2691       sshc->actualcode = CURLE_QUOTE_ERROR;
2692       return;
2693     }
2694     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2695   }
2696   else if(strncasecompare(cmd, "chmod", 5)) {
2697     mode_t perms;
2698     perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2699     /* permissions are octal */
2700     if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2701       Curl_safefree(sshc->quote_path1);
2702       Curl_safefree(sshc->quote_path2);
2703       failf(data, "Syntax error: chmod permissions not a number");
2704       state(conn, SSH_SFTP_CLOSE);
2705       sshc->nextstate = SSH_NO_STATE;
2706       sshc->actualcode = CURLE_QUOTE_ERROR;
2707       return;
2708     }
2709     sshc->quote_attrs->permissions = perms;
2710     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2711   }
2712   else if(strncasecompare(cmd, "chown", 5)) {
2713     sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2714     if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2715         !sshc->acceptfail) {
2716       Curl_safefree(sshc->quote_path1);
2717       Curl_safefree(sshc->quote_path2);
2718       failf(data, "Syntax error: chown uid not a number");
2719       state(conn, SSH_SFTP_CLOSE);
2720       sshc->nextstate = SSH_NO_STATE;
2721       sshc->actualcode = CURLE_QUOTE_ERROR;
2722       return;
2723     }
2724     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2725   }
2726 
2727   /* Now send the completed structure... */
2728   state(conn, SSH_SFTP_QUOTE_SETSTAT);
2729   return;
2730 }
2731 
Curl_ssh_init(void)2732 CURLcode Curl_ssh_init(void)
2733 {
2734   if(ssh_init()) {
2735     DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2736     return CURLE_FAILED_INIT;
2737   }
2738   return CURLE_OK;
2739 }
2740 
Curl_ssh_cleanup(void)2741 void Curl_ssh_cleanup(void)
2742 {
2743   (void)ssh_finalize();
2744 }
2745 
Curl_ssh_version(char * buffer,size_t buflen)2746 size_t Curl_ssh_version(char *buffer, size_t buflen)
2747 {
2748   return msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION);
2749 }
2750 
2751 #endif                          /* USE_LIBSSH */
2752