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