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