зеркало из https://github.com/github/putty.git
Replace enum+union of local channel types with a vtable.
There's now an interface called 'Channel', which handles the local side of an SSH connection-layer channel, in terms of knowing where to send incoming channel data to, whether to close the channel, etc. Channel and the previous 'struct ssh_channel' mutually refer. The latter contains all the SSH-specific parts, and as much of the common logic as possible: in particular, Channel doesn't have to know anything about SSH packet formats, or which SSH protocol version is in use, or deal with all the fiddly stuff about window sizes - with the exception that x11fwd.c's implementation of it does have to be able to ask for a small fixed initial window size for the bodgy system that distinguishes upstream from downstream X forwardings. I've taken the opportunity to move the code implementing the detailed behaviour of agent forwarding out of ssh.c, now that all of it is on the far side of a uniform interface. (This also means that if I later implement agent forwarding directly to a Unix socket as an alternative, it'll be a matter of changing just the one call to agentf_new() that makes the Channel to plug into a forwarding.)
This commit is contained in:
Родитель
8dfb2a1186
Коммит
6a8b9d3813
2
Recipe
2
Recipe
|
@ -254,7 +254,7 @@ SSH = ssh ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor
|
||||||
+ sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf
|
+ sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf
|
||||||
+ sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd
|
+ sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd
|
||||||
+ sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf
|
+ sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf
|
||||||
+ sshgssc pgssapi sshshare sshecc aqsync marshal nullplug
|
+ sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf
|
||||||
WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc
|
WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc
|
||||||
+ winhsock errsock
|
+ winhsock errsock
|
||||||
UXSSH = SSH uxnoise uxagentc uxgss uxshare
|
UXSSH = SSH uxnoise uxagentc uxgss uxshare
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* SSH agent forwarding.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "putty.h"
|
||||||
|
#include "ssh.h"
|
||||||
|
#include "pageant.h"
|
||||||
|
#include "sshchan.h"
|
||||||
|
|
||||||
|
typedef struct agentf {
|
||||||
|
struct ssh_channel *c;
|
||||||
|
bufchain inbuffer;
|
||||||
|
agent_pending_query *pending;
|
||||||
|
int input_wanted;
|
||||||
|
int rcvd_eof;
|
||||||
|
|
||||||
|
Channel chan;
|
||||||
|
} agentf;
|
||||||
|
|
||||||
|
static void agentf_got_response(agentf *af, void *reply, int replylen)
|
||||||
|
{
|
||||||
|
af->pending = NULL;
|
||||||
|
|
||||||
|
if (!reply) {
|
||||||
|
/* The real agent didn't send any kind of reply at all for
|
||||||
|
* some reason, so fake an SSH_AGENT_FAILURE. */
|
||||||
|
reply = "\0\0\0\1\5";
|
||||||
|
replylen = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
sshfwd_write(af->c, reply, replylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agentf_callback(void *vctx, void *reply, int replylen);
|
||||||
|
|
||||||
|
static void agentf_try_forward(agentf *af)
|
||||||
|
{
|
||||||
|
unsigned datalen, length;
|
||||||
|
strbuf *message;
|
||||||
|
unsigned char msglen[4];
|
||||||
|
void *reply;
|
||||||
|
int replylen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't try to parallelise agent requests. Wait for each one to
|
||||||
|
* return before attempting the next.
|
||||||
|
*/
|
||||||
|
if (af->pending)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the outgoing side of the channel connection is currently
|
||||||
|
* throttled, don't submit any new forwarded requests to the real
|
||||||
|
* agent. This causes the input side of the agent forwarding not
|
||||||
|
* to be emptied, exerting the required back-pressure on the
|
||||||
|
* remote client, and encouraging it to read our responses before
|
||||||
|
* sending too many more requests.
|
||||||
|
*/
|
||||||
|
if (!af->input_wanted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/*
|
||||||
|
* Try to extract a complete message from the input buffer.
|
||||||
|
*/
|
||||||
|
datalen = bufchain_size(&af->inbuffer);
|
||||||
|
if (datalen < 4)
|
||||||
|
break; /* not even a length field available yet */
|
||||||
|
|
||||||
|
bufchain_fetch(&af->inbuffer, msglen, 4);
|
||||||
|
length = GET_32BIT(msglen);
|
||||||
|
|
||||||
|
if (length > AGENT_MAX_MSGLEN-4) {
|
||||||
|
/*
|
||||||
|
* If the remote has sent a message that's just _too_
|
||||||
|
* long, we should reject it in advance of seeing the rest
|
||||||
|
* of the incoming message, and also close the connection
|
||||||
|
* for good measure (which avoids us having to faff about
|
||||||
|
* with carefully ignoring just the right number of bytes
|
||||||
|
* from the overlong message).
|
||||||
|
*/
|
||||||
|
agentf_got_response(af, NULL, 0);
|
||||||
|
sshfwd_write_eof(af->c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > datalen - 4)
|
||||||
|
break; /* a whole message is not yet available */
|
||||||
|
|
||||||
|
bufchain_consume(&af->inbuffer, 4);
|
||||||
|
|
||||||
|
message = strbuf_new_for_agent_query();
|
||||||
|
bufchain_fetch_consume(
|
||||||
|
&af->inbuffer, strbuf_append(message, length), length);
|
||||||
|
af->pending = agent_query(
|
||||||
|
message, &reply, &replylen, agentf_callback, af);
|
||||||
|
strbuf_free(message);
|
||||||
|
|
||||||
|
if (af->pending)
|
||||||
|
return; /* agent_query promised to reply in due course */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the agent gave us an answer immediately, pass it
|
||||||
|
* straight on and go round this loop again.
|
||||||
|
*/
|
||||||
|
agentf_got_response(af, reply, replylen);
|
||||||
|
sfree(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we get here (i.e. we left the above while loop via 'break'
|
||||||
|
* rather than 'return'), that means we've determined that the
|
||||||
|
* input buffer for the agent forwarding connection doesn't
|
||||||
|
* contain a complete request.
|
||||||
|
*
|
||||||
|
* So if there's potentially more data to come, we can return now,
|
||||||
|
* and wait for the remote client to send it. But if the remote
|
||||||
|
* has sent EOF, it would be a mistake to do that, because we'd be
|
||||||
|
* waiting a long time. So this is the moment to check for EOF,
|
||||||
|
* and respond appropriately.
|
||||||
|
*/
|
||||||
|
if (af->rcvd_eof)
|
||||||
|
sshfwd_write_eof(af->c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agentf_callback(void *vctx, void *reply, int replylen)
|
||||||
|
{
|
||||||
|
agentf *af = (agentf *)vctx;
|
||||||
|
|
||||||
|
agentf_got_response(af, reply, replylen);
|
||||||
|
sfree(reply);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now try to extract and send further messages from the channel's
|
||||||
|
* input-side buffer.
|
||||||
|
*/
|
||||||
|
agentf_try_forward(af);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agentf_free(Channel *chan);
|
||||||
|
static int agentf_send(Channel *chan, int is_stderr, const void *, int);
|
||||||
|
static void agentf_send_eof(Channel *chan);
|
||||||
|
static char *agentf_log_close_msg(Channel *chan);
|
||||||
|
static void agentf_set_input_wanted(Channel *chan, int wanted);
|
||||||
|
|
||||||
|
static const struct ChannelVtable agentf_channelvt = {
|
||||||
|
agentf_free,
|
||||||
|
chan_remotely_opened_confirmation,
|
||||||
|
chan_remotely_opened_failure,
|
||||||
|
agentf_send,
|
||||||
|
agentf_send_eof,
|
||||||
|
agentf_set_input_wanted,
|
||||||
|
agentf_log_close_msg,
|
||||||
|
chan_no_eager_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
Channel *agentf_new(struct ssh_channel *c)
|
||||||
|
{
|
||||||
|
agentf *af = snew(agentf);
|
||||||
|
af->c = c;
|
||||||
|
af->chan.vt = &agentf_channelvt;
|
||||||
|
af->chan.initial_fixed_window_size = 0;
|
||||||
|
af->rcvd_eof = TRUE;
|
||||||
|
bufchain_init(&af->inbuffer);
|
||||||
|
af->pending = NULL;
|
||||||
|
af->input_wanted = TRUE;
|
||||||
|
return &af->chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agentf_free(Channel *chan)
|
||||||
|
{
|
||||||
|
assert(chan->vt == &agentf_channelvt);
|
||||||
|
agentf *af = FROMFIELD(chan, agentf, chan);
|
||||||
|
|
||||||
|
if (af->pending)
|
||||||
|
agent_cancel_query(af->pending);
|
||||||
|
bufchain_clear(&af->inbuffer);
|
||||||
|
sfree(af);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int agentf_send(Channel *chan, int is_stderr,
|
||||||
|
const void *data, int length)
|
||||||
|
{
|
||||||
|
assert(chan->vt == &agentf_channelvt);
|
||||||
|
agentf *af = FROMFIELD(chan, agentf, chan);
|
||||||
|
bufchain_add(&af->inbuffer, data, length);
|
||||||
|
agentf_try_forward(af);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We exert back-pressure on an agent forwarding client if and
|
||||||
|
* only if we're waiting for the response to an asynchronous agent
|
||||||
|
* request. This prevents the client running out of window while
|
||||||
|
* receiving the _first_ message, but means that if any message
|
||||||
|
* takes time to process, the client will be discouraged from
|
||||||
|
* sending an endless stream of further ones after it.
|
||||||
|
*/
|
||||||
|
return (af->pending ? bufchain_size(&af->inbuffer) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agentf_send_eof(Channel *chan)
|
||||||
|
{
|
||||||
|
assert(chan->vt == &agentf_channelvt);
|
||||||
|
agentf *af = FROMFIELD(chan, agentf, chan);
|
||||||
|
|
||||||
|
af->rcvd_eof = TRUE;
|
||||||
|
|
||||||
|
/* Call try_forward, which will respond to the EOF now if
|
||||||
|
* appropriate, or wait until the queue of outstanding requests is
|
||||||
|
* dealt with if not. */
|
||||||
|
agentf_try_forward(af);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *agentf_log_close_msg(Channel *chan)
|
||||||
|
{
|
||||||
|
return dupstr("Agent-forwarding connection closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agentf_set_input_wanted(Channel *chan, int wanted)
|
||||||
|
{
|
||||||
|
assert(chan->vt == &agentf_channelvt);
|
||||||
|
agentf *af = FROMFIELD(chan, agentf, chan);
|
||||||
|
|
||||||
|
af->input_wanted = wanted;
|
||||||
|
|
||||||
|
/* Agent forwarding channels are buffer-managed by not asking the
|
||||||
|
* agent questions if the SSH channel isn't accepting input. So if
|
||||||
|
* it's started again, we should ask a question if we have one
|
||||||
|
* pending.. */
|
||||||
|
if (wanted)
|
||||||
|
agentf_try_forward(af);
|
||||||
|
}
|
2
defs.h
2
defs.h
|
@ -53,6 +53,8 @@ typedef struct Frontend Frontend;
|
||||||
|
|
||||||
typedef struct ssh_tag *Ssh;
|
typedef struct ssh_tag *Ssh;
|
||||||
|
|
||||||
|
typedef struct Channel Channel;
|
||||||
|
|
||||||
/* Note indirection: for historical reasons (it used to be closer to
|
/* Note indirection: for historical reasons (it used to be closer to
|
||||||
* the OS socket type), the type that most code uses for a socket is
|
* the OS socket type), the type that most code uses for a socket is
|
||||||
* 'Socket', not 'Socket *'. So an implementation of Socket or Plug
|
* 'Socket', not 'Socket *'. So an implementation of Socket or Plug
|
||||||
|
|
143
portfwd.c
143
portfwd.c
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
#include "sshchan.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enumeration of values that live in the 'socks_state' field of
|
* Enumeration of values that live in the 'socks_state' field of
|
||||||
|
@ -21,12 +22,12 @@ typedef enum {
|
||||||
SOCKS_5_CONNECT /* expect a SOCKS 5 connection message */
|
SOCKS_5_CONNECT /* expect a SOCKS 5 connection message */
|
||||||
} SocksState;
|
} SocksState;
|
||||||
|
|
||||||
struct PortForwarding {
|
typedef struct PortForwarding {
|
||||||
struct ssh_channel *c; /* channel structure held by ssh.c */
|
struct ssh_channel *c; /* channel structure held by ssh.c */
|
||||||
Ssh ssh; /* instance of SSH backend itself */
|
Ssh ssh; /* instance of SSH backend itself */
|
||||||
/* Note that ssh need not be filled in if c is non-NULL */
|
/* Note that ssh need not be filled in if c is non-NULL */
|
||||||
Socket s;
|
Socket s;
|
||||||
int throttled, throttle_override;
|
int input_wanted;
|
||||||
int ready;
|
int ready;
|
||||||
SocksState socks_state;
|
SocksState socks_state;
|
||||||
/*
|
/*
|
||||||
|
@ -44,7 +45,8 @@ struct PortForwarding {
|
||||||
size_t socksbuf_consumed;
|
size_t socksbuf_consumed;
|
||||||
|
|
||||||
const Plug_vtable *plugvt;
|
const Plug_vtable *plugvt;
|
||||||
};
|
Channel chan;
|
||||||
|
} PortForwarding;
|
||||||
|
|
||||||
struct PortListener {
|
struct PortListener {
|
||||||
Ssh ssh; /* instance of SSH backend itself */
|
Ssh ssh; /* instance of SSH backend itself */
|
||||||
|
@ -105,6 +107,8 @@ static void pfl_log(Plug plug, int type, SockAddr addr, int port,
|
||||||
/* we have to dump these since we have no interface to logging.c */
|
/* we have to dump these since we have no interface to logging.c */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pfd_close(struct PortForwarding *pf);
|
||||||
|
|
||||||
static void pfd_closing(Plug plug, const char *error_msg, int error_code,
|
static void pfd_closing(Plug plug, const char *error_msg, int error_code,
|
||||||
int calling_back)
|
int calling_back)
|
||||||
{
|
{
|
||||||
|
@ -142,10 +146,12 @@ static void pfl_closing(Plug plug, const char *error_msg, int error_code,
|
||||||
pfl_terminate(pl);
|
pfl_terminate(pl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wrap_send_port_open(void *channel, const char *hostname, int port,
|
static struct ssh_channel *wrap_send_port_open(
|
||||||
Socket s)
|
Ssh ssh, const char *hostname, int port, Socket s, Channel *chan)
|
||||||
{
|
{
|
||||||
char *peerinfo, *description;
|
char *peerinfo, *description;
|
||||||
|
struct ssh_channel *toret;
|
||||||
|
|
||||||
peerinfo = sk_peer_info(s);
|
peerinfo = sk_peer_info(s);
|
||||||
if (peerinfo) {
|
if (peerinfo) {
|
||||||
description = dupprintf("forwarding from %s", peerinfo);
|
description = dupprintf("forwarding from %s", peerinfo);
|
||||||
|
@ -153,8 +159,11 @@ static void wrap_send_port_open(void *channel, const char *hostname, int port,
|
||||||
} else {
|
} else {
|
||||||
description = dupstr("forwarding");
|
description = dupstr("forwarding");
|
||||||
}
|
}
|
||||||
ssh_send_port_open(channel, hostname, port, description);
|
|
||||||
|
toret = ssh_send_port_open(ssh, hostname, port, description, chan);
|
||||||
|
|
||||||
sfree(description);
|
sfree(description);
|
||||||
|
return toret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *ipv4_to_string(unsigned ipv4)
|
static char *ipv4_to_string(unsigned ipv4)
|
||||||
|
@ -396,21 +405,11 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len)
|
||||||
*/
|
*/
|
||||||
sk_set_frozen(pf->s, 1);
|
sk_set_frozen(pf->s, 1);
|
||||||
|
|
||||||
pf->c = new_sock_channel(pf->ssh, pf);
|
pf->c = wrap_send_port_open(pf->ssh, pf->hostname, pf->port, pf->s,
|
||||||
if (pf->c == NULL) {
|
&pf->chan);
|
||||||
pfd_close(pf);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
/* asks to forward to the specified host/port for this */
|
|
||||||
wrap_send_port_open(pf->c, pf->hostname, pf->port, pf->s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pf->ready) {
|
|
||||||
if (sshfwd_write(pf->c, data, len) > 0) {
|
|
||||||
pf->throttled = 1;
|
|
||||||
sk_set_frozen(pf->s, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (pf->ready)
|
||||||
|
sshfwd_write(pf->c, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pfd_sent(Plug plug, int bufsize)
|
static void pfd_sent(Plug plug, int bufsize)
|
||||||
|
@ -429,6 +428,25 @@ static const Plug_vtable PortForwarding_plugvt = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void pfd_chan_free(Channel *chan);
|
||||||
|
static void pfd_open_confirmation(Channel *chan);
|
||||||
|
static void pfd_open_failure(Channel *chan, const char *errtext);
|
||||||
|
static int pfd_send(Channel *chan, int is_stderr, const void *data, int len);
|
||||||
|
static void pfd_send_eof(Channel *chan);
|
||||||
|
static void pfd_set_input_wanted(Channel *chan, int wanted);
|
||||||
|
static char *pfd_log_close_msg(Channel *chan);
|
||||||
|
|
||||||
|
static const struct ChannelVtable PortForwarding_channelvt = {
|
||||||
|
pfd_chan_free,
|
||||||
|
pfd_open_confirmation,
|
||||||
|
pfd_open_failure,
|
||||||
|
pfd_send,
|
||||||
|
pfd_send_eof,
|
||||||
|
pfd_set_input_wanted,
|
||||||
|
pfd_log_close_msg,
|
||||||
|
chan_no_eager_close,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when receiving a PORT OPEN from the server to make a
|
* Called when receiving a PORT OPEN from the server to make a
|
||||||
* connection to a destination host.
|
* connection to a destination host.
|
||||||
|
@ -436,8 +454,8 @@ static const Plug_vtable PortForwarding_plugvt = {
|
||||||
* On success, returns NULL and fills in *pf_ret. On error, returns a
|
* On success, returns NULL and fills in *pf_ret. On error, returns a
|
||||||
* dynamically allocated error message string.
|
* dynamically allocated error message string.
|
||||||
*/
|
*/
|
||||||
char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
|
char *pfd_connect(Channel **chan_ret, char *hostname,int port,
|
||||||
void *c, Conf *conf, int addressfamily)
|
struct ssh_channel *c, Conf *conf, int addressfamily)
|
||||||
{
|
{
|
||||||
SockAddr addr;
|
SockAddr addr;
|
||||||
const char *err;
|
const char *err;
|
||||||
|
@ -459,9 +477,12 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
|
||||||
/*
|
/*
|
||||||
* Open socket.
|
* Open socket.
|
||||||
*/
|
*/
|
||||||
pf = *pf_ret = new_portfwd_state();
|
pf = new_portfwd_state();
|
||||||
|
*chan_ret = &pf->chan;
|
||||||
pf->plugvt = &PortForwarding_plugvt;
|
pf->plugvt = &PortForwarding_plugvt;
|
||||||
pf->throttled = pf->throttle_override = 0;
|
pf->chan.initial_fixed_window_size = 0;
|
||||||
|
pf->chan.vt = &PortForwarding_channelvt;
|
||||||
|
pf->input_wanted = TRUE;
|
||||||
pf->ready = 1;
|
pf->ready = 1;
|
||||||
pf->c = c;
|
pf->c = c;
|
||||||
pf->ssh = NULL; /* we shouldn't need this */
|
pf->ssh = NULL; /* we shouldn't need this */
|
||||||
|
@ -474,7 +495,7 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
|
||||||
char *err_ret = dupstr(err);
|
char *err_ret = dupstr(err);
|
||||||
sk_close(pf->s);
|
sk_close(pf->s);
|
||||||
free_portfwd_state(pf);
|
free_portfwd_state(pf);
|
||||||
*pf_ret = NULL;
|
*chan_ret = NULL;
|
||||||
return err_ret;
|
return err_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,6 +516,9 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
|
||||||
pl = FROMFIELD(p, struct PortListener, plugvt);
|
pl = FROMFIELD(p, struct PortListener, plugvt);
|
||||||
pf = new_portfwd_state();
|
pf = new_portfwd_state();
|
||||||
pf->plugvt = &PortForwarding_plugvt;
|
pf->plugvt = &PortForwarding_plugvt;
|
||||||
|
pf->chan.initial_fixed_window_size = 0;
|
||||||
|
pf->chan.vt = &PortForwarding_channelvt;
|
||||||
|
pf->input_wanted = TRUE;
|
||||||
|
|
||||||
pf->c = NULL;
|
pf->c = NULL;
|
||||||
pf->ssh = pl->ssh;
|
pf->ssh = pl->ssh;
|
||||||
|
@ -505,7 +529,7 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
|
||||||
return err != NULL;
|
return err != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pf->throttled = pf->throttle_override = 0;
|
pf->input_wanted = TRUE;
|
||||||
pf->ready = 0;
|
pf->ready = 0;
|
||||||
|
|
||||||
if (pl->is_dynamic) {
|
if (pl->is_dynamic) {
|
||||||
|
@ -518,15 +542,8 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
|
||||||
pf->socks_state = SOCKS_NONE;
|
pf->socks_state = SOCKS_NONE;
|
||||||
pf->hostname = dupstr(pl->hostname);
|
pf->hostname = dupstr(pl->hostname);
|
||||||
pf->port = pl->port;
|
pf->port = pl->port;
|
||||||
pf->c = new_sock_channel(pl->ssh, pf);
|
pf->c = wrap_send_port_open(pl->ssh, pf->hostname, pf->port,
|
||||||
|
s, &pf->chan);
|
||||||
if (pf->c == NULL) {
|
|
||||||
free_portfwd_state(pf);
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
/* asks to forward to the specified host/port for this */
|
|
||||||
wrap_send_port_open(pf->c, pf->hostname, pf->port, s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -580,7 +597,12 @@ char *pfl_listen(char *desthost, int destport, char *srcaddr,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pfd_close(struct PortForwarding *pf)
|
static char *pfd_log_close_msg(Channel *chan)
|
||||||
|
{
|
||||||
|
return dupstr("Forwarded port closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pfd_close(struct PortForwarding *pf)
|
||||||
{
|
{
|
||||||
if (!pf)
|
if (!pf)
|
||||||
return;
|
return;
|
||||||
|
@ -601,43 +623,42 @@ void pfl_terminate(struct PortListener *pl)
|
||||||
free_portlistener_state(pl);
|
free_portlistener_state(pl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pfd_unthrottle(struct PortForwarding *pf)
|
static void pfd_set_input_wanted(Channel *chan, int wanted)
|
||||||
{
|
{
|
||||||
if (!pf)
|
assert(chan->vt == &PortForwarding_channelvt);
|
||||||
return;
|
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
|
||||||
|
pf->input_wanted = wanted;
|
||||||
pf->throttled = 0;
|
sk_set_frozen(pf->s, !pf->input_wanted);
|
||||||
sk_set_frozen(pf->s, pf->throttled || pf->throttle_override);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pfd_override_throttle(struct PortForwarding *pf, int enable)
|
static void pfd_chan_free(Channel *chan)
|
||||||
{
|
{
|
||||||
if (!pf)
|
assert(chan->vt == &PortForwarding_channelvt);
|
||||||
return;
|
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
|
||||||
|
pfd_close(pf);
|
||||||
pf->throttle_override = enable;
|
|
||||||
sk_set_frozen(pf->s, pf->throttled || pf->throttle_override);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to send data down the raw connection.
|
* Called to send data down the raw connection.
|
||||||
*/
|
*/
|
||||||
int pfd_send(struct PortForwarding *pf, const void *data, int len)
|
static int pfd_send(Channel *chan, int is_stderr, const void *data, int len)
|
||||||
{
|
{
|
||||||
if (pf == NULL)
|
assert(chan->vt == &PortForwarding_channelvt);
|
||||||
return 0;
|
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
|
||||||
return sk_write(pf->s, data, len);
|
return sk_write(pf->s, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pfd_send_eof(struct PortForwarding *pf)
|
static void pfd_send_eof(Channel *chan)
|
||||||
{
|
{
|
||||||
|
assert(chan->vt == &PortForwarding_channelvt);
|
||||||
|
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
|
||||||
sk_write_eof(pf->s);
|
sk_write_eof(pf->s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pfd_confirm(struct PortForwarding *pf)
|
static void pfd_open_confirmation(Channel *chan)
|
||||||
{
|
{
|
||||||
if (pf == NULL)
|
assert(chan->vt == &PortForwarding_channelvt);
|
||||||
return;
|
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
|
||||||
|
|
||||||
pf->ready = 1;
|
pf->ready = 1;
|
||||||
sk_set_frozen(pf->s, 0);
|
sk_set_frozen(pf->s, 0);
|
||||||
|
@ -649,3 +670,15 @@ void pfd_confirm(struct PortForwarding *pf)
|
||||||
pf->socksbuf = NULL;
|
pf->socksbuf = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pfd_open_failure(Channel *chan, const char *errtext)
|
||||||
|
{
|
||||||
|
assert(chan->vt == &PortForwarding_channelvt);
|
||||||
|
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
|
||||||
|
|
||||||
|
char *msg = dupprintf(
|
||||||
|
"Forwarded connection refused by server%s%s",
|
||||||
|
errtext ? ": " : "", errtext ? errtext : "");
|
||||||
|
logevent(ssh_get_frontend(pf->ssh), msg);
|
||||||
|
sfree(msg);
|
||||||
|
}
|
||||||
|
|
783
ssh.c
783
ssh.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
31
ssh.h
31
ssh.h
|
@ -14,12 +14,12 @@ extern void sshfwd_write_eof(struct ssh_channel *c);
|
||||||
extern void sshfwd_unclean_close(struct ssh_channel *c, const char *err);
|
extern void sshfwd_unclean_close(struct ssh_channel *c, const char *err);
|
||||||
extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize);
|
extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize);
|
||||||
Conf *sshfwd_get_conf(struct ssh_channel *c);
|
Conf *sshfwd_get_conf(struct ssh_channel *c);
|
||||||
|
void sshfwd_window_override_removed(struct ssh_channel *c);
|
||||||
void sshfwd_x11_sharing_handover(struct ssh_channel *c,
|
void sshfwd_x11_sharing_handover(struct ssh_channel *c,
|
||||||
void *share_cs, void *share_chan,
|
void *share_cs, void *share_chan,
|
||||||
const char *peer_addr, int peer_port,
|
const char *peer_addr, int peer_port,
|
||||||
int endian, int protomajor, int protominor,
|
int endian, int protomajor, int protominor,
|
||||||
const void *initial_data, int initial_len);
|
const void *initial_data, int initial_len);
|
||||||
void sshfwd_x11_is_local(struct ssh_channel *c);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buffer management constants. There are several of these for
|
* Buffer management constants. There are several of these for
|
||||||
|
@ -185,6 +185,8 @@ void share_setup_x11_channel(void *csv, void *chanv,
|
||||||
int protomajor, int protominor,
|
int protomajor, int protominor,
|
||||||
const void *initial_data, int initial_len);
|
const void *initial_data, int initial_len);
|
||||||
|
|
||||||
|
Frontend *ssh_get_frontend(Ssh ssh);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Useful thing.
|
* Useful thing.
|
||||||
*/
|
*/
|
||||||
|
@ -665,19 +667,12 @@ void logevent(Frontend *, const char *);
|
||||||
struct PortForwarding;
|
struct PortForwarding;
|
||||||
|
|
||||||
/* Allocate and register a new channel for port forwarding */
|
/* Allocate and register a new channel for port forwarding */
|
||||||
void *new_sock_channel(Ssh ssh, struct PortForwarding *pf);
|
struct ssh_channel *ssh_send_port_open(Ssh ssh, const char *hostname, int port,
|
||||||
void ssh_send_port_open(void *channel, const char *hostname, int port,
|
const char *org, Channel *chan);
|
||||||
const char *org);
|
|
||||||
|
|
||||||
/* Exports from portfwd.c */
|
/* Exports from portfwd.c */
|
||||||
extern char *pfd_connect(struct PortForwarding **pf, char *hostname, int port,
|
extern char *pfd_connect(Channel **chan_ret, char *hostname, int port,
|
||||||
void *c, Conf *conf, int addressfamily);
|
struct ssh_channel *c, Conf *conf, int addressfamily);
|
||||||
extern void pfd_close(struct PortForwarding *);
|
|
||||||
extern int pfd_send(struct PortForwarding *, const void *data, int len);
|
|
||||||
extern void pfd_send_eof(struct PortForwarding *);
|
|
||||||
extern void pfd_confirm(struct PortForwarding *);
|
|
||||||
extern void pfd_unthrottle(struct PortForwarding *);
|
|
||||||
extern void pfd_override_throttle(struct PortForwarding *, int enable);
|
|
||||||
struct PortListener;
|
struct PortListener;
|
||||||
/* desthost == NULL indicates dynamic (SOCKS) port forwarding */
|
/* desthost == NULL indicates dynamic (SOCKS) port forwarding */
|
||||||
extern char *pfl_listen(char *desthost, int destport, char *srcaddr,
|
extern char *pfl_listen(char *desthost, int destport, char *srcaddr,
|
||||||
|
@ -750,13 +745,9 @@ extern struct X11Display *x11_setup_display(const char *display, Conf *);
|
||||||
void x11_free_display(struct X11Display *disp);
|
void x11_free_display(struct X11Display *disp);
|
||||||
struct X11FakeAuth *x11_invent_fake_auth(tree234 *t, int authtype);
|
struct X11FakeAuth *x11_invent_fake_auth(tree234 *t, int authtype);
|
||||||
void x11_free_fake_auth(struct X11FakeAuth *auth);
|
void x11_free_fake_auth(struct X11FakeAuth *auth);
|
||||||
struct X11Connection; /* opaque outside x11fwd.c */
|
Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c,
|
||||||
struct X11Connection *x11_init(tree234 *authtree, void *, const char *, int);
|
const char *peeraddr, int peerport,
|
||||||
extern void x11_close(struct X11Connection *);
|
int connection_sharing_possible);
|
||||||
extern int x11_send(struct X11Connection *, const void *, int);
|
|
||||||
extern void x11_send_eof(struct X11Connection *s);
|
|
||||||
extern void x11_unthrottle(struct X11Connection *s);
|
|
||||||
extern void x11_override_throttle(struct X11Connection *s, int enable);
|
|
||||||
char *x11_display(const char *display);
|
char *x11_display(const char *display);
|
||||||
/* Platform-dependent X11 functions */
|
/* Platform-dependent X11 functions */
|
||||||
extern void platform_get_x11_auth(struct X11Display *display, Conf *);
|
extern void platform_get_x11_auth(struct X11Display *display, Conf *);
|
||||||
|
@ -786,6 +777,8 @@ void x11_get_auth_from_authfile(struct X11Display *display,
|
||||||
int x11_identify_auth_proto(ptrlen protoname);
|
int x11_identify_auth_proto(ptrlen protoname);
|
||||||
void *x11_dehexify(ptrlen hex, int *outlen);
|
void *x11_dehexify(ptrlen hex, int *outlen);
|
||||||
|
|
||||||
|
Channel *agentf_new(struct ssh_channel *c);
|
||||||
|
|
||||||
Bignum copybn(Bignum b);
|
Bignum copybn(Bignum b);
|
||||||
Bignum bn_power_2(int n);
|
Bignum bn_power_2(int n);
|
||||||
void bn_restore_invariant(Bignum b);
|
void bn_restore_invariant(Bignum b);
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Abstraction of the various ways to handle the local end of an SSH
|
||||||
|
* connection-layer channel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PUTTY_SSHCHAN_H
|
||||||
|
#define PUTTY_SSHCHAN_H
|
||||||
|
|
||||||
|
struct ChannelVtable {
|
||||||
|
void (*free)(Channel *);
|
||||||
|
|
||||||
|
/* Called for channel types that were created at the same time as
|
||||||
|
* we sent an outgoing CHANNEL_OPEN, when the confirmation comes
|
||||||
|
* back from the server indicating that the channel has been
|
||||||
|
* opened, or the failure message indicating that it hasn't,
|
||||||
|
* respectively. In the latter case, this must _not_ free the
|
||||||
|
* Channel structure - the client will call the free method
|
||||||
|
* separately. But it might do logging or other local cleanup. */
|
||||||
|
void (*open_confirmation)(Channel *);
|
||||||
|
void (*open_failed)(Channel *, const char *error_text);
|
||||||
|
|
||||||
|
int (*send)(Channel *, int is_stderr, const void *buf, int len);
|
||||||
|
void (*send_eof)(Channel *);
|
||||||
|
void (*set_input_wanted)(Channel *, int wanted);
|
||||||
|
|
||||||
|
char *(*log_close_msg)(Channel *);
|
||||||
|
|
||||||
|
int (*want_close)(Channel *, int sent_local_eof, int rcvd_remote_eof);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Channel {
|
||||||
|
const struct ChannelVtable *vt;
|
||||||
|
unsigned initial_fixed_window_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define chan_free(ch) ((ch)->vt->free(ch))
|
||||||
|
#define chan_open_confirmation(ch) ((ch)->vt->open_confirmation(ch))
|
||||||
|
#define chan_open_failed(ch, err) ((ch)->vt->open_failed(ch, err))
|
||||||
|
#define chan_send(ch, err, buf, len) ((ch)->vt->send(ch, err, buf, len))
|
||||||
|
#define chan_send_eof(ch) ((ch)->vt->send_eof(ch))
|
||||||
|
#define chan_set_input_wanted(ch, wanted) \
|
||||||
|
((ch)->vt->set_input_wanted(ch, wanted))
|
||||||
|
#define chan_log_close_msg(ch) ((ch)->vt->send_eof(ch))
|
||||||
|
#define chan_want_close(ch, leof, reof) ((ch)->vt->want_close(ch, leof, reof))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reusable methods you can put in vtables to give default handling of
|
||||||
|
* some of those functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* open_confirmation / open_failed for any channel it doesn't apply to */
|
||||||
|
void chan_remotely_opened_confirmation(Channel *chan);
|
||||||
|
void chan_remotely_opened_failure(Channel *chan, const char *errtext);
|
||||||
|
|
||||||
|
/* want_close for any channel that wants the default behaviour of not
|
||||||
|
* closing until both directions have had an EOF */
|
||||||
|
int chan_no_eager_close(Channel *, int, int);
|
||||||
|
|
||||||
|
#endif /* PUTTY_SSHCHAN_H */
|
|
@ -161,13 +161,17 @@ int sshfwd_write(struct ssh_channel *c, const void *data, int len)
|
||||||
void sshfwd_write_eof(struct ssh_channel *c) { }
|
void sshfwd_write_eof(struct ssh_channel *c) { }
|
||||||
void sshfwd_unclean_close(struct ssh_channel *c, const char *err) { }
|
void sshfwd_unclean_close(struct ssh_channel *c, const char *err) { }
|
||||||
void sshfwd_unthrottle(struct ssh_channel *c, int bufsize) {}
|
void sshfwd_unthrottle(struct ssh_channel *c, int bufsize) {}
|
||||||
|
void sshfwd_window_override_removed(struct ssh_channel *c) { }
|
||||||
|
void chan_remotely_opened_confirmation(Channel *chan) { }
|
||||||
|
void chan_remotely_opened_failure(Channel *chan, const char *err) { }
|
||||||
|
int chan_no_eager_close(Channel *chan, int s, int r) { return FALSE; }
|
||||||
|
|
||||||
Conf *sshfwd_get_conf(struct ssh_channel *c) { return NULL; }
|
Conf *sshfwd_get_conf(struct ssh_channel *c) { return NULL; }
|
||||||
void sshfwd_x11_sharing_handover(struct ssh_channel *c,
|
void sshfwd_x11_sharing_handover(struct ssh_channel *c,
|
||||||
void *share_cs, void *share_chan,
|
void *share_cs, void *share_chan,
|
||||||
const char *peer_addr, int peer_port,
|
const char *peer_addr, int peer_port,
|
||||||
int endian, int protomajor, int protominor,
|
int endian, int protomajor, int protominor,
|
||||||
const void *initial_data, int initial_len) {}
|
const void *initial_data, int initial_len) {}
|
||||||
void sshfwd_x11_is_local(struct ssh_channel *c) {}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These functions are part of the plug for our connection to the X
|
* These functions are part of the plug for our connection to the X
|
||||||
|
|
93
x11fwd.c
93
x11fwd.c
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
#include "sshchan.h"
|
||||||
#include "tree234.h"
|
#include "tree234.h"
|
||||||
|
|
||||||
#define GET_16BIT(endian, cp) \
|
#define GET_16BIT(endian, cp) \
|
||||||
|
@ -26,7 +27,7 @@ struct XDMSeen {
|
||||||
unsigned char clientid[6];
|
unsigned char clientid[6];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct X11Connection {
|
typedef struct X11Connection {
|
||||||
unsigned char firstpkt[12]; /* first X data packet */
|
unsigned char firstpkt[12]; /* first X data packet */
|
||||||
tree234 *authtree;
|
tree234 *authtree;
|
||||||
struct X11Display *disp;
|
struct X11Display *disp;
|
||||||
|
@ -34,7 +35,7 @@ struct X11Connection {
|
||||||
unsigned char *auth_data;
|
unsigned char *auth_data;
|
||||||
int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize;
|
int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize;
|
||||||
int verified;
|
int verified;
|
||||||
int throttled, throttle_override;
|
int input_wanted;
|
||||||
int no_data_sent_to_x_client;
|
int no_data_sent_to_x_client;
|
||||||
char *peer_addr;
|
char *peer_addr;
|
||||||
int peer_port;
|
int peer_port;
|
||||||
|
@ -42,7 +43,8 @@ struct X11Connection {
|
||||||
Socket s;
|
Socket s;
|
||||||
|
|
||||||
const Plug_vtable *plugvt;
|
const Plug_vtable *plugvt;
|
||||||
};
|
Channel chan;
|
||||||
|
} X11Connection;
|
||||||
|
|
||||||
static int xdmseen_cmp(void *a, void *b)
|
static int xdmseen_cmp(void *a, void *b)
|
||||||
{
|
{
|
||||||
|
@ -666,11 +668,8 @@ static void x11_receive(Plug plug, int urgent, char *data, int len)
|
||||||
struct X11Connection *xconn = FROMFIELD(
|
struct X11Connection *xconn = FROMFIELD(
|
||||||
plug, struct X11Connection, plugvt);
|
plug, struct X11Connection, plugvt);
|
||||||
|
|
||||||
if (sshfwd_write(xconn->c, data, len) > 0) {
|
xconn->no_data_sent_to_x_client = FALSE;
|
||||||
xconn->throttled = 1;
|
sshfwd_write(xconn->c, data, len);
|
||||||
xconn->no_data_sent_to_x_client = FALSE;
|
|
||||||
sk_set_frozen(xconn->s, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11_sent(Plug plug, int bufsize)
|
static void x11_sent(Plug plug, int bufsize)
|
||||||
|
@ -707,12 +706,30 @@ static const Plug_vtable X11Connection_plugvt = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void x11_chan_free(Channel *chan);
|
||||||
|
static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len);
|
||||||
|
static void x11_send_eof(Channel *chan);
|
||||||
|
static void x11_set_input_wanted(Channel *chan, int wanted);
|
||||||
|
static char *x11_log_close_msg(Channel *chan);
|
||||||
|
|
||||||
|
static const struct ChannelVtable X11Connection_channelvt = {
|
||||||
|
x11_chan_free,
|
||||||
|
chan_remotely_opened_confirmation,
|
||||||
|
chan_remotely_opened_failure,
|
||||||
|
x11_send,
|
||||||
|
x11_send_eof,
|
||||||
|
x11_set_input_wanted,
|
||||||
|
x11_log_close_msg,
|
||||||
|
chan_no_eager_close,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to set up the X11Connection structure, though this does not
|
* Called to set up the X11Connection structure, though this does not
|
||||||
* yet connect to an actual server.
|
* yet connect to an actual server.
|
||||||
*/
|
*/
|
||||||
struct X11Connection *x11_init(tree234 *authtree, void *c,
|
Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c,
|
||||||
const char *peeraddr, int peerport)
|
const char *peeraddr, int peerport,
|
||||||
|
int connection_sharing_possible)
|
||||||
{
|
{
|
||||||
struct X11Connection *xconn;
|
struct X11Connection *xconn;
|
||||||
|
|
||||||
|
@ -721,11 +738,14 @@ struct X11Connection *x11_init(tree234 *authtree, void *c,
|
||||||
*/
|
*/
|
||||||
xconn = snew(struct X11Connection);
|
xconn = snew(struct X11Connection);
|
||||||
xconn->plugvt = &X11Connection_plugvt;
|
xconn->plugvt = &X11Connection_plugvt;
|
||||||
|
xconn->chan.vt = &X11Connection_channelvt;
|
||||||
|
xconn->chan.initial_fixed_window_size =
|
||||||
|
(connection_sharing_possible ? 128 : 0);
|
||||||
xconn->auth_protocol = NULL;
|
xconn->auth_protocol = NULL;
|
||||||
xconn->authtree = authtree;
|
xconn->authtree = authtree;
|
||||||
xconn->verified = 0;
|
xconn->verified = 0;
|
||||||
xconn->data_read = 0;
|
xconn->data_read = 0;
|
||||||
xconn->throttled = xconn->throttle_override = 0;
|
xconn->input_wanted = TRUE;
|
||||||
xconn->no_data_sent_to_x_client = TRUE;
|
xconn->no_data_sent_to_x_client = TRUE;
|
||||||
xconn->c = c;
|
xconn->c = c;
|
||||||
|
|
||||||
|
@ -746,13 +766,13 @@ struct X11Connection *x11_init(tree234 *authtree, void *c,
|
||||||
xconn->peer_addr = peeraddr ? dupstr(peeraddr) : NULL;
|
xconn->peer_addr = peeraddr ? dupstr(peeraddr) : NULL;
|
||||||
xconn->peer_port = peerport;
|
xconn->peer_port = peerport;
|
||||||
|
|
||||||
return xconn;
|
return &xconn->chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
void x11_close(struct X11Connection *xconn)
|
static void x11_chan_free(Channel *chan)
|
||||||
{
|
{
|
||||||
if (!xconn)
|
assert(chan->vt == &X11Connection_channelvt);
|
||||||
return;
|
X11Connection *xconn = FROMFIELD(chan, X11Connection, chan);
|
||||||
|
|
||||||
if (xconn->auth_protocol) {
|
if (xconn->auth_protocol) {
|
||||||
sfree(xconn->auth_protocol);
|
sfree(xconn->auth_protocol);
|
||||||
|
@ -766,24 +786,14 @@ void x11_close(struct X11Connection *xconn)
|
||||||
sfree(xconn);
|
sfree(xconn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void x11_unthrottle(struct X11Connection *xconn)
|
static void x11_set_input_wanted(Channel *chan, int wanted)
|
||||||
{
|
{
|
||||||
if (!xconn)
|
assert(chan->vt == &X11Connection_channelvt);
|
||||||
return;
|
X11Connection *xconn = FROMFIELD(chan, X11Connection, chan);
|
||||||
|
|
||||||
xconn->throttled = 0;
|
xconn->input_wanted = wanted;
|
||||||
if (xconn->s)
|
if (xconn->s)
|
||||||
sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
|
sk_set_frozen(xconn->s, !xconn->input_wanted);
|
||||||
}
|
|
||||||
|
|
||||||
void x11_override_throttle(struct X11Connection *xconn, int enable)
|
|
||||||
{
|
|
||||||
if (!xconn)
|
|
||||||
return;
|
|
||||||
|
|
||||||
xconn->throttle_override = enable;
|
|
||||||
if (xconn->s)
|
|
||||||
sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11_send_init_error(struct X11Connection *xconn,
|
static void x11_send_init_error(struct X11Connection *xconn,
|
||||||
|
@ -831,13 +841,12 @@ static int x11_parse_ip(const char *addr_string, unsigned long *ip)
|
||||||
/*
|
/*
|
||||||
* Called to send data down the raw connection.
|
* Called to send data down the raw connection.
|
||||||
*/
|
*/
|
||||||
int x11_send(struct X11Connection *xconn, const void *vdata, int len)
|
static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len)
|
||||||
{
|
{
|
||||||
|
assert(chan->vt == &X11Connection_channelvt);
|
||||||
|
X11Connection *xconn = FROMFIELD(chan, X11Connection, chan);
|
||||||
const char *data = (const char *)vdata;
|
const char *data = (const char *)vdata;
|
||||||
|
|
||||||
if (!xconn)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the first packet.
|
* Read the first packet.
|
||||||
*/
|
*/
|
||||||
|
@ -914,7 +923,8 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len)
|
||||||
/*
|
/*
|
||||||
* If this auth points to a connection-sharing downstream
|
* If this auth points to a connection-sharing downstream
|
||||||
* rather than an X display we know how to connect to
|
* rather than an X display we know how to connect to
|
||||||
* directly, pass it off to the sharing module now.
|
* directly, pass it off to the sharing module now. (This will
|
||||||
|
* have the side effect of freeing xconn.)
|
||||||
*/
|
*/
|
||||||
if (auth_matched->share_cs) {
|
if (auth_matched->share_cs) {
|
||||||
sshfwd_x11_sharing_handover(xconn->c, auth_matched->share_cs,
|
sshfwd_x11_sharing_handover(xconn->c, auth_matched->share_cs,
|
||||||
|
@ -929,7 +939,8 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len)
|
||||||
* Now we know we're going to accept the connection, and what
|
* Now we know we're going to accept the connection, and what
|
||||||
* X display to connect to. Actually connect to it.
|
* X display to connect to. Actually connect to it.
|
||||||
*/
|
*/
|
||||||
sshfwd_x11_is_local(xconn->c);
|
xconn->chan.initial_fixed_window_size = 0;
|
||||||
|
sshfwd_window_override_removed(xconn->c);
|
||||||
xconn->disp = auth_matched->disp;
|
xconn->disp = auth_matched->disp;
|
||||||
xconn->s = new_connection(sk_addr_dup(xconn->disp->addr),
|
xconn->s = new_connection(sk_addr_dup(xconn->disp->addr),
|
||||||
xconn->disp->realhost, xconn->disp->port,
|
xconn->disp->realhost, xconn->disp->port,
|
||||||
|
@ -984,8 +995,11 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len)
|
||||||
return sk_write(xconn->s, data, len);
|
return sk_write(xconn->s, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void x11_send_eof(struct X11Connection *xconn)
|
static void x11_send_eof(Channel *chan)
|
||||||
{
|
{
|
||||||
|
assert(chan->vt == &X11Connection_channelvt);
|
||||||
|
X11Connection *xconn = FROMFIELD(chan, X11Connection, chan);
|
||||||
|
|
||||||
if (xconn->s) {
|
if (xconn->s) {
|
||||||
sk_write_eof(xconn->s);
|
sk_write_eof(xconn->s);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1000,6 +1014,11 @@ void x11_send_eof(struct X11Connection *xconn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *x11_log_close_msg(Channel *chan)
|
||||||
|
{
|
||||||
|
return dupstr("Forwarded X11 connection terminated");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Utility functions used by connection sharing to convert textual
|
* Utility functions used by connection sharing to convert textual
|
||||||
* representations of an X11 auth protocol name + hex cookie into our
|
* representations of an X11 auth protocol name + hex cookie into our
|
||||||
|
|
Загрузка…
Ссылка в новой задаче