1 /* $NetBSD: sftp-client.c,v 1.36 2024/07/08 22:33:44 christos Exp $ */
2 /* $OpenBSD: sftp-client.c,v 1.176 2024/05/17 02:39:11 jsg Exp $ */
3
4 /*
5 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* XXX: memleaks */
21 /* XXX: signed vs unsigned */
22 /* XXX: remove all logging, only return status codes */
23 /* XXX: copy between two remote sites */
24
25 #include "includes.h"
26 __RCSID("$NetBSD: sftp-client.c,v 1.36 2024/07/08 22:33:44 christos Exp $");
27
28 #include <sys/param.h> /* MIN MAX */
29 #include <sys/types.h>
30 #include <sys/poll.h>
31 #include <sys/queue.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/statvfs.h>
35 #include <sys/uio.h>
36
37 #include <dirent.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <poll.h>
41 #include <signal.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "xmalloc.h"
49 #include "ssherr.h"
50 #include "sshbuf.h"
51 #include "log.h"
52 #include "atomicio.h"
53 #include "progressmeter.h"
54 #include "misc.h"
55 #include "utf8.h"
56
57 #include "sftp.h"
58 #include "sftp-common.h"
59 #include "sftp-client.h"
60
61 extern volatile sig_atomic_t interrupted;
62 extern int showprogress;
63
64 /* Default size of buffer for up/download (fix sftp.1 scp.1 if changed) */
65 #define DEFAULT_COPY_BUFLEN 32768
66
67 /* Default number of concurrent xfer requests (fix sftp.1 scp.1 if changed) */
68 #define DEFAULT_NUM_REQUESTS 64
69
70 /* Minimum amount of data to read at a time */
71 #define MIN_READ_SIZE 512
72
73 /* Maximum depth to descend in directory trees */
74 #define MAX_DIR_DEPTH 64
75
76 struct sftp_conn {
77 int fd_in;
78 int fd_out;
79 u_int download_buflen;
80 u_int upload_buflen;
81 u_int num_requests;
82 u_int version;
83 u_int msg_id;
84 #define SFTP_EXT_POSIX_RENAME 0x00000001
85 #define SFTP_EXT_STATVFS 0x00000002
86 #define SFTP_EXT_FSTATVFS 0x00000004
87 #define SFTP_EXT_HARDLINK 0x00000008
88 #define SFTP_EXT_FSYNC 0x00000010
89 #define SFTP_EXT_LSETSTAT 0x00000020
90 #define SFTP_EXT_LIMITS 0x00000040
91 #define SFTP_EXT_PATH_EXPAND 0x00000080
92 #define SFTP_EXT_COPY_DATA 0x00000100
93 #define SFTP_EXT_GETUSERSGROUPS_BY_ID 0x00000200
94 u_int exts;
95 u_int64_t limit_kbps;
96 struct bwlimit bwlimit_in, bwlimit_out;
97 };
98
99 /* Tracks in-progress requests during file transfers */
100 struct request {
101 u_int id;
102 size_t len;
103 u_int64_t offset;
104 TAILQ_ENTRY(request) tq;
105 };
106 TAILQ_HEAD(requests, request);
107
108 static u_char *
109 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
110 const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
111
112 static struct request *
request_enqueue(struct requests * requests,u_int id,size_t len,uint64_t offset)113 request_enqueue(struct requests *requests, u_int id, size_t len,
114 uint64_t offset)
115 {
116 struct request *req;
117
118 req = xcalloc(1, sizeof(*req));
119 req->id = id;
120 req->len = len;
121 req->offset = offset;
122 TAILQ_INSERT_TAIL(requests, req, tq);
123 return req;
124 }
125
126 static struct request *
request_find(struct requests * requests,u_int id)127 request_find(struct requests *requests, u_int id)
128 {
129 struct request *req;
130
131 for (req = TAILQ_FIRST(requests);
132 req != NULL && req->id != id;
133 req = TAILQ_NEXT(req, tq))
134 ;
135 return req;
136 }
137
138 static int
sftpio(void * _bwlimit,size_t amount)139 sftpio(void *_bwlimit, size_t amount)
140 {
141 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
142
143 refresh_progress_meter(0);
144 if (bwlimit != NULL)
145 bandwidth_limit(bwlimit, amount);
146 return 0;
147 }
148
149 static void
send_msg(struct sftp_conn * conn,struct sshbuf * m)150 send_msg(struct sftp_conn *conn, struct sshbuf *m)
151 {
152 u_char mlen[4];
153 struct iovec iov[2];
154
155 if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH)
156 fatal("Outbound message too long %zu", sshbuf_len(m));
157
158 /* Send length first */
159 put_u32(mlen, sshbuf_len(m));
160 iov[0].iov_base = mlen;
161 iov[0].iov_len = sizeof(mlen);
162 iov[1].iov_base = __UNCONST(sshbuf_ptr(m));
163 iov[1].iov_len = sshbuf_len(m);
164
165 if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
166 conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
167 sshbuf_len(m) + sizeof(mlen))
168 fatal("Couldn't send packet: %s", strerror(errno));
169
170 sshbuf_reset(m);
171 }
172
173 static void
get_msg_extended(struct sftp_conn * conn,struct sshbuf * m,int initial)174 get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
175 {
176 u_int msg_len;
177 u_char *p;
178 int r;
179
180 sshbuf_reset(m);
181 if ((r = sshbuf_reserve(m, 4, &p)) != 0)
182 fatal_fr(r, "reserve");
183 if (atomicio6(read, conn->fd_in, p, 4, sftpio,
184 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
185 if (errno == EPIPE || errno == ECONNRESET)
186 fatal("Connection closed");
187 else
188 fatal("Couldn't read packet: %s", strerror(errno));
189 }
190
191 if ((r = sshbuf_get_u32(m, &msg_len)) != 0)
192 fatal_fr(r, "sshbuf_get_u32");
193 if (msg_len > SFTP_MAX_MSG_LENGTH) {
194 do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL,
195 "Received message too long %u", msg_len);
196 fatal("Ensure the remote shell produces no output "
197 "for non-interactive sessions.");
198 }
199
200 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
201 fatal_fr(r, "reserve");
202 if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
203 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
204 != msg_len) {
205 if (errno == EPIPE)
206 fatal("Connection closed");
207 else
208 fatal("Read packet: %s", strerror(errno));
209 }
210 }
211
212 static void
get_msg(struct sftp_conn * conn,struct sshbuf * m)213 get_msg(struct sftp_conn *conn, struct sshbuf *m)
214 {
215 get_msg_extended(conn, m, 0);
216 }
217
218 static void
send_string_request(struct sftp_conn * conn,u_int id,u_int code,const char * s,u_int len)219 send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s,
220 u_int len)
221 {
222 struct sshbuf *msg;
223 int r;
224
225 if ((msg = sshbuf_new()) == NULL)
226 fatal_f("sshbuf_new failed");
227 if ((r = sshbuf_put_u8(msg, code)) != 0 ||
228 (r = sshbuf_put_u32(msg, id)) != 0 ||
229 (r = sshbuf_put_string(msg, s, len)) != 0)
230 fatal_fr(r, "compose");
231 send_msg(conn, msg);
232 debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
233 sshbuf_free(msg);
234 }
235
236 static void
send_string_attrs_request(struct sftp_conn * conn,u_int id,u_int code,const void * s,u_int len,Attrib * a)237 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
238 const void *s, u_int len, Attrib *a)
239 {
240 struct sshbuf *msg;
241 int r;
242
243 if ((msg = sshbuf_new()) == NULL)
244 fatal_f("sshbuf_new failed");
245 if ((r = sshbuf_put_u8(msg, code)) != 0 ||
246 (r = sshbuf_put_u32(msg, id)) != 0 ||
247 (r = sshbuf_put_string(msg, s, len)) != 0 ||
248 (r = encode_attrib(msg, a)) != 0)
249 fatal_fr(r, "compose");
250 send_msg(conn, msg);
251 debug3("Sent message fd %d T:%u I:%u F:0x%04x M:%05o",
252 conn->fd_out, code, id, a->flags, a->perm);
253 sshbuf_free(msg);
254 }
255
256 static u_int
get_status(struct sftp_conn * conn,u_int expected_id)257 get_status(struct sftp_conn *conn, u_int expected_id)
258 {
259 struct sshbuf *msg;
260 u_char type;
261 u_int id, status;
262 int r;
263
264 if ((msg = sshbuf_new()) == NULL)
265 fatal_f("sshbuf_new failed");
266 get_msg(conn, msg);
267 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
268 (r = sshbuf_get_u32(msg, &id)) != 0)
269 fatal_fr(r, "compose");
270
271 if (id != expected_id)
272 fatal("ID mismatch (%u != %u)", id, expected_id);
273 if (type != SSH2_FXP_STATUS)
274 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
275 SSH2_FXP_STATUS, type);
276
277 if ((r = sshbuf_get_u32(msg, &status)) != 0)
278 fatal_fr(r, "parse");
279 sshbuf_free(msg);
280
281 debug3("SSH2_FXP_STATUS %u", status);
282
283 return status;
284 }
285
286 static u_char *
get_handle(struct sftp_conn * conn,u_int expected_id,size_t * len,const char * errfmt,...)287 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
288 const char *errfmt, ...)
289 {
290 struct sshbuf *msg;
291 u_int id, status;
292 u_char type;
293 u_char *handle;
294 char errmsg[256];
295 va_list args;
296 int r;
297
298 va_start(args, errfmt);
299 if (errfmt != NULL)
300 vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
301 va_end(args);
302
303 if ((msg = sshbuf_new()) == NULL)
304 fatal_f("sshbuf_new failed");
305 get_msg(conn, msg);
306 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
307 (r = sshbuf_get_u32(msg, &id)) != 0)
308 fatal_fr(r, "parse");
309
310 if (id != expected_id)
311 fatal("%s: ID mismatch (%u != %u)",
312 errfmt == NULL ? __func__ : errmsg, id, expected_id);
313 if (type == SSH2_FXP_STATUS) {
314 if ((r = sshbuf_get_u32(msg, &status)) != 0)
315 fatal_fr(r, "parse status");
316 if (errfmt != NULL)
317 error("%s: %s", errmsg, fx2txt(status));
318 sshbuf_free(msg);
319 return(NULL);
320 } else if (type != SSH2_FXP_HANDLE)
321 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
322 errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
323
324 if ((r = sshbuf_get_string(msg, &handle, len)) != 0)
325 fatal_fr(r, "parse handle");
326 sshbuf_free(msg);
327
328 return handle;
329 }
330
331 static int
get_decode_stat(struct sftp_conn * conn,u_int expected_id,int quiet,Attrib * a)332 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet, Attrib *a)
333 {
334 struct sshbuf *msg;
335 u_int id;
336 u_char type;
337 int r;
338 Attrib attr;
339
340 if (a != NULL)
341 memset(a, '\0', sizeof(*a));
342 if ((msg = sshbuf_new()) == NULL)
343 fatal_f("sshbuf_new failed");
344 get_msg(conn, msg);
345
346 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
347 (r = sshbuf_get_u32(msg, &id)) != 0)
348 fatal_fr(r, "parse");
349
350 if (id != expected_id)
351 fatal("ID mismatch (%u != %u)", id, expected_id);
352 if (type == SSH2_FXP_STATUS) {
353 u_int status;
354
355 if ((r = sshbuf_get_u32(msg, &status)) != 0)
356 fatal_fr(r, "parse status");
357 if (quiet)
358 debug("stat remote: %s", fx2txt(status));
359 else
360 error("stat remote: %s", fx2txt(status));
361 sshbuf_free(msg);
362 return -1;
363 } else if (type != SSH2_FXP_ATTRS) {
364 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
365 SSH2_FXP_ATTRS, type);
366 }
367 if ((r = decode_attrib(msg, &attr)) != 0) {
368 error_fr(r, "decode_attrib");
369 sshbuf_free(msg);
370 return -1;
371 }
372 /* success */
373 if (a != NULL)
374 *a = attr;
375 debug3("Received stat reply T:%u I:%u F:0x%04x M:%05o",
376 type, id, attr.flags, attr.perm);
377 sshbuf_free(msg);
378
379 return 0;
380 }
381
382 static int
get_decode_statvfs(struct sftp_conn * conn,struct sftp_statvfs * st,u_int expected_id,int quiet)383 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
384 u_int expected_id, int quiet)
385 {
386 struct sshbuf *msg;
387 u_char type;
388 u_int id;
389 u_int64_t flag;
390 int r;
391
392 if ((msg = sshbuf_new()) == NULL)
393 fatal_f("sshbuf_new failed");
394 get_msg(conn, msg);
395
396 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
397 (r = sshbuf_get_u32(msg, &id)) != 0)
398 fatal_fr(r, "parse");
399
400 debug3("Received statvfs reply T:%u I:%u", type, id);
401 if (id != expected_id)
402 fatal("ID mismatch (%u != %u)", id, expected_id);
403 if (type == SSH2_FXP_STATUS) {
404 u_int status;
405
406 if ((r = sshbuf_get_u32(msg, &status)) != 0)
407 fatal_fr(r, "parse status");
408 if (quiet)
409 debug("remote statvfs: %s", fx2txt(status));
410 else
411 error("remote statvfs: %s", fx2txt(status));
412 sshbuf_free(msg);
413 return -1;
414 } else if (type != SSH2_FXP_EXTENDED_REPLY) {
415 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
416 SSH2_FXP_EXTENDED_REPLY, type);
417 }
418
419 memset(st, 0, sizeof(*st));
420 if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 ||
421 (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 ||
422 (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 ||
423 (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 ||
424 (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 ||
425 (r = sshbuf_get_u64(msg, &st->f_files)) != 0 ||
426 (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 ||
427 (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 ||
428 (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 ||
429 (r = sshbuf_get_u64(msg, &flag)) != 0 ||
430 (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0)
431 fatal_fr(r, "parse statvfs");
432
433 st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
434 st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
435
436 sshbuf_free(msg);
437
438 return 0;
439 }
440
441 struct sftp_conn *
sftp_init(int fd_in,int fd_out,u_int transfer_buflen,u_int num_requests,u_int64_t limit_kbps)442 sftp_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
443 u_int64_t limit_kbps)
444 {
445 u_char type;
446 struct sshbuf *msg;
447 struct sftp_conn *ret;
448 int r;
449
450 ret = xcalloc(1, sizeof(*ret));
451 ret->msg_id = 1;
452 ret->fd_in = fd_in;
453 ret->fd_out = fd_out;
454 ret->download_buflen = ret->upload_buflen =
455 transfer_buflen ? transfer_buflen : DEFAULT_COPY_BUFLEN;
456 ret->num_requests =
457 num_requests ? num_requests : DEFAULT_NUM_REQUESTS;
458 ret->exts = 0;
459 ret->limit_kbps = 0;
460
461 if ((msg = sshbuf_new()) == NULL)
462 fatal_f("sshbuf_new failed");
463 if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 ||
464 (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
465 fatal_fr(r, "parse");
466
467 send_msg(ret, msg);
468
469 get_msg_extended(ret, msg, 1);
470
471 /* Expecting a VERSION reply */
472 if ((r = sshbuf_get_u8(msg, &type)) != 0)
473 fatal_fr(r, "parse type");
474 if (type != SSH2_FXP_VERSION) {
475 error("Invalid packet back from SSH2_FXP_INIT (type %u)",
476 type);
477 sshbuf_free(msg);
478 free(ret);
479 return(NULL);
480 }
481 if ((r = sshbuf_get_u32(msg, &ret->version)) != 0)
482 fatal_fr(r, "parse version");
483
484 debug2("Remote version: %u", ret->version);
485
486 /* Check for extensions */
487 while (sshbuf_len(msg) > 0) {
488 char *name;
489 u_char *value;
490 size_t vlen;
491 int known = 0;
492
493 if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 ||
494 (r = sshbuf_get_string(msg, &value, &vlen)) != 0)
495 fatal_fr(r, "parse extension");
496 if (strcmp(name, "posix-rename@openssh.com") == 0 &&
497 strcmp((char *)value, "1") == 0) {
498 ret->exts |= SFTP_EXT_POSIX_RENAME;
499 known = 1;
500 } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
501 strcmp((char *)value, "2") == 0) {
502 ret->exts |= SFTP_EXT_STATVFS;
503 known = 1;
504 } else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
505 strcmp((char *)value, "2") == 0) {
506 ret->exts |= SFTP_EXT_FSTATVFS;
507 known = 1;
508 } else if (strcmp(name, "hardlink@openssh.com") == 0 &&
509 strcmp((char *)value, "1") == 0) {
510 ret->exts |= SFTP_EXT_HARDLINK;
511 known = 1;
512 } else if (strcmp(name, "fsync@openssh.com") == 0 &&
513 strcmp((char *)value, "1") == 0) {
514 ret->exts |= SFTP_EXT_FSYNC;
515 known = 1;
516 } else if (strcmp(name, "lsetstat@openssh.com") == 0 &&
517 strcmp((char *)value, "1") == 0) {
518 ret->exts |= SFTP_EXT_LSETSTAT;
519 known = 1;
520 } else if (strcmp(name, "limits@openssh.com") == 0 &&
521 strcmp((char *)value, "1") == 0) {
522 ret->exts |= SFTP_EXT_LIMITS;
523 known = 1;
524 } else if (strcmp(name, "expand-path@openssh.com") == 0 &&
525 strcmp((char *)value, "1") == 0) {
526 ret->exts |= SFTP_EXT_PATH_EXPAND;
527 known = 1;
528 } else if (strcmp(name, "copy-data") == 0 &&
529 strcmp((char *)value, "1") == 0) {
530 ret->exts |= SFTP_EXT_COPY_DATA;
531 known = 1;
532 } else if (strcmp(name,
533 "users-groups-by-id@openssh.com") == 0 &&
534 strcmp((char *)value, "1") == 0) {
535 ret->exts |= SFTP_EXT_GETUSERSGROUPS_BY_ID;
536 known = 1;
537 }
538 if (known) {
539 debug2("Server supports extension \"%s\" revision %s",
540 name, value);
541 } else {
542 debug2("Unrecognised server extension \"%s\"", name);
543 }
544 free(name);
545 free(value);
546 }
547
548 sshbuf_free(msg);
549
550 /* Query the server for its limits */
551 if (ret->exts & SFTP_EXT_LIMITS) {
552 struct sftp_limits limits;
553 if (sftp_get_limits(ret, &limits) != 0)
554 fatal_f("limits failed");
555
556 /* If the caller did not specify, find a good value */
557 if (transfer_buflen == 0) {
558 ret->download_buflen = MINIMUM(limits.read_length,
559 SFTP_MAX_MSG_LENGTH - 1024);
560 ret->upload_buflen = MINIMUM(limits.write_length,
561 SFTP_MAX_MSG_LENGTH - 1024);
562 ret->download_buflen = MAXIMUM(ret->download_buflen, 64);
563 ret->upload_buflen = MAXIMUM(ret->upload_buflen, 64);
564 debug3("server upload/download buffer sizes "
565 "%llu / %llu; using %u / %u",
566 (unsigned long long)limits.write_length,
567 (unsigned long long)limits.read_length,
568 ret->upload_buflen, ret->download_buflen);
569 }
570
571 /* Use the server limit to scale down our value only */
572 if (num_requests == 0 && limits.open_handles) {
573 ret->num_requests =
574 MINIMUM(DEFAULT_NUM_REQUESTS, limits.open_handles);
575 if (ret->num_requests == 0)
576 ret->num_requests = 1;
577 debug3("server handle limit %llu; using %u",
578 (unsigned long long)limits.open_handles,
579 ret->num_requests);
580 }
581 }
582
583 /* Some filexfer v.0 servers don't support large packets */
584 if (ret->version == 0) {
585 ret->download_buflen = MINIMUM(ret->download_buflen, 20480);
586 ret->upload_buflen = MINIMUM(ret->upload_buflen, 20480);
587 }
588
589 ret->limit_kbps = limit_kbps;
590 if (ret->limit_kbps > 0) {
591 bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps,
592 ret->download_buflen);
593 bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
594 ret->upload_buflen);
595 }
596
597 return ret;
598 }
599
600 u_int
sftp_proto_version(struct sftp_conn * conn)601 sftp_proto_version(struct sftp_conn *conn)
602 {
603 return conn->version;
604 }
605
606 int
sftp_get_limits(struct sftp_conn * conn,struct sftp_limits * limits)607 sftp_get_limits(struct sftp_conn *conn, struct sftp_limits *limits)
608 {
609 u_int id, msg_id;
610 u_char type;
611 struct sshbuf *msg;
612 int r;
613
614 if ((conn->exts & SFTP_EXT_LIMITS) == 0) {
615 error("Server does not support limits@openssh.com extension");
616 return -1;
617 }
618
619 if ((msg = sshbuf_new()) == NULL)
620 fatal_f("sshbuf_new failed");
621
622 id = conn->msg_id++;
623 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
624 (r = sshbuf_put_u32(msg, id)) != 0 ||
625 (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0)
626 fatal_fr(r, "compose");
627 send_msg(conn, msg);
628 debug3("Sent message limits@openssh.com I:%u", id);
629
630 get_msg(conn, msg);
631
632 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
633 (r = sshbuf_get_u32(msg, &msg_id)) != 0)
634 fatal_fr(r, "parse");
635
636 debug3("Received limits reply T:%u I:%u", type, msg_id);
637 if (id != msg_id)
638 fatal("ID mismatch (%u != %u)", msg_id, id);
639 if (type != SSH2_FXP_EXTENDED_REPLY) {
640 debug_f("expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
641 SSH2_FXP_EXTENDED_REPLY, type);
642 /* Disable the limits extension */
643 conn->exts &= ~SFTP_EXT_LIMITS;
644 sshbuf_free(msg);
645 return -1;
646 }
647
648 memset(limits, 0, sizeof(*limits));
649 if ((r = sshbuf_get_u64(msg, &limits->packet_length)) != 0 ||
650 (r = sshbuf_get_u64(msg, &limits->read_length)) != 0 ||
651 (r = sshbuf_get_u64(msg, &limits->write_length)) != 0 ||
652 (r = sshbuf_get_u64(msg, &limits->open_handles)) != 0)
653 fatal_fr(r, "parse limits");
654
655 sshbuf_free(msg);
656
657 return 0;
658 }
659
660 int
sftp_close(struct sftp_conn * conn,const u_char * handle,u_int handle_len)661 sftp_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
662 {
663 u_int id, status;
664 struct sshbuf *msg;
665 int r;
666
667 if ((msg = sshbuf_new()) == NULL)
668 fatal_f("sshbuf_new failed");
669
670 id = conn->msg_id++;
671 if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 ||
672 (r = sshbuf_put_u32(msg, id)) != 0 ||
673 (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
674 fatal_fr(r, "parse");
675 send_msg(conn, msg);
676 debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
677
678 status = get_status(conn, id);
679 if (status != SSH2_FX_OK)
680 error("close remote: %s", fx2txt(status));
681
682 sshbuf_free(msg);
683
684 return status == SSH2_FX_OK ? 0 : -1;
685 }
686
687
688 static int
sftp_lsreaddir(struct sftp_conn * conn,const char * path,int print_flag,SFTP_DIRENT *** dir)689 sftp_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
690 SFTP_DIRENT ***dir)
691 {
692 struct sshbuf *msg;
693 u_int count, id, i, expected_id, ents = 0;
694 size_t handle_len;
695 u_char type, *handle;
696 int status = SSH2_FX_FAILURE;
697 int r;
698
699 if (dir)
700 *dir = NULL;
701
702 id = conn->msg_id++;
703
704 if ((msg = sshbuf_new()) == NULL)
705 fatal_f("sshbuf_new failed");
706 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 ||
707 (r = sshbuf_put_u32(msg, id)) != 0 ||
708 (r = sshbuf_put_cstring(msg, path)) != 0)
709 fatal_fr(r, "compose OPENDIR");
710 send_msg(conn, msg);
711
712 handle = get_handle(conn, id, &handle_len,
713 "remote readdir(\"%s\")", path);
714 if (handle == NULL) {
715 sshbuf_free(msg);
716 return -1;
717 }
718
719 if (dir) {
720 ents = 0;
721 *dir = xcalloc(1, sizeof(**dir));
722 (*dir)[0] = NULL;
723 }
724
725 for (; !interrupted;) {
726 id = expected_id = conn->msg_id++;
727
728 debug3("Sending SSH2_FXP_READDIR I:%u", id);
729
730 sshbuf_reset(msg);
731 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 ||
732 (r = sshbuf_put_u32(msg, id)) != 0 ||
733 (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
734 fatal_fr(r, "compose READDIR");
735 send_msg(conn, msg);
736
737 sshbuf_reset(msg);
738
739 get_msg(conn, msg);
740
741 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
742 (r = sshbuf_get_u32(msg, &id)) != 0)
743 fatal_fr(r, "parse");
744
745 debug3("Received reply T:%u I:%u", type, id);
746
747 if (id != expected_id)
748 fatal("ID mismatch (%u != %u)", id, expected_id);
749
750 if (type == SSH2_FXP_STATUS) {
751 u_int rstatus;
752
753 if ((r = sshbuf_get_u32(msg, &rstatus)) != 0)
754 fatal_fr(r, "parse status");
755 debug3("Received SSH2_FXP_STATUS %d", rstatus);
756 if (rstatus == SSH2_FX_EOF)
757 break;
758 error("Couldn't read directory: %s", fx2txt(rstatus));
759 goto out;
760 } else if (type != SSH2_FXP_NAME)
761 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
762 SSH2_FXP_NAME, type);
763
764 if ((r = sshbuf_get_u32(msg, &count)) != 0)
765 fatal_fr(r, "parse count");
766 if (count > SSHBUF_SIZE_MAX)
767 fatal_f("nonsensical number of entries");
768 if (count == 0)
769 break;
770 debug3("Received %d SSH2_FXP_NAME responses", count);
771 for (i = 0; i < count; i++) {
772 char *filename, *longname;
773 Attrib a;
774
775 if ((r = sshbuf_get_cstring(msg, &filename,
776 NULL)) != 0 ||
777 (r = sshbuf_get_cstring(msg, &longname,
778 NULL)) != 0)
779 fatal_fr(r, "parse filenames");
780 if ((r = decode_attrib(msg, &a)) != 0) {
781 error_fr(r, "couldn't decode attrib");
782 free(filename);
783 free(longname);
784 goto out;
785 }
786
787 if (print_flag)
788 mprintf("%s\n", longname);
789
790 /*
791 * Directory entries should never contain '/'
792 * These can be used to attack recursive ops
793 * (e.g. send '../../../../etc/passwd')
794 */
795 if (strchr(filename, '/') != NULL) {
796 error("Server sent suspect path \"%s\" "
797 "during readdir of \"%s\"", filename, path);
798 } else if (dir) {
799 *dir = xreallocarray(*dir, ents + 2, sizeof(**dir));
800 (*dir)[ents] = xcalloc(1, sizeof(***dir));
801 (*dir)[ents]->filename = xstrdup(filename);
802 (*dir)[ents]->longname = xstrdup(longname);
803 memcpy(&(*dir)[ents]->a, &a, sizeof(a));
804 (*dir)[++ents] = NULL;
805 }
806 free(filename);
807 free(longname);
808 }
809 }
810 status = 0;
811
812 out:
813 sshbuf_free(msg);
814 sftp_close(conn, handle, handle_len);
815 free(handle);
816
817 if (status != 0 && dir != NULL) {
818 /* Don't return results on error */
819 sftp_free_dirents(*dir);
820 *dir = NULL;
821 } else if (interrupted && dir != NULL && *dir != NULL) {
822 /* Don't return partial matches on interrupt */
823 sftp_free_dirents(*dir);
824 *dir = xcalloc(1, sizeof(**dir));
825 **dir = NULL;
826 }
827
828 return status == SSH2_FX_OK ? 0 : -1;
829 }
830
831 int
sftp_readdir(struct sftp_conn * conn,const char * path,SFTP_DIRENT *** dir)832 sftp_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
833 {
834 return sftp_lsreaddir(conn, path, 0, dir);
835 }
836
sftp_free_dirents(SFTP_DIRENT ** s)837 void sftp_free_dirents(SFTP_DIRENT **s)
838 {
839 int i;
840
841 if (s == NULL)
842 return;
843 for (i = 0; s[i]; i++) {
844 free(s[i]->filename);
845 free(s[i]->longname);
846 free(s[i]);
847 }
848 free(s);
849 }
850
851 int
sftp_rm(struct sftp_conn * conn,const char * path)852 sftp_rm(struct sftp_conn *conn, const char *path)
853 {
854 u_int status, id;
855
856 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
857
858 id = conn->msg_id++;
859 send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
860 status = get_status(conn, id);
861 if (status != SSH2_FX_OK)
862 error("remote delete %s: %s", path, fx2txt(status));
863 return status == SSH2_FX_OK ? 0 : -1;
864 }
865
866 int
sftp_mkdir(struct sftp_conn * conn,const char * path,Attrib * a,int print_flag)867 sftp_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
868 {
869 u_int status, id;
870
871 debug2("Sending SSH2_FXP_MKDIR \"%s\"", path);
872
873 id = conn->msg_id++;
874 send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
875 strlen(path), a);
876
877 status = get_status(conn, id);
878 if (status != SSH2_FX_OK && print_flag)
879 error("remote mkdir \"%s\": %s", path, fx2txt(status));
880
881 return status == SSH2_FX_OK ? 0 : -1;
882 }
883
884 int
sftp_rmdir(struct sftp_conn * conn,const char * path)885 sftp_rmdir(struct sftp_conn *conn, const char *path)
886 {
887 u_int status, id;
888
889 debug2("Sending SSH2_FXP_RMDIR \"%s\"", path);
890
891 id = conn->msg_id++;
892 send_string_request(conn, id, SSH2_FXP_RMDIR, path,
893 strlen(path));
894
895 status = get_status(conn, id);
896 if (status != SSH2_FX_OK)
897 error("remote rmdir \"%s\": %s", path, fx2txt(status));
898
899 return status == SSH2_FX_OK ? 0 : -1;
900 }
901
902 int
sftp_stat(struct sftp_conn * conn,const char * path,int quiet,Attrib * a)903 sftp_stat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a)
904 {
905 u_int id;
906
907 debug2("Sending SSH2_FXP_STAT \"%s\"", path);
908
909 id = conn->msg_id++;
910
911 send_string_request(conn, id,
912 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
913 path, strlen(path));
914
915 return get_decode_stat(conn, id, quiet, a);
916 }
917
918 int
sftp_lstat(struct sftp_conn * conn,const char * path,int quiet,Attrib * a)919 sftp_lstat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a)
920 {
921 u_int id;
922
923 if (conn->version == 0) {
924 do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
925 "Server version does not support lstat operation");
926 return sftp_stat(conn, path, quiet, a);
927 }
928
929 id = conn->msg_id++;
930 send_string_request(conn, id, SSH2_FXP_LSTAT, path,
931 strlen(path));
932
933 return get_decode_stat(conn, id, quiet, a);
934 }
935
936 #ifdef notyet
937 int
sftp_fstat(struct sftp_conn * conn,const u_char * handle,u_int handle_len,int quiet,Attrib * a)938 sftp_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
939 int quiet, Attrib *a)
940 {
941 u_int id;
942
943 debug2("Sending SSH2_FXP_FSTAT \"%s\"");
944
945 id = conn->msg_id++;
946 send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
947 handle_len);
948
949 return get_decode_stat(conn, id, quiet, a);
950 }
951 #endif
952
953 int
sftp_setstat(struct sftp_conn * conn,const char * path,Attrib * a)954 sftp_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
955 {
956 u_int status, id;
957
958 debug2("Sending SSH2_FXP_SETSTAT \"%s\"", path);
959
960 id = conn->msg_id++;
961 send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
962 strlen(path), a);
963
964 status = get_status(conn, id);
965 if (status != SSH2_FX_OK)
966 error("remote setstat \"%s\": %s", path, fx2txt(status));
967
968 return status == SSH2_FX_OK ? 0 : -1;
969 }
970
971 int
sftp_fsetstat(struct sftp_conn * conn,const u_char * handle,u_int handle_len,Attrib * a)972 sftp_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
973 Attrib *a)
974 {
975 u_int status, id;
976
977 debug2("Sending SSH2_FXP_FSETSTAT");
978
979 id = conn->msg_id++;
980 send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
981 handle_len, a);
982
983 status = get_status(conn, id);
984 if (status != SSH2_FX_OK)
985 error("remote fsetstat: %s", fx2txt(status));
986
987 return status == SSH2_FX_OK ? 0 : -1;
988 }
989
990 /* Implements both the realpath and expand-path operations */
991 static char *
sftp_realpath_expand(struct sftp_conn * conn,const char * path,int expand)992 sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
993 {
994 struct sshbuf *msg;
995 u_int expected_id, count, id;
996 char *filename, *longname;
997 Attrib a;
998 u_char type;
999 int r;
1000 const char *what = "SSH2_FXP_REALPATH";
1001
1002 if (expand)
1003 what = "expand-path@openssh.com";
1004 if ((msg = sshbuf_new()) == NULL)
1005 fatal_f("sshbuf_new failed");
1006
1007 expected_id = id = conn->msg_id++;
1008 if (expand) {
1009 debug2("Sending SSH2_FXP_EXTENDED(expand-path@openssh.com) "
1010 "\"%s\"", path);
1011 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1012 (r = sshbuf_put_u32(msg, id)) != 0 ||
1013 (r = sshbuf_put_cstring(msg,
1014 "expand-path@openssh.com")) != 0 ||
1015 (r = sshbuf_put_cstring(msg, path)) != 0)
1016 fatal_fr(r, "compose %s", what);
1017 send_msg(conn, msg);
1018 } else {
1019 debug2("Sending SSH2_FXP_REALPATH \"%s\"", path);
1020 send_string_request(conn, id, SSH2_FXP_REALPATH,
1021 path, strlen(path));
1022 }
1023 get_msg(conn, msg);
1024 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1025 (r = sshbuf_get_u32(msg, &id)) != 0)
1026 fatal_fr(r, "parse");
1027
1028 if (id != expected_id)
1029 fatal("ID mismatch (%u != %u)", id, expected_id);
1030
1031 if (type == SSH2_FXP_STATUS) {
1032 u_int status;
1033 char *errmsg;
1034
1035 if ((r = sshbuf_get_u32(msg, &status)) != 0 ||
1036 (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0)
1037 fatal_fr(r, "parse status");
1038 error("%s %s: %s", expand ? "expand" : "realpath",
1039 path, *errmsg == '\0' ? fx2txt(status) : errmsg);
1040 free(errmsg);
1041 sshbuf_free(msg);
1042 return NULL;
1043 } else if (type != SSH2_FXP_NAME)
1044 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
1045 SSH2_FXP_NAME, type);
1046
1047 if ((r = sshbuf_get_u32(msg, &count)) != 0)
1048 fatal_fr(r, "parse count");
1049 if (count != 1)
1050 fatal("Got multiple names (%d) from %s", count, what);
1051
1052 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
1053 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
1054 (r = decode_attrib(msg, &a)) != 0)
1055 fatal_fr(r, "parse filename/attrib");
1056
1057 debug3("%s %s -> %s", what, path, filename);
1058
1059 free(longname);
1060
1061 sshbuf_free(msg);
1062
1063 return(filename);
1064 }
1065
1066 char *
sftp_realpath(struct sftp_conn * conn,const char * path)1067 sftp_realpath(struct sftp_conn *conn, const char *path)
1068 {
1069 return sftp_realpath_expand(conn, path, 0);
1070 }
1071
1072 int
sftp_can_expand_path(struct sftp_conn * conn)1073 sftp_can_expand_path(struct sftp_conn *conn)
1074 {
1075 return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0;
1076 }
1077
1078 char *
sftp_expand_path(struct sftp_conn * conn,const char * path)1079 sftp_expand_path(struct sftp_conn *conn, const char *path)
1080 {
1081 if (!sftp_can_expand_path(conn)) {
1082 debug3_f("no server support, fallback to realpath");
1083 return sftp_realpath_expand(conn, path, 0);
1084 }
1085 return sftp_realpath_expand(conn, path, 1);
1086 }
1087
1088 int
sftp_copy(struct sftp_conn * conn,const char * oldpath,const char * newpath)1089 sftp_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
1090 {
1091 Attrib junk, attr;
1092 struct sshbuf *msg;
1093 u_char *old_handle, *new_handle;
1094 u_int mode, status, id;
1095 size_t old_handle_len, new_handle_len;
1096 int r;
1097
1098 /* Return if the extension is not supported */
1099 if ((conn->exts & SFTP_EXT_COPY_DATA) == 0) {
1100 error("Server does not support copy-data extension");
1101 return -1;
1102 }
1103
1104 /* Make sure the file exists, and we can copy its perms */
1105 if (sftp_stat(conn, oldpath, 0, &attr) != 0)
1106 return -1;
1107
1108 /* Do not preserve set[ug]id here, as we do not preserve ownership */
1109 if (attr.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1110 mode = attr.perm & 0777;
1111
1112 if (!S_ISREG(attr.perm)) {
1113 error("Cannot copy non-regular file: %s", oldpath);
1114 return -1;
1115 }
1116 } else {
1117 /* NB: The user's umask will apply to this */
1118 mode = 0666;
1119 }
1120
1121 /* Set up the new perms for the new file */
1122 attrib_clear(&attr);
1123 attr.perm = mode;
1124 attr.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1125
1126 if ((msg = sshbuf_new()) == NULL)
1127 fatal("%s: sshbuf_new failed", __func__);
1128
1129 attrib_clear(&junk); /* Send empty attributes */
1130
1131 /* Open the old file for reading */
1132 id = conn->msg_id++;
1133 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1134 (r = sshbuf_put_u32(msg, id)) != 0 ||
1135 (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
1136 (r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 ||
1137 (r = encode_attrib(msg, &junk)) != 0)
1138 fatal("%s: buffer error: %s", __func__, ssh_err(r));
1139 send_msg(conn, msg);
1140 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, oldpath);
1141
1142 sshbuf_reset(msg);
1143
1144 old_handle = get_handle(conn, id, &old_handle_len,
1145 "remote open(\"%s\")", oldpath);
1146 if (old_handle == NULL) {
1147 sshbuf_free(msg);
1148 return -1;
1149 }
1150
1151 /* Open the new file for writing */
1152 id = conn->msg_id++;
1153 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1154 (r = sshbuf_put_u32(msg, id)) != 0 ||
1155 (r = sshbuf_put_cstring(msg, newpath)) != 0 ||
1156 (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
1157 SSH2_FXF_TRUNC)) != 0 ||
1158 (r = encode_attrib(msg, &attr)) != 0)
1159 fatal("%s: buffer error: %s", __func__, ssh_err(r));
1160 send_msg(conn, msg);
1161 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath);
1162
1163 sshbuf_reset(msg);
1164
1165 new_handle = get_handle(conn, id, &new_handle_len,
1166 "remote open(\"%s\")", newpath);
1167 if (new_handle == NULL) {
1168 sshbuf_free(msg);
1169 free(old_handle);
1170 return -1;
1171 }
1172
1173 /* Copy the file data */
1174 id = conn->msg_id++;
1175 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1176 (r = sshbuf_put_u32(msg, id)) != 0 ||
1177 (r = sshbuf_put_cstring(msg, "copy-data")) != 0 ||
1178 (r = sshbuf_put_string(msg, old_handle, old_handle_len)) != 0 ||
1179 (r = sshbuf_put_u64(msg, 0)) != 0 ||
1180 (r = sshbuf_put_u64(msg, 0)) != 0 ||
1181 (r = sshbuf_put_string(msg, new_handle, new_handle_len)) != 0 ||
1182 (r = sshbuf_put_u64(msg, 0)) != 0)
1183 fatal("%s: buffer error: %s", __func__, ssh_err(r));
1184 send_msg(conn, msg);
1185 debug3("Sent message copy-data \"%s\" 0 0 -> \"%s\" 0",
1186 oldpath, newpath);
1187
1188 status = get_status(conn, id);
1189 if (status != SSH2_FX_OK)
1190 error("Couldn't copy file \"%s\" to \"%s\": %s", oldpath,
1191 newpath, fx2txt(status));
1192
1193 /* Clean up everything */
1194 sshbuf_free(msg);
1195 sftp_close(conn, old_handle, old_handle_len);
1196 sftp_close(conn, new_handle, new_handle_len);
1197 free(old_handle);
1198 free(new_handle);
1199
1200 return status == SSH2_FX_OK ? 0 : -1;
1201 }
1202
1203 int
sftp_rename(struct sftp_conn * conn,const char * oldpath,const char * newpath,int force_legacy)1204 sftp_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
1205 int force_legacy)
1206 {
1207 struct sshbuf *msg;
1208 u_int status, id;
1209 int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy;
1210
1211 if ((msg = sshbuf_new()) == NULL)
1212 fatal_f("sshbuf_new failed");
1213
1214 /* Send rename request */
1215 id = conn->msg_id++;
1216 if (use_ext) {
1217 debug2("Sending SSH2_FXP_EXTENDED(posix-rename@openssh.com) "
1218 "\"%s\" to \"%s\"", oldpath, newpath);
1219 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1220 (r = sshbuf_put_u32(msg, id)) != 0 ||
1221 (r = sshbuf_put_cstring(msg,
1222 "posix-rename@openssh.com")) != 0)
1223 fatal_fr(r, "compose posix-rename");
1224 } else {
1225 debug2("Sending SSH2_FXP_RENAME \"%s\" to \"%s\"",
1226 oldpath, newpath);
1227 if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 ||
1228 (r = sshbuf_put_u32(msg, id)) != 0)
1229 fatal_fr(r, "compose rename");
1230 }
1231 if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
1232 (r = sshbuf_put_cstring(msg, newpath)) != 0)
1233 fatal_fr(r, "compose paths");
1234 send_msg(conn, msg);
1235 debug3("Sent message %s \"%s\" -> \"%s\"",
1236 use_ext ? "posix-rename@openssh.com" :
1237 "SSH2_FXP_RENAME", oldpath, newpath);
1238 sshbuf_free(msg);
1239
1240 status = get_status(conn, id);
1241 if (status != SSH2_FX_OK)
1242 error("remote rename \"%s\" to \"%s\": %s", oldpath,
1243 newpath, fx2txt(status));
1244
1245 return status == SSH2_FX_OK ? 0 : -1;
1246 }
1247
1248 int
sftp_hardlink(struct sftp_conn * conn,const char * oldpath,const char * newpath)1249 sftp_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
1250 {
1251 struct sshbuf *msg;
1252 u_int status, id;
1253 int r;
1254
1255 if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
1256 error("Server does not support hardlink@openssh.com extension");
1257 return -1;
1258 }
1259 debug2("Sending SSH2_FXP_EXTENDED(hardlink@openssh.com) "
1260 "\"%s\" to \"%s\"", oldpath, newpath);
1261
1262 if ((msg = sshbuf_new()) == NULL)
1263 fatal_f("sshbuf_new failed");
1264
1265 /* Send link request */
1266 id = conn->msg_id++;
1267 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1268 (r = sshbuf_put_u32(msg, id)) != 0 ||
1269 (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 ||
1270 (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
1271 (r = sshbuf_put_cstring(msg, newpath)) != 0)
1272 fatal_fr(r, "compose");
1273 send_msg(conn, msg);
1274 debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
1275 oldpath, newpath);
1276 sshbuf_free(msg);
1277
1278 status = get_status(conn, id);
1279 if (status != SSH2_FX_OK)
1280 error("remote link \"%s\" to \"%s\": %s", oldpath,
1281 newpath, fx2txt(status));
1282
1283 return status == SSH2_FX_OK ? 0 : -1;
1284 }
1285
1286 int
sftp_symlink(struct sftp_conn * conn,const char * oldpath,const char * newpath)1287 sftp_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
1288 {
1289 struct sshbuf *msg;
1290 u_int status, id;
1291 int r;
1292
1293 if (conn->version < 3) {
1294 error("This server does not support the symlink operation");
1295 return(SSH2_FX_OP_UNSUPPORTED);
1296 }
1297 debug2("Sending SSH2_FXP_SYMLINK \"%s\" to \"%s\"", oldpath, newpath);
1298
1299 if ((msg = sshbuf_new()) == NULL)
1300 fatal_f("sshbuf_new failed");
1301
1302 /* Send symlink request */
1303 id = conn->msg_id++;
1304 if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 ||
1305 (r = sshbuf_put_u32(msg, id)) != 0 ||
1306 (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
1307 (r = sshbuf_put_cstring(msg, newpath)) != 0)
1308 fatal_fr(r, "compose");
1309 send_msg(conn, msg);
1310 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
1311 newpath);
1312 sshbuf_free(msg);
1313
1314 status = get_status(conn, id);
1315 if (status != SSH2_FX_OK)
1316 error("remote symlink file \"%s\" to \"%s\": %s", oldpath,
1317 newpath, fx2txt(status));
1318
1319 return status == SSH2_FX_OK ? 0 : -1;
1320 }
1321
1322 int
sftp_fsync(struct sftp_conn * conn,u_char * handle,u_int handle_len)1323 sftp_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
1324 {
1325 struct sshbuf *msg;
1326 u_int status, id;
1327 int r;
1328
1329 /* Silently return if the extension is not supported */
1330 if ((conn->exts & SFTP_EXT_FSYNC) == 0)
1331 return -1;
1332 debug2("Sending SSH2_FXP_EXTENDED(fsync@openssh.com)");
1333
1334 /* Send fsync request */
1335 if ((msg = sshbuf_new()) == NULL)
1336 fatal_f("sshbuf_new failed");
1337 id = conn->msg_id++;
1338 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1339 (r = sshbuf_put_u32(msg, id)) != 0 ||
1340 (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
1341 (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1342 fatal_fr(r, "compose");
1343 send_msg(conn, msg);
1344 debug3("Sent message fsync@openssh.com I:%u", id);
1345 sshbuf_free(msg);
1346
1347 status = get_status(conn, id);
1348 if (status != SSH2_FX_OK)
1349 error("remote fsync: %s", fx2txt(status));
1350
1351 return status == SSH2_FX_OK ? 0 : -1;
1352 }
1353
1354 #ifdef notyet
1355 char *
sftp_readlink(struct sftp_conn * conn,const char * path)1356 sftp_readlink(struct sftp_conn *conn, const char *path)
1357 {
1358 struct sshbuf *msg;
1359 u_int expected_id, count, id;
1360 char *filename, *longname;
1361 Attrib a;
1362 u_char type;
1363 int r;
1364
1365 debug2("Sending SSH2_FXP_READLINK \"%s\"", path);
1366
1367 expected_id = id = conn->msg_id++;
1368 send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
1369
1370 if ((msg = sshbuf_new()) == NULL)
1371 fatal_f("sshbuf_new failed");
1372
1373 get_msg(conn, msg);
1374 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1375 (r = sshbuf_get_u32(msg, &id)) != 0)
1376 fatal_fr(r, "parse");
1377
1378 if (id != expected_id)
1379 fatal("ID mismatch (%u != %u)", id, expected_id);
1380
1381 if (type == SSH2_FXP_STATUS) {
1382 u_int status;
1383
1384 if ((r = sshbuf_get_u32(msg, &status)) != 0)
1385 fatal_fr(r, "parse status");
1386 error("Couldn't readlink: %s", fx2txt(status));
1387 sshbuf_free(msg);
1388 return(NULL);
1389 } else if (type != SSH2_FXP_NAME)
1390 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
1391 SSH2_FXP_NAME, type);
1392
1393 if ((r = sshbuf_get_u32(msg, &count)) != 0)
1394 fatal_fr(r, "parse count");
1395 if (count != 1)
1396 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
1397
1398 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
1399 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
1400 (r = decode_attrib(msg, &a)) != 0)
1401 fatal_fr(r, "parse filenames/attrib");
1402
1403 debug3("SSH_FXP_READLINK %s -> %s", path, filename);
1404
1405 free(longname);
1406
1407 sshbuf_free(msg);
1408
1409 return filename;
1410 }
1411 #endif
1412
1413 int
sftp_statvfs(struct sftp_conn * conn,const char * path,struct sftp_statvfs * st,int quiet)1414 sftp_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
1415 int quiet)
1416 {
1417 struct sshbuf *msg;
1418 u_int id;
1419 int r;
1420
1421 if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
1422 error("Server does not support statvfs@openssh.com extension");
1423 return -1;
1424 }
1425
1426 debug2("Sending SSH2_FXP_EXTENDED(statvfs@openssh.com) \"%s\"", path);
1427
1428 id = conn->msg_id++;
1429
1430 if ((msg = sshbuf_new()) == NULL)
1431 fatal_f("sshbuf_new failed");
1432 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1433 (r = sshbuf_put_u32(msg, id)) != 0 ||
1434 (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
1435 (r = sshbuf_put_cstring(msg, path)) != 0)
1436 fatal_fr(r, "compose");
1437 send_msg(conn, msg);
1438 sshbuf_free(msg);
1439
1440 return get_decode_statvfs(conn, st, id, quiet);
1441 }
1442
1443 #ifdef notyet
1444 int
sftp_fstatvfs(struct sftp_conn * conn,const u_char * handle,u_int handle_len,struct sftp_statvfs * st,int quiet)1445 sftp_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
1446 struct sftp_statvfs *st, int quiet)
1447 {
1448 struct sshbuf *msg;
1449 u_int id;
1450
1451 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
1452 error("Server does not support fstatvfs@openssh.com extension");
1453 return -1;
1454 }
1455
1456 debug2("Sending SSH2_FXP_EXTENDED(fstatvfs@openssh.com)");
1457
1458 id = conn->msg_id++;
1459
1460 if ((msg = sshbuf_new()) == NULL)
1461 fatal_f("sshbuf_new failed");
1462 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1463 (r = sshbuf_put_u32(msg, id)) != 0 ||
1464 (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
1465 (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1466 fatal_fr(r, "compose");
1467 send_msg(conn, msg);
1468 sshbuf_free(msg);
1469
1470 return get_decode_statvfs(conn, st, id, quiet);
1471 }
1472 #endif
1473
1474 int
sftp_lsetstat(struct sftp_conn * conn,const char * path,Attrib * a)1475 sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
1476 {
1477 struct sshbuf *msg;
1478 u_int status, id;
1479 int r;
1480
1481 if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) {
1482 error("Server does not support lsetstat@openssh.com extension");
1483 return -1;
1484 }
1485
1486 debug2("Sending SSH2_FXP_EXTENDED(lsetstat@openssh.com) \"%s\"", path);
1487
1488 id = conn->msg_id++;
1489 if ((msg = sshbuf_new()) == NULL)
1490 fatal_f("sshbuf_new failed");
1491 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1492 (r = sshbuf_put_u32(msg, id)) != 0 ||
1493 (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
1494 (r = sshbuf_put_cstring(msg, path)) != 0 ||
1495 (r = encode_attrib(msg, a)) != 0)
1496 fatal_fr(r, "compose");
1497 send_msg(conn, msg);
1498 sshbuf_free(msg);
1499
1500 status = get_status(conn, id);
1501 if (status != SSH2_FX_OK)
1502 error("remote lsetstat \"%s\": %s", path, fx2txt(status));
1503
1504 return status == SSH2_FX_OK ? 0 : -1;
1505 }
1506
1507 static void
send_read_request(struct sftp_conn * conn,u_int id,u_int64_t offset,u_int len,const u_char * handle,u_int handle_len)1508 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
1509 u_int len, const u_char *handle, u_int handle_len)
1510 {
1511 struct sshbuf *msg;
1512 int r;
1513
1514 if ((msg = sshbuf_new()) == NULL)
1515 fatal_f("sshbuf_new failed");
1516 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
1517 (r = sshbuf_put_u32(msg, id)) != 0 ||
1518 (r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
1519 (r = sshbuf_put_u64(msg, offset)) != 0 ||
1520 (r = sshbuf_put_u32(msg, len)) != 0)
1521 fatal_fr(r, "compose");
1522 send_msg(conn, msg);
1523 sshbuf_free(msg);
1524 }
1525
1526 static int
send_open(struct sftp_conn * conn,const char * path,const char * tag,u_int openmode,Attrib * a,u_char ** handlep,size_t * handle_lenp)1527 send_open(struct sftp_conn *conn, const char *path, const char *tag,
1528 u_int openmode, Attrib *a, u_char **handlep, size_t *handle_lenp)
1529 {
1530 Attrib junk;
1531 u_char *handle;
1532 size_t handle_len;
1533 struct sshbuf *msg;
1534 int r;
1535 u_int id;
1536
1537 debug2("Sending SSH2_FXP_OPEN \"%s\"", path);
1538
1539 *handlep = NULL;
1540 *handle_lenp = 0;
1541
1542 if (a == NULL) {
1543 attrib_clear(&junk); /* Send empty attributes */
1544 a = &junk;
1545 }
1546 /* Send open request */
1547 if ((msg = sshbuf_new()) == NULL)
1548 fatal_f("sshbuf_new failed");
1549 id = conn->msg_id++;
1550 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1551 (r = sshbuf_put_u32(msg, id)) != 0 ||
1552 (r = sshbuf_put_cstring(msg, path)) != 0 ||
1553 (r = sshbuf_put_u32(msg, openmode)) != 0 ||
1554 (r = encode_attrib(msg, a)) != 0)
1555 fatal_fr(r, "compose %s open", tag);
1556 send_msg(conn, msg);
1557 sshbuf_free(msg);
1558 debug3("Sent %s message SSH2_FXP_OPEN I:%u P:%s M:0x%04x",
1559 tag, id, path, openmode);
1560 if ((handle = get_handle(conn, id, &handle_len,
1561 "%s open \"%s\"", tag, path)) == NULL)
1562 return -1;
1563 /* success */
1564 *handlep = handle;
1565 *handle_lenp = handle_len;
1566 return 0;
1567 }
1568
1569 static const char *
progress_meter_path(const char * path)1570 progress_meter_path(const char *path)
1571 {
1572 const char *progresspath;
1573
1574 if ((progresspath = strrchr(path, '/')) == NULL)
1575 return path;
1576 progresspath++;
1577 if (*progresspath == '\0')
1578 return path;
1579 return progresspath;
1580 }
1581
1582 int
sftp_download(struct sftp_conn * conn,const char * remote_path,const char * local_path,Attrib * a,int preserve_flag,int resume_flag,int fsync_flag,int inplace_flag)1583 sftp_download(struct sftp_conn *conn, const char *remote_path,
1584 const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
1585 int fsync_flag, int inplace_flag)
1586 {
1587 struct sshbuf *msg;
1588 u_char *handle;
1589 int local_fd = -1, write_error;
1590 int read_error, write_errno, lmodified = 0, reordered = 0, r;
1591 u_int64_t offset = 0, size, highwater = 0, maxack = 0;
1592 u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK;
1593 off_t progress_counter;
1594 size_t handle_len;
1595 struct stat st;
1596 struct requests requests;
1597 struct request *req;
1598 u_char type;
1599 Attrib attr;
1600
1601 debug2_f("download remote \"%s\" to local \"%s\"",
1602 remote_path, local_path);
1603
1604 TAILQ_INIT(&requests);
1605
1606 if (a == NULL) {
1607 if (sftp_stat(conn, remote_path, 0, &attr) != 0)
1608 return -1;
1609 a = &attr;
1610 }
1611
1612 /* Do not preserve set[ug]id here, as we do not preserve ownership */
1613 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1614 mode = a->perm & 0777;
1615 else
1616 mode = 0666;
1617
1618 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1619 (!S_ISREG(a->perm))) {
1620 error("download %s: not a regular file", remote_path);
1621 return(-1);
1622 }
1623
1624 if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1625 size = a->size;
1626 else
1627 size = 0;
1628
1629 buflen = conn->download_buflen;
1630
1631 /* Send open request */
1632 if (send_open(conn, remote_path, "remote", SSH2_FXF_READ, NULL,
1633 &handle, &handle_len) != 0)
1634 return -1;
1635
1636 local_fd = open(local_path, O_WRONLY | O_CREAT |
1637 ((resume_flag || inplace_flag) ? 0 : O_TRUNC), mode | S_IWUSR);
1638 if (local_fd == -1) {
1639 error("open local \"%s\": %s", local_path, strerror(errno));
1640 goto fail;
1641 }
1642 if (resume_flag) {
1643 if (fstat(local_fd, &st) == -1) {
1644 error("stat local \"%s\": %s",
1645 local_path, strerror(errno));
1646 goto fail;
1647 }
1648 if (st.st_size < 0) {
1649 error("\"%s\" has negative size", local_path);
1650 goto fail;
1651 }
1652 if ((u_int64_t)st.st_size > size) {
1653 error("Unable to resume download of \"%s\": "
1654 "local file is larger than remote", local_path);
1655 fail:
1656 sftp_close(conn, handle, handle_len);
1657 free(handle);
1658 if (local_fd != -1)
1659 close(local_fd);
1660 return -1;
1661 }
1662 offset = highwater = maxack = st.st_size;
1663 }
1664
1665 /* Read from remote and write to local */
1666 write_error = read_error = write_errno = num_req = 0;
1667 max_req = 1;
1668 progress_counter = offset;
1669
1670 if (showprogress && size != 0) {
1671 start_progress_meter(progress_meter_path(remote_path),
1672 size, &progress_counter);
1673 }
1674
1675 if ((msg = sshbuf_new()) == NULL)
1676 fatal_f("sshbuf_new failed");
1677
1678 while (num_req > 0 || max_req > 0) {
1679 u_char *data;
1680 size_t len;
1681
1682 /*
1683 * Simulate EOF on interrupt: stop sending new requests and
1684 * allow outstanding requests to drain gracefully
1685 */
1686 if (interrupted) {
1687 if (num_req == 0) /* If we haven't started yet... */
1688 break;
1689 max_req = 0;
1690 }
1691
1692 /* Send some more requests */
1693 while (num_req < max_req) {
1694 debug3("Request range %llu -> %llu (%d/%d)",
1695 (unsigned long long)offset,
1696 (unsigned long long)offset + buflen - 1,
1697 num_req, max_req);
1698 req = request_enqueue(&requests, conn->msg_id++,
1699 buflen, offset);
1700 offset += buflen;
1701 num_req++;
1702 send_read_request(conn, req->id, req->offset,
1703 req->len, handle, handle_len);
1704 }
1705
1706 sshbuf_reset(msg);
1707 get_msg(conn, msg);
1708 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1709 (r = sshbuf_get_u32(msg, &id)) != 0)
1710 fatal_fr(r, "parse");
1711 debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1712
1713 /* Find the request in our queue */
1714 if ((req = request_find(&requests, id)) == NULL)
1715 fatal("Unexpected reply %u", id);
1716
1717 switch (type) {
1718 case SSH2_FXP_STATUS:
1719 if ((r = sshbuf_get_u32(msg, &status)) != 0)
1720 fatal_fr(r, "parse status");
1721 if (status != SSH2_FX_EOF)
1722 read_error = 1;
1723 max_req = 0;
1724 TAILQ_REMOVE(&requests, req, tq);
1725 free(req);
1726 num_req--;
1727 break;
1728 case SSH2_FXP_DATA:
1729 if ((r = sshbuf_get_string(msg, &data, &len)) != 0)
1730 fatal_fr(r, "parse data");
1731 debug3("Received data %llu -> %llu",
1732 (unsigned long long)req->offset,
1733 (unsigned long long)req->offset + len - 1);
1734 if (len > req->len)
1735 fatal("Received more data than asked for "
1736 "%zu > %zu", len, req->len);
1737 lmodified = 1;
1738 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1739 atomicio(vwrite, local_fd, data, len) != len) &&
1740 !write_error) {
1741 write_errno = errno;
1742 write_error = 1;
1743 max_req = 0;
1744 } else {
1745 /*
1746 * Track both the highest offset acknowledged
1747 * and the highest *contiguous* offset
1748 * acknowledged.
1749 * We'll need the latter for ftruncate()ing
1750 * interrupted transfers.
1751 */
1752 if (maxack < req->offset + len)
1753 maxack = req->offset + len;
1754 if (!reordered && req->offset <= highwater)
1755 highwater = maxack;
1756 else if (!reordered && req->offset > highwater)
1757 reordered = 1;
1758 }
1759 progress_counter += len;
1760 free(data);
1761
1762 if (len == req->len) {
1763 TAILQ_REMOVE(&requests, req, tq);
1764 free(req);
1765 num_req--;
1766 } else {
1767 /* Resend the request for the missing data */
1768 debug3("Short data block, re-requesting "
1769 "%llu -> %llu (%2d)",
1770 (unsigned long long)req->offset + len,
1771 (unsigned long long)req->offset +
1772 req->len - 1, num_req);
1773 req->id = conn->msg_id++;
1774 req->len -= len;
1775 req->offset += len;
1776 send_read_request(conn, req->id,
1777 req->offset, req->len, handle, handle_len);
1778 /* Reduce the request size */
1779 if (len < buflen)
1780 buflen = MAXIMUM(MIN_READ_SIZE, len);
1781 }
1782 if (max_req > 0) { /* max_req = 0 iff EOF received */
1783 if (size > 0 && offset > size) {
1784 /* Only one request at a time
1785 * after the expected EOF */
1786 debug3("Finish at %llu (%2d)",
1787 (unsigned long long)offset,
1788 num_req);
1789 max_req = 1;
1790 } else if (max_req < conn->num_requests) {
1791 ++max_req;
1792 }
1793 }
1794 break;
1795 default:
1796 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1797 SSH2_FXP_DATA, type);
1798 }
1799 }
1800
1801 if (showprogress && size)
1802 stop_progress_meter();
1803
1804 /* Sanity check */
1805 if (TAILQ_FIRST(&requests) != NULL)
1806 fatal("Transfer complete, but requests still in queue");
1807
1808 if (!read_error && !write_error && !interrupted) {
1809 /* we got everything */
1810 highwater = maxack;
1811 }
1812
1813 /*
1814 * Truncate at highest contiguous point to avoid holes on interrupt,
1815 * or unconditionally if writing in place.
1816 */
1817 if (inplace_flag || read_error || write_error || interrupted) {
1818 if (reordered && resume_flag &&
1819 (read_error || write_error || interrupted)) {
1820 error("Unable to resume download of \"%s\": "
1821 "server reordered requests", local_path);
1822 }
1823 debug("truncating at %llu", (unsigned long long)highwater);
1824 if (ftruncate(local_fd, highwater) == -1)
1825 error("local ftruncate \"%s\": %s", local_path,
1826 strerror(errno));
1827 }
1828 if (read_error) {
1829 error("read remote \"%s\" : %s", remote_path, fx2txt(status));
1830 status = -1;
1831 sftp_close(conn, handle, handle_len);
1832 } else if (write_error) {
1833 error("write local \"%s\": %s", local_path,
1834 strerror(write_errno));
1835 status = SSH2_FX_FAILURE;
1836 sftp_close(conn, handle, handle_len);
1837 } else {
1838 if (sftp_close(conn, handle, handle_len) != 0 || interrupted)
1839 status = SSH2_FX_FAILURE;
1840 else
1841 status = SSH2_FX_OK;
1842 /* Override umask and utimes if asked */
1843 if (preserve_flag && fchmod(local_fd, mode) == -1)
1844 error("local chmod \"%s\": %s", local_path,
1845 strerror(errno));
1846 if (preserve_flag &&
1847 (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1848 struct timeval tv[2];
1849 tv[0].tv_sec = a->atime;
1850 tv[1].tv_sec = a->mtime;
1851 tv[0].tv_usec = tv[1].tv_usec = 0;
1852 if (utimes(local_path, tv) == -1)
1853 error("local set times \"%s\": %s",
1854 local_path, strerror(errno));
1855 }
1856 if (resume_flag && !lmodified)
1857 logit("File \"%s\" was not modified", local_path);
1858 else if (fsync_flag) {
1859 debug("syncing \"%s\"", local_path);
1860 if (fsync(local_fd) == -1)
1861 error("local sync \"%s\": %s",
1862 local_path, strerror(errno));
1863 }
1864 }
1865 close(local_fd);
1866 sshbuf_free(msg);
1867 free(handle);
1868
1869 return status == SSH2_FX_OK ? 0 : -1;
1870 }
1871
1872 static int
download_dir_internal(struct sftp_conn * conn,const char * src,const char * dst,int depth,Attrib * dirattrib,int preserve_flag,int print_flag,int resume_flag,int fsync_flag,int follow_link_flag,int inplace_flag)1873 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1874 int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
1875 int resume_flag, int fsync_flag, int follow_link_flag, int inplace_flag)
1876 {
1877 int i, ret = 0;
1878 SFTP_DIRENT **dir_entries;
1879 char *filename, *new_src = NULL, *new_dst = NULL;
1880 mode_t mode = 0777, tmpmode = mode;
1881 Attrib *a, ldirattrib, lsym;
1882
1883 if (depth >= MAX_DIR_DEPTH) {
1884 error("Maximum directory depth exceeded: %d levels", depth);
1885 return -1;
1886 }
1887
1888 debug2_f("download dir remote \"%s\" to local \"%s\"", src, dst);
1889
1890 if (dirattrib == NULL) {
1891 if (sftp_stat(conn, src, 1, &ldirattrib) != 0) {
1892 error("stat remote \"%s\" directory failed", src);
1893 return -1;
1894 }
1895 dirattrib = &ldirattrib;
1896 }
1897 if (!S_ISDIR(dirattrib->perm)) {
1898 error("\"%s\" is not a directory", src);
1899 return -1;
1900 }
1901 if (print_flag && print_flag != SFTP_PROGRESS_ONLY)
1902 mprintf("Retrieving %s\n", src);
1903
1904 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1905 mode = dirattrib->perm & 01777;
1906 tmpmode = mode | (S_IWUSR|S_IXUSR);
1907 } else {
1908 debug("download remote \"%s\": server "
1909 "did not send permissions", dst);
1910 }
1911
1912 if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) {
1913 error("mkdir %s: %s", dst, strerror(errno));
1914 return -1;
1915 }
1916
1917 if (sftp_readdir(conn, src, &dir_entries) == -1) {
1918 error("remote readdir \"%s\" failed", src);
1919 return -1;
1920 }
1921
1922 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1923 free(new_dst);
1924 free(new_src);
1925
1926 filename = dir_entries[i]->filename;
1927 new_dst = sftp_path_append(dst, filename);
1928 new_src = sftp_path_append(src, filename);
1929
1930 a = &dir_entries[i]->a;
1931 if (S_ISLNK(a->perm)) {
1932 if (!follow_link_flag) {
1933 logit("download \"%s\": not a regular file",
1934 new_src);
1935 continue;
1936 }
1937 /* Replace the stat contents with the symlink target */
1938 if (sftp_stat(conn, new_src, 1, &lsym) != 0) {
1939 logit("remote stat \"%s\" failed", new_src);
1940 ret = -1;
1941 continue;
1942 }
1943 a = &lsym;
1944 }
1945
1946 if (S_ISDIR(a->perm)) {
1947 if (strcmp(filename, ".") == 0 ||
1948 strcmp(filename, "..") == 0)
1949 continue;
1950 if (download_dir_internal(conn, new_src, new_dst,
1951 depth + 1, a, preserve_flag,
1952 print_flag, resume_flag,
1953 fsync_flag, follow_link_flag, inplace_flag) == -1)
1954 ret = -1;
1955 } else if (S_ISREG(a->perm)) {
1956 if (sftp_download(conn, new_src, new_dst, a,
1957 preserve_flag, resume_flag, fsync_flag,
1958 inplace_flag) == -1) {
1959 error("Download of file %s to %s failed",
1960 new_src, new_dst);
1961 ret = -1;
1962 }
1963 } else
1964 logit("download \"%s\": not a regular file", new_src);
1965
1966 }
1967 free(new_dst);
1968 free(new_src);
1969
1970 if (preserve_flag) {
1971 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1972 struct timeval tv[2];
1973 tv[0].tv_sec = dirattrib->atime;
1974 tv[1].tv_sec = dirattrib->mtime;
1975 tv[0].tv_usec = tv[1].tv_usec = 0;
1976 if (utimes(dst, tv) == -1)
1977 error("local set times on \"%s\": %s",
1978 dst, strerror(errno));
1979 } else
1980 debug("Server did not send times for directory "
1981 "\"%s\"", dst);
1982 }
1983
1984 if (mode != tmpmode && chmod(dst, mode) == -1)
1985 error("local chmod directory \"%s\": %s", dst,
1986 strerror(errno));
1987
1988 sftp_free_dirents(dir_entries);
1989
1990 return ret;
1991 }
1992
1993 int
sftp_download_dir(struct sftp_conn * conn,const char * src,const char * dst,Attrib * dirattrib,int preserve_flag,int print_flag,int resume_flag,int fsync_flag,int follow_link_flag,int inplace_flag)1994 sftp_download_dir(struct sftp_conn *conn, const char *src, const char *dst,
1995 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
1996 int fsync_flag, int follow_link_flag, int inplace_flag)
1997 {
1998 char *src_canon;
1999 int ret;
2000
2001 if ((src_canon = sftp_realpath(conn, src)) == NULL) {
2002 error("download \"%s\": path canonicalization failed", src);
2003 return -1;
2004 }
2005
2006 ret = download_dir_internal(conn, src_canon, dst, 0,
2007 dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag,
2008 follow_link_flag, inplace_flag);
2009 free(src_canon);
2010 return ret;
2011 }
2012
2013 int
sftp_upload(struct sftp_conn * conn,const char * local_path,const char * remote_path,int preserve_flag,int resume,int fsync_flag,int inplace_flag)2014 sftp_upload(struct sftp_conn *conn, const char *local_path,
2015 const char *remote_path, int preserve_flag, int resume,
2016 int fsync_flag, int inplace_flag)
2017 {
2018 int r, local_fd;
2019 u_int openmode, id, status = SSH2_FX_OK, reordered = 0;
2020 off_t offset, progress_counter;
2021 u_char type, *handle, *data;
2022 struct sshbuf *msg;
2023 struct stat sb;
2024 Attrib a, t, c;
2025 u_int32_t startid, ackid;
2026 u_int64_t highwater = 0, maxack = 0;
2027 struct request *ack = NULL;
2028 struct requests acks;
2029 size_t handle_len;
2030
2031 debug2_f("upload local \"%s\" to remote \"%s\"",
2032 local_path, remote_path);
2033
2034 TAILQ_INIT(&acks);
2035
2036 if ((local_fd = open(local_path, O_RDONLY)) == -1) {
2037 error("open local \"%s\": %s", local_path, strerror(errno));
2038 return(-1);
2039 }
2040 if (fstat(local_fd, &sb) == -1) {
2041 error("fstat local \"%s\": %s", local_path, strerror(errno));
2042 close(local_fd);
2043 return(-1);
2044 }
2045 if (!S_ISREG(sb.st_mode)) {
2046 error("local \"%s\" is not a regular file", local_path);
2047 close(local_fd);
2048 return(-1);
2049 }
2050 stat_to_attrib(&sb, &a);
2051
2052 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
2053 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
2054 a.perm &= 0777;
2055 if (!preserve_flag)
2056 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
2057
2058 if (resume) {
2059 /* Get remote file size if it exists */
2060 if (sftp_stat(conn, remote_path, 0, &c) != 0) {
2061 close(local_fd);
2062 return -1;
2063 }
2064
2065 if ((off_t)c.size >= sb.st_size) {
2066 error("resume \"%s\": destination file "
2067 "same size or larger", local_path);
2068 close(local_fd);
2069 return -1;
2070 }
2071
2072 if (lseek(local_fd, (off_t)c.size, SEEK_SET) == -1) {
2073 close(local_fd);
2074 return -1;
2075 }
2076 }
2077
2078 openmode = SSH2_FXF_WRITE|SSH2_FXF_CREAT;
2079 if (resume)
2080 openmode |= SSH2_FXF_APPEND;
2081 else if (!inplace_flag)
2082 openmode |= SSH2_FXF_TRUNC;
2083
2084 /* Send open request */
2085 if (send_open(conn, remote_path, "dest", openmode, &a,
2086 &handle, &handle_len) != 0) {
2087 close(local_fd);
2088 return -1;
2089 }
2090
2091 id = conn->msg_id;
2092 startid = ackid = id + 1;
2093 data = xmalloc(conn->upload_buflen);
2094
2095 /* Read from local and write to remote */
2096 offset = progress_counter = (resume ? c.size : 0);
2097 if (showprogress) {
2098 start_progress_meter(progress_meter_path(local_path),
2099 sb.st_size, &progress_counter);
2100 }
2101
2102 if ((msg = sshbuf_new()) == NULL)
2103 fatal_f("sshbuf_new failed");
2104 for (;;) {
2105 int len;
2106
2107 /*
2108 * Can't use atomicio here because it returns 0 on EOF,
2109 * thus losing the last block of the file.
2110 * Simulate an EOF on interrupt, allowing ACKs from the
2111 * server to drain.
2112 */
2113 if (interrupted || status != SSH2_FX_OK)
2114 len = 0;
2115 else do
2116 len = read(local_fd, data, conn->upload_buflen);
2117 while ((len == -1) && (errno == EINTR || errno == EAGAIN));
2118
2119 if (len == -1) {
2120 fatal("read local \"%s\": %s",
2121 local_path, strerror(errno));
2122 } else if (len != 0) {
2123 ack = request_enqueue(&acks, ++id, len, offset);
2124 sshbuf_reset(msg);
2125 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
2126 (r = sshbuf_put_u32(msg, ack->id)) != 0 ||
2127 (r = sshbuf_put_string(msg, handle,
2128 handle_len)) != 0 ||
2129 (r = sshbuf_put_u64(msg, offset)) != 0 ||
2130 (r = sshbuf_put_string(msg, data, len)) != 0)
2131 fatal_fr(r, "compose");
2132 send_msg(conn, msg);
2133 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
2134 id, (unsigned long long)offset, len);
2135 } else if (TAILQ_FIRST(&acks) == NULL)
2136 break;
2137
2138 if (ack == NULL)
2139 fatal("Unexpected ACK %u", id);
2140
2141 if (id == startid || len == 0 ||
2142 id - ackid >= conn->num_requests) {
2143 u_int rid;
2144
2145 sshbuf_reset(msg);
2146 get_msg(conn, msg);
2147 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
2148 (r = sshbuf_get_u32(msg, &rid)) != 0)
2149 fatal_fr(r, "parse");
2150
2151 if (type != SSH2_FXP_STATUS)
2152 fatal("Expected SSH2_FXP_STATUS(%d) packet, "
2153 "got %d", SSH2_FXP_STATUS, type);
2154
2155 if ((r = sshbuf_get_u32(msg, &status)) != 0)
2156 fatal_fr(r, "parse status");
2157 debug3("SSH2_FXP_STATUS %u", status);
2158
2159 /* Find the request in our queue */
2160 if ((ack = request_find(&acks, rid)) == NULL)
2161 fatal("Can't find request for ID %u", rid);
2162 TAILQ_REMOVE(&acks, ack, tq);
2163 debug3("In write loop, ack for %u %zu bytes at %lld",
2164 ack->id, ack->len, (unsigned long long)ack->offset);
2165 ++ackid;
2166 progress_counter += ack->len;
2167 /*
2168 * Track both the highest offset acknowledged and the
2169 * highest *contiguous* offset acknowledged.
2170 * We'll need the latter for ftruncate()ing
2171 * interrupted transfers.
2172 */
2173 if (maxack < ack->offset + ack->len)
2174 maxack = ack->offset + ack->len;
2175 if (!reordered && ack->offset <= highwater)
2176 highwater = maxack;
2177 else if (!reordered && ack->offset > highwater) {
2178 debug3_f("server reordered ACKs");
2179 reordered = 1;
2180 }
2181 free(ack);
2182 }
2183 offset += len;
2184 if (offset < 0)
2185 fatal_f("offset < 0");
2186 }
2187 sshbuf_free(msg);
2188
2189 if (showprogress)
2190 stop_progress_meter();
2191 free(data);
2192
2193 if (status == SSH2_FX_OK && !interrupted) {
2194 /* we got everything */
2195 highwater = maxack;
2196 }
2197 if (status != SSH2_FX_OK) {
2198 error("write remote \"%s\": %s", remote_path, fx2txt(status));
2199 status = SSH2_FX_FAILURE;
2200 }
2201
2202 if (inplace_flag || (resume && (status != SSH2_FX_OK || interrupted))) {
2203 debug("truncating at %llu", (unsigned long long)highwater);
2204 attrib_clear(&t);
2205 t.flags = SSH2_FILEXFER_ATTR_SIZE;
2206 t.size = highwater;
2207 sftp_fsetstat(conn, handle, handle_len, &t);
2208 }
2209
2210 if (close(local_fd) == -1) {
2211 error("close local \"%s\": %s", local_path, strerror(errno));
2212 status = SSH2_FX_FAILURE;
2213 }
2214
2215 /* Override umask and utimes if asked */
2216 if (preserve_flag)
2217 sftp_fsetstat(conn, handle, handle_len, &a);
2218
2219 if (fsync_flag)
2220 (void)sftp_fsync(conn, handle, handle_len);
2221
2222 if (sftp_close(conn, handle, handle_len) != 0)
2223 status = SSH2_FX_FAILURE;
2224
2225 free(handle);
2226
2227 return status == SSH2_FX_OK ? 0 : -1;
2228 }
2229
2230 static int
upload_dir_internal(struct sftp_conn * conn,const char * src,const char * dst,int depth,int preserve_flag,int print_flag,int resume,int fsync_flag,int follow_link_flag,int inplace_flag)2231 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
2232 int depth, int preserve_flag, int print_flag, int resume, int fsync_flag,
2233 int follow_link_flag, int inplace_flag)
2234 {
2235 int ret = 0;
2236 DIR *dirp;
2237 struct dirent *dp;
2238 char *filename, *new_src = NULL, *new_dst = NULL;
2239 struct stat sb;
2240 Attrib a, dirattrib;
2241 u_int32_t saved_perm;
2242
2243 debug2_f("upload local dir \"%s\" to remote \"%s\"", src, dst);
2244
2245 if (depth >= MAX_DIR_DEPTH) {
2246 error("Maximum directory depth exceeded: %d levels", depth);
2247 return -1;
2248 }
2249
2250 if (stat(src, &sb) == -1) {
2251 error("stat local \"%s\": %s", src, strerror(errno));
2252 return -1;
2253 }
2254 if (!S_ISDIR(sb.st_mode)) {
2255 error("\"%s\" is not a directory", src);
2256 return -1;
2257 }
2258 if (print_flag && print_flag != SFTP_PROGRESS_ONLY)
2259 mprintf("Entering %s\n", src);
2260
2261 stat_to_attrib(&sb, &a);
2262 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
2263 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
2264 a.perm &= 01777;
2265 if (!preserve_flag)
2266 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
2267
2268 /*
2269 * sftp lacks a portable status value to match errno EEXIST,
2270 * so if we get a failure back then we must check whether
2271 * the path already existed and is a directory. Ensure we can
2272 * write to the directory we create for the duration of the transfer.
2273 */
2274 saved_perm = a.perm;
2275 a.perm |= (S_IWUSR|S_IXUSR);
2276 if (sftp_mkdir(conn, dst, &a, 0) != 0) {
2277 if (sftp_stat(conn, dst, 0, &dirattrib) != 0)
2278 return -1;
2279 if (!S_ISDIR(dirattrib.perm)) {
2280 error("\"%s\" exists but is not a directory", dst);
2281 return -1;
2282 }
2283 }
2284 a.perm = saved_perm;
2285
2286 if ((dirp = opendir(src)) == NULL) {
2287 error("local opendir \"%s\": %s", src, strerror(errno));
2288 return -1;
2289 }
2290
2291 while (((dp = readdir(dirp)) != NULL) && !interrupted) {
2292 if (dp->d_ino == 0)
2293 continue;
2294 free(new_dst);
2295 free(new_src);
2296 filename = dp->d_name;
2297 new_dst = sftp_path_append(dst, filename);
2298 new_src = sftp_path_append(src, filename);
2299
2300 if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
2301 continue;
2302 if (lstat(new_src, &sb) == -1) {
2303 logit("local lstat \"%s\": %s", filename,
2304 strerror(errno));
2305 ret = -1;
2306 continue;
2307 }
2308 if (S_ISLNK(sb.st_mode)) {
2309 if (!follow_link_flag) {
2310 logit("%s: not a regular file", filename);
2311 continue;
2312 }
2313 /* Replace the stat contents with the symlink target */
2314 if (stat(new_src, &sb) == -1) {
2315 logit("local stat \"%s\": %s", filename,
2316 strerror(errno));
2317 ret = -1;
2318 continue;
2319 }
2320 }
2321 if (S_ISDIR(sb.st_mode)) {
2322 if (upload_dir_internal(conn, new_src, new_dst,
2323 depth + 1, preserve_flag, print_flag, resume,
2324 fsync_flag, follow_link_flag, inplace_flag) == -1)
2325 ret = -1;
2326 } else if (S_ISREG(sb.st_mode)) {
2327 if (sftp_upload(conn, new_src, new_dst,
2328 preserve_flag, resume, fsync_flag,
2329 inplace_flag) == -1) {
2330 error("upload \"%s\" to \"%s\" failed",
2331 new_src, new_dst);
2332 ret = -1;
2333 }
2334 } else
2335 logit("%s: not a regular file", filename);
2336 }
2337 free(new_dst);
2338 free(new_src);
2339
2340 sftp_setstat(conn, dst, &a);
2341
2342 (void) closedir(dirp);
2343 return ret;
2344 }
2345
2346 int
sftp_upload_dir(struct sftp_conn * conn,const char * src,const char * dst,int preserve_flag,int print_flag,int resume,int fsync_flag,int follow_link_flag,int inplace_flag)2347 sftp_upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
2348 int preserve_flag, int print_flag, int resume, int fsync_flag,
2349 int follow_link_flag, int inplace_flag)
2350 {
2351 char *dst_canon;
2352 int ret;
2353
2354 if ((dst_canon = sftp_realpath(conn, dst)) == NULL) {
2355 error("upload \"%s\": path canonicalization failed", dst);
2356 return -1;
2357 }
2358
2359 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
2360 print_flag, resume, fsync_flag, follow_link_flag, inplace_flag);
2361
2362 free(dst_canon);
2363 return ret;
2364 }
2365
2366 static void
handle_dest_replies(struct sftp_conn * to,const char * to_path,int synchronous,u_int * nreqsp,int * write_errorp)2367 handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous,
2368 u_int *nreqsp, int *write_errorp)
2369 {
2370 struct sshbuf *msg;
2371 u_char type;
2372 u_int id, status;
2373 int r;
2374 struct pollfd pfd;
2375
2376 if ((msg = sshbuf_new()) == NULL)
2377 fatal_f("sshbuf_new failed");
2378
2379 /* Try to eat replies from the upload side */
2380 while (*nreqsp > 0) {
2381 debug3_f("%u outstanding replies", *nreqsp);
2382 if (!synchronous) {
2383 /* Bail out if no data is ready to be read */
2384 pfd.fd = to->fd_in;
2385 pfd.events = POLLIN;
2386 if ((r = poll(&pfd, 1, 0)) == -1) {
2387 if (errno == EINTR)
2388 break;
2389 fatal_f("poll: %s", strerror(errno));
2390 } else if (r == 0)
2391 break; /* fd not ready */
2392 }
2393 sshbuf_reset(msg);
2394 get_msg(to, msg);
2395
2396 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
2397 (r = sshbuf_get_u32(msg, &id)) != 0)
2398 fatal_fr(r, "dest parse");
2399 debug3("Received dest reply T:%u I:%u R:%u", type, id, *nreqsp);
2400 if (type != SSH2_FXP_STATUS) {
2401 fatal_f("Expected SSH2_FXP_STATUS(%d) packet, got %d",
2402 SSH2_FXP_STATUS, type);
2403 }
2404 if ((r = sshbuf_get_u32(msg, &status)) != 0)
2405 fatal_fr(r, "parse dest status");
2406 debug3("dest SSH2_FXP_STATUS %u", status);
2407 if (status != SSH2_FX_OK) {
2408 /* record first error */
2409 if (*write_errorp == 0)
2410 *write_errorp = status;
2411 }
2412 /*
2413 * XXX this doesn't do full reply matching like sftp_upload and
2414 * so cannot gracefully truncate terminated uploads at a
2415 * high-water mark. ATM the only caller of this function (scp)
2416 * doesn't support transfer resumption, so this doesn't matter
2417 * a whole lot.
2418 *
2419 * To be safe, sftp_crossload truncates the destination file to
2420 * zero length on upload failure, since we can't trust the
2421 * server not to have reordered replies that could have
2422 * inserted holes where none existed in the source file.
2423 *
2424 * XXX we could get a more accurate progress bar if we updated
2425 * the counter based on the reply from the destination...
2426 */
2427 (*nreqsp)--;
2428 }
2429 debug3_f("done: %u outstanding replies", *nreqsp);
2430 sshbuf_free(msg);
2431 }
2432
2433 int
sftp_crossload(struct sftp_conn * from,struct sftp_conn * to,const char * from_path,const char * to_path,Attrib * a,int preserve_flag)2434 sftp_crossload(struct sftp_conn *from, struct sftp_conn *to,
2435 const char *from_path, const char *to_path,
2436 Attrib *a, int preserve_flag)
2437 {
2438 struct sshbuf *msg;
2439 int write_error, read_error, r;
2440 u_int64_t offset = 0, size;
2441 u_int id, buflen, num_req, max_req, status = SSH2_FX_OK;
2442 u_int num_upload_req;
2443 off_t progress_counter;
2444 u_char *from_handle, *to_handle;
2445 size_t from_handle_len, to_handle_len;
2446 struct requests requests;
2447 struct request *req;
2448 u_char type;
2449 Attrib attr;
2450
2451 debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path);
2452
2453 TAILQ_INIT(&requests);
2454
2455 if (a == NULL) {
2456 if (sftp_stat(from, from_path, 0, &attr) != 0)
2457 return -1;
2458 a = &attr;
2459 }
2460
2461 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
2462 (!S_ISREG(a->perm))) {
2463 error("download \"%s\": not a regular file", from_path);
2464 return(-1);
2465 }
2466 if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
2467 size = a->size;
2468 else
2469 size = 0;
2470
2471 buflen = from->download_buflen;
2472 if (buflen > to->upload_buflen)
2473 buflen = to->upload_buflen;
2474
2475 /* Send open request to read side */
2476 if (send_open(from, from_path, "origin", SSH2_FXF_READ, NULL,
2477 &from_handle, &from_handle_len) != 0)
2478 return -1;
2479
2480 /* Send open request to write side */
2481 a->flags &= ~SSH2_FILEXFER_ATTR_SIZE;
2482 a->flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
2483 a->perm &= 0777;
2484 if (!preserve_flag)
2485 a->flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
2486 if (send_open(to, to_path, "dest",
2487 SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
2488 &to_handle, &to_handle_len) != 0) {
2489 sftp_close(from, from_handle, from_handle_len);
2490 return -1;
2491 }
2492
2493 /* Read from remote "from" and write to remote "to" */
2494 offset = 0;
2495 write_error = read_error = num_req = num_upload_req = 0;
2496 max_req = 1;
2497 progress_counter = 0;
2498
2499 if (showprogress && size != 0) {
2500 start_progress_meter(progress_meter_path(from_path),
2501 size, &progress_counter);
2502 }
2503 if ((msg = sshbuf_new()) == NULL)
2504 fatal_f("sshbuf_new failed");
2505 while (num_req > 0 || max_req > 0) {
2506 u_char *data;
2507 size_t len;
2508
2509 /*
2510 * Simulate EOF on interrupt: stop sending new requests and
2511 * allow outstanding requests to drain gracefully
2512 */
2513 if (interrupted) {
2514 if (num_req == 0) /* If we haven't started yet... */
2515 break;
2516 max_req = 0;
2517 }
2518
2519 /* Send some more requests */
2520 while (num_req < max_req) {
2521 debug3("Request range %llu -> %llu (%d/%d)",
2522 (unsigned long long)offset,
2523 (unsigned long long)offset + buflen - 1,
2524 num_req, max_req);
2525 req = request_enqueue(&requests, from->msg_id++,
2526 buflen, offset);
2527 offset += buflen;
2528 num_req++;
2529 send_read_request(from, req->id, req->offset,
2530 req->len, from_handle, from_handle_len);
2531 }
2532
2533 /* Try to eat replies from the upload side (nonblocking) */
2534 handle_dest_replies(to, to_path, 0,
2535 &num_upload_req, &write_error);
2536
2537 sshbuf_reset(msg);
2538 get_msg(from, msg);
2539 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
2540 (r = sshbuf_get_u32(msg, &id)) != 0)
2541 fatal_fr(r, "parse");
2542 debug3("Received origin reply T:%u I:%u R:%d",
2543 type, id, max_req);
2544
2545 /* Find the request in our queue */
2546 if ((req = request_find(&requests, id)) == NULL)
2547 fatal("Unexpected reply %u", id);
2548
2549 switch (type) {
2550 case SSH2_FXP_STATUS:
2551 if ((r = sshbuf_get_u32(msg, &status)) != 0)
2552 fatal_fr(r, "parse status");
2553 if (status != SSH2_FX_EOF)
2554 read_error = 1;
2555 max_req = 0;
2556 TAILQ_REMOVE(&requests, req, tq);
2557 free(req);
2558 num_req--;
2559 break;
2560 case SSH2_FXP_DATA:
2561 if ((r = sshbuf_get_string(msg, &data, &len)) != 0)
2562 fatal_fr(r, "parse data");
2563 debug3("Received data %llu -> %llu",
2564 (unsigned long long)req->offset,
2565 (unsigned long long)req->offset + len - 1);
2566 if (len > req->len)
2567 fatal("Received more data than asked for "
2568 "%zu > %zu", len, req->len);
2569
2570 /* Write this chunk out to the destination */
2571 sshbuf_reset(msg);
2572 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
2573 (r = sshbuf_put_u32(msg, to->msg_id++)) != 0 ||
2574 (r = sshbuf_put_string(msg, to_handle,
2575 to_handle_len)) != 0 ||
2576 (r = sshbuf_put_u64(msg, req->offset)) != 0 ||
2577 (r = sshbuf_put_string(msg, data, len)) != 0)
2578 fatal_fr(r, "compose write");
2579 send_msg(to, msg);
2580 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%zu",
2581 id, (unsigned long long)offset, len);
2582 num_upload_req++;
2583 progress_counter += len;
2584 free(data);
2585
2586 if (len == req->len) {
2587 TAILQ_REMOVE(&requests, req, tq);
2588 free(req);
2589 num_req--;
2590 } else {
2591 /* Resend the request for the missing data */
2592 debug3("Short data block, re-requesting "
2593 "%llu -> %llu (%2d)",
2594 (unsigned long long)req->offset + len,
2595 (unsigned long long)req->offset +
2596 req->len - 1, num_req);
2597 req->id = from->msg_id++;
2598 req->len -= len;
2599 req->offset += len;
2600 send_read_request(from, req->id,
2601 req->offset, req->len,
2602 from_handle, from_handle_len);
2603 /* Reduce the request size */
2604 if (len < buflen)
2605 buflen = MAXIMUM(MIN_READ_SIZE, len);
2606 }
2607 if (max_req > 0) { /* max_req = 0 iff EOF received */
2608 if (size > 0 && offset > size) {
2609 /* Only one request at a time
2610 * after the expected EOF */
2611 debug3("Finish at %llu (%2d)",
2612 (unsigned long long)offset,
2613 num_req);
2614 max_req = 1;
2615 } else if (max_req < from->num_requests) {
2616 ++max_req;
2617 }
2618 }
2619 break;
2620 default:
2621 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
2622 SSH2_FXP_DATA, type);
2623 }
2624 }
2625
2626 if (showprogress && size)
2627 stop_progress_meter();
2628
2629 /* Drain replies from the server (blocking) */
2630 debug3_f("waiting for %u replies from destination", num_upload_req);
2631 handle_dest_replies(to, to_path, 1, &num_upload_req, &write_error);
2632
2633 /* Sanity check */
2634 if (TAILQ_FIRST(&requests) != NULL)
2635 fatal("Transfer complete, but requests still in queue");
2636 /* Truncate at 0 length on interrupt or error to avoid holes at dest */
2637 if (read_error || write_error || interrupted) {
2638 debug("truncating \"%s\" at 0", to_path);
2639 sftp_close(to, to_handle, to_handle_len);
2640 free(to_handle);
2641 if (send_open(to, to_path, "dest",
2642 SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
2643 &to_handle, &to_handle_len) != 0) {
2644 error("dest truncate \"%s\" failed", to_path);
2645 to_handle = NULL;
2646 }
2647 }
2648 if (read_error) {
2649 error("read origin \"%s\": %s", from_path, fx2txt(status));
2650 status = -1;
2651 sftp_close(from, from_handle, from_handle_len);
2652 if (to_handle != NULL)
2653 sftp_close(to, to_handle, to_handle_len);
2654 } else if (write_error) {
2655 error("write dest \"%s\": %s", to_path, fx2txt(write_error));
2656 status = SSH2_FX_FAILURE;
2657 sftp_close(from, from_handle, from_handle_len);
2658 if (to_handle != NULL)
2659 sftp_close(to, to_handle, to_handle_len);
2660 } else {
2661 if (sftp_close(from, from_handle, from_handle_len) != 0 ||
2662 interrupted)
2663 status = -1;
2664 else
2665 status = SSH2_FX_OK;
2666 if (to_handle != NULL) {
2667 /* Need to resend utimes after write */
2668 if (preserve_flag)
2669 sftp_fsetstat(to, to_handle, to_handle_len, a);
2670 sftp_close(to, to_handle, to_handle_len);
2671 }
2672 }
2673 sshbuf_free(msg);
2674 free(from_handle);
2675 free(to_handle);
2676
2677 return status == SSH2_FX_OK ? 0 : -1;
2678 }
2679
2680 static int
crossload_dir_internal(struct sftp_conn * from,struct sftp_conn * to,const char * from_path,const char * to_path,int depth,Attrib * dirattrib,int preserve_flag,int print_flag,int follow_link_flag)2681 crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
2682 const char *from_path, const char *to_path,
2683 int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
2684 int follow_link_flag)
2685 {
2686 int i, ret = 0;
2687 SFTP_DIRENT **dir_entries;
2688 char *filename, *new_from_path = NULL, *new_to_path = NULL;
2689 mode_t mode = 0777;
2690 Attrib *a, curdir, ldirattrib, newdir, lsym;
2691
2692 debug2_f("crossload dir src \"%s\" to dst \"%s\"", from_path, to_path);
2693
2694 if (depth >= MAX_DIR_DEPTH) {
2695 error("Maximum directory depth exceeded: %d levels", depth);
2696 return -1;
2697 }
2698
2699 if (dirattrib == NULL) {
2700 if (sftp_stat(from, from_path, 1, &ldirattrib) != 0) {
2701 error("stat remote \"%s\" failed", from_path);
2702 return -1;
2703 }
2704 dirattrib = &ldirattrib;
2705 }
2706 if (!S_ISDIR(dirattrib->perm)) {
2707 error("\"%s\" is not a directory", from_path);
2708 return -1;
2709 }
2710 if (print_flag && print_flag != SFTP_PROGRESS_ONLY)
2711 mprintf("Retrieving %s\n", from_path);
2712
2713 curdir = *dirattrib; /* dirattrib will be clobbered */
2714 curdir.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
2715 curdir.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
2716 if ((curdir.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) == 0) {
2717 debug("Origin did not send permissions for "
2718 "directory \"%s\"", to_path);
2719 curdir.perm = S_IWUSR|S_IXUSR;
2720 curdir.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
2721 }
2722 /* We need to be able to write to the directory while we transfer it */
2723 mode = curdir.perm & 01777;
2724 curdir.perm = mode | (S_IWUSR|S_IXUSR);
2725
2726 /*
2727 * sftp lacks a portable status value to match errno EEXIST,
2728 * so if we get a failure back then we must check whether
2729 * the path already existed and is a directory. Ensure we can
2730 * write to the directory we create for the duration of the transfer.
2731 */
2732 if (sftp_mkdir(to, to_path, &curdir, 0) != 0) {
2733 if (sftp_stat(to, to_path, 0, &newdir) != 0)
2734 return -1;
2735 if (!S_ISDIR(newdir.perm)) {
2736 error("\"%s\" exists but is not a directory", to_path);
2737 return -1;
2738 }
2739 }
2740 curdir.perm = mode;
2741
2742 if (sftp_readdir(from, from_path, &dir_entries) == -1) {
2743 error("origin readdir \"%s\" failed", from_path);
2744 return -1;
2745 }
2746
2747 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
2748 free(new_from_path);
2749 free(new_to_path);
2750
2751 filename = dir_entries[i]->filename;
2752 new_from_path = sftp_path_append(from_path, filename);
2753 new_to_path = sftp_path_append(to_path, filename);
2754
2755 a = &dir_entries[i]->a;
2756 if (S_ISLNK(a->perm)) {
2757 if (!follow_link_flag) {
2758 logit("%s: not a regular file", filename);
2759 continue;
2760 }
2761 /* Replace the stat contents with the symlink target */
2762 if (sftp_stat(from, new_from_path, 1, &lsym) != 0) {
2763 logit("remote stat \"%s\" failed",
2764 new_from_path);
2765 ret = -1;
2766 continue;
2767 }
2768 a = &lsym;
2769 }
2770 if (S_ISDIR(a->perm)) {
2771 if (strcmp(filename, ".") == 0 ||
2772 strcmp(filename, "..") == 0)
2773 continue;
2774 if (crossload_dir_internal(from, to,
2775 new_from_path, new_to_path,
2776 depth + 1, a, preserve_flag,
2777 print_flag, follow_link_flag) == -1)
2778 ret = -1;
2779 } else if (S_ISREG(a->perm)) {
2780 if (sftp_crossload(from, to, new_from_path,
2781 new_to_path, a, preserve_flag) == -1) {
2782 error("crossload \"%s\" to \"%s\" failed",
2783 new_from_path, new_to_path);
2784 ret = -1;
2785 }
2786 } else {
2787 logit("origin \"%s\": not a regular file",
2788 new_from_path);
2789 }
2790 }
2791 free(new_to_path);
2792 free(new_from_path);
2793
2794 sftp_setstat(to, to_path, &curdir);
2795
2796 sftp_free_dirents(dir_entries);
2797
2798 return ret;
2799 }
2800
2801 int
sftp_crossload_dir(struct sftp_conn * from,struct sftp_conn * to,const char * from_path,const char * to_path,Attrib * dirattrib,int preserve_flag,int print_flag,int follow_link_flag)2802 sftp_crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
2803 const char *from_path, const char *to_path,
2804 Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag)
2805 {
2806 char *from_path_canon;
2807 int ret;
2808
2809 if ((from_path_canon = sftp_realpath(from, from_path)) == NULL) {
2810 error("crossload \"%s\": path canonicalization failed",
2811 from_path);
2812 return -1;
2813 }
2814
2815 ret = crossload_dir_internal(from, to, from_path_canon, to_path, 0,
2816 dirattrib, preserve_flag, print_flag, follow_link_flag);
2817 free(from_path_canon);
2818 return ret;
2819 }
2820
2821 int
sftp_can_get_users_groups_by_id(struct sftp_conn * conn)2822 sftp_can_get_users_groups_by_id(struct sftp_conn *conn)
2823 {
2824 return (conn->exts & SFTP_EXT_GETUSERSGROUPS_BY_ID) != 0;
2825 }
2826
2827 int
sftp_get_users_groups_by_id(struct sftp_conn * conn,const u_int * uids,u_int nuids,const u_int * gids,u_int ngids,char *** usernamesp,char *** groupnamesp)2828 sftp_get_users_groups_by_id(struct sftp_conn *conn,
2829 const u_int *uids, u_int nuids,
2830 const u_int *gids, u_int ngids,
2831 char ***usernamesp, char ***groupnamesp)
2832 {
2833 struct sshbuf *msg, *uidbuf, *gidbuf;
2834 u_int i, expected_id, id;
2835 char *name, **usernames = NULL, **groupnames = NULL;
2836 u_char type;
2837 int r;
2838
2839 *usernamesp = *groupnamesp = NULL;
2840 if (!sftp_can_get_users_groups_by_id(conn))
2841 return SSH_ERR_FEATURE_UNSUPPORTED;
2842
2843 if ((msg = sshbuf_new()) == NULL ||
2844 (uidbuf = sshbuf_new()) == NULL ||
2845 (gidbuf = sshbuf_new()) == NULL)
2846 fatal_f("sshbuf_new failed");
2847 expected_id = id = conn->msg_id++;
2848 debug2("Sending SSH2_FXP_EXTENDED(users-groups-by-id@openssh.com)");
2849 for (i = 0; i < nuids; i++) {
2850 if ((r = sshbuf_put_u32(uidbuf, uids[i])) != 0)
2851 fatal_fr(r, "compose uids");
2852 }
2853 for (i = 0; i < ngids; i++) {
2854 if ((r = sshbuf_put_u32(gidbuf, gids[i])) != 0)
2855 fatal_fr(r, "compose gids");
2856 }
2857 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
2858 (r = sshbuf_put_u32(msg, id)) != 0 ||
2859 (r = sshbuf_put_cstring(msg,
2860 "users-groups-by-id@openssh.com")) != 0 ||
2861 (r = sshbuf_put_stringb(msg, uidbuf)) != 0 ||
2862 (r = sshbuf_put_stringb(msg, gidbuf)) != 0)
2863 fatal_fr(r, "compose");
2864 send_msg(conn, msg);
2865 get_msg(conn, msg);
2866 if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
2867 (r = sshbuf_get_u32(msg, &id)) != 0)
2868 fatal_fr(r, "parse");
2869 if (id != expected_id)
2870 fatal("ID mismatch (%u != %u)", id, expected_id);
2871 if (type == SSH2_FXP_STATUS) {
2872 u_int status;
2873 char *errmsg;
2874
2875 if ((r = sshbuf_get_u32(msg, &status)) != 0 ||
2876 (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0)
2877 fatal_fr(r, "parse status");
2878 error("users-groups-by-id %s",
2879 *errmsg == '\0' ? fx2txt(status) : errmsg);
2880 free(errmsg);
2881 sshbuf_free(msg);
2882 sshbuf_free(uidbuf);
2883 sshbuf_free(gidbuf);
2884 return -1;
2885 } else if (type != SSH2_FXP_EXTENDED_REPLY)
2886 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
2887 SSH2_FXP_EXTENDED_REPLY, type);
2888
2889 /* reuse */
2890 sshbuf_free(uidbuf);
2891 sshbuf_free(gidbuf);
2892 uidbuf = gidbuf = NULL;
2893 if ((r = sshbuf_froms(msg, &uidbuf)) != 0 ||
2894 (r = sshbuf_froms(msg, &gidbuf)) != 0)
2895 fatal_fr(r, "parse response");
2896 if (nuids > 0) {
2897 usernames = xcalloc(nuids, sizeof(*usernames));
2898 for (i = 0; i < nuids; i++) {
2899 if ((r = sshbuf_get_cstring(uidbuf, &name, NULL)) != 0)
2900 fatal_fr(r, "parse user name");
2901 /* Handle unresolved names */
2902 if (*name == '\0') {
2903 free(name);
2904 name = NULL;
2905 }
2906 usernames[i] = name;
2907 }
2908 }
2909 if (ngids > 0) {
2910 groupnames = xcalloc(ngids, sizeof(*groupnames));
2911 for (i = 0; i < ngids; i++) {
2912 if ((r = sshbuf_get_cstring(gidbuf, &name, NULL)) != 0)
2913 fatal_fr(r, "parse user name");
2914 /* Handle unresolved names */
2915 if (*name == '\0') {
2916 free(name);
2917 name = NULL;
2918 }
2919 groupnames[i] = name;
2920 }
2921 }
2922 if (sshbuf_len(uidbuf) != 0)
2923 fatal_f("unexpected extra username data");
2924 if (sshbuf_len(gidbuf) != 0)
2925 fatal_f("unexpected extra groupname data");
2926 sshbuf_free(uidbuf);
2927 sshbuf_free(gidbuf);
2928 sshbuf_free(msg);
2929 /* success */
2930 *usernamesp = usernames;
2931 *groupnamesp = groupnames;
2932 return 0;
2933 }
2934
2935 char *
sftp_path_append(const char * p1,const char * p2)2936 sftp_path_append(const char *p1, const char *p2)
2937 {
2938 char *ret;
2939 size_t len = strlen(p1) + strlen(p2) + 2;
2940
2941 ret = xmalloc(len);
2942 strlcpy(ret, p1, len);
2943 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
2944 strlcat(ret, "/", len);
2945 strlcat(ret, p2, len);
2946
2947 return(ret);
2948 }
2949
2950 /*
2951 * Arg p must be dynamically allocated. It will either be returned or
2952 * freed and a replacement allocated. Caller must free returned string.
2953 */
2954 char *
sftp_make_absolute(char * p,const char * pwd)2955 sftp_make_absolute(char *p, const char *pwd)
2956 {
2957 char *abs_str;
2958
2959 /* Derelativise */
2960 if (p && !path_absolute(p)) {
2961 abs_str = sftp_path_append(pwd, p);
2962 free(p);
2963 return(abs_str);
2964 } else
2965 return(p);
2966 }
2967
2968 int
sftp_remote_is_dir(struct sftp_conn * conn,const char * path)2969 sftp_remote_is_dir(struct sftp_conn *conn, const char *path)
2970 {
2971 Attrib a;
2972
2973 /* XXX: report errors? */
2974 if (sftp_stat(conn, path, 1, &a) != 0)
2975 return(0);
2976 if (!(a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
2977 return(0);
2978 return S_ISDIR(a.perm);
2979 }
2980
2981
2982 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
2983 int
sftp_globpath_is_dir(const char * pathname)2984 sftp_globpath_is_dir(const char *pathname)
2985 {
2986 size_t l = strlen(pathname);
2987
2988 return l > 0 && pathname[l - 1] == '/';
2989 }
2990
2991