version 1.193, 2003/07/02 14:51:16 |
version 1.194, 2003/08/29 10:04:36 |
|
|
|
|
/* XXX ugly hack: nonblock is only set by the server */ |
/* XXX ugly hack: nonblock is only set by the server */ |
if (nonblock && isatty(c->rfd)) { |
if (nonblock && isatty(c->rfd)) { |
debug("channel %d: rfd %d isatty", c->self, c->rfd); |
debug2("channel %d: rfd %d isatty", c->self, c->rfd); |
c->isatty = 1; |
c->isatty = 1; |
if (!isatty(c->wfd)) { |
if (!isatty(c->wfd)) { |
error("channel %d: wfd %d is not a tty?", |
error("channel %d: wfd %d is not a tty?", |
|
|
static void |
static void |
channel_close_fds(Channel *c) |
channel_close_fds(Channel *c) |
{ |
{ |
debug3("channel_close_fds: channel %d: r %d w %d e %d", |
debug3("channel %d: close_fds r %d w %d e %d", |
c->self, c->rfd, c->wfd, c->efd); |
c->self, c->rfd, c->wfd, c->efd); |
|
|
channel_close_fd(&c->sock); |
channel_close_fd(&c->sock); |
|
|
for (n = 0, i = 0; i < channels_alloc; i++) |
for (n = 0, i = 0; i < channels_alloc; i++) |
if (channels[i]) |
if (channels[i]) |
n++; |
n++; |
debug("channel_free: channel %d: %s, nchannels %d", c->self, |
debug("channel %d: free: %s, nchannels %d", c->self, |
c->remote_name ? c->remote_name : "???", n); |
c->remote_name ? c->remote_name : "???", n); |
|
|
s = channel_open_message(); |
s = channel_open_message(); |
debug3("channel_free: status: %s", s); |
debug3("channel %d: status: %s", c->self, s); |
xfree(s); |
xfree(s); |
|
|
if (c->sock != -1) |
if (c->sock != -1) |
|
|
logit("channel_request_start: %d: unknown channel id", id); |
logit("channel_request_start: %d: unknown channel id", id); |
return; |
return; |
} |
} |
debug("channel %d: request %s", id, service) ; |
debug2("channel %d: request %s", id, service) ; |
packet_start(SSH2_MSG_CHANNEL_REQUEST); |
packet_start(SSH2_MSG_CHANNEL_REQUEST); |
packet_put_int(c->remote_id); |
packet_put_int(c->remote_id); |
packet_put_cstring(service); |
packet_put_cstring(service); |
|
|
packet_put_int(c->remote_id); |
packet_put_int(c->remote_id); |
packet_send(); |
packet_send(); |
c->type = SSH_CHANNEL_CLOSED; |
c->type = SSH_CHANNEL_CLOSED; |
debug("channel %d: closing after input drain.", c->self); |
debug2("channel %d: closing after input drain.", c->self); |
} |
} |
} |
} |
|
|
|
|
proto_len = ucp[6] + 256 * ucp[7]; |
proto_len = ucp[6] + 256 * ucp[7]; |
data_len = ucp[8] + 256 * ucp[9]; |
data_len = ucp[8] + 256 * ucp[9]; |
} else { |
} else { |
debug("Initial X11 packet contains bad byte order byte: 0x%x", |
debug2("Initial X11 packet contains bad byte order byte: 0x%x", |
ucp[0]); |
ucp[0]); |
return -1; |
return -1; |
} |
} |
|
|
/* Check if authentication protocol matches. */ |
/* Check if authentication protocol matches. */ |
if (proto_len != strlen(x11_saved_proto) || |
if (proto_len != strlen(x11_saved_proto) || |
memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { |
memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { |
debug("X11 connection uses different authentication protocol."); |
debug2("X11 connection uses different authentication protocol."); |
return -1; |
return -1; |
} |
} |
/* Check if authentication data matches our fake data. */ |
/* Check if authentication data matches our fake data. */ |
if (data_len != x11_fake_data_len || |
if (data_len != x11_fake_data_len || |
memcmp(ucp + 12 + ((proto_len + 3) & ~3), |
memcmp(ucp + 12 + ((proto_len + 3) & ~3), |
x11_fake_data, x11_fake_data_len) != 0) { |
x11_fake_data, x11_fake_data_len) != 0) { |
debug("X11 auth data does not match fake data."); |
debug2("X11 auth data does not match fake data."); |
return -1; |
return -1; |
} |
} |
/* Check fake data length */ |
/* Check fake data length */ |
|
|
channel_pre_open(c, readset, writeset); |
channel_pre_open(c, readset, writeset); |
} else if (ret == -1) { |
} else if (ret == -1) { |
logit("X11 connection rejected because of wrong authentication."); |
logit("X11 connection rejected because of wrong authentication."); |
debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); |
debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); |
chan_read_failed(c); |
chan_read_failed(c); |
buffer_clear(&c->input); |
buffer_clear(&c->input); |
chan_ibuf_empty(c); |
chan_ibuf_empty(c); |
|
|
chan_write_failed(c); |
chan_write_failed(c); |
else |
else |
c->type = SSH_CHANNEL_OPEN; |
c->type = SSH_CHANNEL_OPEN; |
debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); |
debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); |
} |
} |
} |
} |
|
|
|
|
strlcpy(c->path, host, sizeof(c->path)); |
strlcpy(c->path, host, sizeof(c->path)); |
c->host_port = ntohs(s4_req.dest_port); |
c->host_port = ntohs(s4_req.dest_port); |
|
|
debug("channel %d: dynamic request: socks4 host %s port %u command %u", |
debug2("channel %d: dynamic request: socks4 host %s port %u command %u", |
c->self, host, c->host_port, s4_req.command); |
c->self, host, c->host_port, s4_req.command); |
|
|
if (s4_req.command != 1) { |
if (s4_req.command != 1) { |
|
|
if (s5_req.version != 0x05 || |
if (s5_req.version != 0x05 || |
s5_req.command != SSH_SOCKS5_CONNECT || |
s5_req.command != SSH_SOCKS5_CONNECT || |
s5_req.reserved != 0x00) { |
s5_req.reserved != 0x00) { |
debug("channel %d: only socks5 connect supported", c->self); |
debug2("channel %d: only socks5 connect supported", c->self); |
return -1; |
return -1; |
} |
} |
switch(s5_req.atyp){ |
switch(s5_req.atyp){ |
|
|
af = AF_INET6; |
af = AF_INET6; |
break; |
break; |
default: |
default: |
debug("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp); |
debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp); |
return -1; |
return -1; |
} |
} |
if (have < 4 + addrlen + 2) |
if (have < 4 + addrlen + 2) |
|
|
return -1; |
return -1; |
c->host_port = ntohs(dest_port); |
c->host_port = ntohs(dest_port); |
|
|
debug("channel %d: dynamic request: socks5 host %s port %u command %u", |
debug2("channel %d: dynamic request: socks5 host %s port %u command %u", |
c->self, c->path, c->host_port, s5_req.command); |
c->self, c->path, c->host_port, s5_req.command); |
|
|
s5_rsp.version = 0x05; |
s5_rsp.version = 0x05; |
|
|
addrlen = sizeof(addr); |
addrlen = sizeof(addr); |
newsock = accept(c->sock, &addr, &addrlen); |
newsock = accept(c->sock, &addr, &addrlen); |
if (c->single_connection) { |
if (c->single_connection) { |
debug("single_connection: closing X11 listener."); |
debug2("single_connection: closing X11 listener."); |
channel_close_fd(&c->sock); |
channel_close_fd(&c->sock); |
chan_mark_dead(c); |
chan_mark_dead(c); |
} |
} |
|
|
/* originator ipaddr and port */ |
/* originator ipaddr and port */ |
packet_put_cstring(remote_ipaddr); |
packet_put_cstring(remote_ipaddr); |
if (datafellows & SSH_BUG_X11FWD) { |
if (datafellows & SSH_BUG_X11FWD) { |
debug("ssh2 x11 bug compat mode"); |
debug2("ssh2 x11 bug compat mode"); |
} else { |
} else { |
packet_put_int(remote_port); |
packet_put_int(remote_port); |
} |
} |
|
|
if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
return 1; |
return 1; |
if (len <= 0) { |
if (len <= 0) { |
debug("channel %d: read<=0 rfd %d len %d", |
debug2("channel %d: read<=0 rfd %d len %d", |
c->self, c->rfd, len); |
c->self, c->rfd, len); |
if (c->type != SSH_CHANNEL_OPEN) { |
if (c->type != SSH_CHANNEL_OPEN) { |
debug("channel %d: not open", c->self); |
debug2("channel %d: not open", c->self); |
chan_mark_dead(c); |
chan_mark_dead(c); |
return -1; |
return -1; |
} else if (compat13) { |
} else if (compat13) { |
buffer_clear(&c->output); |
buffer_clear(&c->output); |
c->type = SSH_CHANNEL_INPUT_DRAINING; |
c->type = SSH_CHANNEL_INPUT_DRAINING; |
debug("channel %d: input draining.", c->self); |
debug2("channel %d: input draining.", c->self); |
} else { |
} else { |
chan_read_failed(c); |
chan_read_failed(c); |
} |
} |
|
|
} |
} |
if (c->input_filter != NULL) { |
if (c->input_filter != NULL) { |
if (c->input_filter(c, buf, len) == -1) { |
if (c->input_filter(c, buf, len) == -1) { |
debug("channel %d: filter stops", c->self); |
debug2("channel %d: filter stops", c->self); |
chan_read_failed(c); |
chan_read_failed(c); |
} |
} |
} else { |
} else { |
|
|
return 1; |
return 1; |
if (len <= 0) { |
if (len <= 0) { |
if (c->type != SSH_CHANNEL_OPEN) { |
if (c->type != SSH_CHANNEL_OPEN) { |
debug("channel %d: not open", c->self); |
debug2("channel %d: not open", c->self); |
chan_mark_dead(c); |
chan_mark_dead(c); |
return -1; |
return -1; |
} else if (compat13) { |
} else if (compat13) { |
buffer_clear(&c->output); |
buffer_clear(&c->output); |
debug("channel %d: input draining.", c->self); |
debug2("channel %d: input draining.", c->self); |
c->type = SSH_CHANNEL_INPUT_DRAINING; |
c->type = SSH_CHANNEL_INPUT_DRAINING; |
} else { |
} else { |
chan_write_failed(c); |
chan_write_failed(c); |
|
|
if (c->detach_user != NULL) { |
if (c->detach_user != NULL) { |
if (!chan_is_dead(c, 0)) |
if (!chan_is_dead(c, 0)) |
return; |
return; |
debug("channel %d: gc: notify user", c->self); |
debug2("channel %d: gc: notify user", c->self); |
c->detach_user(c->self, NULL); |
c->detach_user(c->self, NULL); |
/* if we still have a callback */ |
/* if we still have a callback */ |
if (c->detach_user != NULL) |
if (c->detach_user != NULL) |
return; |
return; |
debug("channel %d: gc: user detached", c->self); |
debug2("channel %d: gc: user detached", c->self); |
} |
} |
if (!chan_is_dead(c, 1)) |
if (!chan_is_dead(c, 1)) |
return; |
return; |
debug("channel %d: garbage collecting", c->self); |
debug2("channel %d: garbage collecting", c->self); |
channel_free(c); |
channel_free(c); |
} |
} |
|
|
|
|
c->confirm(c->self, NULL); |
c->confirm(c->self, NULL); |
debug2("callback done"); |
debug2("callback done"); |
} |
} |
debug("channel %d: open confirm rwindow %u rmax %u", c->self, |
debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
c->remote_window, c->remote_maxpacket); |
c->remote_window, c->remote_maxpacket); |
} |
} |
packet_check_eom(); |
packet_check_eom(); |
|
|
return -1; |
return -1; |
} |
} |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
debug("bind port %d: %.100s", port, strerror(errno)); |
debug2("bind port %d: %.100s", port, strerror(errno)); |
close(sock); |
close(sock); |
|
|
if (ai->ai_next) |
if (ai->ai_next) |
|
|
/* Create a socket. */ |
/* Create a socket. */ |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
if (sock < 0) { |
if (sock < 0) { |
debug("socket: %.100s", strerror(errno)); |
debug2("socket: %.100s", strerror(errno)); |
continue; |
continue; |
} |
} |
/* Connect it to the display. */ |
/* Connect it to the display. */ |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
debug("connect %.100s port %d: %.100s", buf, |
debug2("connect %.100s port %d: %.100s", buf, |
6000 + display_number, strerror(errno)); |
6000 + display_number, strerror(errno)); |
close(sock); |
close(sock); |
continue; |
continue; |