1 /* $OpenBSD: sftp-client.c,v 1.89 2009/08/18 18:36:20 djm Exp $ */
2 /*
3 * Copyright © 2013
4 * Thorsten “mirabilos” Glaser <tg@mirbsd.org>
5 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* XXX: memleaks */
21 /* XXX: signed vs unsigned */
22 /* XXX: remove all logging, only return status codes */
23 /* XXX: copy between two remote sites */
24
25 #include <sys/param.h>
26 #include <sys/queue.h>
27 #include <sys/stat.h>
28 #include <sys/time.h>
29 #include <sys/statvfs.h>
30 #include <sys/uio.h>
31
32 #include <dirent.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <signal.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "xmalloc.h"
42 #include "buffer.h"
43 #include "log.h"
44 #include "atomicio.h"
45 #include "progressmeter.h"
46 #include "misc.h"
47
48 #include "sftp.h"
49 #include "sftp-common.h"
50 #include "sftp-client.h"
51
52 __RCSID("$MirOS: src/usr.bin/ssh/sftp-client.c,v 1.18 2013/10/31 20:07:13 tg Exp $");
53
54 extern volatile sig_atomic_t interrupted;
55 extern int showprogress;
56
57 /* Minimum amount of data to read at a time */
58 #define MIN_READ_SIZE 512
59
60 /* Maximum depth to descend in directory trees */
61 #define MAX_DIR_DEPTH 64
62
63 struct sftp_conn {
64 int fd_in;
65 int fd_out;
66 u_int transfer_buflen;
67 u_int num_requests;
68 u_int version;
69 u_int msg_id;
70 #define SFTP_EXT_POSIX_RENAME 0x00000001
71 #define SFTP_EXT_STATVFS 0x00000002
72 #define SFTP_EXT_FSTATVFS 0x00000004
73 u_int exts;
74 };
75
76 static char *
77 get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...)
78 __attribute__((__format__(__printf__, 4, 5)));
79
80 static void
send_msg(int fd,Buffer * m)81 send_msg(int fd, Buffer *m)
82 {
83 u_char mlen[4];
84 struct iovec iov[2];
85
86 if (buffer_len(m) > SFTP_MAX_MSG_LENGTH)
87 fatal("Outbound message too long %u", buffer_len(m));
88
89 /* Send length first */
90 put_u32(mlen, buffer_len(m));
91 iov[0].iov_base = mlen;
92 iov[0].iov_len = sizeof(mlen);
93 iov[1].iov_base = buffer_ptr(m);
94 iov[1].iov_len = buffer_len(m);
95
96 if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen))
97 fatal("Couldn't send packet: %s", strerror(errno));
98
99 buffer_clear(m);
100 }
101
102 static void
get_msg(int fd,Buffer * m)103 get_msg(int fd, Buffer *m)
104 {
105 u_int msg_len;
106
107 buffer_append_space(m, 4);
108 if (atomicio(read, fd, buffer_ptr(m), 4) != 4) {
109 if (errno == EPIPE)
110 fatal("Connection closed");
111 else
112 fatal("Couldn't read packet: %s", strerror(errno));
113 }
114
115 msg_len = buffer_get_int(m);
116 if (msg_len > SFTP_MAX_MSG_LENGTH)
117 fatal("Received message too long %u", msg_len);
118
119 buffer_append_space(m, msg_len);
120 if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) {
121 if (errno == EPIPE)
122 fatal("Connection closed");
123 else
124 fatal("Read packet: %s", strerror(errno));
125 }
126 }
127
128 static void
send_string_request(int fd,u_int id,u_int code,const char * s,u_int len)129 send_string_request(int fd, u_int id, u_int code, const char *s,
130 u_int len)
131 {
132 Buffer msg;
133
134 buffer_init(&msg);
135 buffer_put_char(&msg, code);
136 buffer_put_int(&msg, id);
137 buffer_put_string(&msg, s, len);
138 send_msg(fd, &msg);
139 debug3("Sent message fd %d T:%u I:%u", fd, code, id);
140 buffer_free(&msg);
141 }
142
143 static void
send_string_attrs_request(int fd,u_int id,u_int code,char * s,u_int len,Attrib * a)144 send_string_attrs_request(int fd, u_int id, u_int code, char *s,
145 u_int len, Attrib *a)
146 {
147 Buffer msg;
148
149 buffer_init(&msg);
150 buffer_put_char(&msg, code);
151 buffer_put_int(&msg, id);
152 buffer_put_string(&msg, s, len);
153 encode_attrib(&msg, a);
154 send_msg(fd, &msg);
155 debug3("Sent message fd %d T:%u I:%u", fd, code, id);
156 buffer_free(&msg);
157 }
158
159 static u_int
get_status(int fd,u_int expected_id)160 get_status(int fd, u_int expected_id)
161 {
162 Buffer msg;
163 u_int type, id, status;
164
165 buffer_init(&msg);
166 get_msg(fd, &msg);
167 type = buffer_get_char(&msg);
168 id = buffer_get_int(&msg);
169
170 if (id != expected_id)
171 fatal("ID mismatch (%u != %u)", id, expected_id);
172 if (type != SSH2_FXP_STATUS)
173 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
174 SSH2_FXP_STATUS, type);
175
176 status = buffer_get_int(&msg);
177 buffer_free(&msg);
178
179 debug3("SSH2_FXP_STATUS %u", status);
180
181 return(status);
182 }
183
184 static char *
get_handle(int fd,u_int expected_id,u_int * len,const char * errfmt,...)185 get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...)
186 {
187 Buffer msg;
188 u_int type, id;
189 char *handle, errmsg[256];
190 va_list args;
191 int status;
192
193 va_start(args, errfmt);
194 if (errfmt != NULL)
195 vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
196 va_end(args);
197
198 buffer_init(&msg);
199 get_msg(fd, &msg);
200 type = buffer_get_char(&msg);
201 id = buffer_get_int(&msg);
202
203 if (id != expected_id)
204 fatal("%s: ID mismatch (%u != %u)",
205 errfmt == NULL ? __func__ : errmsg, id, expected_id);
206 if (type == SSH2_FXP_STATUS) {
207 status = buffer_get_int(&msg);
208 if (errfmt != NULL)
209 error("%s: %s", errmsg, fx2txt(status));
210 buffer_free(&msg);
211 return(NULL);
212 } else if (type != SSH2_FXP_HANDLE)
213 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
214 errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
215
216 handle = buffer_get_string(&msg, len);
217 buffer_free(&msg);
218
219 return(handle);
220 }
221
222 static Attrib *
get_decode_stat(int fd,u_int expected_id,int quiet)223 get_decode_stat(int fd, u_int expected_id, int quiet)
224 {
225 Buffer msg;
226 u_int type, id;
227 Attrib *a;
228
229 buffer_init(&msg);
230 get_msg(fd, &msg);
231
232 type = buffer_get_char(&msg);
233 id = buffer_get_int(&msg);
234
235 debug3("Received stat reply T:%u I:%u", type, id);
236 if (id != expected_id)
237 fatal("ID mismatch (%u != %u)", id, expected_id);
238 if (type == SSH2_FXP_STATUS) {
239 int status = buffer_get_int(&msg);
240
241 if (quiet)
242 debug("Couldn't stat remote file: %s", fx2txt(status));
243 else
244 error("Couldn't stat remote file: %s", fx2txt(status));
245 buffer_free(&msg);
246 return(NULL);
247 } else if (type != SSH2_FXP_ATTRS) {
248 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
249 SSH2_FXP_ATTRS, type);
250 }
251 a = decode_attrib(&msg);
252 buffer_free(&msg);
253
254 return(a);
255 }
256
257 static int
get_decode_statvfs(int fd,struct sftp_statvfs * st,u_int expected_id,int quiet)258 get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id,
259 int quiet)
260 {
261 Buffer msg;
262 u_int type, id, flag;
263
264 buffer_init(&msg);
265 get_msg(fd, &msg);
266
267 type = buffer_get_char(&msg);
268 id = buffer_get_int(&msg);
269
270 debug3("Received statvfs reply T:%u I:%u", type, id);
271 if (id != expected_id)
272 fatal("ID mismatch (%u != %u)", id, expected_id);
273 if (type == SSH2_FXP_STATUS) {
274 int status = buffer_get_int(&msg);
275
276 if (quiet)
277 debug("Couldn't statvfs: %s", fx2txt(status));
278 else
279 error("Couldn't statvfs: %s", fx2txt(status));
280 buffer_free(&msg);
281 return -1;
282 } else if (type != SSH2_FXP_EXTENDED_REPLY) {
283 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
284 SSH2_FXP_EXTENDED_REPLY, type);
285 }
286
287 bzero(st, sizeof(*st));
288 st->f_bsize = buffer_get_int64(&msg);
289 st->f_frsize = buffer_get_int64(&msg);
290 st->f_blocks = buffer_get_int64(&msg);
291 st->f_bfree = buffer_get_int64(&msg);
292 st->f_bavail = buffer_get_int64(&msg);
293 st->f_files = buffer_get_int64(&msg);
294 st->f_ffree = buffer_get_int64(&msg);
295 st->f_favail = buffer_get_int64(&msg);
296 st->f_fsid = buffer_get_int64(&msg);
297 flag = buffer_get_int64(&msg);
298 st->f_namemax = buffer_get_int64(&msg);
299
300 st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
301 st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
302
303 buffer_free(&msg);
304
305 return 0;
306 }
307
308 struct sftp_conn *
do_init(int fd_in,int fd_out,u_int transfer_buflen,u_int num_requests)309 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
310 {
311 u_int type, exts = 0;
312 int version;
313 Buffer msg;
314 struct sftp_conn *ret;
315
316 buffer_init(&msg);
317 buffer_put_char(&msg, SSH2_FXP_INIT);
318 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
319 send_msg(fd_out, &msg);
320
321 buffer_clear(&msg);
322
323 get_msg(fd_in, &msg);
324
325 /* Expecting a VERSION reply */
326 if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
327 error("Invalid packet back from SSH2_FXP_INIT (type %u)",
328 type);
329 buffer_free(&msg);
330 return(NULL);
331 }
332 version = buffer_get_int(&msg);
333
334 debug2("Remote version: %d", version);
335
336 /* Check for extensions */
337 while (buffer_len(&msg) > 0) {
338 char *name = buffer_get_string(&msg, NULL);
339 char *value = buffer_get_string(&msg, NULL);
340 int known = 0;
341
342 if (strcmp(name, "posix-rename@openssh.com") == 0 &&
343 strcmp(value, "1") == 0) {
344 exts |= SFTP_EXT_POSIX_RENAME;
345 known = 1;
346 } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
347 strcmp(value, "2") == 0) {
348 exts |= SFTP_EXT_STATVFS;
349 known = 1;
350 } if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
351 strcmp(value, "2") == 0) {
352 exts |= SFTP_EXT_FSTATVFS;
353 known = 1;
354 }
355 if (known) {
356 debug2("Server supports extension \"%s\" revision %s",
357 name, value);
358 } else {
359 debug2("Unrecognised server extension \"%s\"", name);
360 }
361 xfree(name);
362 xfree(value);
363 }
364
365 buffer_free(&msg);
366
367 ret = xmalloc(sizeof(*ret));
368 ret->fd_in = fd_in;
369 ret->fd_out = fd_out;
370 ret->transfer_buflen = transfer_buflen;
371 ret->num_requests = num_requests;
372 ret->version = version;
373 ret->msg_id = 1;
374 ret->exts = exts;
375
376 /* Some filexfer v.0 servers don't support large packets */
377 if (version == 0)
378 ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
379
380 return(ret);
381 }
382
383 u_int
sftp_proto_version(struct sftp_conn * conn)384 sftp_proto_version(struct sftp_conn *conn)
385 {
386 return(conn->version);
387 }
388
389 int
do_close(struct sftp_conn * conn,char * handle,u_int handle_len)390 do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
391 {
392 u_int id, status;
393 Buffer msg;
394
395 buffer_init(&msg);
396
397 id = conn->msg_id++;
398 buffer_put_char(&msg, SSH2_FXP_CLOSE);
399 buffer_put_int(&msg, id);
400 buffer_put_string(&msg, handle, handle_len);
401 send_msg(conn->fd_out, &msg);
402 debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
403
404 status = get_status(conn->fd_in, id);
405 if (status != SSH2_FX_OK)
406 error("Couldn't close file: %s", fx2txt(status));
407
408 buffer_free(&msg);
409
410 return(status);
411 }
412
413
414 static int
do_lsreaddir(struct sftp_conn * conn,char * path,int printflag,SFTP_DIRENT *** dir)415 do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
416 SFTP_DIRENT ***dir)
417 {
418 Buffer msg;
419 u_int count, type, id, handle_len, i, expected_id, ents = 0;
420 char *handle;
421
422 id = conn->msg_id++;
423
424 buffer_init(&msg);
425 buffer_put_char(&msg, SSH2_FXP_OPENDIR);
426 buffer_put_int(&msg, id);
427 buffer_put_cstring(&msg, path);
428 send_msg(conn->fd_out, &msg);
429
430 buffer_clear(&msg);
431
432 handle = get_handle(conn->fd_in, id, &handle_len,
433 "remote readdir(\"%s\")", path);
434 if (handle == NULL)
435 return(-1);
436
437 if (dir) {
438 ents = 0;
439 *dir = xmalloc(sizeof(**dir));
440 (*dir)[0] = NULL;
441 }
442
443 for (; !interrupted;) {
444 id = expected_id = conn->msg_id++;
445
446 debug3("Sending SSH2_FXP_READDIR I:%u", id);
447
448 buffer_clear(&msg);
449 buffer_put_char(&msg, SSH2_FXP_READDIR);
450 buffer_put_int(&msg, id);
451 buffer_put_string(&msg, handle, handle_len);
452 send_msg(conn->fd_out, &msg);
453
454 buffer_clear(&msg);
455
456 get_msg(conn->fd_in, &msg);
457
458 type = buffer_get_char(&msg);
459 id = buffer_get_int(&msg);
460
461 debug3("Received reply T:%u I:%u", type, id);
462
463 if (id != expected_id)
464 fatal("ID mismatch (%u != %u)", id, expected_id);
465
466 if (type == SSH2_FXP_STATUS) {
467 int status = buffer_get_int(&msg);
468
469 debug3("Received SSH2_FXP_STATUS %d", status);
470
471 if (status == SSH2_FX_EOF) {
472 break;
473 } else {
474 error("Couldn't read directory: %s",
475 fx2txt(status));
476 do_close(conn, handle, handle_len);
477 xfree(handle);
478 return(status);
479 }
480 } else if (type != SSH2_FXP_NAME)
481 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
482 SSH2_FXP_NAME, type);
483
484 count = buffer_get_int(&msg);
485 if (count == 0)
486 break;
487 debug3("Received %d SSH2_FXP_NAME responses", count);
488 for (i = 0; i < count; i++) {
489 char *filename, *longname;
490 Attrib *a;
491
492 filename = buffer_get_string(&msg, NULL);
493 longname = buffer_get_string(&msg, NULL);
494 a = decode_attrib(&msg);
495
496 if (printflag)
497 printf("%s\n", longname);
498
499 /*
500 * Directory entries should never contain '/'
501 * These can be used to attack recursive ops
502 * (e.g. send '../../../../etc/passwd')
503 */
504 if (strchr(filename, '/') != NULL) {
505 error("Server sent suspect path \"%s\" "
506 "during readdir of \"%s\"", filename, path);
507 goto next;
508 }
509
510 if (dir) {
511 *dir = xrealloc(*dir, ents + 2, sizeof(**dir));
512 (*dir)[ents] = xmalloc(sizeof(***dir));
513 (*dir)[ents]->filename = xstrdup(filename);
514 (*dir)[ents]->longname = xstrdup(longname);
515 memcpy(&(*dir)[ents]->a, a, sizeof(*a));
516 (*dir)[++ents] = NULL;
517 }
518 next:
519 xfree(filename);
520 xfree(longname);
521 }
522 }
523
524 buffer_free(&msg);
525 do_close(conn, handle, handle_len);
526 xfree(handle);
527
528 /* Don't return partial matches on interrupt */
529 if (interrupted && dir != NULL && *dir != NULL) {
530 free_sftp_dirents(*dir);
531 *dir = xmalloc(sizeof(**dir));
532 **dir = NULL;
533 }
534
535 return(0);
536 }
537
538 int
do_readdir(struct sftp_conn * conn,char * path,SFTP_DIRENT *** dir)539 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
540 {
541 return(do_lsreaddir(conn, path, 0, dir));
542 }
543
free_sftp_dirents(SFTP_DIRENT ** s)544 void free_sftp_dirents(SFTP_DIRENT **s)
545 {
546 int i;
547
548 for (i = 0; s[i]; i++) {
549 xfree(s[i]->filename);
550 xfree(s[i]->longname);
551 xfree(s[i]);
552 }
553 xfree(s);
554 }
555
556 int
do_rm(struct sftp_conn * conn,char * path)557 do_rm(struct sftp_conn *conn, char *path)
558 {
559 u_int status, id;
560
561 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
562
563 id = conn->msg_id++;
564 send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path,
565 strlen(path));
566 status = get_status(conn->fd_in, id);
567 if (status != SSH2_FX_OK)
568 error("Couldn't delete file: %s", fx2txt(status));
569 return(status);
570 }
571
572 int
do_mkdir(struct sftp_conn * conn,char * path,Attrib * a,int printflag)573 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag)
574 {
575 u_int status, id;
576
577 id = conn->msg_id++;
578 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path,
579 strlen(path), a);
580
581 status = get_status(conn->fd_in, id);
582 if (status != SSH2_FX_OK && printflag)
583 error("Couldn't create directory: %s", fx2txt(status));
584
585 return(status);
586 }
587
588 int
do_rmdir(struct sftp_conn * conn,char * path)589 do_rmdir(struct sftp_conn *conn, char *path)
590 {
591 u_int status, id;
592
593 id = conn->msg_id++;
594 send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path,
595 strlen(path));
596
597 status = get_status(conn->fd_in, id);
598 if (status != SSH2_FX_OK)
599 error("Couldn't remove directory: %s", fx2txt(status));
600
601 return(status);
602 }
603
604 Attrib *
do_stat(struct sftp_conn * conn,char * path,int quiet)605 do_stat(struct sftp_conn *conn, char *path, int quiet)
606 {
607 u_int id;
608
609 id = conn->msg_id++;
610
611 send_string_request(conn->fd_out, id,
612 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
613 path, strlen(path));
614
615 return(get_decode_stat(conn->fd_in, id, quiet));
616 }
617
618 Attrib *
do_lstat(struct sftp_conn * conn,char * path,int quiet)619 do_lstat(struct sftp_conn *conn, char *path, int quiet)
620 {
621 u_int id;
622
623 if (conn->version == 0) {
624 if (quiet)
625 debug("Server version does not support lstat operation");
626 else
627 logit("Server version does not support lstat operation");
628 return(do_stat(conn, path, quiet));
629 }
630
631 id = conn->msg_id++;
632 send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path,
633 strlen(path));
634
635 return(get_decode_stat(conn->fd_in, id, quiet));
636 }
637
638 #ifdef notyet
639 Attrib *
do_fstat(struct sftp_conn * conn,char * handle,u_int handle_len,int quiet)640 do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
641 {
642 u_int id;
643
644 id = conn->msg_id++;
645 send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle,
646 handle_len);
647
648 return(get_decode_stat(conn->fd_in, id, quiet));
649 }
650 #endif
651
652 int
do_setstat(struct sftp_conn * conn,char * path,Attrib * a)653 do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
654 {
655 u_int status, id;
656
657 id = conn->msg_id++;
658 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path,
659 strlen(path), a);
660
661 status = get_status(conn->fd_in, id);
662 if (status != SSH2_FX_OK)
663 error("Couldn't setstat on \"%s\": %s", path,
664 fx2txt(status));
665
666 return(status);
667 }
668
669 int
do_fsetstat(struct sftp_conn * conn,char * handle,u_int handle_len,Attrib * a)670 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
671 Attrib *a)
672 {
673 u_int status, id;
674
675 id = conn->msg_id++;
676 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle,
677 handle_len, a);
678
679 status = get_status(conn->fd_in, id);
680 if (status != SSH2_FX_OK)
681 error("Couldn't fsetstat: %s", fx2txt(status));
682
683 return(status);
684 }
685
686 char *
do_realpath(struct sftp_conn * conn,const char * path)687 do_realpath(struct sftp_conn *conn, const char *path)
688 {
689 Buffer msg;
690 u_int type, expected_id, count, id;
691 char *filename, *longname;
692 Attrib *a;
693
694 expected_id = id = conn->msg_id++;
695 send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path,
696 strlen(path));
697
698 buffer_init(&msg);
699
700 get_msg(conn->fd_in, &msg);
701 type = buffer_get_char(&msg);
702 id = buffer_get_int(&msg);
703
704 if (id != expected_id)
705 fatal("ID mismatch (%u != %u)", id, expected_id);
706
707 if (type == SSH2_FXP_STATUS) {
708 u_int status = buffer_get_int(&msg);
709
710 error("Couldn't canonicalise: %s", fx2txt(status));
711 return(NULL);
712 } else if (type != SSH2_FXP_NAME)
713 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
714 SSH2_FXP_NAME, type);
715
716 count = buffer_get_int(&msg);
717 if (count != 1)
718 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
719
720 filename = buffer_get_string(&msg, NULL);
721 longname = buffer_get_string(&msg, NULL);
722 a = decode_attrib(&msg);
723
724 debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
725
726 xfree(longname);
727
728 buffer_free(&msg);
729
730 return(filename);
731 }
732
733 int
do_rename(struct sftp_conn * conn,char * oldpath,char * newpath)734 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
735 {
736 Buffer msg;
737 u_int status, id;
738
739 buffer_init(&msg);
740
741 /* Send rename request */
742 id = conn->msg_id++;
743 if ((conn->exts & SFTP_EXT_POSIX_RENAME)) {
744 buffer_put_char(&msg, SSH2_FXP_EXTENDED);
745 buffer_put_int(&msg, id);
746 buffer_put_cstring(&msg, "posix-rename@openssh.com");
747 } else {
748 buffer_put_char(&msg, SSH2_FXP_RENAME);
749 buffer_put_int(&msg, id);
750 }
751 buffer_put_cstring(&msg, oldpath);
752 buffer_put_cstring(&msg, newpath);
753 send_msg(conn->fd_out, &msg);
754 debug3("Sent message %s \"%s\" -> \"%s\"",
755 (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" :
756 "SSH2_FXP_RENAME", oldpath, newpath);
757 buffer_free(&msg);
758
759 status = get_status(conn->fd_in, id);
760 if (status != SSH2_FX_OK)
761 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
762 newpath, fx2txt(status));
763
764 return(status);
765 }
766
767 int
do_symlink(struct sftp_conn * conn,char * oldpath,char * newpath)768 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
769 {
770 Buffer msg;
771 u_int status, id;
772
773 if (conn->version < 3) {
774 error("This server does not support the symlink operation");
775 return(SSH2_FX_OP_UNSUPPORTED);
776 }
777
778 buffer_init(&msg);
779
780 /* Send symlink request */
781 id = conn->msg_id++;
782 buffer_put_char(&msg, SSH2_FXP_SYMLINK);
783 buffer_put_int(&msg, id);
784 buffer_put_cstring(&msg, oldpath);
785 buffer_put_cstring(&msg, newpath);
786 send_msg(conn->fd_out, &msg);
787 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
788 newpath);
789 buffer_free(&msg);
790
791 status = get_status(conn->fd_in, id);
792 if (status != SSH2_FX_OK)
793 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
794 newpath, fx2txt(status));
795
796 return(status);
797 }
798
799 #ifdef notyet
800 char *
do_readlink(struct sftp_conn * conn,char * path)801 do_readlink(struct sftp_conn *conn, char *path)
802 {
803 Buffer msg;
804 u_int type, expected_id, count, id;
805 char *filename, *longname;
806 Attrib *a;
807
808 expected_id = id = conn->msg_id++;
809 send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path,
810 strlen(path));
811
812 buffer_init(&msg);
813
814 get_msg(conn->fd_in, &msg);
815 type = buffer_get_char(&msg);
816 id = buffer_get_int(&msg);
817
818 if (id != expected_id)
819 fatal("ID mismatch (%u != %u)", id, expected_id);
820
821 if (type == SSH2_FXP_STATUS) {
822 u_int status = buffer_get_int(&msg);
823
824 error("Couldn't readlink: %s", fx2txt(status));
825 return(NULL);
826 } else if (type != SSH2_FXP_NAME)
827 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
828 SSH2_FXP_NAME, type);
829
830 count = buffer_get_int(&msg);
831 if (count != 1)
832 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
833
834 filename = buffer_get_string(&msg, NULL);
835 longname = buffer_get_string(&msg, NULL);
836 a = decode_attrib(&msg);
837
838 debug3("SSH_FXP_READLINK %s -> %s", path, filename);
839
840 xfree(longname);
841
842 buffer_free(&msg);
843
844 return(filename);
845 }
846 #endif
847
848 int
do_statvfs(struct sftp_conn * conn,const char * path,struct sftp_statvfs * st,int quiet)849 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
850 int quiet)
851 {
852 Buffer msg;
853 u_int id;
854
855 if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
856 error("Server does not support statvfs@openssh.com extension");
857 return -1;
858 }
859
860 id = conn->msg_id++;
861
862 buffer_init(&msg);
863 buffer_clear(&msg);
864 buffer_put_char(&msg, SSH2_FXP_EXTENDED);
865 buffer_put_int(&msg, id);
866 buffer_put_cstring(&msg, "statvfs@openssh.com");
867 buffer_put_cstring(&msg, path);
868 send_msg(conn->fd_out, &msg);
869 buffer_free(&msg);
870
871 return get_decode_statvfs(conn->fd_in, st, id, quiet);
872 }
873
874 #ifdef notyet
875 int
do_fstatvfs(struct sftp_conn * conn,const char * handle,u_int handle_len,struct sftp_statvfs * st,int quiet)876 do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
877 struct sftp_statvfs *st, int quiet)
878 {
879 Buffer msg;
880 u_int id;
881
882 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
883 error("Server does not support fstatvfs@openssh.com extension");
884 return -1;
885 }
886
887 id = conn->msg_id++;
888
889 buffer_init(&msg);
890 buffer_clear(&msg);
891 buffer_put_char(&msg, SSH2_FXP_EXTENDED);
892 buffer_put_int(&msg, id);
893 buffer_put_cstring(&msg, "fstatvfs@openssh.com");
894 buffer_put_string(&msg, handle, handle_len);
895 send_msg(conn->fd_out, &msg);
896 buffer_free(&msg);
897
898 return get_decode_statvfs(conn->fd_in, st, id, quiet);
899 }
900 #endif
901
902 static void
send_read_request(int fd_out,u_int id,u_int64_t offset,u_int len,char * handle,u_int handle_len)903 send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
904 char *handle, u_int handle_len)
905 {
906 Buffer msg;
907
908 buffer_init(&msg);
909 buffer_clear(&msg);
910 buffer_put_char(&msg, SSH2_FXP_READ);
911 buffer_put_int(&msg, id);
912 buffer_put_string(&msg, handle, handle_len);
913 buffer_put_int64(&msg, offset);
914 buffer_put_int(&msg, len);
915 send_msg(fd_out, &msg);
916 buffer_free(&msg);
917 }
918
919 int
do_download(struct sftp_conn * conn,char * remote_path,char * local_path,Attrib * a,int pflag)920 do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
921 Attrib *a, int pflag)
922 {
923 Attrib junk;
924 Buffer msg;
925 char *handle;
926 int local_fd, status = 0, write_error;
927 int read_error, write_errno;
928 u_int64_t offset, size;
929 u_int handle_len, mode, type, id, buflen, num_req, max_req;
930 off_t progress_counter;
931 struct request {
932 u_int id;
933 u_int len;
934 u_int64_t offset;
935 TAILQ_ENTRY(request) tq;
936 };
937 TAILQ_HEAD(reqhead, request) requests;
938 struct request *req;
939
940 TAILQ_INIT(&requests);
941
942 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
943 return -1;
944
945 /* Do not preserve set[ug]id here, as we do not preserve ownership */
946 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
947 mode = a->perm & 0777;
948 else
949 mode = 0666;
950
951 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
952 (!S_ISREG(a->perm))) {
953 error("Cannot download non-regular file: %s", remote_path);
954 return(-1);
955 }
956
957 if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
958 size = a->size;
959 else
960 size = 0;
961
962 buflen = conn->transfer_buflen;
963 buffer_init(&msg);
964
965 /* Send open request */
966 id = conn->msg_id++;
967 buffer_put_char(&msg, SSH2_FXP_OPEN);
968 buffer_put_int(&msg, id);
969 buffer_put_cstring(&msg, remote_path);
970 buffer_put_int(&msg, SSH2_FXF_READ);
971 attrib_clear(&junk); /* Send empty attributes */
972 encode_attrib(&msg, &junk);
973 send_msg(conn->fd_out, &msg);
974 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
975
976 handle = get_handle(conn->fd_in, id, &handle_len,
977 "remote open(\"%s\")", remote_path);
978 if (handle == NULL) {
979 buffer_free(&msg);
980 return(-1);
981 }
982
983 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC,
984 mode | S_IWRITE);
985 if (local_fd == -1) {
986 error("Couldn't open local file \"%s\" for writing: %s",
987 local_path, strerror(errno));
988 do_close(conn, handle, handle_len);
989 buffer_free(&msg);
990 xfree(handle);
991 return(-1);
992 }
993
994 /* Read from remote and write to local */
995 write_error = read_error = write_errno = num_req = offset = 0;
996 max_req = 1;
997 progress_counter = 0;
998
999 if (showprogress && size != 0)
1000 start_progress_meter(remote_path, size, &progress_counter);
1001
1002 while (num_req > 0 || max_req > 0) {
1003 char *data;
1004 u_int len;
1005
1006 /*
1007 * Simulate EOF on interrupt: stop sending new requests and
1008 * allow outstanding requests to drain gracefully
1009 */
1010 if (interrupted) {
1011 if (num_req == 0) /* If we haven't started yet... */
1012 break;
1013 max_req = 0;
1014 }
1015
1016 /* Send some more requests */
1017 while (num_req < max_req) {
1018 debug3("Request range %llu -> %llu (%d/%d)",
1019 (unsigned long long)offset,
1020 (unsigned long long)offset + buflen - 1,
1021 num_req, max_req);
1022 req = xmalloc(sizeof(*req));
1023 req->id = conn->msg_id++;
1024 req->len = buflen;
1025 req->offset = offset;
1026 offset += buflen;
1027 num_req++;
1028 TAILQ_INSERT_TAIL(&requests, req, tq);
1029 send_read_request(conn->fd_out, req->id, req->offset,
1030 req->len, handle, handle_len);
1031 }
1032
1033 buffer_clear(&msg);
1034 get_msg(conn->fd_in, &msg);
1035 type = buffer_get_char(&msg);
1036 id = buffer_get_int(&msg);
1037 debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1038
1039 /* Find the request in our queue */
1040 for (req = TAILQ_FIRST(&requests);
1041 req != NULL && req->id != id;
1042 req = TAILQ_NEXT(req, tq))
1043 ;
1044 if (req == NULL)
1045 fatal("Unexpected reply %u", id);
1046
1047 switch (type) {
1048 case SSH2_FXP_STATUS:
1049 status = buffer_get_int(&msg);
1050 if (status != SSH2_FX_EOF)
1051 read_error = 1;
1052 max_req = 0;
1053 TAILQ_REMOVE(&requests, req, tq);
1054 xfree(req);
1055 num_req--;
1056 break;
1057 case SSH2_FXP_DATA:
1058 data = buffer_get_string(&msg, &len);
1059 debug3("Received data %llu -> %llu",
1060 (unsigned long long)req->offset,
1061 (unsigned long long)req->offset + len - 1);
1062 if (len > req->len)
1063 fatal("Received more data than asked for "
1064 "%u > %u", len, req->len);
1065 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1066 atomicio(vwrite, local_fd, data, len) != len) &&
1067 !write_error) {
1068 write_errno = errno;
1069 write_error = 1;
1070 max_req = 0;
1071 }
1072 progress_counter += len;
1073 xfree(data);
1074
1075 if (len == req->len) {
1076 TAILQ_REMOVE(&requests, req, tq);
1077 xfree(req);
1078 num_req--;
1079 } else {
1080 /* Resend the request for the missing data */
1081 debug3("Short data block, re-requesting "
1082 "%llu -> %llu (%2d)",
1083 (unsigned long long)req->offset + len,
1084 (unsigned long long)req->offset +
1085 req->len - 1, num_req);
1086 req->id = conn->msg_id++;
1087 req->len -= len;
1088 req->offset += len;
1089 send_read_request(conn->fd_out, req->id,
1090 req->offset, req->len, handle, handle_len);
1091 /* Reduce the request size */
1092 if (len < buflen)
1093 buflen = MAX(MIN_READ_SIZE, len);
1094 }
1095 if (max_req > 0) { /* max_req = 0 iff EOF received */
1096 if (size > 0 && offset > size) {
1097 /* Only one request at a time
1098 * after the expected EOF */
1099 debug3("Finish at %llu (%2d)",
1100 (unsigned long long)offset,
1101 num_req);
1102 max_req = 1;
1103 } else if (max_req <= conn->num_requests) {
1104 ++max_req;
1105 }
1106 }
1107 break;
1108 default:
1109 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1110 SSH2_FXP_DATA, type);
1111 }
1112 }
1113
1114 if (showprogress && size)
1115 stop_progress_meter();
1116
1117 /* Sanity check */
1118 if (TAILQ_FIRST(&requests) != NULL)
1119 fatal("Transfer complete, but requests still in queue");
1120
1121 if (read_error) {
1122 error("Couldn't read from remote file \"%s\" : %s",
1123 remote_path, fx2txt(status));
1124 do_close(conn, handle, handle_len);
1125 } else if (write_error) {
1126 error("Couldn't write to \"%s\": %s", local_path,
1127 strerror(write_errno));
1128 status = -1;
1129 do_close(conn, handle, handle_len);
1130 } else {
1131 status = do_close(conn, handle, handle_len);
1132
1133 /* Override umask and utimes if asked */
1134 if (pflag && fchmod(local_fd, mode) == -1)
1135 error("Couldn't set mode on \"%s\": %s", local_path,
1136 strerror(errno));
1137 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1138 struct timeval tv[2];
1139 tv[0].tv_sec = a->atime;
1140 tv[1].tv_sec = a->mtime;
1141 tv[0].tv_usec = tv[1].tv_usec = 0;
1142 if (utimes(local_path, tv) == -1)
1143 error("Can't set times on \"%s\": %s",
1144 local_path, strerror(errno));
1145 }
1146 }
1147 close(local_fd);
1148 buffer_free(&msg);
1149 xfree(handle);
1150
1151 return(status);
1152 }
1153
1154 static int
download_dir_internal(struct sftp_conn * conn,char * src,char * dst,Attrib * dirattrib,int pflag,int printflag,int depth)1155 download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1156 Attrib *dirattrib, int pflag, int printflag, int depth)
1157 {
1158 int i, ret = 0;
1159 SFTP_DIRENT **dir_entries;
1160 char *filename, *new_src, *new_dst;
1161 mode_t mode = 0777;
1162
1163 if (depth >= MAX_DIR_DEPTH) {
1164 error("Maximum directory depth exceeded: %d levels", depth);
1165 return -1;
1166 }
1167
1168 if (dirattrib == NULL &&
1169 (dirattrib = do_stat(conn, src, 1)) == NULL) {
1170 error("Unable to stat remote directory \"%s\"", src);
1171 return -1;
1172 }
1173 if (!S_ISDIR(dirattrib->perm)) {
1174 error("\"%s\" is not a directory", src);
1175 return -1;
1176 }
1177 if (printflag)
1178 printf("Retrieving %s\n", src);
1179
1180 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1181 mode = dirattrib->perm & 01777;
1182 else {
1183 debug("Server did not send permissions for "
1184 "directory \"%s\"", dst);
1185 }
1186
1187 if (mkdir(dst, mode) == -1 && errno != EEXIST) {
1188 error("mkdir %s: %s", dst, strerror(errno));
1189 return -1;
1190 }
1191
1192 if (do_readdir(conn, src, &dir_entries) == -1) {
1193 error("%s: Failed to get directory contents", src);
1194 return -1;
1195 }
1196
1197 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1198 filename = dir_entries[i]->filename;
1199
1200 new_dst = path_append(dst, filename);
1201 new_src = path_append(src, filename);
1202
1203 if (S_ISDIR(dir_entries[i]->a.perm)) {
1204 if (strcmp(filename, ".") == 0 ||
1205 strcmp(filename, "..") == 0)
1206 continue;
1207 if (download_dir_internal(conn, new_src, new_dst,
1208 &(dir_entries[i]->a), pflag, printflag,
1209 depth + 1) == -1)
1210 ret = -1;
1211 } else if (S_ISREG(dir_entries[i]->a.perm) ) {
1212 if (do_download(conn, new_src, new_dst,
1213 &(dir_entries[i]->a), pflag) == -1) {
1214 error("Download of file %s to %s failed",
1215 new_src, new_dst);
1216 ret = -1;
1217 }
1218 } else
1219 logit("%s: not a regular file\n", new_src);
1220
1221 xfree(new_dst);
1222 xfree(new_src);
1223 }
1224
1225 if (pflag) {
1226 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1227 struct timeval tv[2];
1228 tv[0].tv_sec = dirattrib->atime;
1229 tv[1].tv_sec = dirattrib->mtime;
1230 tv[0].tv_usec = tv[1].tv_usec = 0;
1231 if (utimes(dst, tv) == -1)
1232 error("Can't set times on \"%s\": %s",
1233 dst, strerror(errno));
1234 } else
1235 debug("Server did not send times for directory "
1236 "\"%s\"", dst);
1237 }
1238
1239 free_sftp_dirents(dir_entries);
1240
1241 return ret;
1242 }
1243
1244 int
download_dir(struct sftp_conn * conn,char * src,char * dst,Attrib * dirattrib,int pflag,int printflag)1245 download_dir(struct sftp_conn *conn, char *src, char *dst,
1246 Attrib *dirattrib, int pflag, int printflag)
1247 {
1248 char *src_canon;
1249 int ret;
1250
1251 if ((src_canon = do_realpath(conn, src)) == NULL) {
1252 error("Unable to canonicalise path \"%s\"", src);
1253 return -1;
1254 }
1255
1256 ret = download_dir_internal(conn, src_canon, dst,
1257 dirattrib, pflag, printflag, 0);
1258 xfree(src_canon);
1259 return ret;
1260 }
1261
1262 int
do_upload(struct sftp_conn * conn,char * local_path,char * remote_path,int pflag)1263 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1264 int pflag)
1265 {
1266 int local_fd;
1267 int status = SSH2_FX_OK;
1268 u_int handle_len, id, type;
1269 off_t offset;
1270 char *handle, *data;
1271 Buffer msg;
1272 struct stat sb;
1273 Attrib a;
1274 u_int32_t startid;
1275 u_int32_t ackid;
1276 struct outstanding_ack {
1277 u_int id;
1278 u_int len;
1279 off_t offset;
1280 TAILQ_ENTRY(outstanding_ack) tq;
1281 };
1282 TAILQ_HEAD(ackhead, outstanding_ack) acks;
1283 struct outstanding_ack *ack = NULL;
1284
1285 TAILQ_INIT(&acks);
1286
1287 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1288 error("Couldn't open local file \"%s\" for reading: %s",
1289 local_path, strerror(errno));
1290 return(-1);
1291 }
1292 if (fstat(local_fd, &sb) == -1) {
1293 error("Couldn't fstat local file \"%s\": %s",
1294 local_path, strerror(errno));
1295 close(local_fd);
1296 return(-1);
1297 }
1298 if (!S_ISREG(sb.st_mode)) {
1299 error("%s is not a regular file", local_path);
1300 close(local_fd);
1301 return(-1);
1302 }
1303 stat_to_attrib(&sb, &a);
1304
1305 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1306 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1307 a.perm &= 0777;
1308 if (!pflag)
1309 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1310
1311 buffer_init(&msg);
1312
1313 /* Send open request */
1314 id = conn->msg_id++;
1315 buffer_put_char(&msg, SSH2_FXP_OPEN);
1316 buffer_put_int(&msg, id);
1317 buffer_put_cstring(&msg, remote_path);
1318 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
1319 encode_attrib(&msg, &a);
1320 send_msg(conn->fd_out, &msg);
1321 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1322
1323 buffer_clear(&msg);
1324
1325 handle = get_handle(conn->fd_in, id, &handle_len,
1326 "remote open(\"%s\")", remote_path);
1327 if (handle == NULL) {
1328 close(local_fd);
1329 buffer_free(&msg);
1330 return -1;
1331 }
1332
1333 startid = ackid = id + 1;
1334 data = xmalloc(conn->transfer_buflen);
1335
1336 /* Read from local and write to remote */
1337 offset = 0;
1338 if (showprogress)
1339 start_progress_meter(local_path, sb.st_size, &offset);
1340
1341 for (;;) {
1342 int len;
1343
1344 /*
1345 * Can't use atomicio here because it returns 0 on EOF,
1346 * thus losing the last block of the file.
1347 * Simulate an EOF on interrupt, allowing ACKs from the
1348 * server to drain.
1349 */
1350 if (interrupted || status != SSH2_FX_OK)
1351 len = 0;
1352 else do
1353 len = read(local_fd, data, conn->transfer_buflen);
1354 while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1355
1356 if (len == -1)
1357 fatal("Couldn't read from \"%s\": %s", local_path,
1358 strerror(errno));
1359
1360 if (len != 0) {
1361 ack = xmalloc(sizeof(*ack));
1362 ack->id = ++id;
1363 ack->offset = offset;
1364 ack->len = len;
1365 TAILQ_INSERT_TAIL(&acks, ack, tq);
1366
1367 buffer_clear(&msg);
1368 buffer_put_char(&msg, SSH2_FXP_WRITE);
1369 buffer_put_int(&msg, ack->id);
1370 buffer_put_string(&msg, handle, handle_len);
1371 buffer_put_int64(&msg, offset);
1372 buffer_put_string(&msg, data, len);
1373 send_msg(conn->fd_out, &msg);
1374 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1375 id, (unsigned long long)offset, len);
1376 } else if (TAILQ_FIRST(&acks) == NULL)
1377 break;
1378
1379 if (ack == NULL)
1380 fatal("Unexpected ACK %u", id);
1381
1382 if (id == startid || len == 0 ||
1383 id - ackid >= conn->num_requests) {
1384 u_int r_id;
1385
1386 buffer_clear(&msg);
1387 get_msg(conn->fd_in, &msg);
1388 type = buffer_get_char(&msg);
1389 r_id = buffer_get_int(&msg);
1390
1391 if (type != SSH2_FXP_STATUS)
1392 fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1393 "got %d", SSH2_FXP_STATUS, type);
1394
1395 status = buffer_get_int(&msg);
1396 debug3("SSH2_FXP_STATUS %d", status);
1397
1398 /* Find the request in our queue */
1399 for (ack = TAILQ_FIRST(&acks);
1400 ack != NULL && ack->id != r_id;
1401 ack = TAILQ_NEXT(ack, tq))
1402 ;
1403 if (ack == NULL)
1404 fatal("Can't find request for ID %u", r_id);
1405 TAILQ_REMOVE(&acks, ack, tq);
1406 debug3("In write loop, ack for %u %u bytes at %lld",
1407 ack->id, ack->len, (long long)ack->offset);
1408 ++ackid;
1409 xfree(ack);
1410 }
1411 offset += len;
1412 if (offset < 0)
1413 fatal("%s: offset < 0", __func__);
1414 }
1415 buffer_free(&msg);
1416
1417 if (showprogress)
1418 stop_progress_meter();
1419 xfree(data);
1420
1421 if (status != SSH2_FX_OK) {
1422 error("Couldn't write to remote file \"%s\": %s",
1423 remote_path, fx2txt(status));
1424 status = -1;
1425 }
1426
1427 if (close(local_fd) == -1) {
1428 error("Couldn't close local file \"%s\": %s", local_path,
1429 strerror(errno));
1430 status = -1;
1431 }
1432
1433 /* Override umask and utimes if asked */
1434 if (pflag)
1435 do_fsetstat(conn, handle, handle_len, &a);
1436
1437 if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
1438 status = -1;
1439 xfree(handle);
1440
1441 return status;
1442 }
1443
1444 static int
upload_dir_internal(struct sftp_conn * conn,char * src,char * dst,int pflag,int printflag,int depth)1445 upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1446 int pflag, int printflag, int depth)
1447 {
1448 int ret = 0, status;
1449 DIR *dirp;
1450 struct dirent *dp;
1451 char *filename, *new_src, *new_dst;
1452 struct stat sb;
1453 Attrib a;
1454
1455 if (depth >= MAX_DIR_DEPTH) {
1456 error("Maximum directory depth exceeded: %d levels", depth);
1457 return -1;
1458 }
1459
1460 if (stat(src, &sb) == -1) {
1461 error("Couldn't stat directory \"%s\": %s",
1462 src, strerror(errno));
1463 return -1;
1464 }
1465 if (!S_ISDIR(sb.st_mode)) {
1466 error("\"%s\" is not a directory", src);
1467 return -1;
1468 }
1469 if (printflag)
1470 printf("Entering %s\n", src);
1471
1472 attrib_clear(&a);
1473 stat_to_attrib(&sb, &a);
1474 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1475 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1476 a.perm &= 01777;
1477 if (!pflag)
1478 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1479
1480 status = do_mkdir(conn, dst, &a, 0);
1481 /*
1482 * we lack a portable status for errno EEXIST,
1483 * so if we get a SSH2_FX_FAILURE back we must check
1484 * if it was created successfully.
1485 */
1486 if (status != SSH2_FX_OK) {
1487 if (status != SSH2_FX_FAILURE)
1488 return -1;
1489 if (do_stat(conn, dst, 0) == NULL)
1490 return -1;
1491 }
1492
1493 if ((dirp = opendir(src)) == NULL) {
1494 error("Failed to open dir \"%s\": %s", src, strerror(errno));
1495 return -1;
1496 }
1497
1498 while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1499 if (dp->d_ino == 0)
1500 continue;
1501 filename = dp->d_name;
1502 new_dst = path_append(dst, filename);
1503 new_src = path_append(src, filename);
1504
1505 if (S_ISDIR(DTTOIF(dp->d_type))) {
1506 if (strcmp(filename, ".") == 0 ||
1507 strcmp(filename, "..") == 0)
1508 continue;
1509
1510 if (upload_dir_internal(conn, new_src, new_dst,
1511 pflag, depth + 1, printflag) == -1)
1512 ret = -1;
1513 } else if (S_ISREG(DTTOIF(dp->d_type)) ) {
1514 if (do_upload(conn, new_src, new_dst, pflag) == -1) {
1515 error("Uploading of file %s to %s failed!",
1516 new_src, new_dst);
1517 ret = -1;
1518 }
1519 } else
1520 logit("%s: not a regular file\n", filename);
1521 xfree(new_dst);
1522 xfree(new_src);
1523 }
1524
1525 do_setstat(conn, dst, &a);
1526
1527 (void) closedir(dirp);
1528 return ret;
1529 }
1530
1531 int
upload_dir(struct sftp_conn * conn,char * src,char * dst,int printflag,int pflag)1532 upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag,
1533 int pflag)
1534 {
1535 char *dst_canon;
1536 int ret;
1537
1538 if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1539 error("Unable to canonicalise path \"%s\"", dst);
1540 return -1;
1541 }
1542
1543 ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0);
1544 xfree(dst_canon);
1545 return ret;
1546 }
1547
1548 char *
path_append(char * p1,char * p2)1549 path_append(char *p1, char *p2)
1550 {
1551 char *ret;
1552 size_t len = strlen(p1) + strlen(p2) + 2;
1553
1554 ret = xmalloc(len);
1555 strlcpy(ret, p1, len);
1556 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
1557 strlcat(ret, "/", len);
1558 strlcat(ret, p2, len);
1559
1560 return(ret);
1561 }
1562
1563