gpg: Simplify default_recipient().
[gnupg.git] / g10 / keyring.c
index cf67eb0..50f1b82 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include "gpg.h"
-#include "util.h"
+#include "../common/util.h"
 #include "keyring.h"
 #include "packet.h"
 #include "keydb.h"
 #include "options.h"
 #include "main.h" /*for check_key_signature()*/
-#include "i18n.h"
+#include "../common/i18n.h"
+#include "../kbx/keybox.h"
 
-/* off_item is a funny named for an object used to keep track of known
- * keys.  The idea was to use the offset to seek to the known keyblock, but
- * this is not possible if more than one process is using the keyring.
- */
-struct off_item {
-  struct off_item *next;
-  u32 kid[2];
-  /*off_t off;*/
-};
 
-typedef struct off_item **OffsetHashTable;
-
-
-typedef struct keyring_name *KR_NAME;
-struct keyring_name
+typedef struct keyring_resource *KR_RESOURCE;
+struct keyring_resource
 {
-  struct keyring_name *next;
+  struct keyring_resource *next;
   int read_only;
   dotlock_t lockhd;
   int is_locked;
   int did_full_scan;
   char fname[1];
 };
-typedef struct keyring_name const * CONST_KR_NAME;
-
-static KR_NAME kr_names;
-static int active_handles;
-
-static OffsetHashTable kr_offtbl;
-static int kr_offtbl_ready;
+typedef struct keyring_resource const * CONST_KR_RESOURCE;
 
+static KR_RESOURCE kr_resources;
 
 struct keyring_handle
 {
-  CONST_KR_NAME resource;
+  CONST_KR_RESOURCE resource;
   struct {
-    CONST_KR_NAME kr;
+    CONST_KR_RESOURCE kr;
     IOBUF iobuf;
     int eof;
     int error;
   } current;
   struct {
-    CONST_KR_NAME kr;
+    CONST_KR_RESOURCE kr;
     off_t offset;
     size_t pk_no;
     size_t uid_no;
@@ -91,96 +74,96 @@ struct keyring_handle
   } word_match;
 };
 
-
+/* The number of extant handles.  */
+static int active_handles;
 
 static int do_copy (int mode, const char *fname, KBNODE root,
                     off_t start_offset, unsigned int n_packets );
 
 
 \f
-static struct off_item *
-new_offset_item (void)
-{
-  struct off_item *k;
+/* We keep a cache of entries that we have entered in the DB.  This
+   includes not only public keys, but also subkeys.
+
+   Note: we'd like to keep the offset of the items that are present,
+   however, this doesn't work, because another concurrent GnuPG
+   process could modify the keyring.  */
+struct key_present {
+  struct key_present *next;
+  u32 kid[2];
+};
 
-  k = xmalloc_clear (sizeof *k);
-  return k;
-}
+/* For the hash table, we use separate chaining with linked lists.
+   This means that we have an array of N linked lists (buckets), which
+   is indexed by KEYID[1] mod N.  Elements present in the keyring will
+   be on the list; elements not present in the keyring will not be on
+   the list.
 
-#if 0
-static void
-release_offset_items (struct off_item *k)
-{
-  struct off_item *k2;
+   Note: since the hash table stores both present and not present
+   information, it cannot be used until we complete a full scan of the
+   keyring.  This is indicated by key_present_hash_ready.  */
+typedef struct key_present **key_present_hash_t;
+static key_present_hash_t key_present_hash;
+static int key_present_hash_ready;
 
-  for (; k; k = k2)
-    {
-      k2 = k->next;
-      xfree (k);
-    }
-}
-#endif
+#define KEY_PRESENT_HASH_BUCKETS 2048
 
-static OffsetHashTable
-new_offset_hash_table (void)
+/* Allocate a new value for a key present hash table.  */
+static struct key_present *
+key_present_value_new (void)
 {
-  struct off_item **tbl;
+  struct key_present *k;
 
-  tbl = xmalloc_clear (2048 * sizeof *tbl);
-  return tbl;
+  k = xmalloc_clear (sizeof *k);
+  return k;
 }
 
