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