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