+ static unsigned char request[5], *response, *p;
+ static int responselen;
+ static int i, nkeys;
+ static int authed = FALSE;
+ void *r;
+
+ tried_agent = TRUE;
+
+ logevent("Pageant is running. Requesting keys.");
+
+ /* Request the keys held by the agent. */
+ PUT_32BIT(request, 1);
+ request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
+ agent_query(request, 5, &r, &responselen);
+ response = (unsigned char *)r;
+ if (response && responselen >= 5 &&
+ response[4] == SSH2_AGENT_IDENTITIES_ANSWER) {
+ p = response + 5;
+ nkeys = GET_32BIT(p); p += 4;
+ { char buf[64]; sprintf(buf, "Pageant has %d SSH2 keys", nkeys);
+ logevent(buf); }
+ for (i = 0; i < nkeys; i++) {
+ static char *pkblob, *alg, *commentp;
+ static int pklen, alglen, commentlen;
+ static int siglen, retlen, len;
+ static char *q, *agentreq, *ret;
+
+ { char buf[64]; sprintf(buf, "Trying Pageant key #%d", i);
+ logevent(buf); }
+ pklen = GET_32BIT(p); p += 4;
+ pkblob = p; p += pklen;
+ alglen = GET_32BIT(pkblob);
+ alg = pkblob + 4;
+ commentlen = GET_32BIT(p); p += 4;
+ commentp = p; p += commentlen;
+ ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
+ ssh2_pkt_addstring(username);
+ ssh2_pkt_addstring("ssh-connection");/* service requested */
+ ssh2_pkt_addstring("publickey");/* method */
+ ssh2_pkt_addbool(FALSE); /* no signature included */
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_addstring_data(alg, alglen);
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_addstring_data(pkblob, pklen);
+ ssh2_pkt_send();
+
+ crWaitUntilV(ispkt);
+ if (pktin.type != SSH2_MSG_USERAUTH_PK_OK) {
+ logevent("Key refused");
+ continue;
+ }
+
+ if (flags & FLAG_VERBOSE) {
+ c_write_str("Authenticating with public key \"");
+ c_write(commentp, commentlen);
+ c_write_str("\" from agent\r\n");
+ }
+
+ /*
+ * Server is willing to accept the key.
+ * Construct a SIGN_REQUEST.
+ */
+ ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
+ ssh2_pkt_addstring(username);
+ ssh2_pkt_addstring("ssh-connection"); /* service requested */
+ ssh2_pkt_addstring("publickey"); /* method */
+ ssh2_pkt_addbool(TRUE);
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_addstring_data(alg, alglen);
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_addstring_data(pkblob, pklen);
+
+ siglen = pktout.length - 5 + 4 + 20;
+ len = 1; /* message type */
+ len += 4 + pklen; /* key blob */
+ len += 4 + siglen; /* data to sign */
+ len += 4; /* flags */
+ agentreq = smalloc(4 + len);
+ PUT_32BIT(agentreq, len);
+ q = agentreq + 4;
+ *q++ = SSH2_AGENTC_SIGN_REQUEST;
+ PUT_32BIT(q, pklen); q += 4;
+ memcpy(q, pkblob, pklen); q += pklen;
+ PUT_32BIT(q, siglen); q += 4;
+ /* Now the data to be signed... */
+ PUT_32BIT(q, 20); q += 4;
+ memcpy(q, ssh2_session_id, 20); q += 20;
+ memcpy(q, pktout.data+5, pktout.length-5);
+ q += pktout.length-5;
+ /* And finally the (zero) flags word. */
+ PUT_32BIT(q, 0);
+ agent_query(agentreq, len+4, &ret, &retlen);
+ sfree(agentreq);
+ if (ret) {
+ if (ret[4] == SSH2_AGENT_SIGN_RESPONSE) {
+ logevent("Sending Pageant's response");
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_addstring_data(ret+9, GET_32BIT(ret+5));
+ ssh2_pkt_send();
+ authed = TRUE;
+ break;
+ } else {
+ logevent("Pageant failed to answer challenge");
+ sfree(ret);
+ }
+ }
+ }
+ if (authed)
+ continue;