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" 23 RCSID("$OpenBSD: sftp-client.c,v 1.52 2004/11/25 22:22:14 markus Exp $"); 24 25 #include <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 39 extern volatile sig_atomic_t interrupted; 40 extern 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 48 struct 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 57 static void 58 send_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 76 static void 77 get_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 101 static void 102 send_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 116 static void 117 send_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 132 static u_int 133 get_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 157 static char * 158 get_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 187 static Attrib * 188 get_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 222 struct sftp_conn * 223 do_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 277 u_int 278 sftp_proto_version(struct sftp_conn *conn) 279 { 280 return(conn->version); 281 } 282 283 int 284 do_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 308 static int 309 do_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 423 int 424 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) 425 { 426 return(do_lsreaddir(conn, path, 0, dir)); 427 } 428 429 void 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 441 int 442 do_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 457 int 458 do_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 473 int 474 do_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 489 Attrib * 490 do_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 503 Attrib * 504 do_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 523 Attrib * 524 do_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 535 int 536 do_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 552 int 553 do_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 569 char * 570 do_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 616 int 617 do_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 643 int 644 do_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 675 char * 676 do_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 722 static void 723 send_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 739 int 740 do_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 if (pflag && fchmod(local_fd, mode) == -1) 954 error("Couldn't set mode on \"%s\": %s", local_path, 955 strerror(errno)); 956 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 957 struct timeval tv[2]; 958 tv[0].tv_sec = a->atime; 959 tv[1].tv_sec = a->mtime; 960 tv[0].tv_usec = tv[1].tv_usec = 0; 961 if (utimes(local_path, tv) == -1) 962 error("Can't set times on \"%s\": %s", 963 local_path, strerror(errno)); 964 } 965 } 966 close(local_fd); 967 buffer_free(&msg); 968 xfree(handle); 969 970 return(status); 971 } 972 973 int 974 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 975 int pflag) 976 { 977 int local_fd, status; 978 u_int handle_len, id, type; 979 u_int64_t offset; 980 char *handle, *data; 981 Buffer msg; 982 struct stat sb; 983 Attrib a; 984 u_int32_t startid; 985 u_int32_t ackid; 986 struct outstanding_ack { 987 u_int id; 988 u_int len; 989 u_int64_t offset; 990 TAILQ_ENTRY(outstanding_ack) tq; 991 }; 992 TAILQ_HEAD(ackhead, outstanding_ack) acks; 993 struct outstanding_ack *ack = NULL; 994 995 TAILQ_INIT(&acks); 996 997 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 998 error("Couldn't open local file \"%s\" for reading: %s", 999 local_path, strerror(errno)); 1000 return(-1); 1001 } 1002 if (fstat(local_fd, &sb) == -1) { 1003 error("Couldn't fstat local file \"%s\": %s", 1004 local_path, strerror(errno)); 1005 close(local_fd); 1006 return(-1); 1007 } 1008 if (!S_ISREG(sb.st_mode)) { 1009 error("%s is not a regular file", local_path); 1010 close(local_fd); 1011 return(-1); 1012 } 1013 stat_to_attrib(&sb, &a); 1014 1015 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1016 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1017 a.perm &= 0777; 1018 if (!pflag) 1019 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1020 1021 buffer_init(&msg); 1022 1023 /* Send open request */ 1024 id = conn->msg_id++; 1025 buffer_put_char(&msg, SSH2_FXP_OPEN); 1026 buffer_put_int(&msg, id); 1027 buffer_put_cstring(&msg, remote_path); 1028 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 1029 encode_attrib(&msg, &a); 1030 send_msg(conn->fd_out, &msg); 1031 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1032 1033 buffer_clear(&msg); 1034 1035 handle = get_handle(conn->fd_in, id, &handle_len); 1036 if (handle == NULL) { 1037 close(local_fd); 1038 buffer_free(&msg); 1039 return(-1); 1040 } 1041 1042 startid = ackid = id + 1; 1043 data = xmalloc(conn->transfer_buflen); 1044 1045 /* Read from local and write to remote */ 1046 offset = 0; 1047 if (showprogress) 1048 start_progress_meter(local_path, sb.st_size, &offset); 1049 1050 for (;;) { 1051 int len; 1052 1053 /* 1054 * Can't use atomicio here because it returns 0 on EOF, 1055 * thus losing the last block of the file. 1056 * Simulate an EOF on interrupt, allowing ACKs from the 1057 * server to drain. 1058 */ 1059 if (interrupted) 1060 len = 0; 1061 else do 1062 len = read(local_fd, data, conn->transfer_buflen); 1063 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 1064 1065 if (len == -1) 1066 fatal("Couldn't read from \"%s\": %s", local_path, 1067 strerror(errno)); 1068 1069 if (len != 0) { 1070 ack = xmalloc(sizeof(*ack)); 1071 ack->id = ++id; 1072 ack->offset = offset; 1073 ack->len = len; 1074 TAILQ_INSERT_TAIL(&acks, ack, tq); 1075 1076 buffer_clear(&msg); 1077 buffer_put_char(&msg, SSH2_FXP_WRITE); 1078 buffer_put_int(&msg, ack->id); 1079 buffer_put_string(&msg, handle, handle_len); 1080 buffer_put_int64(&msg, offset); 1081 buffer_put_string(&msg, data, len); 1082 send_msg(conn->fd_out, &msg); 1083 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1084 id, (unsigned long long)offset, len); 1085 } else if (TAILQ_FIRST(&acks) == NULL) 1086 break; 1087 1088 if (ack == NULL) 1089 fatal("Unexpected ACK %u", id); 1090 1091 if (id == startid || len == 0 || 1092 id - ackid >= conn->num_requests) { 1093 u_int r_id; 1094 1095 buffer_clear(&msg); 1096 get_msg(conn->fd_in, &msg); 1097 type = buffer_get_char(&msg); 1098 r_id = buffer_get_int(&msg); 1099 1100 if (type != SSH2_FXP_STATUS) 1101 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1102 "got %d", SSH2_FXP_STATUS, type); 1103 1104 status = buffer_get_int(&msg); 1105 debug3("SSH2_FXP_STATUS %d", status); 1106 1107 /* Find the request in our queue */ 1108 for(ack = TAILQ_FIRST(&acks); 1109 ack != NULL && ack->id != r_id; 1110 ack = TAILQ_NEXT(ack, tq)) 1111 ; 1112 if (ack == NULL) 1113 fatal("Can't find request for ID %u", r_id); 1114 TAILQ_REMOVE(&acks, ack, tq); 1115 1116 if (status != SSH2_FX_OK) { 1117 error("Couldn't write to remote file \"%s\": %s", 1118 remote_path, fx2txt(status)); 1119 do_close(conn, handle, handle_len); 1120 close(local_fd); 1121 xfree(data); 1122 xfree(ack); 1123 goto done; 1124 } 1125 debug3("In write loop, ack for %u %u bytes at %llu", 1126 ack->id, ack->len, (unsigned long long)ack->offset); 1127 ++ackid; 1128 xfree(ack); 1129 } 1130 offset += len; 1131 } 1132 if (showprogress) 1133 stop_progress_meter(); 1134 xfree(data); 1135 1136 if (close(local_fd) == -1) { 1137 error("Couldn't close local file \"%s\": %s", local_path, 1138 strerror(errno)); 1139 do_close(conn, handle, handle_len); 1140 status = -1; 1141 goto done; 1142 } 1143 1144 /* Override umask and utimes if asked */ 1145 if (pflag) 1146 do_fsetstat(conn, handle, handle_len, &a); 1147 1148 status = do_close(conn, handle, handle_len); 1149 1150 done: 1151 xfree(handle); 1152 buffer_free(&msg); 1153 return(status); 1154 } 1155