Fix a memory leak and greatly reduce the memory allocated when remembering
[dragonfly.git] / crypto / openssh-4 / sftp-server.c
1 /*
2  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include "includes.h"
17 RCSID("$OpenBSD: sftp-server.c,v 1.50 2006/01/02 01:20:31 djm Exp $");
18
19 #include "buffer.h"
20 #include "bufaux.h"
21 #include "getput.h"
22 #include "log.h"
23 #include "xmalloc.h"
24 #include "misc.h"
25
26 #include "sftp.h"
27 #include "sftp-common.h"
28
29 /* helper */
30 #define get_int64()                     buffer_get_int64(&iqueue);
31 #define get_int()                       buffer_get_int(&iqueue);
32 #define get_string(lenp)                buffer_get_string(&iqueue, lenp);
33 #define TRACE                           debug
34
35 extern char *__progname;
36
37 /* input and output queue */
38 Buffer iqueue;
39 Buffer oqueue;
40
41 /* Version of client */
42 int version;
43
44 /* portable attributes, etc. */
45
46 typedef struct Stat Stat;
47
48 struct Stat {
49         char *name;
50         char *long_name;
51         Attrib attrib;
52 };
53
54 static int
55 errno_to_portable(int unixerrno)
56 {
57         int ret = 0;
58
59         switch (unixerrno) {
60         case 0:
61                 ret = SSH2_FX_OK;
62                 break;
63         case ENOENT:
64         case ENOTDIR:
65         case EBADF:
66         case ELOOP:
67                 ret = SSH2_FX_NO_SUCH_FILE;
68                 break;
69         case EPERM:
70         case EACCES:
71         case EFAULT:
72                 ret = SSH2_FX_PERMISSION_DENIED;
73                 break;
74         case ENAMETOOLONG:
75         case EINVAL:
76                 ret = SSH2_FX_BAD_MESSAGE;
77                 break;
78         default:
79                 ret = SSH2_FX_FAILURE;
80                 break;
81         }
82         return ret;
83 }
84
85 static int
86 flags_from_portable(int pflags)
87 {
88         int flags = 0;
89
90         if ((pflags & SSH2_FXF_READ) &&
91             (pflags & SSH2_FXF_WRITE)) {
92                 flags = O_RDWR;
93         } else if (pflags & SSH2_FXF_READ) {
94                 flags = O_RDONLY;
95         } else if (pflags & SSH2_FXF_WRITE) {
96                 flags = O_WRONLY;
97         }
98         if (pflags & SSH2_FXF_CREAT)
99                 flags |= O_CREAT;
100         if (pflags & SSH2_FXF_TRUNC)
101                 flags |= O_TRUNC;
102         if (pflags & SSH2_FXF_EXCL)
103                 flags |= O_EXCL;
104         return flags;
105 }
106
107 static Attrib *
108 get_attrib(void)
109 {
110         return decode_attrib(&iqueue);
111 }
112
113 /* handle handles */
114
115 typedef struct Handle Handle;
116 struct Handle {
117         int use;
118         DIR *dirp;
119         int fd;
120         char *name;
121 };
122
123 enum {
124         HANDLE_UNUSED,
125         HANDLE_DIR,
126         HANDLE_FILE
127 };
128
129 Handle  handles[100];
130
131 static void
132 handle_init(void)
133 {
134         u_int i;
135
136         for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
137                 handles[i].use = HANDLE_UNUSED;
138 }
139
140 static int
141 handle_new(int use, const char *name, int fd, DIR *dirp)
142 {
143         u_int i;
144
145         for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
146                 if (handles[i].use == HANDLE_UNUSED) {
147                         handles[i].use = use;
148                         handles[i].dirp = dirp;
149                         handles[i].fd = fd;
150                         handles[i].name = xstrdup(name);
151                         return i;
152                 }
153         }
154         return -1;
155 }
156
157 static int
158 handle_is_ok(int i, int type)
159 {
160         return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
161             handles[i].use == type;
162 }
163
164 static int
165 handle_to_string(int handle, char **stringp, int *hlenp)
166 {
167         if (stringp == NULL || hlenp == NULL)
168                 return -1;
169         *stringp = xmalloc(sizeof(int32_t));
170         PUT_32BIT(*stringp, handle);
171         *hlenp = sizeof(int32_t);
172         return 0;
173 }
174
175 static int
176 handle_from_string(const char *handle, u_int hlen)
177 {
178         int val;
179
180         if (hlen != sizeof(int32_t))
181                 return -1;
182         val = GET_32BIT(handle);
183         if (handle_is_ok(val, HANDLE_FILE) ||
184             handle_is_ok(val, HANDLE_DIR))
185                 return val;
186         return -1;
187 }
188
189 static char *
190 handle_to_name(int handle)
191 {
192         if (handle_is_ok(handle, HANDLE_DIR)||
193             handle_is_ok(handle, HANDLE_FILE))
194                 return handles[handle].name;
195         return NULL;
196 }
197
198 static DIR *
199 handle_to_dir(int handle)
200 {
201         if (handle_is_ok(handle, HANDLE_DIR))
202                 return handles[handle].dirp;
203         return NULL;
204 }
205
206 static int
207 handle_to_fd(int handle)
208 {
209         if (handle_is_ok(handle, HANDLE_FILE))
210                 return handles[handle].fd;
211         return -1;
212 }
213
214 static int
215 handle_close(int handle)
216 {
217         int ret = -1;
218
219         if (handle_is_ok(handle, HANDLE_FILE)) {
220                 ret = close(handles[handle].fd);
221                 handles[handle].use = HANDLE_UNUSED;
222                 xfree(handles[handle].name);
223         } else if (handle_is_ok(handle, HANDLE_DIR)) {
224                 ret = closedir(handles[handle].dirp);
225                 handles[handle].use = HANDLE_UNUSED;
226                 xfree(handles[handle].name);
227         } else {
228                 errno = ENOENT;
229         }
230         return ret;
231 }
232
233 static int
234 get_handle(void)
235 {
236         char *handle;
237         int val = -1;
238         u_int hlen;
239
240         handle = get_string(&hlen);
241         if (hlen < 256)
242                 val = handle_from_string(handle, hlen);
243         xfree(handle);
244         return val;
245 }
246
247 /* send replies */
248
249 static void
250 send_msg(Buffer *m)
251 {
252         int mlen = buffer_len(m);
253
254         buffer_put_int(&oqueue, mlen);
255         buffer_append(&oqueue, buffer_ptr(m), mlen);
256         buffer_consume(m, mlen);
257 }
258
259 static void
260 send_status(u_int32_t id, u_int32_t status)
261 {
262         Buffer msg;
263         const char *status_messages[] = {
264                 "Success",                      /* SSH_FX_OK */
265                 "End of file",                  /* SSH_FX_EOF */
266                 "No such file",                 /* SSH_FX_NO_SUCH_FILE */
267                 "Permission denied",            /* SSH_FX_PERMISSION_DENIED */
268                 "Failure",                      /* SSH_FX_FAILURE */
269                 "Bad message",                  /* SSH_FX_BAD_MESSAGE */
270                 "No connection",                /* SSH_FX_NO_CONNECTION */
271                 "Connection lost",              /* SSH_FX_CONNECTION_LOST */
272                 "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */
273                 "Unknown error"                 /* Others */
274         };
275
276         TRACE("sent status id %u error %u", id, status);
277         buffer_init(&msg);
278         buffer_put_char(&msg, SSH2_FXP_STATUS);
279         buffer_put_int(&msg, id);
280         buffer_put_int(&msg, status);
281         if (version >= 3) {
282                 buffer_put_cstring(&msg,
283                     status_messages[MIN(status,SSH2_FX_MAX)]);
284                 buffer_put_cstring(&msg, "");
285         }
286         send_msg(&msg);
287         buffer_free(&msg);
288 }
289 static void
290 send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
291 {
292         Buffer msg;
293
294         buffer_init(&msg);
295         buffer_put_char(&msg, type);
296         buffer_put_int(&msg, id);
297         buffer_put_string(&msg, data, dlen);
298         send_msg(&msg);
299         buffer_free(&msg);
300 }
301
302 static void
303 send_data(u_int32_t id, const char *data, int dlen)
304 {
305         TRACE("sent data id %u len %d", id, dlen);
306         send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
307 }
308
309 static void
310 send_handle(u_int32_t id, int handle)
311 {
312         char *string;
313         int hlen;
314
315         handle_to_string(handle, &string, &hlen);
316         TRACE("sent handle id %u handle %d", id, handle);
317         send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
318         xfree(string);
319 }
320
321 static void
322 send_names(u_int32_t id, int count, const Stat *stats)
323 {
324         Buffer msg;
325         int i;
326
327         buffer_init(&msg);
328         buffer_put_char(&msg, SSH2_FXP_NAME);
329         buffer_put_int(&msg, id);
330         buffer_put_int(&msg, count);
331         TRACE("sent names id %u count %d", id, count);
332         for (i = 0; i < count; i++) {
333                 buffer_put_cstring(&msg, stats[i].name);
334                 buffer_put_cstring(&msg, stats[i].long_name);
335                 encode_attrib(&msg, &stats[i].attrib);
336         }
337         send_msg(&msg);
338         buffer_free(&msg);
339 }
340
341 static void
342 send_attrib(u_int32_t id, const Attrib *a)
343 {
344         Buffer msg;
345
346         TRACE("sent attrib id %u have 0x%x", id, a->flags);
347         buffer_init(&msg);
348         buffer_put_char(&msg, SSH2_FXP_ATTRS);
349         buffer_put_int(&msg, id);
350         encode_attrib(&msg, a);
351         send_msg(&msg);
352         buffer_free(&msg);
353 }
354
355 /* parse incoming */
356
357 static void
358 process_init(void)
359 {
360         Buffer msg;
361
362         version = get_int();
363         TRACE("client version %d", version);
364         buffer_init(&msg);
365         buffer_put_char(&msg, SSH2_FXP_VERSION);
366         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
367         send_msg(&msg);
368         buffer_free(&msg);
369 }
370
371 static void
372 process_open(void)
373 {
374         u_int32_t id, pflags;
375         Attrib *a;
376         char *name;
377         int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
378
379         id = get_int();
380         name = get_string(NULL);
381         pflags = get_int();             /* portable flags */
382         a = get_attrib();
383         flags = flags_from_portable(pflags);
384         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
385         TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
386         fd = open(name, flags, mode);
387         if (fd < 0) {
388                 status = errno_to_portable(errno);
389         } else {
390                 handle = handle_new(HANDLE_FILE, name, fd, NULL);
391                 if (handle < 0) {
392                         close(fd);
393                 } else {
394                         send_handle(id, handle);
395                         status = SSH2_FX_OK;
396                 }
397         }
398         if (status != SSH2_FX_OK)
399                 send_status(id, status);
400         xfree(name);
401 }
402
403 static void
404 process_close(void)
405 {
406         u_int32_t id;
407         int handle, ret, status = SSH2_FX_FAILURE;
408
409         id = get_int();
410         handle = get_handle();
411         TRACE("close id %u handle %d", id, handle);
412         ret = handle_close(handle);
413         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
414         send_status(id, status);
415 }
416
417 static void
418 process_read(void)
419 {
420         char buf[64*1024];
421         u_int32_t id, len;
422         int handle, fd, ret, status = SSH2_FX_FAILURE;
423         u_int64_t off;
424
425         id = get_int();
426         handle = get_handle();
427         off = get_int64();
428         len = get_int();
429
430         TRACE("read id %u handle %d off %llu len %d", id, handle,
431             (unsigned long long)off, len);
432         if (len > sizeof buf) {
433                 len = sizeof buf;
434                 logit("read change len %d", len);
435         }
436         fd = handle_to_fd(handle);
437         if (fd >= 0) {
438                 if (lseek(fd, off, SEEK_SET) < 0) {
439                         error("process_read: seek failed");
440                         status = errno_to_portable(errno);
441                 } else {
442                         ret = read(fd, buf, len);
443                         if (ret < 0) {
444                                 status = errno_to_portable(errno);
445                         } else if (ret == 0) {
446                                 status = SSH2_FX_EOF;
447                         } else {
448                                 send_data(id, buf, ret);
449                                 status = SSH2_FX_OK;
450                         }
451                 }
452         }
453         if (status != SSH2_FX_OK)
454                 send_status(id, status);
455 }
456
457 static void
458 process_write(void)
459 {
460         u_int32_t id;
461         u_int64_t off;
462         u_int len;
463         int handle, fd, ret, status = SSH2_FX_FAILURE;
464         char *data;
465
466         id = get_int();
467         handle = get_handle();
468         off = get_int64();
469         data = get_string(&len);
470
471         TRACE("write id %u handle %d off %llu len %d", id, handle,
472             (unsigned long long)off, len);
473         fd = handle_to_fd(handle);
474         if (fd >= 0) {
475                 if (lseek(fd, off, SEEK_SET) < 0) {
476                         status = errno_to_portable(errno);
477                         error("process_write: seek failed");
478                 } else {
479 /* XXX ATOMICIO ? */
480                         ret = write(fd, data, len);
481                         if (ret < 0) {
482                                 error("process_write: write failed");
483                                 status = errno_to_portable(errno);
484                         } else if ((size_t)ret == len) {
485                                 status = SSH2_FX_OK;
486                         } else {
487                                 logit("nothing at all written");
488                         }
489                 }
490         }
491         send_status(id, status);
492         xfree(data);
493 }
494
495 static void
496 process_do_stat(int do_lstat)
497 {
498         Attrib a;
499         struct stat st;
500         u_int32_t id;
501         char *name;
502         int ret, status = SSH2_FX_FAILURE;
503
504         id = get_int();
505         name = get_string(NULL);
506         TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
507         ret = do_lstat ? lstat(name, &st) : stat(name, &st);
508         if (ret < 0) {
509                 status = errno_to_portable(errno);
510         } else {
511                 stat_to_attrib(&st, &a);
512                 send_attrib(id, &a);
513                 status = SSH2_FX_OK;
514         }
515         if (status != SSH2_FX_OK)
516                 send_status(id, status);
517         xfree(name);
518 }
519
520 static void
521 process_stat(void)
522 {
523         process_do_stat(0);
524 }
525
526 static void
527 process_lstat(void)
528 {
529         process_do_stat(1);
530 }
531
532 static void
533 process_fstat(void)
534 {
535         Attrib a;
536         struct stat st;
537         u_int32_t id;
538         int fd, ret, handle, status = SSH2_FX_FAILURE;
539
540         id = get_int();
541         handle = get_handle();
542         TRACE("fstat id %u handle %d", id, handle);
543         fd = handle_to_fd(handle);
544         if (fd  >= 0) {
545                 ret = fstat(fd, &st);
546                 if (ret < 0) {
547                         status = errno_to_portable(errno);
548                 } else {
549                         stat_to_attrib(&st, &a);
550                         send_attrib(id, &a);
551                         status = SSH2_FX_OK;
552                 }
553         }
554         if (status != SSH2_FX_OK)
555                 send_status(id, status);
556 }
557
558 static struct timeval *
559 attrib_to_tv(const Attrib *a)
560 {
561         static struct timeval tv[2];
562
563         tv[0].tv_sec = a->atime;
564         tv[0].tv_usec = 0;
565         tv[1].tv_sec = a->mtime;
566         tv[1].tv_usec = 0;
567         return tv;
568 }
569
570 static void
571 process_setstat(void)
572 {
573         Attrib *a;
574         u_int32_t id;
575         char *name;
576         int status = SSH2_FX_OK, ret;
577
578         id = get_int();
579         name = get_string(NULL);
580         a = get_attrib();
581         TRACE("setstat id %u name %s", id, name);
582         if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
583                 ret = truncate(name, a->size);
584                 if (ret == -1)
585                         status = errno_to_portable(errno);
586         }
587         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
588                 ret = chmod(name, a->perm & 0777);
589                 if (ret == -1)
590                         status = errno_to_portable(errno);
591         }
592         if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
593                 ret = utimes(name, attrib_to_tv(a));
594                 if (ret == -1)
595                         status = errno_to_portable(errno);
596         }
597         if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
598                 ret = chown(name, a->uid, a->gid);
599                 if (ret == -1)
600                         status = errno_to_portable(errno);
601         }
602         send_status(id, status);
603         xfree(name);
604 }
605
606 static void
607 process_fsetstat(void)
608 {
609         Attrib *a;
610         u_int32_t id;
611         int handle, fd, ret;
612         int status = SSH2_FX_OK;
613         char *name;
614
615         id = get_int();
616         handle = get_handle();
617         a = get_attrib();
618         TRACE("fsetstat id %u handle %d", id, handle);
619         fd = handle_to_fd(handle);
620         name = handle_to_name(handle);
621         if (fd < 0 || name == NULL) {
622                 status = SSH2_FX_FAILURE;
623         } else {
624                 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
625                         ret = ftruncate(fd, a->size);
626                         if (ret == -1)
627                                 status = errno_to_portable(errno);
628                 }
629                 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
630 #ifdef HAVE_FCHMOD
631                         ret = fchmod(fd, a->perm & 0777);
632 #else
633                         ret = chmod(name, a->perm & 0777);
634 #endif
635                         if (ret == -1)
636                                 status = errno_to_portable(errno);
637                 }
638                 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
639 #ifdef HAVE_FUTIMES
640                         ret = futimes(fd, attrib_to_tv(a));
641 #else
642                         ret = utimes(name, attrib_to_tv(a));
643 #endif
644                         if (ret == -1)
645                                 status = errno_to_portable(errno);
646                 }
647                 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
648 #ifdef HAVE_FCHOWN
649                         ret = fchown(fd, a->uid, a->gid);
650 #else
651                         ret = chown(name, a->uid, a->gid);
652 #endif
653                         if (ret == -1)
654                                 status = errno_to_portable(errno);
655                 }
656         }
657         send_status(id, status);
658 }
659
660 static void
661 process_opendir(void)
662 {
663         DIR *dirp = NULL;
664         char *path;
665         int handle, status = SSH2_FX_FAILURE;
666         u_int32_t id;
667
668         id = get_int();
669         path = get_string(NULL);
670         TRACE("opendir id %u path %s", id, path);
671         dirp = opendir(path);
672         if (dirp == NULL) {
673                 status = errno_to_portable(errno);
674         } else {
675                 handle = handle_new(HANDLE_DIR, path, 0, dirp);
676                 if (handle < 0) {
677                         closedir(dirp);
678                 } else {
679                         send_handle(id, handle);
680                         status = SSH2_FX_OK;
681                 }
682
683         }
684         if (status != SSH2_FX_OK)
685                 send_status(id, status);
686         xfree(path);
687 }
688
689 static void
690 process_readdir(void)
691 {
692         DIR *dirp;
693         struct dirent *dp;
694         char *path;
695         int handle;
696         u_int32_t id;
697
698         id = get_int();
699         handle = get_handle();
700         TRACE("readdir id %u handle %d", id, handle);
701         dirp = handle_to_dir(handle);
702         path = handle_to_name(handle);
703         if (dirp == NULL || path == NULL) {
704                 send_status(id, SSH2_FX_FAILURE);
705         } else {
706                 struct stat st;
707                 char pathname[1024];
708                 Stat *stats;
709                 int nstats = 10, count = 0, i;
710
711                 stats = xmalloc(nstats * sizeof(Stat));
712                 while ((dp = readdir(dirp)) != NULL) {
713                         if (count >= nstats) {
714                                 nstats *= 2;
715                                 stats = xrealloc(stats, nstats * sizeof(Stat));
716                         }
717 /* XXX OVERFLOW ? */
718                         snprintf(pathname, sizeof pathname, "%s%s%s", path,
719                             strcmp(path, "/") ? "/" : "", dp->d_name);
720                         if (lstat(pathname, &st) < 0)
721                                 continue;
722                         stat_to_attrib(&st, &(stats[count].attrib));
723                         stats[count].name = xstrdup(dp->d_name);
724                         stats[count].long_name = ls_file(dp->d_name, &st, 0);
725                         count++;
726                         /* send up to 100 entries in one message */
727                         /* XXX check packet size instead */
728                         if (count == 100)
729                                 break;
730                 }
731                 if (count > 0) {
732                         send_names(id, count, stats);
733                         for (i = 0; i < count; i++) {
734                                 xfree(stats[i].name);
735                                 xfree(stats[i].long_name);
736                         }
737                 } else {
738                         send_status(id, SSH2_FX_EOF);
739                 }
740                 xfree(stats);
741         }
742 }
743
744 static void
745 process_remove(void)
746 {
747         char *name;
748         u_int32_t id;
749         int status = SSH2_FX_FAILURE;
750         int ret;
751
752         id = get_int();
753         name = get_string(NULL);
754         TRACE("remove id %u name %s", id, name);
755         ret = unlink(name);
756         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
757         send_status(id, status);
758         xfree(name);
759 }
760
761 static void
762 process_mkdir(void)
763 {
764         Attrib *a;
765         u_int32_t id;
766         char *name;
767         int ret, mode, status = SSH2_FX_FAILURE;
768
769         id = get_int();
770         name = get_string(NULL);
771         a = get_attrib();
772         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
773             a->perm & 0777 : 0777;
774         TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
775         ret = mkdir(name, mode);
776         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
777         send_status(id, status);
778         xfree(name);
779 }
780
781 static void
782 process_rmdir(void)
783 {
784         u_int32_t id;
785         char *name;
786         int ret, status;
787
788         id = get_int();
789         name = get_string(NULL);
790         TRACE("rmdir id %u name %s", id, name);
791         ret = rmdir(name);
792         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
793         send_status(id, status);
794         xfree(name);
795 }
796
797 static void
798 process_realpath(void)
799 {
800         char resolvedname[MAXPATHLEN];
801         u_int32_t id;
802         char *path;
803
804         id = get_int();
805         path = get_string(NULL);
806         if (path[0] == '\0') {
807                 xfree(path);
808                 path = xstrdup(".");
809         }
810         TRACE("realpath id %u path %s", id, path);
811         if (realpath(path, resolvedname) == NULL) {
812                 send_status(id, errno_to_portable(errno));
813         } else {
814                 Stat s;
815                 attrib_clear(&s.attrib);
816                 s.name = s.long_name = resolvedname;
817                 send_names(id, 1, &s);
818         }
819         xfree(path);
820 }
821
822 static void
823 process_rename(void)
824 {
825         u_int32_t id;
826         char *oldpath, *newpath;
827         int status;
828         struct stat sb;
829
830         id = get_int();
831         oldpath = get_string(NULL);
832         newpath = get_string(NULL);
833         TRACE("rename id %u old %s new %s", id, oldpath, newpath);
834         status = SSH2_FX_FAILURE;
835         if (lstat(oldpath, &sb) == -1)
836                 status = errno_to_portable(errno);
837         else if (S_ISREG(sb.st_mode)) {
838                 /* Race-free rename of regular files */
839                 if (link(oldpath, newpath) == -1) {
840                         if (errno == EOPNOTSUPP
841 #ifdef LINK_OPNOTSUPP_ERRNO
842                             || errno == LINK_OPNOTSUPP_ERRNO
843 #endif
844                             ) {
845                                 struct stat st;
846
847                                 /*
848                                  * fs doesn't support links, so fall back to
849                                  * stat+rename.  This is racy.
850                                  */
851                                 if (stat(newpath, &st) == -1) {
852                                         if (rename(oldpath, newpath) == -1)
853                                                 status =
854                                                     errno_to_portable(errno);
855                                         else
856                                                 status = SSH2_FX_OK;
857                                 }
858                         } else {
859                                 status = errno_to_portable(errno);
860                         }
861                 } else if (unlink(oldpath) == -1) {
862                         status = errno_to_portable(errno);
863                         /* clean spare link */
864                         unlink(newpath);
865                 } else
866                         status = SSH2_FX_OK;
867         } else if (stat(newpath, &sb) == -1) {
868                 if (rename(oldpath, newpath) == -1)
869                         status = errno_to_portable(errno);
870                 else
871                         status = SSH2_FX_OK;
872         }
873         send_status(id, status);
874         xfree(oldpath);
875         xfree(newpath);
876 }
877
878 static void
879 process_readlink(void)
880 {
881         u_int32_t id;
882         int len;
883         char buf[MAXPATHLEN];
884         char *path;
885
886         id = get_int();
887         path = get_string(NULL);
888         TRACE("readlink id %u path %s", id, path);
889         if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
890                 send_status(id, errno_to_portable(errno));
891         else {
892                 Stat s;
893
894                 buf[len] = '\0';
895                 attrib_clear(&s.attrib);
896                 s.name = s.long_name = buf;
897                 send_names(id, 1, &s);
898         }
899         xfree(path);
900 }
901
902 static void
903 process_symlink(void)
904 {
905         u_int32_t id;
906         char *oldpath, *newpath;
907         int ret, status;
908
909         id = get_int();
910         oldpath = get_string(NULL);
911         newpath = get_string(NULL);
912         TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
913         /* this will fail if 'newpath' exists */
914         ret = symlink(oldpath, newpath);
915         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
916         send_status(id, status);
917         xfree(oldpath);
918         xfree(newpath);
919 }
920
921 static void
922 process_extended(void)
923 {
924         u_int32_t id;
925         char *request;
926
927         id = get_int();
928         request = get_string(NULL);
929         send_status(id, SSH2_FX_OP_UNSUPPORTED);                /* MUST */
930         xfree(request);
931 }
932
933 /* stolen from ssh-agent */
934
935 static void
936 process(void)
937 {
938         u_int msg_len;
939         u_int buf_len;
940         u_int consumed;
941         u_int type;
942         u_char *cp;
943
944         buf_len = buffer_len(&iqueue);
945         if (buf_len < 5)
946                 return;         /* Incomplete message. */
947         cp = buffer_ptr(&iqueue);
948         msg_len = GET_32BIT(cp);
949         if (msg_len > SFTP_MAX_MSG_LENGTH) {
950                 error("bad message ");
951                 exit(11);
952         }
953         if (buf_len < msg_len + 4)
954                 return;
955         buffer_consume(&iqueue, 4);
956         buf_len -= 4;
957         type = buffer_get_char(&iqueue);
958         switch (type) {
959         case SSH2_FXP_INIT:
960                 process_init();
961                 break;
962         case SSH2_FXP_OPEN:
963                 process_open();
964                 break;
965         case SSH2_FXP_CLOSE:
966                 process_close();
967                 break;
968         case SSH2_FXP_READ:
969                 process_read();
970                 break;
971         case SSH2_FXP_WRITE:
972                 process_write();
973                 break;
974         case SSH2_FXP_LSTAT:
975                 process_lstat();
976                 break;
977         case SSH2_FXP_FSTAT:
978                 process_fstat();
979                 break;
980         case SSH2_FXP_SETSTAT:
981                 process_setstat();
982                 break;
983         case SSH2_FXP_FSETSTAT:
984                 process_fsetstat();
985                 break;
986         case SSH2_FXP_OPENDIR:
987                 process_opendir();
988                 break;
989         case SSH2_FXP_READDIR:
990                 process_readdir();
991                 break;
992         case SSH2_FXP_REMOVE:
993                 process_remove();
994                 break;
995         case SSH2_FXP_MKDIR:
996                 process_mkdir();
997                 break;
998         case SSH2_FXP_RMDIR:
999                 process_rmdir();
1000                 break;
1001         case SSH2_FXP_REALPATH:
1002                 process_realpath();
1003                 break;
1004         case SSH2_FXP_STAT:
1005                 process_stat();
1006                 break;
1007         case SSH2_FXP_RENAME:
1008                 process_rename();
1009                 break;
1010         case SSH2_FXP_READLINK:
1011                 process_readlink();
1012                 break;
1013         case SSH2_FXP_SYMLINK:
1014                 process_symlink();
1015                 break;
1016         case SSH2_FXP_EXTENDED:
1017                 process_extended();
1018                 break;
1019         default:
1020                 error("Unknown message %d", type);
1021                 break;
1022         }
1023         /* discard the remaining bytes from the current packet */
1024         if (buf_len < buffer_len(&iqueue))
1025                 fatal("iqueue grows");
1026         consumed = buf_len - buffer_len(&iqueue);
1027         if (msg_len < consumed)
1028                 fatal("msg_len %d < consumed %d", msg_len, consumed);
1029         if (msg_len > consumed)
1030                 buffer_consume(&iqueue, msg_len - consumed);
1031 }
1032
1033 int
1034 main(int ac, char **av)
1035 {
1036         fd_set *rset, *wset;
1037         int in, out, max;
1038         ssize_t len, olen, set_size;
1039
1040         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1041         sanitise_stdfd();
1042
1043         /* XXX should use getopt */
1044
1045         __progname = ssh_get_progname(av[0]);
1046         handle_init();
1047
1048 #ifdef DEBUG_SFTP_SERVER
1049         log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1050 #endif
1051
1052         in = dup(STDIN_FILENO);
1053         out = dup(STDOUT_FILENO);
1054
1055 #ifdef HAVE_CYGWIN
1056         setmode(in, O_BINARY);
1057         setmode(out, O_BINARY);
1058 #endif
1059
1060         max = 0;
1061         if (in > max)
1062                 max = in;
1063         if (out > max)
1064                 max = out;
1065
1066         buffer_init(&iqueue);
1067         buffer_init(&oqueue);
1068
1069         set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1070         rset = (fd_set *)xmalloc(set_size);
1071         wset = (fd_set *)xmalloc(set_size);
1072
1073         for (;;) {
1074                 memset(rset, 0, set_size);
1075                 memset(wset, 0, set_size);
1076
1077                 FD_SET(in, rset);
1078                 olen = buffer_len(&oqueue);
1079                 if (olen > 0)
1080                         FD_SET(out, wset);
1081
1082                 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1083                         if (errno == EINTR)
1084                                 continue;
1085                         exit(2);
1086                 }
1087
1088                 /* copy stdin to iqueue */
1089                 if (FD_ISSET(in, rset)) {
1090                         char buf[4*4096];
1091                         len = read(in, buf, sizeof buf);
1092                         if (len == 0) {
1093                                 debug("read eof");
1094                                 exit(0);
1095                         } else if (len < 0) {
1096                                 error("read error");
1097                                 exit(1);
1098                         } else {
1099                                 buffer_append(&iqueue, buf, len);
1100                         }
1101                 }
1102                 /* send oqueue to stdout */
1103                 if (FD_ISSET(out, wset)) {
1104                         len = write(out, buffer_ptr(&oqueue), olen);
1105                         if (len < 0) {
1106                                 error("write error");
1107                                 exit(1);
1108                         } else {
1109                                 buffer_consume(&oqueue, len);
1110                         }
1111                 }
1112                 /* process requests from client */
1113                 process();
1114         }
1115 }