=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/channels.c,v retrieving revision 1.112 retrieving revision 1.113 diff -u -r1.112 -r1.113 --- src/usr.bin/ssh/channels.c 2001/05/04 14:34:34 1.112 +++ src/usr.bin/ssh/channels.c 2001/05/04 23:47:33 1.113 @@ -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 #include @@ -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,16 +272,9 @@ 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. */ void @@ -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,8 +1202,11 @@ 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) { if (c->type != SSH_CHANNEL_OPEN && @@ -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; } @@ -1870,12 +1887,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) @@ -2110,11 +2132,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(); @@ -2126,20 +2149,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); } @@ -2373,46 +2402,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(); + debug("Received X11 open request."); - /* Get remote originator name. */ + remote_id = packet_get_int(); if (have_hostname_in_open) { - remote_host = packet_get_string(&remote_len); - remote_len += 4; + remote_host = packet_get_string(NULL); } else { remote_host = xstrdup("unknown (remote did not supply name)"); - remote_len = 0; } + packet_done(); - debug("Received X11 open request."); - packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN); - /* 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) */ @@ -2545,7 +2573,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) @@ -2600,13 +2629,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; } @@ -2615,13 +2647,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 @@ -2635,28 +2668,26 @@ * because authentication forwarding is only enabled if we have an * agent. */ - if (sock < 0) { + 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; + } + } + if (c == NULL) { packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); - packet_put_int(remch); - packet_send(); - return; + 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); } - 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); packet_send(); }