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