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.19 2001/12/19 07:18:56 deraadt 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 for (;;) { 313 int count; 314 315 id = expected_id = msg_id++; 316 317 debug3("Sending SSH2_FXP_READDIR I:%d", id); 318 319 buffer_clear(&msg); 320 buffer_put_char(&msg, SSH2_FXP_READDIR); 321 buffer_put_int(&msg, id); 322 buffer_put_string(&msg, handle, handle_len); 323 send_msg(fd_out, &msg); 324 325 buffer_clear(&msg); 326 327 get_msg(fd_in, &msg); 328 329 type = buffer_get_char(&msg); 330 id = buffer_get_int(&msg); 331 332 debug3("Received reply T:%d I:%d", type, id); 333 334 if (id != expected_id) 335 fatal("ID mismatch (%d != %d)", id, expected_id); 336 337 if (type == SSH2_FXP_STATUS) { 338 int status = buffer_get_int(&msg); 339 340 debug3("Received SSH2_FXP_STATUS %d", status); 341 342 if (status == SSH2_FX_EOF) { 343 break; 344 } else { 345 error("Couldn't read directory: %s", 346 fx2txt(status)); 347 do_close(fd_in, fd_out, handle, handle_len); 348 return(status); 349 } 350 } else if (type != SSH2_FXP_NAME) 351 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 352 SSH2_FXP_NAME, type); 353 354 count = buffer_get_int(&msg); 355 if (count == 0) 356 break; 357 debug3("Received %d SSH2_FXP_NAME responses", count); 358 for (i = 0; i < count; i++) { 359 char *filename, *longname; 360 Attrib *a; 361 362 filename = buffer_get_string(&msg, NULL); 363 longname = buffer_get_string(&msg, NULL); 364 a = decode_attrib(&msg); 365 366 if (printflag) 367 printf("%s\n", longname); 368 369 if (dir) { 370 *dir = xrealloc(*dir, sizeof(**dir) * 371 (ents + 2)); 372 (*dir)[ents] = xmalloc(sizeof(***dir)); 373 (*dir)[ents]->filename = xstrdup(filename); 374 (*dir)[ents]->longname = xstrdup(longname); 375 memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 376 (*dir)[++ents] = NULL; 377 } 378 379 xfree(filename); 380 xfree(longname); 381 } 382 } 383 384 buffer_free(&msg); 385 do_close(fd_in, fd_out, handle, handle_len); 386 xfree(handle); 387 388 return(0); 389 } 390 391 int 392 do_ls(int fd_in, int fd_out, char *path) 393 { 394 return(do_lsreaddir(fd_in, fd_out, path, 1, NULL)); 395 } 396 397 int 398 do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir) 399 { 400 return(do_lsreaddir(fd_in, fd_out, path, 0, dir)); 401 } 402 403 void free_sftp_dirents(SFTP_DIRENT **s) 404 { 405 int i; 406 407 for (i = 0; s[i]; i++) { 408 xfree(s[i]->filename); 409 xfree(s[i]->longname); 410 xfree(s[i]); 411 } 412 xfree(s); 413 } 414 415 int 416 do_rm(int fd_in, int fd_out, char *path) 417 { 418 u_int status, id; 419 420 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 421 422 id = msg_id++; 423 send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path)); 424 status = get_status(fd_in, id); 425 if (status != SSH2_FX_OK) 426 error("Couldn't delete file: %s", fx2txt(status)); 427 return(status); 428 } 429 430 int 431 do_mkdir(int fd_in, int fd_out, char *path, Attrib *a) 432 { 433 u_int status, id; 434 435 id = msg_id++; 436 send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path, 437 strlen(path), a); 438 439 status = get_status(fd_in, id); 440 if (status != SSH2_FX_OK) 441 error("Couldn't create directory: %s", fx2txt(status)); 442 443 return(status); 444 } 445 446 int 447 do_rmdir(int fd_in, int fd_out, char *path) 448 { 449 u_int status, id; 450 451 id = msg_id++; 452 send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path)); 453 454 status = get_status(fd_in, id); 455 if (status != SSH2_FX_OK) 456 error("Couldn't remove directory: %s", fx2txt(status)); 457 458 return(status); 459 } 460 461 Attrib * 462 do_stat(int fd_in, int fd_out, char *path, int quiet) 463 { 464 u_int id; 465 466 id = msg_id++; 467 send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path)); 468 return(get_decode_stat(fd_in, id, quiet)); 469 } 470 471 Attrib * 472 do_lstat(int fd_in, int fd_out, char *path, int quiet) 473 { 474 u_int id; 475 476 id = msg_id++; 477 send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path)); 478 return(get_decode_stat(fd_in, id, quiet)); 479 } 480 481 Attrib * 482 do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet) 483 { 484 u_int id; 485 486 id = msg_id++; 487 send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len); 488 return(get_decode_stat(fd_in, id, quiet)); 489 } 490 491 int 492 do_setstat(int fd_in, int fd_out, char *path, Attrib *a) 493 { 494 u_int status, id; 495 496 id = msg_id++; 497 send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path, 498 strlen(path), a); 499 500 status = get_status(fd_in, id); 501 if (status != SSH2_FX_OK) 502 error("Couldn't setstat on \"%s\": %s", path, 503 fx2txt(status)); 504 505 return(status); 506 } 507 508 int 509 do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len, 510 Attrib *a) 511 { 512 u_int status, id; 513 514 id = msg_id++; 515 send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle, 516 handle_len, a); 517 518 status = get_status(fd_in, id); 519 if (status != SSH2_FX_OK) 520 error("Couldn't fsetstat: %s", fx2txt(status)); 521 522 return(status); 523 } 524 525 char * 526 do_realpath(int fd_in, int fd_out, char *path) 527 { 528 Buffer msg; 529 u_int type, expected_id, count, id; 530 char *filename, *longname; 531 Attrib *a; 532 533 expected_id = id = msg_id++; 534 send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path)); 535 536 buffer_init(&msg); 537 538 get_msg(fd_in, &msg); 539 type = buffer_get_char(&msg); 540 id = buffer_get_int(&msg); 541 542 if (id != expected_id) 543 fatal("ID mismatch (%d != %d)", id, expected_id); 544 545 if (type == SSH2_FXP_STATUS) { 546 u_int status = buffer_get_int(&msg); 547 548 error("Couldn't canonicalise: %s", fx2txt(status)); 549 return(NULL); 550 } else if (type != SSH2_FXP_NAME) 551 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 552 SSH2_FXP_NAME, type); 553 554 count = buffer_get_int(&msg); 555 if (count != 1) 556 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 557 558 filename = buffer_get_string(&msg, NULL); 559 longname = buffer_get_string(&msg, NULL); 560 a = decode_attrib(&msg); 561 562 debug3("SSH_FXP_REALPATH %s -> %s", path, filename); 563 564 xfree(longname); 565 566 buffer_free(&msg); 567 568 return(filename); 569 } 570 571 int 572 do_rename(int fd_in, int fd_out, char *oldpath, char *newpath) 573 { 574 Buffer msg; 575 u_int status, id; 576 577 buffer_init(&msg); 578 579 /* Send rename request */ 580 id = msg_id++; 581 buffer_put_char(&msg, SSH2_FXP_RENAME); 582 buffer_put_int(&msg, id); 583 buffer_put_cstring(&msg, oldpath); 584 buffer_put_cstring(&msg, newpath); 585 send_msg(fd_out, &msg); 586 debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, 587 newpath); 588 buffer_free(&msg); 589 590 status = get_status(fd_in, id); 591 if (status != SSH2_FX_OK) 592 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, 593 fx2txt(status)); 594 595 return(status); 596 } 597 598 int 599 do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath) 600 { 601 Buffer msg; 602 u_int status, id; 603 604 buffer_init(&msg); 605 606 /* Send rename request */ 607 id = msg_id++; 608 buffer_put_char(&msg, SSH2_FXP_SYMLINK); 609 buffer_put_int(&msg, id); 610 buffer_put_cstring(&msg, oldpath); 611 buffer_put_cstring(&msg, newpath); 612 send_msg(fd_out, &msg); 613 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 614 newpath); 615 buffer_free(&msg); 616 617 status = get_status(fd_in, id); 618 if (status != SSH2_FX_OK) 619 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, 620 fx2txt(status)); 621 622 return(status); 623 } 624 625 char * 626 do_readlink(int fd_in, int fd_out, char *path) 627 { 628 Buffer msg; 629 u_int type, expected_id, count, id; 630 char *filename, *longname; 631 Attrib *a; 632 633 expected_id = id = msg_id++; 634 send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path)); 635 636 buffer_init(&msg); 637 638 get_msg(fd_in, &msg); 639 type = buffer_get_char(&msg); 640 id = buffer_get_int(&msg); 641 642 if (id != expected_id) 643 fatal("ID mismatch (%d != %d)", id, expected_id); 644 645 if (type == SSH2_FXP_STATUS) { 646 u_int status = buffer_get_int(&msg); 647 648 error("Couldn't readlink: %s", fx2txt(status)); 649 return(NULL); 650 } else if (type != SSH2_FXP_NAME) 651 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 652 SSH2_FXP_NAME, type); 653 654 count = buffer_get_int(&msg); 655 if (count != 1) 656 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 657 658 filename = buffer_get_string(&msg, NULL); 659 longname = buffer_get_string(&msg, NULL); 660 a = decode_attrib(&msg); 661 662 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 663 664 xfree(longname); 665 666 buffer_free(&msg); 667 668 return(filename); 669 } 670 671 int 672 do_download(int fd_in, int fd_out, char *remote_path, char *local_path, 673 int pflag) 674 { 675 int local_fd; 676 u_int expected_id, handle_len, mode, type, id; 677 u_int64_t offset; 678 char *handle; 679 Buffer msg; 680 Attrib junk, *a; 681 int status; 682 683 a = do_stat(fd_in, fd_out, remote_path, 0); 684 if (a == NULL) 685 return(-1); 686 687 /* XXX: should we preserve set[ug]id? */ 688 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 689 mode = S_IWRITE | (a->perm & 0777); 690 else 691 mode = 0666; 692 693 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 694 (a->perm & S_IFDIR)) { 695 error("Cannot download a directory: %s", remote_path); 696 return(-1); 697 } 698 699 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); 700 if (local_fd == -1) { 701 error("Couldn't open local file \"%s\" for writing: %s", 702 local_path, strerror(errno)); 703 return(-1); 704 } 705 706 buffer_init(&msg); 707 708 /* Send open request */ 709 id = msg_id++; 710 buffer_put_char(&msg, SSH2_FXP_OPEN); 711 buffer_put_int(&msg, id); 712 buffer_put_cstring(&msg, remote_path); 713 buffer_put_int(&msg, SSH2_FXF_READ); 714 attrib_clear(&junk); /* Send empty attributes */ 715 encode_attrib(&msg, &junk); 716 send_msg(fd_out, &msg); 717 debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); 718 719 handle = get_handle(fd_in, id, &handle_len); 720 if (handle == NULL) { 721 buffer_free(&msg); 722 close(local_fd); 723 return(-1); 724 } 725 726 /* Read from remote and write to local */ 727 offset = 0; 728 for (;;) { 729 u_int len; 730 char *data; 731 732 id = expected_id = msg_id++; 733 734 buffer_clear(&msg); 735 buffer_put_char(&msg, SSH2_FXP_READ); 736 buffer_put_int(&msg, id); 737 buffer_put_string(&msg, handle, handle_len); 738 buffer_put_int64(&msg, offset); 739 buffer_put_int(&msg, COPY_SIZE); 740 send_msg(fd_out, &msg); 741 debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u", 742 id, (unsigned long long)offset, COPY_SIZE); 743 744 buffer_clear(&msg); 745 746 get_msg(fd_in, &msg); 747 type = buffer_get_char(&msg); 748 id = buffer_get_int(&msg); 749 debug3("Received reply T:%d I:%d", type, id); 750 if (id != expected_id) 751 fatal("ID mismatch (%d != %d)", id, expected_id); 752 if (type == SSH2_FXP_STATUS) { 753 status = buffer_get_int(&msg); 754 755 if (status == SSH2_FX_EOF) 756 break; 757 else { 758 error("Couldn't read from remote " 759 "file \"%s\" : %s", remote_path, 760 fx2txt(status)); 761 do_close(fd_in, fd_out, handle, handle_len); 762 goto done; 763 } 764 } else if (type != SSH2_FXP_DATA) { 765 fatal("Expected SSH2_FXP_DATA(%d) packet, got %d", 766 SSH2_FXP_DATA, type); 767 } 768 769 data = buffer_get_string(&msg, &len); 770 if (len > COPY_SIZE) 771 fatal("Received more data than asked for %d > %d", 772 len, COPY_SIZE); 773 774 debug3("In read loop, got %d offset %llu", len, 775 (unsigned long long)offset); 776 if (atomicio(write, local_fd, data, len) != len) { 777 error("Couldn't write to \"%s\": %s", local_path, 778 strerror(errno)); 779 do_close(fd_in, fd_out, handle, handle_len); 780 status = -1; 781 xfree(data); 782 goto done; 783 } 784 785 offset += len; 786 xfree(data); 787 } 788 status = do_close(fd_in, fd_out, handle, handle_len); 789 790 /* Override umask and utimes if asked */ 791 if (pflag && fchmod(local_fd, mode) == -1) 792 error("Couldn't set mode on \"%s\": %s", local_path, 793 strerror(errno)); 794 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 795 struct timeval tv[2]; 796 tv[0].tv_sec = a->atime; 797 tv[1].tv_sec = a->mtime; 798 tv[0].tv_usec = tv[1].tv_usec = 0; 799 if (utimes(local_path, tv) == -1) 800 error("Can't set times on \"%s\": %s", local_path, 801 strerror(errno)); 802 } 803 804 done: 805 close(local_fd); 806 buffer_free(&msg); 807 xfree(handle); 808 return status; 809 } 810 811 int 812 do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, 813 int pflag) 814 { 815 int local_fd; 816 u_int handle_len, id; 817 u_int64_t offset; 818 char *handle; 819 Buffer msg; 820 struct stat sb; 821 Attrib a; 822 int status; 823 824 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 825 error("Couldn't open local file \"%s\" for reading: %s", 826 local_path, strerror(errno)); 827 return(-1); 828 } 829 if (fstat(local_fd, &sb) == -1) { 830 error("Couldn't fstat local file \"%s\": %s", 831 local_path, strerror(errno)); 832 close(local_fd); 833 return(-1); 834 } 835 stat_to_attrib(&sb, &a); 836 837 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 838 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 839 a.perm &= 0777; 840 if (!pflag) 841 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 842 843 buffer_init(&msg); 844 845 /* Send open request */ 846 id = msg_id++; 847 buffer_put_char(&msg, SSH2_FXP_OPEN); 848 buffer_put_int(&msg, id); 849 buffer_put_cstring(&msg, remote_path); 850 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 851 encode_attrib(&msg, &a); 852 send_msg(fd_out, &msg); 853 debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); 854 855 buffer_clear(&msg); 856 857 handle = get_handle(fd_in, id, &handle_len); 858 if (handle == NULL) { 859 close(local_fd); 860 buffer_free(&msg); 861 return(-1); 862 } 863 864 /* Read from local and write to remote */ 865 offset = 0; 866 for (;;) { 867 int len; 868 char data[COPY_SIZE]; 869 870 /* 871 * Can't use atomicio here because it returns 0 on EOF, thus losing 872 * the last block of the file 873 */ 874 do 875 len = read(local_fd, data, COPY_SIZE); 876 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 877 878 if (len == -1) 879 fatal("Couldn't read from \"%s\": %s", local_path, 880 strerror(errno)); 881 if (len == 0) 882 break; 883 884 buffer_clear(&msg); 885 buffer_put_char(&msg, SSH2_FXP_WRITE); 886 buffer_put_int(&msg, ++id); 887 buffer_put_string(&msg, handle, handle_len); 888 buffer_put_int64(&msg, offset); 889 buffer_put_string(&msg, data, len); 890 send_msg(fd_out, &msg); 891 debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", 892 id, (unsigned long long)offset, len); 893 894 status = get_status(fd_in, id); 895 if (status != SSH2_FX_OK) { 896 error("Couldn't write to remote file \"%s\": %s", 897 remote_path, fx2txt(status)); 898 do_close(fd_in, fd_out, handle, handle_len); 899 close(local_fd); 900 goto done; 901 } 902 debug3("In write loop, got %d offset %llu", len, 903 (unsigned long long)offset); 904 905 offset += len; 906 } 907 908 if (close(local_fd) == -1) { 909 error("Couldn't close local file \"%s\": %s", local_path, 910 strerror(errno)); 911 do_close(fd_in, fd_out, handle, handle_len); 912 status = -1; 913 goto done; 914 } 915 916 /* Override umask and utimes if asked */ 917 if (pflag) 918 do_fsetstat(fd_in, fd_out, handle, handle_len, &a); 919 920 status = do_close(fd_in, fd_out, handle, handle_len); 921 922 done: 923 xfree(handle); 924 buffer_free(&msg); 925 return status; 926 } 927 928