summaryrefslogtreecommitdiff
path: root/usr.bin/ssh
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2002-03-25 21:13:52 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2002-03-25 21:13:52 +0000
commit407a1452617c42e854e450a90972186bb4983cbe (patch)
tree46a4b2d539e2d23f8c68fcd25a3a149e55a16495 /usr.bin/ssh
parent8436143b1190862baa4fcb67d29042b946d1a14b (diff)
don't send stderr data after EOF, accept this from older known (broken)
sshd servers only, fixes http://bugzilla.mindrot.org/show_bug.cgi?id=179
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r--usr.bin/ssh/channels.c28
-rw-r--r--usr.bin/ssh/channels.h14
-rw-r--r--usr.bin/ssh/compat.c22
-rw-r--r--usr.bin/ssh/compat.h3
-rw-r--r--usr.bin/ssh/nchan.c60
5 files changed, 79 insertions, 48 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index 841a8990e0d..4685ed92003 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/channels.c
@@ -39,7 +39,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.171 2002/03/04 19:37:58 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.172 2002/03/25 21:13:51 markus Exp $");
#include "ssh.h"
#include "ssh1.h"
@@ -706,7 +706,11 @@ channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset)
if (buffer_len(&c->output) > 0) {
FD_SET(c->wfd, writeset);
} else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
- chan_obuf_empty(c);
+ if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
+ debug2("channel %d: obuf_empty delayed efd %d/(%d)",
+ c->self, c->efd, buffer_len(&c->extended));
+ else
+ chan_obuf_empty(c);
}
}
/** XXX check close conditions, too */
@@ -714,7 +718,8 @@ channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset)
if (c->extended_usage == CHAN_EXTENDED_WRITE &&
buffer_len(&c->extended) > 0)
FD_SET(c->efd, writeset);
- else if (c->extended_usage == CHAN_EXTENDED_READ &&
+ else if (!(c->flags & CHAN_EOF_SENT) &&
+ c->extended_usage == CHAN_EXTENDED_READ &&
buffer_len(&c->extended) < c->remote_window)
FD_SET(c->efd, readset);
}
@@ -1632,12 +1637,18 @@ channel_output_poll(void)
fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
/*
* input-buffer is empty and read-socket shutdown:
- * tell peer, that we will not send more data: send IEOF
+ * tell peer, that we will not send more data: send IEOF.
+ * hack for extended data: delay EOF if EFD still in use.
*/
- chan_ibuf_empty(c);
+ if (CHANNEL_EFD_INPUT_ACTIVE(c))
+ debug2("channel %d: ibuf_empty delayed efd %d/(%d)",
+ c->self, c->efd, buffer_len(&c->extended));
+ else
+ chan_ibuf_empty(c);
}
/* Send extended data, i.e. stderr */
if (compat20 &&
+ !(c->flags & CHAN_EOF_SENT) &&
c->remote_window > 0 &&
(len = buffer_len(&c->extended)) > 0 &&
c->extended_usage == CHAN_EXTENDED_READ) {
@@ -1726,6 +1737,13 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
log("channel %d: ext data for non open", id);
return;
}
+ if (c->flags & CHAN_EOF_RCVD) {
+ if (datafellows & SSH_BUG_EXTEOF)
+ debug("channel %d: accepting ext data after eof", id);
+ else
+ packet_disconnect("Received extended_data after EOF "
+ "on channel %d.", id);
+ }
tcode = packet_get_int();
if (c->efd == -1 ||
c->extended_usage != CHAN_EXTENDED_WRITE ||
diff --git a/usr.bin/ssh/channels.h b/usr.bin/ssh/channels.h
index 707d9a92582..0da2d4e5e02 100644
--- a/usr.bin/ssh/channels.h
+++ b/usr.bin/ssh/channels.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.65 2002/03/04 17:27:39 stevesk Exp $ */
+/* $OpenBSD: channels.h,v 1.66 2002/03/25 21:13:51 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -135,6 +135,18 @@ struct Channel {
#define CHAN_CLOSE_SENT 0x01
#define CHAN_CLOSE_RCVD 0x02
+#define CHAN_EOF_SENT 0x04
+#define CHAN_EOF_RCVD 0x08
+
+/* check whether 'efd' is still in use */
+#define CHANNEL_EFD_INPUT_ACTIVE(c) \
+ (compat20 && c->extended_usage == CHAN_EXTENDED_READ && \
+ (c->efd != -1 || \
+ buffer_len(&c->extended) > 0))
+#define CHANNEL_EFD_OUTPUT_ACTIVE(c) \
+ (compat20 && c->extended_usage == CHAN_EXTENDED_WRITE && \
+ ((c->efd != -1 && !(c->flags & CHAN_EOF_RCVD)) || \
+ buffer_len(&c->extended) > 0))
/* channel management */
diff --git a/usr.bin/ssh/compat.c b/usr.bin/ssh/compat.c
index 74d5ed85ed6..8671e641b43 100644
--- a/usr.bin/ssh/compat.c
+++ b/usr.bin/ssh/compat.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: compat.c,v 1.61 2002/03/06 00:24:39 markus Exp $");
+RCSID("$OpenBSD: compat.c,v 1.62 2002/03/25 21:13:51 markus Exp $");
#include "buffer.h"
#include "packet.h"
@@ -61,20 +61,26 @@ compat_datafellows(const char *version)
"OpenSSH-2.1*,"
"OpenSSH_2.1*,"
"OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER|
- SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
+ SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
+ SSH_BUG_EXTEOF},
{ "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
- SSH_OLD_DHGEX|SSH_BUG_NOREKEY},
+ SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
+ SSH_BUG_EXTEOF},
{ "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
- SSH_BUG_NOREKEY},
+ SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
{ "OpenSSH_2.5.0p1*,"
"OpenSSH_2.5.1p1*",
SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
- SSH_BUG_NOREKEY },
+ SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
{ "OpenSSH_2.5.0*,"
"OpenSSH_2.5.1*,"
- "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
- { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY },
- { "Sun_SSH_1.0*", SSH_BUG_NOREKEY },
+ "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
+ SSH_BUG_EXTEOF},
+ { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
+ { "OpenSSH_2.*,"
+ "OpenSSH_3.0*,"
+ "OpenSSH_3.1*", SSH_BUG_EXTEOF},
+ { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
{ "OpenSSH*", 0 },
{ "*MindTerm*", 0 },
{ "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
diff --git a/usr.bin/ssh/compat.h b/usr.bin/ssh/compat.h
index 0eeb782e861..3fb0f97999d 100644
--- a/usr.bin/ssh/compat.h
+++ b/usr.bin/ssh/compat.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: compat.h,v 1.30 2002/03/04 17:27:39 stevesk Exp $ */
+/* $OpenBSD: compat.h,v 1.31 2002/03/25 21:13:51 markus Exp $ */
/*
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
@@ -52,6 +52,7 @@
#define SSH_BUG_OPENFAILURE 0x00020000
#define SSH_BUG_DERIVEKEY 0x00040000
#define SSH_BUG_DUMMYCHAN 0x00100000
+#define SSH_BUG_EXTEOF 0x00200000
void enable_compat13(void);
void enable_compat20(void);
diff --git a/usr.bin/ssh/nchan.c b/usr.bin/ssh/nchan.c
index 8153abbca09..f122779e59c 100644
--- a/usr.bin/ssh/nchan.c
+++ b/usr.bin/ssh/nchan.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: nchan.c,v 1.44 2002/01/21 23:27:10 markus Exp $");
+RCSID("$OpenBSD: nchan.c,v 1.45 2002/03/25 21:13:51 markus Exp $");
#include "ssh1.h"
#include "ssh2.h"
@@ -302,6 +302,7 @@ static void
chan_rcvd_eof2(Channel *c)
{
debug("channel %d: rcvd eof", c->self);
+ c->flags |= CHAN_EOF_RCVD;
if (c->ostate == CHAN_OUTPUT_OPEN)
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
}
@@ -330,6 +331,7 @@ chan_send_eof2(Channel *c)
packet_start(SSH2_MSG_CHANNEL_EOF);
packet_put_int(c->remote_id);
packet_send();
+ c->flags |= CHAN_EOF_SENT;
break;
default:
error("channel %d: cannot send eof for istate %d",
@@ -365,7 +367,8 @@ chan_rcvd_ieof(Channel *c)
else
chan_rcvd_ieof1(c);
if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
- buffer_len(&c->output) == 0)
+ buffer_len(&c->output) == 0 &&
+ !CHANNEL_EFD_OUTPUT_ACTIVE(c))
chan_obuf_empty(c);
}
void
@@ -404,39 +407,30 @@ chan_is_dead(Channel *c, int send)
debug("channel %d: is dead", c->self);
return 1;
}
- /*
- * we have to delay the close message if the efd (for stderr) is
- * still active
- */
- if (((c->extended_usage != CHAN_EXTENDED_IGNORE) &&
- buffer_len(&c->extended) > 0)
-#if 0
- || ((c->extended_usage == CHAN_EXTENDED_READ) &&
- c->efd != -1)
-#endif
- ) {
- debug2("channel %d: active efd: %d len %d type %s",
- c->self, c->efd, buffer_len(&c->extended),
- c->extended_usage==CHAN_EXTENDED_READ ?
- "read": "write");
- } else {
- if (!(c->flags & CHAN_CLOSE_SENT)) {
- if (send) {
- chan_send_close2(c);
- } else {
- /* channel would be dead if we sent a close */
- if (c->flags & CHAN_CLOSE_RCVD) {
- debug("channel %d: almost dead",
- c->self);
- return 1;
- }
+ if ((datafellows & SSH_BUG_EXTEOF) &&
+ c->extended_usage == CHAN_EXTENDED_WRITE &&
+ c->efd != -1 &&
+ buffer_len(&c->extended) > 0) {
+ debug2("channel %d: active efd: %d len %d",
+ c->self, c->efd, buffer_len(&c->extended));
+ return 0;
+ }
+ if (!(c->flags & CHAN_CLOSE_SENT)) {
+ if (send) {
+ chan_send_close2(c);
+ } else {
+ /* channel would be dead if we sent a close */
+ if (c->flags & CHAN_CLOSE_RCVD) {
+ debug("channel %d: almost dead",
+ c->self);
+ return 1;
}
}
- if ((c->flags & CHAN_CLOSE_SENT) &&
- (c->flags & CHAN_CLOSE_RCVD)) {
- debug("channel %d: is dead", c->self);
- return 1;
- }
+ }
+ if ((c->flags & CHAN_CLOSE_SENT) &&
+ (c->flags & CHAN_CLOSE_RCVD)) {
+ debug("channel %d: is dead", c->self);
+ return 1;
}
return 0;
}