hang on exit bug under Linux

Peter Stuge stuge at cdy.org
Sat Dec 15 04:10:59 EST 2001


On Fri, Dec 14, 2001 at 01:58:42AM +0100, Peter Stuge wrote:
> 
> Now off to code up this patch.  Or at least I'll try, had a look at some of
> the code yesterday too but didn't get anywhere..

Ok.  Here we go.  It's not very complicated but it took me some time to get
familiar with all the code, which is very easy to read, kudos to all!
And after finishing it, I fell alseep.  Ohwell.

For this to work as desired the sshd must send the SSH_MSG_CHANNEL_CLOSE
message fast enough for the client to buffer it together with the
CHANNEL_REQ "exit-status", so that CHAN_CLOSE_RCVD is set in the channel
flags when client_process_buffered_input_packets() returns.  If this isn't
acceptable/practical the only alternative I can see is to set a time limit.

The case I'm trying to handle here is "exit-status received for this
channel, but no SSH_MSG_CHANNEL_CLOSE" - when is that a fact?  Sure, if some
other packet than _CHANNEL_EOF or _CHANNEL_CLOSE is received, I'll know.
And I implemented that first, using a dispatch_preprocess function that
would be run before the message handler. But that doesn't cut it when there
simply aren't any packets arriving..

On top of this, much to my disappointment, a backgrounded ssh didn't get
killed when I closed my xterm.  But if it lingers it gets killed.  This is
because bash sends SIGHUP to all jobs when it is exiting.  But since the ssh
fork()s, it's no longer considered to be a job.  Hmm.  I tried putting a
call to setpgrp() and then setsid() in the fork()ed off child, but that
didn't make any difference, obviously I guess.  Is what I want even
possible?

Tell me if I've done something wrong in the patch.  It makes ssh in any case
tell the user about what is happening and why, wheter it lingers, goes to
background or terminates.


//Peter

-- 
irc: CareBear\
irl: Peter Stuge
-------------- next part --------------
diff -r -U 3 openssh-3.0.2p1/clientloop.c openssh-3.0.2p1-linger/clientloop.c
--- openssh-3.0.2p1/clientloop.c	Mon Nov 12 01:06:33 2001
+++ openssh-3.0.2p1-linger/clientloop.c	Fri Dec 14 18:07:20 2001
@@ -779,6 +779,9 @@
 	double start_time, total_time;
 	int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0;
 	char buf[100];
+	Channel *c;
+	int check_linger = 1;
+	pid_t pid;
 
 	debug("Entering interactive session.");
 
@@ -847,6 +850,36 @@
 
 		/* Process buffered packets sent by the server. */
 		client_process_buffered_input_packets();
+
+		if (exit_status != -1 && check_linger) {
+			check_linger = 0;
+			c = channel_lookup(ssh2_chan_id);
+			if (c && !(c->flags & CHAN_CLOSE_RCVD))
+				switch (options.on_linger) {
+				case 0:
+					error("[lingering due to open channel]");
+					break;
+				case 1:
+					error("[backgrounding client with open channels]");
+					leave_raw_mode();
+					channel_stop_listening();
+					pid = fork();
+					if (pid < 0) {
+						error("fork: %.100s", strerror(errno));
+						break;
+					}
+					if (pid != 0)
+						exit(0);
+					buffer_append(&stdin_buffer , "\004", 1);
+					break;
+				case 2:
+					error("[terminating client with open channels - data will be lost]");
+					quit_pending = 1;
+					break;
+				default:
+					fatal("unknown action OnLinger=%d",options.on_linger);
+				}
+		}
 
 		if (compat20 && session_closed && !channel_still_open())
 			break;
diff -r -U 3 openssh-3.0.2p1/readconf.c openssh-3.0.2p1-linger/readconf.c
--- openssh-3.0.2p1/readconf.c	Wed Oct  3 19:39:39 2001
+++ openssh-3.0.2p1-linger/readconf.c	Fri Dec 14 08:58:04 2001
@@ -115,7 +115,8 @@
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
-	oClearAllForwardings, oNoHostAuthenticationForLocalhost 
+	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
+	oOnLinger
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -187,6 +188,7 @@
 	{ "smartcarddevice", oSmartcardDevice },
 	{ "clearallforwardings", oClearAllForwardings }, 
 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 
+	{ "onlinger", oOnLinger },
 	{ NULL, 0 }
 };
 
