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