gpg: Minor cleanup for key listing related code.
[gnupg.git] / g10 / getkey.c
index b5db65d..fe183fa 100644 (file)
@@ -35,6 +35,7 @@
 #include "trustdb.h"
 #include "i18n.h"
 #include "keyserver-internal.h"
+#include "call-agent.h"
 
 #define MAX_PK_CACHE_ENTRIES   PK_UID_CACHE_SIZE
 #define MAX_UID_CACHE_ENTRIES  PK_UID_CACHE_SIZE
@@ -73,6 +74,7 @@ static struct
 typedef struct keyid_list
 {
   struct keyid_list *next;
+  char fpr[MAX_FINGERPRINT_LEN];
   u32 keyid[2];
 } *keyid_list_t;
 
@@ -127,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);
     }
@@ -154,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);
@@ -244,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)
@@ -251,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");
@@ -325,18 +345,6 @@ pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock)
   copy_public_key (pk, a->pkt->pkt.public_key);
 }
 
-static void
-sk_from_block (GETKEY_CTX ctx, PKT_secret_key * sk, KBNODE keyblock)
-{
-  KBNODE a = ctx->found_key ? ctx->found_key : keyblock;
-
-  assert (a->pkt->pkttype == PKT_SECRET_KEY
-         || a->pkt->pkttype == PKT_SECRET_SUBKEY);
-
-  copy_secret_key (sk, a->pkt->pkt.secret_key);
-}
-
-
 /* Get a public key and store it into the allocated pk can be called
  * with PK set to NULL to just read it into some internal
  * structures.  */
@@ -378,7 +386,7 @@ get_pubkey (PKT_public_key * pk, u32 * keyid)
     memset (&ctx, 0, sizeof ctx);
     ctx.exact = 1; /* Use the key ID exactly as given.  */
     ctx.not_allocated = 1;
-    ctx.kr_handle = keydb_new (0);
+    ctx.kr_handle = keydb_new ();
     ctx.nitems = 1;
     ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
     ctx.items[0].u.kid[0] = keyid[0];
@@ -437,9 +445,9 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
   }
 #endif
 
-  hd = keydb_new (0);
+  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;
@@ -452,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])
@@ -480,7 +489,7 @@ get_pubkeyblock (u32 * keyid)
   memset (&ctx, 0, sizeof ctx);
   /* No need to set exact here because we want the entire block.  */
   ctx.not_allocated = 1;
-  ctx.kr_handle = keydb_new (0);
+  ctx.kr_handle = keydb_new ();
   ctx.nitems = 1;
   ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
   ctx.items[0].u.kid[0] = keyid[0];
@@ -494,67 +503,43 @@ get_pubkeyblock (u32 * keyid)
 
 
 
-/****************
- * Get a secret key and store it into sk
+/*
+ * Get a public key and store it into PK.  This functions check that a
+ * corresponding secret key is available.  With no secret key it does
+ * not succeeed.
  */
-int
-get_seckey (PKT_secret_key * sk, u32 * keyid)
+gpg_error_t
+get_seckey (PKT_public_key *pk, u32 *keyid)
 {
-  int rc;
+  gpg_error_t err;
   struct getkey_ctx_s ctx;
-  KBNODE kb = NULL;
+  kbnode_t keyblock = NULL;
 
   memset (&ctx, 0, sizeof ctx);
   ctx.exact = 1; /* Use the key ID exactly as given.  */
   ctx.not_allocated = 1;
-  ctx.kr_handle = keydb_new (1);
+  ctx.kr_handle = keydb_new ();
   ctx.nitems = 1;
   ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
   ctx.items[0].u.kid[0] = keyid[0];
   ctx.items[0].u.kid[1] = keyid[1];
-  ctx.req_algo = sk->req_algo;
-  ctx.req_usage = sk->req_usage;
-  rc = lookup (&ctx, &kb, 1);
-  if (!rc)
+  ctx.req_algo = pk->req_algo;
+  ctx.req_usage = pk->req_usage;
+  err = lookup (&ctx, &keyblock, 1);
+  if (!err)
     {
-      sk_from_block (&ctx, sk, kb);
+      pk_from_block (&ctx, pk, keyblock);
     }
-  get_seckey_end (&ctx);
-  release_kbnode (kb);
-
-  if (!rc)
-    {
-      /* Check the secret key (this may prompt for a passprase to
-       * unlock the secret key.  */
-      rc = check_secret_key (sk, 0);
-    }
-
-  return rc;
-}
-
+  get_pubkey_end (&ctx);
+  release_kbnode (keyblock);
 
