1 /* $OpenBSD: sftp-client.c,v 1.93 2010/09/22 22:58:51 djm Exp $ */
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 /* XXX: signed vs unsigned */
20 /* XXX: remove all logging, only return status codes */
21 /* XXX: copy between two remote sites */
25 #include <sys/types.h>
26 #include <sys/param.h>
27 #ifdef HAVE_SYS_STATVFS_H
28 #include <sys/statvfs.h>
30 #include "openbsd-compat/sys-queue.h"
31 #ifdef HAVE_SYS_STAT_H
32 # include <sys/stat.h>
34 #ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
52 #include "progressmeter.h"
56 #include "sftp-common.h"
57 #include "sftp-client.h"
59 extern volatile sig_atomic_t interrupted
;
60 extern int showprogress
;
62 /* Minimum amount of data to read at a time */
63 #define MIN_READ_SIZE 512
65 /* Maximum depth to descend in directory trees */
66 #define MAX_DIR_DEPTH 64
71 u_int transfer_buflen
;
75 #define SFTP_EXT_POSIX_RENAME 0x00000001
76 #define SFTP_EXT_STATVFS 0x00000002
77 #define SFTP_EXT_FSTATVFS 0x00000004
80 struct bwlimit bwlimit_in
, bwlimit_out
;
84 get_handle(struct sftp_conn
*conn
, u_int expected_id
, u_int
*len
,
85 const char *errfmt
, ...) __attribute__((format(printf
, 4, 5)));
89 sftpio(void *_bwlimit
, size_t amount
)
91 struct bwlimit
*bwlimit
= (struct bwlimit
*)_bwlimit
;
93 bandwidth_limit(bwlimit
, amount
);
98 send_msg(struct sftp_conn
*conn
, Buffer
*m
)
103 if (buffer_len(m
) > SFTP_MAX_MSG_LENGTH
)
104 fatal("Outbound message too long %u", buffer_len(m
));
106 /* Send length first */
107 put_u32(mlen
, buffer_len(m
));
108 iov
[0].iov_base
= mlen
;
109 iov
[0].iov_len
= sizeof(mlen
);
110 iov
[1].iov_base
= buffer_ptr(m
);
111 iov
[1].iov_len
= buffer_len(m
);
113 if (atomiciov6(writev
, conn
->fd_out
, iov
, 2,
114 conn
->limit_kbps
> 0 ? sftpio
: NULL
, &conn
->bwlimit_out
) !=
115 buffer_len(m
) + sizeof(mlen
))
116 fatal("Couldn't send packet: %s", strerror(errno
));
122 get_msg(struct sftp_conn
*conn
, Buffer
*m
)
126 buffer_append_space(m
, 4);
127 if (atomicio6(read
, conn
->fd_in
, buffer_ptr(m
), 4,
128 conn
->limit_kbps
> 0 ? sftpio
: NULL
, &conn
->bwlimit_in
) != 4) {
130 fatal("Connection closed");
132 fatal("Couldn't read packet: %s", strerror(errno
));
135 msg_len
= buffer_get_int(m
);
136 if (msg_len
> SFTP_MAX_MSG_LENGTH
)
137 fatal("Received message too long %u", msg_len
);
139 buffer_append_space(m
, msg_len
);
140 if (atomicio6(read
, conn
->fd_in
, buffer_ptr(m
), msg_len
,
141 conn
->limit_kbps
> 0 ? sftpio
: NULL
, &conn
->bwlimit_in
)
144 fatal("Connection closed");
146 fatal("Read packet: %s", strerror(errno
));
151 send_string_request(struct sftp_conn
*conn
, u_int id
, u_int code
, char *s
,
157 buffer_put_char(&msg
, code
);
158 buffer_put_int(&msg
, id
);
159 buffer_put_string(&msg
, s
, len
);
160 send_msg(conn
, &msg
);
161 debug3("Sent message fd %d T:%u I:%u", conn
->fd_out
, code
, id
);
166 send_string_attrs_request(struct sftp_conn
*conn
, u_int id
, u_int code
,
167 char *s
, u_int len
, Attrib
*a
)
172 buffer_put_char(&msg
, code
);
173 buffer_put_int(&msg
, id
);
174 buffer_put_string(&msg
, s
, len
);
175 encode_attrib(&msg
, a
);
176 send_msg(conn
, &msg
);
177 debug3("Sent message fd %d T:%u I:%u", conn
->fd_out
, code
, id
);
182 get_status(struct sftp_conn
*conn
, u_int expected_id
)
185 u_int type
, id
, status
;
189 type
= buffer_get_char(&msg
);
190 id
= buffer_get_int(&msg
);
192 if (id
!= expected_id
)
193 fatal("ID mismatch (%u != %u)", id
, expected_id
);
194 if (type
!= SSH2_FXP_STATUS
)
195 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
196 SSH2_FXP_STATUS
, type
);
198 status
= buffer_get_int(&msg
);
201 debug3("SSH2_FXP_STATUS %u", status
);
207 get_handle(struct sftp_conn
*conn
, u_int expected_id
, u_int
*len
,
208 const char *errfmt
, ...)
212 char *handle
, errmsg
[256];
216 va_start(args
, errfmt
);
218 vsnprintf(errmsg
, sizeof(errmsg
), errfmt
, args
);
223 type
= buffer_get_char(&msg
);
224 id
= buffer_get_int(&msg
);
226 if (id
!= expected_id
)
227 fatal("%s: ID mismatch (%u != %u)",
228 errfmt
== NULL
? __func__
: errmsg
, id
, expected_id
);
229 if (type
== SSH2_FXP_STATUS
) {
230 status
= buffer_get_int(&msg
);
232 error("%s: %s", errmsg
, fx2txt(status
));
235 } else if (type
!= SSH2_FXP_HANDLE
)
236 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
237 errfmt
== NULL
? __func__
: errmsg
, SSH2_FXP_HANDLE
, type
);
239 handle
= buffer_get_string(&msg
, len
);
246 get_decode_stat(struct sftp_conn
*conn
, u_int expected_id
, int quiet
)
255 type
= buffer_get_char(&msg
);
256 id
= buffer_get_int(&msg
);
258 debug3("Received stat reply T:%u I:%u", type
, id
);
259 if (id
!= expected_id
)
260 fatal("ID mismatch (%u != %u)", id
, expected_id
);
261 if (type
== SSH2_FXP_STATUS
) {
262 int status
= buffer_get_int(&msg
);
265 debug("Couldn't stat remote file: %s", fx2txt(status
));
267 error("Couldn't stat remote file: %s", fx2txt(status
));
270 } else if (type
!= SSH2_FXP_ATTRS
) {
271 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
272 SSH2_FXP_ATTRS
, type
);
274 a
= decode_attrib(&msg
);
281 get_decode_statvfs(struct sftp_conn
*conn
, struct sftp_statvfs
*st
,
282 u_int expected_id
, int quiet
)
285 u_int type
, id
, flag
;
290 type
= buffer_get_char(&msg
);
291 id
= buffer_get_int(&msg
);
293 debug3("Received statvfs reply T:%u I:%u", type
, id
);
294 if (id
!= expected_id
)
295 fatal("ID mismatch (%u != %u)", id
, expected_id
);
296 if (type
== SSH2_FXP_STATUS
) {
297 int status
= buffer_get_int(&msg
);
300 debug("Couldn't statvfs: %s", fx2txt(status
));
302 error("Couldn't statvfs: %s", fx2txt(status
));
305 } else if (type
!= SSH2_FXP_EXTENDED_REPLY
) {
306 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
307 SSH2_FXP_EXTENDED_REPLY
, type
);
310 bzero(st
, sizeof(*st
));
311 st
->f_bsize
= buffer_get_int64(&msg
);
312 st
->f_frsize
= buffer_get_int64(&msg
);
313 st
->f_blocks
= buffer_get_int64(&msg
);
314 st
->f_bfree
= buffer_get_int64(&msg
);
315 st
->f_bavail
= buffer_get_int64(&msg
);
316 st
->f_files
= buffer_get_int64(&msg
);
317 st
->f_ffree
= buffer_get_int64(&msg
);
318 st
->f_favail
= buffer_get_int64(&msg
);
319 st
->f_fsid
= buffer_get_int64(&msg
);
320 flag
= buffer_get_int64(&msg
);
321 st
->f_namemax
= buffer_get_int64(&msg
);
323 st
->f_flag
= (flag
& SSH2_FXE_STATVFS_ST_RDONLY
) ? ST_RDONLY
: 0;
324 st
->f_flag
|= (flag
& SSH2_FXE_STATVFS_ST_NOSUID
) ? ST_NOSUID
: 0;
332 do_init(int fd_in
, int fd_out
, u_int transfer_buflen
, u_int num_requests
,
333 u_int64_t limit_kbps
)
337 struct sftp_conn
*ret
;
339 ret
= xmalloc(sizeof(*ret
));
341 ret
->fd_out
= fd_out
;
342 ret
->transfer_buflen
= transfer_buflen
;
343 ret
->num_requests
= num_requests
;
348 buffer_put_char(&msg
, SSH2_FXP_INIT
);
349 buffer_put_int(&msg
, SSH2_FILEXFER_VERSION
);
356 /* Expecting a VERSION reply */
357 if ((type
= buffer_get_char(&msg
)) != SSH2_FXP_VERSION
) {
358 error("Invalid packet back from SSH2_FXP_INIT (type %u)",
363 ret
->version
= buffer_get_int(&msg
);
365 debug2("Remote version: %u", ret
->version
);
367 /* Check for extensions */
368 while (buffer_len(&msg
) > 0) {
369 char *name
= buffer_get_string(&msg
, NULL
);
370 char *value
= buffer_get_string(&msg
, NULL
);
373 if (strcmp(name
, "posix-rename@openssh.com") == 0 &&
374 strcmp(value
, "1") == 0) {
375 ret
->exts
|= SFTP_EXT_POSIX_RENAME
;
377 } else if (strcmp(name
, "statvfs@openssh.com") == 0 &&
378 strcmp(value
, "2") == 0) {
379 ret
->exts
|= SFTP_EXT_STATVFS
;
381 } if (strcmp(name
, "fstatvfs@openssh.com") == 0 &&
382 strcmp(value
, "2") == 0) {
383 ret
->exts
|= SFTP_EXT_FSTATVFS
;
387 debug2("Server supports extension \"%s\" revision %s",
390 debug2("Unrecognised server extension \"%s\"", name
);
398 /* Some filexfer v.0 servers don't support large packets */
399 if (ret
->version
== 0)
400 ret
->transfer_buflen
= MIN(ret
->transfer_buflen
, 20480);
402 ret
->limit_kbps
= limit_kbps
;
403 if (ret
->limit_kbps
> 0) {
404 bandwidth_limit_init(&ret
->bwlimit_in
, ret
->limit_kbps
,
405 ret
->transfer_buflen
);
406 bandwidth_limit_init(&ret
->bwlimit_out
, ret
->limit_kbps
,
407 ret
->transfer_buflen
);
414 sftp_proto_version(struct sftp_conn
*conn
)
416 return conn
->version
;
420 do_close(struct sftp_conn
*conn
, char *handle
, u_int handle_len
)
428 buffer_put_char(&msg
, SSH2_FXP_CLOSE
);
429 buffer_put_int(&msg
, id
);
430 buffer_put_string(&msg
, handle
, handle_len
);
431 send_msg(conn
, &msg
);
432 debug3("Sent message SSH2_FXP_CLOSE I:%u", id
);
434 status
= get_status(conn
, id
);
435 if (status
!= SSH2_FX_OK
)
436 error("Couldn't close file: %s", fx2txt(status
));
445 do_lsreaddir(struct sftp_conn
*conn
, char *path
, int printflag
,
449 u_int count
, type
, id
, handle_len
, i
, expected_id
, ents
= 0;
455 buffer_put_char(&msg
, SSH2_FXP_OPENDIR
);
456 buffer_put_int(&msg
, id
);
457 buffer_put_cstring(&msg
, path
);
458 send_msg(conn
, &msg
);
462 handle
= get_handle(conn
, id
, &handle_len
,
463 "remote readdir(\"%s\")", path
);
469 *dir
= xmalloc(sizeof(**dir
));
473 for (; !interrupted
;) {
474 id
= expected_id
= conn
->msg_id
++;
476 debug3("Sending SSH2_FXP_READDIR I:%u", id
);
479 buffer_put_char(&msg
, SSH2_FXP_READDIR
);
480 buffer_put_int(&msg
, id
);
481 buffer_put_string(&msg
, handle
, handle_len
);
482 send_msg(conn
, &msg
);
488 type
= buffer_get_char(&msg
);
489 id
= buffer_get_int(&msg
);
491 debug3("Received reply T:%u I:%u", type
, id
);
493 if (id
!= expected_id
)
494 fatal("ID mismatch (%u != %u)", id
, expected_id
);
496 if (type
== SSH2_FXP_STATUS
) {
497 int status
= buffer_get_int(&msg
);
499 debug3("Received SSH2_FXP_STATUS %d", status
);
501 if (status
== SSH2_FX_EOF
) {
504 error("Couldn't read directory: %s",
506 do_close(conn
, handle
, handle_len
);
510 } else if (type
!= SSH2_FXP_NAME
)
511 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
512 SSH2_FXP_NAME
, type
);
514 count
= buffer_get_int(&msg
);
517 debug3("Received %d SSH2_FXP_NAME responses", count
);
518 for (i
= 0; i
< count
; i
++) {
519 char *filename
, *longname
;
522 filename
= buffer_get_string(&msg
, NULL
);
523 longname
= buffer_get_string(&msg
, NULL
);
524 a
= decode_attrib(&msg
);
527 printf("%s\n", longname
);
530 * Directory entries should never contain '/'
531 * These can be used to attack recursive ops
532 * (e.g. send '../../../../etc/passwd')
534 if (strchr(filename
, '/') != NULL
) {
535 error("Server sent suspect path \"%s\" "
536 "during readdir of \"%s\"", filename
, path
);
541 *dir
= xrealloc(*dir
, ents
+ 2, sizeof(**dir
));
542 (*dir
)[ents
] = xmalloc(sizeof(***dir
));
543 (*dir
)[ents
]->filename
= xstrdup(filename
);
544 (*dir
)[ents
]->longname
= xstrdup(longname
);
545 memcpy(&(*dir
)[ents
]->a
, a
, sizeof(*a
));
546 (*dir
)[++ents
] = NULL
;
555 do_close(conn
, handle
, handle_len
);
558 /* Don't return partial matches on interrupt */
559 if (interrupted
&& dir
!= NULL
&& *dir
!= NULL
) {
560 free_sftp_dirents(*dir
);
561 *dir
= xmalloc(sizeof(**dir
));
569 do_readdir(struct sftp_conn
*conn
, char *path
, SFTP_DIRENT
***dir
)
571 return(do_lsreaddir(conn
, path
, 0, dir
));
574 void free_sftp_dirents(SFTP_DIRENT
**s
)
578 for (i
= 0; s
[i
]; i
++) {
579 xfree(s
[i
]->filename
);
580 xfree(s
[i
]->longname
);
587 do_rm(struct sftp_conn
*conn
, char *path
)
591 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path
);
594 send_string_request(conn
, id
, SSH2_FXP_REMOVE
, path
, strlen(path
));
595 status
= get_status(conn
, id
);
596 if (status
!= SSH2_FX_OK
)
597 error("Couldn't delete file: %s", fx2txt(status
));
602 do_mkdir(struct sftp_conn
*conn
, char *path
, Attrib
*a
, int printflag
)
607 send_string_attrs_request(conn
, id
, SSH2_FXP_MKDIR
, path
,
610 status
= get_status(conn
, id
);
611 if (status
!= SSH2_FX_OK
&& printflag
)
612 error("Couldn't create directory: %s", fx2txt(status
));
618 do_rmdir(struct sftp_conn
*conn
, char *path
)
623 send_string_request(conn
, id
, SSH2_FXP_RMDIR
, path
,
626 status
= get_status(conn
, id
);
627 if (status
!= SSH2_FX_OK
)
628 error("Couldn't remove directory: %s", fx2txt(status
));
634 do_stat(struct sftp_conn
*conn
, char *path
, int quiet
)
640 send_string_request(conn
, id
,
641 conn
->version
== 0 ? SSH2_FXP_STAT_VERSION_0
: SSH2_FXP_STAT
,
644 return(get_decode_stat(conn
, id
, quiet
));
648 do_lstat(struct sftp_conn
*conn
, char *path
, int quiet
)
652 if (conn
->version
== 0) {
654 debug("Server version does not support lstat operation");
656 logit("Server version does not support lstat operation");
657 return(do_stat(conn
, path
, quiet
));
661 send_string_request(conn
, id
, SSH2_FXP_LSTAT
, path
,
664 return(get_decode_stat(conn
, id
, quiet
));
669 do_fstat(struct sftp_conn
*conn
, char *handle
, u_int handle_len
, int quiet
)
674 send_string_request(conn
, id
, SSH2_FXP_FSTAT
, handle
,
677 return(get_decode_stat(conn
, id
, quiet
));
682 do_setstat(struct sftp_conn
*conn
, char *path
, Attrib
*a
)
687 send_string_attrs_request(conn
, id
, SSH2_FXP_SETSTAT
, path
,
690 status
= get_status(conn
, id
);
691 if (status
!= SSH2_FX_OK
)
692 error("Couldn't setstat on \"%s\": %s", path
,
699 do_fsetstat(struct sftp_conn
*conn
, char *handle
, u_int handle_len
,
705 send_string_attrs_request(conn
, id
, SSH2_FXP_FSETSTAT
, handle
,
708 status
= get_status(conn
, id
);
709 if (status
!= SSH2_FX_OK
)
710 error("Couldn't fsetstat: %s", fx2txt(status
));
716 do_realpath(struct sftp_conn
*conn
, char *path
)
719 u_int type
, expected_id
, count
, id
;
720 char *filename
, *longname
;
723 expected_id
= id
= conn
->msg_id
++;
724 send_string_request(conn
, id
, SSH2_FXP_REALPATH
, path
,
730 type
= buffer_get_char(&msg
);
731 id
= buffer_get_int(&msg
);
733 if (id
!= expected_id
)
734 fatal("ID mismatch (%u != %u)", id
, expected_id
);
736 if (type
== SSH2_FXP_STATUS
) {
737 u_int status
= buffer_get_int(&msg
);
739 error("Couldn't canonicalise: %s", fx2txt(status
));
742 } else if (type
!= SSH2_FXP_NAME
)
743 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
744 SSH2_FXP_NAME
, type
);
746 count
= buffer_get_int(&msg
);
748 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count
);
750 filename
= buffer_get_string(&msg
, NULL
);
751 longname
= buffer_get_string(&msg
, NULL
);
752 a
= decode_attrib(&msg
);
754 debug3("SSH_FXP_REALPATH %s -> %s", path
, filename
);
764 do_rename(struct sftp_conn
*conn
, char *oldpath
, char *newpath
)
771 /* Send rename request */
773 if ((conn
->exts
& SFTP_EXT_POSIX_RENAME
)) {
774 buffer_put_char(&msg
, SSH2_FXP_EXTENDED
);
775 buffer_put_int(&msg
, id
);
776 buffer_put_cstring(&msg
, "posix-rename@openssh.com");
778 buffer_put_char(&msg
, SSH2_FXP_RENAME
);
779 buffer_put_int(&msg
, id
);
781 buffer_put_cstring(&msg
, oldpath
);
782 buffer_put_cstring(&msg
, newpath
);
783 send_msg(conn
, &msg
);
784 debug3("Sent message %s \"%s\" -> \"%s\"",
785 (conn
->exts
& SFTP_EXT_POSIX_RENAME
) ? "posix-rename@openssh.com" :
786 "SSH2_FXP_RENAME", oldpath
, newpath
);
789 status
= get_status(conn
, id
);
790 if (status
!= SSH2_FX_OK
)
791 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath
,
792 newpath
, fx2txt(status
));
798 do_symlink(struct sftp_conn
*conn
, char *oldpath
, char *newpath
)
803 if (conn
->version
< 3) {
804 error("This server does not support the symlink operation");
805 return(SSH2_FX_OP_UNSUPPORTED
);
810 /* Send symlink request */
812 buffer_put_char(&msg
, SSH2_FXP_SYMLINK
);
813 buffer_put_int(&msg
, id
);
814 buffer_put_cstring(&msg
, oldpath
);
815 buffer_put_cstring(&msg
, newpath
);
816 send_msg(conn
, &msg
);
817 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath
,
821 status
= get_status(conn
, id
);
822 if (status
!= SSH2_FX_OK
)
823 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath
,
824 newpath
, fx2txt(status
));
831 do_readlink(struct sftp_conn
*conn
, char *path
)
834 u_int type
, expected_id
, count
, id
;
835 char *filename
, *longname
;
838 expected_id
= id
= conn
->msg_id
++;
839 send_string_request(conn
, id
, SSH2_FXP_READLINK
, path
, strlen(path
));
844 type
= buffer_get_char(&msg
);
845 id
= buffer_get_int(&msg
);
847 if (id
!= expected_id
)
848 fatal("ID mismatch (%u != %u)", id
, expected_id
);
850 if (type
== SSH2_FXP_STATUS
) {
851 u_int status
= buffer_get_int(&msg
);
853 error("Couldn't readlink: %s", fx2txt(status
));
855 } else if (type
!= SSH2_FXP_NAME
)
856 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
857 SSH2_FXP_NAME
, type
);
859 count
= buffer_get_int(&msg
);
861 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count
);
863 filename
= buffer_get_string(&msg
, NULL
);
864 longname
= buffer_get_string(&msg
, NULL
);
865 a
= decode_attrib(&msg
);
867 debug3("SSH_FXP_READLINK %s -> %s", path
, filename
);
878 do_statvfs(struct sftp_conn
*conn
, const char *path
, struct sftp_statvfs
*st
,
884 if ((conn
->exts
& SFTP_EXT_STATVFS
) == 0) {
885 error("Server does not support statvfs@openssh.com extension");
893 buffer_put_char(&msg
, SSH2_FXP_EXTENDED
);
894 buffer_put_int(&msg
, id
);
895 buffer_put_cstring(&msg
, "statvfs@openssh.com");
896 buffer_put_cstring(&msg
, path
);
897 send_msg(conn
, &msg
);
900 return get_decode_statvfs(conn
, st
, id
, quiet
);
905 do_fstatvfs(struct sftp_conn
*conn
, const char *handle
, u_int handle_len
,
906 struct sftp_statvfs
*st
, int quiet
)
911 if ((conn
->exts
& SFTP_EXT_FSTATVFS
) == 0) {
912 error("Server does not support fstatvfs@openssh.com extension");
920 buffer_put_char(&msg
, SSH2_FXP_EXTENDED
);
921 buffer_put_int(&msg
, id
);
922 buffer_put_cstring(&msg
, "fstatvfs@openssh.com");
923 buffer_put_string(&msg
, handle
, handle_len
);
924 send_msg(conn
, &msg
);
927 return get_decode_statvfs(conn
, st
, id
, quiet
);
932 send_read_request(struct sftp_conn
*conn
, u_int id
, u_int64_t offset
,
933 u_int len
, char *handle
, u_int handle_len
)
939 buffer_put_char(&msg
, SSH2_FXP_READ
);
940 buffer_put_int(&msg
, id
);
941 buffer_put_string(&msg
, handle
, handle_len
);
942 buffer_put_int64(&msg
, offset
);
943 buffer_put_int(&msg
, len
);
944 send_msg(conn
, &msg
);
949 do_download(struct sftp_conn
*conn
, char *remote_path
, char *local_path
,
950 Attrib
*a
, int pflag
)
955 int local_fd
, status
= 0, write_error
;
956 int read_error
, write_errno
;
957 u_int64_t offset
, size
;
958 u_int handle_len
, mode
, type
, id
, buflen
, num_req
, max_req
;
959 off_t progress_counter
;
964 TAILQ_ENTRY(request
) tq
;
966 TAILQ_HEAD(reqhead
, request
) requests
;
969 TAILQ_INIT(&requests
);
971 if (a
== NULL
&& (a
= do_stat(conn
, remote_path
, 0)) == NULL
)
974 /* Do not preserve set[ug]id here, as we do not preserve ownership */
975 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
)
976 mode
= a
->perm
& 0777;
980 if ((a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) &&
981 (!S_ISREG(a
->perm
))) {
982 error("Cannot download non-regular file: %s", remote_path
);
986 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
)
991 buflen
= conn
->transfer_buflen
;
994 /* Send open request */
996 buffer_put_char(&msg
, SSH2_FXP_OPEN
);
997 buffer_put_int(&msg
, id
);
998 buffer_put_cstring(&msg
, remote_path
);
999 buffer_put_int(&msg
, SSH2_FXF_READ
);
1000 attrib_clear(&junk
); /* Send empty attributes */
1001 encode_attrib(&msg
, &junk
);
1002 send_msg(conn
, &msg
);
1003 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id
, remote_path
);
1005 handle
= get_handle(conn
, id
, &handle_len
,
1006 "remote open(\"%s\")", remote_path
);
1007 if (handle
== NULL
) {
1012 local_fd
= open(local_path
, O_WRONLY
| O_CREAT
| O_TRUNC
,
1014 if (local_fd
== -1) {
1015 error("Couldn't open local file \"%s\" for writing: %s",
1016 local_path
, strerror(errno
));
1017 do_close(conn
, handle
, handle_len
);
1023 /* Read from remote and write to local */
1024 write_error
= read_error
= write_errno
= num_req
= offset
= 0;
1026 progress_counter
= 0;
1028 if (showprogress
&& size
!= 0)
1029 start_progress_meter(remote_path
, size
, &progress_counter
);
1031 while (num_req
> 0 || max_req
> 0) {
1036 * Simulate EOF on interrupt: stop sending new requests and
1037 * allow outstanding requests to drain gracefully
1040 if (num_req
== 0) /* If we haven't started yet... */
1045 /* Send some more requests */
1046 while (num_req
< max_req
) {
1047 debug3("Request range %llu -> %llu (%d/%d)",
1048 (unsigned long long)offset
,
1049 (unsigned long long)offset
+ buflen
- 1,
1051 req
= xmalloc(sizeof(*req
));
1052 req
->id
= conn
->msg_id
++;
1054 req
->offset
= offset
;
1057 TAILQ_INSERT_TAIL(&requests
, req
, tq
);
1058 send_read_request(conn
, req
->id
, req
->offset
,
1059 req
->len
, handle
, handle_len
);
1063 get_msg(conn
, &msg
);
1064 type
= buffer_get_char(&msg
);
1065 id
= buffer_get_int(&msg
);
1066 debug3("Received reply T:%u I:%u R:%d", type
, id
, max_req
);
1068 /* Find the request in our queue */
1069 for (req
= TAILQ_FIRST(&requests
);
1070 req
!= NULL
&& req
->id
!= id
;
1071 req
= TAILQ_NEXT(req
, tq
))
1074 fatal("Unexpected reply %u", id
);
1077 case SSH2_FXP_STATUS
:
1078 status
= buffer_get_int(&msg
);
1079 if (status
!= SSH2_FX_EOF
)
1082 TAILQ_REMOVE(&requests
, req
, tq
);
1087 data
= buffer_get_string(&msg
, &len
);
1088 debug3("Received data %llu -> %llu",
1089 (unsigned long long)req
->offset
,
1090 (unsigned long long)req
->offset
+ len
- 1);
1092 fatal("Received more data than asked for "
1093 "%u > %u", len
, req
->len
);
1094 if ((lseek(local_fd
, req
->offset
, SEEK_SET
) == -1 ||
1095 atomicio(vwrite
, local_fd
, data
, len
) != len
) &&
1097 write_errno
= errno
;
1101 progress_counter
+= len
;
1104 if (len
== req
->len
) {
1105 TAILQ_REMOVE(&requests
, req
, tq
);
1109 /* Resend the request for the missing data */
1110 debug3("Short data block, re-requesting "
1111 "%llu -> %llu (%2d)",
1112 (unsigned long long)req
->offset
+ len
,
1113 (unsigned long long)req
->offset
+
1114 req
->len
- 1, num_req
);
1115 req
->id
= conn
->msg_id
++;
1118 send_read_request(conn
, req
->id
,
1119 req
->offset
, req
->len
, handle
, handle_len
);
1120 /* Reduce the request size */
1122 buflen
= MAX(MIN_READ_SIZE
, len
);
1124 if (max_req
> 0) { /* max_req = 0 iff EOF received */
1125 if (size
> 0 && offset
> size
) {
1126 /* Only one request at a time
1127 * after the expected EOF */
1128 debug3("Finish at %llu (%2d)",
1129 (unsigned long long)offset
,
1132 } else if (max_req
<= conn
->num_requests
) {
1138 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1139 SSH2_FXP_DATA
, type
);
1143 if (showprogress
&& size
)
1144 stop_progress_meter();
1147 if (TAILQ_FIRST(&requests
) != NULL
)
1148 fatal("Transfer complete, but requests still in queue");
1151 error("Couldn't read from remote file \"%s\" : %s",
1152 remote_path
, fx2txt(status
));
1153 do_close(conn
, handle
, handle_len
);
1154 } else if (write_error
) {
1155 error("Couldn't write to \"%s\": %s", local_path
,
1156 strerror(write_errno
));
1158 do_close(conn
, handle
, handle_len
);
1160 status
= do_close(conn
, handle
, handle_len
);
1162 /* Override umask and utimes if asked */
1164 if (pflag
&& fchmod(local_fd
, mode
) == -1)
1166 if (pflag
&& chmod(local_path
, mode
) == -1)
1167 #endif /* HAVE_FCHMOD */
1168 error("Couldn't set mode on \"%s\": %s", local_path
,
1170 if (pflag
&& (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
)) {
1171 struct timeval tv
[2];
1172 tv
[0].tv_sec
= a
->atime
;
1173 tv
[1].tv_sec
= a
->mtime
;
1174 tv
[0].tv_usec
= tv
[1].tv_usec
= 0;
1175 if (utimes(local_path
, tv
) == -1)
1176 error("Can't set times on \"%s\": %s",
1177 local_path
, strerror(errno
));
1188 download_dir_internal(struct sftp_conn
*conn
, char *src
, char *dst
,
1189 Attrib
*dirattrib
, int pflag
, int printflag
, int depth
)
1192 SFTP_DIRENT
**dir_entries
;
1193 char *filename
, *new_src
, *new_dst
;
1196 if (depth
>= MAX_DIR_DEPTH
) {
1197 error("Maximum directory depth exceeded: %d levels", depth
);
1201 if (dirattrib
== NULL
&&
1202 (dirattrib
= do_stat(conn
, src
, 1)) == NULL
) {
1203 error("Unable to stat remote directory \"%s\"", src
);
1206 if (!S_ISDIR(dirattrib
->perm
)) {
1207 error("\"%s\" is not a directory", src
);
1211 printf("Retrieving %s\n", src
);
1213 if (dirattrib
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
)
1214 mode
= dirattrib
->perm
& 01777;
1216 debug("Server did not send permissions for "
1217 "directory \"%s\"", dst
);
1220 if (mkdir(dst
, mode
) == -1 && errno
!= EEXIST
) {
1221 error("mkdir %s: %s", dst
, strerror(errno
));
1225 if (do_readdir(conn
, src
, &dir_entries
) == -1) {
1226 error("%s: Failed to get directory contents", src
);
1230 for (i
= 0; dir_entries
[i
] != NULL
&& !interrupted
; i
++) {
1231 filename
= dir_entries
[i
]->filename
;
1233 new_dst
= path_append(dst
, filename
);
1234 new_src
= path_append(src
, filename
);
1236 if (S_ISDIR(dir_entries
[i
]->a
.perm
)) {
1237 if (strcmp(filename
, ".") == 0 ||
1238 strcmp(filename
, "..") == 0)
1240 if (download_dir_internal(conn
, new_src
, new_dst
,
1241 &(dir_entries
[i
]->a
), pflag
, printflag
,
1244 } else if (S_ISREG(dir_entries
[i
]->a
.perm
) ) {
1245 if (do_download(conn
, new_src
, new_dst
,
1246 &(dir_entries
[i
]->a
), pflag
) == -1) {
1247 error("Download of file %s to %s failed",
1252 logit("%s: not a regular file\n", new_src
);
1259 if (dirattrib
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
) {
1260 struct timeval tv
[2];
1261 tv
[0].tv_sec
= dirattrib
->atime
;
1262 tv
[1].tv_sec
= dirattrib
->mtime
;
1263 tv
[0].tv_usec
= tv
[1].tv_usec
= 0;
1264 if (utimes(dst
, tv
) == -1)
1265 error("Can't set times on \"%s\": %s",
1266 dst
, strerror(errno
));
1268 debug("Server did not send times for directory "
1272 free_sftp_dirents(dir_entries
);
1278 download_dir(struct sftp_conn
*conn
, char *src
, char *dst
,
1279 Attrib
*dirattrib
, int pflag
, int printflag
)
1284 if ((src_canon
= do_realpath(conn
, src
)) == NULL
) {
1285 error("Unable to canonicalise path \"%s\"", src
);
1289 ret
= download_dir_internal(conn
, src_canon
, dst
,
1290 dirattrib
, pflag
, printflag
, 0);
1296 do_upload(struct sftp_conn
*conn
, char *local_path
, char *remote_path
,
1300 int status
= SSH2_FX_OK
;
1301 u_int handle_len
, id
, type
;
1303 char *handle
, *data
;
1309 struct outstanding_ack
{
1313 TAILQ_ENTRY(outstanding_ack
) tq
;
1315 TAILQ_HEAD(ackhead
, outstanding_ack
) acks
;
1316 struct outstanding_ack
*ack
= NULL
;
1320 if ((local_fd
= open(local_path
, O_RDONLY
, 0)) == -1) {
1321 error("Couldn't open local file \"%s\" for reading: %s",
1322 local_path
, strerror(errno
));
1325 if (fstat(local_fd
, &sb
) == -1) {
1326 error("Couldn't fstat local file \"%s\": %s",
1327 local_path
, strerror(errno
));
1331 if (!S_ISREG(sb
.st_mode
)) {
1332 error("%s is not a regular file", local_path
);
1336 stat_to_attrib(&sb
, &a
);
1338 a
.flags
&= ~SSH2_FILEXFER_ATTR_SIZE
;
1339 a
.flags
&= ~SSH2_FILEXFER_ATTR_UIDGID
;
1342 a
.flags
&= ~SSH2_FILEXFER_ATTR_ACMODTIME
;
1346 /* Send open request */
1347 id
= conn
->msg_id
++;
1348 buffer_put_char(&msg
, SSH2_FXP_OPEN
);
1349 buffer_put_int(&msg
, id
);
1350 buffer_put_cstring(&msg
, remote_path
);
1351 buffer_put_int(&msg
, SSH2_FXF_WRITE
|SSH2_FXF_CREAT
|SSH2_FXF_TRUNC
);
1352 encode_attrib(&msg
, &a
);
1353 send_msg(conn
, &msg
);
1354 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id
, remote_path
);
1358 handle
= get_handle(conn
, id
, &handle_len
,
1359 "remote open(\"%s\")", remote_path
);
1360 if (handle
== NULL
) {
1366 startid
= ackid
= id
+ 1;
1367 data
= xmalloc(conn
->transfer_buflen
);
1369 /* Read from local and write to remote */
1372 start_progress_meter(local_path
, sb
.st_size
, &offset
);
1378 * Can't use atomicio here because it returns 0 on EOF,
1379 * thus losing the last block of the file.
1380 * Simulate an EOF on interrupt, allowing ACKs from the
1383 if (interrupted
|| status
!= SSH2_FX_OK
)
1386 len
= read(local_fd
, data
, conn
->transfer_buflen
);
1387 while ((len
== -1) &&
1388 (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
1391 fatal("Couldn't read from \"%s\": %s", local_path
,
1395 ack
= xmalloc(sizeof(*ack
));
1397 ack
->offset
= offset
;
1399 TAILQ_INSERT_TAIL(&acks
, ack
, tq
);
1402 buffer_put_char(&msg
, SSH2_FXP_WRITE
);
1403 buffer_put_int(&msg
, ack
->id
);
1404 buffer_put_string(&msg
, handle
, handle_len
);
1405 buffer_put_int64(&msg
, offset
);
1406 buffer_put_string(&msg
, data
, len
);
1407 send_msg(conn
, &msg
);
1408 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1409 id
, (unsigned long long)offset
, len
);
1410 } else if (TAILQ_FIRST(&acks
) == NULL
)
1414 fatal("Unexpected ACK %u", id
);
1416 if (id
== startid
|| len
== 0 ||
1417 id
- ackid
>= conn
->num_requests
) {
1421 get_msg(conn
, &msg
);
1422 type
= buffer_get_char(&msg
);
1423 r_id
= buffer_get_int(&msg
);
1425 if (type
!= SSH2_FXP_STATUS
)
1426 fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1427 "got %d", SSH2_FXP_STATUS
, type
);
1429 status
= buffer_get_int(&msg
);
1430 debug3("SSH2_FXP_STATUS %d", status
);
1432 /* Find the request in our queue */
1433 for (ack
= TAILQ_FIRST(&acks
);
1434 ack
!= NULL
&& ack
->id
!= r_id
;
1435 ack
= TAILQ_NEXT(ack
, tq
))
1438 fatal("Can't find request for ID %u", r_id
);
1439 TAILQ_REMOVE(&acks
, ack
, tq
);
1440 debug3("In write loop, ack for %u %u bytes at %lld",
1441 ack
->id
, ack
->len
, (long long)ack
->offset
);
1447 fatal("%s: offset < 0", __func__
);
1452 stop_progress_meter();
1455 if (status
!= SSH2_FX_OK
) {
1456 error("Couldn't write to remote file \"%s\": %s",
1457 remote_path
, fx2txt(status
));
1461 if (close(local_fd
) == -1) {
1462 error("Couldn't close local file \"%s\": %s", local_path
,
1467 /* Override umask and utimes if asked */
1469 do_fsetstat(conn
, handle
, handle_len
, &a
);
1471 if (do_close(conn
, handle
, handle_len
) != SSH2_FX_OK
)
1479 upload_dir_internal(struct sftp_conn
*conn
, char *src
, char *dst
,
1480 int pflag
, int printflag
, int depth
)
1482 int ret
= 0, status
;
1485 char *filename
, *new_src
, *new_dst
;
1489 if (depth
>= MAX_DIR_DEPTH
) {
1490 error("Maximum directory depth exceeded: %d levels", depth
);
1494 if (stat(src
, &sb
) == -1) {
1495 error("Couldn't stat directory \"%s\": %s",
1496 src
, strerror(errno
));
1499 if (!S_ISDIR(sb
.st_mode
)) {
1500 error("\"%s\" is not a directory", src
);
1504 printf("Entering %s\n", src
);
1507 stat_to_attrib(&sb
, &a
);
1508 a
.flags
&= ~SSH2_FILEXFER_ATTR_SIZE
;
1509 a
.flags
&= ~SSH2_FILEXFER_ATTR_UIDGID
;
1512 a
.flags
&= ~SSH2_FILEXFER_ATTR_ACMODTIME
;
1514 status
= do_mkdir(conn
, dst
, &a
, 0);
1516 * we lack a portable status for errno EEXIST,
1517 * so if we get a SSH2_FX_FAILURE back we must check
1518 * if it was created successfully.
1520 if (status
!= SSH2_FX_OK
) {
1521 if (status
!= SSH2_FX_FAILURE
)
1523 if (do_stat(conn
, dst
, 0) == NULL
)
1527 if ((dirp
= opendir(src
)) == NULL
) {
1528 error("Failed to open dir \"%s\": %s", src
, strerror(errno
));
1532 while (((dp
= readdir(dirp
)) != NULL
) && !interrupted
) {
1535 filename
= dp
->d_name
;
1536 new_dst
= path_append(dst
, filename
);
1537 new_src
= path_append(src
, filename
);
1539 if (lstat(new_src
, &sb
) == -1) {
1540 logit("%s: lstat failed: %s", filename
,
1543 } else if (S_ISDIR(sb
.st_mode
)) {
1544 if (strcmp(filename
, ".") == 0 ||
1545 strcmp(filename
, "..") == 0)
1548 if (upload_dir_internal(conn
, new_src
, new_dst
,
1549 pflag
, printflag
, depth
+ 1) == -1)
1551 } else if (S_ISREG(sb
.st_mode
)) {
1552 if (do_upload(conn
, new_src
, new_dst
, pflag
) == -1) {
1553 error("Uploading of file %s to %s failed!",
1558 logit("%s: not a regular file\n", filename
);
1563 do_setstat(conn
, dst
, &a
);
1565 (void) closedir(dirp
);
1570 upload_dir(struct sftp_conn
*conn
, char *src
, char *dst
, int printflag
,
1576 if ((dst_canon
= do_realpath(conn
, dst
)) == NULL
) {
1577 error("Unable to canonicalise path \"%s\"", dst
);
1581 ret
= upload_dir_internal(conn
, src
, dst_canon
, pflag
, printflag
, 0);
1587 path_append(char *p1
, char *p2
)
1590 size_t len
= strlen(p1
) + strlen(p2
) + 2;
1593 strlcpy(ret
, p1
, len
);
1594 if (p1
[0] != '\0' && p1
[strlen(p1
) - 1] != '/')
1595 strlcat(ret
, "/", len
);
1596 strlcat(ret
, p2
, len
);