sftp-server.c revision 255767
1235783Skib/* $OpenBSD: sftp-server.c,v 1.97 2013/05/17 00:13:14 djm Exp $ */
2235783Skib/*
3235783Skib * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
4235783Skib *
5235783Skib * Permission to use, copy, modify, and distribute this software for any
6235783Skib * purpose with or without fee is hereby granted, provided that the above
7235783Skib * copyright notice and this permission notice appear in all copies.
8235783Skib *
9235783Skib * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10235783Skib * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11235783Skib * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12235783Skib * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13235783Skib * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14235783Skib * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15235783Skib * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16235783Skib */
17235783Skib
18235783Skib#include "includes.h"
19235783Skib
20235783Skib#include <sys/types.h>
21235783Skib#include <sys/param.h>
22235783Skib#include <sys/stat.h>
23235783Skib#ifdef HAVE_SYS_TIME_H
24235783Skib# include <sys/time.h>
25235783Skib#endif
26235783Skib#ifdef HAVE_SYS_MOUNT_H
27235783Skib#include <sys/mount.h>
28235783Skib#endif
29235783Skib#ifdef HAVE_SYS_STATVFS_H
30235783Skib#include <sys/statvfs.h>
31235783Skib#endif
32235783Skib
33235783Skib#include <dirent.h>
34235783Skib#include <errno.h>
35235783Skib#include <fcntl.h>
36235783Skib#include <pwd.h>
37235783Skib#include <stdlib.h>
38235783Skib#include <stdio.h>
39235783Skib#include <string.h>
40235783Skib#include <pwd.h>
41235783Skib#include <time.h>
42235783Skib#include <unistd.h>
43235783Skib#include <stdarg.h>
44235783Skib
45235783Skib#include "xmalloc.h"
46235783Skib#include "buffer.h"
47235783Skib#include "log.h"
48235783Skib#include "misc.h"
49235783Skib#include "uidswap.h"
50235783Skib
51235783Skib#include "sftp.h"
52235783Skib#include "sftp-common.h"
53235783Skib
54235783Skib/* helper */
55235783Skib#define get_int64()			buffer_get_int64(&iqueue);
56235783Skib#define get_int()			buffer_get_int(&iqueue);
57235783Skib#define get_string(lenp)		buffer_get_string(&iqueue, lenp);
58235783Skib
59235783Skib/* Our verbosity */
60235783SkibLogLevel log_level = SYSLOG_LEVEL_ERROR;
61235783Skib
62235783Skib/* Our client */
63235783Skibstruct passwd *pw = NULL;
64235783Skibchar *client_addr = NULL;
65235783Skib
66235783Skib/* input and output queue */
67235783SkibBuffer iqueue;
68235783SkibBuffer oqueue;
69235783Skib
70235783Skib/* Version of client */
71235783Skibu_int version;
72235783Skib
73235783Skib/* Disable writes */
74235783Skibint readonly;
75235783Skib
76235783Skib/* portable attributes, etc. */
77235783Skib
78235783Skibtypedef struct Stat Stat;
79235783Skib
80235783Skibstruct Stat {
81235783Skib	char *name;
82235783Skib	char *long_name;
83235783Skib	Attrib attrib;
84235783Skib};
85235783Skib
86235783Skibstatic int
87235783Skiberrno_to_portable(int unixerrno)
88235783Skib{
89235783Skib	int ret = 0;
90235783Skib
91235783Skib	switch (unixerrno) {
92235783Skib	case 0:
93235783Skib		ret = SSH2_FX_OK;
94235783Skib		break;
95235783Skib	case ENOENT:
96235783Skib	case ENOTDIR:
97235783Skib	case EBADF:
98235783Skib	case ELOOP:
99235783Skib		ret = SSH2_FX_NO_SUCH_FILE;
100235783Skib		break;
101235783Skib	case EPERM:
102235783Skib	case EACCES:
103235783Skib	case EFAULT:
104235783Skib		ret = SSH2_FX_PERMISSION_DENIED;
105235783Skib		break;
106235783Skib	case ENAMETOOLONG:
107235783Skib	case EINVAL:
108235783Skib		ret = SSH2_FX_BAD_MESSAGE;
109235783Skib		break;
110235783Skib	case ENOSYS:
111235783Skib		ret = SSH2_FX_OP_UNSUPPORTED;
112235783Skib		break;
113235783Skib	default:
114235783Skib		ret = SSH2_FX_FAILURE;
115235783Skib		break;
116235783Skib	}
117235783Skib	return ret;
118235783Skib}
119235783Skib
120235783Skibstatic int
121235783Skibflags_from_portable(int pflags)
122235783Skib{
123235783Skib	int flags = 0;
124235783Skib
125235783Skib	if ((pflags & SSH2_FXF_READ) &&
126235783Skib	    (pflags & SSH2_FXF_WRITE)) {
127235783Skib		flags = O_RDWR;
128235783Skib	} else if (pflags & SSH2_FXF_READ) {
129235783Skib		flags = O_RDONLY;
130235783Skib	} else if (pflags & SSH2_FXF_WRITE) {
131235783Skib		flags = O_WRONLY;
132235783Skib	}
133235783Skib	if (pflags & SSH2_FXF_CREAT)
134235783Skib		flags |= O_CREAT;
135235783Skib	if (pflags & SSH2_FXF_TRUNC)
136235783Skib		flags |= O_TRUNC;
137235783Skib	if (pflags & SSH2_FXF_EXCL)
138235783Skib		flags |= O_EXCL;
139235783Skib	return flags;
140235783Skib}
141235783Skib
142235783Skibstatic const char *
143235783Skibstring_from_portable(int pflags)
144235783Skib{
145235783Skib	static char ret[128];
146235783Skib
147235783Skib	*ret = '\0';
148235783Skib
149235783Skib#define PAPPEND(str)	{				\
150235783Skib		if (*ret != '\0')			\
151235783Skib			strlcat(ret, ",", sizeof(ret));	\
152235783Skib		strlcat(ret, str, sizeof(ret));		\
153235783Skib	}
154235783Skib
155235783Skib	if (pflags & SSH2_FXF_READ)
156235783Skib		PAPPEND("READ")
157235783Skib	if (pflags & SSH2_FXF_WRITE)
158235783Skib		PAPPEND("WRITE")
159235783Skib	if (pflags & SSH2_FXF_CREAT)
160235783Skib		PAPPEND("CREATE")
161235783Skib	if (pflags & SSH2_FXF_TRUNC)
162235783Skib		PAPPEND("TRUNCATE")
163235783Skib	if (pflags & SSH2_FXF_EXCL)
164235783Skib		PAPPEND("EXCL")
165235783Skib
166235783Skib	return ret;
167235783Skib}
168235783Skib
169235783Skibstatic Attrib *
170235783Skibget_attrib(void)
171235783Skib{
172235783Skib	return decode_attrib(&iqueue);
173235783Skib}
174235783Skib
175235783Skib/* handle handles */
176235783Skib
177235783Skibtypedef struct Handle Handle;
178235783Skibstruct Handle {
179235783Skib	int use;
180235783Skib	DIR *dirp;
181235783Skib	int fd;
182235783Skib	char *name;
183235783Skib	u_int64_t bytes_read, bytes_write;
184235783Skib	int next_unused;
185235783Skib};
186235783Skib
187235783Skibenum {
188235783Skib	HANDLE_UNUSED,
189235783Skib	HANDLE_DIR,
190235783Skib	HANDLE_FILE
191235783Skib};
192235783Skib
193235783SkibHandle *handles = NULL;
194235783Skibu_int num_handles = 0;
195235783Skibint first_unused_handle = -1;
196235783Skib
197235783Skibstatic void handle_unused(int i)
198235783Skib{
199235783Skib	handles[i].use = HANDLE_UNUSED;
200235783Skib	handles[i].next_unused = first_unused_handle;
201235783Skib	first_unused_handle = i;
202235783Skib}
203235783Skib
204235783Skibstatic int
205235783Skibhandle_new(int use, const char *name, int fd, DIR *dirp)
206235783Skib{
207235783Skib	int i;
208235783Skib
209235783Skib	if (first_unused_handle == -1) {
210235783Skib		if (num_handles + 1 <= num_handles)
211235783Skib			return -1;
212235783Skib		num_handles++;
213235783Skib		handles = xrealloc(handles, num_handles, sizeof(Handle));
214235783Skib		handle_unused(num_handles - 1);
215235783Skib	}
216235783Skib
217235783Skib	i = first_unused_handle;
218235783Skib	first_unused_handle = handles[i].next_unused;
219235783Skib
220235783Skib	handles[i].use = use;
221235783Skib	handles[i].dirp = dirp;
222235783Skib	handles[i].fd = fd;
223235783Skib	handles[i].name = xstrdup(name);
224235783Skib	handles[i].bytes_read = handles[i].bytes_write = 0;
225235783Skib
226235783Skib	return i;
227235783Skib}
228235783Skib
229235783Skibstatic int
230235783Skibhandle_is_ok(int i, int type)
231235783Skib{
232235783Skib	return i >= 0 && (u_int)i < num_handles && handles[i].use == type;
233235783Skib}
234235783Skib
235235783Skibstatic int
236235783Skibhandle_to_string(int handle, char **stringp, int *hlenp)
237235783Skib{
238235783Skib	if (stringp == NULL || hlenp == NULL)
239235783Skib		return -1;
240235783Skib	*stringp = xmalloc(sizeof(int32_t));
241235783Skib	put_u32(*stringp, handle);
242235783Skib	*hlenp = sizeof(int32_t);
243235783Skib	return 0;
244235783Skib}
245235783Skib
246235783Skibstatic int
247235783Skibhandle_from_string(const char *handle, u_int hlen)
248235783Skib{
249235783Skib	int val;
250235783Skib
251235783Skib	if (hlen != sizeof(int32_t))
252235783Skib		return -1;
253235783Skib	val = get_u32(handle);
254235783Skib	if (handle_is_ok(val, HANDLE_FILE) ||
255235783Skib	    handle_is_ok(val, HANDLE_DIR))
256235783Skib		return val;
257235783Skib	return -1;
258235783Skib}
259235783Skib
260235783Skibstatic char *
261235783Skibhandle_to_name(int handle)
262235783Skib{
263235783Skib	if (handle_is_ok(handle, HANDLE_DIR)||
264235783Skib	    handle_is_ok(handle, HANDLE_FILE))
265235783Skib		return handles[handle].name;
266235783Skib	return NULL;
267235783Skib}
268235783Skib
269235783Skibstatic DIR *
270235783Skibhandle_to_dir(int handle)
271235783Skib{
272235783Skib	if (handle_is_ok(handle, HANDLE_DIR))
273235783Skib		return handles[handle].dirp;
274235783Skib	return NULL;
275235783Skib}
276235783Skib
277235783Skibstatic int
278235783Skibhandle_to_fd(int handle)
279235783Skib{
280235783Skib	if (handle_is_ok(handle, HANDLE_FILE))
281235783Skib		return handles[handle].fd;
282235783Skib	return -1;
283235783Skib}
284235783Skib
285235783Skibstatic void
286235783Skibhandle_update_read(int handle, ssize_t bytes)
287235783Skib{
288235783Skib	if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
289235783Skib		handles[handle].bytes_read += bytes;
290235783Skib}
291235783Skib
292235783Skibstatic void
293235783Skibhandle_update_write(int handle, ssize_t bytes)
294235783Skib{
295235783Skib	if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
296235783Skib		handles[handle].bytes_write += bytes;
297235783Skib}
298235783Skib
299235783Skibstatic u_int64_t
300235783Skibhandle_bytes_read(int handle)
301235783Skib{
302235783Skib	if (handle_is_ok(handle, HANDLE_FILE))
303235783Skib		return (handles[handle].bytes_read);
304235783Skib	return 0;
305235783Skib}
306235783Skib
307235783Skibstatic u_int64_t
308235783Skibhandle_bytes_write(int handle)
309235783Skib{
310235783Skib	if (handle_is_ok(handle, HANDLE_FILE))
311235783Skib		return (handles[handle].bytes_write);
312235783Skib	return 0;
313235783Skib}
314235783Skib
315235783Skibstatic int
316235783Skibhandle_close(int handle)
317235783Skib{
318235783Skib	int ret = -1;
319235783Skib
320235783Skib	if (handle_is_ok(handle, HANDLE_FILE)) {
321235783Skib		ret = close(handles[handle].fd);
322235783Skib		free(handles[handle].name);
323235783Skib		handle_unused(handle);
324235783Skib	} else if (handle_is_ok(handle, HANDLE_DIR)) {
325235783Skib		ret = closedir(handles[handle].dirp);
326235783Skib		free(handles[handle].name);
327235783Skib		handle_unused(handle);
328235783Skib	} else {
329235783Skib		errno = ENOENT;
330235783Skib	}
331235783Skib	return ret;
332235783Skib}
333235783Skib
334235783Skibstatic void
335235783Skibhandle_log_close(int handle, char *emsg)
336235783Skib{
337235783Skib	if (handle_is_ok(handle, HANDLE_FILE)) {
338235783Skib		logit("%s%sclose \"%s\" bytes read %llu written %llu",
339235783Skib		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
340235783Skib		    handle_to_name(handle),
341235783Skib		    (unsigned long long)handle_bytes_read(handle),
342235783Skib		    (unsigned long long)handle_bytes_write(handle));
343235783Skib	} else {
344235783Skib		logit("%s%sclosedir \"%s\"",
345235783Skib		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
346235783Skib		    handle_to_name(handle));
347235783Skib	}
348235783Skib}
349235783Skib
350235783Skibstatic void
351235783Skibhandle_log_exit(void)
352235783Skib{
353235783Skib	u_int i;
354235783Skib
355235783Skib	for (i = 0; i < num_handles; i++)
356235783Skib		if (handles[i].use != HANDLE_UNUSED)
357235783Skib			handle_log_close(i, "forced");
358235783Skib}
359235783Skib
360235783Skibstatic int
361235783Skibget_handle(void)
362235783Skib{
363235783Skib	char *handle;
364235783Skib	int val = -1;
365235783Skib	u_int hlen;
366235783Skib
367235783Skib	handle = get_string(&hlen);
368235783Skib	if (hlen < 256)
369235783Skib		val = handle_from_string(handle, hlen);
370235783Skib	free(handle);
371235783Skib	return val;
372235783Skib}
373235783Skib
374235783Skib/* send replies */
375235783Skib
376235783Skibstatic void
377235783Skibsend_msg(Buffer *m)
378235783Skib{
379235783Skib	int mlen = buffer_len(m);
380235783Skib
381235783Skib	buffer_put_int(&oqueue, mlen);
382235783Skib	buffer_append(&oqueue, buffer_ptr(m), mlen);
383235783Skib	buffer_consume(m, mlen);
384235783Skib}
385235783Skib
386235783Skibstatic const char *
387235783Skibstatus_to_message(u_int32_t status)
388235783Skib{
389235783Skib	const char *status_messages[] = {
390235783Skib		"Success",			/* SSH_FX_OK */
391235783Skib		"End of file",			/* SSH_FX_EOF */
392235783Skib		"No such file",			/* SSH_FX_NO_SUCH_FILE */
393235783Skib		"Permission denied",		/* SSH_FX_PERMISSION_DENIED */
394235783Skib		"Failure",			/* SSH_FX_FAILURE */
395235783Skib		"Bad message",			/* SSH_FX_BAD_MESSAGE */
396235783Skib		"No connection",		/* SSH_FX_NO_CONNECTION */
397235783Skib		"Connection lost",		/* SSH_FX_CONNECTION_LOST */
398235783Skib		"Operation unsupported",	/* SSH_FX_OP_UNSUPPORTED */
399235783Skib		"Unknown error"			/* Others */
400235783Skib	};
401235783Skib	return (status_messages[MIN(status,SSH2_FX_MAX)]);
402235783Skib}
403235783Skib
404235783Skibstatic void
405235783Skibsend_status(u_int32_t id, u_int32_t status)
406235783Skib{
407235783Skib	Buffer msg;
408235783Skib
409235783Skib	debug3("request %u: sent status %u", id, status);
410235783Skib	if (log_level > SYSLOG_LEVEL_VERBOSE ||
411235783Skib	    (status != SSH2_FX_OK && status != SSH2_FX_EOF))
412235783Skib		logit("sent status %s", status_to_message(status));
413235783Skib	buffer_init(&msg);
414235783Skib	buffer_put_char(&msg, SSH2_FXP_STATUS);
415235783Skib	buffer_put_int(&msg, id);
416235783Skib	buffer_put_int(&msg, status);
417235783Skib	if (version >= 3) {
418235783Skib		buffer_put_cstring(&msg, status_to_message(status));
419235783Skib		buffer_put_cstring(&msg, "");
420235783Skib	}
421235783Skib	send_msg(&msg);
422235783Skib	buffer_free(&msg);
423235783Skib}
424235783Skibstatic void
425235783Skibsend_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
426235783Skib{
427235783Skib	Buffer msg;
428235783Skib
429235783Skib	buffer_init(&msg);
430235783Skib	buffer_put_char(&msg, type);
431235783Skib	buffer_put_int(&msg, id);
432235783Skib	buffer_put_string(&msg, data, dlen);
433235783Skib	send_msg(&msg);
434235783Skib	buffer_free(&msg);
435235783Skib}
436235783Skib
437235783Skibstatic void
438235783Skibsend_data(u_int32_t id, const char *data, int dlen)
439235783Skib{
440235783Skib	debug("request %u: sent data len %d", id, dlen);
441235783Skib	send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
442235783Skib}
443235783Skib
444235783Skibstatic void
445send_handle(u_int32_t id, int handle)
446{
447	char *string;
448	int hlen;
449
450	handle_to_string(handle, &string, &hlen);
451	debug("request %u: sent handle handle %d", id, handle);
452	send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
453	free(string);
454}
455
456static void
457send_names(u_int32_t id, int count, const Stat *stats)
458{
459	Buffer msg;
460	int i;
461
462	buffer_init(&msg);
463	buffer_put_char(&msg, SSH2_FXP_NAME);
464	buffer_put_int(&msg, id);
465	buffer_put_int(&msg, count);
466	debug("request %u: sent names count %d", id, count);
467	for (i = 0; i < count; i++) {
468		buffer_put_cstring(&msg, stats[i].name);
469		buffer_put_cstring(&msg, stats[i].long_name);
470		encode_attrib(&msg, &stats[i].attrib);
471	}
472	send_msg(&msg);
473	buffer_free(&msg);
474}
475
476static void
477send_attrib(u_int32_t id, const Attrib *a)
478{
479	Buffer msg;
480
481	debug("request %u: sent attrib have 0x%x", id, a->flags);
482	buffer_init(&msg);
483	buffer_put_char(&msg, SSH2_FXP_ATTRS);
484	buffer_put_int(&msg, id);
485	encode_attrib(&msg, a);
486	send_msg(&msg);
487	buffer_free(&msg);
488}
489
490static void
491send_statvfs(u_int32_t id, struct statvfs *st)
492{
493	Buffer msg;
494	u_int64_t flag;
495
496	flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
497	flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
498
499	buffer_init(&msg);
500	buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
501	buffer_put_int(&msg, id);
502	buffer_put_int64(&msg, st->f_bsize);
503	buffer_put_int64(&msg, st->f_frsize);
504	buffer_put_int64(&msg, st->f_blocks);
505	buffer_put_int64(&msg, st->f_bfree);
506	buffer_put_int64(&msg, st->f_bavail);
507	buffer_put_int64(&msg, st->f_files);
508	buffer_put_int64(&msg, st->f_ffree);
509	buffer_put_int64(&msg, st->f_favail);
510	buffer_put_int64(&msg, FSID_TO_ULONG(st->f_fsid));
511	buffer_put_int64(&msg, flag);
512	buffer_put_int64(&msg, st->f_namemax);
513	send_msg(&msg);
514	buffer_free(&msg);
515}
516
517/* parse incoming */
518
519static void
520process_init(void)
521{
522	Buffer msg;
523
524	version = get_int();
525	verbose("received client version %u", version);
526	buffer_init(&msg);
527	buffer_put_char(&msg, SSH2_FXP_VERSION);
528	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
529	/* POSIX rename extension */
530	buffer_put_cstring(&msg, "posix-rename@openssh.com");
531	buffer_put_cstring(&msg, "1"); /* version */
532	/* statvfs extension */
533	buffer_put_cstring(&msg, "statvfs@openssh.com");
534	buffer_put_cstring(&msg, "2"); /* version */
535	/* fstatvfs extension */
536	buffer_put_cstring(&msg, "fstatvfs@openssh.com");
537	buffer_put_cstring(&msg, "2"); /* version */
538	/* hardlink extension */
539	buffer_put_cstring(&msg, "hardlink@openssh.com");
540	buffer_put_cstring(&msg, "1"); /* version */
541	send_msg(&msg);
542	buffer_free(&msg);
543}
544
545static void
546process_open(void)
547{
548	u_int32_t id, pflags;
549	Attrib *a;
550	char *name;
551	int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
552
553	id = get_int();
554	name = get_string(NULL);
555	pflags = get_int();		/* portable flags */
556	debug3("request %u: open flags %d", id, pflags);
557	a = get_attrib();
558	flags = flags_from_portable(pflags);
559	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
560	logit("open \"%s\" flags %s mode 0%o",
561	    name, string_from_portable(pflags), mode);
562	if (readonly &&
563	    ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR))
564		status = SSH2_FX_PERMISSION_DENIED;
565	else {
566		fd = open(name, flags, mode);
567		if (fd < 0) {
568			status = errno_to_portable(errno);
569		} else {
570			handle = handle_new(HANDLE_FILE, name, fd, NULL);
571			if (handle < 0) {
572				close(fd);
573			} else {
574				send_handle(id, handle);
575				status = SSH2_FX_OK;
576			}
577		}
578	}
579	if (status != SSH2_FX_OK)
580		send_status(id, status);
581	free(name);
582}
583
584static void
585process_close(void)
586{
587	u_int32_t id;
588	int handle, ret, status = SSH2_FX_FAILURE;
589
590	id = get_int();
591	handle = get_handle();
592	debug3("request %u: close handle %u", id, handle);
593	handle_log_close(handle, NULL);
594	ret = handle_close(handle);
595	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
596	send_status(id, status);
597}
598
599static void
600process_read(void)
601{
602	char buf[64*1024];
603	u_int32_t id, len;
604	int handle, fd, ret, status = SSH2_FX_FAILURE;
605	u_int64_t off;
606
607	id = get_int();
608	handle = get_handle();
609	off = get_int64();
610	len = get_int();
611
612	debug("request %u: read \"%s\" (handle %d) off %llu len %d",
613	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
614	if (len > sizeof buf) {
615		len = sizeof buf;
616		debug2("read change len %d", len);
617	}
618	fd = handle_to_fd(handle);
619	if (fd >= 0) {
620		if (lseek(fd, off, SEEK_SET) < 0) {
621			error("process_read: seek failed");
622			status = errno_to_portable(errno);
623		} else {
624			ret = read(fd, buf, len);
625			if (ret < 0) {
626				status = errno_to_portable(errno);
627			} else if (ret == 0) {
628				status = SSH2_FX_EOF;
629			} else {
630				send_data(id, buf, ret);
631				status = SSH2_FX_OK;
632				handle_update_read(handle, ret);
633			}
634		}
635	}
636	if (status != SSH2_FX_OK)
637		send_status(id, status);
638}
639
640static void
641process_write(void)
642{
643	u_int32_t id;
644	u_int64_t off;
645	u_int len;
646	int handle, fd, ret, status;
647	char *data;
648
649	id = get_int();
650	handle = get_handle();
651	off = get_int64();
652	data = get_string(&len);
653
654	debug("request %u: write \"%s\" (handle %d) off %llu len %d",
655	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
656	fd = handle_to_fd(handle);
657
658	if (fd < 0)
659		status = SSH2_FX_FAILURE;
660	else if (readonly)
661		status = SSH2_FX_PERMISSION_DENIED;
662	else {
663		if (lseek(fd, off, SEEK_SET) < 0) {
664			status = errno_to_portable(errno);
665			error("process_write: seek failed");
666		} else {
667/* XXX ATOMICIO ? */
668			ret = write(fd, data, len);
669			if (ret < 0) {
670				error("process_write: write failed");
671				status = errno_to_portable(errno);
672			} else if ((size_t)ret == len) {
673				status = SSH2_FX_OK;
674				handle_update_write(handle, ret);
675			} else {
676				debug2("nothing at all written");
677				status = SSH2_FX_FAILURE;
678			}
679		}
680	}
681	send_status(id, status);
682	free(data);
683}
684
685static void
686process_do_stat(int do_lstat)
687{
688	Attrib a;
689	struct stat st;
690	u_int32_t id;
691	char *name;
692	int ret, status = SSH2_FX_FAILURE;
693
694	id = get_int();
695	name = get_string(NULL);
696	debug3("request %u: %sstat", id, do_lstat ? "l" : "");
697	verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
698	ret = do_lstat ? lstat(name, &st) : stat(name, &st);
699	if (ret < 0) {
700		status = errno_to_portable(errno);
701	} else {
702		stat_to_attrib(&st, &a);
703		send_attrib(id, &a);
704		status = SSH2_FX_OK;
705	}
706	if (status != SSH2_FX_OK)
707		send_status(id, status);
708	free(name);
709}
710
711static void
712process_stat(void)
713{
714	process_do_stat(0);
715}
716
717static void
718process_lstat(void)
719{
720	process_do_stat(1);
721}
722
723static void
724process_fstat(void)
725{
726	Attrib a;
727	struct stat st;
728	u_int32_t id;
729	int fd, ret, handle, status = SSH2_FX_FAILURE;
730
731	id = get_int();
732	handle = get_handle();
733	debug("request %u: fstat \"%s\" (handle %u)",
734	    id, handle_to_name(handle), handle);
735	fd = handle_to_fd(handle);
736	if (fd >= 0) {
737		ret = fstat(fd, &st);
738		if (ret < 0) {
739			status = errno_to_portable(errno);
740		} else {
741			stat_to_attrib(&st, &a);
742			send_attrib(id, &a);
743			status = SSH2_FX_OK;
744		}
745	}
746	if (status != SSH2_FX_OK)
747		send_status(id, status);
748}
749
750static struct timeval *
751attrib_to_tv(const Attrib *a)
752{
753	static struct timeval tv[2];
754
755	tv[0].tv_sec = a->atime;
756	tv[0].tv_usec = 0;
757	tv[1].tv_sec = a->mtime;
758	tv[1].tv_usec = 0;
759	return tv;
760}
761
762static void
763process_setstat(void)
764{
765	Attrib *a;
766	u_int32_t id;
767	char *name;
768	int status = SSH2_FX_OK, ret;
769
770	id = get_int();
771	name = get_string(NULL);
772	a = get_attrib();
773	debug("request %u: setstat name \"%s\"", id, name);
774	if (readonly) {
775		status = SSH2_FX_PERMISSION_DENIED;
776		a->flags = 0;
777	}
778	if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
779		logit("set \"%s\" size %llu",
780		    name, (unsigned long long)a->size);
781		ret = truncate(name, a->size);
782		if (ret == -1)
783			status = errno_to_portable(errno);
784	}
785	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
786		logit("set \"%s\" mode %04o", name, a->perm);
787		ret = chmod(name, a->perm & 07777);
788		if (ret == -1)
789			status = errno_to_portable(errno);
790	}
791	if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
792		char buf[64];
793		time_t t = a->mtime;
794
795		strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
796		    localtime(&t));
797		logit("set \"%s\" modtime %s", name, buf);
798		ret = utimes(name, attrib_to_tv(a));
799		if (ret == -1)
800			status = errno_to_portable(errno);
801	}
802	if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
803		logit("set \"%s\" owner %lu group %lu", name,
804		    (u_long)a->uid, (u_long)a->gid);
805		ret = chown(name, a->uid, a->gid);
806		if (ret == -1)
807			status = errno_to_portable(errno);
808	}
809	send_status(id, status);
810	free(name);
811}
812
813static void
814process_fsetstat(void)
815{
816	Attrib *a;
817	u_int32_t id;
818	int handle, fd, ret;
819	int status = SSH2_FX_OK;
820
821	id = get_int();
822	handle = get_handle();
823	a = get_attrib();
824	debug("request %u: fsetstat handle %d", id, handle);
825	fd = handle_to_fd(handle);
826	if (fd < 0)
827		status = SSH2_FX_FAILURE;
828	else if (readonly)
829		status = SSH2_FX_PERMISSION_DENIED;
830	else {
831		char *name = handle_to_name(handle);
832
833		if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
834			logit("set \"%s\" size %llu",
835			    name, (unsigned long long)a->size);
836			ret = ftruncate(fd, a->size);
837			if (ret == -1)
838				status = errno_to_portable(errno);
839		}
840		if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
841			logit("set \"%s\" mode %04o", name, a->perm);
842#ifdef HAVE_FCHMOD
843			ret = fchmod(fd, a->perm & 07777);
844#else
845			ret = chmod(name, a->perm & 07777);
846#endif
847			if (ret == -1)
848				status = errno_to_portable(errno);
849		}
850		if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
851			char buf[64];
852			time_t t = a->mtime;
853
854			strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
855			    localtime(&t));
856			logit("set \"%s\" modtime %s", name, buf);
857#ifdef HAVE_FUTIMES
858			ret = futimes(fd, attrib_to_tv(a));
859#else
860			ret = utimes(name, attrib_to_tv(a));
861#endif
862			if (ret == -1)
863				status = errno_to_portable(errno);
864		}
865		if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
866			logit("set \"%s\" owner %lu group %lu", name,
867			    (u_long)a->uid, (u_long)a->gid);
868#ifdef HAVE_FCHOWN
869			ret = fchown(fd, a->uid, a->gid);
870#else
871			ret = chown(name, a->uid, a->gid);
872#endif
873			if (ret == -1)
874				status = errno_to_portable(errno);
875		}
876	}
877	send_status(id, status);
878}
879
880static void
881process_opendir(void)
882{
883	DIR *dirp = NULL;
884	char *path;
885	int handle, status = SSH2_FX_FAILURE;
886	u_int32_t id;
887
888	id = get_int();
889	path = get_string(NULL);
890	debug3("request %u: opendir", id);
891	logit("opendir \"%s\"", path);
892	dirp = opendir(path);
893	if (dirp == NULL) {
894		status = errno_to_portable(errno);
895	} else {
896		handle = handle_new(HANDLE_DIR, path, 0, dirp);
897		if (handle < 0) {
898			closedir(dirp);
899		} else {
900			send_handle(id, handle);
901			status = SSH2_FX_OK;
902		}
903
904	}
905	if (status != SSH2_FX_OK)
906		send_status(id, status);
907	free(path);
908}
909
910static void
911process_readdir(void)
912{
913	DIR *dirp;
914	struct dirent *dp;
915	char *path;
916	int handle;
917	u_int32_t id;
918
919	id = get_int();
920	handle = get_handle();
921	debug("request %u: readdir \"%s\" (handle %d)", id,
922	    handle_to_name(handle), handle);
923	dirp = handle_to_dir(handle);
924	path = handle_to_name(handle);
925	if (dirp == NULL || path == NULL) {
926		send_status(id, SSH2_FX_FAILURE);
927	} else {
928		struct stat st;
929		char pathname[MAXPATHLEN];
930		Stat *stats;
931		int nstats = 10, count = 0, i;
932
933		stats = xcalloc(nstats, sizeof(Stat));
934		while ((dp = readdir(dirp)) != NULL) {
935			if (count >= nstats) {
936				nstats *= 2;
937				stats = xrealloc(stats, nstats, sizeof(Stat));
938			}
939/* XXX OVERFLOW ? */
940			snprintf(pathname, sizeof pathname, "%s%s%s", path,
941			    strcmp(path, "/") ? "/" : "", dp->d_name);
942			if (lstat(pathname, &st) < 0)
943				continue;
944			stat_to_attrib(&st, &(stats[count].attrib));
945			stats[count].name = xstrdup(dp->d_name);
946			stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
947			count++;
948			/* send up to 100 entries in one message */
949			/* XXX check packet size instead */
950			if (count == 100)
951				break;
952		}
953		if (count > 0) {
954			send_names(id, count, stats);
955			for (i = 0; i < count; i++) {
956				free(stats[i].name);
957				free(stats[i].long_name);
958			}
959		} else {
960			send_status(id, SSH2_FX_EOF);
961		}
962		free(stats);
963	}
964}
965
966static void
967process_remove(void)
968{
969	char *name;
970	u_int32_t id;
971	int status = SSH2_FX_FAILURE;
972	int ret;
973
974	id = get_int();
975	name = get_string(NULL);
976	debug3("request %u: remove", id);
977	logit("remove name \"%s\"", name);
978	if (readonly)
979		status = SSH2_FX_PERMISSION_DENIED;
980	else {
981		ret = unlink(name);
982		status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
983	}
984	send_status(id, status);
985	free(name);
986}
987
988static void
989process_mkdir(void)
990{
991	Attrib *a;
992	u_int32_t id;
993	char *name;
994	int ret, mode, status = SSH2_FX_FAILURE;
995
996	id = get_int();
997	name = get_string(NULL);
998	a = get_attrib();
999	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
1000	    a->perm & 07777 : 0777;
1001	debug3("request %u: mkdir", id);
1002	logit("mkdir name \"%s\" mode 0%o", name, mode);
1003	if (readonly)
1004		status = SSH2_FX_PERMISSION_DENIED;
1005	else {
1006		ret = mkdir(name, mode);
1007		status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1008	}
1009	send_status(id, status);
1010	free(name);
1011}
1012
1013static void
1014process_rmdir(void)
1015{
1016	u_int32_t id;
1017	char *name;
1018	int ret, status;
1019
1020	id = get_int();
1021	name = get_string(NULL);
1022	debug3("request %u: rmdir", id);
1023	logit("rmdir name \"%s\"", name);
1024	if (readonly)
1025		status = SSH2_FX_PERMISSION_DENIED;
1026	else {
1027		ret = rmdir(name);
1028		status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1029	}
1030	send_status(id, status);
1031	free(name);
1032}
1033
1034static void
1035process_realpath(void)
1036{
1037	char resolvedname[MAXPATHLEN];
1038	u_int32_t id;
1039	char *path;
1040
1041	id = get_int();
1042	path = get_string(NULL);
1043	if (path[0] == '\0') {
1044		free(path);
1045		path = xstrdup(".");
1046	}
1047	debug3("request %u: realpath", id);
1048	verbose("realpath \"%s\"", path);
1049	if (realpath(path, resolvedname) == NULL) {
1050		send_status(id, errno_to_portable(errno));
1051	} else {
1052		Stat s;
1053		attrib_clear(&s.attrib);
1054		s.name = s.long_name = resolvedname;
1055		send_names(id, 1, &s);
1056	}
1057	free(path);
1058}
1059
1060static void
1061process_rename(void)
1062{
1063	u_int32_t id;
1064	char *oldpath, *newpath;
1065	int status;
1066	struct stat sb;
1067
1068	id = get_int();
1069	oldpath = get_string(NULL);
1070	newpath = get_string(NULL);
1071	debug3("request %u: rename", id);
1072	logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1073	status = SSH2_FX_FAILURE;
1074	if (readonly)
1075		status = SSH2_FX_PERMISSION_DENIED;
1076	else if (lstat(oldpath, &sb) == -1)
1077		status = errno_to_portable(errno);
1078	else if (S_ISREG(sb.st_mode)) {
1079		/* Race-free rename of regular files */
1080		if (link(oldpath, newpath) == -1) {
1081			if (errno == EOPNOTSUPP || errno == ENOSYS
1082#ifdef EXDEV
1083			    || errno == EXDEV
1084#endif
1085#ifdef LINK_OPNOTSUPP_ERRNO
1086			    || errno == LINK_OPNOTSUPP_ERRNO
1087#endif
1088			    ) {
1089				struct stat st;
1090
1091				/*
1092				 * fs doesn't support links, so fall back to
1093				 * stat+rename.  This is racy.
1094				 */
1095				if (stat(newpath, &st) == -1) {
1096					if (rename(oldpath, newpath) == -1)
1097						status =
1098						    errno_to_portable(errno);
1099					else
1100						status = SSH2_FX_OK;
1101				}
1102			} else {
1103				status = errno_to_portable(errno);
1104			}
1105		} else if (unlink(oldpath) == -1) {
1106			status = errno_to_portable(errno);
1107			/* clean spare link */
1108			unlink(newpath);
1109		} else
1110			status = SSH2_FX_OK;
1111	} else if (stat(newpath, &sb) == -1) {
1112		if (rename(oldpath, newpath) == -1)
1113			status = errno_to_portable(errno);
1114		else
1115			status = SSH2_FX_OK;
1116	}
1117	send_status(id, status);
1118	free(oldpath);
1119	free(newpath);
1120}
1121
1122static void
1123process_readlink(void)
1124{
1125	u_int32_t id;
1126	int len;
1127	char buf[MAXPATHLEN];
1128	char *path;
1129
1130	id = get_int();
1131	path = get_string(NULL);
1132	debug3("request %u: readlink", id);
1133	verbose("readlink \"%s\"", path);
1134	if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1135		send_status(id, errno_to_portable(errno));
1136	else {
1137		Stat s;
1138
1139		buf[len] = '\0';
1140		attrib_clear(&s.attrib);
1141		s.name = s.long_name = buf;
1142		send_names(id, 1, &s);
1143	}
1144	free(path);
1145}
1146
1147static void
1148process_symlink(void)
1149{
1150	u_int32_t id;
1151	char *oldpath, *newpath;
1152	int ret, status;
1153
1154	id = get_int();
1155	oldpath = get_string(NULL);
1156	newpath = get_string(NULL);
1157	debug3("request %u: symlink", id);
1158	logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1159	/* this will fail if 'newpath' exists */
1160	if (readonly)
1161		status = SSH2_FX_PERMISSION_DENIED;
1162	else {
1163		ret = symlink(oldpath, newpath);
1164		status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1165	}
1166	send_status(id, status);
1167	free(oldpath);
1168	free(newpath);
1169}
1170
1171static void
1172process_extended_posix_rename(u_int32_t id)
1173{
1174	char *oldpath, *newpath;
1175	int ret, status;
1176
1177	oldpath = get_string(NULL);
1178	newpath = get_string(NULL);
1179	debug3("request %u: posix-rename", id);
1180	logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1181	if (readonly)
1182		status = SSH2_FX_PERMISSION_DENIED;
1183	else {
1184		ret = rename(oldpath, newpath);
1185		status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1186	}
1187	send_status(id, status);
1188	free(oldpath);
1189	free(newpath);
1190}
1191
1192static void
1193process_extended_statvfs(u_int32_t id)
1194{
1195	char *path;
1196	struct statvfs st;
1197
1198	path = get_string(NULL);
1199	debug3("request %u: statfs", id);
1200	logit("statfs \"%s\"", path);
1201
1202	if (statvfs(path, &st) != 0)
1203		send_status(id, errno_to_portable(errno));
1204	else
1205		send_statvfs(id, &st);
1206        free(path);
1207}
1208
1209static void
1210process_extended_fstatvfs(u_int32_t id)
1211{
1212	int handle, fd;
1213	struct statvfs st;
1214
1215	handle = get_handle();
1216	debug("request %u: fstatvfs \"%s\" (handle %u)",
1217	    id, handle_to_name(handle), handle);
1218	if ((fd = handle_to_fd(handle)) < 0) {
1219		send_status(id, SSH2_FX_FAILURE);
1220		return;
1221	}
1222	if (fstatvfs(fd, &st) != 0)
1223		send_status(id, errno_to_portable(errno));
1224	else
1225		send_statvfs(id, &st);
1226}
1227
1228static void
1229process_extended_hardlink(u_int32_t id)
1230{
1231	char *oldpath, *newpath;
1232	int ret, status;
1233
1234	oldpath = get_string(NULL);
1235	newpath = get_string(NULL);
1236	debug3("request %u: hardlink", id);
1237	logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1238	if (readonly)
1239		status = SSH2_FX_PERMISSION_DENIED;
1240	else {
1241		ret = link(oldpath, newpath);
1242		status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1243	}
1244	send_status(id, status);
1245	free(oldpath);
1246	free(newpath);
1247}
1248
1249static void
1250process_extended(void)
1251{
1252	u_int32_t id;
1253	char *request;
1254
1255	id = get_int();
1256	request = get_string(NULL);
1257	if (strcmp(request, "posix-rename@openssh.com") == 0)
1258		process_extended_posix_rename(id);
1259	else if (strcmp(request, "statvfs@openssh.com") == 0)
1260		process_extended_statvfs(id);
1261	else if (strcmp(request, "fstatvfs@openssh.com") == 0)
1262		process_extended_fstatvfs(id);
1263	else if (strcmp(request, "hardlink@openssh.com") == 0)
1264		process_extended_hardlink(id);
1265	else
1266		send_status(id, SSH2_FX_OP_UNSUPPORTED);	/* MUST */
1267	free(request);
1268}
1269
1270/* stolen from ssh-agent */
1271
1272static void
1273process(void)
1274{
1275	u_int msg_len;
1276	u_int buf_len;
1277	u_int consumed;
1278	u_int type;
1279	u_char *cp;
1280
1281	buf_len = buffer_len(&iqueue);
1282	if (buf_len < 5)
1283		return;		/* Incomplete message. */
1284	cp = buffer_ptr(&iqueue);
1285	msg_len = get_u32(cp);
1286	if (msg_len > SFTP_MAX_MSG_LENGTH) {
1287		error("bad message from %s local user %s",
1288		    client_addr, pw->pw_name);
1289		sftp_server_cleanup_exit(11);
1290	}
1291	if (buf_len < msg_len + 4)
1292		return;
1293	buffer_consume(&iqueue, 4);
1294	buf_len -= 4;
1295	type = buffer_get_char(&iqueue);
1296	switch (type) {
1297	case SSH2_FXP_INIT:
1298		process_init();
1299		break;
1300	case SSH2_FXP_OPEN:
1301		process_open();
1302		break;
1303	case SSH2_FXP_CLOSE:
1304		process_close();
1305		break;
1306	case SSH2_FXP_READ:
1307		process_read();
1308		break;
1309	case SSH2_FXP_WRITE:
1310		process_write();
1311		break;
1312	case SSH2_FXP_LSTAT:
1313		process_lstat();
1314		break;
1315	case SSH2_FXP_FSTAT:
1316		process_fstat();
1317		break;
1318	case SSH2_FXP_SETSTAT:
1319		process_setstat();
1320		break;
1321	case SSH2_FXP_FSETSTAT:
1322		process_fsetstat();
1323		break;
1324	case SSH2_FXP_OPENDIR:
1325		process_opendir();
1326		break;
1327	case SSH2_FXP_READDIR:
1328		process_readdir();
1329		break;
1330	case SSH2_FXP_REMOVE:
1331		process_remove();
1332		break;
1333	case SSH2_FXP_MKDIR:
1334		process_mkdir();
1335		break;
1336	case SSH2_FXP_RMDIR:
1337		process_rmdir();
1338		break;
1339	case SSH2_FXP_REALPATH:
1340		process_realpath();
1341		break;
1342	case SSH2_FXP_STAT:
1343		process_stat();
1344		break;
1345	case SSH2_FXP_RENAME:
1346		process_rename();
1347		break;
1348	case SSH2_FXP_READLINK:
1349		process_readlink();
1350		break;
1351	case SSH2_FXP_SYMLINK:
1352		process_symlink();
1353		break;
1354	case SSH2_FXP_EXTENDED:
1355		process_extended();
1356		break;
1357	default:
1358		error("Unknown message %d", type);
1359		break;
1360	}
1361	/* discard the remaining bytes from the current packet */
1362	if (buf_len < buffer_len(&iqueue)) {
1363		error("iqueue grew unexpectedly");
1364		sftp_server_cleanup_exit(255);
1365	}
1366	consumed = buf_len - buffer_len(&iqueue);
1367	if (msg_len < consumed) {
1368		error("msg_len %d < consumed %d", msg_len, consumed);
1369		sftp_server_cleanup_exit(255);
1370	}
1371	if (msg_len > consumed)
1372		buffer_consume(&iqueue, msg_len - consumed);
1373}
1374
1375/* Cleanup handler that logs active handles upon normal exit */
1376void
1377sftp_server_cleanup_exit(int i)
1378{
1379	if (pw != NULL && client_addr != NULL) {
1380		handle_log_exit();
1381		logit("session closed for local user %s from [%s]",
1382		    pw->pw_name, client_addr);
1383	}
1384	_exit(i);
1385}
1386
1387static void
1388sftp_server_usage(void)
1389{
1390	extern char *__progname;
1391
1392	fprintf(stderr,
1393	    "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
1394	    "[-l log_level]\n\t[-u umask]\n",
1395	    __progname);
1396	exit(1);
1397}
1398
1399int
1400sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1401{
1402	fd_set *rset, *wset;
1403	int in, out, max, ch, skipargs = 0, log_stderr = 0;
1404	ssize_t len, olen, set_size;
1405	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1406	char *cp, *homedir = NULL, buf[4*4096];
1407	long mask;
1408
1409	extern char *optarg;
1410	extern char *__progname;
1411
1412	__progname = ssh_get_progname(argv[0]);
1413	log_init(__progname, log_level, log_facility, log_stderr);
1414
1415	pw = pwcopy(user_pw);
1416
1417	while (!skipargs && (ch = getopt(argc, argv, "d:f:l:u:cehR")) != -1) {
1418		switch (ch) {
1419		case 'R':
1420			readonly = 1;
1421			break;
1422		case 'c':
1423			/*
1424			 * Ignore all arguments if we are invoked as a
1425			 * shell using "sftp-server -c command"
1426			 */
1427			skipargs = 1;
1428			break;
1429		case 'e':
1430			log_stderr = 1;
1431			break;
1432		case 'l':
1433			log_level = log_level_number(optarg);
1434			if (log_level == SYSLOG_LEVEL_NOT_SET)
1435				error("Invalid log level \"%s\"", optarg);
1436			break;
1437		case 'f':
1438			log_facility = log_facility_number(optarg);
1439			if (log_facility == SYSLOG_FACILITY_NOT_SET)
1440				error("Invalid log facility \"%s\"", optarg);
1441			break;
1442		case 'd':
1443			cp = tilde_expand_filename(optarg, user_pw->pw_uid);
1444			homedir = percent_expand(cp, "d", user_pw->pw_dir,
1445			    "u", user_pw->pw_name, (char *)NULL);
1446			free(cp);
1447			break;
1448		case 'u':
1449			errno = 0;
1450			mask = strtol(optarg, &cp, 8);
1451			if (mask < 0 || mask > 0777 || *cp != '\0' ||
1452			    cp == optarg || (mask == 0 && errno != 0))
1453				fatal("Invalid umask \"%s\"", optarg);
1454			(void)umask((mode_t)mask);
1455			break;
1456		case 'h':
1457		default:
1458			sftp_server_usage();
1459		}
1460	}
1461
1462	log_init(__progname, log_level, log_facility, log_stderr);
1463
1464	if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1465		client_addr = xstrdup(cp);
1466		if ((cp = strchr(client_addr, ' ')) == NULL) {
1467			error("Malformed SSH_CONNECTION variable: \"%s\"",
1468			    getenv("SSH_CONNECTION"));
1469			sftp_server_cleanup_exit(255);
1470		}
1471		*cp = '\0';
1472	} else
1473		client_addr = xstrdup("UNKNOWN");
1474
1475	logit("session opened for local user %s from [%s]",
1476	    pw->pw_name, client_addr);
1477
1478	in = STDIN_FILENO;
1479	out = STDOUT_FILENO;
1480
1481#ifdef HAVE_CYGWIN
1482	setmode(in, O_BINARY);
1483	setmode(out, O_BINARY);
1484#endif
1485
1486	max = 0;
1487	if (in > max)
1488		max = in;
1489	if (out > max)
1490		max = out;
1491
1492	buffer_init(&iqueue);
1493	buffer_init(&oqueue);
1494
1495	set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1496	rset = (fd_set *)xmalloc(set_size);
1497	wset = (fd_set *)xmalloc(set_size);
1498
1499	if (homedir != NULL) {
1500		if (chdir(homedir) != 0) {
1501			error("chdir to \"%s\" failed: %s", homedir,
1502			    strerror(errno));
1503		}
1504	}
1505
1506	for (;;) {
1507		memset(rset, 0, set_size);
1508		memset(wset, 0, set_size);
1509
1510		/*
1511		 * Ensure that we can read a full buffer and handle
1512		 * the worst-case length packet it can generate,
1513		 * otherwise apply backpressure by stopping reads.
1514		 */
1515		if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
1516		    buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1517			FD_SET(in, rset);
1518
1519		olen = buffer_len(&oqueue);
1520		if (olen > 0)
1521			FD_SET(out, wset);
1522
1523		if (select(max+1, rset, wset, NULL, NULL) < 0) {
1524			if (errno == EINTR)
1525				continue;
1526			error("select: %s", strerror(errno));
1527			sftp_server_cleanup_exit(2);
1528		}
1529
1530		/* copy stdin to iqueue */
1531		if (FD_ISSET(in, rset)) {
1532			len = read(in, buf, sizeof buf);
1533			if (len == 0) {
1534				debug("read eof");
1535				sftp_server_cleanup_exit(0);
1536			} else if (len < 0) {
1537				error("read: %s", strerror(errno));
1538				sftp_server_cleanup_exit(1);
1539			} else {
1540				buffer_append(&iqueue, buf, len);
1541			}
1542		}
1543		/* send oqueue to stdout */
1544		if (FD_ISSET(out, wset)) {
1545			len = write(out, buffer_ptr(&oqueue), olen);
1546			if (len < 0) {
1547				error("write: %s", strerror(errno));
1548				sftp_server_cleanup_exit(1);
1549			} else {
1550				buffer_consume(&oqueue, len);
1551			}
1552		}
1553
1554		/*
1555		 * Process requests from client if we can fit the results
1556		 * into the output buffer, otherwise stop processing input
1557		 * and let the output queue drain.
1558		 */
1559		if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1560			process();
1561	}
1562}
1563