gpg: Minor cleanup for key listing related code.
[gnupg.git] / g10 / getkey.c
index 4929974..fe183fa 100644 (file)
@@ -74,6 +74,7 @@ static struct
 typedef struct keyid_list
 {
   struct keyid_list *next;
+  char fpr[MAX_FINGERPRINT_LEN];
   u32 keyid[2];
 } *keyid_list_t;
 
@@ -128,17 +129,21 @@ void
 cache_public_key (PKT_public_key * pk)
 {
 #if MAX_PK_CACHE_ENTRIES
-  pk_cache_entry_t ce;
+  pk_cache_entry_t ce, ce2;
   u32 keyid[2];
 
   if (pk_cache_disabled)
     return;
 
-  if (pk->dont_cache)
+  if (pk->flags.dont_cache)
     return;
 
   if (is_ELGAMAL (pk->pubkey_algo)
-      || pk->pubkey_algo == PUBKEY_ALGO_DSA || is_RSA (pk->pubkey_algo))
+      || pk->pubkey_algo == PUBKEY_ALGO_DSA
+      || pk->pubkey_algo == PUBKEY_ALGO_ECDSA
+      || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
+      || pk->pubkey_algo == PUBKEY_ALGO_ECDH
+      || is_RSA (pk->pubkey_algo))
     {
       keyid_from_pk (pk, keyid);
     }
@@ -155,11 +160,25 @@ cache_public_key (PKT_public_key * pk)
 
   if (pk_cache_entries >= MAX_PK_CACHE_ENTRIES)
     {
-      /* fixme: Use another algorithm to free some cache slots.  */
-      pk_cache_disabled = 1;
-      if (opt.verbose > 1)
-       log_info (_("too many entries in pk cache - disabled\n"));
-      return;
+      int n;
+
+      /* Remove the last 50% of the entries.  */
+      for (ce = pk_cache, n = 0; ce && n < pk_cache_entries/2; n++)
+        ce = ce->next;
+      if (ce != pk_cache && ce->next)
+        {
+          ce2 = ce->next;
+          ce->next = NULL;
+          ce = ce2;
+          for (; ce; ce = ce2)
+            {
+              ce2 = ce->next;
+              free_public_key (ce->pk);
+              xfree (ce);
+              pk_cache_entries--;
+            }
+        }
+      assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES);
     }
   pk_cache_entries++;
   ce = xmalloc (sizeof *ce);
@@ -245,6 +264,7 @@ cache_user_id (KBNODE keyblock)
          keyid_list_t a = xmalloc_clear (sizeof *a);
          /* Hmmm: For a long list of keyids it might be an advantage
           * to append the keys.  */
+          fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, NULL);
          keyid_from_pk (k->pkt->pkt.public_key, a->keyid);
          /* First check for duplicates.  */
          for (r = user_id_db; r; r = r->next)