-#if 0
-static void
-release_offset_hash_table (OffsetHashTable tbl)
+/* Allocate a new key present hash table.  */
+static key_present_hash_t
+key_present_hash_new (void)
 {
-  int i;
+  struct key_present **tbl;
 
-  if (!tbl)
-    return;
-  for (i=0; i < 2048; i++)
-    release_offset_items (tbl[i]);
-  xfree (tbl);
+  tbl = xmalloc_clear (KEY_PRESENT_HASH_BUCKETS * sizeof *tbl);
+  return tbl;
 }
-#endif
 
-static struct off_item *
-lookup_offset_hash_table (OffsetHashTable tbl, u32 *kid)
+/* Return whether the value described by KID if it is in the hash
+   table.  Otherwise, return NULL.  */
+static struct key_present *
+key_present_hash_lookup (key_present_hash_t tbl, u32 *kid)
 {
-  struct off_item *k;
+  struct key_present *k;
 
-  for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
+  for (k = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))]; k; k = k->next)
     if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
       return k;
   return NULL;
 }
 
+/* Add the key to the hash table TBL if it is not already present.  */
 static void
-update_offset_hash_table (OffsetHashTable tbl, u32 *kid, off_t off)
+key_present_hash_update (key_present_hash_t tbl, u32 *kid)
 {
-  struct off_item *k;
-
-  (void)off;
+  struct key_present *k;
 
-  for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
+  for (k = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))]; k; k = k->next)
     {
       if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
-        {
-          /*k->off = off;*/
-          return;
-        }
+        return;
     }
 
-  k = new_offset_item ();
+  k = key_present_value_new ();
   k->kid[0] = kid[0];
   k->kid[1] = kid[1];
-  /*k->off = off;*/
-  k->next = tbl[(kid[1] & 0x07ff)];
-  tbl[(kid[1] & 0x07ff)] = k;
+  k->next = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))];
+  tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))] = k;
 }
 
+/* Add all the keys (public and subkeys) present in the keyblock to
+   the hash TBL.  */
 static void
-update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
+key_present_hash_update_from_kb (key_present_hash_t tbl, KBNODE node)
 {
   for (; node; node = node->next)
     {
@@ -189,11 +172,11 @@ update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
         {
           u32 aki[2];
           keyid_from_pk (node->pkt->pkt.public_key, aki);
-          update_offset_hash_table (tbl, aki, off);
+          key_present_hash_update (tbl, aki);
         }
     }
 }
-
+\f
 /*
  * Register a filename for plain keyring files.  ptr is set to a
  * pointer to be used to create a handles etc, or the already-issued
@@ -203,12 +186,13 @@ update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
 int
 keyring_register_filename (const char *fname, int read_only, void **ptr)
 {
-    KR_NAME kr;
+    KR_RESOURCE kr;
 
     if (active_handles)
-        BUG (); /* We don't allow that */
+      /* There are open handles.  */
+      BUG ();
 
