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.58 2006/01/02 01:20:31 djm 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 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 struct sftp_conn { 46 int fd_in; 47 int fd_out; 48 u_int transfer_buflen; 49 u_int num_requests; 50 u_int version; 51 u_int msg_id; 52 }; 53 54 static void 55 send_msg(int fd, Buffer *m) 56 { 57 u_char mlen[4]; 58 59 if (buffer_len(m) > SFTP_MAX_MSG_LENGTH) 60 fatal("Outbound message too long %u", buffer_len(m)); 61 62 /* Send length first */ 63 PUT_32BIT(mlen, buffer_len(m)); 64 if (atomicio(vwrite, fd, mlen, sizeof(mlen)) != sizeof(mlen)) 65 fatal("Couldn't send packet: %s", strerror(errno)); 66 67 if (atomicio(vwrite, fd, buffer_ptr(m), buffer_len(m)) != buffer_len(m)) 68 fatal("Couldn't send packet: %s", strerror(errno)); 69 70 buffer_clear(m); 71 } 72 73 static void 74 get_msg(int fd, Buffer *m) 75 { 76 u_int msg_len; 77 78 buffer_append_space(m, 4); 79 if (atomicio(read, fd, buffer_ptr(m), 4) != 4) { 80 if (errno == EPIPE) 81 fatal("Connection closed"); 82 else 83 fatal("Couldn't read packet: %s", strerror(errno)); 84 } 85 86 msg_len = buffer_get_int(m); 87 if (msg_len > SFTP_MAX_MSG_LENGTH) 88 fatal("Received message too long %u", msg_len); 89 90 buffer_append_space(m, msg_len); 91 if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) { 92 if (errno == EPIPE) 93 fatal("Connection closed"); 94 else 95 fatal("Read packet: %s", strerror(errno)); 96 } 97 } 98 99 static void 100 send_string_request(int fd, u_int id, u_int code, char *s, 101 u_int len) 102 { 103 Buffer msg; 104 105 buffer_init(&msg); 106 buffer_put_char(&msg, code); 107 buffer_put_int(&msg, id); 108 buffer_put_string(&msg, s, len); 109 send_msg(fd, &msg); 110 debug3("Sent message fd %d T:%u I:%u", fd, code, id); 111 buffer_free(&msg); 112 } 113 114 static void 115 send_string_attrs_request(int fd, u_int id, u_int code, char *s, 116 u_int len, Attrib *a) 117 { 118 Buffer msg; 119 120 buffer_init(&msg); 121 buffer_put_char(&msg, code); 122 buffer_put_int(&msg, id); 123 buffer_put_string(&msg, s, len); 124 encode_attrib(&msg, a); 125 send_msg(fd, &msg); 126 debug3("Sent message fd %d T:%u I:%u", fd, code, id); 127 buffer_free(&msg); 128 } 129 130 static u_int 131 get_status(int fd, u_int expected_id) 132 { 133 Buffer msg; 134 u_int type, id, status; 135 136 buffer_init(&msg); 137 get_msg(fd, &msg); 138 type = buffer_get_char(&msg); 139 id = buffer_get_int(&msg); 140 141 if (id != expected_id) 142 fatal("ID mismatch (%u != %u)", id, expected_id); 143 if (type != SSH2_FXP_STATUS) 144 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 145 SSH2_FXP_STATUS, type); 146 147 status = buffer_get_int(&msg); 148 buffer_free(&msg); 149 150 debug3("SSH2_FXP_STATUS %u", status); 151 152 return(status); 153 } 154 155 static char * 156 get_handle(int fd, u_int expected_id, u_int *len) 157 { 158 Buffer msg; 159 u_int type, id; 160 char *handle; 161 162 buffer_init(&msg); 163 get_msg(fd, &msg); 164 type = buffer_get_char(&msg); 165 id = buffer_get_int(&msg); 166 167 if (id != expected_id) 168 fatal("ID mismatch (%u != %u)", id, expected_id); 169 if (type == SSH2_FXP_STATUS) { 170 int status = buffer_get_int(&msg); 171 172 error("Couldn't get handle: %s", fx2txt(status)); 173 buffer_free(&msg); 174 return(NULL); 175 } else if (type != SSH2_FXP_HANDLE) 176 fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u", 177 SSH2_FXP_HANDLE, type); 178 179 handle = buffer_get_string(&msg, len); 180 buffer_free(&msg); 181 182 return(handle); 183 } 184 185 static Attrib * 186 get_decode_stat(int fd, u_int expected_id, int quiet) 187 { 188 Buffer msg; 189 u_int type, id; 190 Attrib *a; 191 192 buffer_init(&msg); 193 get_msg(fd, &msg); 194 195 type = buffer_get_char(&msg); 196 id = buffer_get_int(&msg); 197 198 debug3("Received stat reply T:%u I:%u", type, id); 199 if (id != expected_id) 200 fatal("ID mismatch (%u != %u)", id, expected_id); 201 if (type == SSH2_FXP_STATUS) { 202 int status = buffer_get_int(&msg); 203 204 if (quiet) 205 debug("Couldn't stat remote file: %s", fx2txt(status)); 206 else 207 error("Couldn't stat remote file: %s", fx2txt(status)); 208 buffer_free(&msg); 209 return(NULL); 210 } else if (type != SSH2_FXP_ATTRS) { 211 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 212 SSH2_FXP_ATTRS, type); 213 } 214 a = decode_attrib(&msg); 215 buffer_free(&msg); 216 217 return(a); 218 } 219 220 struct sftp_conn * 221 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) 222 { 223 u_int type; 224 int version; 225 Buffer msg; 226 struct sftp_conn *ret; 227 228 buffer_init(&msg); 229 buffer_put_char(&msg, SSH2_FXP_INIT); 230 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 231 send_msg(fd_out, &msg); 232 233 buffer_clear(&msg); 234 235 get_msg(fd_in, &msg); 236 237 /* Expecting a VERSION reply */ 238 if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { 239 error("Invalid packet back from SSH2_FXP_INIT (type %u)", 240 type); 241 buffer_free(&msg); 242 return(NULL); 243 } 244 version = buffer_get_int(&msg); 245 246 debug2("Remote version: %d", version); 247 248 /* Check for extensions */ 249 while (buffer_len(&msg) > 0) { 250 char *name = buffer_get_string(&msg, NULL); 251 char *value = buffer_get_string(&msg, NULL); 252 253 debug2("Init extension: \"%s\"", name); 254 xfree(name); 255 xfree(value); 256 } 257 258 buffer_free(&msg); 259 260 ret = xmalloc(sizeof(*ret)); 261 ret->fd_in = fd_in; 262 ret->fd_out = fd_out; 263 ret->transfer_buflen = transfer_buflen; 264 ret->num_requests = num_requests; 265 ret->version = version; 266 ret->msg_id = 1; 267 268 /* Some filexfer v.0 servers don't support large packets */ 269 if (version == 0) 270 ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); 271 272 return(ret); 273 } 274 275 u_int 276 sftp_proto_version(struct sftp_conn *conn) 277 { 278 return(conn->version); 279 } 280 281 int 282 do_close(struct sftp_conn *conn, char *handle, u_int handle_len) 283 { 284 u_int id, status; 285 Buffer msg; 286 287 buffer_init(&msg); 288 289 id = conn->msg_id++; 290 buffer_put_char(&msg, SSH2_FXP_CLOSE); 291 buffer_put_int(&msg, id); 292 buffer_put_string(&msg, handle, handle_len); 293 send_msg(conn->fd_out, &msg); 294 debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 295 296 status = get_status(conn->fd_in, id); 297 if (status != SSH2_FX_OK) 298 error("Couldn't close file: %s", fx2txt(status)); 299 300 buffer_free(&msg); 301 302 return(status); 303 } 304 305 306 static int 307 do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, 308 SFTP_DIRENT ***dir) 309 { 310 Buffer msg; 311 u_int count, type, id, handle_len, i, expected_id, ents = 0; 312 char *handle; 313 314 id = conn->msg_id++; 315 316 buffer_init(&msg); 317 buffer_put_char(&msg, SSH2_FXP_OPENDIR); 318 buffer_put_int(&msg, id); 319 buffer_put_cstring(&msg, path); 320 send_msg(conn->fd_out, &msg); 321 322 buffer_clear(&msg); 323 324 handle = get_handle(conn->fd_in, id, &handle_len); 325 if (handle == NULL) 326 return(-1); 327 328 if (dir) { 329 ents = 0; 330 *dir = xmalloc(sizeof(**dir)); 331 (*dir)[0] = NULL; 332 } 333 334 for (; !interrupted;) { 335 id = expected_id = conn->msg_id++; 336 337 debug3("Sending SSH2_FXP_READDIR I:%u", id); 338 339 buffer_clear(&msg); 340 buffer_put_char(&msg, SSH2_FXP_READDIR); 341 buffer_put_int(&msg, id); 342 buffer_put_string(&msg, handle, handle_len); 343 send_msg(conn->fd_out, &msg); 344 345 buffer_clear(&msg); 346 347 get_msg(conn->fd_in, &msg); 348 349 type = buffer_get_char(&msg); 350 id = buffer_get_int(&msg); 351 352 debug3("Received reply T:%u I:%u", type, id); 353 354 if (id != expected_id) 355 fatal("ID mismatch (%u != %u)", id, expected_id); 356 357 if (type == SSH2_FXP_STATUS) { 358 int status = buffer_get_int(&msg); 359 360 debug3("Received SSH2_FXP_STATUS %d", status); 361 362 if (status == SSH2_FX_EOF) { 363 break; 364 } else { 365 error("Couldn't read directory: %s", 366 fx2txt(status)); 367 do_close(conn, handle, handle_len); 368 xfree(handle); 369 return(status); 370 } 371 } else if (type != SSH2_FXP_NAME) 372 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 373 SSH2_FXP_NAME, type); 374 375 count = buffer_get_int(&msg); 376 if (count == 0) 377 break; 378 debug3("Received %d SSH2_FXP_NAME responses", count); 379 for (i = 0; i < count; i++) { 380 char *filename, *longname; 381 Attrib *a; 382 383 filename = buffer_get_string(&msg, NULL); 384 longname = buffer_get_string(&msg, NULL); 385 a = decode_attrib(&msg); 386 387 if (printflag) 388 printf("%s\n", longname); 389 390 if (dir) { 391 *dir = xrealloc(*dir, sizeof(**dir) * 392 (ents + 2)); 393 (*dir)[ents] = xmalloc(sizeof(***dir)); 394 (*dir)[ents]->filename = xstrdup(filename); 395 (*dir)[ents]->longname = xstrdup(longname); 396 memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 397 (*dir)[++ents] = NULL; 398 } 399 400 xfree(filename); 401 xfree(longname); 402 } 403 } 404 405 buffer_free(&msg); 406 do_close(conn, handle, handle_len); 407 xfree(handle); 408 409 /* Don't return partial matches on interrupt */ 410 if (interrupted && dir != NULL && *dir != NULL) { 411 free_sftp_dirents(*dir); 412 *dir = xmalloc(sizeof(**dir)); 413 **dir = NULL; 414 } 415 416 return(0); 417 } 418 419 int 420 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) 421 { 422 return(do_lsreaddir(conn, path, 0, dir)); 423 } 424 425 void free_sftp_dirents(SFTP_DIRENT **s) 426 { 427 int i; 428 429 for (i = 0; s[i]; i++) { 430 xfree(s[i]->filename); 431 xfree(s[i]->longname); 432 xfree(s[i]); 433 } 434 xfree(s); 435 } 436 437 int 438 do_rm(struct sftp_conn *conn, char *path) 439 { 440 u_int status, id; 441 442 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 443 444 id = conn->msg_id++; 445 send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, 446 strlen(path)); 447 status = get_status(conn->fd_in, id); 448 if (status != SSH2_FX_OK) 449 error("Couldn't delete file: %s", fx2txt(status)); 450 return(status); 451 } 452 453 int 454 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a) 455 { 456 u_int status, id; 457 458 id = conn->msg_id++; 459 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, 460 strlen(path), a); 461 462 status = get_status(conn->fd_in, id); 463 if (status != SSH2_FX_OK) 464 error("Couldn't create directory: %s", fx2txt(status)); 465 466 return(status); 467 } 468 469 int 470 do_rmdir(struct sftp_conn *conn, char *path) 471 { 472 u_int status, id; 473 474 id = conn->msg_id++; 475 send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, 476 strlen(path)); 477 478 status = get_status(conn->fd_in, id); 479 if (status != SSH2_FX_OK) 480 error("Couldn't remove directory: %s", fx2txt(status)); 481 482 return(status); 483 } 484 485 Attrib * 486 do_stat(struct sftp_conn *conn, char *path, int quiet) 487 { 488 u_int id; 489 490 id = conn->msg_id++; 491 492 send_string_request(conn->fd_out, id, 493 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 494 path, strlen(path)); 495 496 return(get_decode_stat(conn->fd_in, id, quiet)); 497 } 498 499 Attrib * 500 do_lstat(struct sftp_conn *conn, char *path, int quiet) 501 { 502 u_int id; 503 504 if (conn->version == 0) { 505 if (quiet) 506 debug("Server version does not support lstat operation"); 507 else 508 logit("Server version does not support lstat operation"); 509 return(do_stat(conn, path, quiet)); 510 } 511 512 id = conn->msg_id++; 513 send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, 514 strlen(path)); 515 516 return(get_decode_stat(conn->fd_in, id, quiet)); 517 } 518 519 Attrib * 520 do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) 521 { 522 u_int id; 523 524 id = conn->msg_id++; 525 send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, 526 handle_len); 527 528 return(get_decode_stat(conn->fd_in, id, quiet)); 529 } 530 531 int 532 do_setstat(struct sftp_conn *conn, char *path, Attrib *a) 533 { 534 u_int status, id; 535 536 id = conn->msg_id++; 537 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, 538 strlen(path), a); 539 540 status = get_status(conn->fd_in, id); 541 if (status != SSH2_FX_OK) 542 error("Couldn't setstat on \"%s\": %s", path, 543 fx2txt(status)); 544 545 return(status); 546 } 547 548 int 549 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, 550 Attrib *a) 551 { 552 u_int status, id; 553 554 id = conn->msg_id++; 555 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, 556 handle_len, a); 557 558 status = get_status(conn->fd_in, id); 559 if (status != SSH2_FX_OK) 560 error("Couldn't fsetstat: %s", fx2txt(status)); 561 562 return(status); 563 } 564 565 char * 566 do_realpath(struct sftp_conn *conn, char *path) 567 { 568 Buffer msg; 569 u_int type, expected_id, count, id; 570 char *filename, *longname; 571 Attrib *a; 572 573 expected_id = id = conn->msg_id++; 574 send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, 575 strlen(path)); 576 577 buffer_init(&msg); 578 579 get_msg(conn->fd_in, &msg); 580 type = buffer_get_char(&msg); 581 id = buffer_get_int(&msg); 582 583 if (id != expected_id) 584 fatal("ID mismatch (%u != %u)", id, expected_id); 585 586 if (type == SSH2_FXP_STATUS) { 587 u_int status = buffer_get_int(&msg); 588 589 error("Couldn't canonicalise: %s", fx2txt(status)); 590 return(NULL); 591 } else if (type != SSH2_FXP_NAME) 592 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 593 SSH2_FXP_NAME, type); 594 595 count = buffer_get_int(&msg); 596 if (count != 1) 597 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 598 599 filename = buffer_get_string(&msg, NULL); 600 longname = buffer_get_string(&msg, NULL); 601 a = decode_attrib(&msg); 602 603 debug3("SSH_FXP_REALPATH %s -> %s", path, filename); 604 605 xfree(longname); 606 607 buffer_free(&msg); 608 609 return(filename); 610 } 611 612 int 613 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) 614 { 615 Buffer msg; 616 u_int status, id; 617 618 buffer_init(&msg); 619 620 /* Send rename request */ 621 id = conn->msg_id++; 622 buffer_put_char(&msg, SSH2_FXP_RENAME); 623 buffer_put_int(&msg, id); 624 buffer_put_cstring(&msg, oldpath); 625 buffer_put_cstring(&msg, newpath); 626 send_msg(conn->fd_out, &msg); 627 debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, 628 newpath); 629 buffer_free(&msg); 630 631 status = get_status(conn->fd_in, id); 632 if (status != SSH2_FX_OK) 633 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 634 newpath, fx2txt(status)); 635 636 return(status); 637 } 638 639 int 640 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) 641 { 642 Buffer msg; 643 u_int status, id; 644 645 if (conn->version < 3) { 646 error("This server does not support the symlink operation"); 647 return(SSH2_FX_OP_UNSUPPORTED); 648 } 649 650 buffer_init(&msg); 651 652 /* Send symlink request */ 653 id = conn->msg_id++; 654 buffer_put_char(&msg, SSH2_FXP_SYMLINK); 655 buffer_put_int(&msg, id); 656 buffer_put_cstring(&msg, oldpath); 657 buffer_put_cstring(&msg, newpath); 658 send_msg(conn->fd_out, &msg); 659 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 660 newpath); 661 buffer_free(&msg); 662 663 status = get_status(conn->fd_in, id); 664 if (status != SSH2_FX_OK) 665 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 666 newpath, fx2txt(status)); 667 668 return(status); 669 } 670 671 char * 672 do_readlink(struct sftp_conn *conn, char *path) 673 { 674 Buffer msg; 675 u_int type, expected_id, count, id; 676 char *filename, *longname; 677 Attrib *a; 678 679 expected_id = id = conn->msg_id++; 680 send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, 681 strlen(path)); 682 683 buffer_init(&msg); 684 685 get_msg(conn->fd_in, &msg); 686 type = buffer_get_char(&msg); 687 id = buffer_get_int(&msg); 688 689 if (id != expected_id) 690 fatal("ID mismatch (%u != %u)", id, expected_id); 691 692 if (type == SSH2_FXP_STATUS) { 693 u_int status = buffer_get_int(&msg); 694 695 error("Couldn't readlink: %s", fx2txt(status)); 696 return(NULL); 697 } else if (type != SSH2_FXP_NAME) 698 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 699 SSH2_FXP_NAME, type); 700 701 count = buffer_get_int(&msg); 702 if (count != 1) 703 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 704 705 filename = buffer_get_string(&msg, NULL); 706 longname = buffer_get_string(&msg, NULL); 707 a = decode_attrib(&msg); 708 709 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 710 711 xfree(longname); 712 713 buffer_free(&msg); 714 715 return(filename); 716 } 717 718 static void 719 send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, 720 char *handle, u_int handle_len) 721 { 722 Buffer msg; 723 724 buffer_init(&msg); 725 buffer_clear(&msg); 726 buffer_put_char(&msg, SSH2_FXP_READ); 727 buffer_put_int(&msg, id); 728 buffer_put_string(&msg, handle, handle_len); 729 buffer_put_int64(&msg, offset); 730 buffer_put_int(&msg, len); 731 send_msg(fd_out, &msg); 732 buffer_free(&msg); 733 } 734 735 int 736 do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 737 int pflag) 738 { 739 Attrib junk, *a; 740 Buffer msg; 741 char *handle; 742 int local_fd, status = 0, write_error; 743 int read_error, write_errno; 744 u_int64_t offset, size; 745 u_int handle_len, mode, type, id, buflen, num_req, max_req; 746 off_t progress_counter; 747 struct request { 748 u_int id; 749 u_int len; 750 u_int64_t offset; 751 TAILQ_ENTRY(request) tq; 752 }; 753 TAILQ_HEAD(reqhead, request) requests; 754 struct request *req; 755 756 TAILQ_INIT(&requests); 757 758 a = do_stat(conn, remote_path, 0); 759 if (a == NULL) 760 return(-1); 761 762 /* XXX: should we preserve set[ug]id? */ 763 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 764 mode = a->perm & 0777; 765 else 766 mode = 0666; 767 768 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 769 (!S_ISREG(a->perm))) { 770 error("Cannot download non-regular file: %s", remote_path); 771 return(-1); 772 } 773 774 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 775 size = a->size; 776 else 777 size = 0; 778 779 buflen = conn->transfer_buflen; 780 buffer_init(&msg); 781 782 /* Send open request */ 783 id = conn->msg_id++; 784 buffer_put_char(&msg, SSH2_FXP_OPEN); 785 buffer_put_int(&msg, id); 786 buffer_put_cstring(&msg, remote_path); 787 buffer_put_int(&msg, SSH2_FXF_READ); 788 attrib_clear(&junk); /* Send empty attributes */ 789 encode_attrib(&msg, &junk); 790 send_msg(conn->fd_out, &msg); 791 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 792 793 handle = get_handle(conn->fd_in, id, &handle_len); 794 if (handle == NULL) { 795 buffer_free(&msg); 796 return(-1); 797 } 798 799 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, 800 mode | S_IWRITE); 801 if (local_fd == -1) { 802 error("Couldn't open local file \"%s\" for writing: %s", 803 local_path, strerror(errno)); 804 buffer_free(&msg); 805 xfree(handle); 806 return(-1); 807 } 808 809 /* Read from remote and write to local */ 810 write_error = read_error = write_errno = num_req = offset = 0; 811 max_req = 1; 812 progress_counter = 0; 813 814 if (showprogress && size != 0) 815 start_progress_meter(remote_path, size, &progress_counter); 816 817 while (num_req > 0 || max_req > 0) { 818 char *data; 819 u_int len; 820 821 /* 822 * Simulate EOF on interrupt: stop sending new requests and 823 * allow outstanding requests to drain gracefully 824 */ 825 if (interrupted) { 826 if (num_req == 0) /* If we haven't started yet... */ 827 break; 828 max_req = 0; 829 } 830 831 /* Send some more requests */ 832 while (num_req < max_req) { 833 debug3("Request range %llu -> %llu (%d/%d)", 834 (unsigned long long)offset, 835 (unsigned long long)offset + buflen - 1, 836 num_req, max_req); 837 req = xmalloc(sizeof(*req)); 838 req->id = conn->msg_id++; 839 req->len = buflen; 840 req->offset = offset; 841 offset += buflen; 842 num_req++; 843 TAILQ_INSERT_TAIL(&requests, req, tq); 844 send_read_request(conn->fd_out, req->id, req->offset, 845 req->len, handle, handle_len); 846 } 847 848 buffer_clear(&msg); 849 get_msg(conn->fd_in, &msg); 850 type = buffer_get_char(&msg); 851 id = buffer_get_int(&msg); 852 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 853 854 /* Find the request in our queue */ 855 for (req = TAILQ_FIRST(&requests); 856 req != NULL && req->id != id; 857 req = TAILQ_NEXT(req, tq)) 858 ; 859 if (req == NULL) 860 fatal("Unexpected reply %u", id); 861 862 switch (type) { 863 case SSH2_FXP_STATUS: 864 status = buffer_get_int(&msg); 865 if (status != SSH2_FX_EOF) 866 read_error = 1; 867 max_req = 0; 868 TAILQ_REMOVE(&requests, req, tq); 869 xfree(req); 870 num_req--; 871 break; 872 case SSH2_FXP_DATA: 873 data = buffer_get_string(&msg, &len); 874 debug3("Received data %llu -> %llu", 875 (unsigned long long)req->offset, 876 (unsigned long long)req->offset + len - 1); 877 if (len > req->len) 878 fatal("Received more data than asked for " 879 "%u > %u", len, req->len); 880 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 881 atomicio(vwrite, local_fd, data, len) != len) && 882 !write_error) { 883 write_errno = errno; 884 write_error = 1; 885 max_req = 0; 886 } 887 progress_counter += len; 888 xfree(data); 889 890 if (len == req->len) { 891 TAILQ_REMOVE(&requests, req, tq); 892 xfree(req); 893 num_req--; 894 } else { 895 /* Resend the request for the missing data */ 896 debug3("Short data block, re-requesting " 897 "%llu -> %llu (%2d)", 898 (unsigned long long)req->offset + len, 899 (unsigned long long)req->offset + 900 req->len - 1, num_req); 901 req->id = conn->msg_id++; 902 req->len -= len; 903 req->offset += len; 904 send_read_request(conn->fd_out, req->id, 905 req->offset, req->len, handle, handle_len); 906 /* Reduce the request size */ 907 if (len < buflen) 908 buflen = MAX(MIN_READ_SIZE, len); 909 } 910 if (max_req > 0) { /* max_req = 0 iff EOF received */ 911 if (size > 0 && offset > size) { 912 /* Only one request at a time 913 * after the expected EOF */ 914 debug3("Finish at %llu (%2d)", 915 (unsigned long long)offset, 916 num_req); 917 max_req = 1; 918 } else if (max_req <= conn->num_requests) { 919 ++max_req; 920 } 921 } 922 break; 923 default: 924 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 925 SSH2_FXP_DATA, type); 926 } 927 } 928 929 if (showprogress && size) 930 stop_progress_meter(); 931 932 /* Sanity check */ 933 if (TAILQ_FIRST(&requests) != NULL) 934 fatal("Transfer complete, but requests still in queue"); 935 936 if (read_error) { 937 error("Couldn't read from remote file \"%s\" : %s", 938 remote_path, fx2txt(status)); 939 do_close(conn, handle, handle_len); 940 } else if (write_error) { 941 error("Couldn't write to \"%s\": %s", local_path, 942 strerror(write_errno)); 943 status = -1; 944 do_close(conn, handle, handle_len); 945 } else { 946 status = do_close(conn, handle, handle_len); 947 948 /* Override umask and utimes if asked */ 949 #ifdef HAVE_FCHMOD 950 if (pflag && fchmod(local_fd, mode) == -1) 951 #else 952 if (pflag && chmod(local_path, mode) == -1) 953 #endif /* HAVE_FCHMOD */ 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