version 1.353, 2016/09/19 07:52:42 |
version 1.354, 2016/09/30 09:19:13 |
|
|
#include "ssh.h" |
#include "ssh.h" |
#include "ssh1.h" |
#include "ssh1.h" |
#include "ssh2.h" |
#include "ssh2.h" |
|
#include "ssherr.h" |
#include "packet.h" |
#include "packet.h" |
#include "log.h" |
#include "log.h" |
#include "misc.h" |
#include "misc.h" |
|
|
char *listen_host; /* Remote side should listen address. */ |
char *listen_host; /* Remote side should listen address. */ |
char *listen_path; /* Remote side should listen path. */ |
char *listen_path; /* Remote side should listen path. */ |
int listen_port; /* Remote side should listen port. */ |
int listen_port; /* Remote side should listen port. */ |
|
Channel *downstream; /* Downstream mux*/ |
} ForwardPermission; |
} ForwardPermission; |
|
|
/* List of all permitted host/port pairs to connect by the user. */ |
/* List of all permitted host/port pairs to connect by the user. */ |
|
|
|
|
/* helper */ |
/* helper */ |
static void port_open_helper(Channel *c, char *rtype); |
static void port_open_helper(Channel *c, char *rtype); |
|
static const char *channel_rfwd_bind_host(const char *listen_host); |
|
|
/* non-blocking connect helpers */ |
/* non-blocking connect helpers */ |
static int connect_next(struct channel_connect *); |
static int connect_next(struct channel_connect *); |
|
|
return c; |
return c; |
} |
} |
|
|
|
Channel * |
|
channel_by_remote_id(int remote_id) |
|
{ |
|
Channel *c; |
|
u_int i; |
|
|
|
for (i = 0; i < channels_alloc; i++) { |
|
c = channels[i]; |
|
if (c != NULL && c->remote_id == remote_id) |
|
return c; |
|
} |
|
return NULL; |
|
} |
|
|
/* |
/* |
* Returns the channel if it is allowed to receive protocol messages. |
* Returns the channel if it is allowed to receive protocol messages. |
* Private channels, like listening sockets, may not receive messages. |
* Private channels, like listening sockets, may not receive messages. |
|
|
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
case SSH_CHANNEL_ABANDONED: |
case SSH_CHANNEL_ABANDONED: |
|
case SSH_CHANNEL_MUX_PROXY: |
return (c); |
return (c); |
} |
} |
logit("Non-public channel %d, type %d.", id, c->type); |
logit("Non-public channel %d, type %d.", id, c->type); |
|
|
{ |
{ |
char *s; |
char *s; |
u_int i, n; |
u_int i, n; |
|
Channel *other; |
struct channel_confirm *cc; |
struct channel_confirm *cc; |
|
|
for (n = 0, i = 0; i < channels_alloc; i++) |
for (n = 0, i = 0; i < channels_alloc; i++) { |
if (channels[i]) |
if ((other = channels[i]) != NULL) { |
n++; |
n++; |
|
|
|
/* detach from mux client and prepare for closing */ |
|
if (c->type == SSH_CHANNEL_MUX_CLIENT && |
|
other->type == SSH_CHANNEL_MUX_PROXY && |
|
other->mux_ctx == c) { |
|
other->mux_ctx = NULL; |
|
other->type = SSH_CHANNEL_OPEN; |
|
other->istate = CHAN_INPUT_CLOSED; |
|
other->ostate = CHAN_OUTPUT_CLOSED; |
|
} |
|
} |
|
} |
debug("channel %d: free: %s, nchannels %u", c->self, |
debug("channel %d: free: %s, nchannels %u", c->self, |
c->remote_name ? c->remote_name : "???", n); |
c->remote_name ? c->remote_name : "???", n); |
|
|
|
/* XXX more MUX cleanup: remove remote forwardings */ |
|
if (c->type == SSH_CHANNEL_MUX_CLIENT) { |
|
for (i = 0; i < (u_int)num_permitted_opens; i++) { |
|
if (permitted_opens[i].downstream != c) |
|
continue; |
|
/* cancel on the server, since mux client is gone */ |
|
debug("channel %d: cleanup remote forward for %s:%u", |
|
c->self, |
|
permitted_opens[i].listen_host, |
|
permitted_opens[i].listen_port); |
|
packet_start(SSH2_MSG_GLOBAL_REQUEST); |
|
packet_put_cstring("cancel-tcpip-forward"); |
|
packet_put_char(0); |
|
packet_put_cstring(channel_rfwd_bind_host( |
|
permitted_opens[i].listen_host)); |
|
packet_put_int(permitted_opens[i].listen_port); |
|
packet_send(); |
|
/* unregister */ |
|
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; |
|
free(permitted_opens[i].listen_host); |
|
permitted_opens[i].listen_host = NULL; |
|
permitted_opens[i].listen_path = NULL; |
|
permitted_opens[i].downstream = NULL; |
|
} |
|
} |
|
|
s = channel_open_message(); |
s = channel_open_message(); |
debug3("channel %d: status: %s", c->self, s); |
debug3("channel %d: status: %s", c->self, s); |
free(s); |
free(s); |
|
|
case SSH_CHANNEL_OPEN: |
case SSH_CHANNEL_OPEN: |
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_MUX_CLIENT: |
case SSH_CHANNEL_MUX_CLIENT: |
|
case SSH_CHANNEL_MUX_PROXY: |
return 1; |
return 1; |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
|
|
case SSH_CHANNEL_RPORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
case SSH_CHANNEL_MUX_LISTENER: |
case SSH_CHANNEL_MUX_LISTENER: |
case SSH_CHANNEL_MUX_CLIENT: |
case SSH_CHANNEL_MUX_CLIENT: |
|
case SSH_CHANNEL_MUX_PROXY: |
case SSH_CHANNEL_OPENING: |
case SSH_CHANNEL_OPENING: |
case SSH_CHANNEL_CONNECTING: |
case SSH_CHANNEL_CONNECTING: |
case SSH_CHANNEL_ZOMBIE: |
case SSH_CHANNEL_ZOMBIE: |
|
|
return -1; |
return -1; |
} |
} |
|
|
|
|
/* |
/* |
* Returns a message describing the currently open forwarded connections, |
* Returns a message describing the currently open forwarded connections, |
* suitable for sending to the client. The message contains crlf pairs for |
* suitable for sending to the client. The message contains crlf pairs for |
|
|
case SSH_CHANNEL_AUTH_SOCKET: |
case SSH_CHANNEL_AUTH_SOCKET: |
case SSH_CHANNEL_ZOMBIE: |
case SSH_CHANNEL_ZOMBIE: |
case SSH_CHANNEL_ABANDONED: |
case SSH_CHANNEL_ABANDONED: |
case SSH_CHANNEL_MUX_CLIENT: |
|
case SSH_CHANNEL_MUX_LISTENER: |
case SSH_CHANNEL_MUX_LISTENER: |
case SSH_CHANNEL_UNIX_LISTENER: |
case SSH_CHANNEL_UNIX_LISTENER: |
case SSH_CHANNEL_RUNIX_LISTENER: |
case SSH_CHANNEL_RUNIX_LISTENER: |
|
|
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
|
case SSH_CHANNEL_MUX_PROXY: |
|
case SSH_CHANNEL_MUX_CLIENT: |
snprintf(buf, sizeof buf, |
snprintf(buf, sizeof buf, |
" #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n", |
" #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n", |
c->self, c->remote_name, |
c->self, c->remote_name, |
|
|
} |
} |
} |
} |
|
|
|
/* -- mux proxy support */ |
|
|
|
/* |
|
* When multiplexing channel messages for mux clients we have to deal |
|
* with downstream messages from the mux client and upstream messages |
|
* from the ssh server: |
|
* 1) Handling downstream messages is straightforward and happens |
|
* in channel_proxy_downstream(): |
|
* - We forward all messages (mostly) unmodified to the server. |
|
* - However, in order to route messages from upstream to the correct |
|
* downstream client, we have to replace the channel IDs used by the |
|
* mux clients with a unique channel ID because the mux clients might |
|
* use conflicting channel IDs. |
|
* - so we inspect and change both SSH2_MSG_CHANNEL_OPEN and |
|
* SSH2_MSG_CHANNEL_OPEN_CONFIRMATION messages, create a local |
|
* SSH_CHANNEL_MUX_PROXY channel and replace the mux clients ID |
|
* with the newly allocated channel ID. |
|
* 2) Upstream messages are received by matching SSH_CHANNEL_MUX_PROXY |
|
* channels and procesed by channel_proxy_upstream(). The local channel ID |
|
* is then translated back to the original mux client ID. |
|
* 3) In both cases we need to keep track of matching SSH2_MSG_CHANNEL_CLOSE |
|
* messages so we can clean up SSH_CHANNEL_MUX_PROXY channels. |
|
* 4) The SSH_CHANNEL_MUX_PROXY channels also need to closed when the |
|
* downstream mux client are removed. |
|
* 5) Handling SSH2_MSG_CHANNEL_OPEN messages from the upstream server |
|
* requires more work, because they are not addressed to a specific |
|
* channel. E.g. client_request_forwarded_tcpip() needs to figure |
|
* out whether the request is addressed to the local client or a |
|
* specific downstream client based on the listen-address/port. |
|
* 6) Agent and X11-Forwarding have a similar problem and are currenly |
|
* not supported as the matching session/channel cannot be identified |
|
* easily. |
|
*/ |
|
|
|
/* |
|
* receive packets from downstream mux clients: |
|
* channel callback fired on read from mux client, creates |
|
* SSH_CHANNEL_MUX_PROXY channels and translates channel IDs |
|
* on channel creation. |
|
*/ |
|
int |
|
channel_proxy_downstream(Channel *downstream) |
|
{ |
|
Channel *c = NULL; |
|
struct ssh *ssh = active_state; |
|
struct sshbuf *original = NULL, *modified = NULL; |
|
const u_char *cp; |
|
char *ctype = NULL, *listen_host = NULL; |
|
u_char type; |
|
size_t have; |
|
int ret = -1, r, id, remote_id, listen_port, idx; |
|
|
|
/* sshbuf_dump(&downstream->input, stderr); */ |
|
if ((r = sshbuf_get_string_direct(&downstream->input, &cp, &have)) |
|
!= 0) { |
|
error("%s: malformed message: %s", __func__, ssh_err(r)); |
|
return -1; |
|
} |
|
if (have < 2) { |
|
error("%s: short message", __func__); |
|
return -1; |
|
} |
|
type = cp[1]; |
|
/* skip padlen + type */ |
|
cp += 2; |
|
have -= 2; |
|
if (ssh_packet_log_type(type)) |
|
debug3("%s: channel %u: down->up: type %u", __func__, |
|
downstream->self, type); |
|
|
|
switch (type) { |
|
case SSH2_MSG_CHANNEL_OPEN: |
|
if ((original = sshbuf_from(cp, have)) == NULL || |
|
(modified = sshbuf_new()) == NULL) { |
|
error("%s: alloc", __func__); |
|
goto out; |
|
} |
|
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 || |
|
(r = sshbuf_get_u32(original, &id)) != 0) { |
|
error("%s: parse error %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY, |
|
-1, -1, -1, 0, 0, 0, ctype, 1); |
|
c->mux_ctx = downstream; /* point to mux client */ |
|
c->mux_downstream_id = id; /* original downstream id */ |
|
if ((r = sshbuf_put_cstring(modified, ctype)) != 0 || |
|
(r = sshbuf_put_u32(modified, c->self)) != 0 || |
|
(r = sshbuf_putb(modified, original)) != 0) { |
|
error("%s: compose error %s", __func__, ssh_err(r)); |
|
channel_free(c); |
|
goto out; |
|
} |
|
break; |
|
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: |
|
/* |
|
* Almost the same as SSH2_MSG_CHANNEL_OPEN, except then we |
|
* need to parse 'remote_id' instead of 'ctype'. |
|
*/ |
|
if ((original = sshbuf_from(cp, have)) == NULL || |
|
(modified = sshbuf_new()) == NULL) { |
|
error("%s: alloc", __func__); |
|
goto out; |
|
} |
|
if ((r = sshbuf_get_u32(original, &remote_id)) != 0 || |
|
(r = sshbuf_get_u32(original, &id)) != 0) { |
|
error("%s: parse error %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY, |
|
-1, -1, -1, 0, 0, 0, "mux-down-connect", 1); |
|
c->mux_ctx = downstream; /* point to mux client */ |
|
c->mux_downstream_id = id; |
|
c->remote_id = remote_id; |
|
if ((r = sshbuf_put_u32(modified, remote_id)) != 0 || |
|
(r = sshbuf_put_u32(modified, c->self)) != 0 || |
|
(r = sshbuf_putb(modified, original)) != 0) { |
|
error("%s: compose error %s", __func__, ssh_err(r)); |
|
channel_free(c); |
|
goto out; |
|
} |
|
break; |
|
case SSH2_MSG_GLOBAL_REQUEST: |
|
if ((original = sshbuf_from(cp, have)) == NULL) { |
|
error("%s: alloc", __func__); |
|
goto out; |
|
} |
|
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) { |
|
error("%s: parse error %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
if (strcmp(ctype, "tcpip-forward") != 0) { |
|
error("%s: unsupported request %s", __func__, ctype); |
|
goto out; |
|
} |
|
if ((r = sshbuf_get_u8(original, NULL)) != 0 || |
|
(r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 || |
|
(r = sshbuf_get_u32(original, &listen_port)) != 0) { |
|
error("%s: parse error %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
/* Record that connection to this host/port is permitted. */ |
|
permitted_opens = xreallocarray(permitted_opens, |
|
num_permitted_opens + 1, sizeof(*permitted_opens)); |
|
idx = num_permitted_opens++; |
|
permitted_opens[idx].host_to_connect = xstrdup("<mux>"); |
|
permitted_opens[idx].port_to_connect = -1; |
|
permitted_opens[idx].listen_host = listen_host; |
|
permitted_opens[idx].listen_port = listen_port; |
|
permitted_opens[idx].downstream = downstream; |
|
listen_host = NULL; |
|
break; |
|
case SSH2_MSG_CHANNEL_CLOSE: |
|
if (have < 4) |
|
break; |
|
remote_id = PEEK_U32(cp); |
|
if ((c = channel_by_remote_id(remote_id)) != NULL) { |
|
if (c->flags & CHAN_CLOSE_RCVD) |
|
channel_free(c); |
|
else |
|
c->flags |= CHAN_CLOSE_SENT; |
|
} |
|
break; |
|
} |
|
if (modified) { |
|
if ((r = sshpkt_start(ssh, type)) != 0 || |
|
(r = sshpkt_putb(ssh, modified)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) { |
|
error("%s: send %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
} else { |
|
if ((r = sshpkt_start(ssh, type)) != 0 || |
|
(r = sshpkt_put(ssh, cp, have)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) { |
|
error("%s: send %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
} |
|
ret = 0; |
|
out: |
|
free(ctype); |
|
free(listen_host); |
|
sshbuf_free(original); |
|
sshbuf_free(modified); |
|
return ret; |
|
} |
|
|
|
/* |
|
* receive packets from upstream server and de-multiplex packets |
|
* to correct downstream: |
|
* implemented as a helper for channel input handlers, |
|
* replaces local (proxy) channel ID with downstream channel ID. |
|
*/ |
|
int |
|
channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt) |
|
{ |
|
struct ssh *ssh = active_state; |
|
struct sshbuf *b = NULL; |
|
Channel *downstream; |
|
const u_char *cp = NULL; |
|
size_t len; |
|
int r; |
|
|
|
/* |
|
* When receiving packets from the peer we need to check whether we |
|
* need to forward the packets to the mux client. In this case we |
|
* restore the orignal channel id and keep track of CLOSE messages, |
|
* so we can cleanup the channel. |
|
*/ |
|
if (c == NULL || c->type != SSH_CHANNEL_MUX_PROXY) |
|
return 0; |
|
if ((downstream = c->mux_ctx) == NULL) |
|
return 0; |
|
switch (type) { |
|
case SSH2_MSG_CHANNEL_CLOSE: |
|
case SSH2_MSG_CHANNEL_DATA: |
|
case SSH2_MSG_CHANNEL_EOF: |
|
case SSH2_MSG_CHANNEL_EXTENDED_DATA: |
|
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: |
|
case SSH2_MSG_CHANNEL_OPEN_FAILURE: |
|
case SSH2_MSG_CHANNEL_WINDOW_ADJUST: |
|
case SSH2_MSG_CHANNEL_SUCCESS: |
|
case SSH2_MSG_CHANNEL_FAILURE: |
|
case SSH2_MSG_CHANNEL_REQUEST: |
|
break; |
|
default: |
|
debug2("%s: channel %u: unsupported type %u", __func__, |
|
c->self, type); |
|
return 0; |
|
} |
|
if ((b = sshbuf_new()) == NULL) { |
|
error("%s: alloc reply", __func__); |
|
goto out; |
|
} |
|
/* get remaining payload (after id) */ |
|
cp = sshpkt_ptr(ssh, &len); |
|
if (cp == NULL) { |
|
error("%s: no packet", __func__); |
|
goto out; |
|
} |
|
/* translate id and send to muxclient */ |
|
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */ |
|
(r = sshbuf_put_u8(b, type)) != 0 || |
|
(r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 || |
|
(r = sshbuf_put(b, cp, len)) != 0 || |
|
(r = sshbuf_put_stringb(&downstream->output, b)) != 0) { |
|
error("%s: compose for muxclient %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
/* sshbuf_dump(b, stderr); */ |
|
if (ssh_packet_log_type(type)) |
|
debug3("%s: channel %u: up->down: type %u", __func__, c->self, |
|
type); |
|
out: |
|
/* update state */ |
|
switch (type) { |
|
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: |
|
/* record remote_id for SSH2_MSG_CHANNEL_CLOSE */ |
|
if (cp && len > 4) |
|
c->remote_id = PEEK_U32(cp); |
|
break; |
|
case SSH2_MSG_CHANNEL_CLOSE: |
|
if (c->flags & CHAN_CLOSE_SENT) |
|
channel_free(c); |
|
else |
|
c->flags |= CHAN_CLOSE_RCVD; |
|
break; |
|
} |
|
sshbuf_free(b); |
|
return 1; |
|
} |
|
|
/* -- protocol input */ |
/* -- protocol input */ |
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
|
|
c = channel_lookup(id); |
c = channel_lookup(id); |
if (c == NULL) |
if (c == NULL) |
packet_disconnect("Received data for nonexistent channel %d.", id); |
packet_disconnect("Received data for nonexistent channel %d.", id); |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
|
|
/* Ignore any data for non-open channels (might happen on close) */ |
/* Ignore any data for non-open channels (might happen on close) */ |
if (c->type != SSH_CHANNEL_OPEN && |
if (c->type != SSH_CHANNEL_OPEN && |
|
|
|
|
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 (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
if (c->type != SSH_CHANNEL_OPEN) { |
if (c->type != SSH_CHANNEL_OPEN) { |
logit("channel %d: ext data for non open", id); |
logit("channel %d: ext data for non open", id); |
return 0; |
return 0; |
|
|
c = channel_lookup(id); |
c = channel_lookup(id); |
if (c == NULL) |
if (c == NULL) |
packet_disconnect("Received ieof for nonexistent channel %d.", id); |
packet_disconnect("Received ieof for nonexistent channel %d.", id); |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
chan_rcvd_ieof(c); |
chan_rcvd_ieof(c); |
|
|
/* XXX force input close */ |
/* XXX force input close */ |
|
|
c = channel_lookup(id); |
c = channel_lookup(id); |
if (c == NULL) |
if (c == NULL) |
packet_disconnect("Received close for nonexistent channel %d.", id); |
packet_disconnect("Received close for nonexistent channel %d.", id); |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
/* |
/* |
* Send a confirmation that we have closed the channel and no more |
* Send a confirmation that we have closed the channel and no more |
* data is coming for it. |
* data is coming for it. |
|
|
int id = packet_get_int(); |
int id = packet_get_int(); |
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
packet_check_eom(); |
|
if (c == NULL) |
if (c == NULL) |
packet_disconnect("Received oclose for nonexistent channel %d.", id); |
packet_disconnect("Received oclose for nonexistent channel %d.", id); |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
|
packet_check_eom(); |
chan_rcvd_oclose(c); |
chan_rcvd_oclose(c); |
return 0; |
return 0; |
} |
} |
|
|
int id = packet_get_int(); |
int id = packet_get_int(); |
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
packet_check_eom(); |
|
if (c == NULL) |
if (c == NULL) |
packet_disconnect("Received close confirmation for " |
packet_disconnect("Received close confirmation for " |
"out-of-range channel %d.", id); |
"out-of-range channel %d.", id); |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
|
packet_check_eom(); |
if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED) |
if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED) |
packet_disconnect("Received close confirmation for " |
packet_disconnect("Received close confirmation for " |
"non-closed channel %d (type %d).", id, c->type); |
"non-closed channel %d (type %d).", id, c->type); |
|
|
id = packet_get_int(); |
id = packet_get_int(); |
c = channel_lookup(id); |
c = channel_lookup(id); |
|
|
if (c==NULL || c->type != SSH_CHANNEL_OPENING) |
if (c==NULL) |
packet_disconnect("Received open confirmation for " |
packet_disconnect("Received open confirmation for " |
|
"unknown channel %d.", id); |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
|
if (c->type != SSH_CHANNEL_OPENING) |
|
packet_disconnect("Received open confirmation for " |
"non-opening channel %d.", id); |
"non-opening channel %d.", id); |
remote_id = packet_get_int(); |
remote_id = packet_get_int(); |
/* Record the remote channel number and mark that the channel is now open. */ |
/* Record the remote channel number and mark that the channel is now open. */ |
|
|
id = packet_get_int(); |
id = packet_get_int(); |
c = channel_lookup(id); |
c = channel_lookup(id); |
|
|
if (c==NULL || c->type != SSH_CHANNEL_OPENING) |
if (c==NULL) |
packet_disconnect("Received open failure for " |
packet_disconnect("Received open failure for " |
|
"unknown channel %d.", id); |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
|
if (c->type != SSH_CHANNEL_OPENING) |
|
packet_disconnect("Received open failure for " |
"non-opening channel %d.", id); |
"non-opening channel %d.", id); |
if (compat20) { |
if (compat20) { |
reason = packet_get_int(); |
reason = packet_get_int(); |
|
|
logit("Received window adjust for non-open channel %d.", id); |
logit("Received window adjust for non-open channel %d.", id); |
return 0; |
return 0; |
} |
} |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
adjust = packet_get_int(); |
adjust = packet_get_int(); |
packet_check_eom(); |
packet_check_eom(); |
debug2("channel %d: rcvd adjust %u", id, adjust); |
debug2("channel %d: rcvd adjust %u", id, adjust); |
|
|
packet_set_alive_timeouts(0); |
packet_set_alive_timeouts(0); |
|
|
id = packet_get_int(); |
id = packet_get_int(); |
packet_check_eom(); |
|
|
|
debug2("channel_input_status_confirm: type %d id %d", type, id); |
debug2("channel_input_status_confirm: type %d id %d", type, id); |
|
|
if ((c = channel_lookup(id)) == NULL) { |
if ((c = channel_lookup(id)) == NULL) { |
logit("channel_input_status_confirm: %d: unknown", id); |
logit("channel_input_status_confirm: %d: unknown", id); |
return 0; |
return 0; |
} |
} |
|
if (channel_proxy_upstream(c, type, seq, ctxt)) |
|
return 0; |
|
packet_check_eom(); |
if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) |
if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) |
return 0; |
return 0; |
cc->cb(type, c, cc->ctx); |
cc->cb(type, c, cc->ctx); |
|
|
permitted_opens[idx].listen_path = NULL; |
permitted_opens[idx].listen_path = NULL; |
permitted_opens[idx].listen_port = fwd->listen_port; |
permitted_opens[idx].listen_port = fwd->listen_port; |
} |
} |
|
permitted_opens[idx].downstream = NULL; |
} |
} |
return (idx); |
return (idx); |
} |
} |
|
|
free(permitted_opens[i].listen_host); |
free(permitted_opens[i].listen_host); |
permitted_opens[i].listen_host = NULL; |
permitted_opens[i].listen_host = NULL; |
permitted_opens[i].listen_path = NULL; |
permitted_opens[i].listen_path = NULL; |
|
permitted_opens[i].downstream = NULL; |
|
|
return 0; |
return 0; |
} |
} |
|
|
permitted_opens[i].listen_host = NULL; |
permitted_opens[i].listen_host = NULL; |
free(permitted_opens[i].listen_path); |
free(permitted_opens[i].listen_path); |
permitted_opens[i].listen_path = NULL; |
permitted_opens[i].listen_path = NULL; |
|
permitted_opens[i].downstream = NULL; |
|
|
return 0; |
return 0; |
} |
} |
|
|
permitted_opens[num_permitted_opens].listen_host = NULL; |
permitted_opens[num_permitted_opens].listen_host = NULL; |
permitted_opens[num_permitted_opens].listen_path = NULL; |
permitted_opens[num_permitted_opens].listen_path = NULL; |
permitted_opens[num_permitted_opens].listen_port = 0; |
permitted_opens[num_permitted_opens].listen_port = 0; |
|
permitted_opens[num_permitted_opens].downstream = NULL; |
num_permitted_opens++; |
num_permitted_opens++; |
|
|
all_opens_permitted = 0; |
all_opens_permitted = 0; |
|
|
return c; |
return c; |
} |
} |
|
|
|
/* |
|
* returns either the newly connected channel or the downstream channel |
|
* that needs to deal with this connection. |
|
*/ |
Channel * |
Channel * |
channel_connect_by_listen_address(const char *listen_host, |
channel_connect_by_listen_address(const char *listen_host, |
u_short listen_port, char *ctype, char *rname) |
u_short listen_port, char *ctype, char *rname) |
|
|
for (i = 0; i < num_permitted_opens; i++) { |
for (i = 0; i < num_permitted_opens; i++) { |
if (open_listen_match_tcpip(&permitted_opens[i], listen_host, |
if (open_listen_match_tcpip(&permitted_opens[i], listen_host, |
listen_port, 1)) { |
listen_port, 1)) { |
|
if (permitted_opens[i].downstream) |
|
return permitted_opens[i].downstream; |
return connect_to( |
return connect_to( |
permitted_opens[i].host_to_connect, |
permitted_opens[i].host_to_connect, |
permitted_opens[i].port_to_connect, ctype, rname); |
permitted_opens[i].port_to_connect, ctype, rname); |