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