Bug Summary

File:src/usr.bin/ssh/sftp/../sftp-client.c
Warning:line 545, column 28
Branch condition evaluates to a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

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