sftp-client.c revision 147001
1/* 2 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* XXX: memleaks */ 18/* XXX: signed vs unsigned */ 19/* XXX: remove all logging, only return status codes */ 20/* XXX: copy between two remote sites */ 21 22#include "includes.h" 23RCSID("$OpenBSD: sftp-client.c,v 1.53 2005/03/10 22:01:05 deraadt Exp $"); 24 25#include "openbsd-compat/sys-queue.h" 26 27#include "buffer.h" 28#include "bufaux.h" 29#include "getput.h" 30#include "xmalloc.h" 31#include "log.h" 32#include "atomicio.h" 33#include "progressmeter.h" 34 35#include "sftp.h" 36#include "sftp-common.h" 37#include "sftp-client.h" 38 39extern volatile sig_atomic_t interrupted; 40extern int showprogress; 41 42/* Minimum amount of data to read at at time */ 43#define MIN_READ_SIZE 512 44 45/* Maximum packet size */ 46#define MAX_MSG_LENGTH (256 * 1024) 47 48struct sftp_conn { 49 int fd_in; 50 int fd_out; 51 u_int transfer_buflen; 52 u_int num_requests; 53 u_int version; 54 u_int msg_id; 55}; 56 57static void 58send_msg(int fd, Buffer *m) 59{ 60 u_char mlen[4]; 61 62 if (buffer_len(m) > MAX_MSG_LENGTH) 63 fatal("Outbound message too long %u", buffer_len(m)); 64 65 /* Send length first */ 66 PUT_32BIT(mlen, buffer_len(m)); 67 if (atomicio(vwrite, fd, mlen, sizeof(mlen)) <= 0) 68 fatal("Couldn't send packet: %s", strerror(errno)); 69 70 if (atomicio(vwrite, fd, buffer_ptr(m), buffer_len(m)) <= 0) 71 fatal("Couldn't send packet: %s", strerror(errno)); 72 73 buffer_clear(m); 74} 75 76static void 77get_msg(int fd, Buffer *m) 78{ 79 ssize_t len; 80 u_int msg_len; 81 82 buffer_append_space(m, 4); 83 len = atomicio(read, fd, buffer_ptr(m), 4); 84 if (len == 0) 85 fatal("Connection closed"); 86 else if (len == -1) 87 fatal("Couldn't read packet: %s", strerror(errno)); 88 89 msg_len = buffer_get_int(m); 90 if (msg_len > MAX_MSG_LENGTH) 91 fatal("Received message too long %u", msg_len); 92 93 buffer_append_space(m, msg_len); 94 len = atomicio(read, fd, buffer_ptr(m), msg_len); 95 if (len == 0) 96 fatal("Connection closed"); 97 else if (len == -1) 98 fatal("Read packet: %s", strerror(errno)); 99} 100 101static void 102send_string_request(int fd, u_int id, u_int code, char *s, 103 u_int len) 104{ 105 Buffer msg; 106 107 buffer_init(&msg); 108 buffer_put_char(&msg, code); 109 buffer_put_int(&msg, id); 110 buffer_put_string(&msg, s, len); 111 send_msg(fd, &msg); 112 debug3("Sent message fd %d T:%u I:%u", fd, code, id); 113 buffer_free(&msg); 114} 115 116static void 117send_string_attrs_request(int fd, u_int id, u_int code, char *s, 118 u_int len, Attrib *a) 119{ 120 Buffer msg; 121 122 buffer_init(&msg); 123 buffer_put_char(&msg, code); 124 buffer_put_int(&msg, id); 125 buffer_put_string(&msg, s, len); 126 encode_attrib(&msg, a); 127 send_msg(fd, &msg); 128 debug3("Sent message fd %d T:%u I:%u", fd, code, id); 129 buffer_free(&msg); 130} 131 132static u_int 133get_status(int fd, u_int expected_id) 134{ 135 Buffer msg; 136 u_int type, id, status; 137 138 buffer_init(&msg); 139 get_msg(fd, &msg); 140 type = buffer_get_char(&msg); 141 id = buffer_get_int(&msg); 142 143 if (id != expected_id) 144 fatal("ID mismatch (%u != %u)", id, expected_id); 145 if (type != SSH2_FXP_STATUS) 146 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 147 SSH2_FXP_STATUS, type); 148 149 status = buffer_get_int(&msg); 150 buffer_free(&msg); 151 152 debug3("SSH2_FXP_STATUS %u", status); 153 154 return(status); 155} 156 157static char * 158get_handle(int fd, u_int expected_id, u_int *len) 159{ 160 Buffer msg; 161 u_int type, id; 162 char *handle; 163 164 buffer_init(&msg); 165 get_msg(fd, &msg); 166 type = buffer_get_char(&msg); 167 id = buffer_get_int(&msg); 168 169 if (id != expected_id) 170 fatal("ID mismatch (%u != %u)", id, expected_id); 171 if (type == SSH2_FXP_STATUS) { 172 int status = buffer_get_int(&msg); 173 174 error("Couldn't get handle: %s", fx2txt(status)); 175 buffer_free(&msg); 176 return(NULL); 177 } else if (type != SSH2_FXP_HANDLE) 178 fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u", 179 SSH2_FXP_HANDLE, type); 180 181 handle = buffer_get_string(&msg, len); 182 buffer_free(&msg); 183 184 return(handle); 185} 186 187static Attrib * 188get_decode_stat(int fd, u_int expected_id, int quiet) 189{ 190 Buffer msg; 191 u_int type, id; 192 Attrib *a; 193 194 buffer_init(&msg); 195 get_msg(fd, &msg); 196 197 type = buffer_get_char(&msg); 198 id = buffer_get_int(&msg); 199 200 debug3("Received stat reply T:%u I:%u", type, id); 201 if (id != expected_id) 202 fatal("ID mismatch (%u != %u)", id, expected_id); 203 if (type == SSH2_FXP_STATUS) { 204 int status = buffer_get_int(&msg); 205 206 if (quiet) 207 debug("Couldn't stat remote file: %s", fx2txt(status)); 208 else 209 error("Couldn't stat remote file: %s", fx2txt(status)); 210 buffer_free(&msg); 211 return(NULL); 212 } else if (type != SSH2_FXP_ATTRS) { 213 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 214 SSH2_FXP_ATTRS, type); 215 } 216 a = decode_attrib(&msg); 217 buffer_free(&msg); 218 219 return(a); 220} 221 222struct sftp_conn * 223do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) 224{ 225 u_int type; 226 int version; 227 Buffer msg; 228 struct sftp_conn *ret; 229 230 buffer_init(&msg); 231 buffer_put_char(&msg, SSH2_FXP_INIT); 232 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 233 send_msg(fd_out, &msg); 234 235 buffer_clear(&msg); 236 237 get_msg(fd_in, &msg); 238 239 /* Expecting a VERSION reply */ 240 if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { 241 error("Invalid packet back from SSH2_FXP_INIT (type %u)", 242 type); 243 buffer_free(&msg); 244 return(NULL); 245 } 246 version = buffer_get_int(&msg); 247 248 debug2("Remote version: %d", version); 249 250 /* Check for extensions */ 251 while (buffer_len(&msg) > 0) { 252 char *name = buffer_get_string(&msg, NULL); 253 char *value = buffer_get_string(&msg, NULL); 254 255 debug2("Init extension: \"%s\"", name); 256 xfree(name); 257 xfree(value); 258 } 259 260 buffer_free(&msg); 261 262 ret = xmalloc(sizeof(*ret)); 263 ret->fd_in = fd_in; 264 ret->fd_out = fd_out; 265 ret->transfer_buflen = transfer_buflen; 266 ret->num_requests = num_requests; 267 ret->version = version; 268 ret->msg_id = 1; 269 270 /* Some filexfer v.0 servers don't support large packets */ 271 if (version == 0) 272 ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); 273 274 return(ret); 275} 276 277u_int 278sftp_proto_version(struct sftp_conn *conn) 279{ 280 return(conn->version); 281} 282 283int 284do_close(struct sftp_conn *conn, char *handle, u_int handle_len) 285{ 286 u_int id, status; 287 Buffer msg; 288 289 buffer_init(&msg); 290 291 id = conn->msg_id++; 292 buffer_put_char(&msg, SSH2_FXP_CLOSE); 293 buffer_put_int(&msg, id); 294 buffer_put_string(&msg, handle, handle_len); 295 send_msg(conn->fd_out, &msg); 296 debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 297 298 status = get_status(conn->fd_in, id); 299 if (status != SSH2_FX_OK) 300 error("Couldn't close file: %s", fx2txt(status)); 301 302 buffer_free(&msg); 303 304 return(status); 305} 306 307 308static int 309do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, 310 SFTP_DIRENT ***dir) 311{ 312 Buffer msg; 313 u_int type, id, handle_len, i, expected_id, ents = 0; 314 char *handle; 315 316 id = conn->msg_id++; 317 318 buffer_init(&msg); 319 buffer_put_char(&msg, SSH2_FXP_OPENDIR); 320 buffer_put_int(&msg, id); 321 buffer_put_cstring(&msg, path); 322 send_msg(conn->fd_out, &msg); 323 324 buffer_clear(&msg); 325 326 handle = get_handle(conn->fd_in, id, &handle_len); 327 if (handle == NULL) 328 return(-1); 329 330 if (dir) { 331 ents = 0; 332 *dir = xmalloc(sizeof(**dir)); 333 (*dir)[0] = NULL; 334 } 335 336 for (; !interrupted;) { 337 int count; 338 339 id = expected_id = conn->msg_id++; 340 341 debug3("Sending SSH2_FXP_READDIR I:%u", id); 342 343 buffer_clear(&msg); 344 buffer_put_char(&msg, SSH2_FXP_READDIR); 345 buffer_put_int(&msg, id); 346 buffer_put_string(&msg, handle, handle_len); 347 send_msg(conn->fd_out, &msg); 348 349 buffer_clear(&msg); 350 351 get_msg(conn->fd_in, &msg); 352 353 type = buffer_get_char(&msg); 354 id = buffer_get_int(&msg); 355 356 debug3("Received reply T:%u I:%u", type, id); 357 358 if (id != expected_id) 359 fatal("ID mismatch (%u != %u)", id, expected_id); 360 361 if (type == SSH2_FXP_STATUS) { 362 int status = buffer_get_int(&msg); 363 364 debug3("Received SSH2_FXP_STATUS %d", status); 365 366 if (status == SSH2_FX_EOF) { 367 break; 368 } else { 369 error("Couldn't read directory: %s", 370 fx2txt(status)); 371 do_close(conn, handle, handle_len); 372 xfree(handle); 373 return(status); 374 } 375 } else if (type != SSH2_FXP_NAME) 376 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 377 SSH2_FXP_NAME, type); 378 379 count = buffer_get_int(&msg); 380 if (count == 0) 381 break; 382 debug3("Received %d SSH2_FXP_NAME responses", count); 383 for (i = 0; i < count; i++) { 384 char *filename, *longname; 385 Attrib *a; 386 387 filename = buffer_get_string(&msg, NULL); 388 longname = buffer_get_string(&msg, NULL); 389 a = decode_attrib(&msg); 390 391 if (printflag) 392 printf("%s\n", longname); 393 394 if (dir) { 395 *dir = xrealloc(*dir, sizeof(**dir) * 396 (ents + 2)); 397 (*dir)[ents] = xmalloc(sizeof(***dir)); 398 (*dir)[ents]->filename = xstrdup(filename); 399 (*dir)[ents]->longname = xstrdup(longname); 400 memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 401 (*dir)[++ents] = NULL; 402 } 403 404 xfree(filename); 405 xfree(longname); 406 } 407 } 408 409 buffer_free(&msg); 410 do_close(conn, handle, handle_len); 411 xfree(handle); 412 413 /* Don't return partial matches on interrupt */ 414 if (interrupted && dir != NULL && *dir != NULL) { 415 free_sftp_dirents(*dir); 416 *dir = xmalloc(sizeof(**dir)); 417 **dir = NULL; 418 } 419 420 return(0); 421} 422 423int 424do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) 425{ 426 return(do_lsreaddir(conn, path, 0, dir)); 427} 428 429void free_sftp_dirents(SFTP_DIRENT **s) 430{ 431 int i; 432 433 for (i = 0; s[i]; i++) { 434 xfree(s[i]->filename); 435 xfree(s[i]->longname); 436 xfree(s[i]); 437 } 438 xfree(s); 439} 440 441int 442do_rm(struct sftp_conn *conn, char *path) 443{ 444 u_int status, id; 445 446 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 447 448 id = conn->msg_id++; 449 send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, 450 strlen(path)); 451 status = get_status(conn->fd_in, id); 452 if (status != SSH2_FX_OK) 453 error("Couldn't delete file: %s", fx2txt(status)); 454 return(status); 455} 456 457int 458do_mkdir(struct sftp_conn *conn, char *path, Attrib *a) 459{ 460 u_int status, id; 461 462 id = conn->msg_id++; 463 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, 464 strlen(path), a); 465 466 status = get_status(conn->fd_in, id); 467 if (status != SSH2_FX_OK) 468 error("Couldn't create directory: %s", fx2txt(status)); 469 470 return(status); 471} 472 473int 474do_rmdir(struct sftp_conn *conn, char *path) 475{ 476 u_int status, id; 477 478 id = conn->msg_id++; 479 send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, 480 strlen(path)); 481 482 status = get_status(conn->fd_in, id); 483 if (status != SSH2_FX_OK) 484 error("Couldn't remove directory: %s", fx2txt(status)); 485 486 return(status); 487} 488 489Attrib * 490do_stat(struct sftp_conn *conn, char *path, int quiet) 491{ 492 u_int id; 493 494 id = conn->msg_id++; 495 496 send_string_request(conn->fd_out, id, 497 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 498 path, strlen(path)); 499 500 return(get_decode_stat(conn->fd_in, id, quiet)); 501} 502 503Attrib * 504do_lstat(struct sftp_conn *conn, char *path, int quiet) 505{ 506 u_int id; 507 508 if (conn->version == 0) { 509 if (quiet) 510 debug("Server version does not support lstat operation"); 511 else 512 logit("Server version does not support lstat operation"); 513 return(do_stat(conn, path, quiet)); 514 } 515 516 id = conn->msg_id++; 517 send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, 518 strlen(path)); 519 520 return(get_decode_stat(conn->fd_in, id, quiet)); 521} 522 523Attrib * 524do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) 525{ 526 u_int id; 527 528 id = conn->msg_id++; 529 send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, 530 handle_len); 531 532 return(get_decode_stat(conn->fd_in, id, quiet)); 533} 534 535int 536do_setstat(struct sftp_conn *conn, char *path, Attrib *a) 537{ 538 u_int status, id; 539 540 id = conn->msg_id++; 541 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, 542 strlen(path), a); 543 544 status = get_status(conn->fd_in, id); 545 if (status != SSH2_FX_OK) 546 error("Couldn't setstat on \"%s\": %s", path, 547 fx2txt(status)); 548 549 return(status); 550} 551 552int 553do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, 554 Attrib *a) 555{ 556 u_int status, id; 557 558 id = conn->msg_id++; 559 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, 560 handle_len, a); 561 562 status = get_status(conn->fd_in, id); 563 if (status != SSH2_FX_OK) 564 error("Couldn't fsetstat: %s", fx2txt(status)); 565 566 return(status); 567} 568 569char * 570do_realpath(struct sftp_conn *conn, char *path) 571{ 572 Buffer msg; 573 u_int type, expected_id, count, id; 574 char *filename, *longname; 575 Attrib *a; 576 577 expected_id = id = conn->msg_id++; 578 send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, 579 strlen(path)); 580 581 buffer_init(&msg); 582 583 get_msg(conn->fd_in, &msg); 584 type = buffer_get_char(&msg); 585 id = buffer_get_int(&msg); 586 587 if (id != expected_id) 588 fatal("ID mismatch (%u != %u)", id, expected_id); 589 590 if (type == SSH2_FXP_STATUS) { 591 u_int status = buffer_get_int(&msg); 592 593 error("Couldn't canonicalise: %s", fx2txt(status)); 594 return(NULL); 595 } else if (type != SSH2_FXP_NAME) 596 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 597 SSH2_FXP_NAME, type); 598 599 count = buffer_get_int(&msg); 600 if (count != 1) 601 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 602 603 filename = buffer_get_string(&msg, NULL); 604 longname = buffer_get_string(&msg, NULL); 605 a = decode_attrib(&msg); 606 607 debug3("SSH_FXP_REALPATH %s -> %s", path, filename); 608 609 xfree(longname); 610 611 buffer_free(&msg); 612 613 return(filename); 614} 615 616int 617do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) 618{ 619 Buffer msg; 620 u_int status, id; 621 622 buffer_init(&msg); 623 624 /* Send rename request */ 625 id = conn->msg_id++; 626 buffer_put_char(&msg, SSH2_FXP_RENAME); 627 buffer_put_int(&msg, id); 628 buffer_put_cstring(&msg, oldpath); 629 buffer_put_cstring(&msg, newpath); 630 send_msg(conn->fd_out, &msg); 631 debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, 632 newpath); 633 buffer_free(&msg); 634 635 status = get_status(conn->fd_in, id); 636 if (status != SSH2_FX_OK) 637 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 638 newpath, fx2txt(status)); 639 640 return(status); 641} 642 643int 644do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) 645{ 646 Buffer msg; 647 u_int status, id; 648 649 if (conn->version < 3) { 650 error("This server does not support the symlink operation"); 651 return(SSH2_FX_OP_UNSUPPORTED); 652 } 653 654 buffer_init(&msg); 655 656 /* Send symlink request */ 657 id = conn->msg_id++; 658 buffer_put_char(&msg, SSH2_FXP_SYMLINK); 659 buffer_put_int(&msg, id); 660 buffer_put_cstring(&msg, oldpath); 661 buffer_put_cstring(&msg, newpath); 662 send_msg(conn->fd_out, &msg); 663 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 664 newpath); 665 buffer_free(&msg); 666 667 status = get_status(conn->fd_in, id); 668 if (status != SSH2_FX_OK) 669 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 670 newpath, fx2txt(status)); 671 672 return(status); 673} 674 675char * 676do_readlink(struct sftp_conn *conn, char *path) 677{ 678 Buffer msg; 679 u_int type, expected_id, count, id; 680 char *filename, *longname; 681 Attrib *a; 682 683 expected_id = id = conn->msg_id++; 684 send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, 685 strlen(path)); 686 687 buffer_init(&msg); 688 689 get_msg(conn->fd_in, &msg); 690 type = buffer_get_char(&msg); 691 id = buffer_get_int(&msg); 692 693 if (id != expected_id) 694 fatal("ID mismatch (%u != %u)", id, expected_id); 695 696 if (type == SSH2_FXP_STATUS) { 697 u_int status = buffer_get_int(&msg); 698 699 error("Couldn't readlink: %s", fx2txt(status)); 700 return(NULL); 701 } else if (type != SSH2_FXP_NAME) 702 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 703 SSH2_FXP_NAME, type); 704 705 count = buffer_get_int(&msg); 706 if (count != 1) 707 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 708 709 filename = buffer_get_string(&msg, NULL); 710 longname = buffer_get_string(&msg, NULL); 711 a = decode_attrib(&msg); 712 713 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 714 715 xfree(longname); 716 717 buffer_free(&msg); 718 719 return(filename); 720} 721 722static void 723send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, 724 char *handle, u_int handle_len) 725{ 726 Buffer msg; 727 728 buffer_init(&msg); 729 buffer_clear(&msg); 730 buffer_put_char(&msg, SSH2_FXP_READ); 731 buffer_put_int(&msg, id); 732 buffer_put_string(&msg, handle, handle_len); 733 buffer_put_int64(&msg, offset); 734 buffer_put_int(&msg, len); 735 send_msg(fd_out, &msg); 736 buffer_free(&msg); 737} 738 739int 740do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 741 int pflag) 742{ 743 Attrib junk, *a; 744 Buffer msg; 745 char *handle; 746 int local_fd, status, num_req, max_req, write_error; 747 int read_error, write_errno; 748 u_int64_t offset, size; 749 u_int handle_len, mode, type, id, buflen; 750 off_t progress_counter; 751 struct request { 752 u_int id; 753 u_int len; 754 u_int64_t offset; 755 TAILQ_ENTRY(request) tq; 756 }; 757 TAILQ_HEAD(reqhead, request) requests; 758 struct request *req; 759 760 TAILQ_INIT(&requests); 761 762 a = do_stat(conn, remote_path, 0); 763 if (a == NULL) 764 return(-1); 765 766 /* XXX: should we preserve set[ug]id? */ 767 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 768 mode = a->perm & 0777; 769 else 770 mode = 0666; 771 772 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 773 (!S_ISREG(a->perm))) { 774 error("Cannot download non-regular file: %s", remote_path); 775 return(-1); 776 } 777 778 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 779 size = a->size; 780 else 781 size = 0; 782 783 buflen = conn->transfer_buflen; 784 buffer_init(&msg); 785 786 /* Send open request */ 787 id = conn->msg_id++; 788 buffer_put_char(&msg, SSH2_FXP_OPEN); 789 buffer_put_int(&msg, id); 790 buffer_put_cstring(&msg, remote_path); 791 buffer_put_int(&msg, SSH2_FXF_READ); 792 attrib_clear(&junk); /* Send empty attributes */ 793 encode_attrib(&msg, &junk); 794 send_msg(conn->fd_out, &msg); 795 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 796 797 handle = get_handle(conn->fd_in, id, &handle_len); 798 if (handle == NULL) { 799 buffer_free(&msg); 800 return(-1); 801 } 802 803 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, 804 mode | S_IWRITE); 805 if (local_fd == -1) { 806 error("Couldn't open local file \"%s\" for writing: %s", 807 local_path, strerror(errno)); 808 buffer_free(&msg); 809 xfree(handle); 810 return(-1); 811 } 812 813 /* Read from remote and write to local */ 814 write_error = read_error = write_errno = num_req = offset = 0; 815 max_req = 1; 816 progress_counter = 0; 817 818 if (showprogress && size != 0) 819 start_progress_meter(remote_path, size, &progress_counter); 820 821 while (num_req > 0 || max_req > 0) { 822 char *data; 823 u_int len; 824 825 /* 826 * Simulate EOF on interrupt: stop sending new requests and 827 * allow outstanding requests to drain gracefully 828 */ 829 if (interrupted) { 830 if (num_req == 0) /* If we haven't started yet... */ 831 break; 832 max_req = 0; 833 } 834 835 /* Send some more requests */ 836 while (num_req < max_req) { 837 debug3("Request range %llu -> %llu (%d/%d)", 838 (unsigned long long)offset, 839 (unsigned long long)offset + buflen - 1, 840 num_req, max_req); 841 req = xmalloc(sizeof(*req)); 842 req->id = conn->msg_id++; 843 req->len = buflen; 844 req->offset = offset; 845 offset += buflen; 846 num_req++; 847 TAILQ_INSERT_TAIL(&requests, req, tq); 848 send_read_request(conn->fd_out, req->id, req->offset, 849 req->len, handle, handle_len); 850 } 851 852 buffer_clear(&msg); 853 get_msg(conn->fd_in, &msg); 854 type = buffer_get_char(&msg); 855 id = buffer_get_int(&msg); 856 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 857 858 /* Find the request in our queue */ 859 for (req = TAILQ_FIRST(&requests); 860 req != NULL && req->id != id; 861 req = TAILQ_NEXT(req, tq)) 862 ; 863 if (req == NULL) 864 fatal("Unexpected reply %u", id); 865 866 switch (type) { 867 case SSH2_FXP_STATUS: 868 status = buffer_get_int(&msg); 869 if (status != SSH2_FX_EOF) 870 read_error = 1; 871 max_req = 0; 872 TAILQ_REMOVE(&requests, req, tq); 873 xfree(req); 874 num_req--; 875 break; 876 case SSH2_FXP_DATA: 877 data = buffer_get_string(&msg, &len); 878 debug3("Received data %llu -> %llu", 879 (unsigned long long)req->offset, 880 (unsigned long long)req->offset + len - 1); 881 if (len > req->len) 882 fatal("Received more data than asked for " 883 "%u > %u", len, req->len); 884 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 885 atomicio(vwrite, local_fd, data, len) != len) && 886 !write_error) { 887 write_errno = errno; 888 write_error = 1; 889 max_req = 0; 890 } 891 progress_counter += len; 892 xfree(data); 893 894 if (len == req->len) { 895 TAILQ_REMOVE(&requests, req, tq); 896 xfree(req); 897 num_req--; 898 } else { 899 /* Resend the request for the missing data */ 900 debug3("Short data block, re-requesting " 901 "%llu -> %llu (%2d)", 902 (unsigned long long)req->offset + len, 903 (unsigned long long)req->offset + 904 req->len - 1, num_req); 905 req->id = conn->msg_id++; 906 req->len -= len; 907 req->offset += len; 908 send_read_request(conn->fd_out, req->id, 909 req->offset, req->len, handle, handle_len); 910 /* Reduce the request size */ 911 if (len < buflen) 912 buflen = MAX(MIN_READ_SIZE, len); 913 } 914 if (max_req > 0) { /* max_req = 0 iff EOF received */ 915 if (size > 0 && offset > size) { 916 /* Only one request at a time 917 * after the expected EOF */ 918 debug3("Finish at %llu (%2d)", 919 (unsigned long long)offset, 920 num_req); 921 max_req = 1; 922 } else if (max_req <= conn->num_requests) { 923 ++max_req; 924 } 925 } 926 break; 927 default: 928 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 929 SSH2_FXP_DATA, type); 930 } 931 } 932 933 if (showprogress && size) 934 stop_progress_meter(); 935 936 /* Sanity check */ 937 if (TAILQ_FIRST(&requests) != NULL) 938 fatal("Transfer complete, but requests still in queue"); 939 940 if (read_error) { 941 error("Couldn't read from remote file \"%s\" : %s", 942 remote_path, fx2txt(status)); 943 do_close(conn, handle, handle_len); 944 } else if (write_error) { 945 error("Couldn't write to \"%s\": %s", local_path, 946 strerror(write_errno)); 947 status = -1; 948 do_close(conn, handle, handle_len); 949 } else { 950 status = do_close(conn, handle, handle_len); 951 952 /* Override umask and utimes if asked */ 953#ifdef HAVE_FCHMOD 954 if (pflag && fchmod(local_fd, mode) == -1) 955#else 956 if (pflag && chmod(local_path, mode) == -1) 957#endif /* HAVE_FCHMOD */ 958 error("Couldn't set mode on \"%s\": %s", local_path, 959 strerror(errno)); 960 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 961 struct timeval tv[2]; 962 tv[0].tv_sec = a->atime; 963 tv[1].tv_sec = a->mtime; 964 tv[0].tv_usec = tv[1].tv_usec = 0; 965 if (utimes(local_path, tv) == -1) 966 error("Can't set times on \"%s\": %s", 967 local_path, strerror(errno)); 968 } 969 } 970 close(local_fd); 971 buffer_free(&msg); 972 xfree(handle); 973 974 return(status); 975} 976 977int 978do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 979 int pflag) 980{ 981 int local_fd, status; 982 u_int handle_len, id, type; 983 u_int64_t offset; 984 char *handle, *data; 985 Buffer msg; 986 struct stat sb; 987 Attrib a; 988 u_int32_t startid; 989 u_int32_t ackid; 990 struct outstanding_ack { 991 u_int id; 992 u_int len; 993 u_int64_t offset; 994 TAILQ_ENTRY(outstanding_ack) tq; 995 }; 996 TAILQ_HEAD(ackhead, outstanding_ack) acks; 997 struct outstanding_ack *ack = NULL; 998 999 TAILQ_INIT(&acks); 1000 1001 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 1002 error("Couldn't open local file \"%s\" for reading: %s", 1003 local_path, strerror(errno)); 1004 return(-1); 1005 } 1006 if (fstat(local_fd, &sb) == -1) { 1007 error("Couldn't fstat local file \"%s\": %s", 1008 local_path, strerror(errno)); 1009 close(local_fd); 1010 return(-1); 1011 } 1012 if (!S_ISREG(sb.st_mode)) { 1013 error("%s is not a regular file", local_path); 1014 close(local_fd); 1015 return(-1); 1016 } 1017 stat_to_attrib(&sb, &a); 1018 1019 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1020 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1021 a.perm &= 0777; 1022 if (!pflag) 1023 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1024 1025 buffer_init(&msg); 1026 1027 /* Send open request */ 1028 id = conn->msg_id++; 1029 buffer_put_char(&msg, SSH2_FXP_OPEN); 1030 buffer_put_int(&msg, id); 1031 buffer_put_cstring(&msg, remote_path); 1032 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 1033 encode_attrib(&msg, &a); 1034 send_msg(conn->fd_out, &msg); 1035 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1036 1037 buffer_clear(&msg); 1038 1039 handle = get_handle(conn->fd_in, id, &handle_len); 1040 if (handle == NULL) { 1041 close(local_fd); 1042 buffer_free(&msg); 1043 return(-1); 1044 } 1045 1046 startid = ackid = id + 1; 1047 data = xmalloc(conn->transfer_buflen); 1048 1049 /* Read from local and write to remote */ 1050 offset = 0; 1051 if (showprogress) 1052 start_progress_meter(local_path, sb.st_size, &offset); 1053 1054 for (;;) { 1055 int len; 1056 1057 /* 1058 * Can't use atomicio here because it returns 0 on EOF, 1059 * thus losing the last block of the file. 1060 * Simulate an EOF on interrupt, allowing ACKs from the 1061 * server to drain. 1062 */ 1063 if (interrupted) 1064 len = 0; 1065 else do 1066 len = read(local_fd, data, conn->transfer_buflen); 1067 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 1068 1069 if (len == -1) 1070 fatal("Couldn't read from \"%s\": %s", local_path, 1071 strerror(errno)); 1072 1073 if (len != 0) { 1074 ack = xmalloc(sizeof(*ack)); 1075 ack->id = ++id; 1076 ack->offset = offset; 1077 ack->len = len; 1078 TAILQ_INSERT_TAIL(&acks, ack, tq); 1079 1080 buffer_clear(&msg); 1081 buffer_put_char(&msg, SSH2_FXP_WRITE); 1082 buffer_put_int(&msg, ack->id); 1083 buffer_put_string(&msg, handle, handle_len); 1084 buffer_put_int64(&msg, offset); 1085 buffer_put_string(&msg, data, len); 1086 send_msg(conn->fd_out, &msg); 1087 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1088 id, (unsigned long long)offset, len); 1089 } else if (TAILQ_FIRST(&acks) == NULL) 1090 break; 1091 1092 if (ack == NULL) 1093 fatal("Unexpected ACK %u", id); 1094 1095 if (id == startid || len == 0 || 1096 id - ackid >= conn->num_requests) { 1097 u_int r_id; 1098 1099 buffer_clear(&msg); 1100 get_msg(conn->fd_in, &msg); 1101 type = buffer_get_char(&msg); 1102 r_id = buffer_get_int(&msg); 1103 1104 if (type != SSH2_FXP_STATUS) 1105 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1106 "got %d", SSH2_FXP_STATUS, type); 1107 1108 status = buffer_get_int(&msg); 1109 debug3("SSH2_FXP_STATUS %d", status); 1110 1111 /* Find the request in our queue */ 1112 for (ack = TAILQ_FIRST(&acks); 1113 ack != NULL && ack->id != r_id; 1114 ack = TAILQ_NEXT(ack, tq)) 1115 ; 1116 if (ack == NULL) 1117 fatal("Can't find request for ID %u", r_id); 1118 TAILQ_REMOVE(&acks, ack, tq); 1119 1120 if (status != SSH2_FX_OK) { 1121 error("Couldn't write to remote file \"%s\": %s", 1122 remote_path, fx2txt(status)); 1123 do_close(conn, handle, handle_len); 1124 close(local_fd); 1125 xfree(data); 1126 xfree(ack); 1127 goto done; 1128 } 1129 debug3("In write loop, ack for %u %u bytes at %llu", 1130 ack->id, ack->len, (unsigned long long)ack->offset); 1131 ++ackid; 1132 xfree(ack); 1133 } 1134 offset += len; 1135 } 1136 if (showprogress) 1137 stop_progress_meter(); 1138 xfree(data); 1139 1140 if (close(local_fd) == -1) { 1141 error("Couldn't close local file \"%s\": %s", local_path, 1142 strerror(errno)); 1143 do_close(conn, handle, handle_len); 1144 status = -1; 1145 goto done; 1146 } 1147 1148 /* Override umask and utimes if asked */ 1149 if (pflag) 1150 do_fsetstat(conn, handle, handle_len, &a); 1151 1152 status = do_close(conn, handle, handle_len); 1153 1154done: 1155 xfree(handle); 1156 buffer_free(&msg); 1157 return(status); 1158} 1159