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.45 2004/02/19 21:15:04 markus 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 #ifdef HAVE___PROGNAME
35 extern char *__progname
;
40 /* input and output queue */
44 /* Version of client */
47 /* portable attributes, etc. */
49 typedef struct Stat Stat
;
58 errno_to_portable(int unixerrno
)
70 ret
= SSH2_FX_NO_SUCH_FILE
;
75 ret
= SSH2_FX_PERMISSION_DENIED
;
79 ret
= SSH2_FX_BAD_MESSAGE
;
82 ret
= SSH2_FX_FAILURE
;
89 flags_from_portable(int pflags
)
93 if ((pflags
& SSH2_FXF_READ
) &&
94 (pflags
& SSH2_FXF_WRITE
)) {
96 } else if (pflags
& SSH2_FXF_READ
) {
98 } else if (pflags
& SSH2_FXF_WRITE
) {
101 if (pflags
& SSH2_FXF_CREAT
)
103 if (pflags
& SSH2_FXF_TRUNC
)
105 if (pflags
& SSH2_FXF_EXCL
)
113 return decode_attrib(&iqueue
);
118 typedef struct Handle Handle
;
139 for (i
= 0; i
< sizeof(handles
)/sizeof(Handle
); i
++)
140 handles
[i
].use
= HANDLE_UNUSED
;
144 handle_new(int use
, const char *name
, int fd
, DIR *dirp
)
148 for (i
= 0; i
< sizeof(handles
)/sizeof(Handle
); i
++) {
149 if (handles
[i
].use
== HANDLE_UNUSED
) {
150 handles
[i
].use
= use
;
151 handles
[i
].dirp
= dirp
;
153 handles
[i
].name
= xstrdup(name
);
161 handle_is_ok(int i
, int type
)
163 return i
>= 0 && i
< sizeof(handles
)/sizeof(Handle
) &&
164 handles
[i
].use
== type
;
168 handle_to_string(int handle
, char **stringp
, int *hlenp
)
170 if (stringp
== NULL
|| hlenp
== NULL
)
172 *stringp
= xmalloc(sizeof(int32_t));
173 PUT_32BIT(*stringp
, handle
);
174 *hlenp
= sizeof(int32_t);
179 handle_from_string(const char *handle
, u_int hlen
)
183 if (hlen
!= sizeof(int32_t))
185 val
= GET_32BIT(handle
);
186 if (handle_is_ok(val
, HANDLE_FILE
) ||
187 handle_is_ok(val
, HANDLE_DIR
))
193 handle_to_name(int handle
)
195 if (handle_is_ok(handle
, HANDLE_DIR
)||
196 handle_is_ok(handle
, HANDLE_FILE
))
197 return handles
[handle
].name
;
202 handle_to_dir(int handle
)
204 if (handle_is_ok(handle
, HANDLE_DIR
))
205 return handles
[handle
].dirp
;
210 handle_to_fd(int handle
)
212 if (handle_is_ok(handle
, HANDLE_FILE
))
213 return handles
[handle
].fd
;
218 handle_close(int handle
)
222 if (handle_is_ok(handle
, HANDLE_FILE
)) {
223 ret
= close(handles
[handle
].fd
);
224 handles
[handle
].use
= HANDLE_UNUSED
;
225 xfree(handles
[handle
].name
);
226 } else if (handle_is_ok(handle
, HANDLE_DIR
)) {
227 ret
= closedir(handles
[handle
].dirp
);
228 handles
[handle
].use
= HANDLE_UNUSED
;
229 xfree(handles
[handle
].name
);
243 handle
= get_string(&hlen
);
245 val
= handle_from_string(handle
, hlen
);
255 int mlen
= buffer_len(m
);
257 buffer_put_int(&oqueue
, mlen
);
258 buffer_append(&oqueue
, buffer_ptr(m
), mlen
);
259 buffer_consume(m
, mlen
);
263 send_status(u_int32_t id
, u_int32_t error
)
266 const char *status_messages
[] = {
267 "Success", /* SSH_FX_OK */
268 "End of file", /* SSH_FX_EOF */
269 "No such file", /* SSH_FX_NO_SUCH_FILE */
270 "Permission denied", /* SSH_FX_PERMISSION_DENIED */
271 "Failure", /* SSH_FX_FAILURE */
272 "Bad message", /* SSH_FX_BAD_MESSAGE */
273 "No connection", /* SSH_FX_NO_CONNECTION */
274 "Connection lost", /* SSH_FX_CONNECTION_LOST */
275 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
276 "Unknown error" /* Others */
279 TRACE("sent status id %u error %u", id
, error
);
281 buffer_put_char(&msg
, SSH2_FXP_STATUS
);
282 buffer_put_int(&msg
, id
);
283 buffer_put_int(&msg
, error
);
285 buffer_put_cstring(&msg
,
286 status_messages
[MIN(error
,SSH2_FX_MAX
)]);
287 buffer_put_cstring(&msg
, "");
293 send_data_or_handle(char type
, u_int32_t id
, const char *data
, int dlen
)
298 buffer_put_char(&msg
, type
);
299 buffer_put_int(&msg
, id
);
300 buffer_put_string(&msg
, data
, dlen
);
306 send_data(u_int32_t id
, const char *data
, int dlen
)
308 TRACE("sent data id %u len %d", id
, dlen
);
309 send_data_or_handle(SSH2_FXP_DATA
, id
, data
, dlen
);
313 send_handle(u_int32_t id
, int handle
)
318 handle_to_string(handle
, &string
, &hlen
);
319 TRACE("sent handle id %u handle %d", id
, handle
);
320 send_data_or_handle(SSH2_FXP_HANDLE
, id
, string
, hlen
);
325 send_names(u_int32_t id
, int count
, const Stat
*stats
)
331 buffer_put_char(&msg
, SSH2_FXP_NAME
);
332 buffer_put_int(&msg
, id
);
333 buffer_put_int(&msg
, count
);
334 TRACE("sent names id %u count %d", id
, count
);
335 for (i
= 0; i
< count
; i
++) {
336 buffer_put_cstring(&msg
, stats
[i
].name
);
337 buffer_put_cstring(&msg
, stats
[i
].long_name
);
338 encode_attrib(&msg
, &stats
[i
].attrib
);
345 send_attrib(u_int32_t id
, const Attrib
*a
)
349 TRACE("sent attrib id %u have 0x%x", id
, a
->flags
);
351 buffer_put_char(&msg
, SSH2_FXP_ATTRS
);
352 buffer_put_int(&msg
, id
);
353 encode_attrib(&msg
, a
);
366 TRACE("client version %d", version
);
368 buffer_put_char(&msg
, SSH2_FXP_VERSION
);
369 buffer_put_int(&msg
, SSH2_FILEXFER_VERSION
);
377 u_int32_t id
, pflags
;
380 int handle
, fd
, flags
, mode
, status
= SSH2_FX_FAILURE
;
383 name
= get_string(NULL
);
384 pflags
= get_int(); /* portable flags */
386 flags
= flags_from_portable(pflags
);
387 mode
= (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) ? a
->perm
: 0666;
388 TRACE("open id %u name %s flags %d mode 0%o", id
, name
, pflags
, mode
);
389 fd
= open(name
, flags
, mode
);
391 status
= errno_to_portable(errno
);
393 handle
= handle_new(HANDLE_FILE
, name
, fd
, NULL
);
397 send_handle(id
, handle
);
401 if (status
!= SSH2_FX_OK
)
402 send_status(id
, status
);
410 int handle
, ret
, status
= SSH2_FX_FAILURE
;
413 handle
= get_handle();
414 TRACE("close id %u handle %d", id
, handle
);
415 ret
= handle_close(handle
);
416 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
417 send_status(id
, status
);
425 int handle
, fd
, ret
, status
= SSH2_FX_FAILURE
;
429 handle
= get_handle();
433 TRACE("read id %u handle %d off %llu len %d", id
, handle
,
434 (u_int64_t
)off
, len
);
435 if (len
> sizeof buf
) {
437 logit("read change len %d", len
);
439 fd
= handle_to_fd(handle
);
441 if (lseek(fd
, off
, SEEK_SET
) < 0) {
442 error("process_read: seek failed");
443 status
= errno_to_portable(errno
);
445 ret
= read(fd
, buf
, len
);
447 status
= errno_to_portable(errno
);
448 } else if (ret
== 0) {
449 status
= SSH2_FX_EOF
;
451 send_data(id
, buf
, ret
);
456 if (status
!= SSH2_FX_OK
)
457 send_status(id
, status
);
466 int handle
, fd
, ret
, status
= SSH2_FX_FAILURE
;
470 handle
= get_handle();
472 data
= get_string(&len
);
474 TRACE("write id %u handle %d off %llu len %d", id
, handle
,
475 (u_int64_t
)off
, len
);
476 fd
= handle_to_fd(handle
);
478 if (lseek(fd
, off
, SEEK_SET
) < 0) {
479 status
= errno_to_portable(errno
);
480 error("process_write: seek failed");
483 ret
= write(fd
, data
, len
);
485 error("process_write: write failed");
486 status
= errno_to_portable(errno
);
487 } else if (ret
== len
) {
490 logit("nothing at all written");
494 send_status(id
, status
);
499 process_do_stat(int do_lstat
)
505 int ret
, status
= SSH2_FX_FAILURE
;
508 name
= get_string(NULL
);
509 TRACE("%sstat id %u name %s", do_lstat
? "l" : "", id
, name
);
510 ret
= do_lstat
? lstat(name
, &st
) : stat(name
, &st
);
512 status
= errno_to_portable(errno
);
514 stat_to_attrib(&st
, &a
);
518 if (status
!= SSH2_FX_OK
)
519 send_status(id
, status
);
541 int fd
, ret
, handle
, status
= SSH2_FX_FAILURE
;
544 handle
= get_handle();
545 TRACE("fstat id %u handle %d", id
, handle
);
546 fd
= handle_to_fd(handle
);
548 ret
= fstat(fd
, &st
);
550 status
= errno_to_portable(errno
);
552 stat_to_attrib(&st
, &a
);
557 if (status
!= SSH2_FX_OK
)
558 send_status(id
, status
);
561 static struct timeval
*
562 attrib_to_tv(const Attrib
*a
)
564 static struct timeval tv
[2];
566 tv
[0].tv_sec
= a
->atime
;
568 tv
[1].tv_sec
= a
->mtime
;
574 process_setstat(void)
579 int status
= SSH2_FX_OK
, ret
;
582 name
= get_string(NULL
);
584 TRACE("setstat id %u name %s", id
, name
);
585 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
) {
586 ret
= truncate(name
, a
->size
);
588 status
= errno_to_portable(errno
);
590 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) {
591 ret
= chmod(name
, a
->perm
& 0777);
593 status
= errno_to_portable(errno
);
595 if (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
) {
596 ret
= utimes(name
, attrib_to_tv(a
));
598 status
= errno_to_portable(errno
);
600 if (a
->flags
& SSH2_FILEXFER_ATTR_UIDGID
) {
601 ret
= chown(name
, a
->uid
, a
->gid
);
603 status
= errno_to_portable(errno
);
605 send_status(id
, status
);
610 process_fsetstat(void)
615 int status
= SSH2_FX_OK
;
619 handle
= get_handle();
621 TRACE("fsetstat id %u handle %d", id
, handle
);
622 fd
= handle_to_fd(handle
);
623 name
= handle_to_name(handle
);
624 if (fd
< 0 || name
== NULL
) {
625 status
= SSH2_FX_FAILURE
;
627 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
) {
628 ret
= ftruncate(fd
, a
->size
);
630 status
= errno_to_portable(errno
);
632 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) {
634 ret
= fchmod(fd
, a
->perm
& 0777);
636 ret
= chmod(name
, a
->perm
& 0777);
639 status
= errno_to_portable(errno
);
641 if (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
) {
643 ret
= futimes(fd
, attrib_to_tv(a
));
645 ret
= utimes(name
, attrib_to_tv(a
));
648 status
= errno_to_portable(errno
);
650 if (a
->flags
& SSH2_FILEXFER_ATTR_UIDGID
) {
652 ret
= fchown(fd
, a
->uid
, a
->gid
);
654 ret
= chown(name
, a
->uid
, a
->gid
);
657 status
= errno_to_portable(errno
);
660 send_status(id
, status
);
664 process_opendir(void)
668 int handle
, status
= SSH2_FX_FAILURE
;
672 path
= get_string(NULL
);
673 TRACE("opendir id %u path %s", id
, path
);
674 dirp
= opendir(path
);
676 status
= errno_to_portable(errno
);
678 handle
= handle_new(HANDLE_DIR
, path
, 0, dirp
);
682 send_handle(id
, handle
);
687 if (status
!= SSH2_FX_OK
)
688 send_status(id
, status
);
693 process_readdir(void)
702 handle
= get_handle();
703 TRACE("readdir id %u handle %d", id
, handle
);
704 dirp
= handle_to_dir(handle
);
705 path
= handle_to_name(handle
);
706 if (dirp
== NULL
|| path
== NULL
) {
707 send_status(id
, SSH2_FX_FAILURE
);
712 int nstats
= 10, count
= 0, i
;
714 stats
= xmalloc(nstats
* sizeof(Stat
));
715 while ((dp
= readdir(dirp
)) != NULL
) {
716 if (count
>= nstats
) {
718 stats
= xrealloc(stats
, nstats
* sizeof(Stat
));
721 snprintf(pathname
, sizeof pathname
, "%s%s%s", path
,
722 strcmp(path
, "/") ? "/" : "", dp
->d_name
);
723 if (lstat(pathname
, &st
) < 0)
725 stat_to_attrib(&st
, &(stats
[count
].attrib
));
726 stats
[count
].name
= xstrdup(dp
->d_name
);
727 stats
[count
].long_name
= ls_file(dp
->d_name
, &st
, 0);
729 /* send up to 100 entries in one message */
730 /* XXX check packet size instead */
735 send_names(id
, count
, stats
);
736 for (i
= 0; i
< count
; i
++) {
737 xfree(stats
[i
].name
);
738 xfree(stats
[i
].long_name
);
741 send_status(id
, SSH2_FX_EOF
);
752 int status
= SSH2_FX_FAILURE
;
756 name
= get_string(NULL
);
757 TRACE("remove id %u name %s", id
, name
);
759 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
760 send_status(id
, status
);
770 int ret
, mode
, status
= SSH2_FX_FAILURE
;
773 name
= get_string(NULL
);
775 mode
= (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) ?
776 a
->perm
& 0777 : 0777;
777 TRACE("mkdir id %u name %s mode 0%o", id
, name
, mode
);
778 ret
= mkdir(name
, mode
);
779 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
780 send_status(id
, status
);
792 name
= get_string(NULL
);
793 TRACE("rmdir id %u name %s", id
, name
);
795 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
796 send_status(id
, status
);
801 process_realpath(void)
803 char resolvedname
[MAXPATHLEN
];
808 path
= get_string(NULL
);
809 if (path
[0] == '\0') {
813 TRACE("realpath id %u path %s", id
, path
);
814 if (realpath(path
, resolvedname
) == NULL
) {
815 send_status(id
, errno_to_portable(errno
));
818 attrib_clear(&s
.attrib
);
819 s
.name
= s
.long_name
= resolvedname
;
820 send_names(id
, 1, &s
);
829 char *oldpath
, *newpath
;
834 oldpath
= get_string(NULL
);
835 newpath
= get_string(NULL
);
836 TRACE("rename id %u old %s new %s", id
, oldpath
, newpath
);
837 status
= SSH2_FX_FAILURE
;
838 if (lstat(oldpath
, &sb
) == -1)
839 status
= errno_to_portable(errno
);
840 else if (S_ISREG(sb
.st_mode
)) {
841 /* Race-free rename of regular files */
842 if (link(oldpath
, newpath
) == -1)
843 status
= errno_to_portable(errno
);
844 else if (unlink(oldpath
) == -1) {
845 status
= errno_to_portable(errno
);
846 /* clean spare link */
850 } else if (stat(newpath
, &sb
) == -1) {
851 if (rename(oldpath
, newpath
) == -1)
852 status
= errno_to_portable(errno
);
856 send_status(id
, status
);
862 process_readlink(void)
866 char link
[MAXPATHLEN
];
870 path
= get_string(NULL
);
871 TRACE("readlink id %u path %s", id
, path
);
872 if ((len
= readlink(path
, link
, sizeof(link
) - 1)) == -1)
873 send_status(id
, errno_to_portable(errno
));
878 attrib_clear(&s
.attrib
);
879 s
.name
= s
.long_name
= link
;
880 send_names(id
, 1, &s
);
886 process_symlink(void)
889 char *oldpath
, *newpath
;
893 oldpath
= get_string(NULL
);
894 newpath
= get_string(NULL
);
895 TRACE("symlink id %u old %s new %s", id
, oldpath
, newpath
);
896 /* this will fail if 'newpath' exists */
897 ret
= symlink(oldpath
, newpath
);
898 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
899 send_status(id
, status
);
905 process_extended(void)
911 request
= get_string(NULL
);
912 send_status(id
, SSH2_FX_OP_UNSUPPORTED
); /* MUST */
916 /* stolen from ssh-agent */
927 buf_len
= buffer_len(&iqueue
);
929 return; /* Incomplete message. */
930 cp
= buffer_ptr(&iqueue
);
931 msg_len
= GET_32BIT(cp
);
932 if (msg_len
> 256 * 1024) {
933 error("bad message ");
936 if (buf_len
< msg_len
+ 4)
938 buffer_consume(&iqueue
, 4);
940 type
= buffer_get_char(&iqueue
);
963 case SSH2_FXP_SETSTAT
:
966 case SSH2_FXP_FSETSTAT
:
969 case SSH2_FXP_OPENDIR
:
972 case SSH2_FXP_READDIR
:
975 case SSH2_FXP_REMOVE
:
984 case SSH2_FXP_REALPATH
:
990 case SSH2_FXP_RENAME
:
993 case SSH2_FXP_READLINK
:
996 case SSH2_FXP_SYMLINK
:
999 case SSH2_FXP_EXTENDED
:
1003 error("Unknown message %d", type
);
1006 /* discard the remaining bytes from the current packet */
1007 if (buf_len
< buffer_len(&iqueue
))
1008 fatal("iqueue grows");
1009 consumed
= buf_len
- buffer_len(&iqueue
);
1010 if (msg_len
< consumed
)
1011 fatal("msg_len %d < consumed %d", msg_len
, consumed
);
1012 if (msg_len
> consumed
)
1013 buffer_consume(&iqueue
, msg_len
- consumed
);
1017 main(int ac
, char **av
)
1019 fd_set
*rset
, *wset
;
1021 ssize_t len
, olen
, set_size
;
1023 /* XXX should use getopt */
1025 __progname
= ssh_get_progname(av
[0]);
1028 #ifdef DEBUG_SFTP_SERVER
1029 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1
, SYSLOG_FACILITY_AUTH
, 0);
1032 in
= dup(STDIN_FILENO
);
1033 out
= dup(STDOUT_FILENO
);
1036 setmode(in
, O_BINARY
);
1037 setmode(out
, O_BINARY
);
1046 buffer_init(&iqueue
);
1047 buffer_init(&oqueue
);
1049 set_size
= howmany(max
+ 1, NFDBITS
) * sizeof(fd_mask
);
1050 rset
= (fd_set
*)xmalloc(set_size
);
1051 wset
= (fd_set
*)xmalloc(set_size
);
1054 memset(rset
, 0, set_size
);
1055 memset(wset
, 0, set_size
);
1058 olen
= buffer_len(&oqueue
);
1062 if (select(max
+1, rset
, wset
, NULL
, NULL
) < 0) {
1068 /* copy stdin to iqueue */
1069 if (FD_ISSET(in
, rset
)) {
1071 len
= read(in
, buf
, sizeof buf
);
1075 } else if (len
< 0) {
1076 error("read error");
1079 buffer_append(&iqueue
, buf
, len
);
1082 /* send oqueue to stdout */
1083 if (FD_ISSET(out
, wset
)) {
1084 len
= write(out
, buffer_ptr(&oqueue
), olen
);
1086 error("write error");
1089 buffer_consume(&oqueue
, len
);
1092 /* process requests from client */