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