diff options
-rw-r--r-- | channels.c | 74 | ||||
-rw-r--r-- | ssh_config.5 | 22 | ||||
-rw-r--r-- | sshd_config.5 | 44 |
3 files changed, 99 insertions, 41 deletions
@@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.435 2023/12/18 14:47:20 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.436 2024/01/09 22:19:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -214,6 +214,9 @@ struct ssh_channels { /* Channel timeouts by type */ struct ssh_channel_timeout *timeouts; size_t ntimeouts; + /* Global timeout for all OPEN channels */ + int global_deadline; + time_t lastused; }; /* helper */ @@ -316,6 +319,11 @@ channel_add_timeout(struct ssh *ssh, const char *type_pattern, { struct ssh_channels *sc = ssh->chanctxt; + if (strcmp(type_pattern, "global") == 0) { + debug2_f("global channel timeout %d seconds", timeout_secs); + sc->global_deadline = timeout_secs; + return; + } debug2_f("channel type \"%s\" timeout %d seconds", type_pattern, timeout_secs); sc->timeouts = xrecallocarray(sc->timeouts, sc->ntimeouts, @@ -377,6 +385,38 @@ channel_set_xtype(struct ssh *ssh, int id, const char *xctype) } /* + * update "last used" time on a channel. + * NB. nothing else should update lastused except to clear it. + */ +static void +channel_set_used_time(struct ssh *ssh, Channel *c) +{ + ssh->chanctxt->lastused = monotime(); + if (c != NULL) + c->lastused = ssh->chanctxt->lastused; +} + +/* + * Get the time at which a channel is due to time out for inactivity. + * Returns 0 if the channel is not due to time out ever. + */ +static time_t +channel_get_expiry(struct ssh *ssh, Channel *c) +{ + struct ssh_channels *sc = ssh->chanctxt; + time_t expiry = 0, channel_expiry; + + if (sc->lastused != 0 && sc->global_deadline != 0) + expiry = sc->lastused + sc->global_deadline; + if (c->lastused != 0 && c->inactive_deadline != 0) { + channel_expiry = c->lastused + c->inactive_deadline; + if (expiry == 0 || channel_expiry < expiry) + expiry = channel_expiry; + } + return expiry; +} + +/* * Register filedescriptors for a channel, used when allocating a channel or * when the channel consumer/producer is ready, e.g. shell exec'd */ @@ -441,6 +481,8 @@ channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd, if (efd != -1) set_nonblock(efd); } + /* channel might be entering a larval state, so reset global timeout */ + channel_set_used_time(ssh, NULL); } /* @@ -1197,7 +1239,7 @@ channel_set_fds(struct ssh *ssh, int id, int rfd, int wfd, int efd, channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, is_tty); c->type = SSH_CHANNEL_OPEN; - c->lastused = monotime(); + channel_set_used_time(ssh, c); c->local_window = c->local_window_max = window_max; if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 || @@ -1368,7 +1410,7 @@ channel_pre_x11_open(struct ssh *ssh, Channel *c) if (ret == 1) { c->type = SSH_CHANNEL_OPEN; - c->lastused = monotime(); + channel_set_used_time(ssh, c); channel_pre_open(ssh, c); } else if (ret == -1) { logit("X11 connection rejected because of wrong " @@ -2016,7 +2058,7 @@ channel_post_connecting(struct ssh *ssh, Channel *c) c->self, c->connect_ctx.host, c->connect_ctx.port); channel_connect_ctx_free(&c->connect_ctx); c->type = SSH_CHANNEL_OPEN; - c->lastused = monotime(); + channel_set_used_time(ssh, c); if (isopen) { /* no message necessary */ } else { @@ -2108,7 +2150,7 @@ channel_handle_rfd(struct ssh *ssh, Channel *c) goto rfail; } if (nr != 0) - c->lastused = monotime(); + channel_set_used_time(ssh, c); return 1; } @@ -2134,7 +2176,7 @@ channel_handle_rfd(struct ssh *ssh, Channel *c) } return -1; } - c->lastused = monotime(); + channel_set_used_time(ssh, c); if (c->input_filter != NULL) { if (c->input_filter(ssh, c, buf, len) == -1) { debug2("channel %d: filter stops", c->self); @@ -2215,7 +2257,7 @@ channel_handle_wfd(struct ssh *ssh, Channel *c) } return -1; } - c->lastused = monotime(); + channel_set_used_time(ssh, c); #ifndef BROKEN_TCGETATTR_ICANON if (c->isatty && dlen >= 1 && buf[0] != '\r') { if (tcgetattr(c->wfd, &tio) == 0 && @@ -2264,7 +2306,7 @@ channel_handle_efd_write(struct ssh *ssh, Channel *c) if ((r = sshbuf_consume(c->extended, len)) != 0) fatal_fr(r, "channel %i: consume", c->self); c->local_consumed += len; - c->lastused = monotime(); + channel_set_used_time(ssh, c); } return 1; } @@ -2291,7 +2333,7 @@ channel_handle_efd_read(struct ssh *ssh, Channel *c) channel_close_fd(ssh, c, &c->efd); return 1; } - c->lastused = monotime(); + channel_set_used_time(ssh, c); if (c->extended_usage == CHAN_EXTENDED_IGNORE) debug3("channel %d: discard efd", c->self); else if ((r = sshbuf_put(c->extended, buf, len)) != 0) @@ -2581,10 +2623,9 @@ channel_handler(struct ssh *ssh, int table, struct timespec *timeout) continue; } if (ftab[c->type] != NULL) { - if (table == CHAN_PRE && - c->type == SSH_CHANNEL_OPEN && - c->inactive_deadline != 0 && c->lastused != 0 && - now >= c->lastused + c->inactive_deadline) { + if (table == CHAN_PRE && c->type == SSH_CHANNEL_OPEN && + channel_get_expiry(ssh, c) != 0 && + now >= channel_get_expiry(ssh, c)) { /* channel closed for inactivity */ verbose("channel %d: closing after %u seconds " "of inactivity", c->self, @@ -2596,10 +2637,9 @@ channel_handler(struct ssh *ssh, int table, struct timespec *timeout) /* inactivity timeouts must interrupt poll() */ if (timeout != NULL && c->type == SSH_CHANNEL_OPEN && - c->lastused != 0 && - c->inactive_deadline != 0) { + channel_get_expiry(ssh, c) != 0) { ptimeout_deadline_monotime(timeout, - c->lastused + c->inactive_deadline); + channel_get_expiry(ssh, c)); } } else if (timeout != NULL) { /* @@ -3558,7 +3598,7 @@ channel_input_open_confirmation(int type, u_int32_t seq, struct ssh *ssh) c->open_confirm(ssh, c->self, 1, c->open_confirm_ctx); debug2_f("channel %d: callback done", c->self); } - c->lastused = monotime(); + channel_set_used_time(ssh, c); debug2("channel %d: open confirm rwindow %u rmax %u", c->self, c->remote_window, c->remote_maxpacket); return 0; diff --git a/ssh_config.5 b/ssh_config.5 index 4bbdfefd..15ad012f 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.391 2023/10/12 02:18:18 djm Exp $ -.Dd $Mdocdate: October 12 2023 $ +.\" $OpenBSD: ssh_config.5,v 1.392 2024/01/09 22:19:00 djm Exp $ +.Dd $Mdocdate: January 9 2024 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -463,8 +463,10 @@ Timeouts are specified as one or more .Dq type=interval pairs separated by whitespace, where the .Dq type -must be a channel type name (as described in the table below), optionally -containing wildcard characters. +must be the special keyword +.Dq global +or a channel type name from the list below, optionally containing +wildcard characters. .Pp The timeout value .Dq interval @@ -473,11 +475,19 @@ is specified in seconds or may use any of the units documented in the section. For example, .Dq session=5m -would cause the interactive session to terminate after five minutes of +would cause interactive sessions to terminate after five minutes of inactivity. Specifying a zero value disables the inactivity timeout. .Pp -The available channel types include: +The special timeout +.Dq global +Applies to all active channels, taken together. +Traffic on any active channel will reset the timeout, but when the timeout +expires then all open channels will be closed. +Note that this global timeout is not matched by wildcards and must be +specified explicitly. +.Pp +The available channel type names include: .Bl -tag -width Ds .It Cm agent-connection Open connections to diff --git a/sshd_config.5 b/sshd_config.5 index 7e1a56cd..ca5eeb59 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.350 2023/07/28 05:42:36 jmc Exp $ -.Dd $Mdocdate: July 28 2023 $ +.\" $OpenBSD: sshd_config.5,v 1.351 2024/01/09 22:19:00 djm Exp $ +.Dd $Mdocdate: January 9 2024 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -409,8 +409,10 @@ Timeouts are specified as one or more .Dq type=interval pairs separated by whitespace, where the .Dq type -must be a channel type name (as described in the table below), optionally -containing wildcard characters. +must be the special keyword +.Dq global +or a channel type name from the list below, optionally containing +wildcard characters. .Pp The timeout value .Dq interval @@ -418,11 +420,20 @@ is specified in seconds or may use any of the units documented in the .Sx TIME FORMATS section. For example, -.Dq session:*=5m -would cause all sessions to terminate after five minutes of inactivity. +.Dq session=5m +would cause interactive sessions to terminate after five minutes of +inactivity. Specifying a zero value disables the inactivity timeout. .Pp -The available channel types include: +The special timeout +.Dq global +Applies to all active channels, taken together. +Traffic on any active channel will reset the timeout, but when the timeout +expires then all open channels will be closed. +Note that this global timeout is not matched by wildcards and must be +specified explicitly. +.Pp +The available channel type names include: .Bl -tag -width Ds .It Cm agent-connection Open connections to @@ -443,15 +454,15 @@ listening on behalf of a .Xr ssh 1 remote forwarding, i.e.\& .Cm RemoteForward . -.It Cm session:command -Command execution sessions. -.It Cm session:shell -Interactive shell sessions. -.It Cm session:subsystem:... -Subsystem sessions, e.g. for +.It Cm session +The interactive main session, including shell session, command execution, +.Xr scp 1 , .Xr sftp 1 , -which could be identified as -.Cm session:subsystem:sftp . +etc. +.It Cm tun-connection +Open +.Cm TunnelForward +connections. .It Cm x11-connection Open X11 forwarding sessions. .El @@ -465,9 +476,6 @@ close the SSH connection, nor does it prevent a client from requesting another channel of the same type. In particular, expiring an inactive forwarding session does not prevent another identical forwarding from being subsequently created. -See also -.Cm UnusedConnectionTimeout , -which may be used in conjunction with this option. .Pp The default is not to expire channels of any type for inactivity. .It Cm ChrootDirectory |