1 /* $OpenBSD: sftp-client.c,v 1.161 2022/01/17 21:41:04 djm Exp $ */ 2 /* 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* XXX: memleaks */ 19 /* XXX: signed vs unsigned */ 20 /* XXX: remove all logging, only return status codes */ 21 /* XXX: copy between two remote sites */ 22 23 #include "includes.h" 24 25 #include <sys/types.h> 26 #ifdef HAVE_SYS_STATVFS_H 27 #include <sys/statvfs.h> 28 #endif 29 #include "openbsd-compat/sys-queue.h" 30 #ifdef HAVE_SYS_STAT_H 31 # include <sys/stat.h> 32 #endif 33 #ifdef HAVE_SYS_TIME_H 34 # include <sys/time.h> 35 #endif 36 #include <sys/uio.h> 37 38 #include <dirent.h> 39 #include <errno.h> 40 #ifdef HAVE_POLL_H 41 #include <poll.h> 42 #else 43 # ifdef HAVE_SYS_POLL_H 44 # include <sys/poll.h> 45 # endif 46 #endif 47 #include <fcntl.h> 48 #include <signal.h> 49 #include <stdarg.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 #include "xmalloc.h" 56 #include "ssherr.h" 57 #include "sshbuf.h" 58 #include "log.h" 59 #include "atomicio.h" 60 #include "progressmeter.h" 61 #include "misc.h" 62 #include "utf8.h" 63 64 #include "sftp.h" 65 #include "sftp-common.h" 66 #include "sftp-client.h" 67 68 extern volatile sig_atomic_t interrupted; 69 extern int showprogress; 70 71 /* Default size of buffer for up/download */ 72 #define DEFAULT_COPY_BUFLEN 32768 73 74 /* Default number of concurrent outstanding requests */ 75 #define DEFAULT_NUM_REQUESTS 64 76 77 /* Minimum amount of data to read at a time */ 78 #define MIN_READ_SIZE 512 79 80 /* Maximum depth to descend in directory trees */ 81 #define MAX_DIR_DEPTH 64 82 83 /* Directory separator characters */ 84 #ifdef HAVE_CYGWIN 85 # define SFTP_DIRECTORY_CHARS "/\\" 86 #else /* HAVE_CYGWIN */ 87 # define SFTP_DIRECTORY_CHARS "/" 88 #endif /* HAVE_CYGWIN */ 89 90 struct sftp_conn { 91 int fd_in; 92 int fd_out; 93 u_int download_buflen; 94 u_int upload_buflen; 95 u_int num_requests; 96 u_int version; 97 u_int msg_id; 98 #define SFTP_EXT_POSIX_RENAME 0x00000001 99 #define SFTP_EXT_STATVFS 0x00000002 100 #define SFTP_EXT_FSTATVFS 0x00000004 101 #define SFTP_EXT_HARDLINK 0x00000008 102 #define SFTP_EXT_FSYNC 0x00000010 103 #define SFTP_EXT_LSETSTAT 0x00000020 104 #define SFTP_EXT_LIMITS 0x00000040 105 #define SFTP_EXT_PATH_EXPAND 0x00000080 106 u_int exts; 107 u_int64_t limit_kbps; 108 struct bwlimit bwlimit_in, bwlimit_out; 109 }; 110 111 /* Tracks in-progress requests during file transfers */ 112 struct request { 113 u_int id; 114 size_t len; 115 u_int64_t offset; 116 TAILQ_ENTRY(request) tq; 117 }; 118 TAILQ_HEAD(requests, request); 119 120 static u_char * 121 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, 122 const char *errfmt, ...) __attribute__((format(printf, 4, 5))); 123 124 static struct request * 125 request_enqueue(struct requests *requests, u_int id, size_t len, 126 uint64_t offset) 127 { 128 struct request *req; 129 130 req = xcalloc(1, sizeof(*req)); 131 req->id = id; 132 req->len = len; 133 req->offset = offset; 134 TAILQ_INSERT_TAIL(requests, req, tq); 135 return req; 136 } 137 138 static struct request * 139 request_find(struct requests *requests, u_int id) 140 { 141 struct request *req; 142 143 for (req = TAILQ_FIRST(requests); 144 req != NULL && req->id != id; 145 req = TAILQ_NEXT(req, tq)) 146 ; 147 return req; 148 } 149 150 /* ARGSUSED */ 151 static int 152 sftpio(void *_bwlimit, size_t amount) 153 { 154 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; 155 156 refresh_progress_meter(0); 157 if (bwlimit != NULL) 158 bandwidth_limit(bwlimit, amount); 159 return 0; 160 } 161 162 static void 163 send_msg(struct sftp_conn *conn, struct sshbuf *m) 164 { 165 u_char mlen[4]; 166 struct iovec iov[2]; 167 168 if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH) 169 fatal("Outbound message too long %zu", sshbuf_len(m)); 170 171 /* Send length first */ 172 put_u32(mlen, sshbuf_len(m)); 173 iov[0].iov_base = mlen; 174 iov[0].iov_len = sizeof(mlen); 175 iov[1].iov_base = (u_char *)sshbuf_ptr(m); 176 iov[1].iov_len = sshbuf_len(m); 177 178 if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio, 179 conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) != 180 sshbuf_len(m) + sizeof(mlen)) 181 fatal("Couldn't send packet: %s", strerror(errno)); 182 183 sshbuf_reset(m); 184 } 185 186 static void 187 get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial) 188 { 189 u_int msg_len; 190 u_char *p; 191 int r; 192 193 sshbuf_reset(m); 194 if ((r = sshbuf_reserve(m, 4, &p)) != 0) 195 fatal_fr(r, "reserve"); 196 if (atomicio6(read, conn->fd_in, p, 4, sftpio, 197 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) { 198 if (errno == EPIPE || errno == ECONNRESET) 199 fatal("Connection closed"); 200 else 201 fatal("Couldn't read packet: %s", strerror(errno)); 202 } 203 204 if ((r = sshbuf_get_u32(m, &msg_len)) != 0) 205 fatal_fr(r, "sshbuf_get_u32"); 206 if (msg_len > SFTP_MAX_MSG_LENGTH) { 207 do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL, 208 "Received message too long %u", msg_len); 209 fatal("Ensure the remote shell produces no output " 210 "for non-interactive sessions."); 211 } 212 213 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) 214 fatal_fr(r, "reserve"); 215 if (atomicio6(read, conn->fd_in, p, msg_len, sftpio, 216 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) 217 != msg_len) { 218 if (errno == EPIPE) 219 fatal("Connection closed"); 220 else 221 fatal("Read packet: %s", strerror(errno)); 222 } 223 } 224 225 static void 226 get_msg(struct sftp_conn *conn, struct sshbuf *m) 227 { 228 get_msg_extended(conn, m, 0); 229 } 230 231 static void 232 send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s, 233 u_int len) 234 { 235 struct sshbuf *msg; 236 int r; 237 238 if ((msg = sshbuf_new()) == NULL) 239 fatal_f("sshbuf_new failed"); 240 if ((r = sshbuf_put_u8(msg, code)) != 0 || 241 (r = sshbuf_put_u32(msg, id)) != 0 || 242 (r = sshbuf_put_string(msg, s, len)) != 0) 243 fatal_fr(r, "compose"); 244 send_msg(conn, msg); 245 debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 246 sshbuf_free(msg); 247 } 248 249 static void 250 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, 251 const void *s, u_int len, Attrib *a) 252 { 253 struct sshbuf *msg; 254 int r; 255 256 if ((msg = sshbuf_new()) == NULL) 257 fatal_f("sshbuf_new failed"); 258 if ((r = sshbuf_put_u8(msg, code)) != 0 || 259 (r = sshbuf_put_u32(msg, id)) != 0 || 260 (r = sshbuf_put_string(msg, s, len)) != 0 || 261 (r = encode_attrib(msg, a)) != 0) 262 fatal_fr(r, "compose"); 263 send_msg(conn, msg); 264 debug3("Sent message fd %d T:%u I:%u F:0x%04x M:%05o", 265 conn->fd_out, code, id, a->flags, a->perm); 266 sshbuf_free(msg); 267 } 268 269 static u_int 270 get_status(struct sftp_conn *conn, u_int expected_id) 271 { 272 struct sshbuf *msg; 273 u_char type; 274 u_int id, status; 275 int r; 276 277 if ((msg = sshbuf_new()) == NULL) 278 fatal_f("sshbuf_new failed"); 279 get_msg(conn, msg); 280 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 281 (r = sshbuf_get_u32(msg, &id)) != 0) 282 fatal_fr(r, "compose"); 283 284 if (id != expected_id) 285 fatal("ID mismatch (%u != %u)", id, expected_id); 286 if (type != SSH2_FXP_STATUS) 287 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 288 SSH2_FXP_STATUS, type); 289 290 if ((r = sshbuf_get_u32(msg, &status)) != 0) 291 fatal_fr(r, "parse"); 292 sshbuf_free(msg); 293 294 debug3("SSH2_FXP_STATUS %u", status); 295 296 return status; 297 } 298 299 static u_char * 300 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, 301 const char *errfmt, ...) 302 { 303 struct sshbuf *msg; 304 u_int id, status; 305 u_char type; 306 u_char *handle; 307 char errmsg[256]; 308 va_list args; 309 int r; 310 311 va_start(args, errfmt); 312 if (errfmt != NULL) 313 vsnprintf(errmsg, sizeof(errmsg), errfmt, args); 314 va_end(args); 315 316 if ((msg = sshbuf_new()) == NULL) 317 fatal_f("sshbuf_new failed"); 318 get_msg(conn, msg); 319 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 320 (r = sshbuf_get_u32(msg, &id)) != 0) 321 fatal_fr(r, "parse"); 322 323 if (id != expected_id) 324 fatal("%s: ID mismatch (%u != %u)", 325 errfmt == NULL ? __func__ : errmsg, id, expected_id); 326 if (type == SSH2_FXP_STATUS) { 327 if ((r = sshbuf_get_u32(msg, &status)) != 0) 328 fatal_fr(r, "parse status"); 329 if (errfmt != NULL) 330 error("%s: %s", errmsg, fx2txt(status)); 331 sshbuf_free(msg); 332 return(NULL); 333 } else if (type != SSH2_FXP_HANDLE) 334 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", 335 errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); 336 337 if ((r = sshbuf_get_string(msg, &handle, len)) != 0) 338 fatal_fr(r, "parse handle"); 339 sshbuf_free(msg); 340 341 return handle; 342 } 343 344 /* XXX returning &static is error-prone. Refactor to fill *Attrib argument */ 345 static Attrib * 346 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) 347 { 348 struct sshbuf *msg; 349 u_int id; 350 u_char type; 351 int r; 352 static Attrib a; 353 354 if ((msg = sshbuf_new()) == NULL) 355 fatal_f("sshbuf_new failed"); 356 get_msg(conn, msg); 357 358 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 359 (r = sshbuf_get_u32(msg, &id)) != 0) 360 fatal_fr(r, "parse"); 361 362 if (id != expected_id) 363 fatal("ID mismatch (%u != %u)", id, expected_id); 364 if (type == SSH2_FXP_STATUS) { 365 u_int status; 366 367 if ((r = sshbuf_get_u32(msg, &status)) != 0) 368 fatal_fr(r, "parse status"); 369 if (quiet) 370 debug("stat remote: %s", fx2txt(status)); 371 else 372 error("stat remote: %s", fx2txt(status)); 373 sshbuf_free(msg); 374 return(NULL); 375 } else if (type != SSH2_FXP_ATTRS) { 376 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 377 SSH2_FXP_ATTRS, type); 378 } 379 if ((r = decode_attrib(msg, &a)) != 0) { 380 error_fr(r, "decode_attrib"); 381 sshbuf_free(msg); 382 return NULL; 383 } 384 debug3("Received stat reply T:%u I:%u F:0x%04x M:%05o", 385 type, id, a.flags, a.perm); 386 sshbuf_free(msg); 387 388 return &a; 389 } 390 391 static int 392 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, 393 u_int expected_id, int quiet) 394 { 395 struct sshbuf *msg; 396 u_char type; 397 u_int id; 398 u_int64_t flag; 399 int r; 400 401 if ((msg = sshbuf_new()) == NULL) 402 fatal_f("sshbuf_new failed"); 403 get_msg(conn, msg); 404 405 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 406 (r = sshbuf_get_u32(msg, &id)) != 0) 407 fatal_fr(r, "parse"); 408 409 debug3("Received statvfs reply T:%u I:%u", type, id); 410 if (id != expected_id) 411 fatal("ID mismatch (%u != %u)", id, expected_id); 412 if (type == SSH2_FXP_STATUS) { 413 u_int status; 414 415 if ((r = sshbuf_get_u32(msg, &status)) != 0) 416 fatal_fr(r, "parse status"); 417 if (quiet) 418 debug("remote statvfs: %s", fx2txt(status)); 419 else 420 error("remote statvfs: %s", fx2txt(status)); 421 sshbuf_free(msg); 422 return -1; 423 } else if (type != SSH2_FXP_EXTENDED_REPLY) { 424 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 425 SSH2_FXP_EXTENDED_REPLY, type); 426 } 427 428 memset(st, 0, sizeof(*st)); 429 if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 || 430 (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 || 431 (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 || 432 (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 || 433 (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 || 434 (r = sshbuf_get_u64(msg, &st->f_files)) != 0 || 435 (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 || 436 (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 || 437 (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 || 438 (r = sshbuf_get_u64(msg, &flag)) != 0 || 439 (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0) 440 fatal_fr(r, "parse statvfs"); 441 442 st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; 443 st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; 444 445 sshbuf_free(msg); 446 447 return 0; 448 } 449 450 struct sftp_conn * 451 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, 452 u_int64_t limit_kbps) 453 { 454 u_char type; 455 struct sshbuf *msg; 456 struct sftp_conn *ret; 457 int r; 458 459 ret = xcalloc(1, sizeof(*ret)); 460 ret->msg_id = 1; 461 ret->fd_in = fd_in; 462 ret->fd_out = fd_out; 463 ret->download_buflen = ret->upload_buflen = 464 transfer_buflen ? transfer_buflen : DEFAULT_COPY_BUFLEN; 465 ret->num_requests = 466 num_requests ? num_requests : DEFAULT_NUM_REQUESTS; 467 ret->exts = 0; 468 ret->limit_kbps = 0; 469 470 if ((msg = sshbuf_new()) == NULL) 471 fatal_f("sshbuf_new failed"); 472 if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 || 473 (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0) 474 fatal_fr(r, "parse"); 475 476 send_msg(ret, msg); 477 478 get_msg_extended(ret, msg, 1); 479 480 /* Expecting a VERSION reply */ 481 if ((r = sshbuf_get_u8(msg, &type)) != 0) 482 fatal_fr(r, "parse type"); 483 if (type != SSH2_FXP_VERSION) { 484 error("Invalid packet back from SSH2_FXP_INIT (type %u)", 485 type); 486 sshbuf_free(msg); 487 free(ret); 488 return(NULL); 489 } 490 if ((r = sshbuf_get_u32(msg, &ret->version)) != 0) 491 fatal_fr(r, "parse version"); 492 493 debug2("Remote version: %u", ret->version); 494 495 /* Check for extensions */ 496 while (sshbuf_len(msg) > 0) { 497 char *name; 498 u_char *value; 499 size_t vlen; 500 int known = 0; 501 502 if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 || 503 (r = sshbuf_get_string(msg, &value, &vlen)) != 0) 504 fatal_fr(r, "parse extension"); 505 if (strcmp(name, "posix-rename@openssh.com") == 0 && 506 strcmp((char *)value, "1") == 0) { 507 ret->exts |= SFTP_EXT_POSIX_RENAME; 508 known = 1; 509 } else if (strcmp(name, "statvfs@openssh.com") == 0 && 510 strcmp((char *)value, "2") == 0) { 511 ret->exts |= SFTP_EXT_STATVFS; 512 known = 1; 513 } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && 514 strcmp((char *)value, "2") == 0) { 515 ret->exts |= SFTP_EXT_FSTATVFS; 516 known = 1; 517 } else if (strcmp(name, "hardlink@openssh.com") == 0 && 518 strcmp((char *)value, "1") == 0) { 519 ret->exts |= SFTP_EXT_HARDLINK; 520 known = 1; 521 } else if (strcmp(name, "fsync@openssh.com") == 0 && 522 strcmp((char *)value, "1") == 0) { 523 ret->exts |= SFTP_EXT_FSYNC; 524 known = 1; 525 } else if (strcmp(name, "lsetstat@openssh.com") == 0 && 526 strcmp((char *)value, "1") == 0) { 527 ret->exts |= SFTP_EXT_LSETSTAT; 528 known = 1; 529 } else if (strcmp(name, "limits@openssh.com") == 0 && 530 strcmp((char *)value, "1") == 0) { 531 ret->exts |= SFTP_EXT_LIMITS; 532 known = 1; 533 } else if (strcmp(name, "expand-path@openssh.com") == 0 && 534 strcmp((char *)value, "1") == 0) { 535 ret->exts |= SFTP_EXT_PATH_EXPAND; 536 known = 1; 537 } 538 if (known) { 539 debug2("Server supports extension \"%s\" revision %s", 540 name, value); 541 } else { 542 debug2("Unrecognised server extension \"%s\"", name); 543 } 544 free(name); 545 free(value); 546 } 547 548 sshbuf_free(msg); 549 550 /* Query the server for its limits */ 551 if (ret->exts & SFTP_EXT_LIMITS) { 552 struct sftp_limits limits; 553 if (do_limits(ret, &limits) != 0) 554 fatal_f("limits failed"); 555 556 /* If the caller did not specify, find a good value */ 557 if (transfer_buflen == 0) { 558 ret->download_buflen = limits.read_length; 559 ret->upload_buflen = limits.write_length; 560 debug("Using server download size %u", ret->download_buflen); 561 debug("Using server upload size %u", ret->upload_buflen); 562 } 563 564 /* Use the server limit to scale down our value only */ 565 if (num_requests == 0 && limits.open_handles) { 566 ret->num_requests = 567 MINIMUM(DEFAULT_NUM_REQUESTS, limits.open_handles); 568 debug("Server handle limit %llu; using %u", 569 (unsigned long long)limits.open_handles, 570 ret->num_requests); 571 } 572 } 573 574 /* Some filexfer v.0 servers don't support large packets */ 575 if (ret->version == 0) { 576 ret->download_buflen = MINIMUM(ret->download_buflen, 20480); 577 ret->upload_buflen = MINIMUM(ret->upload_buflen, 20480); 578 } 579 580 ret->limit_kbps = limit_kbps; 581 if (ret->limit_kbps > 0) { 582 bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps, 583 ret->download_buflen); 584 bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps, 585 ret->upload_buflen); 586 } 587 588 return ret; 589 } 590 591 u_int 592 sftp_proto_version(struct sftp_conn *conn) 593 { 594 return conn->version; 595 } 596 597 int 598 do_limits(struct sftp_conn *conn, struct sftp_limits *limits) 599 { 600 u_int id, msg_id; 601 u_char type; 602 struct sshbuf *msg; 603 int r; 604 605 if ((conn->exts & SFTP_EXT_LIMITS) == 0) { 606 error("Server does not support limits@openssh.com extension"); 607 return -1; 608 } 609 610 if ((msg = sshbuf_new()) == NULL) 611 fatal_f("sshbuf_new failed"); 612 613 id = conn->msg_id++; 614 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 615 (r = sshbuf_put_u32(msg, id)) != 0 || 616 (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0) 617 fatal_fr(r, "compose"); 618 send_msg(conn, msg); 619 debug3("Sent message limits@openssh.com I:%u", id); 620 621 get_msg(conn, msg); 622 623 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 624 (r = sshbuf_get_u32(msg, &msg_id)) != 0) 625 fatal_fr(r, "parse"); 626 627 debug3("Received limits reply T:%u I:%u", type, msg_id); 628 if (id != msg_id) 629 fatal("ID mismatch (%u != %u)", msg_id, id); 630 if (type != SSH2_FXP_EXTENDED_REPLY) { 631 debug_f("expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 632 SSH2_FXP_EXTENDED_REPLY, type); 633 /* Disable the limits extension */ 634 conn->exts &= ~SFTP_EXT_LIMITS; 635 sshbuf_free(msg); 636 return 0; 637 } 638 639 memset(limits, 0, sizeof(*limits)); 640 if ((r = sshbuf_get_u64(msg, &limits->packet_length)) != 0 || 641 (r = sshbuf_get_u64(msg, &limits->read_length)) != 0 || 642 (r = sshbuf_get_u64(msg, &limits->write_length)) != 0 || 643 (r = sshbuf_get_u64(msg, &limits->open_handles)) != 0) 644 fatal_fr(r, "parse limits"); 645 646 sshbuf_free(msg); 647 648 return 0; 649 } 650 651 int 652 do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) 653 { 654 u_int id, status; 655 struct sshbuf *msg; 656 int r; 657 658 if ((msg = sshbuf_new()) == NULL) 659 fatal_f("sshbuf_new failed"); 660 661 id = conn->msg_id++; 662 if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 || 663 (r = sshbuf_put_u32(msg, id)) != 0 || 664 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 665 fatal_fr(r, "parse"); 666 send_msg(conn, msg); 667 debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 668 669 status = get_status(conn, id); 670 if (status != SSH2_FX_OK) 671 error("close remote: %s", fx2txt(status)); 672 673 sshbuf_free(msg); 674 675 return status == SSH2_FX_OK ? 0 : -1; 676 } 677 678 679 static int 680 do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, 681 SFTP_DIRENT ***dir) 682 { 683 struct sshbuf *msg; 684 u_int count, id, i, expected_id, ents = 0; 685 size_t handle_len; 686 u_char type, *handle; 687 int status = SSH2_FX_FAILURE; 688 int r; 689 690 if (dir) 691 *dir = NULL; 692 693 id = conn->msg_id++; 694 695 if ((msg = sshbuf_new()) == NULL) 696 fatal_f("sshbuf_new failed"); 697 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 || 698 (r = sshbuf_put_u32(msg, id)) != 0 || 699 (r = sshbuf_put_cstring(msg, path)) != 0) 700 fatal_fr(r, "compose OPENDIR"); 701 send_msg(conn, msg); 702 703 handle = get_handle(conn, id, &handle_len, 704 "remote readdir(\"%s\")", path); 705 if (handle == NULL) { 706 sshbuf_free(msg); 707 return -1; 708 } 709 710 if (dir) { 711 ents = 0; 712 *dir = xcalloc(1, sizeof(**dir)); 713 (*dir)[0] = NULL; 714 } 715 716 for (; !interrupted;) { 717 id = expected_id = conn->msg_id++; 718 719 debug3("Sending SSH2_FXP_READDIR I:%u", id); 720 721 sshbuf_reset(msg); 722 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 || 723 (r = sshbuf_put_u32(msg, id)) != 0 || 724 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 725 fatal_fr(r, "compose READDIR"); 726 send_msg(conn, msg); 727 728 sshbuf_reset(msg); 729 730 get_msg(conn, msg); 731 732 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 733 (r = sshbuf_get_u32(msg, &id)) != 0) 734 fatal_fr(r, "parse"); 735 736 debug3("Received reply T:%u I:%u", type, id); 737 738 if (id != expected_id) 739 fatal("ID mismatch (%u != %u)", id, expected_id); 740 741 if (type == SSH2_FXP_STATUS) { 742 u_int rstatus; 743 744 if ((r = sshbuf_get_u32(msg, &rstatus)) != 0) 745 fatal_fr(r, "parse status"); 746 debug3("Received SSH2_FXP_STATUS %d", rstatus); 747 if (rstatus == SSH2_FX_EOF) 748 break; 749 error("Couldn't read directory: %s", fx2txt(rstatus)); 750 goto out; 751 } else if (type != SSH2_FXP_NAME) 752 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 753 SSH2_FXP_NAME, type); 754 755 if ((r = sshbuf_get_u32(msg, &count)) != 0) 756 fatal_fr(r, "parse count"); 757 if (count > SSHBUF_SIZE_MAX) 758 fatal_f("nonsensical number of entries"); 759 if (count == 0) 760 break; 761 debug3("Received %d SSH2_FXP_NAME responses", count); 762 for (i = 0; i < count; i++) { 763 char *filename, *longname; 764 Attrib a; 765 766 if ((r = sshbuf_get_cstring(msg, &filename, 767 NULL)) != 0 || 768 (r = sshbuf_get_cstring(msg, &longname, 769 NULL)) != 0) 770 fatal_fr(r, "parse filenames"); 771 if ((r = decode_attrib(msg, &a)) != 0) { 772 error_fr(r, "couldn't decode attrib"); 773 free(filename); 774 free(longname); 775 goto out; 776 } 777 778 if (print_flag) 779 mprintf("%s\n", longname); 780 781 /* 782 * Directory entries should never contain '/' 783 * These can be used to attack recursive ops 784 * (e.g. send '../../../../etc/passwd') 785 */ 786 if (strpbrk(filename, SFTP_DIRECTORY_CHARS) != NULL) { 787 error("Server sent suspect path \"%s\" " 788 "during readdir of \"%s\"", filename, path); 789 } else if (dir) { 790 *dir = xreallocarray(*dir, ents + 2, sizeof(**dir)); 791 (*dir)[ents] = xcalloc(1, sizeof(***dir)); 792 (*dir)[ents]->filename = xstrdup(filename); 793 (*dir)[ents]->longname = xstrdup(longname); 794 memcpy(&(*dir)[ents]->a, &a, sizeof(a)); 795 (*dir)[++ents] = NULL; 796 } 797 free(filename); 798 free(longname); 799 } 800 } 801 status = 0; 802 803 out: 804 sshbuf_free(msg); 805 do_close(conn, handle, handle_len); 806 free(handle); 807 808 if (status != 0 && dir != NULL) { 809 /* Don't return results on error */ 810 free_sftp_dirents(*dir); 811 *dir = NULL; 812 } else if (interrupted && dir != NULL && *dir != NULL) { 813 /* Don't return partial matches on interrupt */ 814 free_sftp_dirents(*dir); 815 *dir = xcalloc(1, sizeof(**dir)); 816 **dir = NULL; 817 } 818 819 return status == SSH2_FX_OK ? 0 : -1; 820 } 821 822 int 823 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) 824 { 825 return(do_lsreaddir(conn, path, 0, dir)); 826 } 827 828 void free_sftp_dirents(SFTP_DIRENT **s) 829 { 830 int i; 831 832 if (s == NULL) 833 return; 834 for (i = 0; s[i]; i++) { 835 free(s[i]->filename); 836 free(s[i]->longname); 837 free(s[i]); 838 } 839 free(s); 840 } 841 842 int 843 do_rm(struct sftp_conn *conn, const char *path) 844 { 845 u_int status, id; 846 847 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 848 849 id = conn->msg_id++; 850 send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); 851 status = get_status(conn, id); 852 if (status != SSH2_FX_OK) 853 error("remote delete %s: %s", path, fx2txt(status)); 854 return status == SSH2_FX_OK ? 0 : -1; 855 } 856 857 int 858 do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) 859 { 860 u_int status, id; 861 862 debug2("Sending SSH2_FXP_MKDIR \"%s\"", path); 863 864 id = conn->msg_id++; 865 send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, 866 strlen(path), a); 867 868 status = get_status(conn, id); 869 if (status != SSH2_FX_OK && print_flag) 870 error("remote mkdir \"%s\": %s", path, fx2txt(status)); 871 872 return status == SSH2_FX_OK ? 0 : -1; 873 } 874 875 int 876 do_rmdir(struct sftp_conn *conn, const char *path) 877 { 878 u_int status, id; 879 880 debug2("Sending SSH2_FXP_RMDIR \"%s\"", path); 881 882 id = conn->msg_id++; 883 send_string_request(conn, id, SSH2_FXP_RMDIR, path, 884 strlen(path)); 885 886 status = get_status(conn, id); 887 if (status != SSH2_FX_OK) 888 error("remote rmdir \"%s\": %s", path, fx2txt(status)); 889 890 return status == SSH2_FX_OK ? 0 : -1; 891 } 892 893 Attrib * 894 do_stat(struct sftp_conn *conn, const char *path, int quiet) 895 { 896 u_int id; 897 898 debug2("Sending SSH2_FXP_STAT \"%s\"", path); 899 900 id = conn->msg_id++; 901 902 send_string_request(conn, id, 903 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 904 path, strlen(path)); 905 906 return(get_decode_stat(conn, id, quiet)); 907 } 908 909 Attrib * 910 do_lstat(struct sftp_conn *conn, const char *path, int quiet) 911 { 912 u_int id; 913 914 if (conn->version == 0) { 915 if (quiet) 916 debug("Server version does not support lstat operation"); 917 else 918 logit("Server version does not support lstat operation"); 919 return(do_stat(conn, path, quiet)); 920 } 921 922 id = conn->msg_id++; 923 send_string_request(conn, id, SSH2_FXP_LSTAT, path, 924 strlen(path)); 925 926 return(get_decode_stat(conn, id, quiet)); 927 } 928 929 #ifdef notyet 930 Attrib * 931 do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 932 int quiet) 933 { 934 u_int id; 935 936 debug2("Sending SSH2_FXP_FSTAT \"%s\""); 937 938 id = conn->msg_id++; 939 send_string_request(conn, id, SSH2_FXP_FSTAT, handle, 940 handle_len); 941 942 return(get_decode_stat(conn, id, quiet)); 943 } 944 #endif 945 946 int 947 do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) 948 { 949 u_int status, id; 950 951 debug2("Sending SSH2_FXP_SETSTAT \"%s\"", path); 952 953 id = conn->msg_id++; 954 send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, 955 strlen(path), a); 956 957 status = get_status(conn, id); 958 if (status != SSH2_FX_OK) 959 error("remote setstat \"%s\": %s", path, fx2txt(status)); 960 961 return status == SSH2_FX_OK ? 0 : -1; 962 } 963 964 int 965 do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 966 Attrib *a) 967 { 968 u_int status, id; 969 970 debug2("Sending SSH2_FXP_FSETSTAT"); 971 972 id = conn->msg_id++; 973 send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, 974 handle_len, a); 975 976 status = get_status(conn, id); 977 if (status != SSH2_FX_OK) 978 error("remote fsetstat: %s", fx2txt(status)); 979 980 return status == SSH2_FX_OK ? 0 : -1; 981 } 982 983 /* Implements both the realpath and expand-path operations */ 984 static char * 985 do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) 986 { 987 struct sshbuf *msg; 988 u_int expected_id, count, id; 989 char *filename, *longname; 990 Attrib a; 991 u_char type; 992 int r; 993 const char *what = "SSH2_FXP_REALPATH"; 994 995 if (expand) 996 what = "expand-path@openssh.com"; 997 if ((msg = sshbuf_new()) == NULL) 998 fatal_f("sshbuf_new failed"); 999 1000 expected_id = id = conn->msg_id++; 1001 if (expand) { 1002 debug2("Sending SSH2_FXP_EXTENDED(expand-path@openssh.com) " 1003 "\"%s\"", path); 1004 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1005 (r = sshbuf_put_u32(msg, id)) != 0 || 1006 (r = sshbuf_put_cstring(msg, 1007 "expand-path@openssh.com")) != 0 || 1008 (r = sshbuf_put_cstring(msg, path)) != 0) 1009 fatal_fr(r, "compose %s", what); 1010 send_msg(conn, msg); 1011 } else { 1012 debug2("Sending SSH2_FXP_REALPATH \"%s\"", path); 1013 send_string_request(conn, id, SSH2_FXP_REALPATH, 1014 path, strlen(path)); 1015 } 1016 get_msg(conn, msg); 1017 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1018 (r = sshbuf_get_u32(msg, &id)) != 0) 1019 fatal_fr(r, "parse"); 1020 1021 if (id != expected_id) 1022 fatal("ID mismatch (%u != %u)", id, expected_id); 1023 1024 if (type == SSH2_FXP_STATUS) { 1025 u_int status; 1026 char *errmsg; 1027 1028 if ((r = sshbuf_get_u32(msg, &status)) != 0 || 1029 (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0) 1030 fatal_fr(r, "parse status"); 1031 error("%s %s: %s", expand ? "expand" : "realpath", 1032 path, *errmsg == '\0' ? fx2txt(status) : errmsg); 1033 free(errmsg); 1034 sshbuf_free(msg); 1035 return NULL; 1036 } else if (type != SSH2_FXP_NAME) 1037 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 1038 SSH2_FXP_NAME, type); 1039 1040 if ((r = sshbuf_get_u32(msg, &count)) != 0) 1041 fatal_fr(r, "parse count"); 1042 if (count != 1) 1043 fatal("Got multiple names (%d) from %s", count, what); 1044 1045 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || 1046 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || 1047 (r = decode_attrib(msg, &a)) != 0) 1048 fatal_fr(r, "parse filename/attrib"); 1049 1050 debug3("%s %s -> %s", what, path, filename); 1051 1052 free(longname); 1053 1054 sshbuf_free(msg); 1055 1056 return(filename); 1057 } 1058 1059 char * 1060 do_realpath(struct sftp_conn *conn, const char *path) 1061 { 1062 return do_realpath_expand(conn, path, 0); 1063 } 1064 1065 int 1066 can_expand_path(struct sftp_conn *conn) 1067 { 1068 return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0; 1069 } 1070 1071 char * 1072 do_expand_path(struct sftp_conn *conn, const char *path) 1073 { 1074 if (!can_expand_path(conn)) { 1075 debug3_f("no server support, fallback to realpath"); 1076 return do_realpath_expand(conn, path, 0); 1077 } 1078 return do_realpath_expand(conn, path, 1); 1079 } 1080 1081 int 1082 do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, 1083 int force_legacy) 1084 { 1085 struct sshbuf *msg; 1086 u_int status, id; 1087 int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; 1088 1089 if ((msg = sshbuf_new()) == NULL) 1090 fatal_f("sshbuf_new failed"); 1091 1092 /* Send rename request */ 1093 id = conn->msg_id++; 1094 if (use_ext) { 1095 debug2("Sending SSH2_FXP_EXTENDED(posix-rename@openssh.com) " 1096 "\"%s\" to \"%s\"", oldpath, newpath); 1097 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1098 (r = sshbuf_put_u32(msg, id)) != 0 || 1099 (r = sshbuf_put_cstring(msg, 1100 "posix-rename@openssh.com")) != 0) 1101 fatal_fr(r, "compose posix-rename"); 1102 } else { 1103 debug2("Sending SSH2_FXP_RENAME \"%s\" to \"%s\"", 1104 oldpath, newpath); 1105 if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 || 1106 (r = sshbuf_put_u32(msg, id)) != 0) 1107 fatal_fr(r, "compose rename"); 1108 } 1109 if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1110 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1111 fatal_fr(r, "compose paths"); 1112 send_msg(conn, msg); 1113 debug3("Sent message %s \"%s\" -> \"%s\"", 1114 use_ext ? "posix-rename@openssh.com" : 1115 "SSH2_FXP_RENAME", oldpath, newpath); 1116 sshbuf_free(msg); 1117 1118 status = get_status(conn, id); 1119 if (status != SSH2_FX_OK) 1120 error("remote rename \"%s\" to \"%s\": %s", oldpath, 1121 newpath, fx2txt(status)); 1122 1123 return status == SSH2_FX_OK ? 0 : -1; 1124 } 1125 1126 int 1127 do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) 1128 { 1129 struct sshbuf *msg; 1130 u_int status, id; 1131 int r; 1132 1133 if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { 1134 error("Server does not support hardlink@openssh.com extension"); 1135 return -1; 1136 } 1137 debug2("Sending SSH2_FXP_EXTENDED(hardlink@openssh.com) " 1138 "\"%s\" to \"%s\"", oldpath, newpath); 1139 1140 if ((msg = sshbuf_new()) == NULL) 1141 fatal_f("sshbuf_new failed"); 1142 1143 /* Send link request */ 1144 id = conn->msg_id++; 1145 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1146 (r = sshbuf_put_u32(msg, id)) != 0 || 1147 (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 || 1148 (r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1149 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1150 fatal_fr(r, "compose"); 1151 send_msg(conn, msg); 1152 debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", 1153 oldpath, newpath); 1154 sshbuf_free(msg); 1155 1156 status = get_status(conn, id); 1157 if (status != SSH2_FX_OK) 1158 error("remote link \"%s\" to \"%s\": %s", oldpath, 1159 newpath, fx2txt(status)); 1160 1161 return status == SSH2_FX_OK ? 0 : -1; 1162 } 1163 1164 int 1165 do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) 1166 { 1167 struct sshbuf *msg; 1168 u_int status, id; 1169 int r; 1170 1171 if (conn->version < 3) { 1172 error("This server does not support the symlink operation"); 1173 return(SSH2_FX_OP_UNSUPPORTED); 1174 } 1175 debug2("Sending SSH2_FXP_SYMLINK \"%s\" to \"%s\"", oldpath, newpath); 1176 1177 if ((msg = sshbuf_new()) == NULL) 1178 fatal_f("sshbuf_new failed"); 1179 1180 /* Send symlink request */ 1181 id = conn->msg_id++; 1182 if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 || 1183 (r = sshbuf_put_u32(msg, id)) != 0 || 1184 (r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1185 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1186 fatal_fr(r, "compose"); 1187 send_msg(conn, msg); 1188 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 1189 newpath); 1190 sshbuf_free(msg); 1191 1192 status = get_status(conn, id); 1193 if (status != SSH2_FX_OK) 1194 error("remote symlink file \"%s\" to \"%s\": %s", oldpath, 1195 newpath, fx2txt(status)); 1196 1197 return status == SSH2_FX_OK ? 0 : -1; 1198 } 1199 1200 int 1201 do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) 1202 { 1203 struct sshbuf *msg; 1204 u_int status, id; 1205 int r; 1206 1207 /* Silently return if the extension is not supported */ 1208 if ((conn->exts & SFTP_EXT_FSYNC) == 0) 1209 return -1; 1210 debug2("Sending SSH2_FXP_EXTENDED(fsync@openssh.com)"); 1211 1212 /* Send fsync request */ 1213 if ((msg = sshbuf_new()) == NULL) 1214 fatal_f("sshbuf_new failed"); 1215 id = conn->msg_id++; 1216 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1217 (r = sshbuf_put_u32(msg, id)) != 0 || 1218 (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || 1219 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 1220 fatal_fr(r, "compose"); 1221 send_msg(conn, msg); 1222 debug3("Sent message fsync@openssh.com I:%u", id); 1223 sshbuf_free(msg); 1224 1225 status = get_status(conn, id); 1226 if (status != SSH2_FX_OK) 1227 error("remote fsync: %s", fx2txt(status)); 1228 1229 return status == SSH2_FX_OK ? 0 : -1; 1230 } 1231 1232 #ifdef notyet 1233 char * 1234 do_readlink(struct sftp_conn *conn, const char *path) 1235 { 1236 struct sshbuf *msg; 1237 u_int expected_id, count, id; 1238 char *filename, *longname; 1239 Attrib a; 1240 u_char type; 1241 int r; 1242 1243 debug2("Sending SSH2_FXP_READLINK \"%s\"", path); 1244 1245 expected_id = id = conn->msg_id++; 1246 send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); 1247 1248 if ((msg = sshbuf_new()) == NULL) 1249 fatal_f("sshbuf_new failed"); 1250 1251 get_msg(conn, msg); 1252 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1253 (r = sshbuf_get_u32(msg, &id)) != 0) 1254 fatal_fr(r, "parse"); 1255 1256 if (id != expected_id) 1257 fatal("ID mismatch (%u != %u)", id, expected_id); 1258 1259 if (type == SSH2_FXP_STATUS) { 1260 u_int status; 1261 1262 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1263 fatal_fr(r, "parse status"); 1264 error("Couldn't readlink: %s", fx2txt(status)); 1265 sshbuf_free(msg); 1266 return(NULL); 1267 } else if (type != SSH2_FXP_NAME) 1268 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 1269 SSH2_FXP_NAME, type); 1270 1271 if ((r = sshbuf_get_u32(msg, &count)) != 0) 1272 fatal_fr(r, "parse count"); 1273 if (count != 1) 1274 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 1275 1276 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || 1277 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || 1278 (r = decode_attrib(msg, &a)) != 0) 1279 fatal_fr(r, "parse filenames/attrib"); 1280 1281 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 1282 1283 free(longname); 1284 1285 sshbuf_free(msg); 1286 1287 return filename; 1288 } 1289 #endif 1290 1291 int 1292 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, 1293 int quiet) 1294 { 1295 struct sshbuf *msg; 1296 u_int id; 1297 int r; 1298 1299 if ((conn->exts & SFTP_EXT_STATVFS) == 0) { 1300 error("Server does not support statvfs@openssh.com extension"); 1301 return -1; 1302 } 1303 1304 debug2("Sending SSH2_FXP_EXTENDED(statvfs@openssh.com) \"%s\"", path); 1305 1306 id = conn->msg_id++; 1307 1308 if ((msg = sshbuf_new()) == NULL) 1309 fatal_f("sshbuf_new failed"); 1310 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1311 (r = sshbuf_put_u32(msg, id)) != 0 || 1312 (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 || 1313 (r = sshbuf_put_cstring(msg, path)) != 0) 1314 fatal_fr(r, "compose"); 1315 send_msg(conn, msg); 1316 sshbuf_free(msg); 1317 1318 return get_decode_statvfs(conn, st, id, quiet); 1319 } 1320 1321 #ifdef notyet 1322 int 1323 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 1324 struct sftp_statvfs *st, int quiet) 1325 { 1326 struct sshbuf *msg; 1327 u_int id; 1328 1329 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { 1330 error("Server does not support fstatvfs@openssh.com extension"); 1331 return -1; 1332 } 1333 1334 debug2("Sending SSH2_FXP_EXTENDED(fstatvfs@openssh.com)"); 1335 1336 id = conn->msg_id++; 1337 1338 if ((msg = sshbuf_new()) == NULL) 1339 fatal_f("sshbuf_new failed"); 1340 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1341 (r = sshbuf_put_u32(msg, id)) != 0 || 1342 (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 || 1343 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 1344 fatal_fr(r, "compose"); 1345 send_msg(conn, msg); 1346 sshbuf_free(msg); 1347 1348 return get_decode_statvfs(conn, st, id, quiet); 1349 } 1350 #endif 1351 1352 int 1353 do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a) 1354 { 1355 struct sshbuf *msg; 1356 u_int status, id; 1357 int r; 1358 1359 if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) { 1360 error("Server does not support lsetstat@openssh.com extension"); 1361 return -1; 1362 } 1363 1364 debug2("Sending SSH2_FXP_EXTENDED(lsetstat@openssh.com) \"%s\"", path); 1365 1366 id = conn->msg_id++; 1367 if ((msg = sshbuf_new()) == NULL) 1368 fatal_f("sshbuf_new failed"); 1369 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1370 (r = sshbuf_put_u32(msg, id)) != 0 || 1371 (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 || 1372 (r = sshbuf_put_cstring(msg, path)) != 0 || 1373 (r = encode_attrib(msg, a)) != 0) 1374 fatal_fr(r, "compose"); 1375 send_msg(conn, msg); 1376 sshbuf_free(msg); 1377 1378 status = get_status(conn, id); 1379 if (status != SSH2_FX_OK) 1380 error("remote lsetstat \"%s\": %s", path, fx2txt(status)); 1381 1382 return status == SSH2_FX_OK ? 0 : -1; 1383 } 1384 1385 static void 1386 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, 1387 u_int len, const u_char *handle, u_int handle_len) 1388 { 1389 struct sshbuf *msg; 1390 int r; 1391 1392 if ((msg = sshbuf_new()) == NULL) 1393 fatal_f("sshbuf_new failed"); 1394 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 || 1395 (r = sshbuf_put_u32(msg, id)) != 0 || 1396 (r = sshbuf_put_string(msg, handle, handle_len)) != 0 || 1397 (r = sshbuf_put_u64(msg, offset)) != 0 || 1398 (r = sshbuf_put_u32(msg, len)) != 0) 1399 fatal_fr(r, "compose"); 1400 send_msg(conn, msg); 1401 sshbuf_free(msg); 1402 } 1403 1404 static int 1405 send_open(struct sftp_conn *conn, const char *path, const char *tag, 1406 u_int openmode, Attrib *a, u_char **handlep, size_t *handle_lenp) 1407 { 1408 Attrib junk; 1409 u_char *handle; 1410 size_t handle_len; 1411 struct sshbuf *msg; 1412 int r; 1413 u_int id; 1414 1415 debug2("Sending SSH2_FXP_OPEN \"%s\"", path); 1416 1417 *handlep = NULL; 1418 *handle_lenp = 0; 1419 1420 if (a == NULL) { 1421 attrib_clear(&junk); /* Send empty attributes */ 1422 a = &junk; 1423 } 1424 /* Send open request */ 1425 if ((msg = sshbuf_new()) == NULL) 1426 fatal_f("sshbuf_new failed"); 1427 id = conn->msg_id++; 1428 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || 1429 (r = sshbuf_put_u32(msg, id)) != 0 || 1430 (r = sshbuf_put_cstring(msg, path)) != 0 || 1431 (r = sshbuf_put_u32(msg, openmode)) != 0 || 1432 (r = encode_attrib(msg, a)) != 0) 1433 fatal_fr(r, "compose %s open", tag); 1434 send_msg(conn, msg); 1435 sshbuf_free(msg); 1436 debug3("Sent %s message SSH2_FXP_OPEN I:%u P:%s M:0x%04x", 1437 tag, id, path, openmode); 1438 if ((handle = get_handle(conn, id, &handle_len, 1439 "%s open \"%s\"", tag, path)) == NULL) 1440 return -1; 1441 /* success */ 1442 *handlep = handle; 1443 *handle_lenp = handle_len; 1444 return 0; 1445 } 1446 1447 static const char * 1448 progress_meter_path(const char *path) 1449 { 1450 const char *progresspath; 1451 1452 if ((progresspath = strrchr(path, '/')) == NULL) 1453 return path; 1454 progresspath++; 1455 if (*progresspath == '\0') 1456 return path; 1457 return progresspath; 1458 } 1459 1460 int 1461 do_download(struct sftp_conn *conn, const char *remote_path, 1462 const char *local_path, Attrib *a, int preserve_flag, int resume_flag, 1463 int fsync_flag) 1464 { 1465 struct sshbuf *msg; 1466 u_char *handle; 1467 int local_fd = -1, write_error; 1468 int read_error, write_errno, lmodified = 0, reordered = 0, r; 1469 u_int64_t offset = 0, size, highwater; 1470 u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK; 1471 off_t progress_counter; 1472 size_t handle_len; 1473 struct stat st; 1474 struct requests requests; 1475 struct request *req; 1476 u_char type; 1477 1478 debug2_f("download remote \"%s\" to local \"%s\"", 1479 remote_path, local_path); 1480 1481 TAILQ_INIT(&requests); 1482 1483 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 1484 return -1; 1485 1486 /* Do not preserve set[ug]id here, as we do not preserve ownership */ 1487 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1488 mode = a->perm & 0777; 1489 else 1490 mode = 0666; 1491 1492 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 1493 (!S_ISREG(a->perm))) { 1494 error("download %s: not a regular file", remote_path); 1495 return(-1); 1496 } 1497 1498 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 1499 size = a->size; 1500 else 1501 size = 0; 1502 1503 buflen = conn->download_buflen; 1504 1505 /* Send open request */ 1506 if (send_open(conn, remote_path, "remote", SSH2_FXF_READ, NULL, 1507 &handle, &handle_len) != 0) 1508 return -1; 1509 1510 local_fd = open(local_path, 1511 O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR); 1512 if (local_fd == -1) { 1513 error("open local \"%s\": %s", local_path, strerror(errno)); 1514 goto fail; 1515 } 1516 offset = highwater = 0; 1517 if (resume_flag) { 1518 if (fstat(local_fd, &st) == -1) { 1519 error("stat local \"%s\": %s", 1520 local_path, strerror(errno)); 1521 goto fail; 1522 } 1523 if (st.st_size < 0) { 1524 error("\"%s\" has negative size", local_path); 1525 goto fail; 1526 } 1527 if ((u_int64_t)st.st_size > size) { 1528 error("Unable to resume download of \"%s\": " 1529 "local file is larger than remote", local_path); 1530 fail: 1531 do_close(conn, handle, handle_len); 1532 free(handle); 1533 if (local_fd != -1) 1534 close(local_fd); 1535 return -1; 1536 } 1537 offset = highwater = st.st_size; 1538 } 1539 1540 /* Read from remote and write to local */ 1541 write_error = read_error = write_errno = num_req = 0; 1542 max_req = 1; 1543 progress_counter = offset; 1544 1545 if (showprogress && size != 0) { 1546 start_progress_meter(progress_meter_path(remote_path), 1547 size, &progress_counter); 1548 } 1549 1550 if ((msg = sshbuf_new()) == NULL) 1551 fatal_f("sshbuf_new failed"); 1552 1553 while (num_req > 0 || max_req > 0) { 1554 u_char *data; 1555 size_t len; 1556 1557 /* 1558 * Simulate EOF on interrupt: stop sending new requests and 1559 * allow outstanding requests to drain gracefully 1560 */ 1561 if (interrupted) { 1562 if (num_req == 0) /* If we haven't started yet... */ 1563 break; 1564 max_req = 0; 1565 } 1566 1567 /* Send some more requests */ 1568 while (num_req < max_req) { 1569 debug3("Request range %llu -> %llu (%d/%d)", 1570 (unsigned long long)offset, 1571 (unsigned long long)offset + buflen - 1, 1572 num_req, max_req); 1573 req = request_enqueue(&requests, conn->msg_id++, 1574 buflen, offset); 1575 offset += buflen; 1576 num_req++; 1577 send_read_request(conn, req->id, req->offset, 1578 req->len, handle, handle_len); 1579 } 1580 1581 sshbuf_reset(msg); 1582 get_msg(conn, msg); 1583 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1584 (r = sshbuf_get_u32(msg, &id)) != 0) 1585 fatal_fr(r, "parse"); 1586 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 1587 1588 /* Find the request in our queue */ 1589 if ((req = request_find(&requests, id)) == NULL) 1590 fatal("Unexpected reply %u", id); 1591 1592 switch (type) { 1593 case SSH2_FXP_STATUS: 1594 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1595 fatal_fr(r, "parse status"); 1596 if (status != SSH2_FX_EOF) 1597 read_error = 1; 1598 max_req = 0; 1599 TAILQ_REMOVE(&requests, req, tq); 1600 free(req); 1601 num_req--; 1602 break; 1603 case SSH2_FXP_DATA: 1604 if ((r = sshbuf_get_string(msg, &data, &len)) != 0) 1605 fatal_fr(r, "parse data"); 1606 debug3("Received data %llu -> %llu", 1607 (unsigned long long)req->offset, 1608 (unsigned long long)req->offset + len - 1); 1609 if (len > req->len) 1610 fatal("Received more data than asked for " 1611 "%zu > %zu", len, req->len); 1612 lmodified = 1; 1613 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 1614 atomicio(vwrite, local_fd, data, len) != len) && 1615 !write_error) { 1616 write_errno = errno; 1617 write_error = 1; 1618 max_req = 0; 1619 } 1620 else if (!reordered && req->offset <= highwater) 1621 highwater = req->offset + len; 1622 else if (!reordered && req->offset > highwater) 1623 reordered = 1; 1624 progress_counter += len; 1625 free(data); 1626 1627 if (len == req->len) { 1628 TAILQ_REMOVE(&requests, req, tq); 1629 free(req); 1630 num_req--; 1631 } else { 1632 /* Resend the request for the missing data */ 1633 debug3("Short data block, re-requesting " 1634 "%llu -> %llu (%2d)", 1635 (unsigned long long)req->offset + len, 1636 (unsigned long long)req->offset + 1637 req->len - 1, num_req); 1638 req->id = conn->msg_id++; 1639 req->len -= len; 1640 req->offset += len; 1641 send_read_request(conn, req->id, 1642 req->offset, req->len, handle, handle_len); 1643 /* Reduce the request size */ 1644 if (len < buflen) 1645 buflen = MAXIMUM(MIN_READ_SIZE, len); 1646 } 1647 if (max_req > 0) { /* max_req = 0 iff EOF received */ 1648 if (size > 0 && offset > size) { 1649 /* Only one request at a time 1650 * after the expected EOF */ 1651 debug3("Finish at %llu (%2d)", 1652 (unsigned long long)offset, 1653 num_req); 1654 max_req = 1; 1655 } else if (max_req < conn->num_requests) { 1656 ++max_req; 1657 } 1658 } 1659 break; 1660 default: 1661 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 1662 SSH2_FXP_DATA, type); 1663 } 1664 } 1665 1666 if (showprogress && size) 1667 stop_progress_meter(); 1668 1669 /* Sanity check */ 1670 if (TAILQ_FIRST(&requests) != NULL) 1671 fatal("Transfer complete, but requests still in queue"); 1672 /* Truncate at highest contiguous point to avoid holes on interrupt */ 1673 if (read_error || write_error || interrupted) { 1674 if (reordered && resume_flag) { 1675 error("Unable to resume download of \"%s\": " 1676 "server reordered requests", local_path); 1677 } 1678 debug("truncating at %llu", (unsigned long long)highwater); 1679 if (ftruncate(local_fd, highwater) == -1) 1680 error("local ftruncate \"%s\": %s", local_path, 1681 strerror(errno)); 1682 } 1683 if (read_error) { 1684 error("read remote \"%s\" : %s", remote_path, fx2txt(status)); 1685 status = -1; 1686 do_close(conn, handle, handle_len); 1687 } else if (write_error) { 1688 error("write local \"%s\": %s", local_path, 1689 strerror(write_errno)); 1690 status = SSH2_FX_FAILURE; 1691 do_close(conn, handle, handle_len); 1692 } else { 1693 if (do_close(conn, handle, handle_len) != 0 || interrupted) 1694 status = SSH2_FX_FAILURE; 1695 else 1696 status = SSH2_FX_OK; 1697 /* Override umask and utimes if asked */ 1698 #ifdef HAVE_FCHMOD 1699 if (preserve_flag && fchmod(local_fd, mode) == -1) 1700 #else 1701 if (preserve_flag && chmod(local_path, mode) == -1) 1702 #endif /* HAVE_FCHMOD */ 1703 error("local chmod \"%s\": %s", local_path, 1704 strerror(errno)); 1705 if (preserve_flag && 1706 (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 1707 struct timeval tv[2]; 1708 tv[0].tv_sec = a->atime; 1709 tv[1].tv_sec = a->mtime; 1710 tv[0].tv_usec = tv[1].tv_usec = 0; 1711 if (utimes(local_path, tv) == -1) 1712 error("local set times \"%s\": %s", 1713 local_path, strerror(errno)); 1714 } 1715 if (resume_flag && !lmodified) 1716 logit("File \"%s\" was not modified", local_path); 1717 else if (fsync_flag) { 1718 debug("syncing \"%s\"", local_path); 1719 if (fsync(local_fd) == -1) 1720 error("local sync \"%s\": %s", 1721 local_path, strerror(errno)); 1722 } 1723 } 1724 close(local_fd); 1725 sshbuf_free(msg); 1726 free(handle); 1727 1728 return status == SSH2_FX_OK ? 0 : -1; 1729 } 1730 1731 static int 1732 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, 1733 int depth, Attrib *dirattrib, int preserve_flag, int print_flag, 1734 int resume_flag, int fsync_flag, int follow_link_flag) 1735 { 1736 int i, ret = 0; 1737 SFTP_DIRENT **dir_entries; 1738 char *filename, *new_src = NULL, *new_dst = NULL; 1739 mode_t mode = 0777, tmpmode = mode; 1740 1741 if (depth >= MAX_DIR_DEPTH) { 1742 error("Maximum directory depth exceeded: %d levels", depth); 1743 return -1; 1744 } 1745 1746 debug2_f("download dir remote \"%s\" to local \"%s\"", src, dst); 1747 1748 if (dirattrib == NULL && 1749 (dirattrib = do_stat(conn, src, 1)) == NULL) { 1750 error("stat remote \"%s\" directory failed", src); 1751 return -1; 1752 } 1753 if (!S_ISDIR(dirattrib->perm)) { 1754 error("\"%s\" is not a directory", src); 1755 return -1; 1756 } 1757 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 1758 mprintf("Retrieving %s\n", src); 1759 1760 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 1761 mode = dirattrib->perm & 01777; 1762 tmpmode = mode | (S_IWUSR|S_IXUSR); 1763 } else { 1764 debug("download remote \"%s\": server " 1765 "did not send permissions", dst); 1766 } 1767 1768 if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) { 1769 error("mkdir %s: %s", dst, strerror(errno)); 1770 return -1; 1771 } 1772 1773 if (do_readdir(conn, src, &dir_entries) == -1) { 1774 error("remote readdir \"%s\" failed", src); 1775 return -1; 1776 } 1777 1778 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 1779 free(new_dst); 1780 free(new_src); 1781 1782 filename = dir_entries[i]->filename; 1783 new_dst = path_append(dst, filename); 1784 new_src = path_append(src, filename); 1785 1786 if (S_ISDIR(dir_entries[i]->a.perm)) { 1787 if (strcmp(filename, ".") == 0 || 1788 strcmp(filename, "..") == 0) 1789 continue; 1790 if (download_dir_internal(conn, new_src, new_dst, 1791 depth + 1, &(dir_entries[i]->a), preserve_flag, 1792 print_flag, resume_flag, 1793 fsync_flag, follow_link_flag) == -1) 1794 ret = -1; 1795 } else if (S_ISREG(dir_entries[i]->a.perm) || 1796 (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { 1797 /* 1798 * If this is a symlink then don't send the link's 1799 * Attrib. do_download() will do a FXP_STAT operation 1800 * and get the link target's attributes. 1801 */ 1802 if (do_download(conn, new_src, new_dst, 1803 S_ISLNK(dir_entries[i]->a.perm) ? NULL : 1804 &(dir_entries[i]->a), 1805 preserve_flag, resume_flag, fsync_flag) == -1) { 1806 error("Download of file %s to %s failed", 1807 new_src, new_dst); 1808 ret = -1; 1809 } 1810 } else 1811 logit("download \"%s\": not a regular file", new_src); 1812 1813 } 1814 free(new_dst); 1815 free(new_src); 1816 1817 if (preserve_flag) { 1818 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1819 struct timeval tv[2]; 1820 tv[0].tv_sec = dirattrib->atime; 1821 tv[1].tv_sec = dirattrib->mtime; 1822 tv[0].tv_usec = tv[1].tv_usec = 0; 1823 if (utimes(dst, tv) == -1) 1824 error("local set times on \"%s\": %s", 1825 dst, strerror(errno)); 1826 } else 1827 debug("Server did not send times for directory " 1828 "\"%s\"", dst); 1829 } 1830 1831 if (mode != tmpmode && chmod(dst, mode) == -1) 1832 error("local chmod directory \"%s\": %s", dst, 1833 strerror(errno)); 1834 1835 free_sftp_dirents(dir_entries); 1836 1837 return ret; 1838 } 1839 1840 int 1841 download_dir(struct sftp_conn *conn, const char *src, const char *dst, 1842 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, 1843 int fsync_flag, int follow_link_flag) 1844 { 1845 char *src_canon; 1846 int ret; 1847 1848 if ((src_canon = do_realpath(conn, src)) == NULL) { 1849 error("download \"%s\": path canonicalization failed", src); 1850 return -1; 1851 } 1852 1853 ret = download_dir_internal(conn, src_canon, dst, 0, 1854 dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag, 1855 follow_link_flag); 1856 free(src_canon); 1857 return ret; 1858 } 1859 1860 int 1861 do_upload(struct sftp_conn *conn, const char *local_path, 1862 const char *remote_path, int preserve_flag, int resume, int fsync_flag) 1863 { 1864 int r, local_fd; 1865 u_int status = SSH2_FX_OK; 1866 u_int id; 1867 u_char type; 1868 off_t offset, progress_counter; 1869 u_char *handle, *data; 1870 struct sshbuf *msg; 1871 struct stat sb; 1872 Attrib a, *c = NULL; 1873 u_int32_t startid; 1874 u_int32_t ackid; 1875 struct request *ack = NULL; 1876 struct requests acks; 1877 size_t handle_len; 1878 1879 debug2_f("upload local \"%s\" to remote \"%s\"", 1880 local_path, remote_path); 1881 1882 TAILQ_INIT(&acks); 1883 1884 if ((local_fd = open(local_path, O_RDONLY)) == -1) { 1885 error("open local \"%s\": %s", local_path, strerror(errno)); 1886 return(-1); 1887 } 1888 if (fstat(local_fd, &sb) == -1) { 1889 error("fstat local \"%s\": %s", local_path, strerror(errno)); 1890 close(local_fd); 1891 return(-1); 1892 } 1893 if (!S_ISREG(sb.st_mode)) { 1894 error("local \"%s\" is not a regular file", local_path); 1895 close(local_fd); 1896 return(-1); 1897 } 1898 stat_to_attrib(&sb, &a); 1899 1900 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1901 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1902 a.perm &= 0777; 1903 if (!preserve_flag) 1904 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1905 1906 if (resume) { 1907 /* Get remote file size if it exists */ 1908 if ((c = do_stat(conn, remote_path, 0)) == NULL) { 1909 close(local_fd); 1910 return -1; 1911 } 1912 1913 if ((off_t)c->size >= sb.st_size) { 1914 error("resume \"%s\": destination file " 1915 "same size or larger", local_path); 1916 close(local_fd); 1917 return -1; 1918 } 1919 1920 if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) { 1921 close(local_fd); 1922 return -1; 1923 } 1924 } 1925 1926 /* Send open request */ 1927 if (send_open(conn, remote_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT| 1928 (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC), 1929 &a, &handle, &handle_len) != 0) { 1930 close(local_fd); 1931 return -1; 1932 } 1933 1934 id = conn->msg_id; 1935 startid = ackid = id + 1; 1936 data = xmalloc(conn->upload_buflen); 1937 1938 /* Read from local and write to remote */ 1939 offset = progress_counter = (resume ? c->size : 0); 1940 if (showprogress) { 1941 start_progress_meter(progress_meter_path(local_path), 1942 sb.st_size, &progress_counter); 1943 } 1944 1945 if ((msg = sshbuf_new()) == NULL) 1946 fatal_f("sshbuf_new failed"); 1947 for (;;) { 1948 int len; 1949 1950 /* 1951 * Can't use atomicio here because it returns 0 on EOF, 1952 * thus losing the last block of the file. 1953 * Simulate an EOF on interrupt, allowing ACKs from the 1954 * server to drain. 1955 */ 1956 if (interrupted || status != SSH2_FX_OK) 1957 len = 0; 1958 else do 1959 len = read(local_fd, data, conn->upload_buflen); 1960 while ((len == -1) && 1961 (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)); 1962 1963 if (len == -1) { 1964 fatal("read local \"%s\": %s", 1965 local_path, strerror(errno)); 1966 } else if (len != 0) { 1967 ack = request_enqueue(&acks, ++id, len, offset); 1968 sshbuf_reset(msg); 1969 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 || 1970 (r = sshbuf_put_u32(msg, ack->id)) != 0 || 1971 (r = sshbuf_put_string(msg, handle, 1972 handle_len)) != 0 || 1973 (r = sshbuf_put_u64(msg, offset)) != 0 || 1974 (r = sshbuf_put_string(msg, data, len)) != 0) 1975 fatal_fr(r, "compose"); 1976 send_msg(conn, msg); 1977 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1978 id, (unsigned long long)offset, len); 1979 } else if (TAILQ_FIRST(&acks) == NULL) 1980 break; 1981 1982 if (ack == NULL) 1983 fatal("Unexpected ACK %u", id); 1984 1985 if (id == startid || len == 0 || 1986 id - ackid >= conn->num_requests) { 1987 u_int rid; 1988 1989 sshbuf_reset(msg); 1990 get_msg(conn, msg); 1991 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1992 (r = sshbuf_get_u32(msg, &rid)) != 0) 1993 fatal_fr(r, "parse"); 1994 1995 if (type != SSH2_FXP_STATUS) 1996 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1997 "got %d", SSH2_FXP_STATUS, type); 1998 1999 if ((r = sshbuf_get_u32(msg, &status)) != 0) 2000 fatal_fr(r, "parse status"); 2001 debug3("SSH2_FXP_STATUS %u", status); 2002 2003 /* Find the request in our queue */ 2004 if ((ack = request_find(&acks, rid)) == NULL) 2005 fatal("Can't find request for ID %u", rid); 2006 TAILQ_REMOVE(&acks, ack, tq); 2007 debug3("In write loop, ack for %u %zu bytes at %lld", 2008 ack->id, ack->len, (unsigned long long)ack->offset); 2009 ++ackid; 2010 progress_counter += ack->len; 2011 free(ack); 2012 } 2013 offset += len; 2014 if (offset < 0) 2015 fatal_f("offset < 0"); 2016 } 2017 sshbuf_free(msg); 2018 2019 if (showprogress) 2020 stop_progress_meter(); 2021 free(data); 2022 2023 if (status != SSH2_FX_OK) { 2024 error("write remote \"%s\": %s", remote_path, fx2txt(status)); 2025 status = SSH2_FX_FAILURE; 2026 } 2027 2028 if (close(local_fd) == -1) { 2029 error("close local \"%s\": %s", local_path, strerror(errno)); 2030 status = SSH2_FX_FAILURE; 2031 } 2032 2033 /* Override umask and utimes if asked */ 2034 if (preserve_flag) 2035 do_fsetstat(conn, handle, handle_len, &a); 2036 2037 if (fsync_flag) 2038 (void)do_fsync(conn, handle, handle_len); 2039 2040 if (do_close(conn, handle, handle_len) != 0) 2041 status = SSH2_FX_FAILURE; 2042 2043 free(handle); 2044 2045 return status == SSH2_FX_OK ? 0 : -1; 2046 } 2047 2048 static int 2049 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, 2050 int depth, int preserve_flag, int print_flag, int resume, int fsync_flag, 2051 int follow_link_flag) 2052 { 2053 int ret = 0; 2054 DIR *dirp; 2055 struct dirent *dp; 2056 char *filename, *new_src = NULL, *new_dst = NULL; 2057 struct stat sb; 2058 Attrib a, *dirattrib; 2059 u_int32_t saved_perm; 2060 2061 debug2_f("upload local dir \"%s\" to remote \"%s\"", src, dst); 2062 2063 if (depth >= MAX_DIR_DEPTH) { 2064 error("Maximum directory depth exceeded: %d levels", depth); 2065 return -1; 2066 } 2067 2068 if (stat(src, &sb) == -1) { 2069 error("stat local \"%s\": %s", src, strerror(errno)); 2070 return -1; 2071 } 2072 if (!S_ISDIR(sb.st_mode)) { 2073 error("\"%s\" is not a directory", src); 2074 return -1; 2075 } 2076 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 2077 mprintf("Entering %s\n", src); 2078 2079 stat_to_attrib(&sb, &a); 2080 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2081 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2082 a.perm &= 01777; 2083 if (!preserve_flag) 2084 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 2085 2086 /* 2087 * sftp lacks a portable status value to match errno EEXIST, 2088 * so if we get a failure back then we must check whether 2089 * the path already existed and is a directory. Ensure we can 2090 * write to the directory we create for the duration of the transfer. 2091 */ 2092 saved_perm = a.perm; 2093 a.perm |= (S_IWUSR|S_IXUSR); 2094 if (do_mkdir(conn, dst, &a, 0) != 0) { 2095 if ((dirattrib = do_stat(conn, dst, 0)) == NULL) 2096 return -1; 2097 if (!S_ISDIR(dirattrib->perm)) { 2098 error("\"%s\" exists but is not a directory", dst); 2099 return -1; 2100 } 2101 } 2102 a.perm = saved_perm; 2103 2104 if ((dirp = opendir(src)) == NULL) { 2105 error("local opendir \"%s\": %s", src, strerror(errno)); 2106 return -1; 2107 } 2108 2109 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 2110 if (dp->d_ino == 0) 2111 continue; 2112 free(new_dst); 2113 free(new_src); 2114 filename = dp->d_name; 2115 new_dst = path_append(dst, filename); 2116 new_src = path_append(src, filename); 2117 2118 if (lstat(new_src, &sb) == -1) { 2119 logit("local lstat \"%s\": %s", filename, 2120 strerror(errno)); 2121 ret = -1; 2122 } else if (S_ISDIR(sb.st_mode)) { 2123 if (strcmp(filename, ".") == 0 || 2124 strcmp(filename, "..") == 0) 2125 continue; 2126 2127 if (upload_dir_internal(conn, new_src, new_dst, 2128 depth + 1, preserve_flag, print_flag, resume, 2129 fsync_flag, follow_link_flag) == -1) 2130 ret = -1; 2131 } else if (S_ISREG(sb.st_mode) || 2132 (follow_link_flag && S_ISLNK(sb.st_mode))) { 2133 if (do_upload(conn, new_src, new_dst, 2134 preserve_flag, resume, fsync_flag) == -1) { 2135 error("upload \"%s\" to \"%s\" failed", 2136 new_src, new_dst); 2137 ret = -1; 2138 } 2139 } else 2140 logit("%s: not a regular file", filename); 2141 } 2142 free(new_dst); 2143 free(new_src); 2144 2145 do_setstat(conn, dst, &a); 2146 2147 (void) closedir(dirp); 2148 return ret; 2149 } 2150 2151 int 2152 upload_dir(struct sftp_conn *conn, const char *src, const char *dst, 2153 int preserve_flag, int print_flag, int resume, int fsync_flag, 2154 int follow_link_flag) 2155 { 2156 char *dst_canon; 2157 int ret; 2158 2159 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 2160 error("upload \"%s\": path canonicalization failed", dst); 2161 return -1; 2162 } 2163 2164 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, 2165 print_flag, resume, fsync_flag, follow_link_flag); 2166 2167 free(dst_canon); 2168 return ret; 2169 } 2170 2171 static void 2172 handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous, 2173 u_int *nreqsp, u_int *write_errorp) 2174 { 2175 struct sshbuf *msg; 2176 u_char type; 2177 u_int id, status; 2178 int r; 2179 struct pollfd pfd; 2180 2181 if ((msg = sshbuf_new()) == NULL) 2182 fatal_f("sshbuf_new failed"); 2183 2184 /* Try to eat replies from the upload side */ 2185 while (*nreqsp > 0) { 2186 debug3_f("%u outstanding replies", *nreqsp); 2187 if (!synchronous) { 2188 /* Bail out if no data is ready to be read */ 2189 pfd.fd = to->fd_in; 2190 pfd.events = POLLIN; 2191 if ((r = poll(&pfd, 1, 0)) == -1) { 2192 if (errno == EINTR) 2193 break; 2194 fatal_f("poll: %s", strerror(errno)); 2195 } else if (r == 0) 2196 break; /* fd not ready */ 2197 } 2198 sshbuf_reset(msg); 2199 get_msg(to, msg); 2200 2201 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 2202 (r = sshbuf_get_u32(msg, &id)) != 0) 2203 fatal_fr(r, "dest parse"); 2204 debug3("Received dest reply T:%u I:%u R:%u", type, id, *nreqsp); 2205 if (type != SSH2_FXP_STATUS) { 2206 fatal_f("Expected SSH2_FXP_STATUS(%d) packet, got %d", 2207 SSH2_FXP_STATUS, type); 2208 } 2209 if ((r = sshbuf_get_u32(msg, &status)) != 0) 2210 fatal_fr(r, "parse dest status"); 2211 debug3("dest SSH2_FXP_STATUS %u", status); 2212 if (status != SSH2_FX_OK) { 2213 /* record first error */ 2214 if (*write_errorp == 0) 2215 *write_errorp = status; 2216 } 2217 /* 2218 * XXX this doesn't do full reply matching like do_upload and 2219 * so cannot gracefully truncate terminated uploads at a 2220 * high-water mark. ATM the only caller of this function (scp) 2221 * doesn't support transfer resumption, so this doesn't matter 2222 * a whole lot. 2223 * 2224 * To be safe, do_crossload truncates the destination file to 2225 * zero length on upload failure, since we can't trust the 2226 * server not to have reordered replies that could have 2227 * inserted holes where none existed in the source file. 2228 * 2229 * XXX we could get a more accutate progress bar if we updated 2230 * the counter based on the reply from the destination... 2231 */ 2232 (*nreqsp)--; 2233 } 2234 debug3_f("done: %u outstanding replies", *nreqsp); 2235 sshbuf_free(msg); 2236 } 2237 2238 int 2239 do_crossload(struct sftp_conn *from, struct sftp_conn *to, 2240 const char *from_path, const char *to_path, 2241 Attrib *a, int preserve_flag) 2242 { 2243 struct sshbuf *msg; 2244 int write_error, read_error, r; 2245 u_int64_t offset = 0, size; 2246 u_int id, buflen, num_req, max_req, status = SSH2_FX_OK; 2247 u_int num_upload_req; 2248 off_t progress_counter; 2249 u_char *from_handle, *to_handle; 2250 size_t from_handle_len, to_handle_len; 2251 struct requests requests; 2252 struct request *req; 2253 u_char type; 2254 2255 debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path); 2256 2257 TAILQ_INIT(&requests); 2258 2259 if (a == NULL && (a = do_stat(from, from_path, 0)) == NULL) 2260 return -1; 2261 2262 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 2263 (!S_ISREG(a->perm))) { 2264 error("download \"%s\": not a regular file", from_path); 2265 return(-1); 2266 } 2267 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 2268 size = a->size; 2269 else 2270 size = 0; 2271 2272 buflen = from->download_buflen; 2273 if (buflen > to->upload_buflen) 2274 buflen = to->upload_buflen; 2275 2276 /* Send open request to read side */ 2277 if (send_open(from, from_path, "origin", SSH2_FXF_READ, NULL, 2278 &from_handle, &from_handle_len) != 0) 2279 return -1; 2280 2281 /* Send open request to write side */ 2282 a->flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2283 a->flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2284 a->perm &= 0777; 2285 if (!preserve_flag) 2286 a->flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 2287 if (send_open(to, to_path, "dest", 2288 SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, 2289 &to_handle, &to_handle_len) != 0) { 2290 do_close(from, from_handle, from_handle_len); 2291 return -1; 2292 } 2293 2294 /* Read from remote "from" and write to remote "to" */ 2295 offset = 0; 2296 write_error = read_error = num_req = num_upload_req = 0; 2297 max_req = 1; 2298 progress_counter = 0; 2299 2300 if (showprogress && size != 0) { 2301 start_progress_meter(progress_meter_path(from_path), 2302 size, &progress_counter); 2303 } 2304 if ((msg = sshbuf_new()) == NULL) 2305 fatal_f("sshbuf_new failed"); 2306 while (num_req > 0 || max_req > 0) { 2307 u_char *data; 2308 size_t len; 2309 2310 /* 2311 * Simulate EOF on interrupt: stop sending new requests and 2312 * allow outstanding requests to drain gracefully 2313 */ 2314 if (interrupted) { 2315 if (num_req == 0) /* If we haven't started yet... */ 2316 break; 2317 max_req = 0; 2318 } 2319 2320 /* Send some more requests */ 2321 while (num_req < max_req) { 2322 debug3("Request range %llu -> %llu (%d/%d)", 2323 (unsigned long long)offset, 2324 (unsigned long long)offset + buflen - 1, 2325 num_req, max_req); 2326 req = request_enqueue(&requests, from->msg_id++, 2327 buflen, offset); 2328 offset += buflen; 2329 num_req++; 2330 send_read_request(from, req->id, req->offset, 2331 req->len, from_handle, from_handle_len); 2332 } 2333 2334 /* Try to eat replies from the upload side (nonblocking) */ 2335 handle_dest_replies(to, to_path, 0, 2336 &num_upload_req, &write_error); 2337 2338 sshbuf_reset(msg); 2339 get_msg(from, msg); 2340 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 2341 (r = sshbuf_get_u32(msg, &id)) != 0) 2342 fatal_fr(r, "parse"); 2343 debug3("Received origin reply T:%u I:%u R:%d", 2344 type, id, max_req); 2345 2346 /* Find the request in our queue */ 2347 if ((req = request_find(&requests, id)) == NULL) 2348 fatal("Unexpected reply %u", id); 2349 2350 switch (type) { 2351 case SSH2_FXP_STATUS: 2352 if ((r = sshbuf_get_u32(msg, &status)) != 0) 2353 fatal_fr(r, "parse status"); 2354 if (status != SSH2_FX_EOF) 2355 read_error = 1; 2356 max_req = 0; 2357 TAILQ_REMOVE(&requests, req, tq); 2358 free(req); 2359 num_req--; 2360 break; 2361 case SSH2_FXP_DATA: 2362 if ((r = sshbuf_get_string(msg, &data, &len)) != 0) 2363 fatal_fr(r, "parse data"); 2364 debug3("Received data %llu -> %llu", 2365 (unsigned long long)req->offset, 2366 (unsigned long long)req->offset + len - 1); 2367 if (len > req->len) 2368 fatal("Received more data than asked for " 2369 "%zu > %zu", len, req->len); 2370 2371 /* Write this chunk out to the destination */ 2372 sshbuf_reset(msg); 2373 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 || 2374 (r = sshbuf_put_u32(msg, to->msg_id++)) != 0 || 2375 (r = sshbuf_put_string(msg, to_handle, 2376 to_handle_len)) != 0 || 2377 (r = sshbuf_put_u64(msg, req->offset)) != 0 || 2378 (r = sshbuf_put_string(msg, data, len)) != 0) 2379 fatal_fr(r, "compose write"); 2380 send_msg(to, msg); 2381 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%zu", 2382 id, (unsigned long long)offset, len); 2383 num_upload_req++; 2384 progress_counter += len; 2385 free(data); 2386 2387 if (len == req->len) { 2388 TAILQ_REMOVE(&requests, req, tq); 2389 free(req); 2390 num_req--; 2391 } else { 2392 /* Resend the request for the missing data */ 2393 debug3("Short data block, re-requesting " 2394 "%llu -> %llu (%2d)", 2395 (unsigned long long)req->offset + len, 2396 (unsigned long long)req->offset + 2397 req->len - 1, num_req); 2398 req->id = from->msg_id++; 2399 req->len -= len; 2400 req->offset += len; 2401 send_read_request(from, req->id, 2402 req->offset, req->len, 2403 from_handle, from_handle_len); 2404 /* Reduce the request size */ 2405 if (len < buflen) 2406 buflen = MAXIMUM(MIN_READ_SIZE, len); 2407 } 2408 if (max_req > 0) { /* max_req = 0 iff EOF received */ 2409 if (size > 0 && offset > size) { 2410 /* Only one request at a time 2411 * after the expected EOF */ 2412 debug3("Finish at %llu (%2d)", 2413 (unsigned long long)offset, 2414 num_req); 2415 max_req = 1; 2416 } else if (max_req < from->num_requests) { 2417 ++max_req; 2418 } 2419 } 2420 break; 2421 default: 2422 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 2423 SSH2_FXP_DATA, type); 2424 } 2425 } 2426 2427 if (showprogress && size) 2428 stop_progress_meter(); 2429 2430 /* Drain replies from the server (blocking) */ 2431 debug3_f("waiting for %u replies from destination", num_upload_req); 2432 handle_dest_replies(to, to_path, 1, &num_upload_req, &write_error); 2433 2434 /* Sanity check */ 2435 if (TAILQ_FIRST(&requests) != NULL) 2436 fatal("Transfer complete, but requests still in queue"); 2437 /* Truncate at 0 length on interrupt or error to avoid holes at dest */ 2438 if (read_error || write_error || interrupted) { 2439 debug("truncating \"%s\" at 0", to_path); 2440 do_close(to, to_handle, to_handle_len); 2441 free(to_handle); 2442 if (send_open(to, to_path, "dest", 2443 SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, 2444 &to_handle, &to_handle_len) != 0) { 2445 error("dest truncate \"%s\" failed", to_path); 2446 to_handle = NULL; 2447 } 2448 } 2449 if (read_error) { 2450 error("read origin \"%s\": %s", from_path, fx2txt(status)); 2451 status = -1; 2452 do_close(from, from_handle, from_handle_len); 2453 if (to_handle != NULL) 2454 do_close(to, to_handle, to_handle_len); 2455 } else if (write_error) { 2456 error("write dest \"%s\": %s", to_path, fx2txt(write_error)); 2457 status = SSH2_FX_FAILURE; 2458 do_close(from, from_handle, from_handle_len); 2459 if (to_handle != NULL) 2460 do_close(to, to_handle, to_handle_len); 2461 } else { 2462 if (do_close(from, from_handle, from_handle_len) != 0 || 2463 interrupted) 2464 status = -1; 2465 else 2466 status = SSH2_FX_OK; 2467 if (to_handle != NULL) { 2468 /* Need to resend utimes after write */ 2469 if (preserve_flag) 2470 do_fsetstat(to, to_handle, to_handle_len, a); 2471 do_close(to, to_handle, to_handle_len); 2472 } 2473 } 2474 sshbuf_free(msg); 2475 free(from_handle); 2476 free(to_handle); 2477 2478 return status == SSH2_FX_OK ? 0 : -1; 2479 } 2480 2481 static int 2482 crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, 2483 const char *from_path, const char *to_path, 2484 int depth, Attrib *dirattrib, int preserve_flag, int print_flag, 2485 int follow_link_flag) 2486 { 2487 int i, ret = 0; 2488 SFTP_DIRENT **dir_entries; 2489 char *filename, *new_from_path = NULL, *new_to_path = NULL; 2490 mode_t mode = 0777; 2491 Attrib curdir; 2492 2493 debug2_f("crossload dir src \"%s\" to dst \"%s\"", from_path, to_path); 2494 2495 if (depth >= MAX_DIR_DEPTH) { 2496 error("Maximum directory depth exceeded: %d levels", depth); 2497 return -1; 2498 } 2499 2500 if (dirattrib == NULL && 2501 (dirattrib = do_stat(from, from_path, 1)) == NULL) { 2502 error("stat remote \"%s\" failed", from_path); 2503 return -1; 2504 } 2505 if (!S_ISDIR(dirattrib->perm)) { 2506 error("\"%s\" is not a directory", from_path); 2507 return -1; 2508 } 2509 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 2510 mprintf("Retrieving %s\n", from_path); 2511 2512 curdir = *dirattrib; /* dirattrib will be clobbered */ 2513 curdir.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2514 curdir.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2515 if ((curdir.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) == 0) { 2516 debug("Origin did not send permissions for " 2517 "directory \"%s\"", to_path); 2518 curdir.perm = S_IWUSR|S_IXUSR; 2519 curdir.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 2520 } 2521 /* We need to be able to write to the directory while we transfer it */ 2522 mode = curdir.perm & 01777; 2523 curdir.perm = mode | (S_IWUSR|S_IXUSR); 2524 2525 /* 2526 * sftp lacks a portable status value to match errno EEXIST, 2527 * so if we get a failure back then we must check whether 2528 * the path already existed and is a directory. Ensure we can 2529 * write to the directory we create for the duration of the transfer. 2530 */ 2531 if (do_mkdir(to, to_path, &curdir, 0) != 0) { 2532 if ((dirattrib = do_stat(to, to_path, 0)) == NULL) 2533 return -1; 2534 if (!S_ISDIR(dirattrib->perm)) { 2535 error("\"%s\" exists but is not a directory", to_path); 2536 return -1; 2537 } 2538 } 2539 curdir.perm = mode; 2540 2541 if (do_readdir(from, from_path, &dir_entries) == -1) { 2542 error("origin readdir \"%s\" failed", from_path); 2543 return -1; 2544 } 2545 2546 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 2547 free(new_from_path); 2548 free(new_to_path); 2549 2550 filename = dir_entries[i]->filename; 2551 new_from_path = path_append(from_path, filename); 2552 new_to_path = path_append(to_path, filename); 2553 2554 if (S_ISDIR(dir_entries[i]->a.perm)) { 2555 if (strcmp(filename, ".") == 0 || 2556 strcmp(filename, "..") == 0) 2557 continue; 2558 if (crossload_dir_internal(from, to, 2559 new_from_path, new_to_path, 2560 depth + 1, &(dir_entries[i]->a), preserve_flag, 2561 print_flag, follow_link_flag) == -1) 2562 ret = -1; 2563 } else if (S_ISREG(dir_entries[i]->a.perm) || 2564 (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { 2565 /* 2566 * If this is a symlink then don't send the link's 2567 * Attrib. do_download() will do a FXP_STAT operation 2568 * and get the link target's attributes. 2569 */ 2570 if (do_crossload(from, to, new_from_path, new_to_path, 2571 S_ISLNK(dir_entries[i]->a.perm) ? NULL : 2572 &(dir_entries[i]->a), preserve_flag) == -1) { 2573 error("crossload \"%s\" to \"%s\" failed", 2574 new_from_path, new_to_path); 2575 ret = -1; 2576 } 2577 } else { 2578 logit("origin \"%s\": not a regular file", 2579 new_from_path); 2580 } 2581 } 2582 free(new_to_path); 2583 free(new_from_path); 2584 2585 do_setstat(to, to_path, &curdir); 2586 2587 free_sftp_dirents(dir_entries); 2588 2589 return ret; 2590 } 2591 2592 int 2593 crossload_dir(struct sftp_conn *from, struct sftp_conn *to, 2594 const char *from_path, const char *to_path, 2595 Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag) 2596 { 2597 char *from_path_canon; 2598 int ret; 2599 2600 if ((from_path_canon = do_realpath(from, from_path)) == NULL) { 2601 error("crossload \"%s\": path canonicalization failed", 2602 from_path); 2603 return -1; 2604 } 2605 2606 ret = crossload_dir_internal(from, to, from_path_canon, to_path, 0, 2607 dirattrib, preserve_flag, print_flag, follow_link_flag); 2608 free(from_path_canon); 2609 return ret; 2610 } 2611 2612 char * 2613 path_append(const char *p1, const char *p2) 2614 { 2615 char *ret; 2616 size_t len = strlen(p1) + strlen(p2) + 2; 2617 2618 ret = xmalloc(len); 2619 strlcpy(ret, p1, len); 2620 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 2621 strlcat(ret, "/", len); 2622 strlcat(ret, p2, len); 2623 2624 return(ret); 2625 } 2626 2627 char * 2628 make_absolute(char *p, const char *pwd) 2629 { 2630 char *abs_str; 2631 2632 /* Derelativise */ 2633 if (p && !path_absolute(p)) { 2634 abs_str = path_append(pwd, p); 2635 free(p); 2636 return(abs_str); 2637 } else 2638 return(p); 2639 } 2640 2641 int 2642 remote_is_dir(struct sftp_conn *conn, const char *path) 2643 { 2644 Attrib *a; 2645 2646 /* XXX: report errors? */ 2647 if ((a = do_stat(conn, path, 1)) == NULL) 2648 return(0); 2649 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) 2650 return(0); 2651 return(S_ISDIR(a->perm)); 2652 } 2653 2654 2655 int 2656 local_is_dir(const char *path) 2657 { 2658 struct stat sb; 2659 2660 /* XXX: report errors? */ 2661 if (stat(path, &sb) == -1) 2662 return(0); 2663 2664 return(S_ISDIR(sb.st_mode)); 2665 } 2666 2667 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ 2668 int 2669 globpath_is_dir(const char *pathname) 2670 { 2671 size_t l = strlen(pathname); 2672 2673 return l > 0 && pathname[l - 1] == '/'; 2674 } 2675 2676