-/* Check whether the secret key is available.  This is just a fast
- * check and does not tell us whether the secret key is valid.  It
- * merely tells other whether there is some secret key.
- * Returns:
- *    0                := key is available
- *    G10ERR_NO_SECKEY := key not availabe
- */
-int
-seckey_available (u32 * keyid)
-{
-  int rc;
-  KEYDB_HANDLE hd = keydb_new (1);
+  if (!err)
+    err = agent_probe_secret_key (/*ctrl*/NULL, pk);
 
-  rc = keydb_search_kid (hd, keyid);
-  if (rc == -1)
-    rc = G10ERR_NO_SECKEY;
-  keydb_release (hd);
-  return rc;
+  return err;
 }
 
 
-
 static int
 skip_unusable (void *dummy, u32 * keyid, PKT_user_id * uid)
 {
@@ -599,16 +584,16 @@ leave:
 }
 
 
-/* Try to get the pubkey by the userid. This function looks for the
+/* Try to get the pubkey by the userid.  This function looks for the
  * first pubkey certificate which has the given name in a user_id.  If
- * pk/sk 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 either the pk or
- * the sk.  If ret_kb is not NULL the function will return the
- * keyblock there.  */
+ * 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 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, PKT_secret_key * sk,
+key_byname (GETKEY_CTX *retctx, strlist_t namelist,
+           PKT_public_key *pk,
            int want_secret, int include_unusable,
            KBNODE * ret_kb, KEYDB_HANDLE * ret_kdbhd)
 {
@@ -618,8 +603,6 @@ key_byname (GETKEY_CTX * retctx, strlist_t namelist,
   GETKEY_CTX ctx;
   KBNODE help_kb = NULL;
 
-  /* FIXME: Eventually remove the SK argument.  */
-
   if (retctx)
     {
       /* Reset the returned context in case of error.  */
@@ -651,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;
@@ -671,7 +654,7 @@ key_byname (GETKEY_CTX * retctx, strlist_t namelist,
     }
 
   ctx->want_secret = want_secret;
-  ctx->kr_handle = keydb_new (0);
+  ctx->kr_handle = keydb_new ();
   if (!ret_kb)
     ret_kb = &help_kb;
 
@@ -680,11 +663,7 @@ key_byname (GETKEY_CTX * retctx, strlist_t namelist,
       ctx->req_algo = pk->req_algo;
       ctx->req_usage = pk->req_usage;
     }
-  else if (sk) /* FIXME:  We should remove this.  */
-    {
-      ctx->req_algo = sk->req_algo;
-      ctx->req_usage = sk->req_usage;
-    }
+
   rc = lookup (ctx, ret_kb, want_secret);
   if (!rc && pk)
     {
@@ -718,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)
 {
@@ -734,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.
 
@@ -771,7 +750,7 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
   else
     {
       add_to_strlist (&namelist, name);
-      rc = key_byname (retctx, namelist, pk, NULL, 0,
+      rc = key_byname (retctx, namelist, pk, 0,
                       include_unusable, ret_keyblock, ret_kdbhd);
     }
 
@@ -805,28 +784,28 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
                }
              add_to_strlist (&namelist, name);
              rc = key_byname (anylocalfirst ? retctx : NULL,
-                              namelist, pk, NULL, 0,
+                              namelist, pk, 0,
                               include_unusable, ret_keyblock, ret_kdbhd);
              break;
 
            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;
 
@@ -839,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
@@ -858,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;
@@ -904,18 +883,18 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
                  *retctx = NULL;
                }
              rc = key_byname (anylocalfirst ? retctx : NULL,
-                              namelist, pk, NULL, 0,
+                              namelist, pk, 0,
                               include_unusable, ret_keyblock, ret_kdbhd);
            }
          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));
        }
