version 1.183, 2002/09/17 07:47:02 |
version 1.183.2.2, 2003/09/16 21:20:25 |
|
|
#include "key.h" |
#include "key.h" |
#include "authfd.h" |
#include "authfd.h" |
#include "pathnames.h" |
#include "pathnames.h" |
|
#include "bufaux.h" |
|
|
|
|
/* -- channel core */ |
/* -- channel core */ |
|
|
/* |
/* |
|
|
Channel *c; |
Channel *c; |
|
|
if (id < 0 || id >= channels_alloc) { |
if (id < 0 || id >= channels_alloc) { |
log("channel_lookup: %d: bad id", id); |
logit("channel_lookup: %d: bad id", id); |
return NULL; |
return NULL; |
} |
} |
c = channels[id]; |
c = channels[id]; |
if (c == NULL) { |
if (c == NULL) { |
log("channel_lookup: %d: bad id: channel free", id); |
logit("channel_lookup: %d: bad id: channel free", id); |
return NULL; |
return NULL; |
} |
} |
return c; |
return c; |
|
|
|
|
/* 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?", |
|
|
c->local_consumed = 0; |
c->local_consumed = 0; |
c->local_maxpacket = maxpack; |
c->local_maxpacket = maxpack; |
c->remote_id = -1; |
c->remote_id = -1; |
c->remote_name = remote_name; |
c->remote_name = xstrdup(remote_name); |
c->remote_window = 0; |
c->remote_window = 0; |
c->remote_maxpacket = 0; |
c->remote_maxpacket = 0; |
c->force_drain = 0; |
c->force_drain = 0; |
|
|
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) |
|
|
#if 0 |
#if 0 |
if (!compat20 && |
if (!compat20 && |
buffer_len(&c->input) > packet_get_maxsize()) { |
buffer_len(&c->input) > packet_get_maxsize()) { |
debug("channel %d: big input buffer %d", |
debug2("channel %d: big input buffer %d", |
c->self, buffer_len(&c->input)); |
c->self, buffer_len(&c->input)); |
return 0; |
return 0; |
} |
} |
#endif |
#endif |
if (buffer_len(&c->output) > packet_get_maxsize()) { |
if (buffer_len(&c->output) > packet_get_maxsize()) { |
debug("channel %d: big output buffer %d > %d", |
debug2("channel %d: big output buffer %u > %u", |
c->self, buffer_len(&c->output), |
c->self, buffer_len(&c->output), |
packet_get_maxsize()); |
packet_get_maxsize()); |
return 0; |
return 0; |
|
|
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
log("channel_send_open: %d: bad id", id); |
logit("channel_send_open: %d: bad id", id); |
return; |
return; |
} |
} |
debug("send channel open %d", id); |
debug2("channel %d: send open", id); |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_put_cstring(c->ctype); |
packet_put_cstring(c->ctype); |
packet_put_int(c->self); |
packet_put_int(c->self); |
|
|
} |
} |
|
|
void |
void |
channel_request_start(int local_id, char *service, int wantconfirm) |
channel_request_start(int id, char *service, int wantconfirm) |
{ |
{ |
Channel *c = channel_lookup(local_id); |
Channel *c = channel_lookup(id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
log("channel_request_start: %d: unknown channel id", local_id); |
logit("channel_request_start: %d: unknown channel id", id); |
return; |
return; |
} |
} |
debug("channel request %d: %s", local_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); |
|
|
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
log("channel_register_comfirm: %d: bad id", id); |
logit("channel_register_comfirm: %d: bad id", id); |
return; |
return; |
} |
} |
c->confirm = fn; |
c->confirm = fn; |
|
|
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
log("channel_register_cleanup: %d: bad id", id); |
logit("channel_register_cleanup: %d: bad id", id); |
return; |
return; |
} |
} |
c->detach_user = fn; |
c->detach_user = fn; |
|
|
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
log("channel_cancel_cleanup: %d: bad id", id); |
logit("channel_cancel_cleanup: %d: bad id", id); |
return; |
return; |
} |
} |
c->detach_user = NULL; |
c->detach_user = NULL; |
|
|
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
log("channel_register_filter: %d: bad id", id); |
logit("channel_register_filter: %d: bad id", id); |
return; |
return; |
} |
} |
c->input_filter = fn; |
c->input_filter = fn; |
|
|
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 */ |
|
|
* We have received an X11 connection that has bad |
* We have received an X11 connection that has bad |
* authentication information. |
* authentication information. |
*/ |
*/ |
log("X11 connection rejected because of wrong authentication."); |
logit("X11 connection rejected because of wrong authentication."); |
buffer_clear(&c->input); |
buffer_clear(&c->input); |
buffer_clear(&c->output); |
buffer_clear(&c->output); |
channel_close_fd(&c->sock); |
channel_close_fd(&c->sock); |
|
|
c->type = SSH_CHANNEL_OPEN; |
c->type = SSH_CHANNEL_OPEN; |
channel_pre_open(c, readset, writeset); |
channel_pre_open(c, readset, writeset); |
} else if (ret == -1) { |
} else if (ret == -1) { |
log("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) { |
|
|
return 1; |
return 1; |
} |
} |
|
|
|
/* try to decode a socks5 header */ |
|
#define SSH_SOCKS5_AUTHDONE 0x1000 |
|
#define SSH_SOCKS5_NOAUTH 0x00 |
|
#define SSH_SOCKS5_IPV4 0x01 |
|
#define SSH_SOCKS5_DOMAIN 0x03 |
|
#define SSH_SOCKS5_IPV6 0x04 |
|
#define SSH_SOCKS5_CONNECT 0x01 |
|
#define SSH_SOCKS5_SUCCESS 0x00 |
|
|
|
static int |
|
channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset) |
|
{ |
|
struct { |
|
u_int8_t version; |
|
u_int8_t command; |
|
u_int8_t reserved; |
|
u_int8_t atyp; |
|
} s5_req, s5_rsp; |
|
u_int16_t dest_port; |
|
u_char *p, dest_addr[255+1]; |
|
int i, have, found, nmethods, addrlen, af; |
|
|
|
debug2("channel %d: decode socks5", c->self); |
|
p = buffer_ptr(&c->input); |
|
if (p[0] != 0x05) |
|
return -1; |
|
have = buffer_len(&c->input); |
|
if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { |
|
/* format: ver | nmethods | methods */ |
|
if (have < 2) |
|
return 0; |
|
nmethods = p[1]; |
|
if (have < nmethods + 2) |
|
return 0; |
|
/* look for method: "NO AUTHENTICATION REQUIRED" */ |
|
for (found = 0, i = 2 ; i < nmethods + 2; i++) { |
|
if (p[i] == SSH_SOCKS5_NOAUTH ) { |
|
found = 1; |
|
break; |
|
} |
|
} |
|
if (!found) { |
|
debug("channel %d: method SSH_SOCKS5_NOAUTH not found", |
|
c->self); |
|
return -1; |
|
} |
|
buffer_consume(&c->input, nmethods + 2); |
|
buffer_put_char(&c->output, 0x05); /* version */ |
|
buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */ |
|
FD_SET(c->sock, writeset); |
|
c->flags |= SSH_SOCKS5_AUTHDONE; |
|
debug2("channel %d: socks5 auth done", c->self); |
|
return 0; /* need more */ |
|
} |
|
debug2("channel %d: socks5 post auth", c->self); |
|
if (have < sizeof(s5_req)+1) |
|
return 0; /* need more */ |
|
memcpy((char *)&s5_req, p, sizeof(s5_req)); |
|
if (s5_req.version != 0x05 || |
|
s5_req.command != SSH_SOCKS5_CONNECT || |
|
s5_req.reserved != 0x00) { |
|
debug2("channel %d: only socks5 connect supported", c->self); |
|
return -1; |
|
} |
|
switch(s5_req.atyp){ |
|
case SSH_SOCKS5_IPV4: |
|
addrlen = 4; |
|
af = AF_INET; |
|
break; |
|
case SSH_SOCKS5_DOMAIN: |
|
addrlen = p[sizeof(s5_req)]; |
|
af = -1; |
|
break; |
|
case SSH_SOCKS5_IPV6: |
|
addrlen = 16; |
|
af = AF_INET6; |
|
break; |
|
default: |
|
debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp); |
|
return -1; |
|
} |
|
if (have < 4 + addrlen + 2) |
|
return 0; |
|
buffer_consume(&c->input, sizeof(s5_req)); |
|
if (s5_req.atyp == SSH_SOCKS5_DOMAIN) |
|
buffer_consume(&c->input, 1); /* host string length */ |
|
buffer_get(&c->input, (char *)&dest_addr, addrlen); |
|
buffer_get(&c->input, (char *)&dest_port, 2); |
|
dest_addr[addrlen] = '\0'; |
|
if (s5_req.atyp == SSH_SOCKS5_DOMAIN) |
|
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); |
|
|
|
s5_rsp.version = 0x05; |
|
s5_rsp.command = SSH_SOCKS5_SUCCESS; |
|
s5_rsp.reserved = 0; /* ignored */ |
|
s5_rsp.atyp = SSH_SOCKS5_IPV4; |
|
((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY; |
|
dest_port = 0; /* ignored */ |
|
|
|
buffer_append(&c->output, (char *)&s5_rsp, sizeof(s5_rsp)); |
|
buffer_append(&c->output, (char *)&dest_addr, sizeof(struct in_addr)); |
|
buffer_append(&c->output, (char *)&dest_port, sizeof(dest_port)); |
|
return 1; |
|
} |
|
|
/* dynamic port forwarding */ |
/* dynamic port forwarding */ |
static void |
static void |
channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) |
channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) |
|
|
debug2("channel %d: pre_dynamic: have %d", c->self, have); |
debug2("channel %d: pre_dynamic: have %d", c->self, have); |
/* buffer_dump(&c->input); */ |
/* buffer_dump(&c->input); */ |
/* check if the fixed size part of the packet is in buffer. */ |
/* check if the fixed size part of the packet is in buffer. */ |
if (have < 4) { |
if (have < 3) { |
/* need more */ |
/* need more */ |
FD_SET(c->sock, readset); |
FD_SET(c->sock, readset); |
return; |
return; |
|
|
case 0x04: |
case 0x04: |
ret = channel_decode_socks4(c, readset, writeset); |
ret = channel_decode_socks4(c, readset, writeset); |
break; |
break; |
|
case 0x05: |
|
ret = channel_decode_socks5(c, readset, writeset); |
|
break; |
default: |
default: |
ret = -1; |
ret = -1; |
break; |
break; |
|
|
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); |
} |
} |
|
|
|
|
nc = channel_new("accepted x11 socket", |
nc = channel_new("accepted x11 socket", |
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
c->local_window_max, c->local_maxpacket, |
c->local_window_max, c->local_maxpacket, 0, buf, 1); |
0, xstrdup(buf), 1); |
|
if (compat20) { |
if (compat20) { |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_put_cstring("x11"); |
packet_put_cstring("x11"); |
|
|
/* 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); |
} |
} |
|
|
return; |
return; |
} |
} |
set_nodelay(newsock); |
set_nodelay(newsock); |
nc = channel_new(rtype, |
nc = channel_new(rtype, nextstate, newsock, newsock, -1, |
nextstate, newsock, newsock, -1, |
c->local_window_max, c->local_maxpacket, 0, rtype, 1); |
c->local_window_max, c->local_maxpacket, |
|
0, xstrdup(rtype), 1); |
|
nc->listening_port = c->listening_port; |
nc->listening_port = c->listening_port; |
nc->host_port = c->host_port; |
nc->host_port = c->host_port; |
strlcpy(nc->path, c->path, sizeof(nc->path)); |
strlcpy(nc->path, c->path, sizeof(nc->path)); |
|
|
channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) |
channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) |
{ |
{ |
Channel *nc; |
Channel *nc; |
char *name; |
|
int newsock; |
int newsock; |
struct sockaddr addr; |
struct sockaddr addr; |
socklen_t addrlen; |
socklen_t addrlen; |
|
|
error("accept from auth socket: %.100s", strerror(errno)); |
error("accept from auth socket: %.100s", strerror(errno)); |
return; |
return; |
} |
} |
name = xstrdup("accepted auth socket"); |
|
nc = channel_new("accepted auth socket", |
nc = channel_new("accepted auth socket", |
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
c->local_window_max, c->local_maxpacket, |
c->local_window_max, c->local_maxpacket, |
0, name, 1); |
0, "accepted auth socket", 1); |
if (compat20) { |
if (compat20) { |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_put_cstring("auth-agent@openssh.com"); |
packet_put_cstring("auth-agent@openssh.com"); |
|
|
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); |
} |
} |
|
|
|
|
|
|
if (compat20) { |
if (compat20) { |
if (data_len > c->local_maxpacket) { |
if (data_len > c->local_maxpacket) { |
log("channel %d: rcvd big packet %d, maxpack %d", |
logit("channel %d: rcvd big packet %d, maxpack %d", |
c->self, data_len, c->local_maxpacket); |
c->self, data_len, c->local_maxpacket); |
} |
} |
if (data_len > c->local_window) { |
if (data_len > c->local_window) { |
log("channel %d: rcvd too much data %d, win %d", |
logit("channel %d: rcvd too much data %d, win %d", |
c->self, data_len, c->local_window); |
c->self, data_len, c->local_window); |
xfree(data); |
xfree(data); |
return; |
return; |
|
|
if (c == NULL) |
if (c == NULL) |
packet_disconnect("Received extended_data for bad channel %d.", id); |
packet_disconnect("Received extended_data for bad channel %d.", id); |
if (c->type != SSH_CHANNEL_OPEN) { |
if (c->type != SSH_CHANNEL_OPEN) { |
log("channel %d: ext data for non open", id); |
logit("channel %d: ext data for non open", id); |
return; |
return; |
} |
} |
if (c->flags & CHAN_EOF_RCVD) { |
if (c->flags & CHAN_EOF_RCVD) { |
|
|
if (c->efd == -1 || |
if (c->efd == -1 || |
c->extended_usage != CHAN_EXTENDED_WRITE || |
c->extended_usage != CHAN_EXTENDED_WRITE || |
tcode != SSH2_EXTENDED_DATA_STDERR) { |
tcode != SSH2_EXTENDED_DATA_STDERR) { |
log("channel %d: bad ext data", c->self); |
logit("channel %d: bad ext data", c->self); |
return; |
return; |
} |
} |
data = packet_get_string(&data_len); |
data = packet_get_string(&data_len); |
packet_check_eom(); |
packet_check_eom(); |
if (data_len > c->local_window) { |
if (data_len > c->local_window) { |
log("channel %d: rcvd too much extended_data %d, win %d", |
logit("channel %d: rcvd too much extended_data %d, win %d", |
c->self, data_len, c->local_window); |
c->self, data_len, c->local_window); |
xfree(data); |
xfree(data); |
return; |
return; |
|
|
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(); |
|
|
msg = packet_get_string(NULL); |
msg = packet_get_string(NULL); |
lang = packet_get_string(NULL); |
lang = packet_get_string(NULL); |
} |
} |
log("channel %d: open failed: %s%s%s", id, |
logit("channel %d: open failed: %s%s%s", id, |
reason2txt(reason), msg ? ": ": "", msg ? msg : ""); |
reason2txt(reason), msg ? ": ": "", msg ? msg : ""); |
if (msg != NULL) |
if (msg != NULL) |
xfree(msg); |
xfree(msg); |
|
|
c = channel_lookup(id); |
c = channel_lookup(id); |
|
|
if (c == NULL || c->type != SSH_CHANNEL_OPEN) { |
if (c == NULL || c->type != SSH_CHANNEL_OPEN) { |
log("Received window adjust for " |
logit("Received window adjust for " |
"non-open channel %d.", id); |
"non-open channel %d.", id); |
return; |
return; |
} |
} |
|
|
originator_string, 1); |
originator_string, 1); |
c->remote_id = remote_id; |
c->remote_id = remote_id; |
} |
} |
|
xfree(originator_string); |
if (c == NULL) { |
if (c == NULL) { |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
packet_put_int(remote_id); |
packet_put_int(remote_id); |
|
|
continue; |
continue; |
} |
} |
/* Create a port to listen for the host. */ |
/* Create a port to listen for the host. */ |
sock = socket(ai->ai_family, SOCK_STREAM, 0); |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
if (sock < 0) { |
if (sock < 0) { |
/* this is no error since kernel may not support ipv6 */ |
/* this is no error since kernel may not support ipv6 */ |
verbose("socket: %.100s", strerror(errno)); |
verbose("socket: %.100s", strerror(errno)); |
|
|
/* Allocate a channel number for the socket. */ |
/* Allocate a channel number for the socket. */ |
c = channel_new("port listener", type, sock, sock, -1, |
c = channel_new("port listener", type, sock, sock, -1, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
0, xstrdup("port listener"), 1); |
0, "port listener", 1); |
strlcpy(c->path, host, sizeof(c->path)); |
strlcpy(c->path, host, sizeof(c->path)); |
c->host_port = port_to_connect; |
c->host_port = port_to_connect; |
c->listening_port = listen_port; |
c->listening_port = listen_port; |
|
|
success = 1; |
success = 1; |
break; |
break; |
case SSH_SMSG_FAILURE: |
case SSH_SMSG_FAILURE: |
log("Warning: Server denied remote port forwarding."); |
logit("Warning: Server denied remote port forwarding."); |
break; |
break; |
default: |
default: |
/* Unknown packet */ |
/* Unknown packet */ |
|
|
* privileged port. |
* privileged port. |
*/ |
*/ |
if (port < IPPORT_RESERVED && !is_root) |
if (port < IPPORT_RESERVED && !is_root) |
packet_disconnect("Requested forwarding of port %d but user is not root.", |
packet_disconnect( |
port); |
"Requested forwarding of port %d but user is not root.", |
|
port); |
|
if (host_port == 0) |
|
packet_disconnect("Dynamic forwarding denied."); |
|
|
/* Initiate forwarding */ |
/* Initiate forwarding */ |
channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports); |
channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports); |
|
|
|
|
error("connect_to: getnameinfo failed"); |
error("connect_to: getnameinfo failed"); |
continue; |
continue; |
} |
} |
sock = socket(ai->ai_family, SOCK_STREAM, 0); |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
if (sock < 0) { |
if (sock < 0) { |
error("socket: %.100s", strerror(errno)); |
if (ai->ai_next == NULL) |
|
error("socket: %.100s", strerror(errno)); |
|
else |
|
verbose("socket: %.100s", strerror(errno)); |
continue; |
continue; |
} |
} |
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) |
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) |
|
|
|
|
} |
} |
if (!permit) { |
if (!permit) { |
log("Received request to connect to host %.100s port %d, " |
logit("Received request to connect to host %.100s port %d, " |
"but the request was denied.", host, port); |
"but the request was denied.", host, port); |
return -1; |
return -1; |
} |
} |
|
|
for (ai = aitop; ai; ai = ai->ai_next) { |
for (ai = aitop; ai; ai = ai->ai_next) { |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
continue; |
continue; |
sock = socket(ai->ai_family, SOCK_STREAM, 0); |
sock = socket(ai->ai_family, ai->ai_socktype, |
|
ai->ai_protocol); |
if (sock < 0) { |
if (sock < 0) { |
error("socket: %.100s", strerror(errno)); |
error("socket: %.100s", strerror(errno)); |
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) |
|
|
nc = channel_new("x11 listener", |
nc = channel_new("x11 listener", |
SSH_CHANNEL_X11_LISTENER, sock, sock, -1, |
SSH_CHANNEL_X11_LISTENER, sock, sock, -1, |
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, |
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, |
0, xstrdup("X11 inet listener"), 1); |
0, "X11 inet listener", 1); |
nc->single_connection = single_connection; |
nc->single_connection = single_connection; |
} |
} |
|
|
|
|
} |
} |
for (ai = aitop; ai; ai = ai->ai_next) { |
for (ai = aitop; ai; ai = ai->ai_next) { |
/* Create a socket. */ |
/* Create a socket. */ |
sock = socket(ai->ai_family, SOCK_STREAM, 0); |
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; |
|
|
c->remote_id = remote_id; |
c->remote_id = remote_id; |
c->force_drain = 1; |
c->force_drain = 1; |
} |
} |
|
xfree(remote_host); |
if (c == NULL) { |
if (c == NULL) { |
/* Send refusal to the remote host. */ |
/* Send refusal to the remote host. */ |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
|
|
{ |
{ |
Channel *c = NULL; |
Channel *c = NULL; |
int remote_id, sock; |
int remote_id, sock; |
char *name; |
|
|
|
/* Read the remote channel number from the message. */ |
/* Read the remote channel number from the message. */ |
remote_id = packet_get_int(); |
remote_id = packet_get_int(); |
|
|
* agent. |
* agent. |
*/ |
*/ |
if (sock >= 0) { |
if (sock >= 0) { |
name = xstrdup("authentication agent connection"); |
|
c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, |
c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, |
-1, 0, 0, 0, name, 1); |
-1, 0, 0, 0, "authentication agent connection", 1); |
c->remote_id = remote_id; |
c->remote_id = remote_id; |
c->force_drain = 1; |
c->force_drain = 1; |
} |
} |