1 /* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 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
78 #define SFTP_EXT_HARDLINK 0x00000008
81 struct bwlimit bwlimit_in
, bwlimit_out
;
85 get_handle(struct sftp_conn
*conn
, u_int expected_id
, u_int
*len
,
86 const char *errfmt
, ...) __attribute__((format(printf
, 4, 5)));
90 sftpio(void *_bwlimit
, size_t amount
)
92 struct bwlimit
*bwlimit
= (struct bwlimit
*)_bwlimit
;
94 bandwidth_limit(bwlimit
, amount
);
99 send_msg(struct sftp_conn
*conn
, Buffer
*m
)
104 if (buffer_len(m
) > SFTP_MAX_MSG_LENGTH
)
105 fatal("Outbound message too long %u", buffer_len(m
));
107 /* Send length first */
108 put_u32(mlen
, buffer_len(m
));
109 iov
[0].iov_base
= mlen
;
110 iov
[0].iov_len
= sizeof(mlen
);
111 iov
[1].iov_base
= buffer_ptr(m
);
112 iov
[1].iov_len
= buffer_len(m
);
114 if (atomiciov6(writev
, conn
->fd_out
, iov
, 2,
115 conn
->limit_kbps
> 0 ? sftpio
: NULL
, &conn
->bwlimit_out
) !=
116 buffer_len(m
) + sizeof(mlen
))
117 fatal("Couldn't send packet: %s", strerror(errno
));
123 get_msg(struct sftp_conn
*conn
, Buffer
*m
)
127 buffer_append_space(m
, 4);
128 if (atomicio6(read
, conn
->fd_in
, buffer_ptr(m
), 4,
129 conn
->limit_kbps
> 0 ? sftpio
: NULL
, &conn
->bwlimit_in
) != 4) {
131 fatal("Connection closed");
133 fatal("Couldn't read packet: %s", strerror(errno
));
136 msg_len
= buffer_get_int(m
);
137 if (msg_len
> SFTP_MAX_MSG_LENGTH
)
138 fatal("Received message too long %u", msg_len
);
140 buffer_append_space(m
, msg_len
);
141 if (atomicio6(read
, conn
->fd_in
, buffer_ptr(m
), msg_len
,
142 conn
->limit_kbps
> 0 ? sftpio
: NULL
, &conn
->bwlimit_in
)
145 fatal("Connection closed");
147 fatal("Read packet: %s", strerror(errno
));
152 send_string_request(struct sftp_conn
*conn
, u_int id
, u_int code
, char *s
,
158 buffer_put_char(&msg
, code
);
159 buffer_put_int(&msg
, id
);
160 buffer_put_string(&msg
, s
, len
);
161 send_msg(conn
, &msg
);
162 debug3("Sent message fd %d T:%u I:%u", conn
->fd_out
, code
, id
);
167 send_string_attrs_request(struct sftp_conn
*conn
, u_int id
, u_int code
,
168 char *s
, u_int len
, Attrib
*a
)
173 buffer_put_char(&msg
, code
);
174 buffer_put_int(&msg
, id
);
175 buffer_put_string(&msg
, s
, len
);
176 encode_attrib(&msg
, a
);
177 send_msg(conn
, &msg
);
178 debug3("Sent message fd %d T:%u I:%u", conn
->fd_out
, code
, id
);
183 get_status(struct sftp_conn
*conn
, u_int expected_id
)
186 u_int type
, id
, status
;
190 type
= buffer_get_char(&msg
);
191 id
= buffer_get_int(&msg
);
193 if (id
!= expected_id
)
194 fatal("ID mismatch (%u != %u)", id
, expected_id
);
195 if (type
!= SSH2_FXP_STATUS
)
196 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
197 SSH2_FXP_STATUS
, type
);
199 status
= buffer_get_int(&msg
);
202 debug3("SSH2_FXP_STATUS %u", status
);
208 get_handle(struct sftp_conn
*conn
, u_int expected_id
, u_int
*len
,
209 const char *errfmt
, ...)
213 char *handle
, errmsg
[256];
217 va_start(args
, errfmt
);
219 vsnprintf(errmsg
, sizeof(errmsg
), errfmt
, args
);
224 type
= buffer_get_char(&msg
);
225 id
= buffer_get_int(&msg
);
227 if (id
!= expected_id
)
228 fatal("%s: ID mismatch (%u != %u)",
229 errfmt
== NULL
? __func__
: errmsg
, id
, expected_id
);
230 if (type
== SSH2_FXP_STATUS
) {
231 status
= buffer_get_int(&msg
);
233 error("%s: %s", errmsg
, fx2txt(status
));
236 } else if (type
!= SSH2_FXP_HANDLE
)
237 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
238 errfmt
== NULL
? __func__
: errmsg
, SSH2_FXP_HANDLE
, type
);
240 handle
= buffer_get_string(&msg
, len
);
247 get_decode_stat(struct sftp_conn
*conn
, u_int expected_id
, int quiet
)
256 type
= buffer_get_char(&msg
);
257 id
= buffer_get_int(&msg
);
259 debug3("Received stat reply T:%u I:%u", type
, id
);
260 if (id
!= expected_id
)
261 fatal("ID mismatch (%u != %u)", id
, expected_id
);
262 if (type
== SSH2_FXP_STATUS
) {
263 int status
= buffer_get_int(&msg
);
266 debug("Couldn't stat remote file: %s", fx2txt(status
));
268 error("Couldn't stat remote file: %s", fx2txt(status
));
271 } else if (type
!= SSH2_FXP_ATTRS
) {
272 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
273 SSH2_FXP_ATTRS
, type
);
275 a
= decode_attrib(&msg
);
282 get_decode_statvfs(struct sftp_conn
*conn
, struct sftp_statvfs
*st
,
283 u_int expected_id
, int quiet
)
286 u_int type
, id
, flag
;
291 type
= buffer_get_char(&msg
);
292 id
= buffer_get_int(&msg
);
294 debug3("Received statvfs reply T:%u I:%u", type
, id
);
295 if (id
!= expected_id
)
296 fatal("ID mismatch (%u != %u)", id
, expected_id
);
297 if (type
== SSH2_FXP_STATUS
) {
298 int status
= buffer_get_int(&msg
);
301 debug("Couldn't statvfs: %s", fx2txt(status
));
303 error("Couldn't statvfs: %s", fx2txt(status
));
306 } else if (type
!= SSH2_FXP_EXTENDED_REPLY
) {
307 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
308 SSH2_FXP_EXTENDED_REPLY
, type
);
311 bzero(st
, sizeof(*st
));
312 st
->f_bsize
= buffer_get_int64(&msg
);
313 st
->f_frsize
= buffer_get_int64(&msg
);
314 st
->f_blocks
= buffer_get_int64(&msg
);
315 st
->f_bfree
= buffer_get_int64(&msg
);
316 st
->f_bavail
= buffer_get_int64(&msg
);
317 st
->f_files
= buffer_get_int64(&msg
);
318 st
->f_ffree
= buffer_get_int64(&msg
);
319 st
->f_favail
= buffer_get_int64(&msg
);
320 st
->f_fsid
= buffer_get_int64(&msg
);
321 flag
= buffer_get_int64(&msg
);
322 st
->f_namemax
= buffer_get_int64(&msg
);
324 st
->f_flag
= (flag
& SSH2_FXE_STATVFS_ST_RDONLY
) ? ST_RDONLY
: 0;
325 st
->f_flag
|= (flag
& SSH2_FXE_STATVFS_ST_NOSUID
) ? ST_NOSUID
: 0;
333 do_init(int fd_in
, int fd_out
, u_int transfer_buflen
, u_int num_requests
,
334 u_int64_t limit_kbps
)
338 struct sftp_conn
*ret
;
340 ret
= xmalloc(sizeof(*ret
));
342 ret
->fd_out
= fd_out
;
343 ret
->transfer_buflen
= transfer_buflen
;
344 ret
->num_requests
= num_requests
;
349 buffer_put_char(&msg
, SSH2_FXP_INIT
);
350 buffer_put_int(&msg
, SSH2_FILEXFER_VERSION
);
357 /* Expecting a VERSION reply */
358 if ((type
= buffer_get_char(&msg
)) != SSH2_FXP_VERSION
) {
359 error("Invalid packet back from SSH2_FXP_INIT (type %u)",
364 ret
->version
= buffer_get_int(&msg
);
366 debug2("Remote version: %u", ret
->version
);
368 /* Check for extensions */
369 while (buffer_len(&msg
) > 0) {
370 char *name
= buffer_get_string(&msg
, NULL
);
371 char *value
= buffer_get_string(&msg
, NULL
);
374 if (strcmp(name
, "posix-rename@openssh.com") == 0 &&
375 strcmp(value
, "1") == 0) {
376 ret
->exts
|= SFTP_EXT_POSIX_RENAME
;
378 } else if (strcmp(name
, "statvfs@openssh.com") == 0 &&
379 strcmp(value
, "2") == 0) {
380 ret
->exts
|= SFTP_EXT_STATVFS
;
382 } else if (strcmp(name
, "fstatvfs@openssh.com") == 0 &&
383 strcmp(value
, "2") == 0) {
384 ret
->exts
|= SFTP_EXT_FSTATVFS
;
386 } else if (strcmp(name
, "hardlink@openssh.com") == 0 &&
387 strcmp(value
, "1") == 0) {
388 ret
->exts
|= SFTP_EXT_HARDLINK
;
392 debug2("Server supports extension \"%s\" revision %s",
395 debug2("Unrecognised server extension \"%s\"", name
);
403 /* Some filexfer v.0 servers don't support large packets */
404 if (ret
->version
== 0)
405 ret
->transfer_buflen
= MIN(ret
->transfer_buflen
, 20480);
407 ret
->limit_kbps
= limit_kbps
;
408 if (ret
->limit_kbps
> 0) {
409 bandwidth_limit_init(&ret
->bwlimit_in
, ret
->limit_kbps
,
410 ret
->transfer_buflen
);
411 bandwidth_limit_init(&ret
->bwlimit_out
, ret
->limit_kbps
,
412 ret
->transfer_buflen
);
419 sftp_proto_version(struct sftp_conn
*conn
)
421 return conn
->version
;
425 do_close(struct sftp_conn
*conn
, char *handle
, u_int handle_len
)
433 buffer_put_char(&msg
, SSH2_FXP_CLOSE
);
434 buffer_put_int(&msg
, id
);
435 buffer_put_string(&msg
, handle
, handle_len
);
436 send_msg(conn
, &msg
);
437 debug3("Sent message SSH2_FXP_CLOSE I:%u", id
);
439 status
= get_status(conn
, id
);
440 if (status
!= SSH2_FX_OK
)
441 error("Couldn't close file: %s", fx2txt(status
));
450 do_lsreaddir(struct sftp_conn
*conn
, char *path
, int printflag
,
454 u_int count
, type
, id
, handle_len
, i
, expected_id
, ents
= 0;
460 buffer_put_char(&msg
, SSH2_FXP_OPENDIR
);
461 buffer_put_int(&msg
, id
);
462 buffer_put_cstring(&msg
, path
);
463 send_msg(conn
, &msg
);
467 handle
= get_handle(conn
, id
, &handle_len
,
468 "remote readdir(\"%s\")", path
);
474 *dir
= xmalloc(sizeof(**dir
));
478 for (; !interrupted
;) {
479 id
= expected_id
= conn
->msg_id
++;
481 debug3("Sending SSH2_FXP_READDIR I:%u", id
);
484 buffer_put_char(&msg
, SSH2_FXP_READDIR
);
485 buffer_put_int(&msg
, id
);
486 buffer_put_string(&msg
, handle
, handle_len
);
487 send_msg(conn
, &msg
);
493 type
= buffer_get_char(&msg
);
494 id
= buffer_get_int(&msg
);
496 debug3("Received reply T:%u I:%u", type
, id
);
498 if (id
!= expected_id
)
499 fatal("ID mismatch (%u != %u)", id
, expected_id
);
501 if (type
== SSH2_FXP_STATUS
) {
502 int status
= buffer_get_int(&msg
);
504 debug3("Received SSH2_FXP_STATUS %d", status
);
506 if (status
== SSH2_FX_EOF
) {
509 error("Couldn't read directory: %s",
511 do_close(conn
, handle
, handle_len
);
515 } else if (type
!= SSH2_FXP_NAME
)
516 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
517 SSH2_FXP_NAME
, type
);
519 count
= buffer_get_int(&msg
);
522 debug3("Received %d SSH2_FXP_NAME responses", count
);
523 for (i
= 0; i
< count
; i
++) {
524 char *filename
, *longname
;
527 filename
= buffer_get_string(&msg
, NULL
);
528 longname
= buffer_get_string(&msg
, NULL
);
529 a
= decode_attrib(&msg
);
532 printf("%s\n", longname
);
535 * Directory entries should never contain '/'
536 * These can be used to attack recursive ops
537 * (e.g. send '../../../../etc/passwd')
539 if (strchr(filename
, '/') != NULL
) {
540 error("Server sent suspect path \"%s\" "
541 "during readdir of \"%s\"", filename
, path
);
546 *dir
= xrealloc(*dir
, ents
+ 2, sizeof(**dir
));
547 (*dir
)[ents
] = xmalloc(sizeof(***dir
));
548 (*dir
)[ents
]->filename
= xstrdup(filename
);
549 (*dir
)[ents
]->longname
= xstrdup(longname
);
550 memcpy(&(*dir
)[ents
]->a
, a
, sizeof(*a
));
551 (*dir
)[++ents
] = NULL
;
560 do_close(conn
, handle
, handle_len
);
563 /* Don't return partial matches on interrupt */
564 if (interrupted
&& dir
!= NULL
&& *dir
!= NULL
) {
565 free_sftp_dirents(*dir
);
566 *dir
= xmalloc(sizeof(**dir
));
574 do_readdir(struct sftp_conn
*conn
, char *path
, SFTP_DIRENT
***dir
)
576 return(do_lsreaddir(conn
, path
, 0, dir
));
579 void free_sftp_dirents(SFTP_DIRENT
**s
)
583 for (i
= 0; s
[i
]; i
++) {
584 xfree(s
[i
]->filename
);
585 xfree(s
[i
]->longname
);
592 do_rm(struct sftp_conn
*conn
, char *path
)
596 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path
);
599 send_string_request(conn
, id
, SSH2_FXP_REMOVE
, path
, strlen(path
));
600 status
= get_status(conn
, id
);
601 if (status
!= SSH2_FX_OK
)
602 error("Couldn't delete file: %s", fx2txt(status
));
607 do_mkdir(struct sftp_conn
*conn
, char *path
, Attrib
*a
, int printflag
)
612 send_string_attrs_request(conn
, id
, SSH2_FXP_MKDIR
, path
,
615 status
= get_status(conn
, id
);
616 if (status
!= SSH2_FX_OK
&& printflag
)
617 error("Couldn't create directory: %s", fx2txt(status
));
623 do_rmdir(struct sftp_conn
*conn
, char *path
)
628 send_string_request(conn
, id
, SSH2_FXP_RMDIR
, path
,
631 status
= get_status(conn
, id
);
632 if (status
!= SSH2_FX_OK
)
633 error("Couldn't remove directory: %s", fx2txt(status
));
639 do_stat(struct sftp_conn
*conn
, char *path
, int quiet
)
645 send_string_request(conn
, id
,
646 conn
->version
== 0 ? SSH2_FXP_STAT_VERSION_0
: SSH2_FXP_STAT
,
649 return(get_decode_stat(conn
, id
, quiet
));
653 do_lstat(struct sftp_conn
*conn
, char *path
, int quiet
)
657 if (conn
->version
== 0) {
659 debug("Server version does not support lstat operation");
661 logit("Server version does not support lstat operation");
662 return(do_stat(conn
, path
, quiet
));
666 send_string_request(conn
, id
, SSH2_FXP_LSTAT
, path
,
669 return(get_decode_stat(conn
, id
, quiet
));
674 do_fstat(struct sftp_conn
*conn
, char *handle
, u_int handle_len
, int quiet
)
679 send_string_request(conn
, id
, SSH2_FXP_FSTAT
, handle
,
682 return(get_decode_stat(conn
, id
, quiet
));
687 do_setstat(struct sftp_conn
*conn
, char *path
, Attrib
*a
)
692 send_string_attrs_request(conn
, id
, SSH2_FXP_SETSTAT
, path
,
695 status
= get_status(conn
, id
);
696 if (status
!= SSH2_FX_OK
)
697 error("Couldn't setstat on \"%s\": %s", path
,
704 do_fsetstat(struct sftp_conn
*conn
, char *handle
, u_int handle_len
,
710 send_string_attrs_request(conn
, id
, SSH2_FXP_FSETSTAT
, handle
,
713 status
= get_status(conn
, id
);
714 if (status
!= SSH2_FX_OK
)
715 error("Couldn't fsetstat: %s", fx2txt(status
));
721 do_realpath(struct sftp_conn
*conn
, char *path
)
724 u_int type
, expected_id
, count
, id
;
725 char *filename
, *longname
;
728 expected_id
= id
= conn
->msg_id
++;
729 send_string_request(conn
, id
, SSH2_FXP_REALPATH
, path
,
735 type
= buffer_get_char(&msg
);
736 id
= buffer_get_int(&msg
);
738 if (id
!= expected_id
)
739 fatal("ID mismatch (%u != %u)", id
, expected_id
);
741 if (type
== SSH2_FXP_STATUS
) {
742 u_int status
= buffer_get_int(&msg
);
744 error("Couldn't canonicalise: %s", fx2txt(status
));
747 } else if (type
!= SSH2_FXP_NAME
)
748 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
749 SSH2_FXP_NAME
, type
);
751 count
= buffer_get_int(&msg
);
753 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count
);
755 filename
= buffer_get_string(&msg
, NULL
);
756 longname
= buffer_get_string(&msg
, NULL
);
757 a
= decode_attrib(&msg
);
759 debug3("SSH_FXP_REALPATH %s -> %s", path
, filename
);
769 do_rename(struct sftp_conn
*conn
, char *oldpath
, char *newpath
)
776 /* Send rename request */
778 if ((conn
->exts
& SFTP_EXT_POSIX_RENAME
)) {
779 buffer_put_char(&msg
, SSH2_FXP_EXTENDED
);
780 buffer_put_int(&msg
, id
);
781 buffer_put_cstring(&msg
, "posix-rename@openssh.com");
783 buffer_put_char(&msg
, SSH2_FXP_RENAME
);
784 buffer_put_int(&msg
, id
);
786 buffer_put_cstring(&msg
, oldpath
);
787 buffer_put_cstring(&msg
, newpath
);
788 send_msg(conn
, &msg
);
789 debug3("Sent message %s \"%s\" -> \"%s\"",
790 (conn
->exts
& SFTP_EXT_POSIX_RENAME
) ? "posix-rename@openssh.com" :
791 "SSH2_FXP_RENAME", oldpath
, newpath
);
794 status
= get_status(conn
, id
);
795 if (status
!= SSH2_FX_OK
)
796 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath
,
797 newpath
, fx2txt(status
));
803 do_hardlink(struct sftp_conn
*conn
, char *oldpath
, char *newpath
)
810 /* Send link request */
812 if ((conn
->exts
& SFTP_EXT_HARDLINK
) == 0) {
813 error("Server does not support hardlink@openssh.com extension");
817 buffer_put_char(&msg
, SSH2_FXP_EXTENDED
);
818 buffer_put_int(&msg
, id
);
819 buffer_put_cstring(&msg
, "hardlink@openssh.com");
820 buffer_put_cstring(&msg
, oldpath
);
821 buffer_put_cstring(&msg
, newpath
);
822 send_msg(conn
, &msg
);
823 debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
827 status
= get_status(conn
, id
);
828 if (status
!= SSH2_FX_OK
)
829 error("Couldn't link file \"%s\" to \"%s\": %s", oldpath
,
830 newpath
, fx2txt(status
));
836 do_symlink(struct sftp_conn
*conn
, char *oldpath
, char *newpath
)
841 if (conn
->version
< 3) {
842 error("This server does not support the symlink operation");
843 return(SSH2_FX_OP_UNSUPPORTED
);
848 /* Send symlink request */
850 buffer_put_char(&msg
, SSH2_FXP_SYMLINK
);
851 buffer_put_int(&msg
, id
);
852 buffer_put_cstring(&msg
, oldpath
);
853 buffer_put_cstring(&msg
, newpath
);
854 send_msg(conn
, &msg
);
855 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath
,
859 status
= get_status(conn
, id
);
860 if (status
!= SSH2_FX_OK
)
861 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath
,
862 newpath
, fx2txt(status
));
869 do_readlink(struct sftp_conn
*conn
, char *path
)
872 u_int type
, expected_id
, count
, id
;
873 char *filename
, *longname
;
876 expected_id
= id
= conn
->msg_id
++;
877 send_string_request(conn
, id
, SSH2_FXP_READLINK
, path
, strlen(path
));
882 type
= buffer_get_char(&msg
);
883 id
= buffer_get_int(&msg
);
885 if (id
!= expected_id
)
886 fatal("ID mismatch (%u != %u)", id
, expected_id
);
888 if (type
== SSH2_FXP_STATUS
) {
889 u_int status
= buffer_get_int(&msg
);
891 error("Couldn't readlink: %s", fx2txt(status
));
893 } else if (type
!= SSH2_FXP_NAME
)
894 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
895 SSH2_FXP_NAME
, type
);
897 count
= buffer_get_int(&msg
);
899 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count
);
901 filename
= buffer_get_string(&msg
, NULL
);
902 longname
= buffer_get_string(&msg
, NULL
);
903 a
= decode_attrib(&msg
);
905 debug3("SSH_FXP_READLINK %s -> %s", path
, filename
);
916 do_statvfs(struct sftp_conn
*conn
, const char *path
, struct sftp_statvfs
*st
,
922 if ((conn
->exts
& SFTP_EXT_STATVFS
) == 0) {
923 error("Server does not support statvfs@openssh.com extension");
931 buffer_put_char(&msg
, SSH2_FXP_EXTENDED
);
932 buffer_put_int(&msg
, id
);
933 buffer_put_cstring(&msg
, "statvfs@openssh.com");
934 buffer_put_cstring(&msg
, path
);
935 send_msg(conn
, &msg
);
938 return get_decode_statvfs(conn
, st
, id
, quiet
);
943 do_fstatvfs(struct sftp_conn
*conn
, const char *handle
, u_int handle_len
,
944 struct sftp_statvfs
*st
, int quiet
)
949 if ((conn
->exts
& SFTP_EXT_FSTATVFS
) == 0) {
950 error("Server does not support fstatvfs@openssh.com extension");
958 buffer_put_char(&msg
, SSH2_FXP_EXTENDED
);
959 buffer_put_int(&msg
, id
);
960 buffer_put_cstring(&msg
, "fstatvfs@openssh.com");
961 buffer_put_string(&msg
, handle
, handle_len
);
962 send_msg(conn
, &msg
);
965 return get_decode_statvfs(conn
, st
, id
, quiet
);
970 send_read_request(struct sftp_conn
*conn
, u_int id
, u_int64_t offset
,
971 u_int len
, char *handle
, u_int handle_len
)
977 buffer_put_char(&msg
, SSH2_FXP_READ
);
978 buffer_put_int(&msg
, id
);
979 buffer_put_string(&msg
, handle
, handle_len
);
980 buffer_put_int64(&msg
, offset
);
981 buffer_put_int(&msg
, len
);
982 send_msg(conn
, &msg
);
987 do_download(struct sftp_conn
*conn
, char *remote_path
, char *local_path
,
988 Attrib
*a
, int pflag
)
993 int local_fd
, status
= 0, write_error
;
994 int read_error
, write_errno
;
995 u_int64_t offset
, size
;
996 u_int handle_len
, mode
, type
, id
, buflen
, num_req
, max_req
;
997 off_t progress_counter
;
1002 TAILQ_ENTRY(request
) tq
;
1004 TAILQ_HEAD(reqhead
, request
) requests
;
1005 struct request
*req
;
1007 TAILQ_INIT(&requests
);
1009 if (a
== NULL
&& (a
= do_stat(conn
, remote_path
, 0)) == NULL
)
1012 /* Do not preserve set[ug]id here, as we do not preserve ownership */
1013 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
)
1014 mode
= a
->perm
& 0777;
1018 if ((a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) &&
1019 (!S_ISREG(a
->perm
))) {
1020 error("Cannot download non-regular file: %s", remote_path
);
1024 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
)
1029 buflen
= conn
->transfer_buflen
;
1032 /* Send open request */
1033 id
= conn
->msg_id
++;
1034 buffer_put_char(&msg
, SSH2_FXP_OPEN
);
1035 buffer_put_int(&msg
, id
);
1036 buffer_put_cstring(&msg
, remote_path
);
1037 buffer_put_int(&msg
, SSH2_FXF_READ
);
1038 attrib_clear(&junk
); /* Send empty attributes */
1039 encode_attrib(&msg
, &junk
);
1040 send_msg(conn
, &msg
);
1041 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id
, remote_path
);
1043 handle
= get_handle(conn
, id
, &handle_len
,
1044 "remote open(\"%s\")", remote_path
);
1045 if (handle
== NULL
) {
1050 local_fd
= open(local_path
, O_WRONLY
| O_CREAT
| O_TRUNC
,
1052 if (local_fd
== -1) {
1053 error("Couldn't open local file \"%s\" for writing: %s",
1054 local_path
, strerror(errno
));
1055 do_close(conn
, handle
, handle_len
);
1061 /* Read from remote and write to local */
1062 write_error
= read_error
= write_errno
= num_req
= offset
= 0;
1064 progress_counter
= 0;
1066 if (showprogress
&& size
!= 0)
1067 start_progress_meter(remote_path
, size
, &progress_counter
);
1069 while (num_req
> 0 || max_req
> 0) {
1074 * Simulate EOF on interrupt: stop sending new requests and
1075 * allow outstanding requests to drain gracefully
1078 if (num_req
== 0) /* If we haven't started yet... */
1083 /* Send some more requests */
1084 while (num_req
< max_req
) {
1085 debug3("Request range %llu -> %llu (%d/%d)",
1086 (unsigned long long)offset
,
1087 (unsigned long long)offset
+ buflen
- 1,
1089 req
= xmalloc(sizeof(*req
));
1090 req
->id
= conn
->msg_id
++;
1092 req
->offset
= offset
;
1095 TAILQ_INSERT_TAIL(&requests
, req
, tq
);
1096 send_read_request(conn
, req
->id
, req
->offset
,
1097 req
->len
, handle
, handle_len
);
1101 get_msg(conn
, &msg
);
1102 type
= buffer_get_char(&msg
);
1103 id
= buffer_get_int(&msg
);
1104 debug3("Received reply T:%u I:%u R:%d", type
, id
, max_req
);
1106 /* Find the request in our queue */
1107 for (req
= TAILQ_FIRST(&requests
);
1108 req
!= NULL
&& req
->id
!= id
;
1109 req
= TAILQ_NEXT(req
, tq
))
1112 fatal("Unexpected reply %u", id
);
1115 case SSH2_FXP_STATUS
:
1116 status
= buffer_get_int(&msg
);
1117 if (status
!= SSH2_FX_EOF
)
1120 TAILQ_REMOVE(&requests
, req
, tq
);
1125 data
= buffer_get_string(&msg
, &len
);
1126 debug3("Received data %llu -> %llu",
1127 (unsigned long long)req
->offset
,
1128 (unsigned long long)req
->offset
+ len
- 1);
1130 fatal("Received more data than asked for "
1131 "%u > %u", len
, req
->len
);
1132 if ((lseek(local_fd
, req
->offset
, SEEK_SET
) == -1 ||
1133 atomicio(vwrite
, local_fd
, data
, len
) != len
) &&
1135 write_errno
= errno
;
1139 progress_counter
+= len
;
1142 if (len
== req
->len
) {
1143 TAILQ_REMOVE(&requests
, req
, tq
);
1147 /* Resend the request for the missing data */
1148 debug3("Short data block, re-requesting "
1149 "%llu -> %llu (%2d)",
1150 (unsigned long long)req
->offset
+ len
,
1151 (unsigned long long)req
->offset
+
1152 req
->len
- 1, num_req
);
1153 req
->id
= conn
->msg_id
++;
1156 send_read_request(conn
, req
->id
,
1157 req
->offset
, req
->len
, handle
, handle_len
);
1158 /* Reduce the request size */
1160 buflen
= MAX(MIN_READ_SIZE
, len
);
1162 if (max_req
> 0) { /* max_req = 0 iff EOF received */
1163 if (size
> 0 && offset
> size
) {
1164 /* Only one request at a time
1165 * after the expected EOF */
1166 debug3("Finish at %llu (%2d)",
1167 (unsigned long long)offset
,
1170 } else if (max_req
<= conn
->num_requests
) {
1176 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1177 SSH2_FXP_DATA
, type
);
1181 if (showprogress
&& size
)
1182 stop_progress_meter();
1185 if (TAILQ_FIRST(&requests
) != NULL
)
1186 fatal("Transfer complete, but requests still in queue");
1189 error("Couldn't read from remote file \"%s\" : %s",
1190 remote_path
, fx2txt(status
));
1191 do_close(conn
, handle
, handle_len
);
1192 } else if (write_error
) {
1193 error("Couldn't write to \"%s\": %s", local_path
,
1194 strerror(write_errno
));
1196 do_close(conn
, handle
, handle_len
);
1198 status
= do_close(conn
, handle
, handle_len
);
1200 /* Override umask and utimes if asked */
1202 if (pflag
&& fchmod(local_fd
, mode
) == -1)
1204 if (pflag
&& chmod(local_path
, mode
) == -1)
1205 #endif /* HAVE_FCHMOD */
1206 error("Couldn't set mode on \"%s\": %s", local_path
,
1208 if (pflag
&& (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
)) {
1209 struct timeval tv
[2];
1210 tv
[0].tv_sec
= a
->atime
;
1211 tv
[1].tv_sec
= a
->mtime
;
1212 tv
[0].tv_usec
= tv
[1].tv_usec
= 0;
1213 if (utimes(local_path
, tv
) == -1)
1214 error("Can't set times on \"%s\": %s",
1215 local_path
, strerror(errno
));
1226 download_dir_internal(struct sftp_conn
*conn
, char *src
, char *dst
,
1227 Attrib
*dirattrib
, int pflag
, int printflag
, int depth
)
1230 SFTP_DIRENT
**dir_entries
;
1231 char *filename
, *new_src
, *new_dst
;
1234 if (depth
>= MAX_DIR_DEPTH
) {
1235 error("Maximum directory depth exceeded: %d levels", depth
);
1239 if (dirattrib
== NULL
&&
1240 (dirattrib
= do_stat(conn
, src
, 1)) == NULL
) {
1241 error("Unable to stat remote directory \"%s\"", src
);
1244 if (!S_ISDIR(dirattrib
->perm
)) {
1245 error("\"%s\" is not a directory", src
);
1249 printf("Retrieving %s\n", src
);
1251 if (dirattrib
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
)
1252 mode
= dirattrib
->perm
& 01777;
1254 debug("Server did not send permissions for "
1255 "directory \"%s\"", dst
);
1258 if (mkdir(dst
, mode
) == -1 && errno
!= EEXIST
) {
1259 error("mkdir %s: %s", dst
, strerror(errno
));
1263 if (do_readdir(conn
, src
, &dir_entries
) == -1) {
1264 error("%s: Failed to get directory contents", src
);
1268 for (i
= 0; dir_entries
[i
] != NULL
&& !interrupted
; i
++) {
1269 filename
= dir_entries
[i
]->filename
;
1271 new_dst
= path_append(dst
, filename
);
1272 new_src
= path_append(src
, filename
);
1274 if (S_ISDIR(dir_entries
[i
]->a
.perm
)) {
1275 if (strcmp(filename
, ".") == 0 ||
1276 strcmp(filename
, "..") == 0)
1278 if (download_dir_internal(conn
, new_src
, new_dst
,
1279 &(dir_entries
[i
]->a
), pflag
, printflag
,
1282 } else if (S_ISREG(dir_entries
[i
]->a
.perm
) ) {
1283 if (do_download(conn
, new_src
, new_dst
,
1284 &(dir_entries
[i
]->a
), pflag
) == -1) {
1285 error("Download of file %s to %s failed",
1290 logit("%s: not a regular file\n", new_src
);
1297 if (dirattrib
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
) {
1298 struct timeval tv
[2];
1299 tv
[0].tv_sec
= dirattrib
->atime
;
1300 tv
[1].tv_sec
= dirattrib
->mtime
;
1301 tv
[0].tv_usec
= tv
[1].tv_usec
= 0;
1302 if (utimes(dst
, tv
) == -1)
1303 error("Can't set times on \"%s\": %s",
1304 dst
, strerror(errno
));
1306 debug("Server did not send times for directory "
1310 free_sftp_dirents(dir_entries
);
1316 download_dir(struct sftp_conn
*conn
, char *src
, char *dst
,
1317 Attrib
*dirattrib
, int pflag
, int printflag
)
1322 if ((src_canon
= do_realpath(conn
, src
)) == NULL
) {
1323 error("Unable to canonicalise path \"%s\"", src
);
1327 ret
= download_dir_internal(conn
, src_canon
, dst
,
1328 dirattrib
, pflag
, printflag
, 0);
1334 do_upload(struct sftp_conn
*conn
, char *local_path
, char *remote_path
,
1338 int status
= SSH2_FX_OK
;
1339 u_int handle_len
, id
, type
;
1341 char *handle
, *data
;
1347 struct outstanding_ack
{
1351 TAILQ_ENTRY(outstanding_ack
) tq
;
1353 TAILQ_HEAD(ackhead
, outstanding_ack
) acks
;
1354 struct outstanding_ack
*ack
= NULL
;
1358 if ((local_fd
= open(local_path
, O_RDONLY
, 0)) == -1) {
1359 error("Couldn't open local file \"%s\" for reading: %s",
1360 local_path
, strerror(errno
));
1363 if (fstat(local_fd
, &sb
) == -1) {
1364 error("Couldn't fstat local file \"%s\": %s",
1365 local_path
, strerror(errno
));
1369 if (!S_ISREG(sb
.st_mode
)) {
1370 error("%s is not a regular file", local_path
);
1374 stat_to_attrib(&sb
, &a
);
1376 a
.flags
&= ~SSH2_FILEXFER_ATTR_SIZE
;
1377 a
.flags
&= ~SSH2_FILEXFER_ATTR_UIDGID
;
1380 a
.flags
&= ~SSH2_FILEXFER_ATTR_ACMODTIME
;
1384 /* Send open request */
1385 id
= conn
->msg_id
++;
1386 buffer_put_char(&msg
, SSH2_FXP_OPEN
);
1387 buffer_put_int(&msg
, id
);
1388 buffer_put_cstring(&msg
, remote_path
);
1389 buffer_put_int(&msg
, SSH2_FXF_WRITE
|SSH2_FXF_CREAT
|SSH2_FXF_TRUNC
);
1390 encode_attrib(&msg
, &a
);
1391 send_msg(conn
, &msg
);
1392 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id
, remote_path
);
1396 handle
= get_handle(conn
, id
, &handle_len
,
1397 "remote open(\"%s\")", remote_path
);
1398 if (handle
== NULL
) {
1404 startid
= ackid
= id
+ 1;
1405 data
= xmalloc(conn
->transfer_buflen
);
1407 /* Read from local and write to remote */
1410 start_progress_meter(local_path
, sb
.st_size
, &offset
);
1416 * Can't use atomicio here because it returns 0 on EOF,
1417 * thus losing the last block of the file.
1418 * Simulate an EOF on interrupt, allowing ACKs from the
1421 if (interrupted
|| status
!= SSH2_FX_OK
)
1424 len
= read(local_fd
, data
, conn
->transfer_buflen
);
1425 while ((len
== -1) &&
1426 (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
1429 fatal("Couldn't read from \"%s\": %s", local_path
,
1433 ack
= xmalloc(sizeof(*ack
));
1435 ack
->offset
= offset
;
1437 TAILQ_INSERT_TAIL(&acks
, ack
, tq
);
1440 buffer_put_char(&msg
, SSH2_FXP_WRITE
);
1441 buffer_put_int(&msg
, ack
->id
);
1442 buffer_put_string(&msg
, handle
, handle_len
);
1443 buffer_put_int64(&msg
, offset
);
1444 buffer_put_string(&msg
, data
, len
);
1445 send_msg(conn
, &msg
);
1446 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1447 id
, (unsigned long long)offset
, len
);
1448 } else if (TAILQ_FIRST(&acks
) == NULL
)
1452 fatal("Unexpected ACK %u", id
);
1454 if (id
== startid
|| len
== 0 ||
1455 id
- ackid
>= conn
->num_requests
) {
1459 get_msg(conn
, &msg
);
1460 type
= buffer_get_char(&msg
);
1461 r_id
= buffer_get_int(&msg
);
1463 if (type
!= SSH2_FXP_STATUS
)
1464 fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1465 "got %d", SSH2_FXP_STATUS
, type
);
1467 status
= buffer_get_int(&msg
);
1468 debug3("SSH2_FXP_STATUS %d", status
);
1470 /* Find the request in our queue */
1471 for (ack
= TAILQ_FIRST(&acks
);
1472 ack
!= NULL
&& ack
->id
!= r_id
;
1473 ack
= TAILQ_NEXT(ack
, tq
))
1476 fatal("Can't find request for ID %u", r_id
);
1477 TAILQ_REMOVE(&acks
, ack
, tq
);
1478 debug3("In write loop, ack for %u %u bytes at %lld",
1479 ack
->id
, ack
->len
, (long long)ack
->offset
);
1485 fatal("%s: offset < 0", __func__
);
1490 stop_progress_meter();
1493 if (status
!= SSH2_FX_OK
) {
1494 error("Couldn't write to remote file \"%s\": %s",
1495 remote_path
, fx2txt(status
));
1499 if (close(local_fd
) == -1) {
1500 error("Couldn't close local file \"%s\": %s", local_path
,
1505 /* Override umask and utimes if asked */
1507 do_fsetstat(conn
, handle
, handle_len
, &a
);
1509 if (do_close(conn
, handle
, handle_len
) != SSH2_FX_OK
)
1517 upload_dir_internal(struct sftp_conn
*conn
, char *src
, char *dst
,
1518 int pflag
, int printflag
, int depth
)
1520 int ret
= 0, status
;
1523 char *filename
, *new_src
, *new_dst
;
1527 if (depth
>= MAX_DIR_DEPTH
) {
1528 error("Maximum directory depth exceeded: %d levels", depth
);
1532 if (stat(src
, &sb
) == -1) {
1533 error("Couldn't stat directory \"%s\": %s",
1534 src
, strerror(errno
));
1537 if (!S_ISDIR(sb
.st_mode
)) {
1538 error("\"%s\" is not a directory", src
);
1542 printf("Entering %s\n", src
);
1545 stat_to_attrib(&sb
, &a
);
1546 a
.flags
&= ~SSH2_FILEXFER_ATTR_SIZE
;
1547 a
.flags
&= ~SSH2_FILEXFER_ATTR_UIDGID
;
1550 a
.flags
&= ~SSH2_FILEXFER_ATTR_ACMODTIME
;
1552 status
= do_mkdir(conn
, dst
, &a
, 0);
1554 * we lack a portable status for errno EEXIST,
1555 * so if we get a SSH2_FX_FAILURE back we must check
1556 * if it was created successfully.
1558 if (status
!= SSH2_FX_OK
) {
1559 if (status
!= SSH2_FX_FAILURE
)
1561 if (do_stat(conn
, dst
, 0) == NULL
)
1565 if ((dirp
= opendir(src
)) == NULL
) {
1566 error("Failed to open dir \"%s\": %s", src
, strerror(errno
));
1570 while (((dp
= readdir(dirp
)) != NULL
) && !interrupted
) {
1573 filename
= dp
->d_name
;
1574 new_dst
= path_append(dst
, filename
);
1575 new_src
= path_append(src
, filename
);
1577 if (lstat(new_src
, &sb
) == -1) {
1578 logit("%s: lstat failed: %s", filename
,
1581 } else if (S_ISDIR(sb
.st_mode
)) {
1582 if (strcmp(filename
, ".") == 0 ||
1583 strcmp(filename
, "..") == 0)
1586 if (upload_dir_internal(conn
, new_src
, new_dst
,
1587 pflag
, printflag
, depth
+ 1) == -1)
1589 } else if (S_ISREG(sb
.st_mode
)) {
1590 if (do_upload(conn
, new_src
, new_dst
, pflag
) == -1) {
1591 error("Uploading of file %s to %s failed!",
1596 logit("%s: not a regular file\n", filename
);
1601 do_setstat(conn
, dst
, &a
);
1603 (void) closedir(dirp
);
1608 upload_dir(struct sftp_conn
*conn
, char *src
, char *dst
, int printflag
,
1614 if ((dst_canon
= do_realpath(conn
, dst
)) == NULL
) {
1615 error("Unable to canonicalise path \"%s\"", dst
);
1619 ret
= upload_dir_internal(conn
, src
, dst_canon
, pflag
, printflag
, 0);
1625 path_append(char *p1
, char *p2
)
1628 size_t len
= strlen(p1
) + strlen(p2
) + 2;
1631 strlcpy(ret
, p1
, len
);
1632 if (p1
[0] != '\0' && p1
[strlen(p1
) - 1] != '/')
1633 strlcat(ret
, "/", len
);
1634 strlcat(ret
, p2
, len
);