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