diff options
author | Darren Tucker <dtucker@zip.com.au> | 2010-01-09 22:24:33 +1100 |
---|---|---|
committer | Darren Tucker <dtucker@zip.com.au> | 2010-01-09 22:24:33 +1100 |
commit | db7bf82544800c21a471a89781466bbf4ac08731 (patch) | |
tree | b60f825b76c1aed4719271205ac96d40529f5f6c /sftp-server.c | |
parent | 0b8a2262ac9ee2b2395cf85e3dfa065385c25b5a (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.c | 103 |
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 */ |
71 | int version; | 71 | int version; |
72 | 72 | ||
73 | /* Disable writes */ | ||
74 | int readonly; | ||
75 | |||
73 | /* portable attributes, etc. */ | 76 | /* portable attributes, etc. */ |
74 | 77 | ||
75 | typedef struct Stat Stat; | 78 | typedef 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 | |||
1131 | process_extended_posix_rename(u_int32_t id) | 1169 | process_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 |