1 /* $OpenBSD: sftp-client.c,v 1.115 2014/04/21 14:36:16 logan 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/poll.h> 25 #include <sys/queue.h> 26 #include <sys/stat.h> 27 #include <sys/time.h> 28 #include <sys/param.h> 29 #include <sys/statvfs.h> 30 #include <sys/uio.h> 31 32 #include <dirent.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <signal.h> 36 #include <stdarg.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include "xmalloc.h" 43 #include "buffer.h" 44 #include "log.h" 45 #include "atomicio.h" 46 #include "progressmeter.h" 47 #include "misc.h" 48 49 #include "sftp.h" 50 #include "sftp-common.h" 51 #include "sftp-client.h" 52 53 extern volatile sig_atomic_t interrupted; 54 extern int showprogress; 55 56 /* Minimum amount of data to read at a time */ 57 #define MIN_READ_SIZE 512 58 59 /* Maximum depth to descend in directory trees */ 60 #define MAX_DIR_DEPTH 64 61 62 struct sftp_conn { 63 int fd_in; 64 int fd_out; 65 u_int transfer_buflen; 66 u_int num_requests; 67 u_int version; 68 u_int msg_id; 69 #define SFTP_EXT_POSIX_RENAME 0x00000001 70 #define SFTP_EXT_STATVFS 0x00000002 71 #define SFTP_EXT_FSTATVFS 0x00000004 72 #define SFTP_EXT_HARDLINK 0x00000008 73 #define SFTP_EXT_FSYNC 0x00000010 74 u_int exts; 75 u_int64_t limit_kbps; 76 struct bwlimit bwlimit_in, bwlimit_out; 77 }; 78 79 static char * 80 get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, 81 const char *errfmt, ...) __attribute__((format(printf, 4, 5))); 82 83 /* ARGSUSED */ 84 static int 85 sftpio(void *_bwlimit, size_t amount) 86 { 87 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; 88 89 bandwidth_limit(bwlimit, amount); 90 return 0; 91 } 92 93 static void 94 send_msg(struct sftp_conn *conn, Buffer *m) 95 { 96 u_char mlen[4]; 97 struct iovec iov[2]; 98 99 if (buffer_len(m) > SFTP_MAX_MSG_LENGTH) 100 fatal("Outbound message too long %u", buffer_len(m)); 101 102 /* Send length first */ 103 put_u32(mlen, buffer_len(m)); 104 iov[0].iov_base = mlen; 105 iov[0].iov_len = sizeof(mlen); 106 iov[1].iov_base = buffer_ptr(m); 107 iov[1].iov_len = buffer_len(m); 108 109 if (atomiciov6(writev, conn->fd_out, iov, 2, 110 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != 111 buffer_len(m) + sizeof(mlen)) 112 fatal("Couldn't send packet: %s", strerror(errno)); 113 114 buffer_clear(m); 115 } 116 117 static void 118 get_msg(struct sftp_conn *conn, Buffer *m) 119 { 120 u_int msg_len; 121 122 buffer_append_space(m, 4); 123 if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4, 124 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { 125 if (errno == EPIPE) 126 fatal("Connection closed"); 127 else 128 fatal("Couldn't read packet: %s", strerror(errno)); 129 } 130 131 msg_len = buffer_get_int(m); 132 if (msg_len > SFTP_MAX_MSG_LENGTH) 133 fatal("Received message too long %u", msg_len); 134 135 buffer_append_space(m, msg_len); 136 if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len, 137 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) 138 != msg_len) { 139 if (errno == EPIPE) 140 fatal("Connection closed"); 141 else 142 fatal("Read packet: %s", strerror(errno)); 143 } 144 } 145 146 static void 147 send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s, 148 u_int len) 149 { 150 Buffer msg; 151 152 buffer_init(&msg); 153 buffer_put_char(&msg, code); 154 buffer_put_int(&msg, id); 155 buffer_put_string(&msg, s, len); 156 send_msg(conn, &msg); 157 debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 158 buffer_free(&msg); 159 } 160 161 static void 162 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, 163 char *s, u_int len, Attrib *a) 164 { 165 Buffer msg; 166 167 buffer_init(&msg); 168 buffer_put_char(&msg, code); 169 buffer_put_int(&msg, id); 170 buffer_put_string(&msg, s, len); 171 encode_attrib(&msg, a); 172 send_msg(conn, &msg); 173 debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 174 buffer_free(&msg); 175 } 176 177 static u_int 178 get_status(struct sftp_conn *conn, u_int expected_id) 179 { 180 Buffer msg; 181 u_int type, id, status; 182 183 buffer_init(&msg); 184 get_msg(conn, &msg); 185 type = buffer_get_char(&msg); 186 id = buffer_get_int(&msg); 187 188 if (id != expected_id) 189 fatal("ID mismatch (%u != %u)", id, expected_id); 190 if (type != SSH2_FXP_STATUS) 191 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 192 SSH2_FXP_STATUS, type); 193 194 status = buffer_get_int(&msg); 195 buffer_free(&msg); 196 197 debug3("SSH2_FXP_STATUS %u", status); 198 199 return status; 200 } 201 202 static char * 203 get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, 204 const char *errfmt, ...) 205 { 206 Buffer msg; 207 u_int type, id; 208 char *handle, errmsg[256]; 209 va_list args; 210 int status; 211 212 va_start(args, errfmt); 213 if (errfmt != NULL) 214 vsnprintf(errmsg, sizeof(errmsg), errfmt, args); 215 va_end(args); 216 217 buffer_init(&msg); 218 get_msg(conn, &msg); 219 type = buffer_get_char(&msg); 220 id = buffer_get_int(&msg); 221 222 if (id != expected_id) 223 fatal("%s: ID mismatch (%u != %u)", 224 errfmt == NULL ? __func__ : errmsg, id, expected_id); 225 if (type == SSH2_FXP_STATUS) { 226 status = buffer_get_int(&msg); 227 if (errfmt != NULL) 228 error("%s: %s", errmsg, fx2txt(status)); 229 buffer_free(&msg); 230 return(NULL); 231 } else if (type != SSH2_FXP_HANDLE) 232 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", 233 errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); 234 235 handle = buffer_get_string(&msg, len); 236 buffer_free(&msg); 237 238 return(handle); 239 } 240 241 static Attrib * 242 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) 243 { 244 Buffer msg; 245 u_int type, id; 246 Attrib *a; 247 248 buffer_init(&msg); 249 get_msg(conn, &msg); 250 251 type = buffer_get_char(&msg); 252 id = buffer_get_int(&msg); 253 254 debug3("Received stat reply T:%u I:%u", type, id); 255 if (id != expected_id) 256 fatal("ID mismatch (%u != %u)", id, expected_id); 257 if (type == SSH2_FXP_STATUS) { 258 int status = buffer_get_int(&msg); 259 260 if (quiet) 261 debug("Couldn't stat remote file: %s", fx2txt(status)); 262 else 263 error("Couldn't stat remote file: %s", fx2txt(status)); 264 buffer_free(&msg); 265 return(NULL); 266 } else if (type != SSH2_FXP_ATTRS) { 267 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 268 SSH2_FXP_ATTRS, type); 269 } 270 a = decode_attrib(&msg); 271 buffer_free(&msg); 272 273 return(a); 274 } 275 276 static int 277 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, 278 u_int expected_id, int quiet) 279 { 280 Buffer msg; 281 u_int type, id, flag; 282 283 buffer_init(&msg); 284 get_msg(conn, &msg); 285 286 type = buffer_get_char(&msg); 287 id = buffer_get_int(&msg); 288 289 debug3("Received statvfs reply T:%u I:%u", type, id); 290 if (id != expected_id) 291 fatal("ID mismatch (%u != %u)", id, expected_id); 292 if (type == SSH2_FXP_STATUS) { 293 int status = buffer_get_int(&msg); 294 295 if (quiet) 296 debug("Couldn't statvfs: %s", fx2txt(status)); 297 else 298 error("Couldn't statvfs: %s", fx2txt(status)); 299 buffer_free(&msg); 300 return -1; 301 } else if (type != SSH2_FXP_EXTENDED_REPLY) { 302 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 303 SSH2_FXP_EXTENDED_REPLY, type); 304 } 305 306 memset(st, 0, sizeof(*st)); 307 st->f_bsize = buffer_get_int64(&msg); 308 st->f_frsize = buffer_get_int64(&msg); 309 st->f_blocks = buffer_get_int64(&msg); 310 st->f_bfree = buffer_get_int64(&msg); 311 st->f_bavail = buffer_get_int64(&msg); 312 st->f_files = buffer_get_int64(&msg); 313 st->f_ffree = buffer_get_int64(&msg); 314 st->f_favail = buffer_get_int64(&msg); 315 st->f_fsid = buffer_get_int64(&msg); 316 flag = buffer_get_int64(&msg); 317 st->f_namemax = buffer_get_int64(&msg); 318 319 st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; 320 st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; 321 322 buffer_free(&msg); 323 324 return 0; 325 } 326 327 struct sftp_conn * 328 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, 329 u_int64_t limit_kbps) 330 { 331 u_int type; 332 Buffer msg; 333 struct sftp_conn *ret; 334 335 ret = xcalloc(1, sizeof(*ret)); 336 ret->msg_id = 1; 337 ret->fd_in = fd_in; 338 ret->fd_out = fd_out; 339 ret->transfer_buflen = transfer_buflen; 340 ret->num_requests = num_requests; 341 ret->exts = 0; 342 ret->limit_kbps = 0; 343 344 buffer_init(&msg); 345 buffer_put_char(&msg, SSH2_FXP_INIT); 346 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 347 send_msg(ret, &msg); 348 349 buffer_clear(&msg); 350 351 get_msg(ret, &msg); 352 353 /* Expecting a VERSION reply */ 354 if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { 355 error("Invalid packet back from SSH2_FXP_INIT (type %u)", 356 type); 357 buffer_free(&msg); 358 return(NULL); 359 } 360 ret->version = buffer_get_int(&msg); 361 362 debug2("Remote version: %u", ret->version); 363 364 /* Check for extensions */ 365 while (buffer_len(&msg) > 0) { 366 char *name = buffer_get_string(&msg, NULL); 367 char *value = buffer_get_string(&msg, NULL); 368 int known = 0; 369 370 if (strcmp(name, "posix-rename@openssh.com") == 0 && 371 strcmp(value, "1") == 0) { 372 ret->exts |= SFTP_EXT_POSIX_RENAME; 373 known = 1; 374 } else if (strcmp(name, "statvfs@openssh.com") == 0 && 375 strcmp(value, "2") == 0) { 376 ret->exts |= SFTP_EXT_STATVFS; 377 known = 1; 378 } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && 379 strcmp(value, "2") == 0) { 380 ret->exts |= SFTP_EXT_FSTATVFS; 381 known = 1; 382 } else if (strcmp(name, "hardlink@openssh.com") == 0 && 383 strcmp(value, "1") == 0) { 384 ret->exts |= SFTP_EXT_HARDLINK; 385 known = 1; 386 } else if (strcmp(name, "fsync@openssh.com") == 0 && 387 strcmp(value, "1") == 0) { 388 ret->exts |= SFTP_EXT_FSYNC; 389 known = 1; 390 } 391 if (known) { 392 debug2("Server supports extension \"%s\" revision %s", 393 name, value); 394 } else { 395 debug2("Unrecognised server extension \"%s\"", name); 396 } 397 free(name); 398 free(value); 399 } 400 401 buffer_free(&msg); 402 403 /* Some filexfer v.0 servers don't support large packets */ 404 if (ret->version == 0) 405 ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); 406 407 ret->limit_kbps = limit_kbps; 408 if (ret->limit_kbps > 0) { 409 bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps, 410 ret->transfer_buflen); 411 bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps, 412 ret->transfer_buflen); 413 } 414 415 return ret; 416 } 417 418 u_int 419 sftp_proto_version(struct sftp_conn *conn) 420 { 421 return conn->version; 422 } 423 424 int 425 do_close(struct sftp_conn *conn, char *handle, u_int handle_len) 426 { 427 u_int id, status; 428 Buffer msg; 429 430 buffer_init(&msg); 431 432 id = conn->msg_id++; 433 buffer_put_char(&msg, SSH2_FXP_CLOSE); 434 buffer_put_int(&msg, id); 435 buffer_put_string(&msg, handle, handle_len); 436 send_msg(conn, &msg); 437 debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 438 439 status = get_status(conn, id); 440 if (status != SSH2_FX_OK) 441 error("Couldn't close file: %s", fx2txt(status)); 442 443 buffer_free(&msg); 444 445 return status; 446 } 447 448 449 static int 450 do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, 451 SFTP_DIRENT ***dir) 452 { 453 Buffer msg; 454 u_int count, type, id, handle_len, i, expected_id, ents = 0; 455 char *handle; 456 int status = SSH2_FX_FAILURE; 457 458 if (dir) 459 *dir = NULL; 460 461 id = conn->msg_id++; 462 463 buffer_init(&msg); 464 buffer_put_char(&msg, SSH2_FXP_OPENDIR); 465 buffer_put_int(&msg, id); 466 buffer_put_cstring(&msg, path); 467 send_msg(conn, &msg); 468 469 handle = get_handle(conn, id, &handle_len, 470 "remote readdir(\"%s\")", path); 471 if (handle == NULL) { 472 buffer_free(&msg); 473 return -1; 474 } 475 476 if (dir) { 477 ents = 0; 478 *dir = xcalloc(1, sizeof(**dir)); 479 (*dir)[0] = NULL; 480 } 481 482 for (; !interrupted;) { 483 id = expected_id = conn->msg_id++; 484 485 debug3("Sending SSH2_FXP_READDIR I:%u", id); 486 487 buffer_clear(&msg); 488 buffer_put_char(&msg, SSH2_FXP_READDIR); 489 buffer_put_int(&msg, id); 490 buffer_put_string(&msg, handle, handle_len); 491 send_msg(conn, &msg); 492 493 buffer_clear(&msg); 494 495 get_msg(conn, &msg); 496 497 type = buffer_get_char(&msg); 498 id = buffer_get_int(&msg); 499 500 debug3("Received reply T:%u I:%u", type, id); 501 502 if (id != expected_id) 503 fatal("ID mismatch (%u != %u)", id, expected_id); 504 505 if (type == SSH2_FXP_STATUS) { 506 status = buffer_get_int(&msg); 507 debug3("Received SSH2_FXP_STATUS %d", status); 508 if (status == SSH2_FX_EOF) 509 break; 510 error("Couldn't read directory: %s", fx2txt(status)); 511 goto out; 512 } else if (type != SSH2_FXP_NAME) 513 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 514 SSH2_FXP_NAME, type); 515 516 count = buffer_get_int(&msg); 517 if (count == 0) 518 break; 519 debug3("Received %d SSH2_FXP_NAME responses", count); 520 for (i = 0; i < count; i++) { 521 char *filename, *longname; 522 Attrib *a; 523 524 filename = buffer_get_string(&msg, NULL); 525 longname = buffer_get_string(&msg, NULL); 526 a = decode_attrib(&msg); 527 528 if (print_flag) 529 printf("%s\n", longname); 530 531 /* 532 * Directory entries should never contain '/' 533 * These can be used to attack recursive ops 534 * (e.g. send '../../../../etc/passwd') 535 */ 536 if (strchr(filename, '/') != NULL) { 537 error("Server sent suspect path \"%s\" " 538 "during readdir of \"%s\"", filename, path); 539 } else if (dir) { 540 *dir = xrealloc(*dir, ents + 2, sizeof(**dir)); 541 (*dir)[ents] = xcalloc(1, sizeof(***dir)); 542 (*dir)[ents]->filename = xstrdup(filename); 543 (*dir)[ents]->longname = xstrdup(longname); 544 memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 545 (*dir)[++ents] = NULL; 546 } 547 free(filename); 548 free(longname); 549 } 550 } 551 status = 0; 552 553 out: 554 buffer_free(&msg); 555 do_close(conn, handle, handle_len); 556 free(handle); 557 558 if (status != 0 && dir != NULL) { 559 /* Don't return results on error */ 560 free_sftp_dirents(*dir); 561 *dir = NULL; 562 } else if (interrupted && dir != NULL && *dir != NULL) { 563 /* Don't return partial matches on interrupt */ 564 free_sftp_dirents(*dir); 565 *dir = xcalloc(1, sizeof(**dir)); 566 **dir = NULL; 567 } 568 569 return status; 570 } 571 572 int 573 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) 574 { 575 return(do_lsreaddir(conn, path, 0, dir)); 576 } 577 578 void free_sftp_dirents(SFTP_DIRENT **s) 579 { 580 int i; 581 582 if (s == NULL) 583 return; 584 for (i = 0; s[i]; i++) { 585 free(s[i]->filename); 586 free(s[i]->longname); 587 free(s[i]); 588 } 589 free(s); 590 } 591 592 int 593 do_rm(struct sftp_conn *conn, char *path) 594 { 595 u_int status, id; 596 597 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 598 599 id = conn->msg_id++; 600 send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); 601 status = get_status(conn, id); 602 if (status != SSH2_FX_OK) 603 error("Couldn't delete file: %s", fx2txt(status)); 604 return(status); 605 } 606 607 int 608 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag) 609 { 610 u_int status, id; 611 612 id = conn->msg_id++; 613 send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, 614 strlen(path), a); 615 616 status = get_status(conn, id); 617 if (status != SSH2_FX_OK && print_flag) 618 error("Couldn't create directory: %s", fx2txt(status)); 619 620 return(status); 621 } 622 623 int 624 do_rmdir(struct sftp_conn *conn, char *path) 625 { 626 u_int status, id; 627 628 id = conn->msg_id++; 629 send_string_request(conn, id, SSH2_FXP_RMDIR, path, 630 strlen(path)); 631 632 status = get_status(conn, id); 633 if (status != SSH2_FX_OK) 634 error("Couldn't remove directory: %s", fx2txt(status)); 635 636 return(status); 637 } 638 639 Attrib * 640 do_stat(struct sftp_conn *conn, char *path, int quiet) 641 { 642 u_int id; 643 644 id = conn->msg_id++; 645 646 send_string_request(conn, id, 647 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 648 path, strlen(path)); 649 650 return(get_decode_stat(conn, id, quiet)); 651 } 652 653 Attrib * 654 do_lstat(struct sftp_conn *conn, char *path, int quiet) 655 { 656 u_int id; 657 658 if (conn->version == 0) { 659 if (quiet) 660 debug("Server version does not support lstat operation"); 661 else 662 logit("Server version does not support lstat operation"); 663 return(do_stat(conn, path, quiet)); 664 } 665 666 id = conn->msg_id++; 667 send_string_request(conn, id, SSH2_FXP_LSTAT, path, 668 strlen(path)); 669 670 return(get_decode_stat(conn, id, quiet)); 671 } 672 673 #ifdef notyet 674 Attrib * 675 do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) 676 { 677 u_int id; 678 679 id = conn->msg_id++; 680 send_string_request(conn, id, SSH2_FXP_FSTAT, handle, 681 handle_len); 682 683 return(get_decode_stat(conn, id, quiet)); 684 } 685 #endif 686 687 int 688 do_setstat(struct sftp_conn *conn, char *path, Attrib *a) 689 { 690 u_int status, id; 691 692 id = conn->msg_id++; 693 send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, 694 strlen(path), a); 695 696 status = get_status(conn, id); 697 if (status != SSH2_FX_OK) 698 error("Couldn't setstat on \"%s\": %s", path, 699 fx2txt(status)); 700 701 return(status); 702 } 703 704 int 705 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, 706 Attrib *a) 707 { 708 u_int status, id; 709 710 id = conn->msg_id++; 711 send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, 712 handle_len, a); 713 714 status = get_status(conn, id); 715 if (status != SSH2_FX_OK) 716 error("Couldn't fsetstat: %s", fx2txt(status)); 717 718 return(status); 719 } 720 721 char * 722 do_realpath(struct sftp_conn *conn, char *path) 723 { 724 Buffer msg; 725 u_int type, expected_id, count, id; 726 char *filename, *longname; 727 Attrib *a; 728 729 expected_id = id = conn->msg_id++; 730 send_string_request(conn, id, SSH2_FXP_REALPATH, path, 731 strlen(path)); 732 733 buffer_init(&msg); 734 735 get_msg(conn, &msg); 736 type = buffer_get_char(&msg); 737 id = buffer_get_int(&msg); 738 739 if (id != expected_id) 740 fatal("ID mismatch (%u != %u)", id, expected_id); 741 742 if (type == SSH2_FXP_STATUS) { 743 u_int status = buffer_get_int(&msg); 744 745 error("Couldn't canonicalize: %s", fx2txt(status)); 746 buffer_free(&msg); 747 return NULL; 748 } else if (type != SSH2_FXP_NAME) 749 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 750 SSH2_FXP_NAME, type); 751 752 count = buffer_get_int(&msg); 753 if (count != 1) 754 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 755 756 filename = buffer_get_string(&msg, NULL); 757 longname = buffer_get_string(&msg, NULL); 758 a = decode_attrib(&msg); 759 760 debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename, 761 (unsigned long)a->size); 762 763 free(longname); 764 765 buffer_free(&msg); 766 767 return(filename); 768 } 769 770 int 771 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath, 772 int force_legacy) 773 { 774 Buffer msg; 775 u_int status, id; 776 int use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; 777 778 buffer_init(&msg); 779 780 /* Send rename request */ 781 id = conn->msg_id++; 782 if (use_ext) { 783 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 784 buffer_put_int(&msg, id); 785 buffer_put_cstring(&msg, "posix-rename@openssh.com"); 786 } else { 787 buffer_put_char(&msg, SSH2_FXP_RENAME); 788 buffer_put_int(&msg, id); 789 } 790 buffer_put_cstring(&msg, oldpath); 791 buffer_put_cstring(&msg, newpath); 792 send_msg(conn, &msg); 793 debug3("Sent message %s \"%s\" -> \"%s\"", 794 use_ext ? "posix-rename@openssh.com" : "SSH2_FXP_RENAME", 795 oldpath, newpath); 796 buffer_free(&msg); 797 798 status = get_status(conn, id); 799 if (status != SSH2_FX_OK) 800 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 801 newpath, fx2txt(status)); 802 803 return(status); 804 } 805 806 int 807 do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath) 808 { 809 Buffer msg; 810 u_int status, id; 811 812 if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { 813 error("Server does not support hardlink@openssh.com extension"); 814 return -1; 815 } 816 817 buffer_init(&msg); 818 819 /* Send link request */ 820 id = conn->msg_id++; 821 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 822 buffer_put_int(&msg, id); 823 buffer_put_cstring(&msg, "hardlink@openssh.com"); 824 buffer_put_cstring(&msg, oldpath); 825 buffer_put_cstring(&msg, newpath); 826 send_msg(conn, &msg); 827 debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", 828 oldpath, newpath); 829 buffer_free(&msg); 830 831 status = get_status(conn, id); 832 if (status != SSH2_FX_OK) 833 error("Couldn't link file \"%s\" to \"%s\": %s", oldpath, 834 newpath, fx2txt(status)); 835 836 return(status); 837 } 838 839 int 840 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) 841 { 842 Buffer msg; 843 u_int status, id; 844 845 if (conn->version < 3) { 846 error("This server does not support the symlink operation"); 847 return(SSH2_FX_OP_UNSUPPORTED); 848 } 849 850 buffer_init(&msg); 851 852 /* Send symlink request */ 853 id = conn->msg_id++; 854 buffer_put_char(&msg, SSH2_FXP_SYMLINK); 855 buffer_put_int(&msg, id); 856 buffer_put_cstring(&msg, oldpath); 857 buffer_put_cstring(&msg, newpath); 858 send_msg(conn, &msg); 859 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 860 newpath); 861 buffer_free(&msg); 862 863 status = get_status(conn, id); 864 if (status != SSH2_FX_OK) 865 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 866 newpath, fx2txt(status)); 867 868 return(status); 869 } 870 871 int 872 do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len) 873 { 874 Buffer msg; 875 u_int status, id; 876 877 /* Silently return if the extension is not supported */ 878 if ((conn->exts & SFTP_EXT_FSYNC) == 0) 879 return -1; 880 881 buffer_init(&msg); 882 883 /* Send fsync request */ 884 id = conn->msg_id++; 885 886 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 887 buffer_put_int(&msg, id); 888 buffer_put_cstring(&msg, "fsync@openssh.com"); 889 buffer_put_string(&msg, handle, handle_len); 890 send_msg(conn, &msg); 891 debug3("Sent message fsync@openssh.com I:%u", id); 892 buffer_free(&msg); 893 894 status = get_status(conn, id); 895 if (status != SSH2_FX_OK) 896 error("Couldn't sync file: %s", fx2txt(status)); 897 898 return status; 899 } 900 901 #ifdef notyet 902 char * 903 do_readlink(struct sftp_conn *conn, char *path) 904 { 905 Buffer msg; 906 u_int type, expected_id, count, id; 907 char *filename, *longname; 908 Attrib *a; 909 910 expected_id = id = conn->msg_id++; 911 send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); 912 913 buffer_init(&msg); 914 915 get_msg(conn, &msg); 916 type = buffer_get_char(&msg); 917 id = buffer_get_int(&msg); 918 919 if (id != expected_id) 920 fatal("ID mismatch (%u != %u)", id, expected_id); 921 922 if (type == SSH2_FXP_STATUS) { 923 u_int status = buffer_get_int(&msg); 924 925 error("Couldn't readlink: %s", fx2txt(status)); 926 buffer_free(&msg); 927 return(NULL); 928 } else if (type != SSH2_FXP_NAME) 929 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 930 SSH2_FXP_NAME, type); 931 932 count = buffer_get_int(&msg); 933 if (count != 1) 934 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 935 936 filename = buffer_get_string(&msg, NULL); 937 longname = buffer_get_string(&msg, NULL); 938 a = decode_attrib(&msg); 939 940 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 941 942 free(longname); 943 944 buffer_free(&msg); 945 946 return(filename); 947 } 948 #endif 949 950 int 951 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, 952 int quiet) 953 { 954 Buffer msg; 955 u_int id; 956 957 if ((conn->exts & SFTP_EXT_STATVFS) == 0) { 958 error("Server does not support statvfs@openssh.com extension"); 959 return -1; 960 } 961 962 id = conn->msg_id++; 963 964 buffer_init(&msg); 965 buffer_clear(&msg); 966 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 967 buffer_put_int(&msg, id); 968 buffer_put_cstring(&msg, "statvfs@openssh.com"); 969 buffer_put_cstring(&msg, path); 970 send_msg(conn, &msg); 971 buffer_free(&msg); 972 973 return get_decode_statvfs(conn, st, id, quiet); 974 } 975 976 #ifdef notyet 977 int 978 do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, 979 struct sftp_statvfs *st, int quiet) 980 { 981 Buffer msg; 982 u_int id; 983 984 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { 985 error("Server does not support fstatvfs@openssh.com extension"); 986 return -1; 987 } 988 989 id = conn->msg_id++; 990 991 buffer_init(&msg); 992 buffer_clear(&msg); 993 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 994 buffer_put_int(&msg, id); 995 buffer_put_cstring(&msg, "fstatvfs@openssh.com"); 996 buffer_put_string(&msg, handle, handle_len); 997 send_msg(conn, &msg); 998 buffer_free(&msg); 999 1000 return get_decode_statvfs(conn, st, id, quiet); 1001 } 1002 #endif 1003 1004 static void 1005 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, 1006 u_int len, char *handle, u_int handle_len) 1007 { 1008 Buffer msg; 1009 1010 buffer_init(&msg); 1011 buffer_clear(&msg); 1012 buffer_put_char(&msg, SSH2_FXP_READ); 1013 buffer_put_int(&msg, id); 1014 buffer_put_string(&msg, handle, handle_len); 1015 buffer_put_int64(&msg, offset); 1016 buffer_put_int(&msg, len); 1017 send_msg(conn, &msg); 1018 buffer_free(&msg); 1019 } 1020 1021 int 1022 do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 1023 Attrib *a, int preserve_flag, int resume_flag, int fsync_flag) 1024 { 1025 Attrib junk; 1026 Buffer msg; 1027 char *handle; 1028 int local_fd = -1, status = 0, write_error; 1029 int read_error, write_errno, reordered = 0; 1030 u_int64_t offset = 0, size, highwater; 1031 u_int handle_len, mode, type, id, buflen, num_req, max_req; 1032 off_t progress_counter; 1033 struct stat st; 1034 struct request { 1035 u_int id; 1036 u_int len; 1037 u_int64_t offset; 1038 TAILQ_ENTRY(request) tq; 1039 }; 1040 TAILQ_HEAD(reqhead, request) requests; 1041 struct request *req; 1042 1043 TAILQ_INIT(&requests); 1044 1045 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 1046 return -1; 1047 1048 /* Do not preserve set[ug]id here, as we do not preserve ownership */ 1049 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1050 mode = a->perm & 0777; 1051 else 1052 mode = 0666; 1053 1054 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 1055 (!S_ISREG(a->perm))) { 1056 error("Cannot download non-regular file: %s", remote_path); 1057 return(-1); 1058 } 1059 1060 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 1061 size = a->size; 1062 else 1063 size = 0; 1064 1065 buflen = conn->transfer_buflen; 1066 buffer_init(&msg); 1067 1068 /* Send open request */ 1069 id = conn->msg_id++; 1070 buffer_put_char(&msg, SSH2_FXP_OPEN); 1071 buffer_put_int(&msg, id); 1072 buffer_put_cstring(&msg, remote_path); 1073 buffer_put_int(&msg, SSH2_FXF_READ); 1074 attrib_clear(&junk); /* Send empty attributes */ 1075 encode_attrib(&msg, &junk); 1076 send_msg(conn, &msg); 1077 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1078 1079 handle = get_handle(conn, id, &handle_len, 1080 "remote open(\"%s\")", remote_path); 1081 if (handle == NULL) { 1082 buffer_free(&msg); 1083 return(-1); 1084 } 1085 1086 local_fd = open(local_path, 1087 O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR); 1088 if (local_fd == -1) { 1089 error("Couldn't open local file \"%s\" for writing: %s", 1090 local_path, strerror(errno)); 1091 goto fail; 1092 } 1093 offset = highwater = 0; 1094 if (resume_flag) { 1095 if (fstat(local_fd, &st) == -1) { 1096 error("Unable to stat local file \"%s\": %s", 1097 local_path, strerror(errno)); 1098 goto fail; 1099 } 1100 if (st.st_size < 0) { 1101 error("\"%s\" has negative size", local_path); 1102 goto fail; 1103 } 1104 if ((u_int64_t)st.st_size > size) { 1105 error("Unable to resume download of \"%s\": " 1106 "local file is larger than remote", local_path); 1107 fail: 1108 do_close(conn, handle, handle_len); 1109 buffer_free(&msg); 1110 free(handle); 1111 if (local_fd != -1) 1112 close(local_fd); 1113 return -1; 1114 } 1115 offset = highwater = st.st_size; 1116 } 1117 1118 /* Read from remote and write to local */ 1119 write_error = read_error = write_errno = num_req = 0; 1120 max_req = 1; 1121 progress_counter = offset; 1122 1123 if (showprogress && size != 0) 1124 start_progress_meter(remote_path, size, &progress_counter); 1125 1126 while (num_req > 0 || max_req > 0) { 1127 char *data; 1128 u_int len; 1129 1130 /* 1131 * Simulate EOF on interrupt: stop sending new requests and 1132 * allow outstanding requests to drain gracefully 1133 */ 1134 if (interrupted) { 1135 if (num_req == 0) /* If we haven't started yet... */ 1136 break; 1137 max_req = 0; 1138 } 1139 1140 /* Send some more requests */ 1141 while (num_req < max_req) { 1142 debug3("Request range %llu -> %llu (%d/%d)", 1143 (unsigned long long)offset, 1144 (unsigned long long)offset + buflen - 1, 1145 num_req, max_req); 1146 req = xcalloc(1, sizeof(*req)); 1147 req->id = conn->msg_id++; 1148 req->len = buflen; 1149 req->offset = offset; 1150 offset += buflen; 1151 num_req++; 1152 TAILQ_INSERT_TAIL(&requests, req, tq); 1153 send_read_request(conn, req->id, req->offset, 1154 req->len, handle, handle_len); 1155 } 1156 1157 buffer_clear(&msg); 1158 get_msg(conn, &msg); 1159 type = buffer_get_char(&msg); 1160 id = buffer_get_int(&msg); 1161 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 1162 1163 /* Find the request in our queue */ 1164 for (req = TAILQ_FIRST(&requests); 1165 req != NULL && req->id != id; 1166 req = TAILQ_NEXT(req, tq)) 1167 ; 1168 if (req == NULL) 1169 fatal("Unexpected reply %u", id); 1170 1171 switch (type) { 1172 case SSH2_FXP_STATUS: 1173 status = buffer_get_int(&msg); 1174 if (status != SSH2_FX_EOF) 1175 read_error = 1; 1176 max_req = 0; 1177 TAILQ_REMOVE(&requests, req, tq); 1178 free(req); 1179 num_req--; 1180 break; 1181 case SSH2_FXP_DATA: 1182 data = buffer_get_string(&msg, &len); 1183 debug3("Received data %llu -> %llu", 1184 (unsigned long long)req->offset, 1185 (unsigned long long)req->offset + len - 1); 1186 if (len > req->len) 1187 fatal("Received more data than asked for " 1188 "%u > %u", len, req->len); 1189 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 1190 atomicio(vwrite, local_fd, data, len) != len) && 1191 !write_error) { 1192 write_errno = errno; 1193 write_error = 1; 1194 max_req = 0; 1195 } 1196 else if (!reordered && req->offset <= highwater) 1197 highwater = req->offset + len; 1198 else if (!reordered && req->offset > highwater) 1199 reordered = 1; 1200 progress_counter += len; 1201 free(data); 1202 1203 if (len == req->len) { 1204 TAILQ_REMOVE(&requests, req, tq); 1205 free(req); 1206 num_req--; 1207 } else { 1208 /* Resend the request for the missing data */ 1209 debug3("Short data block, re-requesting " 1210 "%llu -> %llu (%2d)", 1211 (unsigned long long)req->offset + len, 1212 (unsigned long long)req->offset + 1213 req->len - 1, num_req); 1214 req->id = conn->msg_id++; 1215 req->len -= len; 1216 req->offset += len; 1217 send_read_request(conn, req->id, 1218 req->offset, req->len, handle, handle_len); 1219 /* Reduce the request size */ 1220 if (len < buflen) 1221 buflen = MAX(MIN_READ_SIZE, len); 1222 } 1223 if (max_req > 0) { /* max_req = 0 iff EOF received */ 1224 if (size > 0 && offset > size) { 1225 /* Only one request at a time 1226 * after the expected EOF */ 1227 debug3("Finish at %llu (%2d)", 1228 (unsigned long long)offset, 1229 num_req); 1230 max_req = 1; 1231 } else if (max_req <= conn->num_requests) { 1232 ++max_req; 1233 } 1234 } 1235 break; 1236 default: 1237 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 1238 SSH2_FXP_DATA, type); 1239 } 1240 } 1241 1242 if (showprogress && size) 1243 stop_progress_meter(); 1244 1245 /* Sanity check */ 1246 if (TAILQ_FIRST(&requests) != NULL) 1247 fatal("Transfer complete, but requests still in queue"); 1248 /* Truncate at highest contiguous point to avoid holes on interrupt */ 1249 if (read_error || write_error || interrupted) { 1250 if (reordered && resume_flag) { 1251 error("Unable to resume download of \"%s\": " 1252 "server reordered requests", local_path); 1253 } 1254 debug("truncating at %llu", (unsigned long long)highwater); 1255 ftruncate(local_fd, highwater); 1256 } 1257 if (read_error) { 1258 error("Couldn't read from remote file \"%s\" : %s", 1259 remote_path, fx2txt(status)); 1260 status = -1; 1261 do_close(conn, handle, handle_len); 1262 } else if (write_error) { 1263 error("Couldn't write to \"%s\": %s", local_path, 1264 strerror(write_errno)); 1265 status = -1; 1266 do_close(conn, handle, handle_len); 1267 } else { 1268 status = do_close(conn, handle, handle_len); 1269 if (interrupted || status != SSH2_FX_OK) 1270 status = -1; 1271 /* Override umask and utimes if asked */ 1272 if (preserve_flag && fchmod(local_fd, mode) == -1) 1273 error("Couldn't set mode on \"%s\": %s", local_path, 1274 strerror(errno)); 1275 if (preserve_flag && 1276 (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 1277 struct timeval tv[2]; 1278 tv[0].tv_sec = a->atime; 1279 tv[1].tv_sec = a->mtime; 1280 tv[0].tv_usec = tv[1].tv_usec = 0; 1281 if (utimes(local_path, tv) == -1) 1282 error("Can't set times on \"%s\": %s", 1283 local_path, strerror(errno)); 1284 } 1285 if (fsync_flag) { 1286 debug("syncing \"%s\"", local_path); 1287 if (fsync(local_fd) == -1) 1288 error("Couldn't sync file \"%s\": %s", 1289 local_path, strerror(errno)); 1290 } 1291 } 1292 close(local_fd); 1293 buffer_free(&msg); 1294 free(handle); 1295 1296 return(status); 1297 } 1298 1299 static int 1300 download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, 1301 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, 1302 int fsync_flag) 1303 { 1304 int i, ret = 0; 1305 SFTP_DIRENT **dir_entries; 1306 char *filename, *new_src, *new_dst; 1307 mode_t mode = 0777; 1308 1309 if (depth >= MAX_DIR_DEPTH) { 1310 error("Maximum directory depth exceeded: %d levels", depth); 1311 return -1; 1312 } 1313 1314 if (dirattrib == NULL && 1315 (dirattrib = do_stat(conn, src, 1)) == NULL) { 1316 error("Unable to stat remote directory \"%s\"", src); 1317 return -1; 1318 } 1319 if (!S_ISDIR(dirattrib->perm)) { 1320 error("\"%s\" is not a directory", src); 1321 return -1; 1322 } 1323 if (print_flag) 1324 printf("Retrieving %s\n", src); 1325 1326 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1327 mode = dirattrib->perm & 01777; 1328 else { 1329 debug("Server did not send permissions for " 1330 "directory \"%s\"", dst); 1331 } 1332 1333 if (mkdir(dst, mode) == -1 && errno != EEXIST) { 1334 error("mkdir %s: %s", dst, strerror(errno)); 1335 return -1; 1336 } 1337 1338 if (do_readdir(conn, src, &dir_entries) == -1) { 1339 error("%s: Failed to get directory contents", src); 1340 return -1; 1341 } 1342 1343 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 1344 filename = dir_entries[i]->filename; 1345 1346 new_dst = path_append(dst, filename); 1347 new_src = path_append(src, filename); 1348 1349 if (S_ISDIR(dir_entries[i]->a.perm)) { 1350 if (strcmp(filename, ".") == 0 || 1351 strcmp(filename, "..") == 0) 1352 continue; 1353 if (download_dir_internal(conn, new_src, new_dst, 1354 depth + 1, &(dir_entries[i]->a), preserve_flag, 1355 print_flag, resume_flag, fsync_flag) == -1) 1356 ret = -1; 1357 } else if (S_ISREG(dir_entries[i]->a.perm) ) { 1358 if (do_download(conn, new_src, new_dst, 1359 &(dir_entries[i]->a), preserve_flag, 1360 resume_flag, fsync_flag) == -1) { 1361 error("Download of file %s to %s failed", 1362 new_src, new_dst); 1363 ret = -1; 1364 } 1365 } else 1366 logit("%s: not a regular file\n", new_src); 1367 1368 free(new_dst); 1369 free(new_src); 1370 } 1371 1372 if (preserve_flag) { 1373 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1374 struct timeval tv[2]; 1375 tv[0].tv_sec = dirattrib->atime; 1376 tv[1].tv_sec = dirattrib->mtime; 1377 tv[0].tv_usec = tv[1].tv_usec = 0; 1378 if (utimes(dst, tv) == -1) 1379 error("Can't set times on \"%s\": %s", 1380 dst, strerror(errno)); 1381 } else 1382 debug("Server did not send times for directory " 1383 "\"%s\"", dst); 1384 } 1385 1386 free_sftp_dirents(dir_entries); 1387 1388 return ret; 1389 } 1390 1391 int 1392 download_dir(struct sftp_conn *conn, char *src, char *dst, 1393 Attrib *dirattrib, int preserve_flag, int print_flag, 1394 int resume_flag, int fsync_flag) 1395 { 1396 char *src_canon; 1397 int ret; 1398 1399 if ((src_canon = do_realpath(conn, src)) == NULL) { 1400 error("Unable to canonicalize path \"%s\"", src); 1401 return -1; 1402 } 1403 1404 ret = download_dir_internal(conn, src_canon, dst, 0, 1405 dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag); 1406 free(src_canon); 1407 return ret; 1408 } 1409 1410 int 1411 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 1412 int preserve_flag, int resume, int fsync_flag) 1413 { 1414 int local_fd; 1415 int status = SSH2_FX_OK; 1416 u_int handle_len, id, type; 1417 off_t offset, progress_counter; 1418 char *handle, *data; 1419 Buffer msg; 1420 struct stat sb; 1421 Attrib a, *c = NULL; 1422 u_int32_t startid; 1423 u_int32_t ackid; 1424 struct outstanding_ack { 1425 u_int id; 1426 u_int len; 1427 off_t offset; 1428 TAILQ_ENTRY(outstanding_ack) tq; 1429 }; 1430 TAILQ_HEAD(ackhead, outstanding_ack) acks; 1431 struct outstanding_ack *ack = NULL; 1432 1433 TAILQ_INIT(&acks); 1434 1435 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 1436 error("Couldn't open local file \"%s\" for reading: %s", 1437 local_path, strerror(errno)); 1438 return(-1); 1439 } 1440 if (fstat(local_fd, &sb) == -1) { 1441 error("Couldn't fstat local file \"%s\": %s", 1442 local_path, strerror(errno)); 1443 close(local_fd); 1444 return(-1); 1445 } 1446 if (!S_ISREG(sb.st_mode)) { 1447 error("%s is not a regular file", local_path); 1448 close(local_fd); 1449 return(-1); 1450 } 1451 stat_to_attrib(&sb, &a); 1452 1453 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1454 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1455 a.perm &= 0777; 1456 if (!preserve_flag) 1457 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1458 1459 if (resume) { 1460 /* Get remote file size if it exists */ 1461 if ((c = do_stat(conn, remote_path, 0)) == NULL) { 1462 close(local_fd); 1463 return -1; 1464 } 1465 1466 if ((off_t)c->size >= sb.st_size) { 1467 error("destination file bigger or same size as " 1468 "source file"); 1469 close(local_fd); 1470 return -1; 1471 } 1472 1473 if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) { 1474 close(local_fd); 1475 return -1; 1476 } 1477 } 1478 1479 buffer_init(&msg); 1480 1481 /* Send open request */ 1482 id = conn->msg_id++; 1483 buffer_put_char(&msg, SSH2_FXP_OPEN); 1484 buffer_put_int(&msg, id); 1485 buffer_put_cstring(&msg, remote_path); 1486 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| 1487 (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC)); 1488 encode_attrib(&msg, &a); 1489 send_msg(conn, &msg); 1490 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1491 1492 buffer_clear(&msg); 1493 1494 handle = get_handle(conn, id, &handle_len, 1495 "remote open(\"%s\")", remote_path); 1496 if (handle == NULL) { 1497 close(local_fd); 1498 buffer_free(&msg); 1499 return -1; 1500 } 1501 1502 startid = ackid = id + 1; 1503 data = xmalloc(conn->transfer_buflen); 1504 1505 /* Read from local and write to remote */ 1506 offset = progress_counter = (resume ? c->size : 0); 1507 if (showprogress) 1508 start_progress_meter(local_path, sb.st_size, 1509 &progress_counter); 1510 1511 for (;;) { 1512 int len; 1513 1514 /* 1515 * Can't use atomicio here because it returns 0 on EOF, 1516 * thus losing the last block of the file. 1517 * Simulate an EOF on interrupt, allowing ACKs from the 1518 * server to drain. 1519 */ 1520 if (interrupted || status != SSH2_FX_OK) 1521 len = 0; 1522 else do 1523 len = read(local_fd, data, conn->transfer_buflen); 1524 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 1525 1526 if (len == -1) 1527 fatal("Couldn't read from \"%s\": %s", local_path, 1528 strerror(errno)); 1529 1530 if (len != 0) { 1531 ack = xcalloc(1, sizeof(*ack)); 1532 ack->id = ++id; 1533 ack->offset = offset; 1534 ack->len = len; 1535 TAILQ_INSERT_TAIL(&acks, ack, tq); 1536 1537 buffer_clear(&msg); 1538 buffer_put_char(&msg, SSH2_FXP_WRITE); 1539 buffer_put_int(&msg, ack->id); 1540 buffer_put_string(&msg, handle, handle_len); 1541 buffer_put_int64(&msg, offset); 1542 buffer_put_string(&msg, data, len); 1543 send_msg(conn, &msg); 1544 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1545 id, (unsigned long long)offset, len); 1546 } else if (TAILQ_FIRST(&acks) == NULL) 1547 break; 1548 1549 if (ack == NULL) 1550 fatal("Unexpected ACK %u", id); 1551 1552 if (id == startid || len == 0 || 1553 id - ackid >= conn->num_requests) { 1554 u_int r_id; 1555 1556 buffer_clear(&msg); 1557 get_msg(conn, &msg); 1558 type = buffer_get_char(&msg); 1559 r_id = buffer_get_int(&msg); 1560 1561 if (type != SSH2_FXP_STATUS) 1562 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1563 "got %d", SSH2_FXP_STATUS, type); 1564 1565 status = buffer_get_int(&msg); 1566 debug3("SSH2_FXP_STATUS %d", status); 1567 1568 /* Find the request in our queue */ 1569 for (ack = TAILQ_FIRST(&acks); 1570 ack != NULL && ack->id != r_id; 1571 ack = TAILQ_NEXT(ack, tq)) 1572 ; 1573 if (ack == NULL) 1574 fatal("Can't find request for ID %u", r_id); 1575 TAILQ_REMOVE(&acks, ack, tq); 1576 debug3("In write loop, ack for %u %u bytes at %lld", 1577 ack->id, ack->len, (long long)ack->offset); 1578 ++ackid; 1579 progress_counter += ack->len; 1580 free(ack); 1581 } 1582 offset += len; 1583 if (offset < 0) 1584 fatal("%s: offset < 0", __func__); 1585 } 1586 buffer_free(&msg); 1587 1588 if (showprogress) 1589 stop_progress_meter(); 1590 free(data); 1591 1592 if (status != SSH2_FX_OK) { 1593 error("Couldn't write to remote file \"%s\": %s", 1594 remote_path, fx2txt(status)); 1595 status = -1; 1596 } 1597 1598 if (close(local_fd) == -1) { 1599 error("Couldn't close local file \"%s\": %s", local_path, 1600 strerror(errno)); 1601 status = -1; 1602 } 1603 1604 /* Override umask and utimes if asked */ 1605 if (preserve_flag) 1606 do_fsetstat(conn, handle, handle_len, &a); 1607 1608 if (fsync_flag) 1609 (void)do_fsync(conn, handle, handle_len); 1610 1611 if (do_close(conn, handle, handle_len) != SSH2_FX_OK) 1612 status = -1; 1613 free(handle); 1614 1615 return status; 1616 } 1617 1618 static int 1619 upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, 1620 int preserve_flag, int print_flag, int resume, int fsync_flag) 1621 { 1622 int ret = 0, status; 1623 DIR *dirp; 1624 struct dirent *dp; 1625 char *filename, *new_src, *new_dst; 1626 struct stat sb; 1627 Attrib a; 1628 1629 if (depth >= MAX_DIR_DEPTH) { 1630 error("Maximum directory depth exceeded: %d levels", depth); 1631 return -1; 1632 } 1633 1634 if (stat(src, &sb) == -1) { 1635 error("Couldn't stat directory \"%s\": %s", 1636 src, strerror(errno)); 1637 return -1; 1638 } 1639 if (!S_ISDIR(sb.st_mode)) { 1640 error("\"%s\" is not a directory", src); 1641 return -1; 1642 } 1643 if (print_flag) 1644 printf("Entering %s\n", src); 1645 1646 attrib_clear(&a); 1647 stat_to_attrib(&sb, &a); 1648 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1649 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1650 a.perm &= 01777; 1651 if (!preserve_flag) 1652 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1653 1654 status = do_mkdir(conn, dst, &a, 0); 1655 /* 1656 * we lack a portable status for errno EEXIST, 1657 * so if we get a SSH2_FX_FAILURE back we must check 1658 * if it was created successfully. 1659 */ 1660 if (status != SSH2_FX_OK) { 1661 if (status != SSH2_FX_FAILURE) 1662 return -1; 1663 if (do_stat(conn, dst, 0) == NULL) 1664 return -1; 1665 } 1666 1667 if ((dirp = opendir(src)) == NULL) { 1668 error("Failed to open dir \"%s\": %s", src, strerror(errno)); 1669 return -1; 1670 } 1671 1672 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 1673 if (dp->d_ino == 0) 1674 continue; 1675 filename = dp->d_name; 1676 new_dst = path_append(dst, filename); 1677 new_src = path_append(src, filename); 1678 1679 if (lstat(new_src, &sb) == -1) { 1680 logit("%s: lstat failed: %s", filename, 1681 strerror(errno)); 1682 ret = -1; 1683 } else if (S_ISDIR(sb.st_mode)) { 1684 if (strcmp(filename, ".") == 0 || 1685 strcmp(filename, "..") == 0) 1686 continue; 1687 1688 if (upload_dir_internal(conn, new_src, new_dst, 1689 depth + 1, preserve_flag, print_flag, resume, 1690 fsync_flag) == -1) 1691 ret = -1; 1692 } else if (S_ISREG(sb.st_mode)) { 1693 if (do_upload(conn, new_src, new_dst, 1694 preserve_flag, resume, fsync_flag) == -1) { 1695 error("Uploading of file %s to %s failed!", 1696 new_src, new_dst); 1697 ret = -1; 1698 } 1699 } else 1700 logit("%s: not a regular file\n", filename); 1701 free(new_dst); 1702 free(new_src); 1703 } 1704 1705 do_setstat(conn, dst, &a); 1706 1707 (void) closedir(dirp); 1708 return ret; 1709 } 1710 1711 int 1712 upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, 1713 int print_flag, int resume, int fsync_flag) 1714 { 1715 char *dst_canon; 1716 int ret; 1717 1718 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 1719 error("Unable to canonicalize path \"%s\"", dst); 1720 return -1; 1721 } 1722 1723 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, 1724 print_flag, resume, fsync_flag); 1725 1726 free(dst_canon); 1727 return ret; 1728 } 1729 1730 char * 1731 path_append(char *p1, char *p2) 1732 { 1733 char *ret; 1734 size_t len = strlen(p1) + strlen(p2) + 2; 1735 1736 ret = xmalloc(len); 1737 strlcpy(ret, p1, len); 1738 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 1739 strlcat(ret, "/", len); 1740 strlcat(ret, p2, len); 1741 1742 return(ret); 1743 } 1744 1745