drm/i915: Reduce differences with Linux in i915_gem_fault()
[dragonfly.git] / crypto / openssh / sftp-server.c
1 /* $OpenBSD: sftp-server.c,v 1.103 2014/01/17 06:23:24 dtucker 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 #ifdef HAVE_SYS_MOUNT_H
27 #include <sys/mount.h>
28 #endif
29 #ifdef HAVE_SYS_STATVFS_H
30 #include <sys/statvfs.h>
31 #endif
32 #ifdef HAVE_SYS_PRCTL_H
33 #include <sys/prctl.h>
34 #endif
35
36 #include <dirent.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <pwd.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <pwd.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <stdarg.h>
47
48 #include "xmalloc.h"
49 #include "buffer.h"
50 #include "log.h"
51 #include "misc.h"
52 #include "match.h"
53 #include "uidswap.h"
54
55 #include "sftp.h"
56 #include "sftp-common.h"
57
58 /* helper */
59 #define get_int64()                     buffer_get_int64(&iqueue);
60 #define get_int()                       buffer_get_int(&iqueue);
61 #define get_string(lenp)                buffer_get_string(&iqueue, lenp);
62
63 /* Our verbosity */
64 static LogLevel log_level = SYSLOG_LEVEL_ERROR;
65
66 /* Our client */
67 static struct passwd *pw = NULL;
68 static char *client_addr = NULL;
69
70 /* input and output queue */
71 static Buffer iqueue;
72 static Buffer oqueue;
73
74 /* Version of client */
75 static u_int version;
76
77 /* SSH2_FXP_INIT received */
78 static int init_done;
79
80 /* Disable writes */
81 static int readonly;
82
83 /* Requests that are allowed/denied */
84 static char *request_whitelist, *request_blacklist;
85
86 /* portable attributes, etc. */
87 typedef struct Stat Stat;
88
89 struct Stat {
90         char *name;
91         char *long_name;
92         Attrib attrib;
93 };
94
95 /* Packet handlers */
96 static void process_open(u_int32_t id);
97 static void process_close(u_int32_t id);
98 static void process_read(u_int32_t id);
99 static void process_write(u_int32_t id);
100 static void process_stat(u_int32_t id);
101 static void process_lstat(u_int32_t id);
102 static void process_fstat(u_int32_t id);
103 static void process_setstat(u_int32_t id);
104 static void process_fsetstat(u_int32_t id);
105 static void process_opendir(u_int32_t id);
106 static void process_readdir(u_int32_t id);
107 static void process_remove(u_int32_t id);
108 static void process_mkdir(u_int32_t id);
109 static void process_rmdir(u_int32_t id);
110 static void process_realpath(u_int32_t id);
111 static void process_rename(u_int32_t id);
112 static void process_readlink(u_int32_t id);
113 static void process_symlink(u_int32_t id);
114 static void process_extended_posix_rename(u_int32_t id);
115 static void process_extended_statvfs(u_int32_t id);
116 static void process_extended_fstatvfs(u_int32_t id);
117 static void process_extended_hardlink(u_int32_t id);
118 static void process_extended_fsync(u_int32_t id);
119 static void process_extended(u_int32_t id);
120
121 struct sftp_handler {
122         const char *name;       /* user-visible name for fine-grained perms */
123         const char *ext_name;   /* extended request name */
124         u_int type;             /* packet type, for non extended packets */
125         void (*handler)(u_int32_t);
126         int does_write;         /* if nonzero, banned for readonly mode */
127 };
128
129 struct sftp_handler handlers[] = {
130         /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */
131         { "open", NULL, SSH2_FXP_OPEN, process_open, 0 },
132         { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 },
133         { "read", NULL, SSH2_FXP_READ, process_read, 0 },
134         { "write", NULL, SSH2_FXP_WRITE, process_write, 1 },
135         { "lstat", NULL, SSH2_FXP_LSTAT, process_lstat, 0 },
136         { "fstat", NULL, SSH2_FXP_FSTAT, process_fstat, 0 },
137         { "setstat", NULL, SSH2_FXP_SETSTAT, process_setstat, 1 },
138         { "fsetstat", NULL, SSH2_FXP_FSETSTAT, process_fsetstat, 1 },
139         { "opendir", NULL, SSH2_FXP_OPENDIR, process_opendir, 0 },
140         { "readdir", NULL, SSH2_FXP_READDIR, process_readdir, 0 },
141         { "remove", NULL, SSH2_FXP_REMOVE, process_remove, 1 },
142         { "mkdir", NULL, SSH2_FXP_MKDIR, process_mkdir, 1 },
143         { "rmdir", NULL, SSH2_FXP_RMDIR, process_rmdir, 1 },
144         { "realpath", NULL, SSH2_FXP_REALPATH, process_realpath, 0 },
145         { "stat", NULL, SSH2_FXP_STAT, process_stat, 0 },
146         { "rename", NULL, SSH2_FXP_RENAME, process_rename, 1 },
147         { "readlink", NULL, SSH2_FXP_READLINK, process_readlink, 0 },
148         { "symlink", NULL, SSH2_FXP_SYMLINK, process_symlink, 1 },
149         { NULL, NULL, 0, NULL, 0 }
150 };
151
152 /* SSH2_FXP_EXTENDED submessages */
153 struct sftp_handler extended_handlers[] = {
154         { "posix-rename", "posix-rename@openssh.com", 0,
155            process_extended_posix_rename, 1 },
156         { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
157         { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
158         { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
159         { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
160         { NULL, NULL, 0, NULL, 0 }
161 };
162
163 static int
164 request_permitted(struct sftp_handler *h)
165 {
166         char *result;
167
168         if (readonly && h->does_write) {
169                 verbose("Refusing %s request in read-only mode", h->name);
170                 return 0;
171         }
172         if (request_blacklist != NULL &&
173             ((result = match_list(h->name, request_blacklist, NULL))) != NULL) {
174                 free(result);
175                 verbose("Refusing blacklisted %s request", h->name);
176                 return 0;
177         }
178         if (request_whitelist != NULL &&
179             ((result = match_list(h->name, request_whitelist, NULL))) != NULL) {
180                 free(result);
181                 debug2("Permitting whitelisted %s request", h->name);
182                 return 1;
183         }
184         if (request_whitelist != NULL) {
185                 verbose("Refusing non-whitelisted %s request", h->name);
186                 return 0;
187         }
188         return 1;
189 }
190
191 static int
192 errno_to_portable(int unixerrno)
193 {
194         int ret = 0;
195
196         switch (unixerrno) {
197         case 0:
198                 ret = SSH2_FX_OK;
199                 break;
200         case ENOENT:
201         case ENOTDIR:
202         case EBADF:
203         case ELOOP:
204                 ret = SSH2_FX_NO_SUCH_FILE;
205                 break;
206         case EPERM:
207         case EACCES:
208         case EFAULT:
209                 ret = SSH2_FX_PERMISSION_DENIED;
210                 break;
211         case ENAMETOOLONG:
212         case EINVAL:
213                 ret = SSH2_FX_BAD_MESSAGE;
214                 break;
215         case ENOSYS:
216                 ret = SSH2_FX_OP_UNSUPPORTED;
217                 break;
218         default:
219                 ret = SSH2_FX_FAILURE;
220                 break;
221         }
222         return ret;
223 }
224
225 static int
226 flags_from_portable(int pflags)
227 {
228         int flags = 0;
229
230         if ((pflags & SSH2_FXF_READ) &&
231             (pflags & SSH2_FXF_WRITE)) {
232                 flags = O_RDWR;
233         } else if (pflags & SSH2_FXF_READ) {
234                 flags = O_RDONLY;
235         } else if (pflags & SSH2_FXF_WRITE) {
236                 flags = O_WRONLY;
237         }
238         if (pflags & SSH2_FXF_APPEND)
239                 flags |= O_APPEND;
240         if (pflags & SSH2_FXF_CREAT)
241                 flags |= O_CREAT;
242         if (pflags & SSH2_FXF_TRUNC)
243                 flags |= O_TRUNC;
244         if (pflags & SSH2_FXF_EXCL)
245                 flags |= O_EXCL;
246         return flags;
247 }
248
249 static const char *
250 string_from_portable(int pflags)
251 {
252         static char ret[128];
253
254         *ret = '\0';
255
256 #define PAPPEND(str)    {                               \
257                 if (*ret != '\0')                       \
258                         strlcat(ret, ",", sizeof(ret)); \
259                 strlcat(ret, str, sizeof(ret));         \
260         }
261
262         if (pflags & SSH2_FXF_READ)
263                 PAPPEND("READ")
264         if (pflags & SSH2_FXF_WRITE)
265                 PAPPEND("WRITE")
266         if (pflags & SSH2_FXF_APPEND)
267                 PAPPEND("APPEND")
268         if (pflags & SSH2_FXF_CREAT)
269                 PAPPEND("CREATE")
270         if (pflags & SSH2_FXF_TRUNC)
271                 PAPPEND("TRUNCATE")
272         if (pflags & SSH2_FXF_EXCL)
273                 PAPPEND("EXCL")
274
275         return ret;
276 }
277
278 static Attrib *
279 get_attrib(void)
280 {
281         return decode_attrib(&iqueue);
282 }
283
284 /* handle handles */
285
286 typedef struct Handle Handle;
287 struct Handle {
288         int use;
289         DIR *dirp;
290         int fd;
291         int flags;
292         char *name;
293         u_int64_t bytes_read, bytes_write;
294         int next_unused;
295 };
296
297 enum {
298         HANDLE_UNUSED,
299         HANDLE_DIR,
300         HANDLE_FILE
301 };
302
303 Handle *handles = NULL;
304 u_int num_handles = 0;
305 int first_unused_handle = -1;
306
307 static void handle_unused(int i)
308 {
309         handles[i].use = HANDLE_UNUSED;
310         handles[i].next_unused = first_unused_handle;
311         first_unused_handle = i;
312 }
313
314 static int
315 handle_new(int use, const char *name, int fd, int flags, DIR *dirp)
316 {
317         int i;
318
319         if (first_unused_handle == -1) {
320                 if (num_handles + 1 <= num_handles)
321                         return -1;
322                 num_handles++;
323                 handles = xrealloc(handles, num_handles, sizeof(Handle));
324                 handle_unused(num_handles - 1);
325         }
326
327         i = first_unused_handle;
328         first_unused_handle = handles[i].next_unused;
329
330         handles[i].use = use;
331         handles[i].dirp = dirp;
332         handles[i].fd = fd;
333         handles[i].flags = flags;
334         handles[i].name = xstrdup(name);
335         handles[i].bytes_read = handles[i].bytes_write = 0;
336
337         return i;
338 }
339
340 static int
341 handle_is_ok(int i, int type)
342 {
343         return i >= 0 && (u_int)i < num_handles && handles[i].use == type;
344 }
345
346 static int
347 handle_to_string(int handle, char **stringp, int *hlenp)
348 {
349         if (stringp == NULL || hlenp == NULL)
350                 return -1;
351         *stringp = xmalloc(sizeof(int32_t));
352         put_u32(*stringp, handle);
353         *hlenp = sizeof(int32_t);
354         return 0;
355 }
356
357 static int
358 handle_from_string(const char *handle, u_int hlen)
359 {
360         int val;
361
362         if (hlen != sizeof(int32_t))
363                 return -1;
364         val = get_u32(handle);
365         if (handle_is_ok(val, HANDLE_FILE) ||
366             handle_is_ok(val, HANDLE_DIR))
367                 return val;
368         return -1;
369 }
370
371 static char *
372 handle_to_name(int handle)
373 {
374         if (handle_is_ok(handle, HANDLE_DIR)||
375             handle_is_ok(handle, HANDLE_FILE))
376                 return handles[handle].name;
377         return NULL;
378 }
379
380 static DIR *
381 handle_to_dir(int handle)
382 {
383         if (handle_is_ok(handle, HANDLE_DIR))
384                 return handles[handle].dirp;
385         return NULL;
386 }
387
388 static int
389 handle_to_fd(int handle)
390 {
391         if (handle_is_ok(handle, HANDLE_FILE))
392                 return handles[handle].fd;
393         return -1;
394 }
395
396 static int
397 handle_to_flags(int handle)
398 {
399         if (handle_is_ok(handle, HANDLE_FILE))
400                 return handles[handle].flags;
401         return 0;
402 }
403
404 static void
405 handle_update_read(int handle, ssize_t bytes)
406 {
407         if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
408                 handles[handle].bytes_read += bytes;
409 }
410
411 static void
412 handle_update_write(int handle, ssize_t bytes)
413 {
414         if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
415                 handles[handle].bytes_write += bytes;
416 }
417
418 static u_int64_t
419 handle_bytes_read(int handle)
420 {
421         if (handle_is_ok(handle, HANDLE_FILE))
422                 return (handles[handle].bytes_read);
423         return 0;
424 }
425
426 static u_int64_t
427 handle_bytes_write(int handle)
428 {
429         if (handle_is_ok(handle, HANDLE_FILE))
430                 return (handles[handle].bytes_write);
431         return 0;
432 }
433
434 static int
435 handle_close(int handle)
436 {
437         int ret = -1;
438
439         if (handle_is_ok(handle, HANDLE_FILE)) {
440                 ret = close(handles[handle].fd);
441                 free(handles[handle].name);
442                 handle_unused(handle);
443         } else if (handle_is_ok(handle, HANDLE_DIR)) {
444                 ret = closedir(handles[handle].dirp);
445                 free(handles[handle].name);
446                 handle_unused(handle);
447         } else {
448                 errno = ENOENT;
449         }
450         return ret;
451 }
452
453 static void
454 handle_log_close(int handle, char *emsg)
455 {
456         if (handle_is_ok(handle, HANDLE_FILE)) {
457                 logit("%s%sclose \"%s\" bytes read %llu written %llu",
458                     emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
459                     handle_to_name(handle),
460                     (unsigned long long)handle_bytes_read(handle),
461                     (unsigned long long)handle_bytes_write(handle));
462         } else {
463                 logit("%s%sclosedir \"%s\"",
464                     emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
465                     handle_to_name(handle));
466         }
467 }
468
469 static void
470 handle_log_exit(void)
471 {
472         u_int i;
473
474         for (i = 0; i < num_handles; i++)
475                 if (handles[i].use != HANDLE_UNUSED)
476                         handle_log_close(i, "forced");
477 }
478
479 static int
480 get_handle(void)
481 {
482         char *handle;
483         int val = -1;
484         u_int hlen;
485
486         handle = get_string(&hlen);
487         if (hlen < 256)
488                 val = handle_from_string(handle, hlen);
489         free(handle);
490         return val;
491 }
492
493 /* send replies */
494
495 static void
496 send_msg(Buffer *m)
497 {
498         int mlen = buffer_len(m);
499
500         buffer_put_int(&oqueue, mlen);
501         buffer_append(&oqueue, buffer_ptr(m), mlen);
502         buffer_consume(m, mlen);
503 }
504
505 static const char *
506 status_to_message(u_int32_t status)
507 {
508         const char *status_messages[] = {
509                 "Success",                      /* SSH_FX_OK */
510                 "End of file",                  /* SSH_FX_EOF */
511                 "No such file",                 /* SSH_FX_NO_SUCH_FILE */
512                 "Permission denied",            /* SSH_FX_PERMISSION_DENIED */
513                 "Failure",                      /* SSH_FX_FAILURE */
514                 "Bad message",                  /* SSH_FX_BAD_MESSAGE */
515                 "No connection",                /* SSH_FX_NO_CONNECTION */
516                 "Connection lost",              /* SSH_FX_CONNECTION_LOST */
517                 "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */
518                 "Unknown error"                 /* Others */
519         };
520         return (status_messages[MIN(status,SSH2_FX_MAX)]);
521 }
522
523 static void
524 send_status(u_int32_t id, u_int32_t status)
525 {
526         Buffer msg;
527
528         debug3("request %u: sent status %u", id, status);
529         if (log_level > SYSLOG_LEVEL_VERBOSE ||
530             (status != SSH2_FX_OK && status != SSH2_FX_EOF))
531                 logit("sent status %s", status_to_message(status));
532         buffer_init(&msg);
533         buffer_put_char(&msg, SSH2_FXP_STATUS);
534         buffer_put_int(&msg, id);
535         buffer_put_int(&msg, status);
536         if (version >= 3) {
537                 buffer_put_cstring(&msg, status_to_message(status));
538                 buffer_put_cstring(&msg, "");
539         }
540         send_msg(&msg);
541         buffer_free(&msg);
542 }
543 static void
544 send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
545 {
546         Buffer msg;
547
548         buffer_init(&msg);
549         buffer_put_char(&msg, type);
550         buffer_put_int(&msg, id);
551         buffer_put_string(&msg, data, dlen);
552         send_msg(&msg);
553         buffer_free(&msg);
554 }
555
556 static void
557 send_data(u_int32_t id, const char *data, int dlen)
558 {
559         debug("request %u: sent data len %d", id, dlen);
560         send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
561 }
562
563 static void
564 send_handle(u_int32_t id, int handle)
565 {
566         char *string;
567         int hlen;
568
569         handle_to_string(handle, &string, &hlen);
570         debug("request %u: sent handle handle %d", id, handle);
571         send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
572         free(string);
573 }
574
575 static void
576 send_names(u_int32_t id, int count, const Stat *stats)
577 {
578         Buffer msg;
579         int i;
580
581         buffer_init(&msg);
582         buffer_put_char(&msg, SSH2_FXP_NAME);
583         buffer_put_int(&msg, id);
584         buffer_put_int(&msg, count);
585         debug("request %u: sent names count %d", id, count);
586         for (i = 0; i < count; i++) {
587                 buffer_put_cstring(&msg, stats[i].name);
588                 buffer_put_cstring(&msg, stats[i].long_name);
589                 encode_attrib(&msg, &stats[i].attrib);
590         }
591         send_msg(&msg);
592         buffer_free(&msg);
593 }
594
595 static void
596 send_attrib(u_int32_t id, const Attrib *a)
597 {
598         Buffer msg;
599
600         debug("request %u: sent attrib have 0x%x", id, a->flags);
601         buffer_init(&msg);
602         buffer_put_char(&msg, SSH2_FXP_ATTRS);
603         buffer_put_int(&msg, id);
604         encode_attrib(&msg, a);
605         send_msg(&msg);
606         buffer_free(&msg);
607 }
608
609 static void
610 send_statvfs(u_int32_t id, struct statvfs *st)
611 {
612         Buffer msg;
613         u_int64_t flag;
614
615         flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
616         flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
617
618         buffer_init(&msg);
619         buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
620         buffer_put_int(&msg, id);
621         buffer_put_int64(&msg, st->f_bsize);
622         buffer_put_int64(&msg, st->f_frsize);
623         buffer_put_int64(&msg, st->f_blocks);
624         buffer_put_int64(&msg, st->f_bfree);
625         buffer_put_int64(&msg, st->f_bavail);
626         buffer_put_int64(&msg, st->f_files);
627         buffer_put_int64(&msg, st->f_ffree);
628         buffer_put_int64(&msg, st->f_favail);
629         buffer_put_int64(&msg, FSID_TO_ULONG(st->f_fsid));
630         buffer_put_int64(&msg, flag);
631         buffer_put_int64(&msg, st->f_namemax);
632         send_msg(&msg);
633         buffer_free(&msg);
634 }
635
636 /* parse incoming */
637
638 static void
639 process_init(void)
640 {
641         Buffer msg;
642
643         version = get_int();
644         verbose("received client version %u", version);
645         buffer_init(&msg);
646         buffer_put_char(&msg, SSH2_FXP_VERSION);
647         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
648         /* POSIX rename extension */
649         buffer_put_cstring(&msg, "posix-rename@openssh.com");
650         buffer_put_cstring(&msg, "1"); /* version */
651         /* statvfs extension */
652         buffer_put_cstring(&msg, "statvfs@openssh.com");
653         buffer_put_cstring(&msg, "2"); /* version */
654         /* fstatvfs extension */
655         buffer_put_cstring(&msg, "fstatvfs@openssh.com");
656         buffer_put_cstring(&msg, "2"); /* version */
657         /* hardlink extension */
658         buffer_put_cstring(&msg, "hardlink@openssh.com");
659         buffer_put_cstring(&msg, "1"); /* version */
660         /* fsync extension */
661         buffer_put_cstring(&msg, "fsync@openssh.com");
662         buffer_put_cstring(&msg, "1"); /* version */
663         send_msg(&msg);
664         buffer_free(&msg);
665 }
666
667 static void
668 process_open(u_int32_t id)
669 {
670         u_int32_t pflags;
671         Attrib *a;
672         char *name;
673         int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
674
675         name = get_string(NULL);
676         pflags = get_int();             /* portable flags */
677         debug3("request %u: open flags %d", id, pflags);
678         a = get_attrib();
679         flags = flags_from_portable(pflags);
680         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
681         logit("open \"%s\" flags %s mode 0%o",
682             name, string_from_portable(pflags), mode);
683         if (readonly &&
684             ((flags & O_ACCMODE) == O_WRONLY ||
685             (flags & O_ACCMODE) == O_RDWR)) {
686                 verbose("Refusing open request in read-only mode");
687                 status = SSH2_FX_PERMISSION_DENIED;
688         } else {
689                 fd = open(name, flags, mode);
690                 if (fd < 0) {
691                         status = errno_to_portable(errno);
692                 } else {
693                         handle = handle_new(HANDLE_FILE, name, fd, flags, NULL);
694                         if (handle < 0) {
695                                 close(fd);
696                         } else {
697                                 send_handle(id, handle);
698                                 status = SSH2_FX_OK;
699                         }
700                 }
701         }
702         if (status != SSH2_FX_OK)
703                 send_status(id, status);
704         free(name);
705 }
706
707 static void
708 process_close(u_int32_t id)
709 {
710         int handle, ret, status = SSH2_FX_FAILURE;
711
712         handle = get_handle();
713         debug3("request %u: close handle %u", id, handle);
714         handle_log_close(handle, NULL);
715         ret = handle_close(handle);
716         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
717         send_status(id, status);
718 }
719
720 static void
721 process_read(u_int32_t id)
722 {
723         char buf[64*1024];
724         u_int32_t len;
725         int handle, fd, ret, status = SSH2_FX_FAILURE;
726         u_int64_t off;
727
728         handle = get_handle();
729         off = get_int64();
730         len = get_int();
731
732         debug("request %u: read \"%s\" (handle %d) off %llu len %d",
733             id, handle_to_name(handle), handle, (unsigned long long)off, len);
734         if (len > sizeof buf) {
735                 len = sizeof buf;
736                 debug2("read change len %d", len);
737         }
738         fd = handle_to_fd(handle);
739         if (fd >= 0) {
740                 if (lseek(fd, off, SEEK_SET) < 0) {
741                         error("process_read: seek failed");
742                         status = errno_to_portable(errno);
743                 } else {
744                         ret = read(fd, buf, len);
745                         if (ret < 0) {
746                                 status = errno_to_portable(errno);
747                         } else if (ret == 0) {
748                                 status = SSH2_FX_EOF;
749                         } else {
750                                 send_data(id, buf, ret);
751                                 status = SSH2_FX_OK;
752                                 handle_update_read(handle, ret);
753                         }
754                 }
755         }
756         if (status != SSH2_FX_OK)
757                 send_status(id, status);
758 }
759
760 static void
761 process_write(u_int32_t id)
762 {
763         u_int64_t off;
764         u_int len;
765         int handle, fd, ret, status;
766         char *data;
767
768         handle = get_handle();
769         off = get_int64();
770         data = get_string(&len);
771
772         debug("request %u: write \"%s\" (handle %d) off %llu len %d",
773             id, handle_to_name(handle), handle, (unsigned long long)off, len);
774         fd = handle_to_fd(handle);
775         
776         if (fd < 0)
777                 status = SSH2_FX_FAILURE;
778         else {
779                 if (!(handle_to_flags(handle) & O_APPEND) &&
780                                 lseek(fd, off, SEEK_SET) < 0) {
781                         status = errno_to_portable(errno);
782                         error("process_write: seek failed");
783                 } else {
784 /* XXX ATOMICIO ? */
785                         ret = write(fd, data, len);
786                         if (ret < 0) {
787                                 error("process_write: write failed");
788                                 status = errno_to_portable(errno);
789                         } else if ((size_t)ret == len) {
790                                 status = SSH2_FX_OK;
791                                 handle_update_write(handle, ret);
792                         } else {
793                                 debug2("nothing at all written");
794                                 status = SSH2_FX_FAILURE;
795                         }
796                 }
797         }
798         send_status(id, status);
799         free(data);
800 }
801
802 static void
803 process_do_stat(u_int32_t id, int do_lstat)
804 {
805         Attrib a;
806         struct stat st;
807         char *name;
808         int ret, status = SSH2_FX_FAILURE;
809
810         name = get_string(NULL);
811         debug3("request %u: %sstat", id, do_lstat ? "l" : "");
812         verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
813         ret = do_lstat ? lstat(name, &st) : stat(name, &st);
814         if (ret < 0) {
815                 status = errno_to_portable(errno);
816         } else {
817                 stat_to_attrib(&st, &a);
818                 send_attrib(id, &a);
819                 status = SSH2_FX_OK;
820         }
821         if (status != SSH2_FX_OK)
822                 send_status(id, status);
823         free(name);
824 }
825
826 static void
827 process_stat(u_int32_t id)
828 {
829         process_do_stat(id, 0);
830 }
831
832 static void
833 process_lstat(u_int32_t id)
834 {
835         process_do_stat(id, 1);
836 }
837
838 static void
839 process_fstat(u_int32_t id)
840 {
841         Attrib a;
842         struct stat st;
843         int fd, ret, handle, status = SSH2_FX_FAILURE;
844
845         handle = get_handle();
846         debug("request %u: fstat \"%s\" (handle %u)",
847             id, handle_to_name(handle), handle);
848         fd = handle_to_fd(handle);
849         if (fd >= 0) {
850                 ret = fstat(fd, &st);
851                 if (ret < 0) {
852                         status = errno_to_portable(errno);
853                 } else {
854                         stat_to_attrib(&st, &a);
855                         send_attrib(id, &a);
856                         status = SSH2_FX_OK;
857                 }
858         }
859         if (status != SSH2_FX_OK)
860                 send_status(id, status);
861 }
862
863 static struct timeval *
864 attrib_to_tv(const Attrib *a)
865 {
866         static struct timeval tv[2];
867
868         tv[0].tv_sec = a->atime;
869         tv[0].tv_usec = 0;
870         tv[1].tv_sec = a->mtime;
871         tv[1].tv_usec = 0;
872         return tv;
873 }
874
875 static void
876 process_setstat(u_int32_t id)
877 {
878         Attrib *a;
879         char *name;
880         int status = SSH2_FX_OK, ret;
881
882         name = get_string(NULL);
883         a = get_attrib();
884         debug("request %u: setstat name \"%s\"", id, name);
885         if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
886                 logit("set \"%s\" size %llu",
887                     name, (unsigned long long)a->size);
888                 ret = truncate(name, a->size);
889                 if (ret == -1)
890                         status = errno_to_portable(errno);
891         }
892         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
893                 logit("set \"%s\" mode %04o", name, a->perm);
894                 ret = chmod(name, a->perm & 07777);
895                 if (ret == -1)
896                         status = errno_to_portable(errno);
897         }
898         if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
899                 char buf[64];
900                 time_t t = a->mtime;
901
902                 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
903                     localtime(&t));
904                 logit("set \"%s\" modtime %s", name, buf);
905                 ret = utimes(name, attrib_to_tv(a));
906                 if (ret == -1)
907                         status = errno_to_portable(errno);
908         }
909         if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
910                 logit("set \"%s\" owner %lu group %lu", name,
911                     (u_long)a->uid, (u_long)a->gid);
912                 ret = chown(name, a->uid, a->gid);
913                 if (ret == -1)
914                         status = errno_to_portable(errno);
915         }
916         send_status(id, status);
917         free(name);
918 }
919
920 static void
921 process_fsetstat(u_int32_t id)
922 {
923         Attrib *a;
924         int handle, fd, ret;
925         int status = SSH2_FX_OK;
926
927         handle = get_handle();
928         a = get_attrib();
929         debug("request %u: fsetstat handle %d", id, handle);
930         fd = handle_to_fd(handle);
931         if (fd < 0)
932                 status = SSH2_FX_FAILURE;
933         else {
934                 char *name = handle_to_name(handle);
935
936                 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
937                         logit("set \"%s\" size %llu",
938                             name, (unsigned long long)a->size);
939                         ret = ftruncate(fd, a->size);
940                         if (ret == -1)
941                                 status = errno_to_portable(errno);
942                 }
943                 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
944                         logit("set \"%s\" mode %04o", name, a->perm);
945 #ifdef HAVE_FCHMOD
946                         ret = fchmod(fd, a->perm & 07777);
947 #else
948                         ret = chmod(name, a->perm & 07777);
949 #endif
950                         if (ret == -1)
951                                 status = errno_to_portable(errno);
952                 }
953                 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
954                         char buf[64];
955                         time_t t = a->mtime;
956
957                         strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
958                             localtime(&t));
959                         logit("set \"%s\" modtime %s", name, buf);
960 #ifdef HAVE_FUTIMES
961                         ret = futimes(fd, attrib_to_tv(a));
962 #else
963                         ret = utimes(name, attrib_to_tv(a));
964 #endif
965                         if (ret == -1)
966                                 status = errno_to_portable(errno);
967                 }
968                 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
969                         logit("set \"%s\" owner %lu group %lu", name,
970                             (u_long)a->uid, (u_long)a->gid);
971 #ifdef HAVE_FCHOWN
972                         ret = fchown(fd, a->uid, a->gid);
973 #else
974                         ret = chown(name, a->uid, a->gid);
975 #endif
976                         if (ret == -1)
977                                 status = errno_to_portable(errno);
978                 }
979         }
980         send_status(id, status);
981 }
982
983 static void
984 process_opendir(u_int32_t id)
985 {
986         DIR *dirp = NULL;
987         char *path;
988         int handle, status = SSH2_FX_FAILURE;
989
990         path = get_string(NULL);
991         debug3("request %u: opendir", id);
992         logit("opendir \"%s\"", path);
993         dirp = opendir(path);
994         if (dirp == NULL) {
995                 status = errno_to_portable(errno);
996         } else {
997                 handle = handle_new(HANDLE_DIR, path, 0, 0, dirp);
998                 if (handle < 0) {
999                         closedir(dirp);
1000                 } else {
1001                         send_handle(id, handle);
1002                         status = SSH2_FX_OK;
1003                 }
1004
1005         }
1006         if (status != SSH2_FX_OK)
1007                 send_status(id, status);
1008         free(path);
1009 }
1010
1011 static void
1012 process_readdir(u_int32_t id)
1013 {
1014         DIR *dirp;
1015         struct dirent *dp;
1016         char *path;
1017         int handle;
1018
1019         handle = get_handle();
1020         debug("request %u: readdir \"%s\" (handle %d)", id,
1021             handle_to_name(handle), handle);
1022         dirp = handle_to_dir(handle);
1023         path = handle_to_name(handle);
1024         if (dirp == NULL || path == NULL) {
1025                 send_status(id, SSH2_FX_FAILURE);
1026         } else {
1027                 struct stat st;
1028                 char pathname[MAXPATHLEN];
1029                 Stat *stats;
1030                 int nstats = 10, count = 0, i;
1031
1032                 stats = xcalloc(nstats, sizeof(Stat));
1033                 while ((dp = readdir(dirp)) != NULL) {
1034                         if (count >= nstats) {
1035                                 nstats *= 2;
1036                                 stats = xrealloc(stats, nstats, sizeof(Stat));
1037                         }
1038 /* XXX OVERFLOW ? */
1039                         snprintf(pathname, sizeof pathname, "%s%s%s", path,
1040                             strcmp(path, "/") ? "/" : "", dp->d_name);
1041                         if (lstat(pathname, &st) < 0)
1042                                 continue;
1043                         stat_to_attrib(&st, &(stats[count].attrib));
1044                         stats[count].name = xstrdup(dp->d_name);
1045                         stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
1046                         count++;
1047                         /* send up to 100 entries in one message */
1048                         /* XXX check packet size instead */
1049                         if (count == 100)
1050                                 break;
1051                 }
1052                 if (count > 0) {
1053                         send_names(id, count, stats);
1054                         for (i = 0; i < count; i++) {
1055                                 free(stats[i].name);
1056                                 free(stats[i].long_name);
1057                         }
1058                 } else {
1059                         send_status(id, SSH2_FX_EOF);
1060                 }
1061                 free(stats);
1062         }
1063 }
1064
1065 static void
1066 process_remove(u_int32_t id)
1067 {
1068         char *name;
1069         int status = SSH2_FX_FAILURE;
1070         int ret;
1071
1072         name = get_string(NULL);
1073         debug3("request %u: remove", id);
1074         logit("remove name \"%s\"", name);
1075         ret = unlink(name);
1076         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1077         send_status(id, status);
1078         free(name);
1079 }
1080
1081 static void
1082 process_mkdir(u_int32_t id)
1083 {
1084         Attrib *a;
1085         char *name;
1086         int ret, mode, status = SSH2_FX_FAILURE;
1087
1088         name = get_string(NULL);
1089         a = get_attrib();
1090         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
1091             a->perm & 07777 : 0777;
1092         debug3("request %u: mkdir", id);
1093         logit("mkdir name \"%s\" mode 0%o", name, mode);
1094         ret = mkdir(name, mode);
1095         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1096         send_status(id, status);
1097         free(name);
1098 }
1099
1100 static void
1101 process_rmdir(u_int32_t id)
1102 {
1103         char *name;
1104         int ret, status;
1105
1106         name = get_string(NULL);
1107         debug3("request %u: rmdir", id);
1108         logit("rmdir name \"%s\"", name);
1109         ret = rmdir(name);
1110         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1111         send_status(id, status);
1112         free(name);
1113 }
1114
1115 static void
1116 process_realpath(u_int32_t id)
1117 {
1118         char resolvedname[MAXPATHLEN];
1119         char *path;
1120
1121         path = get_string(NULL);
1122         if (path[0] == '\0') {
1123                 free(path);
1124                 path = xstrdup(".");
1125         }
1126         debug3("request %u: realpath", id);
1127         verbose("realpath \"%s\"", path);
1128         if (realpath(path, resolvedname) == NULL) {
1129                 send_status(id, errno_to_portable(errno));
1130         } else {
1131                 Stat s;
1132                 attrib_clear(&s.attrib);
1133                 s.name = s.long_name = resolvedname;
1134                 send_names(id, 1, &s);
1135         }
1136         free(path);
1137 }
1138
1139 static void
1140 process_rename(u_int32_t id)
1141 {
1142         char *oldpath, *newpath;
1143         int status;
1144         struct stat sb;
1145
1146         oldpath = get_string(NULL);
1147         newpath = get_string(NULL);
1148         debug3("request %u: rename", id);
1149         logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1150         status = SSH2_FX_FAILURE;
1151         if (lstat(oldpath, &sb) == -1)
1152                 status = errno_to_portable(errno);
1153         else if (S_ISREG(sb.st_mode)) {
1154                 /* Race-free rename of regular files */
1155                 if (link(oldpath, newpath) == -1) {
1156                         if (errno == EOPNOTSUPP || errno == ENOSYS
1157 #ifdef EXDEV
1158                             || errno == EXDEV
1159 #endif
1160 #ifdef LINK_OPNOTSUPP_ERRNO
1161                             || errno == LINK_OPNOTSUPP_ERRNO
1162 #endif
1163                             ) {
1164                                 struct stat st;
1165
1166                                 /*
1167                                  * fs doesn't support links, so fall back to
1168                                  * stat+rename.  This is racy.
1169                                  */
1170                                 if (stat(newpath, &st) == -1) {
1171                                         if (rename(oldpath, newpath) == -1)
1172                                                 status =
1173                                                     errno_to_portable(errno);
1174                                         else
1175                                                 status = SSH2_FX_OK;
1176                                 }
1177                         } else {
1178                                 status = errno_to_portable(errno);
1179                         }
1180                 } else if (unlink(oldpath) == -1) {
1181                         status = errno_to_portable(errno);
1182                         /* clean spare link */
1183                         unlink(newpath);
1184                 } else
1185                         status = SSH2_FX_OK;
1186         } else if (stat(newpath, &sb) == -1) {
1187                 if (rename(oldpath, newpath) == -1)
1188                         status = errno_to_portable(errno);
1189                 else
1190                         status = SSH2_FX_OK;
1191         }
1192         send_status(id, status);
1193         free(oldpath);
1194         free(newpath);
1195 }
1196
1197 static void
1198 process_readlink(u_int32_t id)
1199 {
1200         int len;
1201         char buf[MAXPATHLEN];
1202         char *path;
1203
1204         path = get_string(NULL);
1205         debug3("request %u: readlink", id);
1206         verbose("readlink \"%s\"", path);
1207         if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1208                 send_status(id, errno_to_portable(errno));
1209         else {
1210                 Stat s;
1211
1212                 buf[len] = '\0';
1213                 attrib_clear(&s.attrib);
1214                 s.name = s.long_name = buf;
1215                 send_names(id, 1, &s);
1216         }
1217         free(path);
1218 }
1219
1220 static void
1221 process_symlink(u_int32_t id)
1222 {
1223         char *oldpath, *newpath;
1224         int ret, status;
1225
1226         oldpath = get_string(NULL);
1227         newpath = get_string(NULL);
1228         debug3("request %u: symlink", id);
1229         logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1230         /* this will fail if 'newpath' exists */
1231         ret = symlink(oldpath, newpath);
1232         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1233         send_status(id, status);
1234         free(oldpath);
1235         free(newpath);
1236 }
1237
1238 static void
1239 process_extended_posix_rename(u_int32_t id)
1240 {
1241         char *oldpath, *newpath;
1242         int ret, status;
1243
1244         oldpath = get_string(NULL);
1245         newpath = get_string(NULL);
1246         debug3("request %u: posix-rename", id);
1247         logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1248         ret = rename(oldpath, newpath);
1249         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1250         send_status(id, status);
1251         free(oldpath);
1252         free(newpath);
1253 }
1254
1255 static void
1256 process_extended_statvfs(u_int32_t id)
1257 {
1258         char *path;
1259         struct statvfs st;
1260
1261         path = get_string(NULL);
1262         debug3("request %u: statvfs", id);
1263         logit("statvfs \"%s\"", path);
1264
1265         if (statvfs(path, &st) != 0)
1266                 send_status(id, errno_to_portable(errno));
1267         else
1268                 send_statvfs(id, &st);
1269         free(path);
1270 }
1271
1272 static void
1273 process_extended_fstatvfs(u_int32_t id)
1274 {
1275         int handle, fd;
1276         struct statvfs st;
1277
1278         handle = get_handle();
1279         debug("request %u: fstatvfs \"%s\" (handle %u)",
1280             id, handle_to_name(handle), handle);
1281         if ((fd = handle_to_fd(handle)) < 0) {
1282                 send_status(id, SSH2_FX_FAILURE);
1283                 return;
1284         }
1285         if (fstatvfs(fd, &st) != 0)
1286                 send_status(id, errno_to_portable(errno));
1287         else
1288                 send_statvfs(id, &st);
1289 }
1290
1291 static void
1292 process_extended_hardlink(u_int32_t id)
1293 {
1294         char *oldpath, *newpath;
1295         int ret, status;
1296
1297         oldpath = get_string(NULL);
1298         newpath = get_string(NULL);
1299         debug3("request %u: hardlink", id);
1300         logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1301         ret = link(oldpath, newpath);
1302         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1303         send_status(id, status);
1304         free(oldpath);
1305         free(newpath);
1306 }
1307
1308 static void
1309 process_extended_fsync(u_int32_t id)
1310 {
1311         int handle, fd, ret, status = SSH2_FX_OP_UNSUPPORTED;
1312
1313         handle = get_handle();
1314         debug3("request %u: fsync (handle %u)", id, handle);
1315         verbose("fsync \"%s\"", handle_to_name(handle));
1316         if ((fd = handle_to_fd(handle)) < 0)
1317                 status = SSH2_FX_NO_SUCH_FILE;
1318         else if (handle_is_ok(handle, HANDLE_FILE)) {
1319                 ret = fsync(fd);
1320                 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1321         }
1322         send_status(id, status);
1323 }
1324
1325 static void
1326 process_extended(u_int32_t id)
1327 {
1328         char *request;
1329         u_int i;
1330
1331         request = get_string(NULL);
1332         for (i = 0; extended_handlers[i].handler != NULL; i++) {
1333                 if (strcmp(request, extended_handlers[i].ext_name) == 0) {
1334                         if (!request_permitted(&extended_handlers[i]))
1335                                 send_status(id, SSH2_FX_PERMISSION_DENIED);
1336                         else
1337                                 extended_handlers[i].handler(id);
1338                         break;
1339                 }
1340         }
1341         if (extended_handlers[i].handler == NULL) {
1342                 error("Unknown extended request \"%.100s\"", request);
1343                 send_status(id, SSH2_FX_OP_UNSUPPORTED);        /* MUST */
1344         }
1345         free(request);
1346 }
1347
1348 /* stolen from ssh-agent */
1349
1350 static void
1351 process(void)
1352 {
1353         u_int msg_len, buf_len, consumed, type, i;
1354         u_char *cp;
1355         u_int32_t id;
1356
1357         buf_len = buffer_len(&iqueue);
1358         if (buf_len < 5)
1359                 return;         /* Incomplete message. */
1360         cp = buffer_ptr(&iqueue);
1361         msg_len = get_u32(cp);
1362         if (msg_len > SFTP_MAX_MSG_LENGTH) {
1363                 error("bad message from %s local user %s",
1364                     client_addr, pw->pw_name);
1365                 sftp_server_cleanup_exit(11);
1366         }
1367         if (buf_len < msg_len + 4)
1368                 return;
1369         buffer_consume(&iqueue, 4);
1370         buf_len -= 4;
1371         type = buffer_get_char(&iqueue);
1372
1373         switch (type) {
1374         case SSH2_FXP_INIT:
1375                 process_init();
1376                 init_done = 1;
1377                 break;
1378         case SSH2_FXP_EXTENDED:
1379                 if (!init_done)
1380                         fatal("Received extended request before init");
1381                 id = get_int();
1382                 process_extended(id);
1383                 break;
1384         default:
1385                 if (!init_done)
1386                         fatal("Received %u request before init", type);
1387                 id = get_int();
1388                 for (i = 0; handlers[i].handler != NULL; i++) {
1389                         if (type == handlers[i].type) {
1390                                 if (!request_permitted(&handlers[i])) {
1391                                         send_status(id,
1392                                             SSH2_FX_PERMISSION_DENIED);
1393                                 } else {
1394                                         handlers[i].handler(id);
1395                                 }
1396                                 break;
1397                         }
1398                 }
1399                 if (handlers[i].handler == NULL)
1400                         error("Unknown message %u", type);
1401         }
1402         /* discard the remaining bytes from the current packet */
1403         if (buf_len < buffer_len(&iqueue)) {
1404                 error("iqueue grew unexpectedly");
1405                 sftp_server_cleanup_exit(255);
1406         }
1407         consumed = buf_len - buffer_len(&iqueue);
1408         if (msg_len < consumed) {
1409                 error("msg_len %u < consumed %u", msg_len, consumed);
1410                 sftp_server_cleanup_exit(255);
1411         }
1412         if (msg_len > consumed)
1413                 buffer_consume(&iqueue, msg_len - consumed);
1414 }
1415
1416 /* Cleanup handler that logs active handles upon normal exit */
1417 void
1418 sftp_server_cleanup_exit(int i)
1419 {
1420         if (pw != NULL && client_addr != NULL) {
1421                 handle_log_exit();
1422                 logit("session closed for local user %s from [%s]",
1423                     pw->pw_name, client_addr);
1424         }
1425         _exit(i);
1426 }
1427
1428 static void
1429 sftp_server_usage(void)
1430 {
1431         extern char *__progname;
1432
1433         fprintf(stderr,
1434             "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
1435             "[-l log_level]\n\t[-P blacklisted_requests] "
1436             "[-p whitelisted_requests] [-u umask]\n"
1437             "       %s -Q protocol_feature\n",
1438             __progname, __progname);
1439         exit(1);
1440 }
1441
1442 int
1443 sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1444 {
1445         fd_set *rset, *wset;
1446         int i, in, out, max, ch, skipargs = 0, log_stderr = 0;
1447         ssize_t len, olen, set_size;
1448         SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1449         char *cp, *homedir = NULL, buf[4*4096];
1450         long mask;
1451
1452         extern char *optarg;
1453         extern char *__progname;
1454
1455         __progname = ssh_get_progname(argv[0]);
1456         log_init(__progname, log_level, log_facility, log_stderr);
1457
1458         pw = pwcopy(user_pw);
1459
1460         while (!skipargs && (ch = getopt(argc, argv,
1461             "d:f:l:P:p:Q:u:cehR")) != -1) {
1462                 switch (ch) {
1463                 case 'Q':
1464                         if (strcasecmp(optarg, "requests") != 0) {
1465                                 fprintf(stderr, "Invalid query type\n");
1466                                 exit(1);
1467                         }
1468                         for (i = 0; handlers[i].handler != NULL; i++)
1469                                 printf("%s\n", handlers[i].name);
1470                         for (i = 0; extended_handlers[i].handler != NULL; i++)
1471                                 printf("%s\n", extended_handlers[i].name);
1472                         exit(0);
1473                         break;
1474                 case 'R':
1475                         readonly = 1;
1476                         break;
1477                 case 'c':
1478                         /*
1479                          * Ignore all arguments if we are invoked as a
1480                          * shell using "sftp-server -c command"
1481                          */
1482                         skipargs = 1;
1483                         break;
1484                 case 'e':
1485                         log_stderr = 1;
1486                         break;
1487                 case 'l':
1488                         log_level = log_level_number(optarg);
1489                         if (log_level == SYSLOG_LEVEL_NOT_SET)
1490                                 error("Invalid log level \"%s\"", optarg);
1491                         break;
1492                 case 'f':
1493                         log_facility = log_facility_number(optarg);
1494                         if (log_facility == SYSLOG_FACILITY_NOT_SET)
1495                                 error("Invalid log facility \"%s\"", optarg);
1496                         break;
1497                 case 'd':
1498                         cp = tilde_expand_filename(optarg, user_pw->pw_uid);
1499                         homedir = percent_expand(cp, "d", user_pw->pw_dir,
1500                             "u", user_pw->pw_name, (char *)NULL);
1501                         free(cp);
1502                         break;
1503                 case 'p':
1504                         if (request_whitelist != NULL)
1505                                 fatal("Permitted requests already set");
1506                         request_whitelist = xstrdup(optarg);
1507                         break;
1508                 case 'P':
1509                         if (request_blacklist != NULL)
1510                                 fatal("Refused requests already set");
1511                         request_blacklist = xstrdup(optarg);
1512                         break;
1513                 case 'u':
1514                         errno = 0;
1515                         mask = strtol(optarg, &cp, 8);
1516                         if (mask < 0 || mask > 0777 || *cp != '\0' ||
1517                             cp == optarg || (mask == 0 && errno != 0))
1518                                 fatal("Invalid umask \"%s\"", optarg);
1519                         (void)umask((mode_t)mask);
1520                         break;
1521                 case 'h':
1522                 default:
1523                         sftp_server_usage();
1524                 }
1525         }
1526
1527         log_init(__progname, log_level, log_facility, log_stderr);
1528
1529 #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
1530         /*
1531          * On Linux, we should try to avoid making /proc/self/{mem,maps}
1532          * available to the user so that sftp access doesn't automatically
1533          * imply arbitrary code execution access that will break
1534          * restricted configurations.
1535          */
1536         if (prctl(PR_SET_DUMPABLE, 0) != 0)
1537                 fatal("unable to make the process undumpable");
1538 #endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */
1539
1540         if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1541                 client_addr = xstrdup(cp);
1542                 if ((cp = strchr(client_addr, ' ')) == NULL) {
1543                         error("Malformed SSH_CONNECTION variable: \"%s\"",
1544                             getenv("SSH_CONNECTION"));
1545                         sftp_server_cleanup_exit(255);
1546                 }
1547                 *cp = '\0';
1548         } else
1549                 client_addr = xstrdup("UNKNOWN");
1550
1551         logit("session opened for local user %s from [%s]",
1552             pw->pw_name, client_addr);
1553
1554         in = STDIN_FILENO;
1555         out = STDOUT_FILENO;
1556
1557 #ifdef HAVE_CYGWIN
1558         setmode(in, O_BINARY);
1559         setmode(out, O_BINARY);
1560 #endif
1561
1562         max = 0;
1563         if (in > max)
1564                 max = in;
1565         if (out > max)
1566                 max = out;
1567
1568         buffer_init(&iqueue);
1569         buffer_init(&oqueue);
1570
1571         set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1572         rset = (fd_set *)xmalloc(set_size);
1573         wset = (fd_set *)xmalloc(set_size);
1574
1575         if (homedir != NULL) {
1576                 if (chdir(homedir) != 0) {
1577                         error("chdir to \"%s\" failed: %s", homedir,
1578                             strerror(errno));
1579                 }
1580         }
1581
1582         for (;;) {
1583                 memset(rset, 0, set_size);
1584                 memset(wset, 0, set_size);
1585
1586                 /*
1587                  * Ensure that we can read a full buffer and handle
1588                  * the worst-case length packet it can generate,
1589                  * otherwise apply backpressure by stopping reads.
1590                  */
1591                 if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
1592                     buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1593                         FD_SET(in, rset);
1594
1595                 olen = buffer_len(&oqueue);
1596                 if (olen > 0)
1597                         FD_SET(out, wset);
1598
1599                 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1600                         if (errno == EINTR)
1601                                 continue;
1602                         error("select: %s", strerror(errno));
1603                         sftp_server_cleanup_exit(2);
1604                 }
1605
1606                 /* copy stdin to iqueue */
1607                 if (FD_ISSET(in, rset)) {
1608                         len = read(in, buf, sizeof buf);
1609                         if (len == 0) {
1610                                 debug("read eof");
1611                                 sftp_server_cleanup_exit(0);
1612                         } else if (len < 0) {
1613                                 error("read: %s", strerror(errno));
1614                                 sftp_server_cleanup_exit(1);
1615                         } else {
1616                                 buffer_append(&iqueue, buf, len);
1617                         }
1618                 }
1619                 /* send oqueue to stdout */
1620                 if (FD_ISSET(out, wset)) {
1621                         len = write(out, buffer_ptr(&oqueue), olen);
1622                         if (len < 0) {
1623                                 error("write: %s", strerror(errno));
1624                                 sftp_server_cleanup_exit(1);
1625                         } else {
1626                                 buffer_consume(&oqueue, len);
1627                         }
1628                 }
1629
1630                 /*
1631                  * Process requests from client if we can fit the results
1632                  * into the output buffer, otherwise stop processing input
1633                  * and let the output queue drain.
1634                  */
1635                 if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1636                         process();
1637         }
1638 }