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