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