summaryrefslogtreecommitdiff
path: root/sftp-server.c
diff options
context:
space:
mode:
authorDarren Tucker <dtucker@zip.com.au>2010-01-09 22:24:33 +1100
committerDarren Tucker <dtucker@zip.com.au>2010-01-09 22:24:33 +1100
commitdb7bf82544800c21a471a89781466bbf4ac08731 (patch)
treeb60f825b76c1aed4719271205ac96d40529f5f6c /sftp-server.c
parent0b8a2262ac9ee2b2395cf85e3dfa065385c25b5a (diff)
- djm@cvs.openbsd.org 2010/01/09 00:20:26
[sftp-server.c sftp-server.8] add a 'read-only' mode to sftp-server(8) that disables open in write mode and all other fs-modifying protocol methods. bz#430 ok dtucker@
Diffstat (limited to 'sftp-server.c')
-rw-r--r--sftp-server.c103
1 files changed, 74 insertions, 29 deletions
diff --git a/sftp-server.c b/sftp-server.c
index cf4e273f8..ab9391cfd 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-server.c,v 1.89 2010/01/04 02:25:15 djm Exp $ */ 1/* $OpenBSD: sftp-server.c,v 1.90 2010/01/09 00:20:26 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 *
@@ -70,6 +70,9 @@ Buffer oqueue;
70/* Version of client */ 70/* Version of client */
71int version; 71int version;
72 72
73/* Disable writes */
74int readonly;
75
73/* portable attributes, etc. */ 76/* portable attributes, etc. */
74 77
75typedef struct Stat Stat; 78typedef struct Stat Stat;
@@ -553,16 +556,21 @@ process_open(void)
553 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; 556 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
554 logit("open \"%s\" flags %s mode 0%o", 557 logit("open \"%s\" flags %s mode 0%o",
555 name, string_from_portable(pflags), mode); 558 name, string_from_portable(pflags), mode);
556 fd = open(name, flags, mode); 559 if (readonly &&
557 if (fd < 0) { 560 ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR))
558 status = errno_to_portable(errno); 561 status = SSH2_FX_PERMISSION_DENIED;
559 } else { 562 else {
560 handle = handle_new(HANDLE_FILE, name, fd, NULL); 563 fd = open(name, flags, mode);
561 if (handle < 0) { 564 if (fd < 0) {
562 close(fd); 565 status = errno_to_portable(errno);
563 } else { 566 } else {
564 send_handle(id, handle); 567 handle = handle_new(HANDLE_FILE, name, fd, NULL);
565 status = SSH2_FX_OK; 568 if (handle < 0) {
569 close(fd);
570 } else {
571 send_handle(id, handle);
572 status = SSH2_FX_OK;
573 }
566 } 574 }
567 } 575 }
568 if (status != SSH2_FX_OK) 576 if (status != SSH2_FX_OK)
@@ -632,7 +640,7 @@ process_write(void)
632 u_int32_t id; 640 u_int32_t id;
633 u_int64_t off; 641 u_int64_t off;
634 u_int len; 642 u_int len;
635 int handle, fd, ret, status = SSH2_FX_FAILURE; 643 int handle, fd, ret, status;
636 char *data; 644 char *data;
637 645
638 id = get_int(); 646 id = get_int();
@@ -643,7 +651,12 @@ process_write(void)
643 debug("request %u: write \"%s\" (handle %d) off %llu len %d", 651 debug("request %u: write \"%s\" (handle %d) off %llu len %d",
644 id, handle_to_name(handle), handle, (unsigned long long)off, len); 652 id, handle_to_name(handle), handle, (unsigned long long)off, len);
645 fd = handle_to_fd(handle); 653 fd = handle_to_fd(handle);
646 if (fd >= 0) { 654
655 if (fd < 0)
656 status = SSH2_FX_FAILURE;
657 else if (readonly)
658 status = SSH2_FX_PERMISSION_DENIED;
659 else {
647 if (lseek(fd, off, SEEK_SET) < 0) { 660 if (lseek(fd, off, SEEK_SET) < 0) {
648 status = errno_to_portable(errno); 661 status = errno_to_portable(errno);
649 error("process_write: seek failed"); 662 error("process_write: seek failed");
@@ -658,6 +671,7 @@ process_write(void)
658 handle_update_write(handle, ret); 671 handle_update_write(handle, ret);
659 } else { 672 } else {
660 debug2("nothing at all written"); 673 debug2("nothing at all written");
674 status = SSH2_FX_FAILURE;
661 } 675 }
662 } 676 }
663 } 677 }
@@ -754,6 +768,10 @@ process_setstat(void)
754 name = get_string(NULL); 768 name = get_string(NULL);
755 a = get_attrib(); 769 a = get_attrib();
756 debug("request %u: setstat name \"%s\"", id, name); 770 debug("request %u: setstat name \"%s\"", id, name);
771 if (readonly) {
772 status = SSH2_FX_PERMISSION_DENIED;
773 a->flags = 0;
774 }
757 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 775 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
758 logit("set \"%s\" size %llu", 776 logit("set \"%s\" size %llu",
759 name, (unsigned long long)a->size); 777 name, (unsigned long long)a->size);
@@ -802,9 +820,11 @@ process_fsetstat(void)
802 a = get_attrib(); 820 a = get_attrib();
803 debug("request %u: fsetstat handle %d", id, handle); 821 debug("request %u: fsetstat handle %d", id, handle);
804 fd = handle_to_fd(handle); 822 fd = handle_to_fd(handle);
805 if (fd < 0) { 823 if (fd < 0)
806 status = SSH2_FX_FAILURE; 824 status = SSH2_FX_FAILURE;
807 } else { 825 else if (readonly)
826 status = SSH2_FX_PERMISSION_DENIED;
827 else {
808 char *name = handle_to_name(handle); 828 char *name = handle_to_name(handle);
809 829
810 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 830 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
@@ -952,8 +972,12 @@ process_remove(void)
952 name = get_string(NULL); 972 name = get_string(NULL);
953 debug3("request %u: remove", id); 973 debug3("request %u: remove", id);
954 logit("remove name \"%s\"", name); 974 logit("remove name \"%s\"", name);
955 ret = unlink(name); 975 if (readonly)
956 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 976 status = SSH2_FX_PERMISSION_DENIED;
977 else {
978 ret = unlink(name);
979 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
980 }
957 send_status(id, status); 981 send_status(id, status);
958 xfree(name); 982 xfree(name);
959} 983}
@@ -973,8 +997,12 @@ process_mkdir(void)
973 a->perm & 07777 : 0777; 997 a->perm & 07777 : 0777;
974 debug3("request %u: mkdir", id); 998 debug3("request %u: mkdir", id);
975 logit("mkdir name \"%s\" mode 0%o", name, mode); 999 logit("mkdir name \"%s\" mode 0%o", name, mode);
976 ret = mkdir(name, mode); 1000 if (readonly)
977 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 1001 status = SSH2_FX_PERMISSION_DENIED;
1002 else {
1003 ret = mkdir(name, mode);
1004 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1005 }
978 send_status(id, status); 1006 send_status(id, status);
979 xfree(name); 1007 xfree(name);
980} 1008}
@@ -990,8 +1018,12 @@ process_rmdir(void)
990 name = get_string(NULL); 1018 name = get_string(NULL);
991 debug3("request %u: rmdir", id); 1019 debug3("request %u: rmdir", id);
992 logit("rmdir name \"%s\"", name); 1020 logit("rmdir name \"%s\"", name);
993 ret = rmdir(name); 1021 if (readonly)
994 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 1022 status = SSH2_FX_PERMISSION_DENIED;
1023 else {
1024 ret = rmdir(name);
1025 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1026 }
995 send_status(id, status); 1027 send_status(id, status);
996 xfree(name); 1028 xfree(name);
997} 1029}
@@ -1036,7 +1068,9 @@ process_rename(void)
1036 debug3("request %u: rename", id); 1068 debug3("request %u: rename", id);
1037 logit("rename old \"%s\" new \"%s\"", oldpath, newpath); 1069 logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1038 status = SSH2_FX_FAILURE; 1070 status = SSH2_FX_FAILURE;
1039 if (lstat(oldpath, &sb) == -1) 1071 if (readonly)
1072 status = SSH2_FX_PERMISSION_DENIED;
1073 else if (lstat(oldpath, &sb) == -1)
1040 status = errno_to_portable(errno); 1074 status = errno_to_portable(errno);
1041 else if (S_ISREG(sb.st_mode)) { 1075 else if (S_ISREG(sb.st_mode)) {
1042 /* Race-free rename of regular files */ 1076 /* Race-free rename of regular files */
@@ -1120,8 +1154,12 @@ process_symlink(void)
1120 debug3("request %u: symlink", id); 1154 debug3("request %u: symlink", id);
1121 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath); 1155 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1122 /* this will fail if 'newpath' exists */ 1156 /* this will fail if 'newpath' exists */
1123 ret = symlink(oldpath, newpath); 1157 if (readonly)
1124 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 1158 status = SSH2_FX_PERMISSION_DENIED;
1159 else {
1160 ret = symlink(oldpath, newpath);
1161 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1162 }
1125 send_status(id, status); 1163 send_status(id, status);
1126 xfree(oldpath); 1164 xfree(oldpath);
1127 xfree(newpath); 1165 xfree(newpath);
@@ -1131,15 +1169,19 @@ static void
1131process_extended_posix_rename(u_int32_t id) 1169process_extended_posix_rename(u_int32_t id)
1132{ 1170{
1133 char *oldpath, *newpath; 1171 char *oldpath, *newpath;
1172 int ret, status;
1134 1173
1135 oldpath = get_string(NULL); 1174 oldpath = get_string(NULL);
1136 newpath = get_string(NULL); 1175 newpath = get_string(NULL);
1137 debug3("request %u: posix-rename", id); 1176 debug3("request %u: posix-rename", id);
1138 logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath); 1177 logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1139 if (rename(oldpath, newpath) == -1) 1178 if (readonly)
1140 send_status(id, errno_to_portable(errno)); 1179 status = SSH2_FX_PERMISSION_DENIED;
1141 else 1180 else {
1142 send_status(id, SSH2_FX_OK); 1181 ret = rename(oldpath, newpath);
1182 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1183 }
1184 send_status(id, status);
1143 xfree(oldpath); 1185 xfree(oldpath);
1144 xfree(newpath); 1186 xfree(newpath);
1145} 1187}
@@ -1322,7 +1364,7 @@ sftp_server_usage(void)
1322 extern char *__progname; 1364 extern char *__progname;
1323 1365
1324 fprintf(stderr, 1366 fprintf(stderr,
1325 "usage: %s [-eh] [-f log_facility] [-l log_level] [-u umask]\n", 1367 "usage: %s [-ehR] [-f log_facility] [-l log_level] [-u umask]\n",
1326 __progname); 1368 __progname);
1327 exit(1); 1369 exit(1);
1328} 1370}
@@ -1344,8 +1386,11 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1344 __progname = ssh_get_progname(argv[0]); 1386 __progname = ssh_get_progname(argv[0]);
1345 log_init(__progname, log_level, log_facility, log_stderr); 1387 log_init(__progname, log_level, log_facility, log_stderr);
1346 1388
1347 while (!skipargs && (ch = getopt(argc, argv, "f:l:u:che")) != -1) { 1389 while (!skipargs && (ch = getopt(argc, argv, "f:l:u:cehR")) != -1) {
1348 switch (ch) { 1390 switch (ch) {
1391 case 'R':
1392 readonly = 1;
1393 break;
1349 case 'c': 1394 case 'c':
1350 /* 1395 /*
1351 * Ignore all arguments if we are invoked as a 1396 * Ignore all arguments if we are invoked as a