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