- djm@cvs.openbsd.org 2010/07/19 09:15:12
[clientloop.c readconf.c readconf.h ssh.c ssh_config.5] add a "ControlPersist" option that automatically starts a background ssh(1) multiplex master when connecting. This connection can stay alive indefinitely, or can be set to automatically close after a user-specified duration of inactivity. bz#1330 - patch by dwmw2 AT infradead.org, but further hacked on by wmertens AT cisco.com, apb AT cequrux.com, martin-mindrot-bugzilla AT earth.li and myself; "looks ok" markus@
This commit is contained in:
parent
c4bb91c79c
commit
e11e1ea5d4
|
@ -16,6 +16,14 @@
|
||||||
bz#1797: fix swapped args in upload_dir_internal(), breaking recursive
|
bz#1797: fix swapped args in upload_dir_internal(), breaking recursive
|
||||||
upload depth checks and causing verbose printing of transfers to always
|
upload depth checks and causing verbose printing of transfers to always
|
||||||
be turned on; patch from imorgan AT nas.nasa.gov
|
be turned on; patch from imorgan AT nas.nasa.gov
|
||||||
|
- djm@cvs.openbsd.org 2010/07/19 09:15:12
|
||||||
|
[clientloop.c readconf.c readconf.h ssh.c ssh_config.5]
|
||||||
|
add a "ControlPersist" option that automatically starts a background
|
||||||
|
ssh(1) multiplex master when connecting. This connection can stay alive
|
||||||
|
indefinitely, or can be set to automatically close after a user-specified
|
||||||
|
duration of inactivity. bz#1330 - patch by dwmw2 AT infradead.org, but
|
||||||
|
further hacked on by wmertens AT cisco.com, apb AT cequrux.com,
|
||||||
|
martin-mindrot-bugzilla AT earth.li and myself; "looks ok" markus@
|
||||||
|
|
||||||
20100819
|
20100819
|
||||||
- (dtucker) [contrib/ssh-copy-ud.1] Bug #1786: update ssh-copy-id.1 with more
|
- (dtucker) [contrib/ssh-copy-ud.1] Bug #1786: update ssh-copy-id.1 with more
|
||||||
|
|
63
clientloop.c
63
clientloop.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: clientloop.c,v 1.221 2010/06/25 23:15:36 djm Exp $ */
|
/* $OpenBSD: clientloop.c,v 1.222 2010/07/19 09:15:12 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -145,6 +145,9 @@ static volatile sig_atomic_t received_signal = 0;
|
||||||
/* Flag indicating whether the user's terminal is in non-blocking mode. */
|
/* Flag indicating whether the user's terminal is in non-blocking mode. */
|
||||||
static int in_non_blocking_mode = 0;
|
static int in_non_blocking_mode = 0;
|
||||||
|
|
||||||
|
/* Time when backgrounded control master using ControlPersist should exit */
|
||||||
|
static time_t control_persist_exit_time = 0;
|
||||||
|
|
||||||
/* Common data for the client loop code. */
|
/* Common data for the client loop code. */
|
||||||
volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
|
volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
|
||||||
static int escape_char1; /* Escape character. (proto1 only) */
|
static int escape_char1; /* Escape character. (proto1 only) */
|
||||||
|
@ -252,6 +255,34 @@ get_current_time(void)
|
||||||
return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
|
return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets control_persist_exit_time to the absolute time when the
|
||||||
|
* backgrounded control master should exit due to expiry of the
|
||||||
|
* ControlPersist timeout. Sets it to 0 if we are not a backgrounded
|
||||||
|
* control master process, or if there is no ControlPersist timeout.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
set_control_persist_exit_time(void)
|
||||||
|
{
|
||||||
|
if (muxserver_sock == -1 || !options.control_persist
|
||||||
|
|| options.control_persist_timeout == 0)
|
||||||
|
/* not using a ControlPersist timeout */
|
||||||
|
control_persist_exit_time = 0;
|
||||||
|
else if (channel_still_open()) {
|
||||||
|
/* some client connections are still open */
|
||||||
|
if (control_persist_exit_time > 0)
|
||||||
|
debug2("%s: cancel scheduled exit", __func__);
|
||||||
|
control_persist_exit_time = 0;
|
||||||
|
} else if (control_persist_exit_time <= 0) {
|
||||||
|
/* a client connection has recently closed */
|
||||||
|
control_persist_exit_time = time(NULL) +
|
||||||
|
(time_t)options.control_persist_timeout;
|
||||||
|
debug2("%s: schedule exit in %d seconds", __func__,
|
||||||
|
options.control_persist_timeout);
|
||||||
|
}
|
||||||
|
/* else we are already counting down to the timeout */
|
||||||
|
}
|
||||||
|
|
||||||
#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
|
#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
|
||||||
void
|
void
|
||||||
client_x11_get_proto(const char *display, const char *xauth_path,
|
client_x11_get_proto(const char *display, const char *xauth_path,
|
||||||
|
@ -533,6 +564,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
|
||||||
int *maxfdp, u_int *nallocp, int rekeying)
|
int *maxfdp, u_int *nallocp, int rekeying)
|
||||||
{
|
{
|
||||||
struct timeval tv, *tvp;
|
struct timeval tv, *tvp;
|
||||||
|
int timeout_secs;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Add any selections by the channel mechanism. */
|
/* Add any selections by the channel mechanism. */
|
||||||
|
@ -576,16 +608,27 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
|
||||||
/*
|
/*
|
||||||
* Wait for something to happen. This will suspend the process until
|
* Wait for something to happen. This will suspend the process until
|
||||||
* some selected descriptor can be read, written, or has some other
|
* some selected descriptor can be read, written, or has some other
|
||||||
* event pending.
|
* event pending, or a timeout expires.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (options.server_alive_interval == 0 || !compat20)
|
timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
|
||||||
|
if (options.server_alive_interval > 0 && compat20)
|
||||||
|
timeout_secs = options.server_alive_interval;
|
||||||
|
set_control_persist_exit_time();
|
||||||
|
if (control_persist_exit_time > 0) {
|
||||||
|
timeout_secs = MIN(timeout_secs,
|
||||||
|
control_persist_exit_time - time(NULL));
|
||||||
|
if (timeout_secs < 0)
|
||||||
|
timeout_secs = 0;
|
||||||
|
}
|
||||||
|
if (timeout_secs == INT_MAX)
|
||||||
tvp = NULL;
|
tvp = NULL;
|
||||||
else {
|
else {
|
||||||
tv.tv_sec = options.server_alive_interval;
|
tv.tv_sec = timeout_secs;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
tvp = &tv;
|
tvp = &tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
|
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
@ -1478,6 +1521,18 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||||
*/
|
*/
|
||||||
if (FD_ISSET(connection_out, writeset))
|
if (FD_ISSET(connection_out, writeset))
|
||||||
packet_write_poll();
|
packet_write_poll();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are a backgrounded control master, and the
|
||||||
|
* timeout has expired without any active client
|
||||||
|
* connections, then quit.
|
||||||
|
*/
|
||||||
|
if (control_persist_exit_time > 0) {
|
||||||
|
if (time(NULL) >= control_persist_exit_time) {
|
||||||
|
debug("ControlPersist timeout expired");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (readset)
|
if (readset)
|
||||||
xfree(readset);
|
xfree(readset);
|
||||||
|
|
36
readconf.c
36
readconf.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: readconf.c,v 1.186 2010/06/25 23:15:36 djm Exp $ */
|
/* $OpenBSD: readconf.c,v 1.187 2010/07/19 09:15:12 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -128,7 +128,8 @@ typedef enum {
|
||||||
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
|
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
|
||||||
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
|
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
|
||||||
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
|
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
|
||||||
oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
|
oSendEnv, oControlPath, oControlMaster, oControlPersist,
|
||||||
|
oHashKnownHosts,
|
||||||
oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
|
oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
|
||||||
oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
|
oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
|
||||||
oDeprecated, oUnsupported
|
oDeprecated, oUnsupported
|
||||||
|
@ -225,6 +226,7 @@ static struct {
|
||||||
{ "sendenv", oSendEnv },
|
{ "sendenv", oSendEnv },
|
||||||
{ "controlpath", oControlPath },
|
{ "controlpath", oControlPath },
|
||||||
{ "controlmaster", oControlMaster },
|
{ "controlmaster", oControlMaster },
|
||||||
|
{ "controlpersist", oControlPersist },
|
||||||
{ "hashknownhosts", oHashKnownHosts },
|
{ "hashknownhosts", oHashKnownHosts },
|
||||||
{ "tunnel", oTunnel },
|
{ "tunnel", oTunnel },
|
||||||
{ "tunneldevice", oTunnelDevice },
|
{ "tunneldevice", oTunnelDevice },
|
||||||
|
@ -882,6 +884,30 @@ parse_int:
|
||||||
*intptr = value;
|
*intptr = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case oControlPersist:
|
||||||
|
/* no/false/yes/true, or a time spec */
|
||||||
|
intptr = &options->control_persist;
|
||||||
|
arg = strdelim(&s);
|
||||||
|
if (!arg || *arg == '\0')
|
||||||
|
fatal("%.200s line %d: Missing ControlPersist"
|
||||||
|
" argument.", filename, linenum);
|
||||||
|
value = 0;
|
||||||
|
value2 = 0; /* timeout */
|
||||||
|
if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
|
||||||
|
value = 0;
|
||||||
|
else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
|
||||||
|
value = 1;
|
||||||
|
else if ((value2 = convtime(arg)) >= 0)
|
||||||
|
value = 1;
|
||||||
|
else
|
||||||
|
fatal("%.200s line %d: Bad ControlPersist argument.",
|
||||||
|
filename, linenum);
|
||||||
|
if (*activep && *intptr == -1) {
|
||||||
|
*intptr = value;
|
||||||
|
options->control_persist_timeout = value2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case oHashKnownHosts:
|
case oHashKnownHosts:
|
||||||
intptr = &options->hash_known_hosts;
|
intptr = &options->hash_known_hosts;
|
||||||
goto parse_flag;
|
goto parse_flag;
|
||||||
|
@ -1083,6 +1109,8 @@ initialize_options(Options * options)
|
||||||
options->num_send_env = 0;
|
options->num_send_env = 0;
|
||||||
options->control_path = NULL;
|
options->control_path = NULL;
|
||||||
options->control_master = -1;
|
options->control_master = -1;
|
||||||
|
options->control_persist = -1;
|
||||||
|
options->control_persist_timeout = 0;
|
||||||
options->hash_known_hosts = -1;
|
options->hash_known_hosts = -1;
|
||||||
options->tun_open = -1;
|
options->tun_open = -1;
|
||||||
options->tun_local = -1;
|
options->tun_local = -1;
|
||||||
|
@ -1218,6 +1246,10 @@ fill_default_options(Options * options)
|
||||||
options->server_alive_count_max = 3;
|
options->server_alive_count_max = 3;
|
||||||
if (options->control_master == -1)
|
if (options->control_master == -1)
|
||||||
options->control_master = 0;
|
options->control_master = 0;
|
||||||
|
if (options->control_persist == -1) {
|
||||||
|
options->control_persist = 0;
|
||||||
|
options->control_persist_timeout = 0;
|
||||||
|
}
|
||||||
if (options->hash_known_hosts == -1)
|
if (options->hash_known_hosts == -1)
|
||||||
options->hash_known_hosts = 0;
|
options->hash_known_hosts = 0;
|
||||||
if (options->tun_open == -1)
|
if (options->tun_open == -1)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: readconf.h,v 1.85 2010/06/25 23:15:36 djm Exp $ */
|
/* $OpenBSD: readconf.h,v 1.86 2010/07/19 09:15:12 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
|
@ -114,6 +114,8 @@ typedef struct {
|
||||||
|
|
||||||
char *control_path;
|
char *control_path;
|
||||||
int control_master;
|
int control_master;
|
||||||
|
int control_persist; /* ControlPersist flag */
|
||||||
|
int control_persist_timeout; /* ControlPersist timeout (seconds) */
|
||||||
|
|
||||||
int hash_known_hosts;
|
int hash_known_hosts;
|
||||||
|
|
||||||
|
|
117
ssh.c
117
ssh.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: ssh.c,v 1.343 2010/07/12 22:41:13 djm Exp $ */
|
/* $OpenBSD: ssh.c,v 1.344 2010/07/19 09:15:12 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -127,6 +127,15 @@ int no_shell_flag = 0;
|
||||||
*/
|
*/
|
||||||
int stdin_null_flag = 0;
|
int stdin_null_flag = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flag indicating that the current process should be backgrounded and
|
||||||
|
* a new slave launched in the foreground for ControlPersist.
|
||||||
|
*/
|
||||||
|
int need_controlpersist_detach = 0;
|
||||||
|
|
||||||
|
/* Copies of flags for ControlPersist foreground slave */
|
||||||
|
int ostdin_null_flag, ono_shell_flag, ono_tty_flag, otty_flag;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flag indicating that ssh should fork after authentication. This is useful
|
* Flag indicating that ssh should fork after authentication. This is useful
|
||||||
* so that the passphrase can be entered manually, and then ssh goes to the
|
* so that the passphrase can be entered manually, and then ssh goes to the
|
||||||
|
@ -877,6 +886,50 @@ main(int ac, char **av)
|
||||||
return exit_status;
|
return exit_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
control_persist_detach(void)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
debug("%s: backgrounding master process", __func__);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* master (current process) into the background, and make the
|
||||||
|
* foreground process a client of the backgrounded master.
|
||||||
|
*/
|
||||||
|
switch ((pid = fork())) {
|
||||||
|
case -1:
|
||||||
|
fatal("%s: fork: %s", __func__, strerror(errno));
|
||||||
|
case 0:
|
||||||
|
/* Child: master process continues mainloop */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Parent: set up mux slave to connect to backgrounded master */
|
||||||
|
debug2("%s: background process is %ld", __func__, (long)pid);
|
||||||
|
stdin_null_flag = ostdin_null_flag;
|
||||||
|
no_shell_flag = ono_shell_flag;
|
||||||
|
no_tty_flag = ono_tty_flag;
|
||||||
|
tty_flag = otty_flag;
|
||||||
|
close(muxserver_sock);
|
||||||
|
muxserver_sock = -1;
|
||||||
|
muxclient(options.control_path);
|
||||||
|
/* muxclient() doesn't return on success. */
|
||||||
|
fatal("Failed to connect to new control master");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do fork() after authentication. Used by "ssh -f" */
|
||||||
|
static void
|
||||||
|
fork_postauth(void)
|
||||||
|
{
|
||||||
|
if (need_controlpersist_detach)
|
||||||
|
control_persist_detach();
|
||||||
|
debug("forking to background");
|
||||||
|
fork_after_authentication_flag = 0;
|
||||||
|
if (daemon(1, 1) < 0)
|
||||||
|
fatal("daemon() failed: %.200s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for remote forward global requests */
|
/* Callback for remote forward global requests */
|
||||||
static void
|
static void
|
||||||
ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
||||||
|
@ -904,12 +957,8 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
||||||
}
|
}
|
||||||
if (++remote_forward_confirms_received == options.num_remote_forwards) {
|
if (++remote_forward_confirms_received == options.num_remote_forwards) {
|
||||||
debug("All remote forwarding requests processed");
|
debug("All remote forwarding requests processed");
|
||||||
if (fork_after_authentication_flag) {
|
if (fork_after_authentication_flag)
|
||||||
fork_after_authentication_flag = 0;
|
fork_postauth();
|
||||||
if (daemon(1, 1) < 0)
|
|
||||||
fatal("daemon() failed: %.200s",
|
|
||||||
strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1153,12 +1202,13 @@ ssh_session(void)
|
||||||
* If requested and we are not interested in replies to remote
|
* If requested and we are not interested in replies to remote
|
||||||
* forwarding requests, then let ssh continue in the background.
|
* forwarding requests, then let ssh continue in the background.
|
||||||
*/
|
*/
|
||||||
if (fork_after_authentication_flag &&
|
if (fork_after_authentication_flag) {
|
||||||
(!options.exit_on_forward_failure ||
|
if (options.exit_on_forward_failure &&
|
||||||
options.num_remote_forwards == 0)) {
|
options.num_remote_forwards > 0) {
|
||||||
fork_after_authentication_flag = 0;
|
debug("deferring postauth fork until remote forward "
|
||||||
if (daemon(1, 1) < 0)
|
"confirmation received");
|
||||||
fatal("daemon() failed: %.200s", strerror(errno));
|
} else
|
||||||
|
fork_postauth();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1281,6 +1331,31 @@ ssh_session2(void)
|
||||||
/* XXX should be pre-session */
|
/* XXX should be pre-session */
|
||||||
ssh_init_forwarding();
|
ssh_init_forwarding();
|
||||||
|
|
||||||
|
/* Start listening for multiplex clients */
|
||||||
|
muxserver_listen();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are in control persist mode, then prepare to background
|
||||||
|
* ourselves and have a foreground client attach as a control
|
||||||
|
* slave. NB. we must save copies of the flags that we override for
|
||||||
|
* the backgrounding, since we defer attachment of the slave until
|
||||||
|
* after the connection is fully established (in particular,
|
||||||
|
* async rfwd replies have been received for ExitOnForwardFailure).
|
||||||
|
*/
|
||||||
|
if (options.control_persist && muxserver_sock != -1) {
|
||||||
|
ostdin_null_flag = stdin_null_flag;
|
||||||
|
ono_shell_flag = no_shell_flag;
|
||||||
|
ono_tty_flag = no_tty_flag;
|
||||||
|
otty_flag = tty_flag;
|
||||||
|
stdin_null_flag = 1;
|
||||||
|
no_shell_flag = 1;
|
||||||
|
no_tty_flag = 1;
|
||||||
|
tty_flag = 0;
|
||||||
|
if (!fork_after_authentication_flag)
|
||||||
|
need_controlpersist_detach = 1;
|
||||||
|
fork_after_authentication_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
|
if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
|
||||||
id = ssh_session2_open();
|
id = ssh_session2_open();
|
||||||
|
|
||||||
|
@ -1299,19 +1374,17 @@ ssh_session2(void)
|
||||||
options.permit_local_command)
|
options.permit_local_command)
|
||||||
ssh_local_cmd(options.local_command);
|
ssh_local_cmd(options.local_command);
|
||||||
|
|
||||||
/* Start listening for multiplex clients */
|
|
||||||
muxserver_listen();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If requested and we are not interested in replies to remote
|
* If requested and we are not interested in replies to remote
|
||||||
* forwarding requests, then let ssh continue in the background.
|
* forwarding requests, then let ssh continue in the background.
|
||||||
*/
|
*/
|
||||||
if (fork_after_authentication_flag &&
|
if (fork_after_authentication_flag) {
|
||||||
(!options.exit_on_forward_failure ||
|
if (options.exit_on_forward_failure &&
|
||||||
options.num_remote_forwards == 0)) {
|
options.num_remote_forwards > 0) {
|
||||||
fork_after_authentication_flag = 0;
|
debug("deferring postauth fork until remote forward "
|
||||||
if (daemon(1, 1) < 0)
|
"confirmation received");
|
||||||
fatal("daemon() failed: %.200s", strerror(errno));
|
} else
|
||||||
|
fork_postauth();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.use_roaming)
|
if (options.use_roaming)
|
||||||
|
|
26
ssh_config.5
26
ssh_config.5
|
@ -34,8 +34,8 @@
|
||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" $OpenBSD: ssh_config.5,v 1.136 2010/07/12 22:41:13 djm Exp $
|
.\" $OpenBSD: ssh_config.5,v 1.137 2010/07/19 09:15:12 djm Exp $
|
||||||
.Dd $Mdocdate: July 12 2010 $
|
.Dd $Mdocdate: July 19 2010 $
|
||||||
.Dt SSH_CONFIG 5
|
.Dt SSH_CONFIG 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -319,6 +319,28 @@ It is recommended that any
|
||||||
used for opportunistic connection sharing include
|
used for opportunistic connection sharing include
|
||||||
at least %h, %p, and %r.
|
at least %h, %p, and %r.
|
||||||
This ensures that shared connections are uniquely identified.
|
This ensures that shared connections are uniquely identified.
|
||||||
|
.It Cm ControlPersist
|
||||||
|
When used in conjunction with
|
||||||
|
.Cm ControlMaster ,
|
||||||
|
specifies that the master connection should remain open
|
||||||
|
in the background (waiting for future client connections)
|
||||||
|
after the initial client connection has been closed.
|
||||||
|
If set to
|
||||||
|
.Dq no ,
|
||||||
|
then the master connection will not be placed into the background,
|
||||||
|
and will close as soon as the initial client connection is closed.
|
||||||
|
If set to
|
||||||
|
.Dq yes ,
|
||||||
|
then the master connection will remain in the background indefinitely
|
||||||
|
(until killed or closed via a mechanism such as the
|
||||||
|
.Xr ssh 1
|
||||||
|
.Dq Fl O No exit
|
||||||
|
option).
|
||||||
|
If set to a time in seconds, or a time in any of the formats documented in
|
||||||
|
.Xr sshd_config 5 ,
|
||||||
|
then the backgrounded master connection will automatically terminate
|
||||||
|
after it has remained idle (with no client connections) for the
|
||||||
|
specified time.
|
||||||
.It Cm DynamicForward
|
.It Cm DynamicForward
|
||||||
Specifies that a TCP port on the local machine be forwarded
|
Specifies that a TCP port on the local machine be forwarded
|
||||||
over the secure channel, and the application
|
over the secure channel, and the application
|
||||||
|
|
Loading…
Reference in New Issue