@@ -252,8 +272,7 @@ cache_user_id (KBNODE keyblock)
              keyid_list_t b = r->keyids;
              for (b = r->keyids; b; b = b->next)
                {
-                 if (b->keyid[0] == a->keyid[0]
-                     && b->keyid[1] == a->keyid[1])
+                 if (!memcmp (b->fpr, a->fpr, MAX_FINGERPRINT_LEN))
                    {
                      if (DBG_CACHE)
                        log_debug ("cache_user_id: already in cache\n");
@@ -428,7 +447,7 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
 
   hd = keydb_new ();
   rc = keydb_search_kid (hd, keyid);
-  if (rc == -1)
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
       keydb_release (hd);
       return G10ERR_NO_PUBKEY;
@@ -441,8 +460,9 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
       return G10ERR_NO_PUBKEY;
     }
 
-  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
-         || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+  assert (keyblock && keyblock->pkt
+          && (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
+              || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY));
 
   keyid_from_pk (keyblock->pkt->pkt.public_key, pkid);
   if (keyid[0] == pkid[0] && keyid[1] == pkid[1])
@@ -568,8 +588,9 @@ leave:
  * first pubkey certificate which has the given name in a user_id.  If
  * PK has the pubkey algo set, the function will only return a pubkey
  * with that algo.  If NAMELIST is NULL, the first key is returned.
- * The caller should provide storage for the PK.  If RET_KB is not
- * NULL the function will return the keyblock there.  */
+ * The caller should provide storage for the PK or pass NULL if it is
+ * not needed.  If RET_KB is not NULL the function stores the entire
+ * keyblock at that address.  */
 static int
 key_byname (GETKEY_CTX *retctx, strlist_t namelist,
            PKT_public_key *pk,
@@ -613,7 +634,7 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist,
        {
          gpg_error_t err;
 
-         err = classify_user_id (r->d, &ctx->items[n]);
+         err = classify_user_id (r->d, &ctx->items[n], 1);
 
          if (ctx->items[n].exact)
            ctx->exact = 1;
@@ -676,7 +697,7 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist,
    to import the key via the online mechanisms defined by
    --auto-key-locate.  */
 int
-get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
+get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
                   const char *name, KBNODE * ret_keyblock,
                   KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl)
 {
@@ -692,7 +713,7 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
 
   is_mbox = is_valid_mailbox (name);
 
-  /* Check whether we the default local search has been disabled.
+  /* Check whether the default local search has been disabled.
      This is the case if either the "nodefault" or the "local" keyword
      are in the list of auto key locate mechanisms.
 
@@ -770,21 +791,21 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
            case AKL_CERT:
              mechanism = "DNS CERT";
              glo_ctrl.in_auto_key_retrieve++;
-             rc = keyserver_import_cert (name, &fpr, &fpr_len);
+             rc = keyserver_import_cert (ctrl, name, &fpr, &fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
            case AKL_PKA:
              mechanism = "PKA";
              glo_ctrl.in_auto_key_retrieve++;
-             rc = keyserver_import_pka (name, &fpr, &fpr_len);
+             rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
            case AKL_LDAP:
              mechanism = "LDAP";
              glo_ctrl.in_auto_key_retrieve++;
-             rc = keyserver_import_ldap (name, &fpr, &fpr_len);
+             rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
@@ -797,9 +818,8 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
                {
                  mechanism = opt.keyserver->uri;
                  glo_ctrl.in_auto_key_retrieve++;
-                 rc =
-                   keyserver_import_name (name, &fpr, &fpr_len,
-                                          opt.keyserver);
+                 rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len,
+                                              opt.keyserver);
                  glo_ctrl.in_auto_key_retrieve--;
                }
              else
@@ -816,7 +836,8 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
                mechanism = akl->spec->uri;
                keyserver = keyserver_match (akl->spec);
                glo_ctrl.in_auto_key_retrieve++;
-               rc = keyserver_import_name (name, &fpr, &fpr_len, keyserver);
+               rc = keyserver_import_name (ctrl,
+                                            name, &fpr, &fpr_len, keyserver);
                glo_ctrl.in_auto_key_retrieve--;
              }
              break;
@@ -868,12 +889,12 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
          if (!rc)
            {
              /* Key found.  */
-             log_info (_("automatically retrieved `%s' via %s\n"),
+             log_info (_("automatically retrieved '%s' via %s\n"),
                        name, mechanism);
              break;
            }
          if (rc != G10ERR_NO_PUBKEY || opt.verbose || no_fingerprint)
-           log_info (_("error retrieving `%s' via %s: %s\n"),
+           log_info (_("error retrieving '%s' via %s: %s\n"),
                      name, mechanism,
                      no_fingerprint ? _("No fingerprint") : g10_errstr (rc));
        }
@@ -907,26 +928,41 @@ get_pubkey_bynames (GETKEY_CTX * retctx, PKT_public_key * pk,
 int
 get_pubkey_next (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE * ret_keyblock)
 {
-  int rc;
-
-  rc = lookup (ctx, ret_keyblock, 0);
-  if (!rc && pk && ret_keyblock)
-    pk_from_block (ctx, pk, *ret_keyblock);
-
-  return rc;
+  return gpg_err_code (getkey_next (ctx, pk, ret_keyblock));
 }
 
 void
 get_pubkey_end (GETKEY_CTX ctx)
 {
-  if (ctx)
-    {
-      memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
-      keydb_release (ctx->kr_handle);
-      free_strlist (ctx->extra_list);
-      if (!ctx->not_allocated)
-       xfree (ctx);
-    }
+  getkey_end (ctx);
+}
+
+
+/* Search for a key with the given standard fingerprint.  In contrast
+ * to get_pubkey_byfprint we assume a right padded fingerprint of the
+ * standard length.  PK may be NULL to only put the result into the
+ * internal caches.  */
+gpg_error_t
+get_pubkey_byfpr (PKT_public_key *pk, const byte *fpr)
+{
+  gpg_error_t err;
+  struct getkey_ctx_s ctx;
+  kbnode_t kb = NULL;
+
+  memset (&ctx, 0, sizeof ctx);
+  ctx.exact = 1;
+  ctx.not_allocated = 1;
+  ctx.kr_handle = keydb_new ();
+  ctx.nitems = 1;
+  ctx.items[0].mode = KEYDB_SEARCH_MODE_FPR;
+  memcpy (ctx.items[0].u.fpr, fpr, MAX_FINGERPRINT_LEN);
+  err = lookup (&ctx, &kb, 0);
+  if (!err && pk)
+    pk_from_block (&ctx, pk, kb);
+  release_kbnode (kb);
+  get_pubkey_end (&ctx);
+
+  return err;
 }
 
 
@@ -988,7 +1024,7 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
 
   hd = keydb_new ();
   rc = keydb_search_fpr (hd, fprbuf);
-  if (rc == -1)
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
       keydb_release (hd);
       return G10ERR_NO_PUBKEY;
@@ -1135,7 +1171,7 @@ get_seckeyblock_byfprint (kbnode_t *ret_keyblock,
 
 
 \f
-/* The new function to return a key.  
+/* The new function to return a key.
    FIXME: Document it.  */
 gpg_error_t
 getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
@@ -1146,17 +1182,18 @@ getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
 }
 
 
-/* Get a key by name and store it into PK.  If RETCTX is not NULL
- * return the search context which needs to be released by the caller
- * using getkey_end.  If NAME is NULL use the default key (see below).
- * On success and if RET_KEYBLOCK is not NULL the found keyblock is
- * stored at this address.  WANT_SECRET passed as true requires that a
- * secret key is available for the selected key.
- * 
+/* Get a key by name and store it into PK if that is not NULL.  If
+ * RETCTX is not NULL return the search context which needs to be
+ * released by the caller using getkey_end.  If NAME is NULL use the
+ * default key (see below).  On success and if RET_KEYBLOCK is not
+ * NULL the found keyblock is stored at this address.  WANT_SECRET
+ * passed as true requires that a secret key is available for the
+ * selected key.
+ *
  * If WANT_SECRET is true and NAME is NULL and a default key has been
  * defined that defined key is used.  In all other cases the first
- * available key is used. 
- * 
+ * available key is used.
+ *
  * FIXME: Explain what is up with unusable keys.
  *
  * FIXME: We also have the get_pubkey_byname function which has a
@@ -1179,7 +1216,7 @@ getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
 
   err = key_byname (retctx, namelist, pk, want_secret, with_unusable,
                     ret_keyblock, NULL);
-  
+
   /* FIXME: Check that we really return GPG_ERR_NO_SECKEY if
      WANT_SECRET has been used.  */
 
@@ -1207,7 +1244,14 @@ getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock)
 void
 getkey_end (getkey_ctx_t ctx)
 {
-  get_pubkey_end (ctx);
+  if (ctx)
+    {
+      memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
+      keydb_release (ctx->kr_handle);
+      free_strlist (ctx->extra_list);
+      if (!ctx->not_allocated)
+       xfree (ctx);
+    }
 }
 
 
@@ -1216,6 +1260,38 @@ getkey_end (getkey_ctx_t ctx)
  ************* Merging stuff ********************
  ************************************************/
 
+/* Set the mainkey_id fields for all keys in KEYBLOCK.  This is
+   usually done by merge_selfsigs but at some places we only need the
+   main_kid but the the full merging.  The function also guarantees
+   that all pk->keyids are computed. */
+void
+setup_main_keyids (kbnode_t keyblock)
+{
+  u32 kid[2], mainkid[2];
+  kbnode_t kbctx, node;
+  PKT_public_key *pk;
+
+  if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
+    BUG ();
+  pk = keyblock->pkt->pkt.public_key;
+
+  keyid_from_pk (pk, mainkid);
+  for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+    {
+      if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
+            || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
+        continue;
+      pk = node->pkt->pkt.public_key;
+      keyid_from_pk (pk, kid); /* Make sure pk->keyid is set.  */
+      if (!pk->main_keyid[0] && !pk->main_keyid[1])
+        {
+          pk->main_keyid[0] = mainkid[0];
+          pk->main_keyid[1] = mainkid[1];
+        }
+    }
+}
+
+
 /* Merge all self-signatures with the keys.  */
 void
 merge_keys_and_selfsig (KBNODE keyblock)
@@ -1271,13 +1347,19 @@ parse_key_usage (PKT_signature * sig)
 
       if (flags)
        key_usage |= PUBKEY_USAGE_UNKNOWN;
+
+      if (!key_usage)
+       key_usage |= PUBKEY_USAGE_NONE;
     }
+  else if (p) /* Key flags of length zero.  */
+    key_usage |= PUBKEY_USAGE_NONE;
 
   /* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a
      capability that we do not handle.  This serves to distinguish
      between a zero key usage which we handle as the default
      capabilities for that algorithm, and a usage that we do not
-     handle. */
+     handle.  Likewise we use PUBKEY_USAGE_NONE to indicate that
+     key_flags have been given but they do not specify any usage.  */
 
   return key_usage;
 }
@@ -1409,6 +1491,8 @@ sig_to_revoke_info (PKT_signature * sig, struct revoke_info *rinfo)
   rinfo->keyid[1] = sig->keyid[1];
 }
 
