xref: /netbsd-src/crypto/external/bsd/openssh/dist/sftp-client.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: sftp-client.c,v 1.27 2021/04/19 14:40:15 christos Exp $	*/
2 /* $OpenBSD: sftp-client.c,v 1.142 2021/04/03 06:18:41 djm 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.27 2021/04/19 14:40:15 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 <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 */
64 #define DEFAULT_COPY_BUFLEN	32768
65 
66 /* Default number of concurrent outstanding requests */
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 	u_int exts;
91 	u_int64_t limit_kbps;
92 	struct bwlimit bwlimit_in, bwlimit_out;
93 };
94 
95 static u_char *
96 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
97     const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
98 
99 /* ARGSUSED */
100 static int
101 sftpio(void *_bwlimit, size_t amount)
102 {
103 	struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
104 
105 	refresh_progress_meter(0);
106 	if (bwlimit != NULL)
107 		bandwidth_limit(bwlimit, amount);
108 	return 0;
109 }
110 
111 static void
112 send_msg(struct sftp_conn *conn, struct sshbuf *m)
113 {
114 	u_char mlen[4];
115 	struct iovec iov[2];
116 
117 	if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH)
118 		fatal("Outbound message too long %zu", sshbuf_len(m));
119 
120 	/* Send length first */
121 	put_u32(mlen, sshbuf_len(m));
122 	iov[0].iov_base = mlen;
123 	iov[0].iov_len = sizeof(mlen);
124 	iov[1].iov_base = __UNCONST(sshbuf_ptr(m));
125 	iov[1].iov_len = sshbuf_len(m);
126 
127 	if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
128 	    conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
129 	    sshbuf_len(m) + sizeof(mlen))
130 		fatal("Couldn't send packet: %s", strerror(errno));
131 
132 	sshbuf_reset(m);
133 }
134 
135 static void
136 get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
137 {
138 	u_int msg_len;
139 	u_char *p;
140 	int r;
141 
142 	if ((r = sshbuf_reserve(m, 4, &p)) != 0)
143 		fatal_fr(r, "reserve");
144 	if (atomicio6(read, conn->fd_in, p, 4, sftpio,
145 	    conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
146 		if (errno == EPIPE || errno == ECONNRESET)
147 			fatal("Connection closed");
148 		else
149 			fatal("Couldn't read packet: %s", strerror(errno));
150 	}
151 
152 	if ((r = sshbuf_get_u32(m, &msg_len)) != 0)
153 		fatal_fr(r, "sshbuf_get_u32");
154 	if (msg_len > SFTP_MAX_MSG_LENGTH) {
155 		do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL,
156 		    "Received message too long %u", msg_len);
157 		fatal("Ensure the remote shell produces no output "
158 		    "for non-interactive sessions.");
159 	}
160 
161 	if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
162 		fatal_fr(r, "reserve");
163 	if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
164 	    conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
165 	    != msg_len) {
166 		if (errno == EPIPE)
167 			fatal("Connection closed");
168 		else
169 			fatal("Read packet: %s", strerror(errno));
170 	}
171 }
172 
173 static void
174 get_msg(struct sftp_conn *conn, struct sshbuf *m)
175 {
176 	get_msg_extended(conn, m, 0);
177 }
178 
179 static void
180 send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s,
181     u_int len)
182 {
183 	struct sshbuf *msg;
184 	int r;
185 
186 	if ((msg = sshbuf_new()) == NULL)
187 		fatal_f("sshbuf_new failed");
188 	if ((r = sshbuf_put_u8(msg, code)) != 0 ||
189 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
190 	    (r = sshbuf_put_string(msg, s, len)) != 0)
191 		fatal_fr(r, "compose");
192 	send_msg(conn, msg);
193 	debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
194 	sshbuf_free(msg);
195 }
196 
197 static void
198 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
199     const void *s, u_int len, Attrib *a)
200 {
201 	struct sshbuf *msg;
202 	int r;
203 
204 	if ((msg = sshbuf_new()) == NULL)
205 		fatal_f("sshbuf_new failed");
206 	if ((r = sshbuf_put_u8(msg, code)) != 0 ||
207 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
208 	    (r = sshbuf_put_string(msg, s, len)) != 0 ||
209 	    (r = encode_attrib(msg, a)) != 0)
210 		fatal_fr(r, "compose");
211 	send_msg(conn, msg);
212 	debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
213 	sshbuf_free(msg);
214 }
215 
216 static u_int
217 get_status(struct sftp_conn *conn, u_int expected_id)
218 {
219 	struct sshbuf *msg;
220 	u_char type;
221 	u_int id, status;
222 	int r;
223 
224 	if ((msg = sshbuf_new()) == NULL)
225 		fatal_f("sshbuf_new failed");
226 	get_msg(conn, msg);
227 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
228 	    (r = sshbuf_get_u32(msg, &id)) != 0)
229 		fatal_fr(r, "compose");
230 
231 	if (id != expected_id)
232 		fatal("ID mismatch (%u != %u)", id, expected_id);
233 	if (type != SSH2_FXP_STATUS)
234 		fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
235 		    SSH2_FXP_STATUS, type);
236 
237 	if ((r = sshbuf_get_u32(msg, &status)) != 0)
238 		fatal_fr(r, "parse");
239 	sshbuf_free(msg);
240 
241 	debug3("SSH2_FXP_STATUS %u", status);
242 
243 	return status;
244 }
245 
246 static u_char *
247 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
248     const char *errfmt, ...)
249 {
250 	struct sshbuf *msg;
251 	u_int id, status;
252 	u_char type;
253 	u_char *handle;
254 	char errmsg[256];
255 	va_list args;
256 	int r;
257 
258 	va_start(args, errfmt);
259 	if (errfmt != NULL)
260 		vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
261 	va_end(args);
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, "parse");
269 
270 	if (id != expected_id)
271 		fatal("%s: ID mismatch (%u != %u)",
272 		    errfmt == NULL ? __func__ : errmsg, id, expected_id);
273 	if (type == SSH2_FXP_STATUS) {
274 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
275 			fatal_fr(r, "parse status");
276 		if (errfmt != NULL)
277 			error("%s: %s", errmsg, fx2txt(status));
278 		sshbuf_free(msg);
279 		return(NULL);
280 	} else if (type != SSH2_FXP_HANDLE)
281 		fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
282 		    errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
283 
284 	if ((r = sshbuf_get_string(msg, &handle, len)) != 0)
285 		fatal_fr(r, "parse handle");
286 	sshbuf_free(msg);
287 
288 	return handle;
289 }
290 
291 static Attrib *
292 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
293 {
294 	struct sshbuf *msg;
295 	u_int id;
296 	u_char type;
297 	int r;
298 	static Attrib a;
299 
300 	if ((msg = sshbuf_new()) == NULL)
301 		fatal_f("sshbuf_new failed");
302 	get_msg(conn, msg);
303 
304 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
305 	    (r = sshbuf_get_u32(msg, &id)) != 0)
306 		fatal_fr(r, "parse");
307 
308 	debug3("Received stat reply T:%u I:%u", type, id);
309 	if (id != expected_id)
310 		fatal("ID mismatch (%u != %u)", id, expected_id);
311 	if (type == SSH2_FXP_STATUS) {
312 		u_int status;
313 
314 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
315 			fatal_fr(r, "parse status");
316 		if (quiet)
317 			debug("Couldn't stat remote file: %s", fx2txt(status));
318 		else
319 			error("Couldn't stat remote file: %s", fx2txt(status));
320 		sshbuf_free(msg);
321 		return(NULL);
322 	} else if (type != SSH2_FXP_ATTRS) {
323 		fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
324 		    SSH2_FXP_ATTRS, type);
325 	}
326 	if ((r = decode_attrib(msg, &a)) != 0) {
327 		error_fr(r, "decode_attrib");
328 		sshbuf_free(msg);
329 		return NULL;
330 	}
331 	sshbuf_free(msg);
332 
333 	return &a;
334 }
335 
336 static int
337 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
338     u_int expected_id, int quiet)
339 {
340 	struct sshbuf *msg;
341 	u_char type;
342 	u_int id;
343 	u_int64_t flag;
344 	int r;
345 
346 	if ((msg = sshbuf_new()) == NULL)
347 		fatal_f("sshbuf_new failed");
348 	get_msg(conn, msg);
349 
350 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
351 	    (r = sshbuf_get_u32(msg, &id)) != 0)
352 		fatal_fr(r, "parse");
353 
354 	debug3("Received statvfs reply T:%u I:%u", type, id);
355 	if (id != expected_id)
356 		fatal("ID mismatch (%u != %u)", id, expected_id);
357 	if (type == SSH2_FXP_STATUS) {
358 		u_int status;
359 
360 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
361 			fatal_fr(r, "parse status");
362 		if (quiet)
363 			debug("Couldn't statvfs: %s", fx2txt(status));
364 		else
365 			error("Couldn't statvfs: %s", fx2txt(status));
366 		sshbuf_free(msg);
367 		return -1;
368 	} else if (type != SSH2_FXP_EXTENDED_REPLY) {
369 		fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
370 		    SSH2_FXP_EXTENDED_REPLY, type);
371 	}
372 
373 	memset(st, 0, sizeof(*st));
374 	if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 ||
375 	    (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 ||
376 	    (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 ||
377 	    (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 ||
378 	    (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 ||
379 	    (r = sshbuf_get_u64(msg, &st->f_files)) != 0 ||
380 	    (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 ||
381 	    (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 ||
382 	    (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 ||
383 	    (r = sshbuf_get_u64(msg, &flag)) != 0 ||
384 	    (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0)
385 		fatal_fr(r, "parse statvfs");
386 
387 	st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
388 	st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
389 
390 	sshbuf_free(msg);
391 
392 	return 0;
393 }
394 
395 struct sftp_conn *
396 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
397     u_int64_t limit_kbps)
398 {
399 	u_char type;
400 	struct sshbuf *msg;
401 	struct sftp_conn *ret;
402 	int r;
403 
404 	ret = xcalloc(1, sizeof(*ret));
405 	ret->msg_id = 1;
406 	ret->fd_in = fd_in;
407 	ret->fd_out = fd_out;
408 	ret->download_buflen = ret->upload_buflen =
409 	    transfer_buflen ? transfer_buflen : DEFAULT_COPY_BUFLEN;
410 	ret->num_requests =
411 	    num_requests ? num_requests : DEFAULT_NUM_REQUESTS;
412 	ret->exts = 0;
413 	ret->limit_kbps = 0;
414 
415 	if ((msg = sshbuf_new()) == NULL)
416 		fatal_f("sshbuf_new failed");
417 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 ||
418 	    (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
419 		fatal_fr(r, "parse");
420 
421 	send_msg(ret, msg);
422 
423 	get_msg_extended(ret, msg, 1);
424 
425 	/* Expecting a VERSION reply */
426 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
427 		fatal_fr(r, "parse type");
428 	if (type != SSH2_FXP_VERSION) {
429 		error("Invalid packet back from SSH2_FXP_INIT (type %u)",
430 		    type);
431 		sshbuf_free(msg);
432 		free(ret);
433 		return(NULL);
434 	}
435 	if ((r = sshbuf_get_u32(msg, &ret->version)) != 0)
436 		fatal_fr(r, "parse version");
437 
438 	debug2("Remote version: %u", ret->version);
439 
440 	/* Check for extensions */
441 	while (sshbuf_len(msg) > 0) {
442 		char *name;
443 		u_char *value;
444 		size_t vlen;
445 		int known = 0;
446 
447 		if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 ||
448 		    (r = sshbuf_get_string(msg, &value, &vlen)) != 0)
449 			fatal_fr(r, "parse extension");
450 		if (strcmp(name, "posix-rename@openssh.com") == 0 &&
451 		    strcmp((char *)value, "1") == 0) {
452 			ret->exts |= SFTP_EXT_POSIX_RENAME;
453 			known = 1;
454 		} else if (strcmp(name, "statvfs@openssh.com") == 0 &&
455 		    strcmp((char *)value, "2") == 0) {
456 			ret->exts |= SFTP_EXT_STATVFS;
457 			known = 1;
458 		} else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
459 		    strcmp((char *)value, "2") == 0) {
460 			ret->exts |= SFTP_EXT_FSTATVFS;
461 			known = 1;
462 		} else if (strcmp(name, "hardlink@openssh.com") == 0 &&
463 		    strcmp((char *)value, "1") == 0) {
464 			ret->exts |= SFTP_EXT_HARDLINK;
465 			known = 1;
466 		} else if (strcmp(name, "fsync@openssh.com") == 0 &&
467 		    strcmp((char *)value, "1") == 0) {
468 			ret->exts |= SFTP_EXT_FSYNC;
469 			known = 1;
470 		} else if (strcmp(name, "lsetstat@openssh.com") == 0 &&
471 		    strcmp((char *)value, "1") == 0) {
472 			ret->exts |= SFTP_EXT_LSETSTAT;
473 			known = 1;
474 		} else if (strcmp(name, "limits@openssh.com") == 0 &&
475 		    strcmp((char *)value, "1") == 0) {
476 			ret->exts |= SFTP_EXT_LIMITS;
477 			known = 1;
478 		}
479 		if (known) {
480 			debug2("Server supports extension \"%s\" revision %s",
481 			    name, value);
482 		} else {
483 			debug2("Unrecognised server extension \"%s\"", name);
484 		}
485 		free(name);
486 		free(value);
487 	}
488 
489 	sshbuf_free(msg);
490 
491 	/* Query the server for its limits */
492 	if (ret->exts & SFTP_EXT_LIMITS) {
493 		struct sftp_limits limits;
494 		if (do_limits(ret, &limits) != 0)
495 			fatal_f("limits failed");
496 
497 		/* If the caller did not specify, find a good value */
498 		if (transfer_buflen == 0) {
499 			ret->download_buflen = limits.read_length;
500 			ret->upload_buflen = limits.write_length;
501 			debug("Using server download size %u", ret->download_buflen);
502 			debug("Using server upload size %u", ret->upload_buflen);
503 		}
504 
505 		/* Use the server limit to scale down our value only */
506 		if (num_requests == 0 && limits.open_handles) {
507 			ret->num_requests =
508 			    MINIMUM(DEFAULT_NUM_REQUESTS, limits.open_handles);
509 			debug("Server handle limit %llu; using %u",
510 			    (unsigned long long)limits.open_handles,
511 			    ret->num_requests);
512 		}
513 	}
514 
515 	/* Some filexfer v.0 servers don't support large packets */
516 	if (ret->version == 0) {
517 		ret->download_buflen = MINIMUM(ret->download_buflen, 20480);
518 		ret->upload_buflen = MINIMUM(ret->upload_buflen, 20480);
519 	}
520 
521 	ret->limit_kbps = limit_kbps;
522 	if (ret->limit_kbps > 0) {
523 		bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps,
524 		    ret->download_buflen);
525 		bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
526 		    ret->upload_buflen);
527 	}
528 
529 	return ret;
530 }
531 
532 u_int
533 sftp_proto_version(struct sftp_conn *conn)
534 {
535 	return conn->version;
536 }
537 
538 int
539 do_limits(struct sftp_conn *conn, struct sftp_limits *limits)
540 {
541 	u_int id, msg_id;
542 	u_char type;
543 	struct sshbuf *msg;
544 	int r;
545 
546 	if ((conn->exts & SFTP_EXT_LIMITS) == 0) {
547 		error("Server does not support limits@openssh.com extension");
548 		return -1;
549 	}
550 
551 	if ((msg = sshbuf_new()) == NULL)
552 		fatal_f("sshbuf_new failed");
553 
554 	id = conn->msg_id++;
555 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
556 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
557 	    (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0)
558 		fatal_fr(r, "compose");
559 	send_msg(conn, msg);
560 	debug3("Sent message limits@openssh.com I:%u", id);
561 
562 	get_msg(conn, msg);
563 
564 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
565 	    (r = sshbuf_get_u32(msg, &msg_id)) != 0)
566 		fatal_fr(r, "parse");
567 
568 	debug3("Received limits reply T:%u I:%u", type, msg_id);
569 	if (id != msg_id)
570 		fatal("ID mismatch (%u != %u)", msg_id, id);
571 	if (type != SSH2_FXP_EXTENDED_REPLY) {
572 		fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
573 		    SSH2_FXP_EXTENDED_REPLY, type);
574 	}
575 
576 	memset(limits, 0, sizeof(*limits));
577 	if ((r = sshbuf_get_u64(msg, &limits->packet_length)) != 0 ||
578 	    (r = sshbuf_get_u64(msg, &limits->read_length)) != 0 ||
579 	    (r = sshbuf_get_u64(msg, &limits->write_length)) != 0 ||
580 	    (r = sshbuf_get_u64(msg, &limits->open_handles)) != 0)
581 		fatal_fr(r, "parse limits");
582 
583 	sshbuf_free(msg);
584 
585 	return 0;
586 }
587 
588 int
589 do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
590 {
591 	u_int id, status;
592 	struct sshbuf *msg;
593 	int r;
594 
595 	if ((msg = sshbuf_new()) == NULL)
596 		fatal_f("sshbuf_new failed");
597 
598 	id = conn->msg_id++;
599 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 ||
600 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
601 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
602 		fatal_fr(r, "parse");
603 	send_msg(conn, msg);
604 	debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
605 
606 	status = get_status(conn, id);
607 	if (status != SSH2_FX_OK)
608 		error("Couldn't close file: %s", fx2txt(status));
609 
610 	sshbuf_free(msg);
611 
612 	return status == SSH2_FX_OK ? 0 : -1;
613 }
614 
615 
616 static int
617 do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
618     SFTP_DIRENT ***dir)
619 {
620 	struct sshbuf *msg;
621 	u_int count, id, i, expected_id, ents = 0;
622 	size_t handle_len;
623 	u_char type, *handle;
624 	int status = SSH2_FX_FAILURE;
625 	int r;
626 
627 	if (dir)
628 		*dir = NULL;
629 
630 	id = conn->msg_id++;
631 
632 	if ((msg = sshbuf_new()) == NULL)
633 		fatal_f("sshbuf_new failed");
634 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 ||
635 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
636 	    (r = sshbuf_put_cstring(msg, path)) != 0)
637 		fatal_fr(r, "compose OPENDIR");
638 	send_msg(conn, msg);
639 
640 	handle = get_handle(conn, id, &handle_len,
641 	    "remote readdir(\"%s\")", path);
642 	if (handle == NULL) {
643 		sshbuf_free(msg);
644 		return -1;
645 	}
646 
647 	if (dir) {
648 		ents = 0;
649 		*dir = xcalloc(1, sizeof(**dir));
650 		(*dir)[0] = NULL;
651 	}
652 
653 	for (; !interrupted;) {
654 		id = expected_id = conn->msg_id++;
655 
656 		debug3("Sending SSH2_FXP_READDIR I:%u", id);
657 
658 		sshbuf_reset(msg);
659 		if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 ||
660 		    (r = sshbuf_put_u32(msg, id)) != 0 ||
661 		    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
662 			fatal_fr(r, "compose READDIR");
663 		send_msg(conn, msg);
664 
665 		sshbuf_reset(msg);
666 
667 		get_msg(conn, msg);
668 
669 		if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
670 		    (r = sshbuf_get_u32(msg, &id)) != 0)
671 			fatal_fr(r, "parse");
672 
673 		debug3("Received reply T:%u I:%u", type, id);
674 
675 		if (id != expected_id)
676 			fatal("ID mismatch (%u != %u)", id, expected_id);
677 
678 		if (type == SSH2_FXP_STATUS) {
679 			u_int rstatus;
680 
681 			if ((r = sshbuf_get_u32(msg, &rstatus)) != 0)
682 				fatal_fr(r, "parse status");
683 			debug3("Received SSH2_FXP_STATUS %d", rstatus);
684 			if (rstatus == SSH2_FX_EOF)
685 				break;
686 			error("Couldn't read directory: %s", fx2txt(rstatus));
687 			goto out;
688 		} else if (type != SSH2_FXP_NAME)
689 			fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
690 			    SSH2_FXP_NAME, type);
691 
692 		if ((r = sshbuf_get_u32(msg, &count)) != 0)
693 			fatal_fr(r, "parse count");
694 		if (count > SSHBUF_SIZE_MAX)
695 			fatal_f("nonsensical number of entries");
696 		if (count == 0)
697 			break;
698 		debug3("Received %d SSH2_FXP_NAME responses", count);
699 		for (i = 0; i < count; i++) {
700 			char *filename, *longname;
701 			Attrib a;
702 
703 			if ((r = sshbuf_get_cstring(msg, &filename,
704 			    NULL)) != 0 ||
705 			    (r = sshbuf_get_cstring(msg, &longname,
706 			    NULL)) != 0)
707 				fatal_fr(r, "parse filenames");
708 			if ((r = decode_attrib(msg, &a)) != 0) {
709 				error_fr(r, "couldn't decode attrib");
710 				free(filename);
711 				free(longname);
712 				goto out;
713 			}
714 
715 			if (print_flag)
716 				mprintf("%s\n", longname);
717 
718 			/*
719 			 * Directory entries should never contain '/'
720 			 * These can be used to attack recursive ops
721 			 * (e.g. send '../../../../etc/passwd')
722 			 */
723 			if (strchr(filename, '/') != NULL) {
724 				error("Server sent suspect path \"%s\" "
725 				    "during readdir of \"%s\"", filename, path);
726 			} else if (dir) {
727 				*dir = xreallocarray(*dir, ents + 2, sizeof(**dir));
728 				(*dir)[ents] = xcalloc(1, sizeof(***dir));
729 				(*dir)[ents]->filename = xstrdup(filename);
730 				(*dir)[ents]->longname = xstrdup(longname);
731 				memcpy(&(*dir)[ents]->a, &a, sizeof(a));
732 				(*dir)[++ents] = NULL;
733 			}
734 			free(filename);
735 			free(longname);
736 		}
737 	}
738 	status = 0;
739 
740  out:
741 	sshbuf_free(msg);
742 	do_close(conn, handle, handle_len);
743 	free(handle);
744 
745 	if (status != 0 && dir != NULL) {
746 		/* Don't return results on error */
747 		free_sftp_dirents(*dir);
748 		*dir = NULL;
749 	} else if (interrupted && dir != NULL && *dir != NULL) {
750 		/* Don't return partial matches on interrupt */
751 		free_sftp_dirents(*dir);
752 		*dir = xcalloc(1, sizeof(**dir));
753 		**dir = NULL;
754 	}
755 
756 	return status == SSH2_FX_OK ? 0 : -1;
757 }
758 
759 int
760 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
761 {
762 	return(do_lsreaddir(conn, path, 0, dir));
763 }
764 
765 void free_sftp_dirents(SFTP_DIRENT **s)
766 {
767 	int i;
768 
769 	if (s == NULL)
770 		return;
771 	for (i = 0; s[i]; i++) {
772 		free(s[i]->filename);
773 		free(s[i]->longname);
774 		free(s[i]);
775 	}
776 	free(s);
777 }
778 
779 int
780 do_rm(struct sftp_conn *conn, const char *path)
781 {
782 	u_int status, id;
783 
784 	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
785 
786 	id = conn->msg_id++;
787 	send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
788 	status = get_status(conn, id);
789 	if (status != SSH2_FX_OK)
790 		error("Couldn't delete file: %s", fx2txt(status));
791 	return status == SSH2_FX_OK ? 0 : -1;
792 }
793 
794 int
795 do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
796 {
797 	u_int status, id;
798 
799 	id = conn->msg_id++;
800 	send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
801 	    strlen(path), a);
802 
803 	status = get_status(conn, id);
804 	if (status != SSH2_FX_OK && print_flag)
805 		error("Couldn't create directory: %s", fx2txt(status));
806 
807 	return status == SSH2_FX_OK ? 0 : -1;
808 }
809 
810 int
811 do_rmdir(struct sftp_conn *conn, const char *path)
812 {
813 	u_int status, id;
814 
815 	id = conn->msg_id++;
816 	send_string_request(conn, id, SSH2_FXP_RMDIR, path,
817 	    strlen(path));
818 
819 	status = get_status(conn, id);
820 	if (status != SSH2_FX_OK)
821 		error("Couldn't remove directory: %s", fx2txt(status));
822 
823 	return status == SSH2_FX_OK ? 0 : -1;
824 }
825 
826 Attrib *
827 do_stat(struct sftp_conn *conn, const char *path, int quiet)
828 {
829 	u_int id;
830 
831 	id = conn->msg_id++;
832 
833 	send_string_request(conn, id,
834 	    conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
835 	    path, strlen(path));
836 
837 	return(get_decode_stat(conn, id, quiet));
838 }
839 
840 Attrib *
841 do_lstat(struct sftp_conn *conn, const char *path, int quiet)
842 {
843 	u_int id;
844 
845 	if (conn->version == 0) {
846 		if (quiet)
847 			debug("Server version does not support lstat operation");
848 		else
849 			logit("Server version does not support lstat operation");
850 		return(do_stat(conn, path, quiet));
851 	}
852 
853 	id = conn->msg_id++;
854 	send_string_request(conn, id, SSH2_FXP_LSTAT, path,
855 	    strlen(path));
856 
857 	return(get_decode_stat(conn, id, quiet));
858 }
859 
860 #ifdef notyet
861 Attrib *
862 do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
863     int quiet)
864 {
865 	u_int id;
866 
867 	id = conn->msg_id++;
868 	send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
869 	    handle_len);
870 
871 	return(get_decode_stat(conn, id, quiet));
872 }
873 #endif
874 
875 int
876 do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
877 {
878 	u_int status, id;
879 
880 	id = conn->msg_id++;
881 	send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
882 	    strlen(path), a);
883 
884 	status = get_status(conn, id);
885 	if (status != SSH2_FX_OK)
886 		error("Couldn't setstat on \"%s\": %s", path,
887 		    fx2txt(status));
888 
889 	return status == SSH2_FX_OK ? 0 : -1;
890 }
891 
892 int
893 do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
894     Attrib *a)
895 {
896 	u_int status, id;
897 
898 	id = conn->msg_id++;
899 	send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
900 	    handle_len, a);
901 
902 	status = get_status(conn, id);
903 	if (status != SSH2_FX_OK)
904 		error("Couldn't fsetstat: %s", fx2txt(status));
905 
906 	return status == SSH2_FX_OK ? 0 : -1;
907 }
908 
909 char *
910 do_realpath(struct sftp_conn *conn, const char *path)
911 {
912 	struct sshbuf *msg;
913 	u_int expected_id, count, id;
914 	char *filename, *longname;
915 	Attrib a;
916 	u_char type;
917 	int r;
918 
919 	expected_id = id = conn->msg_id++;
920 	send_string_request(conn, id, SSH2_FXP_REALPATH, path,
921 	    strlen(path));
922 
923 	if ((msg = sshbuf_new()) == NULL)
924 		fatal_f("sshbuf_new failed");
925 
926 	get_msg(conn, msg);
927 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
928 	    (r = sshbuf_get_u32(msg, &id)) != 0)
929 		fatal_fr(r, "parse");
930 
931 	if (id != expected_id)
932 		fatal("ID mismatch (%u != %u)", id, expected_id);
933 
934 	if (type == SSH2_FXP_STATUS) {
935 		u_int status;
936 
937 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
938 			fatal_fr(r, "parse status");
939 		error("Couldn't canonicalize: %s", fx2txt(status));
940 		sshbuf_free(msg);
941 		return NULL;
942 	} else if (type != SSH2_FXP_NAME)
943 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
944 		    SSH2_FXP_NAME, type);
945 
946 	if ((r = sshbuf_get_u32(msg, &count)) != 0)
947 		fatal_fr(r, "parse count");
948 	if (count != 1)
949 		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
950 
951 	if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
952 	    (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
953 	    (r = decode_attrib(msg, &a)) != 0)
954 		fatal_fr(r, "parse filename/attrib");
955 
956 	debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
957 	    (unsigned long)a.size);
958 
959 	free(longname);
960 
961 	sshbuf_free(msg);
962 
963 	return(filename);
964 }
965 
966 int
967 do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
968     int force_legacy)
969 {
970 	struct sshbuf *msg;
971 	u_int status, id;
972 	int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy;
973 
974 	if ((msg = sshbuf_new()) == NULL)
975 		fatal_f("sshbuf_new failed");
976 
977 	/* Send rename request */
978 	id = conn->msg_id++;
979 	if (use_ext) {
980 		if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
981 		    (r = sshbuf_put_u32(msg, id)) != 0 ||
982 		    (r = sshbuf_put_cstring(msg,
983 		    "posix-rename@openssh.com")) != 0)
984 			fatal_fr(r, "compose posix-rename");
985 	} else {
986 		if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 ||
987 		    (r = sshbuf_put_u32(msg, id)) != 0)
988 			fatal_fr(r, "compose rename");
989 	}
990 	if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
991 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
992 		fatal_fr(r, "compose paths");
993 	send_msg(conn, msg);
994 	debug3("Sent message %s \"%s\" -> \"%s\"",
995 	    use_ext ? "posix-rename@openssh.com" :
996 	    "SSH2_FXP_RENAME", oldpath, newpath);
997 	sshbuf_free(msg);
998 
999 	status = get_status(conn, id);
1000 	if (status != SSH2_FX_OK)
1001 		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
1002 		    newpath, fx2txt(status));
1003 
1004 	return status == SSH2_FX_OK ? 0 : -1;
1005 }
1006 
1007 int
1008 do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
1009 {
1010 	struct sshbuf *msg;
1011 	u_int status, id;
1012 	int r;
1013 
1014 	if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
1015 		error("Server does not support hardlink@openssh.com extension");
1016 		return -1;
1017 	}
1018 
1019 	if ((msg = sshbuf_new()) == NULL)
1020 		fatal_f("sshbuf_new failed");
1021 
1022 	/* Send link request */
1023 	id = conn->msg_id++;
1024 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1025 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1026 	    (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 ||
1027 	    (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
1028 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
1029 		fatal_fr(r, "compose");
1030 	send_msg(conn, msg);
1031 	debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
1032 	    oldpath, newpath);
1033 	sshbuf_free(msg);
1034 
1035 	status = get_status(conn, id);
1036 	if (status != SSH2_FX_OK)
1037 		error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
1038 		    newpath, fx2txt(status));
1039 
1040 	return status == SSH2_FX_OK ? 0 : -1;
1041 }
1042 
1043 int
1044 do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
1045 {
1046 	struct sshbuf *msg;
1047 	u_int status, id;
1048 	int r;
1049 
1050 	if (conn->version < 3) {
1051 		error("This server does not support the symlink operation");
1052 		return(SSH2_FX_OP_UNSUPPORTED);
1053 	}
1054 
1055 	if ((msg = sshbuf_new()) == NULL)
1056 		fatal_f("sshbuf_new failed");
1057 
1058 	/* Send symlink request */
1059 	id = conn->msg_id++;
1060 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 ||
1061 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1062 	    (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
1063 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
1064 		fatal_fr(r, "compose");
1065 	send_msg(conn, msg);
1066 	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
1067 	    newpath);
1068 	sshbuf_free(msg);
1069 
1070 	status = get_status(conn, id);
1071 	if (status != SSH2_FX_OK)
1072 		error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
1073 		    newpath, fx2txt(status));
1074 
1075 	return status == SSH2_FX_OK ? 0 : -1;
1076 }
1077 
1078 int
1079 do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
1080 {
1081 	struct sshbuf *msg;
1082 	u_int status, id;
1083 	int r;
1084 
1085 	/* Silently return if the extension is not supported */
1086 	if ((conn->exts & SFTP_EXT_FSYNC) == 0)
1087 		return -1;
1088 
1089 	/* Send fsync request */
1090 	if ((msg = sshbuf_new()) == NULL)
1091 		fatal_f("sshbuf_new failed");
1092 	id = conn->msg_id++;
1093 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1094 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1095 	    (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
1096 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1097 		fatal_fr(r, "compose");
1098 	send_msg(conn, msg);
1099 	debug3("Sent message fsync@openssh.com I:%u", id);
1100 	sshbuf_free(msg);
1101 
1102 	status = get_status(conn, id);
1103 	if (status != SSH2_FX_OK)
1104 		error("Couldn't sync file: %s", fx2txt(status));
1105 
1106 	return status == SSH2_FX_OK ? 0 : -1;
1107 }
1108 
1109 #ifdef notyet
1110 char *
1111 do_readlink(struct sftp_conn *conn, const char *path)
1112 {
1113 	struct sshbuf *msg;
1114 	u_int expected_id, count, id;
1115 	char *filename, *longname;
1116 	Attrib a;
1117 	u_char type;
1118 	int r;
1119 
1120 	expected_id = id = conn->msg_id++;
1121 	send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
1122 
1123 	if ((msg = sshbuf_new()) == NULL)
1124 		fatal_f("sshbuf_new failed");
1125 
1126 	get_msg(conn, msg);
1127 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1128 	    (r = sshbuf_get_u32(msg, &id)) != 0)
1129 		fatal_fr(r, "parse");
1130 
1131 	if (id != expected_id)
1132 		fatal("ID mismatch (%u != %u)", id, expected_id);
1133 
1134 	if (type == SSH2_FXP_STATUS) {
1135 		u_int status;
1136 
1137 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
1138 			fatal_fr(r, "parse status");
1139 		error("Couldn't readlink: %s", fx2txt(status));
1140 		sshbuf_free(msg);
1141 		return(NULL);
1142 	} else if (type != SSH2_FXP_NAME)
1143 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
1144 		    SSH2_FXP_NAME, type);
1145 
1146 	if ((r = sshbuf_get_u32(msg, &count)) != 0)
1147 		fatal_fr(r, "parse count");
1148 	if (count != 1)
1149 		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
1150 
1151 	if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
1152 	    (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
1153 	    (r = decode_attrib(msg, &a)) != 0)
1154 		fatal_fr(r, "parse filenames/attrib");
1155 
1156 	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
1157 
1158 	free(longname);
1159 
1160 	sshbuf_free(msg);
1161 
1162 	return filename;
1163 }
1164 #endif
1165 
1166 int
1167 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
1168     int quiet)
1169 {
1170 	struct sshbuf *msg;
1171 	u_int id;
1172 	int r;
1173 
1174 	if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
1175 		error("Server does not support statvfs@openssh.com extension");
1176 		return -1;
1177 	}
1178 
1179 	id = conn->msg_id++;
1180 
1181 	if ((msg = sshbuf_new()) == NULL)
1182 		fatal_f("sshbuf_new failed");
1183 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1184 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1185 	    (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
1186 	    (r = sshbuf_put_cstring(msg, path)) != 0)
1187 		fatal_fr(r, "compose");
1188 	send_msg(conn, msg);
1189 	sshbuf_free(msg);
1190 
1191 	return get_decode_statvfs(conn, st, id, quiet);
1192 }
1193 
1194 #ifdef notyet
1195 int
1196 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
1197     struct sftp_statvfs *st, int quiet)
1198 {
1199 	struct sshbuf *msg;
1200 	u_int id;
1201 
1202 	if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
1203 		error("Server does not support fstatvfs@openssh.com extension");
1204 		return -1;
1205 	}
1206 
1207 	id = conn->msg_id++;
1208 
1209 	if ((msg = sshbuf_new()) == NULL)
1210 		fatal_f("sshbuf_new failed");
1211 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1212 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1213 	    (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
1214 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1215 		fatal_fr(r, "compose");
1216 	send_msg(conn, msg);
1217 	sshbuf_free(msg);
1218 
1219 	return get_decode_statvfs(conn, st, id, quiet);
1220 }
1221 #endif
1222 
1223 int
1224 do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
1225 {
1226 	struct sshbuf *msg;
1227 	u_int status, id;
1228 	int r;
1229 
1230 	if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) {
1231 		error("Server does not support lsetstat@openssh.com extension");
1232 		return -1;
1233 	}
1234 
1235 	id = conn->msg_id++;
1236 	if ((msg = sshbuf_new()) == NULL)
1237 		fatal_f("sshbuf_new failed");
1238 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1239 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1240 	    (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
1241 	    (r = sshbuf_put_cstring(msg, path)) != 0 ||
1242 	    (r = encode_attrib(msg, a)) != 0)
1243 		fatal_fr(r, "compose");
1244 	send_msg(conn, msg);
1245 	sshbuf_free(msg);
1246 
1247 	status = get_status(conn, id);
1248 	if (status != SSH2_FX_OK)
1249 		error("Couldn't setstat on \"%s\": %s", path,
1250 		    fx2txt(status));
1251 
1252 	return status == SSH2_FX_OK ? 0 : -1;
1253 }
1254 
1255 static void
1256 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
1257     u_int len, const u_char *handle, u_int handle_len)
1258 {
1259 	struct sshbuf *msg;
1260 	int r;
1261 
1262 	if ((msg = sshbuf_new()) == NULL)
1263 		fatal_f("sshbuf_new failed");
1264 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
1265 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1266 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
1267 	    (r = sshbuf_put_u64(msg, offset)) != 0 ||
1268 	    (r = sshbuf_put_u32(msg, len)) != 0)
1269 		fatal_fr(r, "compose");
1270 	send_msg(conn, msg);
1271 	sshbuf_free(msg);
1272 }
1273 
1274 int
1275 do_download(struct sftp_conn *conn, const char *remote_path,
1276     const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
1277     int fsync_flag)
1278 {
1279 	Attrib junk;
1280 	struct sshbuf *msg;
1281 	u_char *handle;
1282 	int local_fd = -1, write_error;
1283 	int read_error, write_errno, lmodified = 0, reordered = 0, r;
1284 	u_int64_t offset = 0, size, highwater;
1285 	u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK;
1286 	off_t progress_counter;
1287 	size_t handle_len;
1288 	struct stat st;
1289 	struct request {
1290 		u_int id;
1291 		size_t len;
1292 		u_int64_t offset;
1293 		TAILQ_ENTRY(request) tq;
1294 	};
1295 	TAILQ_HEAD(reqhead, request) requests;
1296 	struct request *req;
1297 	u_char type;
1298 
1299 	status = -1;
1300 	TAILQ_INIT(&requests);
1301 
1302 	if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
1303 		return -1;
1304 
1305 	/* Do not preserve set[ug]id here, as we do not preserve ownership */
1306 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1307 		mode = a->perm & 0777;
1308 	else
1309 		mode = 0666;
1310 
1311 	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1312 	    (!S_ISREG(a->perm))) {
1313 		error("Cannot download non-regular file: %s", remote_path);
1314 		return(-1);
1315 	}
1316 
1317 	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1318 		size = a->size;
1319 	else
1320 		size = 0;
1321 
1322 	buflen = conn->download_buflen;
1323 	if ((msg = sshbuf_new()) == NULL)
1324 		fatal_f("sshbuf_new failed");
1325 
1326 	attrib_clear(&junk); /* Send empty attributes */
1327 
1328 	/* Send open request */
1329 	id = conn->msg_id++;
1330 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1331 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1332 	    (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1333 	    (r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 ||
1334 	    (r = encode_attrib(msg, &junk)) != 0)
1335 		fatal_fr(r, "compose");
1336 	send_msg(conn, msg);
1337 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1338 
1339 	handle = get_handle(conn, id, &handle_len,
1340 	    "remote open(\"%s\")", remote_path);
1341 	if (handle == NULL) {
1342 		sshbuf_free(msg);
1343 		return(-1);
1344 	}
1345 
1346 	local_fd = open(local_path,
1347 	    O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
1348 	if (local_fd == -1) {
1349 		error("Couldn't open local file \"%s\" for writing: %s",
1350 		    local_path, strerror(errno));
1351 		goto fail;
1352 	}
1353 	offset = highwater = 0;
1354 	if (resume_flag) {
1355 		if (fstat(local_fd, &st) == -1) {
1356 			error("Unable to stat local file \"%s\": %s",
1357 			    local_path, strerror(errno));
1358 			goto fail;
1359 		}
1360 		if (st.st_size < 0) {
1361 			error("\"%s\" has negative size", local_path);
1362 			goto fail;
1363 		}
1364 		if ((u_int64_t)st.st_size > size) {
1365 			error("Unable to resume download of \"%s\": "
1366 			    "local file is larger than remote", local_path);
1367  fail:
1368 			do_close(conn, handle, handle_len);
1369 			sshbuf_free(msg);
1370 			free(handle);
1371 			if (local_fd != -1)
1372 				close(local_fd);
1373 			return -1;
1374 		}
1375 		offset = highwater = st.st_size;
1376 	}
1377 
1378 	/* Read from remote and write to local */
1379 	write_error = read_error = write_errno = num_req = 0;
1380 	max_req = 1;
1381 	progress_counter = offset;
1382 
1383 	if (showprogress && size != 0)
1384 		start_progress_meter(remote_path, size, &progress_counter);
1385 
1386 	while (num_req > 0 || max_req > 0) {
1387 		u_char *data;
1388 		size_t len;
1389 
1390 		/*
1391 		 * Simulate EOF on interrupt: stop sending new requests and
1392 		 * allow outstanding requests to drain gracefully
1393 		 */
1394 		if (interrupted) {
1395 			if (num_req == 0) /* If we haven't started yet... */
1396 				break;
1397 			max_req = 0;
1398 		}
1399 
1400 		/* Send some more requests */
1401 		while (num_req < max_req) {
1402 			debug3("Request range %llu -> %llu (%d/%d)",
1403 			    (unsigned long long)offset,
1404 			    (unsigned long long)offset + buflen - 1,
1405 			    num_req, max_req);
1406 			req = xcalloc(1, sizeof(*req));
1407 			req->id = conn->msg_id++;
1408 			req->len = buflen;
1409 			req->offset = offset;
1410 			offset += buflen;
1411 			num_req++;
1412 			TAILQ_INSERT_TAIL(&requests, req, tq);
1413 			send_read_request(conn, req->id, req->offset,
1414 			    req->len, handle, handle_len);
1415 		}
1416 
1417 		sshbuf_reset(msg);
1418 		get_msg(conn, msg);
1419 		if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1420 		    (r = sshbuf_get_u32(msg, &id)) != 0)
1421 			fatal_fr(r, "parse");
1422 		debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1423 
1424 		/* Find the request in our queue */
1425 		for (req = TAILQ_FIRST(&requests);
1426 		    req != NULL && req->id != id;
1427 		    req = TAILQ_NEXT(req, tq))
1428 			;
1429 		if (req == NULL)
1430 			fatal("Unexpected reply %u", id);
1431 
1432 		switch (type) {
1433 		case SSH2_FXP_STATUS:
1434 			if ((r = sshbuf_get_u32(msg, &status)) != 0)
1435 				fatal_fr(r, "parse status");
1436 			if (status != SSH2_FX_EOF)
1437 				read_error = 1;
1438 			max_req = 0;
1439 			TAILQ_REMOVE(&requests, req, tq);
1440 			free(req);
1441 			num_req--;
1442 			break;
1443 		case SSH2_FXP_DATA:
1444 			if ((r = sshbuf_get_string(msg, &data, &len)) != 0)
1445 				fatal_fr(r, "parse data");
1446 			debug3("Received data %llu -> %llu",
1447 			    (unsigned long long)req->offset,
1448 			    (unsigned long long)req->offset + len - 1);
1449 			if (len > req->len)
1450 				fatal("Received more data than asked for "
1451 				    "%zu > %zu", len, req->len);
1452 			lmodified = 1;
1453 			if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1454 			    atomicio(vwrite, local_fd, data, len) != len) &&
1455 			    !write_error) {
1456 				write_errno = errno;
1457 				write_error = 1;
1458 				max_req = 0;
1459 			}
1460 			else if (!reordered && req->offset <= highwater)
1461 				highwater = req->offset + len;
1462 			else if (!reordered && req->offset > highwater)
1463 				reordered = 1;
1464 			progress_counter += len;
1465 			free(data);
1466 
1467 			if (len == req->len) {
1468 				TAILQ_REMOVE(&requests, req, tq);
1469 				free(req);
1470 				num_req--;
1471 			} else {
1472 				/* Resend the request for the missing data */
1473 				debug3("Short data block, re-requesting "
1474 				    "%llu -> %llu (%2d)",
1475 				    (unsigned long long)req->offset + len,
1476 				    (unsigned long long)req->offset +
1477 				    req->len - 1, num_req);
1478 				req->id = conn->msg_id++;
1479 				req->len -= len;
1480 				req->offset += len;
1481 				send_read_request(conn, req->id,
1482 				    req->offset, req->len, handle, handle_len);
1483 				/* Reduce the request size */
1484 				if (len < buflen)
1485 					buflen = MAXIMUM(MIN_READ_SIZE, len);
1486 			}
1487 			if (max_req > 0) { /* max_req = 0 iff EOF received */
1488 				if (size > 0 && offset > size) {
1489 					/* Only one request at a time
1490 					 * after the expected EOF */
1491 					debug3("Finish at %llu (%2d)",
1492 					    (unsigned long long)offset,
1493 					    num_req);
1494 					max_req = 1;
1495 				} else if (max_req < conn->num_requests) {
1496 					++max_req;
1497 				}
1498 			}
1499 			break;
1500 		default:
1501 			fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1502 			    SSH2_FXP_DATA, type);
1503 		}
1504 	}
1505 
1506 	if (showprogress && size)
1507 		stop_progress_meter();
1508 
1509 	/* Sanity check */
1510 	if (TAILQ_FIRST(&requests) != NULL)
1511 		fatal("Transfer complete, but requests still in queue");
1512 	/* Truncate at highest contiguous point to avoid holes on interrupt */
1513 	if (read_error || write_error || interrupted) {
1514 		if (reordered && resume_flag) {
1515 			error("Unable to resume download of \"%s\": "
1516 			    "server reordered requests", local_path);
1517 		}
1518 		debug("truncating at %llu", (unsigned long long)highwater);
1519 		if (ftruncate(local_fd, highwater) == -1)
1520 			error("ftruncate \"%s\": %s", local_path,
1521 			    strerror(errno));
1522 	}
1523 	if (read_error) {
1524 		error("Couldn't read from remote file \"%s\" : %s",
1525 		    remote_path, fx2txt(status));
1526 		status = -1;
1527 		do_close(conn, handle, handle_len);
1528 	} else if (write_error) {
1529 		error("Couldn't write to \"%s\": %s", local_path,
1530 		    strerror(write_errno));
1531 		status = SSH2_FX_FAILURE;
1532 		do_close(conn, handle, handle_len);
1533 	} else {
1534 		if (do_close(conn, handle, handle_len) != 0 || interrupted)
1535 			status = SSH2_FX_FAILURE;
1536 		else
1537 			status = SSH2_FX_OK;
1538 		/* Override umask and utimes if asked */
1539 		if (preserve_flag && fchmod(local_fd, mode) == -1)
1540 			error("Couldn't set mode on \"%s\": %s", local_path,
1541 			    strerror(errno));
1542 		if (preserve_flag &&
1543 		    (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1544 			struct timeval tv[2];
1545 			tv[0].tv_sec = a->atime;
1546 			tv[1].tv_sec = a->mtime;
1547 			tv[0].tv_usec = tv[1].tv_usec = 0;
1548 			if (utimes(local_path, tv) == -1)
1549 				error("Can't set times on \"%s\": %s",
1550 				    local_path, strerror(errno));
1551 		}
1552 		if (resume_flag && !lmodified)
1553 			logit("File \"%s\" was not modified", local_path);
1554 		else if (fsync_flag) {
1555 			debug("syncing \"%s\"", local_path);
1556 			if (fsync(local_fd) == -1)
1557 				error("Couldn't sync file \"%s\": %s",
1558 				    local_path, strerror(errno));
1559 		}
1560 	}
1561 	close(local_fd);
1562 	sshbuf_free(msg);
1563 	free(handle);
1564 
1565 	return status == SSH2_FX_OK ? 0 : -1;
1566 }
1567 
1568 static int
1569 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1570     int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
1571     int resume_flag, int fsync_flag)
1572 {
1573 	int i, ret = 0;
1574 	SFTP_DIRENT **dir_entries;
1575 	char *filename, *new_src = NULL, *new_dst = NULL;
1576 	mode_t mode = 0777, tmpmode = mode;
1577 
1578 	if (depth >= MAX_DIR_DEPTH) {
1579 		error("Maximum directory depth exceeded: %d levels", depth);
1580 		return -1;
1581 	}
1582 
1583 	if (dirattrib == NULL &&
1584 	    (dirattrib = do_stat(conn, src, 1)) == NULL) {
1585 		error("Unable to stat remote directory \"%s\"", src);
1586 		return -1;
1587 	}
1588 	if (!S_ISDIR(dirattrib->perm)) {
1589 		error("\"%s\" is not a directory", src);
1590 		return -1;
1591 	}
1592 	if (print_flag)
1593 		mprintf("Retrieving %s\n", src);
1594 
1595 	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1596 		mode = dirattrib->perm & 01777;
1597 		tmpmode = mode | (S_IWUSR|S_IXUSR);
1598 	} else {
1599 		debug("Server did not send permissions for "
1600 		    "directory \"%s\"", dst);
1601 	}
1602 
1603 	if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) {
1604 		error("mkdir %s: %s", dst, strerror(errno));
1605 		return -1;
1606 	}
1607 
1608 	if (do_readdir(conn, src, &dir_entries) == -1) {
1609 		error("%s: Failed to get directory contents", src);
1610 		return -1;
1611 	}
1612 
1613 	for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1614 		free(new_dst);
1615 		free(new_src);
1616 
1617 		filename = dir_entries[i]->filename;
1618 		new_dst = path_append(dst, filename);
1619 		new_src = path_append(src, filename);
1620 
1621 		if (S_ISDIR(dir_entries[i]->a.perm)) {
1622 			if (strcmp(filename, ".") == 0 ||
1623 			    strcmp(filename, "..") == 0)
1624 				continue;
1625 			if (download_dir_internal(conn, new_src, new_dst,
1626 			    depth + 1, &(dir_entries[i]->a), preserve_flag,
1627 			    print_flag, resume_flag, fsync_flag) == -1)
1628 				ret = -1;
1629 		} else if (S_ISREG(dir_entries[i]->a.perm) ) {
1630 			if (do_download(conn, new_src, new_dst,
1631 			    &(dir_entries[i]->a), preserve_flag,
1632 			    resume_flag, fsync_flag) == -1) {
1633 				error("Download of file %s to %s failed",
1634 				    new_src, new_dst);
1635 				ret = -1;
1636 			}
1637 		} else
1638 			logit("%s: not a regular file\n", new_src);
1639 
1640 	}
1641 	free(new_dst);
1642 	free(new_src);
1643 
1644 	if (preserve_flag) {
1645 		if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1646 			struct timeval tv[2];
1647 			tv[0].tv_sec = dirattrib->atime;
1648 			tv[1].tv_sec = dirattrib->mtime;
1649 			tv[0].tv_usec = tv[1].tv_usec = 0;
1650 			if (utimes(dst, tv) == -1)
1651 				error("Can't set times on \"%s\": %s",
1652 				    dst, strerror(errno));
1653 		} else
1654 			debug("Server did not send times for directory "
1655 			    "\"%s\"", dst);
1656 	}
1657 
1658 	if (mode != tmpmode && chmod(dst, mode) == -1)
1659 		error("Can't set final mode on \"%s\": %s", dst,
1660 		    strerror(errno));
1661 
1662 	free_sftp_dirents(dir_entries);
1663 
1664 	return ret;
1665 }
1666 
1667 int
1668 download_dir(struct sftp_conn *conn, const char *src, const char *dst,
1669     Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
1670     int fsync_flag)
1671 {
1672 	char *src_canon;
1673 	int ret;
1674 
1675 	if ((src_canon = do_realpath(conn, src)) == NULL) {
1676 		error("Unable to canonicalize path \"%s\"", src);
1677 		return -1;
1678 	}
1679 
1680 	ret = download_dir_internal(conn, src_canon, dst, 0,
1681 	    dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
1682 	free(src_canon);
1683 	return ret;
1684 }
1685 
1686 int
1687 do_upload(struct sftp_conn *conn, const char *local_path,
1688     const char *remote_path, int preserve_flag, int resume, int fsync_flag)
1689 {
1690 	int r, local_fd;
1691 	u_int status = SSH2_FX_OK;
1692 	u_int id;
1693 	u_char type;
1694 	off_t offset, progress_counter;
1695 	u_char *handle, *data;
1696 	struct sshbuf *msg;
1697 	struct stat sb;
1698 	Attrib a, *c = NULL;
1699 	u_int32_t startid;
1700 	u_int32_t ackid;
1701 	struct outstanding_ack {
1702 		u_int id;
1703 		u_int len;
1704 		off_t offset;
1705 		TAILQ_ENTRY(outstanding_ack) tq;
1706 	};
1707 	TAILQ_HEAD(ackhead, outstanding_ack) acks;
1708 	struct outstanding_ack *ack = NULL;
1709 	size_t handle_len;
1710 
1711 	TAILQ_INIT(&acks);
1712 
1713 	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1714 		error("Couldn't open local file \"%s\" for reading: %s",
1715 		    local_path, strerror(errno));
1716 		return(-1);
1717 	}
1718 	if (fstat(local_fd, &sb) == -1) {
1719 		error("Couldn't fstat local file \"%s\": %s",
1720 		    local_path, strerror(errno));
1721 		close(local_fd);
1722 		return(-1);
1723 	}
1724 	if (!S_ISREG(sb.st_mode)) {
1725 		error("%s is not a regular file", local_path);
1726 		close(local_fd);
1727 		return(-1);
1728 	}
1729 	stat_to_attrib(&sb, &a);
1730 
1731 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1732 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1733 	a.perm &= 0777;
1734 	if (!preserve_flag)
1735 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1736 
1737 	if (resume) {
1738 		/* Get remote file size if it exists */
1739 		if ((c = do_stat(conn, remote_path, 0)) == NULL) {
1740 			close(local_fd);
1741 			return -1;
1742 		}
1743 
1744 		if ((off_t)c->size >= sb.st_size) {
1745 			error("destination file bigger or same size as "
1746 			    "source file");
1747 			close(local_fd);
1748 			return -1;
1749 		}
1750 
1751 		if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
1752 			close(local_fd);
1753 			return -1;
1754 		}
1755 	}
1756 
1757 	if ((msg = sshbuf_new()) == NULL)
1758 		fatal_f("sshbuf_new failed");
1759 
1760 	/* Send open request */
1761 	id = conn->msg_id++;
1762 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1763 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1764 	    (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1765 	    (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
1766 	    (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 ||
1767 	    (r = encode_attrib(msg, &a)) != 0)
1768 		fatal_fr(r, "compose");
1769 	send_msg(conn, msg);
1770 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1771 
1772 	sshbuf_reset(msg);
1773 
1774 	handle = get_handle(conn, id, &handle_len,
1775 	    "remote open(\"%s\")", remote_path);
1776 	if (handle == NULL) {
1777 		close(local_fd);
1778 		sshbuf_free(msg);
1779 		return -1;
1780 	}
1781 
1782 	startid = ackid = id + 1;
1783 	data = xmalloc(conn->upload_buflen);
1784 
1785 	/* Read from local and write to remote */
1786 	offset = progress_counter = (resume ? c->size : 0);
1787 	if (showprogress)
1788 		start_progress_meter(local_path, sb.st_size,
1789 		    &progress_counter);
1790 
1791 	for (;;) {
1792 		int len;
1793 
1794 		/*
1795 		 * Can't use atomicio here because it returns 0 on EOF,
1796 		 * thus losing the last block of the file.
1797 		 * Simulate an EOF on interrupt, allowing ACKs from the
1798 		 * server to drain.
1799 		 */
1800 		if (interrupted || status != SSH2_FX_OK)
1801 			len = 0;
1802 		else do
1803 			len = read(local_fd, data, conn->upload_buflen);
1804 		while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1805 
1806 		if (len == -1)
1807 			fatal("Couldn't read from \"%s\": %s", local_path,
1808 			    strerror(errno));
1809 
1810 		if (len != 0) {
1811 			ack = xcalloc(1, sizeof(*ack));
1812 			ack->id = ++id;
1813 			ack->offset = offset;
1814 			ack->len = len;
1815 			TAILQ_INSERT_TAIL(&acks, ack, tq);
1816 
1817 			sshbuf_reset(msg);
1818 			if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
1819 			    (r = sshbuf_put_u32(msg, ack->id)) != 0 ||
1820 			    (r = sshbuf_put_string(msg, handle,
1821 			    handle_len)) != 0 ||
1822 			    (r = sshbuf_put_u64(msg, offset)) != 0 ||
1823 			    (r = sshbuf_put_string(msg, data, len)) != 0)
1824 				fatal_fr(r, "compose");
1825 			send_msg(conn, msg);
1826 			debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1827 			    id, (unsigned long long)offset, len);
1828 		} else if (TAILQ_FIRST(&acks) == NULL)
1829 			break;
1830 
1831 		if (ack == NULL)
1832 			fatal("Unexpected ACK %u", id);
1833 
1834 		if (id == startid || len == 0 ||
1835 		    id - ackid >= conn->num_requests) {
1836 			u_int rid;
1837 
1838 			sshbuf_reset(msg);
1839 			get_msg(conn, msg);
1840 			if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1841 			    (r = sshbuf_get_u32(msg, &rid)) != 0)
1842 				fatal_fr(r, "parse");
1843 
1844 			if (type != SSH2_FXP_STATUS)
1845 				fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1846 				    "got %d", SSH2_FXP_STATUS, type);
1847 
1848 			if ((r = sshbuf_get_u32(msg, &status)) != 0)
1849 				fatal_fr(r, "parse status");
1850 			debug3("SSH2_FXP_STATUS %u", status);
1851 
1852 			/* Find the request in our queue */
1853 			for (ack = TAILQ_FIRST(&acks);
1854 			    ack != NULL && ack->id != rid;
1855 			    ack = TAILQ_NEXT(ack, tq))
1856 				;
1857 			if (ack == NULL)
1858 				fatal("Can't find request for ID %u", rid);
1859 			TAILQ_REMOVE(&acks, ack, tq);
1860 			debug3("In write loop, ack for %u %u bytes at %lld",
1861 			    ack->id, ack->len, (long long)ack->offset);
1862 			++ackid;
1863 			progress_counter += ack->len;
1864 			free(ack);
1865 		}
1866 		offset += len;
1867 		if (offset < 0)
1868 			fatal_f("offset < 0");
1869 	}
1870 	sshbuf_free(msg);
1871 
1872 	if (showprogress)
1873 		stop_progress_meter();
1874 	free(data);
1875 
1876 	if (status != SSH2_FX_OK) {
1877 		error("Couldn't write to remote file \"%s\": %s",
1878 		    remote_path, fx2txt(status));
1879 		status = SSH2_FX_FAILURE;
1880 	}
1881 
1882 	if (close(local_fd) == -1) {
1883 		error("Couldn't close local file \"%s\": %s", local_path,
1884 		    strerror(errno));
1885 		status = SSH2_FX_FAILURE;
1886 	}
1887 
1888 	/* Override umask and utimes if asked */
1889 	if (preserve_flag)
1890 		do_fsetstat(conn, handle, handle_len, &a);
1891 
1892 	if (fsync_flag)
1893 		(void)do_fsync(conn, handle, handle_len);
1894 
1895 	if (do_close(conn, handle, handle_len) != 0)
1896 		status = SSH2_FX_FAILURE;
1897 
1898 	free(handle);
1899 
1900 	return status == SSH2_FX_OK ? 0 : -1;
1901 }
1902 
1903 static int
1904 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1905     int depth, int preserve_flag, int print_flag, int resume, int fsync_flag)
1906 {
1907 	int ret = 0;
1908 	DIR *dirp;
1909 	struct dirent *dp;
1910 	char *filename, *new_src = NULL, *new_dst = NULL;
1911 	struct stat sb;
1912 	Attrib a, *dirattrib;
1913 	u_int32_t saved_perm;
1914 
1915 	if (depth >= MAX_DIR_DEPTH) {
1916 		error("Maximum directory depth exceeded: %d levels", depth);
1917 		return -1;
1918 	}
1919 
1920 	if (stat(src, &sb) == -1) {
1921 		error("Couldn't stat directory \"%s\": %s",
1922 		    src, strerror(errno));
1923 		return -1;
1924 	}
1925 	if (!S_ISDIR(sb.st_mode)) {
1926 		error("\"%s\" is not a directory", src);
1927 		return -1;
1928 	}
1929 	if (print_flag)
1930 		mprintf("Entering %s\n", src);
1931 
1932 	attrib_clear(&a);
1933 	stat_to_attrib(&sb, &a);
1934 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1935 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1936 	a.perm &= 01777;
1937 	if (!preserve_flag)
1938 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1939 
1940 	/*
1941 	 * sftp lacks a portable status value to match errno EEXIST,
1942 	 * so if we get a failure back then we must check whether
1943 	 * the path already existed and is a directory.  Ensure we can
1944 	 * write to the directory we create for the duration of the transfer.
1945 	 */
1946 	saved_perm = a.perm;
1947 	a.perm |= (S_IWUSR|S_IXUSR);
1948 	if (do_mkdir(conn, dst, &a, 0) != 0) {
1949 		if ((dirattrib = do_stat(conn, dst, 0)) == NULL)
1950 			return -1;
1951 		if (!S_ISDIR(dirattrib->perm)) {
1952 			error("\"%s\" exists but is not a directory", dst);
1953 			return -1;
1954 		}
1955 	}
1956 	a.perm = saved_perm;
1957 
1958 	if ((dirp = opendir(src)) == NULL) {
1959 		error("Failed to open dir \"%s\": %s", src, strerror(errno));
1960 		return -1;
1961 	}
1962 
1963 	while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1964 		if (dp->d_ino == 0)
1965 			continue;
1966 		free(new_dst);
1967 		free(new_src);
1968 		filename = dp->d_name;
1969 		new_dst = path_append(dst, filename);
1970 		new_src = path_append(src, filename);
1971 
1972 		if (lstat(new_src, &sb) == -1) {
1973 			logit("%s: lstat failed: %s", filename,
1974 			    strerror(errno));
1975 			ret = -1;
1976 		} else if (S_ISDIR(sb.st_mode)) {
1977 			if (strcmp(filename, ".") == 0 ||
1978 			    strcmp(filename, "..") == 0)
1979 				continue;
1980 
1981 			if (upload_dir_internal(conn, new_src, new_dst,
1982 			    depth + 1, preserve_flag, print_flag, resume,
1983 			    fsync_flag) == -1)
1984 				ret = -1;
1985 		} else if (S_ISREG(sb.st_mode)) {
1986 			if (do_upload(conn, new_src, new_dst,
1987 			    preserve_flag, resume, fsync_flag) == -1) {
1988 				error("Uploading of file %s to %s failed!",
1989 				    new_src, new_dst);
1990 				ret = -1;
1991 			}
1992 		} else
1993 			logit("%s: not a regular file\n", filename);
1994 	}
1995 	free(new_dst);
1996 	free(new_src);
1997 
1998 	do_setstat(conn, dst, &a);
1999 
2000 	(void) closedir(dirp);
2001 	return ret;
2002 }
2003 
2004 int
2005 upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
2006     int preserve_flag, int print_flag, int resume, int fsync_flag)
2007 {
2008 	char *dst_canon;
2009 	int ret;
2010 
2011 	if ((dst_canon = do_realpath(conn, dst)) == NULL) {
2012 		error("Unable to canonicalize path \"%s\"", dst);
2013 		return -1;
2014 	}
2015 
2016 	ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
2017 	    print_flag, resume, fsync_flag);
2018 
2019 	free(dst_canon);
2020 	return ret;
2021 }
2022 
2023 char *
2024 path_append(const char *p1, const char *p2)
2025 {
2026 	char *ret;
2027 	size_t len = strlen(p1) + strlen(p2) + 2;
2028 
2029 	ret = xmalloc(len);
2030 	strlcpy(ret, p1, len);
2031 	if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
2032 		strlcat(ret, "/", len);
2033 	strlcat(ret, p2, len);
2034 
2035 	return(ret);
2036 }
2037 
2038 char *
2039 make_absolute(char *p, const char *pwd)
2040 {
2041 	char *abs_str;
2042 
2043 	/* Derelativise */
2044 	if (p && !path_absolute(p)) {
2045 		abs_str = path_append(pwd, p);
2046 		free(p);
2047 		return(abs_str);
2048 	} else
2049 		return(p);
2050 }
2051 
2052 int
2053 remote_is_dir(struct sftp_conn *conn, const char *path)
2054 {
2055 	Attrib *a;
2056 
2057 	/* XXX: report errors? */
2058 	if ((a = do_stat(conn, path, 1)) == NULL)
2059 		return(0);
2060 	if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
2061 		return(0);
2062 	return(S_ISDIR(a->perm));
2063 }
2064 
2065 
2066 int
2067 local_is_dir(const char *path)
2068 {
2069 	struct stat sb;
2070 
2071 	/* XXX: report errors? */
2072 	if (stat(path, &sb) == -1)
2073 		return(0);
2074 
2075 	return(S_ISDIR(sb.st_mode));
2076 }
2077 
2078 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
2079 int
2080 globpath_is_dir(const char *pathname)
2081 {
2082 	size_t l = strlen(pathname);
2083 
2084 	return l > 0 && pathname[l - 1] == '/';
2085 }
2086 
2087