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.47 2004/06/25 05:38:48 dtucker Exp $");
26 #include "sftp-common.h"
29 #define get_int64() buffer_get_int64(&iqueue);
30 #define get_int() buffer_get_int(&iqueue);
31 #define get_string(lenp) buffer_get_string(&iqueue, lenp);
34 extern char *__progname;
36 /* input and output queue */
40 /* Version of client */
43 /* portable attributes, etc. */
45 typedef struct Stat Stat;
54 errno_to_portable(int unixerrno)
66 ret = SSH2_FX_NO_SUCH_FILE;
71 ret = SSH2_FX_PERMISSION_DENIED;
75 ret = SSH2_FX_BAD_MESSAGE;
78 ret = SSH2_FX_FAILURE;
85 flags_from_portable(int pflags)
89 if ((pflags & SSH2_FXF_READ) &&
90 (pflags & SSH2_FXF_WRITE)) {
92 } else if (pflags & SSH2_FXF_READ) {
94 } else if (pflags & SSH2_FXF_WRITE) {
97 if (pflags & SSH2_FXF_CREAT)
99 if (pflags & SSH2_FXF_TRUNC)
101 if (pflags & SSH2_FXF_EXCL)
109 return decode_attrib(&iqueue);
114 typedef struct Handle Handle;
135 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
136 handles[i].use = HANDLE_UNUSED;
140 handle_new(int use, const char *name, int fd, DIR *dirp)
144 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
145 if (handles[i].use == HANDLE_UNUSED) {
146 handles[i].use = use;
147 handles[i].dirp = dirp;
149 handles[i].name = xstrdup(name);
157 handle_is_ok(int i, int type)
159 return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&
160 handles[i].use == type;
164 handle_to_string(int handle, char **stringp, int *hlenp)
166 if (stringp == NULL || hlenp == NULL)
168 *stringp = xmalloc(sizeof(int32_t));
169 PUT_32BIT(*stringp, handle);
170 *hlenp = sizeof(int32_t);
175 handle_from_string(const char *handle, u_int hlen)
179 if (hlen != sizeof(int32_t))
181 val = GET_32BIT(handle);
182 if (handle_is_ok(val, HANDLE_FILE) ||
183 handle_is_ok(val, HANDLE_DIR))
189 handle_to_name(int handle)
191 if (handle_is_ok(handle, HANDLE_DIR)||
192 handle_is_ok(handle, HANDLE_FILE))
193 return handles[handle].name;
198 handle_to_dir(int handle)
200 if (handle_is_ok(handle, HANDLE_DIR))
201 return handles[handle].dirp;
206 handle_to_fd(int handle)
208 if (handle_is_ok(handle, HANDLE_FILE))
209 return handles[handle].fd;
214 handle_close(int handle)
218 if (handle_is_ok(handle, HANDLE_FILE)) {
219 ret = close(handles[handle].fd);
220 handles[handle].use = HANDLE_UNUSED;
221 xfree(handles[handle].name);
222 } else if (handle_is_ok(handle, HANDLE_DIR)) {
223 ret = closedir(handles[handle].dirp);
224 handles[handle].use = HANDLE_UNUSED;
225 xfree(handles[handle].name);
239 handle = get_string(&hlen);
241 val = handle_from_string(handle, hlen);
251 int mlen = buffer_len(m);
253 buffer_put_int(&oqueue, mlen);
254 buffer_append(&oqueue, buffer_ptr(m), mlen);
255 buffer_consume(m, mlen);
259 send_status(u_int32_t id, u_int32_t status)
262 const char *status_messages[] = {
263 "Success", /* SSH_FX_OK */
264 "End of file", /* SSH_FX_EOF */
265 "No such file", /* SSH_FX_NO_SUCH_FILE */
266 "Permission denied", /* SSH_FX_PERMISSION_DENIED */
267 "Failure", /* SSH_FX_FAILURE */
268 "Bad message", /* SSH_FX_BAD_MESSAGE */
269 "No connection", /* SSH_FX_NO_CONNECTION */
270 "Connection lost", /* SSH_FX_CONNECTION_LOST */
271 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
272 "Unknown error" /* Others */
275 TRACE("sent status id %u error %u", id, status);
277 buffer_put_char(&msg, SSH2_FXP_STATUS);
278 buffer_put_int(&msg, id);
279 buffer_put_int(&msg, status);
281 buffer_put_cstring(&msg,
282 status_messages[MIN(status,SSH2_FX_MAX)]);
283 buffer_put_cstring(&msg, "");
289 send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
294 buffer_put_char(&msg, type);
295 buffer_put_int(&msg, id);
296 buffer_put_string(&msg, data, dlen);
302 send_data(u_int32_t id, const char *data, int dlen)
304 TRACE("sent data id %u len %d", id, dlen);
305 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
309 send_handle(u_int32_t id, int handle)
314 handle_to_string(handle, &string, &hlen);
315 TRACE("sent handle id %u handle %d", id, handle);
316 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
321 send_names(u_int32_t id, int count, const Stat *stats)
327 buffer_put_char(&msg, SSH2_FXP_NAME);
328 buffer_put_int(&msg, id);
329 buffer_put_int(&msg, count);
330 TRACE("sent names id %u count %d", id, count);
331 for (i = 0; i < count; i++) {
332 buffer_put_cstring(&msg, stats[i].name);
333 buffer_put_cstring(&msg, stats[i].long_name);
334 encode_attrib(&msg, &stats[i].attrib);
341 send_attrib(u_int32_t id, const Attrib *a)
345 TRACE("sent attrib id %u have 0x%x", id, a->flags);
347 buffer_put_char(&msg, SSH2_FXP_ATTRS);
348 buffer_put_int(&msg, id);
349 encode_attrib(&msg, a);
362 TRACE("client version %d", version);
364 buffer_put_char(&msg, SSH2_FXP_VERSION);
365 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
373 u_int32_t id, pflags;
376 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
379 name = get_string(NULL);
380 pflags = get_int(); /* portable flags */
382 flags = flags_from_portable(pflags);
383 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
384 TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
385 fd = open(name, flags, mode);
387 status = errno_to_portable(errno);
389 handle = handle_new(HANDLE_FILE, name, fd, NULL);
393 send_handle(id, handle);
397 if (status != SSH2_FX_OK)
398 send_status(id, status);
406 int handle, ret, status = SSH2_FX_FAILURE;
409 handle = get_handle();
410 TRACE("close id %u handle %d", id, handle);
411 ret = handle_close(handle);
412 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
413 send_status(id, status);
421 int handle, fd, ret, status = SSH2_FX_FAILURE;
425 handle = get_handle();
429 TRACE("read id %u handle %d off %llu len %d", id, handle,
430 (u_int64_t)off, len);
431 if (len > sizeof buf) {
433 logit("read change len %d", len);
435 fd = handle_to_fd(handle);
437 if (lseek(fd, off, SEEK_SET) < 0) {
438 error("process_read: seek failed");
439 status = errno_to_portable(errno);
441 ret = read(fd, buf, len);
443 status = errno_to_portable(errno);
444 } else if (ret == 0) {
445 status = SSH2_FX_EOF;
447 send_data(id, buf, ret);
452 if (status != SSH2_FX_OK)
453 send_status(id, status);
462 int handle, fd, ret, status = SSH2_FX_FAILURE;
466 handle = get_handle();
468 data = get_string(&len);
470 TRACE("write id %u handle %d off %llu len %d", id, handle,
471 (u_int64_t)off, len);
472 fd = handle_to_fd(handle);
474 if (lseek(fd, off, SEEK_SET) < 0) {
475 status = errno_to_portable(errno);
476 error("process_write: seek failed");
479 ret = write(fd, data, len);
481 error("process_write: write failed");
482 status = errno_to_portable(errno);
483 } else if (ret == len) {
486 logit("nothing at all written");
490 send_status(id, status);
495 process_do_stat(int do_lstat)
501 int ret, status = SSH2_FX_FAILURE;
504 name = get_string(NULL);
505 TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
506 ret = do_lstat ? lstat(name, &st) : stat(name, &st);
508 status = errno_to_portable(errno);
510 stat_to_attrib(&st, &a);
514 if (status != SSH2_FX_OK)
515 send_status(id, status);
537 int fd, ret, handle, status = SSH2_FX_FAILURE;
540 handle = get_handle();
541 TRACE("fstat id %u handle %d", id, handle);
542 fd = handle_to_fd(handle);
544 ret = fstat(fd, &st);
546 status = errno_to_portable(errno);
548 stat_to_attrib(&st, &a);
553 if (status != SSH2_FX_OK)
554 send_status(id, status);
557 static struct timeval *
558 attrib_to_tv(const Attrib *a)
560 static struct timeval tv[2];
562 tv[0].tv_sec = a->atime;
564 tv[1].tv_sec = a->mtime;
570 process_setstat(void)
575 int status = SSH2_FX_OK, ret;
578 name = get_string(NULL);
580 TRACE("setstat id %u name %s", id, name);
581 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
582 ret = truncate(name, a->size);
584 status = errno_to_portable(errno);
586 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
587 ret = chmod(name, a->perm & 0777);
589 status = errno_to_portable(errno);
591 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
592 ret = utimes(name, attrib_to_tv(a));
594 status = errno_to_portable(errno);
596 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
597 ret = chown(name, a->uid, a->gid);
599 status = errno_to_portable(errno);
601 send_status(id, status);
606 process_fsetstat(void)
611 int status = SSH2_FX_OK;
615 handle = get_handle();
617 TRACE("fsetstat id %u handle %d", id, handle);
618 fd = handle_to_fd(handle);
619 name = handle_to_name(handle);
620 if (fd < 0 || name == NULL) {
621 status = SSH2_FX_FAILURE;
623 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
624 ret = ftruncate(fd, a->size);
626 status = errno_to_portable(errno);
628 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
630 ret = fchmod(fd, a->perm & 0777);
632 ret = chmod(name, a->perm & 0777);
635 status = errno_to_portable(errno);
637 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
639 ret = futimes(fd, attrib_to_tv(a));
641 ret = utimes(name, attrib_to_tv(a));
644 status = errno_to_portable(errno);
646 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
648 ret = fchown(fd, a->uid, a->gid);
650 ret = chown(name, a->uid, a->gid);
653 status = errno_to_portable(errno);
656 send_status(id, status);
660 process_opendir(void)
664 int handle, status = SSH2_FX_FAILURE;
668 path = get_string(NULL);
669 TRACE("opendir id %u path %s", id, path);
670 dirp = opendir(path);
672 status = errno_to_portable(errno);
674 handle = handle_new(HANDLE_DIR, path, 0, dirp);
678 send_handle(id, handle);
683 if (status != SSH2_FX_OK)
684 send_status(id, status);
689 process_readdir(void)
698 handle = get_handle();
699 TRACE("readdir id %u handle %d", id, handle);
700 dirp = handle_to_dir(handle);
701 path = handle_to_name(handle);
702 if (dirp == NULL || path == NULL) {
703 send_status(id, SSH2_FX_FAILURE);
708 int nstats = 10, count = 0, i;
710 stats = xmalloc(nstats * sizeof(Stat));
711 while ((dp = readdir(dirp)) != NULL) {
712 if (count >= nstats) {
714 stats = xrealloc(stats, nstats * sizeof(Stat));
717 snprintf(pathname, sizeof pathname, "%s%s%s", path,
718 strcmp(path, "/") ? "/" : "", dp->d_name);
719 if (lstat(pathname, &st) < 0)
721 stat_to_attrib(&st, &(stats[count].attrib));
722 stats[count].name = xstrdup(dp->d_name);
723 stats[count].long_name = ls_file(dp->d_name, &st, 0);
725 /* send up to 100 entries in one message */
726 /* XXX check packet size instead */
731 send_names(id, count, stats);
732 for (i = 0; i < count; i++) {
733 xfree(stats[i].name);
734 xfree(stats[i].long_name);
737 send_status(id, SSH2_FX_EOF);
748 int status = SSH2_FX_FAILURE;
752 name = get_string(NULL);
753 TRACE("remove id %u name %s", id, name);
755 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
756 send_status(id, status);
766 int ret, mode, status = SSH2_FX_FAILURE;
769 name = get_string(NULL);
771 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
772 a->perm & 0777 : 0777;
773 TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
774 ret = mkdir(name, mode);
775 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
776 send_status(id, status);
788 name = get_string(NULL);
789 TRACE("rmdir id %u name %s", id, name);
791 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
792 send_status(id, status);
797 process_realpath(void)
799 char resolvedname[MAXPATHLEN];
804 path = get_string(NULL);
805 if (path[0] == '\0') {
809 TRACE("realpath id %u path %s", id, path);
810 if (realpath(path, resolvedname) == NULL) {
811 send_status(id, errno_to_portable(errno));
814 attrib_clear(&s.attrib);
815 s.name = s.long_name = resolvedname;
816 send_names(id, 1, &s);
825 char *oldpath, *newpath;
830 oldpath = get_string(NULL);
831 newpath = get_string(NULL);
832 TRACE("rename id %u old %s new %s", id, oldpath, newpath);
833 status = SSH2_FX_FAILURE;
834 if (lstat(oldpath, &sb) == -1)
835 status = errno_to_portable(errno);
836 else if (S_ISREG(sb.st_mode)) {
837 /* Race-free rename of regular files */
838 if (link(oldpath, newpath) == -1) {
839 if (errno == EOPNOTSUPP
840 #ifdef LINK_OPNOTSUPP_ERRNO
841 || errno == LINK_OPNOTSUPP_ERRNO
847 * fs doesn't support links, so fall back to
848 * stat+rename. This is racy.
850 if (stat(newpath, &st) == -1) {
851 if (rename(oldpath, newpath) == -1)
853 errno_to_portable(errno);
858 status = errno_to_portable(errno);
860 } else if (unlink(oldpath) == -1) {
861 status = errno_to_portable(errno);
862 /* clean spare link */
866 } else if (stat(newpath, &sb) == -1) {
867 if (rename(oldpath, newpath) == -1)
868 status = errno_to_portable(errno);
872 send_status(id, status);
878 process_readlink(void)
882 char buf[MAXPATHLEN];
886 path = get_string(NULL);
887 TRACE("readlink id %u path %s", id, path);
888 if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
889 send_status(id, errno_to_portable(errno));
894 attrib_clear(&s.attrib);
895 s.name = s.long_name = buf;
896 send_names(id, 1, &s);
902 process_symlink(void)
905 char *oldpath, *newpath;
909 oldpath = get_string(NULL);
910 newpath = get_string(NULL);
911 TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
912 /* this will fail if 'newpath' exists */
913 ret = symlink(oldpath, newpath);
914 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
915 send_status(id, status);
921 process_extended(void)
927 request = get_string(NULL);
928 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
932 /* stolen from ssh-agent */
943 buf_len = buffer_len(&iqueue);
945 return; /* Incomplete message. */
946 cp = buffer_ptr(&iqueue);
947 msg_len = GET_32BIT(cp);
948 if (msg_len > 256 * 1024) {
949 error("bad message ");
952 if (buf_len < msg_len + 4)
954 buffer_consume(&iqueue, 4);
956 type = buffer_get_char(&iqueue);
979 case SSH2_FXP_SETSTAT:
982 case SSH2_FXP_FSETSTAT:
985 case SSH2_FXP_OPENDIR:
988 case SSH2_FXP_READDIR:
991 case SSH2_FXP_REMOVE:
1000 case SSH2_FXP_REALPATH:
1006 case SSH2_FXP_RENAME:
1009 case SSH2_FXP_READLINK:
1012 case SSH2_FXP_SYMLINK:
1015 case SSH2_FXP_EXTENDED:
1019 error("Unknown message %d", type);
1022 /* discard the remaining bytes from the current packet */
1023 if (buf_len < buffer_len(&iqueue))
1024 fatal("iqueue grows");
1025 consumed = buf_len - buffer_len(&iqueue);
1026 if (msg_len < consumed)
1027 fatal("msg_len %d < consumed %d", msg_len, consumed);
1028 if (msg_len > consumed)
1029 buffer_consume(&iqueue, msg_len - consumed);
1033 main(int ac, char **av)
1035 fd_set *rset, *wset;
1037 ssize_t len, olen, set_size;
1039 /* XXX should use getopt */
1041 __progname = ssh_get_progname(av[0]);
1044 #ifdef DEBUG_SFTP_SERVER
1045 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1048 in = dup(STDIN_FILENO);
1049 out = dup(STDOUT_FILENO);
1052 setmode(in, O_BINARY);
1053 setmode(out, O_BINARY);
1062 buffer_init(&iqueue);
1063 buffer_init(&oqueue);
1065 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1066 rset = (fd_set *)xmalloc(set_size);
1067 wset = (fd_set *)xmalloc(set_size);
1070 memset(rset, 0, set_size);
1071 memset(wset, 0, set_size);
1074 olen = buffer_len(&oqueue);
1078 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1084 /* copy stdin to iqueue */
1085 if (FD_ISSET(in, rset)) {
1087 len = read(in, buf, sizeof buf);
1091 } else if (len < 0) {
1092 error("read error");
1095 buffer_append(&iqueue, buf, len);
1098 /* send oqueue to stdout */
1099 if (FD_ISSET(out, wset)) {
1100 len = write(out, buffer_ptr(&oqueue), olen);
1102 error("write error");
1105 buffer_consume(&oqueue, len);
1108 /* process requests from client */