Coverage Report

Created: 2026-10-23 07:09

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