@@ -943,32 +922,47 @@ int
 get_pubkey_bynames (GETKEY_CTX * retctx, PKT_public_key * pk,
                    strlist_t names, KBNODE * ret_keyblock)
 {
-  return key_byname (retctx, names, pk, NULL, 0, 1, ret_keyblock, NULL);
+  return key_byname (retctx, names, pk, 0, 1, ret_keyblock, NULL);
 }
 
 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;
 }
 
 
@@ -991,7 +985,7 @@ get_pubkey_byfprint (PKT_public_key * pk,
       memset (&ctx, 0, sizeof ctx);
       ctx.exact = 1;
       ctx.not_allocated = 1;
-      ctx.kr_handle = keydb_new (0);
+      ctx.kr_handle = keydb_new ();
       ctx.nitems = 1;
       ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16
        : KEYDB_SEARCH_MODE_FPR20;
@@ -1028,9 +1022,9 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
   while (i < MAX_FINGERPRINT_LEN)
     fprbuf[i++] = 0;
 
-  hd = keydb_new (0);
+  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;
@@ -1070,7 +1064,7 @@ get_keyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint,
 
       memset (&ctx, 0, sizeof ctx);
       ctx.not_allocated = 1;
-      ctx.kr_handle = keydb_new (0);
+      ctx.kr_handle = keydb_new ();
       ctx.nitems = 1;
       ctx.items[0].mode = (fprint_len == 16
                            ? KEYDB_SEARCH_MODE_FPR16
@@ -1086,15 +1080,15 @@ get_keyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint,
 }
 
 
-/* Get a secret key by name and store it into sk.
- * If NAME is NULL use the default key.   */
-static int
-get_seckey_byname2 (GETKEY_CTX * retctx,
-                   PKT_secret_key * sk, const char *name, int unprotect,
-                   KBNODE * retblock)
+/* Get a secret key by NAME and store it into PK.  If NAME is NULL use
+ * the default key.  This functions checks that a corresponding secret
+ * key is available.  With no secret key it does not succeeed. */
+gpg_error_t
+get_seckey_byname (PKT_public_key *pk, const char *name)
 {
+  gpg_error_t err;
   strlist_t namelist = NULL;
-  int rc, include_unusable = 1;
+  int include_unusable = 1;
 
   /* If we have no name, try to use the default secret key.  If we
      have no default, we'll use the first usable one. */
@@ -1106,139 +1100,103 @@ get_seckey_byname2 (GETKEY_CTX * retctx,
   else
     include_unusable = 0;
 
-  rc = key_byname (retctx, namelist, NULL, sk, 1, include_unusable,
-                  retblock, NULL);
+  err = key_byname (NULL, namelist, pk, 1, include_unusable, NULL, NULL);
 
   free_strlist (namelist);
 
-  if (!rc && unprotect)
-    rc = check_secret_key (sk, 0);
-
-  return rc;
-}
-
-int
-get_seckey_byname (PKT_secret_key * sk, const char *name, int unlock)
-{
-  return get_seckey_byname2 (NULL, sk, name, unlock, NULL);
-}
-
-
-int
-get_seckey_bynames (GETKEY_CTX * retctx, PKT_secret_key * sk,
-                   strlist_t names, KBNODE * ret_keyblock)
-{
-  return key_byname (retctx, names, NULL, sk, 1, 1, ret_keyblock, NULL);
-}
-
-
-int
-get_seckey_next (GETKEY_CTX ctx, PKT_secret_key * sk, KBNODE * ret_keyblock)
-{
-  int rc;
-
-  rc = lookup (ctx, ret_keyblock, 1);
-  if (!rc && sk && ret_keyblock)
-    sk_from_block (ctx, sk, *ret_keyblock);
-
-  return rc;
+  return err;
 }
 
 
-void
-get_seckey_end (GETKEY_CTX ctx)
-{
-  get_pubkey_end (ctx);
-}
-
 
 /* Search for a key with the given fingerprint.
  * FIXME:
- * We should replace this with the _byname function.  Thiscsan be done
+ * We should replace this with the _byname function.  This can be done
  * by creating a userID conforming to the unified fingerprint style.   */
-int
-get_seckey_byfprint (PKT_secret_key * sk,
-                    const byte * fprint, size_t fprint_len)
+gpg_error_t
+get_seckey_byfprint (PKT_public_key *pk, const byte * fprint, size_t fprint_len)
 {
-  int rc;
+  gpg_error_t err;
 
   if (fprint_len == 20 || fprint_len == 16)
     {
       struct getkey_ctx_s ctx;
-      KBNODE kb = NULL;
+      kbnode_t kb = NULL;
 
       memset (&ctx, 0, sizeof ctx);
       ctx.exact = 1;
       ctx.not_allocated = 1;
-      ctx.kr_handle = keydb_new (1);
+      ctx.kr_handle = keydb_new ();
       ctx.nitems = 1;
       ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16
        : KEYDB_SEARCH_MODE_FPR20;
       memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
-      rc = lookup (&ctx, &kb, 1);
-      if (!rc && sk)
-       sk_from_block (&ctx, sk, kb);
+      err = lookup (&ctx, &kb, 1);
+      if (!err && pk)
+       pk_from_block (&ctx, pk, kb);
       release_kbnode (kb);
-      get_seckey_end (&ctx);
+      get_pubkey_end (&ctx);
     }
   else
-    rc = G10ERR_GENERAL;       /* Oops */
-  return rc;
+    err = gpg_error (GPG_ERR_BUG);
+  return err;
 }
 
 
 /* Search for a secret key with the given fingerprint and return the
-   complete keyblock which may have more than only this key. */
-int
-get_seckeyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint,
-                         size_t fprint_len)
+   complete keyblock which may have more than only this key.  Return
+   an error if no corresponding secret key is available.  */
+gpg_error_t
+get_seckeyblock_byfprint (kbnode_t *ret_keyblock,
+                          const byte *fprint, size_t fprint_len)
 {
-  int rc;
+  gpg_error_t err;
   struct getkey_ctx_s ctx;
 
   if (fprint_len != 20 && fprint_len == 16)
-    return G10ERR_GENERAL;     /* Oops */
+    return gpg_error (GPG_ERR_BUG);
 
   memset (&ctx, 0, sizeof ctx);
   ctx.not_allocated = 1;
-  ctx.kr_handle = keydb_new (1);
+  ctx.kr_handle = keydb_new ();
   ctx.nitems = 1;
   ctx.items[0].mode = (fprint_len == 16
                       ? KEYDB_SEARCH_MODE_FPR16 : KEYDB_SEARCH_MODE_FPR20);
   memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
-  rc = lookup (&ctx, ret_keyblock, 1);
-  get_seckey_end (&ctx);
+  err = lookup (&ctx, ret_keyblock, 1);
+  get_pubkey_end (&ctx);
 
-  return rc;
+  return err;
 }
 
 
 \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,
                 strlist_t names, int want_secret, kbnode_t *ret_keyblock)
 {
-  return key_byname (retctx, names, pk, NULL, want_secret, 1,
+  return key_byname (retctx, names, pk, want_secret, 1,
                      ret_keyblock, NULL);
 }
 
 
-/* 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 fucntion which has a
+ * FIXME: We also have the get_pubkey_byname function which has a
  * different semantic.  Should be merged with this one.
  */
 gpg_error_t
@@ -1256,9 +1214,9 @@ getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
   else
     with_unusable = 0;
 
-  err = key_byname (retctx, namelist, pk, NULL, want_secret, with_unusable,
+  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.  */
 
@@ -1286,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);
+    }
 }
 
 
