=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/channels.c,v retrieving revision 1.195.2.2 retrieving revision 1.196 diff -u -r1.195.2.2 -r1.196 --- src/usr.bin/ssh/channels.c 2004/08/19 22:37:30 1.195.2.2 +++ src/usr.bin/ssh/channels.c 2003/09/19 11:31:33 1.196 @@ -39,7 +39,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.195.2.2 2004/08/19 22:37:30 brad Exp $"); +RCSID("$OpenBSD: channels.c,v 1.196 2003/09/19 11:31:33 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -68,7 +68,7 @@ * Size of the channel array. All slots of the array must always be * initialized (at least the type field); unused slots set to NULL */ -static u_int channels_alloc = 0; +static int channels_alloc = 0; /* * Maximum file descriptor value used in any of the channels. This is @@ -141,7 +141,7 @@ { Channel *c; - if (id < 0 || (u_int)id >= channels_alloc) { + if (id < 0 || id >= channels_alloc) { logit("channel_lookup: %d: bad id", id); return NULL; } @@ -172,7 +172,6 @@ c->rfd = rfd; c->wfd = wfd; c->sock = (rfd == wfd) ? rfd : -1; - c->ctl_fd = -1; /* XXX: set elsewhere */ c->efd = efd; c->extended_usage = extusage; @@ -208,8 +207,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) { - int found; - u_int i; + int i, found; Channel *c; /* Do initial allocation if this is the first call. */ @@ -223,10 +221,10 @@ for (found = -1, i = 0; i < channels_alloc; i++) if (channels[i] == NULL) { /* Found a free slot. */ - found = (int)i; + found = i; break; } - if (found < 0) { + if (found == -1) { /* There are no free slots. Take last+1 slot and expand the array. */ found = channels_alloc; if (channels_alloc > 10000) @@ -264,7 +262,6 @@ c->single_connection = 0; c->detach_user = NULL; c->confirm = NULL; - c->confirm_ctx = NULL; c->input_filter = NULL; debug("channel %d: new [%s]", found, remote_name); return c; @@ -273,8 +270,7 @@ static int channel_find_maxfd(void) { - u_int i; - int max = 0; + int i, max = 0; Channel *c; for (i = 0; i < channels_alloc; i++) { @@ -307,11 +303,10 @@ static void channel_close_fds(Channel *c) { - debug3("channel %d: close_fds r %d w %d e %d c %d", - c->self, c->rfd, c->wfd, c->efd, c->ctl_fd); + debug3("channel %d: close_fds r %d w %d e %d", + c->self, c->rfd, c->wfd, c->efd); channel_close_fd(&c->sock); - channel_close_fd(&c->ctl_fd); channel_close_fd(&c->rfd); channel_close_fd(&c->wfd); channel_close_fd(&c->efd); @@ -323,12 +318,12 @@ channel_free(Channel *c) { char *s; - u_int i, n; + int i, n; for (n = 0, i = 0; i < channels_alloc; i++) if (channels[i]) n++; - debug("channel %d: free: %s, nchannels %u", c->self, + debug("channel %d: free: %s, nchannels %d", c->self, c->remote_name ? c->remote_name : "???", n); s = channel_open_message(); @@ -337,8 +332,6 @@ if (c->sock != -1) shutdown(c->sock, SHUT_RDWR); - if (c->ctl_fd != -1) - shutdown(c->ctl_fd, SHUT_RDWR); channel_close_fds(c); buffer_free(&c->input); buffer_free(&c->output); @@ -354,7 +347,7 @@ void channel_free_all(void) { - u_int i; + int i; for (i = 0; i < channels_alloc; i++) if (channels[i] != NULL) @@ -369,7 +362,7 @@ void channel_close_all(void) { - u_int i; + int i; for (i = 0; i < channels_alloc; i++) if (channels[i] != NULL) @@ -383,7 +376,7 @@ void channel_stop_listening(void) { - u_int i; + int i; Channel *c; for (i = 0; i < channels_alloc; i++) { @@ -440,7 +433,7 @@ int channel_still_open(void) { - u_int i; + int i; Channel *c; for (i = 0; i < channels_alloc; i++) { @@ -483,12 +476,12 @@ int channel_find_open(void) { - u_int i; + int i; Channel *c; for (i = 0; i < channels_alloc; i++) { c = channels[i]; - if (c == NULL || c->remote_id < 0) + if (c == NULL) continue; switch (c->type) { case SSH_CHANNEL_CLOSED: @@ -531,7 +524,7 @@ Buffer buffer; Channel *c; char buf[1024], *cp; - u_int i; + int i; buffer_init(&buffer); snprintf(buf, sizeof buf, "The following connections are open:\r\n"); @@ -556,13 +549,12 @@ case SSH_CHANNEL_X11_OPEN: case SSH_CHANNEL_INPUT_DRAINING: case SSH_CHANNEL_OUTPUT_DRAINING: - snprintf(buf, sizeof buf, - " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n", + snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", c->self, c->remote_name, c->type, c->remote_id, c->istate, buffer_len(&c->input), c->ostate, buffer_len(&c->output), - c->rfd, c->wfd, c->ctl_fd); + c->rfd, c->wfd); buffer_append(&buffer, buf, strlen(buf)); continue; default: @@ -603,14 +595,14 @@ logit("channel_request_start: %d: unknown channel id", id); return; } - debug2("channel %d: request %s confirm %d", id, service, wantconfirm); + debug2("channel %d: request %s", id, service) ; packet_start(SSH2_MSG_CHANNEL_REQUEST); packet_put_int(c->remote_id); packet_put_cstring(service); packet_put_char(wantconfirm); } void -channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) +channel_register_confirm(int id, channel_callback_fn *fn) { Channel *c = channel_lookup(id); @@ -619,7 +611,6 @@ return; } c->confirm = fn; - c->confirm_ctx = ctx; } void channel_register_cleanup(int id, channel_callback_fn *fn) @@ -737,10 +728,6 @@ buffer_len(&c->extended) < c->remote_window) FD_SET(c->efd, readset); } - /* XXX: What about efd? races? */ - if (compat20 && c->ctl_fd != -1 && - c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN) - FD_SET(c->ctl_fd, readset); } static void @@ -982,7 +969,7 @@ have = buffer_len(&c->input); if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { /* format: ver | nmethods | methods */ - if (have < 2) + if (have < 2) return 0; nmethods = p[1]; if (have < nmethods + 2) @@ -1043,11 +1030,11 @@ buffer_get(&c->input, (char *)&dest_port, 2); dest_addr[addrlen] = '\0'; if (s5_req.atyp == SSH_SOCKS5_DOMAIN) - strlcpy(c->path, (char *)dest_addr, sizeof(c->path)); + strlcpy(c->path, dest_addr, sizeof(c->path)); else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL) return -1; c->host_port = ntohs(dest_port); - + debug2("channel %d: dynamic request: socks5 host %s port %u command %u", c->self, c->path, c->host_port, s5_req.command); @@ -1489,33 +1476,6 @@ return 1; } static int -channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset) -{ - char buf[16]; - int len; - - /* Monitor control fd to detect if the slave client exits */ - if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) { - len = read(c->ctl_fd, buf, sizeof(buf)); - if (len < 0 && (errno == EINTR || errno == EAGAIN)) - return 1; - if (len <= 0) { - debug2("channel %d: ctl read<=0", c->self); - if (c->type != SSH_CHANNEL_OPEN) { - debug2("channel %d: not open", c->self); - chan_mark_dead(c); - return -1; - } else { - chan_read_failed(c); - chan_write_failed(c); - } - return -1; - } else - fatal("%s: unexpected data on ctl fd", __func__); - } - return 1; -} -static int channel_check_window(Channel *c) { if (c->type == SSH_CHANNEL_OPEN && @@ -1545,7 +1505,6 @@ if (!compat20) return; channel_handle_efd(c, readset, writeset); - channel_handle_ctl(c, readset, writeset); channel_check_window(c); } @@ -1670,7 +1629,7 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) { static int did_init = 0; - u_int i; + int i; Channel *c; if (!did_init) { @@ -1693,9 +1652,10 @@ */ void channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, - u_int *nallocp, int rekeying) + int *nallocp, int rekeying) { - u_int n, sz; + int n; + u_int sz; n = MAX(*maxfdp, channel_max_fd); @@ -1731,7 +1691,8 @@ channel_output_poll(void) { Channel *c; - u_int i, len; + int i; + u_int len; for (i = 0; i < channels_alloc; i++) { c = channels[i]; @@ -1850,25 +1811,13 @@ c->type != SSH_CHANNEL_X11_OPEN) return; + /* same for protocol 1.5 if output end is no longer open */ + if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) + return; + /* Get the data. */ data = packet_get_string(&data_len); - /* - * Ignore data for protocol > 1.3 if output end is no longer open. - * For protocol 2 the sending side is reducing its window as it sends - * data, so we must 'fake' consumption of the data in order to ensure - * that window updates are sent back. Otherwise the connection might - * deadlock. - */ - if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) { - if (compat20) { - c->local_window -= data_len; - c->local_consumed += data_len; - } - xfree(data); - return; - } - if (compat20) { if (data_len > c->local_maxpacket) { logit("channel %d: rcvd big packet %d, maxpack %d", @@ -2044,7 +1993,7 @@ c->remote_maxpacket = packet_get_int(); if (c->confirm) { debug2("callback start"); - c->confirm(c->self, c->confirm_ctx); + c->confirm(c->self, NULL); debug2("callback done"); } debug2("channel %d: open confirm rwindow %u rmax %u", c->self, @@ -2236,7 +2185,7 @@ continue; } /* Start listening for connections on the socket. */ - if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { + if (listen(sock, 5) < 0) { error("listen: %.100s", strerror(errno)); close(sock); continue; @@ -2257,27 +2206,6 @@ return success; } -int -channel_cancel_rport_listener(const char *host, u_short port) -{ - u_int i; - int found = 0; - - for(i = 0; i < channels_alloc; i++) { - Channel *c = channels[i]; - - if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && - strncmp(c->path, host, sizeof(c->path)) == 0 && - c->listening_port == port) { - debug2("%s: close clannel %d", __func__, i); - channel_free(c); - found = 1; - } - } - - return (found); -} - /* protocol local port fwd, used by ssh (and sshd in v1) */ int channel_setup_local_fwd_listener(u_short listen_port, @@ -2355,41 +2283,6 @@ } /* - * Request cancellation of remote forwarding of connection host:port from - * local side. - */ -void -channel_request_rforward_cancel(u_short port) -{ - int i; - const char *address_to_bind = "0.0.0.0"; - - if (!compat20) - return; - - for (i = 0; i < num_permitted_opens; i++) { - if (permitted_opens[i].host_to_connect != NULL && - permitted_opens[i].listen_port == port) - break; - } - if (i >= num_permitted_opens) { - debug("%s: requested forward not found", __func__); - return; - } - packet_start(SSH2_MSG_GLOBAL_REQUEST); - packet_put_cstring("cancel-tcpip-forward"); - packet_put_char(0); - packet_put_cstring(address_to_bind); - packet_put_int(port); - packet_send(); - - permitted_opens[i].listen_port = 0; - permitted_opens[i].port_to_connect = 0; - free(permitted_opens[i].host_to_connect); - permitted_opens[i].host_to_connect = NULL; -} - -/* * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates * listening for the port, and sends back a success reply (or disconnect * message if there was an error). This never returns if there was an error. @@ -2456,8 +2349,7 @@ int i; for (i = 0; i < num_permitted_opens; i++) - if (permitted_opens[i].host_to_connect != NULL) - xfree(permitted_opens[i].host_to_connect); + xfree(permitted_opens[i].host_to_connect); num_permitted_opens = 0; } @@ -2497,8 +2389,8 @@ verbose("socket: %.100s", strerror(errno)); continue; } - if (set_nonblock(sock) == -1) - fatal("%s: set_nonblock(%d)", __func__, sock); + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) + fatal("connect_to: F_SETFL: %s", strerror(errno)); if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && errno != EINPROGRESS) { error("connect_to %.100s port %s: %.100s", ntop, strport, @@ -2525,8 +2417,7 @@ int i; for (i = 0; i < num_permitted_opens; i++) - if (permitted_opens[i].host_to_connect != NULL && - permitted_opens[i].listen_port == listen_port) + if (permitted_opens[i].listen_port == listen_port) return connect_to( permitted_opens[i].host_to_connect, permitted_opens[i].port_to_connect); @@ -2544,8 +2435,7 @@ permit = all_opens_permitted; if (!permit) { for (i = 0; i < num_permitted_opens; i++) - if (permitted_opens[i].host_to_connect != NULL && - permitted_opens[i].port_to_connect == port && + if (permitted_opens[i].port_to_connect == port && strcmp(permitted_opens[i].host_to_connect, host) == 0) permit = 1; @@ -2558,27 +2448,6 @@ return connect_to(host, port); } -void -channel_send_window_changes(void) -{ - u_int i; - struct winsize ws; - - for (i = 0; i < channels_alloc; i++) { - if (channels[i] == NULL || - channels[i]->type != SSH_CHANNEL_OPEN) - continue; - if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0) - continue; - channel_request_start(i, "window-change", 0); - packet_put_int(ws.ws_col); - packet_put_int(ws.ws_row); - packet_put_int(ws.ws_xpixel); - packet_put_int(ws.ws_ypixel); - packet_send(); - } -} - /* -- X11 forwarding */ /* @@ -2617,7 +2486,6 @@ ai->ai_protocol); if (sock < 0) { error("socket: %.100s", strerror(errno)); - freeaddrinfo(aitop); return -1; } if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { @@ -2648,7 +2516,7 @@ /* Start listening for connections on the socket. */ for (n = 0; n < num_socks; n++) { sock = socks[n]; - if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { + if (listen(sock, 5) < 0) { error("listen: %.100s", strerror(errno)); close(sock); return -1; @@ -2869,7 +2737,7 @@ char *new_data; int screen_number; const char *cp; - u_int32_t rnd = 0; + u_int32_t rand = 0; cp = getenv("DISPLAY"); if (cp) @@ -2894,10 +2762,10 @@ if (sscanf(data + 2 * i, "%2x", &value) != 1) fatal("x11_request_forwarding: bad authentication data: %.100s", data); if (i % 4 == 0) - rnd = arc4random(); + rand = arc4random(); x11_saved_data[i] = value; - x11_fake_data[i] = rnd & 0xff; - rnd >>= 8; + x11_fake_data[i] = rand & 0xff; + rand >>= 8; } x11_saved_data_len = data_len; x11_fake_data_len = data_len; @@ -2935,4 +2803,47 @@ packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); packet_send(); packet_write_wait(); +} + +/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ + +void +auth_input_open_request(int type, u_int32_t seq, void *ctxt) +{ + Channel *c = NULL; + int remote_id, sock; + + /* Read the remote channel number from the message. */ + remote_id = packet_get_int(); + packet_check_eom(); + + /* + * Get a connection to the local authentication agent (this may again + * get forwarded). + */ + sock = ssh_get_authentication_socket(); + + /* + * If we could not connect the agent, send an error message back to + * the server. This should never happen unless the agent dies, + * because authentication forwarding is only enabled if we have an + * agent. + */ + if (sock >= 0) { + c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, + -1, 0, 0, 0, "authentication agent connection", 1); + c->remote_id = remote_id; + c->force_drain = 1; + } + 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(); }