xref: /openbsd-src/usr.bin/ssh/sftp-client.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $OpenBSD: sftp-client.c,v 1.86 2008/06/26 06:10:09 djm Exp $ */
2 /*
3  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /* XXX: memleaks */
19 /* XXX: signed vs unsigned */
20 /* XXX: remove all logging, only return status codes */
21 /* XXX: copy between two remote sites */
22 
23 #include <sys/types.h>
24 #include <sys/queue.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <sys/param.h>
28 #include <sys/statvfs.h>
29 #include <sys/uio.h>
30 
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdarg.h>
38 
39 #include "xmalloc.h"
40 #include "buffer.h"
41 #include "log.h"
42 #include "atomicio.h"
43 #include "progressmeter.h"
44 #include "misc.h"
45 
46 #include "sftp.h"
47 #include "sftp-common.h"
48 #include "sftp-client.h"
49 
50 extern volatile sig_atomic_t interrupted;
51 extern int showprogress;
52 
53 /* Minimum amount of data to read at a time */
54 #define MIN_READ_SIZE	512
55 
56 struct sftp_conn {
57 	int fd_in;
58 	int fd_out;
59 	u_int transfer_buflen;
60 	u_int num_requests;
61 	u_int version;
62 	u_int msg_id;
63 #define SFTP_EXT_POSIX_RENAME	0x00000001
64 #define SFTP_EXT_STATVFS	0x00000002
65 #define SFTP_EXT_FSTATVFS	0x00000004
66 	u_int exts;
67 };
68 
69 static void
70 send_msg(int fd, Buffer *m)
71 {
72 	u_char mlen[4];
73 	struct iovec iov[2];
74 
75 	if (buffer_len(m) > SFTP_MAX_MSG_LENGTH)
76 		fatal("Outbound message too long %u", buffer_len(m));
77 
78 	/* Send length first */
79 	put_u32(mlen, buffer_len(m));
80 	iov[0].iov_base = mlen;
81 	iov[0].iov_len = sizeof(mlen);
82 	iov[1].iov_base = buffer_ptr(m);
83 	iov[1].iov_len = buffer_len(m);
84 
85 	if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen))
86 		fatal("Couldn't send packet: %s", strerror(errno));
87 
88 	buffer_clear(m);
89 }
90 
91 static void
92 get_msg(int fd, Buffer *m)
93 {
94 	u_int msg_len;
95 
96 	buffer_append_space(m, 4);
97 	if (atomicio(read, fd, buffer_ptr(m), 4) != 4) {
98 		if (errno == EPIPE)
99 			fatal("Connection closed");
100 		else
101 			fatal("Couldn't read packet: %s", strerror(errno));
102 	}
103 
104 	msg_len = buffer_get_int(m);
105 	if (msg_len > SFTP_MAX_MSG_LENGTH)
106 		fatal("Received message too long %u", msg_len);
107 
108 	buffer_append_space(m, msg_len);
109 	if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) {
110 		if (errno == EPIPE)
111 			fatal("Connection closed");
112 		else
113 			fatal("Read packet: %s", strerror(errno));
114 	}
115 }
116 
117 static void
118 send_string_request(int fd, u_int id, u_int code, char *s,
119     u_int len)
120 {
121 	Buffer msg;
122 
123 	buffer_init(&msg);
124 	buffer_put_char(&msg, code);
125 	buffer_put_int(&msg, id);
126 	buffer_put_string(&msg, s, len);
127 	send_msg(fd, &msg);
128 	debug3("Sent message fd %d T:%u I:%u", fd, code, id);
129 	buffer_free(&msg);
130 }
131 
132 static void
133 send_string_attrs_request(int fd, u_int id, u_int code, char *s,
134     u_int len, Attrib *a)
135 {
136 	Buffer msg;
137 
138 	buffer_init(&msg);
139 	buffer_put_char(&msg, code);
140 	buffer_put_int(&msg, id);
141 	buffer_put_string(&msg, s, len);
142 	encode_attrib(&msg, a);
143 	send_msg(fd, &msg);
144 	debug3("Sent message fd %d T:%u I:%u", fd, code, id);
145 	buffer_free(&msg);
146 }
147 
148 static u_int
149 get_status(int fd, u_int expected_id)
150 {
151 	Buffer msg;
152 	u_int type, id, status;
153 
154 	buffer_init(&msg);
155 	get_msg(fd, &msg);
156 	type = buffer_get_char(&msg);
157 	id = buffer_get_int(&msg);
158 
159 	if (id != expected_id)
160 		fatal("ID mismatch (%u != %u)", id, expected_id);
161 	if (type != SSH2_FXP_STATUS)
162 		fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
163 		    SSH2_FXP_STATUS, type);
164 
165 	status = buffer_get_int(&msg);
166 	buffer_free(&msg);
167 
168 	debug3("SSH2_FXP_STATUS %u", status);
169 
170 	return(status);
171 }
172 
173 static char *
174 get_handle(int fd, u_int expected_id, u_int *len)
175 {
176 	Buffer msg;
177 	u_int type, id;
178 	char *handle;
179 
180 	buffer_init(&msg);
181 	get_msg(fd, &msg);
182 	type = buffer_get_char(&msg);
183 	id = buffer_get_int(&msg);
184 
185 	if (id != expected_id)
186 		fatal("ID mismatch (%u != %u)", id, expected_id);
187 	if (type == SSH2_FXP_STATUS) {
188 		int status = buffer_get_int(&msg);
189 
190 		error("Couldn't get handle: %s", fx2txt(status));
191 		buffer_free(&msg);
192 		return(NULL);
193 	} else if (type != SSH2_FXP_HANDLE)
194 		fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u",
195 		    SSH2_FXP_HANDLE, type);
196 
197 	handle = buffer_get_string(&msg, len);
198 	buffer_free(&msg);
199 
200 	return(handle);
201 }
202 
203 static Attrib *
204 get_decode_stat(int fd, u_int expected_id, int quiet)
205 {
206 	Buffer msg;
207 	u_int type, id;
208 	Attrib *a;
209 
210 	buffer_init(&msg);
211 	get_msg(fd, &msg);
212 
213 	type = buffer_get_char(&msg);
214 	id = buffer_get_int(&msg);
215 
216 	debug3("Received stat reply T:%u I:%u", type, id);
217 	if (id != expected_id)
218 		fatal("ID mismatch (%u != %u)", id, expected_id);
219 	if (type == SSH2_FXP_STATUS) {
220 		int status = buffer_get_int(&msg);
221 
222 		if (quiet)
223 			debug("Couldn't stat remote file: %s", fx2txt(status));
224 		else
225 			error("Couldn't stat remote file: %s", fx2txt(status));
226 		buffer_free(&msg);
227 		return(NULL);
228 	} else if (type != SSH2_FXP_ATTRS) {
229 		fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
230 		    SSH2_FXP_ATTRS, type);
231 	}
232 	a = decode_attrib(&msg);
233 	buffer_free(&msg);
234 
235 	return(a);
236 }
237 
238 static int
239 get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id,
240     int quiet)
241 {
242 	Buffer msg;
243 	u_int type, id, flag;
244 
245 	buffer_init(&msg);
246 	get_msg(fd, &msg);
247 
248 	type = buffer_get_char(&msg);
249 	id = buffer_get_int(&msg);
250 
251 	debug3("Received statvfs reply T:%u I:%u", type, id);
252 	if (id != expected_id)
253 		fatal("ID mismatch (%u != %u)", id, expected_id);
254 	if (type == SSH2_FXP_STATUS) {
255 		int status = buffer_get_int(&msg);
256 
257 		if (quiet)
258 			debug("Couldn't statvfs: %s", fx2txt(status));
259 		else
260 			error("Couldn't statvfs: %s", fx2txt(status));
261 		buffer_free(&msg);
262 		return -1;
263 	} else if (type != SSH2_FXP_EXTENDED_REPLY) {
264 		fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
265 		    SSH2_FXP_EXTENDED_REPLY, type);
266 	}
267 
268 	bzero(st, sizeof(*st));
269 	st->f_bsize = buffer_get_int64(&msg);
270 	st->f_frsize = buffer_get_int64(&msg);
271 	st->f_blocks = buffer_get_int64(&msg);
272 	st->f_bfree = buffer_get_int64(&msg);
273 	st->f_bavail = buffer_get_int64(&msg);
274 	st->f_files = buffer_get_int64(&msg);
275 	st->f_ffree = buffer_get_int64(&msg);
276 	st->f_favail = buffer_get_int64(&msg);
277 	st->f_fsid = buffer_get_int64(&msg);
278 	flag = buffer_get_int64(&msg);
279 	st->f_namemax = buffer_get_int64(&msg);
280 
281 	st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
282 	st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
283 
284 	buffer_free(&msg);
285 
286 	return 0;
287 }
288 
289 struct sftp_conn *
290 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
291 {
292 	u_int type, exts = 0;
293 	int version;
294 	Buffer msg;
295 	struct sftp_conn *ret;
296 
297 	buffer_init(&msg);
298 	buffer_put_char(&msg, SSH2_FXP_INIT);
299 	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
300 	send_msg(fd_out, &msg);
301 
302 	buffer_clear(&msg);
303 
304 	get_msg(fd_in, &msg);
305 
306 	/* Expecting a VERSION reply */
307 	if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
308 		error("Invalid packet back from SSH2_FXP_INIT (type %u)",
309 		    type);
310 		buffer_free(&msg);
311 		return(NULL);
312 	}
313 	version = buffer_get_int(&msg);
314 
315 	debug2("Remote version: %d", version);
316 
317 	/* Check for extensions */
318 	while (buffer_len(&msg) > 0) {
319 		char *name = buffer_get_string(&msg, NULL);
320 		char *value = buffer_get_string(&msg, NULL);
321 		int known = 0;
322 
323 		if (strcmp(name, "posix-rename@openssh.com") == 0 &&
324 		    strcmp(value, "1") == 0) {
325 			exts |= SFTP_EXT_POSIX_RENAME;
326 			known = 1;
327 		} else if (strcmp(name, "statvfs@openssh.com") == 0 &&
328 		    strcmp(value, "2") == 0) {
329 			exts |= SFTP_EXT_STATVFS;
330 			known = 1;
331 		} if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
332 		    strcmp(value, "2") == 0) {
333 			exts |= SFTP_EXT_FSTATVFS;
334 			known = 1;
335 		}
336 		if (known) {
337 			debug2("Server supports extension \"%s\" revision %s",
338 			    name, value);
339 		} else {
340 			debug2("Unrecognised server extension \"%s\"", name);
341 		}
342 		xfree(name);
343 		xfree(value);
344 	}
345 
346 	buffer_free(&msg);
347 
348 	ret = xmalloc(sizeof(*ret));
349 	ret->fd_in = fd_in;
350 	ret->fd_out = fd_out;
351 	ret->transfer_buflen = transfer_buflen;
352 	ret->num_requests = num_requests;
353 	ret->version = version;
354 	ret->msg_id = 1;
355 	ret->exts = exts;
356 
357 	/* Some filexfer v.0 servers don't support large packets */
358 	if (version == 0)
359 		ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
360 
361 	return(ret);
362 }
363 
364 u_int
365 sftp_proto_version(struct sftp_conn *conn)
366 {
367 	return(conn->version);
368 }
369 
370 int
371 do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
372 {
373 	u_int id, status;
374 	Buffer msg;
375 
376 	buffer_init(&msg);
377 
378 	id = conn->msg_id++;
379 	buffer_put_char(&msg, SSH2_FXP_CLOSE);
380 	buffer_put_int(&msg, id);
381 	buffer_put_string(&msg, handle, handle_len);
382 	send_msg(conn->fd_out, &msg);
383 	debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
384 
385 	status = get_status(conn->fd_in, id);
386 	if (status != SSH2_FX_OK)
387 		error("Couldn't close file: %s", fx2txt(status));
388 
389 	buffer_free(&msg);
390 
391 	return(status);
392 }
393 
394 
395 static int
396 do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
397     SFTP_DIRENT ***dir)
398 {
399 	Buffer msg;
400 	u_int count, type, id, handle_len, i, expected_id, ents = 0;
401 	char *handle;
402 
403 	id = conn->msg_id++;
404 
405 	buffer_init(&msg);
406 	buffer_put_char(&msg, SSH2_FXP_OPENDIR);
407 	buffer_put_int(&msg, id);
408 	buffer_put_cstring(&msg, path);
409 	send_msg(conn->fd_out, &msg);
410 
411 	buffer_clear(&msg);
412 
413 	handle = get_handle(conn->fd_in, id, &handle_len);
414 	if (handle == NULL)
415 		return(-1);
416 
417 	if (dir) {
418 		ents = 0;
419 		*dir = xmalloc(sizeof(**dir));
420 		(*dir)[0] = NULL;
421 	}
422 
423 	for (; !interrupted;) {
424 		id = expected_id = conn->msg_id++;
425 
426 		debug3("Sending SSH2_FXP_READDIR I:%u", id);
427 
428 		buffer_clear(&msg);
429 		buffer_put_char(&msg, SSH2_FXP_READDIR);
430 		buffer_put_int(&msg, id);
431 		buffer_put_string(&msg, handle, handle_len);
432 		send_msg(conn->fd_out, &msg);
433 
434 		buffer_clear(&msg);
435 
436 		get_msg(conn->fd_in, &msg);
437 
438 		type = buffer_get_char(&msg);
439 		id = buffer_get_int(&msg);
440 
441 		debug3("Received reply T:%u I:%u", type, id);
442 
443 		if (id != expected_id)
444 			fatal("ID mismatch (%u != %u)", id, expected_id);
445 
446 		if (type == SSH2_FXP_STATUS) {
447 			int status = buffer_get_int(&msg);
448 
449 			debug3("Received SSH2_FXP_STATUS %d", status);
450 
451 			if (status == SSH2_FX_EOF) {
452 				break;
453 			} else {
454 				error("Couldn't read directory: %s",
455 				    fx2txt(status));
456 				do_close(conn, handle, handle_len);
457 				xfree(handle);
458 				return(status);
459 			}
460 		} else if (type != SSH2_FXP_NAME)
461 			fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
462 			    SSH2_FXP_NAME, type);
463 
464 		count = buffer_get_int(&msg);
465 		if (count == 0)
466 			break;
467 		debug3("Received %d SSH2_FXP_NAME responses", count);
468 		for (i = 0; i < count; i++) {
469 			char *filename, *longname;
470 			Attrib *a;
471 
472 			filename = buffer_get_string(&msg, NULL);
473 			longname = buffer_get_string(&msg, NULL);
474 			a = decode_attrib(&msg);
475 
476 			if (printflag)
477 				printf("%s\n", longname);
478 
479 			if (dir) {
480 				*dir = xrealloc(*dir, ents + 2, sizeof(**dir));
481 				(*dir)[ents] = xmalloc(sizeof(***dir));
482 				(*dir)[ents]->filename = xstrdup(filename);
483 				(*dir)[ents]->longname = xstrdup(longname);
484 				memcpy(&(*dir)[ents]->a, a, sizeof(*a));
485 				(*dir)[++ents] = NULL;
486 			}
487 
488 			xfree(filename);
489 			xfree(longname);
490 		}
491 	}
492 
493 	buffer_free(&msg);
494 	do_close(conn, handle, handle_len);
495 	xfree(handle);
496 
497 	/* Don't return partial matches on interrupt */
498 	if (interrupted && dir != NULL && *dir != NULL) {
499 		free_sftp_dirents(*dir);
500 		*dir = xmalloc(sizeof(**dir));
501 		**dir = NULL;
502 	}
503 
504 	return(0);
505 }
506 
507 int
508 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
509 {
510 	return(do_lsreaddir(conn, path, 0, dir));
511 }
512 
513 void free_sftp_dirents(SFTP_DIRENT **s)
514 {
515 	int i;
516 
517 	for (i = 0; s[i]; i++) {
518 		xfree(s[i]->filename);
519 		xfree(s[i]->longname);
520 		xfree(s[i]);
521 	}
522 	xfree(s);
523 }
524 
525 int
526 do_rm(struct sftp_conn *conn, char *path)
527 {
528 	u_int status, id;
529 
530 	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
531 
532 	id = conn->msg_id++;
533 	send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path,
534 	    strlen(path));
535 	status = get_status(conn->fd_in, id);
536 	if (status != SSH2_FX_OK)
537 		error("Couldn't delete file: %s", fx2txt(status));
538 	return(status);
539 }
540 
541 int
542 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a)
543 {
544 	u_int status, id;
545 
546 	id = conn->msg_id++;
547 	send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path,
548 	    strlen(path), a);
549 
550 	status = get_status(conn->fd_in, id);
551 	if (status != SSH2_FX_OK)
552 		error("Couldn't create directory: %s", fx2txt(status));
553 
554 	return(status);
555 }
556 
557 int
558 do_rmdir(struct sftp_conn *conn, char *path)
559 {
560 	u_int status, id;
561 
562 	id = conn->msg_id++;
563 	send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path,
564 	    strlen(path));
565 
566 	status = get_status(conn->fd_in, id);
567 	if (status != SSH2_FX_OK)
568 		error("Couldn't remove directory: %s", fx2txt(status));
569 
570 	return(status);
571 }
572 
573 Attrib *
574 do_stat(struct sftp_conn *conn, char *path, int quiet)
575 {
576 	u_int id;
577 
578 	id = conn->msg_id++;
579 
580 	send_string_request(conn->fd_out, id,
581 	    conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
582 	    path, strlen(path));
583 
584 	return(get_decode_stat(conn->fd_in, id, quiet));
585 }
586 
587 Attrib *
588 do_lstat(struct sftp_conn *conn, char *path, int quiet)
589 {
590 	u_int id;
591 
592 	if (conn->version == 0) {
593 		if (quiet)
594 			debug("Server version does not support lstat operation");
595 		else
596 			logit("Server version does not support lstat operation");
597 		return(do_stat(conn, path, quiet));
598 	}
599 
600 	id = conn->msg_id++;
601 	send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path,
602 	    strlen(path));
603 
604 	return(get_decode_stat(conn->fd_in, id, quiet));
605 }
606 
607 #ifdef notyet
608 Attrib *
609 do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
610 {
611 	u_int id;
612 
613 	id = conn->msg_id++;
614 	send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle,
615 	    handle_len);
616 
617 	return(get_decode_stat(conn->fd_in, id, quiet));
618 }
619 #endif
620 
621 int
622 do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
623 {
624 	u_int status, id;
625 
626 	id = conn->msg_id++;
627 	send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path,
628 	    strlen(path), a);
629 
630 	status = get_status(conn->fd_in, id);
631 	if (status != SSH2_FX_OK)
632 		error("Couldn't setstat on \"%s\": %s", path,
633 		    fx2txt(status));
634 
635 	return(status);
636 }
637 
638 int
639 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
640     Attrib *a)
641 {
642 	u_int status, id;
643 
644 	id = conn->msg_id++;
645 	send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle,
646 	    handle_len, a);
647 
648 	status = get_status(conn->fd_in, id);
649 	if (status != SSH2_FX_OK)
650 		error("Couldn't fsetstat: %s", fx2txt(status));
651 
652 	return(status);
653 }
654 
655 char *
656 do_realpath(struct sftp_conn *conn, char *path)
657 {
658 	Buffer msg;
659 	u_int type, expected_id, count, id;
660 	char *filename, *longname;
661 	Attrib *a;
662 
663 	expected_id = id = conn->msg_id++;
664 	send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path,
665 	    strlen(path));
666 
667 	buffer_init(&msg);
668 
669 	get_msg(conn->fd_in, &msg);
670 	type = buffer_get_char(&msg);
671 	id = buffer_get_int(&msg);
672 
673 	if (id != expected_id)
674 		fatal("ID mismatch (%u != %u)", id, expected_id);
675 
676 	if (type == SSH2_FXP_STATUS) {
677 		u_int status = buffer_get_int(&msg);
678 
679 		error("Couldn't canonicalise: %s", fx2txt(status));
680 		return(NULL);
681 	} else if (type != SSH2_FXP_NAME)
682 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
683 		    SSH2_FXP_NAME, type);
684 
685 	count = buffer_get_int(&msg);
686 	if (count != 1)
687 		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
688 
689 	filename = buffer_get_string(&msg, NULL);
690 	longname = buffer_get_string(&msg, NULL);
691 	a = decode_attrib(&msg);
692 
693 	debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
694 
695 	xfree(longname);
696 
697 	buffer_free(&msg);
698 
699 	return(filename);
700 }
701 
702 int
703 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
704 {
705 	Buffer msg;
706 	u_int status, id;
707 
708 	buffer_init(&msg);
709 
710 	/* Send rename request */
711 	id = conn->msg_id++;
712 	if ((conn->exts & SFTP_EXT_POSIX_RENAME)) {
713 		buffer_put_char(&msg, SSH2_FXP_EXTENDED);
714 		buffer_put_int(&msg, id);
715 		buffer_put_cstring(&msg, "posix-rename@openssh.com");
716 	} else {
717 		buffer_put_char(&msg, SSH2_FXP_RENAME);
718 		buffer_put_int(&msg, id);
719 	}
720 	buffer_put_cstring(&msg, oldpath);
721 	buffer_put_cstring(&msg, newpath);
722 	send_msg(conn->fd_out, &msg);
723 	debug3("Sent message %s \"%s\" -> \"%s\"",
724 	    (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" :
725 	    "SSH2_FXP_RENAME", oldpath, newpath);
726 	buffer_free(&msg);
727 
728 	status = get_status(conn->fd_in, id);
729 	if (status != SSH2_FX_OK)
730 		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
731 		    newpath, fx2txt(status));
732 
733 	return(status);
734 }
735 
736 int
737 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
738 {
739 	Buffer msg;
740 	u_int status, id;
741 
742 	if (conn->version < 3) {
743 		error("This server does not support the symlink operation");
744 		return(SSH2_FX_OP_UNSUPPORTED);
745 	}
746 
747 	buffer_init(&msg);
748 
749 	/* Send symlink request */
750 	id = conn->msg_id++;
751 	buffer_put_char(&msg, SSH2_FXP_SYMLINK);
752 	buffer_put_int(&msg, id);
753 	buffer_put_cstring(&msg, oldpath);
754 	buffer_put_cstring(&msg, newpath);
755 	send_msg(conn->fd_out, &msg);
756 	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
757 	    newpath);
758 	buffer_free(&msg);
759 
760 	status = get_status(conn->fd_in, id);
761 	if (status != SSH2_FX_OK)
762 		error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
763 		    newpath, fx2txt(status));
764 
765 	return(status);
766 }
767 
768 #ifdef notyet
769 char *
770 do_readlink(struct sftp_conn *conn, char *path)
771 {
772 	Buffer msg;
773 	u_int type, expected_id, count, id;
774 	char *filename, *longname;
775 	Attrib *a;
776 
777 	expected_id = id = conn->msg_id++;
778 	send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path,
779 	    strlen(path));
780 
781 	buffer_init(&msg);
782 
783 	get_msg(conn->fd_in, &msg);
784 	type = buffer_get_char(&msg);
785 	id = buffer_get_int(&msg);
786 
787 	if (id != expected_id)
788 		fatal("ID mismatch (%u != %u)", id, expected_id);
789 
790 	if (type == SSH2_FXP_STATUS) {
791 		u_int status = buffer_get_int(&msg);
792 
793 		error("Couldn't readlink: %s", fx2txt(status));
794 		return(NULL);
795 	} else if (type != SSH2_FXP_NAME)
796 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
797 		    SSH2_FXP_NAME, type);
798 
799 	count = buffer_get_int(&msg);
800 	if (count != 1)
801 		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
802 
803 	filename = buffer_get_string(&msg, NULL);
804 	longname = buffer_get_string(&msg, NULL);
805 	a = decode_attrib(&msg);
806 
807 	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
808 
809 	xfree(longname);
810 
811 	buffer_free(&msg);
812 
813 	return(filename);
814 }
815 #endif
816 
817 int
818 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
819     int quiet)
820 {
821 	Buffer msg;
822 	u_int id;
823 
824 	if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
825 		error("Server does not support statvfs@openssh.com extension");
826 		return -1;
827 	}
828 
829 	id = conn->msg_id++;
830 
831 	buffer_init(&msg);
832 	buffer_clear(&msg);
833 	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
834 	buffer_put_int(&msg, id);
835 	buffer_put_cstring(&msg, "statvfs@openssh.com");
836 	buffer_put_cstring(&msg, path);
837 	send_msg(conn->fd_out, &msg);
838 	buffer_free(&msg);
839 
840 	return get_decode_statvfs(conn->fd_in, st, id, quiet);
841 }
842 
843 #ifdef notyet
844 int
845 do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
846     struct sftp_statvfs *st, int quiet)
847 {
848 	Buffer msg;
849 	u_int id;
850 
851 	if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
852 		error("Server does not support fstatvfs@openssh.com extension");
853 		return -1;
854 	}
855 
856 	id = conn->msg_id++;
857 
858 	buffer_init(&msg);
859 	buffer_clear(&msg);
860 	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
861 	buffer_put_int(&msg, id);
862 	buffer_put_cstring(&msg, "fstatvfs@openssh.com");
863 	buffer_put_string(&msg, handle, handle_len);
864 	send_msg(conn->fd_out, &msg);
865 	buffer_free(&msg);
866 
867 	return get_decode_statvfs(conn->fd_in, st, id, quiet);
868 }
869 #endif
870 
871 static void
872 send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
873     char *handle, u_int handle_len)
874 {
875 	Buffer msg;
876 
877 	buffer_init(&msg);
878 	buffer_clear(&msg);
879 	buffer_put_char(&msg, SSH2_FXP_READ);
880 	buffer_put_int(&msg, id);
881 	buffer_put_string(&msg, handle, handle_len);
882 	buffer_put_int64(&msg, offset);
883 	buffer_put_int(&msg, len);
884 	send_msg(fd_out, &msg);
885 	buffer_free(&msg);
886 }
887 
888 int
889 do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
890     int pflag)
891 {
892 	Attrib junk, *a;
893 	Buffer msg;
894 	char *handle;
895 	int local_fd, status = 0, write_error;
896 	int read_error, write_errno;
897 	u_int64_t offset, size;
898 	u_int handle_len, mode, type, id, buflen, num_req, max_req;
899 	off_t progress_counter;
900 	struct request {
901 		u_int id;
902 		u_int len;
903 		u_int64_t offset;
904 		TAILQ_ENTRY(request) tq;
905 	};
906 	TAILQ_HEAD(reqhead, request) requests;
907 	struct request *req;
908 
909 	TAILQ_INIT(&requests);
910 
911 	a = do_stat(conn, remote_path, 0);
912 	if (a == NULL)
913 		return(-1);
914 
915 	/* Do not preserve set[ug]id here, as we do not preserve ownership */
916 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
917 		mode = a->perm & 0777;
918 	else
919 		mode = 0666;
920 
921 	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
922 	    (!S_ISREG(a->perm))) {
923 		error("Cannot download non-regular file: %s", remote_path);
924 		return(-1);
925 	}
926 
927 	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
928 		size = a->size;
929 	else
930 		size = 0;
931 
932 	buflen = conn->transfer_buflen;
933 	buffer_init(&msg);
934 
935 	/* Send open request */
936 	id = conn->msg_id++;
937 	buffer_put_char(&msg, SSH2_FXP_OPEN);
938 	buffer_put_int(&msg, id);
939 	buffer_put_cstring(&msg, remote_path);
940 	buffer_put_int(&msg, SSH2_FXF_READ);
941 	attrib_clear(&junk); /* Send empty attributes */
942 	encode_attrib(&msg, &junk);
943 	send_msg(conn->fd_out, &msg);
944 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
945 
946 	handle = get_handle(conn->fd_in, id, &handle_len);
947 	if (handle == NULL) {
948 		buffer_free(&msg);
949 		return(-1);
950 	}
951 
952 	local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC,
953 	    mode | S_IWRITE);
954 	if (local_fd == -1) {
955 		error("Couldn't open local file \"%s\" for writing: %s",
956 		    local_path, strerror(errno));
957 		do_close(conn, handle, handle_len);
958 		buffer_free(&msg);
959 		xfree(handle);
960 		return(-1);
961 	}
962 
963 	/* Read from remote and write to local */
964 	write_error = read_error = write_errno = num_req = offset = 0;
965 	max_req = 1;
966 	progress_counter = 0;
967 
968 	if (showprogress && size != 0)
969 		start_progress_meter(remote_path, size, &progress_counter);
970 
971 	while (num_req > 0 || max_req > 0) {
972 		char *data;
973 		u_int len;
974 
975 		/*
976 		 * Simulate EOF on interrupt: stop sending new requests and
977 		 * allow outstanding requests to drain gracefully
978 		 */
979 		if (interrupted) {
980 			if (num_req == 0) /* If we haven't started yet... */
981 				break;
982 			max_req = 0;
983 		}
984 
985 		/* Send some more requests */
986 		while (num_req < max_req) {
987 			debug3("Request range %llu -> %llu (%d/%d)",
988 			    (unsigned long long)offset,
989 			    (unsigned long long)offset + buflen - 1,
990 			    num_req, max_req);
991 			req = xmalloc(sizeof(*req));
992 			req->id = conn->msg_id++;
993 			req->len = buflen;
994 			req->offset = offset;
995 			offset += buflen;
996 			num_req++;
997 			TAILQ_INSERT_TAIL(&requests, req, tq);
998 			send_read_request(conn->fd_out, req->id, req->offset,
999 			    req->len, handle, handle_len);
1000 		}
1001 
1002 		buffer_clear(&msg);
1003 		get_msg(conn->fd_in, &msg);
1004 		type = buffer_get_char(&msg);
1005 		id = buffer_get_int(&msg);
1006 		debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1007 
1008 		/* Find the request in our queue */
1009 		for (req = TAILQ_FIRST(&requests);
1010 		    req != NULL && req->id != id;
1011 		    req = TAILQ_NEXT(req, tq))
1012 			;
1013 		if (req == NULL)
1014 			fatal("Unexpected reply %u", id);
1015 
1016 		switch (type) {
1017 		case SSH2_FXP_STATUS:
1018 			status = buffer_get_int(&msg);
1019 			if (status != SSH2_FX_EOF)
1020 				read_error = 1;
1021 			max_req = 0;
1022 			TAILQ_REMOVE(&requests, req, tq);
1023 			xfree(req);
1024 			num_req--;
1025 			break;
1026 		case SSH2_FXP_DATA:
1027 			data = buffer_get_string(&msg, &len);
1028 			debug3("Received data %llu -> %llu",
1029 			    (unsigned long long)req->offset,
1030 			    (unsigned long long)req->offset + len - 1);
1031 			if (len > req->len)
1032 				fatal("Received more data than asked for "
1033 				    "%u > %u", len, req->len);
1034 			if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1035 			    atomicio(vwrite, local_fd, data, len) != len) &&
1036 			    !write_error) {
1037 				write_errno = errno;
1038 				write_error = 1;
1039 				max_req = 0;
1040 			}
1041 			progress_counter += len;
1042 			xfree(data);
1043 
1044 			if (len == req->len) {
1045 				TAILQ_REMOVE(&requests, req, tq);
1046 				xfree(req);
1047 				num_req--;
1048 			} else {
1049 				/* Resend the request for the missing data */
1050 				debug3("Short data block, re-requesting "
1051 				    "%llu -> %llu (%2d)",
1052 				    (unsigned long long)req->offset + len,
1053 				    (unsigned long long)req->offset +
1054 				    req->len - 1, num_req);
1055 				req->id = conn->msg_id++;
1056 				req->len -= len;
1057 				req->offset += len;
1058 				send_read_request(conn->fd_out, req->id,
1059 				    req->offset, req->len, handle, handle_len);
1060 				/* Reduce the request size */
1061 				if (len < buflen)
1062 					buflen = MAX(MIN_READ_SIZE, len);
1063 			}
1064 			if (max_req > 0) { /* max_req = 0 iff EOF received */
1065 				if (size > 0 && offset > size) {
1066 					/* Only one request at a time
1067 					 * after the expected EOF */
1068 					debug3("Finish at %llu (%2d)",
1069 					    (unsigned long long)offset,
1070 					    num_req);
1071 					max_req = 1;
1072 				} else if (max_req <= conn->num_requests) {
1073 					++max_req;
1074 				}
1075 			}
1076 			break;
1077 		default:
1078 			fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1079 			    SSH2_FXP_DATA, type);
1080 		}
1081 	}
1082 
1083 	if (showprogress && size)
1084 		stop_progress_meter();
1085 
1086 	/* Sanity check */
1087 	if (TAILQ_FIRST(&requests) != NULL)
1088 		fatal("Transfer complete, but requests still in queue");
1089 
1090 	if (read_error) {
1091 		error("Couldn't read from remote file \"%s\" : %s",
1092 		    remote_path, fx2txt(status));
1093 		do_close(conn, handle, handle_len);
1094 	} else if (write_error) {
1095 		error("Couldn't write to \"%s\": %s", local_path,
1096 		    strerror(write_errno));
1097 		status = -1;
1098 		do_close(conn, handle, handle_len);
1099 	} else {
1100 		status = do_close(conn, handle, handle_len);
1101 
1102 		/* Override umask and utimes if asked */
1103 		if (pflag && fchmod(local_fd, mode) == -1)
1104 			error("Couldn't set mode on \"%s\": %s", local_path,
1105 			    strerror(errno));
1106 		if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1107 			struct timeval tv[2];
1108 			tv[0].tv_sec = a->atime;
1109 			tv[1].tv_sec = a->mtime;
1110 			tv[0].tv_usec = tv[1].tv_usec = 0;
1111 			if (utimes(local_path, tv) == -1)
1112 				error("Can't set times on \"%s\": %s",
1113 				    local_path, strerror(errno));
1114 		}
1115 	}
1116 	close(local_fd);
1117 	buffer_free(&msg);
1118 	xfree(handle);
1119 
1120 	return(status);
1121 }
1122 
1123 int
1124 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1125     int pflag)
1126 {
1127 	int local_fd;
1128 	int status = SSH2_FX_OK;
1129 	u_int handle_len, id, type;
1130 	off_t offset;
1131 	char *handle, *data;
1132 	Buffer msg;
1133 	struct stat sb;
1134 	Attrib a;
1135 	u_int32_t startid;
1136 	u_int32_t ackid;
1137 	struct outstanding_ack {
1138 		u_int id;
1139 		u_int len;
1140 		off_t offset;
1141 		TAILQ_ENTRY(outstanding_ack) tq;
1142 	};
1143 	TAILQ_HEAD(ackhead, outstanding_ack) acks;
1144 	struct outstanding_ack *ack = NULL;
1145 
1146 	TAILQ_INIT(&acks);
1147 
1148 	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1149 		error("Couldn't open local file \"%s\" for reading: %s",
1150 		    local_path, strerror(errno));
1151 		return(-1);
1152 	}
1153 	if (fstat(local_fd, &sb) == -1) {
1154 		error("Couldn't fstat local file \"%s\": %s",
1155 		    local_path, strerror(errno));
1156 		close(local_fd);
1157 		return(-1);
1158 	}
1159 	if (!S_ISREG(sb.st_mode)) {
1160 		error("%s is not a regular file", local_path);
1161 		close(local_fd);
1162 		return(-1);
1163 	}
1164 	stat_to_attrib(&sb, &a);
1165 
1166 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1167 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1168 	a.perm &= 0777;
1169 	if (!pflag)
1170 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1171 
1172 	buffer_init(&msg);
1173 
1174 	/* Send open request */
1175 	id = conn->msg_id++;
1176 	buffer_put_char(&msg, SSH2_FXP_OPEN);
1177 	buffer_put_int(&msg, id);
1178 	buffer_put_cstring(&msg, remote_path);
1179 	buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
1180 	encode_attrib(&msg, &a);
1181 	send_msg(conn->fd_out, &msg);
1182 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1183 
1184 	buffer_clear(&msg);
1185 
1186 	handle = get_handle(conn->fd_in, id, &handle_len);
1187 	if (handle == NULL) {
1188 		close(local_fd);
1189 		buffer_free(&msg);
1190 		return -1;
1191 	}
1192 
1193 	startid = ackid = id + 1;
1194 	data = xmalloc(conn->transfer_buflen);
1195 
1196 	/* Read from local and write to remote */
1197 	offset = 0;
1198 	if (showprogress)
1199 		start_progress_meter(local_path, sb.st_size, &offset);
1200 
1201 	for (;;) {
1202 		int len;
1203 
1204 		/*
1205 		 * Can't use atomicio here because it returns 0 on EOF,
1206 		 * thus losing the last block of the file.
1207 		 * Simulate an EOF on interrupt, allowing ACKs from the
1208 		 * server to drain.
1209 		 */
1210 		if (interrupted || status != SSH2_FX_OK)
1211 			len = 0;
1212 		else do
1213 			len = read(local_fd, data, conn->transfer_buflen);
1214 		while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1215 
1216 		if (len == -1)
1217 			fatal("Couldn't read from \"%s\": %s", local_path,
1218 			    strerror(errno));
1219 
1220 		if (len != 0) {
1221 			ack = xmalloc(sizeof(*ack));
1222 			ack->id = ++id;
1223 			ack->offset = offset;
1224 			ack->len = len;
1225 			TAILQ_INSERT_TAIL(&acks, ack, tq);
1226 
1227 			buffer_clear(&msg);
1228 			buffer_put_char(&msg, SSH2_FXP_WRITE);
1229 			buffer_put_int(&msg, ack->id);
1230 			buffer_put_string(&msg, handle, handle_len);
1231 			buffer_put_int64(&msg, offset);
1232 			buffer_put_string(&msg, data, len);
1233 			send_msg(conn->fd_out, &msg);
1234 			debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1235 			    id, (unsigned long long)offset, len);
1236 		} else if (TAILQ_FIRST(&acks) == NULL)
1237 			break;
1238 
1239 		if (ack == NULL)
1240 			fatal("Unexpected ACK %u", id);
1241 
1242 		if (id == startid || len == 0 ||
1243 		    id - ackid >= conn->num_requests) {
1244 			u_int r_id;
1245 
1246 			buffer_clear(&msg);
1247 			get_msg(conn->fd_in, &msg);
1248 			type = buffer_get_char(&msg);
1249 			r_id = buffer_get_int(&msg);
1250 
1251 			if (type != SSH2_FXP_STATUS)
1252 				fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1253 				    "got %d", SSH2_FXP_STATUS, type);
1254 
1255 			status = buffer_get_int(&msg);
1256 			debug3("SSH2_FXP_STATUS %d", status);
1257 
1258 			/* Find the request in our queue */
1259 			for (ack = TAILQ_FIRST(&acks);
1260 			    ack != NULL && ack->id != r_id;
1261 			    ack = TAILQ_NEXT(ack, tq))
1262 				;
1263 			if (ack == NULL)
1264 				fatal("Can't find request for ID %u", r_id);
1265 			TAILQ_REMOVE(&acks, ack, tq);
1266 			debug3("In write loop, ack for %u %u bytes at %lld",
1267 			    ack->id, ack->len, (long long)ack->offset);
1268 			++ackid;
1269 			xfree(ack);
1270 		}
1271 		offset += len;
1272 		if (offset < 0)
1273 			fatal("%s: offset < 0", __func__);
1274 	}
1275 	buffer_free(&msg);
1276 
1277 	if (showprogress)
1278 		stop_progress_meter();
1279 	xfree(data);
1280 
1281 	if (status != SSH2_FX_OK) {
1282 		error("Couldn't write to remote file \"%s\": %s",
1283 		    remote_path, fx2txt(status));
1284 		status = -1;
1285 	}
1286 
1287 	if (close(local_fd) == -1) {
1288 		error("Couldn't close local file \"%s\": %s", local_path,
1289 		    strerror(errno));
1290 		status = -1;
1291 	}
1292 
1293 	/* Override umask and utimes if asked */
1294 	if (pflag)
1295 		do_fsetstat(conn, handle, handle_len, &a);
1296 
1297 	if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
1298 		status = -1;
1299 	xfree(handle);
1300 
1301 	return status;
1302 }
1303