xref: /openbsd-src/usr.bin/ssh/sftp-client.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
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.18 2001/07/14 15:10:16 stevesk 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 
313 	for(;;) {
314 		int count;
315 
316 		id = expected_id = msg_id++;
317 
318 		debug3("Sending SSH2_FXP_READDIR I:%d", id);
319 
320 		buffer_clear(&msg);
321 		buffer_put_char(&msg, SSH2_FXP_READDIR);
322 		buffer_put_int(&msg, id);
323 		buffer_put_string(&msg, handle, handle_len);
324 		send_msg(fd_out, &msg);
325 
326 		buffer_clear(&msg);
327 
328 		get_msg(fd_in, &msg);
329 
330 		type = buffer_get_char(&msg);
331 		id = buffer_get_int(&msg);
332 
333 		debug3("Received reply T:%d I:%d", type, id);
334 
335 		if (id != expected_id)
336 			fatal("ID mismatch (%d != %d)", id, expected_id);
337 
338 		if (type == SSH2_FXP_STATUS) {
339 			int status = buffer_get_int(&msg);
340 
341 			debug3("Received SSH2_FXP_STATUS %d", status);
342 
343 			if (status == SSH2_FX_EOF) {
344 				break;
345 			} else {
346 				error("Couldn't read directory: %s",
347 				    fx2txt(status));
348 				do_close(fd_in, fd_out, handle, handle_len);
349 				return(status);
350 			}
351 		} else if (type != SSH2_FXP_NAME)
352 			fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
353 			    SSH2_FXP_NAME, type);
354 
355 		count = buffer_get_int(&msg);
356 		if (count == 0)
357 			break;
358 		debug3("Received %d SSH2_FXP_NAME responses", count);
359 		for(i = 0; i < count; i++) {
360 			char *filename, *longname;
361 			Attrib *a;
362 
363 			filename = buffer_get_string(&msg, NULL);
364 			longname = buffer_get_string(&msg, NULL);
365 			a = decode_attrib(&msg);
366 
367 			if (printflag)
368 				printf("%s\n", longname);
369 
370 			if (dir) {
371 				*dir = xrealloc(*dir, sizeof(**dir) *
372 				    (ents + 2));
373 				(*dir)[ents] = xmalloc(sizeof(***dir));
374 				(*dir)[ents]->filename = xstrdup(filename);
375 				(*dir)[ents]->longname = xstrdup(longname);
376 				memcpy(&(*dir)[ents]->a, a, sizeof(*a));
377 				(*dir)[++ents] = NULL;
378 			}
379 
380 			xfree(filename);
381 			xfree(longname);
382 		}
383 	}
384 
385 	buffer_free(&msg);
386 	do_close(fd_in, fd_out, handle, handle_len);
387 	xfree(handle);
388 
389 	return(0);
390 }
391 
392 int
393 do_ls(int fd_in, int fd_out, char *path)
394 {
395 	return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
396 }
397 
398 int
399 do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
400 {
401 	return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
402 }
403 
404 void free_sftp_dirents(SFTP_DIRENT **s)
405 {
406 	int i;
407 
408 	for(i = 0; s[i]; i++) {
409 		xfree(s[i]->filename);
410 		xfree(s[i]->longname);
411 		xfree(s[i]);
412 	}
413 	xfree(s);
414 }
415 
416 int
417 do_rm(int fd_in, int fd_out, char *path)
418 {
419 	u_int status, id;
420 
421 	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
422 
423 	id = msg_id++;
424 	send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
425 	status = get_status(fd_in, id);
426 	if (status != SSH2_FX_OK)
427 		error("Couldn't delete file: %s", fx2txt(status));
428 	return(status);
429 }
430 
431 int
432 do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
433 {
434 	u_int status, id;
435 
436 	id = msg_id++;
437 	send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
438 	    strlen(path), a);
439 
440 	status = get_status(fd_in, id);
441 	if (status != SSH2_FX_OK)
442 		error("Couldn't create directory: %s", fx2txt(status));
443 
444 	return(status);
445 }
446 
447 int
448 do_rmdir(int fd_in, int fd_out, char *path)
449 {
450 	u_int status, id;
451 
452 	id = msg_id++;
453 	send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
454 
455 	status = get_status(fd_in, id);
456 	if (status != SSH2_FX_OK)
457 		error("Couldn't remove directory: %s", fx2txt(status));
458 
459 	return(status);
460 }
461 
462 Attrib *
463 do_stat(int fd_in, int fd_out, char *path, int quiet)
464 {
465 	u_int id;
466 
467 	id = msg_id++;
468 	send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
469 	return(get_decode_stat(fd_in, id, quiet));
470 }
471 
472 Attrib *
473 do_lstat(int fd_in, int fd_out, char *path, int quiet)
474 {
475 	u_int id;
476 
477 	id = msg_id++;
478 	send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
479 	return(get_decode_stat(fd_in, id, quiet));
480 }
481 
482 Attrib *
483 do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
484 {
485 	u_int id;
486 
487 	id = msg_id++;
488 	send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
489 	return(get_decode_stat(fd_in, id, quiet));
490 }
491 
492 int
493 do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
494 {
495 	u_int status, id;
496 
497 	id = msg_id++;
498 	send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
499 	    strlen(path), a);
500 
501 	status = get_status(fd_in, id);
502 	if (status != SSH2_FX_OK)
503 		error("Couldn't setstat on \"%s\": %s", path,
504 		    fx2txt(status));
505 
506 	return(status);
507 }
508 
509 int
510 do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
511     Attrib *a)
512 {
513 	u_int status, id;
514 
515 	id = msg_id++;
516 	send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
517 	    handle_len, a);
518 
519 	status = get_status(fd_in, id);
520 	if (status != SSH2_FX_OK)
521 		error("Couldn't fsetstat: %s", fx2txt(status));
522 
523 	return(status);
524 }
525 
526 char *
527 do_realpath(int fd_in, int fd_out, char *path)
528 {
529 	Buffer msg;
530 	u_int type, expected_id, count, id;
531 	char *filename, *longname;
532 	Attrib *a;
533 
534 	expected_id = id = msg_id++;
535 	send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
536 
537 	buffer_init(&msg);
538 
539 	get_msg(fd_in, &msg);
540 	type = buffer_get_char(&msg);
541 	id = buffer_get_int(&msg);
542 
543 	if (id != expected_id)
544 		fatal("ID mismatch (%d != %d)", id, expected_id);
545 
546 	if (type == SSH2_FXP_STATUS) {
547 		u_int status = buffer_get_int(&msg);
548 
549 		error("Couldn't canonicalise: %s", fx2txt(status));
550 		return(NULL);
551 	} else if (type != SSH2_FXP_NAME)
552 		fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
553 		    SSH2_FXP_NAME, type);
554 
555 	count = buffer_get_int(&msg);
556 	if (count != 1)
557 		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
558 
559 	filename = buffer_get_string(&msg, NULL);
560 	longname = buffer_get_string(&msg, NULL);
561 	a = decode_attrib(&msg);
562 
563 	debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
564 
565 	xfree(longname);
566 
567 	buffer_free(&msg);
568 
569 	return(filename);
570 }
571 
572 int
573 do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
574 {
575 	Buffer msg;
576 	u_int status, id;
577 
578 	buffer_init(&msg);
579 
580 	/* Send rename request */
581 	id = msg_id++;
582 	buffer_put_char(&msg, SSH2_FXP_RENAME);
583 	buffer_put_int(&msg, id);
584 	buffer_put_cstring(&msg, oldpath);
585 	buffer_put_cstring(&msg, newpath);
586 	send_msg(fd_out, &msg);
587 	debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
588 	    newpath);
589 	buffer_free(&msg);
590 
591 	status = get_status(fd_in, id);
592 	if (status != SSH2_FX_OK)
593 		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
594 		    fx2txt(status));
595 
596 	return(status);
597 }
598 
599 int
600 do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
601 {
602 	Buffer msg;
603 	u_int status, id;
604 
605 	buffer_init(&msg);
606 
607 	/* Send rename request */
608 	id = msg_id++;
609 	buffer_put_char(&msg, SSH2_FXP_SYMLINK);
610 	buffer_put_int(&msg, id);
611 	buffer_put_cstring(&msg, oldpath);
612 	buffer_put_cstring(&msg, newpath);
613 	send_msg(fd_out, &msg);
614 	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
615 	    newpath);
616 	buffer_free(&msg);
617 
618 	status = get_status(fd_in, id);
619 	if (status != SSH2_FX_OK)
620 		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
621 		    fx2txt(status));
622 
623 	return(status);
624 }
625 
626 char *
627 do_readlink(int fd_in, int fd_out, char *path)
628 {
629 	Buffer msg;
630 	u_int type, expected_id, count, id;
631 	char *filename, *longname;
632 	Attrib *a;
633 
634 	expected_id = id = msg_id++;
635 	send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
636 
637 	buffer_init(&msg);
638 
639 	get_msg(fd_in, &msg);
640 	type = buffer_get_char(&msg);
641 	id = buffer_get_int(&msg);
642 
643 	if (id != expected_id)
644 		fatal("ID mismatch (%d != %d)", id, expected_id);
645 
646 	if (type == SSH2_FXP_STATUS) {
647 		u_int status = buffer_get_int(&msg);
648 
649 		error("Couldn't readlink: %s", fx2txt(status));
650 		return(NULL);
651 	} else if (type != SSH2_FXP_NAME)
652 		fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
653 		    SSH2_FXP_NAME, type);
654 
655 	count = buffer_get_int(&msg);
656 	if (count != 1)
657 		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
658 
659 	filename = buffer_get_string(&msg, NULL);
660 	longname = buffer_get_string(&msg, NULL);
661 	a = decode_attrib(&msg);
662 
663 	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
664 
665 	xfree(longname);
666 
667 	buffer_free(&msg);
668 
669 	return(filename);
670 }
671 
672 int
673 do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
674     int pflag)
675 {
676 	int local_fd;
677 	u_int expected_id, handle_len, mode, type, id;
678 	u_int64_t offset;
679 	char *handle;
680 	Buffer msg;
681 	Attrib junk, *a;
682 	int status;
683 
684 	a = do_stat(fd_in, fd_out, remote_path, 0);
685 	if (a == NULL)
686 		return(-1);
687 
688 	/* XXX: should we preserve set[ug]id? */
689 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
690 		mode = S_IWRITE | (a->perm & 0777);
691 	else
692 		mode = 0666;
693 
694 	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
695 	    (a->perm & S_IFDIR)) {
696 		error("Cannot download a directory: %s", remote_path);
697 		return(-1);
698 	}
699 
700 	local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
701 	if (local_fd == -1) {
702 		error("Couldn't open local file \"%s\" for writing: %s",
703 		    local_path, strerror(errno));
704 		return(-1);
705 	}
706 
707 	buffer_init(&msg);
708 
709 	/* Send open request */
710 	id = msg_id++;
711 	buffer_put_char(&msg, SSH2_FXP_OPEN);
712 	buffer_put_int(&msg, id);
713 	buffer_put_cstring(&msg, remote_path);
714 	buffer_put_int(&msg, SSH2_FXF_READ);
715 	attrib_clear(&junk); /* Send empty attributes */
716 	encode_attrib(&msg, &junk);
717 	send_msg(fd_out, &msg);
718 	debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
719 
720 	handle = get_handle(fd_in, id, &handle_len);
721 	if (handle == NULL) {
722 		buffer_free(&msg);
723 		close(local_fd);
724 		return(-1);
725 	}
726 
727 	/* Read from remote and write to local */
728 	offset = 0;
729 	for(;;) {
730 		u_int len;
731 		char *data;
732 
733 		id = expected_id = msg_id++;
734 
735 		buffer_clear(&msg);
736 		buffer_put_char(&msg, SSH2_FXP_READ);
737 		buffer_put_int(&msg, id);
738 		buffer_put_string(&msg, handle, handle_len);
739 		buffer_put_int64(&msg, offset);
740 		buffer_put_int(&msg, COPY_SIZE);
741 		send_msg(fd_out, &msg);
742 		debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
743 		    id, (unsigned long long)offset, COPY_SIZE);
744 
745 		buffer_clear(&msg);
746 
747 		get_msg(fd_in, &msg);
748 		type = buffer_get_char(&msg);
749 		id = buffer_get_int(&msg);
750 		debug3("Received reply T:%d I:%d", type, id);
751 		if (id != expected_id)
752 			fatal("ID mismatch (%d != %d)", id, expected_id);
753 		if (type == SSH2_FXP_STATUS) {
754 			status = buffer_get_int(&msg);
755 
756 			if (status == SSH2_FX_EOF)
757 				break;
758 			else {
759 				error("Couldn't read from remote "
760 				    "file \"%s\" : %s", remote_path,
761 				     fx2txt(status));
762 				do_close(fd_in, fd_out, handle, handle_len);
763 				goto done;
764 			}
765 		} else if (type != SSH2_FXP_DATA) {
766 			fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
767 			    SSH2_FXP_DATA, type);
768 		}
769 
770 		data = buffer_get_string(&msg, &len);
771 		if (len > COPY_SIZE)
772 			fatal("Received more data than asked for %d > %d",
773 			    len, COPY_SIZE);
774 
775 		debug3("In read loop, got %d offset %llu", len,
776 		    (unsigned long long)offset);
777 		if (atomicio(write, local_fd, data, len) != len) {
778 			error("Couldn't write to \"%s\": %s", local_path,
779 			    strerror(errno));
780 			do_close(fd_in, fd_out, handle, handle_len);
781 			status = -1;
782 			xfree(data);
783 			goto done;
784 		}
785 
786 		offset += len;
787 		xfree(data);
788 	}
789 	status = do_close(fd_in, fd_out, handle, handle_len);
790 
791 	/* Override umask and utimes if asked */
792 	if (pflag && fchmod(local_fd, mode) == -1)
793 		error("Couldn't set mode on \"%s\": %s", local_path,
794 		    strerror(errno));
795 	if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
796 		struct timeval tv[2];
797 		tv[0].tv_sec = a->atime;
798 		tv[1].tv_sec = a->mtime;
799 		tv[0].tv_usec = tv[1].tv_usec = 0;
800 		if (utimes(local_path, tv) == -1)
801 			error("Can't set times on \"%s\": %s", local_path,
802 			    strerror(errno));
803 	}
804 
805 done:
806 	close(local_fd);
807 	buffer_free(&msg);
808 	xfree(handle);
809 	return status;
810 }
811 
812 int
813 do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
814     int pflag)
815 {
816 	int local_fd;
817 	u_int handle_len, id;
818 	u_int64_t offset;
819 	char *handle;
820 	Buffer msg;
821 	struct stat sb;
822 	Attrib a;
823 	int status;
824 
825 	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
826 		error("Couldn't open local file \"%s\" for reading: %s",
827 		    local_path, strerror(errno));
828 		return(-1);
829 	}
830 	if (fstat(local_fd, &sb) == -1) {
831 		error("Couldn't fstat local file \"%s\": %s",
832 		    local_path, strerror(errno));
833 		close(local_fd);
834 		return(-1);
835 	}
836 	stat_to_attrib(&sb, &a);
837 
838 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
839 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
840 	a.perm &= 0777;
841 	if (!pflag)
842 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
843 
844 	buffer_init(&msg);
845 
846 	/* Send open request */
847 	id = msg_id++;
848 	buffer_put_char(&msg, SSH2_FXP_OPEN);
849 	buffer_put_int(&msg, id);
850 	buffer_put_cstring(&msg, remote_path);
851 	buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
852 	encode_attrib(&msg, &a);
853 	send_msg(fd_out, &msg);
854 	debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
855 
856 	buffer_clear(&msg);
857 
858 	handle = get_handle(fd_in, id, &handle_len);
859 	if (handle == NULL) {
860 		close(local_fd);
861 		buffer_free(&msg);
862 		return(-1);
863 	}
864 
865 	/* Read from local and write to remote */
866 	offset = 0;
867 	for(;;) {
868 		int len;
869 		char data[COPY_SIZE];
870 
871 		/*
872 		 * Can't use atomicio here because it returns 0 on EOF, thus losing
873 		 * the last block of the file
874 		 */
875 		do
876 			len = read(local_fd, data, COPY_SIZE);
877 		while ((len == -1) && (errno == EINTR || errno == EAGAIN));
878 
879 		if (len == -1)
880 			fatal("Couldn't read from \"%s\": %s", local_path,
881 			    strerror(errno));
882 		if (len == 0)
883 			break;
884 
885 		buffer_clear(&msg);
886 		buffer_put_char(&msg, SSH2_FXP_WRITE);
887 		buffer_put_int(&msg, ++id);
888 		buffer_put_string(&msg, handle, handle_len);
889 		buffer_put_int64(&msg, offset);
890 		buffer_put_string(&msg, data, len);
891 		send_msg(fd_out, &msg);
892 		debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
893 		    id, (unsigned long long)offset, len);
894 
895 		status = get_status(fd_in, id);
896 		if (status != SSH2_FX_OK) {
897 			error("Couldn't write to remote file \"%s\": %s",
898 			    remote_path, fx2txt(status));
899 			do_close(fd_in, fd_out, handle, handle_len);
900 			close(local_fd);
901 			goto done;
902 		}
903 		debug3("In write loop, got %d offset %llu", len,
904 		    (unsigned long long)offset);
905 
906 		offset += len;
907 	}
908 
909 	if (close(local_fd) == -1) {
910 		error("Couldn't close local file \"%s\": %s", local_path,
911 		    strerror(errno));
912 		do_close(fd_in, fd_out, handle, handle_len);
913 		status = -1;
914 		goto done;
915 	}
916 
917 	/* Override umask and utimes if asked */
918 	if (pflag)
919 		do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
920 
921 	status = do_close(fd_in, fd_out, handle, handle_len);
922 
923 done:
924 	xfree(handle);
925 	buffer_free(&msg);
926 	return status;
927 }
928 
929