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