Skip to content

Commit

Permalink
upstream: add ChannelTimeout support to the client, mirroring the
Browse files Browse the repository at this point in the history
same option in the server. ok markus@

OpenBSD-Commit-ID: 55630b26f390ac063980cfe7ad8c54b03284ef02
  • Loading branch information
djmdjm committed Oct 11, 2023
1 parent 76e91e7 commit a752a6c
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 47 deletions.
8 changes: 4 additions & 4 deletions clientloop.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.398 2023/09/10 03:51:55 djm Exp $ */
/* $OpenBSD: clientloop.c,v 1.399 2023/10/11 22:42:26 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -1801,7 +1801,7 @@ client_request_x11(struct ssh *ssh, const char *request_type, int rchan)
sock = x11_connect_display(ssh);
if (sock < 0)
return NULL;
c = channel_new(ssh, "x11",
c = channel_new(ssh, "x11-connection",
SSH_CHANNEL_X11_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1);
c->force_drain = 1;
Expand Down Expand Up @@ -1836,7 +1836,7 @@ client_request_agent(struct ssh *ssh, const char *request_type, int rchan)
else
debug2_fr(r, "ssh_agent_bind_hostkey");

c = channel_new(ssh, "authentication agent connection",
c = channel_new(ssh, "agent-connection",
SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
"authentication agent connection", 1);
Expand Down Expand Up @@ -1864,7 +1864,7 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode,
}
debug("Tunnel forwarding using interface %s", ifname);

c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1,
c = channel_new(ssh, "tun-connection", SSH_CHANNEL_OPENING, fd, fd, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
c->datagram = 1;

Expand Down
39 changes: 38 additions & 1 deletion misc.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.187 2023/08/28 03:31:16 djm Exp $ */
/* $OpenBSD: misc.c,v 1.188 2023/10/11 22:42:26 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005-2020 Damien Miller. All rights reserved.
Expand Down Expand Up @@ -2493,6 +2493,43 @@ format_absolute_time(uint64_t t, char *buf, size_t len)
strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
}

/*
* Parse a "pattern=interval" clause (e.g. a ChannelTimeout).
* Returns 0 on success or non-zero on failure.
* Caller must free *typep.
*/
int
parse_pattern_interval(const char *s, char **typep, int *secsp)
{
char *cp, *sdup;
int secs;

if (typep != NULL)
*typep = NULL;
if (secsp != NULL)
*secsp = 0;
if (s == NULL)
return -1;
sdup = xstrdup(s);

if ((cp = strchr(sdup, '=')) == NULL || cp == sdup) {
free(sdup);
return -1;
}
*cp++ = '\0';
if ((secs = convtime(cp)) < 0) {
free(sdup);
return -1;
}
/* success */
if (typep != NULL)
*typep = xstrdup(sdup);
if (secsp != NULL)
*secsp = secs;
free(sdup);
return 0;
}

/* check if path is absolute */
int
path_absolute(const char *path)
Expand Down
3 changes: 2 additions & 1 deletion misc.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.105 2023/08/28 03:31:16 djm Exp $ */
/* $OpenBSD: misc.h,v 1.106 2023/10/11 22:42:26 djm Exp $ */

