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