Skip to content
This repository has been archived by the owner on Oct 20, 2023. It is now read-only.

Commit

Permalink
Merge the two low-level portfwd setup systems.
Browse files Browse the repository at this point in the history
In commit 09954a8 I introduced the portfwdmgr_connect_socket()
system, which opened a port forwarding given a callback to create the
Socket itself, with the aim of using it to make forwardings to Unix-
domain sockets and Windows named pipes (both initially for agent
forwarding).

But I forgot that a year and a bit ago, in commit 8343961, I already
introduced a similar low-level system for creating a PortForwarding
around an unusual kind of socket: the portfwd_raw_new() system, which
in place of a callback uses a two-phase setup protocol (you create the
socket in between the two setup calls, and can roll it back if the
socket can't be created).

There's really no need to have _both_ these systems! So now I'm
merging them, which is to say, I'm enhancing portfwd_raw_new to have
the one new feature it needs, and throwing away the newer system
completely. The new feature is to be able to control the initial state
of the 'ready' flag: portfwd_raw_new was always used for initiating
port forwardings in response to an incoming local connection, which
means you need to start off with ready=false and set it true when the
other end of the SSH connection sends back OPEN_CONFIRMATION. Now it's
being used for initiating port forwardings in response to a
CHANNEL_OPEN, we need to be able to start with ready=true.

This commit reverts 09954a8 and its
followup fix 12aa06c, and simplifies
the agent_connect system down to a single trivial function that makes
a Socket given a Plug.
  • Loading branch information
sgtatham committed Jan 27, 2020
1 parent 600bf24 commit 2160205
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 131 deletions.
65 changes: 20 additions & 45 deletions portfwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ static const struct ChannelVtable PortForwarding_channelvt = {
chan_no_request_response,
};

Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug)
Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug, bool start_ready)
{
struct PortForwarding *pf;

Expand All @@ -482,7 +482,7 @@ Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug)

pf->cl = cl;
pf->input_wanted = true;
pf->ready = false;
pf->ready = start_ready;

pf->socks_state = SOCKS_NONE;
pf->hostname = NULL;
Expand Down Expand Up @@ -523,7 +523,7 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
Socket *s;
const char *err;

chan = portfwd_raw_new(pl->cl, &plug);
chan = portfwd_raw_new(pl->cl, &plug, false);
s = constructor(ctx, plug);
if ((err = sk_socket_error(s)) != NULL) {
portfwd_raw_free(chan);
Expand Down Expand Up @@ -1120,20 +1120,6 @@ bool portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port)
return true;
}

struct portfwdmgr_connect_ctx {
SockAddr *addr;
int port;
char *canonical_hostname;
Conf *conf;
};
static Socket *portfwdmgr_connect_helper(void *vctx, Plug *plug)
{
struct portfwdmgr_connect_ctx *ctx = (struct portfwdmgr_connect_ctx *)vctx;
return new_connection(sk_addr_dup(ctx->addr), ctx->canonical_hostname,
ctx->port, false, true, false, false, plug,
ctx->conf);
}

/*
* Called when receiving a PORT OPEN from the server to make a
* connection to a destination host.
Expand All @@ -1145,39 +1131,26 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret,
char *hostname, int port, SshChannel *c,
int addressfamily)
{
struct portfwdmgr_connect_ctx ctx[1];
const char *err_retd;
char *err_toret;
SockAddr *addr;
const char *err;
char *dummy_realhost = NULL;
struct PortForwarding *pf;

/*
* Try to find host.
*/
ctx->addr = name_lookup(hostname, port, &ctx->canonical_hostname,
mgr->conf, addressfamily, NULL, NULL);
if ((err_retd = sk_addr_error(ctx->addr)) != NULL) {
err_toret = dupstr(err_retd);
goto out;
addr = name_lookup(hostname, port, &dummy_realhost, mgr->conf,
addressfamily, NULL, NULL);
if ((err = sk_addr_error(addr)) != NULL) {
char *err_ret = dupstr(err);
sk_addr_free(addr);
sfree(dummy_realhost);
return err_ret;
}

ctx->conf = mgr->conf;
ctx->port = port;

err_toret = portfwdmgr_connect_socket(
mgr, chan_ret, portfwdmgr_connect_helper, ctx, c);

out:
sk_addr_free(ctx->addr);
sfree(ctx->canonical_hostname);
return err_toret;
}

