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