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