]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - sftp.c
first pass
[PuTTY.git] / sftp.c
1 /*
2  * sftp.c: SFTP generic client code.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9 #include <limits.h>
10
11 #include "misc.h"
12 #include "int64.h"
13 #include "tree234.h"
14 #include "sftp.h"
15
16 struct sftp_packet {
17     char *data;
18     unsigned length, maxlen;
19     unsigned savedpos;
20     int type;
21 };
22
23 static const char *fxp_error_message;
24 static int fxp_errtype;
25
26 static void fxp_internal_error(const char *msg);
27
28 /* ----------------------------------------------------------------------
29  * SFTP packet construction functions.
30  */
31 static void sftp_pkt_ensure(struct sftp_packet *pkt, int length)
32 {
33     if ((int)pkt->maxlen < length) {
34         pkt->maxlen = length + 256;
35         pkt->data = sresize(pkt->data, pkt->maxlen, char);
36     }
37 }
38 static void sftp_pkt_adddata(struct sftp_packet *pkt,
39                              const void *data, int len)
40 {
41     pkt->length += len;
42     sftp_pkt_ensure(pkt, pkt->length);
43     memcpy(pkt->data + pkt->length - len, data, len);
44 }
45 static void sftp_pkt_addbyte(struct sftp_packet *pkt, unsigned char byte)
46 {
47     sftp_pkt_adddata(pkt, &byte, 1);
48 }
49 static void sftp_pkt_adduint32(struct sftp_packet *pkt,
50                                unsigned long value)
51 {
52     unsigned char x[4];
53     PUT_32BIT(x, value);
54     sftp_pkt_adddata(pkt, x, 4);
55 }
56 static struct sftp_packet *sftp_pkt_init(int pkt_type)
57 {
58     struct sftp_packet *pkt;
59     pkt = snew(struct sftp_packet);
60     pkt->data = NULL;
61     pkt->savedpos = -1;
62     pkt->length = 0;
63     pkt->maxlen = 0;
64     sftp_pkt_adduint32(pkt, 0); /* length field will be filled in later */
65     sftp_pkt_addbyte(pkt, (unsigned char) pkt_type);
66     return pkt;
67 }
68 /*
69 static void sftp_pkt_addbool(struct sftp_packet *pkt, unsigned char value)
70 {
71     sftp_pkt_adddata(pkt, &value, 1);
72 }
73 */
74 static void sftp_pkt_adduint64(struct sftp_packet *pkt, uint64 value)
75 {
76     unsigned char x[8];
77     PUT_32BIT(x, value.hi);
78     PUT_32BIT(x + 4, value.lo);
79     sftp_pkt_adddata(pkt, x, 8);
80 }
81 static void sftp_pkt_addstring_start(struct sftp_packet *pkt)
82 {
83     sftp_pkt_adduint32(pkt, 0);
84     pkt->savedpos = pkt->length;
85 }
86 static void sftp_pkt_addstring_str(struct sftp_packet *pkt, const char *data)
87 {
88     sftp_pkt_adddata(pkt, data, strlen(data));
89     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);
90 }
91 static void sftp_pkt_addstring_data(struct sftp_packet *pkt,
92                                     const char *data, int len)
93 {
94     sftp_pkt_adddata(pkt, data, len);
95     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);
96 }
97 static void sftp_pkt_addstring(struct sftp_packet *pkt, const char *data)
98 {
99     sftp_pkt_addstring_start(pkt);
100     sftp_pkt_addstring_str(pkt, data);
101 }
102 static void sftp_pkt_addattrs(struct sftp_packet *pkt, struct fxp_attrs attrs)
103 {
104     sftp_pkt_adduint32(pkt, attrs.flags);
105     if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
106         sftp_pkt_adduint32(pkt, attrs.size.hi);
107         sftp_pkt_adduint32(pkt, attrs.size.lo);
108     }
109     if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) {
110         sftp_pkt_adduint32(pkt, attrs.uid);
111         sftp_pkt_adduint32(pkt, attrs.gid);
112     }
113     if (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
114         sftp_pkt_adduint32(pkt, attrs.permissions);
115     }
116     if (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME) {
117         sftp_pkt_adduint32(pkt, attrs.atime);
118         sftp_pkt_adduint32(pkt, attrs.mtime);
119     }
120     if (attrs.flags & SSH_FILEXFER_ATTR_EXTENDED) {
121         /*
122          * We currently don't support sending any extended
123          * attributes.
124          */
125     }
126 }
127
128 /* ----------------------------------------------------------------------
129  * SFTP packet decode functions.
130  */
131
132 static int sftp_pkt_getbyte(struct sftp_packet *pkt, unsigned char *ret)
133 {
134     if (pkt->length - pkt->savedpos < 1)
135         return 0;
136     *ret = (unsigned char) pkt->data[pkt->savedpos];
137     pkt->savedpos++;
138     return 1;
139 }
140 static int sftp_pkt_getuint32(struct sftp_packet *pkt, unsigned long *ret)
141 {
142     if (pkt->length - pkt->savedpos < 4)
143         return 0;
144     *ret = GET_32BIT(pkt->data + pkt->savedpos);
145     pkt->savedpos += 4;
146     return 1;
147 }
148 static int sftp_pkt_getstring(struct sftp_packet *pkt,
149                               char **p, int *length)
150 {
151     *p = NULL;
152     if (pkt->length - pkt->savedpos < 4)
153         return 0;
154     *length = toint(GET_32BIT(pkt->data + pkt->savedpos));
155     pkt->savedpos += 4;
156     if ((int)(pkt->length - pkt->savedpos) < *length || *length < 0) {
157         *length = 0;
158         return 0;
159     }
160     *p = pkt->data + pkt->savedpos;
161     pkt->savedpos += *length;
162     return 1;
163 }
164 static int sftp_pkt_getattrs(struct sftp_packet *pkt, struct fxp_attrs *ret)
165 {
166     if (!sftp_pkt_getuint32(pkt, &ret->flags))
167         return 0;
168     if (ret->flags & SSH_FILEXFER_ATTR_SIZE) {
169         unsigned long hi, lo;
170         if (!sftp_pkt_getuint32(pkt, &hi) ||
171             !sftp_pkt_getuint32(pkt, &lo))
172             return 0;
173         ret->size = uint64_make(hi, lo);
174     }
175     if (ret->flags & SSH_FILEXFER_ATTR_UIDGID) {
176         if (!sftp_pkt_getuint32(pkt, &ret->uid) ||
177             !sftp_pkt_getuint32(pkt, &ret->gid))
178             return 0;
179     }
180     if (ret->flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
181         if (!sftp_pkt_getuint32(pkt, &ret->permissions))
182             return 0;
183     }
184     if (ret->flags & SSH_FILEXFER_ATTR_ACMODTIME) {
185         if (!sftp_pkt_getuint32(pkt, &ret->atime) ||
186             !sftp_pkt_getuint32(pkt, &ret->mtime))
187             return 0;
188     }
189     if (ret->flags & SSH_FILEXFER_ATTR_EXTENDED) {
190         unsigned long count;
191         if (!sftp_pkt_getuint32(pkt, &count))
192             return 0;
193         while (count--) {
194             char *str;
195             int len;
196             /*
197              * We should try to analyse these, if we ever find one
198              * we recognise.
199              */
200             if (!sftp_pkt_getstring(pkt, &str, &len) ||
201                 !sftp_pkt_getstring(pkt, &str, &len))
202                 return 0;
203         }
204     }
205     return 1;
206 }
207 static void sftp_pkt_free(struct sftp_packet *pkt)
208 {
209     if (pkt->data)
210         sfree(pkt->data);
211     sfree(pkt);
212 }
213
214 /* ----------------------------------------------------------------------
215  * Send and receive packet functions.
216  */
217 int sftp_send(struct sftp_packet *pkt)
218 {
219     int ret;
220     PUT_32BIT(pkt->data, pkt->length - 4);
221     ret = sftp_senddata(pkt->data, pkt->length);
222     sftp_pkt_free(pkt);
223     return ret;
224 }
225 struct sftp_packet *sftp_recv(void)
226 {
227     struct sftp_packet *pkt;
228     char x[4];
229     unsigned char uc;
230
231     if (!sftp_recvdata(x, 4))
232         return NULL;
233
234     pkt = snew(struct sftp_packet);
235     pkt->savedpos = 0;
236     pkt->length = pkt->maxlen = GET_32BIT(x);
237     pkt->data = snewn(pkt->length, char);
238
239     if (!sftp_recvdata(pkt->data, pkt->length)) {
240         sftp_pkt_free(pkt);
241         return NULL;
242     }
243
244     if (!sftp_pkt_getbyte(pkt, &uc)) {
245         sftp_pkt_free(pkt);
246         return NULL;
247     } else {
248         pkt->type = uc;
249     }
250
251     return pkt;
252 }
253
254 /* ----------------------------------------------------------------------
255  * Request ID allocation and temporary dispatch routines.
256  */
257
258 #define REQUEST_ID_OFFSET 256
259
260 struct sftp_request {
261     unsigned id;
262     int registered;
263     void *userdata;
264 };
265
266 static int sftp_reqcmp(void *av, void *bv)
267 {
268     struct sftp_request *a = (struct sftp_request *)av;
269     struct sftp_request *b = (struct sftp_request *)bv;
270     if (a->id < b->id)
271         return -1;
272     if (a->id > b->id)
273         return +1;
274     return 0;
275 }
276 static int sftp_reqfind(void *av, void *bv)
277 {
278     unsigned *a = (unsigned *) av;
279     struct sftp_request *b = (struct sftp_request *)bv;
280     if (*a < b->id)
281         return -1;
282     if (*a > b->id)
283         return +1;
284     return 0;
285 }
286
287 static tree234 *sftp_requests;
288
289 static struct sftp_request *sftp_alloc_request(void)
290 {
291     unsigned low, high, mid;
292     int tsize;
293     struct sftp_request *r;
294
295     if (sftp_requests == NULL)
296         sftp_requests = newtree234(sftp_reqcmp);
297
298     /*
299      * First-fit allocation of request IDs: always pick the lowest
300      * unused one. To do this, binary-search using the counted
301      * B-tree to find the largest ID which is in a contiguous
302      * sequence from the beginning. (Precisely everything in that
303      * sequence must have ID equal to its tree index plus
304      * REQUEST_ID_OFFSET.)
305      */
306     tsize = count234(sftp_requests);
307
308     low = -1;
309     high = tsize;
310     while (high - low > 1) {
311         mid = (high + low) / 2;
312         r = index234(sftp_requests, mid);
313         if (r->id == mid + REQUEST_ID_OFFSET)
314             low = mid;                 /* this one is fine */
315         else
316             high = mid;                /* this one is past it */
317     }
318     /*
319      * Now low points to either -1, or the tree index of the
320      * largest ID in the initial sequence.
321      */
322     {
323         unsigned i = low + 1 + REQUEST_ID_OFFSET;
324         assert(NULL == find234(sftp_requests, &i, sftp_reqfind));
325     }
326
327     /*
328      * So the request ID we need to create is
329      * low + 1 + REQUEST_ID_OFFSET.
330      */
331     r = snew(struct sftp_request);
332     r->id = low + 1 + REQUEST_ID_OFFSET;
333     r->registered = 0;
334     r->userdata = NULL;
335     add234(sftp_requests, r);
336     return r;
337 }
338
339 void sftp_cleanup_request(void)
340 {
341     if (sftp_requests != NULL) {
342         freetree234(sftp_requests);
343         sftp_requests = NULL;
344     }
345 }
346
347 void sftp_register(struct sftp_request *req)
348 {
349     req->registered = 1;
350 }
351
352 struct sftp_request *sftp_find_request(struct sftp_packet *pktin)
353 {
354     unsigned long id;
355     unsigned fid;
356     struct sftp_request *req;
357
358     if (!pktin) {
359         fxp_internal_error("did not receive a valid SFTP packet\n");
360         return NULL;
361     }
362
363     if (!sftp_pkt_getuint32(pktin, &id)) {
364         fxp_internal_error("did not receive a valid SFTP packet\n");
365         return NULL;
366     }
367     fid = (unsigned)id;
368     req = find234(sftp_requests, &fid, sftp_reqfind);
369
370     if (!req || !req->registered) {
371         fxp_internal_error("request ID mismatch\n");
372         return NULL;
373     }
374
375     del234(sftp_requests, req);
376
377     return req;
378 }
379
380 /* ----------------------------------------------------------------------
381  * String handling routines.
382  */
383
384 static char *mkstr(char *s, int len)
385 {
386     char *p = snewn(len + 1, char);
387     memcpy(p, s, len);
388     p[len] = '\0';
389     return p;
390 }
391
392 /* ----------------------------------------------------------------------
393  * SFTP primitives.
394  */
395
396 /*
397  * Deal with (and free) an FXP_STATUS packet. Return 1 if
398  * SSH_FX_OK, 0 if SSH_FX_EOF, and -1 for anything else (error).
399  * Also place the status into fxp_errtype.
400  */
401 static int fxp_got_status(struct sftp_packet *pktin)
402 {
403     static const char *const messages[] = {
404         /* SSH_FX_OK. The only time we will display a _message_ for this
405          * is if we were expecting something other than FXP_STATUS on
406          * success, so this is actually an error message! */
407         "unexpected OK response",
408         "end of file",
409         "no such file or directory",
410         "permission denied",
411         "failure",
412         "bad message",
413         "no connection",
414         "connection lost",
415         "operation unsupported",
416     };
417
418     if (pktin->type != SSH_FXP_STATUS) {
419         fxp_error_message = "expected FXP_STATUS packet";
420         fxp_errtype = -1;
421     } else {
422         unsigned long ul;
423         if (!sftp_pkt_getuint32(pktin, &ul)) {
424             fxp_error_message = "malformed FXP_STATUS packet";
425             fxp_errtype = -1;
426         } else {
427             fxp_errtype = ul;
428             if (fxp_errtype < 0 ||
429                 fxp_errtype >= sizeof(messages) / sizeof(*messages))
430                 fxp_error_message = "unknown error code";
431             else
432                 fxp_error_message = messages[fxp_errtype];
433         }
434     }
435
436     if (fxp_errtype == SSH_FX_OK)
437         return 1;
438     else if (fxp_errtype == SSH_FX_EOF)
439         return 0;
440     else
441         return -1;
442 }
443
444 static void fxp_internal_error(const char *msg)
445 {
446     fxp_error_message = msg;
447     fxp_errtype = -1;
448 }
449
450 const char *fxp_error(void)
451 {
452     return fxp_error_message;
453 }
454
455 int fxp_error_type(void)
456 {
457     return fxp_errtype;
458 }
459
460 /*
461  * Perform exchange of init/version packets. Return 0 on failure.
462  */
463 int fxp_init(void)
464 {
465     struct sftp_packet *pktout, *pktin;
466     unsigned long remotever;
467
468     pktout = sftp_pkt_init(SSH_FXP_INIT);
469     sftp_pkt_adduint32(pktout, SFTP_PROTO_VERSION);
470     sftp_send(pktout);
471
472     pktin = sftp_recv();
473     if (!pktin) {
474         fxp_internal_error("could not connect");
475         return 0;
476     }
477     if (pktin->type != SSH_FXP_VERSION) {
478         fxp_internal_error("did not receive FXP_VERSION");
479         sftp_pkt_free(pktin);
480         return 0;
481     }
482     if (!sftp_pkt_getuint32(pktin, &remotever)) {
483         fxp_internal_error("malformed FXP_VERSION packet");
484         sftp_pkt_free(pktin);
485         return 0;
486     }
487     if (remotever > SFTP_PROTO_VERSION) {
488         fxp_internal_error
489             ("remote protocol is more advanced than we support");
490         sftp_pkt_free(pktin);
491         return 0;
492     }
493     /*
494      * In principle, this packet might also contain extension-
495      * string pairs. We should work through them and look for any
496      * we recognise. In practice we don't currently do so because
497      * we know we don't recognise _any_.
498      */
499     sftp_pkt_free(pktin);
500
501     return 1;
502 }
503
504 /*
505  * Canonify a pathname.
506  */
507 struct sftp_request *fxp_realpath_send(const char *path)
508 {
509     struct sftp_request *req = sftp_alloc_request();
510     struct sftp_packet *pktout;
511
512     pktout = sftp_pkt_init(SSH_FXP_REALPATH);
513     sftp_pkt_adduint32(pktout, req->id);
514     sftp_pkt_addstring_start(pktout);
515     sftp_pkt_addstring_str(pktout, path);
516     sftp_send(pktout);
517
518     return req;
519 }
520
521 char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req)
522 {
523     sfree(req);
524
525     if (pktin->type == SSH_FXP_NAME) {
526         unsigned long count;
527         char *path;
528         int len;
529
530         if (!sftp_pkt_getuint32(pktin, &count) || count != 1) {
531             fxp_internal_error("REALPATH did not return name count of 1\n");
532             sftp_pkt_free(pktin);
533             return NULL;
534         }
535         if (!sftp_pkt_getstring(pktin, &path, &len)) {
536             fxp_internal_error("REALPATH returned malformed FXP_NAME\n");
537             sftp_pkt_free(pktin);
538             return NULL;
539         }
540         path = mkstr(path, len);
541         sftp_pkt_free(pktin);
542         return path;
543     } else {
544         fxp_got_status(pktin);
545         sftp_pkt_free(pktin);
546         return NULL;
547     }
548 }
549
550 /*
551  * Open a file.
552  */
553 struct sftp_request *fxp_open_send(const char *path, int type,
554                                    struct fxp_attrs *attrs)
555 {
556     struct sftp_request *req = sftp_alloc_request();
557     struct sftp_packet *pktout;
558
559     pktout = sftp_pkt_init(SSH_FXP_OPEN);
560     sftp_pkt_adduint32(pktout, req->id);
561     sftp_pkt_addstring(pktout, path);
562     sftp_pkt_adduint32(pktout, type);
563     if (attrs)
564         sftp_pkt_addattrs(pktout, *attrs);
565     else
566         sftp_pkt_adduint32(pktout, 0); /* empty ATTRS structure */
567     sftp_send(pktout);
568
569     return req;
570 }
571
572 struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin,
573                                  struct sftp_request *req)
574 {
575     sfree(req);
576
577     if (pktin->type == SSH_FXP_HANDLE) {
578         char *hstring;
579         struct fxp_handle *handle;
580         int len;
581
582         if (!sftp_pkt_getstring(pktin, &hstring, &len)) {
583             fxp_internal_error("OPEN returned malformed FXP_HANDLE\n");
584             sftp_pkt_free(pktin);
585             return NULL;
586         }
587         handle = snew(struct fxp_handle);
588         handle->hstring = mkstr(hstring, len);
589         handle->hlen = len;
590         sftp_pkt_free(pktin);
591         return handle;
592     } else {
593         fxp_got_status(pktin);
594         sftp_pkt_free(pktin);
595         return NULL;
596     }
597 }
598
599 /*
600  * Open a directory.
601  */
602 struct sftp_request *fxp_opendir_send(const char *path)
603 {
604     struct sftp_request *req = sftp_alloc_request();
605     struct sftp_packet *pktout;
606
607     pktout = sftp_pkt_init(SSH_FXP_OPENDIR);
608     sftp_pkt_adduint32(pktout, req->id);
609     sftp_pkt_addstring(pktout, path);
610     sftp_send(pktout);
611
612     return req;
613 }
614
615 struct fxp_handle *fxp_opendir_recv(struct sftp_packet *pktin,
616                                     struct sftp_request *req)
617 {
618     sfree(req);
619     if (pktin->type == SSH_FXP_HANDLE) {
620         char *hstring;
621         struct fxp_handle *handle;
622         int len;
623
624         if (!sftp_pkt_getstring(pktin, &hstring, &len)) {
625             fxp_internal_error("OPENDIR returned malformed FXP_HANDLE\n");
626             sftp_pkt_free(pktin);
627             return NULL;
628         }
629         handle = snew(struct fxp_handle);
630         handle->hstring = mkstr(hstring, len);
631         handle->hlen = len;
632         sftp_pkt_free(pktin);
633         return handle;
634     } else {
635         fxp_got_status(pktin);
636         sftp_pkt_free(pktin);
637         return NULL;
638     }
639 }
640
641 /*
642  * Close a file/dir.
643  */
644 struct sftp_request *fxp_close_send(struct fxp_handle *handle)
645 {
646     struct sftp_request *req = sftp_alloc_request();
647     struct sftp_packet *pktout;
648
649     pktout = sftp_pkt_init(SSH_FXP_CLOSE);
650     sftp_pkt_adduint32(pktout, req->id);
651     sftp_pkt_addstring_start(pktout);
652     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
653     sftp_send(pktout);
654
655     sfree(handle->hstring);
656     sfree(handle);
657
658     return req;
659 }
660
661 int fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req)
662 {
663     sfree(req);
664     fxp_got_status(pktin);
665     sftp_pkt_free(pktin);
666     return fxp_errtype == SSH_FX_OK;
667 }
668
669 struct sftp_request *fxp_mkdir_send(const char *path)
670 {
671     struct sftp_request *req = sftp_alloc_request();
672     struct sftp_packet *pktout;
673
674     pktout = sftp_pkt_init(SSH_FXP_MKDIR);
675     sftp_pkt_adduint32(pktout, req->id);
676     sftp_pkt_addstring(pktout, path);
677     sftp_pkt_adduint32(pktout, 0);     /* (FIXME) empty ATTRS structure */
678     sftp_send(pktout);
679
680     return req;
681 }
682
683 int fxp_mkdir_recv(struct sftp_packet *pktin, struct sftp_request *req)
684 {
685     int id;
686     sfree(req);
687     id = fxp_got_status(pktin);
688     sftp_pkt_free(pktin);
689     if (id != 1) {
690         return 0;
691     }
692     return 1;
693 }
694
695 struct sftp_request *fxp_rmdir_send(const char *path)
696 {
697     struct sftp_request *req = sftp_alloc_request();
698     struct sftp_packet *pktout;
699
700     pktout = sftp_pkt_init(SSH_FXP_RMDIR);
701     sftp_pkt_adduint32(pktout, req->id);
702     sftp_pkt_addstring(pktout, path);
703     sftp_send(pktout);
704
705     return req;
706 }
707
708 int fxp_rmdir_recv(struct sftp_packet *pktin, struct sftp_request *req)
709 {
710     int id;
711     sfree(req);
712     id = fxp_got_status(pktin);
713     sftp_pkt_free(pktin);
714     if (id != 1) {
715         return 0;
716     }
717     return 1;
718 }
719
720 struct sftp_request *fxp_remove_send(const char *fname)
721 {
722     struct sftp_request *req = sftp_alloc_request();
723     struct sftp_packet *pktout;
724
725     pktout = sftp_pkt_init(SSH_FXP_REMOVE);
726     sftp_pkt_adduint32(pktout, req->id);
727     sftp_pkt_addstring(pktout, fname);
728     sftp_send(pktout);
729
730     return req;
731 }
732
733 int fxp_remove_recv(struct sftp_packet *pktin, struct sftp_request *req)
734 {
735     int id;
736     sfree(req);
737     id = fxp_got_status(pktin);
738     sftp_pkt_free(pktin);
739     if (id != 1) {
740         return 0;
741     }
742     return 1;
743 }
744
745 struct sftp_request *fxp_rename_send(const char *srcfname,
746                                      const char *dstfname)
747 {
748     struct sftp_request *req = sftp_alloc_request();
749     struct sftp_packet *pktout;
750
751     pktout = sftp_pkt_init(SSH_FXP_RENAME);
752     sftp_pkt_adduint32(pktout, req->id);
753     sftp_pkt_addstring(pktout, srcfname);
754     sftp_pkt_addstring(pktout, dstfname);
755     sftp_send(pktout);
756
757     return req;
758 }
759
760 int fxp_rename_recv(struct sftp_packet *pktin, struct sftp_request *req)
761 {
762     int id;
763     sfree(req);
764     id = fxp_got_status(pktin);
765     sftp_pkt_free(pktin);
766     if (id != 1) {
767         return 0;
768     }
769     return 1;
770 }
771
772 /*
773  * Retrieve the attributes of a file. We have fxp_stat which works
774  * on filenames, and fxp_fstat which works on open file handles.
775  */
776 struct sftp_request *fxp_stat_send(const char *fname)
777 {
778     struct sftp_request *req = sftp_alloc_request();
779     struct sftp_packet *pktout;
780
781     pktout = sftp_pkt_init(SSH_FXP_STAT);
782     sftp_pkt_adduint32(pktout, req->id);
783     sftp_pkt_addstring(pktout, fname);
784     sftp_send(pktout);
785
786     return req;
787 }
788
789 int fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req,
790                   struct fxp_attrs *attrs)
791 {
792     sfree(req);
793     if (pktin->type == SSH_FXP_ATTRS) {
794         if (!sftp_pkt_getattrs(pktin, attrs)) {
795             fxp_internal_error("malformed SSH_FXP_ATTRS packet");
796             sftp_pkt_free(pktin);
797             return 0;
798         }
799         sftp_pkt_free(pktin);
800         return 1;
801     } else {
802         fxp_got_status(pktin);
803         sftp_pkt_free(pktin);
804         return 0;
805     }
806 }
807
808 struct sftp_request *fxp_fstat_send(struct fxp_handle *handle)
809 {
810     struct sftp_request *req = sftp_alloc_request();
811     struct sftp_packet *pktout;
812
813     pktout = sftp_pkt_init(SSH_FXP_FSTAT);
814     sftp_pkt_adduint32(pktout, req->id);
815     sftp_pkt_addstring_start(pktout);
816     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
817     sftp_send(pktout);
818
819     return req;
820 }
821
822 int fxp_fstat_recv(struct sftp_packet *pktin, struct sftp_request *req,
823                    struct fxp_attrs *attrs)
824 {
825     sfree(req);
826     if (pktin->type == SSH_FXP_ATTRS) {
827         if (!sftp_pkt_getattrs(pktin, attrs)) {
828             fxp_internal_error("malformed SSH_FXP_ATTRS packet");
829             sftp_pkt_free(pktin);
830             return 0;
831         }
832         sftp_pkt_free(pktin);
833         return 1;
834     } else {
835         fxp_got_status(pktin);
836         sftp_pkt_free(pktin);
837         return 0;
838     }
839 }
840
841 /*
842  * Set the attributes of a file.
843  */
844 struct sftp_request *fxp_setstat_send(const char *fname,
845                                       struct fxp_attrs attrs)
846 {
847     struct sftp_request *req = sftp_alloc_request();
848     struct sftp_packet *pktout;
849
850     pktout = sftp_pkt_init(SSH_FXP_SETSTAT);
851     sftp_pkt_adduint32(pktout, req->id);
852     sftp_pkt_addstring(pktout, fname);
853     sftp_pkt_addattrs(pktout, attrs);
854     sftp_send(pktout);
855
856     return req;
857 }
858
859 int fxp_setstat_recv(struct sftp_packet *pktin, struct sftp_request *req)
860 {
861     int id;
862     sfree(req);
863     id = fxp_got_status(pktin);
864     sftp_pkt_free(pktin);
865     if (id != 1) {
866         return 0;
867     }
868     return 1;
869 }
870
871 struct sftp_request *fxp_fsetstat_send(struct fxp_handle *handle,
872                                        struct fxp_attrs attrs)
873 {
874     struct sftp_request *req = sftp_alloc_request();
875     struct sftp_packet *pktout;
876
877     pktout = sftp_pkt_init(SSH_FXP_FSETSTAT);
878     sftp_pkt_adduint32(pktout, req->id);
879     sftp_pkt_addstring_start(pktout);
880     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
881     sftp_pkt_addattrs(pktout, attrs);
882     sftp_send(pktout);
883
884     return req;
885 }
886
887 int fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req)
888 {
889     int id;
890     sfree(req);
891     id = fxp_got_status(pktin);
892     sftp_pkt_free(pktin);
893     if (id != 1) {
894         return 0;
895     }
896     return 1;
897 }
898
899 /*
900  * Read from a file. Returns the number of bytes read, or -1 on an
901  * error, or possibly 0 if EOF. (I'm not entirely sure whether it
902  * will return 0 on EOF, or return -1 and store SSH_FX_EOF in the
903  * error indicator. It might even depend on the SFTP server.)
904  */
905 struct sftp_request *fxp_read_send(struct fxp_handle *handle,
906                                    uint64 offset, int len)
907 {
908     struct sftp_request *req = sftp_alloc_request();
909     struct sftp_packet *pktout;
910
911     pktout = sftp_pkt_init(SSH_FXP_READ);
912     sftp_pkt_adduint32(pktout, req->id);
913     sftp_pkt_addstring_start(pktout);
914     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
915     sftp_pkt_adduint64(pktout, offset);
916     sftp_pkt_adduint32(pktout, len);
917     sftp_send(pktout);
918
919     return req;
920 }
921
922 int fxp_read_recv(struct sftp_packet *pktin, struct sftp_request *req,
923                   char *buffer, int len)
924 {
925     sfree(req);
926     if (pktin->type == SSH_FXP_DATA) {
927         char *str;
928         int rlen;
929
930         if (!sftp_pkt_getstring(pktin, &str, &rlen)) {
931             fxp_internal_error("READ returned malformed SSH_FXP_DATA packet");
932             sftp_pkt_free(pktin);
933             return -1;
934         }
935
936         if (rlen > len || rlen < 0) {
937             fxp_internal_error("READ returned more bytes than requested");
938             sftp_pkt_free(pktin);
939             return -1;
940         }
941
942         memcpy(buffer, str, rlen);
943         sftp_pkt_free(pktin);
944         return rlen;
945     } else {
946         fxp_got_status(pktin);
947         sftp_pkt_free(pktin);
948         return -1;
949     }
950 }
951
952 /*
953  * Read from a directory.
954  */
955 struct sftp_request *fxp_readdir_send(struct fxp_handle *handle)
956 {
957     struct sftp_request *req = sftp_alloc_request();
958     struct sftp_packet *pktout;
959
960     pktout = sftp_pkt_init(SSH_FXP_READDIR);
961     sftp_pkt_adduint32(pktout, req->id);
962     sftp_pkt_addstring_start(pktout);
963     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
964     sftp_send(pktout);
965
966     return req;
967 }
968
969 struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin,
970                                    struct sftp_request *req)
971 {
972     sfree(req);
973     if (pktin->type == SSH_FXP_NAME) {
974         struct fxp_names *ret;
975         unsigned long i;
976
977         /*
978          * Sanity-check the number of names. Minimum is obviously
979          * zero. Maximum is the remaining space in the packet
980          * divided by the very minimum length of a name, which is
981          * 12 bytes (4 for an empty filename, 4 for an empty
982          * longname, 4 for a set of attribute flags indicating that
983          * no other attributes are supplied).
984          */
985         if (!sftp_pkt_getuint32(pktin, &i) ||
986             i > (pktin->length-pktin->savedpos)/12) {
987             fxp_internal_error("malformed FXP_NAME packet");
988             sftp_pkt_free(pktin);
989             return NULL;
990         }
991
992         /*
993          * Ensure the implicit multiplication in the snewn() call
994          * doesn't suffer integer overflow and cause us to malloc
995          * too little space.
996          */
997         if (i > INT_MAX / sizeof(struct fxp_name)) {
998             fxp_internal_error("unreasonably large FXP_NAME packet");
999             sftp_pkt_free(pktin);
1000             return NULL;
1001         }
1002
1003         ret = snew(struct fxp_names);
1004         ret->nnames = i;
1005         ret->names = snewn(ret->nnames, struct fxp_name);
1006         for (i = 0; i < (unsigned long)ret->nnames; i++) {
1007             char *str1, *str2;
1008             int len1, len2;
1009             if (!sftp_pkt_getstring(pktin, &str1, &len1) ||
1010                 !sftp_pkt_getstring(pktin, &str2, &len2) ||
1011                 !sftp_pkt_getattrs(pktin, &ret->names[i].attrs)) {
1012                 fxp_internal_error("malformed FXP_NAME packet");
1013                 while (i--) {
1014                     sfree(ret->names[i].filename);
1015                     sfree(ret->names[i].longname);
1016                 }
1017                 sfree(ret->names);
1018                 sfree(ret);
1019                 sfree(pktin);
1020                 return NULL;
1021             }
1022             ret->names[i].filename = mkstr(str1, len1);
1023             ret->names[i].longname = mkstr(str2, len2);
1024         }
1025         sftp_pkt_free(pktin);
1026         return ret;
1027     } else {
1028         fxp_got_status(pktin);
1029         sftp_pkt_free(pktin);
1030         return NULL;
1031     }
1032 }
1033
1034 /*
1035  * Write to a file. Returns 0 on error, 1 on OK.
1036  */
1037 struct sftp_request *fxp_write_send(struct fxp_handle *handle,
1038                                     char *buffer, uint64 offset, int len)
1039 {
1040     struct sftp_request *req = sftp_alloc_request();
1041     struct sftp_packet *pktout;
1042
1043     pktout = sftp_pkt_init(SSH_FXP_WRITE);
1044     sftp_pkt_adduint32(pktout, req->id);
1045     sftp_pkt_addstring_start(pktout);
1046     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
1047     sftp_pkt_adduint64(pktout, offset);
1048     sftp_pkt_addstring_start(pktout);
1049     sftp_pkt_addstring_data(pktout, buffer, len);
1050     sftp_send(pktout);
1051
1052     return req;
1053 }
1054
1055 int fxp_write_recv(struct sftp_packet *pktin, struct sftp_request *req)
1056 {
1057     sfree(req);
1058     fxp_got_status(pktin);
1059     sftp_pkt_free(pktin);
1060     return fxp_errtype == SSH_FX_OK;
1061 }
1062
1063 /*
1064  * Free up an fxp_names structure.
1065  */
1066 void fxp_free_names(struct fxp_names *names)
1067 {
1068     int i;
1069
1070     for (i = 0; i < names->nnames; i++) {
1071         sfree(names->names[i].filename);
1072         sfree(names->names[i].longname);
1073     }
1074     sfree(names->names);
1075     sfree(names);
1076 }
1077
1078 /*
1079  * Duplicate an fxp_name structure.
1080  */
1081 struct fxp_name *fxp_dup_name(struct fxp_name *name)
1082 {
1083     struct fxp_name *ret;
1084     ret = snew(struct fxp_name);
1085     ret->filename = dupstr(name->filename);
1086     ret->longname = dupstr(name->longname);
1087     ret->attrs = name->attrs;          /* structure copy */
1088     return ret;
1089 }
1090
1091 /*
1092  * Free up an fxp_name structure.
1093  */
1094 void fxp_free_name(struct fxp_name *name)
1095 {
1096     sfree(name->filename);
1097     sfree(name->longname);
1098     sfree(name);
1099 }
1100
1101 /*
1102  * Store user data in an sftp_request structure.
1103  */
1104 void *fxp_get_userdata(struct sftp_request *req)
1105 {
1106     return req->userdata;
1107 }
1108
1109 void fxp_set_userdata(struct sftp_request *req, void *data)
1110 {
1111     req->userdata = data;
1112 }
1113
1114 /*
1115  * A wrapper to go round fxp_read_* and fxp_write_*, which manages
1116  * the queueing of multiple read/write requests.
1117  */
1118
1119 struct req {
1120     char *buffer;
1121     int len, retlen, complete;
1122     uint64 offset;
1123     struct req *next, *prev;
1124 };
1125
1126 struct fxp_xfer {
1127     uint64 offset, furthestdata, filesize;
1128     int req_totalsize, req_maxsize, eof, err;
1129     struct fxp_handle *fh;
1130     struct req *head, *tail;
1131 };
1132
1133 static struct fxp_xfer *xfer_init(struct fxp_handle *fh, uint64 offset)
1134 {
1135     struct fxp_xfer *xfer = snew(struct fxp_xfer);
1136
1137     xfer->fh = fh;
1138     xfer->offset = offset;
1139     xfer->head = xfer->tail = NULL;
1140     xfer->req_totalsize = 0;
1141     xfer->req_maxsize = 1048576;
1142     xfer->err = 0;
1143     xfer->filesize = uint64_make(ULONG_MAX, ULONG_MAX);
1144     xfer->furthestdata = uint64_make(0, 0);
1145
1146     return xfer;
1147 }
1148
1149 int xfer_done(struct fxp_xfer *xfer)
1150 {
1151     /*
1152      * We're finished if we've seen EOF _and_ there are no
1153      * outstanding requests.
1154      */
1155     return (xfer->eof || xfer->err) && !xfer->head;
1156 }
1157
1158 void xfer_download_queue(struct fxp_xfer *xfer)
1159 {
1160     while (xfer->req_totalsize < xfer->req_maxsize &&
1161            !xfer->eof && !xfer->err) {
1162         /*
1163          * Queue a new read request.
1164          */
1165         struct req *rr;
1166         struct sftp_request *req;
1167
1168         rr = snew(struct req);
1169         rr->offset = xfer->offset;
1170         rr->complete = 0;
1171         if (xfer->tail) {
1172             xfer->tail->next = rr;
1173             rr->prev = xfer->tail;
1174         } else {
1175             xfer->head = rr;
1176             rr->prev = NULL;
1177         }
1178         xfer->tail = rr;
1179         rr->next = NULL;
1180
1181         rr->len = 32768;
1182         rr->buffer = snewn(rr->len, char);
1183         sftp_register(req = fxp_read_send(xfer->fh, rr->offset, rr->len));
1184         fxp_set_userdata(req, rr);
1185
1186         xfer->offset = uint64_add32(xfer->offset, rr->len);
1187         xfer->req_totalsize += rr->len;
1188
1189 #ifdef DEBUG_DOWNLOAD
1190         { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing read request %p at %s\n", rr, buf); }
1191 #endif
1192     }
1193 }
1194
1195 struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64 offset)
1196 {
1197     struct fxp_xfer *xfer = xfer_init(fh, offset);
1198
1199     xfer->eof = FALSE;
1200     xfer_download_queue(xfer);
1201
1202     return xfer;
1203 }
1204
1205 /*
1206  * Returns INT_MIN to indicate that it didn't even get as far as
1207  * fxp_read_recv and hence has not freed pktin.
1208  */
1209 int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin)
1210 {
1211     struct sftp_request *rreq;
1212     struct req *rr;
1213
1214     rreq = sftp_find_request(pktin);
1215     if (!rreq)
1216         return INT_MIN;            /* this packet doesn't even make sense */
1217     rr = (struct req *)fxp_get_userdata(rreq);
1218     if (!rr) {
1219         fxp_internal_error("request ID is not part of the current download");
1220         return INT_MIN;                /* this packet isn't ours */
1221     }
1222     rr->retlen = fxp_read_recv(pktin, rreq, rr->buffer, rr->len);
1223 #ifdef DEBUG_DOWNLOAD
1224     printf("read request %p has returned [%d]\n", rr, rr->retlen);
1225 #endif
1226
1227     if ((rr->retlen < 0 && fxp_error_type()==SSH_FX_EOF) || rr->retlen == 0) {
1228         xfer->eof = TRUE;
1229         rr->retlen = 0;
1230         rr->complete = -1;
1231 #ifdef DEBUG_DOWNLOAD
1232         printf("setting eof\n");
1233 #endif
1234     } else if (rr->retlen < 0) {
1235         /* some error other than EOF; signal it back to caller */
1236         xfer_set_error(xfer);
1237         rr->complete = -1;
1238         return -1;
1239     }
1240
1241     rr->complete = 1;
1242
1243     /*
1244      * Special case: if we have received fewer bytes than we
1245      * actually read, we should do something. For the moment I'll
1246      * just throw an ersatz FXP error to signal this; the SFTP
1247      * draft I've got says that it can't happen except on special
1248      * files, in which case seeking probably has very little
1249      * meaning and so queueing an additional read request to fill
1250      * up the gap sounds like the wrong answer. I'm not sure what I
1251      * should be doing here - if it _was_ a special file, I suspect
1252      * I simply shouldn't have been queueing multiple requests in
1253      * the first place...
1254      */
1255     if (rr->retlen > 0 && uint64_compare(xfer->furthestdata, rr->offset) < 0) {
1256         xfer->furthestdata = rr->offset;
1257 #ifdef DEBUG_DOWNLOAD
1258         { char buf[40];
1259         uint64_decimal(xfer->furthestdata, buf);
1260         printf("setting furthestdata = %s\n", buf); }
1261 #endif
1262     }
1263
1264     if (rr->retlen < rr->len) {
1265         uint64 filesize = uint64_add32(rr->offset,
1266                                        (rr->retlen < 0 ? 0 : rr->retlen));
1267 #ifdef DEBUG_DOWNLOAD
1268         { char buf[40];
1269         uint64_decimal(filesize, buf);
1270         printf("short block! trying filesize = %s\n", buf); }
1271 #endif
1272         if (uint64_compare(xfer->filesize, filesize) > 0) {
1273             xfer->filesize = filesize;
1274 #ifdef DEBUG_DOWNLOAD
1275             printf("actually changing filesize\n");
1276 #endif      
1277         }
1278     }
1279
1280     if (uint64_compare(xfer->furthestdata, xfer->filesize) > 0) {
1281         fxp_error_message = "received a short buffer from FXP_READ, but not"
1282             " at EOF";
1283         fxp_errtype = -1;
1284         xfer_set_error(xfer);
1285         return -1;
1286     }
1287
1288     return 1;
1289 }
1290
1291 void xfer_set_error(struct fxp_xfer *xfer)
1292 {
1293     xfer->err = 1;
1294 }
1295
1296 int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len)
1297 {
1298     void *retbuf = NULL;
1299     int retlen = 0;
1300
1301     /*
1302      * Discard anything at the head of the rr queue with complete <
1303      * 0; return the first thing with complete > 0.
1304      */
1305     while (xfer->head && xfer->head->complete && !retbuf) {
1306         struct req *rr = xfer->head;
1307
1308         if (rr->complete > 0) {
1309             retbuf = rr->buffer;
1310             retlen = rr->retlen;
1311 #ifdef DEBUG_DOWNLOAD
1312             printf("handing back data from read request %p\n", rr);
1313 #endif
1314         }
1315 #ifdef DEBUG_DOWNLOAD
1316         else
1317             printf("skipping failed read request %p\n", rr);
1318 #endif
1319
1320         xfer->head = xfer->head->next;
1321         if (xfer->head)
1322             xfer->head->prev = NULL;
1323         else
1324             xfer->tail = NULL;
1325         xfer->req_totalsize -= rr->len;
1326         sfree(rr);
1327     }
1328
1329     if (retbuf) {
1330         *buf = retbuf;
1331         *len = retlen;
1332         return 1;
1333     } else
1334         return 0;
1335 }
1336
1337 struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64 offset)
1338 {
1339     struct fxp_xfer *xfer = xfer_init(fh, offset);
1340
1341     /*
1342      * We set `eof' to 1 because this will cause xfer_done() to
1343      * return true iff there are no outstanding requests. During an
1344      * upload, our caller will be responsible for working out
1345      * whether all the data has been sent, so all it needs to know
1346      * from us is whether the outstanding requests have been
1347      * handled once that's done.
1348      */
1349     xfer->eof = 1;
1350
1351     return xfer;
1352 }
1353
1354 int xfer_upload_ready(struct fxp_xfer *xfer)
1355 {
1356     if (sftp_sendbuffer() == 0)
1357         return 1;
1358     else
1359         return 0;
1360 }
1361
1362 void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len)
1363 {
1364     struct req *rr;
1365     struct sftp_request *req;
1366
1367     rr = snew(struct req);
1368     rr->offset = xfer->offset;
1369     rr->complete = 0;
1370     if (xfer->tail) {
1371         xfer->tail->next = rr;
1372         rr->prev = xfer->tail;
1373     } else {
1374         xfer->head = rr;
1375         rr->prev = NULL;
1376     }
1377     xfer->tail = rr;
1378     rr->next = NULL;
1379
1380     rr->len = len;
1381     rr->buffer = NULL;
1382     sftp_register(req = fxp_write_send(xfer->fh, buffer, rr->offset, len));
1383     fxp_set_userdata(req, rr);
1384
1385     xfer->offset = uint64_add32(xfer->offset, rr->len);
1386     xfer->req_totalsize += rr->len;
1387
1388 #ifdef DEBUG_UPLOAD
1389     { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing write request %p at %s [len %d]\n", rr, buf, len); }
1390 #endif
1391 }
1392
1393 /*
1394  * Returns INT_MIN to indicate that it didn't even get as far as
1395  * fxp_write_recv and hence has not freed pktin.
1396  */
1397 int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin)
1398 {
1399     struct sftp_request *rreq;
1400     struct req *rr, *prev, *next;
1401     int ret;
1402
1403     rreq = sftp_find_request(pktin);
1404     if (!rreq)
1405         return INT_MIN;            /* this packet doesn't even make sense */
1406     rr = (struct req *)fxp_get_userdata(rreq);
1407     if (!rr) {
1408         fxp_internal_error("request ID is not part of the current upload");
1409         return INT_MIN;                /* this packet isn't ours */
1410     }
1411     ret = fxp_write_recv(pktin, rreq);
1412 #ifdef DEBUG_UPLOAD
1413     printf("write request %p has returned [%d]\n", rr, ret);
1414 #endif
1415
1416     /*
1417      * Remove this one from the queue.
1418      */
1419     prev = rr->prev;
1420     next = rr->next;
1421     if (prev)
1422         prev->next = next;
1423     else
1424         xfer->head = next;
1425     if (next)
1426         next->prev = prev;
1427     else
1428         xfer->tail = prev;
1429     xfer->req_totalsize -= rr->len;
1430     sfree(rr);
1431
1432     if (!ret)
1433         return -1;
1434
1435     return 1;
1436 }
1437
1438 void xfer_cleanup(struct fxp_xfer *xfer)
1439 {
1440     struct req *rr;
1441     while (xfer->head) {
1442         rr = xfer->head;
1443         xfer->head = xfer->head->next;
1444         sfree(rr->buffer);
1445         sfree(rr);
1446     }
1447     sfree(xfer);
1448 }