diff options
author | djm@openbsd.org <djm@openbsd.org> | 2021-02-18 01:30:17 +0100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2021-02-18 03:17:43 +0100 |
commit | 788cbc5b74a53956ba9fff11e1ca506271a3597f (patch) | |
tree | da241b74c12c8de60579fb5f980249e4466f46cf /sftp-server.c | |
parent | support OpenSSL 3.x cipher IV API change (diff) | |
download | openssh-788cbc5b74a53956ba9fff11e1ca506271a3597f.tar.xz openssh-788cbc5b74a53956ba9fff11e1ca506271a3597f.zip |
upstream: sftp-server: implement limits@openssh.com extension
This is a simple extension that allows the server to clearly
communicate transfer limits it is imposing so the client doesn't
have to guess, or force the user to manually tune. This is
particularly useful when an attempt to use too large of a value
causes the server to abort the connection.
Patch from Mike Frysinger; ok dtucker@
OpenBSD-Commit-ID: f96293221e5aa24102d9bf30e4f4ef04d5f4fb51
Diffstat (limited to 'sftp-server.c')
-rw-r--r-- | sftp-server.c | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/sftp-server.c b/sftp-server.c index c80f0d3f0..7300900ac 100644 --- a/sftp-server.c +++ b/sftp-server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-server.c,v 1.121 2021/02/12 03:49:09 djm Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.122 2021/02/18 00:30:17 djm Exp $ */ /* * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * @@ -19,6 +19,7 @@ #include <sys/types.h> #include <sys/stat.h> +#include <sys/resource.h> #ifdef HAVE_SYS_TIME_H # include <sys/time.h> #endif @@ -53,6 +54,9 @@ char *sftp_realpath(const char *, char *); /* sftp-realpath.c */ +/* Maximum data read that we are willing to accept */ +#define SFTP_MAX_READ_LENGTH (64 * 1024) + /* Our verbosity */ static LogLevel log_level = SYSLOG_LEVEL_ERROR; @@ -110,6 +114,7 @@ static void process_extended_fstatvfs(u_int32_t id); static void process_extended_hardlink(u_int32_t id); static void process_extended_fsync(u_int32_t id); static void process_extended_lsetstat(u_int32_t id); +static void process_extended_limits(u_int32_t id); static void process_extended(u_int32_t id); struct sftp_handler { @@ -152,6 +157,7 @@ static const struct sftp_handler extended_handlers[] = { { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 }, { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 }, { "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 }, + { "limits", "limits@openssh.com", 0, process_extended_limits, 1 }, { NULL, NULL, 0, NULL, 0 } }; @@ -673,6 +679,9 @@ process_init(void) (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ /* lsetstat extension */ (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 || + (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ + /* limits extension */ + (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0 || (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */ fatal_fr(r, "compose"); send_msg(msg); @@ -739,7 +748,7 @@ process_close(u_int32_t id) static void process_read(u_int32_t id) { - u_char buf[64*1024]; + u_char buf[SFTP_MAX_READ_LENGTH]; u_int32_t len; int r, handle, fd, ret, status = SSH2_FX_FAILURE; u_int64_t off; @@ -1438,6 +1447,36 @@ process_extended_lsetstat(u_int32_t id) } static void +process_extended_limits(u_int32_t id) +{ + struct sshbuf *msg; + int r; + uint64_t nfiles = 0; + struct rlimit rlim; + + debug("request %u: limits", id); + + if (getrlimit(RLIMIT_NOFILE, &rlim) != -1 && rlim.rlim_cur > 5) + nfiles = rlim.rlim_cur - 5; /* stdio(3) + syslog + spare */ + + if ((msg = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + /* max-packet-length */ + (r = sshbuf_put_u64(msg, SFTP_MAX_MSG_LENGTH)) != 0 || + /* max-read-length */ + (r = sshbuf_put_u64(msg, SFTP_MAX_READ_LENGTH)) != 0 || + /* max-write-length */ + (r = sshbuf_put_u64(msg, SFTP_MAX_MSG_LENGTH - 1024)) != 0 || + /* max-open-handles */ + (r = sshbuf_put_u64(msg, nfiles)) != 0) + fatal_fr(r, "compose"); + send_msg(msg); + sshbuf_free(msg); +} + +static void process_extended(u_int32_t id) { char *request; |