summaryrefslogtreecommitdiff
path: root/sftp-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp-server.c')
-rw-r--r--sftp-server.c119
1 files changed, 87 insertions, 32 deletions
diff --git a/sftp-server.c b/sftp-server.c
index d984e6049..a98ac2b6d 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-server.c,v 1.85 2009/04/14 16:33:42 stevesk Exp $ */ 1/* $OpenBSD: sftp-server.c,v 1.91 2010/01/13 01:40:16 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) {
@@ -920,7 +940,7 @@ process_readdir(void)
920 continue; 940 continue;
921 stat_to_attrib(&st, &(stats[count].attrib)); 941 stat_to_attrib(&st, &(stats[count].attrib));
922 stats[count].name = xstrdup(dp->d_name); 942 stats[count].name = xstrdup(dp->d_name);
923 stats[count].long_name = ls_file(dp->d_name, &st, 0); 943 stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
924 count++; 944 count++;
925 /* send up to 100 entries in one message */ 945 /* send up to 100 entries in one message */
926 /* XXX check packet size instead */ 946 /* XXX check packet size instead */
@@ -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,8 @@ sftp_server_usage(void)
1322 extern char *__progname; 1364 extern char *__progname;
1323 1365
1324 fprintf(stderr, 1366 fprintf(stderr,
1325 "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname); 1367 "usage: %s [-ehR] [-f log_facility] [-l log_level] [-u umask]\n",
1368 __progname);
1326 exit(1); 1369 exit(1);
1327} 1370}
1328 1371
@@ -1334,6 +1377,8 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1334 ssize_t len, olen, set_size; 1377 ssize_t len, olen, set_size;
1335 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 1378 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1336 char *cp, buf[4*4096]; 1379 char *cp, buf[4*4096];
1380 const char *errmsg;
1381 mode_t mask;
1337 1382
1338 extern char *optarg; 1383 extern char *optarg;
1339 extern char *__progname; 1384 extern char *__progname;
@@ -1341,8 +1386,11 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1341 __progname = ssh_get_progname(argv[0]); 1386 __progname = ssh_get_progname(argv[0]);
1342 log_init(__progname, log_level, log_facility, log_stderr); 1387 log_init(__progname, log_level, log_facility, log_stderr);
1343 1388
1344 while (!skipargs && (ch = getopt(argc, argv, "f:l:che")) != -1) { 1389 while (!skipargs && (ch = getopt(argc, argv, "f:l:u:cehR")) != -1) {
1345 switch (ch) { 1390 switch (ch) {
1391 case 'R':
1392 readonly = 1;
1393 break;
1346 case 'c': 1394 case 'c':
1347 /* 1395 /*
1348 * Ignore all arguments if we are invoked as a 1396 * Ignore all arguments if we are invoked as a
@@ -1363,6 +1411,13 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1363 if (log_facility == SYSLOG_FACILITY_NOT_SET) 1411 if (log_facility == SYSLOG_FACILITY_NOT_SET)
1364 error("Invalid log facility \"%s\"", optarg); 1412 error("Invalid log facility \"%s\"", optarg);
1365 break; 1413 break;
1414 case 'u':
1415 mask = (mode_t)strtonum(optarg, 0, 0777, &errmsg);
1416 if (errmsg != NULL)
1417 fatal("Invalid umask \"%s\": %s",
1418 optarg, errmsg);
1419 (void)umask(mask);
1420 break;
1366 case 'h': 1421 case 'h':
1367 default: 1422 default:
1368 sftp_server_usage(); 1423 sftp_server_usage();
@@ -1387,8 +1442,8 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1387 logit("session opened for local user %s from [%s]", 1442 logit("session opened for local user %s from [%s]",
1388 pw->pw_name, client_addr); 1443 pw->pw_name, client_addr);
1389 1444
1390 in = dup(STDIN_FILENO); 1445 in = STDIN_FILENO;
1391 out = dup(STDOUT_FILENO); 1446 out = STDOUT_FILENO;
1392 1447
1393#ifdef HAVE_CYGWIN 1448#ifdef HAVE_CYGWIN
1394 setmode(in, O_BINARY); 1449 setmode(in, O_BINARY);