VirtualBox

source: vbox/trunk/src/libs/curl-8.11.1/lib/vssh/libssh.c

Last change on this file was 108048, checked in by vboxsync, 3 months ago

curl-8.11.1: Applied and adjusted our curl changes to 8.7.1. jiraref:VBP-1535

  • Property svn:eol-style set to native
File size: 87.5 KB
Line 
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#ifdef HAVE_NETINET_IN_H
35#include <netinet/in.h>
36#endif
37#ifdef HAVE_ARPA_INET_H
38#include <arpa/inet.h>
39#endif
40#ifdef HAVE_NETDB_H
41#include <netdb.h>
42#endif
43#ifdef __VMS
44#include <in.h>
45#include <inet.h>
46#endif
47
48#include <curl/curl.h>
49#include "urldata.h"
50#include "sendf.h"
51#include "hostip.h"
52#include "progress.h"
53#include "transfer.h"
54#include "escape.h"
55#include "http.h" /* for HTTP proxy tunnel stuff */
56#include "ssh.h"
57#include "url.h"
58#include "speedcheck.h"
59#include "getinfo.h"
60#include "strdup.h"
61#include "strcase.h"
62#include "vtls/vtls.h"
63#include "cfilters.h"
64#include "connect.h"
65#include "inet_ntop.h"
66#include "parsedate.h" /* for the week day and month names */
67#include "sockaddr.h" /* required for Curl_sockaddr_storage */
68#include "strtoofft.h"
69#include "multiif.h"
70#include "select.h"
71#include "warnless.h"
72#include "curl_path.h"
73
74#ifdef HAVE_SYS_STAT_H
75#include <sys/stat.h>
76#endif
77#ifdef HAVE_UNISTD_H
78#include <unistd.h>
79#endif
80#ifdef HAVE_FCNTL_H
81#include <fcntl.h>
82#endif
83
84/* The last 3 #include files should be in this order */
85#include "curl_printf.h"
86#include "curl_memory.h"
87#include "memdebug.h"
88
89/* A recent macro provided by libssh. Or make our own. */
90#ifndef SSH_STRING_FREE_CHAR
91#define SSH_STRING_FREE_CHAR(x) \
92 do { \
93 if(x) { \
94 ssh_string_free_char(x); \
95 x = NULL; \
96 } \
97 } while(0)
98#endif
99
100/* These stat values may not be the same as the user's S_IFMT / S_IFLNK */
101#ifndef SSH_S_IFMT
102#define SSH_S_IFMT 00170000
103#endif
104#ifndef SSH_S_IFLNK
105#define SSH_S_IFLNK 0120000
106#endif
107
108/* Local functions: */
109static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
110static CURLcode myssh_multi_statemach(struct Curl_easy *data,
111 bool *done);
112static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
113
114static CURLcode scp_done(struct Curl_easy *data,
115 CURLcode, bool premature);
116static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
117static CURLcode scp_disconnect(struct Curl_easy *data,
118 struct connectdata *conn,
119 bool dead_connection);
120
121static CURLcode sftp_done(struct Curl_easy *data,
122 CURLcode, bool premature);
123static CURLcode sftp_doing(struct Curl_easy *data,
124 bool *dophase_done);
125static CURLcode sftp_disconnect(struct Curl_easy *data,
126 struct connectdata *conn,
127 bool dead);
128static
129CURLcode sftp_perform(struct Curl_easy *data,
130 bool *connected,
131 bool *dophase_done);
132
133static void sftp_quote(struct Curl_easy *data);
134static void sftp_quote_stat(struct Curl_easy *data);
135static int myssh_getsock(struct Curl_easy *data,
136 struct connectdata *conn, curl_socket_t *sock);
137static void myssh_block2waitfor(struct connectdata *conn, bool block);
138
139static CURLcode myssh_setup_connection(struct Curl_easy *data,
140 struct connectdata *conn);
141
142/*
143 * SCP protocol handler.
144 */
145
146const struct Curl_handler Curl_handler_scp = {
147 "SCP", /* scheme */
148 myssh_setup_connection, /* setup_connection */
149 myssh_do_it, /* do_it */
150 scp_done, /* done */
151 ZERO_NULL, /* do_more */
152 myssh_connect, /* connect_it */
153 myssh_multi_statemach, /* connecting */
154 scp_doing, /* doing */
155 myssh_getsock, /* proto_getsock */
156 myssh_getsock, /* doing_getsock */
157 ZERO_NULL, /* domore_getsock */
158 myssh_getsock, /* perform_getsock */
159 scp_disconnect, /* disconnect */
160 ZERO_NULL, /* write_resp */
161 ZERO_NULL, /* write_resp_hd */
162 ZERO_NULL, /* connection_check */
163 ZERO_NULL, /* attach connection */
164 PORT_SSH, /* defport */
165 CURLPROTO_SCP, /* protocol */
166 CURLPROTO_SCP, /* family */
167 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
168};
169
170/*
171 * SFTP protocol handler.
172 */
173
174const struct Curl_handler Curl_handler_sftp = {
175 "SFTP", /* scheme */
176 myssh_setup_connection, /* setup_connection */
177 myssh_do_it, /* do_it */
178 sftp_done, /* done */
179 ZERO_NULL, /* do_more */
180 myssh_connect, /* connect_it */
181 myssh_multi_statemach, /* connecting */
182 sftp_doing, /* doing */
183 myssh_getsock, /* proto_getsock */
184 myssh_getsock, /* doing_getsock */
185 ZERO_NULL, /* domore_getsock */
186 myssh_getsock, /* perform_getsock */
187 sftp_disconnect, /* disconnect */
188 ZERO_NULL, /* write_resp */
189 ZERO_NULL, /* write_resp_hd */
190 ZERO_NULL, /* connection_check */
191 ZERO_NULL, /* attach connection */
192 PORT_SSH, /* defport */
193 CURLPROTO_SFTP, /* protocol */
194 CURLPROTO_SFTP, /* family */
195 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
196 | PROTOPT_NOURLQUERY /* flags */
197};
198
199static CURLcode sftp_error_to_CURLE(int err)
200{
201 switch(err) {
202 case SSH_FX_OK:
203 return CURLE_OK;
204
205 case SSH_FX_NO_SUCH_FILE:
206 case SSH_FX_NO_SUCH_PATH:
207 return CURLE_REMOTE_FILE_NOT_FOUND;
208
209 case SSH_FX_PERMISSION_DENIED:
210 case SSH_FX_WRITE_PROTECT:
211 return CURLE_REMOTE_ACCESS_DENIED;
212
213 case SSH_FX_FILE_ALREADY_EXISTS:
214 return CURLE_REMOTE_FILE_EXISTS;
215
216 default:
217 break;
218 }
219
220 return CURLE_SSH;
221}
222
223#ifndef DEBUGBUILD
224#define state(x,y) mystate(x,y)
225#else
226#define state(x,y) mystate(x,y, __LINE__)
227#endif
228
229/*
230 * SSH State machine related code
231 */
232/* This is the ONLY way to change SSH state! */
233static void mystate(struct Curl_easy *data, sshstate nowstate
234#ifdef DEBUGBUILD
235 , int lineno
236#endif
237 )
238{
239 struct connectdata *conn = data->conn;
240 struct ssh_conn *sshc = &conn->proto.sshc;
241#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
242 /* for debug purposes */
243 static const char *const names[] = {
244 "SSH_STOP",
245 "SSH_INIT",
246 "SSH_S_STARTUP",
247 "SSH_HOSTKEY",
248 "SSH_AUTHLIST",
249 "SSH_AUTH_PKEY_INIT",
250 "SSH_AUTH_PKEY",
251 "SSH_AUTH_PASS_INIT",
252 "SSH_AUTH_PASS",
253 "SSH_AUTH_AGENT_INIT",
254 "SSH_AUTH_AGENT_LIST",
255 "SSH_AUTH_AGENT",
256 "SSH_AUTH_HOST_INIT",
257 "SSH_AUTH_HOST",
258 "SSH_AUTH_KEY_INIT",
259 "SSH_AUTH_KEY",
260 "SSH_AUTH_GSSAPI",
261 "SSH_AUTH_DONE",
262 "SSH_SFTP_INIT",
263 "SSH_SFTP_REALPATH",
264 "SSH_SFTP_QUOTE_INIT",
265 "SSH_SFTP_POSTQUOTE_INIT",
266 "SSH_SFTP_QUOTE",
267 "SSH_SFTP_NEXT_QUOTE",
268 "SSH_SFTP_QUOTE_STAT",
269 "SSH_SFTP_QUOTE_SETSTAT",
270 "SSH_SFTP_QUOTE_SYMLINK",
271 "SSH_SFTP_QUOTE_MKDIR",
272 "SSH_SFTP_QUOTE_RENAME",
273 "SSH_SFTP_QUOTE_RMDIR",
274 "SSH_SFTP_QUOTE_UNLINK",
275 "SSH_SFTP_QUOTE_STATVFS",
276 "SSH_SFTP_GETINFO",
277 "SSH_SFTP_FILETIME",
278 "SSH_SFTP_TRANS_INIT",
279 "SSH_SFTP_UPLOAD_INIT",
280 "SSH_SFTP_CREATE_DIRS_INIT",
281 "SSH_SFTP_CREATE_DIRS",
282 "SSH_SFTP_CREATE_DIRS_MKDIR",
283 "SSH_SFTP_READDIR_INIT",
284 "SSH_SFTP_READDIR",
285 "SSH_SFTP_READDIR_LINK",
286 "SSH_SFTP_READDIR_BOTTOM",
287 "SSH_SFTP_READDIR_DONE",
288 "SSH_SFTP_DOWNLOAD_INIT",
289 "SSH_SFTP_DOWNLOAD_STAT",
290 "SSH_SFTP_CLOSE",
291 "SSH_SFTP_SHUTDOWN",
292 "SSH_SCP_TRANS_INIT",
293 "SSH_SCP_UPLOAD_INIT",
294 "SSH_SCP_DOWNLOAD_INIT",
295 "SSH_SCP_DOWNLOAD",
296 "SSH_SCP_DONE",
297 "SSH_SCP_SEND_EOF",
298 "SSH_SCP_WAIT_EOF",
299 "SSH_SCP_WAIT_CLOSE",
300 "SSH_SCP_CHANNEL_FREE",
301 "SSH_SESSION_DISCONNECT",
302 "SSH_SESSION_FREE",
303 "QUIT"
304 };
305
306
307 if(sshc->state != nowstate) {
308 infof(data, "SSH %p state change from %s to %s (line %d)",
309 (void *) sshc, names[sshc->state], names[nowstate],
310 lineno);
311 }
312#endif
313
314 sshc->state = nowstate;
315}
316
317/* Multiple options:
318 * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
319 * hash (90s style auth, not sure we should have it here)
320 * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
321 * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
322 * is returned by it.
323 * 3. none of the above. We only accept if it is present on known hosts.
324 *
325 * Returns SSH_OK or SSH_ERROR.
326 */
327static int myssh_is_known(struct Curl_easy *data)
328{
329 int rc;
330 struct connectdata *conn = data->conn;
331 struct ssh_conn *sshc = &conn->proto.sshc;
332 ssh_key pubkey;
333 size_t hlen;
334 unsigned char *hash = NULL;
335 char *found_base64 = NULL;
336 char *known_base64 = NULL;
337 int vstate;
338 enum curl_khmatch keymatch;
339 struct curl_khkey foundkey;
340 struct curl_khkey *knownkeyp = NULL;
341 curl_sshkeycallback func =
342 data->set.ssh_keyfunc;
343
344#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
345 struct ssh_knownhosts_entry *knownhostsentry = NULL;
346 struct curl_khkey knownkey;
347#endif
348
349#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
350 rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
351#else
352 rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
353#endif
354 if(rc != SSH_OK)
355 return rc;
356
357 if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
358 int i;
359 char md5buffer[33];
360 const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
361
362 rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
363 &hash, &hlen);
364 if(rc != SSH_OK || hlen != 16) {
365 failf(data,
366 "Denied establishing ssh session: md5 fingerprint not available");
367 goto cleanup;
368 }
369
370 for(i = 0; i < 16; i++)
371 msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
372
373 infof(data, "SSH MD5 fingerprint: %s", md5buffer);
374
375 if(!strcasecompare(md5buffer, pubkey_md5)) {
376 failf(data,
377 "Denied establishing ssh session: mismatch md5 fingerprint. "
378 "Remote %s is not equal to %s", md5buffer, pubkey_md5);
379 rc = SSH_ERROR;
380 goto cleanup;
381 }
382
383 rc = SSH_OK;
384 goto cleanup;
385 }
386
387 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
388
389#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
390 /* Get the known_key from the known hosts file */
391 vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
392 &knownhostsentry);
393
394 /* Case an entry was found in a known hosts file */
395 if(knownhostsentry) {
396 if(knownhostsentry->publickey) {
397 rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
398 &known_base64);
399 if(rc != SSH_OK) {
400 goto cleanup;
401 }
402 knownkey.key = known_base64;
403 knownkey.len = strlen(known_base64);
404
405 switch(ssh_key_type(knownhostsentry->publickey)) {
406 case SSH_KEYTYPE_RSA:
407 knownkey.keytype = CURLKHTYPE_RSA;
408 break;
409 case SSH_KEYTYPE_RSA1:
410 knownkey.keytype = CURLKHTYPE_RSA1;
411 break;
412 case SSH_KEYTYPE_ECDSA:
413 case SSH_KEYTYPE_ECDSA_P256:
414 case SSH_KEYTYPE_ECDSA_P384:
415 case SSH_KEYTYPE_ECDSA_P521:
416 knownkey.keytype = CURLKHTYPE_ECDSA;
417 break;
418 case SSH_KEYTYPE_ED25519:
419 knownkey.keytype = CURLKHTYPE_ED25519;
420 break;
421 case SSH_KEYTYPE_DSS:
422 knownkey.keytype = CURLKHTYPE_DSS;
423 break;
424 default:
425 rc = SSH_ERROR;
426 goto cleanup;
427 }
428 knownkeyp = &knownkey;
429 }
430 }
431
432 switch(vstate) {
433 case SSH_KNOWN_HOSTS_OK:
434 keymatch = CURLKHMATCH_OK;
435 break;
436 case SSH_KNOWN_HOSTS_OTHER:
437 case SSH_KNOWN_HOSTS_NOT_FOUND:
438 case SSH_KNOWN_HOSTS_UNKNOWN:
439 case SSH_KNOWN_HOSTS_ERROR:
440 keymatch = CURLKHMATCH_MISSING;
441 break;
442 default:
443 keymatch = CURLKHMATCH_MISMATCH;
444 break;
445 }
446
447#else
448 vstate = ssh_is_server_known(sshc->ssh_session);
449 switch(vstate) {
450 case SSH_SERVER_KNOWN_OK:
451 keymatch = CURLKHMATCH_OK;
452 break;
453 case SSH_SERVER_FILE_NOT_FOUND:
454 case SSH_SERVER_NOT_KNOWN:
455 keymatch = CURLKHMATCH_MISSING;
456 break;
457 default:
458 keymatch = CURLKHMATCH_MISMATCH;
459 break;
460 }
461#endif
462
463 if(func) { /* use callback to determine action */
464 rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
465 if(rc != SSH_OK)
466 goto cleanup;
467
468 foundkey.key = found_base64;
469 foundkey.len = strlen(found_base64);
470
471 switch(ssh_key_type(pubkey)) {
472 case SSH_KEYTYPE_RSA:
473 foundkey.keytype = CURLKHTYPE_RSA;
474 break;
475 case SSH_KEYTYPE_RSA1:
476 foundkey.keytype = CURLKHTYPE_RSA1;
477 break;
478 case SSH_KEYTYPE_ECDSA:
479#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
480 case SSH_KEYTYPE_ECDSA_P256:
481 case SSH_KEYTYPE_ECDSA_P384:
482 case SSH_KEYTYPE_ECDSA_P521:
483#endif
484 foundkey.keytype = CURLKHTYPE_ECDSA;
485 break;
486#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
487 case SSH_KEYTYPE_ED25519:
488 foundkey.keytype = CURLKHTYPE_ED25519;
489 break;
490#endif
491 case SSH_KEYTYPE_DSS:
492 foundkey.keytype = CURLKHTYPE_DSS;
493 break;
494 default:
495 rc = SSH_ERROR;
496 goto cleanup;
497 }
498
499 Curl_set_in_callback(data, TRUE);
500 rc = func(data, knownkeyp, /* from the knownhosts file */
501 &foundkey, /* from the remote host */
502 keymatch, data->set.ssh_keyfunc_userp);
503 Curl_set_in_callback(data, FALSE);
504
505 switch(rc) {
506 case CURLKHSTAT_FINE_ADD_TO_FILE:
507#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
508 rc = ssh_session_update_known_hosts(sshc->ssh_session);
509#else
510 rc = ssh_write_knownhost(sshc->ssh_session);
511#endif
512 if(rc != SSH_OK) {
513 goto cleanup;
514 }
515 break;
516 case CURLKHSTAT_FINE:
517 break;
518 default: /* REJECT/DEFER */
519 rc = SSH_ERROR;
520 goto cleanup;
521 }
522 }
523 else {
524 if(keymatch != CURLKHMATCH_OK) {
525 rc = SSH_ERROR;
526 goto cleanup;
527 }
528 }
529 }
530 rc = SSH_OK;
531
532cleanup:
533 if(found_base64) {
534 (free)(found_base64);
535 }
536 if(known_base64) {
537 (free)(known_base64);
538 }
539 if(hash)
540 ssh_clean_pubkey_hash(&hash);
541 ssh_key_free(pubkey);
542#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
543 if(knownhostsentry) {
544 ssh_knownhosts_entry_free(knownhostsentry);
545 }
546#endif
547 return rc;
548}
549
550#define MOVE_TO_ERROR_STATE(_r) do { \
551 state(data, SSH_SESSION_DISCONNECT); \
552 sshc->actualcode = _r; \
553 rc = SSH_ERROR; \
554 } while(0)
555
556#define MOVE_TO_SFTP_CLOSE_STATE() do { \
557 state(data, SSH_SFTP_CLOSE); \
558 sshc->actualcode = \
559 sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
560 rc = SSH_ERROR; \
561 } while(0)
562
563#define MOVE_TO_PASSWD_AUTH do { \
564 if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
565 rc = SSH_OK; \
566 state(data, SSH_AUTH_PASS_INIT); \
567 } \
568 else { \
569 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
570 } \
571 } while(0)
572
573#define MOVE_TO_KEY_AUTH do { \
574 if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
575 rc = SSH_OK; \
576 state(data, SSH_AUTH_KEY_INIT); \
577 } \
578 else { \
579 MOVE_TO_PASSWD_AUTH; \
580 } \
581 } while(0)
582
583#define MOVE_TO_GSSAPI_AUTH do { \
584 if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
585 rc = SSH_OK; \
586 state(data, SSH_AUTH_GSSAPI); \
587 } \
588 else { \
589 MOVE_TO_KEY_AUTH; \
590 } \
591 } while(0)
592
593static
594int myssh_auth_interactive(struct connectdata *conn)
595{
596 int rc;
597 struct ssh_conn *sshc = &conn->proto.sshc;
598 int nprompts;
599
600restart:
601 switch(sshc->kbd_state) {
602 case 0:
603 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
604 if(rc == SSH_AUTH_AGAIN)
605 return SSH_AGAIN;
606
607 if(rc != SSH_AUTH_INFO)
608 return SSH_ERROR;
609
610 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
611 if(nprompts != 1)
612 return SSH_ERROR;
613
614 rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
615 if(rc < 0)
616 return SSH_ERROR;
617
618 FALLTHROUGH();
619 case 1:
620 sshc->kbd_state = 1;
621
622 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
623 if(rc == SSH_AUTH_AGAIN)
624 return SSH_AGAIN;
625 else if(rc == SSH_AUTH_SUCCESS)
626 rc = SSH_OK;
627 else if(rc == SSH_AUTH_INFO) {
628 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
629 if(nprompts)
630 return SSH_ERROR;
631
632 sshc->kbd_state = 2;
633 goto restart;
634 }
635 else
636 rc = SSH_ERROR;
637 break;
638 case 2:
639 sshc->kbd_state = 2;
640
641 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
642 if(rc == SSH_AUTH_AGAIN)
643 return SSH_AGAIN;
644 else if(rc == SSH_AUTH_SUCCESS)
645 rc = SSH_OK;
646 else
647 rc = SSH_ERROR;
648
649 break;
650 default:
651 return SSH_ERROR;
652 }
653
654 sshc->kbd_state = 0;
655 return rc;
656}
657
658/*
659 * ssh_statemach_act() runs the SSH state machine as far as it can without
660 * blocking and without reaching the end. The data the pointer 'block' points
661 * to will be set to TRUE if the libssh function returns SSH_AGAIN
662 * meaning it wants to be called again when the socket is ready
663 */
664static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
665{
666 CURLcode result = CURLE_OK;
667 struct connectdata *conn = data->conn;
668 struct SSHPROTO *protop = data->req.p.ssh;
669 struct ssh_conn *sshc = &conn->proto.sshc;
670 curl_socket_t sock = conn->sock[FIRSTSOCKET];
671 int rc = SSH_NO_ERROR, err;
672 int seekerr = CURL_SEEKFUNC_OK;
673 const char *err_msg;
674 *block = 0; /* we are not blocking by default */
675
676 do {
677
678 switch(sshc->state) {
679 case SSH_INIT:
680 sshc->secondCreateDirs = 0;
681 sshc->nextstate = SSH_NO_STATE;
682 sshc->actualcode = CURLE_OK;
683
684#if 0
685 ssh_set_log_level(SSH_LOG_PROTOCOL);
686#endif
687
688 /* Set libssh to non-blocking, since everything internally is
689 non-blocking */
690 ssh_set_blocking(sshc->ssh_session, 0);
691
692 state(data, SSH_S_STARTUP);
693 FALLTHROUGH();
694
695 case SSH_S_STARTUP:
696 rc = ssh_connect(sshc->ssh_session);
697
698 myssh_block2waitfor(conn, (rc == SSH_AGAIN));
699 if(rc == SSH_AGAIN) {
700 DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
701 break;
702 }
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 (%" FMT_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 (cannot 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 cannot
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 do not 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#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
1372 sshc->sftp_send_state = 0;
1373#endif
1374 state(data, SSH_STOP);
1375 break;
1376 }
1377
1378 case SSH_SFTP_CREATE_DIRS_INIT:
1379 if(strlen(protop->path) > 1) {
1380 sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1381 state(data, SSH_SFTP_CREATE_DIRS);
1382 }
1383 else {
1384 state(data, SSH_SFTP_UPLOAD_INIT);
1385 }
1386 break;
1387
1388 case SSH_SFTP_CREATE_DIRS:
1389 sshc->slash_pos = strchr(sshc->slash_pos, '/');
1390 if(sshc->slash_pos) {
1391 *sshc->slash_pos = 0;
1392
1393 infof(data, "Creating directory '%s'", protop->path);
1394 state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
1395 break;
1396 }
1397 state(data, SSH_SFTP_UPLOAD_INIT);
1398 break;
1399
1400 case SSH_SFTP_CREATE_DIRS_MKDIR:
1401 /* 'mode' - parameter is preliminary - default to 0644 */
1402 rc = sftp_mkdir(sshc->sftp_session, protop->path,
1403 (mode_t)data->set.new_directory_perms);
1404 *sshc->slash_pos = '/';
1405 ++sshc->slash_pos;
1406 if(rc < 0) {
1407 /*
1408 * Abort if failure was not that the dir already exists or the
1409 * permission was denied (creation might succeed further down the
1410 * path) - retry on unspecific FAILURE also
1411 */
1412 err = sftp_get_error(sshc->sftp_session);
1413 if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1414 (err != SSH_FX_FAILURE) &&
1415 (err != SSH_FX_PERMISSION_DENIED)) {
1416 MOVE_TO_SFTP_CLOSE_STATE();
1417 break;
1418 }
1419 rc = 0; /* clear rc and continue */
1420 }
1421 state(data, SSH_SFTP_CREATE_DIRS);
1422 break;
1423
1424 case SSH_SFTP_READDIR_INIT:
1425 Curl_pgrsSetDownloadSize(data, -1);
1426 if(data->req.no_body) {
1427 state(data, SSH_STOP);
1428 break;
1429 }
1430
1431 /*
1432 * This is a directory that we are trying to get, so produce a directory
1433 * listing
1434 */
1435 sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1436 protop->path);
1437 if(!sshc->sftp_dir) {
1438 failf(data, "Could not open directory for reading: %s",
1439 ssh_get_error(sshc->ssh_session));
1440 MOVE_TO_SFTP_CLOSE_STATE();
1441 break;
1442 }
1443 state(data, SSH_SFTP_READDIR);
1444 break;
1445
1446 case SSH_SFTP_READDIR:
1447 Curl_dyn_reset(&sshc->readdir_buf);
1448 if(sshc->readdir_attrs)
1449 sftp_attributes_free(sshc->readdir_attrs);
1450
1451 sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1452 if(sshc->readdir_attrs) {
1453 sshc->readdir_filename = sshc->readdir_attrs->name;
1454 sshc->readdir_longentry = sshc->readdir_attrs->longname;
1455 sshc->readdir_len = strlen(sshc->readdir_filename);
1456
1457 if(data->set.list_only) {
1458 char *tmpLine;
1459
1460 tmpLine = aprintf("%s\n", sshc->readdir_filename);
1461 if(!tmpLine) {
1462 state(data, SSH_SFTP_CLOSE);
1463 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1464 break;
1465 }
1466 result = Curl_client_write(data, CLIENTWRITE_BODY,
1467 tmpLine, sshc->readdir_len + 1);
1468 free(tmpLine);
1469
1470 if(result) {
1471 state(data, SSH_STOP);
1472 break;
1473 }
1474
1475 }
1476 else {
1477 if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
1478 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1479 state(data, SSH_STOP);
1480 break;
1481 }
1482
1483 if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1484 ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
1485 SSH_S_IFLNK)) {
1486 sshc->readdir_linkPath = aprintf("%s%s", protop->path,
1487 sshc->readdir_filename);
1488
1489 if(!sshc->readdir_linkPath) {
1490 state(data, SSH_SFTP_CLOSE);
1491 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1492 break;
1493 }
1494
1495 state(data, SSH_SFTP_READDIR_LINK);
1496 break;
1497 }
1498 state(data, SSH_SFTP_READDIR_BOTTOM);
1499 break;
1500 }
1501 }
1502 else if(sftp_dir_eof(sshc->sftp_dir)) {
1503 state(data, SSH_SFTP_READDIR_DONE);
1504 break;
1505 }
1506 else {
1507 failf(data, "Could not open remote file for reading: %s",
1508 ssh_get_error(sshc->ssh_session));
1509 MOVE_TO_SFTP_CLOSE_STATE();
1510 break;
1511 }
1512 break;
1513
1514 case SSH_SFTP_READDIR_LINK:
1515 if(sshc->readdir_link_attrs)
1516 sftp_attributes_free(sshc->readdir_link_attrs);
1517
1518 sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1519 sshc->readdir_linkPath);
1520 if(sshc->readdir_link_attrs == 0) {
1521 failf(data, "Could not read symlink for reading: %s",
1522 ssh_get_error(sshc->ssh_session));
1523 MOVE_TO_SFTP_CLOSE_STATE();
1524 break;
1525 }
1526
1527 if(!sshc->readdir_link_attrs->name) {
1528 sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1529 sshc->readdir_linkPath);
1530 if(!sshc->readdir_filename)
1531 sshc->readdir_len = 0;
1532 else
1533 sshc->readdir_len = strlen(sshc->readdir_tmp);
1534 sshc->readdir_longentry = NULL;
1535 sshc->readdir_filename = sshc->readdir_tmp;
1536 }
1537 else {
1538 sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
1539 sshc->readdir_filename = sshc->readdir_link_attrs->name;
1540 sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1541 }
1542
1543 Curl_safefree(sshc->readdir_linkPath);
1544
1545 if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
1546 sshc->readdir_filename)) {
1547 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1548 break;
1549 }
1550
1551 sftp_attributes_free(sshc->readdir_link_attrs);
1552 sshc->readdir_link_attrs = NULL;
1553 sshc->readdir_filename = NULL;
1554 sshc->readdir_longentry = NULL;
1555
1556 state(data, SSH_SFTP_READDIR_BOTTOM);
1557 FALLTHROUGH();
1558 case SSH_SFTP_READDIR_BOTTOM:
1559 if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
1560 result = CURLE_OUT_OF_MEMORY;
1561 else
1562 result = Curl_client_write(data, CLIENTWRITE_BODY,
1563 Curl_dyn_ptr(&sshc->readdir_buf),
1564 Curl_dyn_len(&sshc->readdir_buf));
1565
1566 ssh_string_free_char(sshc->readdir_tmp);
1567 sshc->readdir_tmp = NULL;
1568
1569 if(result) {
1570 state(data, SSH_STOP);
1571 }
1572 else
1573 state(data, SSH_SFTP_READDIR);
1574 break;
1575
1576 case SSH_SFTP_READDIR_DONE:
1577 sftp_closedir(sshc->sftp_dir);
1578 sshc->sftp_dir = NULL;
1579
1580 /* no data to transfer */
1581 Curl_xfer_setup_nop(data);
1582 state(data, SSH_STOP);
1583 break;
1584
1585 case SSH_SFTP_DOWNLOAD_INIT:
1586 /*
1587 * Work on getting the specified file
1588 */
1589 if(sshc->sftp_file)
1590 sftp_close(sshc->sftp_file);
1591
1592 sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1593 O_RDONLY, (mode_t)data->set.new_file_perms);
1594 if(!sshc->sftp_file) {
1595 failf(data, "Could not open remote file for reading: %s",
1596 ssh_get_error(sshc->ssh_session));
1597
1598 MOVE_TO_SFTP_CLOSE_STATE();
1599 break;
1600 }
1601 sftp_file_set_nonblocking(sshc->sftp_file);
1602 state(data, SSH_SFTP_DOWNLOAD_STAT);
1603 break;
1604
1605 case SSH_SFTP_DOWNLOAD_STAT:
1606 {
1607 sftp_attributes attrs;
1608 curl_off_t size;
1609
1610 attrs = sftp_fstat(sshc->sftp_file);
1611 if(!attrs ||
1612 !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1613 (attrs->size == 0)) {
1614 /*
1615 * sftp_fstat did not return an error, so maybe the server
1616 * just does not support stat()
1617 * OR the server does not return a file size with a stat()
1618 * OR file size is 0
1619 */
1620 data->req.size = -1;
1621 data->req.maxdownload = -1;
1622 Curl_pgrsSetDownloadSize(data, -1);
1623 size = 0;
1624 }
1625 else {
1626 size = attrs->size;
1627
1628 sftp_attributes_free(attrs);
1629
1630 if(size < 0) {
1631 failf(data, "Bad file size (%" FMT_OFF_T ")", size);
1632 return CURLE_BAD_DOWNLOAD_RESUME;
1633 }
1634 if(data->state.use_range) {
1635 curl_off_t from, to;
1636 char *ptr;
1637 char *ptr2;
1638 CURLofft to_t;
1639 CURLofft from_t;
1640
1641 from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
1642 if(from_t == CURL_OFFT_FLOW) {
1643 return CURLE_RANGE_ERROR;
1644 }
1645 while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
1646 ptr++;
1647 to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
1648 if(to_t == CURL_OFFT_FLOW) {
1649 return CURLE_RANGE_ERROR;
1650 }
1651 if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1652 || (to >= size)) {
1653 to = size - 1;
1654 }
1655 if(from_t) {
1656 /* from is relative to end of file */
1657 from = size - to;
1658 to = size - 1;
1659 }
1660 if(from > size) {
1661 failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
1662 FMT_OFF_T ")", from, size);
1663 return CURLE_BAD_DOWNLOAD_RESUME;
1664 }
1665 if(from > to) {
1666 from = to;
1667 size = 0;
1668 }
1669 else {
1670 if((to - from) == CURL_OFF_T_MAX)
1671 return CURLE_RANGE_ERROR;
1672 size = to - from + 1;
1673 }
1674
1675 rc = sftp_seek64(sshc->sftp_file, from);
1676 if(rc) {
1677 MOVE_TO_SFTP_CLOSE_STATE();
1678 break;
1679 }
1680 }
1681 data->req.size = size;
1682 data->req.maxdownload = size;
1683 Curl_pgrsSetDownloadSize(data, size);
1684 }
1685
1686 /* We can resume if we can seek to the resume position */
1687 if(data->state.resume_from) {
1688 if(data->state.resume_from < 0) {
1689 /* We are supposed to download the last abs(from) bytes */
1690 if((curl_off_t)size < -data->state.resume_from) {
1691 failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
1692 FMT_OFF_T ")", data->state.resume_from, size);
1693 return CURLE_BAD_DOWNLOAD_RESUME;
1694 }
1695 /* download from where? */
1696 data->state.resume_from += size;
1697 }
1698 else {
1699 if((curl_off_t)size < data->state.resume_from) {
1700 failf(data, "Offset (%" FMT_OFF_T
1701 ") was beyond file size (%" FMT_OFF_T ")",
1702 data->state.resume_from, size);
1703 return CURLE_BAD_DOWNLOAD_RESUME;
1704 }
1705 }
1706 /* Now store the number of bytes we are expected to download */
1707 data->req.size = size - data->state.resume_from;
1708 data->req.maxdownload = size - data->state.resume_from;
1709 Curl_pgrsSetDownloadSize(data,
1710 size - data->state.resume_from);
1711
1712 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1713 if(rc) {
1714 MOVE_TO_SFTP_CLOSE_STATE();
1715 break;
1716 }
1717 }
1718 }
1719
1720 /* Setup the actual download */
1721 if(data->req.size == 0) {
1722 /* no data to transfer */
1723 Curl_xfer_setup_nop(data);
1724 infof(data, "File already completely downloaded");
1725 state(data, SSH_STOP);
1726 break;
1727 }
1728 Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
1729
1730 /* not set by Curl_xfer_setup to preserve keepon bits */
1731 conn->writesockfd = conn->sockfd;
1732
1733 /* we want to use the _receiving_ function even when the socket turns
1734 out writableable as the underlying libssh recv function will deal
1735 with both accordingly */
1736 data->state.select_bits = CURL_CSELECT_IN;
1737
1738 if(result) {
1739 /* this should never occur; the close state should be entered
1740 at the time the error occurs */
1741 state(data, SSH_SFTP_CLOSE);
1742 sshc->actualcode = result;
1743 }
1744 else {
1745 sshc->sftp_recv_state = 0;
1746 state(data, SSH_STOP);
1747 }
1748 break;
1749
1750 case SSH_SFTP_CLOSE:
1751 if(sshc->sftp_file) {
1752 sftp_close(sshc->sftp_file);
1753 sshc->sftp_file = NULL;
1754 }
1755 Curl_safefree(protop->path);
1756
1757 DEBUGF(infof(data, "SFTP DONE done"));
1758
1759 /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
1760 After nextstate is executed, the control should come back to
1761 SSH_SFTP_CLOSE to pass the correct result back */
1762 if(sshc->nextstate != SSH_NO_STATE &&
1763 sshc->nextstate != SSH_SFTP_CLOSE) {
1764 state(data, sshc->nextstate);
1765 sshc->nextstate = SSH_SFTP_CLOSE;
1766 }
1767 else {
1768 state(data, SSH_STOP);
1769 result = sshc->actualcode;
1770 }
1771 break;
1772
1773 case SSH_SFTP_SHUTDOWN:
1774 /* during times we get here due to a broken transfer and then the
1775 sftp_handle might not have been taken down so make sure that is done
1776 before we proceed */
1777 ssh_set_blocking(sshc->ssh_session, 0);
1778#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
1779 if(sshc->sftp_aio) {
1780 sftp_aio_free(sshc->sftp_aio);
1781 sshc->sftp_aio = NULL;
1782 }
1783#endif
1784
1785 if(sshc->sftp_file) {
1786 sftp_close(sshc->sftp_file);
1787 sshc->sftp_file = NULL;
1788 }
1789
1790 if(sshc->sftp_session) {
1791 sftp_free(sshc->sftp_session);
1792 sshc->sftp_session = NULL;
1793 }
1794
1795 SSH_STRING_FREE_CHAR(sshc->homedir);
1796 data->state.most_recent_ftp_entrypath = NULL;
1797
1798 state(data, SSH_SESSION_DISCONNECT);
1799 break;
1800
1801 case SSH_SCP_TRANS_INIT:
1802 result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
1803 if(result) {
1804 sshc->actualcode = result;
1805 state(data, SSH_STOP);
1806 break;
1807 }
1808
1809 /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
1810 ssh_set_blocking(sshc->ssh_session, 1);
1811
1812 if(data->state.upload) {
1813 if(data->state.infilesize < 0) {
1814 failf(data, "SCP requires a known file size for upload");
1815 sshc->actualcode = CURLE_UPLOAD_FAILED;
1816 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1817 break;
1818 }
1819
1820 sshc->scp_session =
1821 ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
1822 state(data, SSH_SCP_UPLOAD_INIT);
1823 }
1824 else {
1825 sshc->scp_session =
1826 ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
1827 state(data, SSH_SCP_DOWNLOAD_INIT);
1828 }
1829
1830 if(!sshc->scp_session) {
1831 err_msg = ssh_get_error(sshc->ssh_session);
1832 failf(data, "%s", err_msg);
1833 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1834 }
1835
1836 break;
1837
1838 case SSH_SCP_UPLOAD_INIT:
1839
1840 rc = ssh_scp_init(sshc->scp_session);
1841 if(rc != SSH_OK) {
1842 err_msg = ssh_get_error(sshc->ssh_session);
1843 failf(data, "%s", err_msg);
1844 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1845 break;
1846 }
1847
1848 rc = ssh_scp_push_file(sshc->scp_session, protop->path,
1849 data->state.infilesize,
1850 (int)data->set.new_file_perms);
1851 if(rc != SSH_OK) {
1852 err_msg = ssh_get_error(sshc->ssh_session);
1853 failf(data, "%s", err_msg);
1854 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1855 break;
1856 }
1857
1858 /* upload data */
1859 Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
1860
1861 /* not set by Curl_xfer_setup to preserve keepon bits */
1862 conn->sockfd = conn->writesockfd;
1863
1864 /* store this original bitmask setup to use later on if we cannot
1865 figure out a "real" bitmask */
1866 sshc->orig_waitfor = data->req.keepon;
1867
1868 /* we want to use the _sending_ function even when the socket turns
1869 out readable as the underlying libssh scp send function will deal
1870 with both accordingly */
1871 data->state.select_bits = CURL_CSELECT_OUT;
1872
1873 state(data, SSH_STOP);
1874
1875 break;
1876
1877 case SSH_SCP_DOWNLOAD_INIT:
1878
1879 rc = ssh_scp_init(sshc->scp_session);
1880 if(rc != SSH_OK) {
1881 err_msg = ssh_get_error(sshc->ssh_session);
1882 failf(data, "%s", err_msg);
1883 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
1884 break;
1885 }
1886 state(data, SSH_SCP_DOWNLOAD);
1887 FALLTHROUGH();
1888
1889 case SSH_SCP_DOWNLOAD:{
1890 curl_off_t bytecount;
1891
1892 rc = ssh_scp_pull_request(sshc->scp_session);
1893 if(rc != SSH_SCP_REQUEST_NEWFILE) {
1894 err_msg = ssh_get_error(sshc->ssh_session);
1895 failf(data, "%s", err_msg);
1896 MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
1897 break;
1898 }
1899
1900 /* download data */
1901 bytecount = ssh_scp_request_get_size(sshc->scp_session);
1902 data->req.maxdownload = (curl_off_t) bytecount;
1903 Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);
1904
1905 /* not set by Curl_xfer_setup to preserve keepon bits */
1906 conn->writesockfd = conn->sockfd;
1907
1908 /* we want to use the _receiving_ function even when the socket turns
1909 out writableable as the underlying libssh recv function will deal
1910 with both accordingly */
1911 data->state.select_bits = CURL_CSELECT_IN;
1912
1913 state(data, SSH_STOP);
1914 break;
1915 }
1916 case SSH_SCP_DONE:
1917 if(data->state.upload)
1918 state(data, SSH_SCP_SEND_EOF);
1919 else
1920 state(data, SSH_SCP_CHANNEL_FREE);
1921 break;
1922
1923 case SSH_SCP_SEND_EOF:
1924 if(sshc->scp_session) {
1925 rc = ssh_scp_close(sshc->scp_session);
1926 if(rc == SSH_AGAIN) {
1927 /* Currently the ssh_scp_close handles waiting for EOF in
1928 * blocking way.
1929 */
1930 break;
1931 }
1932 if(rc != SSH_OK) {
1933 infof(data, "Failed to close libssh scp channel: %s",
1934 ssh_get_error(sshc->ssh_session));
1935 }
1936 }
1937
1938 state(data, SSH_SCP_CHANNEL_FREE);
1939 break;
1940
1941 case SSH_SCP_CHANNEL_FREE:
1942 if(sshc->scp_session) {
1943 ssh_scp_free(sshc->scp_session);
1944 sshc->scp_session = NULL;
1945 }
1946 DEBUGF(infof(data, "SCP DONE phase complete"));
1947
1948 ssh_set_blocking(sshc->ssh_session, 0);
1949
1950 state(data, SSH_SESSION_DISCONNECT);
1951 FALLTHROUGH();
1952
1953 case SSH_SESSION_DISCONNECT:
1954 /* during weird times when we have been prematurely aborted, the channel
1955 is still alive when we reach this state and we MUST kill the channel
1956 properly first */
1957 if(sshc->scp_session) {
1958 ssh_scp_free(sshc->scp_session);
1959 sshc->scp_session = NULL;
1960 }
1961
1962 ssh_disconnect(sshc->ssh_session);
1963 if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
1964 /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
1965 tell the connection to forget about it. This libssh
1966 bug is fixed in 0.10.0. */
1967 Curl_conn_forget_socket(data, FIRSTSOCKET);
1968 }
1969
1970 SSH_STRING_FREE_CHAR(sshc->homedir);
1971 data->state.most_recent_ftp_entrypath = NULL;
1972
1973 state(data, SSH_SESSION_FREE);
1974 FALLTHROUGH();
1975 case SSH_SESSION_FREE:
1976 if(sshc->ssh_session) {
1977 ssh_free(sshc->ssh_session);
1978 sshc->ssh_session = NULL;
1979 }
1980
1981 /* worst-case scenario cleanup */
1982
1983 DEBUGASSERT(sshc->ssh_session == NULL);
1984 DEBUGASSERT(sshc->scp_session == NULL);
1985
1986 if(sshc->readdir_tmp) {
1987 ssh_string_free_char(sshc->readdir_tmp);
1988 sshc->readdir_tmp = NULL;
1989 }
1990
1991 if(sshc->quote_attrs)
1992 sftp_attributes_free(sshc->quote_attrs);
1993
1994 if(sshc->readdir_attrs)
1995 sftp_attributes_free(sshc->readdir_attrs);
1996
1997 if(sshc->readdir_link_attrs)
1998 sftp_attributes_free(sshc->readdir_link_attrs);
1999
2000 if(sshc->privkey)
2001 ssh_key_free(sshc->privkey);
2002 if(sshc->pubkey)
2003 ssh_key_free(sshc->pubkey);
2004
2005 Curl_safefree(sshc->rsa_pub);
2006 Curl_safefree(sshc->rsa);
2007 Curl_safefree(sshc->quote_path1);
2008 Curl_safefree(sshc->quote_path2);
2009 Curl_dyn_free(&sshc->readdir_buf);
2010 Curl_safefree(sshc->readdir_linkPath);
2011 SSH_STRING_FREE_CHAR(sshc->homedir);
2012
2013 /* the code we are about to return */
2014 result = sshc->actualcode;
2015
2016 memset(sshc, 0, sizeof(struct ssh_conn));
2017
2018 connclose(conn, "SSH session free");
2019 sshc->state = SSH_SESSION_FREE; /* current */
2020 sshc->nextstate = SSH_NO_STATE;
2021 state(data, SSH_STOP);
2022 break;
2023
2024 case SSH_QUIT:
2025 default:
2026 /* internal error */
2027 sshc->nextstate = SSH_NO_STATE;
2028 state(data, SSH_STOP);
2029 break;
2030
2031 }
2032 } while(!rc && (sshc->state != SSH_STOP));
2033
2034
2035 if(rc == SSH_AGAIN) {
2036 /* we would block, we need to wait for the socket to be ready (in the
2037 right direction too)! */
2038 *block = TRUE;
2039 }
2040
2041 return result;
2042}
2043
2044
2045/* called by the multi interface to figure out what socket(s) to wait for and
2046 for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
2047static int myssh_getsock(struct Curl_easy *data,
2048 struct connectdata *conn,
2049 curl_socket_t *sock)
2050{
2051 int bitmap = GETSOCK_BLANK;
2052 (void)data;
2053 sock[0] = conn->sock[FIRSTSOCKET];
2054
2055 if(conn->waitfor & KEEP_RECV)
2056 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
2057
2058 if(conn->waitfor & KEEP_SEND)
2059 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2060
2061 if(!conn->waitfor)
2062 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2063
2064 DEBUGF(infof(data, "ssh_getsock -> %x", bitmap));
2065 return bitmap;
2066}
2067
2068static void myssh_block2waitfor(struct connectdata *conn, bool block)
2069{
2070 struct ssh_conn *sshc = &conn->proto.sshc;
2071
2072 /* If it did not block, or nothing was returned by ssh_get_poll_flags
2073 * have the original set */
2074 conn->waitfor = sshc->orig_waitfor;
2075
2076 if(block) {
2077 int dir = ssh_get_poll_flags(sshc->ssh_session);
2078 conn->waitfor = 0;
2079 /* translate the libssh define bits into our own bit defines */
2080 if(dir & SSH_READ_PENDING)
2081 conn->waitfor |= KEEP_RECV;
2082 if(dir & SSH_WRITE_PENDING)
2083 conn->waitfor |= KEEP_SEND;
2084 }
2085}
2086
2087/* called repeatedly until done from multi.c */
2088static CURLcode myssh_multi_statemach(struct Curl_easy *data,
2089 bool *done)
2090{
2091 struct connectdata *conn = data->conn;
2092 struct ssh_conn *sshc = &conn->proto.sshc;
2093 bool block; /* we store the status and use that to provide a ssh_getsock()
2094 implementation */
2095 CURLcode result = myssh_statemach_act(data, &block);
2096
2097 *done = (sshc->state == SSH_STOP);
2098 myssh_block2waitfor(conn, block);
2099
2100 return result;
2101}
2102
2103static CURLcode myssh_block_statemach(struct Curl_easy *data,
2104 bool disconnect)
2105{
2106 struct connectdata *conn = data->conn;
2107 struct ssh_conn *sshc = &conn->proto.sshc;
2108 CURLcode result = CURLE_OK;
2109
2110 while((sshc->state != SSH_STOP) && !result) {
2111 bool block;
2112 timediff_t left = 1000;
2113 struct curltime now = Curl_now();
2114
2115 result = myssh_statemach_act(data, &block);
2116 if(result)
2117 break;
2118
2119 if(!disconnect) {
2120 if(Curl_pgrsUpdate(data))
2121 return CURLE_ABORTED_BY_CALLBACK;
2122
2123 result = Curl_speedcheck(data, now);
2124 if(result)
2125 break;
2126
2127 left = Curl_timeleft(data, NULL, FALSE);
2128 if(left < 0) {
2129 failf(data, "Operation timed out");
2130 return CURLE_OPERATION_TIMEDOUT;
2131 }
2132 }
2133
2134 if(block) {
2135 curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
2136 /* wait for the socket to become ready */
2137 (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2138 CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2139 }
2140
2141 }
2142
2143 return result;
2144}
2145
2146/*
2147 * SSH setup connection
2148 */
2149static CURLcode myssh_setup_connection(struct Curl_easy *data,
2150 struct connectdata *conn)
2151{
2152 struct SSHPROTO *ssh;
2153 struct ssh_conn *sshc = &conn->proto.sshc;
2154
2155 data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
2156 if(!ssh)
2157 return CURLE_OUT_OF_MEMORY;
2158 Curl_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
2159
2160 return CURLE_OK;
2161}
2162
2163static Curl_recv scp_recv, sftp_recv;
2164static Curl_send scp_send, sftp_send;
2165
2166/*
2167 * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2168 * do protocol-specific actions at connect-time.
2169 */
2170static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
2171{
2172 struct ssh_conn *ssh;
2173 CURLcode result;
2174 struct connectdata *conn = data->conn;
2175 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2176 int rc;
2177
2178 /* initialize per-handle data if not already */
2179 if(!data->req.p.ssh)
2180 myssh_setup_connection(data, conn);
2181
2182 /* We default to persistent connections. We set this already in this connect
2183 function to make the reuse checks properly be able to check this bit. */
2184 connkeep(conn, "SSH default");
2185
2186 if(conn->handler->protocol & CURLPROTO_SCP) {
2187 conn->recv[FIRSTSOCKET] = scp_recv;
2188 conn->send[FIRSTSOCKET] = scp_send;
2189 }
2190 else {
2191 conn->recv[FIRSTSOCKET] = sftp_recv;
2192 conn->send[FIRSTSOCKET] = sftp_send;
2193 }
2194
2195 ssh = &conn->proto.sshc;
2196
2197 ssh->ssh_session = ssh_new();
2198 if(!ssh->ssh_session) {
2199 failf(data, "Failure initialising ssh session");
2200 return CURLE_FAILED_INIT;
2201 }
2202
2203 if(conn->bits.ipv6_ip) {
2204 char ipv6[MAX_IPADR_LEN];
2205 msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name);
2206 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, ipv6);
2207 }
2208 else
2209 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2210
2211 if(rc != SSH_OK) {
2212 failf(data, "Could not set remote host");
2213 return CURLE_FAILED_INIT;
2214 }
2215
2216 rc = ssh_options_parse_config(ssh->ssh_session, NULL);
2217 if(rc != SSH_OK) {
2218 infof(data, "Could not parse SSH configuration files");
2219 /* ignore */
2220 }
2221
2222 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2223 if(rc != SSH_OK) {
2224 failf(data, "Could not set socket");
2225 return CURLE_FAILED_INIT;
2226 }
2227
2228 if(conn->user && conn->user[0] != '\0') {
2229 infof(data, "User: %s", conn->user);
2230 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2231 if(rc != SSH_OK) {
2232 failf(data, "Could not set user");
2233 return CURLE_FAILED_INIT;
2234 }
2235 }
2236
2237 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2238 infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
2239 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2240 data->set.str[STRING_SSH_KNOWNHOSTS]);
2241 if(rc != SSH_OK) {
2242 failf(data, "Could not set known hosts file path");
2243 return CURLE_FAILED_INIT;
2244 }
2245 }
2246
2247 if(conn->remote_port) {
2248 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2249 &conn->remote_port);
2250 if(rc != SSH_OK) {
2251 failf(data, "Could not set remote port");
2252 return CURLE_FAILED_INIT;
2253 }
2254 }
2255
2256 if(data->set.ssh_compression) {
2257 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2258 "zlib,zlib@openssh.com,none");
2259 if(rc != SSH_OK) {
2260 failf(data, "Could not set compression");
2261 return CURLE_FAILED_INIT;
2262 }
2263 }
2264
2265 ssh->privkey = NULL;
2266 ssh->pubkey = NULL;
2267
2268 if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2269 rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2270 &ssh->pubkey);
2271 if(rc != SSH_OK) {
2272 failf(data, "Could not load public key file");
2273 return CURLE_FAILED_INIT;
2274 }
2275 }
2276
2277 /* we do not verify here, we do it at the state machine,
2278 * after connection */
2279
2280 state(data, SSH_INIT);
2281
2282 result = myssh_multi_statemach(data, done);
2283
2284 return result;
2285}
2286
2287/* called from multi.c while DOing */
2288static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
2289{
2290 CURLcode result;
2291
2292 result = myssh_multi_statemach(data, dophase_done);
2293
2294 if(*dophase_done) {
2295 DEBUGF(infof(data, "DO phase is complete"));
2296 }
2297 return result;
2298}
2299
2300/*
2301 ***********************************************************************
2302 *
2303 * scp_perform()
2304 *
2305 * This is the actual DO function for SCP. Get a file according to
2306 * the options previously setup.
2307 */
2308
2309static
2310CURLcode scp_perform(struct Curl_easy *data,
2311 bool *connected, bool *dophase_done)
2312{
2313 CURLcode result = CURLE_OK;
2314
2315 DEBUGF(infof(data, "DO phase starts"));
2316
2317 *dophase_done = FALSE; /* not done yet */
2318
2319 /* start the first command in the DO phase */
2320 state(data, SSH_SCP_TRANS_INIT);
2321
2322 result = myssh_multi_statemach(data, dophase_done);
2323
2324 *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2325
2326 if(*dophase_done) {
2327 DEBUGF(infof(data, "DO phase is complete"));
2328 }
2329
2330 return result;
2331}
2332
2333static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
2334{
2335 CURLcode result;
2336 bool connected = FALSE;
2337 struct connectdata *conn = data->conn;
2338 struct ssh_conn *sshc = &conn->proto.sshc;
2339
2340 *done = FALSE; /* default to false */
2341
2342 data->req.size = -1; /* make sure this is unknown at this point */
2343
2344 sshc->actualcode = CURLE_OK; /* reset error code */
2345 sshc->secondCreateDirs = 0; /* reset the create dir attempt state
2346 variable */
2347
2348 Curl_pgrsSetUploadCounter(data, 0);
2349 Curl_pgrsSetDownloadCounter(data, 0);
2350 Curl_pgrsSetUploadSize(data, -1);
2351 Curl_pgrsSetDownloadSize(data, -1);
2352
2353 if(conn->handler->protocol & CURLPROTO_SCP)
2354 result = scp_perform(data, &connected, done);
2355 else
2356 result = sftp_perform(data, &connected, done);
2357
2358 return result;
2359}
2360
2361/* BLOCKING, but the function is using the state machine so the only reason
2362 this is still blocking is that the multi interface code has no support for
2363 disconnecting operations that takes a while */
2364static CURLcode scp_disconnect(struct Curl_easy *data,
2365 struct connectdata *conn,
2366 bool dead_connection)
2367{
2368 CURLcode result = CURLE_OK;
2369 struct ssh_conn *ssh = &conn->proto.sshc;
2370 (void) dead_connection;
2371
2372 if(ssh->ssh_session) {
2373 /* only if there is a session still around to use! */
2374
2375 state(data, SSH_SESSION_DISCONNECT);
2376
2377 result = myssh_block_statemach(data, TRUE);
2378 }
2379
2380 return result;
2381}
2382
2383/* generic done function for both SCP and SFTP called from their specific
2384 done functions */
2385static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
2386{
2387 CURLcode result = CURLE_OK;
2388 struct SSHPROTO *protop = data->req.p.ssh;
2389
2390 if(!status) {
2391 /* run the state-machine */
2392 result = myssh_block_statemach(data, FALSE);
2393 }
2394 else
2395 result = status;
2396
2397 if(protop)
2398 Curl_safefree(protop->path);
2399 if(Curl_pgrsDone(data))
2400 return CURLE_ABORTED_BY_CALLBACK;
2401
2402 data->req.keepon = 0; /* clear all bits */
2403 return result;
2404}
2405
2406
2407static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
2408 bool premature)
2409{
2410 (void) premature; /* not used */
2411
2412 if(!status)
2413 state(data, SSH_SCP_DONE);
2414
2415 return myssh_done(data, status);
2416
2417}
2418
2419static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2420 const void *mem, size_t len, bool eos, CURLcode *err)
2421{
2422 int rc;
2423 struct connectdata *conn = data->conn;
2424 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2425 (void) err;
2426 (void)eos;
2427
2428 rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2429
2430#if 0
2431 /* The following code is misleading, mostly added as wishful thinking
2432 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2433 * Currently rc can only be number of bytes read or SSH_ERROR. */
2434 myssh_block2waitfor(conn, (rc == SSH_AGAIN));
2435
2436 if(rc == SSH_AGAIN) {
2437 *err = CURLE_AGAIN;
2438 return 0;
2439 }
2440 else
2441#endif
2442 if(rc != SSH_OK) {
2443 *err = CURLE_SSH;
2444 return -1;
2445 }
2446
2447 return len;
2448}
2449
2450static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2451 char *mem, size_t len, CURLcode *err)
2452{
2453 ssize_t nread;
2454 struct connectdata *conn = data->conn;
2455 (void) err;
2456 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2457
2458 /* libssh returns int */
2459 nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2460
2461#if 0
2462 /* The following code is misleading, mostly added as wishful thinking
2463 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2464 * Currently rc can only be SSH_OK or SSH_ERROR. */
2465
2466 myssh_block2waitfor(conn, (nread == SSH_AGAIN));
2467 if(nread == SSH_AGAIN) {
2468 *err = CURLE_AGAIN;
2469 nread = -1;
2470 }
2471#endif
2472
2473 return nread;
2474}
2475
2476/*
2477 * =============== SFTP ===============
2478 */
2479
2480/*
2481 ***********************************************************************
2482 *
2483 * sftp_perform()
2484 *
2485 * This is the actual DO function for SFTP. Get a file/directory according to
2486 * the options previously setup.
2487 */
2488
2489static
2490CURLcode sftp_perform(struct Curl_easy *data,
2491 bool *connected,
2492 bool *dophase_done)
2493{
2494 CURLcode result = CURLE_OK;
2495
2496 DEBUGF(infof(data, "DO phase starts"));
2497
2498 *dophase_done = FALSE; /* not done yet */
2499
2500 /* start the first command in the DO phase */
2501 state(data, SSH_SFTP_QUOTE_INIT);
2502
2503 /* run the state-machine */
2504 result = myssh_multi_statemach(data, dophase_done);
2505
2506 *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2507
2508 if(*dophase_done) {
2509 DEBUGF(infof(data, "DO phase is complete"));
2510 }
2511
2512 return result;
2513}
2514
2515/* called from multi.c while DOing */
2516static CURLcode sftp_doing(struct Curl_easy *data,
2517 bool *dophase_done)
2518{
2519 CURLcode result = myssh_multi_statemach(data, dophase_done);
2520 if(*dophase_done) {
2521 DEBUGF(infof(data, "DO phase is complete"));
2522 }
2523 return result;
2524}
2525
2526/* BLOCKING, but the function is using the state machine so the only reason
2527 this is still blocking is that the multi interface code has no support for
2528 disconnecting operations that takes a while */
2529static CURLcode sftp_disconnect(struct Curl_easy *data,
2530 struct connectdata *conn,
2531 bool dead_connection)
2532{
2533 CURLcode result = CURLE_OK;
2534 (void) dead_connection;
2535
2536 DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2537
2538 if(conn->proto.sshc.ssh_session) {
2539 /* only if there is a session still around to use! */
2540 state(data, SSH_SFTP_SHUTDOWN);
2541 result = myssh_block_statemach(data, TRUE);
2542 }
2543
2544 DEBUGF(infof(data, "SSH DISCONNECT is done"));
2545
2546 return result;
2547
2548}
2549
2550static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2551 bool premature)
2552{
2553 struct connectdata *conn = data->conn;
2554 struct ssh_conn *sshc = &conn->proto.sshc;
2555
2556 if(!status) {
2557 /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2558 errors that could happen due to open file handles during POSTQUOTE
2559 operation */
2560 if(!premature && data->set.postquote && !conn->bits.retry)
2561 sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2562 state(data, SSH_SFTP_CLOSE);
2563 }
2564 return myssh_done(data, status);
2565}
2566
2567/* return number of sent bytes */
2568static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2569 const void *mem, size_t len, bool eos,
2570 CURLcode *err)
2571{
2572 ssize_t nwrite;
2573 struct connectdata *conn = data->conn;
2574 (void)sockindex;
2575 (void)eos;
2576
2577 /* limit the writes to the maximum specified in Section 3 of
2578 * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
2579 */
2580 if(len > 32768)
2581 len = 32768;
2582#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
2583 switch(conn->proto.sshc.sftp_send_state) {
2584 case 0:
2585 sftp_file_set_nonblocking(conn->proto.sshc.sftp_file);
2586 if(sftp_aio_begin_write(conn->proto.sshc.sftp_file, mem, len,
2587 &conn->proto.sshc.sftp_aio) == SSH_ERROR) {
2588 *err = CURLE_SEND_ERROR;
2589 return -1;
2590 }
2591 conn->proto.sshc.sftp_send_state = 1;
2592 FALLTHROUGH();
2593 case 1:
2594 nwrite = sftp_aio_wait_write(&conn->proto.sshc.sftp_aio);
2595 myssh_block2waitfor(conn, (nwrite == SSH_AGAIN) ? TRUE : FALSE);
2596 if(nwrite == SSH_AGAIN) {
2597 *err = CURLE_AGAIN;
2598 return 0;
2599 }
2600 else if(nwrite < 0) {
2601 *err = CURLE_SEND_ERROR;
2602 return -1;
2603 }
2604 if(conn->proto.sshc.sftp_aio) {
2605 sftp_aio_free(conn->proto.sshc.sftp_aio);
2606 conn->proto.sshc.sftp_aio = NULL;
2607 }
2608 conn->proto.sshc.sftp_send_state = 0;
2609 return nwrite;
2610 default:
2611 /* we never reach here */
2612 return -1;
2613 }
2614#else
2615 nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2616
2617 myssh_block2waitfor(conn, FALSE);
2618
2619#if 0 /* not returned by libssh on write */
2620 if(nwrite == SSH_AGAIN) {
2621 *err = CURLE_AGAIN;
2622 nwrite = 0;
2623 }
2624 else
2625#endif
2626 if(nwrite < 0) {
2627 *err = CURLE_SSH;
2628 nwrite = -1;
2629 }
2630
2631 return nwrite;
2632#endif
2633}
2634
2635/*
2636 * Return number of received (decrypted) bytes
2637 * or <0 on error
2638 */
2639static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2640 char *mem, size_t len, CURLcode *err)
2641{
2642 ssize_t nread;
2643 struct connectdata *conn = data->conn;
2644 (void)sockindex;
2645
2646 DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2647
2648 switch(conn->proto.sshc.sftp_recv_state) {
2649 case 0:
2650 conn->proto.sshc.sftp_file_index =
2651 sftp_async_read_begin(conn->proto.sshc.sftp_file,
2652 (uint32_t)len);
2653 if(conn->proto.sshc.sftp_file_index < 0) {
2654 *err = CURLE_RECV_ERROR;
2655 return -1;
2656 }
2657
2658 FALLTHROUGH();
2659 case 1:
2660 conn->proto.sshc.sftp_recv_state = 1;
2661
2662 nread = sftp_async_read(conn->proto.sshc.sftp_file,
2663 mem, (uint32_t)len,
2664 (uint32_t)conn->proto.sshc.sftp_file_index);
2665
2666 myssh_block2waitfor(conn, (nread == SSH_AGAIN));
2667
2668 if(nread == SSH_AGAIN) {
2669 *err = CURLE_AGAIN;
2670 return -1;
2671 }
2672 else if(nread < 0) {
2673 *err = CURLE_RECV_ERROR;
2674 return -1;
2675 }
2676
2677 conn->proto.sshc.sftp_recv_state = 0;
2678 return nread;
2679
2680 default:
2681 /* we never reach here */
2682 return -1;
2683 }
2684}
2685
2686static void sftp_quote(struct Curl_easy *data)
2687{
2688 const char *cp;
2689 struct connectdata *conn = data->conn;
2690 struct SSHPROTO *protop = data->req.p.ssh;
2691 struct ssh_conn *sshc = &conn->proto.sshc;
2692 CURLcode result;
2693
2694 /*
2695 * Support some of the "FTP" commands
2696 */
2697 char *cmd = sshc->quote_item->data;
2698 sshc->acceptfail = FALSE;
2699
2700 /* if a command starts with an asterisk, which a legal SFTP command never
2701 can, the command will be allowed to fail without it causing any
2702 aborts or cancels etc. It will cause libcurl to act as if the command
2703 is successful, whatever the server responds. */
2704
2705 if(cmd[0] == '*') {
2706 cmd++;
2707 sshc->acceptfail = TRUE;
2708 }
2709
2710 if(strcasecompare("pwd", cmd)) {
2711 /* output debug output if that is requested */
2712 char *tmp = aprintf("257 \"%s\" is current directory.\n",
2713 protop->path);
2714 if(!tmp) {
2715 sshc->actualcode = CURLE_OUT_OF_MEMORY;
2716 state(data, SSH_SFTP_CLOSE);
2717 sshc->nextstate = SSH_NO_STATE;
2718 return;
2719 }
2720 Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2721 Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2722
2723 /* this sends an FTP-like "header" to the header callback so that the
2724 current directory can be read very similar to how it is read when
2725 using ordinary FTP. */
2726 result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2727 free(tmp);
2728 if(result) {
2729 state(data, SSH_SFTP_CLOSE);
2730 sshc->nextstate = SSH_NO_STATE;
2731 sshc->actualcode = result;
2732 }
2733 else
2734 state(data, SSH_SFTP_NEXT_QUOTE);
2735 return;
2736 }
2737
2738 /*
2739 * the arguments following the command must be separated from the
2740 * command with a space so we can check for it unconditionally
2741 */
2742 cp = strchr(cmd, ' ');
2743 if(!cp) {
2744 failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2745 state(data, SSH_SFTP_CLOSE);
2746 sshc->nextstate = SSH_NO_STATE;
2747 sshc->actualcode = CURLE_QUOTE_ERROR;
2748 return;
2749 }
2750
2751 /*
2752 * also, every command takes at least one argument so we get that
2753 * first argument right now
2754 */
2755 result = Curl_get_pathname(&cp, &sshc->quote_path1, 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: Bad first parameter");
2761 state(data, SSH_SFTP_CLOSE);
2762 sshc->nextstate = SSH_NO_STATE;
2763 sshc->actualcode = result;
2764 return;
2765 }
2766
2767 /*
2768 * SFTP is a binary protocol, so we do not send text commands
2769 * to the server. Instead, we scan for commands used by
2770 * OpenSSH's sftp program and call the appropriate libssh
2771 * functions.
2772 */
2773 if(strncasecompare(cmd, "chgrp ", 6) ||
2774 strncasecompare(cmd, "chmod ", 6) ||
2775 strncasecompare(cmd, "chown ", 6) ||
2776 strncasecompare(cmd, "atime ", 6) ||
2777 strncasecompare(cmd, "mtime ", 6)) {
2778 /* attribute change */
2779
2780 /* sshc->quote_path1 contains the mode to set */
2781 /* get the destination */
2782 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2783 if(result) {
2784 if(result == CURLE_OUT_OF_MEMORY)
2785 failf(data, "Out of memory");
2786 else
2787 failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2788 "Bad second parameter");
2789 Curl_safefree(sshc->quote_path1);
2790 state(data, SSH_SFTP_CLOSE);
2791 sshc->nextstate = SSH_NO_STATE;
2792 sshc->actualcode = result;
2793 return;
2794 }
2795 sshc->quote_attrs = NULL;
2796 state(data, SSH_SFTP_QUOTE_STAT);
2797 return;
2798 }
2799 if(strncasecompare(cmd, "ln ", 3) ||
2800 strncasecompare(cmd, "symlink ", 8)) {
2801 /* symbolic linking */
2802 /* sshc->quote_path1 is the source */
2803 /* get the destination */
2804 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2805 if(result) {
2806 if(result == CURLE_OUT_OF_MEMORY)
2807 failf(data, "Out of memory");
2808 else
2809 failf(data, "Syntax error in ln/symlink: Bad second parameter");
2810 Curl_safefree(sshc->quote_path1);
2811 state(data, SSH_SFTP_CLOSE);
2812 sshc->nextstate = SSH_NO_STATE;
2813 sshc->actualcode = result;
2814 return;
2815 }
2816 state(data, SSH_SFTP_QUOTE_SYMLINK);
2817 return;
2818 }
2819 else if(strncasecompare(cmd, "mkdir ", 6)) {
2820 /* create dir */
2821 state(data, SSH_SFTP_QUOTE_MKDIR);
2822 return;
2823 }
2824 else if(strncasecompare(cmd, "rename ", 7)) {
2825 /* rename file */
2826 /* first param is the source path */
2827 /* second param is the dest. path */
2828 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2829 if(result) {
2830 if(result == CURLE_OUT_OF_MEMORY)
2831 failf(data, "Out of memory");
2832 else
2833 failf(data, "Syntax error in rename: Bad second parameter");
2834 Curl_safefree(sshc->quote_path1);
2835 state(data, SSH_SFTP_CLOSE);
2836 sshc->nextstate = SSH_NO_STATE;
2837 sshc->actualcode = result;
2838 return;
2839 }
2840 state(data, SSH_SFTP_QUOTE_RENAME);
2841 return;
2842 }
2843 else if(strncasecompare(cmd, "rmdir ", 6)) {
2844 /* delete dir */
2845 state(data, SSH_SFTP_QUOTE_RMDIR);
2846 return;
2847 }
2848 else if(strncasecompare(cmd, "rm ", 3)) {
2849 state(data, SSH_SFTP_QUOTE_UNLINK);
2850 return;
2851 }
2852#ifdef HAS_STATVFS_SUPPORT
2853 else if(strncasecompare(cmd, "statvfs ", 8)) {
2854 state(data, SSH_SFTP_QUOTE_STATVFS);
2855 return;
2856 }
2857#endif
2858
2859 failf(data, "Unknown SFTP command");
2860 Curl_safefree(sshc->quote_path1);
2861 Curl_safefree(sshc->quote_path2);
2862 state(data, SSH_SFTP_CLOSE);
2863 sshc->nextstate = SSH_NO_STATE;
2864 sshc->actualcode = CURLE_QUOTE_ERROR;
2865}
2866
2867static void sftp_quote_stat(struct Curl_easy *data)
2868{
2869 struct connectdata *conn = data->conn;
2870 struct ssh_conn *sshc = &conn->proto.sshc;
2871 char *cmd = sshc->quote_item->data;
2872 sshc->acceptfail = FALSE;
2873
2874 /* if a command starts with an asterisk, which a legal SFTP command never
2875 can, the command will be allowed to fail without it causing any
2876 aborts or cancels etc. It will cause libcurl to act as if the command
2877 is successful, whatever the server responds. */
2878
2879 if(cmd[0] == '*') {
2880 cmd++;
2881 sshc->acceptfail = TRUE;
2882 }
2883
2884 /* We read the file attributes, store them in sshc->quote_attrs
2885 * and modify them accordingly to command. Then we switch to
2886 * QUOTE_SETSTAT state to write new ones.
2887 */
2888
2889 if(sshc->quote_attrs)
2890 sftp_attributes_free(sshc->quote_attrs);
2891 sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2892 if(!sshc->quote_attrs) {
2893 Curl_safefree(sshc->quote_path1);
2894 Curl_safefree(sshc->quote_path2);
2895 failf(data, "Attempt to get SFTP stats failed: %d",
2896 sftp_get_error(sshc->sftp_session));
2897 state(data, SSH_SFTP_CLOSE);
2898 sshc->nextstate = SSH_NO_STATE;
2899 sshc->actualcode = CURLE_QUOTE_ERROR;
2900 return;
2901 }
2902
2903 /* Now set the new attributes... */
2904 if(strncasecompare(cmd, "chgrp", 5)) {
2905 sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2906 if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2907 !sshc->acceptfail) {
2908 Curl_safefree(sshc->quote_path1);
2909 Curl_safefree(sshc->quote_path2);
2910 failf(data, "Syntax error: chgrp gid not a number");
2911 state(data, SSH_SFTP_CLOSE);
2912 sshc->nextstate = SSH_NO_STATE;
2913 sshc->actualcode = CURLE_QUOTE_ERROR;
2914 return;
2915 }
2916 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2917 }
2918 else if(strncasecompare(cmd, "chmod", 5)) {
2919 mode_t perms;
2920 perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2921 /* permissions are octal */
2922 if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2923 Curl_safefree(sshc->quote_path1);
2924 Curl_safefree(sshc->quote_path2);
2925 failf(data, "Syntax error: chmod permissions not a number");
2926 state(data, SSH_SFTP_CLOSE);
2927 sshc->nextstate = SSH_NO_STATE;
2928 sshc->actualcode = CURLE_QUOTE_ERROR;
2929 return;
2930 }
2931 sshc->quote_attrs->permissions = perms;
2932 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2933 }
2934 else if(strncasecompare(cmd, "chown", 5)) {
2935 sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2936 if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2937 !sshc->acceptfail) {
2938 Curl_safefree(sshc->quote_path1);
2939 Curl_safefree(sshc->quote_path2);
2940 failf(data, "Syntax error: chown uid not a number");
2941 state(data, SSH_SFTP_CLOSE);
2942 sshc->nextstate = SSH_NO_STATE;
2943 sshc->actualcode = CURLE_QUOTE_ERROR;
2944 return;
2945 }
2946 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2947 }
2948 else if(strncasecompare(cmd, "atime", 5) ||
2949 strncasecompare(cmd, "mtime", 5)) {
2950 time_t date = Curl_getdate_capped(sshc->quote_path1);
2951 bool fail = FALSE;
2952 if(date == -1) {
2953 failf(data, "incorrect date format for %.*s", 5, cmd);
2954 fail = TRUE;
2955 }
2956#if SIZEOF_TIME_T > 4
2957 else if(date > 0xffffffff) {
2958 failf(data, "date overflow");
2959 fail = TRUE; /* avoid setting a capped time */
2960 }
2961#endif
2962 if(fail) {
2963 Curl_safefree(sshc->quote_path1);
2964 Curl_safefree(sshc->quote_path2);
2965 state(data, SSH_SFTP_CLOSE);
2966 sshc->nextstate = SSH_NO_STATE;
2967 sshc->actualcode = CURLE_QUOTE_ERROR;
2968 return;
2969 }
2970 if(strncasecompare(cmd, "atime", 5))
2971 sshc->quote_attrs->atime = (uint32_t)date;
2972 else /* mtime */
2973 sshc->quote_attrs->mtime = (uint32_t)date;
2974
2975 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2976 }
2977
2978 /* Now send the completed structure... */
2979 state(data, SSH_SFTP_QUOTE_SETSTAT);
2980 return;
2981}
2982
2983CURLcode Curl_ssh_init(void)
2984{
2985 if(ssh_init()) {
2986 DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2987 return CURLE_FAILED_INIT;
2988 }
2989 return CURLE_OK;
2990}
2991
2992void Curl_ssh_cleanup(void)
2993{
2994 (void)ssh_finalize();
2995}
2996
2997void Curl_ssh_version(char *buffer, size_t buflen)
2998{
2999 (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
3000}
3001
3002#endif /* USE_LIBSSH */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette