1 /* $NetBSD: sftp-client.c,v 1.7 2012/12/12 17:42:40 christos Exp $ */ 2 /* $OpenBSD: sftp-client.c,v 1.97 2012/07/02 12:13:26 dtucker 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.7 2012/12/12 17:42:40 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 xfree(name); 394 xfree(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 = xmalloc(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 xfree(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] = xmalloc(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 xfree(filename); 552 xfree(longname); 553 } 554 } 555 556 buffer_free(&msg); 557 do_close(conn, handle, handle_len); 558 xfree(handle); 559 560 /* Don't return partial matches on interrupt */ 561 if (interrupted && dir != NULL && *dir != NULL) { 562 free_sftp_dirents(*dir); 563 *dir = xmalloc(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 xfree(s[i]->filename); 582 xfree(s[i]->longname); 583 xfree(s[i]); 584 } 585 xfree(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 xfree(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 xfree(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) 988 { 989 Attrib junk; 990 Buffer msg; 991 char *handle; 992 int local_fd, status = 0, write_error; 993 int read_error, write_errno; 994 u_int64_t offset, size; 995 u_int handle_len, mode, type, id, buflen, num_req, max_req; 996 off_t progress_counter; 997 struct request { 998 u_int id; 999 u_int len; 1000 u_int64_t offset; 1001 TAILQ_ENTRY(request) tq; 1002 }; 1003 TAILQ_HEAD(reqhead, request) requests; 1004 struct request *req; 1005 1006 status = -1; 1007 TAILQ_INIT(&requests); 1008 1009 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 1010 return -1; 1011 1012 /* Do not preserve set[ug]id here, as we do not preserve ownership */ 1013 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1014 mode = a->perm & 0777; 1015 else 1016 mode = 0666; 1017 1018 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 1019 (!S_ISREG(a->perm))) { 1020 error("Cannot download non-regular file: %s", remote_path); 1021 return(-1); 1022 } 1023 1024 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 1025 size = a->size; 1026 else 1027 size = 0; 1028 1029 buflen = conn->transfer_buflen; 1030 buffer_init(&msg); 1031 1032 /* Send open request */ 1033 id = conn->msg_id++; 1034 buffer_put_char(&msg, SSH2_FXP_OPEN); 1035 buffer_put_int(&msg, id); 1036 buffer_put_cstring(&msg, remote_path); 1037 buffer_put_int(&msg, SSH2_FXF_READ); 1038 attrib_clear(&junk); /* Send empty attributes */ 1039 encode_attrib(&msg, &junk); 1040 send_msg(conn, &msg); 1041 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1042 1043 handle = get_handle(conn, id, &handle_len, 1044 "remote open(\"%s\")", remote_path); 1045 if (handle == NULL) { 1046 buffer_free(&msg); 1047 return(-1); 1048 } 1049 1050 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, 1051 mode | S_IWRITE); 1052 if (local_fd == -1) { 1053 error("Couldn't open local file \"%s\" for writing: %s", 1054 local_path, strerror(errno)); 1055 do_close(conn, handle, handle_len); 1056 buffer_free(&msg); 1057 xfree(handle); 1058 return(-1); 1059 } 1060 1061 /* Read from remote and write to local */ 1062 write_error = read_error = write_errno = num_req = offset = 0; 1063 max_req = 1; 1064 progress_counter = 0; 1065 1066 if (showprogress && size != 0) 1067 start_progress_meter(remote_path, size, &progress_counter); 1068 1069 while (num_req > 0 || max_req > 0) { 1070 char *data; 1071 u_int len; 1072 1073 /* 1074 * Simulate EOF on interrupt: stop sending new requests and 1075 * allow outstanding requests to drain gracefully 1076 */ 1077 if (interrupted) { 1078 if (num_req == 0) /* If we haven't started yet... */ 1079 break; 1080 max_req = 0; 1081 } 1082 1083 /* Send some more requests */ 1084 while (num_req < max_req) { 1085 debug3("Request range %llu -> %llu (%d/%d)", 1086 (unsigned long long)offset, 1087 (unsigned long long)offset + buflen - 1, 1088 num_req, max_req); 1089 req = xmalloc(sizeof(*req)); 1090 req->id = conn->msg_id++; 1091 req->len = buflen; 1092 req->offset = offset; 1093 offset += buflen; 1094 num_req++; 1095 TAILQ_INSERT_TAIL(&requests, req, tq); 1096 send_read_request(conn, req->id, req->offset, 1097 req->len, handle, handle_len); 1098 } 1099 1100 buffer_clear(&msg); 1101 get_msg(conn, &msg); 1102 type = buffer_get_char(&msg); 1103 id = buffer_get_int(&msg); 1104 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 1105 1106 /* Find the request in our queue */ 1107 for (req = TAILQ_FIRST(&requests); 1108 req != NULL && req->id != id; 1109 req = TAILQ_NEXT(req, tq)) 1110 ; 1111 if (req == NULL) 1112 fatal("Unexpected reply %u", id); 1113 1114 switch (type) { 1115 case SSH2_FXP_STATUS: 1116 status = buffer_get_int(&msg); 1117 if (status != SSH2_FX_EOF) 1118 read_error = 1; 1119 max_req = 0; 1120 TAILQ_REMOVE(&requests, req, tq); 1121 xfree(req); 1122 num_req--; 1123 break; 1124 case SSH2_FXP_DATA: 1125 data = buffer_get_string(&msg, &len); 1126 debug3("Received data %llu -> %llu", 1127 (unsigned long long)req->offset, 1128 (unsigned long long)req->offset + len - 1); 1129 if (len > req->len) 1130 fatal("Received more data than asked for " 1131 "%u > %u", len, req->len); 1132 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 1133 atomicio(vwrite, local_fd, data, len) != len) && 1134 !write_error) { 1135 write_errno = errno; 1136 write_error = 1; 1137 max_req = 0; 1138 } 1139 progress_counter += len; 1140 xfree(data); 1141 1142 if (len == req->len) { 1143 TAILQ_REMOVE(&requests, req, tq); 1144 xfree(req); 1145 num_req--; 1146 } else { 1147 /* Resend the request for the missing data */ 1148 debug3("Short data block, re-requesting " 1149 "%llu -> %llu (%2d)", 1150 (unsigned long long)req->offset + len, 1151 (unsigned long long)req->offset + 1152 req->len - 1, num_req); 1153 req->id = conn->msg_id++; 1154 req->len -= len; 1155 req->offset += len; 1156 send_read_request(conn, req->id, 1157 req->offset, req->len, handle, handle_len); 1158 /* Reduce the request size */ 1159 if (len < buflen) 1160 buflen = MAX(MIN_READ_SIZE, len); 1161 } 1162 if (max_req > 0) { /* max_req = 0 iff EOF received */ 1163 if (size > 0 && offset > size) { 1164 /* Only one request at a time 1165 * after the expected EOF */ 1166 debug3("Finish at %llu (%2d)", 1167 (unsigned long long)offset, 1168 num_req); 1169 max_req = 1; 1170 } else if (max_req <= conn->num_requests) { 1171 ++max_req; 1172 } 1173 } 1174 break; 1175 default: 1176 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 1177 SSH2_FXP_DATA, type); 1178 } 1179 } 1180 1181 if (showprogress && size) 1182 stop_progress_meter(); 1183 1184 /* Sanity check */ 1185 if (TAILQ_FIRST(&requests) != NULL) 1186 fatal("Transfer complete, but requests still in queue"); 1187 1188 if (read_error) { 1189 error("Couldn't read from remote file \"%s\" : %s", 1190 remote_path, fx2txt(status)); 1191 do_close(conn, handle, handle_len); 1192 } else if (write_error) { 1193 error("Couldn't write to \"%s\": %s", local_path, 1194 strerror(write_errno)); 1195 status = -1; 1196 do_close(conn, handle, handle_len); 1197 } else { 1198 status = do_close(conn, handle, handle_len); 1199 1200 /* Override umask and utimes if asked */ 1201 if (pflag && fchmod(local_fd, mode) == -1) 1202 error("Couldn't set mode on \"%s\": %s", local_path, 1203 strerror(errno)); 1204 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 1205 struct timeval tv[2]; 1206 tv[0].tv_sec = a->atime; 1207 tv[1].tv_sec = a->mtime; 1208 tv[0].tv_usec = tv[1].tv_usec = 0; 1209 if (utimes(local_path, tv) == -1) 1210 error("Can't set times on \"%s\": %s", 1211 local_path, strerror(errno)); 1212 } 1213 } 1214 close(local_fd); 1215 buffer_free(&msg); 1216 xfree(handle); 1217 1218 return(status); 1219 } 1220 1221 static int 1222 download_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1223 Attrib *dirattrib, int pflag, int printflag, int depth) 1224 { 1225 int i, ret = 0; 1226 SFTP_DIRENT **dir_entries; 1227 char *filename, *new_src, *new_dst; 1228 mode_t mode = 0777; 1229 1230 if (depth >= MAX_DIR_DEPTH) { 1231 error("Maximum directory depth exceeded: %d levels", depth); 1232 return -1; 1233 } 1234 1235 if (dirattrib == NULL && 1236 (dirattrib = do_stat(conn, src, 1)) == NULL) { 1237 error("Unable to stat remote directory \"%s\"", src); 1238 return -1; 1239 } 1240 if (!S_ISDIR(dirattrib->perm)) { 1241 error("\"%s\" is not a directory", src); 1242 return -1; 1243 } 1244 if (printflag) 1245 printf("Retrieving %s\n", src); 1246 1247 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1248 mode = dirattrib->perm & 01777; 1249 else { 1250 debug("Server did not send permissions for " 1251 "directory \"%s\"", dst); 1252 } 1253 1254 if (mkdir(dst, mode) == -1 && errno != EEXIST) { 1255 error("mkdir %s: %s", dst, strerror(errno)); 1256 return -1; 1257 } 1258 1259 if (do_readdir(conn, src, &dir_entries) == -1) { 1260 error("%s: Failed to get directory contents", src); 1261 return -1; 1262 } 1263 1264 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 1265 filename = dir_entries[i]->filename; 1266 1267 new_dst = path_append(dst, filename); 1268 new_src = path_append(src, filename); 1269 1270 if (S_ISDIR(dir_entries[i]->a.perm)) { 1271 if (strcmp(filename, ".") == 0 || 1272 strcmp(filename, "..") == 0) 1273 continue; 1274 if (download_dir_internal(conn, new_src, new_dst, 1275 &(dir_entries[i]->a), pflag, printflag, 1276 depth + 1) == -1) 1277 ret = -1; 1278 } else if (S_ISREG(dir_entries[i]->a.perm) ) { 1279 if (do_download(conn, new_src, new_dst, 1280 &(dir_entries[i]->a), pflag) == -1) { 1281 error("Download of file %s to %s failed", 1282 new_src, new_dst); 1283 ret = -1; 1284 } 1285 } else 1286 logit("%s: not a regular file\n", new_src); 1287 1288 xfree(new_dst); 1289 xfree(new_src); 1290 } 1291 1292 if (pflag) { 1293 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1294 struct timeval tv[2]; 1295 tv[0].tv_sec = dirattrib->atime; 1296 tv[1].tv_sec = dirattrib->mtime; 1297 tv[0].tv_usec = tv[1].tv_usec = 0; 1298 if (utimes(dst, tv) == -1) 1299 error("Can't set times on \"%s\": %s", 1300 dst, strerror(errno)); 1301 } else 1302 debug("Server did not send times for directory " 1303 "\"%s\"", dst); 1304 } 1305 1306 free_sftp_dirents(dir_entries); 1307 1308 return ret; 1309 } 1310 1311 int 1312 download_dir(struct sftp_conn *conn, char *src, char *dst, 1313 Attrib *dirattrib, int pflag, int printflag) 1314 { 1315 char *src_canon; 1316 int ret; 1317 1318 if ((src_canon = do_realpath(conn, src)) == NULL) { 1319 error("Unable to canonicalise path \"%s\"", src); 1320 return -1; 1321 } 1322 1323 ret = download_dir_internal(conn, src_canon, dst, 1324 dirattrib, pflag, printflag, 0); 1325 xfree(src_canon); 1326 return ret; 1327 } 1328 1329 int 1330 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 1331 int pflag) 1332 { 1333 int local_fd; 1334 int status = SSH2_FX_OK; 1335 u_int handle_len, id, type; 1336 off_t offset; 1337 char *handle, *data; 1338 Buffer msg; 1339 struct stat sb; 1340 Attrib a; 1341 u_int32_t startid; 1342 u_int32_t ackid; 1343 struct outstanding_ack { 1344 u_int id; 1345 u_int len; 1346 off_t offset; 1347 TAILQ_ENTRY(outstanding_ack) tq; 1348 }; 1349 TAILQ_HEAD(ackhead, outstanding_ack) acks; 1350 struct outstanding_ack *ack = NULL; 1351 1352 TAILQ_INIT(&acks); 1353 1354 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 1355 error("Couldn't open local file \"%s\" for reading: %s", 1356 local_path, strerror(errno)); 1357 return(-1); 1358 } 1359 if (fstat(local_fd, &sb) == -1) { 1360 error("Couldn't fstat local file \"%s\": %s", 1361 local_path, strerror(errno)); 1362 close(local_fd); 1363 return(-1); 1364 } 1365 if (!S_ISREG(sb.st_mode)) { 1366 error("%s is not a regular file", local_path); 1367 close(local_fd); 1368 return(-1); 1369 } 1370 stat_to_attrib(&sb, &a); 1371 1372 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1373 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1374 a.perm &= 0777; 1375 if (!pflag) 1376 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1377 1378 buffer_init(&msg); 1379 1380 /* Send open request */ 1381 id = conn->msg_id++; 1382 buffer_put_char(&msg, SSH2_FXP_OPEN); 1383 buffer_put_int(&msg, id); 1384 buffer_put_cstring(&msg, remote_path); 1385 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 1386 encode_attrib(&msg, &a); 1387 send_msg(conn, &msg); 1388 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1389 1390 buffer_clear(&msg); 1391 1392 handle = get_handle(conn, id, &handle_len, 1393 "remote open(\"%s\")", remote_path); 1394 if (handle == NULL) { 1395 close(local_fd); 1396 buffer_free(&msg); 1397 return -1; 1398 } 1399 1400 startid = ackid = id + 1; 1401 data = xmalloc(conn->transfer_buflen); 1402 1403 /* Read from local and write to remote */ 1404 offset = 0; 1405 if (showprogress) 1406 start_progress_meter(local_path, sb.st_size, &offset); 1407 1408 for (;;) { 1409 int len; 1410 1411 /* 1412 * Can't use atomicio here because it returns 0 on EOF, 1413 * thus losing the last block of the file. 1414 * Simulate an EOF on interrupt, allowing ACKs from the 1415 * server to drain. 1416 */ 1417 if (interrupted || status != SSH2_FX_OK) 1418 len = 0; 1419 else do 1420 len = read(local_fd, data, conn->transfer_buflen); 1421 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 1422 1423 if (len == -1) 1424 fatal("Couldn't read from \"%s\": %s", local_path, 1425 strerror(errno)); 1426 1427 if (len != 0) { 1428 ack = xmalloc(sizeof(*ack)); 1429 ack->id = ++id; 1430 ack->offset = offset; 1431 ack->len = len; 1432 TAILQ_INSERT_TAIL(&acks, ack, tq); 1433 1434 buffer_clear(&msg); 1435 buffer_put_char(&msg, SSH2_FXP_WRITE); 1436 buffer_put_int(&msg, ack->id); 1437 buffer_put_string(&msg, handle, handle_len); 1438 buffer_put_int64(&msg, offset); 1439 buffer_put_string(&msg, data, len); 1440 send_msg(conn, &msg); 1441 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1442 id, (unsigned long long)offset, len); 1443 } else if (TAILQ_FIRST(&acks) == NULL) 1444 break; 1445 1446 if (ack == NULL) 1447 fatal("Unexpected ACK %u", id); 1448 1449 if (id == startid || len == 0 || 1450 id - ackid >= conn->num_requests) { 1451 u_int r_id; 1452 1453 buffer_clear(&msg); 1454 get_msg(conn, &msg); 1455 type = buffer_get_char(&msg); 1456 r_id = buffer_get_int(&msg); 1457 1458 if (type != SSH2_FXP_STATUS) 1459 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1460 "got %d", SSH2_FXP_STATUS, type); 1461 1462 status = buffer_get_int(&msg); 1463 debug3("SSH2_FXP_STATUS %d", status); 1464 1465 /* Find the request in our queue */ 1466 for (ack = TAILQ_FIRST(&acks); 1467 ack != NULL && ack->id != r_id; 1468 ack = TAILQ_NEXT(ack, tq)) 1469 ; 1470 if (ack == NULL) 1471 fatal("Can't find request for ID %u", r_id); 1472 TAILQ_REMOVE(&acks, ack, tq); 1473 debug3("In write loop, ack for %u %u bytes at %lld", 1474 ack->id, ack->len, (long long)ack->offset); 1475 ++ackid; 1476 xfree(ack); 1477 } 1478 offset += len; 1479 if (offset < 0) 1480 fatal("%s: offset < 0", __func__); 1481 } 1482 buffer_free(&msg); 1483 1484 if (showprogress) 1485 stop_progress_meter(); 1486 xfree(data); 1487 1488 if (status != SSH2_FX_OK) { 1489 error("Couldn't write to remote file \"%s\": %s", 1490 remote_path, fx2txt(status)); 1491 status = -1; 1492 } 1493 1494 if (close(local_fd) == -1) { 1495 error("Couldn't close local file \"%s\": %s", local_path, 1496 strerror(errno)); 1497 status = -1; 1498 } 1499 1500 /* Override umask and utimes if asked */ 1501 if (pflag) 1502 do_fsetstat(conn, handle, handle_len, &a); 1503 1504 if (do_close(conn, handle, handle_len) != SSH2_FX_OK) 1505 status = -1; 1506 xfree(handle); 1507 1508 return status; 1509 } 1510 1511 static int 1512 upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1513 int pflag, int printflag, int depth) 1514 { 1515 int ret = 0, status; 1516 DIR *dirp; 1517 struct dirent *dp; 1518 char *filename, *new_src, *new_dst; 1519 struct stat sb; 1520 Attrib a; 1521 1522 if (depth >= MAX_DIR_DEPTH) { 1523 error("Maximum directory depth exceeded: %d levels", depth); 1524 return -1; 1525 } 1526 1527 if (stat(src, &sb) == -1) { 1528 error("Couldn't stat directory \"%s\": %s", 1529 src, strerror(errno)); 1530 return -1; 1531 } 1532 if (!S_ISDIR(sb.st_mode)) { 1533 error("\"%s\" is not a directory", src); 1534 return -1; 1535 } 1536 if (printflag) 1537 printf("Entering %s\n", src); 1538 1539 attrib_clear(&a); 1540 stat_to_attrib(&sb, &a); 1541 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1542 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1543 a.perm &= 01777; 1544 if (!pflag) 1545 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1546 1547 status = do_mkdir(conn, dst, &a, 0); 1548 /* 1549 * we lack a portable status for errno EEXIST, 1550 * so if we get a SSH2_FX_FAILURE back we must check 1551 * if it was created successfully. 1552 */ 1553 if (status != SSH2_FX_OK) { 1554 if (status != SSH2_FX_FAILURE) 1555 return -1; 1556 if (do_stat(conn, dst, 0) == NULL) 1557 return -1; 1558 } 1559 1560 if ((dirp = opendir(src)) == NULL) { 1561 error("Failed to open dir \"%s\": %s", src, strerror(errno)); 1562 return -1; 1563 } 1564 1565 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 1566 if (dp->d_ino == 0) 1567 continue; 1568 filename = dp->d_name; 1569 new_dst = path_append(dst, filename); 1570 new_src = path_append(src, filename); 1571 1572 if (lstat(new_src, &sb) == -1) { 1573 logit("%s: lstat failed: %s", filename, 1574 strerror(errno)); 1575 ret = -1; 1576 } else if (S_ISDIR(sb.st_mode)) { 1577 if (strcmp(filename, ".") == 0 || 1578 strcmp(filename, "..") == 0) 1579 continue; 1580 1581 if (upload_dir_internal(conn, new_src, new_dst, 1582 pflag, printflag, depth + 1) == -1) 1583 ret = -1; 1584 } else if (S_ISREG(sb.st_mode)) { 1585 if (do_upload(conn, new_src, new_dst, pflag) == -1) { 1586 error("Uploading of file %s to %s failed!", 1587 new_src, new_dst); 1588 ret = -1; 1589 } 1590 } else 1591 logit("%s: not a regular file\n", filename); 1592 xfree(new_dst); 1593 xfree(new_src); 1594 } 1595 1596 do_setstat(conn, dst, &a); 1597 1598 (void) closedir(dirp); 1599 return ret; 1600 } 1601 1602 int 1603 upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag, 1604 int pflag) 1605 { 1606 char *dst_canon; 1607 int ret; 1608 1609 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 1610 error("Unable to canonicalise path \"%s\"", dst); 1611 return -1; 1612 } 1613 1614 ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0); 1615 xfree(dst_canon); 1616 return ret; 1617 } 1618 1619 char * 1620 path_append(char *p1, char *p2) 1621 { 1622 char *ret; 1623 size_t len = strlen(p1) + strlen(p2) + 2; 1624 1625 ret = xmalloc(len); 1626 strlcpy(ret, p1, len); 1627 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 1628 strlcat(ret, "/", len); 1629 strlcat(ret, p2, len); 1630 1631 return(ret); 1632 } 1633 1634