Mailing List Archive

[PATCH] Add ssh_config equivalents of -N, -n and -f
Dear OpenSSH developers,

I kindly ask you to review the attached set of patches which
introduce ssh_config equivalents of the flags -N, -n and -f in
a straight forward way:

* NoShell for -N

* StdinNull for -n

* ForkAfterAuthentication for -f

The ssh_config names were derived directly from the internal flag
names, e.g. no_shell_flag was moved to option.no_shell and hence
the ssh_config name became NoShell. The man pages ssh(1) and
ssh_config(5) are adjusted accordingly.

As a final remark, I noticed that the variable ono_shell_flag (not to
be confused with no_shell_flag) is only assigned once and never used.
So I assume this is dead code and I'm proposing a patch to remove it.


Regards,
Volker

--
Volker Diels-Grabsch
----<<<((()))>>>----
Re: [PATCH] Add ssh_config equivalents of -N, -n and -f [ In reply to ]
Dear OpenSSH developers,

For your convenience, I also created a pull request:

* https://github.com/openssh/openssh-portable/pull/231


Best regards,
Volker


Volker Diels-Grabsch wrote:
> Dear OpenSSH developers,
>
> I kindly ask you to review the attached set of patches which
> introduce ssh_config equivalents of the flags -N, -n and -f in
> a straight forward way:
>
> * NoShell for -N
>
> * StdinNull for -n
>
> * ForkAfterAuthentication for -f
>
> The ssh_config names were derived directly from the internal flag
> names, e.g. no_shell_flag was moved to option.no_shell and hence
> the ssh_config name became NoShell. The man pages ssh(1) and
> ssh_config(5) are adjusted accordingly.
>
> As a final remark, I noticed that the variable ono_shell_flag (not to
> be confused with no_shell_flag) is only assigned once and never used.
> So I assume this is dead code and I'm proposing a patch to remove it.
>
>
> Regards,
> Volker
>
> --
> Volker Diels-Grabsch
> ----<<<((()))>>>----

