diff options
author | Colin Watson <cjwatson@debian.org> | 2011-01-24 12:43:25 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2011-01-24 12:43:25 +0000 |
commit | 626f1d986ff72aa514da63e34744e1de9cf21b9a (patch) | |
tree | d215a5280bc2e57251e4a9e08bfd3674ad824a94 /sftp-client.c | |
parent | 6ed622cb6fe8f71bbe0d998cdd12280410bfb420 (diff) | |
parent | 0970072c89b079b022538e3c366fbfa2c53fc821 (diff) |
* New upstream release (http://www.openssh.org/txt/release-5.7):
- Implement Elliptic Curve Cryptography modes for key exchange (ECDH)
and host/user keys (ECDSA) as specified by RFC5656. ECDH and ECDSA
offer better performance than plain DH and DSA at the same equivalent
symmetric key length, as well as much shorter keys.
- sftp(1)/sftp-server(8): add a protocol extension to support a hard
link operation. It is available through the "ln" command in the
client. The old "ln" behaviour of creating a symlink is available
using its "-s" option or through the preexisting "symlink" command.
- scp(1): Add a new -3 option to scp: Copies between two remote hosts
are transferred through the local host (closes: #508613).
- ssh(1): "atomically" create the listening mux socket by binding it on
a temporary name and then linking it into position after listen() has
succeeded. This allows the mux clients to determine that the server
socket is either ready or stale without races (closes: #454784).
Stale server sockets are now automatically removed (closes: #523250).
- ssh(1): install a SIGCHLD handler to reap expired child process
(closes: #594687).
- ssh(1)/ssh-agent(1): honour $TMPDIR for client xauth and ssh-agent
temporary directories (closes: #357469, although only if you arrange
for ssh-agent to actually see $TMPDIR since the setgid bit will cause
it to be stripped off).
Diffstat (limited to 'sftp-client.c')
-rw-r--r-- | sftp-client.c | 259 |
1 files changed, 160 insertions, 99 deletions
diff --git a/sftp-client.c b/sftp-client.c index 9dab47780..caa384b4e 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.c,v 1.92 2010/07/19 03:16:33 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 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 | * |
@@ -75,15 +75,28 @@ struct sftp_conn { | |||
75 | #define SFTP_EXT_POSIX_RENAME 0x00000001 | 75 | #define SFTP_EXT_POSIX_RENAME 0x00000001 |
76 | #define SFTP_EXT_STATVFS 0x00000002 | 76 | #define SFTP_EXT_STATVFS 0x00000002 |
77 | #define SFTP_EXT_FSTATVFS 0x00000004 | 77 | #define SFTP_EXT_FSTATVFS 0x00000004 |
78 | #define SFTP_EXT_HARDLINK 0x00000008 | ||
78 | u_int exts; | 79 | u_int exts; |
80 | u_int64_t limit_kbps; | ||
81 | struct bwlimit bwlimit_in, bwlimit_out; | ||
79 | }; | 82 | }; |
80 | 83 | ||
81 | static char * | 84 | static char * |
82 | get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | 85 | get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, |
83 | __attribute__((format(printf, 4, 5))); | 86 | const char *errfmt, ...) __attribute__((format(printf, 4, 5))); |
87 | |||
88 | /* ARGSUSED */ | ||
89 | static int | ||
90 | sftpio(void *_bwlimit, size_t amount) | ||
91 | { | ||
92 | struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; | ||
93 | |||
94 | bandwidth_limit(bwlimit, amount); | ||
95 | return 0; | ||
96 | } | ||
84 | 97 | ||
85 | static void | 98 | static void |
86 | send_msg(int fd, Buffer *m) | 99 | send_msg(struct sftp_conn *conn, Buffer *m) |
87 | { | 100 | { |
88 | u_char mlen[4]; | 101 | u_char mlen[4]; |
89 | struct iovec iov[2]; | 102 | struct iovec iov[2]; |
@@ -98,19 +111,22 @@ send_msg(int fd, Buffer *m) | |||
98 | iov[1].iov_base = buffer_ptr(m); | 111 | iov[1].iov_base = buffer_ptr(m); |
99 | iov[1].iov_len = buffer_len(m); | 112 | iov[1].iov_len = buffer_len(m); |
100 | 113 | ||
101 | if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen)) | 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)) | ||
102 | fatal("Couldn't send packet: %s", strerror(errno)); | 117 | fatal("Couldn't send packet: %s", strerror(errno)); |
103 | 118 | ||
104 | buffer_clear(m); | 119 | buffer_clear(m); |
105 | } | 120 | } |
106 | 121 | ||
107 | static void | 122 | static void |
108 | get_msg(int fd, Buffer *m) | 123 | get_msg(struct sftp_conn *conn, Buffer *m) |
109 | { | 124 | { |
110 | u_int msg_len; | 125 | u_int msg_len; |
111 | 126 | ||
112 | buffer_append_space(m, 4); | 127 | buffer_append_space(m, 4); |
113 | if (atomicio(read, fd, buffer_ptr(m), 4) != 4) { | 128 | if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4, |
129 | conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { | ||
114 | if (errno == EPIPE) | 130 | if (errno == EPIPE) |
115 | fatal("Connection closed"); | 131 | fatal("Connection closed"); |
116 | else | 132 | else |
@@ -122,7 +138,9 @@ get_msg(int fd, Buffer *m) | |||
122 | fatal("Received message too long %u", msg_len); | 138 | fatal("Received message too long %u", msg_len); |
123 | 139 | ||
124 | buffer_append_space(m, msg_len); | 140 | buffer_append_space(m, msg_len); |
125 | if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) { | 141 | if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len, |
142 | conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) | ||
143 | != msg_len) { | ||
126 | if (errno == EPIPE) | 144 | if (errno == EPIPE) |
127 | fatal("Connection closed"); | 145 | fatal("Connection closed"); |
128 | else | 146 | else |
@@ -131,7 +149,7 @@ get_msg(int fd, Buffer *m) | |||
131 | } | 149 | } |
132 | 150 | ||
133 | static void | 151 | static void |
134 | send_string_request(int fd, u_int id, u_int code, char *s, | 152 | send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s, |
135 | u_int len) | 153 | u_int len) |
136 | { | 154 | { |
137 | Buffer msg; | 155 | Buffer msg; |
@@ -140,14 +158,14 @@ send_string_request(int fd, u_int id, u_int code, char *s, | |||
140 | buffer_put_char(&msg, code); | 158 | buffer_put_char(&msg, code); |
141 | buffer_put_int(&msg, id); | 159 | buffer_put_int(&msg, id); |
142 | buffer_put_string(&msg, s, len); | 160 | buffer_put_string(&msg, s, len); |
143 | send_msg(fd, &msg); | 161 | send_msg(conn, &msg); |
144 | debug3("Sent message fd %d T:%u I:%u", fd, code, id); | 162 | debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); |
145 | buffer_free(&msg); | 163 | buffer_free(&msg); |
146 | } | 164 | } |
147 | 165 | ||
148 | static void | 166 | static void |
149 | send_string_attrs_request(int fd, u_int id, u_int code, char *s, | 167 | send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, |
150 | u_int len, Attrib *a) | 168 | char *s, u_int len, Attrib *a) |
151 | { | 169 | { |
152 | Buffer msg; | 170 | Buffer msg; |
153 | 171 | ||
@@ -156,19 +174,19 @@ send_string_attrs_request(int fd, u_int id, u_int code, char *s, | |||
156 | buffer_put_int(&msg, id); | 174 | buffer_put_int(&msg, id); |
157 | buffer_put_string(&msg, s, len); | 175 | buffer_put_string(&msg, s, len); |
158 | encode_attrib(&msg, a); | 176 | encode_attrib(&msg, a); |
159 | send_msg(fd, &msg); | 177 | send_msg(conn, &msg); |
160 | debug3("Sent message fd %d T:%u I:%u", fd, code, id); | 178 | debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); |
161 | buffer_free(&msg); | 179 | buffer_free(&msg); |
162 | } | 180 | } |
163 | 181 | ||
164 | static u_int | 182 | static u_int |
165 | get_status(int fd, u_int expected_id) | 183 | get_status(struct sftp_conn *conn, u_int expected_id) |
166 | { | 184 | { |
167 | Buffer msg; | 185 | Buffer msg; |
168 | u_int type, id, status; | 186 | u_int type, id, status; |
169 | 187 | ||
170 | buffer_init(&msg); | 188 | buffer_init(&msg); |
171 | get_msg(fd, &msg); | 189 | get_msg(conn, &msg); |
172 | type = buffer_get_char(&msg); | 190 | type = buffer_get_char(&msg); |
173 | id = buffer_get_int(&msg); | 191 | id = buffer_get_int(&msg); |
174 | 192 | ||
@@ -183,11 +201,12 @@ get_status(int fd, u_int expected_id) | |||
183 | 201 | ||
184 | debug3("SSH2_FXP_STATUS %u", status); | 202 | debug3("SSH2_FXP_STATUS %u", status); |
185 | 203 | ||
186 | return(status); | 204 | return status; |
187 | } | 205 | } |
188 | 206 | ||
189 | static char * | 207 | static char * |
190 | get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | 208 | get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, |
209 | const char *errfmt, ...) | ||
191 | { | 210 | { |
192 | Buffer msg; | 211 | Buffer msg; |
193 | u_int type, id; | 212 | u_int type, id; |
@@ -201,7 +220,7 @@ get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | |||
201 | va_end(args); | 220 | va_end(args); |
202 | 221 | ||
203 | buffer_init(&msg); | 222 | buffer_init(&msg); |
204 | get_msg(fd, &msg); | 223 | get_msg(conn, &msg); |
205 | type = buffer_get_char(&msg); | 224 | type = buffer_get_char(&msg); |
206 | id = buffer_get_int(&msg); | 225 | id = buffer_get_int(&msg); |
207 | 226 | ||
@@ -225,14 +244,14 @@ get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | |||
225 | } | 244 | } |
226 | 245 | ||
227 | static Attrib * | 246 | static Attrib * |
228 | get_decode_stat(int fd, u_int expected_id, int quiet) | 247 | get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) |
229 | { | 248 | { |
230 | Buffer msg; | 249 | Buffer msg; |
231 | u_int type, id; | 250 | u_int type, id; |
232 | Attrib *a; | 251 | Attrib *a; |
233 | 252 | ||
234 | buffer_init(&msg); | 253 | buffer_init(&msg); |
235 | get_msg(fd, &msg); | 254 | get_msg(conn, &msg); |
236 | 255 | ||
237 | type = buffer_get_char(&msg); | 256 | type = buffer_get_char(&msg); |
238 | id = buffer_get_int(&msg); | 257 | id = buffer_get_int(&msg); |
@@ -260,14 +279,14 @@ get_decode_stat(int fd, u_int expected_id, int quiet) | |||
260 | } | 279 | } |
261 | 280 | ||
262 | static int | 281 | static int |
263 | get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id, | 282 | get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, |
264 | int quiet) | 283 | u_int expected_id, int quiet) |
265 | { | 284 | { |
266 | Buffer msg; | 285 | Buffer msg; |
267 | u_int type, id, flag; | 286 | u_int type, id, flag; |
268 | 287 | ||
269 | buffer_init(&msg); | 288 | buffer_init(&msg); |
270 | get_msg(fd, &msg); | 289 | get_msg(conn, &msg); |
271 | 290 | ||
272 | type = buffer_get_char(&msg); | 291 | type = buffer_get_char(&msg); |
273 | id = buffer_get_int(&msg); | 292 | id = buffer_get_int(&msg); |
@@ -311,21 +330,29 @@ get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id, | |||
311 | } | 330 | } |
312 | 331 | ||
313 | struct sftp_conn * | 332 | struct sftp_conn * |
314 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | 333 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, |
334 | u_int64_t limit_kbps) | ||
315 | { | 335 | { |
316 | u_int type, exts = 0; | 336 | u_int type; |
317 | int version; | ||
318 | Buffer msg; | 337 | Buffer msg; |
319 | struct sftp_conn *ret; | 338 | struct sftp_conn *ret; |
320 | 339 | ||
340 | ret = xmalloc(sizeof(*ret)); | ||
341 | ret->fd_in = fd_in; | ||
342 | ret->fd_out = fd_out; | ||
343 | ret->transfer_buflen = transfer_buflen; | ||
344 | ret->num_requests = num_requests; | ||
345 | ret->exts = 0; | ||
346 | ret->limit_kbps = 0; | ||
347 | |||
321 | buffer_init(&msg); | 348 | buffer_init(&msg); |
322 | buffer_put_char(&msg, SSH2_FXP_INIT); | 349 | buffer_put_char(&msg, SSH2_FXP_INIT); |
323 | buffer_put_int(&msg, SSH2_FILEXFER_VERSION); | 350 | buffer_put_int(&msg, SSH2_FILEXFER_VERSION); |
324 | send_msg(fd_out, &msg); | 351 | send_msg(ret, &msg); |
325 | 352 | ||
326 | buffer_clear(&msg); | 353 | buffer_clear(&msg); |
327 | 354 | ||
328 | get_msg(fd_in, &msg); | 355 | get_msg(ret, &msg); |
329 | 356 | ||
330 | /* Expecting a VERSION reply */ | 357 | /* Expecting a VERSION reply */ |
331 | if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { | 358 | if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { |
@@ -334,9 +361,9 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
334 | buffer_free(&msg); | 361 | buffer_free(&msg); |
335 | return(NULL); | 362 | return(NULL); |
336 | } | 363 | } |
337 | version = buffer_get_int(&msg); | 364 | ret->version = buffer_get_int(&msg); |
338 | 365 | ||
339 | debug2("Remote version: %d", version); | 366 | debug2("Remote version: %u", ret->version); |
340 | 367 | ||
341 | /* Check for extensions */ | 368 | /* Check for extensions */ |
342 | while (buffer_len(&msg) > 0) { | 369 | while (buffer_len(&msg) > 0) { |
@@ -346,15 +373,19 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
346 | 373 | ||
347 | if (strcmp(name, "posix-rename@openssh.com") == 0 && | 374 | if (strcmp(name, "posix-rename@openssh.com") == 0 && |
348 | strcmp(value, "1") == 0) { | 375 | strcmp(value, "1") == 0) { |
349 | exts |= SFTP_EXT_POSIX_RENAME; | 376 | ret->exts |= SFTP_EXT_POSIX_RENAME; |
350 | known = 1; | 377 | known = 1; |
351 | } else if (strcmp(name, "statvfs@openssh.com") == 0 && | 378 | } else if (strcmp(name, "statvfs@openssh.com") == 0 && |
352 | strcmp(value, "2") == 0) { | 379 | strcmp(value, "2") == 0) { |
353 | exts |= SFTP_EXT_STATVFS; | 380 | ret->exts |= SFTP_EXT_STATVFS; |
354 | known = 1; | 381 | known = 1; |
355 | } if (strcmp(name, "fstatvfs@openssh.com") == 0 && | 382 | } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && |
356 | strcmp(value, "2") == 0) { | 383 | strcmp(value, "2") == 0) { |
357 | exts |= SFTP_EXT_FSTATVFS; | 384 | ret->exts |= SFTP_EXT_FSTATVFS; |
385 | known = 1; | ||
386 | } else if (strcmp(name, "hardlink@openssh.com") == 0 && | ||
387 | strcmp(value, "1") == 0) { | ||
388 | ret->exts |= SFTP_EXT_HARDLINK; | ||
358 | known = 1; | 389 | known = 1; |
359 | } | 390 | } |
360 | if (known) { | 391 | if (known) { |
@@ -369,26 +400,25 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
369 | 400 | ||
370 | buffer_free(&msg); | 401 | buffer_free(&msg); |
371 | 402 | ||
372 | ret = xmalloc(sizeof(*ret)); | ||
373 | ret->fd_in = fd_in; | ||
374 | ret->fd_out = fd_out; | ||
375 | ret->transfer_buflen = transfer_buflen; | ||
376 | ret->num_requests = num_requests; | ||
377 | ret->version = version; | ||
378 | ret->msg_id = 1; | ||
379 | ret->exts = exts; | ||
380 | |||
381 | /* Some filexfer v.0 servers don't support large packets */ | 403 | /* Some filexfer v.0 servers don't support large packets */ |
382 | if (version == 0) | 404 | if (ret->version == 0) |
383 | ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); | 405 | ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); |
384 | 406 | ||
385 | return(ret); | 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); | ||
413 | } | ||
414 | |||
415 | return ret; | ||
386 | } | 416 | } |
387 | 417 | ||
388 | u_int | 418 | u_int |
389 | sftp_proto_version(struct sftp_conn *conn) | 419 | sftp_proto_version(struct sftp_conn *conn) |
390 | { | 420 | { |
391 | return(conn->version); | 421 | return conn->version; |
392 | } | 422 | } |
393 | 423 | ||
394 | int | 424 | int |
@@ -403,16 +433,16 @@ do_close(struct sftp_conn *conn, char *handle, u_int handle_len) | |||
403 | buffer_put_char(&msg, SSH2_FXP_CLOSE); | 433 | buffer_put_char(&msg, SSH2_FXP_CLOSE); |
404 | buffer_put_int(&msg, id); | 434 | buffer_put_int(&msg, id); |
405 | buffer_put_string(&msg, handle, handle_len); | 435 | buffer_put_string(&msg, handle, handle_len); |
406 | send_msg(conn->fd_out, &msg); | 436 | send_msg(conn, &msg); |
407 | debug3("Sent message SSH2_FXP_CLOSE I:%u", id); | 437 | debug3("Sent message SSH2_FXP_CLOSE I:%u", id); |
408 | 438 | ||
409 | status = get_status(conn->fd_in, id); | 439 | status = get_status(conn, id); |
410 | if (status != SSH2_FX_OK) | 440 | if (status != SSH2_FX_OK) |
411 | error("Couldn't close file: %s", fx2txt(status)); | 441 | error("Couldn't close file: %s", fx2txt(status)); |
412 | 442 | ||
413 | buffer_free(&msg); | 443 | buffer_free(&msg); |
414 | 444 | ||
415 | return(status); | 445 | return status; |
416 | } | 446 | } |
417 | 447 | ||
418 | 448 | ||
@@ -430,14 +460,14 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
430 | buffer_put_char(&msg, SSH2_FXP_OPENDIR); | 460 | buffer_put_char(&msg, SSH2_FXP_OPENDIR); |
431 | buffer_put_int(&msg, id); | 461 | buffer_put_int(&msg, id); |
432 | buffer_put_cstring(&msg, path); | 462 | buffer_put_cstring(&msg, path); |
433 | send_msg(conn->fd_out, &msg); | 463 | send_msg(conn, &msg); |
434 | 464 | ||
435 | buffer_clear(&msg); | 465 | buffer_clear(&msg); |
436 | 466 | ||
437 | handle = get_handle(conn->fd_in, id, &handle_len, | 467 | handle = get_handle(conn, id, &handle_len, |
438 | "remote readdir(\"%s\")", path); | 468 | "remote readdir(\"%s\")", path); |
439 | if (handle == NULL) | 469 | if (handle == NULL) |
440 | return(-1); | 470 | return -1; |
441 | 471 | ||
442 | if (dir) { | 472 | if (dir) { |
443 | ents = 0; | 473 | ents = 0; |
@@ -454,11 +484,11 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
454 | buffer_put_char(&msg, SSH2_FXP_READDIR); | 484 | buffer_put_char(&msg, SSH2_FXP_READDIR); |
455 | buffer_put_int(&msg, id); | 485 | buffer_put_int(&msg, id); |
456 | buffer_put_string(&msg, handle, handle_len); | 486 | buffer_put_string(&msg, handle, handle_len); |
457 | send_msg(conn->fd_out, &msg); | 487 | send_msg(conn, &msg); |
458 | 488 | ||
459 | buffer_clear(&msg); | 489 | buffer_clear(&msg); |
460 | 490 | ||
461 | get_msg(conn->fd_in, &msg); | 491 | get_msg(conn, &msg); |
462 | 492 | ||
463 | type = buffer_get_char(&msg); | 493 | type = buffer_get_char(&msg); |
464 | id = buffer_get_int(&msg); | 494 | id = buffer_get_int(&msg); |
@@ -537,7 +567,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
537 | **dir = NULL; | 567 | **dir = NULL; |
538 | } | 568 | } |
539 | 569 | ||
540 | return(0); | 570 | return 0; |
541 | } | 571 | } |
542 | 572 | ||
543 | int | 573 | int |
@@ -566,9 +596,8 @@ do_rm(struct sftp_conn *conn, char *path) | |||
566 | debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); | 596 | debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); |
567 | 597 | ||
568 | id = conn->msg_id++; | 598 | id = conn->msg_id++; |
569 | send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, | 599 | send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); |
570 | strlen(path)); | 600 | status = get_status(conn, id); |
571 | status = get_status(conn->fd_in, id); | ||
572 | if (status != SSH2_FX_OK) | 601 | if (status != SSH2_FX_OK) |
573 | error("Couldn't delete file: %s", fx2txt(status)); | 602 | error("Couldn't delete file: %s", fx2txt(status)); |
574 | return(status); | 603 | return(status); |
@@ -580,10 +609,10 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) | |||
580 | u_int status, id; | 609 | u_int status, id; |
581 | 610 | ||
582 | id = conn->msg_id++; | 611 | id = conn->msg_id++; |
583 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, | 612 | send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, |
584 | strlen(path), a); | 613 | strlen(path), a); |
585 | 614 | ||
586 | status = get_status(conn->fd_in, id); | 615 | status = get_status(conn, id); |
587 | if (status != SSH2_FX_OK && printflag) | 616 | if (status != SSH2_FX_OK && printflag) |
588 | error("Couldn't create directory: %s", fx2txt(status)); | 617 | error("Couldn't create directory: %s", fx2txt(status)); |
589 | 618 | ||
@@ -596,10 +625,10 @@ do_rmdir(struct sftp_conn *conn, char *path) | |||
596 | u_int status, id; | 625 | u_int status, id; |
597 | 626 | ||
598 | id = conn->msg_id++; | 627 | id = conn->msg_id++; |
599 | send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, | 628 | send_string_request(conn, id, SSH2_FXP_RMDIR, path, |
600 | strlen(path)); | 629 | strlen(path)); |
601 | 630 | ||
602 | status = get_status(conn->fd_in, id); | 631 | status = get_status(conn, id); |
603 | if (status != SSH2_FX_OK) | 632 | if (status != SSH2_FX_OK) |
604 | error("Couldn't remove directory: %s", fx2txt(status)); | 633 | error("Couldn't remove directory: %s", fx2txt(status)); |
605 | 634 | ||
@@ -613,11 +642,11 @@ do_stat(struct sftp_conn *conn, char *path, int quiet) | |||
613 | 642 | ||
614 | id = conn->msg_id++; | 643 | id = conn->msg_id++; |
615 | 644 | ||
616 | send_string_request(conn->fd_out, id, | 645 | send_string_request(conn, id, |
617 | conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, | 646 | conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, |
618 | path, strlen(path)); | 647 | path, strlen(path)); |
619 | 648 | ||
620 | return(get_decode_stat(conn->fd_in, id, quiet)); | 649 | return(get_decode_stat(conn, id, quiet)); |
621 | } | 650 | } |
622 | 651 | ||
623 | Attrib * | 652 | Attrib * |
@@ -634,10 +663,10 @@ do_lstat(struct sftp_conn *conn, char *path, int quiet) | |||
634 | } | 663 | } |
635 | 664 | ||
636 | id = conn->msg_id++; | 665 | id = conn->msg_id++; |
637 | send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, | 666 | send_string_request(conn, id, SSH2_FXP_LSTAT, path, |
638 | strlen(path)); | 667 | strlen(path)); |
639 | 668 | ||
640 | return(get_decode_stat(conn->fd_in, id, quiet)); | 669 | return(get_decode_stat(conn, id, quiet)); |
641 | } | 670 | } |
642 | 671 | ||
643 | #ifdef notyet | 672 | #ifdef notyet |
@@ -647,10 +676,10 @@ do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) | |||
647 | u_int id; | 676 | u_int id; |
648 | 677 | ||
649 | id = conn->msg_id++; | 678 | id = conn->msg_id++; |
650 | send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, | 679 | send_string_request(conn, id, SSH2_FXP_FSTAT, handle, |
651 | handle_len); | 680 | handle_len); |
652 | 681 | ||
653 | return(get_decode_stat(conn->fd_in, id, quiet)); | 682 | return(get_decode_stat(conn, id, quiet)); |
654 | } | 683 | } |
655 | #endif | 684 | #endif |
656 | 685 | ||
@@ -660,10 +689,10 @@ do_setstat(struct sftp_conn *conn, char *path, Attrib *a) | |||
660 | u_int status, id; | 689 | u_int status, id; |
661 | 690 | ||
662 | id = conn->msg_id++; | 691 | id = conn->msg_id++; |
663 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, | 692 | send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, |
664 | strlen(path), a); | 693 | strlen(path), a); |
665 | 694 | ||
666 | status = get_status(conn->fd_in, id); | 695 | status = get_status(conn, id); |
667 | if (status != SSH2_FX_OK) | 696 | if (status != SSH2_FX_OK) |
668 | error("Couldn't setstat on \"%s\": %s", path, | 697 | error("Couldn't setstat on \"%s\": %s", path, |
669 | fx2txt(status)); | 698 | fx2txt(status)); |
@@ -678,10 +707,10 @@ do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, | |||
678 | u_int status, id; | 707 | u_int status, id; |
679 | 708 | ||
680 | id = conn->msg_id++; | 709 | id = conn->msg_id++; |
681 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, | 710 | send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, |
682 | handle_len, a); | 711 | handle_len, a); |
683 | 712 | ||
684 | status = get_status(conn->fd_in, id); | 713 | status = get_status(conn, id); |
685 | if (status != SSH2_FX_OK) | 714 | if (status != SSH2_FX_OK) |
686 | error("Couldn't fsetstat: %s", fx2txt(status)); | 715 | error("Couldn't fsetstat: %s", fx2txt(status)); |
687 | 716 | ||
@@ -697,12 +726,12 @@ do_realpath(struct sftp_conn *conn, char *path) | |||
697 | Attrib *a; | 726 | Attrib *a; |
698 | 727 | ||
699 | expected_id = id = conn->msg_id++; | 728 | expected_id = id = conn->msg_id++; |
700 | send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, | 729 | send_string_request(conn, id, SSH2_FXP_REALPATH, path, |
701 | strlen(path)); | 730 | strlen(path)); |
702 | 731 | ||
703 | buffer_init(&msg); | 732 | buffer_init(&msg); |
704 | 733 | ||
705 | get_msg(conn->fd_in, &msg); | 734 | get_msg(conn, &msg); |
706 | type = buffer_get_char(&msg); | 735 | type = buffer_get_char(&msg); |
707 | id = buffer_get_int(&msg); | 736 | id = buffer_get_int(&msg); |
708 | 737 | ||
@@ -756,13 +785,13 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
756 | } | 785 | } |
757 | buffer_put_cstring(&msg, oldpath); | 786 | buffer_put_cstring(&msg, oldpath); |
758 | buffer_put_cstring(&msg, newpath); | 787 | buffer_put_cstring(&msg, newpath); |
759 | send_msg(conn->fd_out, &msg); | 788 | send_msg(conn, &msg); |
760 | debug3("Sent message %s \"%s\" -> \"%s\"", | 789 | debug3("Sent message %s \"%s\" -> \"%s\"", |
761 | (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : | 790 | (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : |
762 | "SSH2_FXP_RENAME", oldpath, newpath); | 791 | "SSH2_FXP_RENAME", oldpath, newpath); |
763 | buffer_free(&msg); | 792 | buffer_free(&msg); |
764 | 793 | ||
765 | status = get_status(conn->fd_in, id); | 794 | status = get_status(conn, id); |
766 | if (status != SSH2_FX_OK) | 795 | if (status != SSH2_FX_OK) |
767 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, | 796 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, |
768 | newpath, fx2txt(status)); | 797 | newpath, fx2txt(status)); |
@@ -771,6 +800,39 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
771 | } | 800 | } |
772 | 801 | ||
773 | int | 802 | int |
803 | do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath) | ||
804 | { | ||
805 | Buffer msg; | ||
806 | u_int status, id; | ||
807 | |||
808 | buffer_init(&msg); | ||
809 | |||
810 | /* Send link request */ | ||
811 | id = conn->msg_id++; | ||
812 | if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { | ||
813 | error("Server does not support hardlink@openssh.com extension"); | ||
814 | return -1; | ||
815 | } | ||
816 | |||
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\"", | ||
824 | oldpath, newpath); | ||
825 | buffer_free(&msg); | ||
826 | |||
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)); | ||
831 | |||
832 | return(status); | ||
833 | } | ||
834 | |||
835 | int | ||
774 | do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) | 836 | do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) |
775 | { | 837 | { |
776 | Buffer msg; | 838 | Buffer msg; |
@@ -789,12 +851,12 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
789 | buffer_put_int(&msg, id); | 851 | buffer_put_int(&msg, id); |
790 | buffer_put_cstring(&msg, oldpath); | 852 | buffer_put_cstring(&msg, oldpath); |
791 | buffer_put_cstring(&msg, newpath); | 853 | buffer_put_cstring(&msg, newpath); |
792 | send_msg(conn->fd_out, &msg); | 854 | send_msg(conn, &msg); |
793 | debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, | 855 | debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, |
794 | newpath); | 856 | newpath); |
795 | buffer_free(&msg); | 857 | buffer_free(&msg); |
796 | 858 | ||
797 | status = get_status(conn->fd_in, id); | 859 | status = get_status(conn, id); |
798 | if (status != SSH2_FX_OK) | 860 | if (status != SSH2_FX_OK) |
799 | error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, | 861 | error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, |
800 | newpath, fx2txt(status)); | 862 | newpath, fx2txt(status)); |
@@ -812,12 +874,11 @@ do_readlink(struct sftp_conn *conn, char *path) | |||
812 | Attrib *a; | 874 | Attrib *a; |
813 | 875 | ||
814 | expected_id = id = conn->msg_id++; | 876 | expected_id = id = conn->msg_id++; |
815 | send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, | 877 | send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); |
816 | strlen(path)); | ||
817 | 878 | ||
818 | buffer_init(&msg); | 879 | buffer_init(&msg); |
819 | 880 | ||
820 | get_msg(conn->fd_in, &msg); | 881 | get_msg(conn, &msg); |
821 | type = buffer_get_char(&msg); | 882 | type = buffer_get_char(&msg); |
822 | id = buffer_get_int(&msg); | 883 | id = buffer_get_int(&msg); |
823 | 884 | ||
@@ -871,10 +932,10 @@ do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, | |||
871 | buffer_put_int(&msg, id); | 932 | buffer_put_int(&msg, id); |
872 | buffer_put_cstring(&msg, "statvfs@openssh.com"); | 933 | buffer_put_cstring(&msg, "statvfs@openssh.com"); |
873 | buffer_put_cstring(&msg, path); | 934 | buffer_put_cstring(&msg, path); |
874 | send_msg(conn->fd_out, &msg); | 935 | send_msg(conn, &msg); |
875 | buffer_free(&msg); | 936 | buffer_free(&msg); |
876 | 937 | ||
877 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | 938 | return get_decode_statvfs(conn, st, id, quiet); |
878 | } | 939 | } |
879 | 940 | ||
880 | #ifdef notyet | 941 | #ifdef notyet |
@@ -898,16 +959,16 @@ do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, | |||
898 | buffer_put_int(&msg, id); | 959 | buffer_put_int(&msg, id); |
899 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); | 960 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); |
900 | buffer_put_string(&msg, handle, handle_len); | 961 | buffer_put_string(&msg, handle, handle_len); |
901 | send_msg(conn->fd_out, &msg); | 962 | send_msg(conn, &msg); |
902 | buffer_free(&msg); | 963 | buffer_free(&msg); |
903 | 964 | ||
904 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | 965 | return get_decode_statvfs(conn, st, id, quiet); |
905 | } | 966 | } |
906 | #endif | 967 | #endif |
907 | 968 | ||
908 | static void | 969 | static void |
909 | send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | 970 | send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, |
910 | char *handle, u_int handle_len) | 971 | u_int len, char *handle, u_int handle_len) |
911 | { | 972 | { |
912 | Buffer msg; | 973 | Buffer msg; |
913 | 974 | ||
@@ -918,7 +979,7 @@ send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | |||
918 | buffer_put_string(&msg, handle, handle_len); | 979 | buffer_put_string(&msg, handle, handle_len); |
919 | buffer_put_int64(&msg, offset); | 980 | buffer_put_int64(&msg, offset); |
920 | buffer_put_int(&msg, len); | 981 | buffer_put_int(&msg, len); |
921 | send_msg(fd_out, &msg); | 982 | send_msg(conn, &msg); |
922 | buffer_free(&msg); | 983 | buffer_free(&msg); |
923 | } | 984 | } |
924 | 985 | ||
@@ -976,10 +1037,10 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
976 | buffer_put_int(&msg, SSH2_FXF_READ); | 1037 | buffer_put_int(&msg, SSH2_FXF_READ); |
977 | attrib_clear(&junk); /* Send empty attributes */ | 1038 | attrib_clear(&junk); /* Send empty attributes */ |
978 | encode_attrib(&msg, &junk); | 1039 | encode_attrib(&msg, &junk); |
979 | send_msg(conn->fd_out, &msg); | 1040 | send_msg(conn, &msg); |
980 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); | 1041 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); |
981 | 1042 | ||
982 | handle = get_handle(conn->fd_in, id, &handle_len, | 1043 | handle = get_handle(conn, id, &handle_len, |
983 | "remote open(\"%s\")", remote_path); | 1044 | "remote open(\"%s\")", remote_path); |
984 | if (handle == NULL) { | 1045 | if (handle == NULL) { |
985 | buffer_free(&msg); | 1046 | buffer_free(&msg); |
@@ -1032,12 +1093,12 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1032 | offset += buflen; | 1093 | offset += buflen; |
1033 | num_req++; | 1094 | num_req++; |
1034 | TAILQ_INSERT_TAIL(&requests, req, tq); | 1095 | TAILQ_INSERT_TAIL(&requests, req, tq); |
1035 | send_read_request(conn->fd_out, req->id, req->offset, | 1096 | send_read_request(conn, req->id, req->offset, |
1036 | req->len, handle, handle_len); | 1097 | req->len, handle, handle_len); |
1037 | } | 1098 | } |
1038 | 1099 | ||
1039 | buffer_clear(&msg); | 1100 | buffer_clear(&msg); |
1040 | get_msg(conn->fd_in, &msg); | 1101 | get_msg(conn, &msg); |
1041 | type = buffer_get_char(&msg); | 1102 | type = buffer_get_char(&msg); |
1042 | id = buffer_get_int(&msg); | 1103 | id = buffer_get_int(&msg); |
1043 | debug3("Received reply T:%u I:%u R:%d", type, id, max_req); | 1104 | debug3("Received reply T:%u I:%u R:%d", type, id, max_req); |
@@ -1092,7 +1153,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1092 | req->id = conn->msg_id++; | 1153 | req->id = conn->msg_id++; |
1093 | req->len -= len; | 1154 | req->len -= len; |
1094 | req->offset += len; | 1155 | req->offset += len; |
1095 | send_read_request(conn->fd_out, req->id, | 1156 | send_read_request(conn, req->id, |
1096 | req->offset, req->len, handle, handle_len); | 1157 | req->offset, req->len, handle, handle_len); |
1097 | /* Reduce the request size */ | 1158 | /* Reduce the request size */ |
1098 | if (len < buflen) | 1159 | if (len < buflen) |
@@ -1327,12 +1388,12 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1327 | buffer_put_cstring(&msg, remote_path); | 1388 | buffer_put_cstring(&msg, remote_path); |
1328 | buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); | 1389 | buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); |
1329 | encode_attrib(&msg, &a); | 1390 | encode_attrib(&msg, &a); |
1330 | send_msg(conn->fd_out, &msg); | 1391 | send_msg(conn, &msg); |
1331 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); | 1392 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); |
1332 | 1393 | ||
1333 | buffer_clear(&msg); | 1394 | buffer_clear(&msg); |
1334 | 1395 | ||
1335 | handle = get_handle(conn->fd_in, id, &handle_len, | 1396 | handle = get_handle(conn, id, &handle_len, |
1336 | "remote open(\"%s\")", remote_path); | 1397 | "remote open(\"%s\")", remote_path); |
1337 | if (handle == NULL) { | 1398 | if (handle == NULL) { |
1338 | close(local_fd); | 1399 | close(local_fd); |
@@ -1381,7 +1442,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1381 | buffer_put_string(&msg, handle, handle_len); | 1442 | buffer_put_string(&msg, handle, handle_len); |
1382 | buffer_put_int64(&msg, offset); | 1443 | buffer_put_int64(&msg, offset); |
1383 | buffer_put_string(&msg, data, len); | 1444 | buffer_put_string(&msg, data, len); |
1384 | send_msg(conn->fd_out, &msg); | 1445 | send_msg(conn, &msg); |
1385 | debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", | 1446 | debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", |
1386 | id, (unsigned long long)offset, len); | 1447 | id, (unsigned long long)offset, len); |
1387 | } else if (TAILQ_FIRST(&acks) == NULL) | 1448 | } else if (TAILQ_FIRST(&acks) == NULL) |
@@ -1395,7 +1456,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1395 | u_int r_id; | 1456 | u_int r_id; |
1396 | 1457 | ||
1397 | buffer_clear(&msg); | 1458 | buffer_clear(&msg); |
1398 | get_msg(conn->fd_in, &msg); | 1459 | get_msg(conn, &msg); |
1399 | type = buffer_get_char(&msg); | 1460 | type = buffer_get_char(&msg); |
1400 | r_id = buffer_get_int(&msg); | 1461 | r_id = buffer_get_int(&msg); |
1401 | 1462 | ||