diff options
author | Colin Watson <cjwatson@debian.org> | 2009-12-29 21:42:53 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2009-12-29 21:42:53 +0000 |
commit | 87552344215a38d3a2b0d4d63dc151e05978bbe1 (patch) | |
tree | 9f4b96055e6ccaa915e8d59d9f2805e9e119371d /sftp-client.c | |
parent | a25ec0b132c44c9e341e08464ff830de06b81126 (diff) | |
parent | ef94e5613d37bcbf880f21ee6094e4b1c7683a4c (diff) |
import openssh-5.1p1-gsskex-cjwatson-20080722.patch
Diffstat (limited to 'sftp-client.c')
-rw-r--r-- | sftp-client.c | 214 |
1 files changed, 177 insertions, 37 deletions
diff --git a/sftp-client.c b/sftp-client.c index 2746f3245..5e39aa7d2 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.c,v 1.76 2007/01/22 11:32:50 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.c,v 1.86 2008/06/26 06:10:09 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -24,6 +24,9 @@ | |||
24 | 24 | ||
25 | #include <sys/types.h> | 25 | #include <sys/types.h> |
26 | #include <sys/param.h> | 26 | #include <sys/param.h> |
27 | #ifdef HAVE_SYS_STATVFS_H | ||
28 | #include <sys/statvfs.h> | ||
29 | #endif | ||
27 | #include "openbsd-compat/sys-queue.h" | 30 | #include "openbsd-compat/sys-queue.h" |
28 | #ifdef HAVE_SYS_STAT_H | 31 | #ifdef HAVE_SYS_STAT_H |
29 | # include <sys/stat.h> | 32 | # include <sys/stat.h> |
@@ -65,6 +68,10 @@ struct sftp_conn { | |||
65 | u_int num_requests; | 68 | u_int num_requests; |
66 | u_int version; | 69 | u_int version; |
67 | u_int msg_id; | 70 | u_int msg_id; |
71 | #define SFTP_EXT_POSIX_RENAME 0x00000001 | ||
72 | #define SFTP_EXT_STATVFS 0x00000002 | ||
73 | #define SFTP_EXT_FSTATVFS 0x00000004 | ||
74 | u_int exts; | ||
68 | }; | 75 | }; |
69 | 76 | ||
70 | static void | 77 | static void |
@@ -236,10 +243,61 @@ get_decode_stat(int fd, u_int expected_id, int quiet) | |||
236 | return(a); | 243 | return(a); |
237 | } | 244 | } |
238 | 245 | ||
246 | static int | ||
247 | get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id, | ||
248 | int quiet) | ||
249 | { | ||
250 | Buffer msg; | ||
251 | u_int type, id, flag; | ||
252 | |||
253 | buffer_init(&msg); | ||
254 | get_msg(fd, &msg); | ||
255 | |||
256 | type = buffer_get_char(&msg); | ||
257 | id = buffer_get_int(&msg); | ||
258 | |||
259 | debug3("Received statvfs 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); | ||
264 | |||
265 | if (quiet) | ||
266 | debug("Couldn't statvfs: %s", fx2txt(status)); | ||
267 | else | ||
268 | error("Couldn't statvfs: %s", fx2txt(status)); | ||
269 | buffer_free(&msg); | ||
270 | return -1; | ||
271 | } else if (type != SSH2_FXP_EXTENDED_REPLY) { | ||
272 | fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", | ||
273 | SSH2_FXP_EXTENDED_REPLY, type); | ||
274 | } | ||
275 | |||
276 | bzero(st, sizeof(*st)); | ||
277 | st->f_bsize = buffer_get_int64(&msg); | ||
278 | st->f_frsize = buffer_get_int64(&msg); | ||
279 | st->f_blocks = buffer_get_int64(&msg); | ||
280 | st->f_bfree = buffer_get_int64(&msg); | ||
281 | st->f_bavail = buffer_get_int64(&msg); | ||
282 | st->f_files = buffer_get_int64(&msg); | ||
283 | st->f_ffree = buffer_get_int64(&msg); | ||
284 | st->f_favail = buffer_get_int64(&msg); | ||
285 | st->f_fsid = buffer_get_int64(&msg); | ||
286 | flag = buffer_get_int64(&msg); | ||
287 | st->f_namemax = buffer_get_int64(&msg); | ||
288 | |||
289 | st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; | ||
290 | st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; | ||
291 | |||
292 | buffer_free(&msg); | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
239 | struct sftp_conn * | 297 | struct sftp_conn * |
240 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | 298 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) |
241 | { | 299 | { |
242 | u_int type; | 300 | u_int type, exts = 0; |
243 | int version; | 301 | int version; |
244 | Buffer msg; | 302 | Buffer msg; |
245 | struct sftp_conn *ret; | 303 | struct sftp_conn *ret; |
@@ -268,8 +326,27 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
268 | while (buffer_len(&msg) > 0) { | 326 | while (buffer_len(&msg) > 0) { |
269 | char *name = buffer_get_string(&msg, NULL); | 327 | char *name = buffer_get_string(&msg, NULL); |
270 | char *value = buffer_get_string(&msg, NULL); | 328 | char *value = buffer_get_string(&msg, NULL); |
271 | 329 | int known = 0; | |
272 | debug2("Init extension: \"%s\"", name); | 330 | |
331 | if (strcmp(name, "posix-rename@openssh.com") == 0 && | ||
332 | strcmp(value, "1") == 0) { | ||
333 | exts |= SFTP_EXT_POSIX_RENAME; | ||
334 | known = 1; | ||
335 | } else if (strcmp(name, "statvfs@openssh.com") == 0 && | ||
336 | strcmp(value, "2") == 0) { | ||
337 | exts |= SFTP_EXT_STATVFS; | ||
338 | known = 1; | ||
339 | } if (strcmp(name, "fstatvfs@openssh.com") == 0 && | ||
340 | strcmp(value, "2") == 0) { | ||
341 | exts |= SFTP_EXT_FSTATVFS; | ||
342 | known = 1; | ||
343 | } | ||
344 | if (known) { | ||
345 | debug2("Server supports extension \"%s\" revision %s", | ||
346 | name, value); | ||
347 | } else { | ||
348 | debug2("Unrecognised server extension \"%s\"", name); | ||
349 | } | ||
273 | xfree(name); | 350 | xfree(name); |
274 | xfree(value); | 351 | xfree(value); |
275 | } | 352 | } |
@@ -283,6 +360,7 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
283 | ret->num_requests = num_requests; | 360 | ret->num_requests = num_requests; |
284 | ret->version = version; | 361 | ret->version = version; |
285 | ret->msg_id = 1; | 362 | ret->msg_id = 1; |
363 | ret->exts = exts; | ||
286 | 364 | ||
287 | /* Some filexfer v.0 servers don't support large packets */ | 365 | /* Some filexfer v.0 servers don't support large packets */ |
288 | if (version == 0) | 366 | if (version == 0) |
@@ -534,6 +612,7 @@ do_lstat(struct sftp_conn *conn, char *path, int quiet) | |||
534 | return(get_decode_stat(conn->fd_in, id, quiet)); | 612 | return(get_decode_stat(conn->fd_in, id, quiet)); |
535 | } | 613 | } |
536 | 614 | ||
615 | #ifdef notyet | ||
537 | Attrib * | 616 | Attrib * |
538 | do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) | 617 | do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) |
539 | { | 618 | { |
@@ -545,6 +624,7 @@ do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) | |||
545 | 624 | ||
546 | return(get_decode_stat(conn->fd_in, id, quiet)); | 625 | return(get_decode_stat(conn->fd_in, id, quiet)); |
547 | } | 626 | } |
627 | #endif | ||
548 | 628 | ||
549 | int | 629 | int |
550 | do_setstat(struct sftp_conn *conn, char *path, Attrib *a) | 630 | do_setstat(struct sftp_conn *conn, char *path, Attrib *a) |
@@ -637,13 +717,20 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
637 | 717 | ||
638 | /* Send rename request */ | 718 | /* Send rename request */ |
639 | id = conn->msg_id++; | 719 | id = conn->msg_id++; |
640 | buffer_put_char(&msg, SSH2_FXP_RENAME); | 720 | if ((conn->exts & SFTP_EXT_POSIX_RENAME)) { |
641 | buffer_put_int(&msg, id); | 721 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); |
722 | buffer_put_int(&msg, id); | ||
723 | buffer_put_cstring(&msg, "posix-rename@openssh.com"); | ||
724 | } else { | ||
725 | buffer_put_char(&msg, SSH2_FXP_RENAME); | ||
726 | buffer_put_int(&msg, id); | ||
727 | } | ||
642 | buffer_put_cstring(&msg, oldpath); | 728 | buffer_put_cstring(&msg, oldpath); |
643 | buffer_put_cstring(&msg, newpath); | 729 | buffer_put_cstring(&msg, newpath); |
644 | send_msg(conn->fd_out, &msg); | 730 | send_msg(conn->fd_out, &msg); |
645 | debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, | 731 | debug3("Sent message %s \"%s\" -> \"%s\"", |
646 | newpath); | 732 | (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : |
733 | "SSH2_FXP_RENAME", oldpath, newpath); | ||
647 | buffer_free(&msg); | 734 | buffer_free(&msg); |
648 | 735 | ||
649 | status = get_status(conn->fd_in, id); | 736 | status = get_status(conn->fd_in, id); |
@@ -686,6 +773,7 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
686 | return(status); | 773 | return(status); |
687 | } | 774 | } |
688 | 775 | ||
776 | #ifdef notyet | ||
689 | char * | 777 | char * |
690 | do_readlink(struct sftp_conn *conn, char *path) | 778 | do_readlink(struct sftp_conn *conn, char *path) |
691 | { | 779 | { |
@@ -732,6 +820,61 @@ do_readlink(struct sftp_conn *conn, char *path) | |||
732 | 820 | ||
733 | return(filename); | 821 | return(filename); |
734 | } | 822 | } |
823 | #endif | ||
824 | |||
825 | int | ||
826 | do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, | ||
827 | int quiet) | ||
828 | { | ||
829 | Buffer msg; | ||
830 | u_int id; | ||
831 | |||
832 | if ((conn->exts & SFTP_EXT_STATVFS) == 0) { | ||
833 | error("Server does not support statvfs@openssh.com extension"); | ||
834 | return -1; | ||
835 | } | ||
836 | |||
837 | id = conn->msg_id++; | ||
838 | |||
839 | buffer_init(&msg); | ||
840 | buffer_clear(&msg); | ||
841 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); | ||
842 | buffer_put_int(&msg, id); | ||
843 | buffer_put_cstring(&msg, "statvfs@openssh.com"); | ||
844 | buffer_put_cstring(&msg, path); | ||
845 | send_msg(conn->fd_out, &msg); | ||
846 | buffer_free(&msg); | ||
847 | |||
848 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | ||
849 | } | ||
850 | |||
851 | #ifdef notyet | ||
852 | int | ||
853 | do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, | ||
854 | struct sftp_statvfs *st, int quiet) | ||
855 | { | ||
856 | Buffer msg; | ||
857 | u_int id; | ||
858 | |||
859 | if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { | ||
860 | error("Server does not support fstatvfs@openssh.com extension"); | ||
861 | return -1; | ||
862 | } | ||
863 | |||
864 | id = conn->msg_id++; | ||
865 | |||
866 | buffer_init(&msg); | ||
867 | buffer_clear(&msg); | ||
868 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); | ||
869 | buffer_put_int(&msg, id); | ||
870 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); | ||
871 | buffer_put_string(&msg, handle, handle_len); | ||
872 | send_msg(conn->fd_out, &msg); | ||
873 | buffer_free(&msg); | ||
874 | |||
875 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | ||
876 | } | ||
877 | #endif | ||
735 | 878 | ||
736 | static void | 879 | static void |
737 | send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | 880 | send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, |
@@ -777,7 +920,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
777 | if (a == NULL) | 920 | if (a == NULL) |
778 | return(-1); | 921 | return(-1); |
779 | 922 | ||
780 | /* XXX: should we preserve set[ug]id? */ | 923 | /* Do not preserve set[ug]id here, as we do not preserve ownership */ |
781 | if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) | 924 | if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) |
782 | mode = a->perm & 0777; | 925 | mode = a->perm & 0777; |
783 | else | 926 | else |
@@ -819,6 +962,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
819 | if (local_fd == -1) { | 962 | if (local_fd == -1) { |
820 | error("Couldn't open local file \"%s\" for writing: %s", | 963 | error("Couldn't open local file \"%s\" for writing: %s", |
821 | local_path, strerror(errno)); | 964 | local_path, strerror(errno)); |
965 | do_close(conn, handle, handle_len); | ||
822 | buffer_free(&msg); | 966 | buffer_free(&msg); |
823 | xfree(handle); | 967 | xfree(handle); |
824 | return(-1); | 968 | return(-1); |
@@ -992,9 +1136,10 @@ int | |||
992 | do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | 1136 | do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, |
993 | int pflag) | 1137 | int pflag) |
994 | { | 1138 | { |
995 | int local_fd, status; | 1139 | int local_fd; |
1140 | int status = SSH2_FX_OK; | ||
996 | u_int handle_len, id, type; | 1141 | u_int handle_len, id, type; |
997 | u_int64_t offset; | 1142 | off_t offset; |
998 | char *handle, *data; | 1143 | char *handle, *data; |
999 | Buffer msg; | 1144 | Buffer msg; |
1000 | struct stat sb; | 1145 | struct stat sb; |
@@ -1004,7 +1149,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1004 | struct outstanding_ack { | 1149 | struct outstanding_ack { |
1005 | u_int id; | 1150 | u_int id; |
1006 | u_int len; | 1151 | u_int len; |
1007 | u_int64_t offset; | 1152 | off_t offset; |
1008 | TAILQ_ENTRY(outstanding_ack) tq; | 1153 | TAILQ_ENTRY(outstanding_ack) tq; |
1009 | }; | 1154 | }; |
1010 | TAILQ_HEAD(ackhead, outstanding_ack) acks; | 1155 | TAILQ_HEAD(ackhead, outstanding_ack) acks; |
@@ -1054,7 +1199,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1054 | if (handle == NULL) { | 1199 | if (handle == NULL) { |
1055 | close(local_fd); | 1200 | close(local_fd); |
1056 | buffer_free(&msg); | 1201 | buffer_free(&msg); |
1057 | return(-1); | 1202 | return -1; |
1058 | } | 1203 | } |
1059 | 1204 | ||
1060 | startid = ackid = id + 1; | 1205 | startid = ackid = id + 1; |
@@ -1074,11 +1219,12 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1074 | * Simulate an EOF on interrupt, allowing ACKs from the | 1219 | * Simulate an EOF on interrupt, allowing ACKs from the |
1075 | * server to drain. | 1220 | * server to drain. |
1076 | */ | 1221 | */ |
1077 | if (interrupted) | 1222 | if (interrupted || status != SSH2_FX_OK) |
1078 | len = 0; | 1223 | len = 0; |
1079 | else do | 1224 | else do |
1080 | len = read(local_fd, data, conn->transfer_buflen); | 1225 | len = read(local_fd, data, conn->transfer_buflen); |
1081 | while ((len == -1) && (errno == EINTR || errno == EAGAIN)); | 1226 | while ((len == -1) && |
1227 | (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)); | ||
1082 | 1228 | ||
1083 | if (len == -1) | 1229 | if (len == -1) |
1084 | fatal("Couldn't read from \"%s\": %s", local_path, | 1230 | fatal("Couldn't read from \"%s\": %s", local_path, |
@@ -1130,46 +1276,40 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1130 | if (ack == NULL) | 1276 | if (ack == NULL) |
1131 | fatal("Can't find request for ID %u", r_id); | 1277 | fatal("Can't find request for ID %u", r_id); |
1132 | TAILQ_REMOVE(&acks, ack, tq); | 1278 | TAILQ_REMOVE(&acks, ack, tq); |
1133 | 1279 | debug3("In write loop, ack for %u %u bytes at %lld", | |
1134 | if (status != SSH2_FX_OK) { | 1280 | ack->id, ack->len, (long long)ack->offset); |
1135 | error("Couldn't write to remote file \"%s\": %s", | ||
1136 | remote_path, fx2txt(status)); | ||
1137 | if (showprogress) | ||
1138 | stop_progress_meter(); | ||
1139 | do_close(conn, handle, handle_len); | ||
1140 | close(local_fd); | ||
1141 | xfree(data); | ||
1142 | xfree(ack); | ||
1143 | status = -1; | ||
1144 | goto done; | ||
1145 | } | ||
1146 | debug3("In write loop, ack for %u %u bytes at %llu", | ||
1147 | ack->id, ack->len, (unsigned long long)ack->offset); | ||
1148 | ++ackid; | 1281 | ++ackid; |
1149 | xfree(ack); | 1282 | xfree(ack); |
1150 | } | 1283 | } |
1151 | offset += len; | 1284 | offset += len; |
1285 | if (offset < 0) | ||
1286 | fatal("%s: offset < 0", __func__); | ||
1152 | } | 1287 | } |
1288 | buffer_free(&msg); | ||
1289 | |||
1153 | if (showprogress) | 1290 | if (showprogress) |
1154 | stop_progress_meter(); | 1291 | stop_progress_meter(); |
1155 | xfree(data); | 1292 | xfree(data); |
1156 | 1293 | ||
1294 | if (status != SSH2_FX_OK) { | ||
1295 | error("Couldn't write to remote file \"%s\": %s", | ||
1296 | remote_path, fx2txt(status)); | ||
1297 | status = -1; | ||
1298 | } | ||
1299 | |||
1157 | if (close(local_fd) == -1) { | 1300 | if (close(local_fd) == -1) { |
1158 | error("Couldn't close local file \"%s\": %s", local_path, | 1301 | error("Couldn't close local file \"%s\": %s", local_path, |
1159 | strerror(errno)); | 1302 | strerror(errno)); |
1160 | do_close(conn, handle, handle_len); | ||
1161 | status = -1; | 1303 | status = -1; |
1162 | goto done; | ||
1163 | } | 1304 | } |
1164 | 1305 | ||
1165 | /* Override umask and utimes if asked */ | 1306 | /* Override umask and utimes if asked */ |
1166 | if (pflag) | 1307 | if (pflag) |
1167 | do_fsetstat(conn, handle, handle_len, &a); | 1308 | do_fsetstat(conn, handle, handle_len, &a); |
1168 | 1309 | ||
1169 | status = do_close(conn, handle, handle_len); | 1310 | if (do_close(conn, handle, handle_len) != SSH2_FX_OK) |
1170 | 1311 | status = -1; | |
1171 | done: | ||
1172 | xfree(handle); | 1312 | xfree(handle); |
1173 | buffer_free(&msg); | 1313 | |
1174 | return(status); | 1314 | return status; |
1175 | } | 1315 | } |