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