+
+/* Note that R_REVOKED may be set to 0, 1 or 2.  */
 static void
 merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                     struct revoke_info *rinfo)
@@ -1569,7 +1653,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
 
       /* Mark that key as valid: One direct key signature should
        * render a key as valid.  */
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* Pass 1.5: Look for key revocation signatures that were not made
@@ -1597,7 +1681,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                    break;
                  }
                else if (rc == G10ERR_NO_PUBKEY)
-                 pk->maybe_revoked = 1;
+                 pk->flags.maybe_revoked = 1;
 
                /* A failure here means the sig did not verify, was
                   not issued by a revocation key, or a revocation
@@ -1621,7 +1705,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
          if (uidnode && signode)
            {
              fixup_uidnode (uidnode, signode, keytimestamp);
-             pk->is_valid = 1;
+             pk->flags.valid = 1;
            }
          uidnode = k;
          signode = NULL;
@@ -1657,22 +1741,22 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
   if (uidnode && signode)
     {
       fixup_uidnode (uidnode, signode, keytimestamp);
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* If the key isn't valid yet, and we have
      --allow-non-selfsigned-uid set, then force it valid. */
-  if (!pk->is_valid && opt.allow_non_selfsigned_uid)
+  if (!pk->flags.valid && opt.allow_non_selfsigned_uid)
     {
       if (opt.verbose)
        log_info (_("Invalid key %s made valid by"
                    " --allow-non-selfsigned-uid\n"), keystr_from_pk (pk));
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* The key STILL isn't valid, so try and find an ultimately
      trusted signature. */
-  if (!pk->is_valid)
+  if (!pk->flags.valid)
     {
       uidnode = NULL;
 
@@ -1703,7 +1787,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                      && get_ownertrust (ultimate_pk) == TRUST_ULTIMATE)
                    {
                      free_public_key (ultimate_pk);
-                     pk->is_valid = 1;
+                     pk->flags.valid = 1;
                      break;
                    }
 
@@ -1940,7 +2024,7 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
   subpk = subnode->pkt->pkt.public_key;
   keytimestamp = subpk->timestamp;
 
-  subpk->is_valid = 0;
+  subpk->flags.valid = 0;
   subpk->main_keyid[0] = mainpk->main_keyid[0];
   subpk->main_keyid[1] = mainpk->main_keyid[1];
 
@@ -1967,7 +2051,7 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
                     subkeys rather than re-sign old ones as the
                     problem is in the distribution.  Plus, PGP (7)
                     does this the same way.  */
-                 subpk->is_revoked = 1;
+                 subpk->flags.revoked = 1;
                  sig_to_revoke_info (sig, &subpk->revoked);
                  /* Although we could stop now, we continue to
                   * figure out other information like the old expiration
@@ -2023,10 +2107,10 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
   if (openpgp_pk_test_algo (subpk->pubkey_algo))
     return;
 
-  subpk->is_valid = 1;
+  subpk->flags.valid = 1;
 
   /* Find the most recent 0x19 embedded signature on our self-sig. */
-  if (subpk->backsig == 0)
+  if (!subpk->flags.backsig)
     {
       int seq = 0;
       size_t n;
@@ -2091,9 +2175,9 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
 
          /* 2==valid, 1==invalid, 0==didn't check */
          if (check_backsig (mainpk, subpk, backsig) == 0)
-           subpk->backsig = 2;
+           subpk->flags.backsig = 2;
          else
-           subpk->backsig = 1;
+           subpk->flags.backsig = 1;
 
          free_seckey_enc (backsig);
        }
@@ -2121,7 +2205,7 @@ merge_selfsigs (KBNODE keyblock)
   struct revoke_info rinfo;
   PKT_public_key *main_pk;
   prefitem_t *prefs;
-  int mdc_feature;
+  unsigned int mdc_feature;
 
   if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
     {
@@ -2149,7 +2233,7 @@ merge_selfsigs (KBNODE keyblock)
     }
 
   main_pk = keyblock->pkt->pkt.public_key;
-  if (revoked || main_pk->has_expired || !main_pk->is_valid)
+  if (revoked || main_pk->has_expired || !main_pk->flags.valid)
     {
       /* If the primary key is revoked, expired, or invalid we
        * better set the appropriate flags on that key and all
@@ -2160,11 +2244,11 @@ merge_selfsigs (KBNODE keyblock)
              || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
            {
              PKT_public_key *pk = k->pkt->pkt.public_key;
-             if (!main_pk->is_valid)
-               pk->is_valid = 0;
-             if (revoked && !pk->is_revoked)
+             if (!main_pk->flags.valid)
+               pk->flags.valid = 0;
+             if (revoked && !pk->flags.revoked)
                {
-                 pk->is_revoked = revoked;
+                 pk->flags.revoked = revoked;
                  memcpy (&pk->revoked, &rinfo, sizeof (rinfo));
                }
              if (main_pk->has_expired)
@@ -2204,7 +2288,7 @@ merge_selfsigs (KBNODE keyblock)
          if (pk->prefs)
            xfree (pk->prefs);
          pk->prefs = copy_prefs (prefs);
-         pk->mdc_feature = mdc_feature;
+         pk->flags.mdc = mdc_feature;
        }
     }
 }
@@ -2311,13 +2395,13 @@ finish_lookup (GETKEY_CTX ctx)
          if (DBG_CACHE)
            log_debug ("\tchecking subkey %08lX\n",
                       (ulong) keyid_from_pk (pk, NULL));
-         if (!pk->is_valid)
+         if (!pk->flags.valid)
            {
              if (DBG_CACHE)
                log_debug ("\tsubkey not valid\n");
              continue;
            }
-         if (pk->is_revoked)
+         if (pk->flags.revoked)
            {
              if (DBG_CACHE)
                log_debug ("\tsubkey has been revoked\n");
@@ -2366,12 +2450,12 @@ finish_lookup (GETKEY_CTX ctx)
       if (DBG_CACHE && !foundk && !req_prim)
        log_debug ("\tno suitable subkeys found - trying primary\n");
       pk = keyblock->pkt->pkt.public_key;
-      if (!pk->is_valid)
+      if (!pk->flags.valid)
        {
          if (DBG_CACHE)
            log_debug ("\tprimary key not valid\n");
        }
-      else if (pk->is_revoked)
+      else if (pk->flags.revoked)
        {
          if (DBG_CACHE)
            log_debug ("\tprimary key has been revoked\n");
@@ -2443,7 +2527,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
   int no_suitable_key = 0;
 
   rc = 0;
-  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems)))
+  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL)))
     {
       /* If we are searching for the first key we have to make sure
          that the next iteration does not do an implicit reset.
@@ -2459,7 +2543,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
          goto skip;
        }
 
-      if (want_secret && !have_any_secret_key (NULL, ctx->keyblock))
+      if (want_secret && agent_probe_any_secret_key (NULL, ctx->keyblock))
         goto skip; /* No secret key available.  */
 
       /* Warning: node flag bits 0 and 1 should be preserved by
@@ -2479,9 +2563,9 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
       release_kbnode (ctx->keyblock);
       ctx->keyblock = NULL;
     }
-  
+
 found:
-  if (rc && rc != -1)
+  if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     log_error ("keydb_search failed: %s\n", g10_errstr (rc));
 
   if (!rc)
@@ -2489,9 +2573,9 @@ found:
       *ret_keyblock = ctx->keyblock; /* Return the keyblock.  */
       ctx->keyblock = NULL;
     }
-  else if (rc == -1 && no_suitable_key)
+  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && no_suitable_key)
     rc = want_secret? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