@@ -1295,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)
@@ -1350,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;
 }
@@ -1488,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)
@@ -1648,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
@@ -1676,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
@@ -1700,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;
@@ -1736,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;
 
@@ -1782,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;
                    }
 
@@ -2019,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];
 
@@ -2046,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
@@ -2102,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;
@@ -2170,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);
        }
@@ -2200,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)
     {
@@ -2228,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
@@ -2239,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)
@@ -2283,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;
        }
     }
 }
@@ -2390,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");
@@ -2445,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");
@@ -2522,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.
@@ -2538,7 +2543,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
          goto skip;
        }
 
-      if (want_secret && have_secret_key (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
@@ -2558,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)
@@ -2568,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);
@@ -2583,55 +2588,42 @@ found:
 
 
 
-/****************
- * FIXME: Replace by the generic function
- *        It does not work as it is right now - it is used at
- *        2 places:  a) to get the key for an anonyous recipient
- *                   b) to get the ultimately trusted keys.
- *        The a) usage might have some problems.
- *
- * 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)
 {
-  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);
-      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;
@@ -2639,58 +2631,89 @@ enum_secret_keys (void **context, PKT_secret_key * sk,
     }
 
   if (c->eof)
-    return -1;
-
-  do
-    {
-      /* Get the next secret key from the current keyblock.  */
+    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;
+              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.  */
 }
