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