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