summaryrefslogtreecommitdiff
path: root/sftp-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp-server.c')
-rw-r--r--sftp-server.c458
1 files changed, 260 insertions, 198 deletions
diff --git a/sftp-server.c b/sftp-server.c
index 285f21aaf..b8eb59c36 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.103 2014/01/17 06:23:24 dtucker 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,102 @@ 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_fsync(u_int32_t id);
116static void process_extended(u_int32_t id);
117
118struct sftp_handler {
119 const char *name; /* user-visible name for fine-grained perms */
120 const char *ext_name; /* extended request name */
121 u_int type; /* packet type, for non extended packets */
122 void (*handler)(u_int32_t);
123 int does_write; /* if nonzero, banned for readonly mode */
124};
125
126struct sftp_handler handlers[] = {
127 /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */
128 { "open", NULL, SSH2_FXP_OPEN, process_open, 0 },
129 { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 },
130 { "read", NULL, SSH2_FXP_READ, process_read, 0 },
131 { "write", NULL, SSH2_FXP_WRITE, process_write, 1 },
132 { "lstat", NULL, SSH2_FXP_LSTAT, process_lstat, 0 },
133 { "fstat", NULL, SSH2_FXP_FSTAT, process_fstat, 0 },
134 { "setstat", NULL, SSH2_FXP_SETSTAT, process_setstat, 1 },
135 { "fsetstat", NULL, SSH2_FXP_FSETSTAT, process_fsetstat, 1 },
136 { "opendir", NULL, SSH2_FXP_OPENDIR, process_opendir, 0 },
137 { "readdir", NULL, SSH2_FXP_READDIR, process_readdir, 0 },
138 { "remove", NULL, SSH2_FXP_REMOVE, process_remove, 1 },
139 { "mkdir", NULL, SSH2_FXP_MKDIR, process_mkdir, 1 },
140 { "rmdir", NULL, SSH2_FXP_RMDIR, process_rmdir, 1 },
141 { "realpath", NULL, SSH2_FXP_REALPATH, process_realpath, 0 },
142 { "stat", NULL, SSH2_FXP_STAT, process_stat, 0 },
143 { "rename", NULL, SSH2_FXP_RENAME, process_rename, 1 },
144 { "readlink", NULL, SSH2_FXP_READLINK, process_readlink, 0 },
145 { "symlink", NULL, SSH2_FXP_SYMLINK, process_symlink, 1 },
146 { NULL, NULL, 0, NULL, 0 }
147};
148
149/* SSH2_FXP_EXTENDED submessages */
150struct sftp_handler extended_handlers[] = {
151 { "posix-rename", "posix-rename@openssh.com", 0,
152 process_extended_posix_rename, 1 },
153 { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
154 { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
155 { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
156 { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
157 { NULL, NULL, 0, NULL, 0 }
158};
159
160static int
161request_permitted(struct sftp_handler *h)
162{
163 char *result;
164
165 if (readonly && h->does_write) {
166 verbose("Refusing %s request in read-only mode", h->name);
167 return 0;
168 }
169 if (request_blacklist != NULL &&
170 ((result = match_list(h->name, request_blacklist, NULL))) != NULL) {
171 free(result);
172 verbose("Refusing blacklisted %s request", h->name);
173 return 0;
174 }
175 if (request_whitelist != NULL &&
176 ((result = match_list(h->name, request_whitelist, NULL))) != NULL) {
177 free(result);
178 debug2("Permitting whitelisted %s request", h->name);
179 return 1;
180 }
181 if (request_whitelist != NULL) {
182 verbose("Refusing non-whitelisted %s request", h->name);
183 return 0;
184 }
185 return 1;
186}
187
86static int 188static int
87errno_to_portable(int unixerrno) 189errno_to_portable(int unixerrno)
88{ 190{
@@ -130,6 +232,8 @@ flags_from_portable(int pflags)
130 } else if (pflags & SSH2_FXF_WRITE) { 232 } else if (pflags & SSH2_FXF_WRITE) {
131 flags = O_WRONLY; 233 flags = O_WRONLY;
132 } 234 }
235 if (pflags & SSH2_FXF_APPEND)
236 flags |= O_APPEND;
133 if (pflags & SSH2_FXF_CREAT) 237 if (pflags & SSH2_FXF_CREAT)
134 flags |= O_CREAT; 238 flags |= O_CREAT;
135 if (pflags & SSH2_FXF_TRUNC) 239 if (pflags & SSH2_FXF_TRUNC)
@@ -156,6 +260,8 @@ string_from_portable(int pflags)
156 PAPPEND("READ") 260 PAPPEND("READ")
157 if (pflags & SSH2_FXF_WRITE) 261 if (pflags & SSH2_FXF_WRITE)
158 PAPPEND("WRITE") 262 PAPPEND("WRITE")
263 if (pflags & SSH2_FXF_APPEND)
264 PAPPEND("APPEND")
159 if (pflags & SSH2_FXF_CREAT) 265 if (pflags & SSH2_FXF_CREAT)
160 PAPPEND("CREATE") 266 PAPPEND("CREATE")
161 if (pflags & SSH2_FXF_TRUNC) 267 if (pflags & SSH2_FXF_TRUNC)
@@ -179,6 +285,7 @@ struct Handle {
179 int use; 285 int use;
180 DIR *dirp; 286 DIR *dirp;
181 int fd; 287 int fd;
288 int flags;
182 char *name; 289 char *name;
183 u_int64_t bytes_read, bytes_write; 290 u_int64_t bytes_read, bytes_write;
184 int next_unused; 291 int next_unused;
@@ -202,7 +309,7 @@ static void handle_unused(int i)
202} 309}
203 310
204static int 311static int
205handle_new(int use, const char *name, int fd, DIR *dirp) 312handle_new(int use, const char *name, int fd, int flags, DIR *dirp)
206{ 313{
207 int i; 314 int i;
208 315
@@ -220,6 +327,7 @@ handle_new(int use, const char *name, int fd, DIR *dirp)
220 handles[i].use = use; 327 handles[i].use = use;
221 handles[i].dirp = dirp; 328 handles[i].dirp = dirp;
222 handles[i].fd = fd; 329 handles[i].fd = fd;
330 handles[i].flags = flags;
223 handles[i].name = xstrdup(name); 331 handles[i].name = xstrdup(name);
224 handles[i].bytes_read = handles[i].bytes_write = 0; 332 handles[i].bytes_read = handles[i].bytes_write = 0;
225 333
@@ -282,6 +390,14 @@ handle_to_fd(int handle)
282 return -1; 390 return -1;
283} 391}
284 392
393static int
394handle_to_flags(int handle)
395{
396 if (handle_is_ok(handle, HANDLE_FILE))
397 return handles[handle].flags;
398 return 0;
399}
400
285static void 401static void
286handle_update_read(int handle, ssize_t bytes) 402handle_update_read(int handle, ssize_t bytes)
287{ 403{
@@ -538,19 +654,21 @@ process_init(void)
538 /* hardlink extension */ 654 /* hardlink extension */
539 buffer_put_cstring(&msg, "hardlink@openssh.com"); 655 buffer_put_cstring(&msg, "hardlink@openssh.com");
540 buffer_put_cstring(&msg, "1"); /* version */ 656 buffer_put_cstring(&msg, "1"); /* version */
657 /* fsync extension */
658 buffer_put_cstring(&msg, "fsync@openssh.com");
659 buffer_put_cstring(&msg, "1"); /* version */
541 send_msg(&msg); 660 send_msg(&msg);
542 buffer_free(&msg); 661 buffer_free(&msg);
543} 662}
544 663
545static void 664static void
546process_open(void) 665process_open(u_int32_t id)
547{ 666{
548 u_int32_t id, pflags; 667 u_int32_t pflags;
549 Attrib *a; 668 Attrib *a;
550 char *name; 669 char *name;
551 int handle, fd, flags, mode, status = SSH2_FX_FAILURE; 670 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
552 671
553 id = get_int();
554 name = get_string(NULL); 672 name = get_string(NULL);
555 pflags = get_int(); /* portable flags */ 673 pflags = get_int(); /* portable flags */
556 debug3("request %u: open flags %d", id, pflags); 674 debug3("request %u: open flags %d", id, pflags);
@@ -560,14 +678,16 @@ process_open(void)
560 logit("open \"%s\" flags %s mode 0%o", 678 logit("open \"%s\" flags %s mode 0%o",
561 name, string_from_portable(pflags), mode); 679 name, string_from_portable(pflags), mode);
562 if (readonly && 680 if (readonly &&
563 ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR)) 681 ((flags & O_ACCMODE) == O_WRONLY ||
564 status = SSH2_FX_PERMISSION_DENIED; 682 (flags & O_ACCMODE) == O_RDWR)) {
565 else { 683 verbose("Refusing open request in read-only mode");
684 status = SSH2_FX_PERMISSION_DENIED;
685 } else {
566 fd = open(name, flags, mode); 686 fd = open(name, flags, mode);
567 if (fd < 0) { 687 if (fd < 0) {
568 status = errno_to_portable(errno); 688 status = errno_to_portable(errno);
569 } else { 689 } else {
570 handle = handle_new(HANDLE_FILE, name, fd, NULL); 690 handle = handle_new(HANDLE_FILE, name, fd, flags, NULL);
571 if (handle < 0) { 691 if (handle < 0) {
572 close(fd); 692 close(fd);
573 } else { 693 } else {
@@ -582,12 +702,10 @@ process_open(void)
582} 702}
583 703
584static void 704static void
585process_close(void) 705process_close(u_int32_t id)
586{ 706{
587 u_int32_t id;
588 int handle, ret, status = SSH2_FX_FAILURE; 707 int handle, ret, status = SSH2_FX_FAILURE;
589 708
590 id = get_int();
591 handle = get_handle(); 709 handle = get_handle();
592 debug3("request %u: close handle %u", id, handle); 710 debug3("request %u: close handle %u", id, handle);
593 handle_log_close(handle, NULL); 711 handle_log_close(handle, NULL);
@@ -597,14 +715,13 @@ process_close(void)
597} 715}
598 716
599static void 717static void
600process_read(void) 718process_read(u_int32_t id)
601{ 719{
602 char buf[64*1024]; 720 char buf[64*1024];
603 u_int32_t id, len; 721 u_int32_t len;
604 int handle, fd, ret, status = SSH2_FX_FAILURE; 722 int handle, fd, ret, status = SSH2_FX_FAILURE;
605 u_int64_t off; 723 u_int64_t off;
606 724
607 id = get_int();
608 handle = get_handle(); 725 handle = get_handle();
609 off = get_int64(); 726 off = get_int64();
610 len = get_int(); 727 len = get_int();
@@ -638,15 +755,13 @@ process_read(void)
638} 755}
639 756
640static void 757static void
641process_write(void) 758process_write(u_int32_t id)
642{ 759{
643 u_int32_t id;
644 u_int64_t off; 760 u_int64_t off;
645 u_int len; 761 u_int len;
646 int handle, fd, ret, status; 762 int handle, fd, ret, status;
647 char *data; 763 char *data;
648 764
649 id = get_int();
650 handle = get_handle(); 765 handle = get_handle();
651 off = get_int64(); 766 off = get_int64();
652 data = get_string(&len); 767 data = get_string(&len);
@@ -657,10 +772,9 @@ process_write(void)
657 772
658 if (fd < 0) 773 if (fd < 0)
659 status = SSH2_FX_FAILURE; 774 status = SSH2_FX_FAILURE;
660 else if (readonly)
661 status = SSH2_FX_PERMISSION_DENIED;
662 else { 775 else {
663 if (lseek(fd, off, SEEK_SET) < 0) { 776 if (!(handle_to_flags(handle) & O_APPEND) &&
777 lseek(fd, off, SEEK_SET) < 0) {
664 status = errno_to_portable(errno); 778 status = errno_to_portable(errno);
665 error("process_write: seek failed"); 779 error("process_write: seek failed");
666 } else { 780 } else {
@@ -683,15 +797,13 @@ process_write(void)
683} 797}
684 798
685static void 799static void
686process_do_stat(int do_lstat) 800process_do_stat(u_int32_t id, int do_lstat)
687{ 801{
688 Attrib a; 802 Attrib a;
689 struct stat st; 803 struct stat st;
690 u_int32_t id;
691 char *name; 804 char *name;
692 int ret, status = SSH2_FX_FAILURE; 805 int ret, status = SSH2_FX_FAILURE;
693 806
694 id = get_int();
695 name = get_string(NULL); 807 name = get_string(NULL);
696 debug3("request %u: %sstat", id, do_lstat ? "l" : ""); 808 debug3("request %u: %sstat", id, do_lstat ? "l" : "");
697 verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name); 809 verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
@@ -709,26 +821,24 @@ process_do_stat(int do_lstat)
709} 821}
710 822
711static void 823static void
712process_stat(void) 824process_stat(u_int32_t id)
713{ 825{
714 process_do_stat(0); 826 process_do_stat(id, 0);
715} 827}
716 828
717static void 829static void
718process_lstat(void) 830process_lstat(u_int32_t id)
719{ 831{
720 process_do_stat(1); 832 process_do_stat(id, 1);
721} 833}
722 834
723static void 835static void
724process_fstat(void) 836process_fstat(u_int32_t id)
725{ 837{
726 Attrib a; 838 Attrib a;
727 struct stat st; 839 struct stat st;
728 u_int32_t id;
729 int fd, ret, handle, status = SSH2_FX_FAILURE; 840 int fd, ret, handle, status = SSH2_FX_FAILURE;
730 841
731 id = get_int();
732 handle = get_handle(); 842 handle = get_handle();
733 debug("request %u: fstat \"%s\" (handle %u)", 843 debug("request %u: fstat \"%s\" (handle %u)",
734 id, handle_to_name(handle), handle); 844 id, handle_to_name(handle), handle);
@@ -760,21 +870,15 @@ attrib_to_tv(const Attrib *a)
760} 870}
761 871
762static void 872static void
763process_setstat(void) 873process_setstat(u_int32_t id)
764{ 874{
765 Attrib *a; 875 Attrib *a;
766 u_int32_t id;
767 char *name; 876 char *name;
768 int status = SSH2_FX_OK, ret; 877 int status = SSH2_FX_OK, ret;
769 878
770 id = get_int();
771 name = get_string(NULL); 879 name = get_string(NULL);
772 a = get_attrib(); 880 a = get_attrib();
773 debug("request %u: setstat name \"%s\"", id, name); 881 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) { 882 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
779 logit("set \"%s\" size %llu", 883 logit("set \"%s\" size %llu",
780 name, (unsigned long long)a->size); 884 name, (unsigned long long)a->size);
@@ -811,22 +915,18 @@ process_setstat(void)
811} 915}
812 916
813static void 917static void
814process_fsetstat(void) 918process_fsetstat(u_int32_t id)
815{ 919{
816 Attrib *a; 920 Attrib *a;
817 u_int32_t id;
818 int handle, fd, ret; 921 int handle, fd, ret;
819 int status = SSH2_FX_OK; 922 int status = SSH2_FX_OK;
820 923
821 id = get_int();
822 handle = get_handle(); 924 handle = get_handle();
823 a = get_attrib(); 925 a = get_attrib();
824 debug("request %u: fsetstat handle %d", id, handle); 926 debug("request %u: fsetstat handle %d", id, handle);
825 fd = handle_to_fd(handle); 927 fd = handle_to_fd(handle);
826 if (fd < 0) 928 if (fd < 0)
827 status = SSH2_FX_FAILURE; 929 status = SSH2_FX_FAILURE;
828 else if (readonly)
829 status = SSH2_FX_PERMISSION_DENIED;
830 else { 930 else {
831 char *name = handle_to_name(handle); 931 char *name = handle_to_name(handle);
832 932
@@ -878,14 +978,12 @@ process_fsetstat(void)
878} 978}
879 979
880static void 980static void
881process_opendir(void) 981process_opendir(u_int32_t id)
882{ 982{
883 DIR *dirp = NULL; 983 DIR *dirp = NULL;
884 char *path; 984 char *path;
885 int handle, status = SSH2_FX_FAILURE; 985 int handle, status = SSH2_FX_FAILURE;
886 u_int32_t id;
887 986
888 id = get_int();
889 path = get_string(NULL); 987 path = get_string(NULL);
890 debug3("request %u: opendir", id); 988 debug3("request %u: opendir", id);
891 logit("opendir \"%s\"", path); 989 logit("opendir \"%s\"", path);
@@ -893,7 +991,7 @@ process_opendir(void)
893 if (dirp == NULL) { 991 if (dirp == NULL) {
894 status = errno_to_portable(errno); 992 status = errno_to_portable(errno);
895 } else { 993 } else {
896 handle = handle_new(HANDLE_DIR, path, 0, dirp); 994 handle = handle_new(HANDLE_DIR, path, 0, 0, dirp);
897 if (handle < 0) { 995 if (handle < 0) {
898 closedir(dirp); 996 closedir(dirp);
899 } else { 997 } else {
@@ -908,15 +1006,13 @@ process_opendir(void)
908} 1006}
909 1007
910static void 1008static void
911process_readdir(void) 1009process_readdir(u_int32_t id)
912{ 1010{
913 DIR *dirp; 1011 DIR *dirp;
914 struct dirent *dp; 1012 struct dirent *dp;
915 char *path; 1013 char *path;
916 int handle; 1014 int handle;
917 u_int32_t id;
918 1015
919 id = get_int();
920 handle = get_handle(); 1016 handle = get_handle();
921 debug("request %u: readdir \"%s\" (handle %d)", id, 1017 debug("request %u: readdir \"%s\" (handle %d)", id,
922 handle_to_name(handle), handle); 1018 handle_to_name(handle), handle);
@@ -964,81 +1060,61 @@ process_readdir(void)
964} 1060}
965 1061
966static void 1062static void
967process_remove(void) 1063process_remove(u_int32_t id)
968{ 1064{
969 char *name; 1065 char *name;
970 u_int32_t id;
971 int status = SSH2_FX_FAILURE; 1066 int status = SSH2_FX_FAILURE;
972 int ret; 1067 int ret;
973 1068
974 id = get_int();
975 name = get_string(NULL); 1069 name = get_string(NULL);
976 debug3("request %u: remove", id); 1070 debug3("request %u: remove", id);
977 logit("remove name \"%s\"", name); 1071 logit("remove name \"%s\"", name);
978 if (readonly) 1072 ret = unlink(name);
979 status = SSH2_FX_PERMISSION_DENIED; 1073 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); 1074 send_status(id, status);
985 free(name); 1075 free(name);
986} 1076}
987 1077
988static void 1078static void
989process_mkdir(void) 1079process_mkdir(u_int32_t id)
990{ 1080{
991 Attrib *a; 1081 Attrib *a;
992 u_int32_t id;
993 char *name; 1082 char *name;
994 int ret, mode, status = SSH2_FX_FAILURE; 1083 int ret, mode, status = SSH2_FX_FAILURE;
995 1084
996 id = get_int();
997 name = get_string(NULL); 1085 name = get_string(NULL);
998 a = get_attrib(); 1086 a = get_attrib();
999 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? 1087 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
1000 a->perm & 07777 : 0777; 1088 a->perm & 07777 : 0777;
1001 debug3("request %u: mkdir", id); 1089 debug3("request %u: mkdir", id);
1002 logit("mkdir name \"%s\" mode 0%o", name, mode); 1090 logit("mkdir name \"%s\" mode 0%o", name, mode);
1003 if (readonly) 1091 ret = mkdir(name, mode);
1004 status = SSH2_FX_PERMISSION_DENIED; 1092 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); 1093 send_status(id, status);
1010 free(name); 1094 free(name);
1011} 1095}
1012 1096
1013static void 1097static void
1014process_rmdir(void) 1098process_rmdir(u_int32_t id)
1015{ 1099{
1016 u_int32_t id;
1017 char *name; 1100 char *name;
1018 int ret, status; 1101 int ret, status;
1019 1102
1020 id = get_int();
1021 name = get_string(NULL); 1103 name = get_string(NULL);
1022 debug3("request %u: rmdir", id); 1104 debug3("request %u: rmdir", id);
1023 logit("rmdir name \"%s\"", name); 1105 logit("rmdir name \"%s\"", name);
1024 if (readonly) 1106 ret = rmdir(name);
1025 status = SSH2_FX_PERMISSION_DENIED; 1107 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); 1108 send_status(id, status);
1031 free(name); 1109 free(name);
1032} 1110}
1033 1111
1034static void 1112static void
1035process_realpath(void) 1113process_realpath(u_int32_t id)
1036{ 1114{
1037 char resolvedname[MAXPATHLEN]; 1115 char resolvedname[MAXPATHLEN];
1038 u_int32_t id;
1039 char *path; 1116 char *path;
1040 1117
1041 id = get_int();
1042 path = get_string(NULL); 1118 path = get_string(NULL);
1043 if (path[0] == '\0') { 1119 if (path[0] == '\0') {
1044 free(path); 1120 free(path);
@@ -1058,22 +1134,18 @@ process_realpath(void)
1058} 1134}
1059 1135
1060static void 1136static void
1061process_rename(void) 1137process_rename(u_int32_t id)
1062{ 1138{
1063 u_int32_t id;
1064 char *oldpath, *newpath; 1139 char *oldpath, *newpath;
1065 int status; 1140 int status;
1066 struct stat sb; 1141 struct stat sb;
1067 1142
1068 id = get_int();
1069 oldpath = get_string(NULL); 1143 oldpath = get_string(NULL);
1070 newpath = get_string(NULL); 1144 newpath = get_string(NULL);
1071 debug3("request %u: rename", id); 1145 debug3("request %u: rename", id);
1072 logit("rename old \"%s\" new \"%s\"", oldpath, newpath); 1146 logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1073 status = SSH2_FX_FAILURE; 1147 status = SSH2_FX_FAILURE;
1074 if (readonly) 1148 if (lstat(oldpath, &sb) == -1)
1075 status = SSH2_FX_PERMISSION_DENIED;
1076 else if (lstat(oldpath, &sb) == -1)
1077 status = errno_to_portable(errno); 1149 status = errno_to_portable(errno);
1078 else if (S_ISREG(sb.st_mode)) { 1150 else if (S_ISREG(sb.st_mode)) {
1079 /* Race-free rename of regular files */ 1151 /* Race-free rename of regular files */
@@ -1120,14 +1192,12 @@ process_rename(void)
1120} 1192}
1121 1193
1122static void 1194static void
1123process_readlink(void) 1195process_readlink(u_int32_t id)
1124{ 1196{
1125 u_int32_t id;
1126 int len; 1197 int len;
1127 char buf[MAXPATHLEN]; 1198 char buf[MAXPATHLEN];
1128 char *path; 1199 char *path;
1129 1200
1130 id = get_int();
1131 path = get_string(NULL); 1201 path = get_string(NULL);
1132 debug3("request %u: readlink", id); 1202 debug3("request %u: readlink", id);
1133 verbose("readlink \"%s\"", path); 1203 verbose("readlink \"%s\"", path);
@@ -1145,24 +1215,18 @@ process_readlink(void)
1145} 1215}
1146 1216
1147static void 1217static void
1148process_symlink(void) 1218process_symlink(u_int32_t id)
1149{ 1219{
1150 u_int32_t id;
1151 char *oldpath, *newpath; 1220 char *oldpath, *newpath;
1152 int ret, status; 1221 int ret, status;
1153 1222
1154 id = get_int();
1155 oldpath = get_string(NULL); 1223 oldpath = get_string(NULL);
1156 newpath = get_string(NULL); 1224 newpath = get_string(NULL);
1157 debug3("request %u: symlink", id); 1225 debug3("request %u: symlink", id);
1158 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath); 1226 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1159 /* this will fail if 'newpath' exists */ 1227 /* this will fail if 'newpath' exists */
1160 if (readonly) 1228 ret = symlink(oldpath, newpath);
1161 status = SSH2_FX_PERMISSION_DENIED; 1229 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); 1230 send_status(id, status);
1167 free(oldpath); 1231 free(oldpath);
1168 free(newpath); 1232 free(newpath);
@@ -1178,12 +1242,8 @@ process_extended_posix_rename(u_int32_t id)
1178 newpath = get_string(NULL); 1242 newpath = get_string(NULL);
1179 debug3("request %u: posix-rename", id); 1243 debug3("request %u: posix-rename", id);
1180 logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath); 1244 logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1181 if (readonly) 1245 ret = rename(oldpath, newpath);
1182 status = SSH2_FX_PERMISSION_DENIED; 1246 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); 1247 send_status(id, status);
1188 free(oldpath); 1248 free(oldpath);
1189 free(newpath); 1249 free(newpath);
@@ -1196,8 +1256,8 @@ process_extended_statvfs(u_int32_t id)
1196 struct statvfs st; 1256 struct statvfs st;
1197 1257
1198 path = get_string(NULL); 1258 path = get_string(NULL);
1199 debug3("request %u: statfs", id); 1259 debug3("request %u: statvfs", id);
1200 logit("statfs \"%s\"", path); 1260 logit("statvfs \"%s\"", path);
1201 1261
1202 if (statvfs(path, &st) != 0) 1262 if (statvfs(path, &st) != 0)
1203 send_status(id, errno_to_portable(errno)); 1263 send_status(id, errno_to_portable(errno));
@@ -1235,35 +1295,50 @@ process_extended_hardlink(u_int32_t id)
1235 newpath = get_string(NULL); 1295 newpath = get_string(NULL);
1236 debug3("request %u: hardlink", id); 1296 debug3("request %u: hardlink", id);
1237 logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath); 1297 logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1238 if (readonly) 1298 ret = link(oldpath, newpath);
1239 status = SSH2_FX_PERMISSION_DENIED; 1299 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); 1300 send_status(id, status);
1245 free(oldpath); 1301 free(oldpath);
1246 free(newpath); 1302 free(newpath);
1247} 1303}
1248 1304
1249static void 1305static void
1250process_extended(void) 1306process_extended_fsync(u_int32_t id)
1307{
1308 int handle, fd, ret, status = SSH2_FX_OP_UNSUPPORTED;
1309
1310 handle = get_handle();
1311 debug3("request %u: fsync (handle %u)", id, handle);
1312 verbose("fsync \"%s\"", handle_to_name(handle));
1313 if ((fd = handle_to_fd(handle)) < 0)
1314 status = SSH2_FX_NO_SUCH_FILE;
1315 else if (handle_is_ok(handle, HANDLE_FILE)) {
1316 ret = fsync(fd);
1317 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1318 }
1319 send_status(id, status);
1320}
1321
1322static void
1323process_extended(u_int32_t id)
1251{ 1324{
1252 u_int32_t id;
1253 char *request; 1325 char *request;
1326 u_int i;
1254 1327
1255 id = get_int();
1256 request = get_string(NULL); 1328 request = get_string(NULL);
1257 if (strcmp(request, "posix-rename@openssh.com") == 0) 1329 for (i = 0; extended_handlers[i].handler != NULL; i++) {
1258 process_extended_posix_rename(id); 1330 if (strcmp(request, extended_handlers[i].ext_name) == 0) {
1259 else if (strcmp(request, "statvfs@openssh.com") == 0) 1331 if (!request_permitted(&extended_handlers[i]))
1260 process_extended_statvfs(id); 1332 send_status(id, SSH2_FX_PERMISSION_DENIED);
1261 else if (strcmp(request, "fstatvfs@openssh.com") == 0) 1333 else
1262 process_extended_fstatvfs(id); 1334 extended_handlers[i].handler(id);
1263 else if (strcmp(request, "hardlink@openssh.com") == 0) 1335 break;
1264 process_extended_hardlink(id); 1336 }
1265 else 1337 }
1338 if (extended_handlers[i].handler == NULL) {
1339 error("Unknown extended request \"%.100s\"", request);
1266 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ 1340 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
1341 }
1267 free(request); 1342 free(request);
1268} 1343}
1269 1344
@@ -1272,11 +1347,9 @@ process_extended(void)
1272static void 1347static void
1273process(void) 1348process(void)
1274{ 1349{
1275 u_int msg_len; 1350 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; 1351 u_char *cp;
1352 u_int32_t id;
1280 1353
1281 buf_len = buffer_len(&iqueue); 1354 buf_len = buffer_len(&iqueue);
1282 if (buf_len < 5) 1355 if (buf_len < 5)
@@ -1293,70 +1366,35 @@ process(void)
1293 buffer_consume(&iqueue, 4); 1366 buffer_consume(&iqueue, 4);
1294 buf_len -= 4; 1367 buf_len -= 4;
1295 type = buffer_get_char(&iqueue); 1368 type = buffer_get_char(&iqueue);
1369
1296 switch (type) { 1370 switch (type) {
1297 case SSH2_FXP_INIT: 1371 case SSH2_FXP_INIT:
1298 process_init(); 1372 process_init();
1299 break; 1373 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; 1374 break;
1354 case SSH2_FXP_EXTENDED: 1375 case SSH2_FXP_EXTENDED:
1355 process_extended(); 1376 if (!init_done)
1377 fatal("Received extended request before init");
1378 id = get_int();
1379 process_extended(id);
1356 break; 1380 break;
1357 default: 1381 default:
1358 error("Unknown message %d", type); 1382 if (!init_done)
1359 break; 1383 fatal("Received %u request before init", type);
1384 id = get_int();
1385 for (i = 0; handlers[i].handler != NULL; i++) {
1386 if (type == handlers[i].type) {
1387 if (!request_permitted(&handlers[i])) {
1388 send_status(id,
1389 SSH2_FX_PERMISSION_DENIED);
1390 } else {
1391 handlers[i].handler(id);
1392 }
1393 break;
1394 }
1395 }
1396 if (handlers[i].handler == NULL)
1397 error("Unknown message %u", type);
1360 } 1398 }
1361 /* discard the remaining bytes from the current packet */ 1399 /* discard the remaining bytes from the current packet */
1362 if (buf_len < buffer_len(&iqueue)) { 1400 if (buf_len < buffer_len(&iqueue)) {
@@ -1365,7 +1403,7 @@ process(void)
1365 } 1403 }
1366 consumed = buf_len - buffer_len(&iqueue); 1404 consumed = buf_len - buffer_len(&iqueue);
1367 if (msg_len < consumed) { 1405 if (msg_len < consumed) {
1368 error("msg_len %d < consumed %d", msg_len, consumed); 1406 error("msg_len %u < consumed %u", msg_len, consumed);
1369 sftp_server_cleanup_exit(255); 1407 sftp_server_cleanup_exit(255);
1370 } 1408 }
1371 if (msg_len > consumed) 1409 if (msg_len > consumed)
@@ -1391,8 +1429,10 @@ sftp_server_usage(void)
1391 1429
1392 fprintf(stderr, 1430 fprintf(stderr,
1393 "usage: %s [-ehR] [-d start_directory] [-f log_facility] " 1431 "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
1394 "[-l log_level]\n\t[-u umask]\n", 1432 "[-l log_level]\n\t[-P blacklisted_requests] "
1395 __progname); 1433 "[-p whitelisted_requests] [-u umask]\n"
1434 " %s -Q protocol_feature\n",
1435 __progname, __progname);
1396 exit(1); 1436 exit(1);
1397} 1437}
1398 1438
@@ -1400,7 +1440,7 @@ int
1400sftp_server_main(int argc, char **argv, struct passwd *user_pw) 1440sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1401{ 1441{
1402 fd_set *rset, *wset; 1442 fd_set *rset, *wset;
1403 int in, out, max, ch, skipargs = 0, log_stderr = 0; 1443 int i, in, out, max, ch, skipargs = 0, log_stderr = 0;
1404 ssize_t len, olen, set_size; 1444 ssize_t len, olen, set_size;
1405 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 1445 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1406 char *cp, *homedir = NULL, buf[4*4096]; 1446 char *cp, *homedir = NULL, buf[4*4096];
@@ -1414,8 +1454,20 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1414 1454
1415 pw = pwcopy(user_pw); 1455 pw = pwcopy(user_pw);
1416 1456
1417 while (!skipargs && (ch = getopt(argc, argv, "d:f:l:u:cehR")) != -1) { 1457 while (!skipargs && (ch = getopt(argc, argv,
1458 "d:f:l:P:p:Q:u:cehR")) != -1) {
1418 switch (ch) { 1459 switch (ch) {
1460 case 'Q':
1461 if (strcasecmp(optarg, "requests") != 0) {
1462 fprintf(stderr, "Invalid query type\n");
1463 exit(1);
1464 }
1465 for (i = 0; handlers[i].handler != NULL; i++)
1466 printf("%s\n", handlers[i].name);
1467 for (i = 0; extended_handlers[i].handler != NULL; i++)
1468 printf("%s\n", extended_handlers[i].name);
1469 exit(0);
1470 break;
1419 case 'R': 1471 case 'R':
1420 readonly = 1; 1472 readonly = 1;
1421 break; 1473 break;
@@ -1445,6 +1497,16 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1445 "u", user_pw->pw_name, (char *)NULL); 1497 "u", user_pw->pw_name, (char *)NULL);
1446 free(cp); 1498 free(cp);
1447 break; 1499 break;
1500 case 'p':
1501 if (request_whitelist != NULL)
1502 fatal("Permitted requests already set");
1503 request_whitelist = xstrdup(optarg);
1504 break;
1505 case 'P':
1506 if (request_blacklist != NULL)
1507 fatal("Refused requests already set");
1508 request_blacklist = xstrdup(optarg);
1509 break;
1448 case 'u': 1510 case 'u':
1449 errno = 0; 1511 errno = 0;
1450 mask = strtol(optarg, &cp, 8); 1512 mask = strtol(optarg, &cp, 8);