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