diff --git a/putty.h b/putty.h index 8f9643e5..344a559c 100644 --- a/putty.h +++ b/putty.h @@ -1901,6 +1901,16 @@ 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); + /* * Exports from wildcard.c */ diff --git a/ssh1connection-client.c b/ssh1connection-client.c index 850a94fe..f209056e 100644 --- a/ssh1connection-client.c +++ b/ssh1connection-client.c @@ -161,9 +161,32 @@ bool ssh1_handle_direction_specific_packet( c->connlayer = s; ssh1_channel_init(c); c->remoteid = remid; - c->chan = agentf_new(&c->sc); c->halfopen = false; + /* + * 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(); + 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) { + /* + * 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(). + */ + c->chan = agentf_new(&c->sc); + } + pktout = ssh_bpp_new_pktout( s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); put_uint32(pktout, c->remoteid); diff --git a/ssh2connection-client.c b/ssh2connection-client.c index d9e909d2..96302bf6 100644 --- a/ssh2connection-client.c +++ b/ssh2connection-client.c @@ -95,6 +95,30 @@ static ChanopenResult chan_open_auth_agent( ("Agent forwarding is not enabled")); } + /* + * 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 */ + } + } + + /* + * 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)); } diff --git a/unix/uxagentc.c b/unix/uxagentc.c index 30c2244d..b937e7e4 100644 --- a/unix/uxagentc.c +++ b/unix/uxagentc.c @@ -125,17 +125,48 @@ static void agent_select_result(int fd, int event) agent_cancel_query(conn); } +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(ctx->addr, 0, false, false, false, false, plug); +} + +agent_connect_ctx *agent_get_connect_ctx(void) +{ + 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); +} + agent_pending_query *agent_query( strbuf *query, void **out, int *outlen, void (*callback)(void *, void *, int), void *callback_ctx) { - char *name; + const char *name; int sock; struct sockaddr_un addr; int done; agent_pending_query *conn; - name = getenv("SSH_AUTH_SOCK"); + name = agent_socket_path(); if (!name || strlen(name) >= sizeof(addr.sun_path)) goto failure; diff --git a/windows/winpgntc.c b/windows/winpgntc.c index 7166585b..fb7f02e6 100644 --- a/windows/winpgntc.c +++ b/windows/winpgntc.c @@ -135,3 +135,17 @@ agent_pending_query *agent_query( LocalFree(psd); return NULL; } + +Socket *agent_connect(void *vctx, Plug *plug) +{ + unreachable("no agent_connect_ctx can be constructed on this platform"); +} + +agent_connect_ctx *agent_get_connect_ctx(void) +{ + return NULL; +} + +void agent_free_connect_ctx(agent_connect_ctx *ctx) +{ +}