Annotation of src/usr.bin/ssh/sftp-client.c, Revision 1.16
1.1 djm 1: /*
2: * Copyright (c) 2001 Damien Miller. All rights reserved.
3: *
4: * Redistribution and use in source and binary forms, with or without
5: * modification, are permitted provided that the following conditions
6: * are met:
7: * 1. Redistributions of source code must retain the above copyright
8: * notice, this list of conditions and the following disclaimer.
9: * 2. Redistributions in binary form must reproduce the above copyright
10: * notice, this list of conditions and the following disclaimer in the
11: * documentation and/or other materials provided with the distribution.
12: *
13: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23: */
24:
25: /* XXX: memleaks */
26: /* XXX: signed vs unsigned */
27: /* XXX: redesign to allow concurrent overlapped operations */
28: /* XXX: we use fatal too much, error may be more appropriate in places */
29: /* XXX: copy between two remote sites */
30:
31: #include "includes.h"
1.16 ! markus 32: RCSID("$OpenBSD: sftp-client.c,v 1.15 2001/03/19 10:52:51 djm Exp $");
1.1 djm 33:
34: #include "ssh.h"
35: #include "buffer.h"
36: #include "bufaux.h"
37: #include "getput.h"
38: #include "xmalloc.h"
39: #include "log.h"
40: #include "atomicio.h"
41: #include "pathnames.h"
42:
43: #include "sftp.h"
44: #include "sftp-common.h"
45: #include "sftp-client.h"
46:
47: /* How much data to read/write at at time during copies */
48: /* XXX: what should this be? */
49: #define COPY_SIZE 8192
50:
1.4 djm 51: /* Message ID */
52: static u_int msg_id = 1;
53:
1.1 djm 54: void
55: send_msg(int fd, Buffer *m)
56: {
57: int mlen = buffer_len(m);
58: int len;
59: Buffer oqueue;
60:
61: buffer_init(&oqueue);
62: buffer_put_int(&oqueue, mlen);
63: buffer_append(&oqueue, buffer_ptr(m), mlen);
64: buffer_consume(m, mlen);
65:
66: len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));
67: if (len <= 0)
68: fatal("Couldn't send packet: %s", strerror(errno));
69:
70: buffer_free(&oqueue);
71: }
72:
73: void
74: get_msg(int fd, Buffer *m)
75: {
76: u_int len, msg_len;
77: unsigned char buf[4096];
78:
79: len = atomicio(read, fd, buf, 4);
1.15 djm 80: if (len == 0)
81: fatal("Connection closed");
82: else if (len == -1)
1.1 djm 83: fatal("Couldn't read packet: %s", strerror(errno));
84:
85: msg_len = GET_32BIT(buf);
86: if (msg_len > 256 * 1024)
87: fatal("Received message too long %d", msg_len);
88:
89: while (msg_len) {
90: len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
1.15 djm 91: if (len == 0)
92: fatal("Connection closed");
93: else if (len == -1)
1.1 djm 94: fatal("Couldn't read packet: %s", strerror(errno));
95:
96: msg_len -= len;
97: buffer_append(m, buf, len);
98: }
99: }
100:
101: void
102: send_string_request(int fd, u_int id, u_int code, char *s,
103: u_int len)
104: {
105: Buffer msg;
106:
107: buffer_init(&msg);
108: buffer_put_char(&msg, code);
109: buffer_put_int(&msg, id);
110: buffer_put_string(&msg, s, len);
111: send_msg(fd, &msg);
112: debug3("Sent message fd %d T:%d I:%d", fd, code, id);
113: buffer_free(&msg);
114: }
115:
116: void
117: send_string_attrs_request(int fd, u_int id, u_int code, char *s,
118: u_int len, Attrib *a)
119: {
120: Buffer msg;
121:
122: buffer_init(&msg);
123: buffer_put_char(&msg, code);
124: buffer_put_int(&msg, id);
125: buffer_put_string(&msg, s, len);
126: encode_attrib(&msg, a);
127: send_msg(fd, &msg);
128: debug3("Sent message fd %d T:%d I:%d", fd, code, id);
129: buffer_free(&msg);
130: }
131:
132: u_int
133: get_status(int fd, int expected_id)
134: {
135: Buffer msg;
136: u_int type, id, status;
137:
138: buffer_init(&msg);
139: get_msg(fd, &msg);
140: type = buffer_get_char(&msg);
141: id = buffer_get_int(&msg);
142:
143: if (id != expected_id)
144: fatal("ID mismatch (%d != %d)", id, expected_id);
145: if (type != SSH2_FXP_STATUS)
146: fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
147: SSH2_FXP_STATUS, type);
148:
149: status = buffer_get_int(&msg);
150: buffer_free(&msg);
151:
152: debug3("SSH2_FXP_STATUS %d", status);
153:
154: return(status);
155: }
156:
157: char *
158: get_handle(int fd, u_int expected_id, u_int *len)
159: {
160: Buffer msg;
161: u_int type, id;
162: char *handle;
163:
164: buffer_init(&msg);
165: get_msg(fd, &msg);
166: type = buffer_get_char(&msg);
167: id = buffer_get_int(&msg);
168:
169: if (id != expected_id)
170: fatal("ID mismatch (%d != %d)", id, expected_id);
171: if (type == SSH2_FXP_STATUS) {
172: int status = buffer_get_int(&msg);
173:
174: error("Couldn't get handle: %s", fx2txt(status));
175: return(NULL);
176: } else if (type != SSH2_FXP_HANDLE)
177: fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
178: SSH2_FXP_HANDLE, type);
179:
180: handle = buffer_get_string(&msg, len);
181: buffer_free(&msg);
182:
183: return(handle);
184: }
185:
186: Attrib *
1.14 djm 187: get_decode_stat(int fd, u_int expected_id, int quiet)
1.1 djm 188: {
189: Buffer msg;
190: u_int type, id;
191: Attrib *a;
192:
193: buffer_init(&msg);
194: get_msg(fd, &msg);
195:
196: type = buffer_get_char(&msg);
197: id = buffer_get_int(&msg);
198:
199: debug3("Received stat reply T:%d I:%d", type, id);
200: if (id != expected_id)
201: fatal("ID mismatch (%d != %d)", id, expected_id);
202: if (type == SSH2_FXP_STATUS) {
203: int status = buffer_get_int(&msg);
204:
1.14 djm 205: if (quiet)
206: debug("Couldn't stat remote file: %s", fx2txt(status));
207: else
208: error("Couldn't stat remote file: %s", fx2txt(status));
1.1 djm 209: return(NULL);
210: } else if (type != SSH2_FXP_ATTRS) {
211: fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
212: SSH2_FXP_ATTRS, type);
213: }
214: a = decode_attrib(&msg);
215: buffer_free(&msg);
216:
217: return(a);
218: }
219:
220: int
221: do_init(int fd_in, int fd_out)
222: {
223: int type, version;
224: Buffer msg;
225:
226: buffer_init(&msg);
227: buffer_put_char(&msg, SSH2_FXP_INIT);
228: buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
229: send_msg(fd_out, &msg);
230:
231: buffer_clear(&msg);
232:
233: get_msg(fd_in, &msg);
234:
1.3 stevesk 235: /* Expecting a VERSION reply */
1.1 djm 236: if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
237: error("Invalid packet back from SSH2_FXP_INIT (type %d)",
238: type);
239: buffer_free(&msg);
240: return(-1);
241: }
242: version = buffer_get_int(&msg);
243:
244: debug2("Remote version: %d", version);
245:
246: /* Check for extensions */
247: while (buffer_len(&msg) > 0) {
248: char *name = buffer_get_string(&msg, NULL);
249: char *value = buffer_get_string(&msg, NULL);
250:
251: debug2("Init extension: \"%s\"", name);
252: xfree(name);
253: xfree(value);
254: }
255:
256: buffer_free(&msg);
1.11 djm 257:
258: return(version);
1.1 djm 259: }
260:
261: int
262: do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
263: {
264: u_int id, status;
265: Buffer msg;
266:
267: buffer_init(&msg);
268:
1.4 djm 269: id = msg_id++;
1.1 djm 270: buffer_put_char(&msg, SSH2_FXP_CLOSE);
271: buffer_put_int(&msg, id);
272: buffer_put_string(&msg, handle, handle_len);
273: send_msg(fd_out, &msg);
274: debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
275:
276: status = get_status(fd_in, id);
277: if (status != SSH2_FX_OK)
278: error("Couldn't close file: %s", fx2txt(status));
279:
280: buffer_free(&msg);
281:
282: return(status);
283: }
284:
1.12 djm 285:
1.1 djm 286: int
1.16 ! markus 287: do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
1.12 djm 288: SFTP_DIRENT ***dir)
1.1 djm 289: {
290: Buffer msg;
1.13 markus 291: u_int type, id, handle_len, i, expected_id, ents = 0;
1.1 djm 292: char *handle;
293:
1.4 djm 294: id = msg_id++;
1.1 djm 295:
296: buffer_init(&msg);
297: buffer_put_char(&msg, SSH2_FXP_OPENDIR);
298: buffer_put_int(&msg, id);
299: buffer_put_cstring(&msg, path);
300: send_msg(fd_out, &msg);
301:
302: buffer_clear(&msg);
303:
304: handle = get_handle(fd_in, id, &handle_len);
305: if (handle == NULL)
306: return(-1);
307:
1.12 djm 308: if (dir) {
309: ents = 0;
310: *dir = xmalloc(sizeof(**dir));
311: (*dir)[0] = NULL;
312: }
313:
314:
1.1 djm 315: for(;;) {
316: int count;
317:
1.4 djm 318: id = expected_id = msg_id++;
1.1 djm 319:
320: debug3("Sending SSH2_FXP_READDIR I:%d", id);
321:
322: buffer_clear(&msg);
323: buffer_put_char(&msg, SSH2_FXP_READDIR);
324: buffer_put_int(&msg, id);
325: buffer_put_string(&msg, handle, handle_len);
326: send_msg(fd_out, &msg);
327:
328: buffer_clear(&msg);
329:
330: get_msg(fd_in, &msg);
331:
332: type = buffer_get_char(&msg);
333: id = buffer_get_int(&msg);
334:
335: debug3("Received reply T:%d I:%d", type, id);
336:
337: if (id != expected_id)
338: fatal("ID mismatch (%d != %d)", id, expected_id);
339:
340: if (type == SSH2_FXP_STATUS) {
341: int status = buffer_get_int(&msg);
342:
343: debug3("Received SSH2_FXP_STATUS %d", status);
344:
345: if (status == SSH2_FX_EOF) {
346: break;
347: } else {
348: error("Couldn't read directory: %s",
349: fx2txt(status));
350: do_close(fd_in, fd_out, handle, handle_len);
1.9 djm 351: return(status);
1.1 djm 352: }
353: } else if (type != SSH2_FXP_NAME)
354: fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
355: SSH2_FXP_NAME, type);
356:
357: count = buffer_get_int(&msg);
1.7 markus 358: if (count == 0)
359: break;
1.8 stevesk 360: debug3("Received %d SSH2_FXP_NAME responses", count);
1.1 djm 361: for(i = 0; i < count; i++) {
362: char *filename, *longname;
363: Attrib *a;
364:
365: filename = buffer_get_string(&msg, NULL);
366: longname = buffer_get_string(&msg, NULL);
367: a = decode_attrib(&msg);
368:
1.12 djm 369: if (printflag)
370: printf("%s\n", longname);
371:
372: if (dir) {
1.16 ! markus 373: *dir = xrealloc(*dir, sizeof(**dir) *
1.12 djm 374: (ents + 2));
375: (*dir)[ents] = xmalloc(sizeof(***dir));
376: (*dir)[ents]->filename = xstrdup(filename);
377: (*dir)[ents]->longname = xstrdup(longname);
378: memcpy(&(*dir)[ents]->a, a, sizeof(*a));
379: (*dir)[++ents] = NULL;
380: }
1.1 djm 381:
382: xfree(filename);
383: xfree(longname);
384: }
385: }
386:
387: buffer_free(&msg);
388: do_close(fd_in, fd_out, handle, handle_len);
389: xfree(handle);
390:
391: return(0);
392: }
393:
394: int
1.12 djm 395: do_ls(int fd_in, int fd_out, char *path)
396: {
397: return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
398: }
399:
400: int
401: do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
402: {
403: return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
404: }
405:
406: void free_sftp_dirents(SFTP_DIRENT **s)
407: {
408: int i;
409:
410: for(i = 0; s[i]; i++) {
411: xfree(s[i]->filename);
412: xfree(s[i]->longname);
413: xfree(s[i]);
414: }
415: xfree(s);
416: }
417:
418: int
1.1 djm 419: do_rm(int fd_in, int fd_out, char *path)
420: {
421: u_int status, id;
422:
423: debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
424:
1.4 djm 425: id = msg_id++;
1.1 djm 426: send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
427: status = get_status(fd_in, id);
428: if (status != SSH2_FX_OK)
429: error("Couldn't delete file: %s", fx2txt(status));
430: return(status);
431: }
432:
433: int
434: do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
435: {
436: u_int status, id;
437:
1.4 djm 438: id = msg_id++;
1.1 djm 439: send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
440: strlen(path), a);
441:
442: status = get_status(fd_in, id);
443: if (status != SSH2_FX_OK)
444: error("Couldn't create directory: %s", fx2txt(status));
445:
446: return(status);
447: }
448:
449: int
450: do_rmdir(int fd_in, int fd_out, char *path)
451: {
452: u_int status, id;
453:
1.4 djm 454: id = msg_id++;
1.1 djm 455: send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
456:
457: status = get_status(fd_in, id);
458: if (status != SSH2_FX_OK)
459: error("Couldn't remove directory: %s", fx2txt(status));
460:
461: return(status);
462: }
463:
464: Attrib *
1.14 djm 465: do_stat(int fd_in, int fd_out, char *path, int quiet)
1.1 djm 466: {
467: u_int id;
468:
1.4 djm 469: id = msg_id++;
1.1 djm 470: send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
1.14 djm 471: return(get_decode_stat(fd_in, id, quiet));
1.1 djm 472: }
473:
474: Attrib *
1.14 djm 475: do_lstat(int fd_in, int fd_out, char *path, int quiet)
1.1 djm 476: {
477: u_int id;
478:
1.4 djm 479: id = msg_id++;
1.1 djm 480: send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
1.14 djm 481: return(get_decode_stat(fd_in, id, quiet));
1.1 djm 482: }
483:
484: Attrib *
1.14 djm 485: do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
1.1 djm 486: {
487: u_int id;
488:
1.4 djm 489: id = msg_id++;
1.1 djm 490: send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
1.14 djm 491: return(get_decode_stat(fd_in, id, quiet));
1.1 djm 492: }
493:
494: int
495: do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
496: {
497: u_int status, id;
498:
1.4 djm 499: id = msg_id++;
1.1 djm 500: send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
501: strlen(path), a);
502:
503: status = get_status(fd_in, id);
504: if (status != SSH2_FX_OK)
505: error("Couldn't setstat on \"%s\": %s", path,
506: fx2txt(status));
507:
508: return(status);
509: }
510:
511: int
512: do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
513: Attrib *a)
514: {
515: u_int status, id;
516:
1.4 djm 517: id = msg_id++;
1.1 djm 518: send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
519: handle_len, a);
520:
521: status = get_status(fd_in, id);
522: if (status != SSH2_FX_OK)
523: error("Couldn't fsetstat: %s", fx2txt(status));
524:
525: return(status);
526: }
527:
528: char *
529: do_realpath(int fd_in, int fd_out, char *path)
530: {
531: Buffer msg;
532: u_int type, expected_id, count, id;
533: char *filename, *longname;
534: Attrib *a;
535:
1.4 djm 536: expected_id = id = msg_id++;
1.11 djm 537: send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
1.1 djm 538:
539: buffer_init(&msg);
540:
541: get_msg(fd_in, &msg);
542: type = buffer_get_char(&msg);
543: id = buffer_get_int(&msg);
544:
545: if (id != expected_id)
546: fatal("ID mismatch (%d != %d)", id, expected_id);
547:
548: if (type == SSH2_FXP_STATUS) {
549: u_int status = buffer_get_int(&msg);
550:
551: error("Couldn't canonicalise: %s", fx2txt(status));
552: return(NULL);
553: } else if (type != SSH2_FXP_NAME)
554: fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
555: SSH2_FXP_NAME, type);
556:
557: count = buffer_get_int(&msg);
558: if (count != 1)
559: fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
560:
561: filename = buffer_get_string(&msg, NULL);
562: longname = buffer_get_string(&msg, NULL);
563: a = decode_attrib(&msg);
564:
565: debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
566:
567: xfree(longname);
568:
569: buffer_free(&msg);
570:
571: return(filename);
572: }
573:
574: int
575: do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
576: {
577: Buffer msg;
578: u_int status, id;
579:
580: buffer_init(&msg);
581:
582: /* Send rename request */
1.4 djm 583: id = msg_id++;
1.1 djm 584: buffer_put_char(&msg, SSH2_FXP_RENAME);
585: buffer_put_int(&msg, id);
586: buffer_put_cstring(&msg, oldpath);
587: buffer_put_cstring(&msg, newpath);
588: send_msg(fd_out, &msg);
589: debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
590: newpath);
591: buffer_free(&msg);
592:
593: status = get_status(fd_in, id);
594: if (status != SSH2_FX_OK)
595: error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
596: fx2txt(status));
597:
598: return(status);
1.11 djm 599: }
600:
601: int
602: do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
603: {
604: Buffer msg;
605: u_int status, id;
606:
607: buffer_init(&msg);
608:
609: /* Send rename request */
610: id = msg_id++;
611: buffer_put_char(&msg, SSH2_FXP_SYMLINK);
612: buffer_put_int(&msg, id);
613: buffer_put_cstring(&msg, oldpath);
614: buffer_put_cstring(&msg, newpath);
615: send_msg(fd_out, &msg);
616: debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
617: newpath);
618: buffer_free(&msg);
619:
620: status = get_status(fd_in, id);
621: if (status != SSH2_FX_OK)
622: error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
623: fx2txt(status));
624:
625: return(status);
626: }
627:
628: char *
629: do_readlink(int fd_in, int fd_out, char *path)
630: {
631: Buffer msg;
632: u_int type, expected_id, count, id;
633: char *filename, *longname;
634: Attrib *a;
635:
636: expected_id = id = msg_id++;
637: send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
638:
639: buffer_init(&msg);
640:
641: get_msg(fd_in, &msg);
642: type = buffer_get_char(&msg);
643: id = buffer_get_int(&msg);
644:
645: if (id != expected_id)
646: fatal("ID mismatch (%d != %d)", id, expected_id);
647:
648: if (type == SSH2_FXP_STATUS) {
649: u_int status = buffer_get_int(&msg);
650:
651: error("Couldn't readlink: %s", fx2txt(status));
652: return(NULL);
653: } else if (type != SSH2_FXP_NAME)
654: fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
655: SSH2_FXP_NAME, type);
656:
657: count = buffer_get_int(&msg);
658: if (count != 1)
659: fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
660:
661: filename = buffer_get_string(&msg, NULL);
662: longname = buffer_get_string(&msg, NULL);
663: a = decode_attrib(&msg);
664:
665: debug3("SSH_FXP_READLINK %s -> %s", path, filename);
666:
667: xfree(longname);
668:
669: buffer_free(&msg);
670:
671: return(filename);
1.1 djm 672: }
673:
674: int
675: do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
676: int pflag)
677: {
678: int local_fd;
679: u_int expected_id, handle_len, mode, type, id;
680: u_int64_t offset;
681: char *handle;
682: Buffer msg;
683: Attrib junk, *a;
1.5 djm 684: int status;
1.1 djm 685:
1.14 djm 686: a = do_stat(fd_in, fd_out, remote_path, 0);
1.1 djm 687: if (a == NULL)
688: return(-1);
689:
690: /* XXX: should we preserve set[ug]id? */
691: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
692: mode = S_IWRITE | (a->perm & 0777);
693: else
694: mode = 0666;
695:
1.14 djm 696: if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
697: (a->perm & S_IFDIR)) {
698: error("Cannot download a directory: %s", remote_path);
699: return(-1);
700: }
701:
1.1 djm 702: local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
703: if (local_fd == -1) {
704: error("Couldn't open local file \"%s\" for writing: %s",
705: local_path, strerror(errno));
1.14 djm 706: return(-1);
1.1 djm 707: }
708:
709: buffer_init(&msg);
710:
711: /* Send open request */
1.4 djm 712: id = msg_id++;
1.1 djm 713: buffer_put_char(&msg, SSH2_FXP_OPEN);
714: buffer_put_int(&msg, id);
715: buffer_put_cstring(&msg, remote_path);
716: buffer_put_int(&msg, SSH2_FXF_READ);
717: attrib_clear(&junk); /* Send empty attributes */
718: encode_attrib(&msg, &junk);
719: send_msg(fd_out, &msg);
720: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
721:
722: handle = get_handle(fd_in, id, &handle_len);
723: if (handle == NULL) {
724: buffer_free(&msg);
725: close(local_fd);
726: return(-1);
727: }
728:
729: /* Read from remote and write to local */
730: offset = 0;
731: for(;;) {
732: u_int len;
733: char *data;
734:
1.4 djm 735: id = expected_id = msg_id++;
1.1 djm 736:
737: buffer_clear(&msg);
738: buffer_put_char(&msg, SSH2_FXP_READ);
739: buffer_put_int(&msg, id);
740: buffer_put_string(&msg, handle, handle_len);
741: buffer_put_int64(&msg, offset);
742: buffer_put_int(&msg, COPY_SIZE);
743: send_msg(fd_out, &msg);
744: debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
1.2 deraadt 745: id, (unsigned long long)offset, COPY_SIZE);
1.1 djm 746:
747: buffer_clear(&msg);
748:
749: get_msg(fd_in, &msg);
750: type = buffer_get_char(&msg);
751: id = buffer_get_int(&msg);
752: debug3("Received reply T:%d I:%d", type, id);
753: if (id != expected_id)
754: fatal("ID mismatch (%d != %d)", id, expected_id);
755: if (type == SSH2_FXP_STATUS) {
1.5 djm 756: status = buffer_get_int(&msg);
1.1 djm 757:
758: if (status == SSH2_FX_EOF)
759: break;
760: else {
761: error("Couldn't read from remote "
762: "file \"%s\" : %s", remote_path,
763: fx2txt(status));
764: do_close(fd_in, fd_out, handle, handle_len);
1.5 djm 765: goto done;
1.1 djm 766: }
767: } else if (type != SSH2_FXP_DATA) {
768: fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
769: SSH2_FXP_DATA, type);
770: }
771:
772: data = buffer_get_string(&msg, &len);
773: if (len > COPY_SIZE)
774: fatal("Received more data than asked for %d > %d",
775: len, COPY_SIZE);
776:
1.6 itojun 777: debug3("In read loop, got %d offset %llu", len,
1.2 deraadt 778: (unsigned long long)offset);
1.1 djm 779: if (atomicio(write, local_fd, data, len) != len) {
780: error("Couldn't write to \"%s\": %s", local_path,
781: strerror(errno));
782: do_close(fd_in, fd_out, handle, handle_len);
1.5 djm 783: status = -1;
1.1 djm 784: xfree(data);
1.5 djm 785: goto done;
1.1 djm 786: }
787:
788: offset += len;
789: xfree(data);
790: }
1.5 djm 791: status = do_close(fd_in, fd_out, handle, handle_len);
792:
1.10 djm 793: /* Override umask and utimes if asked */
794: if (pflag && fchmod(local_fd, mode) == -1)
795: error("Couldn't set mode on \"%s\": %s", local_path,
796: strerror(errno));
797: if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
798: struct timeval tv[2];
799: tv[0].tv_sec = a->atime;
800: tv[1].tv_sec = a->mtime;
801: tv[0].tv_usec = tv[1].tv_usec = 0;
802: if (utimes(local_path, tv) == -1)
803: error("Can't set times on \"%s\": %s", local_path,
804: strerror(errno));
805: }
806:
1.5 djm 807: done:
808: close(local_fd);
809: buffer_free(&msg);
1.1 djm 810: xfree(handle);
1.5 djm 811: return status;
1.1 djm 812: }
813:
814: int
815: do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
816: int pflag)
817: {
818: int local_fd;
819: u_int handle_len, id;
820: u_int64_t offset;
821: char *handle;
822: Buffer msg;
823: struct stat sb;
824: Attrib a;
1.5 djm 825: int status;
1.1 djm 826:
827: if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
828: error("Couldn't open local file \"%s\" for reading: %s",
829: local_path, strerror(errno));
830: return(-1);
831: }
832: if (fstat(local_fd, &sb) == -1) {
833: error("Couldn't fstat local file \"%s\": %s",
834: local_path, strerror(errno));
835: close(local_fd);
836: return(-1);
837: }
838: stat_to_attrib(&sb, &a);
839:
840: a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
841: a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
842: a.perm &= 0777;
843: if (!pflag)
844: a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
845:
846: buffer_init(&msg);
847:
848: /* Send open request */
1.4 djm 849: id = msg_id++;
1.1 djm 850: buffer_put_char(&msg, SSH2_FXP_OPEN);
851: buffer_put_int(&msg, id);
852: buffer_put_cstring(&msg, remote_path);
853: buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
854: encode_attrib(&msg, &a);
855: send_msg(fd_out, &msg);
856: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
857:
858: buffer_clear(&msg);
859:
860: handle = get_handle(fd_in, id, &handle_len);
861: if (handle == NULL) {
862: close(local_fd);
863: buffer_free(&msg);
864: return(-1);
865: }
866:
867: /* Read from local and write to remote */
868: offset = 0;
869: for(;;) {
870: int len;
871: char data[COPY_SIZE];
872:
873: /*
874: * Can't use atomicio here because it returns 0 on EOF, thus losing
875: * the last block of the file
876: */
877: do
878: len = read(local_fd, data, COPY_SIZE);
879: while ((len == -1) && (errno == EINTR || errno == EAGAIN));
880:
881: if (len == -1)
882: fatal("Couldn't read from \"%s\": %s", local_path,
883: strerror(errno));
884: if (len == 0)
885: break;
886:
887: buffer_clear(&msg);
888: buffer_put_char(&msg, SSH2_FXP_WRITE);
889: buffer_put_int(&msg, ++id);
890: buffer_put_string(&msg, handle, handle_len);
891: buffer_put_int64(&msg, offset);
892: buffer_put_string(&msg, data, len);
893: send_msg(fd_out, &msg);
894: debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
1.2 deraadt 895: id, (unsigned long long)offset, len);
1.1 djm 896:
897: status = get_status(fd_in, id);
898: if (status != SSH2_FX_OK) {
899: error("Couldn't write to remote file \"%s\": %s",
900: remote_path, fx2txt(status));
901: do_close(fd_in, fd_out, handle, handle_len);
902: close(local_fd);
1.5 djm 903: goto done;
1.1 djm 904: }
1.2 deraadt 905: debug3("In write loop, got %d offset %llu", len,
906: (unsigned long long)offset);
1.1 djm 907:
908: offset += len;
909: }
910:
911: if (close(local_fd) == -1) {
912: error("Couldn't close local file \"%s\": %s", local_path,
913: strerror(errno));
914: do_close(fd_in, fd_out, handle, handle_len);
1.5 djm 915: status = -1;
916: goto done;
1.1 djm 917: }
918:
1.10 djm 919: /* Override umask and utimes if asked */
920: if (pflag)
921: do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
922:
1.5 djm 923: status = do_close(fd_in, fd_out, handle, handle_len);
924:
925: done:
926: xfree(handle);
927: buffer_free(&msg);
928: return status;
1.1 djm 929: }
1.12 djm 930: