1/*	$NetBSD: sftp-server.c,v 1.30 2023/10/25 20:19:57 christos Exp $	*/
2/* $OpenBSD: sftp-server.c,v 1.147 2023/04/12 08:53:54 jsg Exp $ */
3
4/*
5 * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "includes.h"
21__RCSID("$NetBSD: sftp-server.c,v 1.30 2023/10/25 20:19:57 christos Exp $");
22
23#include <sys/param.h>	/* MIN */
24#include <sys/types.h>
25#include <sys/resource.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28#include <sys/mount.h>
29#include <sys/statvfs.h>
30
31#include <dirent.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <poll.h>
35#include <stdlib.h>
36#include <stdio.h>
37#include <string.h>
38#include <pwd.h>
39#include <grp.h>
40#include <time.h>
41#include <unistd.h>
42#include <stdarg.h>
43
44#include "atomicio.h"
45#include "xmalloc.h"
46#include "sshbuf.h"
47#include "ssherr.h"
48#include "log.h"
49#include "misc.h"
50#include "match.h"
51#include "uidswap.h"
52
53#include "sftp.h"
54#include "sftp-common.h"
55
56char *sftp_realpath(const char *, char *); /* sftp-realpath.c */
57
58/* Maximum data read that we are willing to accept */
59#define SFTP_MAX_READ_LENGTH (SFTP_MAX_MSG_LENGTH - 1024)
60
61/* Our verbosity */
62static LogLevel log_level = SYSLOG_LEVEL_ERROR;
63
64/* Our client */
65static struct passwd *pw = NULL;
66static char *client_addr = NULL;
67
68/* input and output queue */
69struct sshbuf *iqueue;
70struct sshbuf *oqueue;
71
72/* Version of client */
73static u_int version;
74
75/* SSH2_FXP_INIT received */
76static int init_done;
77
78/* Disable writes */
79static int readonly;
80
81/* Requests that are allowed/denied */
82static char *request_allowlist, *request_denylist;
83
84/* portable attributes, etc. */
85typedef struct Stat Stat;
86
87struct Stat {
88	char *name;
89	char *long_name;
90	Attrib attrib;
91};
92
93/* Packet handlers */
94static void process_open(u_int32_t id);
95static void process_close(u_int32_t id);
96static void process_read(u_int32_t id);
97static void process_write(u_int32_t id);
98static void process_stat(u_int32_t id);
99static void process_lstat(u_int32_t id);
100static void process_fstat(u_int32_t id);
101static void process_setstat(u_int32_t id);
102static void process_fsetstat(u_int32_t id);
103static void process_opendir(u_int32_t id);
104static void process_readdir(u_int32_t id);
105static void process_remove(u_int32_t id);
106static void process_mkdir(u_int32_t id);
107static void process_rmdir(u_int32_t id);
108static void process_realpath(u_int32_t id);
109static void process_rename(u_int32_t id);
110static void process_readlink(u_int32_t id);
111static void process_symlink(u_int32_t id);
112static void process_extended_posix_rename(u_int32_t id);
113static void process_extended_statvfs(u_int32_t id);
114static void process_extended_fstatvfs(u_int32_t id);
115static void process_extended_hardlink(u_int32_t id);
116static void process_extended_fsync(u_int32_t id);
117static void process_extended_lsetstat(u_int32_t id);
118static void process_extended_limits(u_int32_t id);
119static void process_extended_expand(u_int32_t id);
120static void process_extended_copy_data(u_int32_t id);
121static void process_extended_home_directory(u_int32_t id);
122static void process_extended_get_users_groups_by_id(u_int32_t id);
123static void process_extended(u_int32_t id);
124
125struct sftp_handler {
126	const char *name;	/* user-visible name for fine-grained perms */
127	const char *ext_name;	/* extended request name */
128	u_int type;		/* packet type, for non extended packets */
129	void (*handler)(u_int32_t);
130	int does_write;		/* if nonzero, banned for readonly mode */
131};
132
133static const struct sftp_handler handlers[] = {
134	/* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */
135	{ "open", NULL, SSH2_FXP_OPEN, process_open, 0 },
136	{ "close", NULL, SSH2_FXP_CLOSE, process_close, 0 },
137	{ "read", NULL, SSH2_FXP_READ, process_read, 0 },
138	{ "write", NULL, SSH2_FXP_WRITE, process_write, 1 },
139	{ "lstat", NULL, SSH2_FXP_LSTAT, process_lstat, 0 },
140	{ "fstat", NULL, SSH2_FXP_FSTAT, process_fstat, 0 },
141	{ "setstat", NULL, SSH2_FXP_SETSTAT, process_setstat, 1 },
142	{ "fsetstat", NULL, SSH2_FXP_FSETSTAT, process_fsetstat, 1 },
143	{ "opendir", NULL, SSH2_FXP_OPENDIR, process_opendir, 0 },
144	{ "readdir", NULL, SSH2_FXP_READDIR, process_readdir, 0 },
145	{ "remove", NULL, SSH2_FXP_REMOVE, process_remove, 1 },
146	{ "mkdir", NULL, SSH2_FXP_MKDIR, process_mkdir, 1 },
147	{ "rmdir", NULL, SSH2_FXP_RMDIR, process_rmdir, 1 },
148	{ "realpath", NULL, SSH2_FXP_REALPATH, process_realpath, 0 },
149	{ "stat", NULL, SSH2_FXP_STAT, process_stat, 0 },
150	{ "rename", NULL, SSH2_FXP_RENAME, process_rename, 1 },
151	{ "readlink", NULL, SSH2_FXP_READLINK, process_readlink, 0 },
152	{ "symlink", NULL, SSH2_FXP_SYMLINK, process_symlink, 1 },
153	{ NULL, NULL, 0, NULL, 0 }
154};
155
156/* SSH2_FXP_EXTENDED submessages */
157static const struct sftp_handler extended_handlers[] = {
158	{ "posix-rename", "posix-rename@openssh.com", 0,
159	    process_extended_posix_rename, 1 },
160	{ "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
161	{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
162	{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
163	{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
164	{ "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 },
165	{ "limits", "limits@openssh.com", 0, process_extended_limits, 0 },
166	{ "expand-path", "expand-path@openssh.com", 0,
167	    process_extended_expand, 0 },
168	{ "copy-data", "copy-data", 0, process_extended_copy_data, 1 },
169	{ "home-directory", "home-directory", 0,
170	    process_extended_home_directory, 0 },
171	{ "users-groups-by-id", "users-groups-by-id@openssh.com", 0,
172	    process_extended_get_users_groups_by_id, 0 },
173	{ NULL, NULL, 0, NULL, 0 }
174};
175
176static const struct sftp_handler *
177extended_handler_byname(const char *name)
178{
179	int i;
180
181	for (i = 0; extended_handlers[i].handler != NULL; i++) {
182		if (strcmp(name, extended_handlers[i].ext_name) == 0)
183			return &extended_handlers[i];
184	}
185	return NULL;
186}
187
188static int
189request_permitted(const struct sftp_handler *h)
190{
191	char *result;
192
193	if (readonly && h->does_write) {
194		verbose("Refusing %s request in read-only mode", h->name);
195		return 0;
196	}
197	if (request_denylist != NULL &&
198	    ((result = match_list(h->name, request_denylist, NULL))) != NULL) {
199		free(result);
200		verbose("Refusing denylisted %s request", h->name);
201		return 0;
202	}
203	if (request_allowlist != NULL &&
204	    ((result = match_list(h->name, request_allowlist, NULL))) != NULL) {
205		free(result);
206		debug2("Permitting allowlisted %s request", h->name);
207		return 1;
208	}
209	if (request_allowlist != NULL) {
210		verbose("Refusing non-allowlisted %s request", h->name);
211		return 0;
212	}
213	return 1;
214}
215
216static int
217errno_to_portable(int unixerrno)
218{
219	int ret = 0;
220
221	switch (unixerrno) {
222	case 0:
223		ret = SSH2_FX_OK;
224		break;
225	case ENOENT:
226	case ENOTDIR:
227	case EBADF:
228	case ELOOP:
229		ret = SSH2_FX_NO_SUCH_FILE;
230		break;
231	case EPERM:
232	case EACCES:
233	case EFAULT:
234		ret = SSH2_FX_PERMISSION_DENIED;
235		break;
236	case ENAMETOOLONG:
237	case EINVAL:
238		ret = SSH2_FX_BAD_MESSAGE;
239		break;
240	case ENOSYS:
241		ret = SSH2_FX_OP_UNSUPPORTED;
242		break;
243	default:
244		ret = SSH2_FX_FAILURE;
245		break;
246	}
247	return ret;
248}
249
250static int
251flags_from_portable(int pflags)
252{
253	int flags = 0;
254
255	if ((pflags & SSH2_FXF_READ) &&
256	    (pflags & SSH2_FXF_WRITE)) {
257		flags = O_RDWR;
258	} else if (pflags & SSH2_FXF_READ) {
259		flags = O_RDONLY;
260	} else if (pflags & SSH2_FXF_WRITE) {
261		flags = O_WRONLY;
262	}
263	if (pflags & SSH2_FXF_APPEND)
264		flags |= O_APPEND;
265	if (pflags & SSH2_FXF_CREAT)
266		flags |= O_CREAT;
267	if (pflags & SSH2_FXF_TRUNC)
268		flags |= O_TRUNC;
269	if (pflags & SSH2_FXF_EXCL)
270		flags |= O_EXCL;
271	return flags;
272}
273
274static const char *
275string_from_portable(int pflags)
276{
277	static char ret[128];
278
279	*ret = '\0';
280
281#define PAPPEND(str)	{				\
282		if (*ret != '\0')			\
283			strlcat(ret, ",", sizeof(ret));	\
284		strlcat(ret, str, sizeof(ret));		\
285	}
286
287	if (pflags & SSH2_FXF_READ)
288		PAPPEND("READ")
289	if (pflags & SSH2_FXF_WRITE)
290		PAPPEND("WRITE")
291	if (pflags & SSH2_FXF_APPEND)
292		PAPPEND("APPEND")
293	if (pflags & SSH2_FXF_CREAT)
294		PAPPEND("CREATE")
295	if (pflags & SSH2_FXF_TRUNC)
296		PAPPEND("TRUNCATE")
297	if (pflags & SSH2_FXF_EXCL)
298		PAPPEND("EXCL")
299
300	return ret;
301}
302
303/* handle handles */
304
305typedef struct Handle Handle;
306struct Handle {
307	int use;
308	DIR *dirp;
309	int fd;
310	int flags;
311	char *name;
312	u_int64_t bytes_read, bytes_write;
313	int next_unused;
314};
315
316enum {
317	HANDLE_UNUSED,
318	HANDLE_DIR,
319	HANDLE_FILE
320};
321
322static Handle *handles = NULL;
323static u_int num_handles = 0;
324static int first_unused_handle = -1;
325
326static void handle_unused(int i)
327{
328	handles[i].use = HANDLE_UNUSED;
329	handles[i].next_unused = first_unused_handle;
330	first_unused_handle = i;
331}
332
333static int
334handle_new(int use, const char *name, int fd, int flags, DIR *dirp)
335{
336	int i;
337
338	if (first_unused_handle == -1) {
339		if (num_handles + 1 <= num_handles)
340			return -1;
341		num_handles++;
342		handles = xreallocarray(handles, num_handles, sizeof(Handle));
343		handle_unused(num_handles - 1);
344	}
345
346	i = first_unused_handle;
347	first_unused_handle = handles[i].next_unused;
348
349	handles[i].use = use;
350	handles[i].dirp = dirp;
351	handles[i].fd = fd;
352	handles[i].flags = flags;
353	handles[i].name = xstrdup(name);
354	handles[i].bytes_read = handles[i].bytes_write = 0;
355
356	return i;
357}
358
359static int
360handle_is_ok(int i, int type)
361{
362	return i >= 0 && (u_int)i < num_handles && handles[i].use == type;
363}
364
365static int
366handle_to_string(int handle, u_char **stringp, int *hlenp)
367{
368	if (stringp == NULL || hlenp == NULL)
369		return -1;
370	*stringp = xmalloc(sizeof(int32_t));
371	put_u32(*stringp, handle);
372	*hlenp = sizeof(int32_t);
373	return 0;
374}
375
376static int
377handle_from_string(const u_char *handle, u_int hlen)
378{
379	int val;
380
381	if (hlen != sizeof(int32_t))
382		return -1;
383	val = get_u32(handle);
384	if (handle_is_ok(val, HANDLE_FILE) ||
385	    handle_is_ok(val, HANDLE_DIR))
386		return val;
387	return -1;
388}
389
390static char *
391handle_to_name(int handle)
392{
393	if (handle_is_ok(handle, HANDLE_DIR)||
394	    handle_is_ok(handle, HANDLE_FILE))
395		return handles[handle].name;
396	return NULL;
397}
398
399static DIR *
400handle_to_dir(int handle)
401{
402	if (handle_is_ok(handle, HANDLE_DIR))
403		return handles[handle].dirp;
404	return NULL;
405}
406
407static int
408handle_to_fd(int handle)
409{
410	if (handle_is_ok(handle, HANDLE_FILE))
411		return handles[handle].fd;
412	return -1;
413}
414
415static int
416handle_to_flags(int handle)
417{
418	if (handle_is_ok(handle, HANDLE_FILE))
419		return handles[handle].flags;
420	return 0;
421}
422
423static void
424handle_update_read(int handle, ssize_t bytes)
425{
426	if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
427		handles[handle].bytes_read += bytes;
428}
429
430static void
431handle_update_write(int handle, ssize_t bytes)
432{
433	if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
434		handles[handle].bytes_write += bytes;
435}
436
437static u_int64_t
438handle_bytes_read(int handle)
439{
440	if (handle_is_ok(handle, HANDLE_FILE))
441		return (handles[handle].bytes_read);
442	return 0;
443}
444
445static u_int64_t
446handle_bytes_write(int handle)
447{
448	if (handle_is_ok(handle, HANDLE_FILE))
449		return (handles[handle].bytes_write);
450	return 0;
451}
452
453static int
454handle_close(int handle)
455{
456	int ret = -1;
457
458	if (handle_is_ok(handle, HANDLE_FILE)) {
459		ret = close(handles[handle].fd);
460		free(handles[handle].name);
461		handle_unused(handle);
462	} else if (handle_is_ok(handle, HANDLE_DIR)) {
463		ret = closedir(handles[handle].dirp);
464		free(handles[handle].name);
465		handle_unused(handle);
466	} else {
467		errno = ENOENT;
468	}
469	return ret;
470}
471
472static void
473handle_log_close(int handle, const char *emsg)
474{
475	if (handle_is_ok(handle, HANDLE_FILE)) {
476		logit("%s%sclose \"%s\" bytes read %llu written %llu",
477		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
478		    handle_to_name(handle),
479		    (unsigned long long)handle_bytes_read(handle),
480		    (unsigned long long)handle_bytes_write(handle));
481	} else {
482		logit("%s%sclosedir \"%s\"",
483		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
484		    handle_to_name(handle));
485	}
486}
487
488static void
489handle_log_exit(void)
490{
491	u_int i;
492
493	for (i = 0; i < num_handles; i++)
494		if (handles[i].use != HANDLE_UNUSED)
495			handle_log_close(i, "forced");
496}
497
498static int
499get_handle(struct sshbuf *queue, int *hp)
500{
501	u_char *handle;
502	int r;
503	size_t hlen;
504
505	*hp = -1;
506	if ((r = sshbuf_get_string(queue, &handle, &hlen)) != 0)
507		return r;
508	if (hlen < 256)
509		*hp = handle_from_string(handle, hlen);
510	free(handle);
511	return 0;
512}
513
514/* send replies */
515
516static void
517send_msg(struct sshbuf *m)
518{
519	int r;
520
521	if ((r = sshbuf_put_stringb(oqueue, m)) != 0)
522		fatal_fr(r, "enqueue");
523	sshbuf_reset(m);
524}
525
526static const char *
527status_to_message(u_int32_t status)
528{
529	static const char * const status_messages[] = {
530		"Success",			/* SSH_FX_OK */
531		"End of file",			/* SSH_FX_EOF */
532		"No such file",			/* SSH_FX_NO_SUCH_FILE */
533		"Permission denied",		/* SSH_FX_PERMISSION_DENIED */
534		"Failure",			/* SSH_FX_FAILURE */
535		"Bad message",			/* SSH_FX_BAD_MESSAGE */
536		"No connection",		/* SSH_FX_NO_CONNECTION */
537		"Connection lost",		/* SSH_FX_CONNECTION_LOST */
538		"Operation unsupported",	/* SSH_FX_OP_UNSUPPORTED */
539		"Unknown error"			/* Others */
540	};
541	return (status_messages[MINIMUM(status,SSH2_FX_MAX)]);
542}
543
544static void
545send_status_errmsg(u_int32_t id, u_int32_t status, const char *errmsg)
546{
547	struct sshbuf *msg;
548	int r;
549
550	debug3("request %u: sent status %u", id, status);
551	if (log_level > SYSLOG_LEVEL_VERBOSE ||
552	    (status != SSH2_FX_OK && status != SSH2_FX_EOF))
553		logit("sent status %s", status_to_message(status));
554	if ((msg = sshbuf_new()) == NULL)
555		fatal_f("sshbuf_new failed");
556	if ((r = sshbuf_put_u8(msg, SSH2_FXP_STATUS)) != 0 ||
557	    (r = sshbuf_put_u32(msg, id)) != 0 ||
558	    (r = sshbuf_put_u32(msg, status)) != 0)
559		fatal_fr(r, "compose");
560	if (version >= 3) {
561		if ((r = sshbuf_put_cstring(msg, errmsg == NULL ?
562		    status_to_message(status) : errmsg)) != 0 ||
563		    (r = sshbuf_put_cstring(msg, "")) != 0)
564			fatal_fr(r, "compose message");
565	}
566	send_msg(msg);
567	sshbuf_free(msg);
568}
569
570static void
571send_status(u_int32_t id, u_int32_t status)
572{
573	send_status_errmsg(id, status, NULL);
574}
575
576static void
577send_data_or_handle(char type, u_int32_t id, const u_char *data, int dlen)
578{
579	struct sshbuf *msg;
580	int r;
581
582	if ((msg = sshbuf_new()) == NULL)
583		fatal_f("sshbuf_new failed");
584	if ((r = sshbuf_put_u8(msg, type)) != 0 ||
585	    (r = sshbuf_put_u32(msg, id)) != 0 ||
586	    (r = sshbuf_put_string(msg, data, dlen)) != 0)
587		fatal_fr(r, "compose");
588	send_msg(msg);
589	sshbuf_free(msg);
590}
591
592static void
593send_data(u_int32_t id, const u_char *data, int dlen)
594{
595	debug("request %u: sent data len %d", id, dlen);
596	send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
597}
598
599static void
600send_handle(u_int32_t id, int handle)
601{
602	u_char *string;
603	int hlen;
604
605	handle_to_string(handle, &string, &hlen);
606	debug("request %u: sent handle %d", id, handle);
607	send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
608	free(string);
609}
610
611static void
612send_names(u_int32_t id, int count, const Stat *stats)
613{
614	struct sshbuf *msg;
615	int i, r;
616
617	if ((msg = sshbuf_new()) == NULL)
618		fatal_f("sshbuf_new failed");
619	if ((r = sshbuf_put_u8(msg, SSH2_FXP_NAME)) != 0 ||
620	    (r = sshbuf_put_u32(msg, id)) != 0 ||
621	    (r = sshbuf_put_u32(msg, count)) != 0)
622		fatal_fr(r, "compose");
623	debug("request %u: sent names count %d", id, count);
624	for (i = 0; i < count; i++) {
625		if ((r = sshbuf_put_cstring(msg, stats[i].name)) != 0 ||
626		    (r = sshbuf_put_cstring(msg, stats[i].long_name)) != 0 ||
627		    (r = encode_attrib(msg, &stats[i].attrib)) != 0)
628			fatal_fr(r, "compose filenames/attrib");
629	}
630	send_msg(msg);
631	sshbuf_free(msg);
632}
633
634static void
635send_attrib(u_int32_t id, const Attrib *a)
636{
637	struct sshbuf *msg;
638	int r;
639
640	debug("request %u: sent attrib have 0x%x", id, a->flags);
641	if ((msg = sshbuf_new()) == NULL)
642		fatal_f("sshbuf_new failed");
643	if ((r = sshbuf_put_u8(msg, SSH2_FXP_ATTRS)) != 0 ||
644	    (r = sshbuf_put_u32(msg, id)) != 0 ||
645	    (r = encode_attrib(msg, a)) != 0)
646		fatal_fr(r, "compose");
647	send_msg(msg);
648	sshbuf_free(msg);
649}
650
651static void
652send_statvfs(u_int32_t id, struct statvfs *st)
653{
654	struct sshbuf *msg;
655	u_int64_t flag;
656	int r;
657
658	flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
659	flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
660
661	if ((msg = sshbuf_new()) == NULL)
662		fatal_f("sshbuf_new failed");
663	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 ||
664	    (r = sshbuf_put_u32(msg, id)) != 0 ||
665	    (r = sshbuf_put_u64(msg, st->f_bsize)) != 0 ||
666	    (r = sshbuf_put_u64(msg, st->f_frsize)) != 0 ||
667	    (r = sshbuf_put_u64(msg, st->f_blocks)) != 0 ||
668	    (r = sshbuf_put_u64(msg, st->f_bfree)) != 0 ||
669	    (r = sshbuf_put_u64(msg, st->f_bavail)) != 0 ||
670	    (r = sshbuf_put_u64(msg, st->f_files)) != 0 ||
671	    (r = sshbuf_put_u64(msg, st->f_ffree)) != 0 ||
672	    (r = sshbuf_put_u64(msg, st->f_favail)) != 0 ||
673	    (r = sshbuf_put_u64(msg, st->f_fsid)) != 0 ||
674	    (r = sshbuf_put_u64(msg, flag)) != 0 ||
675	    (r = sshbuf_put_u64(msg, st->f_namemax)) != 0)
676		fatal_fr(r, "compose");
677	send_msg(msg);
678	sshbuf_free(msg);
679}
680
681/*
682 * Prepare SSH2_FXP_VERSION extension advertisement for a single extension.
683 * The extension is checked for permission prior to advertisement.
684 */
685static int
686compose_extension(struct sshbuf *msg, const char *name, const char *ver)
687{
688	int r;
689	const struct sftp_handler *exthnd;
690
691	if ((exthnd = extended_handler_byname(name)) == NULL)
692		fatal_f("internal error: no handler for %s", name);
693	if (!request_permitted(exthnd)) {
694		debug2_f("refusing to advertise disallowed extension %s", name);
695		return 0;
696	}
697	if ((r = sshbuf_put_cstring(msg, name)) != 0 ||
698	    (r = sshbuf_put_cstring(msg, ver)) != 0)
699		fatal_fr(r, "compose %s", name);
700	return 0;
701}
702
703/* parse incoming */
704
705static void
706process_init(void)
707{
708	struct sshbuf *msg;
709	int r;
710
711	if ((r = sshbuf_get_u32(iqueue, &version)) != 0)
712		fatal_fr(r, "parse");
713	verbose("received client version %u", version);
714	if ((msg = sshbuf_new()) == NULL)
715		fatal_f("sshbuf_new failed");
716	if ((r = sshbuf_put_u8(msg, SSH2_FXP_VERSION)) != 0 ||
717	    (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
718		fatal_fr(r, "compose");
719
720	 /* extension advertisements */
721	compose_extension(msg, "posix-rename@openssh.com", "1");
722	compose_extension(msg, "statvfs@openssh.com", "2");
723	compose_extension(msg, "fstatvfs@openssh.com", "2");
724	compose_extension(msg, "hardlink@openssh.com", "1");
725	compose_extension(msg, "fsync@openssh.com", "1");
726	compose_extension(msg, "lsetstat@openssh.com", "1");
727	compose_extension(msg, "limits@openssh.com", "1");
728	compose_extension(msg, "expand-path@openssh.com", "1");
729	compose_extension(msg, "copy-data", "1");
730	compose_extension(msg, "home-directory", "1");
731	compose_extension(msg, "users-groups-by-id@openssh.com", "1");
732
733	send_msg(msg);
734	sshbuf_free(msg);
735}
736
737static void
738process_open(u_int32_t id)
739{
740	u_int32_t pflags;
741	Attrib a;
742	char *name;
743	int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE;
744
745	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
746	    (r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */
747	    (r = decode_attrib(iqueue, &a)) != 0)
748		fatal_fr(r, "parse");
749
750	debug3("request %u: open flags %d", id, pflags);
751	flags = flags_from_portable(pflags);
752	mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666;
753	logit("open \"%s\" flags %s mode 0%o",
754	    name, string_from_portable(pflags), mode);
755	if (readonly &&
756	    ((flags & O_ACCMODE) != O_RDONLY ||
757	    (flags & (O_CREAT|O_TRUNC)) != 0)) {
758		verbose("Refusing open request in read-only mode");
759		status = SSH2_FX_PERMISSION_DENIED;
760	} else {
761		fd = open(name, flags, mode);
762		if (fd == -1) {
763			status = errno_to_portable(errno);
764		} else {
765			handle = handle_new(HANDLE_FILE, name, fd, flags, NULL);
766			if (handle < 0) {
767				close(fd);
768			} else {
769				send_handle(id, handle);
770				status = SSH2_FX_OK;
771			}
772		}
773	}
774	if (status != SSH2_FX_OK)
775		send_status(id, status);
776	free(name);
777}
778
779static void
780process_close(u_int32_t id)
781{
782	int r, handle, ret, status = SSH2_FX_FAILURE;
783
784	if ((r = get_handle(iqueue, &handle)) != 0)
785		fatal_fr(r, "parse");
786
787	debug3("request %u: close handle %u", id, handle);
788	handle_log_close(handle, NULL);
789	ret = handle_close(handle);
790	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
791	send_status(id, status);
792}
793
794static void
795process_read(u_int32_t id)
796{
797	static u_char *buf;
798	static size_t buflen;
799	u_int32_t len;
800	int r, handle, fd, ret, status = SSH2_FX_FAILURE;
801	u_int64_t off;
802
803	if ((r = get_handle(iqueue, &handle)) != 0 ||
804	    (r = sshbuf_get_u64(iqueue, &off)) != 0 ||
805	    (r = sshbuf_get_u32(iqueue, &len)) != 0)
806		fatal_fr(r, "parse");
807
808	debug("request %u: read \"%s\" (handle %d) off %llu len %u",
809	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
810	if ((fd = handle_to_fd(handle)) == -1)
811		goto out;
812	if (len > SFTP_MAX_READ_LENGTH) {
813		debug2("read change len %u to %u", len, SFTP_MAX_READ_LENGTH);
814		len = SFTP_MAX_READ_LENGTH;
815	}
816	if (len > buflen) {
817		debug3_f("allocate %zu => %u", buflen, len);
818		if ((buf = realloc(buf, len)) == NULL)
819			fatal_f("realloc failed");
820		buflen = len;
821	}
822	if (lseek(fd, off, SEEK_SET) == -1) {
823		status = errno_to_portable(errno);
824		error_f("seek \"%.100s\": %s", handle_to_name(handle),
825		    strerror(errno));
826		goto out;
827	}
828	if (len == 0) {
829		/* weird, but not strictly disallowed */
830		ret = 0;
831	} else if ((ret = read(fd, buf, len)) == -1) {
832		status = errno_to_portable(errno);
833		error_f("read \"%.100s\": %s", handle_to_name(handle),
834		    strerror(errno));
835		goto out;
836	} else if (ret == 0) {
837		status = SSH2_FX_EOF;
838		goto out;
839	}
840	send_data(id, buf, ret);
841	handle_update_read(handle, ret);
842	/* success */
843	status = SSH2_FX_OK;
844 out:
845	if (status != SSH2_FX_OK)
846		send_status(id, status);
847}
848
849static void
850process_write(u_int32_t id)
851{
852	u_int64_t off;
853	size_t len;
854	int r, handle, fd, ret, status;
855	u_char *data;
856
857	if ((r = get_handle(iqueue, &handle)) != 0 ||
858	    (r = sshbuf_get_u64(iqueue, &off)) != 0 ||
859	    (r = sshbuf_get_string(iqueue, &data, &len)) != 0)
860		fatal_fr(r, "parse");
861
862	debug("request %u: write \"%s\" (handle %d) off %llu len %zu",
863	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
864	fd = handle_to_fd(handle);
865
866	if (fd < 0)
867		status = SSH2_FX_FAILURE;
868	else {
869		if (!(handle_to_flags(handle) & O_APPEND) &&
870		    lseek(fd, off, SEEK_SET) == -1) {
871			status = errno_to_portable(errno);
872			error_f("seek \"%.100s\": %s", handle_to_name(handle),
873			    strerror(errno));
874		} else {
875/* XXX ATOMICIO ? */
876			ret = write(fd, data, len);
877			if (ret == -1) {
878				status = errno_to_portable(errno);
879				error_f("write \"%.100s\": %s",
880				    handle_to_name(handle), strerror(errno));
881			} else if ((size_t)ret == len) {
882				status = SSH2_FX_OK;
883				handle_update_write(handle, ret);
884			} else {
885				debug2_f("nothing at all written");
886				status = SSH2_FX_FAILURE;
887			}
888		}
889	}
890	send_status(id, status);
891	free(data);
892}
893
894static void
895process_do_stat(u_int32_t id, int do_lstat)
896{
897	Attrib a;
898	struct stat st;
899	char *name;
900	int r, status = SSH2_FX_FAILURE;
901
902	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
903		fatal_fr(r, "parse");
904
905	debug3("request %u: %sstat", id, do_lstat ? "l" : "");
906	verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
907	r = do_lstat ? lstat(name, &st) : stat(name, &st);
908	if (r == -1) {
909		status = errno_to_portable(errno);
910	} else {
911		stat_to_attrib(&st, &a);
912		send_attrib(id, &a);
913		status = SSH2_FX_OK;
914	}
915	if (status != SSH2_FX_OK)
916		send_status(id, status);
917	free(name);
918}
919
920static void
921process_stat(u_int32_t id)
922{
923	process_do_stat(id, 0);
924}
925
926static void
927process_lstat(u_int32_t id)
928{
929	process_do_stat(id, 1);
930}
931
932static void
933process_fstat(u_int32_t id)
934{
935	Attrib a;
936	struct stat st;
937	int fd, r, handle, status = SSH2_FX_FAILURE;
938
939	if ((r = get_handle(iqueue, &handle)) != 0)
940		fatal_fr(r, "parse");
941	debug("request %u: fstat \"%s\" (handle %u)",
942	    id, handle_to_name(handle), handle);
943	fd = handle_to_fd(handle);
944	if (fd >= 0) {
945		r = fstat(fd, &st);
946		if (r == -1) {
947			status = errno_to_portable(errno);
948		} else {
949			stat_to_attrib(&st, &a);
950			send_attrib(id, &a);
951			status = SSH2_FX_OK;
952		}
953	}
954	if (status != SSH2_FX_OK)
955		send_status(id, status);
956}
957
958static struct timeval *
959attrib_to_tv(const Attrib *a)
960{
961	static struct timeval tv[2];
962
963	tv[0].tv_sec = a->atime;
964	tv[0].tv_usec = 0;
965	tv[1].tv_sec = a->mtime;
966	tv[1].tv_usec = 0;
967	return tv;
968}
969
970static struct timespec *
971attrib_to_ts(const Attrib *a)
972{
973	static struct timespec ts[2];
974
975	ts[0].tv_sec = a->atime;
976	ts[0].tv_nsec = 0;
977	ts[1].tv_sec = a->mtime;
978	ts[1].tv_nsec = 0;
979	return ts;
980}
981
982static void
983process_setstat(u_int32_t id)
984{
985	Attrib a;
986	char *name;
987	int r, status = SSH2_FX_OK;
988
989	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
990	    (r = decode_attrib(iqueue, &a)) != 0)
991		fatal_fr(r, "parse");
992
993	debug("request %u: setstat name \"%s\"", id, name);
994	if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
995		logit("set \"%s\" size %llu",
996		    name, (unsigned long long)a.size);
997		r = truncate(name, a.size);
998		if (r == -1)
999			status = errno_to_portable(errno);
1000	}
1001	if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1002		logit("set \"%s\" mode %04o", name, a.perm);
1003		r = chmod(name, a.perm & 07777);
1004		if (r == -1)
1005			status = errno_to_portable(errno);
1006	}
1007	if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1008		char buf[64];
1009		time_t t = a.mtime;
1010
1011		strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
1012		    localtime(&t));
1013		logit("set \"%s\" modtime %s", name, buf);
1014		r = utimes(name, attrib_to_tv(&a));
1015		if (r == -1)
1016			status = errno_to_portable(errno);
1017	}
1018	if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
1019		logit("set \"%s\" owner %lu group %lu", name,
1020		    (u_long)a.uid, (u_long)a.gid);
1021		r = chown(name, a.uid, a.gid);
1022		if (r == -1)
1023			status = errno_to_portable(errno);
1024	}
1025	send_status(id, status);
1026	free(name);
1027}
1028
1029static void
1030process_fsetstat(u_int32_t id)
1031{
1032	Attrib a;
1033	int handle, fd, r;
1034	int status = SSH2_FX_OK;
1035
1036	if ((r = get_handle(iqueue, &handle)) != 0 ||
1037	    (r = decode_attrib(iqueue, &a)) != 0)
1038		fatal_fr(r, "parse");
1039
1040	debug("request %u: fsetstat handle %d", id, handle);
1041	fd = handle_to_fd(handle);
1042	if (fd < 0)
1043		status = SSH2_FX_FAILURE;
1044	else {
1045		char *name = handle_to_name(handle);
1046
1047		if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
1048			logit("set \"%s\" size %llu",
1049			    name, (unsigned long long)a.size);
1050			r = ftruncate(fd, a.size);
1051			if (r == -1)
1052				status = errno_to_portable(errno);
1053		}
1054		if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1055			logit("set \"%s\" mode %04o", name, a.perm);
1056			r = fchmod(fd, a.perm & 07777);
1057			if (r == -1)
1058				status = errno_to_portable(errno);
1059		}
1060		if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1061			char buf[64];
1062			time_t t = a.mtime;
1063
1064			strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
1065			    localtime(&t));
1066			logit("set \"%s\" modtime %s", name, buf);
1067			r = futimes(fd, attrib_to_tv(&a));
1068			if (r == -1)
1069				status = errno_to_portable(errno);
1070		}
1071		if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
1072			logit("set \"%s\" owner %lu group %lu", name,
1073			    (u_long)a.uid, (u_long)a.gid);
1074			r = fchown(fd, a.uid, a.gid);
1075			if (r == -1)
1076				status = errno_to_portable(errno);
1077		}
1078	}
1079	send_status(id, status);
1080}
1081
1082static void
1083process_opendir(u_int32_t id)
1084{
1085	DIR *dirp = NULL;
1086	char *path;
1087	int r, handle, status = SSH2_FX_FAILURE;
1088
1089	if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
1090		fatal_fr(r, "parse");
1091
1092	debug3("request %u: opendir", id);
1093	logit("opendir \"%s\"", path);
1094	dirp = opendir(path);
1095	if (dirp == NULL) {
1096		status = errno_to_portable(errno);
1097	} else {
1098		handle = handle_new(HANDLE_DIR, path, 0, 0, dirp);
1099		if (handle < 0) {
1100			closedir(dirp);
1101		} else {
1102			send_handle(id, handle);
1103			status = SSH2_FX_OK;
1104		}
1105
1106	}
1107	if (status != SSH2_FX_OK)
1108		send_status(id, status);
1109	free(path);
1110}
1111
1112static void
1113process_readdir(u_int32_t id)
1114{
1115	DIR *dirp;
1116	struct dirent *dp;
1117	char *path;
1118	int r, handle;
1119
1120	if ((r = get_handle(iqueue, &handle)) != 0)
1121		fatal_fr(r, "parse");
1122
1123	debug("request %u: readdir \"%s\" (handle %d)", id,
1124	    handle_to_name(handle), handle);
1125	dirp = handle_to_dir(handle);
1126	path = handle_to_name(handle);
1127	if (dirp == NULL || path == NULL) {
1128		send_status(id, SSH2_FX_FAILURE);
1129	} else {
1130		struct stat st;
1131		char pathname[PATH_MAX];
1132		Stat *stats;
1133		int nstats = 10, count = 0, i;
1134
1135		stats = xcalloc(nstats, sizeof(Stat));
1136		while ((dp = readdir(dirp)) != NULL) {
1137			if (count >= nstats) {
1138				nstats *= 2;
1139				stats = xreallocarray(stats, nstats, sizeof(Stat));
1140			}
1141/* XXX OVERFLOW ? */
1142			snprintf(pathname, sizeof pathname, "%s%s%s", path,
1143			    strcmp(path, "/") ? "/" : "", dp->d_name);
1144			if (lstat(pathname, &st) == -1)
1145				continue;
1146			stat_to_attrib(&st, &(stats[count].attrib));
1147			stats[count].name = xstrdup(dp->d_name);
1148			stats[count].long_name = ls_file(dp->d_name, &st,
1149			    0, 0, NULL, NULL);
1150			count++;
1151			/* send up to 100 entries in one message */
1152			/* XXX check packet size instead */
1153			if (count == 100)
1154				break;
1155		}
1156		if (count > 0) {
1157			send_names(id, count, stats);
1158			for (i = 0; i < count; i++) {
1159				free(stats[i].name);
1160				free(stats[i].long_name);
1161			}
1162		} else {
1163			send_status(id, SSH2_FX_EOF);
1164		}
1165		free(stats);
1166	}
1167}
1168
1169static void
1170process_remove(u_int32_t id)
1171{
1172	char *name;
1173	int r, status = SSH2_FX_FAILURE;
1174
1175	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
1176		fatal_fr(r, "parse");
1177
1178	debug3("request %u: remove", id);
1179	logit("remove name \"%s\"", name);
1180	r = unlink(name);
1181	status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1182	send_status(id, status);
1183	free(name);
1184}
1185
1186static void
1187process_mkdir(u_int32_t id)
1188{
1189	Attrib a;
1190	char *name;
1191	int r, mode, status = SSH2_FX_FAILURE;
1192
1193	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
1194	    (r = decode_attrib(iqueue, &a)) != 0)
1195		fatal_fr(r, "parse");
1196
1197	mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
1198	    a.perm & 07777 : 0777;
1199	debug3("request %u: mkdir", id);
1200	logit("mkdir name \"%s\" mode 0%o", name, mode);
1201	r = mkdir(name, mode);
1202	status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1203	send_status(id, status);
1204	free(name);
1205}
1206
1207static void
1208process_rmdir(u_int32_t id)
1209{
1210	char *name;
1211	int r, status;
1212
1213	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
1214		fatal_fr(r, "parse");
1215
1216	debug3("request %u: rmdir", id);
1217	logit("rmdir name \"%s\"", name);
1218	r = rmdir(name);
1219	status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1220	send_status(id, status);
1221	free(name);
1222}
1223
1224static void
1225process_realpath(u_int32_t id)
1226{
1227	char resolvedname[PATH_MAX];
1228	char *path;
1229	int r;
1230
1231	if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
1232		fatal_fr(r, "parse");
1233
1234	if (path[0] == '\0') {
1235		free(path);
1236		path = xstrdup(".");
1237	}
1238	debug3("request %u: realpath", id);
1239	verbose("realpath \"%s\"", path);
1240	if (sftp_realpath(path, resolvedname) == NULL) {
1241		send_status(id, errno_to_portable(errno));
1242	} else {
1243		Stat s;
1244		attrib_clear(&s.attrib);
1245		s.name = s.long_name = resolvedname;
1246		send_names(id, 1, &s);
1247	}
1248	free(path);
1249}
1250
1251static void
1252process_rename(u_int32_t id)
1253{
1254	char *oldpath, *newpath;
1255	int r, status;
1256	struct stat sb;
1257
1258	if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
1259	    (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
1260		fatal_fr(r, "parse");
1261
1262	debug3("request %u: rename", id);
1263	logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1264	status = SSH2_FX_FAILURE;
1265	if (lstat(oldpath, &sb) == -1)
1266		status = errno_to_portable(errno);
1267	else if (S_ISREG(sb.st_mode)) {
1268		/* Race-free rename of regular files */
1269		if (link(oldpath, newpath) == -1) {
1270			if (errno == EOPNOTSUPP) {
1271				struct stat st;
1272
1273				/*
1274				 * fs doesn't support links, so fall back to
1275				 * stat+rename.  This is racy.
1276				 */
1277				if (stat(newpath, &st) == -1) {
1278					if (rename(oldpath, newpath) == -1)
1279						status =
1280						    errno_to_portable(errno);
1281					else
1282						status = SSH2_FX_OK;
1283				}
1284			} else {
1285				status = errno_to_portable(errno);
1286			}
1287		} else if (unlink(oldpath) == -1) {
1288			status = errno_to_portable(errno);
1289			/* clean spare link */
1290			unlink(newpath);
1291		} else
1292			status = SSH2_FX_OK;
1293	} else if (stat(newpath, &sb) == -1) {
1294		if (rename(oldpath, newpath) == -1)
1295			status = errno_to_portable(errno);
1296		else
1297			status = SSH2_FX_OK;
1298	}
1299	send_status(id, status);
1300	free(oldpath);
1301	free(newpath);
1302}
1303
1304static void
1305process_readlink(u_int32_t id)
1306{
1307	int r, len;
1308	char buf[PATH_MAX];
1309	char *path;
1310
1311	if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
1312		fatal_fr(r, "parse");
1313
1314	debug3("request %u: readlink", id);
1315	verbose("readlink \"%s\"", path);
1316	if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1317		send_status(id, errno_to_portable(errno));
1318	else {
1319		Stat s;
1320
1321		buf[len] = '\0';
1322		attrib_clear(&s.attrib);
1323		s.name = s.long_name = buf;
1324		send_names(id, 1, &s);
1325	}
1326	free(path);
1327}
1328
1329static void
1330process_symlink(u_int32_t id)
1331{
1332	char *oldpath, *newpath;
1333	int r, status;
1334
1335	if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
1336	    (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
1337		fatal_fr(r, "parse");
1338
1339	debug3("request %u: symlink", id);
1340	logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1341	/* this will fail if 'newpath' exists */
1342	r = symlink(oldpath, newpath);
1343	status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1344	send_status(id, status);
1345	free(oldpath);
1346	free(newpath);
1347}
1348
1349static void
1350process_extended_posix_rename(u_int32_t id)
1351{
1352	char *oldpath, *newpath;
1353	int r, status;
1354
1355	if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
1356	    (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
1357		fatal_fr(r, "parse");
1358
1359	debug3("request %u: posix-rename", id);
1360	logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1361	r = rename(oldpath, newpath);
1362	status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1363	send_status(id, status);
1364	free(oldpath);
1365	free(newpath);
1366}
1367
1368static void
1369process_extended_statvfs(u_int32_t id)
1370{
1371	char *path;
1372	struct statvfs st;
1373	int r;
1374
1375	if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
1376		fatal_fr(r, "parse");
1377	debug3("request %u: statvfs", id);
1378	logit("statvfs \"%s\"", path);
1379
1380	if (statvfs(path, &st) != 0)
1381		send_status(id, errno_to_portable(errno));
1382	else
1383		send_statvfs(id, &st);
1384	free(path);
1385}
1386
1387static void
1388process_extended_fstatvfs(u_int32_t id)
1389{
1390	int r, handle, fd;
1391	struct statvfs st;
1392
1393	if ((r = get_handle(iqueue, &handle)) != 0)
1394		fatal_fr(r, "parse");
1395	debug("request %u: fstatvfs \"%s\" (handle %u)",
1396	    id, handle_to_name(handle), handle);
1397	if ((fd = handle_to_fd(handle)) < 0) {
1398		send_status(id, SSH2_FX_FAILURE);
1399		return;
1400	}
1401	if (fstatvfs(fd, &st) != 0)
1402		send_status(id, errno_to_portable(errno));
1403	else
1404		send_statvfs(id, &st);
1405}
1406
1407static void
1408process_extended_hardlink(u_int32_t id)
1409{
1410	char *oldpath, *newpath;
1411	int r, status;
1412
1413	if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
1414	    (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
1415		fatal_fr(r, "parse");
1416
1417	debug3("request %u: hardlink", id);
1418	logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1419	r = link(oldpath, newpath);
1420	status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1421	send_status(id, status);
1422	free(oldpath);
1423	free(newpath);
1424}
1425
1426static void
1427process_extended_fsync(u_int32_t id)
1428{
1429	int handle, fd, r, status = SSH2_FX_OP_UNSUPPORTED;
1430
1431	if ((r = get_handle(iqueue, &handle)) != 0)
1432		fatal_fr(r, "parse");
1433	debug3("request %u: fsync (handle %u)", id, handle);
1434	verbose("fsync \"%s\"", handle_to_name(handle));
1435	if ((fd = handle_to_fd(handle)) < 0)
1436		status = SSH2_FX_NO_SUCH_FILE;
1437	else if (handle_is_ok(handle, HANDLE_FILE)) {
1438		r = fsync(fd);
1439		status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1440	}
1441	send_status(id, status);
1442}
1443
1444static void
1445process_extended_lsetstat(u_int32_t id)
1446{
1447	Attrib a;
1448	char *name;
1449	int r, status = SSH2_FX_OK;
1450
1451	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
1452	    (r = decode_attrib(iqueue, &a)) != 0)
1453		fatal_fr(r, "parse");
1454
1455	debug("request %u: lsetstat name \"%s\"", id, name);
1456	if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
1457		/* nonsensical for links */
1458		status = SSH2_FX_BAD_MESSAGE;
1459		goto out;
1460	}
1461	if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1462		logit("set \"%s\" mode %04o", name, a.perm);
1463		r = fchmodat(AT_FDCWD, name,
1464		    a.perm & 07777, AT_SYMLINK_NOFOLLOW);
1465		if (r == -1)
1466			status = errno_to_portable(errno);
1467	}
1468	if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1469		char buf[64];
1470		time_t t = a.mtime;
1471
1472		strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
1473		    localtime(&t));
1474		logit("set \"%s\" modtime %s", name, buf);
1475		r = utimensat(AT_FDCWD, name,
1476		    attrib_to_ts(&a), AT_SYMLINK_NOFOLLOW);
1477		if (r == -1)
1478			status = errno_to_portable(errno);
1479	}
1480	if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
1481		logit("set \"%s\" owner %lu group %lu", name,
1482		    (u_long)a.uid, (u_long)a.gid);
1483		r = fchownat(AT_FDCWD, name, a.uid, a.gid,
1484		    AT_SYMLINK_NOFOLLOW);
1485		if (r == -1)
1486			status = errno_to_portable(errno);
1487	}
1488 out:
1489	send_status(id, status);
1490	free(name);
1491}
1492
1493static void
1494process_extended_limits(u_int32_t id)
1495{
1496	struct sshbuf *msg;
1497	int r;
1498	uint64_t nfiles = 0;
1499	struct rlimit rlim;
1500
1501	debug("request %u: limits", id);
1502
1503	if (getrlimit(RLIMIT_NOFILE, &rlim) != -1 && rlim.rlim_cur > 5)
1504		nfiles = rlim.rlim_cur - 5; /* stdio(3) + syslog + spare */
1505
1506	if ((msg = sshbuf_new()) == NULL)
1507		fatal_f("sshbuf_new failed");
1508	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 ||
1509	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1510	    /* max-packet-length */
1511	    (r = sshbuf_put_u64(msg, SFTP_MAX_MSG_LENGTH)) != 0 ||
1512	    /* max-read-length */
1513	    (r = sshbuf_put_u64(msg, SFTP_MAX_READ_LENGTH)) != 0 ||
1514	    /* max-write-length */
1515	    (r = sshbuf_put_u64(msg, SFTP_MAX_MSG_LENGTH - 1024)) != 0 ||
1516	    /* max-open-handles */
1517	    (r = sshbuf_put_u64(msg, nfiles)) != 0)
1518		fatal_fr(r, "compose");
1519	send_msg(msg);
1520	sshbuf_free(msg);
1521}
1522
1523static void
1524process_extended_expand(u_int32_t id)
1525{
1526	char cwd[PATH_MAX], resolvedname[PATH_MAX];
1527	char *path, *npath;
1528	int r;
1529	Stat s;
1530
1531	if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
1532		fatal_fr(r, "parse");
1533	if (getcwd(cwd, sizeof(cwd)) == NULL) {
1534		send_status(id, errno_to_portable(errno));
1535		goto out;
1536	}
1537
1538	debug3("request %u: expand, original \"%s\"", id, path);
1539	if (path[0] == '\0') {
1540		/* empty path */
1541		free(path);
1542		path = xstrdup(".");
1543	} else if (*path == '~') {
1544		/* ~ expand path */
1545		/* Special-case for "~" and "~/" to respect homedir flag */
1546		if (strcmp(path, "~") == 0) {
1547			free(path);
1548			path = xstrdup(cwd);
1549		} else if (strncmp(path, "~/", 2) == 0) {
1550			npath = xstrdup(path + 2);
1551			free(path);
1552			xasprintf(&path, "%s/%s", cwd, npath);
1553			free(npath);
1554		} else {
1555			/* ~user expansions */
1556			if (tilde_expand(path, pw->pw_uid, &npath) != 0) {
1557				send_status_errmsg(id,
1558				    errno_to_portable(ENOENT), "no such user");
1559				goto out;
1560			}
1561			free(path);
1562			path = npath;
1563		}
1564	} else if (*path != '/') {
1565		/* relative path */
1566		xasprintf(&npath, "%s/%s", cwd, path);
1567		free(path);
1568		path = npath;
1569	}
1570	verbose("expand \"%s\"", path);
1571	if (sftp_realpath(path, resolvedname) == NULL) {
1572		send_status(id, errno_to_portable(errno));
1573		goto out;
1574	}
1575	attrib_clear(&s.attrib);
1576	s.name = s.long_name = resolvedname;
1577	send_names(id, 1, &s);
1578 out:
1579	free(path);
1580}
1581
1582static void
1583process_extended_copy_data(u_int32_t id)
1584{
1585	u_char buf[64*1024];
1586	int read_handle, read_fd, write_handle, write_fd;
1587	u_int64_t len, read_off, read_len, write_off;
1588	int r, copy_until_eof, status = SSH2_FX_OP_UNSUPPORTED;
1589	size_t ret;
1590
1591	if ((r = get_handle(iqueue, &read_handle)) != 0 ||
1592	    (r = sshbuf_get_u64(iqueue, &read_off)) != 0 ||
1593	    (r = sshbuf_get_u64(iqueue, &read_len)) != 0 ||
1594	    (r = get_handle(iqueue, &write_handle)) != 0 ||
1595	    (r = sshbuf_get_u64(iqueue, &write_off)) != 0)
1596		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1597
1598	debug("request %u: copy-data from \"%s\" (handle %d) off %llu len %llu "
1599	    "to \"%s\" (handle %d) off %llu",
1600	    id, handle_to_name(read_handle), read_handle,
1601	    (unsigned long long)read_off, (unsigned long long)read_len,
1602	    handle_to_name(write_handle), write_handle,
1603	    (unsigned long long)write_off);
1604
1605	/* For read length of 0, we read until EOF. */
1606	if (read_len == 0) {
1607		read_len = (u_int64_t)-1 - read_off;
1608		copy_until_eof = 1;
1609	} else
1610		copy_until_eof = 0;
1611
1612	read_fd = handle_to_fd(read_handle);
1613	write_fd = handle_to_fd(write_handle);
1614
1615	/* Disallow reading & writing to the same handle or same path or dirs */
1616	if (read_handle == write_handle || read_fd < 0 || write_fd < 0 ||
1617	    !strcmp(handle_to_name(read_handle), handle_to_name(write_handle))) {
1618		status = SSH2_FX_FAILURE;
1619		goto out;
1620	}
1621
1622	if (lseek(read_fd, read_off, SEEK_SET) < 0) {
1623		status = errno_to_portable(errno);
1624		error("%s: read_seek failed", __func__);
1625		goto out;
1626	}
1627
1628	if ((handle_to_flags(write_handle) & O_APPEND) == 0 &&
1629	    lseek(write_fd, write_off, SEEK_SET) < 0) {
1630		status = errno_to_portable(errno);
1631		error("%s: write_seek failed", __func__);
1632		goto out;
1633	}
1634
1635	/* Process the request in chunks. */
1636	while (read_len > 0 || copy_until_eof) {
1637		len = MINIMUM(sizeof(buf), read_len);
1638		read_len -= len;
1639
1640		ret = atomicio(read, read_fd, buf, len);
1641		if (ret == 0 && errno == EPIPE) {
1642			status = copy_until_eof ? SSH2_FX_OK : SSH2_FX_EOF;
1643			break;
1644		} else if (ret == 0) {
1645			status = errno_to_portable(errno);
1646			error("%s: read failed: %s", __func__, strerror(errno));
1647			break;
1648		}
1649		len = ret;
1650		handle_update_read(read_handle, len);
1651
1652		ret = atomicio(vwrite, write_fd, buf, len);
1653		if (ret != len) {
1654			status = errno_to_portable(errno);
1655			error("%s: write failed: %llu != %llu: %s", __func__,
1656			    (unsigned long long)ret, (unsigned long long)len,
1657			    strerror(errno));
1658			break;
1659		}
1660		handle_update_write(write_handle, len);
1661	}
1662
1663	if (read_len == 0)
1664		status = SSH2_FX_OK;
1665
1666 out:
1667	send_status(id, status);
1668}
1669
1670static void
1671process_extended_home_directory(u_int32_t id)
1672{
1673	char *username;
1674	struct passwd *user_pw;
1675	int r;
1676	Stat s;
1677
1678	if ((r = sshbuf_get_cstring(iqueue, &username, NULL)) != 0)
1679		fatal_fr(r, "parse");
1680
1681	debug3("request %u: home-directory \"%s\"", id, username);
1682	if ((user_pw = getpwnam(username)) == NULL) {
1683		send_status(id, SSH2_FX_FAILURE);
1684		goto out;
1685	}
1686
1687	verbose("home-directory \"%s\"", pw->pw_dir);
1688	attrib_clear(&s.attrib);
1689	s.name = s.long_name = pw->pw_dir;
1690	send_names(id, 1, &s);
1691 out:
1692	free(username);
1693}
1694
1695static void
1696process_extended_get_users_groups_by_id(u_int32_t id)
1697{
1698	struct passwd *user_pw;
1699	struct group *gr;
1700	struct sshbuf *uids, *gids, *usernames, *groupnames, *msg;
1701	int r;
1702	u_int n, nusers = 0, ngroups = 0;
1703	const char *name;
1704
1705	if ((usernames = sshbuf_new()) == NULL ||
1706	    (groupnames = sshbuf_new()) == NULL ||
1707	    (msg = sshbuf_new()) == NULL)
1708		fatal_f("sshbuf_new failed");
1709	if ((r = sshbuf_froms(iqueue, &uids)) != 0 ||
1710	    (r = sshbuf_froms(iqueue, &gids)) != 0)
1711		fatal_fr(r, "parse");
1712	debug_f("uids len = %zu, gids len = %zu",
1713	    sshbuf_len(uids), sshbuf_len(gids));
1714	while (sshbuf_len(uids) != 0) {
1715		if ((r = sshbuf_get_u32(uids, &n)) != 0)
1716			fatal_fr(r, "parse inner uid");
1717		user_pw = getpwuid((uid_t)n);
1718		name = user_pw == NULL ? "" : user_pw->pw_name;
1719		debug3_f("uid %u => \"%s\"", n, name);
1720		if ((r = sshbuf_put_cstring(usernames, name)) != 0)
1721			fatal_fr(r, "assemble uid reply");
1722		nusers++;
1723	}
1724	while (sshbuf_len(gids) != 0) {
1725		if ((r = sshbuf_get_u32(gids, &n)) != 0)
1726			fatal_fr(r, "parse inner gid");
1727		gr = getgrgid((gid_t)n);
1728		name = gr == NULL ? "" : gr->gr_name;
1729		debug3_f("gid %u => \"%s\"", n, name);
1730		if ((r = sshbuf_put_cstring(groupnames, name)) != 0)
1731			fatal_fr(r, "assemble gid reply");
1732		nusers++;
1733	}
1734	verbose("users-groups-by-id: %u users, %u groups", nusers, ngroups);
1735
1736	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 ||
1737	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1738	    (r = sshbuf_put_stringb(msg, usernames)) != 0 ||
1739	    (r = sshbuf_put_stringb(msg, groupnames)) != 0)
1740		fatal_fr(r, "compose");
1741	send_msg(msg);
1742
1743	sshbuf_free(uids);
1744	sshbuf_free(gids);
1745	sshbuf_free(usernames);
1746	sshbuf_free(groupnames);
1747	sshbuf_free(msg);
1748}
1749
1750static void
1751process_extended(u_int32_t id)
1752{
1753	char *request;
1754	int r;
1755	const struct sftp_handler *exthand;
1756
1757	if ((r = sshbuf_get_cstring(iqueue, &request, NULL)) != 0)
1758		fatal_fr(r, "parse");
1759	if ((exthand = extended_handler_byname(request)) == NULL) {
1760		error("Unknown extended request \"%.100s\"", request);
1761		send_status(id, SSH2_FX_OP_UNSUPPORTED);	/* MUST */
1762	} else {
1763		if (!request_permitted(exthand))
1764			send_status(id, SSH2_FX_PERMISSION_DENIED);
1765		else
1766			exthand->handler(id);
1767	}
1768	free(request);
1769}
1770
1771/* stolen from ssh-agent */
1772
1773static void
1774process(void)
1775{
1776	u_int msg_len;
1777	u_int buf_len;
1778	u_int consumed;
1779	u_char type;
1780	const u_char *cp;
1781	int i, r;
1782	u_int32_t id;
1783
1784	buf_len = sshbuf_len(iqueue);
1785	if (buf_len < 5)
1786		return;		/* Incomplete message. */
1787	cp = sshbuf_ptr(iqueue);
1788	msg_len = get_u32(cp);
1789	if (msg_len > SFTP_MAX_MSG_LENGTH) {
1790		error("bad message from %s local user %s",
1791		    client_addr, pw->pw_name);
1792		sftp_server_cleanup_exit(11);
1793	}
1794	if (buf_len < msg_len + 4)
1795		return;
1796	if ((r = sshbuf_consume(iqueue, 4)) != 0)
1797		fatal_fr(r, "consume");
1798	buf_len -= 4;
1799	if ((r = sshbuf_get_u8(iqueue, &type)) != 0)
1800		fatal_fr(r, "parse type");
1801
1802	switch (type) {
1803	case SSH2_FXP_INIT:
1804		process_init();
1805		init_done = 1;
1806		break;
1807	case SSH2_FXP_EXTENDED:
1808		if (!init_done)
1809			fatal("Received extended request before init");
1810		if ((r = sshbuf_get_u32(iqueue, &id)) != 0)
1811			fatal_fr(r, "parse extended ID");
1812		process_extended(id);
1813		break;
1814	default:
1815		if (!init_done)
1816			fatal("Received %u request before init", type);
1817		if ((r = sshbuf_get_u32(iqueue, &id)) != 0)
1818			fatal_fr(r, "parse ID");
1819		for (i = 0; handlers[i].handler != NULL; i++) {
1820			if (type == handlers[i].type) {
1821				if (!request_permitted(&handlers[i])) {
1822					send_status(id,
1823					    SSH2_FX_PERMISSION_DENIED);
1824				} else {
1825					handlers[i].handler(id);
1826				}
1827				break;
1828			}
1829		}
1830		if (handlers[i].handler == NULL)
1831			error("Unknown message %u", type);
1832	}
1833	/* discard the remaining bytes from the current packet */
1834	if (buf_len < sshbuf_len(iqueue)) {
1835		error("iqueue grew unexpectedly");
1836		sftp_server_cleanup_exit(255);
1837	}
1838	consumed = buf_len - sshbuf_len(iqueue);
1839	if (msg_len < consumed) {
1840		error("msg_len %u < consumed %u", msg_len, consumed);
1841		sftp_server_cleanup_exit(255);
1842	}
1843	if (msg_len > consumed &&
1844	    (r = sshbuf_consume(iqueue, msg_len - consumed)) != 0)
1845		fatal_fr(r, "consume");
1846}
1847
1848/* Cleanup handler that logs active handles upon normal exit */
1849void
1850sftp_server_cleanup_exit(int i)
1851{
1852	if (pw != NULL && client_addr != NULL) {
1853		handle_log_exit();
1854		logit("session closed for local user %s from [%s]",
1855		    pw->pw_name, client_addr);
1856	}
1857	_exit(i);
1858}
1859
1860__dead static void
1861sftp_server_usage(void)
1862{
1863	extern char *__progname;
1864
1865	fprintf(stderr,
1866	    "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
1867	    "[-l log_level]\n\t[-P denied_requests] "
1868	    "[-p allowed_requests] [-u umask]\n"
1869	    "       %s -Q protocol_feature\n",
1870	    __progname, __progname);
1871	exit(1);
1872}
1873
1874int
1875sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1876{
1877	int i, r, in, out, ch, skipargs = 0, log_stderr = 0;
1878	ssize_t len, olen;
1879	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1880	char *cp, *homedir = NULL, uidstr[32], buf[4*4096];
1881	long mask;
1882
1883	extern char *optarg;
1884	extern char *__progname;
1885
1886	log_init(__progname, log_level, log_facility, log_stderr);
1887
1888	pw = pwcopy(user_pw);
1889
1890	while (!skipargs && (ch = getopt(argc, argv,
1891	    "d:f:l:P:p:Q:u:cehR")) != -1) {
1892		switch (ch) {
1893		case 'Q':
1894			if (strcasecmp(optarg, "requests") != 0) {
1895				fprintf(stderr, "Invalid query type\n");
1896				exit(1);
1897			}
1898			for (i = 0; handlers[i].handler != NULL; i++)
1899				printf("%s\n", handlers[i].name);
1900			for (i = 0; extended_handlers[i].handler != NULL; i++)
1901				printf("%s\n", extended_handlers[i].name);
1902			exit(0);
1903			break;
1904		case 'R':
1905			readonly = 1;
1906			break;
1907		case 'c':
1908			/*
1909			 * Ignore all arguments if we are invoked as a
1910			 * shell using "sftp-server -c command"
1911			 */
1912			skipargs = 1;
1913			break;
1914		case 'e':
1915			log_stderr = 1;
1916			break;
1917		case 'l':
1918			log_level = log_level_number(optarg);
1919			if (log_level == SYSLOG_LEVEL_NOT_SET)
1920				error("Invalid log level \"%s\"", optarg);
1921			break;
1922		case 'f':
1923			log_facility = log_facility_number(optarg);
1924			if (log_facility == SYSLOG_FACILITY_NOT_SET)
1925				error("Invalid log facility \"%s\"", optarg);
1926			break;
1927		case 'd':
1928			cp = tilde_expand_filename(optarg, user_pw->pw_uid);
1929			snprintf(uidstr, sizeof(uidstr), "%llu",
1930			    (unsigned long long)pw->pw_uid);
1931			homedir = percent_expand(cp, "d", user_pw->pw_dir,
1932			    "u", user_pw->pw_name, "U", uidstr, (char *)NULL);
1933			free(cp);
1934			break;
1935		case 'p':
1936			if (request_allowlist != NULL)
1937				fatal("Permitted requests already set");
1938			request_allowlist = xstrdup(optarg);
1939			break;
1940		case 'P':
1941			if (request_denylist != NULL)
1942				fatal("Refused requests already set");
1943			request_denylist = xstrdup(optarg);
1944			break;
1945		case 'u':
1946			errno = 0;
1947			mask = strtol(optarg, &cp, 8);
1948			if (mask < 0 || mask > 0777 || *cp != '\0' ||
1949			    cp == optarg || (mask == 0 && errno != 0))
1950				fatal("Invalid umask \"%s\"", optarg);
1951			(void)umask((mode_t)mask);
1952			break;
1953		case 'h':
1954		default:
1955			sftp_server_usage();
1956		}
1957	}
1958
1959	log_init(__progname, log_level, log_facility, log_stderr);
1960
1961	if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1962		client_addr = xstrdup(cp);
1963		if ((cp = strchr(client_addr, ' ')) == NULL) {
1964			error("Malformed SSH_CONNECTION variable: \"%s\"",
1965			    getenv("SSH_CONNECTION"));
1966			sftp_server_cleanup_exit(255);
1967		}
1968		*cp = '\0';
1969	} else
1970		client_addr = xstrdup("UNKNOWN");
1971
1972	logit("session opened for local user %s from [%s]",
1973	    pw->pw_name, client_addr);
1974
1975	in = STDIN_FILENO;
1976	out = STDOUT_FILENO;
1977
1978	if ((iqueue = sshbuf_new()) == NULL)
1979		fatal_f("sshbuf_new failed");
1980	if ((oqueue = sshbuf_new()) == NULL)
1981		fatal_f("sshbuf_new failed");
1982
1983	if (homedir != NULL) {
1984		if (chdir(homedir) != 0) {
1985			error("chdir to \"%s\" failed: %s", homedir,
1986			    strerror(errno));
1987		}
1988	}
1989
1990	for (;;) {
1991		struct pollfd pfd[2];
1992
1993		memset(pfd, 0, sizeof pfd);
1994		pfd[0].fd = pfd[1].fd = -1;
1995
1996		/*
1997		 * Ensure that we can read a full buffer and handle
1998		 * the worst-case length packet it can generate,
1999		 * otherwise apply backpressure by stopping reads.
2000		 */
2001		if ((r = sshbuf_check_reserve(iqueue, sizeof(buf))) == 0 &&
2002		    (r = sshbuf_check_reserve(oqueue,
2003		    SFTP_MAX_MSG_LENGTH)) == 0) {
2004			pfd[0].fd = in;
2005			pfd[0].events = POLLIN;
2006		}
2007		else if (r != SSH_ERR_NO_BUFFER_SPACE)
2008			fatal_fr(r, "reserve");
2009
2010		olen = sshbuf_len(oqueue);
2011		if (olen > 0) {
2012			pfd[1].fd = out;
2013			pfd[1].events = POLLOUT;
2014		}
2015
2016		if (poll(pfd, 2, -1) == -1) {
2017			if (errno == EINTR)
2018				continue;
2019			error("poll: %s", strerror(errno));
2020			sftp_server_cleanup_exit(2);
2021		}
2022
2023		/* copy stdin to iqueue */
2024		if (pfd[0].revents & (POLLIN|POLLHUP)) {
2025			len = read(in, buf, sizeof buf);
2026			if (len == 0) {
2027				debug("read eof");
2028				sftp_server_cleanup_exit(0);
2029			} else if (len == -1) {
2030				if (errno != EAGAIN && errno != EINTR) {
2031					error("read: %s", strerror(errno));
2032					sftp_server_cleanup_exit(1);
2033				}
2034			} else if ((r = sshbuf_put(iqueue, buf, len)) != 0)
2035				fatal_fr(r, "sshbuf_put");
2036		}
2037		/* send oqueue to stdout */
2038		if (pfd[1].revents & (POLLOUT|POLLHUP)) {
2039			len = write(out, sshbuf_ptr(oqueue), olen);
2040			if (len == 0 || (len == -1 && errno == EPIPE)) {
2041				debug("write eof");
2042				sftp_server_cleanup_exit(0);
2043			} else if (len == -1) {
2044				sftp_server_cleanup_exit(1);
2045				if (errno != EAGAIN && errno != EINTR) {
2046					error("write: %s", strerror(errno));
2047					sftp_server_cleanup_exit(1);
2048				}
2049			} else if ((r = sshbuf_consume(oqueue, len)) != 0)
2050				fatal_fr(r, "consume");
2051		}
2052
2053		/*
2054		 * Process requests from client if we can fit the results
2055		 * into the output buffer, otherwise stop processing input
2056		 * and let the output queue drain.
2057		 */
2058		r = sshbuf_check_reserve(oqueue, SFTP_MAX_MSG_LENGTH);
2059		if (r == 0)
2060			process();
2061		else if (r != SSH_ERR_NO_BUFFER_SPACE)
2062			fatal_fr(r, "reserve");
2063	}
2064}
2065