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