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