aboutsummaryrefslogtreecommitdiffstats
path: root/g10/skclist.c
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2018-06-12 01:36:59 +0000
committerNIIBE Yutaka <[email protected]>2018-08-27 07:24:27 +0000
commit03a8de7def4195b9accde47c1dcb84279361936d (patch)
tree3c8bd334d7689cfa90246bdcd4f4f1f32f39a8a1 /g10/skclist.c
parentg10: Fix comment of enum_secret_keys. (diff)
downloadgnupg-03a8de7def4195b9accde47c1dcb84279361936d.tar.gz
gnupg-03a8de7def4195b9accde47c1dcb84279361936d.zip
g10: Move enum_secret_keys to skclist.c.
* g10/getkey.c (enum_secret_keys): Move to... * g10/skclist.c (enum_secret_keys): ... here. -- The function enum_secret_keys is not used by gpgv.c, but it is in getkey.c. Extending enum_secret_keys will require change of gpgv.c, so moving the function to the file for gpg is better. Signed-off-by: NIIBE Yutaka <[email protected]>
Diffstat (limited to 'g10/skclist.c')
-rw-r--r--g10/skclist.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/g10/skclist.c b/g10/skclist.c
index 78890dc42..f8c8cadf8 100644
--- a/g10/skclist.c
+++ b/g10/skclist.c
@@ -286,3 +286,201 @@ build_sk_list (ctrl_t ctrl,
*ret_sk_list = sk_list;
return err;
}
+
+
+/* Enumerate some secret keys (specifically, those specified with
+ * --default-key and --try-secret-key). Use the following procedure:
+ *
+ * 1) Initialize a void pointer to NULL
+ * 2) Pass a reference to this pointer to this function (content)
+ * and provide space for the secret key (sk)
+ * 3) Call this function as long as it does not return an error (or
+ * until you are done). The error code GPG_ERR_EOF indicates the
+ * end of the listing.
+ * 4) Call this function a last time with SK set to NULL,
+ * so that can free it's context.
+ *
+ * In pseudo-code:
+ *
+ * void *ctx = NULL;
+ * PKT_public_key *sk = xmalloc_clear (sizeof (*sk));
+ *
+ * while ((err = enum_secret_keys (&ctx, sk)))
+ * { // Process SK.
+ * if (done)
+ * break;
+ * sk = xmalloc_clear (sizeof (*sk));
+ * }
+ *
+ * // Release any resources used by CTX.
+ * enum_secret_keys (&ctx, NULL);
+ *
+ * if (gpg_err_code (err) != GPG_ERR_EOF)
+ * ; // An error occurred.
+ */
+gpg_error_t
+enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
+{
+ gpg_error_t err = 0;
+ const char *name;
+ kbnode_t keyblock;
+ struct
+ {
+ int eof;
+ int state;
+ strlist_t sl;
+ kbnode_t keyblock;
+ kbnode_t node;
+ getkey_ctx_t ctx;
+ pubkey_t results;
+ } *c = *context;
+
+ if (!c)
+ {
+ /* Make a new context. */
+ c = xtrycalloc (1, sizeof *c);
+ if (!c)
+ return gpg_error_from_syserror ();
+ *context = c;
+ }
+
+ if (!sk)
+ {
+ /* Free the context. */
+ pubkeys_free (c->results);
+ release_kbnode (c->keyblock);
+ getkey_end (ctrl, c->ctx);
+ xfree (c);
+ *context = NULL;
+ return 0;
+ }
+
+ if (c->eof)
+ return gpg_error (GPG_ERR_EOF);
+
+ for (;;)
+ {
+ /* Loop until we have a keyblock. */
+ while (!c->keyblock)
+ {
+ /* Loop over the list of secret keys. */
+ do
+ {
+ name = NULL;
+ keyblock = NULL;
+ switch (c->state)
+ {
+ case 0: /* First try to use the --default-key. */
+ name = parse_def_secret_key (ctrl);
+ c->state = 1;
+ break;
+
+ case 1: /* Init list of keys to try. */
+ c->sl = opt.secret_keys_to_try;
+ c->state++;
+ break;
+
+ case 2: /* Get next item from list. */
+ if (c->sl)
+ {
+ name = c->sl->d;
+ c->sl = c->sl->next;
+ }
+ else
+ c->state++;
+ break;
+
+ case 3: /* Init search context to enum all secret keys. */
+ err = getkey_bynames (ctrl, &c->ctx, NULL, NULL, 1,
+ &keyblock);
+ if (err)
+ {
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ getkey_end (ctrl, c->ctx);
+ c->ctx = NULL;
+ }
+ c->state++;
+ break;
+
+ case 4: /* Get next item from the context. */
+ if (c->ctx)
+ {
+ err = getkey_next (ctrl, c->ctx, NULL, &keyblock);
+ if (err)
+ {
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ getkey_end (ctrl, c->ctx);
+ c->ctx = NULL;
+ }
+ }
+ else
+ c->state++;
+ break;
+
+ default: /* No more names to check - stop. */
+ c->eof = 1;
+ return gpg_error (GPG_ERR_EOF);
+ }
+ }
+ while ((!name || !*name) && !keyblock);
+
+ if (keyblock)
+ c->node = c->keyblock = keyblock;
+ else
+ {
+ err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
+ if (err)
+ {
+ /* getkey_byname might return a keyblock even in the
+ error case - I have not checked. Thus better release
+ it. */
+ release_kbnode (c->keyblock);
+ c->keyblock = NULL;
+ }
+ else
+ c->node = c->keyblock;
+ }
+ }
+
+ /* Get the next key from the current keyblock. */
+ for (; c->node; c->node = c->node->next)
+ {
+ if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
+ || c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ pubkey_t r;
+
+ /* Skip this candidate if it's already enumerated. */
+ for (r = c->results; r; r = r->next)
+ if (!cmp_public_keys (r->pk, c->node->pkt->pkt.public_key))
+ break;
+ if (r)
+ continue;
+
+ copy_public_key (sk, c->node->pkt->pkt.public_key);
+ c->node = c->node->next;
+
+ r = xtrycalloc (1, sizeof (*r));
+ if (!r)
+ {
+ err = gpg_error_from_syserror ();
+ free_public_key (sk);
+ return err;
+ }
+
+ r->pk = sk;
+ r->keyblock = NULL;
+ r->next = c->results;
+ c->results = r;
+
+ return 0; /* Found. */
+ }
+ }
+
+ /* Dispose the keyblock and continue. */
+ release_kbnode (c->keyblock);
+ c->keyblock = NULL;
+ }
+}