SSH = ssh sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf
+ sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd
+ sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf
- + sshgssc pgssapi sshshare sshecc
+ + sshgssc pgssapi sshshare sshecc aqsync
WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc
+ winhsock errsock
UXSSH = SSH uxnoise uxagentc uxgss uxshare
+ psftp.res winnojmp LIBS
pageant : [G] winpgnt pageant sshrsa sshpubk sshdes sshbn sshmd5 version
- + tree234 misc sshaes sshsha winsecur winpgntc sshdss sshsh256
+ + tree234 misc sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
+ sshsh512 winutils sshecc winmisc winhelp conf pageant.res LIBS
puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC
psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC
-pageant : [X] uxpgnt uxagentc pageant sshrsa sshpubk sshdes sshbn sshmd5
- + version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512 sshecc
- + conf uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons gtkask
- + gtkmisc UXMISC
+pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes sshbn
+ + sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512
+ + sshecc conf uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons
+ + gtkask gtkmisc UXMISC
ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
+ uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg
--- /dev/null
+/*
+ * aqsync.c: the agent_query_synchronous() wrapper function.
+ *
+ * This is a very small thing to have to put in its own module, but it
+ * wants to be shared between back ends, and exist in any SSH client
+ * program and also Pageant, and _nowhere else_ (because it pulls in
+ * the main agent_query).
+ */
+
+#include <assert.h>
+
+#include "putty.h"
+
+void agent_query_synchronous(void *in, int inlen, void **out, int *outlen)
+{
+ agent_pending_query *pending;
+
+ pending = agent_query(in, inlen, out, outlen, NULL, 0);
+ assert(!pending);
+}
+
if (!pageant_local) {
unsigned char request[5], *response;
void *vresponse;
- int resplen, retval;
+ int resplen;
+
request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
PUT_32BIT(request, 1);
- retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
- assert(retval == 1);
+ agent_query_synchronous(request, 5, &vresponse, &resplen);
response = vresponse;
if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
sfree(response);
if (!pageant_local) {
unsigned char request[5], *response;
void *vresponse;
- int resplen, retval;
+ int resplen;
request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
PUT_32BIT(request, 1);
- retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
- assert(retval == 1);
+ agent_query_synchronous(request, 5, &vresponse, &resplen);
response = vresponse;
if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) {
sfree(response);
if (!pageant_local) {
unsigned char *request, *response;
void *vresponse;
- int reqlen, clen, resplen, ret;
+ int reqlen, clen, resplen;
clen = strlen(rkey->comment);
reqlen += 4 + clen;
PUT_32BIT(request, reqlen - 4);
- ret = agent_query(request, reqlen, &vresponse, &resplen,
- NULL, NULL);
- assert(ret == 1);
+ agent_query_synchronous(request, reqlen, &vresponse, &resplen);
response = vresponse;
if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
*retstr = dupstr("The already running Pageant "
if (!pageant_local) {
unsigned char *request, *response;
void *vresponse;
- int reqlen, alglen, clen, keybloblen, resplen, ret;
+ int reqlen, alglen, clen, keybloblen, resplen;
alglen = strlen(skey->alg->name);
clen = strlen(skey->comment);
reqlen += clen + 4;
PUT_32BIT(request, reqlen - 4);
- ret = agent_query(request, reqlen, &vresponse, &resplen,
- NULL, NULL);
- assert(ret == 1);
+ agent_query_synchronous(request, reqlen, &vresponse, &resplen);
response = vresponse;
if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
*retstr = dupstr("The already running Pageant "
memcpy(request + 9, key->blob, key->bloblen);
}
- ret = agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL);
- assert(ret == 1);
+ agent_query_synchronous(request, reqlen, &vresponse, &resplen);
response = vresponse;
if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
*retstr = dupstr("Agent failed to delete key");
int pageant_delete_all_keys(char **retstr)
{
unsigned char request[5], *response;
- int reqlen, resplen, success, ret;
+ int reqlen, resplen, success;
void *vresponse;
PUT_32BIT(request, 1);
request[4] = SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
reqlen = 5;
- ret = agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL);
- assert(ret == 1);
+ agent_query_synchronous(request, reqlen, &vresponse, &resplen);
response = vresponse;
success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
sfree(response);
PUT_32BIT(request, 1);
request[4] = SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
reqlen = 5;
- ret = agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL);
- assert(ret == 1);
+ agent_query_synchronous(request, reqlen, &vresponse, &resplen);
response = vresponse;
success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
sfree(response);
/*
* Exports from pageantc.c.
*
- * agent_query returns 1 for here's-a-response, and 0 for query-in-
- * progress. In the latter case there will be a call to `callback'
- * at some future point, passing callback_ctx as the first
+ * agent_query returns NULL for here's-a-response, and non-NULL for
+ * query-in- progress. In the latter case there will be a call to
+ * `callback' at some future point, passing callback_ctx as the first
* parameter and the actual reply data as the second and third.
*
* The response may be a NULL pointer (in either of the synchronous
* or asynchronous cases), which indicates failure to receive a
* response.
+ *
+ * When the return from agent_query is not NULL, it identifies the
+ * in-progress query in case it needs to be cancelled. If
+ * agent_cancel_query is called, then the pending query is destroyed
+ * and the callback will not be called. (E.g. if you're going to throw
+ * away the thing you were using as callback_ctx.)
+ *
+ * Passing a null pointer as callback forces agent_query to behave
+ * synchronously, i.e. it will block if necessary, and guarantee to
+ * return NULL. The wrapper function agent_query_synchronous() makes
+ * this easier.
*/
-int agent_query(void *in, int inlen, void **out, int *outlen,
- void (*callback)(void *, void *, int), void *callback_ctx);
+typedef struct agent_pending_query agent_pending_query;
+agent_pending_query *agent_query(
+ void *in, int inlen, void **out, int *outlen,
+ void (*callback)(void *, void *, int), void *callback_ctx);
+void agent_cancel_query(agent_pending_query *);
+void agent_query_synchronous(void *in, int inlen, void **out, int *outlen);
int agent_exists(void);
/*
unsigned char msglen[4];
unsigned lensofar, totallen;
int outstanding_requests;
+ agent_pending_query *pending;
} a;
struct ssh_x11_channel {
struct X11Connection *xconn;
* with a newly cross-certified host key.
*/
int cross_certifying;
+
+ /*
+ * Any asynchronous query to our SSH agent that we might have in
+ * flight from the main authentication loop. (Queries from
+ * agent-forwarding channels live in their channel structure.)
+ */
+ agent_pending_query *auth_agent_query;
};
static const char *ssh_pkt_type(Ssh ssh, int type)
{
Ssh ssh = (Ssh) sshv;
+ ssh->auth_agent_query = NULL;
+
ssh->agent_response = reply;
ssh->agent_response_len = replylen;
struct ssh_channel *c = (struct ssh_channel *)cv;
const void *sentreply = reply;
+ c->u.a.pending = NULL;
c->u.a.outstanding_requests--;
if (!sentreply) {
/* Fake SSH_AGENT_FAILURE. */
/* Request the keys held by the agent. */
PUT_32BIT(s->request, 1);
s->request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
- if (!agent_query(s->request, 5, &r, &s->responselen,
- ssh_agent_callback, ssh)) {
+ ssh->auth_agent_query = agent_query(
+ s->request, 5, &r, &s->responselen, ssh_agent_callback, ssh);
+ if (ssh->auth_agent_query) {
do {
crReturn(0);
if (pktin) {
memcpy(q, s->session_id, 16);
q += 16;
PUT_32BIT(q, 1); /* response format */
- if (!agent_query(agentreq, len + 4, &vret, &retlen,
- ssh_agent_callback, ssh)) {
+ ssh->auth_agent_query = agent_query(
+ agentreq, len + 4, &vret, &retlen,
+ ssh_agent_callback, ssh);
+ if (ssh->auth_agent_query) {
sfree(agentreq);
do {
crReturn(0);
c->type = CHAN_AGENT; /* identify channel type */
c->u.a.lensofar = 0;
c->u.a.message = NULL;
+ c->u.a.pending = NULL;
c->u.a.outstanding_requests = 0;
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
PKT_INT, c->remoteid, PKT_INT, c->localid,
void *reply;
int replylen;
c->u.a.outstanding_requests++;
- if (agent_query(c->u.a.message, c->u.a.totallen, &reply, &replylen,
- ssh_agentf_callback, c))
- ssh_agentf_callback(c, reply, replylen);
+ c->u.a.pending = agent_query(
+ c->u.a.message, c->u.a.totallen, &reply, &replylen,
+ ssh_agentf_callback, c);
+ if (!c->u.a.pending)
+ ssh_agentf_callback(c, reply, replylen);
sfree(c->u.a.message);
c->u.a.message = NULL;
c->u.a.lensofar = 0;
msg = "Forwarded X11 connection terminated";
break;
case CHAN_AGENT:
+ if (c->u.a.pending)
+ agent_cancel_query(c->u.a.pending);
sfree(c->u.a.message);
break;
case CHAN_SOCKDATA:
c->type = CHAN_AGENT; /* identify channel type */
c->u.a.lensofar = 0;
c->u.a.message = NULL;
+ c->u.a.pending = NULL;
c->u.a.outstanding_requests = 0;
}
} else {
/* Request the keys held by the agent. */
PUT_32BIT(s->agent_request, 1);
s->agent_request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
- if (!agent_query(s->agent_request, 5, &r, &s->agent_responselen,
- ssh_agent_callback, ssh)) {
+ ssh->auth_agent_query = agent_query(
+ s->agent_request, 5, &r, &s->agent_responselen,
+ ssh_agent_callback, ssh);
+ if (ssh->auth_agent_query) {
do {
crReturnV;
if (pktin) {
s->q += s->pktout->length - 5;
/* And finally the (zero) flags word. */
PUT_32BIT(s->q, 0);
- if (!agent_query(s->agentreq, s->len + 4,
- &vret, &s->retlen,
- ssh_agent_callback, ssh)) {
+ ssh->auth_agent_query = agent_query(
+ s->agentreq, s->len + 4, &vret, &s->retlen,
+ ssh_agent_callback, ssh);
+ if (ssh->auth_agent_query) {
do {
crReturnV;
if (pktin) {
CONF_ssh_rekey_data));
ssh->kex_in_progress = FALSE;
+ ssh->auth_agent_query = NULL;
+
#ifndef NO_GSSAPI
ssh->gsslibs = NULL;
#endif
bufchain_clear(&ssh->queued_incoming_data);
sfree(ssh->username);
conf_free(ssh->conf);
+
+ if (ssh->auth_agent_query)
+ agent_cancel_query(ssh->auth_agent_query);
+
#ifndef NO_GSSAPI
if (ssh->gsslibs)
ssh_gss_cleanup(ssh->gsslibs);
return FALSE;
}
-static tree234 *agent_connections;
-struct agent_connection {
+static tree234 *agent_pending_queries;
+struct agent_pending_query {
int fd;
char *retbuf;
char sizebuf[4];
};
static int agent_conncmp(void *av, void *bv)
{
- struct agent_connection *a = (struct agent_connection *) av;
- struct agent_connection *b = (struct agent_connection *) bv;
+ agent_pending_query *a = (agent_pending_query *) av;
+ agent_pending_query *b = (agent_pending_query *) bv;
if (a->fd < b->fd)
return -1;
if (a->fd > b->fd)
static int agent_connfind(void *av, void *bv)
{
int afd = *(int *) av;
- struct agent_connection *b = (struct agent_connection *) bv;
+ agent_pending_query *b = (agent_pending_query *) bv;
if (afd < b->fd)
return -1;
if (afd > b->fd)
* (conn->retbuf non-NULL and filled with something useful) or has
* failed totally (conn->retbuf is NULL).
*/
-static int agent_try_read(struct agent_connection *conn)
+static int agent_try_read(agent_pending_query *conn)
{
int ret;
return 1;
}
+void agent_cancel_query(agent_pending_query *conn)
+{
+ uxsel_del(conn->fd);
+ close(conn->fd);
+ del234(agent_pending_queries, conn);
+ sfree(conn);
+}
+
static int agent_select_result(int fd, int event)
{
- struct agent_connection *conn;
+ agent_pending_query *conn;
assert(event == 1); /* not selecting for anything but R */
- conn = find234(agent_connections, &fd, agent_connfind);
+ conn = find234(agent_pending_queries, &fd, agent_connfind);
if (!conn) {
uxsel_del(fd);
return 1;
* of that passes to the callback.)
*/
conn->callback(conn->callback_ctx, conn->retbuf, conn->retlen);
- uxsel_del(fd);
- close(fd);
- del234(agent_connections, conn);
- sfree(conn);
+ agent_cancel_query(conn);
return 0;
}
-int agent_query(void *in, int inlen, void **out, int *outlen,
- void (*callback)(void *, void *, int), void *callback_ctx)
+agent_pending_query *agent_query(
+ void *in, int inlen, void **out, int *outlen,
+ void (*callback)(void *, void *, int), void *callback_ctx)
{
char *name;
int sock;
struct sockaddr_un addr;
int done;
- struct agent_connection *conn;
+ agent_pending_query *conn;
name = getenv("SSH_AUTH_SOCK");
if (!name)
done += ret;
}
- conn = snew(struct agent_connection);
+ conn = snew(agent_pending_query);
conn->fd = sock;
conn->retbuf = conn->sizebuf;
conn->retsize = 4;
*out = conn->retbuf;
*outlen = conn->retlen;
sfree(conn);
- return 1;
+ return NULL;
}
/*
* response hasn't been received yet, and call the callback when
* select_result comes back to us.
*/
- if (!agent_connections)
- agent_connections = newtree234(agent_conncmp);
- add234(agent_connections, conn);
+ if (!agent_pending_queries)
+ agent_pending_queries = newtree234(agent_conncmp);
+ add234(agent_pending_queries, conn);
uxsel_set(sock, 1, agent_select_result);
- return 0;
+ return conn;
failure:
*out = NULL;
*outlen = 0;
- return 1;
+ return NULL;
}
return TRUE;
}
-int agent_query(void *in, int inlen, void **out, int *outlen,
- void (*callback)(void *, void *, int), void *callback_ctx)
+void agent_cancel_query(agent_pending_query *q)
+{
+ assert(0 && "Windows agent queries are never asynchronous!");
+}
+
+agent_pending_query *agent_query(
+ void *in, int inlen, void **out, int *outlen,
+ void (*callback)(void *, void *, int), void *callback_ctx)
{
HWND hwnd;
char *mapname;
hwnd = FindWindow("Pageant", "Pageant");
if (!hwnd)
- return 1; /* *out == NULL, so failure */
+ return NULL; /* *out == NULL, so failure */
mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
psa = NULL;
0, AGENT_MAX_MSGLEN, mapname);
if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
sfree(mapname);
- return 1; /* *out == NULL, so failure */
+ return NULL; /* *out == NULL, so failure */
}
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
memcpy(p, in, inlen);
sfree(mapname);
if (psd)
LocalFree(psd);
- return 1;
+ return NULL;
}