1 /* $OpenBSD: sftp-server.c,v 1.61 2006/07/10 11:25:53 djm Exp $ */
3 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
34 #include "sftp-common.h"
37 #define get_int64() buffer_get_int64(&iqueue);
38 #define get_int() buffer_get_int(&iqueue);
39 #define get_string(lenp) buffer_get_string(&iqueue, lenp);
42 LogLevel log_level
= SYSLOG_LEVEL_ERROR
;
45 struct passwd
*pw
= NULL
;
46 char *client_addr
= NULL
;
48 /* input and output queue */
52 /* Version of client */
55 /* portable attributes, etc. */
57 typedef struct Stat Stat
;
66 errno_to_portable(int unixerrno
)
78 ret
= SSH2_FX_NO_SUCH_FILE
;
83 ret
= SSH2_FX_PERMISSION_DENIED
;
87 ret
= SSH2_FX_BAD_MESSAGE
;
90 ret
= SSH2_FX_FAILURE
;
97 flags_from_portable(int pflags
)
101 if ((pflags
& SSH2_FXF_READ
) &&
102 (pflags
& SSH2_FXF_WRITE
)) {
104 } else if (pflags
& SSH2_FXF_READ
) {
106 } else if (pflags
& SSH2_FXF_WRITE
) {
109 if (pflags
& SSH2_FXF_CREAT
)
111 if (pflags
& SSH2_FXF_TRUNC
)
113 if (pflags
& SSH2_FXF_EXCL
)
119 string_from_portable(int pflags
)
121 static char ret
[128];
125 #define PAPPEND(str) { \
127 strlcat(ret, ",", sizeof(ret)); \
128 strlcat(ret, str, sizeof(ret)); \
131 if (pflags
& SSH2_FXF_READ
)
133 if (pflags
& SSH2_FXF_WRITE
)
135 if (pflags
& SSH2_FXF_CREAT
)
137 if (pflags
& SSH2_FXF_TRUNC
)
139 if (pflags
& SSH2_FXF_EXCL
)
148 return decode_attrib(&iqueue
);
153 typedef struct Handle Handle
;
159 u_int64_t bytes_read
, bytes_write
;
175 for (i
= 0; i
< sizeof(handles
)/sizeof(Handle
); i
++)
176 handles
[i
].use
= HANDLE_UNUSED
;
180 handle_new(int use
, const char *name
, int fd
, DIR *dirp
)
184 for (i
= 0; i
< sizeof(handles
)/sizeof(Handle
); i
++) {
185 if (handles
[i
].use
== HANDLE_UNUSED
) {
186 handles
[i
].use
= use
;
187 handles
[i
].dirp
= dirp
;
189 handles
[i
].name
= xstrdup(name
);
190 handles
[i
].bytes_read
= handles
[i
].bytes_write
= 0;
198 handle_is_ok(int i
, int type
)
200 return i
>= 0 && (u_int
)i
< sizeof(handles
)/sizeof(Handle
) &&
201 handles
[i
].use
== type
;
205 handle_to_string(int handle
, char **stringp
, int *hlenp
)
207 if (stringp
== NULL
|| hlenp
== NULL
)
209 *stringp
= xmalloc(sizeof(int32_t));
210 put_u32(*stringp
, handle
);
211 *hlenp
= sizeof(int32_t);
216 handle_from_string(const char *handle
, u_int hlen
)
220 if (hlen
!= sizeof(int32_t))
222 val
= get_u32(handle
);
223 if (handle_is_ok(val
, HANDLE_FILE
) ||
224 handle_is_ok(val
, HANDLE_DIR
))
230 handle_to_name(int handle
)
232 if (handle_is_ok(handle
, HANDLE_DIR
)||
233 handle_is_ok(handle
, HANDLE_FILE
))
234 return handles
[handle
].name
;
239 handle_to_dir(int handle
)
241 if (handle_is_ok(handle
, HANDLE_DIR
))
242 return handles
[handle
].dirp
;
247 handle_to_fd(int handle
)
249 if (handle_is_ok(handle
, HANDLE_FILE
))
250 return handles
[handle
].fd
;
255 handle_update_read(int handle
, ssize_t bytes
)
257 if (handle_is_ok(handle
, HANDLE_FILE
) && bytes
> 0)
258 handles
[handle
].bytes_read
+= bytes
;
262 handle_update_write(int handle
, ssize_t bytes
)
264 if (handle_is_ok(handle
, HANDLE_FILE
) && bytes
> 0)
265 handles
[handle
].bytes_write
+= bytes
;
269 handle_bytes_read(int handle
)
271 if (handle_is_ok(handle
, HANDLE_FILE
))
272 return (handles
[handle
].bytes_read
);
277 handle_bytes_write(int handle
)
279 if (handle_is_ok(handle
, HANDLE_FILE
))
280 return (handles
[handle
].bytes_write
);
285 handle_close(int handle
)
289 if (handle_is_ok(handle
, HANDLE_FILE
)) {
290 ret
= close(handles
[handle
].fd
);
291 handles
[handle
].use
= HANDLE_UNUSED
;
292 xfree(handles
[handle
].name
);
293 } else if (handle_is_ok(handle
, HANDLE_DIR
)) {
294 ret
= closedir(handles
[handle
].dirp
);
295 handles
[handle
].use
= HANDLE_UNUSED
;
296 xfree(handles
[handle
].name
);
304 handle_log_close(int handle
, char *emsg
)
306 if (handle_is_ok(handle
, HANDLE_FILE
)) {
307 logit("%s%sclose \"%s\" bytes read %llu written %llu",
308 emsg
== NULL
? "" : emsg
, emsg
== NULL
? "" : " ",
309 handle_to_name(handle
),
310 handle_bytes_read(handle
), handle_bytes_write(handle
));
312 logit("%s%sclosedir \"%s\"",
313 emsg
== NULL
? "" : emsg
, emsg
== NULL
? "" : " ",
314 handle_to_name(handle
));
319 handle_log_exit(void)
323 for (i
= 0; i
< sizeof(handles
)/sizeof(Handle
); i
++)
324 if (handles
[i
].use
!= HANDLE_UNUSED
)
325 handle_log_close(i
, "forced");
335 handle
= get_string(&hlen
);
337 val
= handle_from_string(handle
, hlen
);
347 int mlen
= buffer_len(m
);
349 buffer_put_int(&oqueue
, mlen
);
350 buffer_append(&oqueue
, buffer_ptr(m
), mlen
);
351 buffer_consume(m
, mlen
);
355 status_to_message(u_int32_t status
)
357 const char *status_messages
[] = {
358 "Success", /* SSH_FX_OK */
359 "End of file", /* SSH_FX_EOF */
360 "No such file", /* SSH_FX_NO_SUCH_FILE */
361 "Permission denied", /* SSH_FX_PERMISSION_DENIED */
362 "Failure", /* SSH_FX_FAILURE */
363 "Bad message", /* SSH_FX_BAD_MESSAGE */
364 "No connection", /* SSH_FX_NO_CONNECTION */
365 "Connection lost", /* SSH_FX_CONNECTION_LOST */
366 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
367 "Unknown error" /* Others */
369 return (status_messages
[MIN(status
,SSH2_FX_MAX
)]);
373 send_status(u_int32_t id
, u_int32_t status
)
377 debug3("request %u: sent status %u", id
, status
);
378 if (log_level
> SYSLOG_LEVEL_VERBOSE
||
379 (status
!= SSH2_FX_OK
&& status
!= SSH2_FX_EOF
))
380 logit("sent status %s", status_to_message(status
));
382 buffer_put_char(&msg
, SSH2_FXP_STATUS
);
383 buffer_put_int(&msg
, id
);
384 buffer_put_int(&msg
, status
);
386 buffer_put_cstring(&msg
, status_to_message(status
));
387 buffer_put_cstring(&msg
, "");
393 send_data_or_handle(char type
, u_int32_t id
, const char *data
, int dlen
)
398 buffer_put_char(&msg
, type
);
399 buffer_put_int(&msg
, id
);
400 buffer_put_string(&msg
, data
, dlen
);
406 send_data(u_int32_t id
, const char *data
, int dlen
)
408 debug("request %u: sent data len %d", id
, dlen
);
409 send_data_or_handle(SSH2_FXP_DATA
, id
, data
, dlen
);
413 send_handle(u_int32_t id
, int handle
)
418 handle_to_string(handle
, &string
, &hlen
);
419 debug("request %u: sent handle handle %d", id
, handle
);
420 send_data_or_handle(SSH2_FXP_HANDLE
, id
, string
, hlen
);
425 send_names(u_int32_t id
, int count
, const Stat
*stats
)
431 buffer_put_char(&msg
, SSH2_FXP_NAME
);
432 buffer_put_int(&msg
, id
);
433 buffer_put_int(&msg
, count
);
434 debug("request %u: sent names count %d", id
, count
);
435 for (i
= 0; i
< count
; i
++) {
436 buffer_put_cstring(&msg
, stats
[i
].name
);
437 buffer_put_cstring(&msg
, stats
[i
].long_name
);
438 encode_attrib(&msg
, &stats
[i
].attrib
);
445 send_attrib(u_int32_t id
, const Attrib
*a
)
449 debug("request %u: sent attrib have 0x%x", id
, a
->flags
);
451 buffer_put_char(&msg
, SSH2_FXP_ATTRS
);
452 buffer_put_int(&msg
, id
);
453 encode_attrib(&msg
, a
);
466 verbose("received client version %d", version
);
468 buffer_put_char(&msg
, SSH2_FXP_VERSION
);
469 buffer_put_int(&msg
, SSH2_FILEXFER_VERSION
);
477 u_int32_t id
, pflags
;
480 int handle
, fd
, flags
, mode
, status
= SSH2_FX_FAILURE
;
483 name
= get_string(NULL
);
484 pflags
= get_int(); /* portable flags */
485 debug3("request %u: open flags %d", id
, pflags
);
487 flags
= flags_from_portable(pflags
);
488 mode
= (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) ? a
->perm
: 0666;
489 logit("open \"%s\" flags %s mode 0%o",
490 name
, string_from_portable(pflags
), mode
);
491 fd
= open(name
, flags
, mode
);
493 status
= errno_to_portable(errno
);
495 handle
= handle_new(HANDLE_FILE
, name
, fd
, NULL
);
499 send_handle(id
, handle
);
503 if (status
!= SSH2_FX_OK
)
504 send_status(id
, status
);
512 int handle
, ret
, status
= SSH2_FX_FAILURE
;
515 handle
= get_handle();
516 debug3("request %u: close handle %u", id
, handle
);
517 handle_log_close(handle
, NULL
);
518 ret
= handle_close(handle
);
519 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
520 send_status(id
, status
);
528 int handle
, fd
, ret
, status
= SSH2_FX_FAILURE
;
532 handle
= get_handle();
536 debug("request %u: read \"%s\" (handle %d) off %llu len %d",
537 id
, handle_to_name(handle
), handle
, (unsigned long long)off
, len
);
538 if (len
> sizeof buf
) {
540 debug2("read change len %d", len
);
542 fd
= handle_to_fd(handle
);
544 if (lseek(fd
, off
, SEEK_SET
) < 0) {
545 error("process_read: seek failed");
546 status
= errno_to_portable(errno
);
548 ret
= read(fd
, buf
, len
);
550 status
= errno_to_portable(errno
);
551 } else if (ret
== 0) {
552 status
= SSH2_FX_EOF
;
554 send_data(id
, buf
, ret
);
556 handle_update_read(handle
, ret
);
560 if (status
!= SSH2_FX_OK
)
561 send_status(id
, status
);
570 int handle
, fd
, ret
, status
= SSH2_FX_FAILURE
;
574 handle
= get_handle();
576 data
= get_string(&len
);
578 debug("request %u: write \"%s\" (handle %d) off %llu len %d",
579 id
, handle_to_name(handle
), handle
, (unsigned long long)off
, len
);
580 fd
= handle_to_fd(handle
);
582 if (lseek(fd
, off
, SEEK_SET
) < 0) {
583 status
= errno_to_portable(errno
);
584 error("process_write: seek failed");
587 ret
= write(fd
, data
, len
);
589 error("process_write: write failed");
590 status
= errno_to_portable(errno
);
591 } else if ((size_t)ret
== len
) {
593 handle_update_write(handle
, ret
);
595 debug2("nothing at all written");
599 send_status(id
, status
);
604 process_do_stat(int do_lstat
)
610 int ret
, status
= SSH2_FX_FAILURE
;
613 name
= get_string(NULL
);
614 debug3("request %u: %sstat", id
, do_lstat
? "l" : "");
615 verbose("%sstat name \"%s\"", do_lstat
? "l" : "", name
);
616 ret
= do_lstat
? lstat(name
, &st
) : stat(name
, &st
);
618 status
= errno_to_portable(errno
);
620 stat_to_attrib(&st
, &a
);
624 if (status
!= SSH2_FX_OK
)
625 send_status(id
, status
);
647 int fd
, ret
, handle
, status
= SSH2_FX_FAILURE
;
650 handle
= get_handle();
651 debug("request %u: fstat \"%s\" (handle %u)",
652 id
, handle_to_name(handle
), handle
);
653 fd
= handle_to_fd(handle
);
655 ret
= fstat(fd
, &st
);
657 status
= errno_to_portable(errno
);
659 stat_to_attrib(&st
, &a
);
664 if (status
!= SSH2_FX_OK
)
665 send_status(id
, status
);
668 static struct timeval
*
669 attrib_to_tv(const Attrib
*a
)
671 static struct timeval tv
[2];
673 tv
[0].tv_sec
= a
->atime
;
675 tv
[1].tv_sec
= a
->mtime
;
681 process_setstat(void)
686 int status
= SSH2_FX_OK
, ret
;
689 name
= get_string(NULL
);
691 debug("request %u: setstat name \"%s\"", id
, name
);
692 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
) {
693 logit("set \"%s\" size %llu", name
, a
->size
);
694 ret
= truncate(name
, a
->size
);
696 status
= errno_to_portable(errno
);
698 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) {
699 logit("set \"%s\" mode %04o", name
, a
->perm
);
700 ret
= chmod(name
, a
->perm
& 0777);
702 status
= errno_to_portable(errno
);
704 if (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
) {
708 strftime(buf
, sizeof(buf
), "%Y%m%d-%H:%M:%S",
710 logit("set \"%s\" modtime %s", name
, buf
);
711 ret
= utimes(name
, attrib_to_tv(a
));
713 status
= errno_to_portable(errno
);
715 if (a
->flags
& SSH2_FILEXFER_ATTR_UIDGID
) {
716 logit("set \"%s\" owner %lu group %lu", name
,
717 (u_long
)a
->uid
, (u_long
)a
->gid
);
718 ret
= chown(name
, a
->uid
, a
->gid
);
720 status
= errno_to_portable(errno
);
722 send_status(id
, status
);
727 process_fsetstat(void)
732 int status
= SSH2_FX_OK
;
735 handle
= get_handle();
737 debug("request %u: fsetstat handle %d", id
, handle
);
738 fd
= handle_to_fd(handle
);
740 status
= SSH2_FX_FAILURE
;
742 char *name
= handle_to_name(handle
);
744 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
) {
745 logit("set \"%s\" size %llu", name
, a
->size
);
746 ret
= ftruncate(fd
, a
->size
);
748 status
= errno_to_portable(errno
);
750 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) {
751 logit("set \"%s\" mode %04o", name
, a
->perm
);
753 ret
= fchmod(fd
, a
->perm
& 0777);
755 ret
= chmod(name
, a
->perm
& 0777);
758 status
= errno_to_portable(errno
);
760 if (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
) {
764 strftime(buf
, sizeof(buf
), "%Y%m%d-%H:%M:%S",
766 logit("set \"%s\" modtime %s", name
, buf
);
768 ret
= futimes(fd
, attrib_to_tv(a
));
770 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
);
779 ret
= fchown(fd
, a
->uid
, a
->gid
);
781 ret
= chown(name
, a
->uid
, a
->gid
);
784 status
= errno_to_portable(errno
);
787 send_status(id
, status
);
791 process_opendir(void)
795 int handle
, status
= SSH2_FX_FAILURE
;
799 path
= get_string(NULL
);
800 debug3("request %u: opendir", id
);
801 logit("opendir \"%s\"", path
);
802 dirp
= opendir(path
);
804 status
= errno_to_portable(errno
);
806 handle
= handle_new(HANDLE_DIR
, path
, 0, dirp
);
810 send_handle(id
, handle
);
815 if (status
!= SSH2_FX_OK
)
816 send_status(id
, status
);
821 process_readdir(void)
830 handle
= get_handle();
831 debug("request %u: readdir \"%s\" (handle %d)", id
,
832 handle_to_name(handle
), handle
);
833 dirp
= handle_to_dir(handle
);
834 path
= handle_to_name(handle
);
835 if (dirp
== NULL
|| path
== NULL
) {
836 send_status(id
, SSH2_FX_FAILURE
);
839 char pathname
[MAXPATHLEN
];
841 int nstats
= 10, count
= 0, i
;
843 stats
= xcalloc(nstats
, sizeof(Stat
));
844 while ((dp
= readdir(dirp
)) != NULL
) {
845 if (count
>= nstats
) {
847 stats
= xrealloc(stats
, nstats
, sizeof(Stat
));
850 snprintf(pathname
, sizeof pathname
, "%s%s%s", path
,
851 strcmp(path
, "/") ? "/" : "", dp
->d_name
);
852 if (lstat(pathname
, &st
) < 0)
854 stat_to_attrib(&st
, &(stats
[count
].attrib
));
855 stats
[count
].name
= xstrdup(dp
->d_name
);
856 stats
[count
].long_name
= ls_file(dp
->d_name
, &st
, 0);
858 /* send up to 100 entries in one message */
859 /* XXX check packet size instead */
864 send_names(id
, count
, stats
);
865 for (i
= 0; i
< count
; i
++) {
866 xfree(stats
[i
].name
);
867 xfree(stats
[i
].long_name
);
870 send_status(id
, SSH2_FX_EOF
);
881 int status
= SSH2_FX_FAILURE
;
885 name
= get_string(NULL
);
886 debug3("request %u: remove", id
);
887 logit("remove name \"%s\"", name
);
889 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
890 send_status(id
, status
);
900 int ret
, mode
, status
= SSH2_FX_FAILURE
;
903 name
= get_string(NULL
);
905 mode
= (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) ?
906 a
->perm
& 0777 : 0777;
907 debug3("request %u: mkdir", id
);
908 logit("mkdir name \"%s\" mode 0%o", name
, mode
);
909 ret
= mkdir(name
, mode
);
910 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
911 send_status(id
, status
);
923 name
= get_string(NULL
);
924 debug3("request %u: rmdir", id
);
925 logit("rmdir name \"%s\"", name
);
927 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
928 send_status(id
, status
);
933 process_realpath(void)
935 char resolvedname
[MAXPATHLEN
];
940 path
= get_string(NULL
);
941 if (path
[0] == '\0') {
945 debug3("request %u: realpath", id
);
946 verbose("realpath \"%s\"", path
);
947 if (realpath(path
, resolvedname
) == NULL
) {
948 send_status(id
, errno_to_portable(errno
));
951 attrib_clear(&s
.attrib
);
952 s
.name
= s
.long_name
= resolvedname
;
953 send_names(id
, 1, &s
);
962 char *oldpath
, *newpath
;
967 oldpath
= get_string(NULL
);
968 newpath
= get_string(NULL
);
969 debug3("request %u: rename", id
);
970 logit("rename old \"%s\" new \"%s\"", oldpath
, newpath
);
971 status
= SSH2_FX_FAILURE
;
972 if (lstat(oldpath
, &sb
) == -1)
973 status
= errno_to_portable(errno
);
974 else if (S_ISREG(sb
.st_mode
)) {
975 /* Race-free rename of regular files */
976 if (link(oldpath
, newpath
) == -1) {
977 if (errno
== EOPNOTSUPP
978 #ifdef LINK_OPNOTSUPP_ERRNO
979 || errno
== LINK_OPNOTSUPP_ERRNO
985 * fs doesn't support links, so fall back to
986 * stat+rename. This is racy.
988 if (stat(newpath
, &st
) == -1) {
989 if (rename(oldpath
, newpath
) == -1)
991 errno_to_portable(errno
);
996 status
= errno_to_portable(errno
);
998 } else if (unlink(oldpath
) == -1) {
999 status
= errno_to_portable(errno
);
1000 /* clean spare link */
1003 status
= SSH2_FX_OK
;
1004 } else if (stat(newpath
, &sb
) == -1) {
1005 if (rename(oldpath
, newpath
) == -1)
1006 status
= errno_to_portable(errno
);
1008 status
= SSH2_FX_OK
;
1010 send_status(id
, status
);
1016 process_readlink(void)
1020 char buf
[MAXPATHLEN
];
1024 path
= get_string(NULL
);
1025 debug3("request %u: readlink", id
);
1026 verbose("readlink \"%s\"", path
);
1027 if ((len
= readlink(path
, buf
, sizeof(buf
) - 1)) == -1)
1028 send_status(id
, errno_to_portable(errno
));
1033 attrib_clear(&s
.attrib
);
1034 s
.name
= s
.long_name
= buf
;
1035 send_names(id
, 1, &s
);
1041 process_symlink(void)
1044 char *oldpath
, *newpath
;
1048 oldpath
= get_string(NULL
);
1049 newpath
= get_string(NULL
);
1050 debug3("request %u: symlink", id
);
1051 logit("symlink old \"%s\" new \"%s\"", oldpath
, newpath
);
1052 /* this will fail if 'newpath' exists */
1053 ret
= symlink(oldpath
, newpath
);
1054 status
= (ret
== -1) ? errno_to_portable(errno
) : SSH2_FX_OK
;
1055 send_status(id
, status
);
1061 process_extended(void)
1067 request
= get_string(NULL
);
1068 send_status(id
, SSH2_FX_OP_UNSUPPORTED
); /* MUST */
1072 /* stolen from ssh-agent */
1083 buf_len
= buffer_len(&iqueue
);
1085 return; /* Incomplete message. */
1086 cp
= buffer_ptr(&iqueue
);
1087 msg_len
= get_u32(cp
);
1088 if (msg_len
> SFTP_MAX_MSG_LENGTH
) {
1089 error("bad message from %s local user %s",
1090 client_addr
, pw
->pw_name
);
1093 if (buf_len
< msg_len
+ 4)
1095 buffer_consume(&iqueue
, 4);
1097 type
= buffer_get_char(&iqueue
);
1105 case SSH2_FXP_CLOSE
:
1111 case SSH2_FXP_WRITE
:
1114 case SSH2_FXP_LSTAT
:
1117 case SSH2_FXP_FSTAT
:
1120 case SSH2_FXP_SETSTAT
:
1123 case SSH2_FXP_FSETSTAT
:
1126 case SSH2_FXP_OPENDIR
:
1129 case SSH2_FXP_READDIR
:
1132 case SSH2_FXP_REMOVE
:
1135 case SSH2_FXP_MKDIR
:
1138 case SSH2_FXP_RMDIR
:
1141 case SSH2_FXP_REALPATH
:
1147 case SSH2_FXP_RENAME
:
1150 case SSH2_FXP_READLINK
:
1153 case SSH2_FXP_SYMLINK
:
1156 case SSH2_FXP_EXTENDED
:
1160 error("Unknown message %d", type
);
1163 /* discard the remaining bytes from the current packet */
1164 if (buf_len
< buffer_len(&iqueue
))
1165 fatal("iqueue grew unexpectedly");
1166 consumed
= buf_len
- buffer_len(&iqueue
);
1167 if (msg_len
< consumed
)
1168 fatal("msg_len %d < consumed %d", msg_len
, consumed
);
1169 if (msg_len
> consumed
)
1170 buffer_consume(&iqueue
, msg_len
- consumed
);
1173 /* Cleanup handler that logs active handles upon normal exit */
1177 if (pw
!= NULL
&& client_addr
!= NULL
) {
1179 logit("session closed for local user %s from [%s]",
1180 pw
->pw_name
, client_addr
);
1188 extern char *__progname
;
1191 "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname
);
1196 main(int argc
, char **argv
)
1198 fd_set
*rset
, *wset
;
1199 int in
, out
, max
, ch
, skipargs
= 0, log_stderr
= 0;
1200 ssize_t len
, olen
, set_size
;
1201 SyslogFacility log_facility
= SYSLOG_FACILITY_AUTH
;
1204 extern char *optarg
;
1205 extern char *__progname
;
1207 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1210 __progname
= ssh_get_progname(argv
[0]);
1211 log_init(__progname
, log_level
, log_facility
, log_stderr
);
1213 while (!skipargs
&& (ch
= getopt(argc
, argv
, "C:f:l:che")) != -1) {
1217 * Ignore all arguments if we are invoked as a
1218 * shell using "sftp-server -c command"
1226 log_level
= log_level_number(optarg
);
1227 if (log_level
== SYSLOG_LEVEL_NOT_SET
)
1228 error("Invalid log level \"%s\"", optarg
);
1231 log_facility
= log_facility_number(optarg
);
1232 if (log_level
== SYSLOG_FACILITY_NOT_SET
)
1233 error("Invalid log facility \"%s\"", optarg
);
1241 log_init(__progname
, log_level
, log_facility
, log_stderr
);
1243 if ((cp
= getenv("SSH_CONNECTION")) != NULL
) {
1244 client_addr
= xstrdup(cp
);
1245 if ((cp
= strchr(client_addr
, ' ')) == NULL
)
1246 fatal("Malformed SSH_CONNECTION variable: \"%s\"",
1247 getenv("SSH_CONNECTION"));
1250 client_addr
= xstrdup("UNKNOWN");
1252 if ((pw
= getpwuid(getuid())) == NULL
)
1253 fatal("No user found for uid %lu", (u_long
)getuid());
1256 logit("session opened for local user %s from [%s]",
1257 pw
->pw_name
, client_addr
);
1261 in
= dup(STDIN_FILENO
);
1262 out
= dup(STDOUT_FILENO
);
1265 setmode(in
, O_BINARY
);
1266 setmode(out
, O_BINARY
);
1275 buffer_init(&iqueue
);
1276 buffer_init(&oqueue
);
1278 set_size
= howmany(max
+ 1, NFDBITS
) * sizeof(fd_mask
);
1279 rset
= (fd_set
*)xmalloc(set_size
);
1280 wset
= (fd_set
*)xmalloc(set_size
);
1283 memset(rset
, 0, set_size
);
1284 memset(wset
, 0, set_size
);
1287 olen
= buffer_len(&oqueue
);
1291 if (select(max
+1, rset
, wset
, NULL
, NULL
) < 0) {
1294 error("select: %s", strerror(errno
));
1298 /* copy stdin to iqueue */
1299 if (FD_ISSET(in
, rset
)) {
1301 len
= read(in
, buf
, sizeof buf
);
1305 } else if (len
< 0) {
1306 error("read: %s", strerror(errno
));
1309 buffer_append(&iqueue
, buf
, len
);
1312 /* send oqueue to stdout */
1313 if (FD_ISSET(out
, wset
)) {
1314 len
= write(out
, buffer_ptr(&oqueue
), olen
);
1316 error("write: %s", strerror(errno
));
1319 buffer_consume(&oqueue
, len
);
1322 /* process requests from client */