- markus@cvs.openbsd.org 2001/05/04 23:47:34
     [channels.c channels.h clientloop.c nchan.c nchan.h serverloop.c ssh.c]
     move to Channel **channels (instead of Channel *channels), fixes realloc
     problems.  channel_new now returns a Channel *, favour Channel * over
     channel id.  remove old channel_allocate interface.
diff --git a/channels.c b/channels.c
index 503a814..2bb0e98 100644
--- a/channels.c
+++ b/channels.c
@@ -40,7 +40,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.112 2001/05/04 14:34:34 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.113 2001/05/04 23:47:33 markus Exp $");
 
 #include <openssl/rsa.h>
 #include <openssl/dsa.h>
@@ -72,18 +72,17 @@
  * Pointer to an array containing all allocated channels.  The array is
  * dynamically extended as needed.
  */
-static Channel *channels = NULL;
+static Channel **channels = NULL;
 
 /*
  * Size of the channel array.  All slots of the array must always be
- * initialized (at least the type field); unused slots are marked with type
- * SSH_CHANNEL_FREE.
+ * initialized (at least the type field); unused slots set to NULL
  */
 static int channels_alloc = 0;
 
 /*
  * Maximum file descriptor value used in any of the channels.  This is
- * updated in channel_allocate.
+ * updated in channel_new.
  */
 static int channel_max_fd = 0;
 
