- markus@cvs.openbsd.org 2001/05/08 19:17:31
     [channels.c serverloop.c]
     adds correct error reporting to async connect()s
     fixes the server-discards-data-before-connected-bug found by
     onoe@sm.sony.co.jp
diff --git a/ChangeLog b/ChangeLog
index b206502..0d9d703 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,11 @@
    - markus@cvs.openbsd.org 2001/05/06 21:23:31
      [cli.c]
      cli_read() fails to catch SIGINT + overflow; from obdb@zzlevo.net
+   - markus@cvs.openbsd.org 2001/05/08 19:17:31
+     [channels.c serverloop.c]
+     adds correct error reporting to async connect()s
+     fixes the server-discards-data-before-connected-bug found by 
+     onoe@sm.sony.co.jp
 
 20010508
  - (bal) Fixed configure test for USE_SIA.  
@@ -5363,4 +5368,4 @@
  - Wrote replacements for strlcpy and mkdtemp
  - Released 1.0pre1
 
-$Id: ChangeLog,v 1.1206 2001/05/08 20:05:44 mouring Exp $
+$Id: ChangeLog,v 1.1207 2001/05/08 20:07:39 mouring Exp $
diff --git a/channels.c b/channels.c
index 2bb0e98..0f3d9ca 100644
--- a/channels.c
+++ b/channels.c
@@ -40,7 +40,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.113 2001/05/04 23:47:33 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.114 2001/05/08 19:17:30 markus Exp $");
 
 #include <openssl/rsa.h>
 #include <openssl/dsa.h>
@@ -842,22 +842,47 @@
 void
 channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset)
 {
+	int err = 0;
+	int sz = sizeof(err);
+
 	if (FD_ISSET(c->sock, writeset)) {
-		int err = 0;
-		int sz = sizeof(err);
-		c->type = SSH_CHANNEL_OPEN;
-		if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &sz) < 0) {
-			debug("getsockopt SO_ERROR failed");
-		} else {
-			if (err == 0) {
-				debug("channel %d: connected", c->self);
-			} else {
-				debug("channel %d: not connected: %s",
-				    c->self, strerror(err));
-				chan_read_failed(c);
-				chan_write_failed(c);
-			}
+		if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err,
+		    &sz) < 0) {
+			err = errno;
+			error("getsockopt SO_ERROR failed");
 		}
+		if (err == 0) {
+			debug("channel %d: connected", c->self);
+			c->type = SSH_CHANNEL_OPEN;
+			if (compat20) {
+				packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+				packet_put_int(c->remote_id);
+				packet_put_int(c->self);
+				packet_put_int(c->local_window);
+				packet_put_int(c->local_maxpacket);
+			} else {
+				packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+				packet_put_int(c->remote_id);
+				packet_put_int(c->self);
+			}
+		} else {
+			debug("channel %d: not connected: %s",
+			    c->self, strerror(err));
+			if (compat20) {
+				packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
+				packet_put_int(c->remote_id);
+				packet_put_int(SSH2_OPEN_CONNECT_FAILED);
+				if (!(datafellows & SSH_BUG_OPENFAILURE)) {
+					packet_put_cstring(strerror(err));
+					packet_put_cstring("");
+				}
+			} else {
+				packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+				packet_put_int(c->remote_id);
+			}
+			chan_mark_dead(c);
+		}
+		packet_send();
 	}
 }
 
@@ -1521,6 +1546,22 @@
 	}
 }
 
+char *
+reason2txt(int reason)
+{
+	switch(reason) {
+	case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED:
+		return "administratively prohibited";
+	case SSH2_OPEN_CONNECT_FAILED:
+		return "connect failed";
+	case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE:
+		return "unknown channel type";
+	case SSH2_OPEN_RESOURCE_SHORTAGE:
+		return "resource shortage";
+	}
+	return "unkown reason";
+}
+
 void
 channel_input_open_failure(int type, int plen, void *ctxt)
 {
@@ -1544,8 +1585,8 @@
 			lang = packet_get_string(NULL);
 		}
 		packet_done();
-		log("channel_open_failure: %d: reason %d %s", id,
-		    reason, msg ? msg : "<no additional info>");
+		log("channel %d: open failed: %s%s%s", id,
+		    reason2txt(reason), msg ? ": ": "", msg ? msg : "");
 		if (msg != NULL)
 			xfree(msg);
 		if (lang != NULL)
@@ -1671,7 +1712,7 @@
 		case SSH_CHANNEL_CLOSED:
 		case SSH_CHANNEL_AUTH_SOCKET:
 		case SSH_CHANNEL_DYNAMIC:
-		case SSH_CHANNEL_CONNECTING: 	/* XXX ??? */
+		case SSH_CHANNEL_CONNECTING:
 			continue;
 		case SSH_CHANNEL_LARVAL:
 			if (!compat20)
@@ -1713,10 +1754,10 @@
 		case SSH_CHANNEL_PORT_LISTENER:
 		case SSH_CHANNEL_RPORT_LISTENER:
 		case SSH_CHANNEL_OPENING:
+		case SSH_CHANNEL_CONNECTING:
 			continue;
 		case SSH_CHANNEL_LARVAL:
 		case SSH_CHANNEL_AUTH_SOCKET:
-		case SSH_CHANNEL_CONNECTING: 	/* XXX ??? */
 		case SSH_CHANNEL_OPEN:
 		case SSH_CHANNEL_X11_OPEN:
 			return i;
@@ -2168,13 +2209,8 @@
 	if (c == NULL) {
 		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
 		packet_put_int(remote_id);
-	} else {
-		/*XXX delay answer? */
-		packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
-		packet_put_int(remote_id);
-		packet_put_int(c->self);
+		packet_send();
 	}
-	packet_send();
 	xfree(host);
 }
 
diff --git a/serverloop.c b/serverloop.c
index 5b31355..6a5f40c 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -35,7 +35,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: serverloop.c,v 1.64 2001/05/04 23:47:34 markus Exp $");
+RCSID("$OpenBSD: serverloop.c,v 1.65 2001/05/08 19:17:31 markus Exp $");
 
 #include "xmalloc.h"
 #include "packet.h"
@@ -890,20 +890,21 @@
 		c->remote_id = rchan;
 		c->remote_window = rwindow;
 		c->remote_maxpacket = rmaxpack;
-
-		packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
-		packet_put_int(c->remote_id);
-		packet_put_int(c->self);
-		packet_put_int(c->local_window);
-		packet_put_int(c->local_maxpacket);
-		packet_send();
+		if (c->type != SSH_CHANNEL_CONNECTING) {
+			packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+			packet_put_int(c->remote_id);
+			packet_put_int(c->self);
+			packet_put_int(c->local_window);
+			packet_put_int(c->local_maxpacket);
+			packet_send();
+		}
 	} else {
 		debug("server_input_channel_open: failure %s", ctype);
 		packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
 		packet_put_int(rchan);
 		packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
 		if (!(datafellows & SSH_BUG_OPENFAILURE)) {
-			packet_put_cstring("bla bla");
+			packet_put_cstring("open failed");
 			packet_put_cstring("");
 		}
 		packet_send();