char *portfwdmgr_connect_socket(PortFwdManager *mgr, Channel **chan_ret,
Socket *(*connect)(void *, Plug *), void *ctx,
SshChannel *c)
{
struct PortForwarding *pf;
const char *err;

/*
* Open socket.
*/
pf = new_portfwd_state();
*chan_ret = &pf->chan;
pf->plug.vt = &PortForwarding_plugvt;
Expand All @@ -1189,7 +1162,9 @@ char *portfwdmgr_connect_socket(PortFwdManager *mgr, Channel **chan_ret,
pf->cl = mgr->cl;
pf->socks_state = SOCKS_NONE;

pf->s = connect(ctx, &pf->plug);
pf->s = new_connection(addr, dummy_realhost, port,
false, true, false, false, &pf->plug, mgr->conf);
sfree(dummy_realhost);
if ((err = sk_socket_error(pf->s)) != NULL) {
char *err_ret = dupstr(err);
sk_close(pf->s);
Expand Down
11 changes: 2 additions & 9 deletions putty.h
Original file line number Diff line number Diff line change
Expand Up @@ -1889,15 +1889,8 @@ void agent_cancel_query(agent_pending_query *);
void agent_query_synchronous(strbuf *in, void **out, int *outlen);
bool agent_exists(void);

/* For stream-oriented agent connections, if available: agent_connect
* is a callback for use with portfwdmgr_connect_socket, and the
* context structure it requires is created and freed by the next two
* functions. agent_get_connect_ctx may return NULL if no streaming
* agent connection is available at all on this platform. */
typedef struct agent_connect_ctx agent_connect_ctx;
Socket *agent_connect(void *vctx, Plug *plug);
agent_connect_ctx *agent_get_connect_ctx(void);
void agent_free_connect_ctx(agent_connect_ctx *ctx);
/* For stream-oriented agent connections, if available. */
Socket *agent_connect(Plug *plug);

/*
* Exports from wildcard.c
Expand Down
4 changes: 2 additions & 2 deletions sesschan.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
SocketPeerInfo *pi;
const char *err;

chan = portfwd_raw_new(sess->c->cl, &plug);
chan = portfwd_raw_new(sess->c->cl, &plug, false);
s = constructor(ctx, plug);
if ((err = sk_socket_error(s)) != NULL) {
portfwd_raw_free(chan);
Expand Down Expand Up @@ -441,7 +441,7 @@ static int agentfwd_accepting(
Socket *s;
const char *err;

chan = portfwd_raw_new(sess->c->cl, &plug);
chan = portfwd_raw_new(sess->c->cl, &plug, false);
s = constructor(ctx, plug);
if ((err = sk_socket_error(s)) != NULL) {
portfwd_raw_free(chan);
Expand Down
5 changes: 1 addition & 4 deletions ssh.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,13 +380,10 @@ void portfwdmgr_close_all(PortFwdManager *mgr);
char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret,
char *hostname, int port, SshChannel *c,
int addressfamily);
char *portfwdmgr_connect_socket(PortFwdManager *mgr, Channel **chan_ret,
Socket *(*connect)(void *, Plug *), void *ctx,
SshChannel *c);
bool portfwdmgr_listen(PortFwdManager *mgr, const char *host, int port,
const char *keyhost, int keyport, Conf *conf);
bool portfwdmgr_unlisten(PortFwdManager *mgr, const char *host, int port);
Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug);
Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug, bool start_ready);
void portfwd_raw_free(Channel *pfchan);
void portfwd_raw_setup(Channel *pfchan, Socket *s, SshChannel *sc);

Expand Down
19 changes: 9 additions & 10 deletions ssh1connection-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,15 @@ bool ssh1_handle_direction_specific_packet(
* agent and set up an ordinary port-forwarding type
* channel over it.
*/
agent_connect_ctx *ctx = agent_get_connect_ctx();
bool got_stream_connection = false;
if (ctx) {
char *err = portfwdmgr_connect_socket(
s->portfwdmgr, &c->chan, agent_connect, ctx, &c->sc);
agent_free_connect_ctx(ctx);
if (err == NULL)
got_stream_connection = true;
}
if (!got_stream_connection) {
Plug *plug;
Channel *ch = portfwd_raw_new(&s->cl, &plug, true);
Socket *skt = agent_connect(plug);
if (!sk_socket_error(skt)) {
portfwd_raw_setup(ch, skt, &c->sc);
c->chan = ch;
} else {
portfwd_raw_free(ch);

/*
* Otherwise, fall back to the old-fashioned system of
* parsing the forwarded data stream ourselves for
Expand Down
35 changes: 15 additions & 20 deletions ssh2connection-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,27 +99,22 @@ static ChanopenResult chan_open_auth_agent(
* If possible, make a stream-oriented connection to the agent and
* set up an ordinary port-forwarding type channel over it.
*/
agent_connect_ctx *ctx = agent_get_connect_ctx();
if (ctx) {
Channel *ch;
char *err = portfwdmgr_connect_socket(
s->portfwdmgr, &ch, agent_connect, ctx, sc);
agent_free_connect_ctx(ctx);

if (err == NULL) {
CHANOPEN_RETURN_SUCCESS(ch);
} else {
sfree(err);
/* now continue to the fallback case below */
}
}
Plug *plug;
Channel *ch = portfwd_raw_new(&s->cl, &plug, true);
Socket *skt = agent_connect(plug);

/*
* Otherwise, fall back to the old-fashioned system of parsing the
* forwarded data stream ourselves for message boundaries, and
* passing each individual message to the one-off agent_query().
*/
CHANOPEN_RETURN_SUCCESS(agentf_new(sc));
if (!sk_socket_error(skt)) {
portfwd_raw_setup(ch, skt, sc);
CHANOPEN_RETURN_SUCCESS(ch);
} else {
portfwd_raw_free(ch);
/*
* Otherwise, fall back to the old-fashioned system of parsing the
* forwarded data stream ourselves for message boundaries, and
* passing each individual message to the one-off agent_query().
*/
CHANOPEN_RETURN_SUCCESS(agentf_new(sc));
}
}

ChanopenResult ssh2_connection_parse_channel_open(
Expand Down
24 changes: 3 additions & 21 deletions unix/uxagentc.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,30 +130,12 @@ static const char *agent_socket_path(void)
return getenv("SSH_AUTH_SOCK");
}

struct agent_connect_ctx {
SockAddr *addr;
};

Socket *agent_connect(void *vctx, Plug *plug)
{
agent_connect_ctx *ctx = (agent_connect_ctx *)vctx;
return sk_new(sk_addr_dup(ctx->addr), 0, false, false, false, false, plug);
}

agent_connect_ctx *agent_get_connect_ctx(void)
Socket *agent_connect(Plug *plug)
{
const char *path = agent_socket_path();
if (!path)
return NULL;
agent_connect_ctx *ctx = snew(agent_connect_ctx);
ctx->addr = unix_sock_addr(path);
return ctx;
}

void agent_free_connect_ctx(agent_connect_ctx *ctx)
{
sk_addr_free(ctx->addr);
sfree(ctx);
return new_error_socket_fmt(plug, "SSH_AUTH_SOCK not set");
return sk_new(unix_sock_addr(path), 0, false, false, false, false, plug);
}

agent_pending_query *agent_query(
Expand Down
25 changes: 5 additions & 20 deletions windows/winpgntc.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,27 +142,12 @@ char *agent_named_pipe_name(void)
return pipename;
}

struct agent_connect_ctx {
char *pipename;
};

Socket *agent_connect(void *vctx, Plug *plug)
{
agent_connect_ctx *ctx = (agent_connect_ctx *)vctx;
return new_named_pipe_client(ctx->pipename, plug);
}

agent_connect_ctx *agent_get_connect_ctx(void)
Socket *agent_connect(Plug *plug)
{
agent_connect_ctx *ctx = snew(agent_connect_ctx);
ctx->pipename = agent_named_pipe_name();
return ctx;
}

void agent_free_connect_ctx(agent_connect_ctx *ctx)
{
sfree(ctx->pipename);
sfree(ctx);
char *pipename = agent_named_pipe_name();
Socket *s = new_named_pipe_client(pipename, plug);
sfree(pipename);
return s;
}

static bool named_pipe_agent_exists(void)
Expand Down

0 comments on commit 2160205

Please sign in to comment.