From: mouring Date: Tue, 26 Mar 2002 03:26:24 +0000 (+0000) Subject: - markus@cvs.openbsd.org 2002/03/25 21:13:51 X-Git-Tag: PRE_SW_KRBV~64 X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/commitdiff_plain/d2296ed797ba1e6ced5d07cea2ce3a8aac19d046 - markus@cvs.openbsd.org 2002/03/25 21:13:51 [channels.c channels.h compat.c compat.h nchan.c] 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 --- diff --git a/ChangeLog b/ChangeLog index fb807587..6d6a764c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -39,6 +39,10 @@ - markus@cvs.openbsd.org 2002/03/25 21:04:02 [ssh.c] simplify num_identity_files handling + - markus@cvs.openbsd.org 2002/03/25 21:13:51 + [channels.c channels.h compat.c compat.h nchan.c] + 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 20020324 - (stevesk) [session.c] disable LOGIN_NEEDS_TERM until we are sure diff --git a/channels.c b/channels.c index 2b1f33f3..95817624 100644 --- a/channels.c +++ b/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/channels.h b/channels.h index 707d9a92..0da2d4e5 100644 --- a/channels.h +++ b/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 @@ -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/compat.c b/compat.c index 74d5ed85..8671e641 100644 --- a/compat.c +++ b/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/compat.h b/compat.h index 0eeb782e..3fb0f979 100644 --- a/compat.h +++ b/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/nchan.c b/nchan.c index fc8e7f18..db38de6a 100644 --- a/nchan.c +++ b/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; }