PATCH: Option so -f waits until forwarded port/x11 is opened before backgrounding

Nicolas Williams Nicolas.Williams at ubsw.com
Thu Jan 17 07:05:14 EST 2002


You can now put "WaitForPortOpenBeforeFork=no" in ssh_config and
"ssh -f ..." will wait until a forwarded port/x11/agent is opened before
backgrounding the client.

See below for the rationale for this feature. It improves error handling
for users of OpenSSH when launching [X11] apps.

As a bonus the backgrounded client closes stdio and the file descriptors
of the channel associated with the ssh session so that in the background
the client stays mum. This could be made a separate option. See the
forkoff() function added to clientloop.c for details.

Patch is attached.

Comments? Should I file a bug report to request that this feature be
added?

Nico

On Fri, Jan 11, 2002 at 10:54:01AM -0500, Nicolas Williams wrote:
> I'd like a feature whereby ssh puts itself in the background after the
> first successful X11 (or other port) forwarding.
> 
> The reason for this is simple: error handling.
> 
> If the application fails to open the X display and exits, then the
> client can still exit with the application's exit code. But if the
> application opens the X display successfully, then it can just display
> any errors by itself.
> 
> I intend to write and contribute such a patch to implement such a
> feature in the next few days.
> 
> Comments?
> 
> Nico
--
-DISCLAIMER: an automatically appended disclaimer may follow. By posting-
-to a public e-mail mailing list I hereby grant permission to distribute-
-and copy this message.-
-------------- next part --------------
Index: 3_0_2p1_w_gss_and_krb5_compat_try.2/ssh.c
--- 3_0_2p1_w_gss_and_krb5_compat_try.2/ssh.c Wed, 21 Nov 2001 10:38:46 -0500
+++ 3_0_2p1_w_gss_and_krb5_compat_try.2(w)/ssh.c Wed, 16 Jan 2002 12:57:39 -0500
@@ -111,6 +111,7 @@
  * background.
  */
 int fork_after_authentication_flag = 0;
+int wait_for_port_open_before_fork = 0;
 
 /*
  * General data structure for command line options and options configurable
@@ -628,6 +629,8 @@
 	/* Fill configuration defaults. */
 	fill_default_options(&options);
 
+	wait_for_port_open_before_fork = options.wait_for_port_open_before_fork;
+
 	/* reinit */
 	log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
 
@@ -1164,7 +1167,7 @@
 		id = ssh_session2_open();
 
 	/* If requested, let ssh continue in the background. */
-	if (fork_after_authentication_flag)
+	if (fork_after_authentication_flag && !options.wait_for_port_open_before_fork)
 		if (daemon(1, 1) < 0)
 			fatal("daemon() failed: %.200s", strerror(errno));
 
Index: 3_0_2p1_w_gss_and_krb5_compat_try.2/readconf.h
--- 3_0_2p1_w_gss_and_krb5_compat_try.2/readconf.h Thu, 10 Jan 2002 14:22:14 -0500
+++ 3_0_2p1_w_gss_and_krb5_compat_try.2(w)/readconf.h Tue, 15 Jan 2002 16:49:44 -0500
@@ -111,6 +111,7 @@
 	Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
 	int	clear_forwardings;
 	int	no_host_authentication_for_localhost;
+	int	wait_for_port_open_before_fork;	/* Like -f, but after first successful port/display open */
 }       Options;
 
 
Index: 3_0_2p1_w_gss_and_krb5_compat_try.2/readconf.c
--- 3_0_2p1_w_gss_and_krb5_compat_try.2/readconf.c Thu, 10 Jan 2002 14:22:14 -0500
+++ 3_0_2p1_w_gss_and_krb5_compat_try.2(w)/readconf.c Tue, 15 Jan 2002 17:35:38 -0500
@@ -111,6 +111,7 @@
 #ifdef AFS
 	oAFSTokenPassing,
 #endif
+	oWaitForPortOpenBeforeFork,
 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
@@ -202,6 +203,7 @@
 	{ "smartcarddevice", oSmartcardDevice },
 	{ "clearallforwardings", oClearAllForwardings }, 
 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 
+	{ "waitforportopenbeforefork", oWaitForPortOpenBeforeFork }, 
 	{ NULL, 0 }
 };
 
@@ -710,6 +712,10 @@
 			*intptr = value;
 		break;
 
+	case oWaitForPortOpenBeforeFork:
+		intptr = &options->wait_for_port_open_before_fork;
+		goto parse_flag;
+
 	default:
 		fatal("process_config_line: Unimplemented opcode %d", opcode);
 	}
@@ -839,6 +845,7 @@
 	options->bind_address = NULL;
 	options->smartcard_device = NULL;
 	options->no_host_authentication_for_localhost = - 1;
+	options->wait_for_port_open_before_fork = -1;
 }
 
 /*
@@ -969,6 +976,8 @@
 		clear_forwardings(options);
 	if (options->no_host_authentication_for_localhost == - 1)
 		options->no_host_authentication_for_localhost = 0;
+	if (options->wait_for_port_open_before_fork == -1)
+		options->wait_for_port_open_before_fork = 0;
 	/* options->proxy_command should not be set by default */
 	/* options->user will be set in the main program if appropriate */
 	/* options->hostname will be set in the main program if appropriate */
