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