Annotation of src/usr.bin/ssh/sftp-client.c, Revision 1.142
1.142 ! djm 1: /* $OpenBSD: sftp-client.c,v 1.141 2021/03/31 22:16:34 djm Exp $ */
1.1 djm 2: /*
1.46 djm 3: * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
1.1 djm 4: *
1.46 djm 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.
1.1 djm 8: *
1.46 djm 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.
1.1 djm 16: */
17:
18: /* XXX: memleaks */
19: /* XXX: signed vs unsigned */
1.23 djm 20: /* XXX: remove all logging, only return status codes */
1.1 djm 21: /* XXX: copy between two remote sites */
22:
1.74 deraadt 23: #include <sys/types.h>
1.93 djm 24: #include <sys/poll.h>
1.21 djm 25: #include <sys/queue.h>
1.60 stevesk 26: #include <sys/stat.h>
1.71 stevesk 27: #include <sys/time.h>
1.82 djm 28: #include <sys/statvfs.h>
1.74 deraadt 29: #include <sys/uio.h>
1.66 stevesk 30:
1.89 djm 31: #include <dirent.h>
1.67 stevesk 32: #include <errno.h>
1.66 stevesk 33: #include <fcntl.h>
1.70 stevesk 34: #include <signal.h>
1.87 dtucker 35: #include <stdarg.h>
1.73 stevesk 36: #include <stdio.h>
1.109 dtucker 37: #include <stdlib.h>
1.69 stevesk 38: #include <string.h>
1.68 stevesk 39: #include <unistd.h>
1.1 djm 40:
1.74 deraadt 41: #include "xmalloc.h"
1.116 djm 42: #include "ssherr.h"
43: #include "sshbuf.h"
1.1 djm 44: #include "log.h"
45: #include "atomicio.h"
1.39 fgsch 46: #include "progressmeter.h"
1.64 djm 47: #include "misc.h"
1.124 schwarze 48: #include "utf8.h"
1.1 djm 49:
50: #include "sftp.h"
51: #include "sftp-common.h"
52: #include "sftp-client.h"
53:
1.49 djm 54: extern volatile sig_atomic_t interrupted;
1.39 fgsch 55: extern int showprogress;
56:
1.141 djm 57: /* Default size of buffer for up/download */
58: #define DEFAULT_COPY_BUFLEN 32768
59:
60: /* Default number of concurrent outstanding requests */
61: #define DEFAULT_NUM_REQUESTS 64
62:
1.59 david 63: /* Minimum amount of data to read at a time */
1.21 djm 64: #define MIN_READ_SIZE 512
65:
1.89 djm 66: /* Maximum depth to descend in directory trees */
67: #define MAX_DIR_DEPTH 64
68:
1.23 djm 69: struct sftp_conn {
70: int fd_in;
71: int fd_out;
1.141 djm 72: u_int download_buflen;
73: u_int upload_buflen;
1.23 djm 74: u_int num_requests;
75: u_int version;
76: u_int msg_id;
1.82 djm 77: #define SFTP_EXT_POSIX_RENAME 0x00000001
78: #define SFTP_EXT_STATVFS 0x00000002
79: #define SFTP_EXT_FSTATVFS 0x00000004
1.94 djm 80: #define SFTP_EXT_HARDLINK 0x00000008
1.107 djm 81: #define SFTP_EXT_FSYNC 0x00000010
1.131 djm 82: #define SFTP_EXT_LSETSTAT 0x00000020
1.141 djm 83: #define SFTP_EXT_LIMITS 0x00000040
1.81 djm 84: u_int exts;
1.93 djm 85: u_int64_t limit_kbps;
86: struct bwlimit bwlimit_in, bwlimit_out;
1.23 djm 87: };
1.4 djm 88:
1.116 djm 89: static u_char *
90: get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
1.93 djm 91: const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
92:
93: /* ARGSUSED */
94: static int
95: sftpio(void *_bwlimit, size_t amount)
96: {
97: struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
98:
1.133 dtucker 99: refresh_progress_meter(0);
1.132 dtucker 100: if (bwlimit != NULL)
101: bandwidth_limit(bwlimit, amount);
1.93 djm 102: return 0;
103: }
1.88 djm 104:
1.17 itojun 105: static void
1.116 djm 106: send_msg(struct sftp_conn *conn, struct sshbuf *m)
1.1 djm 107: {
1.40 djm 108: u_char mlen[4];
1.65 djm 109: struct iovec iov[2];
1.40 djm 110:
1.116 djm 111: if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH)
112: fatal("Outbound message too long %zu", sshbuf_len(m));
1.40 djm 113:
114: /* Send length first */
1.116 djm 115: put_u32(mlen, sshbuf_len(m));
1.65 djm 116: iov[0].iov_base = mlen;
117: iov[0].iov_len = sizeof(mlen);
1.116 djm 118: iov[1].iov_base = (u_char *)sshbuf_ptr(m);
119: iov[1].iov_len = sshbuf_len(m);
1.74 deraadt 120:
1.132 dtucker 121: if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
122: conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
1.116 djm 123: sshbuf_len(m) + sizeof(mlen))
1.1 djm 124: fatal("Couldn't send packet: %s", strerror(errno));
125:
1.116 djm 126: sshbuf_reset(m);
1.1 djm 127: }
128:
1.17 itojun 129: static void
1.128 dtucker 130: get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
1.1 djm 131: {
1.40 djm 132: u_int msg_len;
1.116 djm 133: u_char *p;
134: int r;
1.1 djm 135:
1.116 djm 136: if ((r = sshbuf_reserve(m, 4, &p)) != 0)
1.137 djm 137: fatal_fr(r, "reserve");
1.132 dtucker 138: if (atomicio6(read, conn->fd_in, p, 4, sftpio,
139: conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
1.127 djm 140: if (errno == EPIPE || errno == ECONNRESET)
1.54 avsm 141: fatal("Connection closed");
142: else
143: fatal("Couldn't read packet: %s", strerror(errno));
144: }
1.1 djm 145:
1.116 djm 146: if ((r = sshbuf_get_u32(m, &msg_len)) != 0)
1.137 djm 147: fatal_fr(r, "sshbuf_get_u32");
1.128 dtucker 148: if (msg_len > SFTP_MAX_MSG_LENGTH) {
149: do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL,
150: "Received message too long %u", msg_len);
151: fatal("Ensure the remote shell produces no output "
152: "for non-interactive sessions.");
153: }
1.1 djm 154:
1.116 djm 155: if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
1.137 djm 156: fatal_fr(r, "reserve");
1.132 dtucker 157: if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
158: conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
1.93 djm 159: != msg_len) {
1.54 avsm 160: if (errno == EPIPE)
161: fatal("Connection closed");
162: else
163: fatal("Read packet: %s", strerror(errno));
164: }
1.1 djm 165: }
166:
1.17 itojun 167: static void
1.128 dtucker 168: get_msg(struct sftp_conn *conn, struct sshbuf *m)
169: {
170: get_msg_extended(conn, m, 0);
171: }
172:
173: static void
1.116 djm 174: send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s,
1.1 djm 175: u_int len)
176: {
1.116 djm 177: struct sshbuf *msg;
178: int r;
1.1 djm 179:
1.116 djm 180: if ((msg = sshbuf_new()) == NULL)
1.137 djm 181: fatal_f("sshbuf_new failed");
1.116 djm 182: if ((r = sshbuf_put_u8(msg, code)) != 0 ||
183: (r = sshbuf_put_u32(msg, id)) != 0 ||
184: (r = sshbuf_put_string(msg, s, len)) != 0)
1.137 djm 185: fatal_fr(r, "compose");
1.116 djm 186: send_msg(conn, msg);
1.93 djm 187: debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
1.116 djm 188: sshbuf_free(msg);
1.1 djm 189: }
190:
1.17 itojun 191: static void
1.93 djm 192: send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
1.116 djm 193: const void *s, u_int len, Attrib *a)
1.1 djm 194: {
1.116 djm 195: struct sshbuf *msg;
196: int r;
1.1 djm 197:
1.116 djm 198: if ((msg = sshbuf_new()) == NULL)
1.137 djm 199: fatal_f("sshbuf_new failed");
1.116 djm 200: if ((r = sshbuf_put_u8(msg, code)) != 0 ||
201: (r = sshbuf_put_u32(msg, id)) != 0 ||
202: (r = sshbuf_put_string(msg, s, len)) != 0 ||
203: (r = encode_attrib(msg, a)) != 0)
1.137 djm 204: fatal_fr(r, "compose");
1.116 djm 205: send_msg(conn, msg);
1.93 djm 206: debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
1.116 djm 207: sshbuf_free(msg);
1.1 djm 208: }
209:
1.17 itojun 210: static u_int
1.93 djm 211: get_status(struct sftp_conn *conn, u_int expected_id)
1.1 djm 212: {
1.116 djm 213: struct sshbuf *msg;
214: u_char type;
215: u_int id, status;
216: int r;
1.1 djm 217:
1.116 djm 218: if ((msg = sshbuf_new()) == NULL)
1.137 djm 219: fatal_f("sshbuf_new failed");
1.116 djm 220: get_msg(conn, msg);
221: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
222: (r = sshbuf_get_u32(msg, &id)) != 0)
1.137 djm 223: fatal_fr(r, "compose");
1.1 djm 224:
225: if (id != expected_id)
1.33 deraadt 226: fatal("ID mismatch (%u != %u)", id, expected_id);
1.1 djm 227: if (type != SSH2_FXP_STATUS)
1.33 deraadt 228: fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
1.1 djm 229: SSH2_FXP_STATUS, type);
230:
1.116 djm 231: if ((r = sshbuf_get_u32(msg, &status)) != 0)
1.137 djm 232: fatal_fr(r, "parse");
1.116 djm 233: sshbuf_free(msg);
1.1 djm 234:
1.33 deraadt 235: debug3("SSH2_FXP_STATUS %u", status);
1.1 djm 236:
1.93 djm 237: return status;
1.1 djm 238: }
239:
1.116 djm 240: static u_char *
241: get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
1.93 djm 242: const char *errfmt, ...)
1.1 djm 243: {
1.116 djm 244: struct sshbuf *msg;
245: u_int id, status;
246: u_char type;
247: u_char *handle;
248: char errmsg[256];
1.88 djm 249: va_list args;
1.116 djm 250: int r;
1.88 djm 251:
252: va_start(args, errfmt);
253: if (errfmt != NULL)
254: vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
255: va_end(args);
1.1 djm 256:
1.116 djm 257: if ((msg = sshbuf_new()) == NULL)
1.137 djm 258: fatal_f("sshbuf_new failed");
1.116 djm 259: get_msg(conn, msg);
260: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
261: (r = sshbuf_get_u32(msg, &id)) != 0)
1.137 djm 262: fatal_fr(r, "parse");
1.1 djm 263:
264: if (id != expected_id)
1.88 djm 265: fatal("%s: ID mismatch (%u != %u)",
266: errfmt == NULL ? __func__ : errmsg, id, expected_id);
1.1 djm 267: if (type == SSH2_FXP_STATUS) {
1.116 djm 268: if ((r = sshbuf_get_u32(msg, &status)) != 0)
1.137 djm 269: fatal_fr(r, "parse status");
1.88 djm 270: if (errfmt != NULL)
271: error("%s: %s", errmsg, fx2txt(status));
1.116 djm 272: sshbuf_free(msg);
1.1 djm 273: return(NULL);
274: } else if (type != SSH2_FXP_HANDLE)
1.88 djm 275: fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
276: errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
1.1 djm 277:
1.116 djm 278: if ((r = sshbuf_get_string(msg, &handle, len)) != 0)
1.137 djm 279: fatal_fr(r, "parse handle");
1.116 djm 280: sshbuf_free(msg);
1.1 djm 281:
1.116 djm 282: return handle;
1.1 djm 283: }
284:
1.17 itojun 285: static Attrib *
1.93 djm 286: get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
1.1 djm 287: {
1.116 djm 288: struct sshbuf *msg;
289: u_int id;
290: u_char type;
291: int r;
292: static Attrib a;
293:
294: if ((msg = sshbuf_new()) == NULL)
1.137 djm 295: fatal_f("sshbuf_new failed");
1.116 djm 296: get_msg(conn, msg);
297:
298: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
299: (r = sshbuf_get_u32(msg, &id)) != 0)
1.137 djm 300: fatal_fr(r, "parse");
1.1 djm 301:
1.33 deraadt 302: debug3("Received stat reply T:%u I:%u", type, id);
1.1 djm 303: if (id != expected_id)
1.33 deraadt 304: fatal("ID mismatch (%u != %u)", id, expected_id);
1.1 djm 305: if (type == SSH2_FXP_STATUS) {
1.116 djm 306: u_int status;
1.1 djm 307:
1.116 djm 308: if ((r = sshbuf_get_u32(msg, &status)) != 0)
1.137 djm 309: fatal_fr(r, "parse status");
1.14 djm 310: if (quiet)
311: debug("Couldn't stat remote file: %s", fx2txt(status));
312: else
313: error("Couldn't stat remote file: %s", fx2txt(status));
1.116 djm 314: sshbuf_free(msg);
1.1 djm 315: return(NULL);
316: } else if (type != SSH2_FXP_ATTRS) {
1.33 deraadt 317: fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
1.1 djm 318: SSH2_FXP_ATTRS, type);
319: }
1.116 djm 320: if ((r = decode_attrib(msg, &a)) != 0) {
1.137 djm 321: error_fr(r, "decode_attrib");
1.116 djm 322: sshbuf_free(msg);
323: return NULL;
324: }
325: sshbuf_free(msg);
1.1 djm 326:
1.116 djm 327: return &a;
1.1 djm 328: }
329:
1.82 djm 330: static int
1.93 djm 331: get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
332: u_int expected_id, int quiet)
1.82 djm 333: {
1.116 djm 334: struct sshbuf *msg;
335: u_char type;
336: u_int id;
337: u_int64_t flag;
338: int r;
1.82 djm 339:
1.116 djm 340: if ((msg = sshbuf_new()) == NULL)
1.137 djm 341: fatal_f("sshbuf_new failed");
1.116 djm 342: get_msg(conn, msg);
343:
344: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
345: (r = sshbuf_get_u32(msg, &id)) != 0)
1.137 djm 346: fatal_fr(r, "parse");
1.82 djm 347:
348: debug3("Received statvfs reply T:%u I:%u", type, id);
349: if (id != expected_id)
350: fatal("ID mismatch (%u != %u)", id, expected_id);
351: if (type == SSH2_FXP_STATUS) {
1.116 djm 352: u_int status;
1.82 djm 353:
1.116 djm 354: if ((r = sshbuf_get_u32(msg, &status)) != 0)
1.137 djm 355: fatal_fr(r, "parse status");
1.82 djm 356: if (quiet)
357: debug("Couldn't statvfs: %s", fx2txt(status));
358: else
359: error("Couldn't statvfs: %s", fx2txt(status));
1.116 djm 360: sshbuf_free(msg);
1.82 djm 361: return -1;
362: } else if (type != SSH2_FXP_EXTENDED_REPLY) {
363: fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
364: SSH2_FXP_EXTENDED_REPLY, type);
365: }
366:
1.114 tedu 367: memset(st, 0, sizeof(*st));
1.116 djm 368: if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 ||
369: (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 ||
370: (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 ||
371: (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 ||
372: (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 ||
373: (r = sshbuf_get_u64(msg, &st->f_files)) != 0 ||
374: (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 ||
375: (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 ||
376: (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 ||
377: (r = sshbuf_get_u64(msg, &flag)) != 0 ||
378: (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0)
1.137 djm 379: fatal_fr(r, "parse statvfs");
1.82 djm 380:
381: st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
382: st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
383:
1.116 djm 384: sshbuf_free(msg);
1.82 djm 385:
386: return 0;
387: }
388:
1.23 djm 389: struct sftp_conn *
1.93 djm 390: do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
391: u_int64_t limit_kbps)
1.1 djm 392: {
1.116 djm 393: u_char type;
394: struct sshbuf *msg;
1.23 djm 395: struct sftp_conn *ret;
1.116 djm 396: int r;
1.1 djm 397:
1.103 djm 398: ret = xcalloc(1, sizeof(*ret));
399: ret->msg_id = 1;
1.93 djm 400: ret->fd_in = fd_in;
401: ret->fd_out = fd_out;
1.141 djm 402: ret->download_buflen = ret->upload_buflen =
403: transfer_buflen ? transfer_buflen : DEFAULT_COPY_BUFLEN;
404: ret->num_requests =
405: num_requests ? num_requests : DEFAULT_NUM_REQUESTS;
1.93 djm 406: ret->exts = 0;
407: ret->limit_kbps = 0;
408:
1.116 djm 409: if ((msg = sshbuf_new()) == NULL)
1.137 djm 410: fatal_f("sshbuf_new failed");
1.116 djm 411: if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 ||
412: (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
1.137 djm 413: fatal_fr(r, "parse");
414:
1.116 djm 415: send_msg(ret, msg);
1.1 djm 416:
1.128 dtucker 417: get_msg_extended(ret, msg, 1);
1.1 djm 418:
1.3 stevesk 419: /* Expecting a VERSION reply */
1.116 djm 420: if ((r = sshbuf_get_u8(msg, &type)) != 0)
1.137 djm 421: fatal_fr(r, "parse type");
1.116 djm 422: if (type != SSH2_FXP_VERSION) {
1.33 deraadt 423: error("Invalid packet back from SSH2_FXP_INIT (type %u)",
1.1 djm 424: type);
1.116 djm 425: sshbuf_free(msg);
1.119 jsg 426: free(ret);
1.23 djm 427: return(NULL);
1.1 djm 428: }
1.116 djm 429: if ((r = sshbuf_get_u32(msg, &ret->version)) != 0)
1.137 djm 430: fatal_fr(r, "parse version");
1.1 djm 431:
1.93 djm 432: debug2("Remote version: %u", ret->version);
1.1 djm 433:
434: /* Check for extensions */
1.116 djm 435: while (sshbuf_len(msg) > 0) {
436: char *name;
437: u_char *value;
438: size_t vlen;
1.85 djm 439: int known = 0;
1.1 djm 440:
1.116 djm 441: if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 ||
442: (r = sshbuf_get_string(msg, &value, &vlen)) != 0)
1.137 djm 443: fatal_fr(r, "parse extension");
1.82 djm 444: if (strcmp(name, "posix-rename@openssh.com") == 0 &&
1.116 djm 445: strcmp((char *)value, "1") == 0) {
1.93 djm 446: ret->exts |= SFTP_EXT_POSIX_RENAME;
1.85 djm 447: known = 1;
448: } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
1.116 djm 449: strcmp((char *)value, "2") == 0) {
1.93 djm 450: ret->exts |= SFTP_EXT_STATVFS;
1.85 djm 451: known = 1;
1.94 djm 452: } else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
1.116 djm 453: strcmp((char *)value, "2") == 0) {
1.93 djm 454: ret->exts |= SFTP_EXT_FSTATVFS;
1.85 djm 455: known = 1;
1.94 djm 456: } else if (strcmp(name, "hardlink@openssh.com") == 0 &&
1.116 djm 457: strcmp((char *)value, "1") == 0) {
1.94 djm 458: ret->exts |= SFTP_EXT_HARDLINK;
459: known = 1;
1.116 djm 460: } else if (strcmp(name, "fsync@openssh.com") == 0 &&
461: strcmp((char *)value, "1") == 0) {
462: ret->exts |= SFTP_EXT_FSYNC;
463: known = 1;
1.131 djm 464: } else if (strcmp(name, "lsetstat@openssh.com") == 0 &&
465: strcmp((char *)value, "1") == 0) {
466: ret->exts |= SFTP_EXT_LSETSTAT;
467: known = 1;
1.141 djm 468: } else if (strcmp(name, "limits@openssh.com") == 0 &&
469: strcmp((char *)value, "1") == 0) {
470: ret->exts |= SFTP_EXT_LIMITS;
471: known = 1;
1.85 djm 472: }
473: if (known) {
474: debug2("Server supports extension \"%s\" revision %s",
475: name, value);
476: } else {
477: debug2("Unrecognised server extension \"%s\"", name);
478: }
1.98 djm 479: free(name);
480: free(value);
1.1 djm 481: }
482:
1.116 djm 483: sshbuf_free(msg);
1.11 djm 484:
1.141 djm 485: /* Query the server for its limits */
486: if (ret->exts & SFTP_EXT_LIMITS) {
487: struct sftp_limits limits;
488: if (do_limits(ret, &limits) != 0)
489: fatal_f("limits failed");
490:
491: /* If the caller did not specify, find a good value */
492: if (transfer_buflen == 0) {
493: ret->download_buflen = limits.read_length;
494: ret->upload_buflen = limits.write_length;
495: debug("Using server download size %u", ret->download_buflen);
496: debug("Using server upload size %u", ret->upload_buflen);
497: }
498:
499: /* Use the server limit to scale down our value only */
500: if (num_requests == 0 && limits.open_handles) {
501: ret->num_requests =
502: MINIMUM(DEFAULT_NUM_REQUESTS, limits.open_handles);
503: debug("Server handle limit %llu; using %u",
1.142 ! djm 504: (unsigned long long)limits.open_handles,
! 505: ret->num_requests);
1.141 djm 506: }
507: }
508:
1.23 djm 509: /* Some filexfer v.0 servers don't support large packets */
1.141 djm 510: if (ret->version == 0) {
511: ret->download_buflen = MINIMUM(ret->download_buflen, 20480);
512: ret->upload_buflen = MINIMUM(ret->upload_buflen, 20480);
513: }
1.23 djm 514:
1.93 djm 515: ret->limit_kbps = limit_kbps;
516: if (ret->limit_kbps > 0) {
517: bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps,
1.141 djm 518: ret->download_buflen);
1.93 djm 519: bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
1.141 djm 520: ret->upload_buflen);
1.93 djm 521: }
522:
523: return ret;
1.23 djm 524: }
525:
526: u_int
527: sftp_proto_version(struct sftp_conn *conn)
528: {
1.93 djm 529: return conn->version;
1.1 djm 530: }
531:
532: int
1.141 djm 533: do_limits(struct sftp_conn *conn, struct sftp_limits *limits)
534: {
535: u_int id, msg_id;
536: u_char type;
537: struct sshbuf *msg;
538: int r;
539:
540: if ((conn->exts & SFTP_EXT_LIMITS) == 0) {
541: error("Server does not support limits@openssh.com extension");
542: return -1;
543: }
544:
545: if ((msg = sshbuf_new()) == NULL)
546: fatal_f("sshbuf_new failed");
547:
548: id = conn->msg_id++;
549: if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
550: (r = sshbuf_put_u32(msg, id)) != 0 ||
551: (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0)
552: fatal_fr(r, "compose");
553: send_msg(conn, msg);
554: debug3("Sent message limits@openssh.com I:%u", id);
555:
556: get_msg(conn, msg);
557:
558: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
559: (r = sshbuf_get_u32(msg, &msg_id)) != 0)
560: fatal_fr(r, "parse");
561:
562: debug3("Received limits reply T:%u I:%u", type, msg_id);
563: if (id != msg_id)
564: fatal("ID mismatch (%u != %u)", msg_id, id);
565: if (type != SSH2_FXP_EXTENDED_REPLY) {
566: fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
1.142 ! djm 567: SSH2_FXP_EXTENDED_REPLY, type);
1.141 djm 568: }
569:
570: memset(limits, 0, sizeof(*limits));
571: if ((r = sshbuf_get_u64(msg, &limits->packet_length)) != 0 ||
572: (r = sshbuf_get_u64(msg, &limits->read_length)) != 0 ||
573: (r = sshbuf_get_u64(msg, &limits->write_length)) != 0 ||
574: (r = sshbuf_get_u64(msg, &limits->open_handles)) != 0)
575: fatal_fr(r, "parse limits");
576:
577: sshbuf_free(msg);
578:
579: return 0;
580: }
581:
582: int
1.116 djm 583: do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
1.1 djm 584: {
585: u_int id, status;
1.116 djm 586: struct sshbuf *msg;
587: int r;
1.1 djm 588:
1.116 djm 589: if ((msg = sshbuf_new()) == NULL)
1.137 djm 590: fatal_f("sshbuf_new failed");
1.1 djm 591:
1.23 djm 592: id = conn->msg_id++;
1.116 djm 593: if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 ||
594: (r = sshbuf_put_u32(msg, id)) != 0 ||
595: (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1.137 djm 596: fatal_fr(r, "parse");
1.116 djm 597: send_msg(conn, msg);
1.33 deraadt 598: debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
1.1 djm 599:
1.93 djm 600: status = get_status(conn, id);
1.1 djm 601: if (status != SSH2_FX_OK)
602: error("Couldn't close file: %s", fx2txt(status));
603:
1.116 djm 604: sshbuf_free(msg);
1.1 djm 605:
1.116 djm 606: return status == SSH2_FX_OK ? 0 : -1;
1.1 djm 607: }
608:
1.12 djm 609:
1.17 itojun 610: static int
1.116 djm 611: do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
1.12 djm 612: SFTP_DIRENT ***dir)
1.1 djm 613: {
1.116 djm 614: struct sshbuf *msg;
615: u_int count, id, i, expected_id, ents = 0;
616: size_t handle_len;
1.123 djm 617: u_char type, *handle;
1.111 djm 618: int status = SSH2_FX_FAILURE;
1.116 djm 619: int r;
1.111 djm 620:
621: if (dir)
622: *dir = NULL;
1.1 djm 623:
1.23 djm 624: id = conn->msg_id++;
1.1 djm 625:
1.116 djm 626: if ((msg = sshbuf_new()) == NULL)
1.137 djm 627: fatal_f("sshbuf_new failed");
1.116 djm 628: if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 ||
629: (r = sshbuf_put_u32(msg, id)) != 0 ||
630: (r = sshbuf_put_cstring(msg, path)) != 0)
1.137 djm 631: fatal_fr(r, "compose OPENDIR");
1.116 djm 632: send_msg(conn, msg);
1.1 djm 633:
1.93 djm 634: handle = get_handle(conn, id, &handle_len,
1.88 djm 635: "remote readdir(\"%s\")", path);
1.96 markus 636: if (handle == NULL) {
1.116 djm 637: sshbuf_free(msg);
1.93 djm 638: return -1;
1.96 markus 639: }
1.1 djm 640:
1.12 djm 641: if (dir) {
642: ents = 0;
1.108 djm 643: *dir = xcalloc(1, sizeof(**dir));
1.12 djm 644: (*dir)[0] = NULL;
645: }
646:
1.49 djm 647: for (; !interrupted;) {
1.23 djm 648: id = expected_id = conn->msg_id++;
1.1 djm 649:
1.33 deraadt 650: debug3("Sending SSH2_FXP_READDIR I:%u", id);
1.1 djm 651:
1.116 djm 652: sshbuf_reset(msg);
653: if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 ||
654: (r = sshbuf_put_u32(msg, id)) != 0 ||
655: (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1.137 djm 656: fatal_fr(r, "compose READDIR");
1.116 djm 657: send_msg(conn, msg);
658:
659: sshbuf_reset(msg);
660:
661: get_msg(conn, msg);
662:
663: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
664: (r = sshbuf_get_u32(msg, &id)) != 0)
1.137 djm 665: fatal_fr(r, "parse");
1.1 djm 666:
1.33 deraadt 667: debug3("Received reply T:%u I:%u", type, id);
1.1 djm 668:
669: if (id != expected_id)
1.33 deraadt 670: fatal("ID mismatch (%u != %u)", id, expected_id);
1.1 djm 671:
672: if (type == SSH2_FXP_STATUS) {
1.116 djm 673: u_int rstatus;
674:
675: if ((r = sshbuf_get_u32(msg, &rstatus)) != 0)
1.137 djm 676: fatal_fr(r, "parse status");
1.116 djm 677: debug3("Received SSH2_FXP_STATUS %d", rstatus);
678: if (rstatus == SSH2_FX_EOF)
1.1 djm 679: break;
1.116 djm 680: error("Couldn't read directory: %s", fx2txt(rstatus));
1.111 djm 681: goto out;
1.1 djm 682: } else if (type != SSH2_FXP_NAME)
1.33 deraadt 683: fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
1.1 djm 684: SSH2_FXP_NAME, type);
685:
1.116 djm 686: if ((r = sshbuf_get_u32(msg, &count)) != 0)
1.137 djm 687: fatal_fr(r, "parse count");
1.126 djm 688: if (count > SSHBUF_SIZE_MAX)
1.137 djm 689: fatal_f("nonsensical number of entries");
1.7 markus 690: if (count == 0)
691: break;
1.8 stevesk 692: debug3("Received %d SSH2_FXP_NAME responses", count);
1.19 deraadt 693: for (i = 0; i < count; i++) {
1.1 djm 694: char *filename, *longname;
1.116 djm 695: Attrib a;
1.1 djm 696:
1.116 djm 697: if ((r = sshbuf_get_cstring(msg, &filename,
698: NULL)) != 0 ||
699: (r = sshbuf_get_cstring(msg, &longname,
700: NULL)) != 0)
1.137 djm 701: fatal_fr(r, "parse filenames");
1.116 djm 702: if ((r = decode_attrib(msg, &a)) != 0) {
1.137 djm 703: error_fr(r, "couldn't decode attrib");
1.116 djm 704: free(filename);
705: free(longname);
1.135 djm 706: goto out;
1.116 djm 707: }
1.1 djm 708:
1.105 djm 709: if (print_flag)
1.124 schwarze 710: mprintf("%s\n", longname);
1.12 djm 711:
1.89 djm 712: /*
713: * Directory entries should never contain '/'
714: * These can be used to attack recursive ops
715: * (e.g. send '../../../../etc/passwd')
716: */
717: if (strchr(filename, '/') != NULL) {
718: error("Server sent suspect path \"%s\" "
719: "during readdir of \"%s\"", filename, path);
1.111 djm 720: } else if (dir) {
1.118 deraadt 721: *dir = xreallocarray(*dir, ents + 2, sizeof(**dir));
1.108 djm 722: (*dir)[ents] = xcalloc(1, sizeof(***dir));
1.12 djm 723: (*dir)[ents]->filename = xstrdup(filename);
724: (*dir)[ents]->longname = xstrdup(longname);
1.116 djm 725: memcpy(&(*dir)[ents]->a, &a, sizeof(a));
1.12 djm 726: (*dir)[++ents] = NULL;
727: }
1.98 djm 728: free(filename);
729: free(longname);
1.1 djm 730: }
731: }
1.111 djm 732: status = 0;
1.1 djm 733:
1.111 djm 734: out:
1.116 djm 735: sshbuf_free(msg);
1.23 djm 736: do_close(conn, handle, handle_len);
1.98 djm 737: free(handle);
1.1 djm 738:
1.111 djm 739: if (status != 0 && dir != NULL) {
740: /* Don't return results on error */
741: free_sftp_dirents(*dir);
742: *dir = NULL;
743: } else if (interrupted && dir != NULL && *dir != NULL) {
744: /* Don't return partial matches on interrupt */
1.49 djm 745: free_sftp_dirents(*dir);
1.108 djm 746: *dir = xcalloc(1, sizeof(**dir));
1.49 djm 747: **dir = NULL;
748: }
749:
1.129 djm 750: return status == SSH2_FX_OK ? 0 : -1;
1.12 djm 751: }
752:
753: int
1.116 djm 754: do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
1.12 djm 755: {
1.23 djm 756: return(do_lsreaddir(conn, path, 0, dir));
1.12 djm 757: }
758:
759: void free_sftp_dirents(SFTP_DIRENT **s)
760: {
761: int i;
1.19 deraadt 762:
1.111 djm 763: if (s == NULL)
764: return;
1.19 deraadt 765: for (i = 0; s[i]; i++) {
1.98 djm 766: free(s[i]->filename);
767: free(s[i]->longname);
768: free(s[i]);
1.12 djm 769: }
1.98 djm 770: free(s);
1.12 djm 771: }
772:
773: int
1.116 djm 774: do_rm(struct sftp_conn *conn, const char *path)
1.1 djm 775: {
776: u_int status, id;
777:
778: debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
779:
1.23 djm 780: id = conn->msg_id++;
1.93 djm 781: send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
782: status = get_status(conn, id);
1.1 djm 783: if (status != SSH2_FX_OK)
784: error("Couldn't delete file: %s", fx2txt(status));
1.116 djm 785: return status == SSH2_FX_OK ? 0 : -1;
1.1 djm 786: }
787:
788: int
1.116 djm 789: do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
1.1 djm 790: {
791: u_int status, id;
792:
1.23 djm 793: id = conn->msg_id++;
1.93 djm 794: send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
1.1 djm 795: strlen(path), a);
796:
1.93 djm 797: status = get_status(conn, id);
1.105 djm 798: if (status != SSH2_FX_OK && print_flag)
1.1 djm 799: error("Couldn't create directory: %s", fx2txt(status));
800:
1.116 djm 801: return status == SSH2_FX_OK ? 0 : -1;
1.1 djm 802: }
803:
804: int
1.116 djm 805: do_rmdir(struct sftp_conn *conn, const char *path)
1.1 djm 806: {
807: u_int status, id;
808:
1.23 djm 809: id = conn->msg_id++;
1.93 djm 810: send_string_request(conn, id, SSH2_FXP_RMDIR, path,
1.23 djm 811: strlen(path));
1.1 djm 812:
1.93 djm 813: status = get_status(conn, id);
1.1 djm 814: if (status != SSH2_FX_OK)
815: error("Couldn't remove directory: %s", fx2txt(status));
816:
1.116 djm 817: return status == SSH2_FX_OK ? 0 : -1;
1.1 djm 818: }
819:
820: Attrib *
1.116 djm 821: do_stat(struct sftp_conn *conn, const char *path, int quiet)
1.1 djm 822: {
823: u_int id;
824:
1.23 djm 825: id = conn->msg_id++;
826:
1.93 djm 827: send_string_request(conn, id,
1.28 markus 828: conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
1.23 djm 829: path, strlen(path));
830:
1.93 djm 831: return(get_decode_stat(conn, id, quiet));
1.1 djm 832: }
833:
834: Attrib *
1.116 djm 835: do_lstat(struct sftp_conn *conn, const char *path, int quiet)
1.1 djm 836: {
837: u_int id;
838:
1.23 djm 839: if (conn->version == 0) {
840: if (quiet)
841: debug("Server version does not support lstat operation");
842: else
1.43 itojun 843: logit("Server version does not support lstat operation");
1.30 markus 844: return(do_stat(conn, path, quiet));
1.23 djm 845: }
846:
847: id = conn->msg_id++;
1.93 djm 848: send_string_request(conn, id, SSH2_FXP_LSTAT, path,
1.23 djm 849: strlen(path));
850:
1.93 djm 851: return(get_decode_stat(conn, id, quiet));
1.1 djm 852: }
853:
1.78 chl 854: #ifdef notyet
1.1 djm 855: Attrib *
1.116 djm 856: do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
857: int quiet)
1.1 djm 858: {
859: u_int id;
860:
1.23 djm 861: id = conn->msg_id++;
1.93 djm 862: send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
1.23 djm 863: handle_len);
864:
1.93 djm 865: return(get_decode_stat(conn, id, quiet));
1.1 djm 866: }
1.78 chl 867: #endif
1.1 djm 868:
869: int
1.116 djm 870: do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
1.1 djm 871: {
872: u_int status, id;
873:
1.23 djm 874: id = conn->msg_id++;
1.93 djm 875: send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
1.1 djm 876: strlen(path), a);
877:
1.93 djm 878: status = get_status(conn, id);
1.1 djm 879: if (status != SSH2_FX_OK)
880: error("Couldn't setstat on \"%s\": %s", path,
881: fx2txt(status));
882:
1.116 djm 883: return status == SSH2_FX_OK ? 0 : -1;
1.1 djm 884: }
885:
886: int
1.116 djm 887: do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
1.1 djm 888: Attrib *a)
889: {
890: u_int status, id;
891:
1.23 djm 892: id = conn->msg_id++;
1.93 djm 893: send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
1.1 djm 894: handle_len, a);
895:
1.93 djm 896: status = get_status(conn, id);
1.1 djm 897: if (status != SSH2_FX_OK)
898: error("Couldn't fsetstat: %s", fx2txt(status));
899:
1.116 djm 900: return status == SSH2_FX_OK ? 0 : -1;
1.1 djm 901: }
902:
903: char *
1.116 djm 904: do_realpath(struct sftp_conn *conn, const char *path)
1.1 djm 905: {
1.116 djm 906: struct sshbuf *msg;
907: u_int expected_id, count, id;
1.1 djm 908: char *filename, *longname;
1.116 djm 909: Attrib a;
910: u_char type;
911: int r;
1.1 djm 912:
1.23 djm 913: expected_id = id = conn->msg_id++;
1.93 djm 914: send_string_request(conn, id, SSH2_FXP_REALPATH, path,
1.23 djm 915: strlen(path));
1.1 djm 916:
1.116 djm 917: if ((msg = sshbuf_new()) == NULL)
1.137 djm 918: fatal_f("sshbuf_new failed");
1.1 djm 919:
1.116 djm 920: get_msg(conn, msg);
921: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
922: (r = sshbuf_get_u32(msg, &id)) != 0)
1.137 djm 923: fatal_fr(r, "parse");
1.1 djm 924:
925: if (id != expected_id)
1.33 deraadt 926: fatal("ID mismatch (%u != %u)", id, expected_id);
1.1 djm 927:
928: if (type == SSH2_FXP_STATUS) {
1.116 djm 929: u_int status;
1.1 djm 930:
1.116 djm 931: if ((r = sshbuf_get_u32(msg, &status)) != 0)
1.137 djm 932: fatal_fr(r, "parse status");
1.107 djm 933: error("Couldn't canonicalize: %s", fx2txt(status));
1.116 djm 934: sshbuf_free(msg);
1.91 djm 935: return NULL;
1.1 djm 936: } else if (type != SSH2_FXP_NAME)
1.33 deraadt 937: fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
1.1 djm 938: SSH2_FXP_NAME, type);
939:
1.116 djm 940: if ((r = sshbuf_get_u32(msg, &count)) != 0)
1.137 djm 941: fatal_fr(r, "parse count");
1.1 djm 942: if (count != 1)
943: fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
944:
1.116 djm 945: if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
946: (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
947: (r = decode_attrib(msg, &a)) != 0)
1.137 djm 948: fatal_fr(r, "parse filename/attrib");
1.1 djm 949:
1.97 dtucker 950: debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
1.116 djm 951: (unsigned long)a.size);
1.1 djm 952:
1.98 djm 953: free(longname);
1.1 djm 954:
1.116 djm 955: sshbuf_free(msg);
1.1 djm 956:
957: return(filename);
958: }
959:
960: int
1.116 djm 961: do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
1.102 djm 962: int force_legacy)
1.1 djm 963: {
1.116 djm 964: struct sshbuf *msg;
1.1 djm 965: u_int status, id;
1.116 djm 966: int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy;
1.1 djm 967:
1.116 djm 968: if ((msg = sshbuf_new()) == NULL)
1.137 djm 969: fatal_f("sshbuf_new failed");
1.1 djm 970:
971: /* Send rename request */
1.23 djm 972: id = conn->msg_id++;
1.102 djm 973: if (use_ext) {
1.116 djm 974: if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
975: (r = sshbuf_put_u32(msg, id)) != 0 ||
976: (r = sshbuf_put_cstring(msg,
977: "posix-rename@openssh.com")) != 0)
1.137 djm 978: fatal_fr(r, "compose posix-rename");
1.81 djm 979: } else {
1.116 djm 980: if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 ||
981: (r = sshbuf_put_u32(msg, id)) != 0)
1.137 djm 982: fatal_fr(r, "compose rename");
1.116 djm 983: }
984: if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
985: (r = sshbuf_put_cstring(msg, newpath)) != 0)
1.137 djm 986: fatal_fr(r, "compose paths");
1.116 djm 987: send_msg(conn, msg);
1.81 djm 988: debug3("Sent message %s \"%s\" -> \"%s\"",
1.116 djm 989: use_ext ? "posix-rename@openssh.com" :
990: "SSH2_FXP_RENAME", oldpath, newpath);
991: sshbuf_free(msg);
1.1 djm 992:
1.93 djm 993: status = get_status(conn, id);
1.1 djm 994: if (status != SSH2_FX_OK)
1.23 djm 995: error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
1.94 djm 996: newpath, fx2txt(status));
997:
1.116 djm 998: return status == SSH2_FX_OK ? 0 : -1;
1.94 djm 999: }
1000:
1001: int
1.116 djm 1002: do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
1.94 djm 1003: {
1.116 djm 1004: struct sshbuf *msg;
1.94 djm 1005: u_int status, id;
1.116 djm 1006: int r;
1.94 djm 1007:
1008: if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
1009: error("Server does not support hardlink@openssh.com extension");
1010: return -1;
1011: }
1012:
1.116 djm 1013: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1014: fatal_f("sshbuf_new failed");
1.95 markus 1015:
1016: /* Send link request */
1017: id = conn->msg_id++;
1.116 djm 1018: if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1019: (r = sshbuf_put_u32(msg, id)) != 0 ||
1020: (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 ||
1021: (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
1022: (r = sshbuf_put_cstring(msg, newpath)) != 0)
1.137 djm 1023: fatal_fr(r, "compose");
1.116 djm 1024: send_msg(conn, msg);
1.94 djm 1025: debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
1.142 ! djm 1026: oldpath, newpath);
1.116 djm 1027: sshbuf_free(msg);
1.94 djm 1028:
1029: status = get_status(conn, id);
1030: if (status != SSH2_FX_OK)
1031: error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
1.23 djm 1032: newpath, fx2txt(status));
1.1 djm 1033:
1.116 djm 1034: return status == SSH2_FX_OK ? 0 : -1;
1.11 djm 1035: }
1036:
1037: int
1.116 djm 1038: do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
1.11 djm 1039: {
1.116 djm 1040: struct sshbuf *msg;
1.11 djm 1041: u_int status, id;
1.116 djm 1042: int r;
1.11 djm 1043:
1.23 djm 1044: if (conn->version < 3) {
1045: error("This server does not support the symlink operation");
1046: return(SSH2_FX_OP_UNSUPPORTED);
1047: }
1048:
1.116 djm 1049: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1050: fatal_f("sshbuf_new failed");
1.11 djm 1051:
1.48 djm 1052: /* Send symlink request */
1.23 djm 1053: id = conn->msg_id++;
1.116 djm 1054: if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 ||
1055: (r = sshbuf_put_u32(msg, id)) != 0 ||
1056: (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
1057: (r = sshbuf_put_cstring(msg, newpath)) != 0)
1.137 djm 1058: fatal_fr(r, "compose");
1.116 djm 1059: send_msg(conn, msg);
1.11 djm 1060: debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
1061: newpath);
1.116 djm 1062: sshbuf_free(msg);
1.11 djm 1063:
1.93 djm 1064: status = get_status(conn, id);
1.11 djm 1065: if (status != SSH2_FX_OK)
1.36 markus 1066: error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
1.23 djm 1067: newpath, fx2txt(status));
1.11 djm 1068:
1.116 djm 1069: return status == SSH2_FX_OK ? 0 : -1;
1.11 djm 1070: }
1071:
1.107 djm 1072: int
1.116 djm 1073: do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
1.107 djm 1074: {
1.116 djm 1075: struct sshbuf *msg;
1.107 djm 1076: u_int status, id;
1.116 djm 1077: int r;
1.107 djm 1078:
1079: /* Silently return if the extension is not supported */
1080: if ((conn->exts & SFTP_EXT_FSYNC) == 0)
1081: return -1;
1082:
1083: /* Send fsync request */
1.116 djm 1084: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1085: fatal_f("sshbuf_new failed");
1.107 djm 1086: id = conn->msg_id++;
1.116 djm 1087: if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1088: (r = sshbuf_put_u32(msg, id)) != 0 ||
1089: (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
1090: (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1.137 djm 1091: fatal_fr(r, "compose");
1.116 djm 1092: send_msg(conn, msg);
1.107 djm 1093: debug3("Sent message fsync@openssh.com I:%u", id);
1.116 djm 1094: sshbuf_free(msg);
1.107 djm 1095:
1096: status = get_status(conn, id);
1097: if (status != SSH2_FX_OK)
1098: error("Couldn't sync file: %s", fx2txt(status));
1099:
1.129 djm 1100: return status == SSH2_FX_OK ? 0 : -1;
1.107 djm 1101: }
1102:
1.78 chl 1103: #ifdef notyet
1.11 djm 1104: char *
1.116 djm 1105: do_readlink(struct sftp_conn *conn, const char *path)
1.11 djm 1106: {
1.116 djm 1107: struct sshbuf *msg;
1108: u_int expected_id, count, id;
1.11 djm 1109: char *filename, *longname;
1.116 djm 1110: Attrib a;
1111: u_char type;
1112: int r;
1.11 djm 1113:
1.23 djm 1114: expected_id = id = conn->msg_id++;
1.93 djm 1115: send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
1.11 djm 1116:
1.116 djm 1117: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1118: fatal_f("sshbuf_new failed");
1.11 djm 1119:
1.116 djm 1120: get_msg(conn, msg);
1121: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1122: (r = sshbuf_get_u32(msg, &id)) != 0)
1.137 djm 1123: fatal_fr(r, "parse");
1.11 djm 1124:
1125: if (id != expected_id)
1.33 deraadt 1126: fatal("ID mismatch (%u != %u)", id, expected_id);
1.11 djm 1127:
1128: if (type == SSH2_FXP_STATUS) {
1.116 djm 1129: u_int status;
1.11 djm 1130:
1.116 djm 1131: if ((r = sshbuf_get_u32(msg, &status)) != 0)
1.137 djm 1132: fatal_fr(r, "parse status");
1.11 djm 1133: error("Couldn't readlink: %s", fx2txt(status));
1.116 djm 1134: sshbuf_free(msg);
1.11 djm 1135: return(NULL);
1136: } else if (type != SSH2_FXP_NAME)
1.33 deraadt 1137: fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
1.11 djm 1138: SSH2_FXP_NAME, type);
1139:
1.116 djm 1140: if ((r = sshbuf_get_u32(msg, &count)) != 0)
1.137 djm 1141: fatal_fr(r, "parse count");
1.11 djm 1142: if (count != 1)
1143: fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
1144:
1.116 djm 1145: if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
1146: (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
1147: (r = decode_attrib(msg, &a)) != 0)
1.137 djm 1148: fatal_fr(r, "parse filenames/attrib");
1.11 djm 1149:
1150: debug3("SSH_FXP_READLINK %s -> %s", path, filename);
1151:
1.98 djm 1152: free(longname);
1.11 djm 1153:
1.116 djm 1154: sshbuf_free(msg);
1.11 djm 1155:
1.116 djm 1156: return filename;
1.82 djm 1157: }
1158: #endif
1159:
1160: int
1.84 dtucker 1161: do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
1.82 djm 1162: int quiet)
1163: {
1.116 djm 1164: struct sshbuf *msg;
1.82 djm 1165: u_int id;
1.116 djm 1166: int r;
1.82 djm 1167:
1168: if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
1169: error("Server does not support statvfs@openssh.com extension");
1170: return -1;
1171: }
1172:
1173: id = conn->msg_id++;
1174:
1.116 djm 1175: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1176: fatal_f("sshbuf_new failed");
1.116 djm 1177: if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1178: (r = sshbuf_put_u32(msg, id)) != 0 ||
1179: (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
1180: (r = sshbuf_put_cstring(msg, path)) != 0)
1.137 djm 1181: fatal_fr(r, "compose");
1.116 djm 1182: send_msg(conn, msg);
1183: sshbuf_free(msg);
1.82 djm 1184:
1.93 djm 1185: return get_decode_statvfs(conn, st, id, quiet);
1.82 djm 1186: }
1187:
1188: #ifdef notyet
1189: int
1.116 djm 1190: do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
1.84 dtucker 1191: struct sftp_statvfs *st, int quiet)
1.82 djm 1192: {
1.116 djm 1193: struct sshbuf *msg;
1.82 djm 1194: u_int id;
1195:
1196: if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
1197: error("Server does not support fstatvfs@openssh.com extension");
1198: return -1;
1199: }
1200:
1201: id = conn->msg_id++;
1202:
1.116 djm 1203: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1204: fatal_f("sshbuf_new failed");
1.116 djm 1205: if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1206: (r = sshbuf_put_u32(msg, id)) != 0 ||
1207: (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
1208: (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1.137 djm 1209: fatal_fr(r, "compose");
1.116 djm 1210: send_msg(conn, msg);
1211: sshbuf_free(msg);
1.82 djm 1212:
1.93 djm 1213: return get_decode_statvfs(conn, st, id, quiet);
1.1 djm 1214: }
1.78 chl 1215: #endif
1.1 djm 1216:
1.131 djm 1217: int
1218: do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
1219: {
1220: struct sshbuf *msg;
1221: u_int status, id;
1222: int r;
1223:
1224: if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) {
1225: error("Server does not support lsetstat@openssh.com extension");
1226: return -1;
1227: }
1228:
1229: id = conn->msg_id++;
1230: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1231: fatal_f("sshbuf_new failed");
1.131 djm 1232: if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1233: (r = sshbuf_put_u32(msg, id)) != 0 ||
1234: (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
1235: (r = sshbuf_put_cstring(msg, path)) != 0 ||
1236: (r = encode_attrib(msg, a)) != 0)
1.137 djm 1237: fatal_fr(r, "compose");
1.131 djm 1238: send_msg(conn, msg);
1239: sshbuf_free(msg);
1240:
1241: status = get_status(conn, id);
1242: if (status != SSH2_FX_OK)
1243: error("Couldn't setstat on \"%s\": %s", path,
1244: fx2txt(status));
1245:
1246: return status == SSH2_FX_OK ? 0 : -1;
1247: }
1248:
1.21 djm 1249: static void
1.93 djm 1250: send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
1.116 djm 1251: u_int len, const u_char *handle, u_int handle_len)
1.21 djm 1252: {
1.116 djm 1253: struct sshbuf *msg;
1254: int r;
1.28 markus 1255:
1.116 djm 1256: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1257: fatal_f("sshbuf_new failed");
1.116 djm 1258: if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
1259: (r = sshbuf_put_u32(msg, id)) != 0 ||
1260: (r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
1261: (r = sshbuf_put_u64(msg, offset)) != 0 ||
1262: (r = sshbuf_put_u32(msg, len)) != 0)
1.137 djm 1263: fatal_fr(r, "compose");
1.116 djm 1264: send_msg(conn, msg);
1265: sshbuf_free(msg);
1.28 markus 1266: }
1.21 djm 1267:
1.1 djm 1268: int
1.116 djm 1269: do_download(struct sftp_conn *conn, const char *remote_path,
1270: const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
1271: int fsync_flag)
1.1 djm 1272: {
1.89 djm 1273: Attrib junk;
1.116 djm 1274: struct sshbuf *msg;
1275: u_char *handle;
1276: int local_fd = -1, write_error;
1.134 djm 1277: int read_error, write_errno, lmodified = 0, reordered = 0, r;
1.101 djm 1278: u_int64_t offset = 0, size, highwater;
1.116 djm 1279: u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK;
1.39 fgsch 1280: off_t progress_counter;
1.116 djm 1281: size_t handle_len;
1.101 djm 1282: struct stat st;
1.21 djm 1283: struct request {
1284: u_int id;
1.116 djm 1285: size_t len;
1.21 djm 1286: u_int64_t offset;
1.28 markus 1287: TAILQ_ENTRY(request) tq;
1.21 djm 1288: };
1289: TAILQ_HEAD(reqhead, request) requests;
1290: struct request *req;
1.116 djm 1291: u_char type;
1.21 djm 1292:
1293: TAILQ_INIT(&requests);
1.1 djm 1294:
1.89 djm 1295: if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
1296: return -1;
1.1 djm 1297:
1.86 djm 1298: /* Do not preserve set[ug]id here, as we do not preserve ownership */
1.1 djm 1299: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1.38 djm 1300: mode = a->perm & 0777;
1.1 djm 1301: else
1302: mode = 0666;
1303:
1.14 djm 1304: if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1.41 djm 1305: (!S_ISREG(a->perm))) {
1306: error("Cannot download non-regular file: %s", remote_path);
1.14 djm 1307: return(-1);
1308: }
1309:
1.21 djm 1310: if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1311: size = a->size;
1312: else
1313: size = 0;
1314:
1.141 djm 1315: buflen = conn->download_buflen;
1.116 djm 1316: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1317: fatal_f("sshbuf_new failed");
1.116 djm 1318:
1319: attrib_clear(&junk); /* Send empty attributes */
1.1 djm 1320:
1321: /* Send open request */
1.23 djm 1322: id = conn->msg_id++;
1.116 djm 1323: if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1324: (r = sshbuf_put_u32(msg, id)) != 0 ||
1325: (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1326: (r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 ||
1327: (r = encode_attrib(msg, &junk)) != 0)
1.137 djm 1328: fatal_fr(r, "compose");
1.116 djm 1329: send_msg(conn, msg);
1.33 deraadt 1330: debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1.1 djm 1331:
1.93 djm 1332: handle = get_handle(conn, id, &handle_len,
1.88 djm 1333: "remote open(\"%s\")", remote_path);
1.1 djm 1334: if (handle == NULL) {
1.116 djm 1335: sshbuf_free(msg);
1.1 djm 1336: return(-1);
1337: }
1338:
1.105 djm 1339: local_fd = open(local_path,
1340: O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
1.23 djm 1341: if (local_fd == -1) {
1342: error("Couldn't open local file \"%s\" for writing: %s",
1343: local_path, strerror(errno));
1.101 djm 1344: goto fail;
1345: }
1346: offset = highwater = 0;
1.105 djm 1347: if (resume_flag) {
1.101 djm 1348: if (fstat(local_fd, &st) == -1) {
1349: error("Unable to stat local file \"%s\": %s",
1350: local_path, strerror(errno));
1351: goto fail;
1352: }
1.113 djm 1353: if (st.st_size < 0) {
1354: error("\"%s\" has negative size", local_path);
1355: goto fail;
1356: }
1357: if ((u_int64_t)st.st_size > size) {
1.101 djm 1358: error("Unable to resume download of \"%s\": "
1359: "local file is larger than remote", local_path);
1360: fail:
1361: do_close(conn, handle, handle_len);
1.116 djm 1362: sshbuf_free(msg);
1.101 djm 1363: free(handle);
1.110 djm 1364: if (local_fd != -1)
1365: close(local_fd);
1.101 djm 1366: return -1;
1367: }
1368: offset = highwater = st.st_size;
1.23 djm 1369: }
1370:
1.1 djm 1371: /* Read from remote and write to local */
1.101 djm 1372: write_error = read_error = write_errno = num_req = 0;
1.21 djm 1373: max_req = 1;
1.101 djm 1374: progress_counter = offset;
1.39 fgsch 1375:
1.47 djm 1376: if (showprogress && size != 0)
1377: start_progress_meter(remote_path, size, &progress_counter);
1.39 fgsch 1378:
1.21 djm 1379: while (num_req > 0 || max_req > 0) {
1.116 djm 1380: u_char *data;
1381: size_t len;
1.1 djm 1382:
1.49 djm 1383: /*
1.51 deraadt 1384: * Simulate EOF on interrupt: stop sending new requests and
1.49 djm 1385: * allow outstanding requests to drain gracefully
1386: */
1387: if (interrupted) {
1388: if (num_req == 0) /* If we haven't started yet... */
1389: break;
1390: max_req = 0;
1391: }
1392:
1.21 djm 1393: /* Send some more requests */
1394: while (num_req < max_req) {
1.28 markus 1395: debug3("Request range %llu -> %llu (%d/%d)",
1.25 itojun 1396: (unsigned long long)offset,
1397: (unsigned long long)offset + buflen - 1,
1398: num_req, max_req);
1.108 djm 1399: req = xcalloc(1, sizeof(*req));
1.23 djm 1400: req->id = conn->msg_id++;
1.21 djm 1401: req->len = buflen;
1402: req->offset = offset;
1403: offset += buflen;
1404: num_req++;
1405: TAILQ_INSERT_TAIL(&requests, req, tq);
1.93 djm 1406: send_read_request(conn, req->id, req->offset,
1.21 djm 1407: req->len, handle, handle_len);
1408: }
1.1 djm 1409:
1.116 djm 1410: sshbuf_reset(msg);
1411: get_msg(conn, msg);
1412: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1413: (r = sshbuf_get_u32(msg, &id)) != 0)
1.137 djm 1414: fatal_fr(r, "parse");
1.33 deraadt 1415: debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1.21 djm 1416:
1417: /* Find the request in our queue */
1.53 deraadt 1418: for (req = TAILQ_FIRST(&requests);
1.21 djm 1419: req != NULL && req->id != id;
1420: req = TAILQ_NEXT(req, tq))
1421: ;
1422: if (req == NULL)
1423: fatal("Unexpected reply %u", id);
1424:
1425: switch (type) {
1426: case SSH2_FXP_STATUS:
1.116 djm 1427: if ((r = sshbuf_get_u32(msg, &status)) != 0)
1.137 djm 1428: fatal_fr(r, "parse status");
1.21 djm 1429: if (status != SSH2_FX_EOF)
1430: read_error = 1;
1431: max_req = 0;
1432: TAILQ_REMOVE(&requests, req, tq);
1.98 djm 1433: free(req);
1.21 djm 1434: num_req--;
1435: break;
1436: case SSH2_FXP_DATA:
1.116 djm 1437: if ((r = sshbuf_get_string(msg, &data, &len)) != 0)
1.137 djm 1438: fatal_fr(r, "parse data");
1.26 itojun 1439: debug3("Received data %llu -> %llu",
1.28 markus 1440: (unsigned long long)req->offset,
1.26 itojun 1441: (unsigned long long)req->offset + len - 1);
1.21 djm 1442: if (len > req->len)
1443: fatal("Received more data than asked for "
1.116 djm 1444: "%zu > %zu", len, req->len);
1.134 djm 1445: lmodified = 1;
1.21 djm 1446: if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1.44 deraadt 1447: atomicio(vwrite, local_fd, data, len) != len) &&
1.21 djm 1448: !write_error) {
1449: write_errno = errno;
1450: write_error = 1;
1451: max_req = 0;
1452: }
1.101 djm 1453: else if (!reordered && req->offset <= highwater)
1454: highwater = req->offset + len;
1455: else if (!reordered && req->offset > highwater)
1456: reordered = 1;
1.39 fgsch 1457: progress_counter += len;
1.98 djm 1458: free(data);
1.1 djm 1459:
1.21 djm 1460: if (len == req->len) {
1461: TAILQ_REMOVE(&requests, req, tq);
1.98 djm 1462: free(req);
1.21 djm 1463: num_req--;
1464: } else {
1465: /* Resend the request for the missing data */
1466: debug3("Short data block, re-requesting "
1.26 itojun 1467: "%llu -> %llu (%2d)",
1.28 markus 1468: (unsigned long long)req->offset + len,
1.27 itojun 1469: (unsigned long long)req->offset +
1470: req->len - 1, num_req);
1.23 djm 1471: req->id = conn->msg_id++;
1.21 djm 1472: req->len -= len;
1473: req->offset += len;
1.93 djm 1474: send_read_request(conn, req->id,
1.23 djm 1475: req->offset, req->len, handle, handle_len);
1.21 djm 1476: /* Reduce the request size */
1477: if (len < buflen)
1.125 deraadt 1478: buflen = MAXIMUM(MIN_READ_SIZE, len);
1.21 djm 1479: }
1480: if (max_req > 0) { /* max_req = 0 iff EOF received */
1481: if (size > 0 && offset > size) {
1482: /* Only one request at a time
1483: * after the expected EOF */
1484: debug3("Finish at %llu (%2d)",
1.26 itojun 1485: (unsigned long long)offset,
1486: num_req);
1.21 djm 1487: max_req = 1;
1.136 djm 1488: } else if (max_req < conn->num_requests) {
1.21 djm 1489: ++max_req;
1490: }
1.1 djm 1491: }
1.21 djm 1492: break;
1493: default:
1.33 deraadt 1494: fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1.1 djm 1495: SSH2_FXP_DATA, type);
1496: }
1.21 djm 1497: }
1.1 djm 1498:
1.39 fgsch 1499: if (showprogress && size)
1500: stop_progress_meter();
1501:
1.21 djm 1502: /* Sanity check */
1503: if (TAILQ_FIRST(&requests) != NULL)
1504: fatal("Transfer complete, but requests still in queue");
1.101 djm 1505: /* Truncate at highest contiguous point to avoid holes on interrupt */
1506: if (read_error || write_error || interrupted) {
1.105 djm 1507: if (reordered && resume_flag) {
1.101 djm 1508: error("Unable to resume download of \"%s\": "
1509: "server reordered requests", local_path);
1510: }
1511: debug("truncating at %llu", (unsigned long long)highwater);
1.120 djm 1512: if (ftruncate(local_fd, highwater) == -1)
1513: error("ftruncate \"%s\": %s", local_path,
1514: strerror(errno));
1.101 djm 1515: }
1.21 djm 1516: if (read_error) {
1.28 markus 1517: error("Couldn't read from remote file \"%s\" : %s",
1.21 djm 1518: remote_path, fx2txt(status));
1.103 djm 1519: status = -1;
1.23 djm 1520: do_close(conn, handle, handle_len);
1.21 djm 1521: } else if (write_error) {
1522: error("Couldn't write to \"%s\": %s", local_path,
1523: strerror(write_errno));
1.116 djm 1524: status = SSH2_FX_FAILURE;
1.23 djm 1525: do_close(conn, handle, handle_len);
1.21 djm 1526: } else {
1.116 djm 1527: if (do_close(conn, handle, handle_len) != 0 || interrupted)
1528: status = SSH2_FX_FAILURE;
1529: else
1530: status = SSH2_FX_OK;
1.21 djm 1531: /* Override umask and utimes if asked */
1.105 djm 1532: if (preserve_flag && fchmod(local_fd, mode) == -1)
1.21 djm 1533: error("Couldn't set mode on \"%s\": %s", local_path,
1.37 deraadt 1534: strerror(errno));
1.105 djm 1535: if (preserve_flag &&
1536: (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1.21 djm 1537: struct timeval tv[2];
1538: tv[0].tv_sec = a->atime;
1539: tv[1].tv_sec = a->mtime;
1540: tv[0].tv_usec = tv[1].tv_usec = 0;
1541: if (utimes(local_path, tv) == -1)
1542: error("Can't set times on \"%s\": %s",
1.37 deraadt 1543: local_path, strerror(errno));
1.1 djm 1544: }
1.134 djm 1545: if (resume_flag && !lmodified)
1546: logit("File \"%s\" was not modified", local_path);
1547: else if (fsync_flag) {
1.107 djm 1548: debug("syncing \"%s\"", local_path);
1549: if (fsync(local_fd) == -1)
1550: error("Couldn't sync file \"%s\": %s",
1551: local_path, strerror(errno));
1552: }
1.10 djm 1553: }
1.5 djm 1554: close(local_fd);
1.116 djm 1555: sshbuf_free(msg);
1.98 djm 1556: free(handle);
1.23 djm 1557:
1.129 djm 1558: return status == SSH2_FX_OK ? 0 : -1;
1.1 djm 1559: }
1560:
1.89 djm 1561: static int
1.116 djm 1562: download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1563: int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
1564: int resume_flag, int fsync_flag)
1.89 djm 1565: {
1566: int i, ret = 0;
1567: SFTP_DIRENT **dir_entries;
1.130 djm 1568: char *filename, *new_src = NULL, *new_dst = NULL;
1.138 dtucker 1569: mode_t mode = 0777, tmpmode = mode;
1.89 djm 1570:
1571: if (depth >= MAX_DIR_DEPTH) {
1572: error("Maximum directory depth exceeded: %d levels", depth);
1573: return -1;
1574: }
1575:
1576: if (dirattrib == NULL &&
1577: (dirattrib = do_stat(conn, src, 1)) == NULL) {
1578: error("Unable to stat remote directory \"%s\"", src);
1579: return -1;
1580: }
1581: if (!S_ISDIR(dirattrib->perm)) {
1582: error("\"%s\" is not a directory", src);
1583: return -1;
1584: }
1.105 djm 1585: if (print_flag)
1.124 schwarze 1586: mprintf("Retrieving %s\n", src);
1.89 djm 1587:
1.138 dtucker 1588: if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.89 djm 1589: mode = dirattrib->perm & 01777;
1.138 dtucker 1590: tmpmode = mode | (S_IWUSR|S_IXUSR);
1591: } else {
1.89 djm 1592: debug("Server did not send permissions for "
1593: "directory \"%s\"", dst);
1594: }
1595:
1.138 dtucker 1596: if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) {
1.89 djm 1597: error("mkdir %s: %s", dst, strerror(errno));
1598: return -1;
1599: }
1600:
1601: if (do_readdir(conn, src, &dir_entries) == -1) {
1602: error("%s: Failed to get directory contents", src);
1603: return -1;
1604: }
1605:
1606: for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1.130 djm 1607: free(new_dst);
1608: free(new_src);
1609:
1.89 djm 1610: filename = dir_entries[i]->filename;
1611: new_dst = path_append(dst, filename);
1612: new_src = path_append(src, filename);
1613:
1614: if (S_ISDIR(dir_entries[i]->a.perm)) {
1615: if (strcmp(filename, ".") == 0 ||
1616: strcmp(filename, "..") == 0)
1617: continue;
1618: if (download_dir_internal(conn, new_src, new_dst,
1.105 djm 1619: depth + 1, &(dir_entries[i]->a), preserve_flag,
1.107 djm 1620: print_flag, resume_flag, fsync_flag) == -1)
1.89 djm 1621: ret = -1;
1622: } else if (S_ISREG(dir_entries[i]->a.perm) ) {
1623: if (do_download(conn, new_src, new_dst,
1.107 djm 1624: &(dir_entries[i]->a), preserve_flag,
1625: resume_flag, fsync_flag) == -1) {
1.89 djm 1626: error("Download of file %s to %s failed",
1627: new_src, new_dst);
1628: ret = -1;
1629: }
1630: } else
1631: logit("%s: not a regular file\n", new_src);
1632:
1633: }
1.130 djm 1634: free(new_dst);
1635: free(new_src);
1.89 djm 1636:
1.105 djm 1637: if (preserve_flag) {
1.89 djm 1638: if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1639: struct timeval tv[2];
1640: tv[0].tv_sec = dirattrib->atime;
1641: tv[1].tv_sec = dirattrib->mtime;
1642: tv[0].tv_usec = tv[1].tv_usec = 0;
1643: if (utimes(dst, tv) == -1)
1644: error("Can't set times on \"%s\": %s",
1645: dst, strerror(errno));
1646: } else
1647: debug("Server did not send times for directory "
1648: "\"%s\"", dst);
1649: }
1650:
1.138 dtucker 1651: if (mode != tmpmode && chmod(dst, mode) == -1)
1652: error("Can't set final mode on \"%s\": %s", dst,
1653: strerror(errno));
1654:
1.89 djm 1655: free_sftp_dirents(dir_entries);
1656:
1657: return ret;
1658: }
1659:
1660: int
1.116 djm 1661: download_dir(struct sftp_conn *conn, const char *src, const char *dst,
1662: Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
1663: int fsync_flag)
1.89 djm 1664: {
1665: char *src_canon;
1666: int ret;
1667:
1668: if ((src_canon = do_realpath(conn, src)) == NULL) {
1.107 djm 1669: error("Unable to canonicalize path \"%s\"", src);
1.89 djm 1670: return -1;
1671: }
1672:
1.105 djm 1673: ret = download_dir_internal(conn, src_canon, dst, 0,
1.107 djm 1674: dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
1.98 djm 1675: free(src_canon);
1.89 djm 1676: return ret;
1677: }
1678:
1.1 djm 1679: int
1.116 djm 1680: do_upload(struct sftp_conn *conn, const char *local_path,
1681: const char *remote_path, int preserve_flag, int resume, int fsync_flag)
1.1 djm 1682: {
1.116 djm 1683: int r, local_fd;
1684: u_int status = SSH2_FX_OK;
1685: u_int id;
1686: u_char type;
1.100 dtucker 1687: off_t offset, progress_counter;
1.116 djm 1688: u_char *handle, *data;
1689: struct sshbuf *msg;
1.1 djm 1690: struct stat sb;
1.115 logan 1691: Attrib a, *c = NULL;
1.21 djm 1692: u_int32_t startid;
1693: u_int32_t ackid;
1.22 djm 1694: struct outstanding_ack {
1695: u_int id;
1696: u_int len;
1.77 djm 1697: off_t offset;
1.28 markus 1698: TAILQ_ENTRY(outstanding_ack) tq;
1.22 djm 1699: };
1700: TAILQ_HEAD(ackhead, outstanding_ack) acks;
1.50 pedro 1701: struct outstanding_ack *ack = NULL;
1.116 djm 1702: size_t handle_len;
1.22 djm 1703:
1704: TAILQ_INIT(&acks);
1.1 djm 1705:
1706: if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1707: error("Couldn't open local file \"%s\" for reading: %s",
1708: local_path, strerror(errno));
1709: return(-1);
1710: }
1711: if (fstat(local_fd, &sb) == -1) {
1712: error("Couldn't fstat local file \"%s\": %s",
1713: local_path, strerror(errno));
1.41 djm 1714: close(local_fd);
1715: return(-1);
1716: }
1717: if (!S_ISREG(sb.st_mode)) {
1718: error("%s is not a regular file", local_path);
1.1 djm 1719: close(local_fd);
1720: return(-1);
1721: }
1722: stat_to_attrib(&sb, &a);
1723:
1724: a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1725: a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1726: a.perm &= 0777;
1.105 djm 1727: if (!preserve_flag)
1.1 djm 1728: a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1729:
1.115 logan 1730: if (resume) {
1731: /* Get remote file size if it exists */
1732: if ((c = do_stat(conn, remote_path, 0)) == NULL) {
1.122 djm 1733: close(local_fd);
1.115 logan 1734: return -1;
1735: }
1736:
1737: if ((off_t)c->size >= sb.st_size) {
1738: error("destination file bigger or same size as "
1.142 ! djm 1739: "source file");
1.115 logan 1740: close(local_fd);
1741: return -1;
1742: }
1743:
1744: if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
1745: close(local_fd);
1746: return -1;
1747: }
1748: }
1749:
1.116 djm 1750: if ((msg = sshbuf_new()) == NULL)
1.137 djm 1751: fatal_f("sshbuf_new failed");
1.1 djm 1752:
1753: /* Send open request */
1.23 djm 1754: id = conn->msg_id++;
1.116 djm 1755: if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1756: (r = sshbuf_put_u32(msg, id)) != 0 ||
1757: (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1758: (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
1759: (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 ||
1760: (r = encode_attrib(msg, &a)) != 0)
1.137 djm 1761: fatal_fr(r, "compose");
1.116 djm 1762: send_msg(conn, msg);
1.33 deraadt 1763: debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1.1 djm 1764:
1.116 djm 1765: sshbuf_reset(msg);
1.1 djm 1766:
1.93 djm 1767: handle = get_handle(conn, id, &handle_len,
1.88 djm 1768: "remote open(\"%s\")", remote_path);
1.1 djm 1769: if (handle == NULL) {
1770: close(local_fd);
1.116 djm 1771: sshbuf_free(msg);
1.80 djm 1772: return -1;
1.1 djm 1773: }
1774:
1.21 djm 1775: startid = ackid = id + 1;
1.141 djm 1776: data = xmalloc(conn->upload_buflen);
1.20 djm 1777:
1.1 djm 1778: /* Read from local and write to remote */
1.115 logan 1779: offset = progress_counter = (resume ? c->size : 0);
1.39 fgsch 1780: if (showprogress)
1.100 dtucker 1781: start_progress_meter(local_path, sb.st_size,
1782: &progress_counter);
1.39 fgsch 1783:
1.19 deraadt 1784: for (;;) {
1.1 djm 1785: int len;
1786:
1787: /*
1.51 deraadt 1788: * Can't use atomicio here because it returns 0 on EOF,
1.49 djm 1789: * thus losing the last block of the file.
1.51 deraadt 1790: * Simulate an EOF on interrupt, allowing ACKs from the
1.49 djm 1791: * server to drain.
1.1 djm 1792: */
1.80 djm 1793: if (interrupted || status != SSH2_FX_OK)
1.49 djm 1794: len = 0;
1795: else do
1.141 djm 1796: len = read(local_fd, data, conn->upload_buflen);
1.1 djm 1797: while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1798:
1799: if (len == -1)
1800: fatal("Couldn't read from \"%s\": %s", local_path,
1801: strerror(errno));
1.21 djm 1802:
1803: if (len != 0) {
1.108 djm 1804: ack = xcalloc(1, sizeof(*ack));
1.22 djm 1805: ack->id = ++id;
1806: ack->offset = offset;
1807: ack->len = len;
1808: TAILQ_INSERT_TAIL(&acks, ack, tq);
1809:
1.116 djm 1810: sshbuf_reset(msg);
1811: if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
1812: (r = sshbuf_put_u32(msg, ack->id)) != 0 ||
1813: (r = sshbuf_put_string(msg, handle,
1814: handle_len)) != 0 ||
1815: (r = sshbuf_put_u64(msg, offset)) != 0 ||
1816: (r = sshbuf_put_string(msg, data, len)) != 0)
1.137 djm 1817: fatal_fr(r, "compose");
1.116 djm 1818: send_msg(conn, msg);
1.33 deraadt 1819: debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1.37 deraadt 1820: id, (unsigned long long)offset, len);
1.22 djm 1821: } else if (TAILQ_FIRST(&acks) == NULL)
1.1 djm 1822: break;
1823:
1.22 djm 1824: if (ack == NULL)
1825: fatal("Unexpected ACK %u", id);
1826:
1.28 markus 1827: if (id == startid || len == 0 ||
1.23 djm 1828: id - ackid >= conn->num_requests) {
1.116 djm 1829: u_int rid;
1.31 djm 1830:
1.116 djm 1831: sshbuf_reset(msg);
1832: get_msg(conn, msg);
1833: if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1834: (r = sshbuf_get_u32(msg, &rid)) != 0)
1.137 djm 1835: fatal_fr(r, "parse");
1.22 djm 1836:
1837: if (type != SSH2_FXP_STATUS)
1838: fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1839: "got %d", SSH2_FXP_STATUS, type);
1840:
1.116 djm 1841: if ((r = sshbuf_get_u32(msg, &status)) != 0)
1.137 djm 1842: fatal_fr(r, "parse status");
1.116 djm 1843: debug3("SSH2_FXP_STATUS %u", status);
1.22 djm 1844:
1845: /* Find the request in our queue */
1.53 deraadt 1846: for (ack = TAILQ_FIRST(&acks);
1.116 djm 1847: ack != NULL && ack->id != rid;
1.22 djm 1848: ack = TAILQ_NEXT(ack, tq))
1849: ;
1850: if (ack == NULL)
1.116 djm 1851: fatal("Can't find request for ID %u", rid);
1.22 djm 1852: TAILQ_REMOVE(&acks, ack, tq);
1.77 djm 1853: debug3("In write loop, ack for %u %u bytes at %lld",
1854: ack->id, ack->len, (long long)ack->offset);
1.21 djm 1855: ++ackid;
1.100 dtucker 1856: progress_counter += ack->len;
1.98 djm 1857: free(ack);
1.1 djm 1858: }
1859: offset += len;
1.77 djm 1860: if (offset < 0)
1.137 djm 1861: fatal_f("offset < 0");
1.1 djm 1862: }
1.116 djm 1863: sshbuf_free(msg);
1.80 djm 1864:
1.39 fgsch 1865: if (showprogress)
1866: stop_progress_meter();
1.98 djm 1867: free(data);
1.1 djm 1868:
1.80 djm 1869: if (status != SSH2_FX_OK) {
1870: error("Couldn't write to remote file \"%s\": %s",
1871: remote_path, fx2txt(status));
1.116 djm 1872: status = SSH2_FX_FAILURE;
1.80 djm 1873: }
1874:
1.1 djm 1875: if (close(local_fd) == -1) {
1876: error("Couldn't close local file \"%s\": %s", local_path,
1877: strerror(errno));
1.116 djm 1878: status = SSH2_FX_FAILURE;
1.1 djm 1879: }
1880:
1.10 djm 1881: /* Override umask and utimes if asked */
1.105 djm 1882: if (preserve_flag)
1.23 djm 1883: do_fsetstat(conn, handle, handle_len, &a);
1.10 djm 1884:
1.107 djm 1885: if (fsync_flag)
1886: (void)do_fsync(conn, handle, handle_len);
1887:
1.121 djm 1888: if (do_close(conn, handle, handle_len) != 0)
1.116 djm 1889: status = SSH2_FX_FAILURE;
1890:
1.98 djm 1891: free(handle);
1.5 djm 1892:
1.116 djm 1893: return status == SSH2_FX_OK ? 0 : -1;
1.1 djm 1894: }
1.89 djm 1895:
1896: static int
1.116 djm 1897: upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1898: int depth, int preserve_flag, int print_flag, int resume, int fsync_flag)
1.89 djm 1899: {
1.116 djm 1900: int ret = 0;
1.89 djm 1901: DIR *dirp;
1902: struct dirent *dp;
1.130 djm 1903: char *filename, *new_src = NULL, *new_dst = NULL;
1.89 djm 1904: struct stat sb;
1.121 djm 1905: Attrib a, *dirattrib;
1.138 dtucker 1906: u_int32_t saved_perm;
1.89 djm 1907:
1908: if (depth >= MAX_DIR_DEPTH) {
1909: error("Maximum directory depth exceeded: %d levels", depth);
1910: return -1;
1911: }
1912:
1913: if (stat(src, &sb) == -1) {
1914: error("Couldn't stat directory \"%s\": %s",
1915: src, strerror(errno));
1916: return -1;
1917: }
1918: if (!S_ISDIR(sb.st_mode)) {
1919: error("\"%s\" is not a directory", src);
1920: return -1;
1921: }
1.105 djm 1922: if (print_flag)
1.124 schwarze 1923: mprintf("Entering %s\n", src);
1.89 djm 1924:
1925: attrib_clear(&a);
1926: stat_to_attrib(&sb, &a);
1927: a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1928: a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1929: a.perm &= 01777;
1.105 djm 1930: if (!preserve_flag)
1.89 djm 1931: a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1.101 djm 1932:
1.89 djm 1933: /*
1.121 djm 1934: * sftp lacks a portable status value to match errno EEXIST,
1935: * so if we get a failure back then we must check whether
1.138 dtucker 1936: * the path already existed and is a directory. Ensure we can
1937: * write to the directory we create for the duration of the transfer.
1.89 djm 1938: */
1.138 dtucker 1939: saved_perm = a.perm;
1940: a.perm |= (S_IWUSR|S_IXUSR);
1.121 djm 1941: if (do_mkdir(conn, dst, &a, 0) != 0) {
1942: if ((dirattrib = do_stat(conn, dst, 0)) == NULL)
1.89 djm 1943: return -1;
1.121 djm 1944: if (!S_ISDIR(dirattrib->perm)) {
1945: error("\"%s\" exists but is not a directory", dst);
1.89 djm 1946: return -1;
1.121 djm 1947: }
1.89 djm 1948: }
1.138 dtucker 1949: a.perm = saved_perm;
1.89 djm 1950:
1951: if ((dirp = opendir(src)) == NULL) {
1952: error("Failed to open dir \"%s\": %s", src, strerror(errno));
1953: return -1;
1954: }
1.101 djm 1955:
1.89 djm 1956: while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1957: if (dp->d_ino == 0)
1958: continue;
1.130 djm 1959: free(new_dst);
1960: free(new_src);
1.89 djm 1961: filename = dp->d_name;
1962: new_dst = path_append(dst, filename);
1963: new_src = path_append(src, filename);
1964:
1.90 dtucker 1965: if (lstat(new_src, &sb) == -1) {
1966: logit("%s: lstat failed: %s", filename,
1967: strerror(errno));
1968: ret = -1;
1969: } else if (S_ISDIR(sb.st_mode)) {
1.89 djm 1970: if (strcmp(filename, ".") == 0 ||
1971: strcmp(filename, "..") == 0)
1972: continue;
1973:
1974: if (upload_dir_internal(conn, new_src, new_dst,
1.115 logan 1975: depth + 1, preserve_flag, print_flag, resume,
1.107 djm 1976: fsync_flag) == -1)
1.89 djm 1977: ret = -1;
1.90 dtucker 1978: } else if (S_ISREG(sb.st_mode)) {
1.105 djm 1979: if (do_upload(conn, new_src, new_dst,
1.115 logan 1980: preserve_flag, resume, fsync_flag) == -1) {
1.89 djm 1981: error("Uploading of file %s to %s failed!",
1982: new_src, new_dst);
1983: ret = -1;
1984: }
1985: } else
1986: logit("%s: not a regular file\n", filename);
1987: }
1.130 djm 1988: free(new_dst);
1989: free(new_src);
1.89 djm 1990:
1991: do_setstat(conn, dst, &a);
1992:
1993: (void) closedir(dirp);
1994: return ret;
1995: }
1996:
1997: int
1.116 djm 1998: upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
1999: int preserve_flag, int print_flag, int resume, int fsync_flag)
1.89 djm 2000: {
2001: char *dst_canon;
2002: int ret;
2003:
2004: if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1.107 djm 2005: error("Unable to canonicalize path \"%s\"", dst);
1.89 djm 2006: return -1;
2007: }
2008:
1.106 djm 2009: ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
1.115 logan 2010: print_flag, resume, fsync_flag);
1.107 djm 2011:
1.98 djm 2012: free(dst_canon);
1.89 djm 2013: return ret;
2014: }
2015:
2016: char *
1.116 djm 2017: path_append(const char *p1, const char *p2)
1.89 djm 2018: {
2019: char *ret;
2020: size_t len = strlen(p1) + strlen(p2) + 2;
2021:
2022: ret = xmalloc(len);
2023: strlcpy(ret, p1, len);
2024: if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
2025: strlcat(ret, "/", len);
2026: strlcat(ret, p2, len);
2027:
2028: return(ret);
1.139 djm 2029: }
2030:
2031: char *
2032: make_absolute(char *p, const char *pwd)
2033: {
2034: char *abs_str;
2035:
2036: /* Derelativise */
2037: if (p && !path_absolute(p)) {
2038: abs_str = path_append(pwd, p);
2039: free(p);
2040: return(abs_str);
2041: } else
2042: return(p);
2043: }
2044:
2045: int
2046: remote_is_dir(struct sftp_conn *conn, const char *path)
2047: {
2048: Attrib *a;
2049:
2050: /* XXX: report errors? */
2051: if ((a = do_stat(conn, path, 1)) == NULL)
2052: return(0);
2053: if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
2054: return(0);
2055: return(S_ISDIR(a->perm));
2056: }
2057:
2058:
2059: int
2060: local_is_dir(const char *path)
2061: {
2062: struct stat sb;
2063:
2064: /* XXX: report errors? */
2065: if (stat(path, &sb) == -1)
2066: return(0);
2067:
2068: return(S_ISDIR(sb.st_mode));
2069: }
2070:
2071: /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
2072: int
2073: globpath_is_dir(const char *pathname)
2074: {
2075: size_t l = strlen(pathname);
2076:
2077: return l > 0 && pathname[l - 1] == '/';
1.89 djm 2078: }
2079: