aboutsummaryrefslogtreecommitdiffstats
path: root/g10/getkey.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--g10/getkey.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/g10/getkey.c b/g10/getkey.c
index ad0c207bf..45c3f512b 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -366,6 +366,282 @@ getkey_disable_caches ()
}
+void
+pubkey_free (struct pubkey *key)
+{
+ xfree (key->pk);
+ release_kbnode (key->keyblock);
+ xfree (key);
+}
+
+void
+pubkeys_free (struct pubkey *keys)
+{
+ while (keys)
+ {
+ struct pubkey *next = keys->next;
+ pubkey_free (keys);
+ keys = next;
+ }
+}
+
+/* Returns all keys that match the search specfication SEARCH_TERMS.
+
+ This function also checks for and warns about duplicate entries in
+ the keydb, which can occur if the user has configured multiple
+ keyrings or keyboxes or if a keyring or keybox was corrupted.
+
+ Note: SEARCH_TERMS will not be expanded (i.e., it may not be a
+ group).
+
+ USE is the operation for which the key is required. It must be
+ either PUBKEY_USAGE_ENC, PUBKEY_USAGE_SIG, PUBKEY_USAGE_CERT or
+ PUBKEY_USAGE_AUTH.
+
+ XXX: Currently, only PUBKEY_USAGE_ENC and PUBKEY_USAGE_SIG are
+ implemented.
+
+ INCLUDE_UNUSABLE indicates whether disabled keys are allowed.
+ (Recipients specified with --encrypt-to and --hidden-encrypt-to may
+ be disabled. It is possible to edit disabled keys.)
+
+ SOURCE is the context in which SEARCH_TERMS was specified, e.g.,
+ "--encrypt-to", etc. If this function is called interactively,
+ then this should be NULL.
+
+ If WARN_POSSIBLY_AMBIGUOUS is set, then emits a warning if the user
+ does not specify a long key id or a fingerprint.
+
+ The results are placed in *KEYS. *KEYS must be NULL! */
+gpg_error_t
+get_pubkeys (ctrl_t ctrl,
+ char *search_terms, int use, int include_unusable, char *source,
+ int warn_possibly_ambiguous,
+ struct pubkey **keys)
+{
+ /* We show a warning when a key appears multiple times in the DB.
+ This can happen for two reasons:
+
+ - The user has configured multiple keyrings or keyboxes.
+
+ - The keyring or keybox has been corrupted in some way, e.g., a
+ bug or a random process changing them.
+
+ For each duplicate, we only want to show the key once. Hence,
+ this list. */
+ static strlist_t key_dups;
+
+ /* USE transformed to a string. */
+ char *use_str;
+
+ gpg_error_t err;
+
+ KEYDB_SEARCH_DESC desc;
+
+ GETKEY_CTX ctx;
+ struct pubkey *results = NULL;
+ struct pubkey *r;
+
+ int count;
+
+ char fingerprint[2 * MAX_FINGERPRINT_LEN + 1];
+
+ if (DBG_LOOKUP)
+ {
+ log_debug ("\n");
+ log_debug ("%s: Checking %s=%s\n",
+ __func__, source ? source : "user input", search_terms);
+ }
+
+ if (*keys)
+ log_bug ("%s: KEYS should be NULL!\n", __func__);
+
+ switch (use)
+ {
+ case PUBKEY_USAGE_ENC: use_str = "encrypt"; break;
+ case PUBKEY_USAGE_SIG: use_str = "sign"; break;
+ case PUBKEY_USAGE_CERT: use_str = "cetify"; break;
+ case PUBKEY_USAGE_AUTH: use_str = "authentication"; break;
+ default: log_bug ("%s: Bad value for USE (%d)\n", __func__, use);
+ }
+
+ if (use == PUBKEY_USAGE_CERT || use == PUBKEY_USAGE_AUTH)
+ log_bug ("%s: use=%s is unimplemented.\n", __func__, use_str);
+
+ err = classify_user_id (search_terms, &desc, 1);
+ if (err)
+ {
+ log_info (_("key \"%s\" not found: %s\n"),
+ search_terms, gpg_strerror (err));
+ if (!opt.quiet && source)
+ log_info (_("(check argument of option '%s')\n"), source);
+ goto out;
+ }
+
+ if (warn_possibly_ambiguous
+ && ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
+ || desc.mode == KEYDB_SEARCH_MODE_FPR16
+ || desc.mode == KEYDB_SEARCH_MODE_FPR20
+ || desc.mode == KEYDB_SEARCH_MODE_FPR))
+ {
+ log_info (_("Warning: '%s' should be a long key ID or a fingerprint\n"),
+ search_terms);
+ if (!opt.quiet && source)
+ log_info (_("(check argument of option '%s')\n"), source);
+ }
+
+ /* Gather all of the results. */
+ ctx = NULL;
+ count = 0;
+ do
+ {
+ PKT_public_key *pk = xmalloc_clear (sizeof *pk);
+ KBNODE kb;
+ pk->req_usage = use;
+
+ if (! ctx)
+ err = get_pubkey_byname (ctrl, &ctx, pk, search_terms, &kb, NULL,
+ include_unusable, 1);
+ else
+ err = getkey_next (ctx, pk, &kb);
+
+ if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ /* No more results. */
+ {
+ xfree (pk);
+ break;
+ }
+ else if (err)
+ /* An error (other than "not found"). */
+ {
+ log_error (_("error looking up: %s\n"),
+ gpg_strerror (err));
+ xfree (pk);
+ break;
+ }
+
+ /* Another result! */
+ count ++;
+
+ r = xmalloc_clear (sizeof (*r));
+ r->pk = pk;
+ r->keyblock = kb;
+ r->next = results;
+ results = r;
+ }
+ while (ctx);
+ getkey_end (ctx);
+
+ if (DBG_LOOKUP)
+ {
+ log_debug ("%s resulted in %d matches.\n", search_terms, count);
+ for (r = results; r; r = r->next)
+ log_debug (" %s\n",
+ hexfingerprint (r->keyblock->pkt->pkt.public_key,
+ fingerprint, sizeof (fingerprint)));
+ }
+
+ if (! results && gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ /* No match. */
+ {
+ if (DBG_LOOKUP)
+ log_debug ("%s: '%s' not found.\n", __func__, search_terms);
+
+ log_info (_("key \"%s\" not found\n"), search_terms);
+ if (!opt.quiet && source)
+ log_info (_("(check argument of option '%s')\n"), source);
+
+ goto out;
+ }
+ else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ /* No more matches. */
+ ;
+ else if (err)
+ /* Some other error. An error message was already printed
+ out. Free RESULTS and continue. */
+ goto out;
+
+ /* Check for duplicates. */
+ if (DBG_LOOKUP)
+ log_debug ("%s: Checking results of %s='%s' for dups\n",
+ __func__, source ? source : "user input", search_terms);
+ count = 0;
+ for (r = results; r; r = r->next)
+ {
+ struct pubkey **prevp;
+ struct pubkey *next;
+ struct pubkey *r2;
+ int dups = 0;
+
+ prevp = &r->next;
+ next = r->next;
+ while ((r2 = next))
+ {
+ if (cmp_public_keys (r->keyblock->pkt->pkt.public_key,
+ r2->keyblock->pkt->pkt.public_key) != 0)
+ /* Not a dup. */
+ {
+ prevp = &r2->next;
+ next = r2->next;
+ continue;
+ }
+
+ dups ++;
+ count ++;
+
+ /* Remove R2 from the list. */
+ *prevp = r2->next;
+ release_kbnode (r2->keyblock);
+ next = r2->next;
+ xfree (r2);
+ }
+
+ if (dups)
+ {
+ hexfingerprint (r->keyblock->pkt->pkt.public_key,
+ fingerprint, sizeof fingerprint);
+ if (! strlist_find (key_dups, fingerprint))
+ {
+ char fingerprint_formatted[MAX_FORMATTED_FINGERPRINT_LEN + 1];
+
+ log_info (_("Warning: %s appears in the keyring %d times.\n"),
+ format_hexfingerprint (fingerprint,
+ fingerprint_formatted,
+ sizeof fingerprint_formatted),
+ 1 + dups);
+ add_to_strlist (&key_dups, fingerprint);
+ }
+ }
+ }
+
+ if (DBG_LOOKUP && count)
+ {
+ log_debug ("After removing %d dups:\n", count);
+ for (r = results, count = 0; r; r = r->next)
+ log_debug (" %d: %s\n",
+ count,
+ hexfingerprint (r->keyblock->pkt->pkt.public_key,
+ fingerprint, sizeof fingerprint));
+ }
+
+ out:
+ if (err)
+ {
+ while ((r = results))
+ {
+ results = results->next;
+ pubkey_free (r);
+ release_kbnode (r->keyblock);
+ xfree (r);
+ }
+ }
+ else
+ *keys = results;
+
+ return err;
+}
+
+
static void
pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
KBNODE found_key)