-  else if (rc == -1)
+  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     rc = want_secret? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
 
   release_kbnode (ctx->keyblock);
@@ -2504,57 +2588,42 @@ found:
 
 
 
-/****************
- * FIXME: Replace by the generic function
- *        It does not work as it is right now - it is used at
- *        one place:  to get the key for an anonymous recipient.
- *
- * set with_subkeys true to include subkeys
- * set with_spm true to include secret-parts-missing keys
- *
- * Enumerate all primary secret keys.  Caller must use these procedure:
+/*
+ * Enumerate certain secret keys.  Caller must use these procedure:
  *  1) create a void pointer and initialize it to NULL
  *  2) pass this void pointer by reference to this function
  *     and provide space for the secret key (pass a buffer for sk)
- *  3) call this function as long as it does not return -1
- *     to indicate EOF.
+ *  3) call this function as long as it does not return an error.
+ *     The error code GPG_ERR_EOF indicates the end of the listing.
  *  4) Always call this function a last time with SK set to NULL,
  *     so that can free it's context.
  */
-int
-enum_secret_keys (void **context, PKT_secret_key * sk,
-                 int with_subkeys, int with_spm)
+gpg_error_t
+enum_secret_keys (void **context, PKT_public_key *sk)
 {
-  log_debug ("FIXME: Anonymous recipient does not yet work\n");
-  return -1;
-#if 0
-
-  int rc = 0;
+  gpg_error_t err = 0;
+  const char *name;
   struct
   {
     int eof;
-    int first;
-    KEYDB_HANDLE hd;
-    KBNODE keyblock;
-    KBNODE node;
+    int state;
+    strlist_t sl;
+    kbnode_t keyblock;
+    kbnode_t node;
   } *c = *context;
 
-
   if (!c)
     {
       /* Make a new context.  */
-      c = xmalloc_clear (sizeof *c);
+      c = xtrycalloc (1, sizeof *c);
+      if (!c)
+        return gpg_error_from_syserror ();
       *context = c;
-      c->hd = keydb_new (1);  /*FIXME*/
-      c->first = 1;
-      c->keyblock = NULL;
-      c->node = NULL;
     }
 
   if (!sk)
     {
       /* Free the context.  */
-      keydb_release (c->hd);
       release_kbnode (c->keyblock);
       xfree (c);
       *context = NULL;
@@ -2562,59 +2631,89 @@ enum_secret_keys (void **context, PKT_secret_key * sk,
     }
 
   if (c->eof)
-    return -1;
+    return gpg_error (GPG_ERR_EOF);
 
-  do
+  for (;;)
     {
-      /* Get the next secret key from the current keyblock.  */
+      /* Loop until we have a keyblock.  */
+      while (!c->keyblock)
+        {
+          /* Loop over the list of secret keys.  */
+          do
+            {
+              name = NULL;
+              switch (c->state)
+                {
+                case 0: /* First try to use the --default-key.  */
+                  if (opt.def_secret_key && *opt.def_secret_key)
+                    name = opt.def_secret_key;
+                  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;
+
+                default: /* No more names to check - stop.  */
+                  c->eof = 1;
+                  return gpg_error (GPG_ERR_EOF);
+                }
+            }
+          while (!name || !*name);
+
+          err = getkey_byname (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_SECRET_KEY
-              || (with_subkeys
-                  && c->node->pkt->pkttype == PKT_SECRET_SUBKEY))
-             && !(c->node->pkt->pkt.secret_key->protect.s2k.mode == 1001
-                  && !with_spm))
+         if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
+              || c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
            {
-             copy_secret_key (sk, c->node->pkt->pkt.secret_key);
+             copy_public_key (sk, c->node->pkt->pkt.public_key);
              c->node = c->node->next;
              return 0; /* Found.  */
            }
-       }
-      release_kbnode (c->keyblock);
-      c->keyblock = c->node = NULL;
-
-      rc = c->first ? keydb_search_first (c->hd) : keydb_search_next (c->hd);
-      c->first = 0;
-      if (rc)
-       {
-         keydb_release (c->hd);
-         c->hd = NULL;
-         c->eof = 1;
-         return -1; /* eof */
-       }
+        }
 
-      rc = keydb_get_keyblock (c->hd, &c->keyblock);
-      c->node = c->keyblock;
+      /* Dispose the keyblock and continue.  */
+      release_kbnode (c->keyblock);
+      c->keyblock = NULL;
     }
