summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2013-10-15 11:55:57 +1100
committerDamien Miller <djm@mindrot.org>2013-10-15 11:55:57 +1100
commit6eaeebf27d92f39a38c772aa3f20c2250af2dd29 (patch)
tree00c274ab9fbfaddd6c0a63881b1821c68b6c45da
parentdf62d71e64d29d1054e7a53d1a801075ef70335f (diff)
- djm@cvs.openbsd.org 2013/10/09 23:42:17
[sftp-server.8 sftp-server.c] Add ability to whitelist and/or blacklist sftp protocol requests by name. Refactor dispatch loop and consolidate read-only mode checks. Make global variables static, since sftp-server is linked into sshd(8). ok dtucker@
-rw-r--r--ChangeLog9
-rw-r--r--sftp-server.838
-rw-r--r--sftp-server.c403
3 files changed, 258 insertions, 192 deletions
diff --git a/ChangeLog b/ChangeLog
index 5eb73c9f9..2ab5a2cbf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
120131015
2 - (djm) OpenBSD CVS Sync
3 - djm@cvs.openbsd.org 2013/10/09 23:42:17
4 [sftp-server.8 sftp-server.c]
5 Add ability to whitelist and/or blacklist sftp protocol requests by name.
6 Refactor dispatch loop and consolidate read-only mode checks.
7 Make global variables static, since sftp-server is linked into sshd(8).
8 ok dtucker@
9
120131010 1020131010
2 - (dtucker) OpenBSD CVS Sync 11 - (dtucker) OpenBSD CVS Sync
3 - sthen@cvs.openbsd.org 2013/09/16 11:35:43 12 - sthen@cvs.openbsd.org 2013/09/16 11:35:43
diff --git a/sftp-server.8 b/sftp-server.8
index cc925b96e..d7604b28d 100644
--- a/sftp-server.8
+++ b/sftp-server.8
@@ -1,4 +1,4 @@
1.\" $OpenBSD: sftp-server.8,v 1.23 2013/07/16 00:07:52 schwarze Exp $ 1.\" $OpenBSD: sftp-server.8,v 1.24 2013/10/09 23:42:17 djm Exp $
2.\" 2.\"
3.\" Copyright (c) 2000 Markus Friedl. All rights reserved. 3.\" Copyright (c) 2000 Markus Friedl. All rights reserved.
4.\" 4.\"
@@ -22,7 +22,7 @@
22.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24.\" 24.\"
25.Dd $Mdocdate: July 16 2013 $ 25.Dd $Mdocdate: October 9 2013 $
26.Dt SFTP-SERVER 8 26.Dt SFTP-SERVER 8
27.Os 27.Os
28.Sh NAME 28.Sh NAME
@@ -30,11 +30,15 @@
30.Nd SFTP server subsystem 30.Nd SFTP server subsystem
31.Sh SYNOPSIS 31.Sh SYNOPSIS
32.Nm sftp-server 32.Nm sftp-server
33.Bk -words
33.Op Fl ehR 34.Op Fl ehR
34.Op Fl d Ar start_directory 35.Op Fl d Ar start_directory
35.Op Fl f Ar log_facility 36.Op Fl f Ar log_facility
36.Op Fl l Ar log_level 37.Op Fl l Ar log_level
37.Op Fl u Ar umask 38.Op Fl u Ar umask
39.Ek
40.Nm
41.Fl Q Ar protocol_feature
38.Sh DESCRIPTION 42.Sh DESCRIPTION
39.Nm 43.Nm
40is a program that speaks the server side of SFTP protocol 44is a program that speaks the server side of SFTP protocol
@@ -93,6 +97,36 @@ performs on behalf of the client.
93DEBUG and DEBUG1 are equivalent. 97DEBUG and DEBUG1 are equivalent.
94DEBUG2 and DEBUG3 each specify higher levels of debugging output. 98DEBUG2 and DEBUG3 each specify higher levels of debugging output.
95The default is ERROR. 99The default is ERROR.
100.It Fl P Ar blacklisted_requests
101Specify a comma-separated list of sftp protocol requests that are banned by
102the server.
103.Nm
104will reply to any blacklisted request with a failure.
105The
106.Fl Q
107flag allows querying
108.Nm
109to determine the supported request types.
110If both a blacklist and a whitelist are specified, then the blacklist is
111applied before the whitelist.
112.It Fl p Ar whitelisted_requests
113Specify a comma-separated list of sftp protocol requests that are permitted
114by the server.
115All request types that are not on the whitelist will be logged and replied
116to with a failure message.
117.Pp
118Care must be taken when using this feature to ensure that requests made
119implicitly by sftp clients are permitted.
120.It Fl Q Ar protocol_feature
121Query protocol features supported by
122.Nm .
123At present the only feature that may be queried is
124.Dq requests ,
125that may be used for whitelisting or blacklisting (flags
126.Fl p
127and
128.Fl P
129respectively.)
96.It Fl R 130.It Fl R
97Places this instance of 131Places this instance of
98.Nm 132.Nm
diff --git a/sftp-server.c b/sftp-server.c
index 285f21aaf..ca8335ec7 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-server.c,v 1.97 2013/05/17 00:13:14 djm Exp $ */ 1/* $OpenBSD: sftp-server.c,v 1.98 2013/10/09 23:42:17 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
4 * 4 *
@@ -46,6 +46,7 @@
46#include "buffer.h" 46#include "buffer.h"
47#include "log.h" 47#include "log.h"
48#include "misc.h" 48#include "misc.h"
49#include "match.h"
49#include "uidswap.h" 50#include "uidswap.h"
50 51
51#include "sftp.h" 52#include "sftp.h"
@@ -57,24 +58,29 @@
57#define get_string(lenp) buffer_get_string(&iqueue, lenp); 58#define get_string(lenp) buffer_get_string(&iqueue, lenp);
58 59
59/* Our verbosity */ 60/* Our verbosity */
60LogLevel log_level = SYSLOG_LEVEL_ERROR; 61static LogLevel log_level = SYSLOG_LEVEL_ERROR;
61 62
62/* Our client */ 63/* Our client */
63struct passwd *pw = NULL; 64static struct passwd *pw = NULL;
64char *client_addr = NULL; 65static char *client_addr = NULL;
65 66
66/* input and output queue */ 67/* input and output queue */
67Buffer iqueue; 68static Buffer iqueue;
68Buffer oqueue; 69static Buffer oqueue;
69 70
70/* Version of client */ 71/* Version of client */
71u_int version; 72static u_int version;
73
74/* SSH2_FXP_INIT received */
75static int init_done;
72 76
73/* Disable writes */ 77/* Disable writes */
74int readonly; 78static int readonly;
75 79
76/* portable attributes, etc. */ 80/* Requests that are allowed/denied */
81static char *request_whitelist, *request_blacklist;
77 82
83/* portable attributes, etc. */
78typedef struct Stat Stat; 84typedef struct Stat Stat;
79 85
80struct Stat { 86struct Stat {
@@ -83,6 +89,100 @@ struct Stat {
83 Attrib attrib; 89 Attrib attrib;
84}; 90};
85 91
92/* Packet handlers */
93static void process_open(u_int32_t id);
94static void process_close(u_int32_t id);
95static void process_read(u_int32_t id);
96static void process_write(u_int32_t id);
97static void process_stat(u_int32_t id);
98static void process_lstat(u_int32_t id);
99static void process_fstat(u_int32_t id);
100static void process_setstat(u_int32_t id);
101static void process_fsetstat(u_int32_t id);
102static void process_opendir(u_int32_t id);
103static void process_readdir(u_int32_t id);
104static void process_remove(u_int32_t id);
105static void process_mkdir(u_int32_t id);
106static void process_rmdir(u_int32_t id);
107static void process_realpath(u_int32_t id);
108static void process_rename(u_int32_t id);
109static void process_readlink(u_int32_t id);
110static void process_symlink(u_int32_t id);
111static void process_extended_posix_rename(u_int32_t id);
112static void process_extended_statvfs(u_int32_t id);
113static void process_extended_fstatvfs(u_int32_t id);
114static void process_extended_hardlink(u_int32_t id);
115static void process_extended(u_int32_t id);
116
117struct sftp_handler {
118 const char *name; /* user-visible name for fine-grained perms */
119 const char *ext_name; /* extended request name */
120 u_int type; /* packet type, for non extended packets */
121 void (*handler)(u_int32_t);
122 int does_write; /* if nonzero, banned for readonly mode */
123};
124
125struct sftp_handler handlers[] = {
126 /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */
127 { "open", NULL, SSH2_FXP_OPEN, process_open, 0 },
128 { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 },
129 { "read", NULL, SSH2_FXP_READ, process_read, 0 },
130 { "write", NULL, SSH2_FXP_WRITE, process_write, 1 },
131 { "lstat", NULL, SSH2_FXP_LSTAT, process_lstat, 0 },
132 { "fstat", NULL, SSH2_FXP_FSTAT, process_fstat, 0 },
133 { "setstat", NULL, SSH2_FXP_SETSTAT, process_setstat, 1 },
134 { "fsetstat", NULL, SSH2_FXP_FSETSTAT, process_fsetstat, 1 },
135 { "opendir", NULL, SSH2_FXP_OPENDIR, process_opendir, 0 },
136 { "readdir", NULL, SSH2_FXP_READDIR, process_readdir, 0 },
137 { "remove", NULL, SSH2_FXP_REMOVE, process_remove, 1 },
138 { "mkdir", NULL, SSH2_FXP_MKDIR, process_mkdir, 1 },
139 { "rmdir", NULL, SSH2_FXP_RMDIR, process_rmdir, 1 },
140 { "realpath", NULL, SSH2_FXP_REALPATH, process_realpath, 0 },
141 { "stat", NULL, SSH2_FXP_STAT, process_stat, 0 },
142 { "rename", NULL, SSH2_FXP_RENAME, process_rename, 1 },
143 { "readlink", NULL, SSH2_FXP_READLINK, process_readlink, 0 },
144 { "symlink", NULL, SSH2_FXP_SYMLINK, process_symlink, 1 },
145 { NULL, NULL, 0, NULL, 0 }
146};
147
148/* SSH2_FXP_EXTENDED submessages */
149struct sftp_handler extended_handlers[] = {
150 { "posix-rename", "posix-rename@openssh.com", 0,
151 process_extended_posix_rename, 1 },
152 { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
153 { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
154 { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
155 { NULL, NULL, 0, NULL, 0 }
156};
157
158static int
159request_permitted(struct sftp_handler *h)
160{
161 char *result;
162
163 if (readonly && h->does_write) {
164 verbose("Refusing %s request in read-only mode", h->name);
165 return 0;
166 }
167 if (request_blacklist != NULL &&
168 ((result = match_list(h->name, request_blacklist, NULL))) != NULL) {
169 free(result);
170 verbose("Refusing blacklisted %s request", h->name);
171 return 0;
172 }
173 if (request_whitelist != NULL &&
174 ((result = match_list(h->name, request_whitelist, NULL))) != NULL) {
175 free(result);
176 debug2("Permitting whitelisted %s request", h->name);
177 return 1;
178 }
179 if (request_whitelist != NULL) {
180 verbose("Refusing non-whitelisted %s request", h->name);
181 return 0;
182 }
183 return 1;
184}
185
86static int 186static int
87errno_to_portable(int unixerrno) 187errno_to_portable(int unixerrno)
88{ 188{
@@ -543,14 +643,13 @@ process_init(void)
543} 643}
544 644
545static void 645static void
546process_open(void) 646process_open(u_int32_t id)
547{ 647{
548 u_int32_t id, pflags; 648 u_int32_t pflags;
549 Attrib *a; 649 Attrib *a;
550 char *name; 650 char *name;
551 int handle, fd, flags, mode, status = SSH2_FX_FAILURE; 651 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
552 652
553 id = get_int();
554 name = get_string(NULL); 653 name = get_string(NULL);
555 pflags = get_int(); /* portable flags */ 654 pflags = get_int(); /* portable flags */
556 debug3("request %u: open flags %d", id, pflags); 655 debug3("request %u: open flags %d", id, pflags);
@@ -560,9 +659,11 @@ process_open(void)
560 logit("open \"%s\" flags %s mode 0%o", 659 logit("open \"%s\" flags %s mode 0%o",
561 name, string_from_portable(pflags), mode); 660 name, string_from_portable(pflags), mode);
562 if (readonly && 661 if (readonly &&
563 ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR)) 662 ((flags & O_ACCMODE) == O_WRONLY ||
564 status = SSH2_FX_PERMISSION_DENIED; 663 (flags & O_ACCMODE) == O_RDWR)) {
565 else { 664 verbose("Refusing open request in read-only mode");
665 status = SSH2_FX_PERMISSION_DENIED;
666 } else {
566 fd = open(name, flags, mode); 667 fd = open(name, flags, mode);
567 if (fd < 0) { 668 if (fd < 0) {
568 status = errno_to_portable(errno); 669 status = errno_to_portable(errno);
@@ -582,12 +683,10 @@ process_open(void)
582} 683}
583 684
584static void 685static void
585process_close(void) 686process_close(u_int32_t id)
586{ 687{
587 u_int32_t id;
588 int handle, ret, status = SSH2_FX_FAILURE; 688 int handle, ret, status = SSH2_FX_FAILURE;
589 689
590 id = get_int();
591 handle = get_handle(); 690 handle = get_handle();
592 debug3("request %u: close handle %u", id, handle); 691 debug3("request %u: close handle %u", id, handle);
593 handle_log_close(handle, NULL); 692 handle_log_close(handle, NULL);
@@ -597,14 +696,13 @@ process_close(void)
597} 696}
598 697
599static void 698static void
600process_read(void) 699process_read(u_int32_t id)
601{ 700{
602 char buf[64*1024]; 701 char buf[64*1024];
603 u_int32_t id, len; 702 u_int32_t len;
604 int handle, fd, ret, status = SSH2_FX_FAILURE; 703 int handle, fd, ret, status = SSH2_FX_FAILURE;
605 u_int64_t off; 704 u_int64_t off;
606 705
607 id = get_int();
608 handle = get_handle(); 706 handle = get_handle();
609 off = get_int64(); 707 off = get_int64();
610 len = get_int(); 708 len = get_int();
@@ -638,15 +736,13 @@ process_read(void)
638} 736}
639 737
640static void 738static void
641process_write(void) 739process_write(u_int32_t id)
642{ 740{
643 u_int32_t id;
644 u_int64_t off; 741 u_int64_t off;
645 u_int len; 742 u_int len;
646 int handle, fd, ret, status; 743 int handle, fd, ret, status;
647 char *data; 744 char *data;
648 745
649 id = get_int();
650 handle = get_handle(); 746 handle = get_handle();
651 off = get_int64(); 747 off = get_int64();
652 data = get_string(&len); 748 data = get_string(&len);
@@ -657,8 +753,6 @@ process_write(void)
657 753
658 if (fd < 0) 754 if (fd < 0)
659 status = SSH2_FX_FAILURE; 755 status = SSH2_FX_FAILURE;
660 else if (readonly)
661 status = SSH2_FX_PERMISSION_DENIED;
662 else { 756 else {
663 if (lseek(fd, off, SEEK_SET) < 0) { 757 if (lseek(fd, off, SEEK_SET) < 0) {
664 status = errno_to_portable(errno); 758 status = errno_to_portable(errno);
@@ -683,15 +777,13 @@ process_write(void)
683} 777}
684 778
685static void 779static void
686process_do_stat(int do_lstat) 780process_do_stat(u_int32_t id, int do_lstat)
687{ 781{
688 Attrib a; 782 Attrib a;
689 struct stat st; 783 struct stat st;
690 u_int32_t id;
691 char *name; 784 char *name;
692 int ret, status = SSH2_FX_FAILURE; 785 int ret, status = SSH2_FX_FAILURE;
693 786
694 id = get_int();
695 name = get_string(NULL); 787 name = get_string(NULL);
696 debug3("request %u: %sstat", id, do_lstat ? "l" : ""); 788 debug3("request %u: %sstat", id, do_lstat ? "l" : "");
697 verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name); 789 verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
@@ -709,26 +801,24 @@ process_do_stat(int do_lstat)
709} 801}
710 802
711static void 803static void
712process_stat(void) 804process_stat(u_int32_t id)
713{ 805{
714 process_do_stat(0); 806 process_do_stat(id, 0);
715} 807}
716 808
717static void 809static void
718process_lstat(void) 810process_lstat(u_int32_t id)
719{ 811{
720 process_do_stat(1); 812 process_do_stat(id, 1);
721} 813}
722 814
723static void 815static void
724process_fstat(void) 816process_fstat(u_int32_t id)
725{ 817{
726 Attrib a; 818 Attrib a;
727 struct stat st; 819 struct stat st;
728 u_int32_t id;
729 int fd, ret, handle, status = SSH2_FX_FAILURE; 820 int fd, ret, handle, status = SSH2_FX_FAILURE;
730 821
731 id = get_int();
732 handle = get_handle(); 822 handle = get_handle();
733 debug("request %u: fstat \"%s\" (handle %u)", 823 debug("request %u: fstat \"%s\" (handle %u)",
734 id, handle_to_name(handle), handle); 824 id, handle_to_name(handle), handle);
@@ -760,21 +850,15 @@ attrib_to_tv(const Attrib *a)
760} 850}
761 851
762static void 852static void
763process_setstat(void) 853process_setstat(u_int32_t id)
764{ 854{
765 Attrib *a; 855 Attrib *a;
766 u_int32_t id;
767 char *name; 856 char *name;
768 int status = SSH2_FX_OK, ret; 857 int status = SSH2_FX_OK, ret;
769 858
770 id = get_int();
771 name = get_string(NULL); 859 name = get_string(NULL);
772 a = get_attrib(); 860 a = get_attrib();
773 debug("request %u: setstat name \"%s\"", id, name); 861 debug("request %u: setstat name \"%s\"", id, name);
774 if (readonly) {
775 status = SSH2_FX_PERMISSION_DENIED;
776 a->flags = 0;
777 }
778 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 862 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
779 logit("set \"%s\" size %llu", 863 logit("set \"%s\" size %llu",
780 name, (unsigned long long)a->size); 864 name, (unsigned long long)a->size);
@@ -811,22 +895,18 @@ process_setstat(void)
811} 895}
812 896
813static void 897static void
814process_fsetstat(void) 898process_fsetstat(u_int32_t id)
815{ 899{
816 Attrib *a; 900 Attrib *a;
817 u_int32_t id;
818 int handle, fd, ret; 901 int handle, fd, ret;
819 int status = SSH2_FX_OK; 902 int status = SSH2_FX_OK;
820 903
821 id = get_int();
822 handle = get_handle(); 904 handle = get_handle();
823 a = get_attrib(); 905 a = get_attrib();
824 debug("request %u: fsetstat handle %d", id, handle); 906 debug("request %u: fsetstat handle %d", id, handle);
825 fd = handle_to_fd(handle); 907 fd = handle_to_fd(handle);
826 if (fd < 0) 908 if (fd < 0)
827 status = SSH2_FX_FAILURE; 909 status = SSH2_FX_FAILURE;
828 else if (readonly)
829 status = SSH2_FX_PERMISSION_DENIED;
830 else { 910 else {
831 char *name = handle_to_name(handle); 911 char *name = handle_to_name(handle);
832 912
@@ -878,14 +958,12 @@ process_fsetstat(void)
878} 958}
879 959
880static void 960static void
881process_opendir(void) 961process_opendir(u_int32_t id)
882{ 962{
883 DIR *dirp = NULL; 963 DIR *dirp = NULL;
884 char *path; 964 char *path;
885 int handle, status = SSH2_FX_FAILURE; 965 int handle, status = SSH2_FX_FAILURE;
886 u_int32_t id;
887 966
888 id = get_int();
889 path = get_string(NULL); 967 path = get_string(NULL);
890 debug3("request %u: opendir", id); 968 debug3("request %u: opendir", id);
891 logit("opendir \"%s\"", path); 969 logit("opendir \"%s\"", path);
@@ -908,15 +986,13 @@ process_opendir(void)
908} 986}
909 987
910static void 988static void
911process_readdir(void) 989process_readdir(u_int32_t id)
912{ 990{
913 DIR *dirp; 991 DIR *dirp;
914 struct dirent *dp; 992 struct dirent *dp;
915 char *path; 993 char *path;
916 int handle; 994 int handle;
917 u_int32_t id;
918 995
919 id = get_int();
920 handle = get_handle(); 996 handle = get_handle();
921 debug("request %u: readdir \"%s\" (handle %d)", id, 997 debug("request %u: readdir \"%s\" (handle %d)", id,
922 handle_to_name(handle), handle); 998 handle_to_name(handle), handle);
@@ -964,81 +1040,61 @@ process_readdir(void)
964} 1040}
965 1041
966static void 1042static void
967process_remove(void) 1043process_remove(u_int32_t id)
968{ 1044{
969 char *name; 1045 char *name;
970 u_int32_t id;
971 int status = SSH2_FX_FAILURE; 1046 int status = SSH2_FX_FAILURE;
972 int ret; 1047 int ret;
973 1048
974 id = get_int();
975 name = get_string(NULL); 1049 name = get_string(NULL);
976 debug3("request %u: remove", id); 1050 debug3("request %u: remove", id);
977 logit("remove name \"%s\"", name); 1051 logit("remove name \"%s\"", name);
978 if (readonly) 1052 ret = unlink(name);
979 status = SSH2_FX_PERMISSION_DENIED; 1053 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
980 else {
981 ret = unlink(name);
982 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
983 }
984 send_status(id, status); 1054 send_status(id, status);
985 free(name); 1055 free(name);
986} 1056}
987 1057
988static void 1058static void
989process_mkdir(void) 1059process_mkdir(u_int32_t id)
990{ 1060{
991 Attrib *a; 1061 Attrib *a;
992 u_int32_t id;
993 char *name; 1062 char *name;
994 int ret, mode, status = SSH2_FX_FAILURE; 1063 int ret, mode, status = SSH2_FX_FAILURE;
995 1064
996 id = get_int();
997 name = get_string(NULL); 1065 name = get_string(NULL);
998 a = get_attrib(); 1066 a = get_attrib();
999 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? 1067 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
1000 a->perm & 07777 : 0777; 1068 a->perm & 07777 : 0777;
1001 debug3("request %u: mkdir", id); 1069 debug3("request %u: mkdir", id);
1002 logit("mkdir name \"%s\" mode 0%o", name, mode); 1070 logit("mkdir name \"%s\" mode 0%o", name, mode);
1003 if (readonly) 1071 ret = mkdir(name, mode);
1004 status = SSH2_FX_PERMISSION_DENIED; 1072 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1005 else {
1006 ret = mkdir(name, mode);
1007 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1008 }
1009 send_status(id, status); 1073 send_status(id, status);
1010 free(name); 1074 free(name);
1011} 1075}
1012 1076
1013static void 1077static void
1014process_rmdir(void) 1078process_rmdir(u_int32_t id)
1015{ 1079{
1016 u_int32_t id;
1017 char *name; 1080 char *name;
1018 int ret, status; 1081 int ret, status;
1019 1082
1020 id = get_int();
1021 name = get_string(NULL); 1083 name = get_string(NULL);
1022 debug3("request %u: rmdir", id); 1084 debug3("request %u: rmdir", id);
1023 logit("rmdir name \"%s\"", name); 1085 logit("rmdir name \"%s\"", name);
1024 if (readonly) 1086 ret = rmdir(name);
1025 status = SSH2_FX_PERMISSION_DENIED; 1087 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1026 else {
1027 ret = rmdir(name);
1028 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1029 }
1030 send_status(id, status); 1088 send_status(id, status);
1031 free(name); 1089 free(name);
1032} 1090}
1033 1091
1034static void 1092static void
1035process_realpath(void) 1093process_realpath(u_int32_t id)
1036{ 1094{
1037 char resolvedname[MAXPATHLEN]; 1095 char resolvedname[MAXPATHLEN];
1038 u_int32_t id;
1039 char *path; 1096 char *path;
1040 1097
1041 id = get_int();
1042 path = get_string(NULL); 1098 path = get_string(NULL);
1043 if (path[0] == '\0') { 1099 if (path[0] == '\0') {
1044 free(path); 1100 free(path);
@@ -1058,22 +1114,18 @@ process_realpath(void)
1058} 1114}
1059 1115
1060static void 1116static void
1061process_rename(void) 1117process_rename(u_int32_t id)
1062{ 1118{
1063 u_int32_t id;
1064 char *oldpath, *newpath; 1119 char *oldpath, *newpath;
1065 int status; 1120 int status;
1066 struct stat sb; 1121 struct stat sb;
1067 1122
1068 id = get_int();
1069 oldpath = get_string(NULL); 1123 oldpath = get_string(NULL);
1070 newpath = get_string(NULL); 1124 newpath = get_string(NULL);
1071 debug3("request %u: rename", id); 1125 debug3("request %u: rename", id);
1072 logit("rename old \"%s\" new \"%s\"", oldpath, newpath); 1126 logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1073 status = SSH2_FX_FAILURE; 1127 status = SSH2_FX_FAILURE;
1074 if (readonly) 1128 if (lstat(oldpath, &sb) == -1)
1075 status = SSH2_FX_PERMISSION_DENIED;
1076 else if (lstat(oldpath, &sb) == -1)
1077 status = errno_to_portable(errno); 1129 status = errno_to_portable(errno);
1078 else if (S_ISREG(sb.st_mode)) { 1130 else if (S_ISREG(sb.st_mode)) {
1079 /* Race-free rename of regular files */ 1131 /* Race-free rename of regular files */
@@ -1120,14 +1172,12 @@ process_rename(void)
1120} 1172}
1121 1173
1122static void 1174static void
1123process_readlink(void) 1175process_readlink(u_int32_t id)
1124{ 1176{
1125 u_int32_t id;
1126 int len; 1177 int len;
1127 char buf[MAXPATHLEN]; 1178 char buf[MAXPATHLEN];
1128 char *path; 1179 char *path;
1129 1180
1130 id = get_int();
1131 path = get_string(NULL); 1181 path = get_string(NULL);
1132 debug3("request %u: readlink", id); 1182 debug3("request %u: readlink", id);
1133 verbose("readlink \"%s\"", path); 1183 verbose("readlink \"%s\"", path);
@@ -1145,24 +1195,18 @@ process_readlink(void)
1145} 1195}
1146 1196
1147static void 1197static void
1148process_symlink(void) 1198process_symlink(u_int32_t id)
1149{ 1199{
1150 u_int32_t id;
1151 char *oldpath, *newpath; 1200 char *oldpath, *newpath;
1152 int ret, status; 1201 int ret, status;
1153 1202
1154 id = get_int();
1155 oldpath = get_string(NULL); 1203 oldpath = get_string(NULL);
1156 newpath = get_string(NULL); 1204 newpath = get_string(NULL);
1157 debug3("request %u: symlink", id); 1205 debug3("request %u: symlink", id);
1158 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath); 1206 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1159 /* this will fail if 'newpath' exists */ 1207 /* this will fail if 'newpath' exists */
1160 if (readonly) 1208 ret = symlink(oldpath, newpath);
1161 status = SSH2_FX_PERMISSION_DENIED; 1209 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1162 else {
1163 ret = symlink(oldpath, newpath);
1164 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1165 }
1166 send_status(id, status); 1210 send_status(id, status);
1167 free(oldpath); 1211 free(oldpath);
1168 free(newpath); 1212 free(newpath);
@@ -1178,12 +1222,8 @@ process_extended_posix_rename(u_int32_t id)
1178 newpath = get_string(NULL); 1222 newpath = get_string(NULL);
1179 debug3("request %u: posix-rename", id); 1223 debug3("request %u: posix-rename", id);
1180 logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath); 1224 logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1181 if (readonly) 1225 ret = rename(oldpath, newpath);
1182 status = SSH2_FX_PERMISSION_DENIED; 1226 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1183 else {
1184 ret = rename(oldpath, newpath);
1185 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1186 }
1187 send_status(id, status); 1227 send_status(id, status);
1188 free(oldpath); 1228 free(oldpath);
1189 free(newpath); 1229 free(newpath);
@@ -1235,35 +1275,33 @@ process_extended_hardlink(u_int32_t id)
1235 newpath = get_string(NULL); 1275 newpath = get_string(NULL);
1236 debug3("request %u: hardlink", id); 1276 debug3("request %u: hardlink", id);
1237 logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath); 1277 logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1238 if (readonly) 1278 ret = link(oldpath, newpath);
1239 status = SSH2_FX_PERMISSION_DENIED; 1279 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1240 else {
1241 ret = link(oldpath, newpath);
1242 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1243 }
1244 send_status(id, status); 1280 send_status(id, status);
1245 free(oldpath); 1281 free(oldpath);
1246 free(newpath); 1282 free(newpath);
1247} 1283}
1248 1284
1249static void 1285static void
1250process_extended(void) 1286process_extended(u_int32_t id)
1251{ 1287{
1252 u_int32_t id;
1253 char *request; 1288 char *request;
1289 u_int i;
1254 1290
1255 id = get_int();
1256 request = get_string(NULL); 1291 request = get_string(NULL);
1257 if (strcmp(request, "posix-rename@openssh.com") == 0) 1292 for (i = 0; extended_handlers[i].handler != NULL; i++) {
1258 process_extended_posix_rename(id); 1293 if (strcmp(request, extended_handlers[i].ext_name) == 0) {
1259 else if (strcmp(request, "statvfs@openssh.com") == 0) 1294 if (!request_permitted(&extended_handlers[i]))
1260 process_extended_statvfs(id); 1295 send_status(id, SSH2_FX_PERMISSION_DENIED);
1261 else if (strcmp(request, "fstatvfs@openssh.com") == 0) 1296 else
1262 process_extended_fstatvfs(id); 1297 extended_handlers[i].handler(id);
1263 else if (strcmp(request, "hardlink@openssh.com") == 0) 1298 break;
1264 process_extended_hardlink(id); 1299 }
1265 else 1300 }
1301 if (extended_handlers[i].handler == NULL) {
1302 error("Unknown extended request \"%.100s\"", request);
1266 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ 1303 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
1304 }
1267 free(request); 1305 free(request);
1268} 1306}
1269 1307
@@ -1272,11 +1310,9 @@ process_extended(void)
1272static void 1310static void
1273process(void) 1311process(void)
1274{ 1312{
1275 u_int msg_len; 1313 u_int msg_len, buf_len, consumed, type, i;
1276 u_int buf_len;
1277 u_int consumed;
1278 u_int type;
1279 u_char *cp; 1314 u_char *cp;
1315 u_int32_t id;
1280 1316
1281 buf_len = buffer_len(&iqueue); 1317 buf_len = buffer_len(&iqueue);
1282 if (buf_len < 5) 1318 if (buf_len < 5)
@@ -1293,70 +1329,35 @@ process(void)
1293 buffer_consume(&iqueue, 4); 1329 buffer_consume(&iqueue, 4);
1294 buf_len -= 4; 1330 buf_len -= 4;
1295 type = buffer_get_char(&iqueue); 1331 type = buffer_get_char(&iqueue);
1332
1296 switch (type) { 1333 switch (type) {
1297 case SSH2_FXP_INIT: 1334 case SSH2_FXP_INIT:
1298 process_init(); 1335 process_init();
1299 break; 1336 init_done = 1;
1300 case SSH2_FXP_OPEN:
1301 process_open();
1302 break;
1303 case SSH2_FXP_CLOSE:
1304 process_close();
1305 break;
1306 case SSH2_FXP_READ:
1307 process_read();
1308 break;
1309 case SSH2_FXP_WRITE:
1310 process_write();
1311 break;
1312 case SSH2_FXP_LSTAT:
1313 process_lstat();
1314 break;
1315 case SSH2_FXP_FSTAT:
1316 process_fstat();
1317 break;
1318 case SSH2_FXP_SETSTAT:
1319 process_setstat();
1320 break;
1321 case SSH2_FXP_FSETSTAT:
1322 process_fsetstat();
1323 break;
1324 case SSH2_FXP_OPENDIR:
1325 process_opendir();
1326 break;
1327 case SSH2_FXP_READDIR:
1328 process_readdir();
1329 break;
1330 case SSH2_FXP_REMOVE:
1331 process_remove();
1332 break;
1333 case SSH2_FXP_MKDIR:
1334 process_mkdir();
1335 break;
1336 case SSH2_FXP_RMDIR:
1337 process_rmdir();
1338 break;
1339 case SSH2_FXP_REALPATH:
1340 process_realpath();
1341 break;
1342 case SSH2_FXP_STAT:
1343 process_stat();
1344 break;
1345 case SSH2_FXP_RENAME:
1346 process_rename();
1347 break;
1348 case SSH2_FXP_READLINK:
1349 process_readlink();
1350 break;
1351 case SSH2_FXP_SYMLINK:
1352 process_symlink();
1353 break; 1337 break;
1354 case SSH2_FXP_EXTENDED: 1338 case SSH2_FXP_EXTENDED:
1355 process_extended(); 1339 if (!init_done)
1340 fatal("Received extended request before init");
1341 id = get_int();
1342 process_extended(id);
1356 break; 1343 break;
1357 default: 1344 default:
1358 error("Unknown message %d", type); 1345 if (!init_done)
1359 break; 1346 fatal("Received %u request before init", type);
1347 id = get_int();
1348 for (i = 0; handlers[i].handler != NULL; i++) {
1349 if (type == handlers[i].type) {
1350 if (!request_permitted(&handlers[i])) {
1351 send_status(id,
1352 SSH2_FX_PERMISSION_DENIED);
1353 } else {
1354 handlers[i].handler(id);
1355 }
1356 break;
1357 }
1358 }
1359 if (handlers[i].handler == NULL)
1360 error("Unknown message %u", type);
1360 } 1361 }
1361 /* discard the remaining bytes from the current packet */ 1362 /* discard the remaining bytes from the current packet */
1362 if (buf_len < buffer_len(&iqueue)) { 1363 if (buf_len < buffer_len(&iqueue)) {
@@ -1365,7 +1366,7 @@ process(void)
1365 } 1366 }
1366 consumed = buf_len - buffer_len(&iqueue); 1367 consumed = buf_len - buffer_len(&iqueue);
1367 if (msg_len < consumed) { 1368 if (msg_len < consumed) {
1368 error("msg_len %d < consumed %d", msg_len, consumed); 1369 error("msg_len %u < consumed %u", msg_len, consumed);
1369 sftp_server_cleanup_exit(255); 1370 sftp_server_cleanup_exit(255);
1370 } 1371 }
1371 if (msg_len > consumed) 1372 if (msg_len > consumed)
@@ -1400,7 +1401,7 @@ int
1400sftp_server_main(int argc, char **argv, struct passwd *user_pw) 1401sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1401{ 1402{
1402 fd_set *rset, *wset; 1403 fd_set *rset, *wset;
1403 int in, out, max, ch, skipargs = 0, log_stderr = 0; 1404 int i, in, out, max, ch, skipargs = 0, log_stderr = 0;
1404 ssize_t len, olen, set_size; 1405 ssize_t len, olen, set_size;
1405 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 1406 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1406 char *cp, *homedir = NULL, buf[4*4096]; 1407 char *cp, *homedir = NULL, buf[4*4096];
@@ -1414,8 +1415,20 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1414 1415
1415 pw = pwcopy(user_pw); 1416 pw = pwcopy(user_pw);
1416 1417
1417 while (!skipargs && (ch = getopt(argc, argv, "d:f:l:u:cehR")) != -1) { 1418 while (!skipargs && (ch = getopt(argc, argv,
1419 "d:f:l:P:p:Q:u:cehR")) != -1) {
1418 switch (ch) { 1420 switch (ch) {
1421 case 'Q':
1422 if (strcasecmp(optarg, "requests") != 0) {
1423 fprintf(stderr, "Invalid query type\n");
1424 exit(1);
1425 }
1426 for (i = 0; handlers[i].handler != NULL; i++)
1427 printf("%s\n", handlers[i].name);
1428 for (i = 0; extended_handlers[i].handler != NULL; i++)
1429 printf("%s\n", extended_handlers[i].name);
1430 exit(0);
1431 break;
1419 case 'R': 1432 case 'R':
1420 readonly = 1; 1433 readonly = 1;
1421 break; 1434 break;
@@ -1445,6 +1458,16 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1445 "u", user_pw->pw_name, (char *)NULL); 1458 "u", user_pw->pw_name, (char *)NULL);
1446 free(cp); 1459 free(cp);
1447 break; 1460 break;
1461 case 'p':
1462 if (request_whitelist != NULL)
1463 fatal("Permitted requests already set");
1464 request_whitelist = xstrdup(optarg);
1465 break;
1466 case 'P':
1467 if (request_blacklist != NULL)
1468 fatal("Refused requests already set");
1469 request_blacklist = xstrdup(optarg);
1470 break;
1448 case 'u': 1471 case 'u':
1449 errno = 0; 1472 errno = 0;
1450 mask = strtol(optarg, &cp, 8); 1473 mask = strtol(optarg, &cp, 8);