1 /* $NetBSD: sftp-client.c,v 1.5 2011/07/25 03:03:11 christos Exp $ */ 2 /* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 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.5 2011/07/25 03:03:11 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 buffer_clear(&msg); 462 463 handle = get_handle(conn, id, &handle_len, 464 "remote readdir(\"%s\")", path); 465 if (handle == NULL) 466 return -1; 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 return(status); 510 } 511 } else if (type != SSH2_FXP_NAME) 512 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 513 SSH2_FXP_NAME, type); 514 515 count = buffer_get_int(&msg); 516 if (count == 0) 517 break; 518 debug3("Received %d SSH2_FXP_NAME responses", count); 519 for (i = 0; i < count; i++) { 520 char *filename, *longname; 521 Attrib *a; 522 523 filename = buffer_get_string(&msg, NULL); 524 longname = buffer_get_string(&msg, NULL); 525 a = decode_attrib(&msg); 526 527 if (printflag) 528 printf("%s\n", longname); 529 530 /* 531 * Directory entries should never contain '/' 532 * These can be used to attack recursive ops 533 * (e.g. send '../../../../etc/passwd') 534 */ 535 if (strchr(filename, '/') != NULL) { 536 error("Server sent suspect path \"%s\" " 537 "during readdir of \"%s\"", filename, path); 538 goto next; 539 } 540 541 if (dir) { 542 *dir = xrealloc(*dir, ents + 2, sizeof(**dir)); 543 (*dir)[ents] = xmalloc(sizeof(***dir)); 544 (*dir)[ents]->filename = xstrdup(filename); 545 (*dir)[ents]->longname = xstrdup(longname); 546 memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 547 (*dir)[++ents] = NULL; 548 } 549 next: 550 xfree(filename); 551 xfree(longname); 552 } 553 } 554 555 buffer_free(&msg); 556 do_close(conn, handle, handle_len); 557 xfree(handle); 558 559 /* Don't return partial matches on interrupt */ 560 if (interrupted && dir != NULL && *dir != NULL) { 561 free_sftp_dirents(*dir); 562 *dir = xmalloc(sizeof(**dir)); 563 **dir = NULL; 564 } 565 566 return 0; 567 } 568 569 int 570 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) 571 { 572 return(do_lsreaddir(conn, path, 0, dir)); 573 } 574 575 void free_sftp_dirents(SFTP_DIRENT **s) 576 { 577 int i; 578 579 for (i = 0; s[i]; i++) { 580 xfree(s[i]->filename); 581 xfree(s[i]->longname); 582 xfree(s[i]); 583 } 584 xfree(s); 585 } 586 587 int 588 do_rm(struct sftp_conn *conn, char *path) 589 { 590 u_int status, id; 591 592 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 593 594 id = conn->msg_id++; 595 send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); 596 status = get_status(conn, id); 597 if (status != SSH2_FX_OK) 598 error("Couldn't delete file: %s", fx2txt(status)); 599 return(status); 600 } 601 602 int 603 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) 604 { 605 u_int status, id; 606 607 id = conn->msg_id++; 608 send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, 609 strlen(path), a); 610 611 status = get_status(conn, id); 612 if (status != SSH2_FX_OK && printflag) 613 error("Couldn't create directory: %s", fx2txt(status)); 614 615 return(status); 616 } 617 618 int 619 do_rmdir(struct sftp_conn *conn, char *path) 620 { 621 u_int status, id; 622 623 id = conn->msg_id++; 624 send_string_request(conn, id, SSH2_FXP_RMDIR, path, 625 strlen(path)); 626 627 status = get_status(conn, id); 628 if (status != SSH2_FX_OK) 629 error("Couldn't remove directory: %s", fx2txt(status)); 630 631 return(status); 632 } 633 634 Attrib * 635 do_stat(struct sftp_conn *conn, const char *path, int quiet) 636 { 637 u_int id; 638 639 id = conn->msg_id++; 640 641 send_string_request(conn, id, 642 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 643 path, strlen(path)); 644 645 return(get_decode_stat(conn, id, quiet)); 646 } 647 648 Attrib * 649 do_lstat(struct sftp_conn *conn, const char *path, int quiet) 650 { 651 u_int id; 652 653 if (conn->version == 0) { 654 if (quiet) 655 debug("Server version does not support lstat operation"); 656 else 657 logit("Server version does not support lstat operation"); 658 return(do_stat(conn, path, quiet)); 659 } 660 661 id = conn->msg_id++; 662 send_string_request(conn, id, SSH2_FXP_LSTAT, path, 663 strlen(path)); 664 665 return(get_decode_stat(conn, id, quiet)); 666 } 667 668 #ifdef notyet 669 Attrib * 670 do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) 671 { 672 u_int id; 673 674 id = conn->msg_id++; 675 send_string_request(conn, id, SSH2_FXP_FSTAT, handle, 676 handle_len); 677 678 return(get_decode_stat(conn, id, quiet)); 679 } 680 #endif 681 682 int 683 do_setstat(struct sftp_conn *conn, char *path, Attrib *a) 684 { 685 u_int status, id; 686 687 id = conn->msg_id++; 688 send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, 689 strlen(path), a); 690 691 status = get_status(conn, id); 692 if (status != SSH2_FX_OK) 693 error("Couldn't setstat on \"%s\": %s", path, 694 fx2txt(status)); 695 696 return(status); 697 } 698 699 int 700 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, 701 Attrib *a) 702 { 703 u_int status, id; 704 705 id = conn->msg_id++; 706 send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, 707 handle_len, a); 708 709 status = get_status(conn, id); 710 if (status != SSH2_FX_OK) 711 error("Couldn't fsetstat: %s", fx2txt(status)); 712 713 return(status); 714 } 715 716 char * 717 do_realpath(struct sftp_conn *conn, const char *path) 718 { 719 Buffer msg; 720 u_int type, expected_id, count, id; 721 char *filename, *longname; 722 Attrib *a; 723 724 expected_id = id = conn->msg_id++; 725 send_string_request(conn, id, SSH2_FXP_REALPATH, path, 726 strlen(path)); 727 728 buffer_init(&msg); 729 730 get_msg(conn, &msg); 731 type = buffer_get_char(&msg); 732 id = buffer_get_int(&msg); 733 734 if (id != expected_id) 735 fatal("ID mismatch (%u != %u)", id, expected_id); 736 737 if (type == SSH2_FXP_STATUS) { 738 u_int status = buffer_get_int(&msg); 739 740 error("Couldn't canonicalise: %s", fx2txt(status)); 741 buffer_free(&msg); 742 return NULL; 743 } else if (type != SSH2_FXP_NAME) 744 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 745 SSH2_FXP_NAME, type); 746 747 count = buffer_get_int(&msg); 748 if (count != 1) 749 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 750 751 filename = buffer_get_string(&msg, NULL); 752 longname = buffer_get_string(&msg, NULL); 753 a = decode_attrib(&msg); 754 755 debug3("SSH_FXP_REALPATH %s -> %s", path, filename); 756 757 xfree(longname); 758 759 buffer_free(&msg); 760 761 return(filename); 762 } 763 764 int 765 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) 766 { 767 Buffer msg; 768 u_int status, id; 769 770 buffer_init(&msg); 771 772 /* Send rename request */ 773 id = conn->msg_id++; 774 if ((conn->exts & SFTP_EXT_POSIX_RENAME)) { 775 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 776 buffer_put_int(&msg, id); 777 buffer_put_cstring(&msg, "posix-rename@openssh.com"); 778 } else { 779 buffer_put_char(&msg, SSH2_FXP_RENAME); 780 buffer_put_int(&msg, id); 781 } 782 buffer_put_cstring(&msg, oldpath); 783 buffer_put_cstring(&msg, newpath); 784 send_msg(conn, &msg); 785 debug3("Sent message %s \"%s\" -> \"%s\"", 786 (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : 787 "SSH2_FXP_RENAME", oldpath, newpath); 788 buffer_free(&msg); 789 790 status = get_status(conn, id); 791 if (status != SSH2_FX_OK) 792 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 793 newpath, fx2txt(status)); 794 795 return(status); 796 } 797 798 int 799 do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath) 800 { 801 Buffer msg; 802 u_int status, id; 803 804 buffer_init(&msg); 805 806 /* Send link request */ 807 id = conn->msg_id++; 808 if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { 809 error("Server does not support hardlink@openssh.com extension"); 810 return -1; 811 } 812 813 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 814 buffer_put_int(&msg, id); 815 buffer_put_cstring(&msg, "hardlink@openssh.com"); 816 buffer_put_cstring(&msg, oldpath); 817 buffer_put_cstring(&msg, newpath); 818 send_msg(conn, &msg); 819 debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", 820 oldpath, newpath); 821 buffer_free(&msg); 822 823 status = get_status(conn, id); 824 if (status != SSH2_FX_OK) 825 error("Couldn't link file \"%s\" to \"%s\": %s", oldpath, 826 newpath, fx2txt(status)); 827 828 return(status); 829 } 830 831 int 832 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) 833 { 834 Buffer msg; 835 u_int status, id; 836 837 if (conn->version < 3) { 838 error("This server does not support the symlink operation"); 839 return(SSH2_FX_OP_UNSUPPORTED); 840 } 841 842 buffer_init(&msg); 843 844 /* Send symlink request */ 845 id = conn->msg_id++; 846 buffer_put_char(&msg, SSH2_FXP_SYMLINK); 847 buffer_put_int(&msg, id); 848 buffer_put_cstring(&msg, oldpath); 849 buffer_put_cstring(&msg, newpath); 850 send_msg(conn, &msg); 851 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 852 newpath); 853 buffer_free(&msg); 854 855 status = get_status(conn, id); 856 if (status != SSH2_FX_OK) 857 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 858 newpath, fx2txt(status)); 859 860 return(status); 861 } 862 863 #ifdef notyet 864 char * 865 do_readlink(struct sftp_conn *conn, char *path) 866 { 867 Buffer msg; 868 u_int type, expected_id, count, id; 869 char *filename, *longname; 870 Attrib *a; 871 872 expected_id = id = conn->msg_id++; 873 send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); 874 875 buffer_init(&msg); 876 877 get_msg(conn, &msg); 878 type = buffer_get_char(&msg); 879 id = buffer_get_int(&msg); 880 881 if (id != expected_id) 882 fatal("ID mismatch (%u != %u)", id, expected_id); 883 884 if (type == SSH2_FXP_STATUS) { 885 u_int status = buffer_get_int(&msg); 886 887 error("Couldn't readlink: %s", fx2txt(status)); 888 return(NULL); 889 } else if (type != SSH2_FXP_NAME) 890 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 891 SSH2_FXP_NAME, type); 892 893 count = buffer_get_int(&msg); 894 if (count != 1) 895 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 896 897 filename = buffer_get_string(&msg, NULL); 898 longname = buffer_get_string(&msg, NULL); 899 a = decode_attrib(&msg); 900 901 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 902 903 xfree(longname); 904 905 buffer_free(&msg); 906 907 return(filename); 908 } 909 #endif 910 911 int 912 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, 913 int quiet) 914 { 915 Buffer msg; 916 u_int id; 917 918 if ((conn->exts & SFTP_EXT_STATVFS) == 0) { 919 error("Server does not support statvfs@openssh.com extension"); 920 return -1; 921 } 922 923 id = conn->msg_id++; 924 925 buffer_init(&msg); 926 buffer_clear(&msg); 927 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 928 buffer_put_int(&msg, id); 929 buffer_put_cstring(&msg, "statvfs@openssh.com"); 930 buffer_put_cstring(&msg, path); 931 send_msg(conn, &msg); 932 buffer_free(&msg); 933 934 return get_decode_statvfs(conn, st, id, quiet); 935 } 936 937 #ifdef notyet 938 int 939 do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, 940 struct sftp_statvfs *st, int quiet) 941 { 942 Buffer msg; 943 u_int id; 944 945 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { 946 error("Server does not support fstatvfs@openssh.com extension"); 947 return -1; 948 } 949 950 id = conn->msg_id++; 951 952 buffer_init(&msg); 953 buffer_clear(&msg); 954 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 955 buffer_put_int(&msg, id); 956 buffer_put_cstring(&msg, "fstatvfs@openssh.com"); 957 buffer_put_string(&msg, handle, handle_len); 958 send_msg(conn, &msg); 959 buffer_free(&msg); 960 961 return get_decode_statvfs(conn, st, id, quiet); 962 } 963 #endif 964 965 static void 966 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, 967 u_int len, char *handle, u_int handle_len) 968 { 969 Buffer msg; 970 971 buffer_init(&msg); 972 buffer_clear(&msg); 973 buffer_put_char(&msg, SSH2_FXP_READ); 974 buffer_put_int(&msg, id); 975 buffer_put_string(&msg, handle, handle_len); 976 buffer_put_int64(&msg, offset); 977 buffer_put_int(&msg, len); 978 send_msg(conn, &msg); 979 buffer_free(&msg); 980 } 981 982 int 983 do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 984 Attrib *a, int pflag) 985 { 986 Attrib junk; 987 Buffer msg; 988 char *handle; 989 int local_fd, status = 0, write_error; 990 int read_error, write_errno; 991 u_int64_t offset, size; 992 u_int handle_len, mode, type, id, buflen, num_req, max_req; 993 off_t progress_counter; 994 struct request { 995 u_int id; 996 u_int len; 997 u_int64_t offset; 998 TAILQ_ENTRY(request) tq; 999 }; 1000 TAILQ_HEAD(reqhead, request) requests; 1001 struct request *req; 1002 1003 status = -1; 1004 TAILQ_INIT(&requests); 1005 1006 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 1007 return -1; 1008 1009 /* Do not preserve set[ug]id here, as we do not preserve ownership */ 1010 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1011 mode = a->perm & 0777; 1012 else 1013 mode = 0666; 1014 1015 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 1016 (!S_ISREG(a->perm))) { 1017 error("Cannot download non-regular file: %s", remote_path); 1018 return(-1); 1019 } 1020 1021 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 1022 size = a->size; 1023 else 1024 size = 0; 1025 1026 buflen = conn->transfer_buflen; 1027 buffer_init(&msg); 1028 1029 /* Send open request */ 1030 id = conn->msg_id++; 1031 buffer_put_char(&msg, SSH2_FXP_OPEN); 1032 buffer_put_int(&msg, id); 1033 buffer_put_cstring(&msg, remote_path); 1034 buffer_put_int(&msg, SSH2_FXF_READ); 1035 attrib_clear(&junk); /* Send empty attributes */ 1036 encode_attrib(&msg, &junk); 1037 send_msg(conn, &msg); 1038 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1039 1040 handle = get_handle(conn, id, &handle_len, 1041 "remote open(\"%s\")", remote_path); 1042 if (handle == NULL) { 1043 buffer_free(&msg); 1044 return(-1); 1045 } 1046 1047 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, 1048 mode | S_IWRITE); 1049 if (local_fd == -1) { 1050 error("Couldn't open local file \"%s\" for writing: %s", 1051 local_path, strerror(errno)); 1052 do_close(conn, handle, handle_len); 1053 buffer_free(&msg); 1054 xfree(handle); 1055 return(-1); 1056 } 1057 1058 /* Read from remote and write to local */ 1059 write_error = read_error = write_errno = num_req = offset = 0; 1060 max_req = 1; 1061 progress_counter = 0; 1062 1063 if (showprogress && size != 0) 1064 start_progress_meter(remote_path, size, &progress_counter); 1065 1066 while (num_req > 0 || max_req > 0) { 1067 char *data; 1068 u_int len; 1069 1070 /* 1071 * Simulate EOF on interrupt: stop sending new requests and 1072 * allow outstanding requests to drain gracefully 1073 */ 1074 if (interrupted) { 1075 if (num_req == 0) /* If we haven't started yet... */ 1076 break; 1077 max_req = 0; 1078 } 1079 1080 /* Send some more requests */ 1081 while (num_req < max_req) { 1082 debug3("Request range %llu -> %llu (%d/%d)", 1083 (unsigned long long)offset, 1084 (unsigned long long)offset + buflen - 1, 1085 num_req, max_req); 1086 req = xmalloc(sizeof(*req)); 1087 req->id = conn->msg_id++; 1088 req->len = buflen; 1089 req->offset = offset; 1090 offset += buflen; 1091 num_req++; 1092 TAILQ_INSERT_TAIL(&requests, req, tq); 1093 send_read_request(conn, req->id, req->offset, 1094 req->len, handle, handle_len); 1095 } 1096 1097 buffer_clear(&msg); 1098 get_msg(conn, &msg); 1099 type = buffer_get_char(&msg); 1100 id = buffer_get_int(&msg); 1101 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 1102 1103 /* Find the request in our queue */ 1104 for (req = TAILQ_FIRST(&requests); 1105 req != NULL && req->id != id; 1106 req = TAILQ_NEXT(req, tq)) 1107 ; 1108 if (req == NULL) 1109 fatal("Unexpected reply %u", id); 1110 1111 switch (type) { 1112 case SSH2_FXP_STATUS: 1113 status = buffer_get_int(&msg); 1114 if (status != SSH2_FX_EOF) 1115 read_error = 1; 1116 max_req = 0; 1117 TAILQ_REMOVE(&requests, req, tq); 1118 xfree(req); 1119 num_req--; 1120 break; 1121 case SSH2_FXP_DATA: 1122 data = buffer_get_string(&msg, &len); 1123 debug3("Received data %llu -> %llu", 1124 (unsigned long long)req->offset, 1125 (unsigned long long)req->offset + len - 1); 1126 if (len > req->len) 1127 fatal("Received more data than asked for " 1128 "%u > %u", len, req->len); 1129 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 1130 atomicio(vwrite, local_fd, data, len) != len) && 1131 !write_error) { 1132 write_errno = errno; 1133 write_error = 1; 1134 max_req = 0; 1135 } 1136 progress_counter += len; 1137 xfree(data); 1138 1139 if (len == req->len) { 1140 TAILQ_REMOVE(&requests, req, tq); 1141 xfree(req); 1142 num_req--; 1143 } else { 1144 /* Resend the request for the missing data */ 1145 debug3("Short data block, re-requesting " 1146 "%llu -> %llu (%2d)", 1147 (unsigned long long)req->offset + len, 1148 (unsigned long long)req->offset + 1149 req->len - 1, num_req); 1150 req->id = conn->msg_id++; 1151 req->len -= len; 1152 req->offset += len; 1153 send_read_request(conn, req->id, 1154 req->offset, req->len, handle, handle_len); 1155 /* Reduce the request size */ 1156 if (len < buflen) 1157 buflen = MAX(MIN_READ_SIZE, len); 1158 } 1159 if (max_req > 0) { /* max_req = 0 iff EOF received */ 1160 if (size > 0 && offset > size) { 1161 /* Only one request at a time 1162 * after the expected EOF */ 1163 debug3("Finish at %llu (%2d)", 1164 (unsigned long long)offset, 1165 num_req); 1166 max_req = 1; 1167 } else if (max_req <= conn->num_requests) { 1168 ++max_req; 1169 } 1170 } 1171 break; 1172 default: 1173 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 1174 SSH2_FXP_DATA, type); 1175 } 1176 } 1177 1178 if (showprogress && size) 1179 stop_progress_meter(); 1180 1181 /* Sanity check */ 1182 if (TAILQ_FIRST(&requests) != NULL) 1183 fatal("Transfer complete, but requests still in queue"); 1184 1185 if (read_error) { 1186 error("Couldn't read from remote file \"%s\" : %s", 1187 remote_path, fx2txt(status)); 1188 do_close(conn, handle, handle_len); 1189 } else if (write_error) { 1190 error("Couldn't write to \"%s\": %s", local_path, 1191 strerror(write_errno)); 1192 status = -1; 1193 do_close(conn, handle, handle_len); 1194 } else { 1195 status = do_close(conn, handle, handle_len); 1196 1197 /* Override umask and utimes if asked */ 1198 if (pflag && fchmod(local_fd, mode) == -1) 1199 error("Couldn't set mode on \"%s\": %s", local_path, 1200 strerror(errno)); 1201 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 1202 struct timeval tv[2]; 1203 tv[0].tv_sec = a->atime; 1204 tv[1].tv_sec = a->mtime; 1205 tv[0].tv_usec = tv[1].tv_usec = 0; 1206 if (utimes(local_path, tv) == -1) 1207 error("Can't set times on \"%s\": %s", 1208 local_path, strerror(errno)); 1209 } 1210 } 1211 close(local_fd); 1212 buffer_free(&msg); 1213 xfree(handle); 1214 1215 return(status); 1216 } 1217 1218 static int 1219 download_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1220 Attrib *dirattrib, int pflag, int printflag, int depth) 1221 { 1222 int i, ret = 0; 1223 SFTP_DIRENT **dir_entries; 1224 char *filename, *new_src, *new_dst; 1225 mode_t mode = 0777; 1226 1227 if (depth >= MAX_DIR_DEPTH) { 1228 error("Maximum directory depth exceeded: %d levels", depth); 1229 return -1; 1230 } 1231 1232 if (dirattrib == NULL && 1233 (dirattrib = do_stat(conn, src, 1)) == NULL) { 1234 error("Unable to stat remote directory \"%s\"", src); 1235 return -1; 1236 } 1237 if (!S_ISDIR(dirattrib->perm)) { 1238 error("\"%s\" is not a directory", src); 1239 return -1; 1240 } 1241 if (printflag) 1242 printf("Retrieving %s\n", src); 1243 1244 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1245 mode = dirattrib->perm & 01777; 1246 else { 1247 debug("Server did not send permissions for " 1248 "directory \"%s\"", dst); 1249 } 1250 1251 if (mkdir(dst, mode) == -1 && errno != EEXIST) { 1252 error("mkdir %s: %s", dst, strerror(errno)); 1253 return -1; 1254 } 1255 1256 if (do_readdir(conn, src, &dir_entries) == -1) { 1257 error("%s: Failed to get directory contents", src); 1258 return -1; 1259 } 1260 1261 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 1262 filename = dir_entries[i]->filename; 1263 1264 new_dst = path_append(dst, filename); 1265 new_src = path_append(src, filename); 1266 1267 if (S_ISDIR(dir_entries[i]->a.perm)) { 1268 if (strcmp(filename, ".") == 0 || 1269 strcmp(filename, "..") == 0) 1270 continue; 1271 if (download_dir_internal(conn, new_src, new_dst, 1272 &(dir_entries[i]->a), pflag, printflag, 1273 depth + 1) == -1) 1274 ret = -1; 1275 } else if (S_ISREG(dir_entries[i]->a.perm) ) { 1276 if (do_download(conn, new_src, new_dst, 1277 &(dir_entries[i]->a), pflag) == -1) { 1278 error("Download of file %s to %s failed", 1279 new_src, new_dst); 1280 ret = -1; 1281 } 1282 } else 1283 logit("%s: not a regular file\n", new_src); 1284 1285 xfree(new_dst); 1286 xfree(new_src); 1287 } 1288 1289 if (pflag) { 1290 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1291 struct timeval tv[2]; 1292 tv[0].tv_sec = dirattrib->atime; 1293 tv[1].tv_sec = dirattrib->mtime; 1294 tv[0].tv_usec = tv[1].tv_usec = 0; 1295 if (utimes(dst, tv) == -1) 1296 error("Can't set times on \"%s\": %s", 1297 dst, strerror(errno)); 1298 } else 1299 debug("Server did not send times for directory " 1300 "\"%s\"", dst); 1301 } 1302 1303 free_sftp_dirents(dir_entries); 1304 1305 return ret; 1306 } 1307 1308 int 1309 download_dir(struct sftp_conn *conn, char *src, char *dst, 1310 Attrib *dirattrib, int pflag, int printflag) 1311 { 1312 char *src_canon; 1313 int ret; 1314 1315 if ((src_canon = do_realpath(conn, src)) == NULL) { 1316 error("Unable to canonicalise path \"%s\"", src); 1317 return -1; 1318 } 1319 1320 ret = download_dir_internal(conn, src_canon, dst, 1321 dirattrib, pflag, printflag, 0); 1322 xfree(src_canon); 1323 return ret; 1324 } 1325 1326 int 1327 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 1328 int pflag) 1329 { 1330 int local_fd; 1331 int status = SSH2_FX_OK; 1332 u_int handle_len, id, type; 1333 off_t offset; 1334 char *handle, *data; 1335 Buffer msg; 1336 struct stat sb; 1337 Attrib a; 1338 u_int32_t startid; 1339 u_int32_t ackid; 1340 struct outstanding_ack { 1341 u_int id; 1342 u_int len; 1343 off_t offset; 1344 TAILQ_ENTRY(outstanding_ack) tq; 1345 }; 1346 TAILQ_HEAD(ackhead, outstanding_ack) acks; 1347 struct outstanding_ack *ack = NULL; 1348 1349 TAILQ_INIT(&acks); 1350 1351 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 1352 error("Couldn't open local file \"%s\" for reading: %s", 1353 local_path, strerror(errno)); 1354 return(-1); 1355 } 1356 if (fstat(local_fd, &sb) == -1) { 1357 error("Couldn't fstat local file \"%s\": %s", 1358 local_path, strerror(errno)); 1359 close(local_fd); 1360 return(-1); 1361 } 1362 if (!S_ISREG(sb.st_mode)) { 1363 error("%s is not a regular file", local_path); 1364 close(local_fd); 1365 return(-1); 1366 } 1367 stat_to_attrib(&sb, &a); 1368 1369 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1370 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1371 a.perm &= 0777; 1372 if (!pflag) 1373 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1374 1375 buffer_init(&msg); 1376 1377 /* Send open request */ 1378 id = conn->msg_id++; 1379 buffer_put_char(&msg, SSH2_FXP_OPEN); 1380 buffer_put_int(&msg, id); 1381 buffer_put_cstring(&msg, remote_path); 1382 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 1383 encode_attrib(&msg, &a); 1384 send_msg(conn, &msg); 1385 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1386 1387 buffer_clear(&msg); 1388 1389 handle = get_handle(conn, id, &handle_len, 1390 "remote open(\"%s\")", remote_path); 1391 if (handle == NULL) { 1392 close(local_fd); 1393 buffer_free(&msg); 1394 return -1; 1395 } 1396 1397 startid = ackid = id + 1; 1398 data = xmalloc(conn->transfer_buflen); 1399 1400 /* Read from local and write to remote */ 1401 offset = 0; 1402 if (showprogress) 1403 start_progress_meter(local_path, sb.st_size, &offset); 1404 1405 for (;;) { 1406 int len; 1407 1408 /* 1409 * Can't use atomicio here because it returns 0 on EOF, 1410 * thus losing the last block of the file. 1411 * Simulate an EOF on interrupt, allowing ACKs from the 1412 * server to drain. 1413 */ 1414 if (interrupted || status != SSH2_FX_OK) 1415 len = 0; 1416 else do 1417 len = read(local_fd, data, conn->transfer_buflen); 1418 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 1419 1420 if (len == -1) 1421 fatal("Couldn't read from \"%s\": %s", local_path, 1422 strerror(errno)); 1423 1424 if (len != 0) { 1425 ack = xmalloc(sizeof(*ack)); 1426 ack->id = ++id; 1427 ack->offset = offset; 1428 ack->len = len; 1429 TAILQ_INSERT_TAIL(&acks, ack, tq); 1430 1431 buffer_clear(&msg); 1432 buffer_put_char(&msg, SSH2_FXP_WRITE); 1433 buffer_put_int(&msg, ack->id); 1434 buffer_put_string(&msg, handle, handle_len); 1435 buffer_put_int64(&msg, offset); 1436 buffer_put_string(&msg, data, len); 1437 send_msg(conn, &msg); 1438 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1439 id, (unsigned long long)offset, len); 1440 } else if (TAILQ_FIRST(&acks) == NULL) 1441 break; 1442 1443 if (ack == NULL) 1444 fatal("Unexpected ACK %u", id); 1445 1446 if (id == startid || len == 0 || 1447 id - ackid >= conn->num_requests) { 1448 u_int r_id; 1449 1450 buffer_clear(&msg); 1451 get_msg(conn, &msg); 1452 type = buffer_get_char(&msg); 1453 r_id = buffer_get_int(&msg); 1454 1455 if (type != SSH2_FXP_STATUS) 1456 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1457 "got %d", SSH2_FXP_STATUS, type); 1458 1459 status = buffer_get_int(&msg); 1460 debug3("SSH2_FXP_STATUS %d", status); 1461 1462 /* Find the request in our queue */ 1463 for (ack = TAILQ_FIRST(&acks); 1464 ack != NULL && ack->id != r_id; 1465 ack = TAILQ_NEXT(ack, tq)) 1466 ; 1467 if (ack == NULL) 1468 fatal("Can't find request for ID %u", r_id); 1469 TAILQ_REMOVE(&acks, ack, tq); 1470 debug3("In write loop, ack for %u %u bytes at %lld", 1471 ack->id, ack->len, (long long)ack->offset); 1472 ++ackid; 1473 xfree(ack); 1474 } 1475 offset += len; 1476 if (offset < 0) 1477 fatal("%s: offset < 0", __func__); 1478 } 1479 buffer_free(&msg); 1480 1481 if (showprogress) 1482 stop_progress_meter(); 1483 xfree(data); 1484 1485 if (status != SSH2_FX_OK) { 1486 error("Couldn't write to remote file \"%s\": %s", 1487 remote_path, fx2txt(status)); 1488 status = -1; 1489 } 1490 1491 if (close(local_fd) == -1) { 1492 error("Couldn't close local file \"%s\": %s", local_path, 1493 strerror(errno)); 1494 status = -1; 1495 } 1496 1497 /* Override umask and utimes if asked */ 1498 if (pflag) 1499 do_fsetstat(conn, handle, handle_len, &a); 1500 1501 if (do_close(conn, handle, handle_len) != SSH2_FX_OK) 1502 status = -1; 1503 xfree(handle); 1504 1505 return status; 1506 } 1507 1508 static int 1509 upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1510 int pflag, int printflag, int depth) 1511 { 1512 int ret = 0, status; 1513 DIR *dirp; 1514 struct dirent *dp; 1515 char *filename, *new_src, *new_dst; 1516 struct stat sb; 1517 Attrib a; 1518 1519 if (depth >= MAX_DIR_DEPTH) { 1520 error("Maximum directory depth exceeded: %d levels", depth); 1521 return -1; 1522 } 1523 1524 if (stat(src, &sb) == -1) { 1525 error("Couldn't stat directory \"%s\": %s", 1526 src, strerror(errno)); 1527 return -1; 1528 } 1529 if (!S_ISDIR(sb.st_mode)) { 1530 error("\"%s\" is not a directory", src); 1531 return -1; 1532 } 1533 if (printflag) 1534 printf("Entering %s\n", src); 1535 1536 attrib_clear(&a); 1537 stat_to_attrib(&sb, &a); 1538 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1539 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1540 a.perm &= 01777; 1541 if (!pflag) 1542 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1543 1544 status = do_mkdir(conn, dst, &a, 0); 1545 /* 1546 * we lack a portable status for errno EEXIST, 1547 * so if we get a SSH2_FX_FAILURE back we must check 1548 * if it was created successfully. 1549 */ 1550 if (status != SSH2_FX_OK) { 1551 if (status != SSH2_FX_FAILURE) 1552 return -1; 1553 if (do_stat(conn, dst, 0) == NULL) 1554 return -1; 1555 } 1556 1557 if ((dirp = opendir(src)) == NULL) { 1558 error("Failed to open dir \"%s\": %s", src, strerror(errno)); 1559 return -1; 1560 } 1561 1562 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 1563 if (dp->d_ino == 0) 1564 continue; 1565 filename = dp->d_name; 1566 new_dst = path_append(dst, filename); 1567 new_src = path_append(src, filename); 1568 1569 if (lstat(new_src, &sb) == -1) { 1570 logit("%s: lstat failed: %s", filename, 1571 strerror(errno)); 1572 ret = -1; 1573 } else if (S_ISDIR(sb.st_mode)) { 1574 if (strcmp(filename, ".") == 0 || 1575 strcmp(filename, "..") == 0) 1576 continue; 1577 1578 if (upload_dir_internal(conn, new_src, new_dst, 1579 pflag, printflag, depth + 1) == -1) 1580 ret = -1; 1581 } else if (S_ISREG(sb.st_mode)) { 1582 if (do_upload(conn, new_src, new_dst, pflag) == -1) { 1583 error("Uploading of file %s to %s failed!", 1584 new_src, new_dst); 1585 ret = -1; 1586 } 1587 } else 1588 logit("%s: not a regular file\n", filename); 1589 xfree(new_dst); 1590 xfree(new_src); 1591 } 1592 1593 do_setstat(conn, dst, &a); 1594 1595 (void) closedir(dirp); 1596 return ret; 1597 } 1598 1599 int 1600 upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag, 1601 int pflag) 1602 { 1603 char *dst_canon; 1604 int ret; 1605 1606 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 1607 error("Unable to canonicalise path \"%s\"", dst); 1608 return -1; 1609 } 1610 1611 ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0); 1612 xfree(dst_canon); 1613 return ret; 1614 } 1615 1616 char * 1617 path_append(char *p1, char *p2) 1618 { 1619 char *ret; 1620 size_t len = strlen(p1) + strlen(p2) + 2; 1621 1622 ret = xmalloc(len); 1623 strlcpy(ret, p1, len); 1624 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 1625 strlcat(ret, "/", len); 1626 strlcat(ret, p2, len); 1627 1628 return(ret); 1629 } 1630 1631