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