mirror of
git://anongit.mindrot.org/openssh.git
synced 2024-11-23 09:17:32 +08:00
upstream: Implement channel inactivity timeouts
This adds a sshd_config ChannelTimeouts directive that allows channels that have not seen traffic in a configurable interval to be automatically closed. Different timeouts may be applied to session, X11, agent and TCP forwarding channels. Note: this only affects channels over an opened SSH connection and not the connection itself. Most clients close the connection when their channels go away, with a notable exception being ssh(1) in multiplexing mode. ok markus dtucker OpenBSD-Commit-ID: ae8bba3ed9d9f95ff2e2dc8dcadfa36b48e6c0b8
This commit is contained in:
parent
0e34348d0b
commit
2d1ff2b943
118
channels.c
118
channels.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: channels.c,v 1.425 2023/01/06 02:42:34 djm Exp $ */
|
||||
/* $OpenBSD: channels.c,v 1.426 2023/01/06 02:47:18 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -151,6 +151,12 @@ struct permission_set {
|
||||
int all_permitted;
|
||||
};
|
||||
|
||||
/* Used to record timeouts per channel type */
|
||||
struct ssh_channel_timeout {
|
||||
char *type_pattern;
|
||||
u_int timeout_secs;
|
||||
};
|
||||
|
||||
/* Master structure for channels state */
|
||||
struct ssh_channels {
|
||||
/*
|
||||
@ -204,6 +210,10 @@ struct ssh_channels {
|
||||
|
||||
/* AF_UNSPEC or AF_INET or AF_INET6 */
|
||||
int IPv4or6;
|
||||
|
||||
/* Channel timeouts by type */
|
||||
struct ssh_channel_timeout *timeouts;
|
||||
size_t ntimeouts;
|
||||
};
|
||||
|
||||
/* helper */
|
||||
@ -296,10 +306,59 @@ channel_lookup(struct ssh *ssh, int id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a timeout for open channels whose c->ctype (or c->xctype if it is set)
|
||||
* match type_pattern.
|
||||
*/
|
||||
void
|
||||
channel_add_timeout(struct ssh *ssh, const char *type_pattern,
|
||||
u_int timeout_secs)
|
||||
{
|
||||
struct ssh_channels *sc = ssh->chanctxt;
|
||||
|
||||
debug2_f("channel type \"%s\" timeout %u seconds",
|
||||
type_pattern, timeout_secs);
|
||||
sc->timeouts = xrecallocarray(sc->timeouts, sc->ntimeouts,
|
||||
sc->ntimeouts + 1, sizeof(*sc->timeouts));
|
||||
sc->timeouts[sc->ntimeouts].type_pattern = xstrdup(type_pattern);
|
||||
sc->timeouts[sc->ntimeouts].timeout_secs = timeout_secs;
|
||||
sc->ntimeouts++;
|
||||
}
|
||||
|
||||
/* Clears all previously-added channel timeouts */
|
||||
void
|
||||
channel_clear_timeouts(struct ssh *ssh)
|
||||
{
|
||||
struct ssh_channels *sc = ssh->chanctxt;
|
||||
size_t i;
|
||||
|
||||
debug3_f("clearing");
|
||||
for (i = 0; i < sc->ntimeouts; i++)
|
||||
free(sc->timeouts[i].type_pattern);
|
||||
free(sc->timeouts);
|
||||
sc->timeouts = NULL;
|
||||
sc->ntimeouts = 0;
|
||||
}
|
||||
|
||||
static u_int
|
||||
lookup_timeout(struct ssh *ssh, const char *type)
|
||||
{
|
||||
struct ssh_channels *sc = ssh->chanctxt;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sc->ntimeouts; i++) {
|
||||
if (match_pattern(type, sc->timeouts[i].type_pattern))
|
||||
return sc->timeouts[i].timeout_secs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets "extended type" of a channel; used by session layer to add additional
|
||||
* information about channel types (e.g. shell, login, subsystem) that can then
|
||||
* be used to select timeouts.
|
||||
* Will reset c->inactive_deadline as a side-effect.
|
||||
*/
|
||||
void
|
||||
channel_set_xtype(struct ssh *ssh, int id, const char *xctype)
|
||||
@ -311,7 +370,10 @@ channel_set_xtype(struct ssh *ssh, int id, const char *xctype)
|
||||
if (c->xctype != NULL)
|
||||
free(c->xctype);
|
||||
c->xctype = xstrdup(xctype);
|
||||
debug2_f("labeled channel %d as %s", id, xctype);
|
||||
/* Type has changed, so look up inactivity deadline again */
|
||||
c->inactive_deadline = lookup_timeout(ssh, c->xctype);
|
||||
debug2_f("labeled channel %d as %s (inactive timeout %u)", id, xctype,
|
||||
c->inactive_deadline);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -433,8 +495,10 @@ channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd,
|
||||
c->remote_name = xstrdup(remote_name);
|
||||
c->ctl_chan = -1;
|
||||
c->delayed = 1; /* prevent call to channel_post handler */
|
||||
c->inactive_deadline = lookup_timeout(ssh, c->ctype);
|
||||
TAILQ_INIT(&c->status_confirms);
|
||||
debug("channel %d: new [%s]", found, remote_name);
|
||||
debug("channel %d: new %s [%s] (inactive timeout: %u)",
|
||||
found, c->ctype, remote_name, c->inactive_deadline);
|
||||
return c;
|
||||
}
|
||||
|
||||
@ -1107,6 +1171,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();
|
||||
c->local_window = c->local_window_max = window_max;
|
||||
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 ||
|
||||
@ -1263,6 +1328,9 @@ channel_force_close(struct ssh *ssh, Channel *c, int abandon)
|
||||
channel_close_fd(ssh, c, &c->efd);
|
||||
if (abandon)
|
||||
c->type = SSH_CHANNEL_ABANDONED;
|
||||
/* exempt from inactivity timeouts */
|
||||
c->inactive_deadline = 0;
|
||||
c->lastused = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1274,6 +1342,7 @@ channel_pre_x11_open(struct ssh *ssh, Channel *c)
|
||||
|
||||
if (ret == 1) {
|
||||
c->type = SSH_CHANNEL_OPEN;
|
||||
c->lastused = monotime();
|
||||
channel_pre_open(ssh, c);
|
||||
} else if (ret == -1) {
|
||||
logit("X11 connection rejected because of wrong "
|
||||
@ -1917,6 +1986,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();
|
||||
if (isopen) {
|
||||
/* no message necessary */
|
||||
} else {
|
||||
@ -1965,7 +2035,7 @@ channel_handle_rfd(struct ssh *ssh, Channel *c)
|
||||
char buf[CHAN_RBUF];
|
||||
ssize_t len;
|
||||
int r, force;
|
||||
size_t have, avail, maxlen = CHANNEL_MAX_READ;
|
||||
size_t nr = 0, have, avail, maxlen = CHANNEL_MAX_READ;
|
||||
int pty_zeroread = 0;
|
||||
|
||||
#ifdef PTY_ZEROREAD
|
||||
@ -1994,7 +2064,7 @@ channel_handle_rfd(struct ssh *ssh, Channel *c)
|
||||
}
|
||||
if (maxlen > avail)
|
||||
maxlen = avail;
|
||||
if ((r = sshbuf_read(c->rfd, c->input, maxlen, NULL)) != 0) {
|
||||
if ((r = sshbuf_read(c->rfd, c->input, maxlen, &nr)) != 0) {
|
||||
if (errno == EINTR || (!force &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK)))
|
||||
return 1;
|
||||
@ -2002,6 +2072,8 @@ channel_handle_rfd(struct ssh *ssh, Channel *c)
|
||||
c->self, c->rfd, maxlen, ssh_err(r));
|
||||
goto rfail;
|
||||
}
|
||||
if (nr != 0)
|
||||
c->lastused = monotime();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -2027,6 +2099,7 @@ channel_handle_rfd(struct ssh *ssh, Channel *c)
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
c->lastused = monotime();
|
||||
if (c->input_filter != NULL) {
|
||||
if (c->input_filter(ssh, c, buf, len) == -1) {
|
||||
debug2("channel %d: filter stops", c->self);
|
||||
@ -2107,6 +2180,7 @@ channel_handle_wfd(struct ssh *ssh, Channel *c)
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
c->lastused = monotime();
|
||||
#ifndef BROKEN_TCGETATTR_ICANON
|
||||
if (c->isatty && dlen >= 1 && buf[0] != '\r') {
|
||||
if (tcgetattr(c->wfd, &tio) == 0 &&
|
||||
@ -2155,6 +2229,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();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -2179,7 +2254,10 @@ channel_handle_efd_read(struct ssh *ssh, Channel *c)
|
||||
if (len <= 0) {
|
||||
debug2("channel %d: closing read-efd %d", c->self, c->efd);
|
||||
channel_close_fd(ssh, c, &c->efd);
|
||||
} else if (c->extended_usage == CHAN_EXTENDED_IGNORE)
|
||||
return 1;
|
||||
}
|
||||
c->lastused = monotime();
|
||||
if (c->extended_usage == CHAN_EXTENDED_IGNORE)
|
||||
debug3("channel %d: discard efd", c->self);
|
||||
else if ((r = sshbuf_put(c->extended, buf, len)) != 0)
|
||||
fatal_fr(r, "channel %i: append", c->self);
|
||||
@ -2468,14 +2546,29 @@ channel_handler(struct ssh *ssh, int table, struct timespec *timeout)
|
||||
continue;
|
||||
}
|
||||
if (ftab[c->type] != NULL) {
|
||||
/*
|
||||
* Run handlers that are not paused.
|
||||
*/
|
||||
if (c->notbefore <= now)
|
||||
if (table == CHAN_PRE &&
|
||||
c->type == SSH_CHANNEL_OPEN &&
|
||||
c->inactive_deadline != 0 && c->lastused != 0 &&
|
||||
now >= c->lastused + c->inactive_deadline) {
|
||||
/* channel closed for inactivity */
|
||||
verbose("channel %d: closing after %u seconds "
|
||||
"of inactivity", c->self,
|
||||
c->inactive_deadline);
|
||||
channel_force_close(ssh, c, 1);
|
||||
} else if (c->notbefore <= now) {
|
||||
/* Run handlers that are not paused. */
|
||||
(*ftab[c->type])(ssh, c);
|
||||
else if (timeout != NULL) {
|
||||
/* inactivity timeouts must interrupt poll() */
|
||||
if (timeout != NULL &&
|
||||
c->type == SSH_CHANNEL_OPEN &&
|
||||
c->lastused != 0 &&
|
||||
c->inactive_deadline != 0) {
|
||||
ptimeout_deadline_monotime(timeout,
|
||||
c->lastused + c->inactive_deadline);
|
||||
}
|
||||
} else if (timeout != NULL) {
|
||||
/*
|
||||
* Arrange for poll wakeup when channel pause
|
||||
* Arrange for poll() wakeup when channel pause
|
||||
* timer expires.
|
||||
*/
|
||||
ptimeout_deadline_monotime(timeout,
|
||||
@ -3412,6 +3505,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();
|
||||
debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
|
||||
c->remote_window, c->remote_maxpacket);
|
||||
return 0;
|
||||
|
13
channels.h
13
channels.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: channels.h,v 1.146 2023/01/06 02:42:34 djm Exp $ */
|
||||
/* $OpenBSD: channels.h,v 1.147 2023/01/06 02:47:18 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -203,6 +203,13 @@ struct Channel {
|
||||
void *mux_ctx;
|
||||
int mux_pause;
|
||||
int mux_downstream_id;
|
||||
|
||||
/* Inactivity timeouts */
|
||||
|
||||
/* Last traffic seen for OPEN channels */
|
||||
time_t lastused;
|
||||
/* Inactivity timeout deadline in seconds (0 = no timeout) */
|
||||
u_int inactive_deadline;
|
||||
};
|
||||
|
||||
#define CHAN_EXTENDED_IGNORE 0
|
||||
@ -299,6 +306,10 @@ void channel_cancel_cleanup(struct ssh *, int);
|
||||
int channel_close_fd(struct ssh *, Channel *, int *);
|
||||
void channel_send_window_changes(struct ssh *);
|
||||
|
||||
/* channel inactivity timeouts */
|
||||
void channel_add_timeout(struct ssh *, const char *, u_int);
|
||||
void channel_clear_timeouts(struct ssh *);
|
||||
|
||||
/* mux proxy support */
|
||||
|
||||
int channel_proxy_downstream(struct ssh *, Channel *mc);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: monitor_wrap.c,v 1.125 2022/06/15 16:08:25 djm Exp $ */
|
||||
/* $OpenBSD: monitor_wrap.c,v 1.126 2023/01/06 02:47:18 djm Exp $ */
|
||||
/*
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
||||
@ -339,6 +339,7 @@ out:
|
||||
for (i = 0; i < options.num_log_verbose; i++)
|
||||
log_verbose_add(options.log_verbose[i]);
|
||||
process_permitopen(ssh, &options);
|
||||
process_channel_timeouts(ssh, &options);
|
||||
free(newopts);
|
||||
|
||||
sshbuf_free(m);
|
||||
|
110
servconf.c
110
servconf.c
@ -1,5 +1,5 @@
|
||||
|
||||
/* $OpenBSD: servconf.c,v 1.388 2022/11/07 10:05:39 dtucker Exp $ */
|
||||
/* $OpenBSD: servconf.c,v 1.389 2023/01/06 02:47:18 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
@ -196,6 +196,8 @@ initialize_server_options(ServerOptions *options)
|
||||
options->disable_forwarding = -1;
|
||||
options->expose_userauth_info = -1;
|
||||
options->required_rsa_size = -1;
|
||||
options->channel_timeouts = NULL;
|
||||
options->num_channel_timeouts = 0;
|
||||
}
|
||||
|
||||
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
|
||||
@ -458,6 +460,16 @@ fill_default_server_options(ServerOptions *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->pid_file);
|
||||
CLEAR_ON_NONE(options->xauth_location);
|
||||
CLEAR_ON_NONE(options->banner);
|
||||
@ -469,19 +481,16 @@ fill_default_server_options(ServerOptions *options)
|
||||
CLEAR_ON_NONE(options->chroot_directory);
|
||||
CLEAR_ON_NONE(options->routing_domain);
|
||||
CLEAR_ON_NONE(options->host_key_agent);
|
||||
|
||||
for (i = 0; i < options->num_host_key_files; i++)
|
||||
CLEAR_ON_NONE(options->host_key_files[i]);
|
||||
for (i = 0; i < options->num_host_cert_files; i++)
|
||||
CLEAR_ON_NONE(options->host_cert_files[i]);
|
||||
#undef CLEAR_ON_NONE
|
||||
|
||||
/* Similar handling for AuthenticationMethods=any */
|
||||
if (options->num_auth_methods == 1 &&
|
||||
strcmp(options->auth_methods[0], "any") == 0) {
|
||||
free(options->auth_methods[0]);
|
||||
options->auth_methods[0] = NULL;
|
||||
options->num_auth_methods = 0;
|
||||
}
|
||||
CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
|
||||
CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any");
|
||||
#undef CLEAR_ON_NONE
|
||||
#undef CLEAR_ON_NONE_ARRAY
|
||||
}
|
||||
|
||||
/* Keyword tokens. */
|
||||
@ -520,7 +529,7 @@ typedef enum {
|
||||
sStreamLocalBindMask, sStreamLocalBindUnlink,
|
||||
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
|
||||
sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
|
||||
sRequiredRSASize,
|
||||
sRequiredRSASize, sChannelTimeout,
|
||||
sDeprecated, sIgnore, sUnsupported
|
||||
} ServerOpCodes;
|
||||
|
||||
@ -681,6 +690,7 @@ static struct {
|
||||
{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
|
||||
{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
|
||||
{ "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
|
||||
{ "channeltimeout", sChannelTimeout, SSHCFG_ALL },
|
||||
{ NULL, sBadOption, 0 }
|
||||
};
|
||||
|
||||
@ -944,6 +954,58 @@ 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, u_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 = (u_int)secs;
|
||||
free(sdup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
process_channel_timeouts(struct ssh *ssh, ServerOptions *options)
|
||||
{
|
||||
u_int i, secs;
|
||||
char *type;
|
||||
|
||||
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],
|
||||
&type, &secs) != 0) {
|
||||
fatal_f("internal error: bad timeout %s",
|
||||
options->channel_timeouts[i]);
|
||||
}
|
||||
channel_add_timeout(ssh, type, secs);
|
||||
free(type);
|
||||
}
|
||||
}
|
||||
|
||||
struct connection_info *
|
||||
get_connection_info(struct ssh *ssh, int populate, int use_dns)
|
||||
{
|
||||
@ -2451,6 +2513,30 @@ process_server_config_line_depth(ServerOptions *options, char *line,
|
||||
intptr = &options->required_rsa_size;
|
||||
goto parse_int;
|
||||
|
||||
case sChannelTimeout:
|
||||
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_timeout(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 sDeprecated:
|
||||
case sIgnore:
|
||||
case sUnsupported:
|
||||
@ -2818,6 +2904,8 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
|
||||
printf(" %s", vals[i]);
|
||||
if (code == sAuthenticationMethods && count == 0)
|
||||
printf(" any");
|
||||
else if (code == sChannelTimeout && count == 0)
|
||||
printf(" none");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@ -2986,6 +3074,8 @@ dump_config(ServerOptions *o)
|
||||
o->num_auth_methods, o->auth_methods);
|
||||
dump_cfg_strarray_oneline(sLogVerbose,
|
||||
o->num_log_verbose, o->log_verbose);
|
||||
dump_cfg_strarray_oneline(sChannelTimeout,
|
||||
o->num_channel_timeouts, o->channel_timeouts);
|
||||
|
||||
/* other arguments */
|
||||
for (i = 0; i < o->num_subsystems; i++)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: servconf.h,v 1.157 2022/09/17 10:34:29 djm Exp $ */
|
||||
/* $OpenBSD: servconf.h,v 1.158 2023/01/06 02:47:19 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -230,6 +230,9 @@ typedef struct {
|
||||
u_int64_t timing_secret;
|
||||
char *sk_provider;
|
||||
int required_rsa_size; /* minimum size of RSA keys */
|
||||
|
||||
char **channel_timeouts; /* inactivity timeout by channel type */
|
||||
u_int num_channel_timeouts;
|
||||
} ServerOptions;
|
||||
|
||||
/* Information about the incoming connection as used by Match */
|
||||
@ -287,6 +290,7 @@ TAILQ_HEAD(include_list, include_item);
|
||||
M_CP_STRARRAYOPT(auth_methods, num_auth_methods); \
|
||||
M_CP_STRARRAYOPT(permitted_opens, num_permitted_opens); \
|
||||
M_CP_STRARRAYOPT(permitted_listens, num_permitted_listens); \
|
||||
M_CP_STRARRAYOPT(channel_timeouts, num_channel_timeouts); \
|
||||
M_CP_STRARRAYOPT(log_verbose, num_log_verbose); \
|
||||
} while (0)
|
||||
|
||||
@ -296,6 +300,7 @@ void fill_default_server_options(ServerOptions *);
|
||||
int process_server_config_line(ServerOptions *, char *, const char *, int,
|
||||
int *, struct connection_info *, struct include_list *includes);
|
||||
void process_permitopen(struct ssh *ssh, ServerOptions *options);
|
||||
void process_channel_timeouts(struct ssh *ssh, ServerOptions *);
|
||||
void load_server_config(const char *, struct sshbuf *);
|
||||
void parse_server_config(ServerOptions *, const char *, struct sshbuf *,
|
||||
struct include_list *includes, struct connection_info *, int);
|
||||
|
3
sshd.c
3
sshd.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshd.c,v 1.594 2022/12/16 06:56:47 djm Exp $ */
|
||||
/* $OpenBSD: sshd.c,v 1.595 2023/01/06 02:47:19 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -2158,6 +2158,7 @@ main(int ac, char **av)
|
||||
/* Prepare the channels layer */
|
||||
channel_init_channels(ssh);
|
||||
channel_set_af(ssh, options.address_family);
|
||||
process_channel_timeouts(ssh, &options);
|
||||
process_permitopen(ssh, &options);
|
||||
|
||||
/* Set SO_KEEPALIVE if requested. */
|
||||
|
@ -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.343 2022/09/17 10:34:29 djm Exp $
|
||||
.Dd $Mdocdate: September 17 2022 $
|
||||
.\" $OpenBSD: sshd_config.5,v 1.344 2023/01/06 02:47:19 djm Exp $
|
||||
.Dd $Mdocdate: January 6 2023 $
|
||||
.Dt SSHD_CONFIG 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -395,6 +395,71 @@ from the default set instead of replacing them.
|
||||
.Pp
|
||||
Certificates signed using other algorithms will not be accepted for
|
||||
public key or host-based authentication.
|
||||
.It Cm ChannelTimeout
|
||||
Specifies whether and how quickly
|
||||
.Xr sshd 8
|
||||
should close inactive channels.
|
||||
Timeouts for 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 all sessions 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:command
|
||||
Command execution sessions.
|
||||
.It Cm session:shell
|
||||
Interactive shell sessions.
|
||||
.It Cm session:subsystem:...
|
||||
Subsystem sessions, e.g. for
|
||||
.Xr sftp 1 ,
|
||||
which could be identified as
|
||||
.Cm session:subsystem:sftp .
|
||||
.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 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 ChrootDirectory
|
||||
Specifies the pathname of a directory to
|
||||
.Xr chroot 2
|
||||
|
Loading…
Reference in New Issue
Block a user