> commit cc8f234a71985b6c5a2b4b2323c74db3725cc41b
> Author: Volker Diels-Grabsch <v@njh.eu>
> Date: Sun Feb 21 00:47:05 2021 +0100
>
> Add ssh_config option NoShell with same behavior as -N
>
> diff --git a/clientloop.c b/clientloop.c
> index 60b46d1..21b9c54 100644
> --- a/clientloop.c
> +++ b/clientloop.c
> @@ -118,9 +118,6 @@ extern Options options;
> /* Flag indicating that stdin should be redirected from /dev/null. */
> extern int stdin_null_flag;
>
> -/* Flag indicating that no shell has been requested */
> -extern int no_shell_flag;
> -
> /* Flag indicating that ssh should daemonise after authentication is complete */
> extern int fork_after_authentication_flag;
>
> @@ -1434,7 +1431,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
> * exit status to be returned. In that case, clear error code if the
> * connection was deliberately terminated at this end.
> */
> - if (no_shell_flag && received_signal == SIGTERM) {
> + if (options.no_shell && received_signal == SIGTERM) {
> received_signal = 0;
> exit_status = 0;
> }
> @@ -2439,7 +2436,7 @@ client_stop_mux(void)
> * If we are in persist mode, or don't have a shell, signal that we
> * should close when all active channels are closed.
> */
> - if (options.control_persist || no_shell_flag) {
> + if (options.control_persist || options.no_shell) {
> session_closed = 1;
> setproctitle("[stopped mux]");
> }
> diff --git a/readconf.c b/readconf.c
> index 554efd7..cdbb298 100644
> --- a/readconf.c
> +++ b/readconf.c
> @@ -166,7 +166,8 @@ typedef enum {
> oTunnel, oTunnelDevice,
> oLocalCommand, oPermitLocalCommand, oRemoteCommand,
> oVisualHostKey,
> - oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
> + oKexAlgorithms, oIPQoS, oRequestTTY, oNoShell,
> + oIgnoreUnknown, oProxyUseFdpass,
> oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
> oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
> oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
> @@ -294,6 +295,7 @@ static struct {
> { "kexalgorithms", oKexAlgorithms },
> { "ipqos", oIPQoS },
> { "requesttty", oRequestTTY },
> + { "noshell", oNoShell },
> { "proxyusefdpass", oProxyUseFdpass },
> { "canonicaldomains", oCanonicalDomains },
> { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
> @@ -1694,6 +1696,10 @@ parse_keytypes:
> multistate_ptr = multistate_requesttty;
> goto parse_multistate;
>
> + case oNoShell:
> + intptr = &options->no_shell;
> + goto parse_flag;
> +
> case oIgnoreUnknown:
> charptr = &options->ignored_unknown;
> goto parse_string;
> @@ -2050,6 +2056,7 @@ initialize_options(Options * options)
> options->ip_qos_interactive = -1;
> options->ip_qos_bulk = -1;
> options->request_tty = -1;
> + options->no_shell = -1;
> options->proxy_use_fdpass = -1;
> options->ignored_unknown = NULL;
> options->num_canonical_domains = 0;
> @@ -2230,6 +2237,8 @@ fill_default_options(Options * options)
> options->ip_qos_bulk = IPTOS_DSCP_CS1;
> if (options->request_tty == -1)
> options->request_tty = REQUEST_TTY_AUTO;
> + if (options->no_shell == -1)
> + options->no_shell = 0;
> if (options->proxy_use_fdpass == -1)
> options->proxy_use_fdpass = 0;
> if (options->canonicalize_max_dots == -1)
> @@ -2788,6 +2797,7 @@ dump_client_config(Options *o, const char *host)
> dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
> dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
> dump_cfg_fmtint(oRequestTTY, o->request_tty);
> + dump_cfg_fmtint(oNoShell, o->no_shell);
> 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 d6a1555..50261ee 100644
> --- a/readconf.h
> +++ b/readconf.h
> @@ -143,6 +143,7 @@ typedef struct {
> int visual_host_key;
>
> int request_tty;
> + int no_shell;
>
> int proxy_use_fdpass;
>
> diff --git a/ssh.1 b/ssh.1
> index 5553178..ac06025 100644
> --- a/ssh.1
> +++ b/ssh.1
> @@ -425,6 +425,11 @@ keyword for more information.
> .It Fl N
> Do not execute a remote command.
> This is useful for just forwarding ports.
> +Refer to the description of
> +.Cm NoShell
> +in
> +.Xr ssh_config 5
> +for details.
> .Pp
> .It Fl n
> Redirects stdin from
> diff --git a/ssh.c b/ssh.c
> index f34ca0d..ae8144e 100644
> --- a/ssh.c
> +++ b/ssh.c
> @@ -126,9 +126,6 @@ int debug_flag = 0;
> /* Flag indicating whether a tty should be requested */
> int tty_flag = 0;
>
> -/* don't exec a shell */
> -int no_shell_flag = 0;
> -
> /*
> * Flag indicating that nothing should be read from stdin. This can be set
> * on the command line.
> @@ -933,7 +930,7 @@ main(int ac, char **av)
> exit(255);
> }
> options.request_tty = REQUEST_TTY_NO;
> - no_shell_flag = 1;
> + options.no_shell = 1;
> break;
> case 'q':
> options.log_level = SYSLOG_LEVEL_QUIET;
> @@ -1036,7 +1033,7 @@ main(int ac, char **av)
> #endif
> break;
> case 'N':
> - no_shell_flag = 1;
> + options.no_shell = 1;
> options.request_tty = REQUEST_TTY_NO;
> break;
> case 'T':
> @@ -1349,7 +1346,7 @@ main(int ac, char **av)
>
> /* Cannot fork to background if no command. */
> if (fork_after_authentication_flag && sshbuf_len(command) == 0 &&
> - options.remote_command == NULL && !no_shell_flag)
> + options.remote_command == NULL && !options.no_shell)
> fatal("Cannot fork into background without a command "
> "to execute.");
>
> @@ -2065,7 +2062,7 @@ ssh_session2_open(struct ssh *ssh)
> debug3("%s: channel_new: %d", __func__, c->self);
>
> channel_send_open(ssh, c->self);
> - if (!no_shell_flag)
> + if (!options.no_shell)
> channel_register_open_confirm(ssh, c->self,
> ssh_session2_setup, NULL);
>
> @@ -2114,11 +2111,11 @@ ssh_session2(struct ssh *ssh, struct passwd *pw)
> */
> if (options.control_persist && muxserver_sock != -1) {
> ostdin_null_flag = stdin_null_flag;
> - ono_shell_flag = no_shell_flag;
> + ono_shell_flag = options.no_shell;
> orequest_tty = options.request_tty;
> otty_flag = tty_flag;
> stdin_null_flag = 1;
> - no_shell_flag = 1;
> + options.no_shell = 1;
> tty_flag = 0;
> if (!fork_after_authentication_flag)
> need_controlpersist_detach = 1;
> @@ -2131,7 +2128,7 @@ ssh_session2(struct ssh *ssh, struct passwd *pw)
> if (options.control_persist && muxserver_sock == -1)
> ssh_init_stdio_forwarding(ssh);
>
> - if (!no_shell_flag)
> + if (!options.no_shell)
> id = ssh_session2_open(ssh);
> else {
> ssh_packet_set_interactive(ssh,
> diff --git a/ssh_config.5 b/ssh_config.5
> index 6be1f1a..5a9ee10 100644
> --- a/ssh_config.5
> +++ b/ssh_config.5
> @@ -1222,6 +1222,16 @@ The argument to this keyword must be
> or
> .Cm no
> (the default).
> +.It Cm NoShell
> +Do not execute a remote command.
> +This is useful for just forwarding ports.
> +The argument to this keyword must be
> +.Cm yes
> +(same as the
> +.Fl N
> +option) or
> +.Cm no
> +(the default).
> .It Cm NumberOfPasswordPrompts
> Specifies the number of password prompts before giving up.
> The argument to this keyword must be an integer.

> commit fb21e68322281f4640841fb4f0d8f0589ccd6266
> Author: Volker Diels-Grabsch <v@njh.eu>
> Date: Sun Feb 21 02:49:54 2021 +0100
>
> Add ssh_config option StdinNull with same behavior as -n
>
> diff --git a/clientloop.c b/clientloop.c
> index 21b9c54..690b776 100644
> --- a/clientloop.c
> +++ b/clientloop.c
> @@ -115,9 +115,6 @@
> /* import options */
> extern Options options;
>
> -/* Flag indicating that stdin should be redirected from /dev/null. */
> -extern int stdin_null_flag;
> -
> /* Flag indicating that ssh should daemonise after authentication is complete */
> extern int fork_after_authentication_flag;
>
> diff --git a/mux.c b/mux.c
> index 376f0d7..84d7467 100644
> --- a/mux.c
> +++ b/mux.c
> @@ -71,7 +71,6 @@
> /* from ssh.c */
> extern int tty_flag;
> extern Options options;
> -extern int stdin_null_flag;
> extern char *host;
> extern int subsystem_flag;
> extern struct sshbuf *command;
> @@ -1913,7 +1912,7 @@ mux_client_request_session(int fd)
>
> ssh_signal(SIGPIPE, SIG_IGN);
>
> - if (stdin_null_flag) {
> + if (options.stdin_null) {
> if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
> fatal("open(/dev/null): %s", strerror(errno));
> if (dup2(devnull, STDIN_FILENO) == -1)
> @@ -2148,7 +2147,7 @@ mux_client_request_stdio_fwd(int fd)
>
> ssh_signal(SIGPIPE, SIG_IGN);
>
> - if (stdin_null_flag) {
> + if (options.stdin_null) {
> if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
> fatal("open(/dev/null): %s", strerror(errno));
> if (dup2(devnull, STDIN_FILENO) == -1)
> diff --git a/readconf.c b/readconf.c
> index cdbb298..88e6408 100644
> --- a/readconf.c
> +++ b/readconf.c
> @@ -166,7 +166,7 @@ typedef enum {
> oTunnel, oTunnelDevice,
> oLocalCommand, oPermitLocalCommand, oRemoteCommand,
> oVisualHostKey,
> - oKexAlgorithms, oIPQoS, oRequestTTY, oNoShell,
> + oKexAlgorithms, oIPQoS, oRequestTTY, oNoShell, oStdinNull,
> oIgnoreUnknown, oProxyUseFdpass,
> oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
> oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
> @@ -296,6 +296,7 @@ static struct {
> { "ipqos", oIPQoS },
> { "requesttty", oRequestTTY },
> { "noshell", oNoShell },
> + { "stdinnull", oStdinNull },
> { "proxyusefdpass", oProxyUseFdpass },
> { "canonicaldomains", oCanonicalDomains },
> { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
> @@ -1700,6 +1701,10 @@ parse_keytypes:
> intptr = &options->no_shell;
> goto parse_flag;
>
> + case oStdinNull:
> + intptr = &options->stdin_null;
> + goto parse_flag;
> +
> case oIgnoreUnknown:
> charptr = &options->ignored_unknown;
> goto parse_string;
> @@ -2057,6 +2062,7 @@ initialize_options(Options * options)
> options->ip_qos_bulk = -1;
> options->request_tty = -1;
> options->no_shell = -1;
> + options->stdin_null = -1;
> options->proxy_use_fdpass = -1;
> options->ignored_unknown = NULL;
> options->num_canonical_domains = 0;
> @@ -2239,6 +2245,8 @@ fill_default_options(Options * options)
> options->request_tty = REQUEST_TTY_AUTO;
> if (options->no_shell == -1)
> options->no_shell = 0;
> + if (options->stdin_null == -1)
> + options->stdin_null = 0;
> if (options->proxy_use_fdpass == -1)
> options->proxy_use_fdpass = 0;
> if (options->canonicalize_max_dots == -1)
> @@ -2798,6 +2806,7 @@ dump_client_config(Options *o, const char *host)
> dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
> dump_cfg_fmtint(oRequestTTY, o->request_tty);
> dump_cfg_fmtint(oNoShell, o->no_shell);
> + dump_cfg_fmtint(oStdinNull, o->stdin_null);
> 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 50261ee..5de3e62 100644
> --- a/readconf.h
> +++ b/readconf.h
> @@ -144,6 +144,7 @@ typedef struct {
>
> int request_tty;
> int no_shell;
> + int stdin_null;
>
> int proxy_use_fdpass;
>
> diff --git a/ssh.1 b/ssh.1
> index ac06025..c8d8489 100644
> --- a/ssh.1
> +++ b/ssh.1
> @@ -451,6 +451,11 @@ program will be put in the background.
> needs to ask for a password or passphrase; see also the
> .Fl f
> option.)
> +Refer to the description of
> +.Cm StdinNull
> +in
> +.Xr ssh_config 5
> +for details.
> .Pp
> .It Fl O Ar ctl_cmd
> Control an active connection multiplexing master process.
> diff --git a/ssh.c b/ssh.c
> index ae8144e..dd5195e 100644
> --- a/ssh.c
> +++ b/ssh.c
> @@ -126,12 +126,6 @@ int debug_flag = 0;
> /* Flag indicating whether a tty should be requested */
> int tty_flag = 0;
>
> -/*
> - * Flag indicating that nothing should be read from stdin. This can be set
> - * on the command line.
> - */
> -int stdin_null_flag = 0;
> -
> /*
> * Flag indicating that the current process should be backgrounded and
> * a new mux-client launched in the foreground for ControlPersist.
> @@ -734,11 +728,11 @@ main(int ac, char **av)
> options.address_family = AF_INET6;
> break;
> case 'n':
> - stdin_null_flag = 1;
> + options.stdin_null = 1;
> break;
> case 'f':
> fork_after_authentication_flag = 1;
> - stdin_null_flag = 1;
> + options.stdin_null = 1;
> break;
> case 'x':
> options.forward_x11 = 0;
> @@ -1366,7 +1360,7 @@ main(int ac, char **av)
> (muxclient_command && muxclient_command != SSHMUX_COMMAND_PROXY))
> tty_flag = 0;
> /* Do not allocate a tty if stdin is not a tty. */
> - if ((!isatty(fileno(stdin)) || stdin_null_flag) &&
> + if ((!isatty(fileno(stdin)) || options.stdin_null) &&
> options.request_tty != REQUEST_TTY_FORCE) {
> if (tty_flag)
> logit("Pseudo-terminal will not be allocated because "
> @@ -1712,7 +1706,7 @@ control_persist_detach(void)
> default:
> /* Parent: set up mux client to connect to backgrounded master */
> debug2("%s: background process is %ld", __func__, (long)pid);
> - stdin_null_flag = ostdin_null_flag;
> + options.stdin_null = ostdin_null_flag;
> options.request_tty = orequest_tty;
> tty_flag = otty_flag;
> close(muxserver_sock);
> @@ -2029,7 +2023,7 @@ ssh_session2_open(struct ssh *ssh)
> Channel *c;
> int window, packetmax, in, out, err;
>
> - if (stdin_null_flag) {
> + if (options.stdin_null) {
> in = open(_PATH_DEVNULL, O_RDONLY);
> } else {
> in = dup(STDIN_FILENO);
> @@ -2110,11 +2104,11 @@ ssh_session2(struct ssh *ssh, struct passwd *pw)
> * async rfwd replies have been received for ExitOnForwardFailure).
> */
> if (options.control_persist && muxserver_sock != -1) {
> - ostdin_null_flag = stdin_null_flag;
> + ostdin_null_flag = options.stdin_null;
> ono_shell_flag = options.no_shell;
> orequest_tty = options.request_tty;
> otty_flag = tty_flag;
> - stdin_null_flag = 1;
> + options.stdin_null = 1;
> options.no_shell = 1;
> tty_flag = 0;
> if (!fork_after_authentication_flag)
> diff --git a/ssh_config.5 b/ssh_config.5
> index 5a9ee10..345626d 100644
> --- a/ssh_config.5
> +++ b/ssh_config.5
> @@ -1584,6 +1584,33 @@ be sent to the server.
> Similarly to
> .Cm SendEnv ,
> the server must be prepared to accept the environment variable.
> +.It Cm StdinNull
> +Redirects stdin from
> +.Pa /dev/null
> +(actually, prevents reading from stdin).
> +This must be used when
> +.Nm ssh
> +is run in the background.
> +A common trick is to use this to run X11 programs on a remote machine.
> +For example,
> +.Ic ssh shadows.cs.hut.fi emacs &
> +will start an emacs on shadows.cs.hut.fi, and the X11
> +connection will be automatically forwarded over an encrypted channel.
> +The
> +.Nm ssh
> +program will be put in the background.
> +(This does not work if
> +.Nm ssh
> +needs to ask for a password or passphrase; see also the
> +.Fl f
> +option.)
> +The argument to this keyword must be
> +.Cm yes
> +(same as the
> +.Fl n
> +option) or
> +.Cm no
> +(the default).
> .It Cm StreamLocalBindMask
> Sets the octal file creation mode mask
> .Pq umask

> commit 626845489dd712ee25cec79d255aaf61c1cc629e
> Author: Volker Diels-Grabsch <v@njh.eu>
> Date: Sun Feb 21 03:18:49 2021 +0100
>
> Remove dead variable ono_shell_flag which is set once but never used
>
> diff --git a/ssh.c b/ssh.c
> index dd5195e..8533763 100644
> --- a/ssh.c
> +++ b/ssh.c
> @@ -133,7 +133,7 @@ int tty_flag = 0;
> int need_controlpersist_detach = 0;
>
> /* Copies of flags for ControlPersist foreground mux-client */
> -int ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty;
> +int ostdin_null_flag, otty_flag, orequest_tty;
>
> /*
> * Flag indicating that ssh should fork after authentication. This is useful
> @@ -2105,7 +2105,6 @@ ssh_session2(struct ssh *ssh, struct passwd *pw)
> */
> if (options.control_persist && muxserver_sock != -1) {
> ostdin_null_flag = options.stdin_null;
> - ono_shell_flag = options.no_shell;
> orequest_tty = options.request_tty;
> otty_flag = tty_flag;
> options.stdin_null = 1;

> commit 869c8b5108dc413afffd7f8520c1075137cc015c
> Author: Volker Diels-Grabsch <v@njh.eu>
> Date: Sun Feb 21 03:11:37 2021 +0100
>
> Add ssh_config option ForkAfterAuthentication with same behavior as -f
>
> diff --git a/clientloop.c b/clientloop.c
> index 690b776..34ba047 100644
> --- a/clientloop.c
> +++ b/clientloop.c
> @@ -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 */
>
> @@ -1255,7 +1252,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
> fatal("%s pledge(): %s", __func__, 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("%s pledge(): %s", __func__, strerror(errno));
> diff --git a/readconf.c b/readconf.c
> index 88e6408..c00c3bb 100644
> --- a/readconf.c
> +++ b/readconf.c
> @@ -167,7 +167,7 @@ typedef enum {
> oLocalCommand, oPermitLocalCommand, oRemoteCommand,
> oVisualHostKey,
> oKexAlgorithms, oIPQoS, oRequestTTY, oNoShell, oStdinNull,
> - oIgnoreUnknown, oProxyUseFdpass,
> + oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
> oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
> oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
> oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
> @@ -297,6 +297,7 @@ static struct {
> { "requesttty", oRequestTTY },
> { "noshell", oNoShell },
> { "stdinnull", oStdinNull },
> + { "forkafterauthentication", oForkAfterAuthentication },
> { "proxyusefdpass", oProxyUseFdpass },
> { "canonicaldomains", oCanonicalDomains },
> { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
> @@ -1705,6 +1706,10 @@ parse_keytypes:
> 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;
> @@ -2063,6 +2068,7 @@ initialize_options(Options * options)
> options->request_tty = -1;
> options->no_shell = -1;
> options->stdin_null = -1;
> + options->fork_after_authentication = -1;
> options->proxy_use_fdpass = -1;
> options->ignored_unknown = NULL;
> options->num_canonical_domains = 0;
> @@ -2247,6 +2253,8 @@ fill_default_options(Options * options)
> options->no_shell = 0;
> 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)
> @@ -2807,6 +2815,7 @@ dump_client_config(Options *o, const char *host)
> dump_cfg_fmtint(oRequestTTY, o->request_tty);
> dump_cfg_fmtint(oNoShell, o->no_shell);
> 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 5de3e62..dd76aa5 100644
> --- a/readconf.h
> +++ b/readconf.h
> @@ -145,6 +145,7 @@ typedef struct {
> int request_tty;
> int no_shell;
> int stdin_null;
> + int fork_after_authentication;
>
> int proxy_use_fdpass;
>
> diff --git a/ssh.1 b/ssh.1
> index c8d8489..3f9cd05 100644
> --- a/ssh.1
> +++ b/ssh.1
> @@ -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
> diff --git a/ssh.c b/ssh.c
> index 8533763..5e2bfe3 100644
> --- a/ssh.c
> +++ b/ssh.c
> @@ -135,13 +135,6 @@ int need_controlpersist_detach = 0;
> /* Copies of flags for ControlPersist foreground mux-client */
> int ostdin_null_flag, 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.
> @@ -731,7 +724,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':
> @@ -1339,7 +1332,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.no_shell)
> fatal("Cannot fork into background without a command "
> "to execute.");
> @@ -1741,7 +1734,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 ((devnull = open(_PATH_DEVNULL, O_WRONLY)) == -1)
> @@ -1765,7 +1758,7 @@ forwarding_success(void)
> return;
> if (--forward_confirms_pending == 0) {
> debug("%s: all expected forwarding replies received", __func__);
> - if (fork_after_authentication_flag)
> + if (options.fork_after_authentication)
> fork_postauth();
> } else {
> debug2("%s: %d expected forwarding replies remaining",
> @@ -2110,9 +2103,9 @@ ssh_session2(struct ssh *ssh, struct passwd *pw)
> options.stdin_null = 1;
> options.no_shell = 1;
> tty_flag = 0;
> - if (!fork_after_authentication_flag)
> + if (!options.fork_after_authentication)
> need_controlpersist_detach = 1;
> - fork_after_authentication_flag = 1;
> + options.fork_after_authentication = 1;
> }
> /*
> * ControlPersist mux listen socket setup failed, attempt the
> @@ -2168,7 +2161,7 @@ ssh_session2(struct ssh *ssh, struct passwd *pw)
> * 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 345626d..34bb56a 100644
> --- a/ssh_config.5
> +++ b/ssh_config.5
> @@ -682,6 +682,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.
> @@ -1602,8 +1641,8 @@ program will be put in the background.
> (This does not work if
> .Nm ssh
> needs to ask for a password or passphrase; see also the
> -.Fl f
> -option.)
> +.Cm ForkAfterAuthentication
> +configuration option.)
> The argument to this keyword must be
> .Cm yes
> (same as the


--
Volker Diels-Grabsch
----<<<((()))>>>----
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev