xref: /openbsd-src/usr.bin/ssh/sftp-client.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*
2  * Copyright (c) 2001 Damien Miller.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 /* XXX: memleaks */
26 /* XXX: signed vs unsigned */
27 /* XXX: redesign to allow concurrent overlapped operations */
28 /* XXX: we use fatal too much, error may be more appropriate in places */
29 /* XXX: copy between two remote sites */
30 
31 #include "includes.h"
32 RCSID("$OpenBSD: sftp-client.c,v 1.19 2001/12/19 07:18:56 deraadt Exp $");
33 
34 #include "buffer.h"
35 #include "bufaux.h"
36 #include "getput.h"
37 #include "xmalloc.h"
38 #include "log.h"
39 #include "atomicio.h"
40 
41 #include "sftp.h"
42 #include "sftp-common.h"
43 #include "sftp-client.h"
44 
45 /* How much data to read/write at at time during copies */
46 /* XXX: what should this be? */
47 #define COPY_SIZE	8192
48 
49 /* Message ID */
50 static u_int msg_id = 1;
51 
52 static void
53 send_msg(int fd, Buffer *m)
54 {
55 	int mlen = buffer_len(m);
56 	int len;
57 	Buffer oqueue;
58 
59 	buffer_init(&oqueue);
60 	buffer_put_int(&oqueue, mlen);
61 	buffer_append(&oqueue, buffer_ptr(m), mlen);
62 	buffer_consume(m, mlen);
63 
64 	len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));
65 	if (len <= 0)
66 		fatal("Couldn't send packet: %s", strerror(errno));
67 
68 	buffer_free(&oqueue);
69 }
70 
71 static void
72 get_msg(int fd, Buffer *m)
73 {
74 	u_int len, msg_len;
75 	unsigned char buf[4096];
76 
77 	len = atomicio(read, fd, buf, 4);
78 	if (len == 0)
79 		fatal("Connection closed");
80 	else if (len == -1)
81 		fatal("Couldn't read packet: %s", strerror(errno));
82 
83 	msg_len = GET_32BIT(buf);
84 	if (msg_len > 256 * 1024)
85 		fatal("Received message too long %d", msg_len);
86 
87 	while (msg_len) {
88 		len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
89 		if (len == 0)
90 			fatal("Connection closed");
91 		else if (len == -1)
92 			fatal("Couldn't read packet: %s", strerror(errno));
93 
94 		msg_len -= len;
95 		buffer_append(m, buf, len);
96 	}
97 }
98 
99 static void
100 send_string_request(int fd, u_int id, u_int code, char *s,
101     u_int len)
102 {
103 	Buffer msg;
104 
105 	buffer_init(&msg);
106 	buffer_put_char(&msg, code);
107 	buffer_put_int(&msg, id);
108 	buffer_put_string(&msg, s, len);
109 	send_msg(fd, &msg);
110 	debug3("Sent message fd %d T:%d I:%d", fd, code, id);
111 	buffer_free(&msg);
112 }
113 
114 static void
115 send_string_attrs_request(int fd, u_int id, u_int code, char *s,
116     u_int len, Attrib *a)
117 {
118 	Buffer msg;
119 
120 	buffer_init(&msg);
121 	buffer_put_char(&msg, code);
122 	buffer_put_int(&msg, id);
123 	buffer_put_string(&msg, s, len);
124 	encode_attrib(&msg, a);
125 	send_msg(fd, &msg);
126 	debug3("Sent message fd %d T:%d I:%d", fd, code, id);
127 	buffer_free(&msg);
128 }
129 
130 static u_int
131 get_status(int fd, int expected_id)
132 {
133 	Buffer msg;
134 	u_int type, id, status;
135 
136 	buffer_init(&msg);
137 	get_msg(fd, &msg);
138 	type = buffer_get_char(&msg);
139 	id = buffer_get_int(&msg);
140 
141 	if (id != expected_id)
142 		fatal("ID mismatch (%d != %d)", id, expected_id);
143 	if (type != SSH2_FXP_STATUS)
144 		fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
145 		    SSH2_FXP_STATUS, type);
146 
147 	status = buffer_get_int(&msg);
148 	buffer_free(&msg);
149 
150 	debug3("SSH2_FXP_STATUS %d", status);
151 
152 	return(status);
153 }
154 
155 static char *
156 get_handle(int fd, u_int expected_id, u_int *len)
157 {
158 	Buffer msg;
159 	u_int type, id;
160 	char *handle;
161 
162 	buffer_init(&msg);
163 	get_msg(fd, &msg);
164 	type = buffer_get_char(&msg);
165 	id = buffer_get_int(&msg);
166 
167 	if (id != expected_id)
168 		fatal("ID mismatch (%d != %d)", id, expected_id);
169 	if (type == SSH2_FXP_STATUS) {
170 		int status = buffer_get_int(&msg);
171 
172 		error("Couldn't get handle: %s", fx2txt(status));
173 		return(NULL);
174 	} else if (type != SSH2_FXP_HANDLE)
175 		fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
176 		    SSH2_FXP_HANDLE, type);
177 
178 	handle = buffer_get_string(&msg, len);
179 	buffer_free(&msg);
180 
181 	return(handle);
182 }
183 
184 static Attrib *
185 get_decode_stat(int fd, u_int expected_id, int quiet)
186 {
187 	Buffer msg;
188 	u_int type, id;
189 	Attrib *a;
190 
191 	buffer_init(&msg);
192 	get_msg(fd, &msg);
193 
194 	type = buffer_get_char(&msg);
195 	id = buffer_get_int(&msg);
196 
197 	debug3("Received stat reply T:%d I:%d", type, id);
198 	if (id != expected_id)
199 		fatal("ID mismatch (%d != %d)", id, expected_id);
200 	if (type == SSH2_FXP_STATUS) {
201 		int status = buffer_get_int(&msg);
202 
203 		if (quiet)
204 			debug("Couldn't stat remote file: %s", fx2txt(status));
205 		else
206 			error("Couldn't stat remote file: %s", fx2txt(status));
207 		return(NULL);
208 	} else if (type != SSH2_FXP_ATTRS) {
209 		fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
210 		    SSH2_FXP_ATTRS, type);
211 	}
212 	a = decode_attrib(&msg);
213 	buffer_free(&msg);
214 
215 	return(a);
216 }
217 
218 int
219 do_init(int fd_in, int fd_out)
220 {
221 	int type, version;
222 	Buffer msg;
223 
224 	buffer_init(&msg);
225 	buffer_put_char(&msg, SSH2_FXP_INIT);
226 	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
227 	send_msg(fd_out, &msg);
228 
229 	buffer_clear(&msg);
230 
231 	get_msg(fd_in, &msg);
232 
233 	/* Expecting a VERSION reply */
234 	if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
235 		error("Invalid packet back from SSH2_FXP_INIT (type %d)",
236 		    type);
237 		buffer_free(&msg);
238 		return(-1);
239 	}
240 	version = buffer_get_int(&msg);
241 
242 	debug2("Remote version: %d", version);
243 
244 	/* Check for extensions */
245 	while (buffer_len(&msg) > 0) {
246 		char *name = buffer_get_string(&msg, NULL);
247 		char *value = buffer_get_string(&msg, NULL);
248 
249 		debug2("Init extension: \"%s\"", name);
250 		xfree(name);
251 		xfree(value);
252 	}
253 
254 	buffer_free(&msg);
255 
256 	return(version);
257 }
258 
259 int
260 do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
261 {
262 	u_int id, status;
263 	Buffer msg;
264 
265 	buffer_init(&msg);
266 
267 	id = msg_id++;
268 	buffer_put_char(&msg, SSH2_FXP_CLOSE);
269 	buffer_put_int(&msg, id);
270 	buffer_put_string(&msg, handle, handle_len);
271 	send_msg(fd_out, &msg);
272 	debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
273 
274 	status = get_status(fd_in, id);
275 	if (status != SSH2_FX_OK)
276 		error("Couldn't close file: %s", fx2txt(status));
277 
278 	buffer_free(&msg);
279 
280 	return(status);
281 }
282 
283 
284 static int
285 do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
286     SFTP_DIRENT ***dir)
287 {
288 	Buffer msg;
289 	u_int type, id, handle_len, i, expected_id, ents = 0;
290 	char *handle;
291 
292 	id = msg_id++;
293 
294 	buffer_init(&msg);
295 	buffer_put_char(&msg, SSH2_FXP_OPENDIR);
296 	buffer_put_int(&msg, id);
297 	buffer_put_cstring(&msg, path);
298 	send_msg(fd_out, &msg);
299 
300 	buffer_clear(&msg);
301 
302 	handle = get_handle(fd_in, id, &handle_len);
303 	if (handle == NULL)
304 		return(-1);
305 
306 	if (dir) {
307 		ents = 0;
308 		*dir = xmalloc(sizeof(**dir));
309 		(*dir)[0] = NULL;
310 	}
311 
312 	for (;;) {
313 		int count;
314 
315 		id = expected_id = msg_id++;
316 
317 		debug3("Sending SSH2_FXP_READDIR I:%d", id);
318 
319 		buffer_clear(&msg);
320 		buffer_put_char(&msg, SSH2_FXP_READDIR);
321 		buffer_put_int(&msg, id);
322 		buffer_put_string(&msg, handle, handle_len);
323 		send_msg(fd_out, &msg);
324 
325 		buffer_clear(&msg);
326 
327 		get_msg(fd_in, &msg);
328 
329 		type = buffer_get_char(&msg);
330 		id = buffer_get_int(&msg);
331 
332 		debug3("Received reply T:%d I:%d", type, id);
333 
334 		if (id != expected_id)
335 			fatal("ID mismatch (%d != %d)", id, expected_id);
336 
337 		if (type == SSH2_FXP_STATUS) {
338 			int status = buffer_get_int(&msg);
339 
340 			debug3("Received SSH2_FXP_STATUS %d", status);
341 
342 			if (status == SSH2_FX_EOF) {
343 				break;
344 			} else {
345 				error("Couldn't read directory: %s",
346 				    fx2txt(status));
347 				do_close(fd_in, fd_out, handle, handle_len);
348 				return(status);
349 			}
350 		} else if (type != SSH2_FXP_NAME)
351 			fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
352 			    SSH2_FXP_NAME, type);
353 
354 		count = buffer_get_int(&msg);
355 		if (count == 0)
356 			break;
357 		debug3("Received %d SSH2_FXP_NAME responses", count);
358 		for (i = 0; i < count; i++) {
359 			char *filename, *longname;
360 			Attrib *a;
361 
362 			filename = buffer_get_string(&msg, NULL);
363 			longname = buffer_get_string(&msg, NULL);
364 			a = decode_attrib(&msg);
365 
366 			if (printflag)
367 				printf("%s\n", longname);
368 
369 			if (dir) {
370 				*dir = xrealloc(*dir, sizeof(**dir) *
371 				    (ents + 2));
372 				(*dir)[ents] = xmalloc(sizeof(***dir));
373 				(*dir)[ents]->filename = xstrdup(filename);
374 				(*dir)[ents]->longname = xstrdup(longname);
375 				memcpy(&(*dir)[ents]->a, a, sizeof(*a));
376 				(*dir)[++ents] = NULL;
377 			}
378 
379 			xfree(filename);
380 			xfree(longname);
381 		}
382 	}
383 
384 	buffer_free(&msg);
385 	do_close(fd_in, fd_out, handle, handle_len);
386 	xfree(handle);
387 
388 	return(0);
389 }
390 
391 int
392 do_ls(int fd_in, int fd_out, char *path)
393 {
394 	return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
395 }
396 
397 int
398 do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
399 {
400 	return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
401 }
402 
403 void free_sftp_dirents(SFTP_DIRENT **s)
404 {
405 	int i;
406 
407 	for (i = 0; s[i]; i++) {
408 		xfree(s[i]->filename);
409 		xfree(s[i]->longname);
410 		xfree(s[i]);
411 	}
412 	xfree(s);
413 }
414 
415 int
416 do_rm(int fd_in, int fd_out, char *path)
417 {
418 	u_int status, id;
419 
420 	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
421 
422 	id = msg_id++;
423 	send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
424 	status = get_status(fd_in, id);
425 	if (status != SSH2_FX_OK)
426 		error("Couldn't delete file: %s", fx2txt(status));
427 	return(status);
428 }
429 
430 int
431 do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
432 {
433 	u_int status, id;
434 
435 	id = msg_id++;
436 	send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
437 	    strlen(path), a);
438 
439 	status = get_status(fd_in, id);
440 	if (status != SSH2_FX_OK)
441 		error("Couldn't create directory: %s", fx2txt(status));
442 
443 	return(status);
444 }
445 
446 int
447 do_rmdir(int fd_in, int fd_out, char *path)
448 {
449 	u_int status, id;
450 
451 	id = msg_id++;
452 	send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
453 
454 	status = get_status(fd_in, id);
455 	if (status != SSH2_FX_OK)
456 		error("Couldn't remove directory: %s", fx2txt(status));
457 
458 	return(status);
459 }
460 
461 Attrib *
462 do_stat(int fd_in, int fd_out, char *path, int quiet)
463 {
464 	u_int id;
465 
466 	id = msg_id++;
467 	send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
468 	return(get_decode_stat(fd_in, id, quiet));
469 }
470 
471 Attrib *
472 do_lstat(int fd_in, int fd_out, char *path, int quiet)
473 {
474 	u_int id;
475 
476 	id = msg_id++;
477 	send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
478 	return(get_decode_stat(fd_in, id, quiet));
479 }
480 
481 Attrib *
482 do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
483 {
484 	u_int id;
485 
486 	id = msg_id++;
487 	send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
488 	return(get_decode_stat(fd_in, id, quiet));
489 }
490 
491 int
492 do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
493 {
494 	u_int status, id;
495 
496 	id = msg_id++;
497 	send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
498 	    strlen(path), a);
499 
500 	status = get_status(fd_in, id);
501 	if (status != SSH2_FX_OK)
502 		error("Couldn't setstat on \"%s\": %s", path,
503 		    fx2txt(status));
504 
505 	return(status);
506 }
507 
508 int
509 do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
510     Attrib *a)
511 {
512 	u_int status, id;
513 
514 	id = msg_id++;
515 	send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
516 	    handle_len, a);
517 
518 	status = get_status(fd_in, id);
519 	if (status != SSH2_FX_OK)
520 		error("Couldn't fsetstat: %s", fx2txt(status));
521 
522 	return(status);
523 }
524 
525 char *
526 do_realpath(int fd_in, int fd_out, char *path)
527 {
528 	Buffer msg;
529 	u_int type, expected_id, count, id;
530 	char *filename, *longname;
531 	Attrib *a;
532 
533 	expected_id = id = msg_id++;
534 	send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
535 
536 	buffer_init(&msg);
537 
538 	get_msg(fd_in, &msg);
539 	type = buffer_get_char(&msg);
540 	id = buffer_get_int(&msg);
541 
542 	if (id != expected_id)
543 		fatal("ID mismatch (%d != %d)", id, expected_id);
544 
545 	if (type == SSH2_FXP_STATUS) {
546 		u_int status = buffer_get_int(&msg);
547 
548 		error("Couldn't canonicalise: %s", fx2txt(status));
549 		return(NULL);
550 	} else if (type != SSH2_FXP_NAME)
551 		fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
552 		    SSH2_FXP_NAME, type);
553 
554 	count = buffer_get_int(&msg);
555 	if (count != 1)
556 		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
557 
558 	filename = buffer_get_string(&msg, NULL);
559 	longname = buffer_get_string(&msg, NULL);
560 	a = decode_attrib(&msg);
561 
562 	debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
563 
564 	xfree(longname);
565 
566 	buffer_free(&msg);
567 
568 	return(filename);
569 }
570 
571 int
572 do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
573 {
574 	Buffer msg;
575 	u_int status, id;
576 
577 	buffer_init(&msg);
578 
579 	/* Send rename request */
580 	id = msg_id++;
581 	buffer_put_char(&msg, SSH2_FXP_RENAME);
582 	buffer_put_int(&msg, id);
583 	buffer_put_cstring(&msg, oldpath);
584 	buffer_put_cstring(&msg, newpath);
585 	send_msg(fd_out, &msg);
586 	debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
587 	    newpath);
588 	buffer_free(&msg);
589 
590 	status = get_status(fd_in, id);
591 	if (status != SSH2_FX_OK)
592 		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
593 		    fx2txt(status));
594 
595 	return(status);
596 }
597 
598 int
599 do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
600 {
601 	Buffer msg;
602 	u_int status, id;
603 
604 	buffer_init(&msg);
605 
606 	/* Send rename request */
607 	id = msg_id++;
608 	buffer_put_char(&msg, SSH2_FXP_SYMLINK);
609 	buffer_put_int(&msg, id);
610 	buffer_put_cstring(&msg, oldpath);
611 	buffer_put_cstring(&msg, newpath);
612 	send_msg(fd_out, &msg);
613 	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
614 	    newpath);
615 	buffer_free(&msg);
616 
617 	status = get_status(fd_in, id);
618 	if (status != SSH2_FX_OK)
619 		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
620 		    fx2txt(status));
621 
622 	return(status);
623 }
624 
625 char *
626 do_readlink(int fd_in, int fd_out, char *path)
627 {
628 	Buffer msg;
629 	u_int type, expected_id, count, id;
630 	char *filename, *longname;
631 	Attrib *a;
632 
633 	expected_id = id = msg_id++;
634 	send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
635 
636 	buffer_init(&msg);
637 
638 	get_msg(fd_in, &msg);
639 	type = buffer_get_char(&msg);
640 	id = buffer_get_int(&msg);
641 
642 	if (id != expected_id)
643 		fatal("ID mismatch (%d != %d)", id, expected_id);
644 
645 	if (type == SSH2_FXP_STATUS) {
646 		u_int status = buffer_get_int(&msg);
647 
648 		error("Couldn't readlink: %s", fx2txt(status));
649 		return(NULL);
650 	} else if (type != SSH2_FXP_NAME)
651 		fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
652 		    SSH2_FXP_NAME, type);
653 
654 	count = buffer_get_int(&msg);
655 	if (count != 1)
656 		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
657 
658 	filename = buffer_get_string(&msg, NULL);
659 	longname = buffer_get_string(&msg, NULL);
660 	a = decode_attrib(&msg);
661 
662 	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
663 
664 	xfree(longname);
665 
666 	buffer_free(&msg);
667 
668 	return(filename);
669 }
670 
671 int
672 do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
673     int pflag)
674 {
675 	int local_fd;
676 	u_int expected_id, handle_len, mode, type, id;
677 	u_int64_t offset;
678 	char *handle;
679 	Buffer msg;
680 	Attrib junk, *a;
681 	int status;
682 
683 	a = do_stat(fd_in, fd_out, remote_path, 0);
684 	if (a == NULL)
685 		return(-1);
686 
687 	/* XXX: should we preserve set[ug]id? */
688 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
689 		mode = S_IWRITE | (a->perm & 0777);
690 	else
691 		mode = 0666;
692 
693 	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
694 	    (a->perm & S_IFDIR)) {
695 		error("Cannot download a directory: %s", remote_path);
696 		return(-1);
697 	}
698 
699 	local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
700 	if (local_fd == -1) {
701 		error("Couldn't open local file \"%s\" for writing: %s",
702 		    local_path, strerror(errno));
703 		return(-1);
704 	}
705 
706 	buffer_init(&msg);
707 
708 	/* Send open request */
709 	id = msg_id++;
710 	buffer_put_char(&msg, SSH2_FXP_OPEN);
711 	buffer_put_int(&msg, id);
712 	buffer_put_cstring(&msg, remote_path);
713 	buffer_put_int(&msg, SSH2_FXF_READ);
714 	attrib_clear(&junk); /* Send empty attributes */
715 	encode_attrib(&msg, &junk);
716 	send_msg(fd_out, &msg);
717 	debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
718 
719 	handle = get_handle(fd_in, id, &handle_len);
720 	if (handle == NULL) {
721 		buffer_free(&msg);
722 		close(local_fd);
723 		return(-1);
724 	}
725 
726 	/* Read from remote and write to local */
727 	offset = 0;
728 	for (;;) {
729 		u_int len;
730 		char *data;
731 
732 		id = expected_id = msg_id++;
733 
734 		buffer_clear(&msg);
735 		buffer_put_char(&msg, SSH2_FXP_READ);
736 		buffer_put_int(&msg, id);
737 		buffer_put_string(&msg, handle, handle_len);
738 		buffer_put_int64(&msg, offset);
739 		buffer_put_int(&msg, COPY_SIZE);
740 		send_msg(fd_out, &msg);
741 		debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
742 		    id, (unsigned long long)offset, COPY_SIZE);
743 
744 		buffer_clear(&msg);
745 
746 		get_msg(fd_in, &msg);
747 		type = buffer_get_char(&msg);
748 		id = buffer_get_int(&msg);
749 		debug3("Received reply T:%d I:%d", type, id);
750 		if (id != expected_id)
751 			fatal("ID mismatch (%d != %d)", id, expected_id);
752 		if (type == SSH2_FXP_STATUS) {
753 			status = buffer_get_int(&msg);
754 
755 			if (status == SSH2_FX_EOF)
756 				break;
757 			else {
758 				error("Couldn't read from remote "
759 				    "file \"%s\" : %s", remote_path,
760 				    fx2txt(status));
761 				do_close(fd_in, fd_out, handle, handle_len);
762 				goto done;
763 			}
764 		} else if (type != SSH2_FXP_DATA) {
765 			fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
766 			    SSH2_FXP_DATA, type);
767 		}
768 
769 		data = buffer_get_string(&msg, &len);
770 		if (len > COPY_SIZE)
771 			fatal("Received more data than asked for %d > %d",
772 			    len, COPY_SIZE);
773 
774 		debug3("In read loop, got %d offset %llu", len,
775 		    (unsigned long long)offset);
776 		if (atomicio(write, local_fd, data, len) != len) {
777 			error("Couldn't write to \"%s\": %s", local_path,
778 			    strerror(errno));
779 			do_close(fd_in, fd_out, handle, handle_len);
780 			status = -1;
781 			xfree(data);
782 			goto done;
783 		}
784 
785 		offset += len;
786 		xfree(data);
787 	}
788 	status = do_close(fd_in, fd_out, handle, handle_len);
789 
790 	/* Override umask and utimes if asked */
791 	if (pflag && fchmod(local_fd, mode) == -1)
792 		error("Couldn't set mode on \"%s\": %s", local_path,
793 		    strerror(errno));
794 	if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
795 		struct timeval tv[2];
796 		tv[0].tv_sec = a->atime;
797 		tv[1].tv_sec = a->mtime;
798 		tv[0].tv_usec = tv[1].tv_usec = 0;
799 		if (utimes(local_path, tv) == -1)
800 			error("Can't set times on \"%s\": %s", local_path,
801 			    strerror(errno));
802 	}
803 
804 done:
805 	close(local_fd);
806 	buffer_free(&msg);
807 	xfree(handle);
808 	return status;
809 }
810 
811 int
812 do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
813     int pflag)
814 {
815 	int local_fd;
816 	u_int handle_len, id;
817 	u_int64_t offset;
818 	char *handle;
819 	Buffer msg;
820 	struct stat sb;
821 	Attrib a;
822 	int status;
823 
824 	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
825 		error("Couldn't open local file \"%s\" for reading: %s",
826 		    local_path, strerror(errno));
827 		return(-1);
828 	}
829 	if (fstat(local_fd, &sb) == -1) {
830 		error("Couldn't fstat local file \"%s\": %s",
831 		    local_path, strerror(errno));
832 		close(local_fd);
833 		return(-1);
834 	}
835 	stat_to_attrib(&sb, &a);
836 
837 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
838 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
839 	a.perm &= 0777;
840 	if (!pflag)
841 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
842 
843 	buffer_init(&msg);
844 
845 	/* Send open request */
846 	id = msg_id++;
847 	buffer_put_char(&msg, SSH2_FXP_OPEN);
848 	buffer_put_int(&msg, id);
849 	buffer_put_cstring(&msg, remote_path);
850 	buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
851 	encode_attrib(&msg, &a);
852 	send_msg(fd_out, &msg);
853 	debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
854 
855 	buffer_clear(&msg);
856 
857 	handle = get_handle(fd_in, id, &handle_len);
858 	if (handle == NULL) {
859 		close(local_fd);
860 		buffer_free(&msg);
861 		return(-1);
862 	}
863 
864 	/* Read from local and write to remote */
865 	offset = 0;
866 	for (;;) {
867 		int len;
868 		char data[COPY_SIZE];
869 
870 		/*
871 		 * Can't use atomicio here because it returns 0 on EOF, thus losing
872 		 * the last block of the file
873 		 */
874 		do
875 			len = read(local_fd, data, COPY_SIZE);
876 		while ((len == -1) && (errno == EINTR || errno == EAGAIN));
877 
878 		if (len == -1)
879 			fatal("Couldn't read from \"%s\": %s", local_path,
880 			    strerror(errno));
881 		if (len == 0)
882 			break;
883 
884 		buffer_clear(&msg);
885 		buffer_put_char(&msg, SSH2_FXP_WRITE);
886 		buffer_put_int(&msg, ++id);
887 		buffer_put_string(&msg, handle, handle_len);
888 		buffer_put_int64(&msg, offset);
889 		buffer_put_string(&msg, data, len);
890 		send_msg(fd_out, &msg);
891 		debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
892 		    id, (unsigned long long)offset, len);
893 
894 		status = get_status(fd_in, id);
895 		if (status != SSH2_FX_OK) {
896 			error("Couldn't write to remote file \"%s\": %s",
897 			    remote_path, fx2txt(status));
898 			do_close(fd_in, fd_out, handle, handle_len);
899 			close(local_fd);
900 			goto done;
901 		}
902 		debug3("In write loop, got %d offset %llu", len,
903 		    (unsigned long long)offset);
904 
905 		offset += len;
906 	}
907 
908 	if (close(local_fd) == -1) {
909 		error("Couldn't close local file \"%s\": %s", local_path,
910 		    strerror(errno));
911 		do_close(fd_in, fd_out, handle, handle_len);
912 		status = -1;
913 		goto done;
914 	}
915 
916 	/* Override umask and utimes if asked */
917 	if (pflag)
918 		do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
919 
920 	status = do_close(fd_in, fd_out, handle, handle_len);
921 
922 done:
923 	xfree(handle);
924 	buffer_free(&msg);
925 	return status;
926 }
927 
928