1 /* 2 * Copyright (c) 2001 Damien Miller. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 /* XXX: memleaks */ 26 /* XXX: signed vs unsigned */ 27 /* XXX: redesign to allow concurrent overlapped operations */ 28 /* XXX: we use fatal too much, error may be more appropriate in places */ 29 /* XXX: copy between two remote sites */ 30 31 #include "includes.h" 32 RCSID("$OpenBSD: sftp-client.c,v 1.18 2001/07/14 15:10:16 stevesk Exp $"); 33 34 #include "buffer.h" 35 #include "bufaux.h" 36 #include "getput.h" 37 #include "xmalloc.h" 38 #include "log.h" 39 #include "atomicio.h" 40 41 #include "sftp.h" 42 #include "sftp-common.h" 43 #include "sftp-client.h" 44 45 /* How much data to read/write at at time during copies */ 46 /* XXX: what should this be? */ 47 #define COPY_SIZE 8192 48 49 /* Message ID */ 50 static u_int msg_id = 1; 51 52 static void 53 send_msg(int fd, Buffer *m) 54 { 55 int mlen = buffer_len(m); 56 int len; 57 Buffer oqueue; 58 59 buffer_init(&oqueue); 60 buffer_put_int(&oqueue, mlen); 61 buffer_append(&oqueue, buffer_ptr(m), mlen); 62 buffer_consume(m, mlen); 63 64 len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue)); 65 if (len <= 0) 66 fatal("Couldn't send packet: %s", strerror(errno)); 67 68 buffer_free(&oqueue); 69 } 70 71 static void 72 get_msg(int fd, Buffer *m) 73 { 74 u_int len, msg_len; 75 unsigned char buf[4096]; 76 77 len = atomicio(read, fd, buf, 4); 78 if (len == 0) 79 fatal("Connection closed"); 80 else if (len == -1) 81 fatal("Couldn't read packet: %s", strerror(errno)); 82 83 msg_len = GET_32BIT(buf); 84 if (msg_len > 256 * 1024) 85 fatal("Received message too long %d", msg_len); 86 87 while (msg_len) { 88 len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf))); 89 if (len == 0) 90 fatal("Connection closed"); 91 else if (len == -1) 92 fatal("Couldn't read packet: %s", strerror(errno)); 93 94 msg_len -= len; 95 buffer_append(m, buf, len); 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:%d I:%d", 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:%d I:%d", fd, code, id); 127 buffer_free(&msg); 128 } 129 130 static u_int 131 get_status(int fd, 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 (%d != %d)", id, expected_id); 143 if (type != SSH2_FXP_STATUS) 144 fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d", 145 SSH2_FXP_STATUS, type); 146 147 status = buffer_get_int(&msg); 148 buffer_free(&msg); 149 150 debug3("SSH2_FXP_STATUS %d", 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 (%d != %d)", 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 return(NULL); 174 } else if (type != SSH2_FXP_HANDLE) 175 fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d", 176 SSH2_FXP_HANDLE, type); 177 178 handle = buffer_get_string(&msg, len); 179 buffer_free(&msg); 180 181 return(handle); 182 } 183 184 static Attrib * 185 get_decode_stat(int fd, u_int expected_id, int quiet) 186 { 187 Buffer msg; 188 u_int type, id; 189 Attrib *a; 190 191 buffer_init(&msg); 192 get_msg(fd, &msg); 193 194 type = buffer_get_char(&msg); 195 id = buffer_get_int(&msg); 196 197 debug3("Received stat reply T:%d I:%d", type, id); 198 if (id != expected_id) 199 fatal("ID mismatch (%d != %d)", id, expected_id); 200 if (type == SSH2_FXP_STATUS) { 201 int status = buffer_get_int(&msg); 202 203 if (quiet) 204 debug("Couldn't stat remote file: %s", fx2txt(status)); 205 else 206 error("Couldn't stat remote file: %s", fx2txt(status)); 207 return(NULL); 208 } else if (type != SSH2_FXP_ATTRS) { 209 fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d", 210 SSH2_FXP_ATTRS, type); 211 } 212 a = decode_attrib(&msg); 213 buffer_free(&msg); 214 215 return(a); 216 } 217 218 int 219 do_init(int fd_in, int fd_out) 220 { 221 int type, version; 222 Buffer msg; 223 224 buffer_init(&msg); 225 buffer_put_char(&msg, SSH2_FXP_INIT); 226 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 227 send_msg(fd_out, &msg); 228 229 buffer_clear(&msg); 230 231 get_msg(fd_in, &msg); 232 233 /* Expecting a VERSION reply */ 234 if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { 235 error("Invalid packet back from SSH2_FXP_INIT (type %d)", 236 type); 237 buffer_free(&msg); 238 return(-1); 239 } 240 version = buffer_get_int(&msg); 241 242 debug2("Remote version: %d", version); 243 244 /* Check for extensions */ 245 while (buffer_len(&msg) > 0) { 246 char *name = buffer_get_string(&msg, NULL); 247 char *value = buffer_get_string(&msg, NULL); 248 249 debug2("Init extension: \"%s\"", name); 250 xfree(name); 251 xfree(value); 252 } 253 254 buffer_free(&msg); 255 256 return(version); 257 } 258 259 int 260 do_close(int fd_in, int fd_out, char *handle, u_int handle_len) 261 { 262 u_int id, status; 263 Buffer msg; 264 265 buffer_init(&msg); 266 267 id = msg_id++; 268 buffer_put_char(&msg, SSH2_FXP_CLOSE); 269 buffer_put_int(&msg, id); 270 buffer_put_string(&msg, handle, handle_len); 271 send_msg(fd_out, &msg); 272 debug3("Sent message SSH2_FXP_CLOSE I:%d", id); 273 274 status = get_status(fd_in, id); 275 if (status != SSH2_FX_OK) 276 error("Couldn't close file: %s", fx2txt(status)); 277 278 buffer_free(&msg); 279 280 return(status); 281 } 282 283 284 static int 285 do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, 286 SFTP_DIRENT ***dir) 287 { 288 Buffer msg; 289 u_int type, id, handle_len, i, expected_id, ents = 0; 290 char *handle; 291 292 id = msg_id++; 293 294 buffer_init(&msg); 295 buffer_put_char(&msg, SSH2_FXP_OPENDIR); 296 buffer_put_int(&msg, id); 297 buffer_put_cstring(&msg, path); 298 send_msg(fd_out, &msg); 299 300 buffer_clear(&msg); 301 302 handle = get_handle(fd_in, id, &handle_len); 303 if (handle == NULL) 304 return(-1); 305 306 if (dir) { 307 ents = 0; 308 *dir = xmalloc(sizeof(**dir)); 309 (*dir)[0] = NULL; 310 } 311 312 313 for(;;) { 314 int count; 315 316 id = expected_id = msg_id++; 317 318 debug3("Sending SSH2_FXP_READDIR I:%d", id); 319 320 buffer_clear(&msg); 321 buffer_put_char(&msg, SSH2_FXP_READDIR); 322 buffer_put_int(&msg, id); 323 buffer_put_string(&msg, handle, handle_len); 324 send_msg(fd_out, &msg); 325 326 buffer_clear(&msg); 327 328 get_msg(fd_in, &msg); 329 330 type = buffer_get_char(&msg); 331 id = buffer_get_int(&msg); 332 333 debug3("Received reply T:%d I:%d", type, id); 334 335 if (id != expected_id) 336 fatal("ID mismatch (%d != %d)", id, expected_id); 337 338 if (type == SSH2_FXP_STATUS) { 339 int status = buffer_get_int(&msg); 340 341 debug3("Received SSH2_FXP_STATUS %d", status); 342 343 if (status == SSH2_FX_EOF) { 344 break; 345 } else { 346 error("Couldn't read directory: %s", 347 fx2txt(status)); 348 do_close(fd_in, fd_out, handle, handle_len); 349 return(status); 350 } 351 } else if (type != SSH2_FXP_NAME) 352 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 353 SSH2_FXP_NAME, type); 354 355 count = buffer_get_int(&msg); 356 if (count == 0) 357 break; 358 debug3("Received %d SSH2_FXP_NAME responses", count); 359 for(i = 0; i < count; i++) { 360 char *filename, *longname; 361 Attrib *a; 362 363 filename = buffer_get_string(&msg, NULL); 364 longname = buffer_get_string(&msg, NULL); 365 a = decode_attrib(&msg); 366 367 if (printflag) 368 printf("%s\n", longname); 369 370 if (dir) { 371 *dir = xrealloc(*dir, sizeof(**dir) * 372 (ents + 2)); 373 (*dir)[ents] = xmalloc(sizeof(***dir)); 374 (*dir)[ents]->filename = xstrdup(filename); 375 (*dir)[ents]->longname = xstrdup(longname); 376 memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 377 (*dir)[++ents] = NULL; 378 } 379 380 xfree(filename); 381 xfree(longname); 382 } 383 } 384 385 buffer_free(&msg); 386 do_close(fd_in, fd_out, handle, handle_len); 387 xfree(handle); 388 389 return(0); 390 } 391 392 int 393 do_ls(int fd_in, int fd_out, char *path) 394 { 395 return(do_lsreaddir(fd_in, fd_out, path, 1, NULL)); 396 } 397 398 int 399 do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir) 400 { 401 return(do_lsreaddir(fd_in, fd_out, path, 0, dir)); 402 } 403 404 void free_sftp_dirents(SFTP_DIRENT **s) 405 { 406 int i; 407 408 for(i = 0; s[i]; i++) { 409 xfree(s[i]->filename); 410 xfree(s[i]->longname); 411 xfree(s[i]); 412 } 413 xfree(s); 414 } 415 416 int 417 do_rm(int fd_in, int fd_out, char *path) 418 { 419 u_int status, id; 420 421 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 422 423 id = msg_id++; 424 send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path)); 425 status = get_status(fd_in, id); 426 if (status != SSH2_FX_OK) 427 error("Couldn't delete file: %s", fx2txt(status)); 428 return(status); 429 } 430 431 int 432 do_mkdir(int fd_in, int fd_out, char *path, Attrib *a) 433 { 434 u_int status, id; 435 436 id = msg_id++; 437 send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path, 438 strlen(path), a); 439 440 status = get_status(fd_in, id); 441 if (status != SSH2_FX_OK) 442 error("Couldn't create directory: %s", fx2txt(status)); 443 444 return(status); 445 } 446 447 int 448 do_rmdir(int fd_in, int fd_out, char *path) 449 { 450 u_int status, id; 451 452 id = msg_id++; 453 send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path)); 454 455 status = get_status(fd_in, id); 456 if (status != SSH2_FX_OK) 457 error("Couldn't remove directory: %s", fx2txt(status)); 458 459 return(status); 460 } 461 462 Attrib * 463 do_stat(int fd_in, int fd_out, char *path, int quiet) 464 { 465 u_int id; 466 467 id = msg_id++; 468 send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path)); 469 return(get_decode_stat(fd_in, id, quiet)); 470 } 471 472 Attrib * 473 do_lstat(int fd_in, int fd_out, char *path, int quiet) 474 { 475 u_int id; 476 477 id = msg_id++; 478 send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path)); 479 return(get_decode_stat(fd_in, id, quiet)); 480 } 481 482 Attrib * 483 do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet) 484 { 485 u_int id; 486 487 id = msg_id++; 488 send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len); 489 return(get_decode_stat(fd_in, id, quiet)); 490 } 491 492 int 493 do_setstat(int fd_in, int fd_out, char *path, Attrib *a) 494 { 495 u_int status, id; 496 497 id = msg_id++; 498 send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path, 499 strlen(path), a); 500 501 status = get_status(fd_in, id); 502 if (status != SSH2_FX_OK) 503 error("Couldn't setstat on \"%s\": %s", path, 504 fx2txt(status)); 505 506 return(status); 507 } 508 509 int 510 do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len, 511 Attrib *a) 512 { 513 u_int status, id; 514 515 id = msg_id++; 516 send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle, 517 handle_len, a); 518 519 status = get_status(fd_in, id); 520 if (status != SSH2_FX_OK) 521 error("Couldn't fsetstat: %s", fx2txt(status)); 522 523 return(status); 524 } 525 526 char * 527 do_realpath(int fd_in, int fd_out, char *path) 528 { 529 Buffer msg; 530 u_int type, expected_id, count, id; 531 char *filename, *longname; 532 Attrib *a; 533 534 expected_id = id = msg_id++; 535 send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path)); 536 537 buffer_init(&msg); 538 539 get_msg(fd_in, &msg); 540 type = buffer_get_char(&msg); 541 id = buffer_get_int(&msg); 542 543 if (id != expected_id) 544 fatal("ID mismatch (%d != %d)", id, expected_id); 545 546 if (type == SSH2_FXP_STATUS) { 547 u_int status = buffer_get_int(&msg); 548 549 error("Couldn't canonicalise: %s", fx2txt(status)); 550 return(NULL); 551 } else if (type != SSH2_FXP_NAME) 552 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 553 SSH2_FXP_NAME, type); 554 555 count = buffer_get_int(&msg); 556 if (count != 1) 557 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 558 559 filename = buffer_get_string(&msg, NULL); 560 longname = buffer_get_string(&msg, NULL); 561 a = decode_attrib(&msg); 562 563 debug3("SSH_FXP_REALPATH %s -> %s", path, filename); 564 565 xfree(longname); 566 567 buffer_free(&msg); 568 569 return(filename); 570 } 571 572 int 573 do_rename(int fd_in, int fd_out, char *oldpath, char *newpath) 574 { 575 Buffer msg; 576 u_int status, id; 577 578 buffer_init(&msg); 579 580 /* Send rename request */ 581 id = msg_id++; 582 buffer_put_char(&msg, SSH2_FXP_RENAME); 583 buffer_put_int(&msg, id); 584 buffer_put_cstring(&msg, oldpath); 585 buffer_put_cstring(&msg, newpath); 586 send_msg(fd_out, &msg); 587 debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, 588 newpath); 589 buffer_free(&msg); 590 591 status = get_status(fd_in, id); 592 if (status != SSH2_FX_OK) 593 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, 594 fx2txt(status)); 595 596 return(status); 597 } 598 599 int 600 do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath) 601 { 602 Buffer msg; 603 u_int status, id; 604 605 buffer_init(&msg); 606 607 /* Send rename request */ 608 id = msg_id++; 609 buffer_put_char(&msg, SSH2_FXP_SYMLINK); 610 buffer_put_int(&msg, id); 611 buffer_put_cstring(&msg, oldpath); 612 buffer_put_cstring(&msg, newpath); 613 send_msg(fd_out, &msg); 614 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 615 newpath); 616 buffer_free(&msg); 617 618 status = get_status(fd_in, id); 619 if (status != SSH2_FX_OK) 620 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, 621 fx2txt(status)); 622 623 return(status); 624 } 625 626 char * 627 do_readlink(int fd_in, int fd_out, char *path) 628 { 629 Buffer msg; 630 u_int type, expected_id, count, id; 631 char *filename, *longname; 632 Attrib *a; 633 634 expected_id = id = msg_id++; 635 send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path)); 636 637 buffer_init(&msg); 638 639 get_msg(fd_in, &msg); 640 type = buffer_get_char(&msg); 641 id = buffer_get_int(&msg); 642 643 if (id != expected_id) 644 fatal("ID mismatch (%d != %d)", id, expected_id); 645 646 if (type == SSH2_FXP_STATUS) { 647 u_int status = buffer_get_int(&msg); 648 649 error("Couldn't readlink: %s", fx2txt(status)); 650 return(NULL); 651 } else if (type != SSH2_FXP_NAME) 652 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 653 SSH2_FXP_NAME, type); 654 655 count = buffer_get_int(&msg); 656 if (count != 1) 657 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 658 659 filename = buffer_get_string(&msg, NULL); 660 longname = buffer_get_string(&msg, NULL); 661 a = decode_attrib(&msg); 662 663 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 664 665 xfree(longname); 666 667 buffer_free(&msg); 668 669 return(filename); 670 } 671 672 int 673 do_download(int fd_in, int fd_out, char *remote_path, char *local_path, 674 int pflag) 675 { 676 int local_fd; 677 u_int expected_id, handle_len, mode, type, id; 678 u_int64_t offset; 679 char *handle; 680 Buffer msg; 681 Attrib junk, *a; 682 int status; 683 684 a = do_stat(fd_in, fd_out, remote_path, 0); 685 if (a == NULL) 686 return(-1); 687 688 /* XXX: should we preserve set[ug]id? */ 689 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 690 mode = S_IWRITE | (a->perm & 0777); 691 else 692 mode = 0666; 693 694 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 695 (a->perm & S_IFDIR)) { 696 error("Cannot download a directory: %s", remote_path); 697 return(-1); 698 } 699 700 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); 701 if (local_fd == -1) { 702 error("Couldn't open local file \"%s\" for writing: %s", 703 local_path, strerror(errno)); 704 return(-1); 705 } 706 707 buffer_init(&msg); 708 709 /* Send open request */ 710 id = msg_id++; 711 buffer_put_char(&msg, SSH2_FXP_OPEN); 712 buffer_put_int(&msg, id); 713 buffer_put_cstring(&msg, remote_path); 714 buffer_put_int(&msg, SSH2_FXF_READ); 715 attrib_clear(&junk); /* Send empty attributes */ 716 encode_attrib(&msg, &junk); 717 send_msg(fd_out, &msg); 718 debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); 719 720 handle = get_handle(fd_in, id, &handle_len); 721 if (handle == NULL) { 722 buffer_free(&msg); 723 close(local_fd); 724 return(-1); 725 } 726 727 /* Read from remote and write to local */ 728 offset = 0; 729 for(;;) { 730 u_int len; 731 char *data; 732 733 id = expected_id = msg_id++; 734 735 buffer_clear(&msg); 736 buffer_put_char(&msg, SSH2_FXP_READ); 737 buffer_put_int(&msg, id); 738 buffer_put_string(&msg, handle, handle_len); 739 buffer_put_int64(&msg, offset); 740 buffer_put_int(&msg, COPY_SIZE); 741 send_msg(fd_out, &msg); 742 debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u", 743 id, (unsigned long long)offset, COPY_SIZE); 744 745 buffer_clear(&msg); 746 747 get_msg(fd_in, &msg); 748 type = buffer_get_char(&msg); 749 id = buffer_get_int(&msg); 750 debug3("Received reply T:%d I:%d", type, id); 751 if (id != expected_id) 752 fatal("ID mismatch (%d != %d)", id, expected_id); 753 if (type == SSH2_FXP_STATUS) { 754 status = buffer_get_int(&msg); 755 756 if (status == SSH2_FX_EOF) 757 break; 758 else { 759 error("Couldn't read from remote " 760 "file \"%s\" : %s", remote_path, 761 fx2txt(status)); 762 do_close(fd_in, fd_out, handle, handle_len); 763 goto done; 764 } 765 } else if (type != SSH2_FXP_DATA) { 766 fatal("Expected SSH2_FXP_DATA(%d) packet, got %d", 767 SSH2_FXP_DATA, type); 768 } 769 770 data = buffer_get_string(&msg, &len); 771 if (len > COPY_SIZE) 772 fatal("Received more data than asked for %d > %d", 773 len, COPY_SIZE); 774 775 debug3("In read loop, got %d offset %llu", len, 776 (unsigned long long)offset); 777 if (atomicio(write, local_fd, data, len) != len) { 778 error("Couldn't write to \"%s\": %s", local_path, 779 strerror(errno)); 780 do_close(fd_in, fd_out, handle, handle_len); 781 status = -1; 782 xfree(data); 783 goto done; 784 } 785 786 offset += len; 787 xfree(data); 788 } 789 status = do_close(fd_in, fd_out, handle, handle_len); 790 791 /* Override umask and utimes if asked */ 792 if (pflag && fchmod(local_fd, mode) == -1) 793 error("Couldn't set mode on \"%s\": %s", local_path, 794 strerror(errno)); 795 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 796 struct timeval tv[2]; 797 tv[0].tv_sec = a->atime; 798 tv[1].tv_sec = a->mtime; 799 tv[0].tv_usec = tv[1].tv_usec = 0; 800 if (utimes(local_path, tv) == -1) 801 error("Can't set times on \"%s\": %s", local_path, 802 strerror(errno)); 803 } 804 805 done: 806 close(local_fd); 807 buffer_free(&msg); 808 xfree(handle); 809 return status; 810 } 811 812 int 813 do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, 814 int pflag) 815 { 816 int local_fd; 817 u_int handle_len, id; 818 u_int64_t offset; 819 char *handle; 820 Buffer msg; 821 struct stat sb; 822 Attrib a; 823 int status; 824 825 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 826 error("Couldn't open local file \"%s\" for reading: %s", 827 local_path, strerror(errno)); 828 return(-1); 829 } 830 if (fstat(local_fd, &sb) == -1) { 831 error("Couldn't fstat local file \"%s\": %s", 832 local_path, strerror(errno)); 833 close(local_fd); 834 return(-1); 835 } 836 stat_to_attrib(&sb, &a); 837 838 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 839 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 840 a.perm &= 0777; 841 if (!pflag) 842 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 843 844 buffer_init(&msg); 845 846 /* Send open request */ 847 id = msg_id++; 848 buffer_put_char(&msg, SSH2_FXP_OPEN); 849 buffer_put_int(&msg, id); 850 buffer_put_cstring(&msg, remote_path); 851 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 852 encode_attrib(&msg, &a); 853 send_msg(fd_out, &msg); 854 debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); 855 856 buffer_clear(&msg); 857 858 handle = get_handle(fd_in, id, &handle_len); 859 if (handle == NULL) { 860 close(local_fd); 861 buffer_free(&msg); 862 return(-1); 863 } 864 865 /* Read from local and write to remote */ 866 offset = 0; 867 for(;;) { 868 int len; 869 char data[COPY_SIZE]; 870 871 /* 872 * Can't use atomicio here because it returns 0 on EOF, thus losing 873 * the last block of the file 874 */ 875 do 876 len = read(local_fd, data, COPY_SIZE); 877 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 878 879 if (len == -1) 880 fatal("Couldn't read from \"%s\": %s", local_path, 881 strerror(errno)); 882 if (len == 0) 883 break; 884 885 buffer_clear(&msg); 886 buffer_put_char(&msg, SSH2_FXP_WRITE); 887 buffer_put_int(&msg, ++id); 888 buffer_put_string(&msg, handle, handle_len); 889 buffer_put_int64(&msg, offset); 890 buffer_put_string(&msg, data, len); 891 send_msg(fd_out, &msg); 892 debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", 893 id, (unsigned long long)offset, len); 894 895 status = get_status(fd_in, id); 896 if (status != SSH2_FX_OK) { 897 error("Couldn't write to remote file \"%s\": %s", 898 remote_path, fx2txt(status)); 899 do_close(fd_in, fd_out, handle, handle_len); 900 close(local_fd); 901 goto done; 902 } 903 debug3("In write loop, got %d offset %llu", len, 904 (unsigned long long)offset); 905 906 offset += len; 907 } 908 909 if (close(local_fd) == -1) { 910 error("Couldn't close local file \"%s\": %s", local_path, 911 strerror(errno)); 912 do_close(fd_in, fd_out, handle, handle_len); 913 status = -1; 914 goto done; 915 } 916 917 /* Override umask and utimes if asked */ 918 if (pflag) 919 do_fsetstat(fd_in, fd_out, handle, handle_len, &a); 920 921 status = do_close(fd_in, fd_out, handle, handle_len); 922 923 done: 924 xfree(handle); 925 buffer_free(&msg); 926 return status; 927 } 928 929