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