Index: 3_0_2p1_w_gss_and_krb5_compat_try.2/clientloop.c
--- 3_0_2p1_w_gss_and_krb5_compat_try.2/clientloop.c Wed, 21 Nov 2001 10:38:46 -0500
+++ 3_0_2p1_w_gss_and_krb5_compat_try.2(w)/clientloop.c Wed, 16 Jan 2002 14:50:24 -0500
@@ -95,6 +95,9 @@
  */
 extern char *host;
 
+extern int fork_after_authentication_flag;
+extern int wait_for_port_open_before_fork;
+
 /*
  * Flag to indicate that we have received a window change signal which has
  * not yet been processed.  This will cause a message indicating the new
@@ -1007,6 +1010,79 @@
 
 /*********/
 
+/*
+ * Detach the program (continue to serve connections,
+ * but put in background and no more new connections).
+ */
+static
+void
+forkoff(int stop_listening)
+{
+	pid_t pid;
+	int fd;
+	int bytes = 0;
+	Channel *c;
+
+	/* Restore tty modes. */
+	leave_raw_mode();
+
+	/* Stop listening for new connections. */
+	if (stop_listening)
+		channel_stop_listening();
+
+	fprintf(stderr, "Forking off into the background - %s",
+		stop_listening ? "no longer listening" : "still listening");
+
+	/* Fork into background. */
+	pid = fork();
+	if (pid < 0) {
+		error("fork: %.100s", strerror(errno));
+		return;
+	}
+	if (pid != 0) {	/* This is the parent. */
+		/* The parent just exits. */
+		exit(0);
+	}
+
+	c = channel_lookup(session_ident);
+	if (c == NULL)
+		error("couldn't lookup session channel");
+
+	/* The child continues serving connections. */
+	/* fake EOF on stdin */
+	if (compat20) {
+		buffer_append(&stdin_buffer, "\004", 1);
+	} else if (!stdin_eof) {
+		/*
+		 * Sending SSH_CMSG_EOF alone does not always appear
+		 * to be enough.  So we try to send an EOF character
+		 * first.
+		 */
+		packet_start(SSH_CMSG_STDIN_DATA);
+		packet_put_string("\004", 1);
+		packet_send();
+		/* Close stdin. */
+		stdin_eof = 1;
+		if (buffer_len(&stdin_buffer) == 0) {
+			packet_start(SSH_CMSG_EOF);
+			packet_send();
+		}
+	}
+	chan_read_failed(c);
+	chan_write_failed(c);
+	channel_close_fds(c);
+	fd = open(_PATH_DEVNULL, O_RDWR, 0);
+	if (fd < 0)
+		return;
+	(void) dup2(fd, STDIN_FILENO);
+	(void) dup2(fd, STDOUT_FILENO);
+	(void) dup2(fd, STDERR_FILENO);
+	if (fd > 2)
+		(void) close(fd);
+	
+	return;
+}
+
 static void
 client_input_stdout_data(int type, int plen, void *ctxt)
 {
@@ -1187,6 +1263,8 @@
 			packet_put_int(c->local_maxpacket);
 			packet_send();
 		}
+		if (fork_after_authentication_flag && wait_for_port_open_before_fork)
+			forkoff(0);
 	} else {
 		debug("failure %s", ctype);
 		packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
Index: 3_0_2p1_w_gss_and_krb5_compat_try.2/channels.h
--- 3_0_2p1_w_gss_and_krb5_compat_try.2/channels.h Wed, 21 Nov 2001 10:38:46 -0500
+++ 3_0_2p1_w_gss_and_krb5_compat_try.2(w)/channels.h Wed, 16 Jan 2002 13:24:53 -0500
@@ -153,6 +153,7 @@
 void	 channel_register_filter(int, channel_filter_fn *);
 void	 channel_cancel_cleanup(int);
 int	 channel_close_fd(int *);
+void	 channel_close_fds(Channel *);
 
 /* protocol handler */
 
Index: 3_0_2p1_w_gss_and_krb5_compat_try.2/channels.c
--- 3_0_2p1_w_gss_and_krb5_compat_try.2/channels.c Wed, 21 Nov 2001 10:38:46 -0500
+++ 3_0_2p1_w_gss_and_krb5_compat_try.2(w)/channels.c Wed, 16 Jan 2002 14:48:11 -0500
@@ -301,7 +301,7 @@
 
 /* Close all channel fd/socket. */
 
-static void
+void
 channel_close_fds(Channel *c)
 {
 	debug3("channel_close_fds: channel %d: r %d w %d e %d",
-------------- next part --------------

Visit our website at http://www.ubswarburg.com

This message contains confidential information and is intended only 
for the individual named.  If you are not the named addressee you 
should not disseminate, distribute or copy this e-mail.  Please 
notify the sender immediately by e-mail if you have received this 
e-mail by mistake and delete this e-mail from your system.

E-mail transmission cannot be guaranteed to be secure or error-free 
as information could be intercepted, corrupted, lost, destroyed, 
arrive late or incomplete, or contain viruses.  The sender therefore 
does not accept liability for any errors or omissions in the contents 
of this message which arise as a result of e-mail transmission.  If 
verification is required please request a hard-copy version.  This 
message is provided for informational purposes and should not be 
construed as a solicitation or offer to buy or sell any securities or 
related financial instruments.


More information about the openssh-unix-dev mailing list