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