@@ -150,12 +149,13 @@
 channel_lookup(int id)
 {
 	Channel *c;
+
 	if (id < 0 || id > channels_alloc) {
 		log("channel_lookup: %d: bad id", id);
 		return NULL;
 	}
-	c = &channels[id];
-	if (c->type == SSH_CHANNEL_FREE) {
+	c = channels[id];
+	if (c == NULL) {
 		log("channel_lookup: %d: bad id: channel free", id);
 		return NULL;
 	}
@@ -212,7 +212,7 @@
  * remote_name to be freed.
  */
 
-int
+Channel *
 channel_new(char *ctype, int type, int rfd, int wfd, int efd,
     int window, int maxpack, int extusage, char *remote_name, int nonblock)
 {
@@ -223,9 +223,9 @@
 	if (channels_alloc == 0) {
 		chan_init();
 		channels_alloc = 10;
-		channels = xmalloc(channels_alloc * sizeof(Channel));
+		channels = xmalloc(channels_alloc * sizeof(Channel *));
 		for (i = 0; i < channels_alloc; i++)
-			channels[i].type = SSH_CHANNEL_FREE;
+			channels[i] = NULL;
 		/*
 		 * Kludge: arrange a call to channel_stop_listening if we
 		 * terminate with fatal().
@@ -234,7 +234,7 @@
 	}
 	/* Try to find a free slot where to put the new channel. */
 	for (found = -1, i = 0; i < channels_alloc; i++)
-		if (channels[i].type == SSH_CHANNEL_FREE) {
+		if (channels[i] == NULL) {
 			/* Found a free slot. */
 			found = i;
 			break;
@@ -244,12 +244,12 @@
 		found = channels_alloc;
 		channels_alloc += 10;
 		debug2("channel: expanding %d", channels_alloc);
-		channels = xrealloc(channels, channels_alloc * sizeof(Channel));
+		channels = xrealloc(channels, channels_alloc * sizeof(Channel *));
 		for (i = found; i < channels_alloc; i++)
-			channels[i].type = SSH_CHANNEL_FREE;
+			channels[i] = NULL;
 	}
-	/* Initialize and return new channel number. */
-	c = &channels[found];
+	/* Initialize and return new channel. */
+	c = channels[found] = xmalloc(sizeof(Channel));
 	buffer_init(&c->input);
 	buffer_init(&c->output);
 	buffer_init(&c->extended);
@@ -272,15 +272,8 @@
 	c->dettach_user = NULL;
 	c->input_filter = NULL;
 	debug("channel %d: new [%s]", found, remote_name);
-	return found;
+	return c;
 }
-/* old interface XXX */
-int
-channel_allocate(int type, int sock, char *remote_name)
-{
-	return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name, 1);
-}
-
 
 /* Close all channel fd/socket. */
 
@@ -308,18 +301,16 @@
 /* Free the channel and close its fd/socket. */
 
 void
-channel_free(int id)
+channel_free(Channel *c)
 {
-	Channel *c = channel_lookup(id);
-	char *s = channel_open_message();
+	char *s;
 
-	if (c == NULL)
-		packet_disconnect("channel free: bad local channel %d", id);
-	debug("channel_free: channel %d: status: %s", id, s);
+	s = channel_open_message();
+	debug("channel_free: channel %d: status: %s", c->self, s);
 	xfree(s);
 
 	if (c->dettach_user != NULL) {
-		debug("channel_free: channel %d: dettaching channel user", id);
+		debug("channel_free: channel %d: dettaching channel user", c->self);
 		c->dettach_user(c->self, NULL);
 	}
 	if (c->sock != -1)
@@ -328,11 +319,12 @@
 	buffer_free(&c->input);
 	buffer_free(&c->output);
 	buffer_free(&c->extended);
-	c->type = SSH_CHANNEL_FREE;
 	if (c->remote_name) {
 		xfree(c->remote_name);
 		c->remote_name = NULL;
 	}
+	channels[c->self] = NULL;
+	xfree(c);
 }
 
 /*
@@ -428,7 +420,7 @@
 channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset)
 {
 	if (buffer_len(&c->output) == 0)
-		channel_free(c->self);
+		chan_mark_dead(c);
 	else
 		FD_SET(c->sock, writeset);
 }
@@ -640,7 +632,7 @@
 		break;
 	}
 	if (ret < 0) {
-		channel_free(c->self);
+		chan_mark_dead(c);
 	} else if (ret == 0) {
 		debug2("channel %d: pre_dynamic: need more", c->self);
 		/* need more */
@@ -656,8 +648,9 @@
 void
 channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
 {
+	Channel *nc;
 	struct sockaddr addr;
-	int newsock, newch, oldch;
+	int newsock;
 	socklen_t addrlen;
 	char buf[16384], *remote_ipaddr;
 	int remote_port;
@@ -675,16 +668,19 @@
 		snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
 		    remote_ipaddr, remote_port);
 
-		oldch = c->self;
-		newch = channel_new("x11",
+		nc = channel_new("accepted x11 socket",
 		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
 		    c->local_window_max, c->local_maxpacket,
 		    0, xstrdup(buf), 1);
-		c = channel_lookup(oldch);
+		if (nc == NULL) {
+			close(newsock);
+			xfree(remote_ipaddr);
+			return;
+		}
 		if (compat20) {
 			packet_start(SSH2_MSG_CHANNEL_OPEN);
 			packet_put_cstring("x11");
-			packet_put_int(newch);
+			packet_put_int(nc->self);
 			packet_put_int(c->local_window_max);
 			packet_put_int(c->local_maxpacket);
 			/* originator ipaddr and port */
@@ -697,7 +693,7 @@
 			packet_send();
 		} else {
 			packet_start(SSH_SMSG_X11_OPEN);
-			packet_put_int(newch);
+			packet_put_int(nc->self);
 			if (have_hostname_in_open)
 				packet_put_string(buf, strlen(buf));
 			packet_send();
@@ -764,7 +760,7 @@
 {
 	Channel *nc;
 	struct sockaddr addr;
-	int newsock, newch, nextstate, oldch;
+	int newsock, nextstate;
 	socklen_t addrlen;
 	char *rtype;
 
@@ -784,16 +780,13 @@
 			error("accept: %.100s", strerror(errno));
 			return;
 		}
-		oldch = c->self;
-		newch = channel_new(rtype,
+		nc = channel_new(rtype,
 		    nextstate, newsock, newsock, -1,
 		    c->local_window_max, c->local_maxpacket,
 		    0, xstrdup(rtype), 1);
-
-		c = channel_lookup(oldch);
-		nc = channel_lookup(newch);
 		if (nc == NULL) {
-			error("xxx: no new channel:");
+			error("channel_post_port_listener: no new channel:");
+			close(newsock);
 			return;
 		}
 		nc->listening_port = c->listening_port;
@@ -812,8 +805,9 @@
 void
 channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset)
 {
+	Channel *nc;
+	int newsock;
 	struct sockaddr addr;
-	int newsock, newch, oldch;
 	socklen_t addrlen;
 
 	if (FD_ISSET(c->sock, readset)) {
@@ -823,21 +817,23 @@
 			error("accept from auth socket: %.100s", strerror(errno));
 			return;
 		}
-		oldch = c->self;
-		newch = channel_new("accepted auth socket",
+		nc = channel_new("accepted auth socket",
 		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
 		    c->local_window_max, c->local_maxpacket,
 		    0, xstrdup("accepted auth socket"), 1);
-		c = channel_lookup(oldch);
+		if (nc == NULL) {
+			error("channel_post_auth_listener: channel_new failed");
+			close(newsock);
+		}
 		if (compat20) {
 			packet_start(SSH2_MSG_CHANNEL_OPEN);
 			packet_put_cstring("auth-agent@openssh.com");
-			packet_put_int(newch);
+			packet_put_int(nc->self);
 			packet_put_int(c->local_window_max);
 			packet_put_int(c->local_maxpacket);
 		} else {
 			packet_start(SSH_SMSG_AGENT_OPEN);
-			packet_put_int(newch);
+			packet_put_int(nc->self);
 		}
 		packet_send();
 	}
@@ -881,7 +877,7 @@
 			    c->self, c->rfd, len);
 			if (c->type != SSH_CHANNEL_OPEN) {
 				debug("channel %d: not open", c->self);
-				channel_free(c->self);
+				chan_mark_dead(c);
 				return -1;
 			} else if (compat13) {
 				buffer_consume(&c->output, buffer_len(&c->output));
@@ -920,7 +916,7 @@
 		if (len <= 0) {
 			if (c->type != SSH_CHANNEL_OPEN) {
 				debug("channel %d: not open", c->self);
-				channel_free(c->self);
+				chan_mark_dead(c);
 				return -1;
 			} else if (compat13) {
 				buffer_consume(&c->output, buffer_len(&c->output));
@@ -1138,13 +1134,12 @@
 		did_init = 1;
 	}
 	for (i = 0; i < channels_alloc; i++) {
-		c = &channels[i];
-		if (c->type == SSH_CHANNEL_FREE)
+		c = channels[i];
+		if (c == NULL)
 			continue;
 		if (ftab[c->type] == NULL)
 			continue;
 		(*ftab[c->type])(c, readset, writeset);
-		c = &channels[i]; /* XXX realloc */
 		if (chan_is_dead(c)) {
 			/*
 			 * we have to remove the fd's from the select mask
@@ -1161,7 +1156,7 @@
 				if (c->extended_usage == CHAN_EXTENDED_WRITE)
 					FD_CLR(c->efd, writeset);
 			}
-			channel_free(c->self);
+			channel_free(c);
 		}
 	}
 }
@@ -1207,7 +1202,10 @@
 	Channel *c;
 
 	for (i = 0; i < channels_alloc; i++) {
-		c = &channels[i];
+
+		c = channels[i];
+		if (c == NULL)
+			continue;
 
 		/* We are only interested in channels that can have buffered incoming data. */
 		if (compat13) {
@@ -1391,8 +1389,8 @@
 	Channel *c;
 
 	for (i = 0; i < channels_alloc; i++) {
-		c = &channels[i];
-		if (c->type == SSH_CHANNEL_OPEN) {
+		c = channels[i];
+		if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
 			if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {
 				debug("channel %d: big input buffer %d",
 				    c->self, buffer_len(&c->input));
@@ -1486,7 +1484,7 @@
 	if (c->type != SSH_CHANNEL_CLOSED)
 		packet_disconnect("Received close confirmation for "
 		    "non-closed channel %d (type %d).", id, c->type);
-	channel_free(c->self);
+	channel_free(c);
 }
 
 void
@@ -1554,7 +1552,7 @@
 			xfree(lang);
 	}
 	/* Free the channel.  This will also close the socket. */
-	channel_free(id);
+	channel_free(c);
 }
 
 void
@@ -1615,21 +1613,26 @@
 channel_stop_listening()
 {
 	int i;
+	Channel *c;
+
 	for (i = 0; i < channels_alloc; i++) {
-		switch (channels[i].type) {
-		case SSH_CHANNEL_AUTH_SOCKET:
-			close(channels[i].sock);
-			unlink(channels[i].path);
-			channel_free(i);
-			break;
-		case SSH_CHANNEL_PORT_LISTENER:
-		case SSH_CHANNEL_RPORT_LISTENER:
-		case SSH_CHANNEL_X11_LISTENER:
-			close(channels[i].sock);
-			channel_free(i);
-			break;
-		default:
-			break;
+		c = channels[i];
+		if (c != NULL) {
+			switch (c->type) {
+			case SSH_CHANNEL_AUTH_SOCKET:
+				close(c->sock);
+				unlink(c->path);
+				channel_free(c);
+				break;
+			case SSH_CHANNEL_PORT_LISTENER:
+			case SSH_CHANNEL_RPORT_LISTENER:
+			case SSH_CHANNEL_X11_LISTENER:
+				close(c->sock);
+				channel_free(c);
+				break;
+			default:
+				break;
+			}
 		}
 	}
 }
@@ -1643,9 +1646,10 @@
 channel_close_all()
 {
 	int i;
+
 	for (i = 0; i < channels_alloc; i++)
-		if (channels[i].type != SSH_CHANNEL_FREE)
-			channel_close_fds(&channels[i]);
+		if (channels[i] != NULL)
+			channel_close_fds(channels[i]);
 }
 
 /* Returns true if any channel is still open. */
@@ -1653,10 +1657,14 @@
 int
 channel_still_open()
 {
-	u_int i;
-	for (i = 0; i < channels_alloc; i++)
-		switch (channels[i].type) {
-		case SSH_CHANNEL_FREE:
+	int i;
+	Channel *c;
+
+	for (i = 0; i < channels_alloc; i++) {
+		c = channels[i];
+		if (c == NULL)
+			continue;
+		switch (c->type) {
 		case SSH_CHANNEL_X11_LISTENER:
 		case SSH_CHANNEL_PORT_LISTENER:
 		case SSH_CHANNEL_RPORT_LISTENER:
@@ -1679,9 +1687,10 @@
 				fatal("cannot happen: OUT_DRAIN");
 			return 1;
 		default:
-			fatal("channel_still_open: bad channel type %d", channels[i].type);
+			fatal("channel_still_open: bad channel type %d", c->type);
 			/* NOTREACHED */
 		}
+	}
 	return 0;
 }
 
@@ -1690,12 +1699,16 @@
 int
 channel_find_open()
 {
-	u_int i;
-	for (i = 0; i < channels_alloc; i++)
-		switch (channels[i].type) {
+	int i;
+	Channel *c;
+
+	for (i = 0; i < channels_alloc; i++) {
+		c = channels[i];
+		if (c == NULL)
+			continue;
+		switch (c->type) {
 		case SSH_CHANNEL_CLOSED:
 		case SSH_CHANNEL_DYNAMIC:
-		case SSH_CHANNEL_FREE:
 		case SSH_CHANNEL_X11_LISTENER:
 		case SSH_CHANNEL_PORT_LISTENER:
 		case SSH_CHANNEL_RPORT_LISTENER:
@@ -1713,9 +1726,10 @@
 				fatal("cannot happen: OUT_DRAIN");
 			return i;
 		default:
-			fatal("channel_find_open: bad channel type %d", channels[i].type);
+			fatal("channel_find_open: bad channel type %d", c->type);
 			/* NOTREACHED */
 		}
+	}
 	return -1;
 }
 
@@ -1730,16 +1744,18 @@
 channel_open_message()
 {
 	Buffer buffer;
+	Channel *c;
+	char buf[1024], *cp;
 	int i;
-	char buf[512], *cp;
 
 	buffer_init(&buffer);
 	snprintf(buf, sizeof buf, "The following connections are open:\r\n");
 	buffer_append(&buffer, buf, strlen(buf));
 	for (i = 0; i < channels_alloc; i++) {
-		Channel *c = &channels[i];
+		c = channels[i];
+		if (c == NULL)
+			continue;
 		switch (c->type) {
-		case SSH_CHANNEL_FREE:
 		case SSH_CHANNEL_X11_LISTENER:
 		case SSH_CHANNEL_PORT_LISTENER:
 		case SSH_CHANNEL_RPORT_LISTENER:
@@ -1797,7 +1813,8 @@
     const char *host_to_connect, u_short port_to_connect,
     int gateway_ports, int remote_fwd)
 {
-	int success, ch, sock, on = 1, ctype;
+	Channel *c;
+	int success, sock, on = 1, ctype;
 	struct addrinfo hints, *ai, *aitop;
 	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
 	const char *host;
@@ -1813,7 +1830,7 @@
 		ctype  =SSH_CHANNEL_PORT_LISTENER;
 	}
 
-	if (strlen(host) > sizeof(channels[0].path) - 1) {
+	if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) {
 		error("Forward host name too long.");
 		return success;
 	}
@@ -1874,12 +1891,17 @@
 			continue;
 		}
 		/* Allocate a channel number for the socket. */
-		ch = channel_new("port listener", ctype, sock, sock, -1,
+		c = channel_new("port listener", ctype, sock, sock, -1,
 		    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
 		    0, xstrdup("port listener"), 1);
-		strlcpy(channels[ch].path, host, sizeof(channels[ch].path));
-		channels[ch].host_port = port_to_connect;
-		channels[ch].listening_port = listen_port;
+		if (c == NULL) {
+			error("channel_request_forwarding: channel_new failed");
+			close(sock);
+			continue;
+		}
+		strlcpy(c->path, host, sizeof(c->path));
+		c->host_port = port_to_connect;
+		c->listening_port = listen_port;
 		success = 1;
 	}
 	if (success == 0)
@@ -2116,11 +2138,12 @@
 void
 channel_input_port_open(int type, int plen, void *ctxt)
 {
+	Channel *c = NULL;
 	u_short host_port;
 	char *host, *originator_string;
-	int remote_channel, sock = -1, newch;
+	int remote_id, sock = -1;
 
-	remote_channel = packet_get_int();
+	remote_id = packet_get_int();
 	host = packet_get_string(NULL);
 	host_port = packet_get_int();
 
@@ -2132,20 +2155,26 @@
 	packet_done();
 	sock = channel_connect_to(host, host_port);
 	if (sock != -1) {
-		newch = channel_allocate(SSH_CHANNEL_CONNECTING,
-		    sock, originator_string);
-		channels[newch].remote_id = remote_channel;
-
+		c = channel_new("connected socket",
+		    SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
+		    originator_string, 1);
+		if (c == NULL) {
+			error("channel_input_port_open: channel_new failed");
+			close(sock);
+		} else {
+			c->remote_id = remote_id;
+		}
+	}
+	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_channel);
-		packet_put_int(newch);
-		packet_send();
-	} else {
-		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
-		packet_put_int(remote_channel);
-		packet_send();
+		packet_put_int(remote_id);
+		packet_put_int(c->self);
 	}
+	packet_send();
 	xfree(host);
 }
 
@@ -2430,46 +2459,45 @@
 void
 x11_input_open(int type, int plen, void *ctxt)
 {
-	int remote_channel, sock = 0, newch;
+	Channel *c = NULL;
+	int remote_id, sock = 0;
 	char *remote_host;
-	u_int remote_len;
-
-	/* Get remote channel number. */
-	remote_channel = packet_get_int();
-
-	/* Get remote originator name. */
-	if (have_hostname_in_open) {
-		remote_host = packet_get_string(&remote_len);
-		remote_len += 4;
-	} else {
-		remote_host = xstrdup("unknown (remote did not supply name)");
-		remote_len = 0;
-	}
 
 	debug("Received X11 open request.");
-	packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN);
+
+	remote_id = packet_get_int();
+	if (have_hostname_in_open) {
+		remote_host = packet_get_string(NULL);
+	} else {
+		remote_host = xstrdup("unknown (remote did not supply name)");
+	}
+	packet_done();
 
 	/* Obtain a connection to the real X display. */
 	sock = x11_connect_display();
-	if (sock == -1) {
+	if (sock != -1) {
+		/* Allocate a channel for this connection. */
+		c = channel_new("connected x11 socket",
+		    SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0,
+		    remote_host, 1);
+		if (c == NULL) {
+			error("x11_input_open: channel_new failed");
+			close(sock);
+		} else {
+			c->remote_id = remote_id;
+		}
+	}
+	if (c == NULL) {
 		/* Send refusal to the remote host. */
 		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
-		packet_put_int(remote_channel);
-		packet_send();
+		packet_put_int(remote_id);
 	} else {
-		/* Allocate a channel for this connection. */
-		newch = channel_allocate(
-		     (x11_saved_proto == NULL) ?
-		     SSH_CHANNEL_OPEN : SSH_CHANNEL_X11_OPEN,
-		     sock, remote_host);
-		channels[newch].remote_id = remote_channel;
-
 		/* Send a confirmation to the remote host. */
 		packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
-		packet_put_int(remote_channel);
-		packet_put_int(newch);
-		packet_send();
+		packet_put_int(remote_id);
+		packet_put_int(c->self);
 	}
+	packet_send();
 }
 
 /* dummy protocol handler that denies SSH-1 requests (agent/x11) */
@@ -2602,7 +2630,8 @@
 int
 auth_input_request_forwarding(struct passwd * pw)
 {
-	int sock, newch;
+	Channel *nc;
+	int sock;
 	struct sockaddr_un sunaddr;
 
 	if (auth_get_socket_name() != NULL)
@@ -2657,13 +2686,16 @@
 		packet_disconnect("listen: %.100s", strerror(errno));
 
 	/* Allocate a channel for the authentication agent socket. */
-	newch = channel_new("auth socket",
+	nc = channel_new("auth socket",
 	    SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
 	    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
 	    0, xstrdup("auth socket"), 1);
-
-	strlcpy(channels[newch].path, channel_forwarded_auth_socket_name,
-	    sizeof(channels[newch].path));
+	if (nc == NULL) {
+		error("auth_input_request_forwarding: channel_new failed");
+		close(sock);
+		return 0;
+	}
+	strlcpy(nc->path, channel_forwarded_auth_socket_name, sizeof(nc->path));
 	return 1;
 }
 
@@ -2672,13 +2704,14 @@
 void
 auth_input_open_request(int type, int plen, void *ctxt)
 {
-	int remch, sock, newch;
+	Channel *c = NULL;
+	int remote_id, sock;
 	char *dummyname;
 
 	packet_integrity_check(plen, 4, type);
 
 	/* Read the remote channel number from the message. */
-	remch = packet_get_int();
+	remote_id = packet_get_int();
 
 	/*
 	 * Get a connection to the local authentication agent (this may again
@@ -2692,28 +2725,26 @@
 	 * because authentication forwarding is only enabled if we have an
 	 * agent.
 	 */
-	if (sock < 0) {
-		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
-		packet_put_int(remch);
-		packet_send();
-		return;
+	if (sock >= 0) {
+		dummyname = xstrdup("authentication agent connection");
+		c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, -1, 0, 0, 0, dummyname, 1);
+		if (c == NULL) {
+			error("auth_input_open_request: channel_new failed");
+			close(sock);
+		} else {
+			c->remote_id = remote_id;
+		}
 	}
-	debug("Forwarding authentication connection.");
-
-	/*
-	 * Dummy host name.  This will be freed when the channel is freed; it
-	 * will still be valid in the packet_put_string below since the
-	 * channel cannot yet be freed at that point.
-	 */
-	dummyname = xstrdup("authentication agent connection");
-
-	newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);
-	channels[newch].remote_id = remch;
-
-	/* Send a confirmation to the remote host. */
-	packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
-	packet_put_int(remch);
-	packet_put_int(newch);
+	if (c == NULL) {
+		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+		packet_put_int(remote_id);
+	} else {
+		/* Send a confirmation to the remote host. */
+		debug("Forwarding authentication connection.");
+		packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+		packet_put_int(remote_id);
+		packet_put_int(c->self);
+	}
 	packet_send();
 }