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