1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25#include "curl_setup.h" 26 27#ifdef USE_WOLFSSH 28 29#include <limits.h> 30 31#include <wolfssh/ssh.h> 32#include <wolfssh/wolfsftp.h> 33#include "urldata.h" 34#include "cfilters.h" 35#include "connect.h" 36#include "sendf.h" 37#include "progress.h" 38#include "curl_path.h" 39#include "strtoofft.h" 40#include "transfer.h" 41#include "speedcheck.h" 42#include "select.h" 43#include "multiif.h" 44#include "warnless.h" 45#include "strdup.h" 46 47/* The last 3 #include files should be in this order */ 48#include "curl_printf.h" 49#include "curl_memory.h" 50#include "memdebug.h" 51 52static CURLcode wssh_connect(struct Curl_easy *data, bool *done); 53static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done); 54static CURLcode wssh_do(struct Curl_easy *data, bool *done); 55#if 0 56static CURLcode wscp_done(struct Curl_easy *data, 57 CURLcode, bool premature); 58static CURLcode wscp_doing(struct Curl_easy *data, 59 bool *dophase_done); 60static CURLcode wscp_disconnect(struct Curl_easy *data, 61 struct connectdata *conn, 62 bool dead_connection); 63#endif 64static CURLcode wsftp_done(struct Curl_easy *data, 65 CURLcode, bool premature); 66static CURLcode wsftp_doing(struct Curl_easy *data, 67 bool *dophase_done); 68static CURLcode wsftp_disconnect(struct Curl_easy *data, 69 struct connectdata *conn, 70 bool dead); 71static int wssh_getsock(struct Curl_easy *data, 72 struct connectdata *conn, 73 curl_socket_t *sock); 74static CURLcode wssh_setup_connection(struct Curl_easy *data, 75 struct connectdata *conn); 76 77#if 0 78/* 79 * SCP protocol handler. 80 */ 81 82const struct Curl_handler Curl_handler_scp = { 83 "SCP", /* scheme */ 84 wssh_setup_connection, /* setup_connection */ 85 wssh_do, /* do_it */ 86 wscp_done, /* done */ 87 ZERO_NULL, /* do_more */ 88 wssh_connect, /* connect_it */ 89 wssh_multi_statemach, /* connecting */ 90 wscp_doing, /* doing */ 91 wssh_getsock, /* proto_getsock */ 92 wssh_getsock, /* doing_getsock */ 93 ZERO_NULL, /* domore_getsock */ 94 wssh_getsock, /* perform_getsock */ 95 wscp_disconnect, /* disconnect */ 96 ZERO_NULL, /* write_resp */ 97 ZERO_NULL, /* connection_check */ 98 ZERO_NULL, /* attach connection */ 99 PORT_SSH, /* defport */ 100 CURLPROTO_SCP, /* protocol */ 101 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION 102 | PROTOPT_NOURLQUERY /* flags */ 103}; 104 105#endif 106 107/* 108 * SFTP protocol handler. 109 */ 110 111const struct Curl_handler Curl_handler_sftp = { 112 "SFTP", /* scheme */ 113 wssh_setup_connection, /* setup_connection */ 114 wssh_do, /* do_it */ 115 wsftp_done, /* done */ 116 ZERO_NULL, /* do_more */ 117 wssh_connect, /* connect_it */ 118 wssh_multi_statemach, /* connecting */ 119 wsftp_doing, /* doing */ 120 wssh_getsock, /* proto_getsock */ 121 wssh_getsock, /* doing_getsock */ 122 ZERO_NULL, /* domore_getsock */ 123 wssh_getsock, /* perform_getsock */ 124 wsftp_disconnect, /* disconnect */ 125 ZERO_NULL, /* write_resp */ 126 ZERO_NULL, /* connection_check */ 127 ZERO_NULL, /* attach connection */ 128 PORT_SSH, /* defport */ 129 CURLPROTO_SFTP, /* protocol */ 130 CURLPROTO_SFTP, /* family */ 131 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION 132 | PROTOPT_NOURLQUERY /* flags */ 133}; 134 135/* 136 * SSH State machine related code 137 */ 138/* This is the ONLY way to change SSH state! */ 139static void state(struct Curl_easy *data, sshstate nowstate) 140{ 141 struct connectdata *conn = data->conn; 142 struct ssh_conn *sshc = &conn->proto.sshc; 143#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 144 /* for debug purposes */ 145 static const char * const names[] = { 146 "SSH_STOP", 147 "SSH_INIT", 148 "SSH_S_STARTUP", 149 "SSH_HOSTKEY", 150 "SSH_AUTHLIST", 151 "SSH_AUTH_PKEY_INIT", 152 "SSH_AUTH_PKEY", 153 "SSH_AUTH_PASS_INIT", 154 "SSH_AUTH_PASS", 155 "SSH_AUTH_AGENT_INIT", 156 "SSH_AUTH_AGENT_LIST", 157 "SSH_AUTH_AGENT", 158 "SSH_AUTH_HOST_INIT", 159 "SSH_AUTH_HOST", 160 "SSH_AUTH_KEY_INIT", 161 "SSH_AUTH_KEY", 162 "SSH_AUTH_GSSAPI", 163 "SSH_AUTH_DONE", 164 "SSH_SFTP_INIT", 165 "SSH_SFTP_REALPATH", 166 "SSH_SFTP_QUOTE_INIT", 167 "SSH_SFTP_POSTQUOTE_INIT", 168 "SSH_SFTP_QUOTE", 169 "SSH_SFTP_NEXT_QUOTE", 170 "SSH_SFTP_QUOTE_STAT", 171 "SSH_SFTP_QUOTE_SETSTAT", 172 "SSH_SFTP_QUOTE_SYMLINK", 173 "SSH_SFTP_QUOTE_MKDIR", 174 "SSH_SFTP_QUOTE_RENAME", 175 "SSH_SFTP_QUOTE_RMDIR", 176 "SSH_SFTP_QUOTE_UNLINK", 177 "SSH_SFTP_QUOTE_STATVFS", 178 "SSH_SFTP_GETINFO", 179 "SSH_SFTP_FILETIME", 180 "SSH_SFTP_TRANS_INIT", 181 "SSH_SFTP_UPLOAD_INIT", 182 "SSH_SFTP_CREATE_DIRS_INIT", 183 "SSH_SFTP_CREATE_DIRS", 184 "SSH_SFTP_CREATE_DIRS_MKDIR", 185 "SSH_SFTP_READDIR_INIT", 186 "SSH_SFTP_READDIR", 187 "SSH_SFTP_READDIR_LINK", 188 "SSH_SFTP_READDIR_BOTTOM", 189 "SSH_SFTP_READDIR_DONE", 190 "SSH_SFTP_DOWNLOAD_INIT", 191 "SSH_SFTP_DOWNLOAD_STAT", 192 "SSH_SFTP_CLOSE", 193 "SSH_SFTP_SHUTDOWN", 194 "SSH_SCP_TRANS_INIT", 195 "SSH_SCP_UPLOAD_INIT", 196 "SSH_SCP_DOWNLOAD_INIT", 197 "SSH_SCP_DOWNLOAD", 198 "SSH_SCP_DONE", 199 "SSH_SCP_SEND_EOF", 200 "SSH_SCP_WAIT_EOF", 201 "SSH_SCP_WAIT_CLOSE", 202 "SSH_SCP_CHANNEL_FREE", 203 "SSH_SESSION_DISCONNECT", 204 "SSH_SESSION_FREE", 205 "QUIT" 206 }; 207 208 /* a precaution to make sure the lists are in sync */ 209 DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST); 210 211 if(sshc->state != nowstate) { 212 infof(data, "wolfssh %p state change from %s to %s", 213 (void *)sshc, names[sshc->state], names[nowstate]); 214 } 215#endif 216 217 sshc->state = nowstate; 218} 219 220static ssize_t wscp_send(struct Curl_easy *data, int sockindex, 221 const void *mem, size_t len, CURLcode *err) 222{ 223 ssize_t nwrite = 0; 224 (void)data; 225 (void)sockindex; /* we only support SCP on the fixed known primary socket */ 226 (void)mem; 227 (void)len; 228 (void)err; 229 230 return nwrite; 231} 232 233static ssize_t wscp_recv(struct Curl_easy *data, int sockindex, 234 char *mem, size_t len, CURLcode *err) 235{ 236 ssize_t nread = 0; 237 (void)data; 238 (void)sockindex; /* we only support SCP on the fixed known primary socket */ 239 (void)mem; 240 (void)len; 241 (void)err; 242 243 return nread; 244} 245 246/* return number of sent bytes */ 247static ssize_t wsftp_send(struct Curl_easy *data, int sockindex, 248 const void *mem, size_t len, CURLcode *err) 249{ 250 struct connectdata *conn = data->conn; 251 struct ssh_conn *sshc = &conn->proto.sshc; 252 word32 offset[2]; 253 int rc; 254 (void)sockindex; 255 256 offset[0] = (word32)sshc->offset&0xFFFFFFFF; 257 offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; 258 259 rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle, 260 sshc->handleSz, 261 &offset[0], 262 (byte *)mem, (word32)len); 263 264 if(rc == WS_FATAL_ERROR) 265 rc = wolfSSH_get_error(sshc->ssh_session); 266 if(rc == WS_WANT_READ) { 267 conn->waitfor = KEEP_RECV; 268 *err = CURLE_AGAIN; 269 return -1; 270 } 271 else if(rc == WS_WANT_WRITE) { 272 conn->waitfor = KEEP_SEND; 273 *err = CURLE_AGAIN; 274 return -1; 275 } 276 if(rc < 0) { 277 failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc); 278 return -1; 279 } 280 DEBUGASSERT(rc == (int)len); 281 infof(data, "sent %zu bytes SFTP from offset %" CURL_FORMAT_CURL_OFF_T, 282 len, sshc->offset); 283 sshc->offset += len; 284 return (ssize_t)rc; 285} 286 287/* 288 * Return number of received (decrypted) bytes 289 * or <0 on error 290 */ 291static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex, 292 char *mem, size_t len, CURLcode *err) 293{ 294 int rc; 295 struct connectdata *conn = data->conn; 296 struct ssh_conn *sshc = &conn->proto.sshc; 297 word32 offset[2]; 298 (void)sockindex; 299 300 offset[0] = (word32)sshc->offset&0xFFFFFFFF; 301 offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; 302 303 rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle, 304 sshc->handleSz, 305 &offset[0], 306 (byte *)mem, (word32)len); 307 if(rc == WS_FATAL_ERROR) 308 rc = wolfSSH_get_error(sshc->ssh_session); 309 if(rc == WS_WANT_READ) { 310 conn->waitfor = KEEP_RECV; 311 *err = CURLE_AGAIN; 312 return -1; 313 } 314 else if(rc == WS_WANT_WRITE) { 315 conn->waitfor = KEEP_SEND; 316 *err = CURLE_AGAIN; 317 return -1; 318 } 319 320 DEBUGASSERT(rc <= (int)len); 321 322 if(rc < 0) { 323 failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc); 324 return -1; 325 } 326 sshc->offset += len; 327 328 return (ssize_t)rc; 329} 330 331/* 332 * SSH setup and connection 333 */ 334static CURLcode wssh_setup_connection(struct Curl_easy *data, 335 struct connectdata *conn) 336{ 337 struct SSHPROTO *ssh; 338 (void)conn; 339 340 data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); 341 if(!ssh) 342 return CURLE_OUT_OF_MEMORY; 343 344 return CURLE_OK; 345} 346 347static int userauth(byte authtype, 348 WS_UserAuthData* authdata, 349 void *ctx) 350{ 351 struct Curl_easy *data = ctx; 352 DEBUGF(infof(data, "wolfssh callback: type %s", 353 authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" : 354 "PUBLICCKEY")); 355 if(authtype == WOLFSSH_USERAUTH_PASSWORD) { 356 authdata->sf.password.password = (byte *)data->conn->passwd; 357 authdata->sf.password.passwordSz = (word32) strlen(data->conn->passwd); 358 } 359 360 return 0; 361} 362 363static CURLcode wssh_connect(struct Curl_easy *data, bool *done) 364{ 365 struct connectdata *conn = data->conn; 366 struct ssh_conn *sshc; 367 curl_socket_t sock = conn->sock[FIRSTSOCKET]; 368 int rc; 369 370 /* initialize per-handle data if not already */ 371 if(!data->req.p.ssh) 372 wssh_setup_connection(data, conn); 373 374 /* We default to persistent connections. We set this already in this connect 375 function to make the reuse checks properly be able to check this bit. */ 376 connkeep(conn, "SSH default"); 377 378 if(conn->handler->protocol & CURLPROTO_SCP) { 379 conn->recv[FIRSTSOCKET] = wscp_recv; 380 conn->send[FIRSTSOCKET] = wscp_send; 381 } 382 else { 383 conn->recv[FIRSTSOCKET] = wsftp_recv; 384 conn->send[FIRSTSOCKET] = wsftp_send; 385 } 386 sshc = &conn->proto.sshc; 387 sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); 388 if(!sshc->ctx) { 389 failf(data, "No wolfSSH context"); 390 goto error; 391 } 392 393 sshc->ssh_session = wolfSSH_new(sshc->ctx); 394 if(!sshc->ssh_session) { 395 failf(data, "No wolfSSH session"); 396 goto error; 397 } 398 399 rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user); 400 if(rc != WS_SUCCESS) { 401 failf(data, "wolfSSH failed to set user name"); 402 goto error; 403 } 404 405 /* set callback for authentication */ 406 wolfSSH_SetUserAuth(sshc->ctx, userauth); 407 wolfSSH_SetUserAuthCtx(sshc->ssh_session, data); 408 409 rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock); 410 if(rc) { 411 failf(data, "wolfSSH failed to set socket"); 412 goto error; 413 } 414 415#if 0 416 wolfSSH_Debugging_ON(); 417#endif 418 419 *done = TRUE; 420 if(conn->handler->protocol & CURLPROTO_SCP) 421 state(data, SSH_INIT); 422 else 423 state(data, SSH_SFTP_INIT); 424 425 return wssh_multi_statemach(data, done); 426error: 427 wolfSSH_free(sshc->ssh_session); 428 wolfSSH_CTX_free(sshc->ctx); 429 return CURLE_FAILED_INIT; 430} 431 432/* 433 * wssh_statemach_act() runs the SSH state machine as far as it can without 434 * blocking and without reaching the end. The data the pointer 'block' points 435 * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it 436 * wants to be called again when the socket is ready 437 */ 438 439static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) 440{ 441 CURLcode result = CURLE_OK; 442 struct connectdata *conn = data->conn; 443 struct ssh_conn *sshc = &conn->proto.sshc; 444 struct SSHPROTO *sftp_scp = data->req.p.ssh; 445 WS_SFTPNAME *name; 446 int rc = 0; 447 *block = FALSE; /* we're not blocking by default */ 448 449 do { 450 switch(sshc->state) { 451 case SSH_INIT: 452 state(data, SSH_S_STARTUP); 453 break; 454 455 case SSH_S_STARTUP: 456 rc = wolfSSH_connect(sshc->ssh_session); 457 if(rc != WS_SUCCESS) 458 rc = wolfSSH_get_error(sshc->ssh_session); 459 if(rc == WS_WANT_READ) { 460 *block = TRUE; 461 conn->waitfor = KEEP_RECV; 462 return CURLE_OK; 463 } 464 else if(rc == WS_WANT_WRITE) { 465 *block = TRUE; 466 conn->waitfor = KEEP_SEND; 467 return CURLE_OK; 468 } 469 else if(rc != WS_SUCCESS) { 470 state(data, SSH_STOP); 471 return CURLE_SSH; 472 } 473 infof(data, "wolfssh connected"); 474 state(data, SSH_STOP); 475 break; 476 case SSH_STOP: 477 break; 478 479 case SSH_SFTP_INIT: 480 rc = wolfSSH_SFTP_connect(sshc->ssh_session); 481 if(rc != WS_SUCCESS) 482 rc = wolfSSH_get_error(sshc->ssh_session); 483 if(rc == WS_WANT_READ) { 484 *block = TRUE; 485 conn->waitfor = KEEP_RECV; 486 return CURLE_OK; 487 } 488 else if(rc == WS_WANT_WRITE) { 489 *block = TRUE; 490 conn->waitfor = KEEP_SEND; 491 return CURLE_OK; 492 } 493 else if(rc == WS_SUCCESS) { 494 infof(data, "wolfssh SFTP connected"); 495 state(data, SSH_SFTP_REALPATH); 496 } 497 else { 498 failf(data, "wolfssh SFTP connect error %d", rc); 499 return CURLE_SSH; 500 } 501 break; 502 case SSH_SFTP_REALPATH: 503 name = wolfSSH_SFTP_RealPath(sshc->ssh_session, (char *)"."); 504 rc = wolfSSH_get_error(sshc->ssh_session); 505 if(rc == WS_WANT_READ) { 506 *block = TRUE; 507 conn->waitfor = KEEP_RECV; 508 return CURLE_OK; 509 } 510 else if(rc == WS_WANT_WRITE) { 511 *block = TRUE; 512 conn->waitfor = KEEP_SEND; 513 return CURLE_OK; 514 } 515 else if(name && (rc == WS_SUCCESS)) { 516 sshc->homedir = Curl_memdup0(name->fName, name->fSz); 517 if(!sshc->homedir) 518 sshc->actualcode = CURLE_OUT_OF_MEMORY; 519 wolfSSH_SFTPNAME_list_free(name); 520 state(data, SSH_STOP); 521 return CURLE_OK; 522 } 523 failf(data, "wolfssh SFTP realpath %d", rc); 524 return CURLE_SSH; 525 526 case SSH_SFTP_QUOTE_INIT: 527 result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path); 528 if(result) { 529 sshc->actualcode = result; 530 state(data, SSH_STOP); 531 break; 532 } 533 534 if(data->set.quote) { 535 infof(data, "Sending quote commands"); 536 sshc->quote_item = data->set.quote; 537 state(data, SSH_SFTP_QUOTE); 538 } 539 else { 540 state(data, SSH_SFTP_GETINFO); 541 } 542 break; 543 case SSH_SFTP_GETINFO: 544 if(data->set.get_filetime) { 545 state(data, SSH_SFTP_FILETIME); 546 } 547 else { 548 state(data, SSH_SFTP_TRANS_INIT); 549 } 550 break; 551 case SSH_SFTP_TRANS_INIT: 552 if(data->state.upload) 553 state(data, SSH_SFTP_UPLOAD_INIT); 554 else { 555 if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') 556 state(data, SSH_SFTP_READDIR_INIT); 557 else 558 state(data, SSH_SFTP_DOWNLOAD_INIT); 559 } 560 break; 561 case SSH_SFTP_UPLOAD_INIT: { 562 word32 flags; 563 WS_SFTP_FILEATRB createattrs; 564 if(data->state.resume_from) { 565 WS_SFTP_FILEATRB attrs; 566 if(data->state.resume_from < 0) { 567 rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, 568 &attrs); 569 if(rc != WS_SUCCESS) 570 break; 571 572 if(rc) { 573 data->state.resume_from = 0; 574 } 575 else { 576 curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; 577 if(size < 0) { 578 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); 579 return CURLE_BAD_DOWNLOAD_RESUME; 580 } 581 data->state.resume_from = size; 582 } 583 } 584 } 585 586 if(data->set.remote_append) 587 /* Try to open for append, but create if nonexisting */ 588 flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND; 589 else if(data->state.resume_from > 0) 590 /* If we have restart position then open for append */ 591 flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND; 592 else 593 /* Clear file before writing (normal behavior) */ 594 flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC; 595 596 memset(&createattrs, 0, sizeof(createattrs)); 597 createattrs.per = (word32)data->set.new_file_perms; 598 sshc->handleSz = sizeof(sshc->handle); 599 rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, 600 flags, &createattrs, 601 sshc->handle, &sshc->handleSz); 602 if(rc == WS_FATAL_ERROR) 603 rc = wolfSSH_get_error(sshc->ssh_session); 604 if(rc == WS_WANT_READ) { 605 *block = TRUE; 606 conn->waitfor = KEEP_RECV; 607 return CURLE_OK; 608 } 609 else if(rc == WS_WANT_WRITE) { 610 *block = TRUE; 611 conn->waitfor = KEEP_SEND; 612 return CURLE_OK; 613 } 614 else if(rc == WS_SUCCESS) { 615 infof(data, "wolfssh SFTP open succeeded"); 616 } 617 else { 618 failf(data, "wolfssh SFTP upload open failed: %d", rc); 619 return CURLE_SSH; 620 } 621 state(data, SSH_SFTP_DOWNLOAD_STAT); 622 623 /* If we have a restart point then we need to seek to the correct 624 position. */ 625 if(data->state.resume_from > 0) { 626 /* Let's read off the proper amount of bytes from the input. */ 627 int seekerr = CURL_SEEKFUNC_OK; 628 if(conn->seek_func) { 629 Curl_set_in_callback(data, true); 630 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, 631 SEEK_SET); 632 Curl_set_in_callback(data, false); 633 } 634 635 if(seekerr != CURL_SEEKFUNC_OK) { 636 curl_off_t passed = 0; 637 638 if(seekerr != CURL_SEEKFUNC_CANTSEEK) { 639 failf(data, "Could not seek stream"); 640 return CURLE_FTP_COULDNT_USE_REST; 641 } 642 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ 643 do { 644 char scratch[4*1024]; 645 size_t readthisamountnow = 646 (data->state.resume_from - passed > 647 (curl_off_t)sizeof(scratch)) ? 648 sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); 649 650 size_t actuallyread; 651 Curl_set_in_callback(data, true); 652 actuallyread = data->state.fread_func(scratch, 1, 653 readthisamountnow, 654 data->state.in); 655 Curl_set_in_callback(data, false); 656 657 passed += actuallyread; 658 if((actuallyread == 0) || (actuallyread > readthisamountnow)) { 659 /* this checks for greater-than only to make sure that the 660 CURL_READFUNC_ABORT return code still aborts */ 661 failf(data, "Failed to read data"); 662 return CURLE_FTP_COULDNT_USE_REST; 663 } 664 } while(passed < data->state.resume_from); 665 } 666 667 /* now, decrease the size of the read */ 668 if(data->state.infilesize > 0) { 669 data->state.infilesize -= data->state.resume_from; 670 data->req.size = data->state.infilesize; 671 Curl_pgrsSetUploadSize(data, data->state.infilesize); 672 } 673 674 sshc->offset += data->state.resume_from; 675 } 676 if(data->state.infilesize > 0) { 677 data->req.size = data->state.infilesize; 678 Curl_pgrsSetUploadSize(data, data->state.infilesize); 679 } 680 /* upload data */ 681 Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); 682 683 /* not set by Curl_setup_transfer to preserve keepon bits */ 684 conn->sockfd = conn->writesockfd; 685 686 if(result) { 687 state(data, SSH_SFTP_CLOSE); 688 sshc->actualcode = result; 689 } 690 else { 691 /* store this original bitmask setup to use later on if we can't 692 figure out a "real" bitmask */ 693 sshc->orig_waitfor = data->req.keepon; 694 695 /* we want to use the _sending_ function even when the socket turns 696 out readable as the underlying libssh2 sftp send function will deal 697 with both accordingly */ 698 data->state.select_bits = CURL_CSELECT_OUT; 699 700 /* since we don't really wait for anything at this point, we want the 701 state machine to move on as soon as possible so we set a very short 702 timeout here */ 703 Curl_expire(data, 0, EXPIRE_RUN_NOW); 704 705 state(data, SSH_STOP); 706 } 707 break; 708 } 709 case SSH_SFTP_DOWNLOAD_INIT: 710 sshc->handleSz = sizeof(sshc->handle); 711 rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, 712 WOLFSSH_FXF_READ, NULL, 713 sshc->handle, &sshc->handleSz); 714 if(rc == WS_FATAL_ERROR) 715 rc = wolfSSH_get_error(sshc->ssh_session); 716 if(rc == WS_WANT_READ) { 717 *block = TRUE; 718 conn->waitfor = KEEP_RECV; 719 return CURLE_OK; 720 } 721 else if(rc == WS_WANT_WRITE) { 722 *block = TRUE; 723 conn->waitfor = KEEP_SEND; 724 return CURLE_OK; 725 } 726 else if(rc == WS_SUCCESS) { 727 infof(data, "wolfssh SFTP open succeeded"); 728 state(data, SSH_SFTP_DOWNLOAD_STAT); 729 return CURLE_OK; 730 } 731 732 failf(data, "wolfssh SFTP open failed: %d", rc); 733 return CURLE_SSH; 734 735 case SSH_SFTP_DOWNLOAD_STAT: { 736 WS_SFTP_FILEATRB attrs; 737 curl_off_t size; 738 739 rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs); 740 if(rc == WS_FATAL_ERROR) 741 rc = wolfSSH_get_error(sshc->ssh_session); 742 if(rc == WS_WANT_READ) { 743 *block = TRUE; 744 conn->waitfor = KEEP_RECV; 745 return CURLE_OK; 746 } 747 else if(rc == WS_WANT_WRITE) { 748 *block = TRUE; 749 conn->waitfor = KEEP_SEND; 750 return CURLE_OK; 751 } 752 else if(rc == WS_SUCCESS) { 753 infof(data, "wolfssh STAT succeeded"); 754 } 755 else { 756 failf(data, "wolfssh SFTP open failed: %d", rc); 757 data->req.size = -1; 758 data->req.maxdownload = -1; 759 Curl_pgrsSetDownloadSize(data, -1); 760 return CURLE_SSH; 761 } 762 763 size = ((curl_off_t)attrs.sz[1] <<32) | attrs.sz[0]; 764 765 data->req.size = size; 766 data->req.maxdownload = size; 767 Curl_pgrsSetDownloadSize(data, size); 768 769 infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes", size); 770 771 /* We cannot seek with wolfSSH so resuming and range requests are not 772 possible */ 773 if(data->state.use_range || data->state.resume_from) { 774 infof(data, "wolfSSH cannot do range/seek on SFTP"); 775 return CURLE_BAD_DOWNLOAD_RESUME; 776 } 777 778 /* Setup the actual download */ 779 if(data->req.size == 0) { 780 /* no data to transfer */ 781 Curl_setup_transfer(data, -1, -1, FALSE, -1); 782 infof(data, "File already completely downloaded"); 783 state(data, SSH_STOP); 784 break; 785 } 786 Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1); 787 788 /* not set by Curl_setup_transfer to preserve keepon bits */ 789 conn->writesockfd = conn->sockfd; 790 791 /* we want to use the _receiving_ function even when the socket turns 792 out writableable as the underlying libssh2 recv function will deal 793 with both accordingly */ 794 data->state.select_bits = CURL_CSELECT_IN; 795 796 if(result) { 797 /* this should never occur; the close state should be entered 798 at the time the error occurs */ 799 state(data, SSH_SFTP_CLOSE); 800 sshc->actualcode = result; 801 } 802 else { 803 state(data, SSH_STOP); 804 } 805 break; 806 } 807 case SSH_SFTP_CLOSE: 808 if(sshc->handleSz) 809 rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle, 810 sshc->handleSz); 811 else 812 rc = WS_SUCCESS; /* directory listing */ 813 if(rc == WS_WANT_READ) { 814 *block = TRUE; 815 conn->waitfor = KEEP_RECV; 816 return CURLE_OK; 817 } 818 else if(rc == WS_WANT_WRITE) { 819 *block = TRUE; 820 conn->waitfor = KEEP_SEND; 821 return CURLE_OK; 822 } 823 else if(rc == WS_SUCCESS) { 824 state(data, SSH_STOP); 825 return CURLE_OK; 826 } 827 828 failf(data, "wolfssh SFTP CLOSE failed: %d", rc); 829 return CURLE_SSH; 830 831 case SSH_SFTP_READDIR_INIT: 832 Curl_pgrsSetDownloadSize(data, -1); 833 if(data->req.no_body) { 834 state(data, SSH_STOP); 835 break; 836 } 837 state(data, SSH_SFTP_READDIR); 838 break; 839 840 case SSH_SFTP_READDIR: 841 name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path); 842 if(!name) 843 rc = wolfSSH_get_error(sshc->ssh_session); 844 else 845 rc = WS_SUCCESS; 846 847 if(rc == WS_WANT_READ) { 848 *block = TRUE; 849 conn->waitfor = KEEP_RECV; 850 return CURLE_OK; 851 } 852 else if(rc == WS_WANT_WRITE) { 853 *block = TRUE; 854 conn->waitfor = KEEP_SEND; 855 return CURLE_OK; 856 } 857 else if(name && (rc == WS_SUCCESS)) { 858 WS_SFTPNAME *origname = name; 859 result = CURLE_OK; 860 while(name) { 861 char *line = aprintf("%s\n", 862 data->set.list_only ? 863 name->fName : name->lName); 864 if(!line) { 865 state(data, SSH_SFTP_CLOSE); 866 sshc->actualcode = CURLE_OUT_OF_MEMORY; 867 break; 868 } 869 result = Curl_client_write(data, CLIENTWRITE_BODY, 870 line, strlen(line)); 871 free(line); 872 if(result) { 873 sshc->actualcode = result; 874 break; 875 } 876 name = name->next; 877 } 878 wolfSSH_SFTPNAME_list_free(origname); 879 state(data, SSH_STOP); 880 return result; 881 } 882 failf(data, "wolfssh SFTP ls failed: %d", rc); 883 return CURLE_SSH; 884 885 case SSH_SFTP_SHUTDOWN: 886 Curl_safefree(sshc->homedir); 887 wolfSSH_free(sshc->ssh_session); 888 wolfSSH_CTX_free(sshc->ctx); 889 state(data, SSH_STOP); 890 return CURLE_OK; 891 default: 892 break; 893 } 894 } while(!rc && (sshc->state != SSH_STOP)); 895 return result; 896} 897 898/* called repeatedly until done from multi.c */ 899static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done) 900{ 901 struct connectdata *conn = data->conn; 902 struct ssh_conn *sshc = &conn->proto.sshc; 903 CURLcode result = CURLE_OK; 904 bool block; /* we store the status and use that to provide a ssh_getsock() 905 implementation */ 906 do { 907 result = wssh_statemach_act(data, &block); 908 *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; 909 /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then 910 try again */ 911 if(*done) { 912 DEBUGF(infof(data, "wssh_statemach_act says DONE")); 913 } 914 } while(!result && !*done && !block); 915 916 return result; 917} 918 919static 920CURLcode wscp_perform(struct Curl_easy *data, 921 bool *connected, 922 bool *dophase_done) 923{ 924 (void)data; 925 (void)connected; 926 (void)dophase_done; 927 return CURLE_OK; 928} 929 930static 931CURLcode wsftp_perform(struct Curl_easy *data, 932 bool *connected, 933 bool *dophase_done) 934{ 935 CURLcode result = CURLE_OK; 936 937 DEBUGF(infof(data, "DO phase starts")); 938 939 *dophase_done = FALSE; /* not done yet */ 940 941 /* start the first command in the DO phase */ 942 state(data, SSH_SFTP_QUOTE_INIT); 943 944 /* run the state-machine */ 945 result = wssh_multi_statemach(data, dophase_done); 946 947 *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); 948 949 if(*dophase_done) { 950 DEBUGF(infof(data, "DO phase is complete")); 951 } 952 953 return result; 954} 955 956/* 957 * The DO function is generic for both protocols. 958 */ 959static CURLcode wssh_do(struct Curl_easy *data, bool *done) 960{ 961 CURLcode result; 962 bool connected = 0; 963 struct connectdata *conn = data->conn; 964 struct ssh_conn *sshc = &conn->proto.sshc; 965 966 *done = FALSE; /* default to false */ 967 data->req.size = -1; /* make sure this is unknown at this point */ 968 sshc->actualcode = CURLE_OK; /* reset error code */ 969 sshc->secondCreateDirs = 0; /* reset the create dir attempt state 970 variable */ 971 972 Curl_pgrsSetUploadCounter(data, 0); 973 Curl_pgrsSetDownloadCounter(data, 0); 974 Curl_pgrsSetUploadSize(data, -1); 975 Curl_pgrsSetDownloadSize(data, -1); 976 977 if(conn->handler->protocol & CURLPROTO_SCP) 978 result = wscp_perform(data, &connected, done); 979 else 980 result = wsftp_perform(data, &connected, done); 981 982 return result; 983} 984 985static CURLcode wssh_block_statemach(struct Curl_easy *data, 986 bool disconnect) 987{ 988 struct connectdata *conn = data->conn; 989 struct ssh_conn *sshc = &conn->proto.sshc; 990 CURLcode result = CURLE_OK; 991 992 while((sshc->state != SSH_STOP) && !result) { 993 bool block; 994 timediff_t left = 1000; 995 struct curltime now = Curl_now(); 996 997 result = wssh_statemach_act(data, &block); 998 if(result) 999 break; 1000 1001 if(!disconnect) { 1002 if(Curl_pgrsUpdate(data)) 1003 return CURLE_ABORTED_BY_CALLBACK; 1004 1005 result = Curl_speedcheck(data, now); 1006 if(result) 1007 break; 1008 1009 left = Curl_timeleft(data, NULL, FALSE); 1010 if(left < 0) { 1011 failf(data, "Operation timed out"); 1012 return CURLE_OPERATION_TIMEDOUT; 1013 } 1014 } 1015 1016 if(!result) { 1017 int dir = conn->waitfor; 1018 curl_socket_t sock = conn->sock[FIRSTSOCKET]; 1019 curl_socket_t fd_read = CURL_SOCKET_BAD; 1020 curl_socket_t fd_write = CURL_SOCKET_BAD; 1021 if(dir == KEEP_RECV) 1022 fd_read = sock; 1023 else if(dir == KEEP_SEND) 1024 fd_write = sock; 1025 1026 /* wait for the socket to become ready */ 1027 (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 1028 left>1000?1000:left); /* ignore result */ 1029 } 1030 } 1031 1032 return result; 1033} 1034 1035/* generic done function for both SCP and SFTP called from their specific 1036 done functions */ 1037static CURLcode wssh_done(struct Curl_easy *data, CURLcode status) 1038{ 1039 CURLcode result = CURLE_OK; 1040 struct SSHPROTO *sftp_scp = data->req.p.ssh; 1041 1042 if(!status) { 1043 /* run the state-machine */ 1044 result = wssh_block_statemach(data, FALSE); 1045 } 1046 else 1047 result = status; 1048 1049 if(sftp_scp) 1050 Curl_safefree(sftp_scp->path); 1051 if(Curl_pgrsDone(data)) 1052 return CURLE_ABORTED_BY_CALLBACK; 1053 1054 data->req.keepon = 0; /* clear all bits */ 1055 return result; 1056} 1057 1058#if 0 1059static CURLcode wscp_done(struct Curl_easy *data, 1060 CURLcode code, bool premature) 1061{ 1062 CURLcode result = CURLE_OK; 1063 (void)conn; 1064 (void)code; 1065 (void)premature; 1066 1067 return result; 1068} 1069 1070static CURLcode wscp_doing(struct Curl_easy *data, 1071 bool *dophase_done) 1072{ 1073 CURLcode result = CURLE_OK; 1074 (void)conn; 1075 (void)dophase_done; 1076 1077 return result; 1078} 1079 1080static CURLcode wscp_disconnect(struct Curl_easy *data, 1081 struct connectdata *conn, bool dead_connection) 1082{ 1083 CURLcode result = CURLE_OK; 1084 (void)data; 1085 (void)conn; 1086 (void)dead_connection; 1087 1088 return result; 1089} 1090#endif 1091 1092static CURLcode wsftp_done(struct Curl_easy *data, 1093 CURLcode code, bool premature) 1094{ 1095 (void)premature; 1096 state(data, SSH_SFTP_CLOSE); 1097 1098 return wssh_done(data, code); 1099} 1100 1101static CURLcode wsftp_doing(struct Curl_easy *data, 1102 bool *dophase_done) 1103{ 1104 CURLcode result = wssh_multi_statemach(data, dophase_done); 1105 1106 if(*dophase_done) { 1107 DEBUGF(infof(data, "DO phase is complete")); 1108 } 1109 return result; 1110} 1111 1112static CURLcode wsftp_disconnect(struct Curl_easy *data, 1113 struct connectdata *conn, 1114 bool dead) 1115{ 1116 CURLcode result = CURLE_OK; 1117 (void)dead; 1118 1119 DEBUGF(infof(data, "SSH DISCONNECT starts now")); 1120 1121 if(conn->proto.sshc.ssh_session) { 1122 /* only if there's a session still around to use! */ 1123 state(data, SSH_SFTP_SHUTDOWN); 1124 result = wssh_block_statemach(data, TRUE); 1125 } 1126 1127 DEBUGF(infof(data, "SSH DISCONNECT is done")); 1128 return result; 1129} 1130 1131static int wssh_getsock(struct Curl_easy *data, 1132 struct connectdata *conn, 1133 curl_socket_t *sock) 1134{ 1135 int bitmap = GETSOCK_BLANK; 1136 int dir = conn->waitfor; 1137 (void)data; 1138 sock[0] = conn->sock[FIRSTSOCKET]; 1139 1140 if(dir == KEEP_RECV) 1141 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); 1142 else if(dir == KEEP_SEND) 1143 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); 1144 1145 return bitmap; 1146} 1147 1148void Curl_ssh_version(char *buffer, size_t buflen) 1149{ 1150 (void)msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING); 1151} 1152 1153CURLcode Curl_ssh_init(void) 1154{ 1155 if(WS_SUCCESS != wolfSSH_Init()) { 1156 DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n")); 1157 return CURLE_FAILED_INIT; 1158 } 1159 1160 return CURLE_OK; 1161} 1162void Curl_ssh_cleanup(void) 1163{ 1164 (void)wolfSSH_Cleanup(); 1165} 1166 1167#endif /* USE_WOLFSSH */ 1168