As you are now probably aware, the portability team for openssh still
has not fixed the hang-on-exit bug in the 2.9.9p2 release.
Attached is a patch for 2.9.9p2 that fixes the hang-on-exit bug for Linux
systems. It also adds a useful exit delay feature that has also not yet been
incorporated into the main sources.
For more information, see the SNFS (secure NFS) web page:
http://www.math.ualberta.ca/imaging/snfs
-- John Bowman
University of Alberta
diff -u openssh-2.9.9p2/channels.c openssh-2.9.9p2J/channels.c
--- openssh-2.9.9p2/channels.c Mon Sep 17 23:53:12 2001
+++ openssh-2.9.9p2J/channels.c Thu Sep 27 22:12:43 2001
@@ -1527,8 +1527,18 @@
c = channels[i];
if (c == NULL)
continue;
- if (ftab[c->type] != NULL)
+ if (ftab[c->type] != NULL) {
+ 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)) {
/*
* we have to remove the fd's from the select mask
diff -u openssh-2.9.9p2/channels.h openssh-2.9.9p2J/channels.h
--- openssh-2.9.9p2/channels.h Mon Sep 17 23:51:14 2001
+++ openssh-2.9.9p2J/channels.h Thu Sep 27 22:16:44 2001
@@ -219,6 +219,7 @@
void chan_mark_dead(Channel *);
void chan_init_iostates(Channel *);
void chan_init(void);
+void chan_shutdown_read(Channel *);
typedef void chan_event_fn(Channel *);
diff -u openssh-2.9.9p2/clientloop.c openssh-2.9.9p2J/clientloop.c
--- openssh-2.9.9p2/clientloop.c Mon Sep 17 23:51:14 2001
+++ openssh-2.9.9p2J/clientloop.c Fri Sep 28 12:47:09 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;
@@ -122,7 +123,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. */
static void client_init_dispatch(void);
int session_ident = -1;
@@ -320,6 +322,10 @@
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
int *maxfdp, int *nallocp, int rekeying)
{
+ struct timeval timer;
+ struct timeval *timerp;
+ int rc;
+
/* Add any selections by the channel mechanism. */
channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying);
@@ -343,11 +349,12 @@
FD_SET(fileno(stderr), *writesetp);
} else {
/* channel_prepare_select could have closed the last channel */
- if (session_closed && !channel_still_open()) {
+ if ((session_status == SessionClose)
+ && !channel_still_open()) {
if (!packet_have_data_to_write())
return;
} else {
- FD_SET(connection_in, *readsetp);
+ FD_SET(connection_in, *readsetp);
}
}
@@ -364,7 +371,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];
/*
@@ -381,7 +398,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;
}
static void
@@ -442,9 +460,12 @@
len = read(connection_in, buf, sizeof(buf));
if (len == 0) {
/* Received EOF. The remote host has closed the connection. */
+/* This message duplicates the one already in client_loop(). */
+#if 0
snprintf(buf, sizeof buf, "Connection to %.300s closed by remote
host.\r\n",
host);
buffer_append(&stderr_buffer, buf, strlen(buf));
+#endif
quit_pending = 1;
return;
}
@@ -753,7 +774,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();
}
@@ -778,6 +799,7 @@
start_time = get_current_time();
/* Initialize variables. */
+ if(!have_pty) session_status=SessionWait;
escape_pending = 0;
last_was_cr = 1;
exit_status = -1;
@@ -842,7 +864,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 -u openssh-2.9.9p2/nchan.c openssh-2.9.9p2J/nchan.c
--- openssh-2.9.9p2/nchan.c Thu Sep 20 13:33:33 2001
+++ openssh-2.9.9p2J/nchan.c Thu Sep 27 22:09:31 2001
@@ -81,7 +81,7 @@
/* helper */
static void chan_shutdown_write(Channel *);
-static void chan_shutdown_read(Channel *);
+void chan_shutdown_read(Channel *);
/*
* SSH1 specific implementation of event functions
@@ -524,7 +524,7 @@
c->self, c->wfd, strerror(errno));
}
}
-static void
+void
chan_shutdown_read(Channel *c)
{
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
diff -u openssh-2.9.9p2/readconf.c openssh-2.9.9p2J/readconf.c
--- openssh-2.9.9p2/readconf.c Wed Sep 19 18:57:56 2001
+++ openssh-2.9.9p2J/readconf.c Thu Sep 27 22:17:56 2001
@@ -115,7 +115,7 @@
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
- oClearAllForwardings
+ oClearAllForwardings, oSleep
} OpCodes;
/* Textual representations of the tokens. */
@@ -186,6 +186,7 @@
{ "bindaddress", oBindAddress },
{ "smartcarddevice", oSmartcardDevice },
{ "clearallforwardings", oClearAllForwardings },
+ { "sleep", oSleep },
{ NULL, 0 }
};
@@ -523,6 +524,10 @@
intptr = &options->connection_attempts;
goto parse_int;
+ case oSleep:
+ intptr = &options->sleep;
+ goto parse_int;
+
case oCipher:
intptr = &options->cipher;
arg = strdelim(&s);
@@ -793,6 +798,7 @@
options->preferred_authentications = NULL;
options->bind_address = NULL;
options->smartcard_device = NULL;
+ options->sleep = -1;
}
/*
diff -u openssh-2.9.9p2/readconf.h openssh-2.9.9p2J/readconf.h
--- openssh-2.9.9p2/readconf.h Wed Sep 19 18:57:56 2001
+++ openssh-2.9.9p2J/readconf.h Thu Sep 27 22:01:07 2001
@@ -101,6 +101,7 @@
int num_remote_forwards;
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
int clear_forwardings;
+ int sleep; /* Exit delay in seconds */
} Options;
diff -u openssh-2.9.9p2/session.c openssh-2.9.9p2J/session.c
--- openssh-2.9.9p2/session.c Sun Sep 16 16:17:15 2001
+++ openssh-2.9.9p2J/session.c Thu Sep 27 22:01:07 2001
@@ -1906,6 +1906,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 -u openssh-2.9.9p2/ssh.c openssh-2.9.9p2J/ssh.c
--- openssh-2.9.9p2/ssh.c Mon Sep 24 16:04:03 2001
+++ openssh-2.9.9p2J/ssh.c Thu Sep 27 22:04:49 2001
@@ -195,6 +195,7 @@
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, " -D port Enable dynamic application-level port
forwarding.\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");
@@ -320,7 +321,7 @@
again:
while ((opt = getopt(ac, av,
- "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) {
+ "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:S:TVX")) != -1) {
switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
@@ -495,7 +496,13 @@
add_remote_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) {