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