1 /* $NetBSD: sftp-server.c,v 1.1.1.2 2009/12/27 01:07:08 christos Exp $ */
2 /* $OpenBSD: sftp-server.c,v 1.85 2009/04/14 16:33:42 stevesk Exp $ */
4 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 __RCSID("$NetBSD: sftp-server.c,v 1.2 2009/06/07 22:38:47 christos Exp $");
21 #include <sys/types.h>
24 #include <sys/param.h>
25 #include <sys/mount.h>
26 #include <sys/statvfs.h>
46 #include "sftp-common.h"
49 #define get_int64() buffer_get_int64(&iqueue);
50 #define get_int() buffer_get_int(&iqueue);
51 #define get_string(lenp) buffer_get_string(&iqueue, lenp);
54 LogLevel log_level
= SYSLOG_LEVEL_ERROR
;
57 struct passwd
*pw
= NULL
;
58 char *client_addr
= NULL
;
60 /* input and output queue */
64 /* Version of client */
67 /* portable attributes, etc. */
69 typedef struct Stat Stat
;
78 errno_to_portable(int unixerrno
)
90 ret
= SSH2_FX_NO_SUCH_FILE
;
95 ret
= SSH2_FX_PERMISSION_DENIED
;
99 ret
= SSH2_FX_BAD_MESSAGE
;
102 ret
= SSH2_FX_OP_UNSUPPORTED
;
105 ret
= SSH2_FX_FAILURE
;
112 flags_from_portable(int pflags
)
116 if ((pflags
& SSH2_FXF_READ
) &&
117 (pflags
& SSH2_FXF_WRITE
)) {
119 } else if (pflags
& SSH2_FXF_READ
) {
121 } else if (pflags
& SSH2_FXF_WRITE
) {
124 if (pflags
& SSH2_FXF_CREAT
)
126 if (pflags
& SSH2_FXF_TRUNC
)
128 if (pflags
& SSH2_FXF_EXCL
)
134 string_from_portable(int pflags
)
136 static char ret
[128];
140 #define PAPPEND(str) { \
142 strlcat(ret, ",", sizeof(ret)); \
143 strlcat(ret, str, sizeof(ret)); \
146 if (pflags
& SSH2_FXF_READ
)
148 if (pflags
& SSH2_FXF_WRITE
)
150 if (pflags
& SSH2_FXF_CREAT
)
152 if (pflags
& SSH2_FXF_TRUNC
)
154 if (pflags
& SSH2_FXF_EXCL
)
163 return decode_attrib(&iqueue
);
168 typedef struct Handle Handle
;
174 u_int64_t bytes_read
, bytes_write
;
184 Handle
*handles
= NULL
;
185 u_int num_handles
= 0;
186 int first_unused_handle
= -1;
188 static void handle_unused(int i
)
190 handles
[i
].use
= HANDLE_UNUSED
;
191 handles
[i
].next_unused
= first_unused_handle
;
192 first_unused_handle
= i
;
196 handle_new(int use
, const char *name
, int fd
, DIR *dirp
)
200 if (first_unused_handle
== -1) {
201 if (num_handles
+ 1 <= num_handles
)
204 handles
= xrealloc(handles
, num_handles
, sizeof(Handle
));
205 handle_unused(num_handles
- 1);
208 i
= first_unused_handle
;
209 first_unused_handle
= handles
[i
].next_unused
;
211 handles
[i
].use
= use
;
212 handles
[i
].dirp
= dirp
;
214 handles
[i
].name
= xstrdup(name
);
215 handles
[i
].bytes_read
= handles
[i
].bytes_write
= 0;
221 handle_is_ok(int i
, int type
)
223 return i
>= 0 && (u_int
)i
< num_handles
&& handles
[i
].use
== type
;
227 handle_to_string(int handle
, char **stringp
, int *hlenp
)
229 if (stringp
== NULL
|| hlenp
== NULL
)
231 *stringp
= xmalloc(sizeof(int32_t));
232 put_u32(*stringp
, handle
);
233 *hlenp
= sizeof(int32_t);
238 handle_from_string(const char *handle
, u_int hlen
)
242 if (hlen
!= sizeof(int32_t))
244 val
= get_u32(handle
);
245 if (handle_is_ok(val
, HANDLE_FILE
) ||
246 handle_is_ok(val
, HANDLE_DIR
))
252 handle_to_name(int handle
)
254 if (handle_is_ok(handle
, HANDLE_DIR
)||
255 handle_is_ok(handle
, HANDLE_FILE
))
256 return handles
[handle
].name
;
261 handle_to_dir(int handle
)
263 if (handle_is_ok(handle
, HANDLE_DIR
))
264 return handles
[handle
].dirp
;
269 handle_to_fd(int handle
)
271 if (handle_is_ok(handle
, HANDLE_FILE
))
272 return handles
[handle
].fd
;
277 handle_update_read(int handle
, ssize_t bytes
)
279 if (handle_is_ok(handle
, HANDLE_FILE
) && bytes
> 0)
280 handles
[handle
].bytes_read
+= bytes
;
284 handle_update_write(int handle
, ssize_t bytes
)
286 if (handle_is_ok(handle
, HANDLE_FILE
) && bytes
> 0)
287 handles
[handle
].bytes_write
+= bytes
;
291 handle_bytes_read(int handle
)
293 if (handle_is_ok(handle
, HANDLE_FILE
))
294 return (handles
[handle
].bytes_read
);
299 handle_bytes_write(int handle
)
301 if (handle_is_ok(handle
, HANDLE_FILE
))
302 return (handles
[handle
].bytes_write
);
307 handle_close(int handle
)
311 if (handle_is_ok(handle
, HANDLE_FILE
)) {
312 ret
= close(handles
[handle
].fd
);
313 xfree(handles
[handle
].name
);
314 handle_unused(handle
);
315 } else if (handle_is_ok(handle
, HANDLE_DIR
)) {
316 ret
= closedir(handles
[handle
].dirp
);
317 xfree(handles
[handle
].name
);
318 handle_unused(handle
);
326 handle_log_close(int handle
, char *emsg
)
328 if (handle_is_ok(handle
, HANDLE_FILE
)) {
329 logit("%s%sclose \"%s\" bytes read %llu written %llu",
330 emsg
== NULL
? "" : emsg
, emsg
== NULL
? "" : " ",
331 handle_to_name(handle
),
332 (unsigned long long)handle_bytes_read(handle
),
333 (unsigned long long)handle_bytes_write(handle
));
335 logit("%s%sclosedir \"%s\"",
336 emsg
== NULL
? "" : emsg
, emsg
== NULL
? "" : " ",
337 handle_to_name(handle
));
342 handle_log_exit(void)
346 for (i
= 0; i
< num_handles
; i
++)
347 if (handles
[i
].use
!= HANDLE_UNUSED
)
348 handle_log_close(i
, "forced");
358 handle
= get_string(&hlen
);
360 val
= handle_from_string(handle
, hlen
);
370 int mlen
= buffer_len(m
);
372 buffer_put_int(&oqueue
, mlen
);
373 buffer_append(&oqueue
, buffer_ptr(m
), mlen
);
374 buffer_consume(m
, mlen
);
378 status_to_message(u_int32_t status
)
380 const char *status_messages
[] = {
381 "Success", /* SSH_FX_OK */
382 "End of file", /* SSH_FX_EOF */
383 "No such file", /* SSH_FX_NO_SUCH_FILE */
384 "Permission denied", /* SSH_FX_PERMISSION_DENIED */
385 "Failure", /* SSH_FX_FAILURE */
386 "Bad message", /* SSH_FX_BAD_MESSAGE */
387 "No connection", /* SSH_FX_NO_CONNECTION */
388 "Connection lost", /* SSH_FX_CONNECTION_LOST */
389 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
390 "Unknown error" /* Others */
392 return (status_messages
[MIN(status
,SSH2_FX_MAX
)]);
396 send_status(u_int32_t id
, u_int32_t status
)
400 debug3("request %u: sent status %u", id
, status
);
401 if (log_level
> SYSLOG_LEVEL_VERBOSE
||
402 (status
!= SSH2_FX_OK
&& status
!= SSH2_FX_EOF
))
403 logit("sent status %s", status_to_message(status
));
405 buffer_put_char(&msg
, SSH2_FXP_STATUS
);
406 buffer_put_int(&msg
, id
);
407 buffer_put_int(&msg
, status
);
409 buffer_put_cstring(&msg
, status_to_message(status
));
410 buffer_put_cstring(&msg
, "");
416 send_data_or_handle(char type
, u_int32_t id
, const char *data
, int dlen
)
421 buffer_put_char(&msg
, type
);
422 buffer_put_int(&msg
, id
);
423 buffer_put_string(&msg
, data
, dlen
);
429 send_data(u_int32_t id
, const char *data
, int dlen
)
431 debug("request %u: sent data len %d", id
, dlen
);
432 send_data_or_handle(SSH2_FXP_DATA
, id
, data
, dlen
);
436 send_handle(u_int32_t id
, int handle
)
441 handle_to_string(handle
, &string
, &hlen
);
442 debug("request %u: sent handle handle %d", id
, handle
);
443 send_data_or_handle(SSH2_FXP_HANDLE
, id
, string
, hlen
);
448 send_names(u_int32_t id
, int count
, const Stat
*stats
)
454 buffer_put_char(&msg
, SSH2_FXP_NAME
);
455 buffer_put_int(&msg
, id
);
456 buffer_put_int(&msg
, count
);
457 debug("request %u: sent names count %d", id
, count
);
458 for (i
= 0; i
< count
; i
++) {
459 buffer_put_cstring(&msg
, stats
[i
].name
);
460 buffer_put_cstring(&msg
, stats
[i
].long_name
);
461 encode_attrib(&msg
, &stats
[i
].attrib
);
468 send_attrib(u_int32_t id
, const Attrib
*a
)
472 debug("request %u: sent attrib have 0x%x", id
, a
->flags
);
474 buffer_put_char(&msg
, SSH2_FXP_ATTRS
);
475 buffer_put_int(&msg
, id
);
476 encode_attrib(&msg
, a
);
482 send_statvfs(u_int32_t id
, struct statvfs
*st
)
487 flag
= (st
->f_flag
& ST_RDONLY
) ? SSH2_FXE_STATVFS_ST_RDONLY
: 0;
488 flag
|= (st
->f_flag
& ST_NOSUID
) ? SSH2_FXE_STATVFS_ST_NOSUID
: 0;
491 buffer_put_char(&msg
, SSH2_FXP_EXTENDED_REPLY
);
492 buffer_put_int(&msg
, id
);
493 buffer_put_int64(&msg
, st
->f_bsize
);
494 buffer_put_int64(&msg
, st
->f_frsize
);
495 buffer_put_int64(&msg
, st
->f_blocks
);
496 buffer_put_int64(&msg
, st
->f_bfree
);
497 buffer_put_int64(&msg
, st
->f_bavail
);
498 buffer_put_int64(&msg
, st
->f_files
);
499 buffer_put_int64(&msg
, st
->f_ffree
);
500 buffer_put_int64(&msg
, st
->f_favail
);
501 buffer_put_int64(&msg
, st
->f_fsid
);
502 buffer_put_int64(&msg
, flag
);
503 buffer_put_int64(&msg
, st
->f_namemax
);
516 verbose("received client version %d", version
);
518 buffer_put_char(&msg
, SSH2_FXP_VERSION
);
519 buffer_put_int(&msg
, SSH2_FILEXFER_VERSION
);
520 /* POSIX rename extension */
521 buffer_put_cstring(&msg
, "posix-rename@openssh.com");
522 buffer_put_cstring(&msg
, "1"); /* version */
523 /* statvfs extension */
524 buffer_put_cstring(&msg
, "statvfs@openssh.com");
525 buffer_put_cstring(&msg
, "2"); /* version */
526 /* fstatvfs extension */
527 buffer_put_cstring(&msg
, "fstatvfs@openssh.com");
528 buffer_put_cstring(&msg
, "2"); /* version */
536 u_int32_t id
, pflags
;
539 int handle
, fd
, flags
, mode
, status
= SSH2_FX_FAILURE
;
542 name
= get_string(NULL
);
543 pflags
= get_int(); /* portable flags */
544 debug3("request %u: open flags %d", id
, pflags
);
546 flags
= flags_from_portable(pflags
);
547 mode
= (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) ? a
->perm
: 0666;
548 logit("open \"%s\" flags %s mode 0%o",
549 name
, string_from_portable(pflags
), mode
);
550 fd
= open(name
, flags
, mode
);
552 status
= errno_to_portable(errno
);
554 handle
= handle_new(HANDLE_FILE
, name
, fd
, NULL
);
558 send_handle(id
, handle
);
562 if (status
!= SSH2_FX_OK
)
563 send_status(id
, status
);
571 int handle
, ret
, status
= SSH2_FX_FAILURE
;
574 handle
= get_handle();
575 debug3("request %u: close handle %u", id
, handle
);
576 handle_log_close(handle
, NULL
);
577 ret
= handle_close(handle
);
578 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
579 send_status(id
, status
);
587 int handle
, fd
, ret
, status
= SSH2_FX_FAILURE
;
591 handle
= get_handle();
595 debug("request %u: read \"%s\" (handle %d) off %llu len %d",
596 id
, handle_to_name(handle
), handle
, (unsigned long long)off
, len
);
597 if (len
> sizeof buf
) {
599 debug2("read change len %d", len
);
601 fd
= handle_to_fd(handle
);
603 if (lseek(fd
, off
, SEEK_SET
) < 0) {
604 error("process_read: seek failed");
605 status
= errno_to_portable(errno
);
607 ret
= read(fd
, buf
, len
);
609 status
= errno_to_portable(errno
);
610 } else if (ret
== 0) {
611 status
= SSH2_FX_EOF
;
613 send_data(id
, buf
, ret
);
615 handle_update_read(handle
, ret
);
619 if (status
!= SSH2_FX_OK
)
620 send_status(id
, status
);
629 int handle
, fd
, ret
, status
= SSH2_FX_FAILURE
;
633 handle
= get_handle();
635 data
= get_string(&len
);
637 debug("request %u: write \"%s\" (handle %d) off %llu len %d",
638 id
, handle_to_name(handle
), handle
, (unsigned long long)off
, len
);
639 fd
= handle_to_fd(handle
);
641 if (lseek(fd
, off
, SEEK_SET
) < 0) {
642 status
= errno_to_portable(errno
);
643 error("process_write: seek failed");
646 ret
= write(fd
, data
, len
);
648 error("process_write: write failed");
649 status
= errno_to_portable(errno
);
650 } else if ((size_t)ret
== len
) {
652 handle_update_write(handle
, ret
);
654 debug2("nothing at all written");
658 send_status(id
, status
);
663 process_do_stat(int do_lstat
)
669 int ret
, status
= SSH2_FX_FAILURE
;
672 name
= get_string(NULL
);
673 debug3("request %u: %sstat", id
, do_lstat
? "l" : "");
674 verbose("%sstat name \"%s\"", do_lstat
? "l" : "", name
);
675 ret
= do_lstat
? lstat(name
, &st
) : stat(name
, &st
);
677 status
= errno_to_portable(errno
);
679 stat_to_attrib(&st
, &a
);
683 if (status
!= SSH2_FX_OK
)
684 send_status(id
, status
);
706 int fd
, ret
, handle
, status
= SSH2_FX_FAILURE
;
709 handle
= get_handle();
710 debug("request %u: fstat \"%s\" (handle %u)",
711 id
, handle_to_name(handle
), handle
);
712 fd
= handle_to_fd(handle
);
714 ret
= fstat(fd
, &st
);
716 status
= errno_to_portable(errno
);
718 stat_to_attrib(&st
, &a
);
723 if (status
!= SSH2_FX_OK
)
724 send_status(id
, status
);
727 static struct timeval
*
728 attrib_to_tv(const Attrib
*a
)
730 static struct timeval tv
[2];
732 tv
[0].tv_sec
= a
->atime
;
734 tv
[1].tv_sec
= a
->mtime
;
740 process_setstat(void)
745 int status
= SSH2_FX_OK
, ret
;
748 name
= get_string(NULL
);
750 debug("request %u: setstat name \"%s\"", id
, name
);
751 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
) {
752 logit("set \"%s\" size %llu",
753 name
, (unsigned long long)a
->size
);
754 ret
= truncate(name
, a
->size
);
756 status
= errno_to_portable(errno
);
758 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) {
759 logit("set \"%s\" mode %04o", name
, a
->perm
);
760 ret
= chmod(name
, a
->perm
& 07777);
762 status
= errno_to_portable(errno
);
764 if (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
) {
768 strftime(buf
, sizeof(buf
), "%Y%m%d-%H:%M:%S",
770 logit("set \"%s\" modtime %s", name
, buf
);
771 ret
= utimes(name
, attrib_to_tv(a
));
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 ret
= chown(name
, a
->uid
, a
->gid
);
780 status
= errno_to_portable(errno
);
782 send_status(id
, status
);
787 process_fsetstat(void)
792 int status
= SSH2_FX_OK
;
795 handle
= get_handle();
797 debug("request %u: fsetstat handle %d", id
, handle
);
798 fd
= handle_to_fd(handle
);
800 status
= SSH2_FX_FAILURE
;
802 char *name
= handle_to_name(handle
);
804 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
) {
805 logit("set \"%s\" size %llu",
806 name
, (unsigned long long)a
->size
);
807 ret
= ftruncate(fd
, a
->size
);
809 status
= errno_to_portable(errno
);
811 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) {
812 logit("set \"%s\" mode %04o", name
, a
->perm
);
813 ret
= fchmod(fd
, a
->perm
& 07777);
815 status
= errno_to_portable(errno
);
817 if (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
) {
821 strftime(buf
, sizeof(buf
), "%Y%m%d-%H:%M:%S",
823 logit("set \"%s\" modtime %s", name
, buf
);
824 ret
= futimes(fd
, attrib_to_tv(a
));
826 status
= errno_to_portable(errno
);
828 if (a
->flags
& SSH2_FILEXFER_ATTR_UIDGID
) {
829 logit("set \"%s\" owner %lu group %lu", name
,
830 (u_long
)a
->uid
, (u_long
)a
->gid
);
831 ret
= fchown(fd
, a
->uid
, a
->gid
);
833 status
= errno_to_portable(errno
);
836 send_status(id
, status
);
840 process_opendir(void)
844 int handle
, status
= SSH2_FX_FAILURE
;
848 path
= get_string(NULL
);
849 debug3("request %u: opendir", id
);
850 logit("opendir \"%s\"", path
);
851 dirp
= opendir(path
);
853 status
= errno_to_portable(errno
);
855 handle
= handle_new(HANDLE_DIR
, path
, 0, dirp
);
859 send_handle(id
, handle
);
864 if (status
!= SSH2_FX_OK
)
865 send_status(id
, status
);
870 process_readdir(void)
879 handle
= get_handle();
880 debug("request %u: readdir \"%s\" (handle %d)", id
,
881 handle_to_name(handle
), handle
);
882 dirp
= handle_to_dir(handle
);
883 path
= handle_to_name(handle
);
884 if (dirp
== NULL
|| path
== NULL
) {
885 send_status(id
, SSH2_FX_FAILURE
);
888 char pathname
[MAXPATHLEN
];
890 int nstats
= 10, count
= 0, i
;
892 stats
= xcalloc(nstats
, sizeof(Stat
));
893 while ((dp
= readdir(dirp
)) != NULL
) {
894 if (count
>= nstats
) {
896 stats
= xrealloc(stats
, nstats
, sizeof(Stat
));
899 snprintf(pathname
, sizeof pathname
, "%s%s%s", path
,
900 strcmp(path
, "/") ? "/" : "", dp
->d_name
);
901 if (lstat(pathname
, &st
) < 0)
903 stat_to_attrib(&st
, &(stats
[count
].attrib
));
904 stats
[count
].name
= xstrdup(dp
->d_name
);
905 stats
[count
].long_name
= ls_file(dp
->d_name
, &st
, 0);
907 /* send up to 100 entries in one message */
908 /* XXX check packet size instead */
913 send_names(id
, count
, stats
);
914 for (i
= 0; i
< count
; i
++) {
915 xfree(stats
[i
].name
);
916 xfree(stats
[i
].long_name
);
919 send_status(id
, SSH2_FX_EOF
);
930 int status
= SSH2_FX_FAILURE
;
934 name
= get_string(NULL
);
935 debug3("request %u: remove", id
);
936 logit("remove name \"%s\"", name
);
938 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
939 send_status(id
, status
);
949 int ret
, mode
, status
= SSH2_FX_FAILURE
;
952 name
= get_string(NULL
);
954 mode
= (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) ?
955 a
->perm
& 07777 : 0777;
956 debug3("request %u: mkdir", id
);
957 logit("mkdir name \"%s\" mode 0%o", name
, mode
);
958 ret
= mkdir(name
, mode
);
959 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
960 send_status(id
, status
);
972 name
= get_string(NULL
);
973 debug3("request %u: rmdir", id
);
974 logit("rmdir name \"%s\"", name
);
976 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
977 send_status(id
, status
);
982 process_realpath(void)
984 char resolvedname
[MAXPATHLEN
];
989 path
= get_string(NULL
);
990 if (path
[0] == '\0') {
994 debug3("request %u: realpath", id
);
995 verbose("realpath \"%s\"", path
);
996 if (realpath(path
, resolvedname
) == NULL
) {
997 send_status(id
, errno_to_portable(errno
));
1000 attrib_clear(&s
.attrib
);
1001 s
.name
= s
.long_name
= resolvedname
;
1002 send_names(id
, 1, &s
);
1008 process_rename(void)
1011 char *oldpath
, *newpath
;
1016 oldpath
= get_string(NULL
);
1017 newpath
= get_string(NULL
);
1018 debug3("request %u: rename", id
);
1019 logit("rename old \"%s\" new \"%s\"", oldpath
, newpath
);
1020 status
= SSH2_FX_FAILURE
;
1021 if (lstat(oldpath
, &sb
) == -1)
1022 status
= errno_to_portable(errno
);
1023 else if (S_ISREG(sb
.st_mode
)) {
1024 /* Race-free rename of regular files */
1025 if (link(oldpath
, newpath
) == -1) {
1026 if (errno
== EOPNOTSUPP
) {
1030 * fs doesn't support links, so fall back to
1031 * stat+rename. This is racy.
1033 if (stat(newpath
, &st
) == -1) {
1034 if (rename(oldpath
, newpath
) == -1)
1036 errno_to_portable(errno
);
1038 status
= SSH2_FX_OK
;
1041 status
= errno_to_portable(errno
);
1043 } else if (unlink(oldpath
) == -1) {
1044 status
= errno_to_portable(errno
);
1045 /* clean spare link */
1048 status
= SSH2_FX_OK
;
1049 } else if (stat(newpath
, &sb
) == -1) {
1050 if (rename(oldpath
, newpath
) == -1)
1051 status
= errno_to_portable(errno
);
1053 status
= SSH2_FX_OK
;
1055 send_status(id
, status
);
1061 process_readlink(void)
1065 char buf
[MAXPATHLEN
];
1069 path
= get_string(NULL
);
1070 debug3("request %u: readlink", id
);
1071 verbose("readlink \"%s\"", path
);
1072 if ((len
= readlink(path
, buf
, sizeof(buf
) - 1)) == -1)
1073 send_status(id
, errno_to_portable(errno
));
1078 attrib_clear(&s
.attrib
);
1079 s
.name
= s
.long_name
= buf
;
1080 send_names(id
, 1, &s
);
1086 process_symlink(void)
1089 char *oldpath
, *newpath
;
1093 oldpath
= get_string(NULL
);
1094 newpath
= get_string(NULL
);
1095 debug3("request %u: symlink", id
);
1096 logit("symlink old \"%s\" new \"%s\"", oldpath
, newpath
);
1097 /* this will fail if 'newpath' exists */
1098 ret
= symlink(oldpath
, newpath
);
1099 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
1100 send_status(id
, status
);
1106 process_extended_posix_rename(u_int32_t id
)
1108 char *oldpath
, *newpath
;
1110 oldpath
= get_string(NULL
);
1111 newpath
= get_string(NULL
);
1112 debug3("request %u: posix-rename", id
);
1113 logit("posix-rename old \"%s\" new \"%s\"", oldpath
, newpath
);
1114 if (rename(oldpath
, newpath
) == -1)
1115 send_status(id
, errno_to_portable(errno
));
1117 send_status(id
, SSH2_FX_OK
);
1123 process_extended_statvfs(u_int32_t id
)
1128 path
= get_string(NULL
);
1129 debug3("request %u: statfs", id
);
1130 logit("statfs \"%s\"", path
);
1132 if (statvfs(path
, &st
) != 0)
1133 send_status(id
, errno_to_portable(errno
));
1135 send_statvfs(id
, &st
);
1140 process_extended_fstatvfs(u_int32_t id
)
1145 handle
= get_handle();
1146 debug("request %u: fstatvfs \"%s\" (handle %u)",
1147 id
, handle_to_name(handle
), handle
);
1148 if ((fd
= handle_to_fd(handle
)) < 0) {
1149 send_status(id
, SSH2_FX_FAILURE
);
1152 if (fstatvfs(fd
, &st
) != 0)
1153 send_status(id
, errno_to_portable(errno
));
1155 send_statvfs(id
, &st
);
1159 process_extended(void)
1165 request
= get_string(NULL
);
1166 if (strcmp(request
, "posix-rename@openssh.com") == 0)
1167 process_extended_posix_rename(id
);
1168 else if (strcmp(request
, "statvfs@openssh.com") == 0)
1169 process_extended_statvfs(id
);
1170 else if (strcmp(request
, "fstatvfs@openssh.com") == 0)
1171 process_extended_fstatvfs(id
);
1173 send_status(id
, SSH2_FX_OP_UNSUPPORTED
); /* MUST */
1177 /* stolen from ssh-agent */
1188 buf_len
= buffer_len(&iqueue
);
1190 return; /* Incomplete message. */
1191 cp
= buffer_ptr(&iqueue
);
1192 msg_len
= get_u32(cp
);
1193 if (msg_len
> SFTP_MAX_MSG_LENGTH
) {
1194 error("bad message from %s local user %s",
1195 client_addr
, pw
->pw_name
);
1196 sftp_server_cleanup_exit(11);
1198 if (buf_len
< msg_len
+ 4)
1200 buffer_consume(&iqueue
, 4);
1202 type
= buffer_get_char(&iqueue
);
1210 case SSH2_FXP_CLOSE
:
1216 case SSH2_FXP_WRITE
:
1219 case SSH2_FXP_LSTAT
:
1222 case SSH2_FXP_FSTAT
:
1225 case SSH2_FXP_SETSTAT
:
1228 case SSH2_FXP_FSETSTAT
:
1231 case SSH2_FXP_OPENDIR
:
1234 case SSH2_FXP_READDIR
:
1237 case SSH2_FXP_REMOVE
:
1240 case SSH2_FXP_MKDIR
:
1243 case SSH2_FXP_RMDIR
:
1246 case SSH2_FXP_REALPATH
:
1252 case SSH2_FXP_RENAME
:
1255 case SSH2_FXP_READLINK
:
1258 case SSH2_FXP_SYMLINK
:
1261 case SSH2_FXP_EXTENDED
:
1265 error("Unknown message %d", type
);
1268 /* discard the remaining bytes from the current packet */
1269 if (buf_len
< buffer_len(&iqueue
)) {
1270 error("iqueue grew unexpectedly");
1271 sftp_server_cleanup_exit(255);
1273 consumed
= buf_len
- buffer_len(&iqueue
);
1274 if (msg_len
< consumed
) {
1275 error("msg_len %d < consumed %d", msg_len
, consumed
);
1276 sftp_server_cleanup_exit(255);
1278 if (msg_len
> consumed
)
1279 buffer_consume(&iqueue
, msg_len
- consumed
);
1282 /* Cleanup handler that logs active handles upon normal exit */
1284 sftp_server_cleanup_exit(int i
)
1286 if (pw
!= NULL
&& client_addr
!= NULL
) {
1288 logit("session closed for local user %s from [%s]",
1289 pw
->pw_name
, client_addr
);
1295 sftp_server_usage(void)
1297 extern char *__progname
;
1300 "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname
);
1305 sftp_server_main(int argc
, char **argv
, struct passwd
*user_pw
)
1307 fd_set
*rset
, *wset
;
1308 int in
, out
, max
, ch
, skipargs
= 0, log_stderr
= 0;
1309 ssize_t len
, olen
, set_size
;
1310 SyslogFacility log_facility
= SYSLOG_FACILITY_AUTH
;
1311 char *cp
, buf
[4*4096];
1313 extern char *optarg
;
1314 extern char *__progname
;
1316 log_init(__progname
, log_level
, log_facility
, log_stderr
);
1318 while (!skipargs
&& (ch
= getopt(argc
, argv
, "f:l:che")) != -1) {
1322 * Ignore all arguments if we are invoked as a
1323 * shell using "sftp-server -c command"
1331 log_level
= log_level_number(optarg
);
1332 if (log_level
== SYSLOG_LEVEL_NOT_SET
)
1333 error("Invalid log level \"%s\"", optarg
);
1336 log_facility
= log_facility_number(optarg
);
1337 if (log_facility
== SYSLOG_FACILITY_NOT_SET
)
1338 error("Invalid log facility \"%s\"", optarg
);
1342 sftp_server_usage();
1346 log_init(__progname
, log_level
, log_facility
, log_stderr
);
1348 if ((cp
= getenv("SSH_CONNECTION")) != NULL
) {
1349 client_addr
= xstrdup(cp
);
1350 if ((cp
= strchr(client_addr
, ' ')) == NULL
) {
1351 error("Malformed SSH_CONNECTION variable: \"%s\"",
1352 getenv("SSH_CONNECTION"));
1353 sftp_server_cleanup_exit(255);
1357 client_addr
= xstrdup("UNKNOWN");
1359 pw
= pwcopy(user_pw
);
1361 logit("session opened for local user %s from [%s]",
1362 pw
->pw_name
, client_addr
);
1364 in
= dup(STDIN_FILENO
);
1365 out
= dup(STDOUT_FILENO
);
1373 buffer_init(&iqueue
);
1374 buffer_init(&oqueue
);
1376 set_size
= howmany(max
+ 1, NFDBITS
) * sizeof(fd_mask
);
1377 rset
= (fd_set
*)xmalloc(set_size
);
1378 wset
= (fd_set
*)xmalloc(set_size
);
1381 memset(rset
, 0, set_size
);
1382 memset(wset
, 0, set_size
);
1385 * Ensure that we can read a full buffer and handle
1386 * the worst-case length packet it can generate,
1387 * otherwise apply backpressure by stopping reads.
1389 if (buffer_check_alloc(&iqueue
, sizeof(buf
)) &&
1390 buffer_check_alloc(&oqueue
, SFTP_MAX_MSG_LENGTH
))
1393 olen
= buffer_len(&oqueue
);
1397 if (select(max
+1, rset
, wset
, NULL
, NULL
) < 0) {
1400 error("select: %s", strerror(errno
));
1401 sftp_server_cleanup_exit(2);
1404 /* copy stdin to iqueue */
1405 if (FD_ISSET(in
, rset
)) {
1406 len
= read(in
, buf
, sizeof buf
);
1409 sftp_server_cleanup_exit(0);
1410 } else if (len
< 0) {
1411 error("read: %s", strerror(errno
));
1412 sftp_server_cleanup_exit(1);
1414 buffer_append(&iqueue
, buf
, len
);
1417 /* send oqueue to stdout */
1418 if (FD_ISSET(out
, wset
)) {
1419 len
= write(out
, buffer_ptr(&oqueue
), olen
);
1421 error("write: %s", strerror(errno
));
1422 sftp_server_cleanup_exit(1);
1424 buffer_consume(&oqueue
, len
);
1429 * Process requests from client if we can fit the results
1430 * into the output buffer, otherwise stop processing input
1431 * and let the output queue drain.
1433 if (buffer_check_alloc(&oqueue
, SFTP_MAX_MSG_LENGTH
))