Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pageant.c')
-rw-r--r--pageant.c839
1 files changed, 545 insertions, 294 deletions
diff --git a/pageant.c b/pageant.c
index 8ca9310b..455e434f 100644
--- a/pageant.c
+++ b/pageant.c
@@ -33,8 +33,10 @@ struct PageantClientDialogId {
int dummy;
};
-typedef struct PageantKeySort PageantKeySort;
-typedef struct PageantKey PageantKey;
+typedef struct PageantPrivateKeySort PageantPrivateKeySort;
+typedef struct PageantPublicKeySort PageantPublicKeySort;
+typedef struct PageantPrivateKey PageantPrivateKey;
+typedef struct PageantPublicKey PageantPublicKey;
typedef struct PageantAsyncOp PageantAsyncOp;
typedef struct PageantAsyncOpVtable PageantAsyncOpVtable;
typedef struct PageantClientRequestNode PageantClientRequestNode;
@@ -85,33 +87,106 @@ static void pageant_async_op_callback(void *vctx)
}
/*
- * Master list of all the keys we have stored, in any form at all.
+ * Master lists of all the keys we have stored, in any form at all.
+ *
+ * We store private and public keys in separate lists, because
+ * multiple public keys can share the same private key (due to one
+ * having a certificate and the other not, or having more than one
+ * different certificate). And when we decrypt or re-encrypt a private
+ * key, we don't really want to faff about doing it multiple times if
+ * there's more than one public key it goes with. If someone tries to
+ * re-encrypt a key to make their machine safer against unattended
+ * access, then it would be embarrassing to find they'd forgotten to
+ * re-encrypt the _other_ copy of it; conversely, once you've
+ * decrypted a key, it's pointless to make someone type yet another
+ * passphrase.
+ *
+ * (Causing multiple keys to become decrypted in one go isn't a
+ * security hole in its own right, because the signatures generated by
+ * certified and uncertified keys are identical. So an attacker
+ * gaining access to an agent containing one encrypted and one
+ * cleartext key with the same private half would still be *able* to
+ * generate signatures that went with the encrypted one, even if the
+ * agent refused to hand them out in response to the most obvious kind
+ * of request.)
*/
-static tree234 *keytree;
-struct PageantKeySort {
- /* Prefix of the main PageantKey structure which contains all the
- * data that the sorting order depends on. Also simple enough that
- * you can construct one for lookup purposes. */
+struct PageantPrivateKeySort {
+ /*
+ * Information used by the sorting criterion for the private key
+ * tree.
+ */
int ssh_version; /* 1 or 2; primary sort key */
- ptrlen public_blob; /* secondary sort key */
+ ptrlen base_pub; /* secondary sort key; never includes a certificate */
+};
+static int privkey_cmpfn(void *av, void *bv)
+{
+ PageantPrivateKeySort *a = (PageantPrivateKeySort *)av;
+ PageantPrivateKeySort *b = (PageantPrivateKeySort *)bv;
+
+ if (a->ssh_version != b->ssh_version)
+ return a->ssh_version < b->ssh_version ? -1 : +1;
+ else
+ return ptrlen_strcmp(a->base_pub, b->base_pub);
+}
+
+struct PageantPublicKeySort {
+ /*
+ * Information used by the sorting criterion for the public key
+ * tree. Begins with the private key sorting criterion, so that
+ * all the public keys sharing a private key appear adjacent in
+ * the tree. That's a reasonably sensible order to list them in
+ * for the user, and more importantly, it makes it easy to
+ * discover when we're deleting the last public key that goes with
+ * a particular private one, so as to delete that too. Easier than
+ * messing about with fragile reference counts.
+ */
+ PageantPrivateKeySort priv;
+ ptrlen full_pub; /* may match priv.base_pub, or may include a cert */
};
-struct PageantKey {
- PageantKeySort sort;
- strbuf *public_blob; /* the true owner of sort.public_blob */
- char *comment; /* stored separately, whether or not in rkey/skey */
+static int pubkey_cmpfn(void *av, void *bv)
+{
+ PageantPublicKeySort *a = (PageantPublicKeySort *)av;
+ PageantPublicKeySort *b = (PageantPublicKeySort *)bv;
+
+ int c = privkey_cmpfn(&a->priv, &b->priv);
+ if (c)
+ return c;
+ else
+ return ptrlen_strcmp(a->full_pub, b->full_pub);
+}
+
+struct PageantPrivateKey {
+ PageantPrivateKeySort sort;
+ strbuf *base_pub; /* the true owner of sort.base_pub */
union {
- RSAKey *rkey; /* if ssh_version == 1 */
- ssh2_userkey *skey; /* if ssh_version == 2 */
+ RSAKey *rkey; /* if sort.priv.ssh_version == 1 */
+ ssh_key *skey; /* if sort.priv.ssh_version == 2 */
};
strbuf *encrypted_key_file;
+ /* encrypted_key_comment stores the comment belonging to the
+ * encrypted key file. This is used when presenting deferred
+ * decryption prompts, because if the user had encrypted their
+ * uncert and cert keys with different passphrases, the passphrase
+ * prompt must reliably signal which file they're supposed to be
+ * entering the passphrase for. */
+ char *encrypted_key_comment;
bool decryption_prompt_active;
PageantKeyRequestNode blocked_requests;
PageantClientDialogId dlgid;
};
+static tree234 *privkeytree;
+
+struct PageantPublicKey {
+ PageantPublicKeySort sort;
+ strbuf *base_pub; /* the true owner of sort.priv.base_pub */
+ strbuf *full_pub; /* the true owner of sort.full_pub */
+ char *comment;
+};
+static tree234 *pubkeytree;
typedef struct PageantSignOp PageantSignOp;
struct PageantSignOp {
- PageantKey *pk;
+ PageantPrivateKey *priv;
strbuf *data_to_sign;
unsigned flags;
int crLine;
@@ -124,47 +199,40 @@ struct PageantSignOp {
/* Master lock that indicates whether a GUI request is currently in
* progress */
static bool gui_request_in_progress = false;
+static PageantKeyRequestNode requests_blocked_on_gui =
+ { &requests_blocked_on_gui, &requests_blocked_on_gui };
static void failure(PageantClient *pc, PageantClientRequestId *reqid,
strbuf *sb, unsigned char type, const char *fmt, ...);
-static void fail_requests_for_key(PageantKey *pk, const char *reason);
-static PageantKey *pageant_nth_key(int ssh_version, int i);
+static void fail_requests_for_key(PageantPrivateKey *priv, const char *reason);
+static PageantPublicKey *pageant_nth_pubkey(int ssh_version, int i);
-static void pk_free(PageantKey *pk)
+static void pk_priv_free(PageantPrivateKey *priv)
{
- if (pk->public_blob) strbuf_free(pk->public_blob);
- sfree(pk->comment);
- if (pk->sort.ssh_version == 1 && pk->rkey) {
- freersakey(pk->rkey);
- sfree(pk->rkey);
+ if (priv->base_pub)
+ strbuf_free(priv->base_pub);
+ if (priv->sort.ssh_version == 1 && priv->rkey) {
+ freersakey(priv->rkey);
+ sfree(priv->rkey);
}
- if (pk->sort.ssh_version == 2 && pk->skey) {
- sfree(pk->skey->comment);
- ssh_key_free(pk->skey->key);
- sfree(pk->skey);
+ if (priv->sort.ssh_version == 2 && priv->skey) {
+ ssh_key_free(priv->skey);
}
- if (pk->encrypted_key_file) strbuf_free(pk->encrypted_key_file);
- fail_requests_for_key(pk, "key deleted from Pageant while signing "
+ if (priv->encrypted_key_file)
+ strbuf_free(priv->encrypted_key_file);
+ if (priv->encrypted_key_comment)
+ sfree(priv->encrypted_key_comment);
+ fail_requests_for_key(priv, "key deleted from Pageant while signing "
"request was pending");
- sfree(pk);
-}
-
-static int cmpkeys(void *av, void *bv)
-{
- PageantKeySort *a = (PageantKeySort *)av, *b = (PageantKeySort *)bv;
-
- if (a->ssh_version != b->ssh_version)
- return a->ssh_version < b->ssh_version ? -1 : +1;
- else
- return ptrlen_strcmp(a->public_blob, b->public_blob);
+ sfree(priv);
}
-static inline PageantKeySort keysort(int version, ptrlen blob)
+static void pk_pub_free(PageantPublicKey *pub)
{
- PageantKeySort sort;
- sort.ssh_version = version;
- sort.public_blob = blob;
- return sort;
+ if (pub->full_pub)
+ strbuf_free(pub->full_pub);
+ sfree(pub->comment);
+ sfree(pub);
}
static strbuf *makeblob1(RSAKey *rkey)
@@ -175,126 +243,308 @@ static strbuf *makeblob1(RSAKey *rkey)
return blob;
}
-static strbuf *makeblob2(ssh2_userkey *skey)
+static strbuf *makeblob2full(ssh_key *key)
{
strbuf *blob = strbuf_new();
- ssh_key_public_blob(skey->key, BinarySink_UPCAST(blob));
+ ssh_key_public_blob(key, BinarySink_UPCAST(blob));
return blob;
}
-static PageantKey *findkey1(RSAKey *reqkey)
+static strbuf *makeblob2base(ssh_key *key)
+{
+ strbuf *blob = strbuf_new();
+ ssh_key_public_blob(ssh_key_base_key(key), BinarySink_UPCAST(blob));
+ return blob;
+}
+
+static PageantPrivateKey *pub_to_priv(PageantPublicKey *pub)
+{
+ PageantPrivateKey *priv = find234(privkeytree, &pub->sort.priv, NULL);
+ assert(priv && "Public and private trees out of sync!");
+ return priv;
+}
+
+static PageantPublicKey *findpubkey1(RSAKey *reqkey)
{
strbuf *blob = makeblob1(reqkey);
- PageantKeySort sort = keysort(1, ptrlen_from_strbuf(blob));
- PageantKey *toret = find234(keytree, &sort, NULL);
+ PageantPublicKeySort sort;
+ sort.priv.ssh_version = 1;
+ sort.priv.base_pub = ptrlen_from_strbuf(blob);
+ sort.full_pub = ptrlen_from_strbuf(blob);
+ PageantPublicKey *toret = find234(pubkeytree, &sort, NULL);
strbuf_free(blob);
return toret;
}
-static PageantKey *findkey2(ptrlen blob)
+/*
+ * Constructs the base_pub element of a PageantPublicKeySort, starting
+ * from full_pub. This may involve allocating a strbuf to store it in,
+ * which must survive until after you've finished using the resulting
+ * PageantPublicKeySort. Hence, the strbuf (if any) is returned from
+ * this function, and if it's non-NULL then the caller must eventually
+ * free it.
+ */
+static strbuf *make_base_pub_2(PageantPublicKeySort *sort)
+{
+ /* Start with the fallback option of making base_pub equal full_pub */
+ sort->priv.base_pub = sort->full_pub;
+
+ /* Now reconstruct a distinct base_pub without a cert, if possible
+ * and necessary */
+ strbuf *base_pub = NULL;
+ BinarySource src[1];
+ BinarySource_BARE_INIT_PL(src, sort->full_pub);
+ ptrlen algname = get_string(src);
+ const ssh_keyalg *alg = find_pubkey_alg_len(algname);
+ if (alg && alg->is_certificate) {
+ ssh_key *key = ssh_key_new_pub(alg, sort->full_pub);
+ if (key) {
+ base_pub = strbuf_new();
+ ssh_key_public_blob(ssh_key_base_key(key),
+ BinarySink_UPCAST(base_pub));
+ sort->priv.base_pub = ptrlen_from_strbuf(base_pub);
+ ssh_key_free(key);
+ }
+ }
+
+ return base_pub; /* caller must free once they're done with sort */
+}
+
+static PageantPublicKey *findpubkey2(ptrlen full_pub)
{
- PageantKeySort sort = keysort(2, blob);
- return find234(keytree, &sort, NULL);
+ PageantPublicKeySort sort;
+ sort.priv.ssh_version = 2;
+ sort.full_pub = full_pub;
+ strbuf *base_pub = make_base_pub_2(&sort);
+ PageantPublicKey *toret = find234(pubkeytree, &sort, NULL);
+ if (base_pub)
+ strbuf_free(base_pub);
+ return toret;
}
-static int find_first_key_for_version(int ssh_version)
+static int find_first_pubkey_for_version(int ssh_version)
{
- PageantKeySort sort = keysort(ssh_version, PTRLEN_LITERAL(""));
+ PageantPublicKeySort sort;
+ sort.priv.ssh_version = ssh_version;
+ sort.priv.base_pub = PTRLEN_LITERAL("");
+ sort.full_pub = PTRLEN_LITERAL("");
int pos;
- if (findrelpos234(keytree, &sort, NULL, REL234_GE, &pos))
+ if (findrelpos234(pubkeytree, &sort, NULL, REL234_GE, &pos))
return pos;
- return count234(keytree);
+ return count234(pubkeytree);
}
static int count_keys(int ssh_version)
{
- return (find_first_key_for_version(ssh_version + 1) -
- find_first_key_for_version(ssh_version));
+ return (find_first_pubkey_for_version(ssh_version + 1) -
+ find_first_pubkey_for_version(ssh_version));
}
int pageant_count_ssh1_keys(void) { return count_keys(1); }
int pageant_count_ssh2_keys(void) { return count_keys(2); }
-static bool pageant_add_ssh1_key(RSAKey *rkey)
+/*
+ * Common code to add a key to the trees. We fill in as many fields
+ * here as we can share between SSH versions: the ptrlens in the
+ * sorting field, the whole of pub->sort.priv, and the linked list of
+ * blocked requests.
+ */
+static bool pageant_add_key_common(PageantPublicKey *pub,
+ PageantPrivateKey *priv)
{
- PageantKey *pk = snew(PageantKey);
- memset(pk, 0, sizeof(PageantKey));
- pk->sort.ssh_version = 1;
- pk->public_blob = makeblob1(rkey);
- pk->sort.public_blob = ptrlen_from_strbuf(pk->public_blob);
- pk->blocked_requests.next = pk->blocked_requests.prev =
- &pk->blocked_requests;
-
- if (add234(keytree, pk) == pk) {
- pk->rkey = rkey;
- if (rkey->comment)
- pk->comment = dupstr(rkey->comment);
+ int ssh_version = priv->sort.ssh_version;
+
+ priv->sort.base_pub = ptrlen_from_strbuf(priv->base_pub);
+
+ pub->base_pub = strbuf_dup(priv->sort.base_pub);
+ pub->sort.priv.ssh_version = priv->sort.ssh_version;
+ pub->sort.priv.base_pub = ptrlen_from_strbuf(pub->base_pub);
+ pub->sort.full_pub = ptrlen_from_strbuf(pub->full_pub);
+ priv->blocked_requests.next = priv->blocked_requests.prev =
+ &priv->blocked_requests;
+
+ /*
+ * Try to add the private key to privkeytree, or combine new parts
+ * of it with what's already there.
+ */
+ PageantPrivateKey *priv_in_tree = add234(privkeytree, priv);
+ if (priv_in_tree == priv) {
+ /* The key wasn't in the tree at all, and we've just added it. */
+ } else {
+ /* The key was already in the tree, so we'll be freeing priv. */
+
+ if (ssh_version == 2 && priv->skey && !priv_in_tree->skey) {
+ /* The key was only stored encrypted, and now we have an
+ * unencrypted version to add to the existing record. */
+ priv_in_tree->skey = priv->skey;
+ priv->skey = NULL; /* so pk_priv_free won't free it */
+ }
+
+ if (ssh_version == 2 && priv->encrypted_key_file &&
+ !priv_in_tree->encrypted_key_file) {
+ /* Conversely, the key was only stored in clear, and now
+ * we have an encrypted version to add to it. */
+ priv_in_tree->encrypted_key_file = priv->encrypted_key_file;
+ priv->encrypted_key_file = NULL;
+ priv_in_tree->encrypted_key_comment = priv->encrypted_key_comment;
+ priv->encrypted_key_comment = NULL;
+ }
+
+ pk_priv_free(priv);
+ }
+
+ /*
+ * Try to add the public key.
+ */
+ PageantPublicKey *pub_in_tree = add234(pubkeytree, pub);
+ if (pub_in_tree == pub) {
+ /* Successfully added a new key. */
return true;
} else {
- pk_free(pk);
+ /* This public key was already there. */
+ pk_pub_free(pub);
return false;
}
}
+static bool pageant_add_ssh1_key(RSAKey *rkey)
+{
+ PageantPublicKey *pub = snew(PageantPublicKey);
+ memset(pub, 0, sizeof(PageantPublicKey));
+ PageantPrivateKey *priv = snew(PageantPrivateKey);
+ memset(priv, 0, sizeof(PageantPrivateKey));
+
+ priv->sort.ssh_version = 1;
+ priv->base_pub = makeblob1(rkey);
+ pub->full_pub = makeblob1(rkey);
+
+ if (rkey->comment)
+ pub->comment = dupstr(rkey->comment);
+
+ priv->rkey = snew(RSAKey);
+ duprsakey(priv->rkey, rkey);
+
+ return pageant_add_key_common(pub, priv);
+}
+
static bool pageant_add_ssh2_key(ssh2_userkey *skey)
{
- PageantKey *pk = snew(PageantKey);
- memset(pk, 0, sizeof(PageantKey));
- pk->sort.ssh_version = 2;
- pk->public_blob = makeblob2(skey);
- pk->sort.public_blob = ptrlen_from_strbuf(pk->public_blob);
- pk->blocked_requests.next = pk->blocked_requests.prev =
- &pk->blocked_requests;
+ PageantPublicKey *pub = snew(PageantPublicKey);
+ memset(pub, 0, sizeof(PageantPublicKey));
+ PageantPrivateKey *priv = snew(PageantPrivateKey);
+ memset(priv, 0, sizeof(PageantPrivateKey));
- PageantKey *pk_in_tree = add234(keytree, pk);
- if (pk_in_tree == pk) {
- /* The key wasn't in the tree at all, and we've just added it. */
- pk->skey = skey;
- if (skey->comment)
- pk->comment = dupstr(skey->comment);
- return true;
- } else if (!pk_in_tree->skey) {
- /* The key was only stored encrypted, and now we have an
- * unencrypted version to add to the existing record. */
- pk_in_tree->skey = skey;
- pk_free(pk);
- return true;
+ priv->sort.ssh_version = 2;
+ priv->base_pub = makeblob2base(skey->key);
+ pub->full_pub = makeblob2full(skey->key);
+
+ if (skey->comment)
+ pub->comment = dupstr(skey->comment);
+
+ /* Duplicate the ssh_key to go in priv */
+ {
+ strbuf *tmp = strbuf_new_nm();
+ ssh_key_openssh_blob(skey->key, BinarySink_UPCAST(tmp));
+ BinarySource src[1];
+ BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(tmp));
+ priv->skey = ssh_key_new_priv_openssh(ssh_key_alg(skey->key), src);
+ strbuf_free(tmp);
+ }
+
+ return pageant_add_key_common(pub, priv);
+}
+
+static bool pageant_add_ssh2_key_encrypted(PageantPublicKeySort sort,
+ const char *comment, ptrlen keyfile)
+{
+ PageantPublicKey *pub = snew(PageantPublicKey);
+ memset(pub, 0, sizeof(PageantPublicKey));
+ PageantPrivateKey *priv = snew(PageantPrivateKey);
+ memset(priv, 0, sizeof(PageantPrivateKey));
+
+ assert(sort.priv.ssh_version == 2);
+ priv->sort.ssh_version = sort.priv.ssh_version;
+ priv->base_pub = strbuf_dup(sort.priv.base_pub);
+ pub->full_pub = strbuf_dup(sort.full_pub);
+
+ pub->comment = dupstr(comment);
+
+ priv->encrypted_key_file = strbuf_dup_nm(keyfile);
+ priv->encrypted_key_comment = dupstr(comment);
+
+ return pageant_add_key_common(pub, priv);
+}
+
+static void remove_pubkey_cleanup(PageantPublicKey *pub)
+{
+ /* Common function called when we've just removed a public key
+ * from pubkeytree: we must also check whether that was the last
+ * public key sharing a private half, and if so, remove the
+ * corresponding private entry too. */
+
+ PageantPublicKeySort pubsearch;
+ pubsearch.priv = pub->sort.priv;
+ pubsearch.full_pub = PTRLEN_LITERAL("");
+ PageantPublicKey *pubfound = findrel234(
+ pubkeytree, &pubsearch, NULL, REL234_GE);
+
+ if (pubfound && !privkey_cmpfn(&pub->sort.priv, &pubfound->sort.priv)) {
+ /* There's still a public key which has the same sort.priv as
+ * the one we've just removed. We're good. */
} else {
- /* The key was already in the tree in full. */
- pk_free(pk);
- return false;
+ /* We've just removed the last public key of the family, so
+ * delete the private half as well. */
+ PageantPrivateKey *priv = del234(privkeytree, &pub->sort.priv);
+ assert(priv);
+ assert(!privkey_cmpfn(&priv->sort, &pub->sort.priv));
+ pk_priv_free(priv);
}
}
+static PageantPublicKey *del_pubkey_pos(int pos)
+{
+ PageantPublicKey *deleted = delpos234(pubkeytree, pos);
+ remove_pubkey_cleanup(deleted);
+ return deleted;
+}
+
+static void del_pubkey(PageantPublicKey *to_delete)
+{
+ PageantPublicKey *deleted = del234(pubkeytree, to_delete);
+ remove_pubkey_cleanup(deleted);
+}
+
static void remove_all_keys(int ssh_version)
{
- int start = find_first_key_for_version(ssh_version);
- int end = find_first_key_for_version(ssh_version + 1);
+ int start = find_first_pubkey_for_version(ssh_version);
+ int end = find_first_pubkey_for_version(ssh_version + 1);
while (end > start) {
- PageantKey *pk = delpos234(keytree, --end);
- assert(pk->sort.ssh_version == ssh_version);
- pk_free(pk);
+ PageantPublicKey *pub = del_pubkey_pos(--end);
+ assert(pub->sort.priv.ssh_version == ssh_version);
+ pk_pub_free(pub);
}
}
static void list_keys(BinarySink *bs, int ssh_version, bool extended)
{
int i;
- PageantKey *pk;
+ PageantPublicKey *pub;
put_uint32(bs, count_keys(ssh_version));
- for (i = find_first_key_for_version(ssh_version);
- NULL != (pk = index234(keytree, i)); i++) {
- if (pk->sort.ssh_version != ssh_version)
+ for (i = find_first_pubkey_for_version(ssh_version);
+ NULL != (pub = index234(pubkeytree, i)); i++) {
+ if (pub->sort.priv.ssh_version != ssh_version)
break;
if (ssh_version > 1)
- put_stringpl(bs, pk->sort.public_blob);
+ put_stringpl(bs, pub->sort.full_pub);
else
- put_datapl(bs, pk->sort.public_blob); /* no header */
+ put_datapl(bs, pub->sort.full_pub); /* no header */
- put_stringpl(bs, ptrlen_from_asciz(pk->comment));
+ put_stringpl(bs, ptrlen_from_asciz(pub->comment));
if (extended) {
+ assert(ssh_version == 2); /* extended lists not supported in v1 */
+
/*
* Append to each key entry a string containing extension
* data. This string begins with a flags word, and may in
@@ -303,12 +553,14 @@ static void list_keys(BinarySink *bs, int ssh_version, bool extended)
* string, so that clients that only partially understand
* it can still find the parts they do understand.
*/
+ PageantPrivateKey *priv = pub_to_priv(pub);
+
strbuf *sb = strbuf_new();
uint32_t flags = 0;
- if (!pk->skey)
+ if (!priv->skey)
flags |= LIST_EXTENDED_FLAG_HAS_NO_CLEARTEXT_KEY;
- if (pk->encrypted_key_file)
+ if (priv->encrypted_key_file)
flags |= LIST_EXTENDED_FLAG_HAS_ENCRYPTED_KEY_FILE;
put_uint32(sb, flags);
@@ -359,13 +611,24 @@ static PRINTF_LIKE(5, 6) void failure(
}
}
-static void signop_link(PageantSignOp *so)
+static void signop_link_to_key(PageantSignOp *so)
+{
+ assert(!so->pkr.prev);
+ assert(!so->pkr.next);
+
+ so->pkr.prev = so->priv->blocked_requests.prev;
+ so->pkr.next = &so->priv->blocked_requests;
+ so->pkr.prev->next = &so->pkr;
+ so->pkr.next->prev = &so->pkr;
+}
+
+static void signop_link_to_pending_gui_request(PageantSignOp *so)
{
assert(!so->pkr.prev);
assert(!so->pkr.next);
- so->pkr.prev = so->pk->blocked_requests.prev;
- so->pkr.next = &so->pk->blocked_requests;
+ so->pkr.prev = requests_blocked_on_gui.prev;
+ so->pkr.next = &requests_blocked_on_gui;
so->pkr.prev->next = &so->pkr;
so->pkr.next->prev = &so->pkr;
}
@@ -376,6 +639,7 @@ static void signop_unlink(PageantSignOp *so)
assert(so->pkr.prev);
so->pkr.next->prev = so->pkr.prev;
so->pkr.prev->next = so->pkr.next;
+ so->pkr.prev = so->pkr.next = NULL;
} else {
assert(!so->pkr.prev);
}
@@ -388,19 +652,19 @@ static void signop_free(PageantAsyncOp *pao)
sfree(so);
}
-static bool request_passphrase(PageantClient *pc, PageantKey *pk)
+static bool request_passphrase(PageantClient *pc, PageantPrivateKey *priv)
{
- if (!pk->decryption_prompt_active) {
+ if (!priv->decryption_prompt_active) {
assert(!gui_request_in_progress);
bool created_dlg = pageant_client_ask_passphrase(
- pc, &pk->dlgid, pk->comment);
+ pc, &priv->dlgid, priv->encrypted_key_comment);
if (!created_dlg)
return false;
gui_request_in_progress = true;
- pk->decryption_prompt_active = true;
+ priv->decryption_prompt_active = true;
}
return true;
@@ -413,13 +677,16 @@ static void signop_coroutine(PageantAsyncOp *pao)
crBegin(so->crLine);
- while (!so->pk->skey && gui_request_in_progress)
+ while (!so->priv->skey && gui_request_in_progress) {
+ signop_link_to_pending_gui_request(so);
crReturnV;
+ signop_unlink(so);
+ }
- if (!so->pk->skey) {
- assert(so->pk->encrypted_key_file);
+ if (!so->priv->skey) {
+ assert(so->priv->encrypted_key_file);
- if (!request_passphrase(so->pao.info->pc, so->pk)) {
+ if (!request_passphrase(so->pao.info->pc, so->priv)) {
response = strbuf_new();
failure(so->pao.info->pc, so->pao.reqid, response,
so->failure_type, "on-demand decryption could not "
@@ -427,12 +694,12 @@ static void signop_coroutine(PageantAsyncOp *pao)
goto respond;
}
- signop_link(so);
+ signop_link_to_key(so);
crReturnV;
signop_unlink(so);
}
- uint32_t supported_flags = ssh_key_alg(so->pk->skey->key)->supported_flags;
+ uint32_t supported_flags = ssh_key_supported_flags(so->priv->skey);
if (so->flags & ~supported_flags) {
/*
* We MUST reject any message containing flags we don't
@@ -445,7 +712,7 @@ static void signop_coroutine(PageantAsyncOp *pao)
goto respond;
}
- char *invalid = ssh_key_invalid(so->pk->skey->key, so->flags);
+ char *invalid = ssh_key_invalid(so->priv->skey, so->flags);
if (invalid) {
response = strbuf_new();
failure(so->pao.info->pc, so->pao.reqid, response, so->failure_type,
@@ -455,7 +722,7 @@ static void signop_coroutine(PageantAsyncOp *pao)
}
strbuf *signature = strbuf_new();
- ssh_key_sign(so->pk->skey->key, ptrlen_from_strbuf(so->data_to_sign),
+ ssh_key_sign(so->priv->skey, ptrlen_from_strbuf(so->data_to_sign),
so->flags, BinarySink_UPCAST(signature));
response = strbuf_new();
@@ -476,10 +743,10 @@ static const PageantAsyncOpVtable signop_vtable = {
.free = signop_free,
};
-static void fail_requests_for_key(PageantKey *pk, const char *reason)
+static void fail_requests_for_key(PageantPrivateKey *priv, const char *reason)
{
- while (pk->blocked_requests.next != &pk->blocked_requests) {
- PageantSignOp *so = container_of(pk->blocked_requests.next,
+ while (priv->blocked_requests.next != &priv->blocked_requests) {
+ PageantSignOp *so = container_of(priv->blocked_requests.next,
PageantSignOp, pkr);
signop_unlink(so);
strbuf *sb = strbuf_new();
@@ -492,12 +759,20 @@ static void fail_requests_for_key(PageantKey *pk, const char *reason)
}
}
-static void unblock_requests_for_key(PageantKey *pk)
+static void unblock_requests_for_key(PageantPrivateKey *priv)
{
- for (PageantKeyRequestNode *pkr = pk->blocked_requests.next;
- pkr != &pk->blocked_requests; pkr = pkr->next) {
- PageantSignOp *so = container_of(pk->blocked_requests.next,
- PageantSignOp, pkr);
+ for (PageantKeyRequestNode *pkr = priv->blocked_requests.next;
+ pkr != &priv->blocked_requests; pkr = pkr->next) {
+ PageantSignOp *so = container_of(pkr, PageantSignOp, pkr);
+ queue_toplevel_callback(pageant_async_op_callback, &so->pao);
+ }
+}
+
+static void unblock_pending_gui_requests(void)
+{
+ for (PageantKeyRequestNode *pkr = requests_blocked_on_gui.next;
+ pkr != &requests_blocked_on_gui; pkr = pkr->next) {
+ PageantSignOp *so = container_of(pkr, PageantSignOp, pkr);
queue_toplevel_callback(pageant_async_op_callback, &so->pao);
}
}
@@ -505,38 +780,33 @@ static void unblock_requests_for_key(PageantKey *pk)
void pageant_passphrase_request_success(PageantClientDialogId *dlgid,
ptrlen passphrase)
{
- PageantKey *pk = container_of(dlgid, PageantKey, dlgid);
+ PageantPrivateKey *priv = container_of(dlgid, PageantPrivateKey, dlgid);
assert(gui_request_in_progress);
gui_request_in_progress = false;
- pk->decryption_prompt_active = false;
+ priv->decryption_prompt_active = false;
- if (!pk->skey) {
+ if (!priv->skey) {
const char *error;
BinarySource src[1];
BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(
- pk->encrypted_key_file));
-
- strbuf *ppsb = strbuf_new_nm();
- put_datapl(ppsb, passphrase);
-
- pk->skey = ppk_load_s(src, ppsb->s, &error);
+ priv->encrypted_key_file));
+ strbuf *ppsb = strbuf_dup_nm(passphrase);
+ ssh2_userkey *skey = ppk_load_s(src, ppsb->s, &error);
strbuf_free(ppsb);
- if (!pk->skey) {
- fail_requests_for_key(pk, "unable to decrypt key");
+ if (!skey) {
+ fail_requests_for_key(priv, "unable to decrypt key");
return;
- } else if (pk->skey == SSH2_WRONG_PASSPHRASE) {
- pk->skey = NULL;
-
+ } else if (skey == SSH2_WRONG_PASSPHRASE) {
/*
* Find a PageantClient to use for another attempt at
* request_passphrase.
*/
- PageantKeyRequestNode *pkr = pk->blocked_requests.next;
- if (pkr == &pk->blocked_requests) {
+ PageantKeyRequestNode *pkr = priv->blocked_requests.next;
+ if (pkr == &priv->blocked_requests) {
/*
* Special case: if all the requests have gone away at
* this point, we need not bother putting up a request
@@ -545,32 +815,39 @@ void pageant_passphrase_request_success(PageantClientDialogId *dlgid,
return;
}
- PageantSignOp *so = container_of(pk->blocked_requests.next,
+ PageantSignOp *so = container_of(priv->blocked_requests.next,
PageantSignOp, pkr);
- pk->decryption_prompt_active = false;
- if (!request_passphrase(so->pao.info->pc, pk)) {
- fail_requests_for_key(pk, "unable to continue creating "
+ priv->decryption_prompt_active = false;
+ if (!request_passphrase(so->pao.info->pc, so->priv)) {
+ fail_requests_for_key(priv, "unable to continue creating "
"passphrase prompts");
}
return;
} else {
+ priv->skey = skey->key;
+ sfree(skey->comment);
+ sfree(skey);
keylist_update();
}
}
- unblock_requests_for_key(pk);
+ unblock_requests_for_key(priv);
+
+ unblock_pending_gui_requests();
}
void pageant_passphrase_request_refused(PageantClientDialogId *dlgid)
{
- PageantKey *pk = container_of(dlgid, PageantKey, dlgid);
+ PageantPrivateKey *priv = container_of(dlgid, PageantPrivateKey, dlgid);
assert(gui_request_in_progress);
gui_request_in_progress = false;
- pk->decryption_prompt_active = false;
+ priv->decryption_prompt_active = false;
- fail_requests_for_key(pk, "user refused to supply passphrase");
+ fail_requests_for_key(priv, "user refused to supply passphrase");
+
+ unblock_pending_gui_requests();
}
typedef struct PageantImmOp PageantImmOp;
@@ -608,9 +885,11 @@ static const PageantAsyncOpVtable immop_vtable = {
.free = immop_free,
};
-static bool reencrypt_key(PageantKey *pk)
+static bool reencrypt_key(PageantPublicKey *pub)
{
- if (pk->sort.ssh_version != 2) {
+ PageantPrivateKey *priv = pub_to_priv(pub);
+
+ if (priv->sort.ssh_version != 2) {
/*
* We don't support storing SSH-1 keys in encrypted form at
* all.
@@ -618,7 +897,7 @@ static bool reencrypt_key(PageantKey *pk)
return false;
}
- if (!pk->encrypted_key_file) {
+ if (!priv->encrypted_key_file) {
/*
* We can't re-encrypt a key if it doesn't have an encrypted
* form. (We could make one up, of course - but with what
@@ -627,14 +906,12 @@ static bool reencrypt_key(PageantKey *pk)
return false;
}
- /* Only actually free pk->skey if it exists. But we return success
+ /* Only actually free priv->skey if it exists. But we return success
* regardless, so that 'please ensure this key isn't stored
* decrypted' is idempotent. */
- if (pk->skey) {
- sfree(pk->skey->comment);
- ssh_key_free(pk->skey->key);
- sfree(pk->skey);
- pk->skey = NULL;
+ if (priv->skey) {
+ ssh_key_free(priv->skey);
+ priv->skey = NULL;
}
return true;
@@ -678,9 +955,10 @@ static PageantAsyncOp *pageant_make_op(
"reply: SSH1_AGENT_RSA_IDENTITIES_ANSWER");
if (!pc->suppress_logging) {
int i;
- PageantKey *pk;
- for (i = 0; NULL != (pk = pageant_nth_key(1, i)); i++) {
- char *fingerprint = rsa_ssh1_fingerprint(pk->rkey);
+ PageantPublicKey *pub;
+ for (i = 0; NULL != (pub = pageant_nth_pubkey(1, i)); i++) {
+ PageantPrivateKey *priv = pub_to_priv(pub);
+ char *fingerprint = rsa_ssh1_fingerprint(priv->rkey);
pageant_client_log(pc, reqid, "returned key: %s",
fingerprint);
sfree(fingerprint);
@@ -701,12 +979,12 @@ static PageantAsyncOp *pageant_make_op(
pageant_client_log(pc, reqid, "reply: SSH2_AGENT_IDENTITIES_ANSWER");
if (!pc->suppress_logging) {
int i;
- PageantKey *pk;
- for (i = 0; NULL != (pk = pageant_nth_key(2, i)); i++) {
- char *fingerprint = ssh2_fingerprint_blob(
- ptrlen_from_strbuf(pk->public_blob), SSH_FPTYPE_DEFAULT);
+ PageantPublicKey *pub;
+ for (i = 0; NULL != (pub = pageant_nth_pubkey(2, i)); i++) {
+ char *fingerprint = ssh2_double_fingerprint_blob(
+ pub->sort.full_pub, SSH_FPTYPE_DEFAULT);
pageant_client_log(pc, reqid, "returned key: %s %s",
- fingerprint, pk->comment);
+ fingerprint, pub->comment);
sfree(fingerprint);
}
}
@@ -719,7 +997,8 @@ static PageantAsyncOp *pageant_make_op(
* or not.
*/
RSAKey reqkey;
- PageantKey *pk;
+ PageantPublicKey *pub;
+ PageantPrivateKey *priv;
mp_int *challenge, *response;
ptrlen session_id;
unsigned response_type;
@@ -753,11 +1032,12 @@ static PageantAsyncOp *pageant_make_op(
sfree(fingerprint);
}
- if ((pk = findkey1(&reqkey)) == NULL) {
+ if ((pub = findpubkey1(&reqkey)) == NULL) {
fail("key not found");
goto challenge1_cleanup;
}
- response = rsa_ssh1_decrypt(challenge, pk->rkey);
+ priv = pub_to_priv(pub);
+ response = rsa_ssh1_decrypt(challenge, priv->rkey);
{
ssh_hash *h = ssh_hash_new(&ssh_md5);
@@ -772,7 +1052,7 @@ static PageantAsyncOp *pageant_make_op(
pageant_client_log(pc, reqid, "reply: SSH1_AGENT_RSA_RESPONSE");
- challenge1_cleanup:
+ challenge1_cleanup:
if (response)
mp_free(response);
mp_free(challenge);
@@ -785,7 +1065,7 @@ static PageantAsyncOp *pageant_make_op(
* SSH_AGENT_FAILURE, depending on whether we have that key
* or not.
*/
- PageantKey *pk;
+ PageantPublicKey *pub;
ptrlen keyblob, sigdata;
uint32_t flags;
@@ -813,12 +1093,12 @@ static PageantAsyncOp *pageant_make_op(
have_flags = true;
if (!pc->suppress_logging) {
- char *fingerprint = ssh2_fingerprint_blob(
+ char *fingerprint = ssh2_double_fingerprint_blob(
keyblob, SSH_FPTYPE_DEFAULT);
pageant_client_log(pc, reqid, "requested key: %s", fingerprint);
sfree(fingerprint);
}
- if ((pk = findkey2(keyblob)) == NULL) {
+ if ((pub = findpubkey2(keyblob)) == NULL) {
fail("key not found");
goto responded;
}
@@ -836,11 +1116,11 @@ static PageantAsyncOp *pageant_make_op(
so->pao.info = pc->info;
so->pao.cr.prev = pc->info->head.prev;
so->pao.cr.next = &pc->info->head;
+ so->pao.cr.prev->next = so->pao.cr.next->prev = &so->pao.cr;
so->pao.reqid = reqid;
- so->pk = pk;
+ so->priv = pub_to_priv(pub);
so->pkr.prev = so->pkr.next = NULL;
- so->data_to_sign = strbuf_new();
- put_datapl(so->data_to_sign, sigdata);
+ so->data_to_sign = strbuf_dup(sigdata);
so->flags = flags;
so->failure_type = failure_type;
so->crLine = 0;
@@ -885,7 +1165,7 @@ static PageantAsyncOp *pageant_make_op(
fail("key already present");
}
- add1_cleanup:
+ add1_cleanup:
if (key) {
freersakey(key);
sfree(key);
@@ -946,7 +1226,7 @@ static PageantAsyncOp *pageant_make_op(
fail("key already present");
}
- add2_cleanup:
+ add2_cleanup:
if (key) {
if (key->key)
ssh_key_free(key->key);
@@ -963,7 +1243,7 @@ static PageantAsyncOp *pageant_make_op(
* start with.
*/
RSAKey reqkey;
- PageantKey *pk;
+ PageantPublicKey *pub;
pageant_client_log(pc, reqid,
"request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
@@ -985,15 +1265,15 @@ static PageantAsyncOp *pageant_make_op(
sfree(fingerprint);
}
- pk = findkey1(&reqkey);
+ pub = findpubkey1(&reqkey);
freersakey(&reqkey);
- if (pk) {
+ if (pub) {
pageant_client_log(pc, reqid, "found with comment: %s",
- pk->rkey->comment);
+ pub->comment);
- del234(keytree, pk);
+ del_pubkey(pub);
keylist_update();
- pk_free(pk);
+ pk_pub_free(pub);
put_byte(sb, SSH_AGENT_SUCCESS);
pageant_client_log(pc, reqid, "reply: SSH_AGENT_SUCCESS");
@@ -1008,7 +1288,7 @@ static PageantAsyncOp *pageant_make_op(
* perhaps SSH_AGENT_FAILURE if it wasn't in the list to
* start with.
*/
- PageantKey *pk;
+ PageantPublicKey *pub;
ptrlen blob;
pageant_client_log(pc, reqid, "request: SSH2_AGENTC_REMOVE_IDENTITY");
@@ -1021,23 +1301,23 @@ static PageantAsyncOp *pageant_make_op(
}
if (!pc->suppress_logging) {
- char *fingerprint = ssh2_fingerprint_blob(
+ char *fingerprint = ssh2_double_fingerprint_blob(
blob, SSH_FPTYPE_DEFAULT);
pageant_client_log(pc, reqid, "unwanted key: %s", fingerprint);
sfree(fingerprint);
}
- pk = findkey2(blob);
- if (!pk) {
+ pub = findpubkey2(blob);
+ if (!pub) {
fail("key not found");
goto responded;
}
- pageant_client_log(pc, reqid, "found with comment: %s", pk->comment);
+ pageant_client_log(pc, reqid, "found with comment: %s", pub->comment);
- del234(keytree, pk);
+ del_pubkey(pub);
keylist_update();
- pk_free(pk);
+ pk_pub_free(pub);
put_byte(sb, SSH_AGENT_SUCCESS);
pageant_client_log(pc, reqid, "reply: SSH_AGENT_SUCCESS");
@@ -1120,22 +1400,24 @@ static PageantAsyncOp *pageant_make_op(
goto responded;
}
+ strbuf *base_pub = NULL;
+ strbuf *full_pub = NULL;
BinarySource src[1];
const char *error;
- strbuf *public_blob = strbuf_new();
+ full_pub = strbuf_new();
char *comment;
BinarySource_BARE_INIT_PL(src, keyfile);
- if (!ppk_loadpub_s(src, NULL, BinarySink_UPCAST(public_blob),
+ if (!ppk_loadpub_s(src, NULL, BinarySink_UPCAST(full_pub),
&comment, &error)) {
fail("failed to extract public key blob: %s", error);
goto add_ppk_cleanup;
}
if (!pc->suppress_logging) {
- char *fingerprint = ssh2_fingerprint_blob(
- ptrlen_from_strbuf(public_blob), SSH_FPTYPE_DEFAULT);
+ char *fingerprint = ssh2_double_fingerprint_blob(
+ ptrlen_from_strbuf(full_pub), SSH_FPTYPE_DEFAULT);
pageant_client_log(pc, reqid, "add-ppk: %s %s",
fingerprint, comment);
sfree(fingerprint);
@@ -1168,57 +1450,21 @@ static PageantAsyncOp *pageant_make_op(
goto add_ppk_cleanup;
}
- PageantKeySort sort =
- keysort(2, ptrlen_from_strbuf(public_blob));
+ PageantPublicKeySort sort;
+ sort.priv.ssh_version = 2;
+ sort.full_pub = ptrlen_from_strbuf(full_pub);
+ base_pub = make_base_pub_2(&sort);
- PageantKey *pk = find234(keytree, &sort, NULL);
- if (pk) {
- /*
- * This public key blob already exists in the
- * keytree. Add the encrypted key file to the
- * existing record, if it doesn't have one already.
- */
- if (!pk->encrypted_key_file) {
- pk->encrypted_key_file = strbuf_new_nm();
- put_datapl(pk->encrypted_key_file, keyfile);
-
- keylist_update();
- put_byte(sb, SSH_AGENT_SUCCESS);
- pageant_client_log(
- pc, reqid, "reply: SSH_AGENT_SUCCESS (added encrypted"
- " PPK to existing key record)");
- } else {
- fail("key already present");
- }
- } else {
- /*
- * We're adding a new key record containing only
- * an encrypted key file.
- */
- PageantKey *pk = snew(PageantKey);
- memset(pk, 0, sizeof(PageantKey));
- pk->blocked_requests.next = pk->blocked_requests.prev =
- &pk->blocked_requests;
- pk->sort.ssh_version = 2;
- pk->public_blob = public_blob;
- public_blob = NULL;
- pk->sort.public_blob = ptrlen_from_strbuf(pk->public_blob);
- pk->comment = dupstr(comment);
- pk->encrypted_key_file = strbuf_new_nm();
- put_datapl(pk->encrypted_key_file, keyfile);
-
- PageantKey *added = add234(keytree, pk);
- assert(added == pk); (void)added;
-
- keylist_update();
- put_byte(sb, SSH_AGENT_SUCCESS);
- pageant_client_log(pc, reqid, "reply: SSH_AGENT_SUCCESS (made"
- " new encrypted-only key record)");
- }
+ pageant_add_ssh2_key_encrypted(sort, comment, keyfile);
+ keylist_update();
+ put_byte(sb, SSH_AGENT_SUCCESS);
+ pageant_client_log(pc, reqid, "reply: SSH_AGENT_SUCCESS");
- add_ppk_cleanup:
- if (public_blob)
- strbuf_free(public_blob);
+ add_ppk_cleanup:
+ if (full_pub)
+ strbuf_free(full_pub);
+ if (base_pub)
+ strbuf_free(base_pub);
sfree(comment);
break;
}
@@ -1239,23 +1485,23 @@ static PageantAsyncOp *pageant_make_op(
}
if (!pc->suppress_logging) {
- char *fingerprint = ssh2_fingerprint_blob(
+ char *fingerprint = ssh2_double_fingerprint_blob(
blob, SSH_FPTYPE_DEFAULT);
pageant_client_log(pc, reqid, "key to re-encrypt: %s",
fingerprint);
sfree(fingerprint);
}
- PageantKey *pk = findkey2(blob);
- if (!pk) {
+ PageantPublicKey *pub = findpubkey2(blob);
+ if (!pub) {
fail("key not found");
goto responded;
}
pageant_client_log(pc, reqid,
- "found with comment: %s", pk->comment);
+ "found with comment: %s", pub->comment);
- if (!reencrypt_key(pk)) {
+ if (!reencrypt_key(pub)) {
fail("this key couldn't be re-encrypted");
goto responded;
}
@@ -1282,10 +1528,10 @@ static PageantAsyncOp *pageant_make_op(
* having made a state change.)
*/
unsigned nfailures = 0, nsuccesses = 0;
- PageantKey *pk;
+ PageantPublicKey *pub;
- for (int i = 0; (pk = index234(keytree, i)) != NULL; i++) {
- if (reencrypt_key(pk))
+ for (int i = 0; (pub = index234(pubkeytree, i)) != NULL; i++) {
+ if (reencrypt_key(pub))
nsuccesses++;
else
nfailures++;
@@ -1322,13 +1568,13 @@ static PageantAsyncOp *pageant_make_op(
"reply: SSH2_AGENT_SUCCESS + key list");
if (!pc->suppress_logging) {
int i;
- PageantKey *pk;
- for (i = 0; NULL != (pk = pageant_nth_key(2, i)); i++) {
- char *fingerprint = ssh2_fingerprint_blob(
- ptrlen_from_strbuf(pk->public_blob),
+ PageantPublicKey *pub;
+ for (i = 0; NULL != (pub = pageant_nth_pubkey(2, i)); i++) {
+ char *fingerprint = ssh2_double_fingerprint_blob(
+ ptrlen_from_strbuf(pub->full_pub),
SSH_FPTYPE_DEFAULT);
pageant_client_log(pc, reqid, "returned key: %s %s",
- fingerprint, pk->comment);
+ fingerprint, pub->comment);
sfree(fingerprint);
}
}
@@ -1353,6 +1599,7 @@ static PageantAsyncOp *pageant_make_op(
io->pao.info = pc->info;
io->pao.cr.prev = pc->info->head.prev;
io->pao.cr.next = &pc->info->head;
+ io->pao.cr.prev->next = io->pao.cr.next->prev = &io->pao.cr;
io->pao.reqid = reqid;
io->response = sb;
io->crLine = 0;
@@ -1369,43 +1616,47 @@ void pageant_handle_msg(PageantClient *pc, PageantClientRequestId *reqid,
void pageant_init(void)
{
pageant_local = true;
- keytree = newtree234(cmpkeys);
+ pubkeytree = newtree234(pubkey_cmpfn);
+ privkeytree = newtree234(privkey_cmpfn);
}
-static PageantKey *pageant_nth_key(int ssh_version, int i)
+static PageantPublicKey *pageant_nth_pubkey(int ssh_version, int i)
{
- PageantKey *pk = index234(
- keytree, find_first_key_for_version(ssh_version) + i);
- if (pk && pk->sort.ssh_version == ssh_version)
- return pk;
+ PageantPublicKey *pub = index234(
+ pubkeytree, find_first_pubkey_for_version(ssh_version) + i);
+ if (pub && pub->sort.priv.ssh_version == ssh_version)
+ return pub;
else
return NULL;
}
bool pageant_delete_nth_ssh1_key(int i)
{
- PageantKey *pk = delpos234(keytree, find_first_key_for_version(1) + i);
- if (!pk)
+ PageantPublicKey *pub = del_pubkey_pos(
+ find_first_pubkey_for_version(1) + i);
+ if (!pub)
return false;
- pk_free(pk);
+ pk_pub_free(pub);
return true;
}
bool pageant_delete_nth_ssh2_key(int i)
{
- PageantKey *pk = delpos234(keytree, find_first_key_for_version(2) + i);
- if (!pk)
+ PageantPublicKey *pub = del_pubkey_pos(
+ find_first_pubkey_for_version(2) + i);
+ if (!pub)
return false;
- pk_free(pk);
+ pk_pub_free(pub);
return true;
}
bool pageant_reencrypt_nth_ssh2_key(int i)
{
- PageantKey *pk = index234(keytree, find_first_key_for_version(2) + i);
- if (!pk)
+ PageantPublicKey *pub = index234(
+ pubkeytree, find_first_pubkey_for_version(2) + i);
+ if (!pub)
return false;
- return reencrypt_key(pk);
+ return reencrypt_key(pub);
}
void pageant_delete_all(void)
@@ -1416,9 +1667,9 @@ void pageant_delete_all(void)
void pageant_reencrypt_all(void)
{
- PageantKey *pk;
- for (int i = 0; (pk = index234(keytree, i)) != NULL; i++)
- reencrypt_key(pk);
+ PageantPublicKey *pub;
+ for (int i = 0; (pub = index234(pubkeytree, i)) != NULL; i++)
+ reencrypt_key(pub);
}
/* ----------------------------------------------------------------------
@@ -1461,12 +1712,12 @@ struct pageant_conn_state {
Plug plug;
};
-static void pageant_conn_closing(Plug *plug, const char *error_msg,
- int error_code, bool calling_back)
+static void pageant_conn_closing(Plug *plug, PlugCloseType type,
+ const char *error_msg)
{
struct pageant_conn_state *pc = container_of(
plug, struct pageant_conn_state, plug);
- if (error_msg)
+ if (type != PLUGCLOSE_NORMAL)
pageant_listener_client_log(pc->plc, "c#%"SIZEu": error: %s",
pc->conn_index, error_msg);
else
@@ -1608,12 +1859,12 @@ struct pageant_listen_state {
Plug plug;
};
-static void pageant_listen_closing(Plug *plug, const char *error_msg,
- int error_code, bool calling_back)
+static void pageant_listen_closing(Plug *plug, PlugCloseType type,
+ const char *error_msg)
{
struct pageant_listen_state *pl = container_of(
plug, struct pageant_listen_state, plug);
- if (error_msg)
+ if (type != PLUGCLOSE_NORMAL)
pageant_listener_client_log(pl->plc, "listening socket: error: %s",
error_msg);
sk_close(pl->listensock);
@@ -1624,6 +1875,7 @@ static const PlugVtable pageant_connection_plugvt = {
.closing = pageant_conn_closing,
.receive = pageant_conn_receive,
.sent = pageant_conn_sent,
+ .log = nullplug_log,
};
static int pageant_listen_accepting(Plug *plug,
@@ -1672,6 +1924,7 @@ static int pageant_listen_accepting(Plug *plug,
static const PlugVtable pageant_listener_plugvt = {
.closing = pageant_listen_closing,
.accepting = pageant_listen_accepting,
+ .log = nullplug_log,
};
struct pageant_listen_state *pageant_listener_new(
@@ -2229,8 +2482,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
if (kl1) {
for (size_t i = 0; i < kl1->nkeys; i++) {
- cbkey.blob = strbuf_new();
- put_datapl(cbkey.blob, kl1->keys[i].blob);
+ cbkey.blob = strbuf_dup(kl1->keys[i].blob);
cbkey.comment = mkstr(kl1->keys[i].comment);
cbkey.ssh_version = 1;
@@ -2261,8 +2513,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
if (kl2) {
for (size_t i = 0; i < kl2->nkeys; i++) {
- cbkey.blob = strbuf_new();
- put_datapl(cbkey.blob, kl2->keys[i].blob);
+ cbkey.blob = strbuf_dup(kl2->keys[i].blob);
cbkey.comment = mkstr(kl2->keys[i].comment);
cbkey.ssh_version = 2;