/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
Expand Down Expand Up @@ -95,6 +95,7 @@ int valid_env_name(const char *);
const char *atoi_err(const char *, int *);
int parse_absolute_time(const char *, uint64_t *);
void format_absolute_time(uint64_t, char *, size_t);
int parse_pattern_interval(const char *, char **, int *);
int path_absolute(const char *);
int stdfd_devnull(int, int, int);
int lib_contains_symbol(const char *, const char *);
Expand Down
47 changes: 45 additions & 2 deletions readconf.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.381 2023/08/28 03:31:16 djm Exp $ */
/* $OpenBSD: readconf.c,v 1.382 2023/10/11 22:42:26 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -178,7 +178,7 @@ typedef enum {
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
oEnableEscapeCommandline, oObscureKeystrokeTiming,
oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;

Expand Down Expand Up @@ -328,6 +328,7 @@ static struct {
{ "requiredrsasize", oRequiredRSASize },
{ "enableescapecommandline", oEnableEscapeCommandline },
{ "obscurekeystroketiming", oObscureKeystrokeTiming },
{ "channeltimeout", oChannelTimeout },

{ NULL, oBadOption }
};
Expand Down Expand Up @@ -2323,6 +2324,31 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
*intptr = value;
break;

case oChannelTimeout:
uvalue = options->num_channel_timeouts;
i = 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
if (i > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
} else if (parse_pattern_interval(arg,
NULL, NULL) != 0) {
fatal("%s line %d: invalid channel timeout %s",
filename, linenum, arg);
}
if (!*activep || uvalue != 0)
continue;
opt_array_append(filename, linenum, keyword,
&options->channel_timeouts,
&options->num_channel_timeouts, arg);
}
break;

case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
Expand Down Expand Up @@ -2575,6 +2601,8 @@ initialize_options(Options * options)
options->enable_escape_commandline = -1;
options->obscure_keystroke_timing_interval = -1;
options->tag = NULL;
options->channel_timeouts = NULL;
options->num_channel_timeouts = 0;
}

/*
Expand Down Expand Up @@ -2815,6 +2843,16 @@ fill_default_options(Options * options)
v = NULL; \
} \
} while(0)
#define CLEAR_ON_NONE_ARRAY(v, nv, none) \
do { \
if (options->nv == 1 && \
strcasecmp(options->v[0], none) == 0) { \
free(options->v[0]); \
free(options->v); \
options->v = NULL; \
options->nv = 0; \
} \
} while (0)
CLEAR_ON_NONE(options->local_command);
CLEAR_ON_NONE(options->remote_command);
CLEAR_ON_NONE(options->proxy_command);
Expand All @@ -2823,6 +2861,9 @@ fill_default_options(Options * options)
CLEAR_ON_NONE(options->pkcs11_provider);
CLEAR_ON_NONE(options->sk_provider);
CLEAR_ON_NONE(options->known_hosts_command);
CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
#undef CLEAR_ON_NONE
#undef CLEAR_ON_NONE_ARRAY
if (options->jump_host != NULL &&
strcmp(options->jump_host, "none") == 0 &&
options->jump_port == 0 && options->jump_user == NULL) {
Expand Down Expand Up @@ -3527,6 +3568,8 @@ dump_client_config(Options *o, const char *host)
dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
dump_cfg_strarray_oneline(oLogVerbose,
o->num_log_verbose, o->log_verbose);
dump_cfg_strarray_oneline(oChannelTimeout,
o->num_channel_timeouts, o->channel_timeouts);

/* Special cases */

Expand Down
5 changes: 4 additions & 1 deletion readconf.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.152 2023/08/28 03:31:16 djm Exp $ */
/* $OpenBSD: readconf.h,v 1.153 2023/10/11 22:42:26 djm Exp $ */