-  while (!rc);
-
-  return rc; /* Error.  */
-#endif
 }
-\f
-
 
+\f
 /*********************************************
  ***********  User ID printing helpers *******
  *********************************************/
 
 /* Return a string with a printable representation of the user_id.
  * this string must be freed by xfree.   */
-char *
+static char *
 get_user_id_string (u32 * keyid)
 {
   user_id_db_t r;
-  char *p;
   int pass = 0;
   /* Try it two times; second pass reads from key resources.  */
   do
@@ -2626,17 +2725,13 @@ get_user_id_string (u32 * keyid)
            {
              if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
                {
-                 p = xmalloc (keystrlen () + 1 + r->len + 1);
-                 sprintf (p, "%s %.*s", keystr (keyid), r->len, r->name);
-                 return p;
+                 return xasprintf ("%s %.*s", keystr (keyid), r->len, r->name);
                }
            }
        }
     }
   while (++pass < 2 && !get_pubkey (NULL, keyid));
-  p = xmalloc (keystrlen () + 5);
-  sprintf (p, "%s [?]", keystr (keyid));
-  return p;
+  return xasprintf ("%s [?]", keystr (keyid));
 }
 
 
@@ -2654,33 +2749,30 @@ char *
 get_long_user_id_string (u32 * keyid)
 {
   user_id_db_t r;
-  char *p;
+  keyid_list_t a;
   int pass = 0;
   /* Try it two times; second pass reads from key resources.  */
   do
     {
       for (r = user_id_db; r; r = r->next)
        {
-         keyid_list_t a;
          for (a = r->keyids; a; a = a->next)
            {
              if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
                {
-                 p = xmalloc (r->len + 20);
-                 sprintf (p, "%08lX%08lX %.*s",
-                          (ulong) keyid[0], (ulong) keyid[1],
-                          r->len, r->name);
-                 return p;
+                 return xasprintf ("%08lX%08lX %.*s",
+                                    (ulong) keyid[0], (ulong) keyid[1],
+                                    r->len, r->name);
                }
            }
        }
     }
   while (++pass < 2 && !get_pubkey (NULL, keyid));
-  p = xmalloc (25);
-  sprintf (p, "%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
-  return p;
+  return xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
 }
 
+
+/* Please try to use get_user_id_native instead of this one.  */
 char *
 get_user_id (u32 * keyid, size_t * rn)
 {
@@ -2698,7 +2790,10 @@ get_user_id (u32 * keyid, size_t * rn)
            {
              if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
                {
-                 p = xmalloc (r->len);
+                  /* An empty string as user id is possible.  Make
+                     sure that the malloc allocates one byte and does
+                     not bail out.  */
+                 p = xmalloc (r->len? r->len : 1);
                  memcpy (p, r->name, r->len);
                  *rn = r->len;
                  return p;
@@ -2712,6 +2807,7 @@ get_user_id (u32 * keyid, size_t * rn)
   return p;
 }
 
+/* Please try to use get_user_id_byfpr_native instead of this one.  */
 char *
 get_user_id_native (u32 * keyid)
 {
@@ -2722,6 +2818,55 @@ get_user_id_native (u32 * keyid)
   return p2;
 }
 
+
+/* Return a user id from the caching by looking it up using the FPR
+   which mustbe of size MAX_FINGERPRINT_LEN.  */
+char *
+get_user_id_byfpr (const byte *fpr, size_t *rn)
+{
+  user_id_db_t r;
+  char *p;
+  int pass = 0;
+
+  /* Try it two times; second pass reads from key resources.  */
+  do
+    {
+      for (r = user_id_db; r; r = r->next)
+       {
+         keyid_list_t a;
+         for (a = r->keyids; a; a = a->next)
+           {
+             if (!memcmp (a->fpr, fpr, MAX_FINGERPRINT_LEN))
+               {
+                  /* An empty string as user id is possible.  Make
+                     sure that the malloc allocates one byte and does
+                     not bail out.  */
+                 p = xmalloc (r->len? r->len : 1);
+                 memcpy (p, r->name, r->len);
+                 *rn = r->len;
+                 return p;
+               }
+           }
+       }
+    }
+  while (++pass < 2 && !get_pubkey_byfpr (NULL, fpr));
+  p = xstrdup (user_id_not_found_utf8 ());
+  *rn = strlen (p);
+  return p;
+}
+
+char *
+get_user_id_byfpr_native (const byte *fpr)
+{
+  size_t rn;
+  char *p = get_user_id_byfpr (fpr, &rn);
+  char *p2 = utf8_to_native (p, rn, 0);
+  xfree (p);
+  return p2;
+}
+
+
+
 KEYDB_HANDLE
 get_ctx_handle (GETKEY_CTX ctx)
 {
@@ -2764,7 +2909,14 @@ parse_auto_key_locate (char *options)
 
       akl = xmalloc_clear (sizeof (*akl));
 
-      if (ascii_strcasecmp (tok, "nodefault") == 0)
+      if (ascii_strcasecmp (tok, "clear") == 0)
+       {
+          xfree (akl);
+          free_akl (opt.auto_key_locate);
+          opt.auto_key_locate = NULL;
+          continue;
+        }
+      else if (ascii_strcasecmp (tok, "nodefault") == 0)
        akl->type = AKL_NODEFAULT;
       else if (ascii_strcasecmp (tok, "local") == 0)
        akl->type = AKL_LOCAL;
@@ -2852,9 +3004,8 @@ have_secret_key_with_kid (u32 *keyid)
   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
   desc.u.kid[0] = keyid[0];
   desc.u.kid[1] = keyid[1];
-  while (!result && !(err = keydb_search (kdbhd, &desc, 1)))
+  while (!result && !(err = keydb_search (kdbhd, &desc, 1, NULL)))
     {
-      desc.mode = KEYDB_SEARCH_MODE_NEXT;
       err = keydb_get_keyblock (kdbhd, &keyblock);
       if (err)
         {
@@ -2883,146 +3034,3 @@ have_secret_key_with_kid (u32 *keyid)
   keydb_release (kdbhd);
   return result;
 }
-
-
-
-#if 0
-/*
- * Merge the secret keys from secblock into the pubblock thereby
- * replacing the public (sub)keys with their secret counterparts Hmmm:
- * It might be better to get away from the concept of entire secret
- * keys at all and have a way to store just the real secret parts
- * from the key.
- *
- * FIXME: this is not anymore needed but we keep it as example code for the
- * new code we need to write for the import/export feature.
- */
-static void
-merge_public_with_secret (KBNODE pubblock, KBNODE secblock)
-{
-  KBNODE pub;
-
-  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
-  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
-
-  for (pub = pubblock; pub; pub = pub->next)
-    {
-      if (pub->pkt->pkttype == PKT_PUBLIC_KEY)
-       {
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-         PKT_secret_key *sk = secblock->pkt->pkt.secret_key;
-         assert (pub == pubblock); /* Only in the first node.  */
-         /* There is nothing to compare in this case, so just replace
-          * some information.  */
-         copy_public_parts_to_secret_key (pk, sk);
-         free_public_key (pk);
-         pub->pkt->pkttype = PKT_SECRET_KEY;
-         pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
-       }
-      else if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-       {
-         KBNODE sec;
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-
-         /* This is more complicated: It may happen that the sequence
-          * of the subkeys dosn't match, so we have to find the
-          * appropriate secret key.  */
-         for (sec = secblock->next; sec; sec = sec->next)
-           {
-             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
-               {
-                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
-                 if (!cmp_public_secret_key (pk, sk))
-                   {
-                     copy_public_parts_to_secret_key (pk, sk);
-                     free_public_key (pk);
-                     pub->pkt->pkttype = PKT_SECRET_SUBKEY;
-                     pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
-                     break;
-                   }
-               }
-           }
-         if (!sec)
-           BUG (); /* Already checked in premerge.  */
-       }
-    }
-}
-
-
-/* This function checks that for every public subkey a corresponding
- * secret subkey is available and deletes the public subkey otherwise.
- * We need this function because we can't delete it later when we
- * actually merge the secret parts into the pubring.
- * The function also plays some games with the node flags.
- *
- * FIXME: this is not anymore needed but we keep it as example code for the
- * new code we need to write for the import/export feature.
- */
-static void
-premerge_public_with_secret (KBNODE pubblock, KBNODE secblock)
-{
-  KBNODE last, pub;
-
-  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
-  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
-
-  for (pub = pubblock, last = NULL; pub; last = pub, pub = pub->next)
-    {
-      pub->flag &= ~3; /* Reset bits 0 and 1.  */
-      if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-       {
-         KBNODE sec;
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-
-         for (sec = secblock->next; sec; sec = sec->next)
-           {
-             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
-               {
-                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
-                 if (!cmp_public_secret_key (pk, sk))
-                   {
-                     if (sk->protect.s2k.mode == 1001)
-                       {
-                         /* The secret parts are not available so
-                            we can't use that key for signing etc.
-                            Fix the pubkey usage */
-                         pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG
-                                               | PUBKEY_USAGE_AUTH);
-                       }
-                     /* Transfer flag bits 0 and 1 to the pubblock.  */
-                     pub->flag |= (sec->flag & 3);
-                     break;
-                   }
-               }
-           }
-         if (!sec)
-           {
-             KBNODE next, ll;
-
-             if (opt.verbose)
-               log_info (_("no secret subkey"
-                           " for public subkey %s - ignoring\n"),
-                         keystr_from_pk (pk));
-             /* We have to remove the subkey in this case.  */
-             assert (last);
-             /* Find the next subkey.  */
-             for (next = pub->next, ll = pub;
-                  next && next->pkt->pkttype != PKT_PUBLIC_SUBKEY;
-                  ll = next, next = next->next)
-               ;
-             /* Make new link.  */
-             last->next = next;
-             /* Release this public subkey with all sigs.  */
-             ll->next = NULL;
-             release_kbnode (pub);
-             /* Let the loop continue.  */
-             pub = last;
-           }
-       }
-    }
-  /* We need to copy the found bits (0 and 1) from the secret key to
-     the public key.  This has already been done for the subkeys but
-     got lost on the primary key - fix it here.  */
-  pubblock->flag |= (secblock->flag & 3);
-}
-#endif /*0*/