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