sftp-client.c revision 164147
12926Sphk/* $OpenBSD: sftp-client.c,v 1.75 2006/10/22 02:25:50 djm Exp $ */
22926Sphk/*
32926Sphk * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
493150Sphk *
52926Sphk * Permission to use, copy, modify, and distribute this software for any
62926Sphk * purpose with or without fee is hereby granted, provided that the above
72926Sphk * copyright notice and this permission notice appear in all copies.
82926Sphk *
950479Speter * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
102926Sphk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
112926Sphk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
122886Sphk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1329526Scharnier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1429526Scharnier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1529526Scharnier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
162886Sphk */
172886Sphk
1829526Scharnier/* XXX: memleaks */
1929526Scharnier/* XXX: signed vs unsigned */
202886Sphk/* XXX: remove all logging, only return status codes */
212886Sphk/* XXX: copy between two remote sites */
2229526Scharnier
232886Sphk#include "includes.h"
242886Sphk
252886Sphk#include <sys/types.h>
2615456Sphk#include <sys/param.h>
272886Sphk#include "openbsd-compat/sys-queue.h"
282886Sphk#ifdef HAVE_SYS_STAT_H
292886Sphk# include <sys/stat.h>
3013917Sphk#endif
3113917Sphk#ifdef HAVE_SYS_TIME_H
3217946Sphk# include <sys/time.h>
3313917Sphk#endif
342886Sphk#include <sys/uio.h>
352886Sphk
362886Sphk#include <errno.h>
372886Sphk#include <fcntl.h>
382886Sphk#include <signal.h>
392886Sphk#include <stdarg.h>
402886Sphk#include <stdio.h>
412886Sphk#include <string.h>
422886Sphk#include <unistd.h>
432886Sphk
442886Sphk#include "xmalloc.h"
452886Sphk#include "buffer.h"
462886Sphk#include "log.h"
472886Sphk#include "atomicio.h"
482886Sphk#include "progressmeter.h"
4913917Sphk#include "misc.h"
502886Sphk
512886Sphk#include "sftp.h"
522886Sphk#include "sftp-common.h"
532971Sphk#include "sftp-client.h"
542886Sphk
552886Sphkextern volatile sig_atomic_t interrupted;
5617946Sphkextern int showprogress;
5717946Sphk
582886Sphk/* Minimum amount of data to read at a time */
592886Sphk#define MIN_READ_SIZE	512
602886Sphk
612886Sphkstruct sftp_conn {
6217946Sphk	int fd_in;
6317946Sphk	int fd_out;
6417946Sphk	u_int transfer_buflen;
6517946Sphk	u_int num_requests;
6617946Sphk	u_int version;
6717946Sphk	u_int msg_id;
6817946Sphk};
6917946Sphk
7017946Sphkstatic void
712886Sphksend_msg(int fd, Buffer *m)
722886Sphk{
7313917Sphk	u_char mlen[4];
7413917Sphk	struct iovec iov[2];
752886Sphk
762886Sphk	if (buffer_len(m) > SFTP_MAX_MSG_LENGTH)
772886Sphk		fatal("Outbound message too long %u", buffer_len(m));
782886Sphk
792886Sphk	/* Send length first */
802886Sphk	put_u32(mlen, buffer_len(m));
812886Sphk	iov[0].iov_base = mlen;
822886Sphk	iov[0].iov_len = sizeof(mlen);
832886Sphk	iov[1].iov_base = buffer_ptr(m);
842886Sphk	iov[1].iov_len = buffer_len(m);
852886Sphk
8613917Sphk	if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen))
8713917Sphk		fatal("Couldn't send packet: %s", strerror(errno));
8817946Sphk
8917946Sphk	buffer_clear(m);
902886Sphk}
918857Srgrimes
922886Sphkstatic void
932886Sphkget_msg(int fd, Buffer *m)
942886Sphk{
952886Sphk	u_int msg_len;
962886Sphk
972886Sphk	buffer_append_space(m, 4);
982886Sphk	if (atomicio(read, fd, buffer_ptr(m), 4) != 4) {
992886Sphk		if (errno == EPIPE)
1008857Srgrimes			fatal("Connection closed");
1012886Sphk		else
1022886Sphk			fatal("Couldn't read packet: %s", strerror(errno));
1032886Sphk	}
1042886Sphk
1052926Sphk	msg_len = buffer_get_int(m);
1062926Sphk	if (msg_len > SFTP_MAX_MSG_LENGTH)
1072926Sphk		fatal("Received message too long %u", msg_len);
1082926Sphk
1092926Sphk	buffer_append_space(m, msg_len);
1102926Sphk	if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) {
1112926Sphk		if (errno == EPIPE)
1122926Sphk			fatal("Connection closed");
1132926Sphk		else
1148857Srgrimes			fatal("Read packet: %s", strerror(errno));
1152886Sphk	}
1162926Sphk}
1172886Sphk
1182926Sphkstatic void
1192926Sphksend_string_request(int fd, u_int id, u_int code, char *s,
1202926Sphk    u_int len)
1212948Sphk{
12217946Sphk	Buffer msg;
12317946Sphk
12415456Sphk	buffer_init(&msg);
12515456Sphk	buffer_put_char(&msg, code);
12617946Sphk	buffer_put_int(&msg, id);
12717946Sphk	buffer_put_string(&msg, s, len);
1282886Sphk	send_msg(fd, &msg);
1292971Sphk	debug3("Sent message fd %d T:%u I:%u", fd, code, id);
1302971Sphk	buffer_free(&msg);
1312971Sphk}
1322971Sphk
1332971Sphkstatic void
1342971Sphksend_string_attrs_request(int fd, u_int id, u_int code, char *s,
1352971Sphk    u_int len, Attrib *a)
1362971Sphk{
1376889Sphk	Buffer msg;
13817946Sphk
1392886Sphk	buffer_init(&msg);
1402886Sphk	buffer_put_char(&msg, code);
1412886Sphk	buffer_put_int(&msg, id);
1422886Sphk	buffer_put_string(&msg, s, len);
1432971Sphk	encode_attrib(&msg, a);
1442886Sphk	send_msg(fd, &msg);
1452886Sphk	debug3("Sent message fd %d T:%u I:%u", fd, code, id);
14613917Sphk	buffer_free(&msg);
1472886Sphk}
1482886Sphk
1492886Sphkstatic u_int
1502886Sphkget_status(int fd, u_int expected_id)
1512886Sphk{
1522926Sphk	Buffer msg;
1532926Sphk	u_int type, id, status;
1542926Sphk
1552926Sphk	buffer_init(&msg);
15613917Sphk	get_msg(fd, &msg);
1572886Sphk	type = buffer_get_char(&msg);
1586889Sphk	id = buffer_get_int(&msg);
1592886Sphk
16017946Sphk	if (id != expected_id)
1612886Sphk		fatal("ID mismatch (%u != %u)", id, expected_id);
1622886Sphk	if (type != SSH2_FXP_STATUS)
1632926Sphk		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
174static char *
175get_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
204static Attrib *
205get_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
239struct sftp_conn *
240do_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
294u_int
295sftp_proto_version(struct sftp_conn *conn)
296{
297	return(conn->version);
298}
299
300int
301do_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
325static int
326do_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
437int
438do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
439{
440	return(do_lsreaddir(conn, path, 0, dir));
441}
442
443void 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
455int
456do_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
471int
472do_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
487int
488do_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
503Attrib *
504do_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
517Attrib *
518do_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
537Attrib *
538do_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
549int
550do_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
566int
567do_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
583char *
584do_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
630int
631do_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
657int
658do_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
689char *
690do_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
736static void
737send_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
753int
754do_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
991int
992do_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
1170done:
1171	xfree(handle);
1172	buffer_free(&msg);
1173	return(status);
1174}
1175