@@ -678,6 +680,25 @@
 			*intptr = value;
 		break;
 
+	case oOnLinger:
+		intptr = &options->on_linger;
+		arg = strdelim(&s);
+		if (!arg || *arg == '\0')
+			fatal("%.200s line %d: Missing linger/background/dataloss argument.",
+			      filename, linenum);
+		value = 0;	/* To avoid compiler warning... */
+		if (strcmp(arg, "linger") == 0)
+			value = 0;
+		else if (strcmp(arg, "background") == 0)
+			value = 1;
+		else if (strcmp(arg, "dataloss") == 0)
+			value = 2;
+		else
+			fatal("%.200s line %d: Bad linger/background/dataloss argument.", filename, linenum);
+		if (*activep && *intptr == -1)
+			*intptr = value;
+		break;
+
 	default:
 		fatal("process_config_line: Unimplemented opcode %d", opcode);
 	}
@@ -799,6 +820,7 @@
 	options->bind_address = NULL;
 	options->smartcard_device = NULL;
 	options->no_host_authentication_for_localhost = - 1;
+	options->on_linger = -1;
 }
 
 /*
@@ -919,6 +941,8 @@
 		clear_forwardings(options);
 	if (options->no_host_authentication_for_localhost == - 1)
 		options->no_host_authentication_for_localhost = 0;
+	if (options->on_linger == -1)
+		options->on_linger = 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 */
diff -r -U 3 openssh-3.0.2p1/readconf.h openssh-3.0.2p1-linger/readconf.h
--- openssh-3.0.2p1/readconf.h	Wed Oct  3 19:39:39 2001
+++ openssh-3.0.2p1-linger/readconf.h	Fri Dec 14 08:57:24 2001
@@ -102,6 +102,8 @@
 	Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
 	int	clear_forwardings;
 	int	no_host_authentication_for_localhost;
+
+	int	on_linger;
 }       Options;
 
 
diff -r -U 3 openssh-3.0.2p1/ssh.0 openssh-3.0.2p1-linger/ssh.0
--- openssh-3.0.2p1/ssh.0	Sun Dec  2 00:38:46 2001
+++ openssh-3.0.2p1-linger/ssh.0	Fri Dec 14 09:57:09 2001
@@ -619,6 +619,18 @@
              Specifies the number of password prompts before giving up.  The
              argument to this keyword must be an integer.  Default is 3.
 
+     OnLinger
+             Specifies what action to take when a user tries to log out and
+             there are background processes on the remote host whose stdin,
+             stdout or stderr are open and unredirected.  If this flag is set
+             to `linger'', ssh will wait until the remote file descripts are
+             closed.  If this flag is set to `background'', ssh will put it-
+             self in the background and no data will be lost.  If this flag is
+             set to `dataloss'', ssh will terminate and any data from the re-
+             mote background process will be lost.  The argument must be
+             `linger'', `background'' or `dataloss''. The default is
+             `linger''.
+
      PasswordAuthentication
              Specifies whether to use password authentication.  The argument
              to this keyword must be ``yes'' or ``no''.  The default is
diff -r -U 3 openssh-3.0.2p1/ssh.1 openssh-3.0.2p1-linger/ssh.1
--- openssh-3.0.2p1/ssh.1	Mon Nov 12 01:05:49 2001
+++ openssh-3.0.2p1-linger/ssh.1	Fri Dec 14 09:24:41 2001
@@ -995,6 +995,28 @@
 Specifies the number of password prompts before giving up.
 The argument to this keyword must be an integer.
 Default is 3.
+.It Cm OnLinger
+Specifies what action to take when a user tries to log out and there are
+background processes on the remote host whose stdin, stdout or stderr are
+open and unredirected.  If this flag is set to
+.Dq linger ,
+.Nm
+will wait until the remote file descripts are closed.  If this flag is set
+to
+.Dq background , 
+.Nm
+will put itself in the background and no data will be lost.  If this flag
+is set to
+.Dq dataloss , 
+.Nm
+will terminate and any data from the remote background process will be lost.
+The argument must be
+.Dq linger ,
+.Dq background
+or
+.Dq dataloss .
+The default is
+.Dq linger .
 .It Cm PasswordAuthentication
 Specifies whether to use password authentication.
 The argument to this keyword must be


More information about the openssh-unix-dev mailing list