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