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

Volker Diels-Grabsch v at njh.eu
Fri Feb 26 11:46:40 AEDT 2021


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 at 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 at 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 at 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 at 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
----<<<((()))>>>----


More information about the openssh-unix-dev mailing list