-/* $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
/* 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 */
{
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,
c->inactive_deadline);
}
+/*
+ * 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
if (efd != -1)
set_nonblock(efd);
}
+ /* channel might be entering a larval state, so reset global timeout */
+ channel_set_used_time(ssh, NULL);
}
/*
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 ||
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 "
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 {
goto rfail;
}
if (nr != 0)
- c->lastused = monotime();
+ channel_set_used_time(ssh, c);
return 1;
}
}
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);
}
return -1;
}
- c->lastused = monotime();
+ channel_set_used_time(ssh, c);
if (c->isatty && dlen >= 1 && buf[0] != '\r') {
if (tcgetattr(c->wfd, &tio) == 0 &&
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
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;
}
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)
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,
/* 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) {
/*
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;
.\" (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
.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
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
.\" (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
.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
.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
.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
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