summaryrefslogtreecommitdiff
path: root/sftp-server.c
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 /sftp-server.c
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@
Diffstat (limited to 'sftp-server.c')
-rw-r--r--sftp-server.c403
1 files changed, 213 insertions, 190 deletions
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);