>In the changelog, there is an entry:
>
>20001129
> - (djm) Back out all the serverloop.c hacks. sshd will now hang again
> if there are background children with open fds.
>
> Does this mean that this is regarded as expected (and correct) behavior,
that
> should not change in the future, or does it mean that this behavior is a
> known problem that someone will eventually fix?
Yes, this is a known bug with openssh-2.9p2 under Linux (and some other
operating systems). This behaviour deviates from the programs rsh and ssh
that openssh purportedly replaces.
This problem has been fixed with a patch that was posted to this list
several months ago. Unlike the original serverloop hacks mentioned above,
under Linux the patch does not break ssh or scp or lead to data loss.
Note: A minor update to the patch was made 29Aug01 so that it works
correctly with the -T option. I attach the latest version below.
For more information, see http://www.math.ualberta.ca/imaging/snfs/
-- John Bowman
University of Alberta
diff -ur openssh-2.9p2/channels.c openssh-2.9p2J2/channels.c
--- openssh-2.9p2/channels.c Wed Jun 13 13:18:05 2001
+++ openssh-2.9p2J2/channels.c Wed Aug 29 15:04:44 2001
@@ -1137,6 +1137,15 @@
continue;
if (ftab[c->type] == NULL)
continue;
+ if(c->istate == CHAN_INPUT_OPEN && c->rfd == -1) {
+ int type=c->type;
+ c->type=SSH_CHANNEL_CLOSED;
+ if(channel_find_open() == -1)
+ shutdown(packet_get_connection_out(),
+ SHUT_RDWR);
+ c->type=type;
+ continue;
+ }
(*ftab[c->type])(c, readset, writeset);
if (chan_is_dead(c)) {
/*
diff -ur openssh-2.9p2/clientloop.c openssh-2.9p2J2/clientloop.c
--- openssh-2.9p2/clientloop.c Fri Apr 20 06:50:51 2001
+++ openssh-2.9p2J2/clientloop.c Wed Aug 29 14:58:14 2001
@@ -84,6 +84,7 @@
/* import options */
extern Options options;
+extern int no_tty_flag;
/* Flag indicating that stdin should be redirected from /dev/null. */
extern int stdin_null_flag;
@@ -121,8 +122,8 @@
static int connection_in; /* Connection to server (input). */
static int connection_out; /* Connection to server (output). */
static int need_rekeying; /* Set to non-zero if rekeying is requested. */
-static int session_closed = 0; /* In SSH2: login session closed. */
-
+enum SessionStatus {SessionOpen, SessionClose, SessionWait};
+static int session_status = SessionOpen; /* In SSH2: login session closed. */
void client_init_dispatch(void);
int session_ident = -1;
@@ -324,6 +325,10 @@
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
int *maxfdp, int rekeying)
{
+ struct timeval timer;
+ struct timeval *timerp;
+ int rc;
+
/* Add any selections by the channel mechanism. */
channel_prepare_select(readsetp, writesetp, maxfdp, rekeying);
@@ -346,7 +351,14 @@
if (buffer_len(&stderr_buffer) > 0)
FD_SET(fileno(stderr), *writesetp);
} else {
- FD_SET(connection_in, *readsetp);
+ /* channel_prepare_select could have closed the last channel */
+ if ((session_status == SessionClose)
+ && !channel_still_open()) {
+ if (!packet_have_data_to_write())
+ return;
+ } else {
+ FD_SET(connection_in, *readsetp);
+ }
}
/* Select server connection if have data to write to the server. */
@@ -362,7 +374,17 @@
* SSH_MSG_IGNORE packet when the timeout expires.
*/
- if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {
+ if((session_status == SessionWait && options.sleep > 0) ||
+ (no_tty_flag && options.sleep == -1)) {
+ timer.tv_sec=options.sleep > 0 ? options.sleep : 0;
+ timer.tv_usec=0;
+ timerp=&timer;
+ } else {
+ timerp=NULL;
+ }
+
+ rc=select((*maxfdp)+1, *readsetp, *writesetp, NULL, timerp);
+ if (rc < 0) {
char buf[100];
/*
@@ -379,7 +401,8 @@
snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
quit_pending = 1;
- }
+ } else if (rc == 0 && session_status == SessionWait)
+ session_status=SessionClose;
}
void
@@ -440,9 +463,13 @@
len = read(connection_in, buf, sizeof(buf));
if (len == 0) {
/* Received EOF. The remote host has closed the connection. */
- snprintf(buf, sizeof buf, "Connection to %.300s closed by remote
host.\r\n",
- host);
- buffer_append(&stderr_buffer, buf, strlen(buf));
+/*
+ * This message duplicates the one already in client_loop().
+ *
+ * snprintf(buf, sizeof buf, "Connection to %.300s closed by remote
host.\r\n",
+ * host);
+ * buffer_append(&stderr_buffer, buf, strlen(buf));
+ */
quit_pending = 1;
return;
}
@@ -751,7 +778,7 @@
if (id != session_ident)
error("client_channel_closed: id %d != session_ident %d",
id, session_ident);
- session_closed = 1;
+ session_status = (options.sleep >= 0) ? SessionWait : SessionClose;
if (in_raw_mode())
leave_raw_mode();
}
@@ -776,6 +803,7 @@
start_time = get_current_time();
/* Initialize variables. */
+ if(!have_pty) session_status=SessionWait;
escape_pending = 0;
last_was_cr = 1;
exit_status = -1;
@@ -840,7 +868,8 @@
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets();
- if (compat20 && session_closed && !channel_still_open())
+ if (compat20 && (session_status == SessionClose)
+ && !channel_still_open())
break;
rekeying = (xxx_kex != NULL && !xxx_kex->done);
diff -ur openssh-2.9p2/nchan.c openssh-2.9p2J2/nchan.c
--- openssh-2.9p2/nchan.c Tue Apr 3 07:02:48 2001
+++ openssh-2.9p2J2/nchan.c Tue Jun 19 03:27:30 2001
@@ -56,7 +56,7 @@
/* helper */
static void chan_shutdown_write(Channel *c);
-static void chan_shutdown_read(Channel *c);
+void chan_shutdown_read(Channel *c);
/*
* SSH1 specific implementation of event functions
@@ -479,7 +479,7 @@
c->wfd = -1;
}
}
-static void
+void
chan_shutdown_read(Channel *c)
{
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
diff -ur openssh-2.9p2/nchan.h openssh-2.9p2J2/nchan.h
--- openssh-2.9p2/nchan.h Sun Mar 4 23:16:12 2001
+++ openssh-2.9p2J2/nchan.h Tue Jun 19 03:27:30 2001
@@ -88,4 +88,5 @@
void chan_init_iostates(Channel * c);
void chan_init(void);
+void chan_shutdown_read(Channel *c);
#endif
diff -ur openssh-2.9p2/readconf.c openssh-2.9p2J2/readconf.c
--- openssh-2.9p2/readconf.c Tue Apr 17 12:11:37 2001
+++ openssh-2.9p2J2/readconf.c Tue Jun 19 03:27:30 2001
@@ -111,7 +111,7 @@
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
- oHostKeyAlgorithms
+ oHostKeyAlgorithms, oSleep
} OpCodes;
/* Textual representations of the tokens. */
@@ -177,6 +177,7 @@
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
+ { "sleep", oSleep },
{ NULL, 0 }
};
@@ -494,6 +495,10 @@
intptr = &options->connection_attempts;
goto parse_int;
+ case oSleep:
+ intptr = &options->sleep;
+ goto parse_int;
+
case oCipher:
intptr = &options->cipher;
arg = strdelim(&s);
@@ -761,6 +766,7 @@
options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1;
options->preferred_authentications = NULL;
+ options->sleep = -1;
}
/*
diff -ur openssh-2.9p2/readconf.h openssh-2.9p2J2/readconf.h
--- openssh-2.9p2/readconf.h Tue Apr 17 12:11:37 2001
+++ openssh-2.9p2J2/readconf.h Tue Jun 19 03:27:30 2001
@@ -97,6 +97,7 @@
/* Remote TCP/IP forward requests. */
int num_remote_forwards;
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
+ int sleep; /* Exit delay in seconds */
} Options;
diff -ur openssh-2.9p2/session.c openssh-2.9p2J2/session.c
--- openssh-2.9p2/session.c Sat Jun 16 21:40:51 2001
+++ openssh-2.9p2J2/session.c Tue Jun 19 03:27:30 2001
@@ -1928,6 +1928,9 @@
*/
if (c->ostate != CHAN_OUTPUT_CLOSED)
chan_write_failed(c);
+ if (c->istate == CHAN_INPUT_OPEN && compat20) {
+ chan_shutdown_read(c);
+ }
s->chanid = -1;
}
diff -ur openssh-2.9p2/ssh.c openssh-2.9p2J2/ssh.c
--- openssh-2.9p2/ssh.c Tue Apr 17 12:14:35 2001
+++ openssh-2.9p2J2/ssh.c Wed Aug 29 14:56:31 2001
@@ -182,6 +182,7 @@
fprintf(stderr, " -R listen-port:host:port Forward remote port to
local address\n");
fprintf(stderr, " These cause %s to listen for connections
on a port, and\n", __progname);
fprintf(stderr, " forward them to the other side by
connecting to host:port.\n");
+ fprintf(stderr, " -S delay Set exit delay (in seconds; 0 means wait
forever).\n");
fprintf(stderr, " -C Enable compression.\n");
fprintf(stderr, " -N Do not execute a shell or
command.\n");
fprintf(stderr, " -g Allow remote hosts to connect to forwarded
ports.\n");
@@ -318,7 +319,7 @@
opt = av[optind][1];
if (!opt)
usage();
- if (strchr("eilcmpLRDo", opt)) { /* options with arguments */
+ if (strchr("eilcmpLRSDo", opt)) { /* options with arguments */
optarg = av[optind] + 2;
if (strcmp(optarg, "") == 0) {
if (optind >= ac - 1)
@@ -488,7 +489,13 @@
}
add_local_forward(&options, fwd_port, buf, fwd_host_port);
break;
-
+ case 'S':
+ options.sleep = atoi(optarg);
+ if (options.sleep < 0) {
+ fprintf(stderr, "Bad delay value '%s'\n", optarg);
+ exit(1);
+ }
+ break;
case 'D':
fwd_port = a2port(optarg);
if (fwd_port == 0) {