-    for (kr=kr_names; kr; kr = kr->next)
+    for (kr=kr_resources; kr; kr = kr->next)
       {
         if (same_file_p (kr->fname, fname))
          {
@@ -227,12 +211,12 @@ keyring_register_filename (const char *fname, int read_only, void **ptr)
     kr->is_locked = 0;
     kr->did_full_scan = 0;
     /* keep a list of all issued pointers */
-    kr->next = kr_names;
-    kr_names = kr;
+    kr->next = kr_resources;
+    kr_resources = kr;
 
     /* create the offset table the first time a function here is used */
-    if (!kr_offtbl)
-      kr_offtbl = new_offset_hash_table ();
+    if (!key_present_hash)
+      key_present_hash = key_present_hash_new ();
 
     *ptr=kr;
 
@@ -242,7 +226,7 @@ keyring_register_filename (const char *fname, int read_only, void **ptr)
 int
 keyring_is_writable (void *token)
 {
-  KR_NAME r = token;
+  KR_RESOURCE r = token;
 
   return r? (r->read_only || !access (r->fname, W_OK)) : 0;
 }
@@ -250,17 +234,19 @@ keyring_is_writable (void *token)
 
 \f
 /* Create a new handle for the resource associated with TOKEN.
-
+   On error NULL is returned and ERRNO is set.
    The returned handle must be released using keyring_release (). */
 KEYRING_HANDLE
 keyring_new (void *token)
 {
   KEYRING_HANDLE hd;
-  KR_NAME resource = token;
+  KR_RESOURCE resource = token;
 
-  assert (resource);
+  log_assert (resource);
 
-  hd = xmalloc_clear (sizeof *hd);
+  hd = xtrycalloc (1, sizeof *hd);
+  if (!hd)
+    return hd;
   hd->resource = resource;
   active_handles++;
   return hd;
@@ -271,7 +257,7 @@ keyring_release (KEYRING_HANDLE hd)
 {
     if (!hd)
         return;
-    assert (active_handles > 0);
+    log_assert (active_handles > 0);
     active_handles--;
     xfree (hd->word_match.name);
     xfree (hd->word_match.pattern);
@@ -315,14 +301,14 @@ keyring_get_resource_name (KEYRING_HANDLE hd)
 int
 keyring_lock (KEYRING_HANDLE hd, int yes)
 {
-    KR_NAME kr;
+    KR_RESOURCE kr;
     int rc = 0;
 
     (void)hd;
 
     if (yes) {
         /* first make sure the lock handles are created */
-        for (kr=kr_names; kr; kr = kr->next) {
+        for (kr=kr_resources; kr; kr = kr->next) {
             if (!keyring_is_writable(kr))
                 continue;
             if (!kr->lockhd) {
@@ -337,12 +323,24 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
             return rc;
 
         /* and now set the locks */
-        for (kr=kr_names; kr; kr = kr->next) {
+        for (kr=kr_resources; kr; kr = kr->next) {
             if (!keyring_is_writable(kr))
                 continue;
             if (kr->is_locked)
-                ;
-            else if (dotlock_take (kr->lockhd, -1) ) {
+                continue;
+
+#ifdef HAVE_W32_SYSTEM
+            /* Under Windows we need to CloseHandle the file before we
+             * try to lock it.  This is because another process might
+             * have taken the lock and is using keybox_file_rename to
+             * rename the base file.  How if our dotlock_take below is
+             * waiting for the lock but we have the base file still
+             * open, keybox_file_rename will never succeed as we are
+             * in a deadlock.  */
+            iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0,
+                         (char*)kr->fname);
+#endif /*HAVE_W32_SYSTEM*/
+            if (dotlock_take (kr->lockhd, -1) ) {
                 log_info ("can't lock '%s'\n", kr->fname );
                 rc = GPG_ERR_GENERAL;
             }
@@ -352,12 +350,13 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
     }
 
     if (rc || !yes) {
-        for (kr=kr_names; kr; kr = kr->next) {
+        for (kr=kr_resources; kr; kr = kr->next) {
             if (!keyring_is_writable(kr))
                 continue;
             if (!kr->is_locked)
-                ;
-            else if (dotlock_release (kr->lockhd))
+                continue;
+
+            if (dotlock_release (kr->lockhd))
                 log_info ("can't unlock '%s'\n", kr->fname );
             else
                 kr->is_locked = 0;
@@ -379,6 +378,7 @@ int
 keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
 {
     PACKET *pkt;
+    struct parse_packet_ctx_s parsectx;
     int rc;
     KBNODE keyblock = NULL, node, lastnode;
     IOBUF a;
@@ -408,13 +408,14 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
 
     pkt = xmalloc (sizeof *pkt);
     init_packet (pkt);
-    hd->found.n_packets = 0;;
+    init_parse_packet (&parsectx, a);
+    hd->found.n_packets = 0;
     lastnode = NULL;
     save_mode = set_packet_list_mode(0);
-    while ((rc=parse_packet (a, pkt)) != -1) {
-        hd->found.n_packets++;
+    while ((rc=parse_packet (&parsectx, pkt)) != -1) {
+        hd->found.n_packets = parsectx.n_parsed_packets;
         if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) {
-           free_packet (pkt);
+           free_packet (pkt, &parsectx);
            init_packet (pkt);
            continue;
        }
@@ -460,7 +461,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
           default:
            log_error ("skipped packet of type %d in keyring\n",
                        (int)pkt->pkttype);
-           free_packet(pkt);
+           free_packet(pkt, &parsectx);
            init_packet(pkt);
            continue;
           }
@@ -472,29 +473,6 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
         }
 
         in_cert = 1;
-        if (pkt->pkttype == PKT_RING_TRUST)
-          {
-            /*(this code is duplicated after the loop)*/
-            if ( lastnode
-                 && lastnode->pkt->pkttype == PKT_SIGNATURE
-                 && (pkt->pkt.ring_trust->sigcache & 1) ) {
-                /* This is a ring trust packet with a checked signature
-                 * status cache following directly a signature paket.
-                 * Set the cache status into that signature packet.  */
-                PKT_signature *sig = lastnode->pkt->pkt.signature;
-
-                sig->flags.checked = 1;
-                sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
-            }
-            /* Reset LASTNODE, so that we set the cache status only from
-             * the ring trust packet immediately following a signature. */
-            lastnode = NULL;
-           free_packet(pkt);
-           init_packet(pkt);
-           continue;
-          }
-
-
         node = lastnode = new_kbnode (pkt);
         if (!keyblock)
           keyblock = node;
@@ -530,18 +508,10 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
     if (rc || !ret_kb)
        release_kbnode (keyblock);
     else {
-        /*(duplicated from the loop body)*/
-        if ( pkt && pkt->pkttype == PKT_RING_TRUST
-             && lastnode
-             && lastnode->pkt->pkttype == PKT_SIGNATURE
-             && (pkt->pkt.ring_trust->sigcache & 1) ) {
-            PKT_signature *sig = lastnode->pkt->pkt.signature;
-            sig->flags.checked = 1;
-            sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
-        }
-       *ret_kb = keyblock;
+        *ret_kb = keyblock;
     }
-    free_packet (pkt);
+    free_packet (pkt, &parsectx);
+    deinit_parse_packet (&parsectx);
     xfree (pkt);
     iobuf_close(a);
 
@@ -586,9 +556,9 @@ keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
     rc = do_copy (3, hd->found.kr->fname, kb,
                   hd->found.offset, hd->found.n_packets );
     if (!rc) {
-      if (kr_offtbl)
+      if (key_present_hash)
         {
-          update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
+          key_present_hash_update_from_kb (key_present_hash, kb);
         }
       /* better reset the found info */
       hd->found.kr = NULL;
@@ -632,9 +602,9 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
 
     /* do the insert */
     rc = do_copy (1, fname, kb, 0, 0 );
-    if (!rc && kr_offtbl)
+    if (!rc && key_present_hash)
       {
-        update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
+        key_present_hash_update_from_kb (key_present_hash, kb);
       }
 
     return rc;
@@ -691,9 +661,8 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
 int
 keyring_search_reset (KEYRING_HANDLE hd)
 {
-    assert (hd);
+    log_assert (hd);
 
-    hd->current.kr = NULL;
     iobuf_close (hd->current.iobuf);
     hd->current.iobuf = NULL;
     hd->current.eof = 0;
@@ -701,6 +670,12 @@ keyring_search_reset (KEYRING_HANDLE hd)
 
     hd->found.kr = NULL;
     hd->found.offset = 0;
+
+    if (hd->current.kr)
+      iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0,
+                   (char*)hd->current.kr->fname);
+    hd->current.kr = NULL;
+
     return 0;
 }
 
@@ -749,10 +724,10 @@ prepare_search (KEYRING_HANDLE hd)
         if (!hd->current.kr) {
           if (DBG_LOOKUP)
             log_debug ("%s: keyring not available!\n", __func__);
-            hd->current.eof = 1;
-            return -1; /* keyring not available */
+          hd->current.eof = 1;
+          return -1; /* keyring not available */
         }
-        assert (!hd->current.iobuf);
+        log_assert (!hd->current.iobuf);
     }
     else { /* EOF */
         if (DBG_LOOKUP)
@@ -778,7 +753,7 @@ prepare_search (KEYRING_HANDLE hd)
 
 \f
 /* A map of the all characters valid used for word_match()
- * Valid characters are in in this table converted to uppercase.
+ * Valid characters are in this table converted to uppercase.
  * because the upper 128 bytes have special meaning, we assume
  * that they are all valid.
  * Note: We must use numerical values here in case that this program
@@ -929,13 +904,27 @@ compare_name (int mode, const char *name, const char *uid, size_t uidlen)
     else if (   mode == KEYDB_SEARCH_MODE_MAIL
              || mode == KEYDB_SEARCH_MODE_MAILSUB
              || mode == KEYDB_SEARCH_MODE_MAILEND) {
+        int have_angles = 1;
        for (i=0, s= uid; i < uidlen && *s != '<'; s++, i++)
            ;
+       if (i == uidlen)
+         {
+           /* The UID is a plain addr-spec (cf. RFC2822 section 4.3).  */
+           have_angles = 0;
+           s = uid;
+           i = 0;
+         }
        if (i < uidlen)  {
-           /* skip opening delim and one char and look for the closing one*/
-           s++; i++;
-           for (se=s+1, i++; i < uidlen && *se != '>'; se++, i++)
-               ;
+           if (have_angles)
+             {
+               /* skip opening delim and one char and look for the closing one*/
+               s++; i++;
+               for (se=s+1, i++; i < uidlen && *se != '>'; se++, i++)
+                 ;
+             }
+           else
+             se = s + uidlen;
+
            if (i < uidlen) {
                i = se - s;
                if (mode == KEYDB_SEARCH_MODE_MAIL) {
@@ -972,6 +961,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
 {
   int rc;
   PACKET pkt;
+  struct parse_packet_ctx_s parsectx;
   int save_mode;
   off_t offset, main_offset;
   size_t n;
@@ -979,7 +969,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   int pk_no, uid_no;
   int initial_skip;
   int scanned_from_start;
-  int use_offtbl;
+  int use_key_present_hash;
   PKT_user_id *uid = NULL;
   PKT_public_key *pk = NULL;
   u32 aki[2];
@@ -1036,13 +1026,13 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       return rc;
     }
 
-  use_offtbl = !!kr_offtbl;
-  if (!use_offtbl)
+  use_key_present_hash = !!key_present_hash;
+  if (!use_key_present_hash)
     {
       if (DBG_LOOKUP)
         log_debug ("%s: no offset table.\n", __func__);
     }
-  else if (!kr_offtbl_ready)
+  else if (!key_present_hash_ready)
     {
       if (DBG_LOOKUP)
         log_debug ("%s: initializing offset table. (need_keyid: %d => 1)\n",
@@ -1051,12 +1041,12 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
     }
   else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
     {
-      struct off_item *oi;
+      struct key_present *oi;
 
       if (DBG_LOOKUP)
         log_debug ("%s: look up by long key id, checking cache\n", __func__);
 
-      oi = lookup_offset_hash_table (kr_offtbl, desc[0].u.kid);
+      oi = key_present_hash_lookup (key_present_hash, desc[0].u.kid);
       if (!oi)
         { /* We know that we don't have this key */
           if (DBG_LOOKUP)
@@ -1084,7 +1074,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
           if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS)
             name = desc[n].u.name;
         }
-      assert (name);
+      log_assert (name);
       if ( !hd->word_match.name || strcmp (hd->word_match.name, name) )
         {
           /* name changed */
@@ -1107,15 +1097,16 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   if (DBG_LOOKUP)
     log_debug ("%s: %ssearching from start of resource.\n",
                __func__, scanned_from_start ? "" : "not ");
+  init_parse_packet (&parsectx, hd->current.iobuf);
   while (1)
     {
       byte afp[MAX_FINGERPRINT_LEN];
       size_t an;
 
-      rc = search_packet (hd->current.iobuf, &pkt, &offset, need_uid);
+      rc = search_packet (&parsectx, &pkt, &offset, need_uid);
       if (ignore_legacy && gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
         {
-          free_packet (&pkt);
+          free_packet (&pkt, &parsectx);
           continue;
         }
       if (rc)
@@ -1129,7 +1120,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         }
       if (initial_skip)
         {
-          free_packet (&pkt);
+          free_packet (&pkt, &parsectx);
           continue;
         }
 
@@ -1151,8 +1142,10 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
           if (need_keyid)
             keyid_from_pk (pk, aki);
 
-          if (use_offtbl && !kr_offtbl_ready && scanned_from_start)
-            update_offset_hash_table (kr_offtbl, aki, main_offset);
+          if (use_key_present_hash
+              && !key_present_hash_ready
+              && scanned_from_start)
+            key_present_hash_update (key_present_hash, aki);
         }
       else if (pkt.pkttype == PKT_USER_ID)
         {
@@ -1209,7 +1202,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
             goto found;
           }
        }
-      free_packet (&pkt);
+      free_packet (&pkt, &parsectx);
       continue;
     found:
       if (rc)
@@ -1236,13 +1229,13 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         }
       if (n == ndesc)
         goto real_found;
-      free_packet (&pkt);
+      free_packet (&pkt, &parsectx);
     }
  real_found:
   if (!rc)
     {
       if (DBG_LOOKUP)
-        log_debug ("%s: returing success\n", __func__);
+        log_debug ("%s: returning success\n", __func__);
       hd->found.offset = main_offset;
       hd->found.kr = hd->current.kr;
       hd->found.pk_no = pk? pk_no : 0;
@@ -1256,12 +1249,14 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       hd->current.eof = 1;
       /* if we scanned all keyrings, we are sure that
        * all known key IDs are in our offtbl, mark that. */
-      if (use_offtbl && !kr_offtbl_ready && scanned_from_start)
+      if (use_key_present_hash
+          && !key_present_hash_ready
+          && scanned_from_start)
         {
-          KR_NAME kr;
+          KR_RESOURCE kr;
 
           /* First set the did_full_scan flag for this keyring.  */
-          for (kr=kr_names; kr; kr = kr->next)
+          for (kr=kr_resources; kr; kr = kr->next)
             {
               if (hd->resource == kr)
                 {
@@ -1271,13 +1266,13 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
             }
           /* Then check whether all flags are set and if so, mark the
              offtbl ready */
-          for (kr=kr_names; kr; kr = kr->next)
+          for (kr=kr_resources; kr; kr = kr->next)
             {
               if (!kr->did_full_scan)
                 break;
             }
           if (!kr)
-            kr_offtbl_ready = 1;
+            key_present_hash_ready = 1;
         }
     }
   else
@@ -1288,7 +1283,8 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       hd->current.error = rc;
     }
 
-  free_packet(&pkt);
+  free_packet (&pkt, &parsectx);
+  deinit_parse_packet (&parsectx);
   set_packet_list_mode(save_mode);
   return rc;
 }
@@ -1298,69 +1294,36 @@ static int
 create_tmp_file (const char *template,
                  char **r_bakfname, char **r_tmpfname, IOBUF *r_fp)
 {
-  char *bakfname, *tmpfname;
+  gpg_error_t err;
   mode_t oldmask;
 
-  *r_bakfname = NULL;
-  *r_tmpfname = NULL;
-
-# ifdef USE_ONLY_8DOT3
-  /* Here is another Windoze bug?:
-   * you can't rename("pubring.gpg.tmp", "pubring.gpg");
-   * but       rename("pubring.gpg.tmp", "pubring.aaa");
-   * works.  So we replace .gpg by .bak or .tmp
-   */
-  if (strlen (template) > 4
-      && !strcmp (template+strlen(template)-4, EXTSEP_S GPGEXT_GPG) )
-    {
-      bakfname = xmalloc (strlen (template) + 1);
-      strcpy (bakfname, template);
-      strcpy (bakfname+strlen(template)-4, EXTSEP_S "bak");
+  err = keybox_tmp_names (template, 1, r_bakfname, r_tmpfname);
+  if (err)
+    return err;
 
-      tmpfname = xmalloc (strlen( template ) + 1 );
-      strcpy (tmpfname,template);
-      strcpy (tmpfname+strlen(template)-4, EXTSEP_S "tmp");
+  /* Create the temp file with limited access.  Note that the umask
+     call is not anymore needed because iobuf_create now takes care of
+     it.  However, it does not harm and thus we keep it.  */
+  oldmask = umask (077);
+  if (is_secured_filename (*r_tmpfname))
+    {
+      *r_fp = NULL;
+      gpg_err_set_errno (EPERM);
     }
-    else
-      { /* file does not end with gpg; hmmm */
-       bakfname = xmalloc (strlen( template ) + 5);
-       strcpy (stpcpy(bakfname, template), EXTSEP_S "bak");
-
-       tmpfname = xmalloc (strlen( template ) + 5);
-       strcpy (stpcpy(tmpfname, template), EXTSEP_S "tmp");
+  else
+    *r_fp = iobuf_create (*r_tmpfname, 1);
+  umask (oldmask);
+  if (!*r_fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("can't create '%s': %s\n"), *r_tmpfname, gpg_strerror (err));
+      xfree (*r_tmpfname);
+      *r_tmpfname = NULL;
+      xfree (*r_bakfname);
+      *r_bakfname = NULL;
     }
-# else /* Posix file names */
-    bakfname = xmalloc (strlen( template ) + 2);
-    strcpy (stpcpy (bakfname,template),"~");
-
-    tmpfname = xmalloc (strlen( template ) + 5);
-    strcpy (stpcpy(tmpfname,template), EXTSEP_S "tmp");
-# endif /* Posix filename */
-
-    /* Create the temp file with limited access.  Note that the umask
-       call is not anymore needed because iobuf_create now takes care
-       of it.  However, it does not harm and thus we keep it.  */
-    oldmask=umask(077);
-    if (is_secured_filename (tmpfname))
-      {
-        *r_fp = NULL;
-        gpg_err_set_errno (EPERM);
-      }
-    else
-      *r_fp = iobuf_create (tmpfname, 1);
-    umask(oldmask);
-    if (!*r_fp)
-      {
-        int rc = gpg_error_from_syserror ();
-       log_error(_("can't create '%s': %s\n"), tmpfname, strerror(errno) );
-        xfree (tmpfname);
-        xfree (bakfname);
-       return rc;
-      }
 
-    *r_bakfname = bakfname;
-    *r_tmpfname = tmpfname;
-    return 0;
+  return err;
 }
 
 
@@ -1368,6 +1331,7 @@ static int
 rename_tmp_file (const char *bakfname, const char *tmpfname, const char *fname)
 {
   int rc = 0;
+  int block = 0;
 
   /* Invalidate close caches.  */
   if (iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ))
@@ -1379,32 +1343,25 @@ rename_tmp_file (const char *bakfname, const char *tmpfname, const char *fname)
   iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname );
 
   /* First make a backup file. */
-#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
-  gnupg_remove (bakfname);
-#endif
-  if (rename (fname, bakfname) )
-    {
-      rc = gpg_error_from_syserror ();
-      log_error ("renaming '%s' to '%s' failed: %s\n",
-                 fname, bakfname, strerror(errno) );
-      return rc;
-    }
+  block = 1;
+  rc = gnupg_rename_file (fname, bakfname, &block);
+  if (rc)
+    goto fail;
 
   /* then rename the file */
-#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
-  gnupg_remove( fname );
-#endif
-  if (rename (tmpfname, fname) )
+  rc = gnupg_rename_file (tmpfname, fname, NULL);
+  if (block)
+    {
+      gnupg_unblock_all_signals ();
+      block = 0;
+    }
+  if (rc)
     {
-      rc = gpg_error_from_syserror ();
-      log_error (_("renaming '%s' to '%s' failed: %s\n"),
-                 tmpfname, fname, strerror(errno) );
       register_secured_file (fname);
       goto fail;
     }
 
   /* Now make sure the file has the same permissions as the original */
-
 #ifndef HAVE_DOSISH_SYSTEM
   {
     struct stat statbuf;
@@ -1422,6 +1379,8 @@ rename_tmp_file (const char *bakfname, const char *tmpfname, const char *fname)
   return 0;
 
  fail:
+  if (block)
+    gnupg_unblock_all_signals ();
   return rc;
 }
 
@@ -1434,36 +1393,12 @@ write_keyblock (IOBUF fp, KBNODE keyblock)
 
   while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
     {
-      if (node->pkt->pkttype == PKT_RING_TRUST)
-        continue; /* we write it later on our own */
-
-      if ( (rc = build_packet (fp, node->pkt) ))
+      if ( (rc = build_packet_and_meta (fp, node->pkt) ))
         {
           log_error ("build_packet(%d) failed: %s\n",
                      node->pkt->pkttype, gpg_strerror (rc) );
           return rc;
         }
-      if (node->pkt->pkttype == PKT_SIGNATURE)
-        { /* always write a signature cache packet */
-          PKT_signature *sig = node->pkt->pkt.signature;
-          unsigned int cacheval = 0;
-
-          if (sig->flags.checked)
-            {
-              cacheval |= 1;
-              if (sig->flags.valid)
-                cacheval |= 2;
-            }
-          iobuf_put (fp, 0xb0); /* old style packet 12, 1 byte len*/
-          iobuf_put (fp, 2);    /* 2 bytes */
-          iobuf_put (fp, 0);    /* unused */
-          if (iobuf_put (fp, cacheval))
-            {
-              rc = gpg_error_from_syserror ();
-              log_error ("writing sigcache packet failed\n");
-              return rc;
-            }
-        }
     }
   return 0;
 }
@@ -1474,7 +1409,7 @@ write_keyblock (IOBUF fp, KBNODE keyblock)
  * This is only done for the public keyrings.
  */
 int
-keyring_rebuild_cache (void *token,int noisy)
+keyring_rebuild_cache (ctrl_t ctrl, void *token, int noisy)
 {
   KEYRING_HANDLE hd;
   KEYDB_SEARCH_DESC desc;
@@ -1487,6 +1422,8 @@ keyring_rebuild_cache (void *token,int noisy)
   ulong count = 0, sigcount = 0;
 
   hd = keyring_new (token);
+  if (!hd)
+    return gpg_error_from_syserror ();
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
 
@@ -1496,7 +1433,7 @@ keyring_rebuild_cache (void *token,int noisy)
 
   for (;;)
     {
-      rc = keyring_search (hd, &desc, 1, NULL, 0);
+      rc = keyring_search (hd, &desc, 1, NULL, 1 /* ignore_legacy */);
       if (rc)
         break;  /* ready.  */
 
@@ -1517,6 +1454,8 @@ keyring_rebuild_cache (void *token,int noisy)
                * the original file is closed */
               tmpfp = NULL;
             }
+          /* Static analyzer note: BAKFILENAME is never NULL here
+             because it is controlled by LASTRESNAME.  */
           rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
                                              lastresname) : 0;
           xfree (tmpfilename);  tmpfilename = NULL;
@@ -1531,9 +1470,6 @@ keyring_rebuild_cache (void *token,int noisy)
             goto leave;
         }
 
-      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
-        continue;
-
       release_kbnode (keyblock);
       rc = keyring_get_keyblock (hd, &keyblock);
       if (rc)
@@ -1590,7 +1526,7 @@ keyring_rebuild_cache (void *token,int noisy)
                          || openpgp_pk_test_algo(sig->pubkey_algo)))
                     sig->flags.checked=sig->flags.valid=0;
                   else
-                    check_key_signature (keyblock, node, NULL);
+                    check_key_signature (ctrl, keyblock, node, NULL);
 
                   sigcount++;
                 }
@@ -1602,8 +1538,10 @@ keyring_rebuild_cache (void *token,int noisy)
             goto leave;
 
           if ( !(++count % 50) && noisy && !opt.quiet)
-            log_info(_("%lu keys cached so far (%lu signatures)\n"),
-                     count, sigcount );
+            log_info (ngettext("%lu keys cached so far (%lu signature)\n",
+                               "%lu keys cached so far (%lu signatures)\n",
+                               sigcount),
+                      count, sigcount);
         }
     } /* end main loop */
   if (rc == -1)
@@ -1613,8 +1551,15 @@ keyring_rebuild_cache (void *token,int noisy)
       log_error ("keyring_search failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
-  if(noisy || opt.verbose)
-    log_info(_("%lu keys cached (%lu signatures)\n"), count, sigcount );
+
+  if (noisy || opt.verbose)
+    {
+      log_info (ngettext("%lu key cached",
+                         "%lu keys cached", count), count);
+      log_printf (ngettext(" (%lu signature)\n",
+                           " (%lu signatures)\n", sigcount), sigcount);
+    }
+
   if (tmpfp)
     {
       if (iobuf_close (tmpfp))
@@ -1644,6 +1589,7 @@ keyring_rebuild_cache (void *token,int noisy)
   return rc;
 }
 
+
 \f
 /****************
  * Perform insert/delete/update operation.
@@ -1729,7 +1675,6 @@ do_copy (int mode, const char *fname, KBNODE root,
            iobuf_cancel(newfp);
            goto leave;
        }
-       rc = 0;
     }
 
     if( mode == 2 || mode == 3 ) { /* delete or update */
@@ -1743,7 +1688,7 @@ do_copy (int mode, const char *fname, KBNODE root,
            goto leave;
        }
        /* skip this keyblock */
-       assert( n_packets );
+       log_assert( n_packets );
        rc = skip_some_packets( fp, n_packets );
        if( rc ) {
            log_error("%s: skipping %u packets failed: %s\n",
@@ -1773,7 +1718,6 @@ do_copy (int mode, const char *fname, KBNODE root,
            iobuf_cancel(newfp);
            goto leave;
        }
-       rc = 0;
     }
 
     /* close both files */