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