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