/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
Expand Down Expand Up @@ -182,6 +182,9 @@ typedef struct {
int enable_escape_commandline; /* ~C commandline */
int obscure_keystroke_timing_interval;

char **channel_timeouts; /* inactivity timeout by channel type */
u_int num_channel_timeouts;

char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;

Expand Down
40 changes: 4 additions & 36 deletions servconf.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: servconf.c,v 1.402 2023/09/08 06:34:24 djm Exp $ */
/* $OpenBSD: servconf.c,v 1.403 2023/10/11 22:42:26 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
Expand Down Expand Up @@ -956,39 +956,6 @@ process_permitopen(struct ssh *ssh, ServerOptions *options)
options->num_permitted_listens);
}

/* Parse a ChannelTimeout clause "pattern=interval" */
static int
parse_timeout(const char *s, char **typep, int *secsp)
{
char *cp, *sdup;
int secs;

if (typep != NULL)
*typep = NULL;
if (secsp != NULL)
*secsp = 0;
if (s == NULL)
return -1;
sdup = xstrdup(s);

if ((cp = strchr(sdup, '=')) == NULL || cp == sdup) {
free(sdup);
return -1;
}
*cp++ = '\0';
if ((secs = convtime(cp)) < 0) {
free(sdup);
return -1;
}
/* success */
if (typep != NULL)
*typep = xstrdup(sdup);
if (secsp != NULL)
*secsp = secs;
free(sdup);
return 0;
}

void
process_channel_timeouts(struct ssh *ssh, ServerOptions *options)
{
Expand All @@ -999,7 +966,7 @@ process_channel_timeouts(struct ssh *ssh, ServerOptions *options)
debug3_f("setting %u timeouts", options->num_channel_timeouts);
channel_clear_timeouts(ssh);
for (i = 0; i < options->num_channel_timeouts; i++) {
if (parse_timeout(options->channel_timeouts[i],
if (parse_pattern_interval(options->channel_timeouts[i],
&type, &secs) != 0) {
fatal_f("internal error: bad timeout %s",
options->channel_timeouts[i]);
Expand Down Expand Up @@ -2549,7 +2516,8 @@ process_server_config_line_depth(ServerOptions *options, char *line,
filename, linenum, keyword);
goto out;
}
} else if (parse_timeout(arg, NULL, NULL) != 0) {
} else if (parse_pattern_interval(arg,
NULL, NULL) != 0) {
fatal("%s line %d: invalid channel timeout %s",
filename, linenum, arg);
}
Expand Down
16 changes: 15 additions & 1 deletion ssh.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.594 2023/09/03 23:59:32 djm Exp $ */
/* $OpenBSD: ssh.c,v 1.595 2023/10/11 22:42:26 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -1573,6 +1573,20 @@ main(int ac, char **av)
else
timeout_ms = options.connection_timeout * 1000;

/* Apply channels timeouts, if set */
channel_clear_timeouts(ssh);
for (j = 0; j < options.num_channel_timeouts; j++) {
debug3("applying channel timeout %s",
options.channel_timeouts[j]);
if (parse_pattern_interval(options.channel_timeouts[j],
&cp, &i) != 0) {
fatal_f("internal error: bad timeout %s",
options.channel_timeouts[j]);
}
channel_add_timeout(ssh, cp, i);
free(cp);
}

/* Open a connection to the remote host. */
if (ssh_connect(ssh, host, options.host_arg, addrs, &hostaddr,
options.port, options.connection_attempts,
Expand Down
69 changes: 68 additions & 1 deletion ssh_config.5
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,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.
.\"
.\" $OpenBSD: ssh_config.5,v 1.389 2023/10/11 06:40:54 djm Exp $
.\" $OpenBSD: ssh_config.5,v 1.390 2023/10/11 22:42:26 djm Exp $
.Dd $Mdocdate: October 11 2023 $
.Dt SSH_CONFIG 5
.Os
Expand Down Expand Up @@ -455,6 +455,73 @@ Multiple
.Cm CertificateFile
directives will add to the list of certificates used for
authentication.
.It Cm ChannelTimeout
Specifies whether and how quickly
.Xr ssh 1
should close inactive channels.
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.
.Pp
The timeout value
.Dq interval
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 the interactive session to terminate after five minutes of
inactivity.
Specifying a zero value disables the inactivity timeout.
.Pp
The available channel types include:
.Bl -tag -width Ds
.It Cm agent-connection
Open connections to
.Xr ssh-agent 1 .
.It Cm direct-tcpip , Cm direct-streamlocal@openssh.com
Open TCP or Unix socket (respectively) connections that have
been established from a
.Xr ssh 1
local forwarding, i.e.\&
.Cm LocalForward
or
.Cm DynamicForward .
.It Cm forwarded-tcpip , Cm forwarded-streamlocal@openssh.com
Open TCP or Unix socket (respectively) connections that have been
established to a
.Xr sshd 8
listening on behalf of a
.Xr ssh 1
remote forwarding, i.e.\&
.Cm RemoteForward .
.It Cm session
The interactive main session, including shell session, command execution,
.Xr scp 1 ,
.Xr sftp 1 ,
etc.
.It Cm tun-connection
Open
.Cm TunnelForward
connections.
.It Cm x11-connection
Open X11 forwarding sessions.
.El
.Pp
Note that in all the above cases, terminating an inactive session does not
guarantee to remove all resources associated with the session, e.g. shell
processes or X11 clients relating to the session may continue to execute.
.Pp
Moreover, terminating an inactive channel or session does not necessarily
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.
.Pp
The default is not to expire channels of any type for inactivity.
.It Cm CheckHostIP
If set to
.Cm yes ,
Expand Down

0 comments on commit a752a6c

Please sign in to comment.