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.48 2005/06/17 02:44:33 djm 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 && (u_int
)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 ((size_t)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 */