-\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
@@ -2702,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));
 }
 
 
@@ -2730,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)
 {
@@ -2774,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;
@@ -2788,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)
 {
@@ -2798,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)
 {
@@ -2840,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;
@@ -2893,178 +2969,68 @@ parse_auto_key_locate (char *options)
 }
 
 
-/* Return 0 if a secret key is available for the key described by
-   KEYBLOCK.  FIXME: How do we handel subkeys?  */
-gpg_error_t
-have_secret_key (kbnode_t keyblock)
-{
-  gpg_error_t err;
-  unsigned char fpr[MAX_FINGERPRINT_LEN];
-  size_t fprlen;
-  KEYDB_HANDLE kdh;
-
-  if (!keyblock || keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
-    return gpg_error (GPG_ERR_NO_PUBKEY);  /* Should not happen.  */
-
-  fingerprint_from_pk (keyblock->pkt->pkt.public_key, fpr, &fprlen);
-  while (fprlen < MAX_FINGERPRINT_LEN) 
-    fpr[fprlen++] = 0;
-
-  /* FIXME: Always allocating a new handle is too slow.  However this
-     entire implementation is anyway a temporary solution until we can
-     ask gpg-agent for the secret key.  */
-  kdh = keydb_new (1);
-  if (!kdh)
-    return gpg_error (GPG_ERR_GENERAL);
-
-  err = keydb_search_fpr (kdh, fpr);
-  if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF)
-    err = gpg_error (GPG_ERR_NO_SECKEY);
-
-  keydb_release (kdh);
-
-  return err;
-}
-
-
-
-#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)
+/* Return true if a secret key or secret subkey is available for one
+   of the public keys in KEYBLOCK.  */
+int
+have_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
 {
-  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;
+  kbnode_t node;
 
-         /* 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.  */
-       }
-    }
+  for (node = keyblock; node; node = node->next)
+    if ((node->pkt->pkttype == PKT_PUBLIC_KEY
+         || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+        && !agent_probe_secret_key (ctrl, node->pkt->pkt.public_key))
+      return 1;
+  return 0;
 }
 
 
-/* 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)
+/* Return true if a secret key is available for the public key with
+ * the given KEYID.  This is just a fast check and does not tell us
+ * whether the secret key is valid.  It merely tells os whether there
+ * is some secret key.  */
+int
+have_secret_key_with_kid (u32 *keyid)
 {
-  KBNODE last, pub;
-
-  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
-  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
+  gpg_error_t err;
+  KEYDB_HANDLE kdbhd;
+  KEYDB_SEARCH_DESC desc;
+  kbnode_t keyblock;
+  kbnode_t node;
+  int result = 0;
+
+  kdbhd = keydb_new ();
+  memset (&desc, 0, sizeof desc);
+  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, NULL)))
+    {
+      err = keydb_get_keyblock (kdbhd, &keyblock);
+      if (err)
+        {
+          log_error (_("error reading keyblock: %s\n"), g10_errstr (err));
+          break;
+        }
 
-  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)
+      for (node = keyblock; node; node = node->next)
        {
-         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;
+          /* Bit 0 of the flags is set if the search found the key
+             using that key or subkey.  */
+         if ((node->flag & 1))
+            {
+              assert (node->pkt->pkttype == PKT_PUBLIC_KEY
+                      || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+
+              if (!agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
+                {
+                  result = 1;
+                  break;
+                }
            }
        }
+      release_kbnode (keyblock);
     }
-  /* 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);
+  keydb_release (kdbhd);
+  return result;
 }
-#endif /*0*/