+ char *pp_copy = dupstr(this_passphrase);
+ if (addpos234(passphrases, pp_copy, 0) != pp_copy) {
+ /* No need; it was already there. */
+ smemclr(pp_copy, strlen(pp_copy));
+ sfree(pp_copy);
+ }
+ }
+
+ if (comment)
+ sfree(comment);
+
+ if (type == SSH_KEYTYPE_SSH1) {
+ if (!pageant_local) {
+ unsigned char *request, *response;
+ void *vresponse;
+ int reqlen, clen, resplen, ret;
+
+ clen = strlen(rkey->comment);
+
+ reqlen = 4 + 1 + /* length, message type */
+ 4 + /* bit count */
+ ssh1_bignum_length(rkey->modulus) +
+ ssh1_bignum_length(rkey->exponent) +
+ ssh1_bignum_length(rkey->private_exponent) +
+ ssh1_bignum_length(rkey->iqmp) +
+ ssh1_bignum_length(rkey->p) +
+ ssh1_bignum_length(rkey->q) + 4 + clen /* comment */
+ ;
+
+ request = snewn(reqlen, unsigned char);
+
+ request[4] = SSH1_AGENTC_ADD_RSA_IDENTITY;
+ reqlen = 5;
+ PUT_32BIT(request + reqlen, bignum_bitcount(rkey->modulus));
+ reqlen += 4;
+ reqlen += ssh1_write_bignum(request + reqlen, rkey->modulus);
+ reqlen += ssh1_write_bignum(request + reqlen, rkey->exponent);
+ reqlen +=
+ ssh1_write_bignum(request + reqlen,
+ rkey->private_exponent);
+ reqlen += ssh1_write_bignum(request + reqlen, rkey->iqmp);
+ reqlen += ssh1_write_bignum(request + reqlen, rkey->p);
+ reqlen += ssh1_write_bignum(request + reqlen, rkey->q);
+ PUT_32BIT(request + reqlen, clen);
+ memcpy(request + reqlen + 4, rkey->comment, clen);
+ reqlen += 4 + clen;
+ PUT_32BIT(request, reqlen - 4);
+
+ ret = agent_query(request, reqlen, &vresponse, &resplen,
+ NULL, NULL);
+ assert(ret == 1);
+ response = vresponse;
+ if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
+ *retstr = dupstr("The already running Pageant "
+ "refused to add the key.");
+ return PAGEANT_ACTION_FAILURE;
+ }
+ sfree(request);
+ sfree(response);
+ } else {
+ if (!pageant_add_ssh1_key(rkey)) {
+ sfree(rkey); /* already present, don't waste RAM */
+ }
+ }
+ } else {
+ if (!pageant_local) {
+ unsigned char *request, *response;
+ void *vresponse;
+ int reqlen, alglen, clen, keybloblen, resplen, ret;
+ alglen = strlen(skey->alg->name);
+ clen = strlen(skey->comment);
+
+ keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0);
+
+ reqlen = 4 + 1 + /* length, message type */
+ 4 + alglen + /* algorithm name */
+ keybloblen + /* key data */
+ 4 + clen /* comment */
+ ;
+
+ request = snewn(reqlen, unsigned char);
+
+ request[4] = SSH2_AGENTC_ADD_IDENTITY;
+ reqlen = 5;
+ PUT_32BIT(request + reqlen, alglen);
+ reqlen += 4;
+ memcpy(request + reqlen, skey->alg->name, alglen);
+ reqlen += alglen;
+ reqlen += skey->alg->openssh_fmtkey(skey->data,
+ request + reqlen,
+ keybloblen);
+ PUT_32BIT(request + reqlen, clen);
+ memcpy(request + reqlen + 4, skey->comment, clen);
+ reqlen += clen + 4;
+ PUT_32BIT(request, reqlen - 4);
+
+ ret = agent_query(request, reqlen, &vresponse, &resplen,
+ NULL, NULL);
+ assert(ret == 1);
+ response = vresponse;
+ if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
+ *retstr = dupstr("The already running Pageant "
+ "refused to add the key.");
+ return PAGEANT_ACTION_FAILURE;
+ }
+
+ sfree(request);
+ sfree(response);
+ } else {
+ if (!pageant_add_ssh2_key(skey)) {
+ skey->alg->freekey(skey->data);
+ sfree(skey); /* already present, don't waste RAM */
+ }
+ }
+ }
+ return PAGEANT_ACTION_OK;
+}
+
+int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
+ char **retstr)
+{
+ unsigned char *keylist, *p;
+ int i, nkeys, keylistlen;
+ char *comment;
+ struct pageant_pubkey cbkey;
+
+ keylist = pageant_get_keylist1(&keylistlen);
+ if (keylistlen < 4) {
+ *retstr = dupstr("Received broken SSH-1 key list from agent");
+ sfree(keylist);
+ return PAGEANT_ACTION_FAILURE;
+ }
+ nkeys = toint(GET_32BIT(keylist));
+ if (nkeys < 0) {
+ *retstr = dupstr("Received broken SSH-1 key list from agent");
+ sfree(keylist);
+ return PAGEANT_ACTION_FAILURE;
+ }
+ p = keylist + 4;
+ keylistlen -= 4;
+
+ for (i = 0; i < nkeys; i++) {
+ struct RSAKey rkey;
+ char fingerprint[128];
+ int n;
+
+ /* public blob and fingerprint */
+ memset(&rkey, 0, sizeof(rkey));
+ n = makekey(p, keylistlen, &rkey, NULL, 0);
+ if (n < 0 || n > keylistlen) {
+ freersakey(&rkey);
+ *retstr = dupstr("Received broken SSH-1 key list from agent");
+ sfree(keylist);
+ return PAGEANT_ACTION_FAILURE;
+ }
+ p += n, keylistlen -= n;
+ rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey);
+
+ /* comment */
+ if (keylistlen < 4) {
+ *retstr = dupstr("Received broken SSH-1 key list from agent");
+ freersakey(&rkey);
+ sfree(keylist);
+ return PAGEANT_ACTION_FAILURE;
+ }
+ n = toint(GET_32BIT(p));
+ p += 4, keylistlen -= 4;
+ if (n < 0 || keylistlen < n) {
+ *retstr = dupstr("Received broken SSH-1 key list from agent");
+ freersakey(&rkey);
+ sfree(keylist);
+ return PAGEANT_ACTION_FAILURE;
+ }
+ comment = dupprintf("%.*s", (int)n, (const char *)p);
+ p += n, keylistlen -= n;
+
+ cbkey.blob = rsa_public_blob(&rkey, &cbkey.bloblen);
+ cbkey.comment = comment;
+ cbkey.ssh_version = 1;
+ callback(callback_ctx, fingerprint, comment, &cbkey);
+ sfree(cbkey.blob);
+ freersakey(&rkey);
+ sfree(comment);
+ }