From a917e973a1b90b40ff1e950df083364b48fc6c78 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 23 Jul 2021 04:04:52 +0000 Subject: [PATCH] upstream: Add a ForkAfterAuthentication ssh_config(5) counterpart to the ssh(1) -f flag. Last part of GHPR231 from Volker Diels-Grabsch. ok dtucker OpenBSD-Commit-ID: b18aeda12efdebe2093d55263c90fe4ea0bce0d3 --- clientloop.c | 7 ++----- readconf.c | 13 +++++++++++-- readconf.h | 3 ++- ssh.1 | 8 +++++++- ssh.c | 23 ++++++++--------------- ssh_config.5 | 41 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 70 insertions(+), 25 deletions(-) diff --git a/clientloop.c b/clientloop.c index 7eb6b63bd..bfcd50c26 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.368 2021/07/23 04:00:59 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.369 2021/07/23 04:04:52 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -115,9 +115,6 @@ /* import options */ extern Options options; -/* Flag indicating that ssh should daemonise after authentication is complete */ -extern int fork_after_authentication_flag; - /* Control socket */ extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */ @@ -1240,7 +1237,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, fatal_f("pledge(): %s", strerror(errno)); } else if (!option_clear_or_none(options.proxy_command) || - fork_after_authentication_flag) { + options.fork_after_authentication) { debug("pledge: proc"); if (pledge("stdio cpath unix inet dns proc tty", NULL) == -1) fatal_f("pledge(): %s", strerror(errno)); diff --git a/readconf.c b/readconf.c index 681e78f76..03369a086 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.360 2021/07/23 04:00:59 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.361 2021/07/23 04:04:52 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -168,7 +168,7 @@ typedef enum { oLocalCommand, oPermitLocalCommand, oRemoteCommand, oVisualHostKey, oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull, - oIgnoreUnknown, oProxyUseFdpass, + oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass, oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, @@ -300,6 +300,7 @@ static struct { { "requesttty", oRequestTTY }, { "sessiontype", oSessionType }, { "stdinnull", oStdinNull }, + { "forkafterauthentication", oForkAfterAuthentication }, { "proxyusefdpass", oProxyUseFdpass }, { "canonicaldomains", oCanonicalDomains }, { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, @@ -1959,6 +1960,10 @@ parse_pubkey_algos: intptr = &options->stdin_null; goto parse_flag; + case oForkAfterAuthentication: + intptr = &options->fork_after_authentication; + goto parse_flag; + case oIgnoreUnknown: charptr = &options->ignored_unknown; goto parse_string; @@ -2383,6 +2388,7 @@ initialize_options(Options * options) options->request_tty = -1; options->session_type = -1; options->stdin_null = -1; + options->fork_after_authentication = -1; options->proxy_use_fdpass = -1; options->ignored_unknown = NULL; options->num_canonical_domains = 0; @@ -2573,6 +2579,8 @@ fill_default_options(Options * options) options->session_type = SESSION_TYPE_DEFAULT; if (options->stdin_null == -1) options->stdin_null = 0; + if (options->fork_after_authentication == -1) + options->fork_after_authentication = 0; if (options->proxy_use_fdpass == -1) options->proxy_use_fdpass = 0; if (options->canonicalize_max_dots == -1) @@ -3252,6 +3260,7 @@ dump_client_config(Options *o, const char *host) dump_cfg_fmtint(oRequestTTY, o->request_tty); dump_cfg_fmtint(oSessionType, o->session_type); dump_cfg_fmtint(oStdinNull, o->stdin_null); + dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication); dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); diff --git a/readconf.h b/readconf.h index 08ca9e7a7..f7d53b067 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.143 2021/07/23 04:00:59 djm Exp $ */ +/* $OpenBSD: readconf.h,v 1.144 2021/07/23 04:04:52 djm Exp $ */ /* * Author: Tatu Ylonen @@ -148,6 +148,7 @@ typedef struct { int request_tty; int session_type; int stdin_null; + int fork_after_authentication; int proxy_use_fdpass; diff --git a/ssh.1 b/ssh.1 index b31175ffe..46ad55ad4 100644 --- a/ssh.1 +++ b/ssh.1 @@ -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.1,v 1.423 2021/07/23 04:00:59 djm Exp $ +.\" $OpenBSD: ssh.1,v 1.424 2021/07/23 04:04:52 djm Exp $ .Dd $Mdocdate: July 23 2021 $ .Dt SSH 1 .Os @@ -259,6 +259,11 @@ then a client started with .Fl f will wait for all remote port forwards to be successfully established before placing itself in the background. +Refer to the description of +.Cm ForkAfterAuthentication +in +.Xr ssh_config 5 +for details. .Pp .It Fl G Causes @@ -508,6 +513,7 @@ For full details of the options listed below, and their possible values, see .It EscapeChar .It ExitOnForwardFailure .It FingerprintHash +.It ForkAfterAuthentication .It ForwardAgent .It ForwardX11 .It ForwardX11Timeout diff --git a/ssh.c b/ssh.c index 8a5aaa7ef..62a64ecc1 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.563 2021/07/23 04:00:59 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.564 2021/07/23 04:04:52 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -135,13 +135,6 @@ int need_controlpersist_detach = 0; /* Copies of flags for ControlPersist foreground mux-client */ int ostdin_null_flag, osession_type, otty_flag, orequest_tty; -/* - * 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 - * background. - */ -int fork_after_authentication_flag = 0; - /* * General data structure for command line options and options configurable * in configuration files. See readconf.h. @@ -720,7 +713,7 @@ main(int ac, char **av) options.stdin_null = 1; break; case 'f': - fork_after_authentication_flag = 1; + options.fork_after_authentication = 1; options.stdin_null = 1; break; case 'x': @@ -1324,7 +1317,7 @@ main(int ac, char **av) fatal("Cannot execute command-line and remote command."); /* Cannot fork to background if no command. */ - if (fork_after_authentication_flag && sshbuf_len(command) == 0 && + if (options.fork_after_authentication && sshbuf_len(command) == 0 && options.remote_command == NULL && options.session_type != SESSION_TYPE_NONE) fatal("Cannot fork into background without a command " @@ -1752,7 +1745,7 @@ fork_postauth(void) if (need_controlpersist_detach) control_persist_detach(); debug("forking to background"); - fork_after_authentication_flag = 0; + options.fork_after_authentication = 0; if (daemon(1, 1) == -1) fatal("daemon() failed: %.200s", strerror(errno)); if (stdfd_devnull(1, 1, !(log_is_on_stderr() && debug_flag)) == -1) @@ -1766,7 +1759,7 @@ forwarding_success(void) return; if (--forward_confirms_pending == 0) { debug_f("all expected forwarding replies received"); - if (fork_after_authentication_flag) + if (options.fork_after_authentication) fork_postauth(); } else { debug2_f("%d expected forwarding replies remaining", @@ -2145,11 +2138,11 @@ ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) options.stdin_null = 1; options.session_type = SESSION_TYPE_NONE; tty_flag = 0; - if (!fork_after_authentication_flag && + if (!options.fork_after_authentication && (osession_type != SESSION_TYPE_NONE || options.stdio_forward_host != NULL)) need_controlpersist_detach = 1; - fork_after_authentication_flag = 1; + options.fork_after_authentication = 1; } /* * ControlPersist mux listen socket setup failed, attempt the @@ -2196,7 +2189,7 @@ ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) * If requested and we are not interested in replies to remote * forwarding requests, then let ssh continue in the background. */ - if (fork_after_authentication_flag) { + if (options.fork_after_authentication) { if (options.exit_on_forward_failure && options.num_remote_forwards > 0) { debug("deferring postauth fork until remote forward " diff --git a/ssh_config.5 b/ssh_config.5 index eb417c95a..94a7ea14d 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -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.358 2021/07/23 04:00:59 djm Exp $ +.\" $OpenBSD: ssh_config.5,v 1.359 2021/07/23 04:04:52 djm Exp $ .Dd $Mdocdate: July 23 2021 $ .Dt SSH_CONFIG 5 .Os @@ -676,6 +676,45 @@ Valid options are: and .Cm sha256 (the default). +.It Cm ForkAfterAuthentication +Requests +.Nm ssh +to go to background just before command execution. +This is useful if +.Nm ssh +is going to ask for passwords or passphrases, but the user +wants it in the background. +This implies the +.Cm StdinNull +configuration option being set to +.Dq yes . +The recommended way to start X11 programs at a remote site is with +something like +.Ic ssh -f host xterm , +which is the same as +.Ic ssh host xterm +if the +.Cm ForkAfterAuthentication +configuration option is set to +.Dq yes . +.Pp +If the +.Cm ExitOnForwardFailure +configuration option is set to +.Dq yes , +then a client started with the +.Cm ForkAfterAuthentication +configuration option being set to +.Dq yes +will wait for all remote port forwards to be successfully established +before placing itself in the background. +The argument to this keyword must be +.Cm yes +(same as the +.Fl f +option) or +.Cm no +(the default). .It Cm ForwardAgent Specifies whether the connection to the authentication agent (if any) will be forwarded to the remote machine.