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