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