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