2 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
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.
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.
17 RCSID("$OpenBSD: sftp-server.c,v 1.50 2006/01/02 01:20:31 djm Exp $");
27 #include "sftp-common.h"
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);
35 extern char *__progname;
37 /* input and output queue */
41 /* Version of client */
44 /* portable attributes, etc. */
46 typedef struct Stat Stat;
55 errno_to_portable(int unixerrno)
67 ret = SSH2_FX_NO_SUCH_FILE;
72 ret = SSH2_FX_PERMISSION_DENIED;
76 ret = SSH2_FX_BAD_MESSAGE;
79 ret = SSH2_FX_FAILURE;
86 flags_from_portable(int pflags)
90 if ((pflags & SSH2_FXF_READ) &&
91 (pflags & SSH2_FXF_WRITE)) {
93 } else if (pflags & SSH2_FXF_READ) {
95 } else if (pflags & SSH2_FXF_WRITE) {
98 if (pflags & SSH2_FXF_CREAT)
100 if (pflags & SSH2_FXF_TRUNC)
102 if (pflags & SSH2_FXF_EXCL)
110 return decode_attrib(&iqueue);
115 typedef struct Handle Handle;
136 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
137 handles[i].use = HANDLE_UNUSED;
141 handle_new(int use, const char *name, int fd, DIR *dirp)
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;
150 handles[i].name = xstrdup(name);
158 handle_is_ok(int i, int type)
160 return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
161 handles[i].use == type;
165 handle_to_string(int handle, char **stringp, int *hlenp)
167 if (stringp == NULL || hlenp == NULL)
169 *stringp = xmalloc(sizeof(int32_t));
170 PUT_32BIT(*stringp, handle);
171 *hlenp = sizeof(int32_t);
176 handle_from_string(const char *handle, u_int hlen)
180 if (hlen != sizeof(int32_t))
182 val = GET_32BIT(handle);
183 if (handle_is_ok(val, HANDLE_FILE) ||
184 handle_is_ok(val, HANDLE_DIR))
190 handle_to_name(int handle)
192 if (handle_is_ok(handle, HANDLE_DIR)||
193 handle_is_ok(handle, HANDLE_FILE))
194 return handles[handle].name;
199 handle_to_dir(int handle)
201 if (handle_is_ok(handle, HANDLE_DIR))
202 return handles[handle].dirp;
207 handle_to_fd(int handle)
209 if (handle_is_ok(handle, HANDLE_FILE))
210 return handles[handle].fd;
215 handle_close(int handle)
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);
240 handle = get_string(&hlen);
242 val = handle_from_string(handle, hlen);
252 int mlen = buffer_len(m);
254 buffer_put_int(&oqueue, mlen);
255 buffer_append(&oqueue, buffer_ptr(m), mlen);
256 buffer_consume(m, mlen);
260 send_status(u_int32_t id, u_int32_t status)
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 */
276 TRACE("sent status id %u error %u", id, status);
278 buffer_put_char(&msg, SSH2_FXP_STATUS);
279 buffer_put_int(&msg, id);
280 buffer_put_int(&msg, status);
282 buffer_put_cstring(&msg,
283 status_messages[MIN(status,SSH2_FX_MAX)]);
284 buffer_put_cstring(&msg, "");
290 send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
295 buffer_put_char(&msg, type);
296 buffer_put_int(&msg, id);
297 buffer_put_string(&msg, data, dlen);
303 send_data(u_int32_t id, const char *data, int dlen)
305 TRACE("sent data id %u len %d", id, dlen);
306 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
310 send_handle(u_int32_t id, int handle)
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);
322 send_names(u_int32_t id, int count, const Stat *stats)
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);
342 send_attrib(u_int32_t id, const Attrib *a)
346 TRACE("sent attrib id %u have 0x%x", id, a->flags);
348 buffer_put_char(&msg, SSH2_FXP_ATTRS);
349 buffer_put_int(&msg, id);
350 encode_attrib(&msg, a);
363 TRACE("client version %d", version);
365 buffer_put_char(&msg, SSH2_FXP_VERSION);
366 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
374 u_int32_t id, pflags;
377 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
380 name = get_string(NULL);
381 pflags = get_int(); /* portable flags */
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);
388 status = errno_to_portable(errno);
390 handle = handle_new(HANDLE_FILE, name, fd, NULL);
394 send_handle(id, handle);
398 if (status != SSH2_FX_OK)
399 send_status(id, status);
407 int handle, ret, status = SSH2_FX_FAILURE;
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);
422 int handle, fd, ret, status = SSH2_FX_FAILURE;
426 handle = get_handle();
430 TRACE("read id %u handle %d off %llu len %d", id, handle,
431 (unsigned long long)off, len);
432 if (len > sizeof buf) {
434 logit("read change len %d", len);
436 fd = handle_to_fd(handle);
438 if (lseek(fd, off, SEEK_SET) < 0) {
439 error("process_read: seek failed");
440 status = errno_to_portable(errno);
442 ret = read(fd, buf, len);
444 status = errno_to_portable(errno);
445 } else if (ret == 0) {
446 status = SSH2_FX_EOF;
448 send_data(id, buf, ret);
453 if (status != SSH2_FX_OK)
454 send_status(id, status);
463 int handle, fd, ret, status = SSH2_FX_FAILURE;
467 handle = get_handle();
469 data = get_string(&len);
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);
475 if (lseek(fd, off, SEEK_SET) < 0) {
476 status = errno_to_portable(errno);
477 error("process_write: seek failed");
480 ret = write(fd, data, len);
482 error("process_write: write failed");
483 status = errno_to_portable(errno);
484 } else if ((size_t)ret == len) {
487 logit("nothing at all written");
491 send_status(id, status);
496 process_do_stat(int do_lstat)
502 int ret, status = SSH2_FX_FAILURE;
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);
509 status = errno_to_portable(errno);
511 stat_to_attrib(&st, &a);
515 if (status != SSH2_FX_OK)
516 send_status(id, status);
538 int fd, ret, handle, status = SSH2_FX_FAILURE;
541 handle = get_handle();
542 TRACE("fstat id %u handle %d", id, handle);
543 fd = handle_to_fd(handle);
545 ret = fstat(fd, &st);
547 status = errno_to_portable(errno);
549 stat_to_attrib(&st, &a);
554 if (status != SSH2_FX_OK)
555 send_status(id, status);
558 static struct timeval *
559 attrib_to_tv(const Attrib *a)
561 static struct timeval tv[2];
563 tv[0].tv_sec = a->atime;
565 tv[1].tv_sec = a->mtime;
571 process_setstat(void)
576 int status = SSH2_FX_OK, ret;
579 name = get_string(NULL);
581 TRACE("setstat id %u name %s", id, name);
582 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
583 ret = truncate(name, a->size);
585 status = errno_to_portable(errno);
587 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
588 ret = chmod(name, a->perm & 0777);
590 status = errno_to_portable(errno);
592 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
593 ret = utimes(name, attrib_to_tv(a));
595 status = errno_to_portable(errno);
597 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
598 ret = chown(name, a->uid, a->gid);
600 status = errno_to_portable(errno);
602 send_status(id, status);
607 process_fsetstat(void)
612 int status = SSH2_FX_OK;
616 handle = get_handle();
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;
624 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
625 ret = ftruncate(fd, a->size);
627 status = errno_to_portable(errno);
629 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
631 ret = fchmod(fd, a->perm & 0777);
633 ret = chmod(name, a->perm & 0777);
636 status = errno_to_portable(errno);
638 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
640 ret = futimes(fd, attrib_to_tv(a));
642 ret = utimes(name, attrib_to_tv(a));
645 status = errno_to_portable(errno);
647 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
649 ret = fchown(fd, a->uid, a->gid);
651 ret = chown(name, a->uid, a->gid);
654 status = errno_to_portable(errno);
657 send_status(id, status);
661 process_opendir(void)
665 int handle, status = SSH2_FX_FAILURE;
669 path = get_string(NULL);
670 TRACE("opendir id %u path %s", id, path);
671 dirp = opendir(path);
673 status = errno_to_portable(errno);
675 handle = handle_new(HANDLE_DIR, path, 0, dirp);
679 send_handle(id, handle);
684 if (status != SSH2_FX_OK)
685 send_status(id, status);
690 process_readdir(void)
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);
709 int nstats = 10, count = 0, i;
711 stats = xmalloc(nstats * sizeof(Stat));
712 while ((dp = readdir(dirp)) != NULL) {
713 if (count >= nstats) {
715 stats = xrealloc(stats, nstats * sizeof(Stat));
718 snprintf(pathname, sizeof pathname, "%s%s%s", path,
719 strcmp(path, "/") ? "/" : "", dp->d_name);
720 if (lstat(pathname, &st) < 0)
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);
726 /* send up to 100 entries in one message */
727 /* XXX check packet size instead */
732 send_names(id, count, stats);
733 for (i = 0; i < count; i++) {
734 xfree(stats[i].name);
735 xfree(stats[i].long_name);
738 send_status(id, SSH2_FX_EOF);
749 int status = SSH2_FX_FAILURE;
753 name = get_string(NULL);
754 TRACE("remove id %u name %s", id, name);
756 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
757 send_status(id, status);
767 int ret, mode, status = SSH2_FX_FAILURE;
770 name = get_string(NULL);
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);
789 name = get_string(NULL);
790 TRACE("rmdir id %u name %s", id, name);
792 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
793 send_status(id, status);
798 process_realpath(void)
800 char resolvedname[MAXPATHLEN];
805 path = get_string(NULL);
806 if (path[0] == '\0') {
810 TRACE("realpath id %u path %s", id, path);
811 if (realpath(path, resolvedname) == NULL) {
812 send_status(id, errno_to_portable(errno));
815 attrib_clear(&s.attrib);
816 s.name = s.long_name = resolvedname;
817 send_names(id, 1, &s);
826 char *oldpath, *newpath;
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
848 * fs doesn't support links, so fall back to
849 * stat+rename. This is racy.
851 if (stat(newpath, &st) == -1) {
852 if (rename(oldpath, newpath) == -1)
854 errno_to_portable(errno);
859 status = errno_to_portable(errno);
861 } else if (unlink(oldpath) == -1) {
862 status = errno_to_portable(errno);
863 /* clean spare link */
867 } else if (stat(newpath, &sb) == -1) {
868 if (rename(oldpath, newpath) == -1)
869 status = errno_to_portable(errno);
873 send_status(id, status);
879 process_readlink(void)
883 char buf[MAXPATHLEN];
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));
895 attrib_clear(&s.attrib);
896 s.name = s.long_name = buf;
897 send_names(id, 1, &s);
903 process_symlink(void)
906 char *oldpath, *newpath;
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);
922 process_extended(void)
928 request = get_string(NULL);
929 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
933 /* stolen from ssh-agent */
944 buf_len = buffer_len(&iqueue);
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 ");
953 if (buf_len < msg_len + 4)
955 buffer_consume(&iqueue, 4);
957 type = buffer_get_char(&iqueue);
980 case SSH2_FXP_SETSTAT:
983 case SSH2_FXP_FSETSTAT:
986 case SSH2_FXP_OPENDIR:
989 case SSH2_FXP_READDIR:
992 case SSH2_FXP_REMOVE:
1001 case SSH2_FXP_REALPATH:
1007 case SSH2_FXP_RENAME:
1010 case SSH2_FXP_READLINK:
1013 case SSH2_FXP_SYMLINK:
1016 case SSH2_FXP_EXTENDED:
1020 error("Unknown message %d", type);
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);
1034 main(int ac, char **av)
1036 fd_set *rset, *wset;
1038 ssize_t len, olen, set_size;
1040 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1043 /* XXX should use getopt */
1045 __progname = ssh_get_progname(av[0]);
1048 #ifdef DEBUG_SFTP_SERVER
1049 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1052 in = dup(STDIN_FILENO);
1053 out = dup(STDOUT_FILENO);
1056 setmode(in, O_BINARY);
1057 setmode(out, O_BINARY);
1066 buffer_init(&iqueue);
1067 buffer_init(&oqueue);
1069 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1070 rset = (fd_set *)xmalloc(set_size);
1071 wset = (fd_set *)xmalloc(set_size);
1074 memset(rset, 0, set_size);
1075 memset(wset, 0, set_size);
1078 olen = buffer_len(&oqueue);
1082 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1088 /* copy stdin to iqueue */
1089 if (FD_ISSET(in, rset)) {
1091 len = read(in, buf, sizeof buf);
1095 } else if (len < 0) {
1096 error("read error");
1099 buffer_append(&iqueue, buf, len);
1102 /* send oqueue to stdout */
1103 if (FD_ISSET(out, wset)) {
1104 len = write(out, buffer_ptr(&oqueue), olen);
1106 error("write error");
1109 buffer_consume(&oqueue, len);
1112 /* process requests from client */