diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2010-01-09 00:20:27 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2010-01-09 00:20:27 +0000 |
commit | 5dc179008864e0f1d8a93c9c49c05bf0166c255f (patch) | |
tree | 91e83b7231398368e75e99a9ec43a1269b6aede1 /usr.bin/ssh | |
parent | 7ec564029b2d8795f5249a3ae71d1754aa79df85 (diff) |
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 'usr.bin/ssh')
-rw-r--r-- | usr.bin/ssh/sftp-server.8 | 12 | ||||
-rw-r--r-- | usr.bin/ssh/sftp-server.c | 103 |
2 files changed, 83 insertions, 32 deletions
diff --git a/usr.bin/ssh/sftp-server.8 b/usr.bin/ssh/sftp-server.8 index ee73c345b98..84036922c6f 100644 --- a/usr.bin/ssh/sftp-server.8 +++ b/usr.bin/ssh/sftp-server.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp-server.8,v 1.17 2009/08/31 21:01:29 djm Exp $ +.\" $OpenBSD: sftp-server.8,v 1.18 2010/01/09 00:20:26 djm Exp $ .\" .\" Copyright (c) 2000 Markus Friedl. All rights reserved. .\" @@ -22,7 +22,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: August 31 2009 $ +.Dd $Mdocdate: January 9 2010 $ .Dt SFTP-SERVER 8 .Os .Sh NAME @@ -30,7 +30,7 @@ .Nd SFTP server subsystem .Sh SYNOPSIS .Nm sftp-server -.Op Fl eh +.Op Fl ehR .Op Fl f Ar log_facility .Op Fl l Ar log_level .Op Fl u Ar umask @@ -81,6 +81,12 @@ performs on behalf of the client. DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. The default is ERROR. +.It Fl R +Places this instance of +.Nm +into a read-only mode. +Attempts to open files for writing, as well as other operations that change +the state of the filesystem will be denied. .It Fl u Ar umask Sets an explicit .Xr umask 2 diff --git a/usr.bin/ssh/sftp-server.c b/usr.bin/ssh/sftp-server.c index 4248aedeeeb..06171e1f3ce 100644 --- a/usr.bin/ssh/sftp-server.c +++ b/usr.bin/ssh/sftp-server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-server.c,v 1.89 2010/01/04 02:25:15 djm Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.90 2010/01/09 00:20:26 djm Exp $ */ /* * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * @@ -61,6 +61,9 @@ Buffer oqueue; /* Version of client */ int version; +/* Disable writes */ +int readonly; + /* portable attributes, etc. */ typedef struct Stat Stat; @@ -544,16 +547,21 @@ process_open(void) mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; logit("open \"%s\" flags %s mode 0%o", name, string_from_portable(pflags), mode); - fd = open(name, flags, mode); - if (fd < 0) { - status = errno_to_portable(errno); - } else { - handle = handle_new(HANDLE_FILE, name, fd, NULL); - if (handle < 0) { - close(fd); + if (readonly && + ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR)) + status = SSH2_FX_PERMISSION_DENIED; + else { + fd = open(name, flags, mode); + if (fd < 0) { + status = errno_to_portable(errno); } else { - send_handle(id, handle); - status = SSH2_FX_OK; + handle = handle_new(HANDLE_FILE, name, fd, NULL); + if (handle < 0) { + close(fd); + } else { + send_handle(id, handle); + status = SSH2_FX_OK; + } } } if (status != SSH2_FX_OK) @@ -623,7 +631,7 @@ process_write(void) u_int32_t id; u_int64_t off; u_int len; - int handle, fd, ret, status = SSH2_FX_FAILURE; + int handle, fd, ret, status; char *data; id = get_int(); @@ -634,7 +642,12 @@ process_write(void) debug("request %u: write \"%s\" (handle %d) off %llu len %d", id, handle_to_name(handle), handle, (unsigned long long)off, len); fd = handle_to_fd(handle); - if (fd >= 0) { + + if (fd < 0) + status = SSH2_FX_FAILURE; + else if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { if (lseek(fd, off, SEEK_SET) < 0) { status = errno_to_portable(errno); error("process_write: seek failed"); @@ -649,6 +662,7 @@ process_write(void) handle_update_write(handle, ret); } else { debug2("nothing at all written"); + status = SSH2_FX_FAILURE; } } } @@ -745,6 +759,10 @@ process_setstat(void) name = get_string(NULL); a = get_attrib(); debug("request %u: setstat name \"%s\"", id, name); + if (readonly) { + status = SSH2_FX_PERMISSION_DENIED; + a->flags = 0; + } if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { logit("set \"%s\" size %llu", name, (unsigned long long)a->size); @@ -793,9 +811,11 @@ process_fsetstat(void) a = get_attrib(); debug("request %u: fsetstat handle %d", id, handle); fd = handle_to_fd(handle); - if (fd < 0) { + if (fd < 0) status = SSH2_FX_FAILURE; - } else { + else if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { char *name = handle_to_name(handle); if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { @@ -931,8 +951,12 @@ process_remove(void) name = get_string(NULL); debug3("request %u: remove", id); logit("remove name \"%s\"", name); - ret = unlink(name); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = unlink(name); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(name); } @@ -952,8 +976,12 @@ process_mkdir(void) a->perm & 07777 : 0777; debug3("request %u: mkdir", id); logit("mkdir name \"%s\" mode 0%o", name, mode); - ret = mkdir(name, mode); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = mkdir(name, mode); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(name); } @@ -969,8 +997,12 @@ process_rmdir(void) name = get_string(NULL); debug3("request %u: rmdir", id); logit("rmdir name \"%s\"", name); - ret = rmdir(name); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = rmdir(name); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(name); } @@ -1015,7 +1047,9 @@ process_rename(void) debug3("request %u: rename", id); logit("rename old \"%s\" new \"%s\"", oldpath, newpath); status = SSH2_FX_FAILURE; - if (lstat(oldpath, &sb) == -1) + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else if (lstat(oldpath, &sb) == -1) status = errno_to_portable(errno); else if (S_ISREG(sb.st_mode)) { /* Race-free rename of regular files */ @@ -1092,8 +1126,12 @@ process_symlink(void) debug3("request %u: symlink", id); logit("symlink old \"%s\" new \"%s\"", oldpath, newpath); /* this will fail if 'newpath' exists */ - ret = symlink(oldpath, newpath); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = symlink(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(oldpath); xfree(newpath); @@ -1103,15 +1141,19 @@ static void process_extended_posix_rename(u_int32_t id) { char *oldpath, *newpath; + int ret, status; oldpath = get_string(NULL); newpath = get_string(NULL); debug3("request %u: posix-rename", id); logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath); - if (rename(oldpath, newpath) == -1) - send_status(id, errno_to_portable(errno)); - else - send_status(id, SSH2_FX_OK); + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = rename(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } + send_status(id, status); xfree(oldpath); xfree(newpath); } @@ -1294,7 +1336,7 @@ sftp_server_usage(void) extern char *__progname; fprintf(stderr, - "usage: %s [-eh] [-f log_facility] [-l log_level] [-u umask]\n", + "usage: %s [-ehR] [-f log_facility] [-l log_level] [-u umask]\n", __progname); exit(1); } @@ -1315,8 +1357,11 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) log_init(__progname, log_level, log_facility, log_stderr); - while (!skipargs && (ch = getopt(argc, argv, "f:l:u:che")) != -1) { + while (!skipargs && (ch = getopt(argc, argv, "f:l:u:cehR")) != -1) { switch (ch) { + case 'R': + readonly = 1; + break; case 'c': /* * Ignore all arguments if we are invoked as a |